Merge branch 'master' into mesmerize_quickfiz
This commit is contained in:
@@ -1,280 +1,282 @@
|
||||
/obj/item/antag_spawner
|
||||
throw_speed = 1
|
||||
throw_range = 5
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
var/used = FALSE
|
||||
|
||||
/obj/item/antag_spawner/proc/spawn_antag(client/C, turf/T, kind = "", datum/mind/user)
|
||||
return
|
||||
|
||||
/obj/item/antag_spawner/proc/equip_antag(mob/target)
|
||||
return
|
||||
|
||||
|
||||
///////////WIZARD
|
||||
|
||||
/obj/item/antag_spawner/contract
|
||||
name = "contract"
|
||||
desc = "A magic contract previously signed by an apprentice. In exchange for instruction in the magical arts, they are bound to answer your call for aid."
|
||||
icon = 'icons/obj/wizard.dmi'
|
||||
icon_state ="scroll2"
|
||||
|
||||
/obj/item/antag_spawner/contract/attack_self(mob/user)
|
||||
user.set_machine(src)
|
||||
var/dat
|
||||
if(used)
|
||||
dat = "<B>You have already summoned your apprentice.</B><BR>"
|
||||
else
|
||||
dat = "<B>Contract of Apprenticeship:</B><BR>"
|
||||
dat += "<I>Using this contract, you may summon an apprentice to aid you on your mission.</I><BR>"
|
||||
dat += "<I>If you are unable to establish contact with your apprentice, you can feed the contract back to the spellbook to refund your points.</I><BR>"
|
||||
dat += "<B>Which school of magic is your apprentice studying?:</B><BR>"
|
||||
dat += "<A href='byond://?src=[REF(src)];school=[APPRENTICE_DESTRUCTION]'>Destruction</A><BR>"
|
||||
dat += "<I>Your apprentice is skilled in offensive magic. They know Magic Missile and Fireball.</I><BR>"
|
||||
dat += "<A href='byond://?src=[REF(src)];school=[APPRENTICE_BLUESPACE]'>Bluespace Manipulation</A><BR>"
|
||||
dat += "<I>Your apprentice is able to defy physics, melting through solid objects and travelling great distances in the blink of an eye. They know Teleport and Ethereal Jaunt.</I><BR>"
|
||||
dat += "<A href='byond://?src=[REF(src)];school=[APPRENTICE_HEALING]'>Healing</A><BR>"
|
||||
dat += "<I>Your apprentice is training to cast spells that will aid your survival. They know Forcewall and Charge and come with a Staff of Healing.</I><BR>"
|
||||
dat += "<A href='byond://?src=[REF(src)];school=[APPRENTICE_ROBELESS]'>Robeless</A><BR>"
|
||||
dat += "<I>Your apprentice is training to cast spells without their robes. They know Knock and Mindswap.</I><BR>"
|
||||
user << browse(dat, "window=radio")
|
||||
onclose(user, "radio")
|
||||
return
|
||||
|
||||
/obj/item/antag_spawner/contract/Topic(href, href_list)
|
||||
..()
|
||||
var/mob/living/carbon/human/H = usr
|
||||
|
||||
if(H.stat || H.restrained())
|
||||
return
|
||||
if(!ishuman(H))
|
||||
return 1
|
||||
|
||||
if(loc == H || (in_range(src, H) && isturf(loc)))
|
||||
H.set_machine(src)
|
||||
if(href_list["school"])
|
||||
if(used)
|
||||
to_chat(H, "You already used this contract!")
|
||||
return
|
||||
var/list/candidates = pollCandidatesForMob("Do you want to play as a wizard's [href_list["school"]] apprentice?", ROLE_WIZARD, null, ROLE_WIZARD, 150, src, ignore_category = POLL_IGNORE_WIZARD)
|
||||
if(LAZYLEN(candidates))
|
||||
if(QDELETED(src))
|
||||
return
|
||||
if(used)
|
||||
to_chat(H, "You already used this contract!")
|
||||
return
|
||||
used = TRUE
|
||||
var/mob/dead/observer/C = pick(candidates)
|
||||
spawn_antag(C.client, get_turf(src), href_list["school"],H.mind)
|
||||
else
|
||||
to_chat(H, "Unable to reach your apprentice! You can either attack the spellbook with the contract to refund your points, or wait and try again later.")
|
||||
|
||||
/obj/item/antag_spawner/contract/spawn_antag(client/C, turf/T, kind ,datum/mind/user)
|
||||
new /obj/effect/particle_effect/smoke(T)
|
||||
var/mob/living/carbon/human/M = new/mob/living/carbon/human(T)
|
||||
C.prefs.copy_to(M)
|
||||
M.key = C.key
|
||||
var/datum/mind/app_mind = M.mind
|
||||
|
||||
var/datum/antagonist/wizard/apprentice/app = new()
|
||||
app.master = user
|
||||
app.school = kind
|
||||
|
||||
var/datum/antagonist/wizard/master_wizard = user.has_antag_datum(/datum/antagonist/wizard)
|
||||
if(master_wizard)
|
||||
if(!master_wizard.wiz_team)
|
||||
master_wizard.create_wiz_team()
|
||||
app.wiz_team = master_wizard.wiz_team
|
||||
master_wizard.wiz_team.add_member(app_mind)
|
||||
app_mind.add_antag_datum(app)
|
||||
//TODO Kill these if possible
|
||||
app_mind.assigned_role = "Apprentice"
|
||||
app_mind.special_role = "apprentice"
|
||||
//
|
||||
SEND_SOUND(M, sound('sound/effects/magic.ogg'))
|
||||
|
||||
///////////BORGS AND OPERATIVES
|
||||
|
||||
|
||||
/obj/item/antag_spawner/nuke_ops
|
||||
name = "syndicate operative teleporter"
|
||||
desc = "A single-use teleporter designed to quickly reinforce operatives in the field."
|
||||
icon = 'icons/obj/device.dmi'
|
||||
icon_state = "locator"
|
||||
var/borg_to_spawn
|
||||
|
||||
/obj/item/antag_spawner/nuke_ops/proc/check_usability(mob/user)
|
||||
if(used)
|
||||
to_chat(user, "<span class='warning'>[src] is out of power!</span>")
|
||||
return FALSE
|
||||
if(!user.mind.has_antag_datum(/datum/antagonist/nukeop,TRUE))
|
||||
to_chat(user, "<span class='danger'>AUTHENTICATION FAILURE. ACCESS DENIED.</span>")
|
||||
return FALSE
|
||||
if(!user.onSyndieBase())
|
||||
to_chat(user, "<span class='warning'>[src] is out of range! It can only be used at your base!</span>")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
|
||||
/obj/item/antag_spawner/nuke_ops/attack_self(mob/user)
|
||||
if(!(check_usability(user)))
|
||||
return
|
||||
|
||||
to_chat(user, "<span class='notice'>You activate [src] and wait for confirmation.</span>")
|
||||
var/list/nuke_candidates = pollGhostCandidates("Do you want to play as a syndicate [borg_to_spawn ? "[lowertext(borg_to_spawn)] cyborg":"operative"]?", ROLE_OPERATIVE, null, ROLE_OPERATIVE, 150, POLL_IGNORE_SYNDICATE)
|
||||
if(LAZYLEN(nuke_candidates))
|
||||
if(QDELETED(src) || !check_usability(user))
|
||||
return
|
||||
used = TRUE
|
||||
var/mob/dead/observer/G = pick(nuke_candidates)
|
||||
spawn_antag(G.client, get_turf(src), "syndieborg", user.mind)
|
||||
do_sparks(4, TRUE, src)
|
||||
qdel(src)
|
||||
else
|
||||
to_chat(user, "<span class='warning'>Unable to connect to Syndicate command. Please wait and try again later or use the teleporter on your uplink to get your points refunded.</span>")
|
||||
|
||||
/obj/item/antag_spawner/nuke_ops/spawn_antag(client/C, turf/T, kind, datum/mind/user)
|
||||
var/mob/living/carbon/human/M = new/mob/living/carbon/human(T)
|
||||
C.prefs.copy_to(M)
|
||||
M.key = C.key
|
||||
|
||||
var/datum/antagonist/nukeop/new_op = new()
|
||||
new_op.send_to_spawnpoint = FALSE
|
||||
new_op.nukeop_outfit = /datum/outfit/syndicate/no_crystals
|
||||
|
||||
var/datum/antagonist/nukeop/creator_op = user.has_antag_datum(/datum/antagonist/nukeop,TRUE)
|
||||
if(creator_op)
|
||||
M.mind.add_antag_datum(new_op,creator_op.nuke_team)
|
||||
M.mind.special_role = "Nuclear Operative"
|
||||
|
||||
//////CLOWN OP
|
||||
/obj/item/antag_spawner/nuke_ops/clown
|
||||
name = "clown operative teleporter"
|
||||
desc = "A single-use teleporter designed to quickly reinforce clown operatives in the field."
|
||||
|
||||
/obj/item/antag_spawner/nuke_ops/clown/spawn_antag(client/C, turf/T, kind, datum/mind/user)
|
||||
var/mob/living/carbon/human/M = new/mob/living/carbon/human(T)
|
||||
C.prefs.copy_to(M)
|
||||
M.key = C.key
|
||||
|
||||
var/datum/antagonist/nukeop/clownop/new_op = new /datum/antagonist/nukeop/clownop()
|
||||
new_op.send_to_spawnpoint = FALSE
|
||||
new_op.nukeop_outfit = /datum/outfit/syndicate/clownop/no_crystals
|
||||
|
||||
var/datum/antagonist/nukeop/creator_op = user.has_antag_datum(/datum/antagonist/nukeop/clownop,TRUE)
|
||||
if(creator_op)
|
||||
M.mind.add_antag_datum(new_op, creator_op.nuke_team)
|
||||
M.mind.special_role = "Clown Operative"
|
||||
|
||||
|
||||
//////SYNDICATE BORG
|
||||
/obj/item/antag_spawner/nuke_ops/borg_tele
|
||||
name = "syndicate cyborg teleporter"
|
||||
desc = "A single-use teleporter designed to quickly reinforce operatives in the field."
|
||||
icon = 'icons/obj/device.dmi'
|
||||
icon_state = "locator"
|
||||
|
||||
/obj/item/antag_spawner/nuke_ops/borg_tele/assault
|
||||
name = "syndicate assault cyborg teleporter"
|
||||
borg_to_spawn = "Assault"
|
||||
|
||||
/obj/item/antag_spawner/nuke_ops/borg_tele/medical
|
||||
name = "syndicate medical teleporter"
|
||||
borg_to_spawn = "Medical"
|
||||
|
||||
/obj/item/antag_spawner/nuke_ops/borg_tele/saboteur
|
||||
name = "syndicate saboteur teleporter"
|
||||
borg_to_spawn = "Saboteur"
|
||||
|
||||
/obj/item/antag_spawner/nuke_ops/borg_tele/spawn_antag(client/C, turf/T, kind, datum/mind/user)
|
||||
var/mob/living/silicon/robot/R
|
||||
var/datum/antagonist/nukeop/creator_op = user.has_antag_datum(/datum/antagonist/nukeop,TRUE)
|
||||
if(!creator_op)
|
||||
return
|
||||
|
||||
switch(borg_to_spawn)
|
||||
if("Medical")
|
||||
R = new /mob/living/silicon/robot/modules/syndicate/medical(T)
|
||||
if("Saboteur")
|
||||
R = new /mob/living/silicon/robot/modules/syndicate/saboteur(T)
|
||||
else
|
||||
R = new /mob/living/silicon/robot/modules/syndicate(T) //Assault borg by default
|
||||
|
||||
var/brainfirstname = pick(GLOB.first_names_male)
|
||||
if(prob(50))
|
||||
brainfirstname = pick(GLOB.first_names_female)
|
||||
var/brainopslastname = pick(GLOB.last_names)
|
||||
if(creator_op.nuke_team.syndicate_name) //the brain inside the syndiborg has the same last name as the other ops.
|
||||
brainopslastname = creator_op.nuke_team.syndicate_name
|
||||
var/brainopsname = "[brainfirstname] [brainopslastname]"
|
||||
|
||||
R.mmi.name = "Man-Machine Interface: [brainopsname]"
|
||||
R.mmi.brain.name = "[brainopsname]'s brain"
|
||||
R.mmi.brainmob.real_name = brainopsname
|
||||
R.mmi.brainmob.name = brainopsname
|
||||
R.real_name = R.name
|
||||
|
||||
R.key = C.key
|
||||
|
||||
var/datum/antagonist/nukeop/new_borg = new()
|
||||
new_borg.send_to_spawnpoint = FALSE
|
||||
R.mind.add_antag_datum(new_borg,creator_op.nuke_team)
|
||||
R.mind.special_role = "Syndicate Cyborg"
|
||||
|
||||
///////////SLAUGHTER DEMON
|
||||
|
||||
/obj/item/antag_spawner/slaughter_demon //Warning edgiest item in the game
|
||||
name = "vial of blood"
|
||||
desc = "A magically infused bottle of blood, distilled from countless murder victims. Used in unholy rituals to attract horrifying creatures."
|
||||
icon = 'icons/obj/wizard.dmi'
|
||||
icon_state = "vial"
|
||||
|
||||
var/shatter_msg = "<span class='notice'>You shatter the bottle, no turning back now!</span>"
|
||||
var/veil_msg = "<span class='warning'>You sense a dark presence lurking just beyond the veil...</span>"
|
||||
var/mob/living/demon_type = /mob/living/simple_animal/slaughter
|
||||
var/antag_type = /datum/antagonist/slaughter
|
||||
|
||||
|
||||
/obj/item/antag_spawner/slaughter_demon/attack_self(mob/user)
|
||||
if(!is_station_level(user.z))
|
||||
to_chat(user, "<span class='notice'>You should probably wait until you reach the station.</span>")
|
||||
return
|
||||
if(used)
|
||||
return
|
||||
var/list/candidates = pollCandidatesForMob("Do you want to play as a [initial(demon_type.name)]?", ROLE_ALIEN, null, ROLE_ALIEN, 50, src, ignore_category = POLL_IGNORE_DEMON)
|
||||
if(LAZYLEN(candidates))
|
||||
if(used || QDELETED(src))
|
||||
return
|
||||
used = TRUE
|
||||
var/mob/dead/observer/C = pick(candidates)
|
||||
spawn_antag(C.client, get_turf(src), initial(demon_type.name),user.mind)
|
||||
to_chat(user, shatter_msg)
|
||||
to_chat(user, veil_msg)
|
||||
playsound(user.loc, 'sound/effects/glassbr1.ogg', 100, 1)
|
||||
qdel(src)
|
||||
else
|
||||
to_chat(user, "<span class='notice'>You can't seem to work up the nerve to shatter the bottle. Perhaps you should try again later.</span>")
|
||||
|
||||
|
||||
/obj/item/antag_spawner/slaughter_demon/spawn_antag(client/C, turf/T, kind = "", datum/mind/user)
|
||||
var/obj/effect/dummy/phased_mob/slaughter/holder = new /obj/effect/dummy/phased_mob/slaughter(T)
|
||||
var/mob/living/simple_animal/slaughter/S = new demon_type(holder)
|
||||
S.holder = holder
|
||||
S.key = C.key
|
||||
S.mind.assigned_role = S.name
|
||||
S.mind.special_role = S.name
|
||||
S.mind.add_antag_datum(antag_type)
|
||||
to_chat(S, S.playstyle_string)
|
||||
to_chat(S, "<B>You are currently not currently in the same plane of existence as the station. \
|
||||
Ctrl+Click a blood pool to manifest.</B>")
|
||||
|
||||
/obj/item/antag_spawner/slaughter_demon/laughter
|
||||
name = "vial of tickles"
|
||||
desc = "A magically infused bottle of clown love, distilled from countless hugging attacks. Used in funny rituals to attract adorable creatures."
|
||||
icon = 'icons/obj/wizard.dmi'
|
||||
icon_state = "vial"
|
||||
color = "#FF69B4" // HOT PINK
|
||||
|
||||
veil_msg = "<span class='warning'>You sense an adorable presence lurking just beyond the veil...</span>"
|
||||
demon_type = /mob/living/simple_animal/slaughter/laughter
|
||||
antag_type = /datum/antagonist/slaughter/laughter
|
||||
/obj/item/antag_spawner
|
||||
throw_speed = 1
|
||||
throw_range = 5
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
var/used = FALSE
|
||||
|
||||
/obj/item/antag_spawner/proc/spawn_antag(client/C, turf/T, kind = "", datum/mind/user)
|
||||
return
|
||||
|
||||
/obj/item/antag_spawner/proc/equip_antag(mob/target)
|
||||
return
|
||||
|
||||
|
||||
///////////WIZARD
|
||||
|
||||
/obj/item/antag_spawner/contract
|
||||
name = "contract"
|
||||
desc = "A magic contract previously signed by an apprentice. In exchange for instruction in the magical arts, they are bound to answer your call for aid."
|
||||
icon = 'icons/obj/wizard.dmi'
|
||||
icon_state ="scroll2"
|
||||
|
||||
/obj/item/antag_spawner/contract/attack_self(mob/user)
|
||||
user.set_machine(src)
|
||||
var/dat
|
||||
if(used)
|
||||
dat = "<B>You have already summoned your apprentice.</B><BR>"
|
||||
else
|
||||
dat = "<B>Contract of Apprenticeship:</B><BR>"
|
||||
dat += "<I>Using this contract, you may summon an apprentice to aid you on your mission.</I><BR>"
|
||||
dat += "<I>If you are unable to establish contact with your apprentice, you can feed the contract back to the spellbook to refund your points.</I><BR>"
|
||||
dat += "<B>Which school of magic is your apprentice studying?:</B><BR>"
|
||||
dat += "<A href='byond://?src=[REF(src)];school=[APPRENTICE_DESTRUCTION]'>Destruction</A><BR>"
|
||||
dat += "<I>Your apprentice is skilled in offensive magic. They know Magic Missile and Fireball.</I><BR>"
|
||||
dat += "<A href='byond://?src=[REF(src)];school=[APPRENTICE_BLUESPACE]'>Bluespace Manipulation</A><BR>"
|
||||
dat += "<I>Your apprentice is able to defy physics, melting through solid objects and travelling great distances in the blink of an eye. They know Teleport and Ethereal Jaunt.</I><BR>"
|
||||
dat += "<A href='byond://?src=[REF(src)];school=[APPRENTICE_HEALING]'>Healing</A><BR>"
|
||||
dat += "<I>Your apprentice is training to cast spells that will aid your survival. They know Forcewall and Charge and come with a Staff of Healing.</I><BR>"
|
||||
dat += "<A href='byond://?src=[REF(src)];school=[APPRENTICE_ROBELESS]'>Robeless</A><BR>"
|
||||
dat += "<I>Your apprentice is training to cast spells without their robes. They know Knock and Mindswap.</I><BR>"
|
||||
dat += "<A href='byond://?src=[REF(src)];school=[APPRENTICE_MARTIAL]'>Martial Artist</a><BR>"
|
||||
dat += "<I>Your apprentice is training in ancient martial arts. They know the Plasmafist and Nuclear Fist.</I><BR>"
|
||||
user << browse(dat, "window=radio")
|
||||
onclose(user, "radio")
|
||||
return
|
||||
|
||||
/obj/item/antag_spawner/contract/Topic(href, href_list)
|
||||
..()
|
||||
var/mob/living/carbon/human/H = usr
|
||||
|
||||
if(H.stat || H.restrained())
|
||||
return
|
||||
if(!ishuman(H))
|
||||
return 1
|
||||
|
||||
if(loc == H || (in_range(src, H) && isturf(loc)))
|
||||
H.set_machine(src)
|
||||
if(href_list["school"])
|
||||
if(used)
|
||||
to_chat(H, "You already used this contract!")
|
||||
return
|
||||
var/list/candidates = pollCandidatesForMob("Do you want to play as a wizard's [href_list["school"]] apprentice?", ROLE_WIZARD, null, ROLE_WIZARD, 150, src, ignore_category = POLL_IGNORE_WIZARD)
|
||||
if(LAZYLEN(candidates))
|
||||
if(QDELETED(src))
|
||||
return
|
||||
if(used)
|
||||
to_chat(H, "You already used this contract!")
|
||||
return
|
||||
used = TRUE
|
||||
var/mob/dead/observer/C = pick(candidates)
|
||||
spawn_antag(C.client, get_turf(src), href_list["school"],H.mind)
|
||||
else
|
||||
to_chat(H, "Unable to reach your apprentice! You can either attack the spellbook with the contract to refund your points, or wait and try again later.")
|
||||
|
||||
/obj/item/antag_spawner/contract/spawn_antag(client/C, turf/T, kind ,datum/mind/user)
|
||||
new /obj/effect/particle_effect/smoke(T)
|
||||
var/mob/living/carbon/human/M = new/mob/living/carbon/human(T)
|
||||
C.prefs.copy_to(M)
|
||||
M.key = C.key
|
||||
var/datum/mind/app_mind = M.mind
|
||||
|
||||
var/datum/antagonist/wizard/apprentice/app = new()
|
||||
app.master = user
|
||||
app.school = kind
|
||||
|
||||
var/datum/antagonist/wizard/master_wizard = user.has_antag_datum(/datum/antagonist/wizard)
|
||||
if(master_wizard)
|
||||
if(!master_wizard.wiz_team)
|
||||
master_wizard.create_wiz_team()
|
||||
app.wiz_team = master_wizard.wiz_team
|
||||
master_wizard.wiz_team.add_member(app_mind)
|
||||
app_mind.add_antag_datum(app)
|
||||
//TODO Kill these if possible
|
||||
app_mind.assigned_role = "Apprentice"
|
||||
app_mind.special_role = "apprentice"
|
||||
//
|
||||
SEND_SOUND(M, sound('sound/effects/magic.ogg'))
|
||||
|
||||
///////////BORGS AND OPERATIVES
|
||||
|
||||
|
||||
/obj/item/antag_spawner/nuke_ops
|
||||
name = "syndicate operative teleporter"
|
||||
desc = "A single-use teleporter designed to quickly reinforce operatives in the field."
|
||||
icon = 'icons/obj/device.dmi'
|
||||
icon_state = "locator"
|
||||
var/borg_to_spawn
|
||||
|
||||
/obj/item/antag_spawner/nuke_ops/proc/check_usability(mob/user)
|
||||
if(used)
|
||||
to_chat(user, "<span class='warning'>[src] is out of power!</span>")
|
||||
return FALSE
|
||||
if(!user.mind.has_antag_datum(/datum/antagonist/nukeop,TRUE))
|
||||
to_chat(user, "<span class='danger'>AUTHENTICATION FAILURE. ACCESS DENIED.</span>")
|
||||
return FALSE
|
||||
if(!user.onSyndieBase())
|
||||
to_chat(user, "<span class='warning'>[src] is out of range! It can only be used at your base!</span>")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
|
||||
/obj/item/antag_spawner/nuke_ops/attack_self(mob/user)
|
||||
if(!(check_usability(user)))
|
||||
return
|
||||
|
||||
to_chat(user, "<span class='notice'>You activate [src] and wait for confirmation.</span>")
|
||||
var/list/nuke_candidates = pollGhostCandidates("Do you want to play as a syndicate [borg_to_spawn ? "[lowertext(borg_to_spawn)] cyborg":"operative"]?", ROLE_OPERATIVE, null, ROLE_OPERATIVE, 150, POLL_IGNORE_SYNDICATE)
|
||||
if(LAZYLEN(nuke_candidates))
|
||||
if(QDELETED(src) || !check_usability(user))
|
||||
return
|
||||
used = TRUE
|
||||
var/mob/dead/observer/G = pick(nuke_candidates)
|
||||
spawn_antag(G.client, get_turf(src), "syndieborg", user.mind)
|
||||
do_sparks(4, TRUE, src)
|
||||
qdel(src)
|
||||
else
|
||||
to_chat(user, "<span class='warning'>Unable to connect to Syndicate command. Please wait and try again later or use the teleporter on your uplink to get your points refunded.</span>")
|
||||
|
||||
/obj/item/antag_spawner/nuke_ops/spawn_antag(client/C, turf/T, kind, datum/mind/user)
|
||||
var/mob/living/carbon/human/M = new/mob/living/carbon/human(T)
|
||||
C.prefs.copy_to(M)
|
||||
M.key = C.key
|
||||
|
||||
var/datum/antagonist/nukeop/new_op = new()
|
||||
new_op.send_to_spawnpoint = FALSE
|
||||
new_op.nukeop_outfit = /datum/outfit/syndicate/no_crystals
|
||||
|
||||
var/datum/antagonist/nukeop/creator_op = user.has_antag_datum(/datum/antagonist/nukeop,TRUE)
|
||||
if(creator_op)
|
||||
M.mind.add_antag_datum(new_op,creator_op.nuke_team)
|
||||
M.mind.special_role = "Nuclear Operative"
|
||||
|
||||
//////CLOWN OP
|
||||
/obj/item/antag_spawner/nuke_ops/clown
|
||||
name = "clown operative teleporter"
|
||||
desc = "A single-use teleporter designed to quickly reinforce clown operatives in the field."
|
||||
|
||||
/obj/item/antag_spawner/nuke_ops/clown/spawn_antag(client/C, turf/T, kind, datum/mind/user)
|
||||
var/mob/living/carbon/human/M = new/mob/living/carbon/human(T)
|
||||
C.prefs.copy_to(M)
|
||||
M.key = C.key
|
||||
|
||||
var/datum/antagonist/nukeop/clownop/new_op = new /datum/antagonist/nukeop/clownop()
|
||||
new_op.send_to_spawnpoint = FALSE
|
||||
new_op.nukeop_outfit = /datum/outfit/syndicate/clownop/no_crystals
|
||||
|
||||
var/datum/antagonist/nukeop/creator_op = user.has_antag_datum(/datum/antagonist/nukeop/clownop,TRUE)
|
||||
if(creator_op)
|
||||
M.mind.add_antag_datum(new_op, creator_op.nuke_team)
|
||||
M.mind.special_role = "Clown Operative"
|
||||
|
||||
|
||||
//////SYNDICATE BORG
|
||||
/obj/item/antag_spawner/nuke_ops/borg_tele
|
||||
name = "syndicate cyborg teleporter"
|
||||
desc = "A single-use teleporter designed to quickly reinforce operatives in the field."
|
||||
icon = 'icons/obj/device.dmi'
|
||||
icon_state = "locator"
|
||||
|
||||
/obj/item/antag_spawner/nuke_ops/borg_tele/assault
|
||||
name = "syndicate assault cyborg teleporter"
|
||||
borg_to_spawn = "Assault"
|
||||
|
||||
/obj/item/antag_spawner/nuke_ops/borg_tele/medical
|
||||
name = "syndicate medical teleporter"
|
||||
borg_to_spawn = "Medical"
|
||||
|
||||
/obj/item/antag_spawner/nuke_ops/borg_tele/saboteur
|
||||
name = "syndicate saboteur teleporter"
|
||||
borg_to_spawn = "Saboteur"
|
||||
|
||||
/obj/item/antag_spawner/nuke_ops/borg_tele/spawn_antag(client/C, turf/T, kind, datum/mind/user)
|
||||
var/mob/living/silicon/robot/R
|
||||
var/datum/antagonist/nukeop/creator_op = user.has_antag_datum(/datum/antagonist/nukeop,TRUE)
|
||||
if(!creator_op)
|
||||
return
|
||||
|
||||
switch(borg_to_spawn)
|
||||
if("Medical")
|
||||
R = new /mob/living/silicon/robot/modules/syndicate/medical(T)
|
||||
if("Saboteur")
|
||||
R = new /mob/living/silicon/robot/modules/syndicate/saboteur(T)
|
||||
else
|
||||
R = new /mob/living/silicon/robot/modules/syndicate(T) //Assault borg by default
|
||||
|
||||
var/brainfirstname = pick(GLOB.first_names_male)
|
||||
if(prob(50))
|
||||
brainfirstname = pick(GLOB.first_names_female)
|
||||
var/brainopslastname = pick(GLOB.last_names)
|
||||
if(creator_op.nuke_team.syndicate_name) //the brain inside the syndiborg has the same last name as the other ops.
|
||||
brainopslastname = creator_op.nuke_team.syndicate_name
|
||||
var/brainopsname = "[brainfirstname] [brainopslastname]"
|
||||
|
||||
R.mmi.name = "Man-Machine Interface: [brainopsname]"
|
||||
R.mmi.brain.name = "[brainopsname]'s brain"
|
||||
R.mmi.brainmob.real_name = brainopsname
|
||||
R.mmi.brainmob.name = brainopsname
|
||||
R.real_name = R.name
|
||||
|
||||
R.key = C.key
|
||||
|
||||
var/datum/antagonist/nukeop/new_borg = new()
|
||||
new_borg.send_to_spawnpoint = FALSE
|
||||
R.mind.add_antag_datum(new_borg,creator_op.nuke_team)
|
||||
R.mind.special_role = "Syndicate Cyborg"
|
||||
|
||||
///////////SLAUGHTER DEMON
|
||||
|
||||
/obj/item/antag_spawner/slaughter_demon //Warning edgiest item in the game
|
||||
name = "vial of blood"
|
||||
desc = "A magically infused bottle of blood, distilled from countless murder victims. Used in unholy rituals to attract horrifying creatures."
|
||||
icon = 'icons/obj/wizard.dmi'
|
||||
icon_state = "vial"
|
||||
|
||||
var/shatter_msg = "<span class='notice'>You shatter the bottle, no turning back now!</span>"
|
||||
var/veil_msg = "<span class='warning'>You sense a dark presence lurking just beyond the veil...</span>"
|
||||
var/mob/living/demon_type = /mob/living/simple_animal/slaughter
|
||||
var/antag_type = /datum/antagonist/slaughter
|
||||
|
||||
|
||||
/obj/item/antag_spawner/slaughter_demon/attack_self(mob/user)
|
||||
if(!is_station_level(user.z))
|
||||
to_chat(user, "<span class='notice'>You should probably wait until you reach the station.</span>")
|
||||
return
|
||||
if(used)
|
||||
return
|
||||
var/list/candidates = pollCandidatesForMob("Do you want to play as a [initial(demon_type.name)]?", ROLE_ALIEN, null, ROLE_ALIEN, 50, src, ignore_category = POLL_IGNORE_DEMON)
|
||||
if(LAZYLEN(candidates))
|
||||
if(used || QDELETED(src))
|
||||
return
|
||||
used = TRUE
|
||||
var/mob/dead/observer/C = pick(candidates)
|
||||
spawn_antag(C.client, get_turf(src), initial(demon_type.name),user.mind)
|
||||
to_chat(user, shatter_msg)
|
||||
to_chat(user, veil_msg)
|
||||
playsound(user.loc, 'sound/effects/glassbr1.ogg', 100, 1)
|
||||
qdel(src)
|
||||
else
|
||||
to_chat(user, "<span class='notice'>You can't seem to work up the nerve to shatter the bottle. Perhaps you should try again later.</span>")
|
||||
|
||||
|
||||
/obj/item/antag_spawner/slaughter_demon/spawn_antag(client/C, turf/T, kind = "", datum/mind/user)
|
||||
var/obj/effect/dummy/phased_mob/slaughter/holder = new /obj/effect/dummy/phased_mob/slaughter(T)
|
||||
var/mob/living/simple_animal/slaughter/S = new demon_type(holder)
|
||||
S.holder = holder
|
||||
S.key = C.key
|
||||
S.mind.assigned_role = S.name
|
||||
S.mind.special_role = S.name
|
||||
S.mind.add_antag_datum(antag_type)
|
||||
to_chat(S, S.playstyle_string)
|
||||
to_chat(S, "<B>You are currently not currently in the same plane of existence as the station. \
|
||||
Ctrl+Click a blood pool to manifest.</B>")
|
||||
|
||||
/obj/item/antag_spawner/slaughter_demon/laughter
|
||||
name = "vial of tickles"
|
||||
desc = "A magically infused bottle of clown love, distilled from countless hugging attacks. Used in funny rituals to attract adorable creatures."
|
||||
icon = 'icons/obj/wizard.dmi'
|
||||
icon_state = "vial"
|
||||
color = "#FF69B4" // HOT PINK
|
||||
|
||||
veil_msg = "<span class='warning'>You sense an adorable presence lurking just beyond the veil...</span>"
|
||||
demon_type = /mob/living/simple_animal/slaughter/laughter
|
||||
antag_type = /datum/antagonist/slaughter/laughter
|
||||
|
||||
@@ -65,6 +65,8 @@
|
||||
//Equip
|
||||
var/mob/living/carbon/human/H = owner.current
|
||||
H.set_species(/datum/species/abductor)
|
||||
var/obj/item/organ/tongue/abductor/T = H.getorganslot(ORGAN_SLOT_TONGUE)
|
||||
T.mothership = "[team.name]"
|
||||
|
||||
H.real_name = "[team.name] [sub_role]"
|
||||
H.equipOutfit(outfit)
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
actions_types = list(/datum/action/item_action/hands_free/activate)
|
||||
allowed = list(
|
||||
/obj/item/abductor,
|
||||
/obj/item/abductor_baton,
|
||||
/obj/item/abductor/baton,
|
||||
/obj/item/melee/baton,
|
||||
/obj/item/gun/energy,
|
||||
/obj/item/restraints/handcuffs
|
||||
@@ -57,7 +57,7 @@
|
||||
|
||||
/obj/item/clothing/suit/armor/abductor/vest/item_action_slot_check(slot, mob/user, datum/action/A)
|
||||
if(slot == SLOT_WEAR_SUIT) //we only give the mob the ability to activate the vest if he's actually wearing it.
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
/obj/item/clothing/suit/armor/abductor/vest/proc/SetDisguise(datum/icon_snapshot/entry)
|
||||
disguise = entry
|
||||
@@ -89,11 +89,9 @@
|
||||
|
||||
/obj/item/clothing/suit/armor/abductor/vest/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
|
||||
DeactivateStealth()
|
||||
return 0
|
||||
|
||||
/obj/item/clothing/suit/armor/abductor/vest/IsReflect()
|
||||
DeactivateStealth()
|
||||
return 0
|
||||
|
||||
/obj/item/clothing/suit/armor/abductor/vest/ui_action_click()
|
||||
switch(mode)
|
||||
@@ -111,7 +109,10 @@
|
||||
to_chat(loc, "<span class='warning'>Combat injection is still recharging.</span>")
|
||||
return
|
||||
var/mob/living/carbon/human/M = loc
|
||||
M.do_adrenaline(150, FALSE, 0, 0, TRUE, list("inaprovaline" = 3, "synaptizine" = 10, "omnizine" = 10), "<span class='boldnotice'>You feel a sudden surge of energy!</span>")
|
||||
M.adjustStaminaLoss(-75)
|
||||
M.SetUnconscious(0)
|
||||
M.SetStun(0)
|
||||
M.SetKnockdown(0)
|
||||
combat_cooldown = 0
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
@@ -131,9 +132,11 @@
|
||||
|
||||
/obj/item/abductor
|
||||
icon = 'icons/obj/abductor.dmi'
|
||||
lefthand_file = 'icons/mob/inhands/antag/abductor_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/antag/abductor_righthand.dmi'
|
||||
|
||||
/obj/item/abductor/proc/AbductorCheck(mob/user)
|
||||
if(HAS_TRAIT(user, TRAIT_ABDUCTOR_TRAINING))
|
||||
if (HAS_TRAIT(user, TRAIT_ABDUCTOR_TRAINING))
|
||||
return TRUE
|
||||
if (istype(user) && user.mind && HAS_TRAIT(user.mind, TRAIT_ABDUCTOR_TRAINING))
|
||||
return TRUE
|
||||
@@ -158,8 +161,6 @@
|
||||
desc = "A dual-mode tool for retrieving specimens and scanning appearances. Scanning can be done through cameras."
|
||||
icon_state = "gizmo_scan"
|
||||
item_state = "silencer"
|
||||
lefthand_file = 'icons/mob/inhands/antag/abductor_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/antag/abductor_righthand.dmi'
|
||||
var/mode = GIZMO_SCAN
|
||||
var/mob/living/marked = null
|
||||
var/obj/machinery/abductor/console/console
|
||||
@@ -218,12 +219,9 @@
|
||||
if(marked == target)
|
||||
to_chat(user, "<span class='warning'>This specimen is already marked!</span>")
|
||||
return
|
||||
if(ishuman(target))
|
||||
if(isabductor(target))
|
||||
marked = target
|
||||
to_chat(user, "<span class='notice'>You mark [target] for future retrieval.</span>")
|
||||
else
|
||||
prepare(target,user)
|
||||
if(isabductor(target) || iscow(target))
|
||||
marked = target
|
||||
to_chat(user, "<span class='notice'>You mark [target] for future retrieval.</span>")
|
||||
else
|
||||
prepare(target,user)
|
||||
|
||||
@@ -247,8 +245,6 @@
|
||||
desc = "A compact device used to shut down communications equipment."
|
||||
icon_state = "silencer"
|
||||
item_state = "gizmo"
|
||||
lefthand_file = 'icons/mob/inhands/antag/abductor_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/antag/abductor_righthand.dmi'
|
||||
|
||||
/obj/item/abductor/silencer/attack(mob/living/M, mob/user)
|
||||
if(!AbductorCheck(user))
|
||||
@@ -292,8 +288,6 @@
|
||||
or to send a command to a test subject with a charged gland."
|
||||
icon_state = "mind_device_message"
|
||||
item_state = "silencer"
|
||||
lefthand_file = 'icons/mob/inhands/antag/abductor_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/antag/abductor_righthand.dmi'
|
||||
var/mode = MIND_DEVICE_MESSAGE
|
||||
|
||||
/obj/item/abductor/mind_device/attack_self(mob/user)
|
||||
@@ -389,6 +383,17 @@
|
||||
item_state = "alienpistol"
|
||||
trigger_guard = TRIGGER_GUARD_ALLOW_ALL
|
||||
|
||||
/obj/item/gun/energy/shrink_ray
|
||||
name = "shrink ray blaster"
|
||||
desc = "This is a piece of frightening alien tech that enhances the magnetic pull of atoms in a localized space to temporarily make an object shrink. \
|
||||
That or it's just space magic. Either way, it shrinks stuff."
|
||||
ammo_type = list(/obj/item/ammo_casing/energy/shrink)
|
||||
item_state = "shrink_ray"
|
||||
icon_state = "shrink_ray"
|
||||
fire_delay = 30
|
||||
selfcharge = 1//shot costs 200 energy, has a max capacity of 1000 for 5 shots. self charge returns 25 energy every couple ticks, so about 1 shot charged every 12~ seconds
|
||||
trigger_guard = TRIGGER_GUARD_ALLOW_ALL// variable-size trigger, get it? (abductors need this to be set so the gun is usable for them)
|
||||
|
||||
/obj/item/paper/guides/antag/abductor
|
||||
name = "Dissection Guide"
|
||||
icon_state = "alienpaper_words"
|
||||
@@ -422,21 +427,18 @@
|
||||
#define BATON_PROBE 3
|
||||
#define BATON_MODES 4
|
||||
|
||||
/obj/item/abductor_baton
|
||||
/obj/item/abductor/baton
|
||||
name = "advanced baton"
|
||||
desc = "A quad-mode baton used for incapacitation and restraining of specimens."
|
||||
var/mode = BATON_STUN
|
||||
icon = 'icons/obj/abductor.dmi'
|
||||
icon_state = "wonderprodStun"
|
||||
item_state = "wonderprod"
|
||||
lefthand_file = 'icons/mob/inhands/antag/abductor_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/antag/abductor_righthand.dmi'
|
||||
slot_flags = ITEM_SLOT_BELT
|
||||
force = 7
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
actions_types = list(/datum/action/item_action/toggle_mode)
|
||||
|
||||
/obj/item/abductor_baton/proc/toggle(mob/living/user=usr)
|
||||
/obj/item/abductor/baton/proc/toggle(mob/living/user=usr)
|
||||
mode = (mode+1)%BATON_MODES
|
||||
var/txt
|
||||
switch(mode)
|
||||
@@ -452,7 +454,7 @@
|
||||
to_chat(usr, "<span class='notice'>You switch the baton to [txt] mode.</span>")
|
||||
update_icon()
|
||||
|
||||
/obj/item/abductor_baton/update_icon()
|
||||
/obj/item/abductor/baton/update_icon()
|
||||
switch(mode)
|
||||
if(BATON_STUN)
|
||||
icon_state = "wonderprodStun"
|
||||
@@ -467,8 +469,8 @@
|
||||
icon_state = "wonderprodProbe"
|
||||
item_state = "wonderprodProbe"
|
||||
|
||||
/obj/item/abductor_baton/attack(mob/target, mob/living/user)
|
||||
if(!isabductor(user))
|
||||
/obj/item/abductor/baton/attack(mob/target, mob/living/user)
|
||||
if(!AbductorCheck(user))
|
||||
return
|
||||
|
||||
if(iscyborg(target))
|
||||
@@ -482,11 +484,9 @@
|
||||
|
||||
user.do_attack_animation(L)
|
||||
|
||||
if(ishuman(L))
|
||||
var/mob/living/carbon/human/H = L
|
||||
if(H.check_shields(src, 0, "[user]'s [name]", MELEE_ATTACK))
|
||||
playsound(L, 'sound/weapons/genhit.ogg', 50, 1)
|
||||
return 0
|
||||
if(L.check_shields(src, 0, "[user]'s [name]", MELEE_ATTACK))
|
||||
playsound(L, 'sound/weapons/genhit.ogg', 50, TRUE)
|
||||
return FALSE
|
||||
|
||||
switch (mode)
|
||||
if(BATON_STUN)
|
||||
@@ -498,10 +498,10 @@
|
||||
if(BATON_PROBE)
|
||||
ProbeAttack(L,user)
|
||||
|
||||
/obj/item/abductor_baton/attack_self(mob/living/user)
|
||||
/obj/item/abductor/baton/attack_self(mob/living/user)
|
||||
toggle(user)
|
||||
|
||||
/obj/item/abductor_baton/proc/StunAttack(mob/living/L,mob/living/user)
|
||||
/obj/item/abductor/baton/proc/StunAttack(mob/living/L,mob/living/user)
|
||||
|
||||
L.lastattacker = user.real_name
|
||||
L.lastattackerckey = user.ckey
|
||||
@@ -513,7 +513,7 @@
|
||||
|
||||
L.visible_message("<span class='danger'>[user] has stunned [L] with [src]!</span>", \
|
||||
"<span class='userdanger'>[user] has stunned you with [src]!</span>")
|
||||
playsound(loc, 'sound/weapons/egloves.ogg', 50, 1, -1)
|
||||
playsound(src, 'sound/weapons/egloves.ogg', 50, TRUE, -1)
|
||||
|
||||
if(ishuman(L))
|
||||
var/mob/living/carbon/human/H = L
|
||||
@@ -521,7 +521,7 @@
|
||||
|
||||
log_combat(user, L, "stunned")
|
||||
|
||||
/obj/item/abductor_baton/proc/SleepAttack(mob/living/L,mob/living/user)
|
||||
/obj/item/abductor/baton/proc/SleepAttack(mob/living/L,mob/living/user)
|
||||
if(L.incapacitated(TRUE, TRUE))
|
||||
if(L.anti_magic_check(FALSE, FALSE, TRUE, 0))
|
||||
to_chat(user, "<span class='warning'>The specimen's tinfoil protection is interfering with the sleep inducement!</span>")
|
||||
@@ -531,7 +531,7 @@
|
||||
return
|
||||
L.visible_message("<span class='danger'>[user] has induced sleep in [L] with [src]!</span>", \
|
||||
"<span class='userdanger'>You suddenly feel very drowsy!</span>")
|
||||
playsound(loc, 'sound/weapons/egloves.ogg', 50, 1, -1)
|
||||
playsound(src, 'sound/weapons/egloves.ogg', 50, TRUE, -1)
|
||||
L.Sleeping(1200)
|
||||
log_combat(user, L, "put to sleep")
|
||||
else
|
||||
@@ -545,13 +545,13 @@
|
||||
L.visible_message("<span class='danger'>[user] tried to induce sleep in [L] with [src]!</span>", \
|
||||
"<span class='userdanger'>You suddenly feel drowsy!</span>")
|
||||
|
||||
/obj/item/abductor_baton/proc/CuffAttack(mob/living/L,mob/living/user)
|
||||
/obj/item/abductor/baton/proc/CuffAttack(mob/living/L,mob/living/user)
|
||||
if(!iscarbon(L))
|
||||
return
|
||||
var/mob/living/carbon/C = L
|
||||
if(!C.handcuffed)
|
||||
if(C.get_num_arms(FALSE) >= 2 || C.get_arm_ignore())
|
||||
playsound(loc, 'sound/weapons/cablecuff.ogg', 30, 1, -2)
|
||||
playsound(src, 'sound/weapons/cablecuff.ogg', 30, TRUE, -2)
|
||||
C.visible_message("<span class='danger'>[user] begins restraining [C] with [src]!</span>", \
|
||||
"<span class='userdanger'>[user] begins shaping an energy field around your hands!</span>")
|
||||
if(do_mob(user, C, 30) && (C.get_num_arms(FALSE) >= 2 || C.get_arm_ignore()))
|
||||
@@ -565,7 +565,7 @@
|
||||
else
|
||||
to_chat(user, "<span class='warning'>[C] doesn't have two hands...</span>")
|
||||
|
||||
/obj/item/abductor_baton/proc/ProbeAttack(mob/living/L,mob/living/user)
|
||||
/obj/item/abductor/baton/proc/ProbeAttack(mob/living/L,mob/living/user)
|
||||
L.visible_message("<span class='danger'>[user] probes [L] with [src]!</span>", \
|
||||
"<span class='userdanger'>[user] probes you!</span>")
|
||||
|
||||
@@ -610,7 +610,7 @@
|
||||
S.start()
|
||||
. = ..()
|
||||
|
||||
/obj/item/abductor_baton/examine(mob/user)
|
||||
/obj/item/abductor/baton/examine(mob/user)
|
||||
. = ..()
|
||||
switch(mode)
|
||||
if(BATON_STUN)
|
||||
@@ -639,10 +639,44 @@
|
||||
AddComponent(/datum/component/wearertargeting/earprotection, list(SLOT_EARS))
|
||||
|
||||
/obj/item/radio/headset/abductor/attackby(obj/item/W, mob/user, params)
|
||||
if(istype(W, /obj/item/screwdriver))
|
||||
if(W.tool_behaviour == TOOL_SCREWDRIVER)
|
||||
return // Stops humans from disassembling abductor headsets.
|
||||
return ..()
|
||||
|
||||
/obj/item/abductor_machine_beacon
|
||||
name = "machine beacon"
|
||||
desc = "A beacon designed to instantly tele-construct abductor machinery."
|
||||
icon = 'icons/obj/abductor.dmi'
|
||||
icon_state = "beacon"
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
var/obj/machinery/spawned_machine
|
||||
|
||||
/obj/item/abductor_machine_beacon/attack_self(mob/user)
|
||||
..()
|
||||
user.visible_message("<span class='notice'>[user] places down [src] and activates it.</span>", "<span class='notice'>You place down [src] and activate it.</span>")
|
||||
user.dropItemToGround(src)
|
||||
playsound(src, 'sound/machines/terminal_alert.ogg', 50)
|
||||
addtimer(CALLBACK(src, .proc/try_spawn_machine), 30)
|
||||
|
||||
/obj/item/abductor_machine_beacon/proc/try_spawn_machine()
|
||||
var/viable = FALSE
|
||||
if(isfloorturf(loc))
|
||||
var/turf/T = loc
|
||||
viable = TRUE
|
||||
for(var/obj/thing in T.contents)
|
||||
if(thing.density || ismachinery(thing) || isstructure(thing))
|
||||
viable = FALSE
|
||||
if(viable)
|
||||
playsound(src, 'sound/effects/phasein.ogg', 50, TRUE)
|
||||
var/new_machine = new spawned_machine(loc)
|
||||
visible_message("<span class='notice'>[new_machine] warps on top of the beacon!</span>")
|
||||
qdel(src)
|
||||
else
|
||||
playsound(src, 'sound/machines/buzz-two.ogg', 50)
|
||||
|
||||
/obj/item/abductor_machine_beacon/chem_dispenser
|
||||
name = "beacon - Reagent Synthesizer"
|
||||
spawned_machine = /obj/machinery/chem_dispenser/abductor
|
||||
|
||||
/obj/item/scalpel/alien
|
||||
name = "alien scalpel"
|
||||
@@ -706,11 +740,11 @@
|
||||
framestackamount = 1
|
||||
|
||||
/obj/structure/table_frame/abductor/attackby(obj/item/I, mob/user, params)
|
||||
if(istype(I, /obj/item/wrench))
|
||||
if(I.tool_behaviour == TOOL_WRENCH)
|
||||
to_chat(user, "<span class='notice'>You start disassembling [src]...</span>")
|
||||
I.play_tool_sound(src)
|
||||
if(I.use_tool(src, user, 30))
|
||||
playsound(src.loc, 'sound/items/deconstruct.ogg', 50, 1)
|
||||
playsound(src, 'sound/items/deconstruct.ogg', 50, TRUE)
|
||||
for(var/i = 1, i <= framestackamount, i++)
|
||||
new framestack(get_turf(src))
|
||||
qdel(src)
|
||||
@@ -760,9 +794,8 @@
|
||||
icon = 'icons/obj/abductor.dmi'
|
||||
icon_state = "bed"
|
||||
can_buckle = 1
|
||||
buckle_lying = 1
|
||||
|
||||
var/static/list/injected_reagents = list("corazone")
|
||||
var/static/list/injected_reagents = list(/datum/reagent/medicine/corazone)
|
||||
|
||||
/obj/structure/table/optable/abductor/Crossed(atom/movable/AM)
|
||||
. = ..()
|
||||
@@ -798,3 +831,11 @@
|
||||
airlock_type = /obj/machinery/door/airlock/abductor
|
||||
material_type = /obj/item/stack/sheet/mineral/abductor
|
||||
noglass = TRUE
|
||||
|
||||
/obj/item/clothing/under/abductor
|
||||
desc = "The most advanced form of jumpsuit known to reality, looks uncomfortable."
|
||||
name = "alien jumpsuit"
|
||||
icon_state = "abductor"
|
||||
item_state = "bl_suit"
|
||||
armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 10, bio = 10, rad = 0, fire = 0, acid = 0)
|
||||
can_adjust = 0
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/datum/outfit/abductor
|
||||
name = "Abductor Basic"
|
||||
uniform = /obj/item/clothing/under/color/grey //they're greys gettit
|
||||
uniform = /obj/item/clothing/under/abductor
|
||||
shoes = /obj/item/clothing/shoes/combat
|
||||
back = /obj/item/storage/backpack
|
||||
ears = /obj/item/radio/headset/abductor
|
||||
@@ -34,7 +34,7 @@
|
||||
name = "Abductor Agent"
|
||||
head = /obj/item/clothing/head/helmet/abductor
|
||||
suit = /obj/item/clothing/suit/armor/abductor/vest
|
||||
suit_store = /obj/item/abductor_baton
|
||||
suit_store = /obj/item/abductor/baton
|
||||
belt = /obj/item/storage/belt/military/abductor/full
|
||||
|
||||
backpack_contents = list(
|
||||
|
||||
@@ -5,18 +5,23 @@
|
||||
icon_state = "gland"
|
||||
status = ORGAN_ROBOTIC
|
||||
beating = TRUE
|
||||
organ_flags = ORGAN_NO_SPOIL
|
||||
var/true_name = "baseline placebo referencer"
|
||||
var/cooldown_low = 300
|
||||
var/cooldown_high = 300
|
||||
var/next_activation = 0
|
||||
var/uses // -1 For infinite
|
||||
var/human_only = 0
|
||||
var/active = 0
|
||||
var/human_only = FALSE
|
||||
var/active = FALSE
|
||||
|
||||
var/mind_control_uses = 1
|
||||
var/mind_control_duration = 1800
|
||||
var/active_mind_control = FALSE
|
||||
|
||||
/obj/item/organ/heart/gland/Initialize()
|
||||
. = ..()
|
||||
icon_state = pick(list("health", "spider", "slime", "emp", "species", "egg", "vent", "mindshock", "viral"))
|
||||
|
||||
/obj/item/organ/heart/gland/examine(mob/user)
|
||||
. = ..()
|
||||
if((user.mind && HAS_TRAIT(user.mind, TRAIT_ABDUCTOR_SCIENTIST_TRAINING)) || isobserver(user))
|
||||
@@ -55,14 +60,18 @@
|
||||
active_mind_control = TRUE
|
||||
message_admins("[key_name(user)] sent an abductor mind control message to [key_name(owner)]: [command]")
|
||||
update_gland_hud()
|
||||
|
||||
var/obj/screen/alert/mind_control/mind_alert = owner.throw_alert("mind_control", /obj/screen/alert/mind_control)
|
||||
mind_alert.command = command
|
||||
addtimer(CALLBACK(src, .proc/clear_mind_control), mind_control_duration)
|
||||
return TRUE
|
||||
|
||||
/obj/item/organ/heart/gland/proc/clear_mind_control()
|
||||
if(!ownerCheck() || !active_mind_control)
|
||||
return FALSE
|
||||
to_chat(owner, "<span class='userdanger'>You feel the compulsion fade, and you completely forget about your previous orders.</span>")
|
||||
to_chat(owner, "<span class='userdanger'>You feel the compulsion fade, and you <i>completely forget</i> about your previous orders.</span>")
|
||||
owner.clear_alert("mind_control")
|
||||
active_mind_control = FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/item/organ/heart/gland/Remove(mob/living/carbon/M, special = 0)
|
||||
active = 0
|
||||
@@ -98,257 +107,4 @@
|
||||
active = 0
|
||||
|
||||
/obj/item/organ/heart/gland/proc/activate()
|
||||
return
|
||||
|
||||
/obj/item/organ/heart/gland/heals
|
||||
true_name = "coherency harmonizer"
|
||||
cooldown_low = 200
|
||||
cooldown_high = 400
|
||||
uses = -1
|
||||
icon_state = "health"
|
||||
mind_control_uses = 3
|
||||
mind_control_duration = 3000
|
||||
|
||||
/obj/item/organ/heart/gland/heals/activate()
|
||||
to_chat(owner, "<span class='notice'>You feel curiously revitalized.</span>")
|
||||
owner.adjustToxLoss(-20, FALSE, TRUE)
|
||||
owner.heal_bodypart_damage(20, 20, 0, TRUE)
|
||||
owner.adjustOxyLoss(-20)
|
||||
|
||||
/obj/item/organ/heart/gland/slime
|
||||
true_name = "gastric animation galvanizer"
|
||||
cooldown_low = 600
|
||||
cooldown_high = 1200
|
||||
uses = -1
|
||||
icon_state = "slime"
|
||||
mind_control_uses = 1
|
||||
mind_control_duration = 2400
|
||||
|
||||
/obj/item/organ/heart/gland/slime/Insert(mob/living/carbon/M, special = 0, drop_if_replaced = TRUE)
|
||||
..()
|
||||
owner.faction |= "slime"
|
||||
owner.grant_language(/datum/language/slime)
|
||||
|
||||
/obj/item/organ/heart/gland/slime/activate()
|
||||
to_chat(owner, "<span class='warning'>You feel nauseated!</span>")
|
||||
owner.vomit(20)
|
||||
|
||||
var/mob/living/simple_animal/slime/Slime = new(get_turf(owner), "grey")
|
||||
Slime.Friends = list(owner)
|
||||
Slime.Leader = owner
|
||||
|
||||
/obj/item/organ/heart/gland/mindshock
|
||||
true_name = "neural crosstalk uninhibitor"
|
||||
cooldown_low = 400
|
||||
cooldown_high = 700
|
||||
uses = -1
|
||||
icon_state = "mindshock"
|
||||
mind_control_uses = 1
|
||||
mind_control_duration = 6000
|
||||
|
||||
/obj/item/organ/heart/gland/mindshock/activate()
|
||||
to_chat(owner, "<span class='notice'>You get a headache.</span>")
|
||||
|
||||
var/turf/T = get_turf(owner)
|
||||
for(var/mob/living/carbon/H in orange(4,T))
|
||||
if(H == owner)
|
||||
continue
|
||||
switch(pick(1,3))
|
||||
if(1)
|
||||
to_chat(H, "<span class='userdanger'>You hear a loud buzz in your head, silencing your thoughts!</span>")
|
||||
H.Stun(50)
|
||||
if(2)
|
||||
to_chat(H, "<span class='warning'>You hear an annoying buzz in your head.</span>")
|
||||
H.confused += 15
|
||||
H.adjustOrganLoss(ORGAN_SLOT_BRAIN, 10, 160)
|
||||
if(3)
|
||||
H.hallucination += 60
|
||||
|
||||
/obj/item/organ/heart/gland/pop
|
||||
true_name = "anthropmorphic translocator"
|
||||
cooldown_low = 900
|
||||
cooldown_high = 1800
|
||||
uses = -1
|
||||
human_only = TRUE
|
||||
icon_state = "species"
|
||||
mind_control_uses = 5
|
||||
mind_control_duration = 300
|
||||
|
||||
/obj/item/organ/heart/gland/pop/activate()
|
||||
to_chat(owner, "<span class='notice'>You feel unlike yourself.</span>")
|
||||
randomize_human(owner)
|
||||
var/species = pick(list(/datum/species/human, /datum/species/lizard, /datum/species/insect, /datum/species/fly))
|
||||
owner.set_species(species)
|
||||
|
||||
/obj/item/organ/heart/gland/ventcrawling
|
||||
true_name = "pliant cartilage enabler"
|
||||
cooldown_low = 1800
|
||||
cooldown_high = 2400
|
||||
uses = 1
|
||||
icon_state = "vent"
|
||||
mind_control_uses = 4
|
||||
mind_control_duration = 1800
|
||||
|
||||
/obj/item/organ/heart/gland/ventcrawling/activate()
|
||||
to_chat(owner, "<span class='notice'>You feel very stretchy.</span>")
|
||||
owner.ventcrawler = VENTCRAWLER_ALWAYS
|
||||
|
||||
/obj/item/organ/heart/gland/viral
|
||||
true_name = "contamination incubator"
|
||||
cooldown_low = 1800
|
||||
cooldown_high = 2400
|
||||
uses = 1
|
||||
icon_state = "viral"
|
||||
mind_control_uses = 1
|
||||
mind_control_duration = 1800
|
||||
|
||||
/obj/item/organ/heart/gland/viral/activate()
|
||||
to_chat(owner, "<span class='warning'>You feel sick.</span>")
|
||||
var/datum/disease/advance/A = random_virus(pick(2,6),6)
|
||||
A.carrier = TRUE
|
||||
owner.ForceContractDisease(A, FALSE, TRUE)
|
||||
|
||||
/obj/item/organ/heart/gland/viral/proc/random_virus(max_symptoms, max_level)
|
||||
if(max_symptoms > VIRUS_SYMPTOM_LIMIT)
|
||||
max_symptoms = VIRUS_SYMPTOM_LIMIT
|
||||
var/datum/disease/advance/A = new /datum/disease/advance()
|
||||
var/list/datum/symptom/possible_symptoms = list()
|
||||
for(var/symptom in subtypesof(/datum/symptom))
|
||||
var/datum/symptom/S = symptom
|
||||
if(initial(S.level) > max_level)
|
||||
continue
|
||||
if(initial(S.level) <= 0) //unobtainable symptoms
|
||||
continue
|
||||
possible_symptoms += S
|
||||
for(var/i in 1 to max_symptoms)
|
||||
var/datum/symptom/chosen_symptom = pick_n_take(possible_symptoms)
|
||||
if(chosen_symptom)
|
||||
var/datum/symptom/S = new chosen_symptom
|
||||
A.symptoms += S
|
||||
A.Refresh() //just in case someone already made and named the same disease
|
||||
return A
|
||||
|
||||
/obj/item/organ/heart/gland/trauma
|
||||
true_name = "white matter randomiser"
|
||||
cooldown_low = 800
|
||||
cooldown_high = 1200
|
||||
uses = 5
|
||||
icon_state = "emp"
|
||||
mind_control_uses = 3
|
||||
mind_control_duration = 1800
|
||||
|
||||
/obj/item/organ/heart/gland/trauma/activate()
|
||||
to_chat(owner, "<span class='warning'>You feel a spike of pain in your head.</span>")
|
||||
if(prob(33))
|
||||
owner.gain_trauma_type(BRAIN_TRAUMA_SPECIAL, rand(TRAUMA_RESILIENCE_BASIC, TRAUMA_RESILIENCE_LOBOTOMY))
|
||||
else
|
||||
if(prob(20))
|
||||
owner.gain_trauma_type(BRAIN_TRAUMA_SEVERE, rand(TRAUMA_RESILIENCE_BASIC, TRAUMA_RESILIENCE_LOBOTOMY))
|
||||
else
|
||||
owner.gain_trauma_type(BRAIN_TRAUMA_MILD, rand(TRAUMA_RESILIENCE_BASIC, TRAUMA_RESILIENCE_LOBOTOMY))
|
||||
|
||||
/obj/item/organ/heart/gland/spiderman
|
||||
true_name = "araneae cloister accelerator"
|
||||
cooldown_low = 450
|
||||
cooldown_high = 900
|
||||
uses = -1
|
||||
icon_state = "spider"
|
||||
mind_control_uses = 2
|
||||
mind_control_duration = 2400
|
||||
|
||||
/obj/item/organ/heart/gland/spiderman/activate()
|
||||
to_chat(owner, "<span class='warning'>You feel something crawling in your skin.</span>")
|
||||
owner.faction |= "spiders"
|
||||
var/obj/structure/spider/spiderling/S = new(owner.drop_location())
|
||||
S.directive = "Protect your nest inside [owner.real_name]."
|
||||
|
||||
/obj/item/organ/heart/gland/egg
|
||||
true_name = "roe/enzymatic synthesizer"
|
||||
cooldown_low = 300
|
||||
cooldown_high = 400
|
||||
uses = -1
|
||||
icon_state = "egg"
|
||||
lefthand_file = 'icons/mob/inhands/misc/food_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/misc/food_righthand.dmi'
|
||||
mind_control_uses = 2
|
||||
mind_control_duration = 1800
|
||||
|
||||
/obj/item/organ/heart/gland/egg/activate()
|
||||
owner.visible_message("<span class='alertalien'>[owner] [pick(EGG_LAYING_MESSAGES)]</span>")
|
||||
var/turf/T = owner.drop_location()
|
||||
new /obj/item/reagent_containers/food/snacks/egg/gland(T)
|
||||
|
||||
/obj/item/organ/heart/gland/electric
|
||||
true_name = "electron accumulator/discharger"
|
||||
cooldown_low = 800
|
||||
cooldown_high = 1200
|
||||
uses = -1
|
||||
mind_control_uses = 2
|
||||
mind_control_duration = 900
|
||||
|
||||
/obj/item/organ/heart/gland/electric/Insert(mob/living/carbon/M, special = 0, drop_if_replaced = TRUE)
|
||||
..()
|
||||
ADD_TRAIT(owner, TRAIT_SHOCKIMMUNE, ORGAN_TRAIT)
|
||||
|
||||
/obj/item/organ/heart/gland/electric/Remove(mob/living/carbon/M, special = 0)
|
||||
REMOVE_TRAIT(owner, TRAIT_SHOCKIMMUNE, ORGAN_TRAIT)
|
||||
..()
|
||||
|
||||
/obj/item/organ/heart/gland/electric/activate()
|
||||
owner.visible_message("<span class='danger'>[owner]'s skin starts emitting electric arcs!</span>",\
|
||||
"<span class='warning'>You feel electric energy building up inside you!</span>")
|
||||
playsound(get_turf(owner), "sparks", 100, 1, -1)
|
||||
addtimer(CALLBACK(src, .proc/zap), rand(30, 100))
|
||||
|
||||
/obj/item/organ/heart/gland/electric/proc/zap()
|
||||
tesla_zap(owner, 4, 8000, TESLA_MOB_DAMAGE | TESLA_OBJ_DAMAGE | TESLA_MOB_STUN)
|
||||
playsound(get_turf(owner), 'sound/magic/lightningshock.ogg', 50, 1)
|
||||
|
||||
/obj/item/organ/heart/gland/chem
|
||||
true_name = "intrinsic pharma-provider"
|
||||
cooldown_low = 50
|
||||
cooldown_high = 50
|
||||
uses = -1
|
||||
mind_control_uses = 3
|
||||
mind_control_duration = 1200
|
||||
var/list/possible_reagents = list()
|
||||
|
||||
/obj/item/organ/heart/gland/chem/Initialize()
|
||||
..()
|
||||
for(var/X in subtypesof(/datum/reagent/drug))
|
||||
var/datum/reagent/R = X
|
||||
possible_reagents += initial(R.id)
|
||||
for(var/X in subtypesof(/datum/reagent/medicine))
|
||||
var/datum/reagent/R = X
|
||||
possible_reagents += initial(R.id)
|
||||
for(var/X in typesof(/datum/reagent/toxin))
|
||||
var/datum/reagent/R = X
|
||||
possible_reagents += initial(R.id)
|
||||
|
||||
/obj/item/organ/heart/gland/chem/activate()
|
||||
var/chem_to_add = pick(possible_reagents)
|
||||
owner.reagents.add_reagent(chem_to_add, 2)
|
||||
owner.adjustToxLoss(-2, TRUE, TRUE)
|
||||
..()
|
||||
|
||||
/obj/item/organ/heart/gland/plasma
|
||||
true_name = "effluvium sanguine-synonym emitter"
|
||||
cooldown_low = 1200
|
||||
cooldown_high = 1800
|
||||
uses = -1
|
||||
mind_control_uses = 1
|
||||
mind_control_duration = 800
|
||||
|
||||
/obj/item/organ/heart/gland/plasma/activate()
|
||||
to_chat(owner, "<span class='warning'>You feel bloated.</span>")
|
||||
addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, owner, "<span class='userdanger'>A massive stomachache overcomes you.</span>"), 150)
|
||||
addtimer(CALLBACK(src, .proc/vomit_plasma), 200)
|
||||
|
||||
/obj/item/organ/heart/gland/plasma/proc/vomit_plasma()
|
||||
if(!owner)
|
||||
return
|
||||
owner.visible_message("<span class='danger'>[owner] vomits a cloud of plasma!</span>")
|
||||
var/turf/open/T = get_turf(owner)
|
||||
if(istype(T))
|
||||
T.atmos_spawn_air("plasma=50;TEMP=[T20C]")
|
||||
owner.vomit()
|
||||
return
|
||||
@@ -0,0 +1,19 @@
|
||||
/obj/item/organ/heart/gland/access
|
||||
true_name = "anagraphic electro-scrambler"
|
||||
cooldown_low = 600
|
||||
cooldown_high = 1200
|
||||
uses = 1
|
||||
icon_state = "mindshock"
|
||||
mind_control_uses = 3
|
||||
mind_control_duration = 900
|
||||
|
||||
/obj/item/organ/heart/gland/access/activate()
|
||||
to_chat(owner, "<span class='notice'>You feel like a VIP for some reason.</span>")
|
||||
RegisterSignal(owner, COMSIG_MOB_ALLOWED, .proc/free_access)
|
||||
|
||||
/obj/item/organ/heart/gland/access/proc/free_access(datum/source, obj/O)
|
||||
return TRUE
|
||||
|
||||
/obj/item/organ/heart/gland/access/Remove(mob/living/carbon/M, special = 0)
|
||||
UnregisterSignal(owner, COMSIG_MOB_ALLOWED)
|
||||
..()
|
||||
@@ -0,0 +1,18 @@
|
||||
/obj/item/organ/heart/gland/blood
|
||||
true_name = "pseudonuclear hemo-destabilizer"
|
||||
cooldown_low = 1200
|
||||
cooldown_high = 1800
|
||||
uses = -1
|
||||
icon_state = "egg"
|
||||
lefthand_file = 'icons/mob/inhands/misc/food_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/misc/food_righthand.dmi'
|
||||
mind_control_uses = 3
|
||||
mind_control_duration = 1500
|
||||
|
||||
/obj/item/organ/heart/gland/blood/activate()
|
||||
if(!ishuman(owner) || !owner.dna.species)
|
||||
return
|
||||
var/mob/living/carbon/human/H = owner
|
||||
var/datum/species/species = H.dna.species
|
||||
to_chat(H, "<span class='warning'>You feel your blood heat up for a moment.</span>")
|
||||
species.exotic_blood = get_random_reagent_id()
|
||||
@@ -0,0 +1,20 @@
|
||||
/obj/item/organ/heart/gland/chem
|
||||
true_name = "intrinsic pharma-provider"
|
||||
cooldown_low = 50
|
||||
cooldown_high = 50
|
||||
uses = -1
|
||||
icon_state = "viral"
|
||||
mind_control_uses = 3
|
||||
mind_control_duration = 1200
|
||||
var/list/possible_reagents = list()
|
||||
|
||||
/obj/item/organ/heart/gland/chem/Initialize()
|
||||
. = ..()
|
||||
for(var/R in subtypesof(/datum/reagent/drug) + subtypesof(/datum/reagent/medicine) + typesof(/datum/reagent/toxin))
|
||||
possible_reagents += R
|
||||
|
||||
/obj/item/organ/heart/gland/chem/activate()
|
||||
var/chem_to_add = pick(possible_reagents)
|
||||
owner.reagents.add_reagent(chem_to_add, 2)
|
||||
owner.adjustToxLoss(-5, TRUE, TRUE)
|
||||
..()
|
||||
@@ -0,0 +1,15 @@
|
||||
/obj/item/organ/heart/gland/egg
|
||||
true_name = "roe/enzymatic synthesizer"
|
||||
cooldown_low = 300
|
||||
cooldown_high = 400
|
||||
uses = -1
|
||||
icon_state = "egg"
|
||||
lefthand_file = 'icons/mob/inhands/misc/food_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/misc/food_righthand.dmi'
|
||||
mind_control_uses = 2
|
||||
mind_control_duration = 1800
|
||||
|
||||
/obj/item/organ/heart/gland/egg/activate()
|
||||
owner.visible_message("<span class='alertalien'>[owner] [pick(EGG_LAYING_MESSAGES)]</span>")
|
||||
var/turf/T = owner.drop_location()
|
||||
new /obj/item/reagent_containers/food/snacks/egg/gland(T)
|
||||
@@ -0,0 +1,26 @@
|
||||
/obj/item/organ/heart/gland/electric
|
||||
true_name = "electron accumulator/discharger"
|
||||
cooldown_low = 800
|
||||
cooldown_high = 1200
|
||||
icon_state = "species"
|
||||
uses = -1
|
||||
mind_control_uses = 2
|
||||
mind_control_duration = 900
|
||||
|
||||
/obj/item/organ/heart/gland/electric/Insert(mob/living/carbon/M, special = 0, drop_if_replaced = TRUE)
|
||||
..()
|
||||
ADD_TRAIT(owner, TRAIT_SHOCKIMMUNE, "abductor_gland")
|
||||
|
||||
/obj/item/organ/heart/gland/electric/Remove(mob/living/carbon/M, special = 0)
|
||||
REMOVE_TRAIT(owner, TRAIT_SHOCKIMMUNE, "abductor_gland")
|
||||
..()
|
||||
|
||||
/obj/item/organ/heart/gland/electric/activate()
|
||||
owner.visible_message("<span class='danger'>[owner]'s skin starts emitting electric arcs!</span>",\
|
||||
"<span class='warning'>You feel electric energy building up inside you!</span>")
|
||||
playsound(get_turf(owner), "sparks", 100, TRUE, -1)
|
||||
addtimer(CALLBACK(src, .proc/zap), rand(30, 100))
|
||||
|
||||
/obj/item/organ/heart/gland/electric/proc/zap()
|
||||
tesla_zap(owner, 4, 8000, TESLA_MOB_DAMAGE | TESLA_OBJ_DAMAGE | TESLA_MOB_STUN)
|
||||
playsound(get_turf(owner), 'sound/magic/lightningshock.ogg', 50, TRUE)
|
||||
@@ -0,0 +1,178 @@
|
||||
/obj/item/organ/heart/gland/heal
|
||||
true_name = "organic replicator"
|
||||
cooldown_low = 200
|
||||
cooldown_high = 400
|
||||
uses = -1
|
||||
human_only = TRUE
|
||||
icon_state = "health"
|
||||
mind_control_uses = 3
|
||||
mind_control_duration = 3000
|
||||
|
||||
/obj/item/organ/heart/gland/heal/activate()
|
||||
if(!(owner.mob_biotypes & MOB_ORGANIC))
|
||||
return
|
||||
|
||||
for(var/organ in owner.internal_organs)
|
||||
if(istype(organ, /obj/item/organ/cyberimp))
|
||||
reject_implant(organ)
|
||||
return
|
||||
|
||||
var/obj/item/organ/liver/liver = owner.getorganslot(ORGAN_SLOT_LIVER)
|
||||
if((!liver/* && !HAS_TRAIT(owner, TRAIT_NOMETABOLISM)*/) || (liver && ((liver.damage > (liver.maxHealth / 2)) || (istype(liver, /obj/item/organ/liver/cybernetic)))))
|
||||
replace_liver(liver)
|
||||
return
|
||||
|
||||
var/obj/item/organ/lungs/lungs = owner.getorganslot(ORGAN_SLOT_LUNGS)
|
||||
if((!lungs && !HAS_TRAIT(owner, TRAIT_NOBREATH)) || (lungs && (istype(lungs, /obj/item/organ/lungs/cybernetic))))
|
||||
replace_lungs(lungs)
|
||||
return
|
||||
|
||||
var/obj/item/organ/eyes/eyes = owner.getorganslot(ORGAN_SLOT_EYES)
|
||||
if(!eyes || (eyes && ((HAS_TRAIT_FROM(owner, TRAIT_NEARSIGHT, EYE_DAMAGE)) || (HAS_TRAIT_FROM(owner, TRAIT_BLIND, EYE_DAMAGE)) || (istype(eyes, /obj/item/organ/eyes/robotic)))))
|
||||
replace_eyes(eyes)
|
||||
return
|
||||
|
||||
var/obj/item/bodypart/limb
|
||||
var/list/limb_list = list(BODY_ZONE_L_ARM, BODY_ZONE_R_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)
|
||||
for(var/zone in limb_list)
|
||||
limb = owner.get_bodypart(zone)
|
||||
if(!limb)
|
||||
replace_limb(zone)
|
||||
return
|
||||
if((limb.get_damage() >= (limb.max_damage / 2)) || (limb.status == BODYPART_ROBOTIC))
|
||||
replace_limb(zone, limb)
|
||||
return
|
||||
|
||||
if(owner.getToxLoss() > 40)
|
||||
replace_blood()
|
||||
return
|
||||
var/tox_amount = 0
|
||||
for(var/datum/reagent/toxin/T in owner.reagents.reagent_list)
|
||||
tox_amount += owner.reagents.get_reagent_amount(T.type)
|
||||
if(tox_amount > 10)
|
||||
replace_blood()
|
||||
return
|
||||
if(owner.blood_volume < BLOOD_VOLUME_OKAY)
|
||||
owner.blood_volume = BLOOD_VOLUME_NORMAL
|
||||
to_chat(owner, "<span class='warning'>You feel your blood pulsing within you.</span>")
|
||||
return
|
||||
|
||||
var/obj/item/bodypart/chest/chest = owner.get_bodypart(BODY_ZONE_CHEST)
|
||||
if((chest.get_damage() >= (chest.max_damage / 4)) || (chest.status == BODYPART_ROBOTIC))
|
||||
replace_chest(chest)
|
||||
return
|
||||
|
||||
/obj/item/organ/heart/gland/heal/proc/reject_implant(obj/item/organ/cyberimp/implant)
|
||||
owner.visible_message("<span class='warning'>[owner] vomits up his [implant.name]!</span>", "<span class='userdanger'>You suddenly vomit up your [implant.name]!</span>")
|
||||
owner.vomit(0, TRUE, TRUE, 1, FALSE, FALSE, FALSE, TRUE)
|
||||
implant.Remove(owner)
|
||||
implant.forceMove(owner.drop_location())
|
||||
|
||||
/obj/item/organ/heart/gland/heal/proc/replace_liver(obj/item/organ/liver/liver)
|
||||
if(liver)
|
||||
owner.visible_message("<span class='warning'>[owner] vomits up his [liver.name]!</span>", "<span class='userdanger'>You suddenly vomit up your [liver.name]!</span>")
|
||||
owner.vomit(0, TRUE, TRUE, 1, FALSE, FALSE, FALSE, TRUE)
|
||||
liver.Remove(owner)
|
||||
liver.forceMove(owner.drop_location())
|
||||
else
|
||||
to_chat(owner, "<span class='warning'>You feel a weird rumble in your bowels...</span>")
|
||||
|
||||
var/liver_type = /obj/item/organ/liver
|
||||
if(owner?.dna?.species?.mutantliver)
|
||||
liver_type = owner.dna.species.mutantliver
|
||||
var/obj/item/organ/liver/new_liver = new liver_type()
|
||||
new_liver.Insert(owner)
|
||||
|
||||
/obj/item/organ/heart/gland/heal/proc/replace_lungs(obj/item/organ/lungs/lungs)
|
||||
if(lungs)
|
||||
owner.visible_message("<span class='warning'>[owner] vomits up his [lungs.name]!</span>", "<span class='userdanger'>You suddenly vomit up your [lungs.name]!</span>")
|
||||
owner.vomit(0, TRUE, TRUE, 1, FALSE, FALSE, FALSE, TRUE)
|
||||
lungs.Remove(owner)
|
||||
lungs.forceMove(owner.drop_location())
|
||||
else
|
||||
to_chat(owner, "<span class='warning'>You feel a weird rumble inside your chest...</span>")
|
||||
|
||||
var/lung_type = /obj/item/organ/lungs
|
||||
if(owner.dna.species && owner.dna.species.mutantlungs)
|
||||
lung_type = owner.dna.species.mutantlungs
|
||||
var/obj/item/organ/lungs/new_lungs = new lung_type()
|
||||
new_lungs.Insert(owner)
|
||||
|
||||
/obj/item/organ/heart/gland/heal/proc/replace_eyes(obj/item/organ/eyes/eyes)
|
||||
if(eyes)
|
||||
owner.visible_message("<span class='warning'>[owner]'s [eyes.name] fall out of their sockets!</span>", "<span class='userdanger'>Your [eyes.name] fall out of their sockets!</span>")
|
||||
playsound(owner, 'sound/effects/splat.ogg', 50, TRUE)
|
||||
eyes.Remove(owner)
|
||||
eyes.forceMove(owner.drop_location())
|
||||
else
|
||||
to_chat(owner, "<span class='warning'>You feel a weird rumble behind your eye sockets...</span>")
|
||||
|
||||
addtimer(CALLBACK(src, .proc/finish_replace_eyes), rand(100, 200))
|
||||
|
||||
/obj/item/organ/heart/gland/heal/proc/finish_replace_eyes()
|
||||
var/eye_type = /obj/item/organ/eyes
|
||||
if(owner.dna.species && owner.dna.species.mutanteyes)
|
||||
eye_type = owner.dna.species.mutanteyes
|
||||
var/obj/item/organ/eyes/new_eyes = new eye_type()
|
||||
new_eyes.Insert(owner)
|
||||
owner.visible_message("<span class='warning'>A pair of new eyes suddenly inflates into [owner]'s eye sockets!</span>", "<span class='userdanger'>A pair of new eyes suddenly inflates into your eye sockets!</span>")
|
||||
|
||||
/obj/item/organ/heart/gland/heal/proc/replace_limb(body_zone, obj/item/bodypart/limb)
|
||||
if(limb)
|
||||
owner.visible_message("<span class='warning'>[owner]'s [limb.name] suddenly detaches from [owner.p_their()] body!</span>", "<span class='userdanger'>Your [limb.name] suddenly detaches from your body!</span>")
|
||||
playsound(owner, "desceration", 50, TRUE, -1)
|
||||
limb.drop_limb()
|
||||
else
|
||||
to_chat(owner, "<span class='warning'>You feel a weird tingle in your [parse_zone(body_zone)]... even if you don't have one.</span>")
|
||||
|
||||
addtimer(CALLBACK(src, .proc/finish_replace_limb, body_zone), rand(150, 300))
|
||||
|
||||
/obj/item/organ/heart/gland/heal/proc/finish_replace_limb(body_zone)
|
||||
owner.visible_message("<span class='warning'>With a loud snap, [owner]'s [parse_zone(body_zone)] rapidly grows back from [owner.p_their()] body!</span>",
|
||||
"<span class='userdanger'>With a loud snap, your [parse_zone(body_zone)] rapidly grows back from your body!</span>",
|
||||
"<span class='warning'>Your hear a loud snap.</span>")
|
||||
playsound(owner, 'sound/magic/demon_consume.ogg', 50, TRUE)
|
||||
owner.regenerate_limb(body_zone)
|
||||
|
||||
/obj/item/organ/heart/gland/heal/proc/replace_blood()
|
||||
owner.visible_message("<span class='warning'>[owner] starts vomiting huge amounts of blood!</span>", "<span class='userdanger'>You suddenly start vomiting huge amounts of blood!</span>")
|
||||
keep_replacing_blood()
|
||||
|
||||
/obj/item/organ/heart/gland/heal/proc/keep_replacing_blood()
|
||||
var/keep_going = FALSE
|
||||
owner.vomit(0, TRUE, FALSE, 3, FALSE, FALSE, FALSE, TRUE)
|
||||
owner.Stun(15)
|
||||
owner.adjustToxLoss(-15, TRUE, TRUE)
|
||||
|
||||
owner.blood_volume = min(BLOOD_VOLUME_NORMAL, owner.blood_volume + 20)
|
||||
if(owner.blood_volume < BLOOD_VOLUME_NORMAL)
|
||||
keep_going = TRUE
|
||||
|
||||
if(owner.getToxLoss())
|
||||
keep_going = TRUE
|
||||
for(var/datum/reagent/toxin/R in owner.reagents.reagent_list)
|
||||
owner.reagents.remove_reagent(R.type, 4)
|
||||
if(owner.reagents.has_reagent(R.type))
|
||||
keep_going = TRUE
|
||||
if(keep_going)
|
||||
addtimer(CALLBACK(src, .proc/keep_replacing_blood), 30)
|
||||
|
||||
/obj/item/organ/heart/gland/heal/proc/replace_chest(obj/item/bodypart/chest/chest)
|
||||
if(chest.status == BODYPART_ROBOTIC)
|
||||
owner.visible_message("<span class='warning'>[owner]'s [chest.name] rapidly expels its mechanical components, replacing them with flesh!</span>", "<span class='userdanger'>Your [chest.name] rapidly expels its mechanical components, replacing them with flesh!</span>")
|
||||
playsound(owner, 'sound/magic/clockwork/anima_fragment_attack.ogg', 50, TRUE)
|
||||
var/list/dirs = GLOB.alldirs.Copy()
|
||||
for(var/i in 1 to 3)
|
||||
var/obj/effect/decal/cleanable/robot_debris/debris = new(get_turf(owner))
|
||||
debris.streak(dirs)
|
||||
else
|
||||
owner.visible_message("<span class='warning'>[owner]'s [chest.name] sheds off its damaged flesh, rapidly replacing it!</span>", "<span class='warning'>Your [chest.name] sheds off its damaged flesh, rapidly replacing it!</span>")
|
||||
playsound(owner, 'sound/effects/splat.ogg', 50, TRUE)
|
||||
var/list/dirs = GLOB.alldirs.Copy()
|
||||
for(var/i in 1 to 3)
|
||||
var/obj/effect/decal/cleanable/blood/gibs/gibs = new(get_turf(owner))
|
||||
gibs.streak(dirs)
|
||||
|
||||
var/obj/item/bodypart/chest/new_chest = new(null)
|
||||
new_chest.replace_limb(owner, TRUE)
|
||||
qdel(chest)
|
||||
@@ -0,0 +1,64 @@
|
||||
/obj/item/organ/heart/gland/mindshock
|
||||
true_name = "neural crosstalk uninhibitor"
|
||||
cooldown_low = 400
|
||||
cooldown_high = 700
|
||||
uses = -1
|
||||
icon_state = "mindshock"
|
||||
mind_control_uses = 1
|
||||
mind_control_duration = 6000
|
||||
var/list/mob/living/carbon/human/broadcasted_mobs = list()
|
||||
|
||||
/obj/item/organ/heart/gland/mindshock/activate()
|
||||
to_chat(owner, "<span class='notice'>You get a headache.</span>")
|
||||
|
||||
var/turf/T = get_turf(owner)
|
||||
for(var/mob/living/carbon/H in orange(4,T))
|
||||
if(H == owner)
|
||||
continue
|
||||
switch(pick(1,3))
|
||||
if(1)
|
||||
to_chat(H, "<span class='userdanger'>You hear a loud buzz in your head, silencing your thoughts!</span>")
|
||||
H.Stun(50)
|
||||
if(2)
|
||||
to_chat(H, "<span class='warning'>You hear an annoying buzz in your head.</span>")
|
||||
H.confused += 15
|
||||
H.adjustOrganLoss(ORGAN_SLOT_BRAIN, 10, 160)
|
||||
if(3)
|
||||
H.hallucination += 60
|
||||
|
||||
/obj/item/organ/heart/gland/mindshock/mind_control(command, mob/living/user)
|
||||
if(!ownerCheck() || !mind_control_uses || active_mind_control)
|
||||
return FALSE
|
||||
mind_control_uses--
|
||||
for(var/mob/M in oview(7, owner))
|
||||
if(!ishuman(M))
|
||||
continue
|
||||
var/mob/living/carbon/human/H = M
|
||||
if(H.stat)
|
||||
continue
|
||||
|
||||
broadcasted_mobs += H
|
||||
to_chat(H, "<span class='userdanger'>You suddenly feel an irresistible compulsion to follow an order...</span>")
|
||||
to_chat(H, "<span class='mind_control'>[command]</span>")
|
||||
|
||||
message_admins("[key_name(user)] broadcasted an abductor mind control message from [key_name(owner)] to [key_name(H)]: [command]")
|
||||
|
||||
var/obj/screen/alert/mind_control/mind_alert = H.throw_alert("mind_control", /obj/screen/alert/mind_control)
|
||||
mind_alert.command = command
|
||||
|
||||
if(LAZYLEN(broadcasted_mobs))
|
||||
active_mind_control = TRUE
|
||||
addtimer(CALLBACK(src, .proc/clear_mind_control), mind_control_duration)
|
||||
|
||||
update_gland_hud()
|
||||
return TRUE
|
||||
|
||||
/obj/item/organ/heart/gland/mindshock/clear_mind_control()
|
||||
if(!active_mind_control || !LAZYLEN(broadcasted_mobs))
|
||||
return FALSE
|
||||
for(var/M in broadcasted_mobs)
|
||||
var/mob/living/carbon/human/H = M
|
||||
to_chat(H, "<span class='userdanger'>You feel the compulsion fade, and you <i>completely forget</i> about your previous orders.</span>")
|
||||
H.clear_alert("mind_control")
|
||||
active_mind_control = FALSE
|
||||
return TRUE
|
||||
@@ -0,0 +1,22 @@
|
||||
/obj/item/organ/heart/gland/plasma
|
||||
true_name = "effluvium sanguine-synonym emitter"
|
||||
cooldown_low = 1200
|
||||
cooldown_high = 1800
|
||||
icon_state = "slime"
|
||||
uses = -1
|
||||
mind_control_uses = 1
|
||||
mind_control_duration = 800
|
||||
|
||||
/obj/item/organ/heart/gland/plasma/activate()
|
||||
to_chat(owner, "<span class='warning'>You feel bloated.</span>")
|
||||
addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, owner, "<span class='userdanger'>A massive stomachache overcomes you.</span>"), 150)
|
||||
addtimer(CALLBACK(src, .proc/vomit_plasma), 200)
|
||||
|
||||
/obj/item/organ/heart/gland/plasma/proc/vomit_plasma()
|
||||
if(!owner)
|
||||
return
|
||||
owner.visible_message("<span class='danger'>[owner] vomits a cloud of plasma!</span>")
|
||||
var/turf/open/T = get_turf(owner)
|
||||
if(istype(T))
|
||||
T.atmos_spawn_air("plasma=50;TEMP=[T20C]")
|
||||
owner.vomit()
|
||||
@@ -0,0 +1,47 @@
|
||||
/obj/item/organ/heart/gland/quantum
|
||||
true_name = "quantic de-observation matrix"
|
||||
cooldown_low = 150
|
||||
cooldown_high = 150
|
||||
uses = -1
|
||||
icon_state = "emp"
|
||||
mind_control_uses = 2
|
||||
mind_control_duration = 1200
|
||||
var/mob/living/carbon/entangled_mob
|
||||
|
||||
/obj/item/organ/heart/gland/quantum/activate()
|
||||
if(entangled_mob)
|
||||
return
|
||||
for(var/mob/M in oview(owner, 7))
|
||||
if(!iscarbon(M))
|
||||
continue
|
||||
entangled_mob = M
|
||||
addtimer(CALLBACK(src, .proc/quantum_swap), rand(600, 2400))
|
||||
return
|
||||
|
||||
/obj/item/organ/heart/gland/quantum/proc/quantum_swap()
|
||||
if(QDELETED(entangled_mob))
|
||||
entangled_mob = null
|
||||
return
|
||||
var/turf/T = get_turf(owner)
|
||||
do_teleport(owner, get_turf(entangled_mob),null,TRUE,channel = TELEPORT_CHANNEL_QUANTUM)
|
||||
do_teleport(entangled_mob, T,null,TRUE,channel = TELEPORT_CHANNEL_QUANTUM)
|
||||
to_chat(owner, "<span class='warning'>You suddenly find yourself somewhere else!</span>")
|
||||
to_chat(entangled_mob, "<span class='warning'>You suddenly find yourself somewhere else!</span>")
|
||||
if(!active_mind_control) //Do not reset entangled mob while mind control is active
|
||||
entangled_mob = null
|
||||
|
||||
/obj/item/organ/heart/gland/quantum/mind_control(command, mob/living/user)
|
||||
if(..())
|
||||
if(entangled_mob && ishuman(entangled_mob) && (entangled_mob.stat < DEAD))
|
||||
to_chat(entangled_mob, "<span class='userdanger'>You suddenly feel an irresistible compulsion to follow an order...</span>")
|
||||
to_chat(entangled_mob, "<span class='mind_control'>[command]</span>")
|
||||
var/obj/screen/alert/mind_control/mind_alert = entangled_mob.throw_alert("mind_control", /obj/screen/alert/mind_control)
|
||||
mind_alert.command = command
|
||||
message_admins("[key_name(owner)] mirrored an abductor mind control message to [key_name(entangled_mob)]: [command]")
|
||||
update_gland_hud()
|
||||
|
||||
/obj/item/organ/heart/gland/quantum/clear_mind_control()
|
||||
if(active_mind_control)
|
||||
to_chat(entangled_mob, "<span class='userdanger'>You feel the compulsion fade, and you completely forget about your previous orders.</span>")
|
||||
entangled_mob.clear_alert("mind_control")
|
||||
..()
|
||||
@@ -0,0 +1,21 @@
|
||||
/obj/item/organ/heart/gland/slime
|
||||
true_name = "gastric animation galvanizer"
|
||||
cooldown_low = 600
|
||||
cooldown_high = 1200
|
||||
uses = -1
|
||||
icon_state = "slime"
|
||||
mind_control_uses = 1
|
||||
mind_control_duration = 2400
|
||||
|
||||
/obj/item/organ/heart/gland/slime/Insert(mob/living/carbon/M, special = 0, drop_if_replaced = TRUE)
|
||||
..()
|
||||
owner.faction |= "slime"
|
||||
owner.grant_language(/datum/language/slime)
|
||||
|
||||
/obj/item/organ/heart/gland/slime/activate()
|
||||
to_chat(owner, "<span class='warning'>You feel nauseated!</span>")
|
||||
owner.vomit(20)
|
||||
|
||||
var/mob/living/simple_animal/slime/Slime = new(get_turf(owner), "grey")
|
||||
Slime.Friends = list(owner)
|
||||
Slime.Leader = owner
|
||||
@@ -0,0 +1,14 @@
|
||||
/obj/item/organ/heart/gland/spiderman
|
||||
true_name = "araneae cloister accelerator"
|
||||
cooldown_low = 450
|
||||
cooldown_high = 900
|
||||
uses = -1
|
||||
icon_state = "spider"
|
||||
mind_control_uses = 2
|
||||
mind_control_duration = 2400
|
||||
|
||||
/obj/item/organ/heart/gland/spiderman/activate()
|
||||
to_chat(owner, "<span class='warning'>You feel something crawling in your skin.</span>")
|
||||
owner.faction |= "spiders"
|
||||
var/obj/structure/spider/spiderling/S = new(owner.drop_location())
|
||||
S.directive = "Protect your nest inside [owner.real_name]."
|
||||
@@ -0,0 +1,15 @@
|
||||
/obj/item/organ/heart/gland/transform
|
||||
true_name = "anthropmorphic transmorphosizer"
|
||||
cooldown_low = 900
|
||||
cooldown_high = 1800
|
||||
uses = -1
|
||||
human_only = TRUE
|
||||
icon_state = "species"
|
||||
mind_control_uses = 7
|
||||
mind_control_duration = 300
|
||||
|
||||
/obj/item/organ/heart/gland/transform/activate()
|
||||
to_chat(owner, "<span class='notice'>You feel unlike yourself.</span>")
|
||||
randomize_human(owner)
|
||||
var/species = pick(list(/datum/species/human, /datum/species/lizard, /datum/species/insect, /datum/species/fly))
|
||||
owner.set_species(species)
|
||||
@@ -0,0 +1,18 @@
|
||||
/obj/item/organ/heart/gland/trauma
|
||||
true_name = "white matter randomiser"
|
||||
cooldown_low = 800
|
||||
cooldown_high = 1200
|
||||
uses = 5
|
||||
icon_state = "emp"
|
||||
mind_control_uses = 3
|
||||
mind_control_duration = 1800
|
||||
|
||||
/obj/item/organ/heart/gland/trauma/activate()
|
||||
to_chat(owner, "<span class='warning'>You feel a spike of pain in your head.</span>")
|
||||
if(prob(33))
|
||||
owner.gain_trauma_type(BRAIN_TRAUMA_SPECIAL, rand(TRAUMA_RESILIENCE_BASIC, TRAUMA_RESILIENCE_LOBOTOMY))
|
||||
else
|
||||
if(prob(20))
|
||||
owner.gain_trauma_type(BRAIN_TRAUMA_SEVERE, rand(TRAUMA_RESILIENCE_BASIC, TRAUMA_RESILIENCE_LOBOTOMY))
|
||||
else
|
||||
owner.gain_trauma_type(BRAIN_TRAUMA_MILD, rand(TRAUMA_RESILIENCE_BASIC, TRAUMA_RESILIENCE_LOBOTOMY))
|
||||
@@ -0,0 +1,12 @@
|
||||
/obj/item/organ/heart/gland/ventcrawling
|
||||
true_name = "pliant cartilage enabler"
|
||||
cooldown_low = 1800
|
||||
cooldown_high = 2400
|
||||
uses = 1
|
||||
icon_state = "vent"
|
||||
mind_control_uses = 4
|
||||
mind_control_duration = 1800
|
||||
|
||||
/obj/item/organ/heart/gland/ventcrawling/activate()
|
||||
to_chat(owner, "<span class='notice'>You feel very stretchy.</span>")
|
||||
owner.ventcrawler = VENTCRAWLER_ALWAYS
|
||||
@@ -0,0 +1,34 @@
|
||||
/obj/item/organ/heart/gland/viral
|
||||
true_name = "contamination incubator"
|
||||
cooldown_low = 1800
|
||||
cooldown_high = 2400
|
||||
uses = 1
|
||||
icon_state = "viral"
|
||||
mind_control_uses = 1
|
||||
mind_control_duration = 1800
|
||||
|
||||
/obj/item/organ/heart/gland/viral/activate()
|
||||
to_chat(owner, "<span class='warning'>You feel sick.</span>")
|
||||
var/datum/disease/advance/A = random_virus(pick(2,6),6)
|
||||
A.carrier = TRUE
|
||||
owner.ForceContractDisease(A, FALSE, TRUE)
|
||||
|
||||
/obj/item/organ/heart/gland/viral/proc/random_virus(max_symptoms, max_level)
|
||||
if(max_symptoms > VIRUS_SYMPTOM_LIMIT)
|
||||
max_symptoms = VIRUS_SYMPTOM_LIMIT
|
||||
var/datum/disease/advance/A = new /datum/disease/advance()
|
||||
var/list/datum/symptom/possible_symptoms = list()
|
||||
for(var/symptom in subtypesof(/datum/symptom))
|
||||
var/datum/symptom/S = symptom
|
||||
if(initial(S.level) > max_level)
|
||||
continue
|
||||
if(initial(S.level) <= 0) //unobtainable symptoms
|
||||
continue
|
||||
possible_symptoms += S
|
||||
for(var/i in 1 to max_symptoms)
|
||||
var/datum/symptom/chosen_symptom = pick_n_take(possible_symptoms)
|
||||
if(chosen_symptom)
|
||||
var/datum/symptom/S = new chosen_symptom
|
||||
A.symptoms += S
|
||||
A.Refresh() //just in case someone already made and named the same disease
|
||||
return A
|
||||
@@ -43,12 +43,15 @@
|
||||
dat += "Collected Samples : [points] <br>"
|
||||
dat += "Gear Credits: [credits] <br>"
|
||||
dat += "<b>Transfer data in exchange for supplies:</b><br>"
|
||||
dat += "<a href='?src=[REF(src)];dispense=baton'>Advanced Baton</A><br>"
|
||||
dat += "<a href='?src=[REF(src)];dispense=helmet'>Agent Helmet</A><br>"
|
||||
dat += "<a href='?src=[REF(src)];dispense=vest'>Agent Vest</A><br>"
|
||||
dat += "<a href='?src=[REF(src)];dispense=silencer'>Radio Silencer</A><br>"
|
||||
dat += "<a href='?src=[REF(src)];dispense=tool'>Science Tool</A><br>"
|
||||
dat += "<a href='?src=[REF(src)];dispense=mind_device'>Mental Interface Device</A><br>"
|
||||
dat += "<a href='?src=[REF(src)];dispense=baton'>Advanced Baton (2 Credits)</A><br>"
|
||||
dat += "<a href='?src=[REF(src)];dispense=mind_device'>Mental Interface Device (2 Credits)</A><br>"
|
||||
dat += "<a href='?src=[REF(src)];dispense=chem_dispenser'>Reagent Synthesizer (2 Credits)</A><br>"
|
||||
dat += "<a href='?src=[REF(src)];dispense=shrink_ray'>Shrink Ray Blaster (2 Credits)</a><br>"
|
||||
dat += "<a href='?src=[REF(src)];dispense=helmet'>Agent Helmet (1 Credit)</A><br>"
|
||||
dat += "<a href='?src=[REF(src)];dispense=vest'>Agent Vest (1 Credit)</A><br>"
|
||||
dat += "<a href='?src=[REF(src)];dispense=silencer'>Radio Silencer (1 Credit)</A><br>"
|
||||
dat += "<a href='?src=[REF(src)];dispense=tool'>Science Tool (1 Credit)</A><br>"
|
||||
dat += "<a href='?src=[REF(src)];dispense=tongue'>Superlingual Matrix (1 Credit)</a><br>"
|
||||
else
|
||||
dat += "<span class='bad'>NO EXPERIMENT MACHINE DETECTED</span> <br>"
|
||||
|
||||
@@ -101,7 +104,7 @@
|
||||
else if(href_list["dispense"])
|
||||
switch(href_list["dispense"])
|
||||
if("baton")
|
||||
Dispense(/obj/item/abductor_baton,cost=2)
|
||||
Dispense(/obj/item/abductor/baton,cost=2)
|
||||
if("helmet")
|
||||
Dispense(/obj/item/clothing/head/helmet/abductor)
|
||||
if("silencer")
|
||||
@@ -112,6 +115,12 @@
|
||||
Dispense(/obj/item/clothing/suit/armor/abductor/vest)
|
||||
if("mind_device")
|
||||
Dispense(/obj/item/abductor/mind_device,cost=2)
|
||||
if("chem_dispenser")
|
||||
Dispense(/obj/item/abductor_machine_beacon/chem_dispenser,cost=2)
|
||||
if("tongue")
|
||||
Dispense(/obj/item/organ/tongue/abductor)
|
||||
if("shrink_ray")
|
||||
Dispense(/obj/item/gun/energy/shrink_ray,cost=2)
|
||||
updateUsrDialog()
|
||||
|
||||
/obj/machinery/abductor/console/proc/TeleporterRetrieve()
|
||||
@@ -136,9 +145,9 @@
|
||||
|
||||
var/entry_name
|
||||
if(remote)
|
||||
entry_name = show_radial_menu(usr, camera.eyeobj, disguises2)
|
||||
entry_name = show_radial_menu(usr, camera.eyeobj, disguises2, tooltips = TRUE)
|
||||
else
|
||||
entry_name = show_radial_menu(usr, src, disguises2)
|
||||
entry_name = show_radial_menu(usr, src, disguises2, require_near = TRUE, tooltips = TRUE)
|
||||
|
||||
var/datum/icon_snapshot/chosen = disguises[entry_name]
|
||||
if(chosen && vest && (remote || in_range(usr,src)))
|
||||
@@ -236,4 +245,4 @@
|
||||
new item(drop_location)
|
||||
|
||||
else
|
||||
say("Insufficent data!")
|
||||
say("Insufficent data!")
|
||||
@@ -143,9 +143,9 @@
|
||||
create_reagents(10)
|
||||
|
||||
if(overmind && overmind.blob_reagent_datum)
|
||||
reagents.add_reagent(overmind.blob_reagent_datum.id, 10)
|
||||
reagents.add_reagent(overmind.blob_reagent_datum.type, 10)
|
||||
else
|
||||
reagents.add_reagent("spore", 10)
|
||||
reagents.add_reagent(/datum/reagent/toxin/spore, 10)
|
||||
|
||||
// Attach the smoke spreader and setup/start it.
|
||||
S.attach(location)
|
||||
|
||||
@@ -1,40 +1,64 @@
|
||||
/obj/structure/blob/shield
|
||||
name = "strong blob"
|
||||
icon = 'icons/mob/blob.dmi'
|
||||
icon_state = "blob_shield"
|
||||
desc = "A solid wall of slightly twitching tendrils."
|
||||
max_integrity = 150
|
||||
brute_resist = 0.25
|
||||
explosion_block = 3
|
||||
point_return = 4
|
||||
atmosblock = TRUE
|
||||
armor = list("melee" = 25, "bullet" = 25, "laser" = 15, "energy" = 10, "bomb" = 20, "bio" = 0, "rad" = 0, "fire" = 90, "acid" = 90)
|
||||
var/weakened
|
||||
|
||||
/obj/structure/blob/shield/scannerreport()
|
||||
if(atmosblock)
|
||||
return "Will prevent the spread of atmospheric changes."
|
||||
return "N/A"
|
||||
|
||||
/obj/structure/blob/shield/core
|
||||
point_return = 0
|
||||
|
||||
/obj/structure/blob/shield/update_icon()
|
||||
..()
|
||||
if(obj_integrity <= 70)
|
||||
icon_state = "blob_shield_damaged"
|
||||
name = "weakened strong blob"
|
||||
desc = "A wall of twitching tendrils."
|
||||
atmosblock = FALSE
|
||||
if(!weakened)
|
||||
armor = armor.setRating("melee" = 15, "bullet" = 15, "laser" = 5, "energy" = 0, "bomb" = 10, "bio" = 0, "rad" = 0, "fire" = 90, "acid" = 90)
|
||||
weakened = TRUE
|
||||
else
|
||||
icon_state = initial(icon_state)
|
||||
name = initial(name)
|
||||
desc = initial(desc)
|
||||
atmosblock = TRUE
|
||||
if(weakened)
|
||||
armor = armor.setRating("melee" = 25, "bullet" = 25, "laser" = 15, "energy" = 10, "bomb" = 20, "bio" = 0, "rad" = 0, "fire" = 90, "acid" = 90)
|
||||
weakened = FALSE
|
||||
air_update_turf(1)
|
||||
/obj/structure/blob/shield
|
||||
name = "strong blob"
|
||||
icon = 'icons/mob/blob.dmi'
|
||||
icon_state = "blob_shield"
|
||||
desc = "A solid wall of slightly twitching tendrils."
|
||||
var/damaged_desc = "A wall of twitching tendrils."
|
||||
max_integrity = 150
|
||||
brute_resist = 0.25
|
||||
explosion_block = 3
|
||||
point_return = 4
|
||||
atmosblock = TRUE
|
||||
armor = list("melee" = 25, "bullet" = 25, "laser" = 15, "energy" = 10, "bomb" = 20, "bio" = 0, "rad" = 0, "fire" = 90, "acid" = 90)
|
||||
var/weakened
|
||||
|
||||
/obj/structure/blob/shield/scannerreport()
|
||||
if(atmosblock)
|
||||
return "Will prevent the spread of atmospheric changes."
|
||||
return "N/A"
|
||||
|
||||
/obj/structure/blob/shield/core
|
||||
point_return = 0
|
||||
|
||||
/obj/structure/blob/shield/update_icon()
|
||||
..()
|
||||
if(obj_integrity < max_integrity * 0.5)
|
||||
icon_state = "[initial(icon_state)]_damaged"
|
||||
name = "weakened [initial(name)]"
|
||||
desc = "[damaged_desc]"
|
||||
atmosblock = FALSE
|
||||
if(!weakened)
|
||||
armor = armor.setRating("melee" = 15, "bullet" = 15, "laser" = 5, "energy" = 0, "bomb" = 10, "bio" = 0, "rad" = 0, "fire" = 90, "acid" = 90)
|
||||
weakened = TRUE
|
||||
else
|
||||
icon_state = initial(icon_state)
|
||||
name = initial(name)
|
||||
desc = initial(desc)
|
||||
atmosblock = TRUE
|
||||
if(weakened)
|
||||
armor = armor.setRating("melee" = 25, "bullet" = 25, "laser" = 15, "energy" = 10, "bomb" = 20, "bio" = 0, "rad" = 0, "fire" = 90, "acid" = 90)
|
||||
weakened = FALSE
|
||||
air_update_turf(1)
|
||||
|
||||
/obj/structure/blob/shield/reflective
|
||||
name = "reflective blob"
|
||||
desc = "A solid wall of slightly twitching tendrils with a reflective glow."
|
||||
damaged_desc = "A wall of twitching tendrils with a reflective glow."
|
||||
icon_state = "blob_glow"
|
||||
flags_1 = CHECK_RICOCHET_1
|
||||
point_return = 8
|
||||
max_integrity = 50
|
||||
brute_resist = 1
|
||||
explosion_block = 2
|
||||
|
||||
/obj/structure/blob/shield/reflective/handle_ricochet(obj/item/projectile/P)
|
||||
var/turf/p_turf = get_turf(P)
|
||||
var/face_direction = get_dir(src, p_turf)
|
||||
var/face_angle = dir2angle(face_direction)
|
||||
var/incidence_s = GET_ANGLE_OF_INCIDENCE(face_angle, (P.Angle + 180))
|
||||
if(abs(incidence_s) > 90 && abs(incidence_s) < 270)
|
||||
return FALSE
|
||||
var/new_angle_s = SIMPLIFY_DEGREES(face_angle + incidence_s)
|
||||
P.setAngle(new_angle_s)
|
||||
visible_message("<span class='warning'>[P] reflects off [src]!</span>")
|
||||
return TRUE
|
||||
@@ -113,12 +113,22 @@
|
||||
|
||||
/mob/camera/blob/verb/create_shield_power()
|
||||
set category = "Blob"
|
||||
set name = "Create Shield Blob (15)"
|
||||
set desc = "Create a shield blob, which will block fire and is hard to kill."
|
||||
set name = "Create/Upgrade Shield Blob (15)"
|
||||
set desc = "Create a shield blob, which will block fire and is hard to kill. Using this on an existing shield blob turns it into a reflective blob, capable of reflecting most projectiles but making it much weaker than usual to brute attacks."
|
||||
create_shield()
|
||||
|
||||
/mob/camera/blob/proc/create_shield(turf/T)
|
||||
createSpecial(15, /obj/structure/blob/shield, 0, 0, T)
|
||||
var/obj/structure/blob/shield/S = locate(/obj/structure/blob/shield) in T
|
||||
if(S)
|
||||
if(!can_buy(15))
|
||||
return
|
||||
if(S.obj_integrity < S.max_integrity * 0.5)
|
||||
to_chat(src, "<span class='warning'>This shield blob is too damaged to be modified properly!</span>")
|
||||
return
|
||||
to_chat(src, "<span class='warning'>You secrete a reflective ooze over the shield blob, allowing it to reflect projectiles at the cost of reduced intregrity.</span>")
|
||||
S.change_to(/obj/structure/blob/shield/reflective, src)
|
||||
else
|
||||
createSpecial(15, /obj/structure/blob/shield, 0, 0, T)
|
||||
|
||||
/mob/camera/blob/verb/create_resource()
|
||||
set category = "Blob"
|
||||
@@ -156,7 +166,7 @@
|
||||
if(!can_buy(40))
|
||||
return
|
||||
|
||||
var/list/mob/dead/observer/candidates = pollGhostCandidates("Do you want to play as a [blob_reagent_datum.name] blobbernaut?", ROLE_BLOB, null, ROLE_BLOB, 50) //players must answer rapidly
|
||||
var/list/mob/candidates = pollGhostCandidates("Do you want to play as a [blob_reagent_datum.name] blobbernaut?", ROLE_BLOB, null, ROLE_BLOB, 50) //players must answer rapidly
|
||||
if(LAZYLEN(candidates)) //if we got at least one candidate, they're a blobbernaut now.
|
||||
B.max_integrity = initial(B.max_integrity) * 0.25 //factories that produced a blobbernaut have much lower health
|
||||
B.obj_integrity = min(B.obj_integrity, B.max_integrity)
|
||||
@@ -171,7 +181,7 @@
|
||||
blobber.update_icons()
|
||||
blobber.adjustHealth(blobber.maxHealth * 0.5)
|
||||
blob_mobs += blobber
|
||||
var/mob/dead/observer/C = pick(candidates)
|
||||
var/mob/C = pick(candidates)
|
||||
C.transfer_ckey(blobber)
|
||||
SEND_SOUND(blobber, sound('sound/effects/blobattack.ogg'))
|
||||
SEND_SOUND(blobber, sound('sound/effects/attackblob.ogg'))
|
||||
@@ -359,7 +369,7 @@
|
||||
to_chat(src, "<b>You can expand, which will attack people, damage objects, or place a Normal Blob if the tile is clear.</b>")
|
||||
to_chat(src, "<i>Normal Blobs</i> will expand your reach and can be upgraded into special blobs that perform certain functions.")
|
||||
to_chat(src, "<b>You can upgrade normal blobs into the following types of blob:</b>")
|
||||
to_chat(src, "<i>Shield Blobs</i> are strong and expensive blobs which take more damage. In additon, they are fireproof and can block air, use these to protect yourself from station fires.")
|
||||
to_chat(src, "<i>Shield Blobs</i> are strong and expensive blobs which take more damage. In additon, they are fireproof and can block air, use these to protect yourself from station fires. Upgrading them again will result in a reflective blob, capable of reflecting most projectiles at the cost of the strong blob's extra health.")
|
||||
to_chat(src, "<i>Resource Blobs</i> are blobs which produce more resources for you, build as many of these as possible to consume the station. This type of blob must be placed near node blobs or your core to work.")
|
||||
to_chat(src, "<i>Factory Blobs</i> are blobs that spawn blob spores which will attack nearby enemies. This type of blob must be placed near node blobs or your core to work.")
|
||||
to_chat(src, "<i>Blobbernauts</i> can be produced from factories for a cost, and are hard to kill, powerful, and moderately smart. The factory used to create one will become fragile and briefly unable to produce spores.")
|
||||
|
||||
@@ -128,7 +128,7 @@
|
||||
|
||||
/mob/living/carbon/human/ShowAsPaleExamine()
|
||||
// Check for albino, as per human/examine.dm's check.
|
||||
if(skin_tone == "albino")
|
||||
if(dna.species.use_skintones && skin_tone == "albino")
|
||||
return TRUE
|
||||
|
||||
return ..() // Return vamp check
|
||||
|
||||
@@ -84,8 +84,8 @@
|
||||
//It is called from your coffin on close (by you only)
|
||||
if(poweron_masquerade == TRUE || owner.current.AmStaked())
|
||||
return FALSE
|
||||
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.adjustStaminaLoss(-2 + (regenRate * -8) * mult, 0) // Humans lose stamina damage really quickly. Vamps should heal more.
|
||||
owner.current.adjustCloneLoss(-0.1 * (regenRate * 2) * mult, 0)
|
||||
owner.current.adjustOrganLoss(ORGAN_SLOT_BRAIN, -1 * (regenRate * 4) * mult) //adjustBrainLoss(-1 * (regenRate * 4) * mult, 0)
|
||||
// No Bleeding
|
||||
if(ishuman(owner.current)) //NOTE Current bleeding is horrible, not to count the amount of blood ballistics delete.
|
||||
@@ -97,7 +97,7 @@
|
||||
var/fireheal = 0 // BURN: Heal in Coffin while Fakedeath, or when damage above maxhealth (you can never fully heal fire)
|
||||
var/amInCoffinWhileTorpor = istype(C.loc, /obj/structure/closet/crate/coffin) && (mult == 0 || HAS_TRAIT(C, TRAIT_DEATHCOMA)) // Check for mult 0 OR death coma. (mult 0 means we're testing from coffin)
|
||||
if(amInCoffinWhileTorpor)
|
||||
mult *= 5 // Increase multiplier if we're sleeping in a coffin.
|
||||
mult *= 4 // Increase multiplier if we're sleeping in a coffin.
|
||||
fireheal = min(C.getFireLoss_nonProsthetic(), regenRate) // NOTE: Burn damage ONLY heals in torpor.
|
||||
costMult = 0.25
|
||||
C.ExtinguishMob()
|
||||
@@ -118,6 +118,8 @@
|
||||
if(bruteheal + fireheal + toxinheal > 0) // Just a check? Don't heal/spend, and return.
|
||||
if(mult == 0)
|
||||
return TRUE
|
||||
if(owner.current.stat >= UNCONSCIOUS) //Faster regeneration while unconcious, so you dont have to wait all day
|
||||
mult *= 2
|
||||
// We have damage. Let's heal (one time)
|
||||
C.adjustBruteLoss(-bruteheal * mult, forced = TRUE)// Heal BRUTE / BURN in random portions throughout the body.
|
||||
C.adjustFireLoss(-fireheal * mult, forced = TRUE)
|
||||
@@ -187,19 +189,19 @@
|
||||
/datum/antagonist/bloodsucker/proc/HandleDeath()
|
||||
// FINAL DEATH
|
||||
// Fire Damage? (above double health)
|
||||
if (owner.current.getFireLoss_nonProsthetic() >= owner.current.getMaxHealth() * 2)
|
||||
if(owner.current.getFireLoss_nonProsthetic() >= owner.current.getMaxHealth() * 1.5)
|
||||
FinalDeath()
|
||||
return
|
||||
// Staked while "Temp Death" or Asleep
|
||||
if (owner.current.StakeCanKillMe() && owner.current.AmStaked())
|
||||
if(owner.current.StakeCanKillMe() && owner.current.AmStaked())
|
||||
FinalDeath()
|
||||
return
|
||||
// Not "Alive"?
|
||||
if (!owner.current || !isliving(owner.current) || isbrain(owner.current) || !get_turf(owner.current))
|
||||
if(!owner.current || !isliving(owner.current) || isbrain(owner.current) || !get_turf(owner.current))
|
||||
FinalDeath()
|
||||
return
|
||||
// Missing Brain or Heart?
|
||||
if (!owner.current.HaveBloodsuckerBodyparts())
|
||||
if(!owner.current.HaveBloodsuckerBodyparts())
|
||||
FinalDeath()
|
||||
return
|
||||
// Disable Powers: Masquerade * NOTE * This should happen as a FLAW!
|
||||
@@ -212,21 +214,21 @@
|
||||
var/total_toxloss = owner.current.getToxLoss() //This is neater than just putting it in total_damage
|
||||
var/total_damage = total_brute + total_burn + total_toxloss
|
||||
// Died? Convert to Torpor (fake death)
|
||||
if (owner.current.stat >= DEAD)
|
||||
if(owner.current.stat >= DEAD)
|
||||
Torpor_Begin()
|
||||
to_chat(owner, "<span class='danger'>Your immortal body will not yet relinquish your soul to the abyss. You enter Torpor.</span>")
|
||||
sleep(30) //To avoid spam
|
||||
if (poweron_masquerade == TRUE)
|
||||
to_chat(owner, "<span class='warning'>Your wounds will not heal until you disable the <span class='boldnotice'>Masquerade</span> power.</span>")
|
||||
// End Torpor:
|
||||
else // No damage, OR toxin healed AND brute healed and NOT in coffin (since you cannot heal burn)
|
||||
if (total_damage <= 0 || total_toxloss <= 0 && total_brute <= 0 && !istype(owner.current.loc, /obj/structure/closet/crate/coffin))
|
||||
if(total_damage <= 0 || total_toxloss <= 0 && total_brute <= 0 && !istype(owner.current.loc, /obj/structure/closet/crate/coffin))
|
||||
// Not Daytime, Not in Torpor
|
||||
if (!SSticker.mode.is_daylight() && HAS_TRAIT_FROM(owner.current, TRAIT_DEATHCOMA, "bloodsucker"))
|
||||
if(!SSticker.mode.is_daylight() && HAS_TRAIT_FROM(owner.current, TRAIT_DEATHCOMA, "bloodsucker"))
|
||||
Torpor_End()
|
||||
// Fake Unconscious
|
||||
if (poweron_masquerade == TRUE && total_damage >= owner.current.getMaxHealth() - HEALTH_THRESHOLD_FULLCRIT)
|
||||
if(poweron_masquerade == TRUE && total_damage >= owner.current.getMaxHealth() - HEALTH_THRESHOLD_FULLCRIT)
|
||||
owner.current.Unconscious(20,1)
|
||||
|
||||
//HEALTH_THRESHOLD_CRIT 0
|
||||
//HEALTH_THRESHOLD_FULLCRIT -30
|
||||
//HEALTH_THRESHOLD_DEAD -100
|
||||
@@ -241,8 +243,8 @@
|
||||
owner.current.update_sight()
|
||||
owner.current.reload_fullscreen()
|
||||
// Disable ALL Powers
|
||||
for (var/datum/action/bloodsucker/power in powers)
|
||||
if (power.active && !power.can_use_in_torpor)
|
||||
for(var/datum/action/bloodsucker/power in powers)
|
||||
if(power.active && !power.can_use_in_torpor)
|
||||
power.DeactivatePower()
|
||||
|
||||
|
||||
@@ -281,7 +283,7 @@
|
||||
// Free my Vassals!
|
||||
FreeAllVassals()
|
||||
// Elders get Dusted
|
||||
if (vamplevel >= 4) // (vamptitle)
|
||||
if(vamplevel >= 4) // (vamptitle)
|
||||
owner.current.visible_message("<span class='warning'>[owner.current]'s skin crackles and dries, their skin and bones withering to dust. A hollow cry whips from what is now a sandy pile of remains.</span>", \
|
||||
"<span class='userdanger'>Your soul escapes your withering body as the abyss welcomes you to your Final Death.</span>", \
|
||||
"<span class='italics'>You hear a dry, crackling sound.</span>")
|
||||
@@ -306,7 +308,7 @@
|
||||
if (!isliving(src))
|
||||
return
|
||||
var/mob/living/L = src
|
||||
if (!L.AmBloodsucker())
|
||||
if(!L.AmBloodsucker())
|
||||
return
|
||||
// We're a vamp? Try to eat food...
|
||||
var/datum/antagonist/bloodsucker/bloodsuckerdatum = mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER)
|
||||
@@ -315,7 +317,7 @@
|
||||
|
||||
/datum/antagonist/bloodsucker/proc/handle_eat_human_food(var/food_nutrition) // Called from snacks.dm and drinks.dm
|
||||
set waitfor = FALSE
|
||||
if (!owner.current || !iscarbon(owner.current))
|
||||
if(!owner.current || !iscarbon(owner.current))
|
||||
return
|
||||
var/mob/living/carbon/C = owner.current
|
||||
// Remove Nutrition, Give Bad Food
|
||||
|
||||
@@ -35,8 +35,8 @@
|
||||
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)
|
||||
var/static/list/defaultTraits = list (TRAIT_STABLEHEART, TRAIT_NOBREATH, TRAIT_SLEEPIMMUNE, TRAIT_NOCRITDAMAGE, TRAIT_RESISTCOLD, TRAIT_RADIMMUNE, TRAIT_NIGHT_VISION, \
|
||||
TRAIT_NOSOFTCRIT, TRAIT_NOHARDCRIT, TRAIT_AGEUSIA, TRAIT_COLDBLOODED, TRAIT_NONATURALHEAL, TRAIT_NOMARROW, TRAIT_NOPULSE, TRAIT_VIRUSIMMUNE)
|
||||
// NOTES: TRAIT_AGEUSIA <-- Doesn't like flavors.
|
||||
// REMOVED: TRAIT_NODEATH
|
||||
// TO ADD:
|
||||
@@ -183,7 +183,7 @@
|
||||
BuyPower(new /datum/action/bloodsucker/masquerade)
|
||||
BuyPower(new /datum/action/bloodsucker/veil)
|
||||
// Traits
|
||||
for (var/T in defaultTraits)
|
||||
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
|
||||
@@ -200,10 +200,10 @@
|
||||
var/mob/living/carbon/human/H = owner.current
|
||||
var/datum/species/S = H.dna.species
|
||||
// Make Changes
|
||||
S.brutemod *= 0.5 // <-------------------- Start small, but burn mod increases based on rank!
|
||||
S.coldmod = 0
|
||||
S.stunmod *= 0.25
|
||||
S.siemens_coeff *= 0.75 //base electrocution coefficient 1
|
||||
H.physiology.brute_mod *= 0.8 // <-------------------- Start small, but burn mod increases based on rank!
|
||||
H.physiology.cold_mod = 0
|
||||
H.physiology.stun_mod *= 0.35
|
||||
H.physiology.siemens_coeff *= 0.75 //base electrocution coefficient 1
|
||||
//S.heatmod += 0.5 // Heat shouldn't affect. Only Fire.
|
||||
//S.punchstunthreshold = 8 //damage at which punches from this race will stun 9
|
||||
S.punchdamagelow += 1 //lowest possible punch damage 0
|
||||
@@ -319,12 +319,10 @@ datum/antagonist/bloodsucker/proc/SpendRank()
|
||||
if(ishuman(owner.current))
|
||||
var/mob/living/carbon/human/H = owner.current
|
||||
var/datum/species/S = H.dna.species
|
||||
S.burnmod *= 0.025 // Slightly more burn damage
|
||||
S.stunmod *= 0.95 // Slightly less stun time.
|
||||
S.punchdamagelow += 0.5
|
||||
S.punchdamagehigh += 0.5 // NOTE: This affects the hitting power of Brawn.
|
||||
// More Health
|
||||
owner.current.setMaxHealth(owner.current.maxHealth + 5)
|
||||
owner.current.setMaxHealth(owner.current.maxHealth + 10)
|
||||
// Vamp Stats
|
||||
regenRate += 0.05 // Points of brute healed (starts at 0.3)
|
||||
feedAmount += 2 // Increase how quickly I munch down vics (15)
|
||||
@@ -336,7 +334,7 @@ datum/antagonist/bloodsucker/proc/SpendRank()
|
||||
// Assign True Reputation
|
||||
if(vamplevel == 4)
|
||||
SelectReputation(am_fledgling = FALSE, forced = TRUE)
|
||||
to_chat(owner.current, "<span class='notice'>You are now a rank [vamplevel] Bloodsucker. Your strength, resistence, health, feed rate, regen rate, and maximum blood have all increased!</span>")
|
||||
to_chat(owner.current, "<span class='notice'>You are now a rank [vamplevel] Bloodsucker. Your strength, health, feed rate, regen rate, and maximum blood have all increased!</span>")
|
||||
to_chat(owner.current, "<span class='notice'>Your existing powers have all ranked up as well!</span>")
|
||||
update_hud(TRUE)
|
||||
owner.current.playsound_local(null, 'sound/effects/pope_entry.ogg', 25, 1) // Play THIS sound for user only. The "null" is where turf would go if a location was needed. Null puts it right in their head.
|
||||
|
||||
@@ -56,11 +56,6 @@
|
||||
var/obj/item/organ/eyes/vassal/E = new
|
||||
E.Insert(owner.current)
|
||||
|
||||
/obj/item/organ/eyes/vassal/
|
||||
lighting_alpha = 180 // LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE <--- This is too low a value at 128. We need to SEE what the darkness is so we can hide in it.
|
||||
see_in_dark = 12
|
||||
flash_protect = -1 //These eyes are weaker to flashes, but let you see in the dark
|
||||
|
||||
/datum/antagonist/vassal/proc/remove_thrall_eyes()
|
||||
var/obj/item/organ/eyes/E = new
|
||||
E.Insert(owner.current)
|
||||
|
||||
@@ -51,6 +51,11 @@
|
||||
return "<span class='danger'>no</span>" // Bloodsuckers don't have a heartbeat at all when stopped (default is "an unstable")
|
||||
// EYES //
|
||||
|
||||
/obj/item/organ/eyes/vassal/
|
||||
lighting_alpha = 180 // LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE <--- This is too low a value at 128. We need to SEE what the darkness is so we can hide in it.
|
||||
see_in_dark = 12
|
||||
flash_protect = -1 //These eyes are weaker to flashes, but let you see in the dark
|
||||
|
||||
/obj/item/organ/eyes/vassal/bloodsucker
|
||||
flash_protect = 2 //Eye healing isnt working properly
|
||||
sight_flags = SEE_MOBS // Taken from augmented_eyesight.dm
|
||||
|
||||
@@ -78,7 +78,7 @@
|
||||
var/mob/living/carbon/C = target
|
||||
// Needs to be Down/Slipped in some way to Stake.
|
||||
if(!C.can_be_staked() || target == user)
|
||||
to_chat(user, "<span class='danger'>You cant stake [target] when they are moving moving about! They have to be laying down!</span>")
|
||||
to_chat(user, "<span class='danger'>You can't stake [target] when they are moving about! They have to be laying down or grabbed by the neck!</span>")
|
||||
return
|
||||
// Oops! Can't.
|
||||
if(HAS_TRAIT(C, TRAIT_PIERCEIMMUNE))
|
||||
@@ -113,7 +113,7 @@
|
||||
// Can this target be staked? If someone stands up before this is complete, it fails. Best used on someone stationary.
|
||||
/mob/living/carbon/proc/can_be_staked()
|
||||
//return resting || IsKnockdown() || IsUnconscious() || (stat && (stat != SOFT_CRIT || pulledby)) || (has_trait(TRAIT_FAKEDEATH)) || resting || IsStun() || IsFrozen() || (pulledby && pulledby.grab_state >= GRAB_NECK)
|
||||
return (src.resting || src.lying)
|
||||
return (resting || lying || IsUnconscious() || pulledby && pulledby.grab_state >= GRAB_NECK)
|
||||
// ABOVE: Taken from update_mobility() in living.dm
|
||||
|
||||
/obj/item/stake/hardened
|
||||
|
||||
@@ -130,7 +130,7 @@
|
||||
/obj/structure/bloodsucker/vassalrack/MouseDrop_T(atom/movable/O, mob/user)
|
||||
if(!O.Adjacent(src) || O == user || !isliving(O) || !isliving(user) || useLock || has_buckled_mobs() || user.incapacitated())
|
||||
return
|
||||
if(!anchored && user.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER))
|
||||
if(!anchored && isvamp(user))
|
||||
to_chat(user, "<span class='danger'>Until this rack is secured in place, it cannot serve its purpose.</span>")
|
||||
return
|
||||
// PULL TARGET: Remember if I was pullin this guy, so we can restore this
|
||||
@@ -183,7 +183,7 @@
|
||||
|
||||
/obj/structure/bloodsucker/vassalrack/user_unbuckle_mob(mob/living/M, mob/user)
|
||||
// Attempt Unbuckle
|
||||
if(!user.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER))
|
||||
if(!isvamp(user))
|
||||
if(M == user)
|
||||
M.visible_message("<span class='danger'>[user] tries to release themself from the rack!</span>",\
|
||||
"<span class='danger'>You attempt to release yourself from the rack!</span>") // For sound if not seen --> "<span class='italics'>You hear a squishy wet noise.</span>")
|
||||
@@ -275,7 +275,7 @@
|
||||
// All done!
|
||||
if(convert_progress <= 0)
|
||||
// FAIL: Can't be Vassal
|
||||
if(!SSticker.mode.can_make_vassal(target, user, display_warning=FALSE) && HAS_TRAIT(target, TRAIT_MINDSHIELD)) // If I'm an unconvertable Antag ONLY
|
||||
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!
|
||||
@@ -453,7 +453,7 @@
|
||||
|
||||
/obj/structure/bloodsucker/candelabrum/examine(mob/user)
|
||||
. = ..()
|
||||
if((user.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER)) || isobserver(user))
|
||||
if((isvamp()) || 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)
|
||||
@@ -461,15 +461,13 @@
|
||||
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)
|
||||
if(istype(V) || istype(T))
|
||||
if(isvamp(user) || istype(T))
|
||||
toggle()
|
||||
|
||||
/obj/structure/bloodsucker/candelabrum/AltClick(mob/user)
|
||||
var/datum/antagonist/bloodsucker/V = user.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER)
|
||||
// Bloodsuckers can turn their candles on from a distance. SPOOOOKY.
|
||||
if(istype(V))
|
||||
if(isvamp(user))
|
||||
toggle()
|
||||
|
||||
/obj/structure/bloodsucker/candelabrum/proc/toggle(mob/user)
|
||||
@@ -486,8 +484,7 @@
|
||||
if(lit)
|
||||
for(var/mob/living/carbon/human/H in viewers(7, src))
|
||||
var/datum/antagonist/vassal/T = H.mind.has_antag_datum(ANTAG_DATUM_VASSAL)
|
||||
var/datum/antagonist/bloodsucker/V = H.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER)
|
||||
if(V || T) //We dont want vassals or vampires affected by this
|
||||
if(isvamp(H) || T) //We dont want vassals or vampires affected by this
|
||||
return
|
||||
H.hallucination = 20
|
||||
SEND_SIGNAL(H, COMSIG_ADD_MOOD_EVENT, "vampcandle", /datum/mood_event/vampcandle)
|
||||
|
||||
@@ -9,8 +9,9 @@
|
||||
bloodsucker_can_buy = TRUE
|
||||
amToggle = TRUE
|
||||
warn_constant_cost = TRUE
|
||||
var/was_running
|
||||
|
||||
var/light_min = 0.5 // If lum is above this, no good.
|
||||
var/light_min = 0.2 // If lum is above this, no good.
|
||||
|
||||
/datum/action/bloodsucker/cloak/CheckCanUse(display_error)
|
||||
. = ..()
|
||||
@@ -26,18 +27,16 @@
|
||||
/datum/action/bloodsucker/cloak/ActivatePower()
|
||||
var/datum/antagonist/bloodsucker/bloodsuckerdatum = owner.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER)
|
||||
var/mob/living/user = owner
|
||||
var/was_running = (user.m_intent == MOVE_INTENT_RUN)
|
||||
was_running = (user.m_intent == MOVE_INTENT_RUN)
|
||||
if(was_running)
|
||||
user.toggle_move_intent()
|
||||
ADD_TRAIT(user, TRAIT_NORUNNING, "cloak of darkness")
|
||||
while(bloodsuckerdatum && ContinueActive(user) || user.m_intent == MOVE_INTENT_RUN)
|
||||
// Pay Blood Toll (if awake)
|
||||
owner.alpha = max(0, owner.alpha - min(75, 20 + 15 * level_current))
|
||||
owner.alpha = max(20, owner.alpha - min(75, 10 + 5 * level_current))
|
||||
bloodsuckerdatum.AddBloodVolume(-0.2)
|
||||
sleep(5) // Check every few ticks that we haven't disabled this power
|
||||
// Return to Running (if you were before)
|
||||
if(was_running && user.m_intent != MOVE_INTENT_RUN)
|
||||
user.toggle_move_intent()
|
||||
|
||||
/datum/action/bloodsucker/cloak/ContinueActive(mob/living/user, mob/living/target)
|
||||
if (!..())
|
||||
@@ -55,3 +54,5 @@
|
||||
..()
|
||||
REMOVE_TRAIT(user, TRAIT_NORUNNING, "cloak of darkness")
|
||||
user.alpha = 255
|
||||
if(was_running && user.m_intent != MOVE_INTENT_RUN)
|
||||
user.toggle_move_intent()
|
||||
|
||||
@@ -51,14 +51,17 @@
|
||||
REMOVE_TRAIT(user, TRAIT_COLDBLOODED, "bloodsucker")
|
||||
REMOVE_TRAIT(user, TRAIT_NOHARDCRIT, "bloodsucker")
|
||||
REMOVE_TRAIT(user, TRAIT_NOSOFTCRIT, "bloodsucker")
|
||||
REMOVE_TRAIT(user, TRAIT_VIRUSIMMUNE, "bloodsucker")
|
||||
var/obj/item/organ/heart/vampheart/H = user.getorganslot(ORGAN_SLOT_HEART)
|
||||
|
||||
var/obj/item/organ/eyes/vassal/bloodsucker/E = user.getorganslot(ORGAN_SLOT_EYES)
|
||||
E.flash_protect = 0
|
||||
|
||||
// WE ARE ALIVE! //
|
||||
bloodsuckerdatum.poweron_masquerade = TRUE
|
||||
while(bloodsuckerdatum && ContinueActive(user))
|
||||
|
||||
// HEART
|
||||
if (istype(H))
|
||||
if(istype(H))
|
||||
H.FakeStart()
|
||||
|
||||
// PASSIVE (done from LIFE)
|
||||
@@ -67,7 +70,7 @@
|
||||
// Don't Heal
|
||||
|
||||
// Pay Blood Toll (if awake)
|
||||
if (user.stat == CONSCIOUS)
|
||||
if(user.stat == CONSCIOUS)
|
||||
bloodsuckerdatum.AddBloodVolume(-0.2)
|
||||
|
||||
sleep(20) // Check every few ticks that we haven't disabled this power
|
||||
@@ -89,9 +92,13 @@
|
||||
ADD_TRAIT(user, TRAIT_COLDBLOODED, "bloodsucker")
|
||||
ADD_TRAIT(user, TRAIT_NOHARDCRIT, "bloodsucker")
|
||||
ADD_TRAIT(user, TRAIT_NOSOFTCRIT, "bloodsucker")
|
||||
ADD_TRAIT(user, TRAIT_VIRUSIMMUNE, "bloodsucker")
|
||||
|
||||
// HEART
|
||||
var/obj/item/organ/heart/H = user.getorganslot(ORGAN_SLOT_HEART)
|
||||
var/obj/item/organ/eyes/vassal/bloodsucker/E = user.getorganslot(ORGAN_SLOT_EYES)
|
||||
H.Stop()
|
||||
|
||||
E.flash_protect = 2
|
||||
|
||||
to_chat(user, "<span class='notice'>Your heart beats one final time, while your skin dries out and your icy pallor returns.</span>")
|
||||
|
||||
@@ -89,17 +89,14 @@
|
||||
|
||||
if(istype(target))
|
||||
target.Stun(40) //Utterly useless without this, its okay since there are so many checks to go through
|
||||
target.silent = 45 //Shhhh little lamb
|
||||
target.apply_status_effect(STATUS_EFFECT_MESMERIZE, 45) //So you cant rotate with combat mode, plus fancy status alert
|
||||
|
||||
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 * 12
|
||||
target.silent = power_time + 20
|
||||
target.apply_status_effect(STATUS_EFFECT_MESMERIZE, 100 + level_current * 15)
|
||||
target.apply_status_effect(STATUS_EFFECT_MESMERIZE, power_time + 80)
|
||||
to_chat(user, "<span class='notice'>[target] is fixed in place by your hypnotic gaze.</span>")
|
||||
target.Stun(power_time)
|
||||
//target.silent += power_time / 10 // Silent isn't based on ticks.
|
||||
target.next_move = world.time + power_time // <--- Use direct change instead. We want an unmodified delay to their next move // target.changeNext_move(power_time) // check click.dm
|
||||
target.notransform = TRUE // <--- Fuck it. We tried using next_move, but they could STILL resist. We're just doing a hard freeze.
|
||||
spawn(power_time)
|
||||
|
||||
@@ -89,13 +89,7 @@
|
||||
user.invisibility = INVISIBILITY_MAXIMUM
|
||||
|
||||
// LOSE CUFFS
|
||||
if(user.handcuffed)
|
||||
var/obj/O = user.handcuffed
|
||||
user.dropItemToGround(O)
|
||||
if(user.legcuffed)
|
||||
var/obj/O = user.legcuffed
|
||||
user.dropItemToGround(O)
|
||||
|
||||
|
||||
// Wait...
|
||||
sleep(mist_delay / 2)
|
||||
|
||||
|
||||
@@ -1,84 +1,84 @@
|
||||
/*
|
||||
* Don't use the apostrophe in name or desc. Causes script errors.
|
||||
* TODO: combine atleast some of the functionality with /proc_holder/spell
|
||||
*/
|
||||
|
||||
/obj/effect/proc_holder/changeling
|
||||
panel = "Changeling"
|
||||
name = "Prototype Sting"
|
||||
desc = "" // Fluff
|
||||
var/helptext = "" // Details
|
||||
var/chemical_cost = 0 // negative chemical cost is for passive abilities (chemical glands)
|
||||
var/dna_cost = -1 //cost of the sting in dna points. 0 = auto-purchase, -1 = cannot be purchased
|
||||
var/req_dna = 0 //amount of dna needed to use this ability. Changelings always have atleast 1
|
||||
var/req_human = 0 //if you need to be human to use this ability
|
||||
var/req_absorbs = 0 //similar to req_dna, but only gained from absorbing, not DNA sting
|
||||
var/req_stat = CONSCIOUS // CONSCIOUS, UNCONSCIOUS or DEAD
|
||||
var/always_keep = 0 // important for abilities like revive that screw you if you lose them.
|
||||
var/ignores_fakedeath = FALSE // usable with the FAKEDEATH flag
|
||||
var/loudness = 0 //Determines how much having this ability will affect changeling blood tests. At 4, the blood will react violently and turn to ash, creating a unique message in the process. At 10, the blood will explode when heated.
|
||||
|
||||
|
||||
/obj/effect/proc_holder/changeling/proc/on_purchase(mob/user, is_respec)
|
||||
action.Grant(user)
|
||||
if(!is_respec)
|
||||
SSblackbox.record_feedback("tally", "changeling_power_purchase", 1, name)
|
||||
|
||||
/obj/effect/proc_holder/changeling/proc/on_refund(mob/user)
|
||||
action.Remove(user)
|
||||
return
|
||||
|
||||
/obj/effect/proc_holder/changeling/Click()
|
||||
var/mob/user = usr
|
||||
if(!user || !user.mind || !user.mind.has_antag_datum(/datum/antagonist/changeling))
|
||||
return
|
||||
try_to_sting(user)
|
||||
|
||||
/obj/effect/proc_holder/changeling/proc/try_to_sting(mob/user, mob/target)
|
||||
if(!can_sting(user, target))
|
||||
return
|
||||
var/datum/antagonist/changeling/c = user.mind.has_antag_datum(/datum/antagonist/changeling)
|
||||
if(sting_action(user, target))
|
||||
SSblackbox.record_feedback("nested tally", "changeling_powers", 1, list("[name]"))
|
||||
sting_feedback(user, target)
|
||||
c.chem_charges -= chemical_cost
|
||||
|
||||
/obj/effect/proc_holder/changeling/proc/sting_action(mob/user, mob/target)
|
||||
return 0
|
||||
|
||||
/obj/effect/proc_holder/changeling/proc/sting_feedback(mob/user, mob/target)
|
||||
return 0
|
||||
|
||||
//Fairly important to remember to return 1 on success >.<
|
||||
/obj/effect/proc_holder/changeling/proc/can_sting(mob/living/user, mob/target)
|
||||
if(!ishuman(user) && !ismonkey(user)) //typecast everything from mob to carbon from this point onwards
|
||||
return 0
|
||||
if(req_human && !ishuman(user))
|
||||
to_chat(user, "<span class='warning'>We cannot do that in this form!</span>")
|
||||
return 0
|
||||
var/datum/antagonist/changeling/c = user.mind.has_antag_datum(/datum/antagonist/changeling)
|
||||
if(c.chem_charges < chemical_cost)
|
||||
to_chat(user, "<span class='warning'>We require at least [chemical_cost] unit\s of chemicals to do that!</span>")
|
||||
return 0
|
||||
if(c.absorbedcount < req_dna)
|
||||
to_chat(user, "<span class='warning'>We require at least [req_dna] sample\s of compatible DNA.</span>")
|
||||
return 0
|
||||
if(c.trueabsorbs < req_absorbs)
|
||||
to_chat(user, "<span class='warning'>We require at least [req_absorbs] sample\s of DNA gained through our Absorb ability.</span>")
|
||||
if(req_stat < user.stat)
|
||||
to_chat(user, "<span class='warning'>We are incapacitated.</span>")
|
||||
return 0
|
||||
if((HAS_TRAIT(user, TRAIT_DEATHCOMA)) && (!ignores_fakedeath))
|
||||
to_chat(user, "<span class='warning'>We are incapacitated.</span>")
|
||||
return 0
|
||||
return 1
|
||||
|
||||
//used in /mob/Stat()
|
||||
/obj/effect/proc_holder/changeling/proc/can_be_used_by(mob/user)
|
||||
if(QDELETED(user))
|
||||
return FALSE
|
||||
if(!ishuman(user) && !ismonkey(user))
|
||||
return FALSE
|
||||
if(req_human && !ishuman(user))
|
||||
return FALSE
|
||||
return TRUE
|
||||
/*
|
||||
* Don't use the apostrophe in name or desc. Causes script errors.
|
||||
* TODO: combine atleast some of the functionality with /proc_holder/spell
|
||||
*/
|
||||
|
||||
/obj/effect/proc_holder/changeling
|
||||
panel = "Changeling"
|
||||
name = "Prototype Sting"
|
||||
desc = "" // Fluff
|
||||
var/helptext = "" // Details
|
||||
var/chemical_cost = 0 // negative chemical cost is for passive abilities (chemical glands)
|
||||
var/dna_cost = -1 //cost of the sting in dna points. 0 = auto-purchase, -1 = cannot be purchased
|
||||
var/req_dna = 0 //amount of dna needed to use this ability. Changelings always have atleast 1
|
||||
var/req_human = 0 //if you need to be human to use this ability
|
||||
var/req_absorbs = 0 //similar to req_dna, but only gained from absorbing, not DNA sting
|
||||
var/req_stat = CONSCIOUS // CONSCIOUS, UNCONSCIOUS or DEAD
|
||||
var/always_keep = 0 // important for abilities like revive that screw you if you lose them.
|
||||
var/ignores_fakedeath = FALSE // usable with the FAKEDEATH flag
|
||||
var/loudness = 0 //Determines how much having this ability will affect changeling blood tests. At 4, the blood will react violently and turn to ash, creating a unique message in the process. At 10, the blood will explode when heated.
|
||||
|
||||
|
||||
/obj/effect/proc_holder/changeling/proc/on_purchase(mob/user, is_respec)
|
||||
action.Grant(user)
|
||||
if(!is_respec)
|
||||
SSblackbox.record_feedback("tally", "changeling_power_purchase", 1, name)
|
||||
|
||||
/obj/effect/proc_holder/changeling/proc/on_refund(mob/user)
|
||||
action.Remove(user)
|
||||
return
|
||||
|
||||
/obj/effect/proc_holder/changeling/Click()
|
||||
var/mob/user = usr
|
||||
if(!user || !user.mind || !user.mind.has_antag_datum(/datum/antagonist/changeling))
|
||||
return
|
||||
try_to_sting(user)
|
||||
|
||||
/obj/effect/proc_holder/changeling/proc/try_to_sting(mob/user, mob/target)
|
||||
if(!can_sting(user, target))
|
||||
return
|
||||
var/datum/antagonist/changeling/c = user.mind.has_antag_datum(/datum/antagonist/changeling)
|
||||
if(sting_action(user, target))
|
||||
SSblackbox.record_feedback("nested tally", "changeling_powers", 1, list("[name]"))
|
||||
sting_feedback(user, target)
|
||||
c.chem_charges -= chemical_cost
|
||||
|
||||
/obj/effect/proc_holder/changeling/proc/sting_action(mob/user, mob/target)
|
||||
return 0
|
||||
|
||||
/obj/effect/proc_holder/changeling/proc/sting_feedback(mob/user, mob/target)
|
||||
return 0
|
||||
|
||||
//Fairly important to remember to return 1 on success >.<
|
||||
/obj/effect/proc_holder/changeling/proc/can_sting(mob/living/user, mob/target)
|
||||
if(!ishuman(user) && !ismonkey(user)) //typecast everything from mob to carbon from this point onwards
|
||||
return 0
|
||||
if(req_human && !ishuman(user))
|
||||
to_chat(user, "<span class='warning'>We cannot do that in this form!</span>")
|
||||
return 0
|
||||
var/datum/antagonist/changeling/c = user.mind.has_antag_datum(/datum/antagonist/changeling)
|
||||
if(c.chem_charges < chemical_cost)
|
||||
to_chat(user, "<span class='warning'>We require at least [chemical_cost] unit\s of chemicals to do that!</span>")
|
||||
return 0
|
||||
if(c.absorbedcount < req_dna)
|
||||
to_chat(user, "<span class='warning'>We require at least [req_dna] sample\s of compatible DNA.</span>")
|
||||
return 0
|
||||
if(c.trueabsorbs < req_absorbs)
|
||||
to_chat(user, "<span class='warning'>We require at least [req_absorbs] sample\s of DNA gained through our Absorb ability.</span>")
|
||||
if(req_stat < user.stat)
|
||||
to_chat(user, "<span class='warning'>We are incapacitated.</span>")
|
||||
return 0
|
||||
if((HAS_TRAIT(user, TRAIT_DEATHCOMA)) && (!ignores_fakedeath))
|
||||
to_chat(user, "<span class='warning'>We are incapacitated.</span>")
|
||||
return 0
|
||||
return 1
|
||||
|
||||
//used in /mob/Stat()
|
||||
/obj/effect/proc_holder/changeling/proc/can_be_used_by(mob/user)
|
||||
if(QDELETED(user))
|
||||
return FALSE
|
||||
if(!ishuman(user) && !ismonkey(user))
|
||||
return FALSE
|
||||
if(req_human && !ishuman(user))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
@@ -1,117 +1,117 @@
|
||||
/obj/effect/proc_holder/changeling/absorbDNA
|
||||
name = "Absorb DNA"
|
||||
desc = "Absorb the DNA of our victim."
|
||||
chemical_cost = 0
|
||||
dna_cost = 0
|
||||
req_human = 1
|
||||
action_icon = 'icons/mob/actions/actions_changeling.dmi'
|
||||
action_icon_state = "ling_absorb_dna"
|
||||
action_background_icon_state = "bg_ling"
|
||||
|
||||
/obj/effect/proc_holder/changeling/absorbDNA/can_sting(mob/living/carbon/user)
|
||||
if(!..())
|
||||
return
|
||||
|
||||
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
|
||||
if(changeling.isabsorbing)
|
||||
to_chat(user, "<span class='warning'>We are already absorbing!</span>")
|
||||
return
|
||||
|
||||
if(!user.pulling || !iscarbon(user.pulling))
|
||||
to_chat(user, "<span class='warning'>We must be grabbing a creature to absorb them!</span>")
|
||||
return
|
||||
if(user.grab_state <= GRAB_NECK)
|
||||
to_chat(user, "<span class='warning'>We must have a tighter grip to absorb this creature!</span>")
|
||||
return
|
||||
|
||||
var/mob/living/carbon/target = user.pulling
|
||||
return changeling.can_absorb_dna(target)
|
||||
|
||||
|
||||
|
||||
/obj/effect/proc_holder/changeling/absorbDNA/sting_action(mob/user)
|
||||
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
|
||||
var/mob/living/carbon/human/target = user.pulling
|
||||
changeling.isabsorbing = 1
|
||||
for(var/i in 1 to 3)
|
||||
switch(i)
|
||||
if(1)
|
||||
to_chat(user, "<span class='notice'>This creature is compatible. We must hold still...</span>")
|
||||
if(2)
|
||||
user.visible_message("<span class='warning'>[user] extends a proboscis!</span>", "<span class='notice'>We extend a proboscis.</span>")
|
||||
if(3)
|
||||
user.visible_message("<span class='danger'>[user] stabs [target] with the proboscis!</span>", "<span class='notice'>We stab [target] with the proboscis.</span>")
|
||||
to_chat(target, "<span class='userdanger'>You feel a sharp stabbing pain!</span>")
|
||||
target.take_overall_damage(40)
|
||||
|
||||
SSblackbox.record_feedback("nested tally", "changeling_powers", 1, list("Absorb DNA", "[i]"))
|
||||
if(!do_mob(user, target, 150))
|
||||
to_chat(user, "<span class='warning'>Our absorption of [target] has been interrupted!</span>")
|
||||
changeling.isabsorbing = 0
|
||||
return
|
||||
|
||||
SSblackbox.record_feedback("nested tally", "changeling_powers", 1, list("Absorb DNA", "4"))
|
||||
user.visible_message("<span class='danger'>[user] sucks the fluids from [target]!</span>", "<span class='notice'>We have absorbed [target].</span>")
|
||||
to_chat(target, "<span class='userdanger'>You are absorbed by the changeling!</span>")
|
||||
|
||||
if(!changeling.has_dna(target.dna))
|
||||
changeling.add_new_profile(target)
|
||||
changeling.trueabsorbs++
|
||||
|
||||
if(user.nutrition < NUTRITION_LEVEL_WELL_FED)
|
||||
user.nutrition = min((user.nutrition + target.nutrition), NUTRITION_LEVEL_WELL_FED)
|
||||
|
||||
if(target.mind)//if the victim has got a mind
|
||||
// Absorb a lizard, speak Draconic.
|
||||
user.copy_known_languages_from(target)
|
||||
|
||||
target.mind.show_memory(user, 0) //I can read your mind, kekeke. Output all their notes.
|
||||
|
||||
//Some of target's recent speech, so the changeling can attempt to imitate them better.
|
||||
//Recent as opposed to all because rounds tend to have a LOT of text.
|
||||
var/list/recent_speech = list()
|
||||
|
||||
var/list/say_log = target.logging[LOG_SAY]
|
||||
|
||||
if(LAZYLEN(say_log) > LING_ABSORB_RECENT_SPEECH)
|
||||
recent_speech = say_log.Copy(say_log.len-LING_ABSORB_RECENT_SPEECH+1,0) //0 so len-LING_ARS+1 to end of list
|
||||
else
|
||||
for(var/spoken_memory in say_log)
|
||||
if(recent_speech.len >= LING_ABSORB_RECENT_SPEECH)
|
||||
break
|
||||
recent_speech[spoken_memory] = say_log[spoken_memory]
|
||||
|
||||
if(recent_speech.len)
|
||||
changeling.antag_memory += "<B>Some of [target]'s speech patterns, we should study these to better impersonate [target.p_them()]!</B><br>"
|
||||
to_chat(user, "<span class='boldnotice'>Some of [target]'s speech patterns, we should study these to better impersonate [target.p_them()]!</span>")
|
||||
for(var/spoken_memory in recent_speech)
|
||||
changeling.antag_memory += "\"[recent_speech[spoken_memory]]\"<br>"
|
||||
to_chat(user, "<span class='notice'>\"[recent_speech[spoken_memory]]\"</span>")
|
||||
changeling.antag_memory += "<B>We have no more knowledge of [target]'s speech patterns.</B><br>"
|
||||
to_chat(user, "<span class='boldnotice'>We have no more knowledge of [target]'s speech patterns.</span>")
|
||||
|
||||
|
||||
var/datum/antagonist/changeling/target_ling = target.mind.has_antag_datum(/datum/antagonist/changeling)
|
||||
if(target_ling)//If the target was a changeling, suck out their extra juice and objective points!
|
||||
to_chat(user, "<span class='boldnotice'>[target] was one of us. We have absorbed their power.</span>")
|
||||
target_ling.remove_changeling_powers()
|
||||
changeling.geneticpoints += round(target_ling.geneticpoints/2)
|
||||
target_ling.geneticpoints = 0
|
||||
target_ling.canrespec = 0
|
||||
changeling.chem_storage += round(target_ling.chem_storage/2)
|
||||
changeling.chem_charges += min(target_ling.chem_charges, changeling.chem_storage)
|
||||
target_ling.chem_charges = 0
|
||||
target_ling.chem_storage = 0
|
||||
changeling.absorbedcount += (target_ling.absorbedcount)
|
||||
target_ling.stored_profiles.len = 1
|
||||
target_ling.absorbedcount = 0
|
||||
|
||||
|
||||
changeling.chem_charges=min(changeling.chem_charges+10, changeling.chem_storage)
|
||||
|
||||
changeling.isabsorbing = 0
|
||||
changeling.canrespec = 1
|
||||
|
||||
target.death(0)
|
||||
target.Drain()
|
||||
return TRUE
|
||||
/obj/effect/proc_holder/changeling/absorbDNA
|
||||
name = "Absorb DNA"
|
||||
desc = "Absorb the DNA of our victim."
|
||||
chemical_cost = 0
|
||||
dna_cost = 0
|
||||
req_human = 1
|
||||
action_icon = 'icons/mob/actions/actions_changeling.dmi'
|
||||
action_icon_state = "ling_absorb_dna"
|
||||
action_background_icon_state = "bg_ling"
|
||||
|
||||
/obj/effect/proc_holder/changeling/absorbDNA/can_sting(mob/living/carbon/user)
|
||||
if(!..())
|
||||
return
|
||||
|
||||
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
|
||||
if(changeling.isabsorbing)
|
||||
to_chat(user, "<span class='warning'>We are already absorbing!</span>")
|
||||
return
|
||||
|
||||
if(!user.pulling || !iscarbon(user.pulling))
|
||||
to_chat(user, "<span class='warning'>We must be grabbing a creature to absorb them!</span>")
|
||||
return
|
||||
if(user.grab_state <= GRAB_NECK)
|
||||
to_chat(user, "<span class='warning'>We must have a tighter grip to absorb this creature!</span>")
|
||||
return
|
||||
|
||||
var/mob/living/carbon/target = user.pulling
|
||||
return changeling.can_absorb_dna(target)
|
||||
|
||||
|
||||
|
||||
/obj/effect/proc_holder/changeling/absorbDNA/sting_action(mob/user)
|
||||
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
|
||||
var/mob/living/carbon/human/target = user.pulling
|
||||
changeling.isabsorbing = 1
|
||||
for(var/i in 1 to 3)
|
||||
switch(i)
|
||||
if(1)
|
||||
to_chat(user, "<span class='notice'>This creature is compatible. We must hold still...</span>")
|
||||
if(2)
|
||||
user.visible_message("<span class='warning'>[user] extends a proboscis!</span>", "<span class='notice'>We extend a proboscis.</span>")
|
||||
if(3)
|
||||
user.visible_message("<span class='danger'>[user] stabs [target] with the proboscis!</span>", "<span class='notice'>We stab [target] with the proboscis.</span>")
|
||||
to_chat(target, "<span class='userdanger'>You feel a sharp stabbing pain!</span>")
|
||||
target.take_overall_damage(40)
|
||||
|
||||
SSblackbox.record_feedback("nested tally", "changeling_powers", 1, list("Absorb DNA", "[i]"))
|
||||
if(!do_mob(user, target, 150))
|
||||
to_chat(user, "<span class='warning'>Our absorption of [target] has been interrupted!</span>")
|
||||
changeling.isabsorbing = 0
|
||||
return
|
||||
|
||||
SSblackbox.record_feedback("nested tally", "changeling_powers", 1, list("Absorb DNA", "4"))
|
||||
user.visible_message("<span class='danger'>[user] sucks the fluids from [target]!</span>", "<span class='notice'>We have absorbed [target].</span>")
|
||||
to_chat(target, "<span class='userdanger'>You are absorbed by the changeling!</span>")
|
||||
|
||||
if(!changeling.has_dna(target.dna))
|
||||
changeling.add_new_profile(target)
|
||||
changeling.trueabsorbs++
|
||||
|
||||
if(user.nutrition < NUTRITION_LEVEL_WELL_FED)
|
||||
user.nutrition = min((user.nutrition + target.nutrition), NUTRITION_LEVEL_WELL_FED)
|
||||
|
||||
if(target.mind)//if the victim has got a mind
|
||||
// Absorb a lizard, speak Draconic.
|
||||
user.copy_known_languages_from(target)
|
||||
|
||||
target.mind.show_memory(user, 0) //I can read your mind, kekeke. Output all their notes.
|
||||
|
||||
//Some of target's recent speech, so the changeling can attempt to imitate them better.
|
||||
//Recent as opposed to all because rounds tend to have a LOT of text.
|
||||
var/list/recent_speech = list()
|
||||
|
||||
var/list/say_log = target.logging[LOG_SAY]
|
||||
|
||||
if(LAZYLEN(say_log) > LING_ABSORB_RECENT_SPEECH)
|
||||
recent_speech = say_log.Copy(say_log.len-LING_ABSORB_RECENT_SPEECH+1,0) //0 so len-LING_ARS+1 to end of list
|
||||
else
|
||||
for(var/spoken_memory in say_log)
|
||||
if(recent_speech.len >= LING_ABSORB_RECENT_SPEECH)
|
||||
break
|
||||
recent_speech[spoken_memory] = say_log[spoken_memory]
|
||||
|
||||
if(recent_speech.len)
|
||||
changeling.antag_memory += "<B>Some of [target]'s speech patterns, we should study these to better impersonate [target.p_them()]!</B><br>"
|
||||
to_chat(user, "<span class='boldnotice'>Some of [target]'s speech patterns, we should study these to better impersonate [target.p_them()]!</span>")
|
||||
for(var/spoken_memory in recent_speech)
|
||||
changeling.antag_memory += "\"[recent_speech[spoken_memory]]\"<br>"
|
||||
to_chat(user, "<span class='notice'>\"[recent_speech[spoken_memory]]\"</span>")
|
||||
changeling.antag_memory += "<B>We have no more knowledge of [target]'s speech patterns.</B><br>"
|
||||
to_chat(user, "<span class='boldnotice'>We have no more knowledge of [target]'s speech patterns.</span>")
|
||||
|
||||
|
||||
var/datum/antagonist/changeling/target_ling = target.mind.has_antag_datum(/datum/antagonist/changeling)
|
||||
if(target_ling)//If the target was a changeling, suck out their extra juice and objective points!
|
||||
to_chat(user, "<span class='boldnotice'>[target] was one of us. We have absorbed their power.</span>")
|
||||
target_ling.remove_changeling_powers()
|
||||
changeling.geneticpoints += round(target_ling.geneticpoints/2)
|
||||
target_ling.geneticpoints = 0
|
||||
target_ling.canrespec = 0
|
||||
changeling.chem_storage += round(target_ling.chem_storage/2)
|
||||
changeling.chem_charges += min(target_ling.chem_charges, changeling.chem_storage)
|
||||
target_ling.chem_charges = 0
|
||||
target_ling.chem_storage = 0
|
||||
changeling.absorbedcount += (target_ling.absorbedcount)
|
||||
target_ling.stored_profiles.len = 1
|
||||
target_ling.absorbedcount = 0
|
||||
|
||||
|
||||
changeling.chem_charges=min(changeling.chem_charges+10, changeling.chem_storage)
|
||||
|
||||
changeling.isabsorbing = 0
|
||||
changeling.canrespec = 1
|
||||
|
||||
target.death(0)
|
||||
target.Drain()
|
||||
return TRUE
|
||||
|
||||
@@ -13,5 +13,5 @@
|
||||
|
||||
//Recover from stuns.
|
||||
/obj/effect/proc_holder/changeling/adrenaline/sting_action(mob/living/user)
|
||||
user.do_adrenaline(0, FALSE, 70, 0, TRUE, list("epinephrine" = 3, "changelingmeth" = 10, "mannitol" = 10, "regen_jelly" = 10, "changelingadrenaline" = 5), "<span class='notice'>Energy rushes through us.</span>", 0, 0.75, 0)
|
||||
user.do_adrenaline(0, FALSE, 70, 0, TRUE, list(/datum/reagent/medicine/epinephrine = 3, /datum/reagent/drug/methamphetamine/changeling = 10, /datum/reagent/medicine/mannitol = 10, /datum/reagent/medicine/regen_jelly = 10, /datum/reagent/medicine/changelingadrenaline = 5), "<span class='notice'>Energy rushes through us.</span>", 0, 0.75, 0)
|
||||
return TRUE
|
||||
@@ -1,43 +1,43 @@
|
||||
/obj/effect/proc_holder/changeling/fakedeath
|
||||
name = "Reviving Stasis"
|
||||
desc = "We fall into a stasis, allowing us to regenerate and trick our enemies."
|
||||
chemical_cost = 15
|
||||
dna_cost = 0
|
||||
req_dna = 1
|
||||
req_stat = DEAD
|
||||
ignores_fakedeath = TRUE
|
||||
action_icon = 'icons/mob/actions/actions_changeling.dmi'
|
||||
action_icon_state = "ling_regenerative_stasis"
|
||||
action_background_icon_state = "bg_ling"
|
||||
|
||||
//Fake our own death and fully heal. You will appear to be dead but regenerate fully after a short delay.
|
||||
/obj/effect/proc_holder/changeling/fakedeath/sting_action(mob/living/user)
|
||||
to_chat(user, "<span class='notice'>We begin our stasis, preparing energy to arise once more.</span>")
|
||||
if(user.stat != DEAD)
|
||||
user.emote("deathgasp")
|
||||
user.tod = STATION_TIME_TIMESTAMP("hh:mm:ss")
|
||||
user.fakedeath("changeling") //play dead
|
||||
user.update_stat()
|
||||
user.update_canmove()
|
||||
|
||||
addtimer(CALLBACK(src, .proc/ready_to_regenerate, user), LING_FAKEDEATH_TIME, TIMER_UNIQUE)
|
||||
return TRUE
|
||||
|
||||
/obj/effect/proc_holder/changeling/fakedeath/proc/ready_to_regenerate(mob/user)
|
||||
if(user && user.mind)
|
||||
var/datum/antagonist/changeling/C = user.mind.has_antag_datum(/datum/antagonist/changeling)
|
||||
if(C && C.purchasedpowers)
|
||||
to_chat(user, "<span class='notice'>We are ready to revive.</span>")
|
||||
var/obj/effect/proc_holder/changeling/revive/RV = new /obj/effect/proc_holder/changeling/revive(null)
|
||||
C.purchasedpowers += RV
|
||||
RV.action.Grant(user)
|
||||
|
||||
/obj/effect/proc_holder/changeling/fakedeath/can_sting(mob/living/user)
|
||||
if(HAS_TRAIT_FROM(user, TRAIT_DEATHCOMA, "changeling"))
|
||||
to_chat(user, "<span class='warning'>We are already reviving.</span>")
|
||||
return
|
||||
if(!user.stat) //Confirmation for living changelings if they want to fake their death
|
||||
switch(alert("Are we sure we wish to fake our own death?",,"Yes", "No"))
|
||||
if("No")
|
||||
return
|
||||
return ..()
|
||||
/obj/effect/proc_holder/changeling/fakedeath
|
||||
name = "Reviving Stasis"
|
||||
desc = "We fall into a stasis, allowing us to regenerate and trick our enemies."
|
||||
chemical_cost = 15
|
||||
dna_cost = 0
|
||||
req_dna = 1
|
||||
req_stat = DEAD
|
||||
ignores_fakedeath = TRUE
|
||||
action_icon = 'icons/mob/actions/actions_changeling.dmi'
|
||||
action_icon_state = "ling_regenerative_stasis"
|
||||
action_background_icon_state = "bg_ling"
|
||||
|
||||
//Fake our own death and fully heal. You will appear to be dead but regenerate fully after a short delay.
|
||||
/obj/effect/proc_holder/changeling/fakedeath/sting_action(mob/living/user)
|
||||
to_chat(user, "<span class='notice'>We begin our stasis, preparing energy to arise once more.</span>")
|
||||
if(user.stat != DEAD)
|
||||
user.emote("deathgasp")
|
||||
user.tod = STATION_TIME_TIMESTAMP("hh:mm:ss")
|
||||
user.fakedeath("changeling") //play dead
|
||||
user.update_stat()
|
||||
user.update_canmove()
|
||||
|
||||
addtimer(CALLBACK(src, .proc/ready_to_regenerate, user), LING_FAKEDEATH_TIME, TIMER_UNIQUE)
|
||||
return TRUE
|
||||
|
||||
/obj/effect/proc_holder/changeling/fakedeath/proc/ready_to_regenerate(mob/user)
|
||||
if(user && user.mind)
|
||||
var/datum/antagonist/changeling/C = user.mind.has_antag_datum(/datum/antagonist/changeling)
|
||||
if(C && C.purchasedpowers)
|
||||
to_chat(user, "<span class='notice'>We are ready to revive.</span>")
|
||||
var/obj/effect/proc_holder/changeling/revive/RV = new /obj/effect/proc_holder/changeling/revive(null)
|
||||
C.purchasedpowers += RV
|
||||
RV.action.Grant(user)
|
||||
|
||||
/obj/effect/proc_holder/changeling/fakedeath/can_sting(mob/living/user)
|
||||
if(HAS_TRAIT_FROM(user, TRAIT_DEATHCOMA, "changeling"))
|
||||
to_chat(user, "<span class='warning'>We are already reviving.</span>")
|
||||
return
|
||||
if(!user.stat) //Confirmation for living changelings if they want to fake their death
|
||||
switch(alert("Are we sure we wish to fake our own death?",,"Yes", "No"))
|
||||
if("No")
|
||||
return
|
||||
return ..()
|
||||
|
||||
@@ -25,7 +25,8 @@
|
||||
to_chat(H, "<span class='userdanger'>You are blinded by a shower of blood!</span>")
|
||||
H.Stun(20)
|
||||
H.blur_eyes(20)
|
||||
H.adjust_eye_damage(5)
|
||||
var/obj/item/organ/eyes/eyes = H.getorganslot(ORGAN_SLOT_EYES)
|
||||
eyes?.applyOrganDamage(5)
|
||||
H.confused += 3
|
||||
for(var/mob/living/silicon/S in range(2,user))
|
||||
to_chat(S, "<span class='userdanger'>Your sensors are disabled by a shower of blood!</span>")
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
target.mind.linglink = 1
|
||||
target.say("[MODE_TOKEN_CHANGELING] AAAAARRRRGGGGGHHHHH!!")
|
||||
to_chat(target, "<font color=#800040><span class='boldannounce'>You can now communicate in the changeling hivemind, say \"[MODE_TOKEN_CHANGELING] message\" to communicate!</span>")
|
||||
target.reagents.add_reagent("salbutamol", 40) // So they don't choke to death while you interrogate them
|
||||
target.reagents.add_reagent(/datum/reagent/medicine/salbutamol, 40) // So they don't choke to death while you interrogate them
|
||||
sleep(1800)
|
||||
SSblackbox.record_feedback("nested tally", "changeling_powers", 1, list("[name]", "[i]"))
|
||||
if(!do_mob(user, target, 20))
|
||||
|
||||
@@ -500,7 +500,7 @@
|
||||
/obj/item/clothing/suit/space/changeling/process()
|
||||
if(ishuman(loc))
|
||||
var/mob/living/carbon/human/H = loc
|
||||
H.reagents.add_reagent("salbutamol", REAGENTS_METABOLISM)
|
||||
H.reagents.add_reagent(/datum/reagent/medicine/salbutamol, REAGENTS_METABOLISM)
|
||||
|
||||
/obj/item/clothing/head/helmet/space/changeling
|
||||
name = "flesh mass"
|
||||
|
||||
@@ -28,10 +28,10 @@
|
||||
C.vomit(0, toxic = TRUE)
|
||||
O.forceMove(get_turf(user))
|
||||
|
||||
user.reagents.add_reagent("mutadone", 10)
|
||||
user.reagents.add_reagent("pen_jelly", 20)
|
||||
user.reagents.add_reagent("antihol", 10)
|
||||
user.reagents.add_reagent("mannitol", 25)
|
||||
user.reagents.add_reagent(/datum/reagent/medicine/mutadone, 10)
|
||||
user.reagents.add_reagent(/datum/reagent/medicine/pen_acid/pen_jelly, 20)
|
||||
user.reagents.add_reagent(/datum/reagent/medicine/antihol, 10)
|
||||
user.reagents.add_reagent(/datum/reagent/medicine/mannitol, 25)
|
||||
|
||||
if(isliving(user))
|
||||
var/mob/living/L = user
|
||||
|
||||
@@ -1,44 +1,44 @@
|
||||
/obj/effect/proc_holder/changeling/revive
|
||||
name = "Revive"
|
||||
desc = "We regenerate, healing all damage from our form."
|
||||
helptext = "Does not regrow lost organs or a missing head."
|
||||
req_stat = DEAD
|
||||
always_keep = TRUE
|
||||
ignores_fakedeath = TRUE
|
||||
action_icon = 'icons/mob/actions/actions_changeling.dmi'
|
||||
action_icon_state = "ling_revive"
|
||||
action_background_icon_state = "bg_ling"
|
||||
|
||||
//Revive from revival stasis
|
||||
/obj/effect/proc_holder/changeling/revive/sting_action(mob/living/carbon/user)
|
||||
user.cure_fakedeath("changeling")
|
||||
user.revive(full_heal = 1)
|
||||
var/list/missing = user.get_missing_limbs()
|
||||
missing -= BODY_ZONE_HEAD // headless changelings are funny
|
||||
if(missing.len)
|
||||
playsound(user, 'sound/magic/demon_consume.ogg', 50, 1)
|
||||
user.visible_message("<span class='warning'>[user]'s missing limbs \
|
||||
reform, making a loud, grotesque sound!</span>",
|
||||
"<span class='userdanger'>Your limbs regrow, making a \
|
||||
loud, crunchy sound and giving you great pain!</span>",
|
||||
"<span class='italics'>You hear organic matter ripping \
|
||||
and tearing!</span>")
|
||||
user.emote("scream")
|
||||
user.regenerate_limbs(0, list(BODY_ZONE_HEAD))
|
||||
user.regenerate_organs()
|
||||
to_chat(user, "<span class='notice'>We have revived ourselves.</span>")
|
||||
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
|
||||
changeling.purchasedpowers -= src
|
||||
src.action.Remove(user)
|
||||
return TRUE
|
||||
|
||||
/obj/effect/proc_holder/changeling/revive/can_be_used_by(mob/living/user)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
|
||||
if(HAS_TRAIT(user, CHANGELING_DRAIN) || ((user.stat != DEAD) && !(HAS_TRAIT(user, TRAIT_DEATHCOMA))))
|
||||
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
|
||||
changeling.purchasedpowers -= src
|
||||
return FALSE
|
||||
|
||||
/obj/effect/proc_holder/changeling/revive
|
||||
name = "Revive"
|
||||
desc = "We regenerate, healing all damage from our form."
|
||||
helptext = "Does not regrow lost organs or a missing head."
|
||||
req_stat = DEAD
|
||||
always_keep = TRUE
|
||||
ignores_fakedeath = TRUE
|
||||
action_icon = 'icons/mob/actions/actions_changeling.dmi'
|
||||
action_icon_state = "ling_revive"
|
||||
action_background_icon_state = "bg_ling"
|
||||
|
||||
//Revive from revival stasis
|
||||
/obj/effect/proc_holder/changeling/revive/sting_action(mob/living/carbon/user)
|
||||
user.cure_fakedeath("changeling")
|
||||
user.revive(full_heal = 1)
|
||||
var/list/missing = user.get_missing_limbs()
|
||||
missing -= BODY_ZONE_HEAD // headless changelings are funny
|
||||
if(missing.len)
|
||||
playsound(user, 'sound/magic/demon_consume.ogg', 50, 1)
|
||||
user.visible_message("<span class='warning'>[user]'s missing limbs \
|
||||
reform, making a loud, grotesque sound!</span>",
|
||||
"<span class='userdanger'>Your limbs regrow, making a \
|
||||
loud, crunchy sound and giving you great pain!</span>",
|
||||
"<span class='italics'>You hear organic matter ripping \
|
||||
and tearing!</span>")
|
||||
user.emote("scream")
|
||||
user.regenerate_limbs(0, list(BODY_ZONE_HEAD))
|
||||
user.regenerate_organs()
|
||||
to_chat(user, "<span class='notice'>We have revived ourselves.</span>")
|
||||
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
|
||||
changeling.purchasedpowers -= src
|
||||
src.action.Remove(user)
|
||||
return TRUE
|
||||
|
||||
/obj/effect/proc_holder/changeling/revive/can_be_used_by(mob/living/user)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
|
||||
if(HAS_TRAIT(user, CHANGELING_DRAIN) || ((user.stat != DEAD) && !(HAS_TRAIT(user, TRAIT_DEATHCOMA))))
|
||||
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
|
||||
changeling.purchasedpowers -= src
|
||||
return FALSE
|
||||
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
/obj/effect/proc_holder/changeling/spiders
|
||||
name = "Spread Infestation"
|
||||
desc = "Our form divides, creating arachnids which will grow into deadly beasts."
|
||||
helptext = "The spiders are thoughtless creatures, and may attack their creators when fully grown. Requires at least 3 DNA gained through Absorb, and not through DNA sting. This ability is very loud, and will guarantee that our blood will react violently to heat."
|
||||
chemical_cost = 45
|
||||
dna_cost = 1
|
||||
loudness = 4
|
||||
req_absorbs = 3
|
||||
action_icon = 'icons/effects/effects.dmi'
|
||||
action_icon_state = "spiderling"
|
||||
action_background_icon_state = "bg_ling"
|
||||
|
||||
//Makes some spiderlings. Good for setting traps and causing general trouble.
|
||||
/obj/effect/proc_holder/changeling/spiders/sting_action(mob/user)
|
||||
spawn_atom_to_turf(/obj/structure/spider/spiderling/hunter, user, 2, FALSE)
|
||||
return TRUE
|
||||
/obj/effect/proc_holder/changeling/spiders
|
||||
name = "Spread Infestation"
|
||||
desc = "Our form divides, creating arachnids which will grow into deadly beasts."
|
||||
helptext = "The spiders are thoughtless creatures, and may attack their creators when fully grown. Requires at least 3 DNA gained through Absorb, and not through DNA sting. This ability is very loud, and will guarantee that our blood will react violently to heat."
|
||||
chemical_cost = 45
|
||||
dna_cost = 1
|
||||
loudness = 4
|
||||
req_absorbs = 3
|
||||
action_icon = 'icons/effects/effects.dmi'
|
||||
action_icon_state = "spiderling"
|
||||
action_background_icon_state = "bg_ling"
|
||||
|
||||
//Makes some spiderlings. Good for setting traps and causing general trouble.
|
||||
/obj/effect/proc_holder/changeling/spiders/sting_action(mob/user)
|
||||
spawn_atom_to_turf(/obj/structure/spider/spiderling/hunter, user, 2, FALSE)
|
||||
return TRUE
|
||||
|
||||
@@ -1,266 +1,266 @@
|
||||
/obj/effect/proc_holder/changeling/sting
|
||||
name = "Tiny Prick"
|
||||
desc = "Stabby stabby."
|
||||
var/sting_icon = null
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/Click()
|
||||
var/mob/user = usr
|
||||
if(!user || !user.mind)
|
||||
return
|
||||
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
|
||||
if(!changeling)
|
||||
return
|
||||
if(!changeling.chosen_sting)
|
||||
set_sting(user)
|
||||
else
|
||||
unset_sting(user)
|
||||
return
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/proc/set_sting(mob/user)
|
||||
to_chat(user, "<span class='notice'>We prepare our sting, use alt+click or middle mouse button on target to sting them.</span>")
|
||||
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
|
||||
changeling.chosen_sting = src
|
||||
|
||||
user.hud_used.lingstingdisplay.icon_state = sting_icon
|
||||
user.hud_used.lingstingdisplay.invisibility = 0
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/proc/unset_sting(mob/user)
|
||||
to_chat(user, "<span class='warning'>We retract our sting, we can't sting anyone for now.</span>")
|
||||
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
|
||||
changeling.chosen_sting = null
|
||||
|
||||
user.hud_used.lingstingdisplay.icon_state = null
|
||||
user.hud_used.lingstingdisplay.invisibility = INVISIBILITY_ABSTRACT
|
||||
|
||||
/mob/living/carbon/proc/unset_sting()
|
||||
if(mind)
|
||||
var/datum/antagonist/changeling/changeling = mind.has_antag_datum(/datum/antagonist/changeling)
|
||||
if(changeling && changeling.chosen_sting)
|
||||
changeling.chosen_sting.unset_sting(src)
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/can_sting(mob/user, mob/target)
|
||||
if(!..())
|
||||
return
|
||||
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
|
||||
if(!changeling.chosen_sting)
|
||||
to_chat(user, "We haven't prepared our sting yet!")
|
||||
if(!iscarbon(target))
|
||||
return
|
||||
if(!isturf(user.loc))
|
||||
return
|
||||
if(!AStar(user, target.loc, /turf/proc/Distance, changeling.sting_range, simulated_only = 0))
|
||||
return
|
||||
return 1
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/sting_feedback(mob/user, mob/target)
|
||||
if(!target)
|
||||
return
|
||||
to_chat(user, "<span class='notice'>We stealthily sting [target.name].</span>")
|
||||
if(target.mind && target.mind.has_antag_datum(/datum/antagonist/changeling))
|
||||
to_chat(target, "<span class='warning'>You feel a tiny prick.</span>")
|
||||
return 1
|
||||
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/transformation
|
||||
name = "Temporary Transformation Sting"
|
||||
desc = "We silently sting a human, injecting a chemical that forces them to transform into a chosen being for a limited time. Additional stings extend the duration."
|
||||
helptext = "The victim will transform much like a changeling would for a limited time. Does not provide a warning to others. Mutations will not be transferred, and monkeys will become human. This ability is loud, and might cause our blood to react violently to heat."
|
||||
sting_icon = "sting_transform"
|
||||
chemical_cost = 10
|
||||
dna_cost = 2
|
||||
loudness = 1
|
||||
var/datum/changelingprofile/selected_dna = null
|
||||
action_icon = 'icons/mob/actions/actions_changeling.dmi'
|
||||
action_icon_state = "ling_sting_transform"
|
||||
action_background_icon_state = "bg_ling"
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/transformation/Click()
|
||||
var/mob/user = usr
|
||||
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
|
||||
if(changeling.chosen_sting)
|
||||
unset_sting(user)
|
||||
return
|
||||
selected_dna = changeling.select_dna("Select the target DNA: ", "Target DNA")
|
||||
if(!selected_dna)
|
||||
return
|
||||
if(NOTRANSSTING in selected_dna.dna.species.species_traits)
|
||||
to_chat(user, "<span class = 'notice'>That DNA is not compatible with changeling retrovirus!</span>")
|
||||
return
|
||||
..()
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/transformation/can_sting(mob/user, mob/living/carbon/target)
|
||||
if(!..())
|
||||
return
|
||||
if((HAS_TRAIT(target, TRAIT_HUSK)) || !iscarbon(target) || (NOTRANSSTING in target.dna.species.species_traits))
|
||||
to_chat(user, "<span class='warning'>Our sting appears ineffective against its DNA.</span>")
|
||||
return 0
|
||||
return 1
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/transformation/sting_action(mob/user, mob/target)
|
||||
|
||||
if(ismonkey(target))
|
||||
to_chat(user, "<span class='notice'>Our genes cry out as we sting [target.name]!</span>")
|
||||
|
||||
var/mob/living/carbon/C = target
|
||||
. = TRUE
|
||||
if(istype(C))
|
||||
if(C.reagents.has_reagent("changeling_sting_real"))
|
||||
C.reagents.add_reagent("changeling_sting_real",120)
|
||||
log_combat(user, target, "stung", "transformation sting", ", extending the duration.")
|
||||
else
|
||||
C.reagents.add_reagent("changeling_sting_real",120,list("desired_dna" = selected_dna.dna))
|
||||
log_combat(user, target, "stung", "transformation sting", " new identity is '[selected_dna.dna.real_name]'")
|
||||
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/false_armblade
|
||||
name = "False Armblade Sting"
|
||||
desc = "We silently sting a human, injecting a retrovirus that mutates their arm to temporarily appear as an armblade."
|
||||
helptext = "The victim will form an armblade much like a changeling would, except the armblade is dull and useless. This ability is somewhat loud, and carries a small risk of our blood gaining violent sensitivity to heat."
|
||||
sting_icon = "sting_armblade"
|
||||
chemical_cost = 20
|
||||
dna_cost = 1
|
||||
loudness = 1
|
||||
action_icon = 'icons/mob/actions/actions_changeling.dmi'
|
||||
action_icon_state = "ling_sting_fake"
|
||||
action_background_icon_state = "bg_ling"
|
||||
|
||||
/obj/item/melee/arm_blade/false
|
||||
desc = "A grotesque mass of flesh that used to be your arm. Although it looks dangerous at first, you can tell it's actually quite dull and useless."
|
||||
force = 5 //Basically as strong as a punch
|
||||
fake = TRUE
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/false_armblade/can_sting(mob/user, mob/target)
|
||||
if(!..())
|
||||
return
|
||||
if(isliving(target))
|
||||
var/mob/living/L = target
|
||||
if((HAS_TRAIT(L, TRAIT_HUSK)) || !L.has_dna())
|
||||
to_chat(user, "<span class='warning'>Our sting appears ineffective against its DNA.</span>")
|
||||
return 0
|
||||
return 1
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/false_armblade/sting_action(mob/user, mob/target)
|
||||
log_combat(user, target, "stung", object="false armblade sting")
|
||||
|
||||
var/obj/item/held = target.get_active_held_item()
|
||||
if(held && !target.dropItemToGround(held))
|
||||
to_chat(user, "<span class='warning'>[held] is stuck to [target.p_their()] hand, you cannot grow a false armblade over it!</span>")
|
||||
return
|
||||
|
||||
if(ismonkey(target))
|
||||
to_chat(user, "<span class='notice'>Our genes cry out as we sting [target.name]!</span>")
|
||||
|
||||
var/obj/item/melee/arm_blade/false/blade = new(target,1)
|
||||
target.put_in_hands(blade)
|
||||
target.visible_message("<span class='warning'>A grotesque blade forms around [target.name]\'s arm!</span>", "<span class='userdanger'>Your arm twists and mutates, transforming into a horrific monstrosity!</span>", "<span class='italics'>You hear organic matter ripping and tearing!</span>")
|
||||
playsound(target, 'sound/effects/blobattack.ogg', 30, 1)
|
||||
|
||||
addtimer(CALLBACK(src, .proc/remove_fake, target, blade), 600)
|
||||
return TRUE
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/false_armblade/proc/remove_fake(mob/target, obj/item/melee/arm_blade/false/blade)
|
||||
playsound(target, 'sound/effects/blobattack.ogg', 30, 1)
|
||||
target.visible_message("<span class='warning'>With a sickening crunch, \
|
||||
[target] reforms [target.p_their()] [blade.name] into an arm!</span>",
|
||||
"<span class='warning'>[blade] reforms back to normal.</span>",
|
||||
"<span class='italics>You hear organic matter ripping and tearing!</span>")
|
||||
|
||||
qdel(blade)
|
||||
target.update_inv_hands()
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/extract_dna
|
||||
name = "Extract DNA Sting"
|
||||
desc = "We stealthily sting a target and extract their DNA."
|
||||
helptext = "Will give you the DNA of your target, allowing you to transform into them."
|
||||
sting_icon = "sting_extract"
|
||||
chemical_cost = 25
|
||||
dna_cost = 0
|
||||
action_icon = 'icons/mob/actions/actions_changeling.dmi'
|
||||
action_icon_state = "ling_sting_extract"
|
||||
action_background_icon_state = "bg_ling"
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/extract_dna/can_sting(mob/user, mob/target)
|
||||
if(..())
|
||||
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
|
||||
return changeling.can_absorb_dna(target)
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/extract_dna/sting_action(mob/user, mob/living/carbon/human/target)
|
||||
log_combat(user, target, "stung", "extraction sting")
|
||||
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
|
||||
if(!(changeling.has_dna(target.dna)))
|
||||
changeling.add_new_profile(target)
|
||||
return TRUE
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/mute
|
||||
name = "Mute Sting"
|
||||
desc = "We silently sting a human, completely silencing them for a short time."
|
||||
helptext = "Does not provide a warning to the victim that they have been stung, until they try to speak and cannot. This ability is loud, and might cause our blood to react violently to heat."
|
||||
sting_icon = "sting_mute"
|
||||
chemical_cost = 20
|
||||
dna_cost = 2
|
||||
loudness = 2
|
||||
action_icon = 'icons/mob/actions/actions_changeling.dmi'
|
||||
action_icon_state = "ling_sting_mute"
|
||||
action_background_icon_state = "bg_ling"
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/mute/sting_action(mob/user, mob/living/carbon/target)
|
||||
log_combat(user, target, "stung", "mute sting")
|
||||
target.silent += 30
|
||||
return TRUE
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/blind
|
||||
name = "Blind Sting"
|
||||
desc = "Temporarily blinds the target."
|
||||
helptext = "This sting completely blinds a target for a short time. This ability is somewhat loud, and carries a small risk of our blood gaining violent sensitivity to heat."
|
||||
sting_icon = "sting_blind"
|
||||
chemical_cost = 25
|
||||
dna_cost = 1
|
||||
loudness = 1
|
||||
action_icon = 'icons/mob/actions/actions_changeling.dmi'
|
||||
action_icon_state = "ling_sting_blind"
|
||||
action_background_icon_state = "bg_ling"
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/blind/sting_action(mob/user, mob/living/carbon/target)
|
||||
log_combat(user, target, "stung", "blind sting")
|
||||
to_chat(target, "<span class='danger'>Your eyes burn horrifically!</span>")
|
||||
target.become_nearsighted(EYE_DAMAGE)
|
||||
target.blind_eyes(20)
|
||||
target.blur_eyes(40)
|
||||
return TRUE
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/LSD
|
||||
name = "Hallucination Sting"
|
||||
desc = "Causes terror in the target and deals a minor amount of toxin damage."
|
||||
helptext = "We evolve the ability to sting a target with a powerful toxic hallucinogenic chemical. The target does not notice they have been stung, and the effect begins instantaneously. This ability is somewhat loud, and carries a small risk of our blood gaining violent sensitivity to heat."
|
||||
sting_icon = "sting_lsd"
|
||||
chemical_cost = 10
|
||||
dna_cost = 1
|
||||
loudness = 1
|
||||
action_icon = 'icons/mob/actions/actions_changeling.dmi'
|
||||
action_icon_state = "ling_sting_lsd"
|
||||
action_background_icon_state = "bg_ling"
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/LSD/sting_action(mob/user, mob/target)
|
||||
log_combat(user, target, "stung", "LSD sting")
|
||||
if(target.reagents)
|
||||
target.reagents.add_reagent("regenerative_materia", 5)
|
||||
target.reagents.add_reagent("mindbreaker", 5)
|
||||
return TRUE
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/cryo
|
||||
name = "Cryogenic Sting"
|
||||
desc = "We silently sting a human with a cocktail of chemicals that freeze them."
|
||||
helptext = "Does not provide a warning to the victim, though they will likely realize they are suddenly freezing. This ability is somewhat loud, and carries a small risk of our blood gaining violent sensitivity to heat."
|
||||
sting_icon = "sting_cryo"
|
||||
chemical_cost = 15
|
||||
dna_cost = 2
|
||||
loudness = 1
|
||||
action_icon = 'icons/mob/actions/actions_changeling.dmi'
|
||||
action_icon_state = "ling_sting_cryo"
|
||||
action_background_icon_state = "bg_ling"
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/cryo/sting_action(mob/user, mob/target)
|
||||
log_combat(user, target, "stung", "cryo sting")
|
||||
if(target.reagents)
|
||||
target.reagents.add_reagent("frostoil", 30)
|
||||
return TRUE
|
||||
/obj/effect/proc_holder/changeling/sting
|
||||
name = "Tiny Prick"
|
||||
desc = "Stabby stabby."
|
||||
var/sting_icon = null
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/Click()
|
||||
var/mob/user = usr
|
||||
if(!user || !user.mind)
|
||||
return
|
||||
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
|
||||
if(!changeling)
|
||||
return
|
||||
if(!changeling.chosen_sting)
|
||||
set_sting(user)
|
||||
else
|
||||
unset_sting(user)
|
||||
return
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/proc/set_sting(mob/user)
|
||||
to_chat(user, "<span class='notice'>We prepare our sting, use alt+click or middle mouse button on target to sting them.</span>")
|
||||
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
|
||||
changeling.chosen_sting = src
|
||||
|
||||
user.hud_used.lingstingdisplay.icon_state = sting_icon
|
||||
user.hud_used.lingstingdisplay.invisibility = 0
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/proc/unset_sting(mob/user)
|
||||
to_chat(user, "<span class='warning'>We retract our sting, we can't sting anyone for now.</span>")
|
||||
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
|
||||
changeling.chosen_sting = null
|
||||
|
||||
user.hud_used.lingstingdisplay.icon_state = null
|
||||
user.hud_used.lingstingdisplay.invisibility = INVISIBILITY_ABSTRACT
|
||||
|
||||
/mob/living/carbon/proc/unset_sting()
|
||||
if(mind)
|
||||
var/datum/antagonist/changeling/changeling = mind.has_antag_datum(/datum/antagonist/changeling)
|
||||
if(changeling && changeling.chosen_sting)
|
||||
changeling.chosen_sting.unset_sting(src)
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/can_sting(mob/user, mob/target)
|
||||
if(!..())
|
||||
return
|
||||
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
|
||||
if(!changeling.chosen_sting)
|
||||
to_chat(user, "We haven't prepared our sting yet!")
|
||||
if(!iscarbon(target))
|
||||
return
|
||||
if(!isturf(user.loc))
|
||||
return
|
||||
if(!AStar(user, target.loc, /turf/proc/Distance, changeling.sting_range, simulated_only = 0))
|
||||
return
|
||||
return 1
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/sting_feedback(mob/user, mob/target)
|
||||
if(!target)
|
||||
return
|
||||
to_chat(user, "<span class='notice'>We stealthily sting [target.name].</span>")
|
||||
if(target.mind && target.mind.has_antag_datum(/datum/antagonist/changeling))
|
||||
to_chat(target, "<span class='warning'>You feel a tiny prick.</span>")
|
||||
return 1
|
||||
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/transformation
|
||||
name = "Temporary Transformation Sting"
|
||||
desc = "We silently sting a human, injecting a chemical that forces them to transform into a chosen being for a limited time. Additional stings extend the duration."
|
||||
helptext = "The victim will transform much like a changeling would for a limited time. Does not provide a warning to others. Mutations will not be transferred, and monkeys will become human. This ability is loud, and might cause our blood to react violently to heat."
|
||||
sting_icon = "sting_transform"
|
||||
chemical_cost = 10
|
||||
dna_cost = 2
|
||||
loudness = 1
|
||||
var/datum/changelingprofile/selected_dna = null
|
||||
action_icon = 'icons/mob/actions/actions_changeling.dmi'
|
||||
action_icon_state = "ling_sting_transform"
|
||||
action_background_icon_state = "bg_ling"
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/transformation/Click()
|
||||
var/mob/user = usr
|
||||
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
|
||||
if(changeling.chosen_sting)
|
||||
unset_sting(user)
|
||||
return
|
||||
selected_dna = changeling.select_dna("Select the target DNA: ", "Target DNA")
|
||||
if(!selected_dna)
|
||||
return
|
||||
if(NOTRANSSTING in selected_dna.dna.species.species_traits)
|
||||
to_chat(user, "<span class = 'notice'>That DNA is not compatible with changeling retrovirus!</span>")
|
||||
return
|
||||
..()
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/transformation/can_sting(mob/user, mob/living/carbon/target)
|
||||
if(!..())
|
||||
return
|
||||
if((HAS_TRAIT(target, TRAIT_HUSK)) || !iscarbon(target) || (NOTRANSSTING in target.dna.species.species_traits))
|
||||
to_chat(user, "<span class='warning'>Our sting appears ineffective against its DNA.</span>")
|
||||
return 0
|
||||
return 1
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/transformation/sting_action(mob/user, mob/target)
|
||||
|
||||
if(ismonkey(target))
|
||||
to_chat(user, "<span class='notice'>Our genes cry out as we sting [target.name]!</span>")
|
||||
|
||||
var/mob/living/carbon/C = target
|
||||
. = TRUE
|
||||
if(istype(C))
|
||||
if(C.reagents.has_reagent(/datum/reagent/changeling_string))
|
||||
C.reagents.add_reagent(/datum/reagent/changeling_string,120)
|
||||
log_combat(user, target, "stung", "transformation sting", ", extending the duration.")
|
||||
else
|
||||
C.reagents.add_reagent(/datum/reagent/changeling_string,120,list("desired_dna" = selected_dna.dna))
|
||||
log_combat(user, target, "stung", "transformation sting", " new identity is '[selected_dna.dna.real_name]'")
|
||||
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/false_armblade
|
||||
name = "False Armblade Sting"
|
||||
desc = "We silently sting a human, injecting a retrovirus that mutates their arm to temporarily appear as an armblade."
|
||||
helptext = "The victim will form an armblade much like a changeling would, except the armblade is dull and useless. This ability is somewhat loud, and carries a small risk of our blood gaining violent sensitivity to heat."
|
||||
sting_icon = "sting_armblade"
|
||||
chemical_cost = 20
|
||||
dna_cost = 1
|
||||
loudness = 1
|
||||
action_icon = 'icons/mob/actions/actions_changeling.dmi'
|
||||
action_icon_state = "ling_sting_fake"
|
||||
action_background_icon_state = "bg_ling"
|
||||
|
||||
/obj/item/melee/arm_blade/false
|
||||
desc = "A grotesque mass of flesh that used to be your arm. Although it looks dangerous at first, you can tell it's actually quite dull and useless."
|
||||
force = 5 //Basically as strong as a punch
|
||||
fake = TRUE
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/false_armblade/can_sting(mob/user, mob/target)
|
||||
if(!..())
|
||||
return
|
||||
if(isliving(target))
|
||||
var/mob/living/L = target
|
||||
if((HAS_TRAIT(L, TRAIT_HUSK)) || !L.has_dna())
|
||||
to_chat(user, "<span class='warning'>Our sting appears ineffective against its DNA.</span>")
|
||||
return 0
|
||||
return 1
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/false_armblade/sting_action(mob/user, mob/target)
|
||||
log_combat(user, target, "stung", object="false armblade sting")
|
||||
|
||||
var/obj/item/held = target.get_active_held_item()
|
||||
if(held && !target.dropItemToGround(held))
|
||||
to_chat(user, "<span class='warning'>[held] is stuck to [target.p_their()] hand, you cannot grow a false armblade over it!</span>")
|
||||
return
|
||||
|
||||
if(ismonkey(target))
|
||||
to_chat(user, "<span class='notice'>Our genes cry out as we sting [target.name]!</span>")
|
||||
|
||||
var/obj/item/melee/arm_blade/false/blade = new(target,1)
|
||||
target.put_in_hands(blade)
|
||||
target.visible_message("<span class='warning'>A grotesque blade forms around [target.name]\'s arm!</span>", "<span class='userdanger'>Your arm twists and mutates, transforming into a horrific monstrosity!</span>", "<span class='italics'>You hear organic matter ripping and tearing!</span>")
|
||||
playsound(target, 'sound/effects/blobattack.ogg', 30, 1)
|
||||
|
||||
addtimer(CALLBACK(src, .proc/remove_fake, target, blade), 600)
|
||||
return TRUE
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/false_armblade/proc/remove_fake(mob/target, obj/item/melee/arm_blade/false/blade)
|
||||
playsound(target, 'sound/effects/blobattack.ogg', 30, 1)
|
||||
target.visible_message("<span class='warning'>With a sickening crunch, \
|
||||
[target] reforms [target.p_their()] [blade.name] into an arm!</span>",
|
||||
"<span class='warning'>[blade] reforms back to normal.</span>",
|
||||
"<span class='italics>You hear organic matter ripping and tearing!</span>")
|
||||
|
||||
qdel(blade)
|
||||
target.update_inv_hands()
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/extract_dna
|
||||
name = "Extract DNA Sting"
|
||||
desc = "We stealthily sting a target and extract their DNA."
|
||||
helptext = "Will give you the DNA of your target, allowing you to transform into them."
|
||||
sting_icon = "sting_extract"
|
||||
chemical_cost = 25
|
||||
dna_cost = 0
|
||||
action_icon = 'icons/mob/actions/actions_changeling.dmi'
|
||||
action_icon_state = "ling_sting_extract"
|
||||
action_background_icon_state = "bg_ling"
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/extract_dna/can_sting(mob/user, mob/target)
|
||||
if(..())
|
||||
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
|
||||
return changeling.can_absorb_dna(target)
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/extract_dna/sting_action(mob/user, mob/living/carbon/human/target)
|
||||
log_combat(user, target, "stung", "extraction sting")
|
||||
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
|
||||
if(!(changeling.has_dna(target.dna)))
|
||||
changeling.add_new_profile(target)
|
||||
return TRUE
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/mute
|
||||
name = "Mute Sting"
|
||||
desc = "We silently sting a human, completely silencing them for a short time."
|
||||
helptext = "Does not provide a warning to the victim that they have been stung, until they try to speak and cannot. This ability is loud, and might cause our blood to react violently to heat."
|
||||
sting_icon = "sting_mute"
|
||||
chemical_cost = 20
|
||||
dna_cost = 2
|
||||
loudness = 2
|
||||
action_icon = 'icons/mob/actions/actions_changeling.dmi'
|
||||
action_icon_state = "ling_sting_mute"
|
||||
action_background_icon_state = "bg_ling"
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/mute/sting_action(mob/user, mob/living/carbon/target)
|
||||
log_combat(user, target, "stung", "mute sting")
|
||||
target.silent += 30
|
||||
return TRUE
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/blind
|
||||
name = "Blind Sting"
|
||||
desc = "Temporarily blinds the target."
|
||||
helptext = "This sting completely blinds a target for a short time. This ability is somewhat loud, and carries a small risk of our blood gaining violent sensitivity to heat."
|
||||
sting_icon = "sting_blind"
|
||||
chemical_cost = 25
|
||||
dna_cost = 1
|
||||
loudness = 1
|
||||
action_icon = 'icons/mob/actions/actions_changeling.dmi'
|
||||
action_icon_state = "ling_sting_blind"
|
||||
action_background_icon_state = "bg_ling"
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/blind/sting_action(mob/user, mob/living/carbon/target)
|
||||
log_combat(user, target, "stung", "blind sting")
|
||||
to_chat(target, "<span class='danger'>Your eyes burn horrifically!</span>")
|
||||
target.become_nearsighted(EYE_DAMAGE)
|
||||
target.blind_eyes(20)
|
||||
target.blur_eyes(40)
|
||||
return TRUE
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/LSD
|
||||
name = "Hallucination Sting"
|
||||
desc = "Causes terror in the target and deals a minor amount of toxin damage."
|
||||
helptext = "We evolve the ability to sting a target with a powerful toxic hallucinogenic chemical. The target does not notice they have been stung, and the effect begins instantaneously. This ability is somewhat loud, and carries a small risk of our blood gaining violent sensitivity to heat."
|
||||
sting_icon = "sting_lsd"
|
||||
chemical_cost = 10
|
||||
dna_cost = 1
|
||||
loudness = 1
|
||||
action_icon = 'icons/mob/actions/actions_changeling.dmi'
|
||||
action_icon_state = "ling_sting_lsd"
|
||||
action_background_icon_state = "bg_ling"
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/LSD/sting_action(mob/user, mob/target)
|
||||
log_combat(user, target, "stung", "LSD sting")
|
||||
if(target.reagents)
|
||||
target.reagents.add_reagent(/datum/reagent/blob/regenerative_materia, 5)
|
||||
target.reagents.add_reagent(/datum/reagent/toxin/mindbreaker, 5)
|
||||
return TRUE
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/cryo
|
||||
name = "Cryogenic Sting"
|
||||
desc = "We silently sting a human with a cocktail of chemicals that freeze them."
|
||||
helptext = "Does not provide a warning to the victim, though they will likely realize they are suddenly freezing. This ability is somewhat loud, and carries a small risk of our blood gaining violent sensitivity to heat."
|
||||
sting_icon = "sting_cryo"
|
||||
chemical_cost = 15
|
||||
dna_cost = 2
|
||||
loudness = 1
|
||||
action_icon = 'icons/mob/actions/actions_changeling.dmi'
|
||||
action_icon_state = "ling_sting_cryo"
|
||||
action_background_icon_state = "bg_ling"
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/cryo/sting_action(mob/user, mob/target)
|
||||
log_combat(user, target, "stung", "cryo sting")
|
||||
if(target.reagents)
|
||||
target.reagents.add_reagent(/datum/reagent/consumable/frostoil, 30)
|
||||
return TRUE
|
||||
|
||||
@@ -77,13 +77,16 @@
|
||||
for(var/mob/living/M in viewers(5, src))
|
||||
if(!is_servant_of_ratvar(M) && M != L)
|
||||
M.flash_act()
|
||||
if(iscultist(L))
|
||||
if(iscultist(L)) //No longer stuns cultists, instead sets them on fire and burns them
|
||||
to_chat(L, "<span class='heavy_brass'>\"Watch your step, wretch.\"</span>")
|
||||
L.adjustBruteLoss(10)
|
||||
L.Knockdown(80, FALSE)
|
||||
L.adjustFireLoss(10)
|
||||
L.Knockdown(20, FALSE)
|
||||
L.adjust_fire_stacks(5) //Burn!
|
||||
L.IgniteMob()
|
||||
else
|
||||
L.Stun(40)
|
||||
L.visible_message("<span class='warning'>[src] appears around [L] in a burst of light!</span>", \
|
||||
"<span class='userdanger'>[target_flashed ? "An unseen force":"The glowing sigil around you"] holds you in place!</span>")
|
||||
L.Stun(40)
|
||||
"<span class='userdanger'>[target_flashed ? "An unseen force":"The glowing sigil around you"] [iscultist(L) ? "painfully bursts into flames!" : "holds you in place!"]</span>")
|
||||
L.apply_status_effect(STATUS_EFFECT_BELLIGERENT)
|
||||
new /obj/effect/temp_visual/ratvar/sigil/transgression(get_turf(src))
|
||||
qdel(src)
|
||||
|
||||
@@ -345,3 +345,8 @@
|
||||
if(!power_amount)
|
||||
power_amount = -(CLOCKCULT_POWER_UNIT*0.02)
|
||||
return ..()
|
||||
|
||||
|
||||
// Winter coat
|
||||
/obj/item/clothing/suit/hooded/wintercoat/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent) //four sheets of metal
|
||||
return list("operation_time" = 30, "new_obj_type" = /obj/item/clothing/suit/hooded/wintercoat/ratvar, "power_cost" = POWER_METAL * 4, "spawn_dir" = SOUTH)
|
||||
|
||||
@@ -100,7 +100,7 @@
|
||||
var/burndamage = L.getFireLoss()
|
||||
var/oxydamage = L.getOxyLoss()
|
||||
var/totaldamage = brutedamage + burndamage + oxydamage
|
||||
if(!totaldamage && (!L.reagents || !L.reagents.has_reagent("holywater")))
|
||||
if(!totaldamage && (!L.reagents || !L.reagents.has_reagent(/datum/reagent/water/holywater)))
|
||||
to_chat(ranged_ability_user, "<span class='inathneq'>\"[L] is unhurt and untainted.\"</span>")
|
||||
return TRUE
|
||||
|
||||
@@ -108,7 +108,7 @@
|
||||
|
||||
to_chat(ranged_ability_user, "<span class='brass'>You bathe [L == ranged_ability_user ? "yourself":"[L]"] in Inath-neq's power!</span>")
|
||||
var/targetturf = get_turf(L)
|
||||
var/has_holy_water = (L.reagents && L.reagents.has_reagent("holywater"))
|
||||
var/has_holy_water = (L.reagents && L.reagents.has_reagent(/datum/reagent/water/holywater))
|
||||
var/healseverity = max(round(totaldamage*0.05, 1), 1) //shows the general severity of the damage you just healed, 1 glow per 20
|
||||
for(var/i in 1 to healseverity)
|
||||
new /obj/effect/temp_visual/heal(targetturf, "#1E8CE1")
|
||||
@@ -129,7 +129,7 @@
|
||||
playsound(targetturf, 'sound/magic/staff_healing.ogg', 50, 1)
|
||||
|
||||
if(has_holy_water)
|
||||
L.reagents.remove_reagent("holywater", 1000)
|
||||
L.reagents.del_reagent(/datum/reagent/water/holywater)
|
||||
|
||||
remove_ranged_ability()
|
||||
|
||||
@@ -193,15 +193,26 @@
|
||||
L.visible_message("<span class='warning'>[L]'s eyes flare with dim light!</span>")
|
||||
playsound(L, 'sound/weapons/sear.ogg', 50, TRUE)
|
||||
else
|
||||
L.visible_message("<span class='warning'>[L]'s eyes blaze with brilliant light!</span>", \
|
||||
"<span class='userdanger'>Your vision suddenly screams with white-hot light!</span>")
|
||||
L.Knockdown(15, TRUE, FALSE, 15)
|
||||
L.apply_status_effect(STATUS_EFFECT_KINDLE)
|
||||
L.flash_act(1, 1)
|
||||
if(issilicon(target))
|
||||
var/mob/living/silicon/S = L
|
||||
S.emp_act(EMP_HEAVY)
|
||||
if(iscultist(L))
|
||||
if(!iscultist(L))
|
||||
L.visible_message("<span class='warning'>[L]'s eyes blaze with brilliant light!</span>", \
|
||||
"<span class='userdanger'>Your vision suddenly screams with white-hot light!</span>")
|
||||
L.Knockdown(15, TRUE, FALSE, 15)
|
||||
L.apply_status_effect(STATUS_EFFECT_KINDLE)
|
||||
L.flash_act(1, 1)
|
||||
if(issilicon(target))
|
||||
var/mob/living/silicon/S = L
|
||||
S.emp_act(EMP_HEAVY)
|
||||
else //for Nar'sian weaklings
|
||||
to_chat(L, "<span class='heavy_brass'>\"How does it feel to see the light, dog?\"</span>")
|
||||
L.visible_message("<span class='warning'>[L]'s eyes flare with burning light!</span>", \
|
||||
"<span class='userdanger'>Your vision suddenly screams with a flash of burning hot light!</span>") //Debuffs Narsian cultists hard + deals some burn instead of just hardstunning them; Only the confusion part can stack
|
||||
L.flash_act(1,1)
|
||||
if(iscarbon(target))
|
||||
var/mob/living/carbon/C = L
|
||||
C.stuttering = max(8, C.stuttering)
|
||||
C.drowsyness = max(8, C.drowsyness)
|
||||
C.confused += CLAMP(16 - C.confused, 0, 8)
|
||||
C.apply_status_effect(STATUS_EFFECT_BELLIGERENT)
|
||||
L.adjustFireLoss(15)
|
||||
..()
|
||||
|
||||
|
||||
@@ -56,8 +56,14 @@
|
||||
L.visible_message("<span class='warning'>[src] bounces off of [L], as if repelled by an unseen force!</span>")
|
||||
else if(!..())
|
||||
if(!L.anti_magic_check())
|
||||
if(issilicon(L) || iscultist(L))
|
||||
if(issilicon(L))
|
||||
L.Knockdown(100)
|
||||
else if(iscultist(L))
|
||||
L.confused += CLAMP(10 - L.confused, 0, 5) // Spearthrow now confuses enemy cultists + just deals extra damage / sets on fire instead of hardstunning + damage
|
||||
to_chat(L, "<span class ='userdanger'>[src] crashes into you with burning force, sending you reeling!</span>")
|
||||
L.adjust_fire_stacks(2)
|
||||
L.Knockdown(1)
|
||||
L.IgniteMob()
|
||||
else
|
||||
L.Knockdown(40)
|
||||
GLOB.clockwork_vitality += L.adjustFireLoss(bonus_burn * 3) //normally a total of 40 damage, 70 with ratvar
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
resistance_flags = FIRE_PROOF | ACID_PROOF
|
||||
flags_inv = HIDEEARS|HIDEHAIR|HIDEFACE|HIDESNOUT
|
||||
mutantrace_variation = MUTANTRACE_VARIATION
|
||||
mutantrace_variation = STYLE_MUZZLE
|
||||
armor = list("melee" = 50, "bullet" = 70, "laser" = -25, "energy" = 0, "bomb" = 60, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100)
|
||||
|
||||
/obj/item/clothing/head/helmet/clockwork/Initialize()
|
||||
|
||||
@@ -103,7 +103,7 @@
|
||||
. = ..()
|
||||
addtimer(CALLBACK(src, .proc/check_on_mob, user), 1) //dropped is called before the item is out of the slot, so we need to check slightly later
|
||||
|
||||
/obj/item/clockwork/slab/worn_overlays(isinhands = FALSE, icon_file)
|
||||
/obj/item/clockwork/slab/worn_overlays(isinhands = FALSE, icon_file, style_flags = NONE)
|
||||
. = list()
|
||||
if(isinhands && item_state && inhand_overlay)
|
||||
var/mutable_appearance/M = mutable_appearance(icon_file, "slab_[inhand_overlay]")
|
||||
@@ -162,9 +162,11 @@
|
||||
access_display(user)
|
||||
|
||||
/obj/item/clockwork/slab/AltClick(mob/living/user)
|
||||
. = ..()
|
||||
if(is_servant_of_ratvar(user) && linking && user.canUseTopic(src, BE_CLOSE, ismonkey(user)))
|
||||
linking = null
|
||||
to_chat(user, "<span class='notice'>Object link canceled.</span>")
|
||||
return TRUE
|
||||
|
||||
/obj/item/clockwork/slab/proc/access_display(mob/living/user)
|
||||
if(!is_servant_of_ratvar(user))
|
||||
|
||||
@@ -139,7 +139,7 @@
|
||||
var/new_thing_type = fabrication_values["new_obj_type"]
|
||||
if(isturf(target)) //if our target is a turf, we're just going to ChangeTurf it and assume it'll work out.
|
||||
var/turf/T = target
|
||||
T.ChangeTurf(new_thing_type)
|
||||
T.ChangeTurf(new_thing_type, flags = CHANGETURF_INHERIT_AIR)
|
||||
else
|
||||
if(new_thing_type)
|
||||
if(fabrication_values["dir_in_new"])
|
||||
|
||||
@@ -48,10 +48,11 @@
|
||||
|
||||
/obj/item/clothing/glasses/wraith_spectacles/proc/blind_cultist(mob/living/victim)
|
||||
if(iscultist(victim))
|
||||
var/obj/item/organ/eyes/eyes = victim.getorganslot(ORGAN_SLOT_EYES)
|
||||
to_chat(victim, "<span class='heavy_brass'>\"It looks like Nar'Sie's dogs really don't value their eyes.\"</span>")
|
||||
to_chat(victim, "<span class='userdanger'>Your eyes explode with horrific pain!</span>")
|
||||
victim.emote("scream")
|
||||
victim.become_blind(EYE_DAMAGE)
|
||||
eyes?.applyOrganDamage(eyes.maxHealth)
|
||||
victim.adjust_blurriness(30)
|
||||
victim.adjust_blindness(30)
|
||||
return TRUE
|
||||
@@ -141,21 +142,23 @@
|
||||
if(glasses_right && !WS.up && !GLOB.ratvar_awakens && !GLOB.ratvar_approaches)
|
||||
apply_eye_damage(H)
|
||||
else
|
||||
var/obj/item/organ/eyes/eyes = H.getorganslot(ORGAN_SLOT_EYES)
|
||||
if(GLOB.ratvar_awakens)
|
||||
H.cure_nearsighted(list(EYE_DAMAGE))
|
||||
H.cure_blind(list(EYE_DAMAGE))
|
||||
H.adjust_eye_damage(-eye_damage_done)
|
||||
eyes?.applyOrganDamage(-eye_damage_done)
|
||||
eye_damage_done = 0
|
||||
else if(prob(50) && eye_damage_done)
|
||||
H.adjust_eye_damage(-1)
|
||||
eyes?.applyOrganDamage(-1)
|
||||
eye_damage_done = max(0, eye_damage_done - 1)
|
||||
if(!eye_damage_done)
|
||||
qdel(src)
|
||||
|
||||
/datum/status_effect/wraith_spectacles/proc/apply_eye_damage(mob/living/carbon/human/H)
|
||||
if(HAS_TRAIT(H, TRAIT_BLIND))
|
||||
var/obj/item/organ/eyes/eyes = H.getorganslot(ORGAN_SLOT_EYES)
|
||||
if(HAS_TRAIT(H, TRAIT_BLIND) || !eyes)
|
||||
return
|
||||
H.adjust_eye_damage(0.5)
|
||||
eyes.applyOrganDamage(0.5)
|
||||
eye_damage_done += 0.5
|
||||
if(eye_damage_done >= 20)
|
||||
H.adjust_blurriness(2)
|
||||
@@ -166,7 +169,7 @@
|
||||
if(eye_damage_done >= blind_breakpoint)
|
||||
if(!HAS_TRAIT(H, TRAIT_BLIND))
|
||||
to_chat(H, "<span class='nzcrentr_large'>A piercing white light floods your vision. Suddenly, all goes dark!</span>")
|
||||
H.become_blind(EYE_DAMAGE)
|
||||
eyes.applyOrganDamage(eyes.maxHealth)
|
||||
|
||||
if(prob(min(20, 5 + eye_damage_done)))
|
||||
to_chat(H, "<span class='nzcrentr_small'><i>Your eyes continue to burn.</i></span>")
|
||||
|
||||
@@ -98,7 +98,7 @@
|
||||
else
|
||||
to_chat(M, message)
|
||||
|
||||
/mob/camera/eminence/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode)
|
||||
/mob/camera/eminence/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode, atom/movable/source)
|
||||
. = ..()
|
||||
if(is_reebe(z) || is_servant_of_ratvar(speaker) || GLOB.ratvar_approaches || GLOB.ratvar_awakens) //Away from Reebe, the Eminence can't hear anything
|
||||
to_chat(src, message)
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#define MARAUDER_SLOWDOWN_PERCENTAGE 0.40 //Below this percentage of health, marauders will become slower
|
||||
#define MARAUDER_SHIELD_REGEN_TIME 200 //In deciseconds, how long it takes for shields to regenerate after breaking
|
||||
#define MARAUDER_SPACE_FULL_DAMAGE 6 //amount of damage per life tick while inside space
|
||||
#define MARAUDER_SPACE_NEAR_DAMAGE 4 //amount of damage taking per Life() tick from being next to space.
|
||||
|
||||
//Clockwork marauder: A well-rounded frontline construct. Only one can exist for every two human servants.
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder
|
||||
@@ -20,12 +22,14 @@
|
||||
movement_type = FLYING
|
||||
a_intent = INTENT_HARM
|
||||
loot = list(/obj/item/clockwork/component/geis_capacitor/fallen_armor)
|
||||
light_range = 2
|
||||
light_power = 1.1
|
||||
light_range = 3
|
||||
light_power = 1.7
|
||||
playstyle_string = "<span class='big bold'><span class='neovgre'>You are a clockwork marauder,</span></span><b> a well-rounded frontline construct of Ratvar. Although you have no \
|
||||
unique abilities, you're a fearsome fighter in one-on-one combat, and your shield protects from projectiles!<br><br>Obey the Servants and do as they \
|
||||
tell you. Your primary goal is to defend the Ark from destruction; they are your allies in this, and should be protected from harm.</b>"
|
||||
tell you. Your primary goal is to defend the Ark from destruction; they are your allies in this, and should be protected from harm.</b> \
|
||||
<span class='danger big'>Be warned, however, that you will rapidly decay near the void of space.</span>"
|
||||
empower_string = "<span class='neovgre'>The Anima Bulwark's power flows through you! Your weapon will strike harder, your armor is sturdier, and your shield is more durable.</span>"
|
||||
var/default_speed = 0
|
||||
var/max_shield_health = 3
|
||||
var/shield_health = 3 //Amount of projectiles that can be deflected within
|
||||
var/shield_health_regen = 0 //When world.time equals this, shield health will regenerate
|
||||
@@ -36,10 +40,21 @@
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/Life()
|
||||
..()
|
||||
var/turf/T = get_turf(src)
|
||||
var/turf/open/space/S = isspaceturf(T)? T : null
|
||||
var/less_space_damage
|
||||
if(!istype(S))
|
||||
var/turf/open/space/nearS = locate() in oview(1)
|
||||
if(nearS)
|
||||
S = nearS
|
||||
less_space_damage = TRUE
|
||||
if(S)
|
||||
to_chat(src, "<span class='userdanger'>The void of space drains Ratvar's Light from you! You feel yourself rapidly decaying. It would be wise to get back inside!</span>")
|
||||
adjustBruteLoss(less_space_damage? MARAUDER_SPACE_NEAR_DAMAGE : MARAUDER_SPACE_FULL_DAMAGE)
|
||||
if(!GLOB.ratvar_awakens && health / maxHealth <= MARAUDER_SLOWDOWN_PERCENTAGE)
|
||||
speed = initial(speed) + 1 //Yes, this slows them down
|
||||
speed = default_speed + 1 //Yes, this slows them down
|
||||
else
|
||||
speed = initial(speed)
|
||||
speed = default_speed
|
||||
if(shield_health < max_shield_health && world.time >= shield_health_regen)
|
||||
shield_health_regen = world.time + MARAUDER_SHIELD_REGEN_TIME
|
||||
to_chat(src, "<span class='neovgre'>Your shield has recovered, <b>[shield_health]</b> blocks remaining!</span>")
|
||||
|
||||
@@ -87,9 +87,22 @@
|
||||
object_path = /obj/item/clockwork/construct_chassis/clockwork_marauder
|
||||
construct_type = /mob/living/simple_animal/hostile/clockwork/marauder
|
||||
combat_construct = TRUE
|
||||
var/static/recent_marauders = 0
|
||||
var/static/time_since_last_marauder = 0
|
||||
var/static/scaled_recital_time = 0
|
||||
var/static/last_marauder = 0
|
||||
|
||||
/datum/clockwork_scripture/create_object/construct/clockwork_marauder/post_recital()
|
||||
last_marauder = world.time
|
||||
return ..()
|
||||
|
||||
/datum/clockwork_scripture/create_object/construct/clockwork_marauder/pre_recital()
|
||||
if(!is_reebe(invoker.z))
|
||||
if(!CONFIG_GET(flag/allow_clockwork_marauder_on_station))
|
||||
to_chat(invoker, "<span class='brass'>This particular station is too far from the influence of the Hierophant Network. You can not summon a marauder here.</span>")
|
||||
return FALSE
|
||||
if(world.time < (last_marauder + CONFIG_GET(number/marauder_delay_non_reebe)))
|
||||
to_chat(invoker, "<span class='brass'>The hierophant network is still strained from the last summoning of a marauder on a plane without the strong energy connection of Reebe to support it. \
|
||||
You must wait another [DisplayTimeText((last_marauder + CONFIG_GET(number/marauder_delay_non_reebe)) - world.time, TRUE)]!</span>")
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/datum/clockwork_scripture/create_object/construct/clockwork_marauder/update_construct_limit()
|
||||
var/human_servants = 0
|
||||
@@ -98,27 +111,7 @@
|
||||
var/mob/living/L = M.current
|
||||
if(ishuman(L) && L.stat != DEAD)
|
||||
human_servants++
|
||||
construct_limit = round(CLAMP((human_servants / 4), 1, 3)) - recent_marauders //1 per 4 human servants, maximum of 3, reduced by recent marauder creation
|
||||
if(recent_marauders)
|
||||
to_chat(invoker, "<span class='warning'>The Hierophant Network is depleted by a summoning in the last [DisplayTimeText(MARAUDER_SCRIPTURE_SCALING_THRESHOLD, TRUE)] - limiting the number of available marauders by [recent_marauders]!</span>")
|
||||
|
||||
/datum/clockwork_scripture/create_object/construct/clockwork_marauder/pre_recital()
|
||||
channel_time = initial(channel_time)
|
||||
if(recent_marauders)
|
||||
scaled_recital_time = min(recent_marauders * MARAUDER_SCRIPTURE_SCALING_TIME, MARAUDER_SCRIPTURE_SCALING_MAX)
|
||||
to_chat(invoker, "<span class='warning'>The Hierophant Network is under strain from repeated summoning, making this scripture [DisplayTimeText(scaled_recital_time)] slower!</span>")
|
||||
channel_time += scaled_recital_time
|
||||
return TRUE
|
||||
|
||||
/datum/clockwork_scripture/create_object/construct/clockwork_marauder/scripture_effects()
|
||||
. = ..()
|
||||
recent_marauders++
|
||||
addtimer(CALLBACK(GLOBAL_PROC, .proc/marauder_reset),MARAUDER_SCRIPTURE_SCALING_THRESHOLD)
|
||||
|
||||
/proc/marauder_reset()
|
||||
var/datum/clockwork_scripture/create_object/construct/clockwork_marauder/CM = new()
|
||||
CM.recent_marauders--
|
||||
qdel(CM)
|
||||
construct_limit = round(CLAMP((human_servants / 4), 1, 3)) //1 per 4 human servants, maximum of 3
|
||||
|
||||
//Summon Neovgre: Summon a very powerful combat mech that explodes when destroyed for massive damage.
|
||||
/datum/clockwork_scripture/create_object/summon_arbiter
|
||||
@@ -146,6 +139,6 @@
|
||||
|
||||
/datum/clockwork_scripture/create_object/summon_arbiter/check_special_requirements()
|
||||
if(GLOB.neovgre_exists)
|
||||
to_chat(invoker, "<span class='brass'>\"You've already got one...\"</span>")
|
||||
to_chat(invoker, "<span class='nezbere'>\"Only one of my weapons may exist in this temporal stream!\"</span>")
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
if(anchored)
|
||||
T.PlaceOnTop(/turf/closed/wall/clockwork)
|
||||
else
|
||||
T.PlaceOnTop(/turf/open/floor/clockwork)
|
||||
T.PlaceOnTop(/turf/open/floor/clockwork, flags = CHANGETURF_INHERIT_AIR)
|
||||
new /obj/structure/falsewall/brass(T)
|
||||
qdel(src)
|
||||
else
|
||||
|
||||
@@ -438,21 +438,27 @@
|
||||
target.visible_message("<span class='warning'>[L] starts to glow in a halo of light!</span>", \
|
||||
"<span class='userdanger'>A feeling of warmth washes over you, rays of holy light surround your body and protect you from the flash of light!</span>")
|
||||
else
|
||||
to_chat(user, "<span class='cultitalic'>In an brilliant flash of red, [L] falls to the ground!</span>")
|
||||
L.Knockdown(160)
|
||||
L.adjustStaminaLoss(140) //Ensures hard stamcrit
|
||||
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))
|
||||
if(!iscultist(L))
|
||||
L.Knockdown(160)
|
||||
L.adjustStaminaLoss(140) //Ensures hard stamcrit
|
||||
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 += CLAMP(12 - C.silent, 0, 6)
|
||||
C.stuttering += CLAMP(30 - C.stuttering, 0, 15)
|
||||
C.cultslurring += CLAMP(30 - C.cultslurring, 0, 15)
|
||||
C.Jitter(15)
|
||||
else // cultstun no longer hardstuns + damages hostile cultists, instead debuffs them hard + deals some damage; debuffs for a bit longer since they don't add the clockie belligerent debuff
|
||||
if(iscarbon(target))
|
||||
var/mob/living/carbon/C = L
|
||||
C.stuttering = max(10, C.stuttering)
|
||||
C.drowsyness = max(10, C.drowsyness)
|
||||
C.confused += CLAMP(20 - C.confused, 0, 10)
|
||||
L.adjustBruteLoss(15)
|
||||
to_chat(user, "<span class='cultitalic'>In an brilliant flash of red, [L] [iscultist(L) ? "writhes in pain" : "falls to the ground!"]</span>")
|
||||
uses--
|
||||
..()
|
||||
|
||||
@@ -579,6 +585,12 @@
|
||||
new /obj/item/stack/sheet/runed_metal(T,quantity)
|
||||
to_chat(user, "<span class='warning'>A dark cloud emanates 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))
|
||||
if(istype(target, /obj/item/clothing/suit/hooded/wintercoat) && target.type != /obj/item/clothing/suit/hooded/wintercoat/narsie)
|
||||
if (do_after(user,30,target=target))
|
||||
new /obj/item/clothing/suit/hooded/wintercoat/narsie(T)
|
||||
qdel(target)
|
||||
to_chat(user, "<span class='warning'>A dark cloud emanates from you hand and swirls around [target], transforming it into a narsian winter coat!</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)
|
||||
|
||||
@@ -128,7 +128,8 @@
|
||||
current.clear_alert("bloodsense")
|
||||
if(ishuman(current))
|
||||
var/mob/living/carbon/human/H = current
|
||||
H.eye_color = initial(H.eye_color)
|
||||
var/obj/item/organ/eyes/eyes = H.getorganslot(ORGAN_SLOT_EYES)
|
||||
H.eye_color = eyes?.eye_color || initial(H.eye_color)
|
||||
H.dna.update_ui_block(DNA_EYE_COLOR_BLOCK)
|
||||
REMOVE_TRAIT(H, TRAIT_CULT_EYES, "valid_cultist")
|
||||
H.update_body()
|
||||
|
||||
@@ -331,7 +331,7 @@
|
||||
flags_inv = HIDEFACE|HIDEHAIR|HIDEFACIALHAIR|HIDEEARS|HIDEEYES|HIDESNOUT
|
||||
armor = list("melee" = 30, "bullet" = 30, "laser" = 30,"energy" = 20, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 10, "acid" = 10)
|
||||
flags_cover = HEADCOVERSEYES | HEADCOVERSMOUTH
|
||||
mutantrace_variation = MUTANTRACE_VARIATION
|
||||
mutantrace_variation = STYLE_MUZZLE
|
||||
|
||||
/obj/item/clothing/suit/magusred
|
||||
name = "magus robes"
|
||||
@@ -424,7 +424,7 @@
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/obj/item/clothing/suit/hooded/cultrobes/cult_shield/worn_overlays(isinhands)
|
||||
/obj/item/clothing/suit/hooded/cultrobes/cult_shield/worn_overlays(isinhands, icon_file, style_flags = NONE)
|
||||
. = list()
|
||||
if(!isinhands && current_charges)
|
||||
. += mutable_appearance('icons/effects/cult_effects.dmi', "shield-cult", MOB_LAYER + 0.01)
|
||||
@@ -487,7 +487,7 @@
|
||||
icon = 'icons/obj/drinks.dmi'
|
||||
icon_state = "holyflask"
|
||||
color = "#333333"
|
||||
list_reagents = list("unholywater" = 50)
|
||||
list_reagents = list(/datum/reagent/fuel/unholywater = 50)
|
||||
|
||||
/obj/item/shuttle_curse
|
||||
name = "cursed orb"
|
||||
@@ -703,7 +703,10 @@
|
||||
else if(!..())
|
||||
if(!L.anti_magic_check())
|
||||
if(is_servant_of_ratvar(L))
|
||||
L.Knockdown(100)
|
||||
to_chat(L, "<span class='cultlarge'>\"Kneel for me, scum\"</span>")
|
||||
L.confused += CLAMP(10 - L.confused, 0, 5) //confuses and lightly knockdowns + damages hostile cultists instead of hardstunning like before
|
||||
L.Knockdown(15)
|
||||
L.adjustBruteLoss(10)
|
||||
else
|
||||
L.Knockdown(50)
|
||||
break_spear(T)
|
||||
@@ -794,7 +797,7 @@
|
||||
if(ishuman(target))
|
||||
var/mob/living/carbon/human/H = target
|
||||
if(H.stat != DEAD)
|
||||
H.reagents.add_reagent("unholywater", 4)
|
||||
H.reagents.add_reagent(/datum/reagent/fuel/unholywater, 4)
|
||||
if(isshade(target) || isconstruct(target))
|
||||
var/mob/living/simple_animal/M = target
|
||||
if(M.health+5 < M.maxHealth)
|
||||
@@ -895,7 +898,7 @@
|
||||
if(ishuman(target))
|
||||
var/mob/living/carbon/human/H = target
|
||||
if(H.stat != DEAD)
|
||||
H.reagents.add_reagent("unholywater", 7)
|
||||
H.reagents.add_reagent(/datum/reagent/fuel/unholywater, 7)
|
||||
if(isshade(target) || isconstruct(target))
|
||||
var/mob/living/simple_animal/M = target
|
||||
if(M.health+15 < M.maxHealth)
|
||||
|
||||
@@ -239,9 +239,9 @@
|
||||
var/turf/T = safepick(validturfs)
|
||||
if(T)
|
||||
if(istype(T, /turf/open/floor/plating))
|
||||
T.PlaceOnTop(/turf/open/floor/engine/cult)
|
||||
T.PlaceOnTop(/turf/open/floor/engine/cult, flags = CHANGETURF_INHERIT_AIR)
|
||||
else
|
||||
T.ChangeTurf(/turf/open/floor/engine/cult)
|
||||
T.ChangeTurf(/turf/open/floor/engine/cult, flags = CHANGETURF_INHERIT_AIR)
|
||||
else
|
||||
var/turf/open/floor/engine/cult/F = safepick(cultturfs)
|
||||
if(F)
|
||||
|
||||
@@ -24,11 +24,11 @@ This file contains the cult dagger and rune list code
|
||||
|
||||
/obj/item/melee/cultblade/dagger/attack(mob/living/M, mob/living/user)
|
||||
if(iscultist(M))
|
||||
if(M.reagents && M.reagents.has_reagent("holywater")) //allows cultists to be rescued from the clutches of ordained religion
|
||||
if(M.reagents && M.reagents.has_reagent(/datum/reagent/water/holywater)) //allows cultists to be rescued from the clutches of ordained religion
|
||||
to_chat(user, "<span class='cult'>You remove the taint from [M].</span>" )
|
||||
var/holy2unholy = M.reagents.get_reagent_amount("holywater")
|
||||
M.reagents.del_reagent("holywater")
|
||||
M.reagents.add_reagent("unholywater",holy2unholy)
|
||||
var/holy2unholy = M.reagents.get_reagent_amount(/datum/reagent/water/holywater)
|
||||
M.reagents.del_reagent(/datum/reagent/water/holywater)
|
||||
M.reagents.add_reagent(/datum/reagent/fuel/unholywater,holy2unholy)
|
||||
log_combat(user, M, "smacked", src, " removing the holy water from them")
|
||||
return FALSE
|
||||
. = ..()
|
||||
|
||||
@@ -384,14 +384,14 @@ GLOBAL_LIST_INIT(devil_suffix, list(" the Red", " the Soulless", " the Master",
|
||||
if(BANISH_WATER)
|
||||
if(iscarbon(body))
|
||||
var/mob/living/carbon/H = body
|
||||
return H.reagents.has_reagent("holy water")
|
||||
return H.reagents.has_reagent(/datum/reagent/water/holywater)
|
||||
return 0
|
||||
if(BANISH_COFFIN)
|
||||
return (body && istype(body.loc, /obj/structure/closet/crate/coffin))
|
||||
if(BANISH_FORMALDYHIDE)
|
||||
if(iscarbon(body))
|
||||
var/mob/living/carbon/H = body
|
||||
return H.reagents.has_reagent("formaldehyde")
|
||||
return H.reagents.has_reagent(/datum/reagent/toxin/formaldehyde)
|
||||
return 0
|
||||
if(BANISH_RUNES)
|
||||
if(body)
|
||||
|
||||
@@ -197,11 +197,11 @@
|
||||
if(!ascended)
|
||||
var/b_loss
|
||||
switch (severity)
|
||||
if (1)
|
||||
if (EXPLODE_DEVASTATE)
|
||||
b_loss = 500
|
||||
if (2)
|
||||
if (EXPLODE_HEAVY)
|
||||
b_loss = 150
|
||||
if(3)
|
||||
if(EXPLODE_LIGHT)
|
||||
b_loss = 30
|
||||
if(has_bane(BANE_LIGHT))
|
||||
b_loss *=2
|
||||
|
||||
@@ -117,7 +117,7 @@ the new instance inside the host to be updated to the template's stats.
|
||||
follow_next(Dir & NORTHWEST)
|
||||
last_move_tick = world.time
|
||||
|
||||
/mob/camera/disease/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode)
|
||||
/mob/camera/disease/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode, atom/movable/source)
|
||||
. = ..()
|
||||
var/atom/movable/to_follow = speaker
|
||||
if(radio_freq)
|
||||
@@ -129,7 +129,7 @@ the new instance inside the host to be updated to the template's stats.
|
||||
else
|
||||
link = ""
|
||||
// Recompose the message, because it's scrambled by default
|
||||
message = compose_message(speaker, message_language, raw_message, radio_freq, spans, message_mode)
|
||||
message = compose_message(speaker, message_language, raw_message, radio_freq, spans, message_mode, FALSE, source)
|
||||
to_chat(src, "[link] [message]")
|
||||
|
||||
|
||||
|
||||
@@ -34,6 +34,12 @@
|
||||
. = ..()
|
||||
name_source = GLOB.commando_names
|
||||
|
||||
/datum/antagonist/ert/deathsquad/apply_innate_effects(mob/living/mob_override)
|
||||
ADD_TRAIT(owner, TRAIT_DISK_VERIFIER, DEATHSQUAD_TRAIT)
|
||||
|
||||
/datum/antagonist/ert/deathsquad/remove_innate_effects(mob/living/mob_override)
|
||||
REMOVE_TRAIT(owner, TRAIT_DISK_VERIFIER, DEATHSQUAD_TRAIT)
|
||||
|
||||
/datum/antagonist/ert/security // kinda handled by the base template but here for completion
|
||||
|
||||
/datum/antagonist/ert/security/amber
|
||||
|
||||
@@ -5,6 +5,14 @@
|
||||
antagpanel_category = "ClownOp"
|
||||
nukeop_outfit = /datum/outfit/syndicate/clownop
|
||||
|
||||
/datum/antagonist/nukeop/clownop/on_gain()
|
||||
. = ..()
|
||||
ADD_TRAIT(owner, TRAIT_CLOWN_MENTALITY, NUKEOP_ANTAGONIST)
|
||||
|
||||
/datum/antagonist/nukeop/clownop/on_removal()
|
||||
REMOVE_TRAIT(owner, TRAIT_CLOWN_MENTALITY, NUKEOP_ANTAGONIST)
|
||||
return ..()
|
||||
|
||||
/datum/antagonist/nukeop/leader/clownop
|
||||
name = "Clown Operative Leader"
|
||||
roundend_category = "clown operatives"
|
||||
|
||||
@@ -76,9 +76,10 @@ GLOBAL_VAR_INIT(war_declared, FALSE)
|
||||
CONFIG_SET(number/shuttle_refuel_delay, max(CONFIG_GET(number/shuttle_refuel_delay), CHALLENGE_SHUTTLE_DELAY))
|
||||
if(istype(SSticker.mode, /datum/game_mode/dynamic))
|
||||
var/datum/game_mode/dynamic/mode = SSticker.mode
|
||||
var/threat_spent = CONFIG_GET(number/dynamic_warops_cost)
|
||||
mode.spend_threat(threat_spent)
|
||||
mode.log_threat("Nuke ops spent [threat_spent] on war ops.")
|
||||
if(!(mode.storyteller.flags & WAROPS_ALWAYS_ALLOWED))
|
||||
var/threat_spent = CONFIG_GET(number/dynamic_warops_cost)
|
||||
mode.spend_threat(threat_spent)
|
||||
mode.log_threat("Nuke ops spent [threat_spent] on war ops.")
|
||||
SSblackbox.record_feedback("amount", "nuclear_challenge_mode", 1)
|
||||
|
||||
qdel(src)
|
||||
@@ -101,12 +102,13 @@ GLOBAL_VAR_INIT(war_declared, FALSE)
|
||||
return FALSE
|
||||
if(istype(SSticker.mode, /datum/game_mode/dynamic))
|
||||
var/datum/game_mode/dynamic/mode = SSticker.mode
|
||||
if(mode.threat_level < CONFIG_GET(number/dynamic_warops_requirement))
|
||||
to_chat(user, "Due to the dynamic space in which the station resides, you are too deep into Nanotrasen territory to reasonably go loud.")
|
||||
return FALSE
|
||||
else if(mode.threat < CONFIG_GET(number/dynamic_warops_cost))
|
||||
to_chat(user, "Due to recent threats on the station, Nanotrasen is looking too closely for a war declaration to be wise.")
|
||||
return FALSE
|
||||
if(!(mode.storyteller.flags & WAROPS_ALWAYS_ALLOWED))
|
||||
if(mode.threat_level < CONFIG_GET(number/dynamic_warops_requirement))
|
||||
to_chat(user, "Due to the dynamic space in which the station resides, you are too deep into Nanotrasen territory to reasonably go loud.")
|
||||
return FALSE
|
||||
else if(mode.threat < CONFIG_GET(number/dynamic_warops_cost))
|
||||
to_chat(user, "Due to recent threats on the station, Nanotrasen is looking too closely for a war declaration to be wise.")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/item/nuclear_challenge/clownops
|
||||
|
||||
@@ -513,7 +513,7 @@
|
||||
/obj/machinery/nuclearbomb/beer/proc/fizzbuzz()
|
||||
var/datum/reagents/R = new/datum/reagents(1000)
|
||||
R.my_atom = src
|
||||
R.add_reagent("beer", 100)
|
||||
R.add_reagent(/datum/reagent/consumable/ethanol/beer, 100)
|
||||
|
||||
var/datum/effect_system/foam_spread/foam = new
|
||||
foam.set_up(200, get_turf(src), R)
|
||||
@@ -611,10 +611,7 @@ This is here to make the tiles around the station mininuke change when it's arme
|
||||
if(!fake)
|
||||
return
|
||||
|
||||
var/ghost = isobserver(user)
|
||||
var/captain = user.mind && user.mind.assigned_role == "Captain"
|
||||
var/nukie = user.mind && user.mind.has_antag_datum(/datum/antagonist/nukeop)
|
||||
if(ghost || captain || nukie)
|
||||
if(isobserver(user) || HAS_TRAIT(user, TRAIT_DISK_VERIFIER) || (user.mind && HAS_TRAIT(user.mind, TRAIT_DISK_VERIFIER)))
|
||||
. += "<span class='warning'>The serial numbers on [src] are incorrect.</span>"
|
||||
|
||||
/obj/item/disk/nuclear/attackby(obj/item/I, mob/living/user, params)
|
||||
@@ -653,3 +650,7 @@ This is here to make the tiles around the station mininuke change when it's arme
|
||||
|
||||
/obj/item/disk/nuclear/fake
|
||||
fake = TRUE
|
||||
|
||||
/obj/item/disk/nuclear/fake/obvious
|
||||
name = "cheap plastic imitation of the nuclear authentication disk"
|
||||
desc = "How anyone could mistake this for the real thing is beyond you."
|
||||
|
||||
@@ -23,10 +23,12 @@
|
||||
/datum/antagonist/nukeop/apply_innate_effects(mob/living/mob_override)
|
||||
var/mob/living/M = mob_override || owner.current
|
||||
update_synd_icons_added(M)
|
||||
ADD_TRAIT(owner, TRAIT_DISK_VERIFIER, NUKEOP_TRAIT)
|
||||
|
||||
/datum/antagonist/nukeop/remove_innate_effects(mob/living/mob_override)
|
||||
var/mob/living/M = mob_override || owner.current
|
||||
update_synd_icons_removed(M)
|
||||
REMOVE_TRAIT(owner, TRAIT_DISK_VERIFIER, NUKEOP_TRAIT)
|
||||
|
||||
/datum/antagonist/nukeop/proc/equip_op()
|
||||
if(!ishuman(owner.current))
|
||||
@@ -42,7 +44,6 @@
|
||||
owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/ops.ogg',100,0)
|
||||
to_chat(owner, "<span class='notice'>You are a [nuke_team ? nuke_team.syndicate_name : "syndicate"] agent!</span>")
|
||||
owner.announce_objectives()
|
||||
return
|
||||
|
||||
/datum/antagonist/nukeop/on_gain()
|
||||
give_alias()
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
spacewalk = TRUE
|
||||
sight = SEE_SELF
|
||||
throwforce = 0
|
||||
blood_volume = 0
|
||||
|
||||
see_in_dark = 8
|
||||
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
ShiftClickOn(A)
|
||||
return
|
||||
if(modifiers["alt"])
|
||||
AltClickNoInteract(src, A)
|
||||
altclick_listed_turf(A)
|
||||
return
|
||||
|
||||
if(ishuman(A))
|
||||
@@ -353,7 +353,7 @@
|
||||
to_chat(H, "<span class='revenminor'>You feel [pick("suddenly sick", "a surge of nausea", "like your skin is <i>wrong</i>")].</span>")
|
||||
else
|
||||
if(mob.reagents)
|
||||
mob.reagents.add_reagent("plasma", 5)
|
||||
mob.reagents.add_reagent(/datum/reagent/toxin/plasma, 5)
|
||||
else
|
||||
mob.adjustToxLoss(5)
|
||||
for(var/obj/structure/spacevine/vine in T) //Fucking with botanists, the ability.
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/datum/round_event_control/spawn_swarmer
|
||||
name = "Spawn Swarmer Shell"
|
||||
typepath = /datum/round_event/spawn_swarmer
|
||||
weight = 7
|
||||
max_occurrences = 1 //Only once okay fam
|
||||
weight = 0
|
||||
max_occurrences = 0
|
||||
earliest_start = 30 MINUTES
|
||||
min_players = 15
|
||||
|
||||
|
||||
@@ -80,6 +80,8 @@
|
||||
if(istype(SSticker.mode,/datum/game_mode/dynamic))
|
||||
mode = SSticker.mode
|
||||
is_dynamic = TRUE
|
||||
if(mode.storyteller.flags & NO_ASSASSIN)
|
||||
is_hijacker = FALSE
|
||||
if(GLOB.joined_player_list.len>=GLOB.dynamic_high_pop_limit)
|
||||
is_hijacker = (prob(10) && mode.threat_level > CONFIG_GET(number/dynamic_hijack_high_population_requirement))
|
||||
else
|
||||
@@ -180,7 +182,7 @@
|
||||
destroy_objective.owner = owner
|
||||
destroy_objective.find_target()
|
||||
add_objective(destroy_objective)
|
||||
else if(prob(30))
|
||||
else if(prob(30) || (is_dynamic && (mode.storyteller.flags & NO_ASSASSIN)))
|
||||
var/datum/objective/maroon/maroon_objective = new
|
||||
maroon_objective.owner = owner
|
||||
maroon_objective.find_target()
|
||||
|
||||
@@ -505,6 +505,7 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list(
|
||||
if(!is_station_level(F.z))
|
||||
continue
|
||||
F.obj_flags |= EMAGGED
|
||||
F.update_icon()
|
||||
to_chat(owner, "<span class='notice'>All thermal sensors on the station have been disabled. Fire alerts will no longer be recognized.</span>")
|
||||
owner.playsound_local(owner, 'sound/machines/terminal_off.ogg', 50, 0)
|
||||
|
||||
|
||||
@@ -1,445 +1,445 @@
|
||||
|
||||
//Apprenticeship contract - moved to antag_spawner.dm
|
||||
|
||||
///////////////////////////Veil Render//////////////////////
|
||||
|
||||
/obj/item/veilrender
|
||||
name = "veil render"
|
||||
desc = "A wicked curved blade of alien origin, recovered from the ruins of a vast city."
|
||||
icon = 'icons/obj/wizard.dmi'
|
||||
icon_state = "render"
|
||||
item_state = "knife"
|
||||
lefthand_file = 'icons/mob/inhands/equipment/kitchen_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/equipment/kitchen_righthand.dmi'
|
||||
force = 15
|
||||
throwforce = 10
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
hitsound = 'sound/weapons/bladeslice.ogg'
|
||||
var/charges = 1
|
||||
var/spawn_type = /obj/singularity/wizard
|
||||
var/spawn_amt = 1
|
||||
var/activate_descriptor = "reality"
|
||||
var/rend_desc = "You should run now."
|
||||
var/spawn_fast = 0 //if 1, ignores checking for mobs on loc before spawning
|
||||
|
||||
/obj/item/veilrender/attack_self(mob/user)
|
||||
if(charges > 0)
|
||||
new /obj/effect/rend(get_turf(user), spawn_type, spawn_amt, rend_desc, spawn_fast)
|
||||
charges--
|
||||
user.visible_message("<span class='boldannounce'>[src] hums with power as [user] deals a blow to [activate_descriptor] itself!</span>")
|
||||
else
|
||||
to_chat(user, "<span class='danger'>The unearthly energies that powered the blade are now dormant.</span>")
|
||||
|
||||
/obj/effect/rend
|
||||
name = "tear in the fabric of reality"
|
||||
desc = "You should run now."
|
||||
icon = 'icons/effects/effects.dmi'
|
||||
icon_state = "rift"
|
||||
density = TRUE
|
||||
anchored = TRUE
|
||||
var/spawn_path = /mob/living/simple_animal/cow //defaulty cows to prevent unintentional narsies
|
||||
var/spawn_amt_left = 20
|
||||
var/spawn_fast = 0
|
||||
|
||||
/obj/effect/rend/New(loc, var/spawn_type, var/spawn_amt, var/desc, var/spawn_fast)
|
||||
src.spawn_path = spawn_type
|
||||
src.spawn_amt_left = spawn_amt
|
||||
src.desc = desc
|
||||
src.spawn_fast = spawn_fast
|
||||
START_PROCESSING(SSobj, src)
|
||||
return
|
||||
|
||||
/obj/effect/rend/process()
|
||||
if(!spawn_fast)
|
||||
if(locate(/mob) in loc)
|
||||
return
|
||||
new spawn_path(loc)
|
||||
spawn_amt_left--
|
||||
if(spawn_amt_left <= 0)
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/rend/attackby(obj/item/I, mob/user, params)
|
||||
if(istype(I, /obj/item/nullrod))
|
||||
user.visible_message("<span class='danger'>[user] seals \the [src] with \the [I].</span>")
|
||||
qdel(src)
|
||||
return
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/effect/rend/singularity_pull()
|
||||
return
|
||||
|
||||
/obj/effect/rend/singularity_pull()
|
||||
return
|
||||
|
||||
/obj/item/veilrender/vealrender
|
||||
name = "veal render"
|
||||
desc = "A wicked curved blade of alien origin, recovered from the ruins of a vast farm."
|
||||
spawn_type = /mob/living/simple_animal/cow
|
||||
spawn_amt = 20
|
||||
activate_descriptor = "hunger"
|
||||
rend_desc = "Reverberates with the sound of ten thousand moos."
|
||||
|
||||
/obj/item/veilrender/honkrender
|
||||
name = "honk render"
|
||||
desc = "A wicked curved blade of alien origin, recovered from the ruins of a vast circus."
|
||||
spawn_type = /mob/living/simple_animal/hostile/retaliate/clown
|
||||
spawn_amt = 10
|
||||
activate_descriptor = "depression"
|
||||
rend_desc = "Gently wafting with the sounds of endless laughter."
|
||||
icon_state = "clownrender"
|
||||
|
||||
////TEAR IN REALITY
|
||||
|
||||
/obj/singularity/wizard
|
||||
name = "tear in the fabric of reality"
|
||||
desc = "This isn't right."
|
||||
icon = 'icons/effects/224x224.dmi'
|
||||
icon_state = "reality"
|
||||
pixel_x = -96
|
||||
pixel_y = -96
|
||||
dissipate = 0
|
||||
move_self = 0
|
||||
consume_range = 3
|
||||
grav_pull = 4
|
||||
current_size = STAGE_FOUR
|
||||
allowed_size = STAGE_FOUR
|
||||
|
||||
/obj/singularity/wizard/process()
|
||||
move()
|
||||
eat()
|
||||
return
|
||||
|
||||
/obj/singularity/wizard/attack_tk(mob/user)
|
||||
if(iscarbon(user))
|
||||
var/mob/living/carbon/C = user
|
||||
var/datum/component/mood/insaneinthemembrane = C.GetComponent(/datum/component/mood)
|
||||
if(insaneinthemembrane.sanity < 15)
|
||||
return //they've already seen it and are about to die, or are just too insane to care
|
||||
to_chat(C, "<span class='userdanger'>OH GOD! NONE OF IT IS REAL! NONE OF IT IS REEEEEEEEEEEEEEEEEEEEEEEEAL!</span>")
|
||||
insaneinthemembrane.sanity = 0
|
||||
for(var/lore in typesof(/datum/brain_trauma/severe))
|
||||
C.gain_trauma(lore)
|
||||
addtimer(CALLBACK(src, /obj/singularity/wizard.proc/deranged, C), 100)
|
||||
|
||||
/obj/singularity/wizard/proc/deranged(mob/living/carbon/C)
|
||||
if(!C || C.stat == DEAD)
|
||||
return
|
||||
C.vomit(0, TRUE, TRUE, 3, TRUE)
|
||||
C.spew_organ(3, 2)
|
||||
C.death()
|
||||
|
||||
/obj/singularity/wizard/mapped/admin_investigate_setup()
|
||||
return
|
||||
|
||||
/////////////////////////////////////////Scrying///////////////////
|
||||
|
||||
/obj/item/scrying
|
||||
name = "scrying orb"
|
||||
desc = "An incandescent orb of otherworldly energy, staring into it gives you vision beyond mortal means."
|
||||
icon = 'icons/obj/projectiles.dmi'
|
||||
icon_state ="bluespace"
|
||||
throw_speed = 3
|
||||
throw_range = 7
|
||||
throwforce = 15
|
||||
damtype = BURN
|
||||
force = 15
|
||||
hitsound = 'sound/items/welder2.ogg'
|
||||
|
||||
var/xray_granted = FALSE
|
||||
|
||||
/obj/item/scrying/equipped(mob/user)
|
||||
if(!xray_granted && ishuman(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
if(!(H.dna.check_mutation(XRAY)))
|
||||
H.dna.add_mutation(XRAY)
|
||||
xray_granted = TRUE
|
||||
. = ..()
|
||||
|
||||
/obj/item/scrying/attack_self(mob/user)
|
||||
to_chat(user, "<span class='notice'>You can see...everything!</span>")
|
||||
visible_message("<span class='danger'>[user] stares into [src], their eyes glazing over.</span>")
|
||||
user.ghostize(1)
|
||||
|
||||
/////////////////////////////////////////Necromantic Stone///////////////////
|
||||
|
||||
/obj/item/necromantic_stone
|
||||
name = "necromantic stone"
|
||||
desc = "A shard capable of resurrecting humans as skeleton thralls."
|
||||
icon = 'icons/obj/wizard.dmi'
|
||||
icon_state = "necrostone"
|
||||
item_state = "electronic"
|
||||
lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
var/list/spooky_scaries = list()
|
||||
var/unlimited = 0
|
||||
|
||||
/obj/item/necromantic_stone/unlimited
|
||||
unlimited = 1
|
||||
|
||||
/obj/item/necromantic_stone/attack(mob/living/carbon/human/M, mob/living/carbon/human/user)
|
||||
if(!istype(M))
|
||||
return ..()
|
||||
|
||||
if(!istype(user) || !user.canUseTopic(M, BE_CLOSE))
|
||||
return
|
||||
|
||||
if(M.stat != DEAD)
|
||||
to_chat(user, "<span class='warning'>This artifact can only affect the dead!</span>")
|
||||
return
|
||||
|
||||
if(!M.mind || !M.client)
|
||||
to_chat(user, "<span class='warning'>There is no soul connected to this body...</span>")
|
||||
return
|
||||
|
||||
check_spooky()//clean out/refresh the list
|
||||
if(spooky_scaries.len >= 3 && !unlimited)
|
||||
to_chat(user, "<span class='warning'>This artifact can only affect three undead at a time!</span>")
|
||||
return
|
||||
|
||||
M.set_species(/datum/species/skeleton/space, icon_update=0)
|
||||
M.revive(full_heal = 1, admin_revive = 1)
|
||||
spooky_scaries |= M
|
||||
to_chat(M, "<span class='userdanger'>You have been revived by </span><B>[user.real_name]!</B>")
|
||||
to_chat(M, "<span class='userdanger'>[user.p_theyre(TRUE)] your master now, assist [user.p_them()] even if it costs you your new life!</span>")
|
||||
|
||||
equip_roman_skeleton(M)
|
||||
|
||||
desc = "A shard capable of resurrecting humans as skeleton thralls[unlimited ? "." : ", [spooky_scaries.len]/3 active thralls."]"
|
||||
|
||||
/obj/item/necromantic_stone/proc/check_spooky()
|
||||
if(unlimited) //no point, the list isn't used.
|
||||
return
|
||||
|
||||
for(var/X in spooky_scaries)
|
||||
if(!ishuman(X))
|
||||
spooky_scaries.Remove(X)
|
||||
continue
|
||||
var/mob/living/carbon/human/H = X
|
||||
if(H.stat == DEAD)
|
||||
H.dust(TRUE)
|
||||
spooky_scaries.Remove(X)
|
||||
continue
|
||||
listclearnulls(spooky_scaries)
|
||||
|
||||
//Funny gimmick, skeletons always seem to wear roman/ancient armour
|
||||
/obj/item/necromantic_stone/proc/equip_roman_skeleton(mob/living/carbon/human/H)
|
||||
for(var/obj/item/I in H)
|
||||
H.dropItemToGround(I)
|
||||
|
||||
var/hat = pick(/obj/item/clothing/head/helmet/roman, /obj/item/clothing/head/helmet/roman/legionnaire)
|
||||
H.equip_to_slot_or_del(new hat(H), SLOT_HEAD)
|
||||
H.equip_to_slot_or_del(new /obj/item/clothing/under/roman(H), SLOT_W_UNIFORM)
|
||||
H.equip_to_slot_or_del(new /obj/item/clothing/shoes/roman(H), SLOT_SHOES)
|
||||
H.put_in_hands(new /obj/item/shield/riot/roman(H), TRUE)
|
||||
H.put_in_hands(new /obj/item/claymore(H), TRUE)
|
||||
H.equip_to_slot_or_del(new /obj/item/twohanded/spear(H), SLOT_BACK)
|
||||
|
||||
|
||||
/obj/item/voodoo
|
||||
name = "wicker doll"
|
||||
desc = "Something creepy about it."
|
||||
icon = 'icons/obj/wizard.dmi'
|
||||
icon_state = "voodoo"
|
||||
item_state = "electronic"
|
||||
lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
|
||||
var/mob/living/carbon/human/target = null
|
||||
var/list/mob/living/carbon/human/possible = list()
|
||||
var/obj/item/voodoo_link = null
|
||||
var/cooldown_time = 30 //3s
|
||||
var/cooldown = 0
|
||||
max_integrity = 10
|
||||
resistance_flags = FLAMMABLE
|
||||
|
||||
/obj/item/voodoo/attackby(obj/item/I, mob/user, params)
|
||||
if(target && cooldown < world.time)
|
||||
if(I.get_temperature())
|
||||
to_chat(target, "<span class='userdanger'>You suddenly feel very hot</span>")
|
||||
target.adjust_bodytemperature(50)
|
||||
GiveHint(target)
|
||||
else if(is_pointed(I))
|
||||
to_chat(target, "<span class='userdanger'>You feel a stabbing pain in [parse_zone(user.zone_selected)]!</span>")
|
||||
target.Knockdown(40)
|
||||
GiveHint(target)
|
||||
else if(istype(I, /obj/item/bikehorn))
|
||||
to_chat(target, "<span class='userdanger'>HONK</span>")
|
||||
SEND_SOUND(target, 'sound/items/airhorn.ogg')
|
||||
target.adjustEarDamage(0,3)
|
||||
GiveHint(target)
|
||||
cooldown = world.time +cooldown_time
|
||||
return
|
||||
|
||||
if(!voodoo_link)
|
||||
if(I.loc == user && istype(I) && I.w_class <= WEIGHT_CLASS_SMALL)
|
||||
if (user.transferItemToLoc(I,src))
|
||||
voodoo_link = I
|
||||
to_chat(user, "You attach [I] to the doll.")
|
||||
update_targets()
|
||||
|
||||
/obj/item/voodoo/check_eye(mob/user)
|
||||
if(loc != user)
|
||||
user.reset_perspective(null)
|
||||
user.unset_machine()
|
||||
|
||||
/obj/item/voodoo/attack_self(mob/user)
|
||||
if(!target && possible.len)
|
||||
target = input(user, "Select your victim!", "Voodoo") as null|anything in possible
|
||||
return
|
||||
|
||||
if(user.zone_selected == BODY_ZONE_CHEST)
|
||||
if(voodoo_link)
|
||||
target = null
|
||||
voodoo_link.forceMove(drop_location())
|
||||
to_chat(user, "<span class='notice'>You remove the [voodoo_link] from the doll.</span>")
|
||||
voodoo_link = null
|
||||
update_targets()
|
||||
return
|
||||
|
||||
if(target && cooldown < world.time)
|
||||
switch(user.zone_selected)
|
||||
if(BODY_ZONE_PRECISE_MOUTH)
|
||||
var/wgw = sanitize(input(user, "What would you like the victim to say", "Voodoo", null) as text)
|
||||
target.say(wgw, forced = "voodoo doll")
|
||||
log_game("[key_name(user)] made [key_name(target)] say [wgw] with a voodoo doll.")
|
||||
if(BODY_ZONE_PRECISE_EYES)
|
||||
user.set_machine(src)
|
||||
user.reset_perspective(target)
|
||||
spawn(100)
|
||||
user.reset_perspective(null)
|
||||
user.unset_machine()
|
||||
if(BODY_ZONE_R_LEG,BODY_ZONE_L_LEG)
|
||||
to_chat(user, "<span class='notice'>You move the doll's legs around.</span>")
|
||||
var/turf/T = get_step(target,pick(GLOB.cardinals))
|
||||
target.Move(T)
|
||||
if(BODY_ZONE_R_ARM,BODY_ZONE_L_ARM)
|
||||
target.click_random_mob()
|
||||
GiveHint(target)
|
||||
if(BODY_ZONE_HEAD)
|
||||
to_chat(user, "<span class='notice'>You smack the doll's head with your hand.</span>")
|
||||
target.Dizzy(10)
|
||||
to_chat(target, "<span class='warning'>You suddenly feel as if your head was hit with a hammer!</span>")
|
||||
GiveHint(target,user)
|
||||
cooldown = world.time + cooldown_time
|
||||
|
||||
/obj/item/voodoo/proc/update_targets()
|
||||
LAZYINITLIST(possible)
|
||||
if(!voodoo_link)
|
||||
return
|
||||
for(var/mob/living/carbon/human/H in GLOB.alive_mob_list)
|
||||
if(md5(H.dna.uni_identity) in voodoo_link.fingerprints)
|
||||
possible |= H
|
||||
|
||||
/obj/item/voodoo/proc/GiveHint(mob/victim,force=0)
|
||||
if(prob(50) || force)
|
||||
var/way = dir2text(get_dir(victim,get_turf(src)))
|
||||
to_chat(victim, "<span class='notice'>You feel a dark presence from [way]</span>")
|
||||
if(prob(20) || force)
|
||||
var/area/A = get_area(src)
|
||||
to_chat(victim, "<span class='notice'>You feel a dark presence from [A.name]</span>")
|
||||
|
||||
/obj/item/voodoo/suicide_act(mob/living/carbon/user)
|
||||
user.visible_message("<span class='suicide'>[user] links the voodoo doll to [user.p_them()]self and sits on it, infinitely crushing [user.p_them()]self! It looks like [user.p_theyre()] trying to commit suicide!</span>")
|
||||
user.gib()
|
||||
return(BRUTELOSS)
|
||||
|
||||
/obj/item/voodoo/fire_act(exposed_temperature, exposed_volume)
|
||||
if(target)
|
||||
target.adjust_fire_stacks(20)
|
||||
target.IgniteMob()
|
||||
GiveHint(target,1)
|
||||
return ..()
|
||||
|
||||
//Provides a decent heal, need to pump every 6 seconds
|
||||
/obj/item/organ/heart/cursed/wizard
|
||||
pump_delay = 60
|
||||
heal_brute = 25
|
||||
heal_burn = 25
|
||||
heal_oxy = 25
|
||||
|
||||
//Warp Whistle: Provides uncontrolled long distance teleportation.
|
||||
|
||||
/obj/item/warpwhistle
|
||||
name = "warp whistle"
|
||||
desc = "One toot on this whistle will send you to a far away land!"
|
||||
icon = 'icons/obj/wizard.dmi'
|
||||
icon_state = "whistle"
|
||||
var/on_cooldown = 0 //0: usable, 1: in use, 2: on cooldown
|
||||
var/mob/living/carbon/last_user
|
||||
|
||||
/obj/item/warpwhistle/proc/interrupted(mob/living/carbon/user)
|
||||
if(!user || QDELETED(src) || user.notransform)
|
||||
on_cooldown = FALSE
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/obj/item/warpwhistle/proc/end_effect(mob/living/carbon/user)
|
||||
user.invisibility = initial(user.invisibility)
|
||||
user.status_flags &= ~GODMODE
|
||||
user.canmove = TRUE
|
||||
|
||||
/obj/item/warpwhistle/attack_self(mob/living/carbon/user)
|
||||
if(!istype(user) || on_cooldown)
|
||||
return
|
||||
var/turf/T = get_turf(user)
|
||||
var/area/A = get_area(user)
|
||||
if(!T || !A || A.noteleport)
|
||||
to_chat(user, "<span class='warning'>You play \the [src], yet no sound comes out of it... Looks like it won't work here.</span>")
|
||||
return
|
||||
on_cooldown = TRUE
|
||||
last_user = user
|
||||
playsound(T,'sound/magic/warpwhistle.ogg', 200, 1)
|
||||
user.canmove = FALSE
|
||||
new /obj/effect/temp_visual/tornado(T)
|
||||
sleep(20)
|
||||
if(interrupted(user))
|
||||
return
|
||||
user.invisibility = INVISIBILITY_MAXIMUM
|
||||
user.status_flags |= GODMODE
|
||||
sleep(20)
|
||||
if(interrupted(user))
|
||||
end_effect(user)
|
||||
return
|
||||
var/breakout = 0
|
||||
while(breakout < 50)
|
||||
if(!T)
|
||||
end_effect(user)
|
||||
return
|
||||
var/turf/potential_T = find_safe_turf()
|
||||
if(!potential_T)
|
||||
end_effect(user)
|
||||
return
|
||||
if(T.z != potential_T.z || abs(get_dist_euclidian(potential_T,T)) > 50 - breakout)
|
||||
do_teleport(user, potential_T, channel = TELEPORT_CHANNEL_MAGIC)
|
||||
user.canmove = 0
|
||||
T = potential_T
|
||||
break
|
||||
breakout += 1
|
||||
new /obj/effect/temp_visual/tornado(T)
|
||||
sleep(20)
|
||||
end_effect(user)
|
||||
if(interrupted(user))
|
||||
return
|
||||
on_cooldown = 2
|
||||
sleep(40)
|
||||
on_cooldown = 0
|
||||
|
||||
/obj/item/warpwhistle/Destroy()
|
||||
if(on_cooldown == 1 && last_user) //Flute got dunked somewhere in the teleport
|
||||
end_effect(last_user)
|
||||
return ..()
|
||||
|
||||
/obj/effect/temp_visual/tornado
|
||||
icon = 'icons/obj/wizard.dmi'
|
||||
icon_state = "tornado"
|
||||
name = "tornado"
|
||||
desc = "This thing sucks!"
|
||||
layer = FLY_LAYER
|
||||
randomdir = 0
|
||||
duration = 40
|
||||
pixel_x = 500
|
||||
|
||||
/obj/effect/temp_visual/tornado/Initialize()
|
||||
. = ..()
|
||||
animate(src, pixel_x = -500, time = 40)
|
||||
|
||||
//Apprenticeship contract - moved to antag_spawner.dm
|
||||
|
||||
///////////////////////////Veil Render//////////////////////
|
||||
|
||||
/obj/item/veilrender
|
||||
name = "veil render"
|
||||
desc = "A wicked curved blade of alien origin, recovered from the ruins of a vast city."
|
||||
icon = 'icons/obj/wizard.dmi'
|
||||
icon_state = "render"
|
||||
item_state = "knife"
|
||||
lefthand_file = 'icons/mob/inhands/equipment/kitchen_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/equipment/kitchen_righthand.dmi'
|
||||
force = 15
|
||||
throwforce = 10
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
hitsound = 'sound/weapons/bladeslice.ogg'
|
||||
var/charges = 1
|
||||
var/spawn_type = /obj/singularity/wizard
|
||||
var/spawn_amt = 1
|
||||
var/activate_descriptor = "reality"
|
||||
var/rend_desc = "You should run now."
|
||||
var/spawn_fast = 0 //if 1, ignores checking for mobs on loc before spawning
|
||||
|
||||
/obj/item/veilrender/attack_self(mob/user)
|
||||
if(charges > 0)
|
||||
new /obj/effect/rend(get_turf(user), spawn_type, spawn_amt, rend_desc, spawn_fast)
|
||||
charges--
|
||||
user.visible_message("<span class='boldannounce'>[src] hums with power as [user] deals a blow to [activate_descriptor] itself!</span>")
|
||||
else
|
||||
to_chat(user, "<span class='danger'>The unearthly energies that powered the blade are now dormant.</span>")
|
||||
|
||||
/obj/effect/rend
|
||||
name = "tear in the fabric of reality"
|
||||
desc = "You should run now."
|
||||
icon = 'icons/effects/effects.dmi'
|
||||
icon_state = "rift"
|
||||
density = TRUE
|
||||
anchored = TRUE
|
||||
var/spawn_path = /mob/living/simple_animal/cow //defaulty cows to prevent unintentional narsies
|
||||
var/spawn_amt_left = 20
|
||||
var/spawn_fast = 0
|
||||
|
||||
/obj/effect/rend/New(loc, var/spawn_type, var/spawn_amt, var/desc, var/spawn_fast)
|
||||
src.spawn_path = spawn_type
|
||||
src.spawn_amt_left = spawn_amt
|
||||
src.desc = desc
|
||||
src.spawn_fast = spawn_fast
|
||||
START_PROCESSING(SSobj, src)
|
||||
return
|
||||
|
||||
/obj/effect/rend/process()
|
||||
if(!spawn_fast)
|
||||
if(locate(/mob) in loc)
|
||||
return
|
||||
new spawn_path(loc)
|
||||
spawn_amt_left--
|
||||
if(spawn_amt_left <= 0)
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/rend/attackby(obj/item/I, mob/user, params)
|
||||
if(istype(I, /obj/item/nullrod))
|
||||
user.visible_message("<span class='danger'>[user] seals \the [src] with \the [I].</span>")
|
||||
qdel(src)
|
||||
return
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/effect/rend/singularity_pull()
|
||||
return
|
||||
|
||||
/obj/effect/rend/singularity_pull()
|
||||
return
|
||||
|
||||
/obj/item/veilrender/vealrender
|
||||
name = "veal render"
|
||||
desc = "A wicked curved blade of alien origin, recovered from the ruins of a vast farm."
|
||||
spawn_type = /mob/living/simple_animal/cow
|
||||
spawn_amt = 20
|
||||
activate_descriptor = "hunger"
|
||||
rend_desc = "Reverberates with the sound of ten thousand moos."
|
||||
|
||||
/obj/item/veilrender/honkrender
|
||||
name = "honk render"
|
||||
desc = "A wicked curved blade of alien origin, recovered from the ruins of a vast circus."
|
||||
spawn_type = /mob/living/simple_animal/hostile/retaliate/clown
|
||||
spawn_amt = 10
|
||||
activate_descriptor = "depression"
|
||||
rend_desc = "Gently wafting with the sounds of endless laughter."
|
||||
icon_state = "clownrender"
|
||||
|
||||
////TEAR IN REALITY
|
||||
|
||||
/obj/singularity/wizard
|
||||
name = "tear in the fabric of reality"
|
||||
desc = "This isn't right."
|
||||
icon = 'icons/effects/224x224.dmi'
|
||||
icon_state = "reality"
|
||||
pixel_x = -96
|
||||
pixel_y = -96
|
||||
dissipate = 0
|
||||
move_self = 0
|
||||
consume_range = 3
|
||||
grav_pull = 4
|
||||
current_size = STAGE_FOUR
|
||||
allowed_size = STAGE_FOUR
|
||||
|
||||
/obj/singularity/wizard/process()
|
||||
move()
|
||||
eat()
|
||||
return
|
||||
|
||||
/obj/singularity/wizard/attack_tk(mob/user)
|
||||
if(iscarbon(user))
|
||||
var/mob/living/carbon/C = user
|
||||
var/datum/component/mood/insaneinthemembrane = C.GetComponent(/datum/component/mood)
|
||||
if(insaneinthemembrane.sanity < 15)
|
||||
return //they've already seen it and are about to die, or are just too insane to care
|
||||
to_chat(C, "<span class='userdanger'>OH GOD! NONE OF IT IS REAL! NONE OF IT IS REEEEEEEEEEEEEEEEEEEEEEEEAL!</span>")
|
||||
insaneinthemembrane.sanity = 0
|
||||
for(var/lore in typesof(/datum/brain_trauma/severe))
|
||||
C.gain_trauma(lore)
|
||||
addtimer(CALLBACK(src, /obj/singularity/wizard.proc/deranged, C), 100)
|
||||
|
||||
/obj/singularity/wizard/proc/deranged(mob/living/carbon/C)
|
||||
if(!C || C.stat == DEAD)
|
||||
return
|
||||
C.vomit(0, TRUE, TRUE, 3, TRUE)
|
||||
C.spew_organ(3, 2)
|
||||
C.death()
|
||||
|
||||
/obj/singularity/wizard/mapped/admin_investigate_setup()
|
||||
return
|
||||
|
||||
/////////////////////////////////////////Scrying///////////////////
|
||||
|
||||
/obj/item/scrying
|
||||
name = "scrying orb"
|
||||
desc = "An incandescent orb of otherworldly energy, staring into it gives you vision beyond mortal means."
|
||||
icon = 'icons/obj/projectiles.dmi'
|
||||
icon_state ="bluespace"
|
||||
throw_speed = 3
|
||||
throw_range = 7
|
||||
throwforce = 15
|
||||
damtype = BURN
|
||||
force = 15
|
||||
hitsound = 'sound/items/welder2.ogg'
|
||||
|
||||
var/xray_granted = FALSE
|
||||
|
||||
/obj/item/scrying/equipped(mob/user)
|
||||
if(!xray_granted && ishuman(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
if(!(H.dna.check_mutation(XRAY)))
|
||||
H.dna.add_mutation(XRAY)
|
||||
xray_granted = TRUE
|
||||
. = ..()
|
||||
|
||||
/obj/item/scrying/attack_self(mob/user)
|
||||
to_chat(user, "<span class='notice'>You can see...everything!</span>")
|
||||
visible_message("<span class='danger'>[user] stares into [src], their eyes glazing over.</span>")
|
||||
user.ghostize(1)
|
||||
|
||||
/////////////////////////////////////////Necromantic Stone///////////////////
|
||||
|
||||
/obj/item/necromantic_stone
|
||||
name = "necromantic stone"
|
||||
desc = "A shard capable of resurrecting humans as skeleton thralls."
|
||||
icon = 'icons/obj/wizard.dmi'
|
||||
icon_state = "necrostone"
|
||||
item_state = "electronic"
|
||||
lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
var/list/spooky_scaries = list()
|
||||
var/unlimited = 0
|
||||
|
||||
/obj/item/necromantic_stone/unlimited
|
||||
unlimited = 1
|
||||
|
||||
/obj/item/necromantic_stone/attack(mob/living/carbon/human/M, mob/living/carbon/human/user)
|
||||
if(!istype(M))
|
||||
return ..()
|
||||
|
||||
if(!istype(user) || !user.canUseTopic(M, BE_CLOSE))
|
||||
return
|
||||
|
||||
if(M.stat != DEAD)
|
||||
to_chat(user, "<span class='warning'>This artifact can only affect the dead!</span>")
|
||||
return
|
||||
|
||||
if(!M.mind || !M.client)
|
||||
to_chat(user, "<span class='warning'>There is no soul connected to this body...</span>")
|
||||
return
|
||||
|
||||
check_spooky()//clean out/refresh the list
|
||||
if(spooky_scaries.len >= 3 && !unlimited)
|
||||
to_chat(user, "<span class='warning'>This artifact can only affect three undead at a time!</span>")
|
||||
return
|
||||
|
||||
M.set_species(/datum/species/skeleton/space, icon_update=0)
|
||||
M.revive(full_heal = 1, admin_revive = 1)
|
||||
spooky_scaries |= M
|
||||
to_chat(M, "<span class='userdanger'>You have been revived by </span><B>[user.real_name]!</B>")
|
||||
to_chat(M, "<span class='userdanger'>[user.p_theyre(TRUE)] your master now, assist [user.p_them()] even if it costs you your new life!</span>")
|
||||
|
||||
equip_roman_skeleton(M)
|
||||
|
||||
desc = "A shard capable of resurrecting humans as skeleton thralls[unlimited ? "." : ", [spooky_scaries.len]/3 active thralls."]"
|
||||
|
||||
/obj/item/necromantic_stone/proc/check_spooky()
|
||||
if(unlimited) //no point, the list isn't used.
|
||||
return
|
||||
|
||||
for(var/X in spooky_scaries)
|
||||
if(!ishuman(X))
|
||||
spooky_scaries.Remove(X)
|
||||
continue
|
||||
var/mob/living/carbon/human/H = X
|
||||
if(H.stat == DEAD)
|
||||
H.dust(TRUE)
|
||||
spooky_scaries.Remove(X)
|
||||
continue
|
||||
listclearnulls(spooky_scaries)
|
||||
|
||||
//Funny gimmick, skeletons always seem to wear roman/ancient armour
|
||||
/obj/item/necromantic_stone/proc/equip_roman_skeleton(mob/living/carbon/human/H)
|
||||
for(var/obj/item/I in H)
|
||||
H.dropItemToGround(I)
|
||||
|
||||
var/hat = pick(/obj/item/clothing/head/helmet/roman, /obj/item/clothing/head/helmet/roman/legionnaire)
|
||||
H.equip_to_slot_or_del(new hat(H), SLOT_HEAD)
|
||||
H.equip_to_slot_or_del(new /obj/item/clothing/under/roman(H), SLOT_W_UNIFORM)
|
||||
H.equip_to_slot_or_del(new /obj/item/clothing/shoes/roman(H), SLOT_SHOES)
|
||||
H.put_in_hands(new /obj/item/shield/riot/roman(H), TRUE)
|
||||
H.put_in_hands(new /obj/item/claymore(H), TRUE)
|
||||
H.equip_to_slot_or_del(new /obj/item/twohanded/spear(H), SLOT_BACK)
|
||||
|
||||
|
||||
/obj/item/voodoo
|
||||
name = "wicker doll"
|
||||
desc = "Something creepy about it."
|
||||
icon = 'icons/obj/wizard.dmi'
|
||||
icon_state = "voodoo"
|
||||
item_state = "electronic"
|
||||
lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
|
||||
var/mob/living/carbon/human/target = null
|
||||
var/list/mob/living/carbon/human/possible = list()
|
||||
var/obj/item/voodoo_link = null
|
||||
var/cooldown_time = 30 //3s
|
||||
var/cooldown = 0
|
||||
max_integrity = 10
|
||||
resistance_flags = FLAMMABLE
|
||||
|
||||
/obj/item/voodoo/attackby(obj/item/I, mob/user, params)
|
||||
if(target && cooldown < world.time)
|
||||
if(I.get_temperature())
|
||||
to_chat(target, "<span class='userdanger'>You suddenly feel very hot</span>")
|
||||
target.adjust_bodytemperature(50)
|
||||
GiveHint(target)
|
||||
else if(is_pointed(I))
|
||||
to_chat(target, "<span class='userdanger'>You feel a stabbing pain in [parse_zone(user.zone_selected)]!</span>")
|
||||
target.Knockdown(40)
|
||||
GiveHint(target)
|
||||
else if(istype(I, /obj/item/bikehorn))
|
||||
to_chat(target, "<span class='userdanger'>HONK</span>")
|
||||
SEND_SOUND(target, 'sound/items/airhorn.ogg')
|
||||
target.adjustEarDamage(0,3)
|
||||
GiveHint(target)
|
||||
cooldown = world.time +cooldown_time
|
||||
return
|
||||
|
||||
if(!voodoo_link)
|
||||
if(I.loc == user && istype(I) && I.w_class <= WEIGHT_CLASS_SMALL)
|
||||
if (user.transferItemToLoc(I,src))
|
||||
voodoo_link = I
|
||||
to_chat(user, "You attach [I] to the doll.")
|
||||
update_targets()
|
||||
|
||||
/obj/item/voodoo/check_eye(mob/user)
|
||||
if(loc != user)
|
||||
user.reset_perspective(null)
|
||||
user.unset_machine()
|
||||
|
||||
/obj/item/voodoo/attack_self(mob/user)
|
||||
if(!target && possible.len)
|
||||
target = input(user, "Select your victim!", "Voodoo") as null|anything in possible
|
||||
return
|
||||
|
||||
if(user.zone_selected == BODY_ZONE_CHEST)
|
||||
if(voodoo_link)
|
||||
target = null
|
||||
voodoo_link.forceMove(drop_location())
|
||||
to_chat(user, "<span class='notice'>You remove the [voodoo_link] from the doll.</span>")
|
||||
voodoo_link = null
|
||||
update_targets()
|
||||
return
|
||||
|
||||
if(target && cooldown < world.time)
|
||||
switch(user.zone_selected)
|
||||
if(BODY_ZONE_PRECISE_MOUTH)
|
||||
var/wgw = sanitize(input(user, "What would you like the victim to say", "Voodoo", null) as text)
|
||||
target.say(wgw, forced = "voodoo doll")
|
||||
log_game("[key_name(user)] made [key_name(target)] say [wgw] with a voodoo doll.")
|
||||
if(BODY_ZONE_PRECISE_EYES)
|
||||
user.set_machine(src)
|
||||
user.reset_perspective(target)
|
||||
spawn(100)
|
||||
user.reset_perspective(null)
|
||||
user.unset_machine()
|
||||
if(BODY_ZONE_R_LEG,BODY_ZONE_L_LEG)
|
||||
to_chat(user, "<span class='notice'>You move the doll's legs around.</span>")
|
||||
var/turf/T = get_step(target,pick(GLOB.cardinals))
|
||||
target.Move(T)
|
||||
if(BODY_ZONE_R_ARM,BODY_ZONE_L_ARM)
|
||||
target.click_random_mob()
|
||||
GiveHint(target)
|
||||
if(BODY_ZONE_HEAD)
|
||||
to_chat(user, "<span class='notice'>You smack the doll's head with your hand.</span>")
|
||||
target.Dizzy(10)
|
||||
to_chat(target, "<span class='warning'>You suddenly feel as if your head was hit with a hammer!</span>")
|
||||
GiveHint(target,user)
|
||||
cooldown = world.time + cooldown_time
|
||||
|
||||
/obj/item/voodoo/proc/update_targets()
|
||||
LAZYINITLIST(possible)
|
||||
if(!voodoo_link)
|
||||
return
|
||||
for(var/mob/living/carbon/human/H in GLOB.alive_mob_list)
|
||||
if(md5(H.dna.uni_identity) in voodoo_link.fingerprints)
|
||||
possible |= H
|
||||
|
||||
/obj/item/voodoo/proc/GiveHint(mob/victim,force=0)
|
||||
if(prob(50) || force)
|
||||
var/way = dir2text(get_dir(victim,get_turf(src)))
|
||||
to_chat(victim, "<span class='notice'>You feel a dark presence from [way]</span>")
|
||||
if(prob(20) || force)
|
||||
var/area/A = get_area(src)
|
||||
to_chat(victim, "<span class='notice'>You feel a dark presence from [A.name]</span>")
|
||||
|
||||
/obj/item/voodoo/suicide_act(mob/living/carbon/user)
|
||||
user.visible_message("<span class='suicide'>[user] links the voodoo doll to [user.p_them()]self and sits on it, infinitely crushing [user.p_them()]self! It looks like [user.p_theyre()] trying to commit suicide!</span>")
|
||||
user.gib()
|
||||
return(BRUTELOSS)
|
||||
|
||||
/obj/item/voodoo/fire_act(exposed_temperature, exposed_volume)
|
||||
if(target)
|
||||
target.adjust_fire_stacks(20)
|
||||
target.IgniteMob()
|
||||
GiveHint(target,1)
|
||||
return ..()
|
||||
|
||||
//Provides a decent heal, need to pump every 6 seconds
|
||||
/obj/item/organ/heart/cursed/wizard
|
||||
pump_delay = 60
|
||||
heal_brute = 25
|
||||
heal_burn = 25
|
||||
heal_oxy = 25
|
||||
|
||||
//Warp Whistle: Provides uncontrolled long distance teleportation.
|
||||
|
||||
/obj/item/warpwhistle
|
||||
name = "warp whistle"
|
||||
desc = "One toot on this whistle will send you to a far away land!"
|
||||
icon = 'icons/obj/wizard.dmi'
|
||||
icon_state = "whistle"
|
||||
var/on_cooldown = 0 //0: usable, 1: in use, 2: on cooldown
|
||||
var/mob/living/carbon/last_user
|
||||
|
||||
/obj/item/warpwhistle/proc/interrupted(mob/living/carbon/user)
|
||||
if(!user || QDELETED(src) || user.notransform)
|
||||
on_cooldown = FALSE
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/obj/item/warpwhistle/proc/end_effect(mob/living/carbon/user)
|
||||
user.invisibility = initial(user.invisibility)
|
||||
user.status_flags &= ~GODMODE
|
||||
user.canmove = TRUE
|
||||
|
||||
/obj/item/warpwhistle/attack_self(mob/living/carbon/user)
|
||||
if(!istype(user) || on_cooldown)
|
||||
return
|
||||
var/turf/T = get_turf(user)
|
||||
var/area/A = get_area(user)
|
||||
if(!T || !A || A.noteleport)
|
||||
to_chat(user, "<span class='warning'>You play \the [src], yet no sound comes out of it... Looks like it won't work here.</span>")
|
||||
return
|
||||
on_cooldown = TRUE
|
||||
last_user = user
|
||||
playsound(T,'sound/magic/warpwhistle.ogg', 200, 1)
|
||||
user.canmove = FALSE
|
||||
new /obj/effect/temp_visual/tornado(T)
|
||||
sleep(20)
|
||||
if(interrupted(user))
|
||||
return
|
||||
user.invisibility = INVISIBILITY_MAXIMUM
|
||||
user.status_flags |= GODMODE
|
||||
sleep(20)
|
||||
if(interrupted(user))
|
||||
end_effect(user)
|
||||
return
|
||||
var/breakout = 0
|
||||
while(breakout < 50)
|
||||
if(!T)
|
||||
end_effect(user)
|
||||
return
|
||||
var/turf/potential_T = find_safe_turf()
|
||||
if(!potential_T)
|
||||
end_effect(user)
|
||||
return
|
||||
if(T.z != potential_T.z || abs(get_dist_euclidian(potential_T,T)) > 50 - breakout)
|
||||
do_teleport(user, potential_T, channel = TELEPORT_CHANNEL_MAGIC)
|
||||
user.canmove = 0
|
||||
T = potential_T
|
||||
break
|
||||
breakout += 1
|
||||
new /obj/effect/temp_visual/tornado(T)
|
||||
sleep(20)
|
||||
end_effect(user)
|
||||
if(interrupted(user))
|
||||
return
|
||||
on_cooldown = 2
|
||||
sleep(40)
|
||||
on_cooldown = 0
|
||||
|
||||
/obj/item/warpwhistle/Destroy()
|
||||
if(on_cooldown == 1 && last_user) //Flute got dunked somewhere in the teleport
|
||||
end_effect(last_user)
|
||||
return ..()
|
||||
|
||||
/obj/effect/temp_visual/tornado
|
||||
icon = 'icons/obj/wizard.dmi'
|
||||
icon_state = "tornado"
|
||||
name = "tornado"
|
||||
desc = "This thing sucks!"
|
||||
layer = FLY_LAYER
|
||||
randomdir = 0
|
||||
duration = 40
|
||||
pixel_x = 500
|
||||
|
||||
/obj/effect/temp_visual/tornado/Initialize()
|
||||
. = ..()
|
||||
animate(src, pixel_x = -500, time = 40)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -177,6 +177,10 @@
|
||||
owner.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/knock(null))
|
||||
owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/mind_transfer(null))
|
||||
to_chat(owner, "<B>Your service has not gone unrewarded, however. Studying under [master.current.real_name], you have learned stealthy, robeless spells. You are able to cast knock and mindswap.")
|
||||
if(APPRENTICE_MARTIAL)
|
||||
owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/touch/nuclear_fist(null))
|
||||
H.put_in_hands(new /obj/item/book/granter/martial/plasma_fist(H))
|
||||
to_chat(owner, "<B>Your service has not gone unrewarded, however. Studying under [master.current.real_name], you have learned mystical martial abilities. You are also able to use the Nuclear Fist at will.")
|
||||
|
||||
/datum/antagonist/wizard/apprentice/create_objectives()
|
||||
var/datum/objective/protect/new_objective = new /datum/objective/protect
|
||||
|
||||
Reference in New Issue
Block a user