mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-07-09 22:25:46 +01:00
Ports Morph
Refactors a bunch of lesser antag mobs into gamemodes/miniantags
This commit is contained in:
@@ -1,35 +0,0 @@
|
||||
//Cortical borer spawn event - care of RobRichards1997 with minor editing by Zuhayr.
|
||||
|
||||
/datum/event/borer_infestation
|
||||
announceWhen = 400
|
||||
|
||||
var/spawncount = 5
|
||||
var/successSpawn = 0 //So we don't make a command report if nothing gets spawned.
|
||||
|
||||
/datum/event/borer_infestation/setup()
|
||||
announceWhen = rand(announceWhen, announceWhen + 50)
|
||||
spawncount = rand(1, 3)
|
||||
|
||||
/datum/event/borer_infestation/announce()
|
||||
if(successSpawn)
|
||||
command_announcement.Announce("Unidentified lifesigns detected coming aboard [station_name()]. Secure any exterior access, including ducting and ventilation.", "Lifesign Alert", new_sound = 'sound/AI/aliens.ogg')
|
||||
|
||||
/datum/event/borer_infestation/start()
|
||||
var/list/vents = list()
|
||||
for(var/obj/machinery/atmospherics/unary/vent_pump/temp_vent in world)
|
||||
if((temp_vent.loc.z in config.station_levels) && !temp_vent.welded)
|
||||
//Stops cortical borers getting stuck in small networks. See: Security, Virology
|
||||
if(temp_vent.parent.other_atmosmch.len > 50)
|
||||
vents += temp_vent
|
||||
|
||||
var/list/candidates = get_candidates(ROLE_BORER,ALIEN_AFK_BRACKET)
|
||||
while(spawncount > 0 && vents.len && candidates.len)
|
||||
var/obj/vent = pick_n_take(vents)
|
||||
var/client/C = pick_n_take(candidates)
|
||||
|
||||
var/mob/living/simple_animal/borer/new_borer = new(vent.loc)
|
||||
new_borer.key = C.key
|
||||
|
||||
spawncount--
|
||||
successSpawn = 1
|
||||
|
||||
@@ -169,7 +169,8 @@ var/list/event_last_fired = list()
|
||||
new /datum/event_meta(EVENT_LEVEL_MODERATE, "Flux Anomaly", /datum/event/anomaly/anomaly_flux, 50, list(ASSIGNMENT_ENGINEER = 50)),
|
||||
new /datum/event_meta(EVENT_LEVEL_MODERATE, "Gravitational Anomaly", /datum/event/anomaly/anomaly_grav, 200),
|
||||
new /datum/event_meta(EVENT_LEVEL_MODERATE, "Revenant", /datum/event/revenant, 150),
|
||||
new /datum/event_meta(EVENT_LEVEL_MODERATE, "Swarmer Spawn", /datum/event/spawn_swarmer, 150, is_one_shot = 1)
|
||||
new /datum/event_meta(EVENT_LEVEL_MODERATE, "Swarmer Spawn", /datum/event/spawn_swarmer, 150, is_one_shot = 1),
|
||||
new /datum/event_meta(EVENT_LEVEL_MODERATE, "Morph Spawn", /datum/event/spawn_morph, 0, is_one_shot = 1)
|
||||
)
|
||||
|
||||
/datum/event_container/major
|
||||
|
||||
@@ -1,194 +0,0 @@
|
||||
//Travel through pools of blood. Slaughter Demon powers for everyone!
|
||||
#define BLOODCRAWL 1
|
||||
#define BLOODCRAWL_EAT 2
|
||||
|
||||
/mob/living/proc/phaseout(var/obj/effect/decal/cleanable/B)
|
||||
|
||||
if(iscarbon(src))
|
||||
var/mob/living/carbon/C = src
|
||||
if(C.l_hand || C.r_hand)
|
||||
C << "<span class='warning'>You may not hold items while blood crawling!</span>"
|
||||
return 0
|
||||
var/obj/item/weapon/bloodcrawl/B1 = new(C)
|
||||
var/obj/item/weapon/bloodcrawl/B2 = new(C)
|
||||
B1.icon_state = "bloodhand_left"
|
||||
B2.icon_state = "bloodhand_right"
|
||||
C.put_in_hands(B1)
|
||||
C.put_in_hands(B2)
|
||||
C.regenerate_icons()
|
||||
|
||||
var/mob/living/kidnapped = null
|
||||
var/turf/mobloc = get_turf(src.loc)
|
||||
var/turf/bloodloc = get_turf(B.loc)
|
||||
if(Adjacent(bloodloc))
|
||||
src.notransform = TRUE
|
||||
spawn(0)
|
||||
src.visible_message("<span class='danger'>[src] sinks into [B].</span>")
|
||||
playsound(get_turf(src), 'sound/misc/enter_blood.ogg', 100, 1, -1)
|
||||
var/obj/effect/dummy/slaughter/holder = new /obj/effect/dummy/slaughter( mobloc )
|
||||
var/atom/movable/overlay/animation = new /atom/movable/overlay( mobloc )
|
||||
animation.name = "odd blood"
|
||||
animation.density = 0
|
||||
animation.anchored = 1
|
||||
animation.icon = 'icons/mob/mob.dmi'
|
||||
animation.icon_state = "jaunt"
|
||||
animation.layer = 5
|
||||
animation.master = holder
|
||||
animation.dir = src.dir
|
||||
|
||||
src.ExtinguishMob()
|
||||
if(src.buckled)
|
||||
src.buckled.unbuckle_mob()
|
||||
if(src.pulling && src.bloodcrawl == BLOODCRAWL_EAT)
|
||||
if(istype(src.pulling, /mob/living/))
|
||||
var/mob/living/victim = src.pulling
|
||||
if(victim.stat == CONSCIOUS)
|
||||
src.visible_message("<span class='warning'>[victim] kicks free of [B] just before entering it!</span>")
|
||||
else
|
||||
victim.loc = holder///holder
|
||||
victim.emote("scream")
|
||||
src.visible_message("<span class='warning'><b>[src] drags [victim] into [B]!</b></span>")
|
||||
kidnapped = victim
|
||||
flick("jaunt",animation)
|
||||
src.loc = holder
|
||||
src.holder = holder
|
||||
|
||||
if(kidnapped)
|
||||
src << "<B>You begin to feast on [kidnapped]. You can not move while you are doing this.</B>"
|
||||
src.visible_message("<span class='warning'><B>Loud eating sounds come from the blood...</B></span>")
|
||||
sleep(6)
|
||||
if (animation)
|
||||
qdel(animation)
|
||||
for(var/i = 3; i > 0; i--)
|
||||
playsound(get_turf(src),'sound/misc/Demon_consume.ogg', 100, 1)
|
||||
sleep(30)
|
||||
if (kidnapped)
|
||||
src << "<B>You devour [kidnapped]. Your health is fully restored.</B>"
|
||||
src.adjustBruteLoss(-1000)
|
||||
src.adjustFireLoss(-1000)
|
||||
src.adjustOxyLoss(-1000)
|
||||
src.adjustToxLoss(-1000)
|
||||
|
||||
if (istype(src, /mob/living/simple_animal/slaughter)) //rason, do not want humans to get this
|
||||
|
||||
var/mob/living/simple_animal/slaughter/demon = src
|
||||
demon.devoured++
|
||||
kidnapped << "<span class='userdanger'>You feel teeth sink into your flesh, and the--</span>"
|
||||
kidnapped.adjustBruteLoss(1000)
|
||||
kidnapped.forceMove(src)
|
||||
demon.consumed_mobs.Add(kidnapped)
|
||||
else
|
||||
kidnapped.ghostize()
|
||||
qdel(kidnapped)
|
||||
else
|
||||
src << "<span class='danger'>You happily devour... nothing? Your meal vanished at some point!</span>"
|
||||
else
|
||||
sleep(6)
|
||||
if (animation)
|
||||
qdel(animation)
|
||||
src.notransform = 0
|
||||
|
||||
/obj/item/weapon/bloodcrawl
|
||||
name = "blood crawl"
|
||||
desc = "You are unable to hold anything while in this form."
|
||||
icon = 'icons/effects/blood.dmi'
|
||||
flags = NODROP
|
||||
|
||||
/mob/living/proc/phasein(var/obj/effect/decal/cleanable/B)
|
||||
if(src.notransform)
|
||||
src << "<span class='warning'>Finish eating first!</span>"
|
||||
else
|
||||
var/atom/movable/overlay/animation = new /atom/movable/overlay( B.loc )
|
||||
animation.name = "odd blood"
|
||||
animation.density = 0
|
||||
animation.anchored = 1
|
||||
animation.icon = 'icons/mob/mob.dmi'
|
||||
animation.icon_state = "jauntup" //Paradise Port:I reversed the jaunt animation so it looks like its rising up
|
||||
animation.layer = 5
|
||||
animation.master = B.loc
|
||||
animation.dir = src.dir
|
||||
B.visible_message("<span class='warning'>[B] starts to bubble...</span>")
|
||||
if(!do_after(src, 20, target = B))
|
||||
return
|
||||
if(!B)
|
||||
return
|
||||
src.forceMove(B.loc)
|
||||
src.client.eye = src
|
||||
if (prob(25) && istype(src, /mob/living/simple_animal/slaughter))
|
||||
var/list/voice = list('sound/hallucinations/behind_you1.ogg','sound/hallucinations/im_here1.ogg','sound/hallucinations/turn_around1.ogg','sound/hallucinations/i_see_you1.ogg')
|
||||
playsound(get_turf(src), pick(voice),50, 1, -1)
|
||||
src.visible_message("<span class='warning'><B>\The [src] rises out of \the [B]!</B>")
|
||||
playsound(get_turf(src), 'sound/misc/exit_blood.ogg', 100, 1, -1)
|
||||
flick("jauntup",animation)
|
||||
qdel(src.holder)
|
||||
src.holder = null
|
||||
if(iscarbon(src))
|
||||
var/mob/living/carbon/C = src
|
||||
for(var/obj/item/weapon/bloodcrawl/BC in C)
|
||||
C.flags = null
|
||||
C.unEquip(BC)
|
||||
qdel(BC)
|
||||
var/oldcolor = src.color
|
||||
src.color = B.color
|
||||
sleep(6)//wait for animation to finish
|
||||
if(animation)
|
||||
qdel(animation)
|
||||
spawn(30)
|
||||
src.color = oldcolor
|
||||
|
||||
/obj/effect/decal/cleanable/blood/CtrlClick(mob/living/user)
|
||||
..()
|
||||
if(user.bloodcrawl)
|
||||
if(user.holder)
|
||||
user.phasein(src)
|
||||
else
|
||||
user.phaseout(src)
|
||||
|
||||
|
||||
|
||||
/obj/effect/decal/cleanable/trail_holder/CtrlClick(mob/living/user)
|
||||
..()
|
||||
if(user.bloodcrawl)
|
||||
if(user.holder)
|
||||
user.phasein(src)
|
||||
else
|
||||
user.phaseout(src)
|
||||
|
||||
|
||||
|
||||
/turf/CtrlClick(var/mob/living/user)
|
||||
..()
|
||||
if(user.bloodcrawl)
|
||||
for(var/obj/effect/decal/cleanable/B in src.contents)
|
||||
if(istype(B, /obj/effect/decal/cleanable/blood) || istype(B, /obj/effect/decal/cleanable/trail_holder))
|
||||
if(user.holder)
|
||||
user.phasein(B)
|
||||
break
|
||||
else
|
||||
user.phaseout(B)
|
||||
break
|
||||
|
||||
/obj/effect/dummy/slaughter //Can't use the wizard one, blocked by jaunt/slow
|
||||
name = "odd blood"
|
||||
icon = 'icons/effects/effects.dmi'
|
||||
icon_state = "nothing"
|
||||
var/canmove = 1
|
||||
density = 0
|
||||
anchored = 1
|
||||
|
||||
/obj/effect/dummy/slaughter/relaymove(var/mob/user, direction)
|
||||
if (!src.canmove || !direction) return
|
||||
var/turf/newLoc = get_step(src,direction)
|
||||
loc = newLoc
|
||||
src.canmove = 0
|
||||
spawn(1)
|
||||
src.canmove = 1
|
||||
|
||||
/obj/effect/dummy/slaughter/ex_act(severity)
|
||||
return 1
|
||||
|
||||
/obj/effect/dummy/slaughter/bullet_act(blah)
|
||||
return
|
||||
|
||||
/obj/effect/dummy/slaughter/singularity_act(blah)
|
||||
return
|
||||
@@ -1,508 +0,0 @@
|
||||
/mob/living/captive_brain
|
||||
name = "host brain"
|
||||
real_name = "host brain"
|
||||
|
||||
/mob/living/captive_brain/say(var/message)
|
||||
|
||||
if (src.client)
|
||||
if(client.prefs.muted & MUTE_IC)
|
||||
src << "\red You cannot speak in IC (muted)."
|
||||
return
|
||||
if (src.client.handle_spam_prevention(message,MUTE_IC))
|
||||
return
|
||||
|
||||
if(istype(src.loc,/mob/living/simple_animal/borer))
|
||||
message = trim(sanitize(copytext(message, 1, MAX_MESSAGE_LEN)))
|
||||
if (!message)
|
||||
return
|
||||
log_say("[key_name(src)] : [message]")
|
||||
if (stat == DEAD)
|
||||
return say_dead(message)
|
||||
var/mob/living/simple_animal/borer/B = src.loc
|
||||
src << "You whisper silently, \"[message]\""
|
||||
B.host << "The captive mind of [src] whispers, \"[message]\""
|
||||
|
||||
for(var/mob/M in mob_list)
|
||||
if(M.mind && (istype(M, /mob/dead/observer)))
|
||||
M << "<i>Thought-speech, <b>[src]</b> -> <b>[B.truename]:</b> [message]</i>"
|
||||
|
||||
/mob/living/captive_brain/emote(var/message)
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/borer
|
||||
name = "cortical borer"
|
||||
real_name = "cortical borer"
|
||||
desc = "A small, quivering sluglike creature."
|
||||
speak_emote = list("chirrups")
|
||||
emote_hear = list("chirrups")
|
||||
response_help = "pokes"
|
||||
response_disarm = "prods the"
|
||||
response_harm = "stomps on the"
|
||||
icon_state = "brainslug"
|
||||
icon_living = "brainslug"
|
||||
icon_dead = "brainslug_dead"
|
||||
speed = 5
|
||||
a_intent = I_HARM
|
||||
stop_automated_movement = 1
|
||||
status_flags = CANPUSH
|
||||
attacktext = "nips"
|
||||
friendly = "prods"
|
||||
wander = 0
|
||||
small = 1
|
||||
density = 0
|
||||
pass_flags = PASSTABLE
|
||||
ventcrawler = 2
|
||||
|
||||
var/used_dominate
|
||||
var/chemicals = 10 // Chemicals used for reproduction and spitting neurotoxin.
|
||||
var/mob/living/carbon/human/host // Human host for the brain worm.
|
||||
var/truename // Name used for brainworm-speak.
|
||||
var/mob/living/captive_brain/host_brain // Used for swapping control of the body back and forth.
|
||||
var/controlling // Used in human death check.
|
||||
var/docile = 0 // Sugar can stop borers from acting.
|
||||
|
||||
/mob/living/simple_animal/borer/Life()
|
||||
|
||||
..()
|
||||
|
||||
if(host)
|
||||
|
||||
if(!stat && host.stat != DEAD)
|
||||
|
||||
if(host.reagents.has_reagent("sugar"))
|
||||
if(!docile)
|
||||
if(controlling)
|
||||
host << "\blue You feel the soporific flow of sugar in your host's blood, lulling you into docility."
|
||||
else
|
||||
src << "\blue You feel the soporific flow of sugar in your host's blood, lulling you into docility."
|
||||
docile = 1
|
||||
else
|
||||
if(docile)
|
||||
if(controlling)
|
||||
host << "\blue You shake off your lethargy as the sugar leaves your host's blood."
|
||||
else
|
||||
src << "\blue You shake off your lethargy as the sugar leaves your host's blood."
|
||||
docile = 0
|
||||
|
||||
if(chemicals < 250)
|
||||
chemicals++
|
||||
if(controlling)
|
||||
|
||||
if(docile)
|
||||
host << "\blue You are feeling far too docile to continue controlling your host..."
|
||||
host.release_control()
|
||||
return
|
||||
|
||||
if(prob(5))
|
||||
host.adjustBrainLoss(rand(1,2))
|
||||
|
||||
if(prob(host.getBrainLoss()/20))
|
||||
host.say("*[pick(list("blink","blink_r","choke","aflap","drool","twitch","twitch_s","gasp"))]")
|
||||
|
||||
/mob/living/simple_animal/borer/New(var/by_gamemode=0)
|
||||
..()
|
||||
add_language("Cortical Link")
|
||||
truename = "[pick("Primary","Secondary","Tertiary","Quaternary")] [rand(1000,9999)]"
|
||||
|
||||
if(!by_gamemode)
|
||||
request_player()
|
||||
|
||||
/mob/living/simple_animal/borer/Stat()
|
||||
..()
|
||||
statpanel("Status")
|
||||
|
||||
if(shuttle_master.emergency.mode >= SHUTTLE_RECALL)
|
||||
var/timeleft = shuttle_master.emergency.timeLeft()
|
||||
if(timeleft > 0)
|
||||
stat(null, "[add_zero(num2text((timeleft / 60) % 60),2)]:[add_zero(num2text(timeleft % 60), 2)]")
|
||||
|
||||
if (client.statpanel == "Status")
|
||||
stat("Chemicals", chemicals)
|
||||
|
||||
// VERBS!
|
||||
|
||||
/mob/living/simple_animal/borer/proc/borer_speak(var/message)
|
||||
if(!message)
|
||||
return
|
||||
|
||||
for(var/mob/M in mob_list)
|
||||
if(M.mind && (istype(M, /mob/living/simple_animal/borer) || istype(M, /mob/dead/observer)))
|
||||
M << "<i>Cortical link, <b>[truename]:</b> [copytext(message, 2)]</i>"
|
||||
|
||||
/mob/living/simple_animal/borer/verb/dominate_victim()
|
||||
set category = "Alien"
|
||||
set name = "Dominate Victim"
|
||||
set desc = "Freeze the limbs of a potential host with supernatural fear."
|
||||
|
||||
if(world.time - used_dominate < 300)
|
||||
src << "You cannot use that ability again so soon."
|
||||
return
|
||||
|
||||
if(host)
|
||||
src << "You cannot do that from within a host body."
|
||||
return
|
||||
|
||||
if(src.stat)
|
||||
src << "You cannot do that in your current state."
|
||||
return
|
||||
|
||||
var/list/choices = list()
|
||||
for(var/mob/living/carbon/C in view(3,src))
|
||||
if(C.stat != DEAD)
|
||||
choices += C
|
||||
|
||||
if(world.time - used_dominate < 300)
|
||||
src << "You cannot use that ability again so soon."
|
||||
return
|
||||
|
||||
var/mob/living/carbon/M = input(src,"Who do you wish to dominate?") in null|choices
|
||||
|
||||
if(!M || !src) return
|
||||
|
||||
if(M.has_brain_worms())
|
||||
src << "You cannot infest someone who is already infested!"
|
||||
return
|
||||
|
||||
src << "\red You focus your psychic lance on [M] and freeze their limbs with a wave of terrible dread."
|
||||
M << "\red You feel a creeping, horrible sense of dread come over you, freezing your limbs and setting your heart racing."
|
||||
M.Weaken(3)
|
||||
|
||||
used_dominate = world.time
|
||||
|
||||
/mob/living/simple_animal/borer/verb/bond_brain()
|
||||
set category = "Alien"
|
||||
set name = "Assume Control"
|
||||
set desc = "Fully connect to the brain of your host."
|
||||
|
||||
if(!host)
|
||||
src << "You are not inside a host body."
|
||||
return
|
||||
|
||||
if(src.stat)
|
||||
src << "You cannot do that in your current state."
|
||||
return
|
||||
|
||||
if(docile)
|
||||
src << "\blue You are feeling far too docile to do that."
|
||||
return
|
||||
|
||||
src << "You begin delicately adjusting your connection to the host brain..."
|
||||
|
||||
spawn(300+(host.getBrainLoss()*5))
|
||||
|
||||
if(!host || !src || controlling)
|
||||
return
|
||||
else
|
||||
src << "\red <B>You plunge your probosci deep into the cortex of the host brain, interfacing directly with their nervous system.</B>"
|
||||
host << "\red <B>You feel a strange shifting sensation behind your eyes as an alien consciousness displaces yours.</B>"
|
||||
var/borer_key = src.key
|
||||
host.attack_log += text("\[[time_stamp()]\] <font color='blue'>[key_name(src)] has assumed control of [key_name(host)]</font>")
|
||||
msg_admin_attack("[key_name_admin(src)] has assumed control of [key_name_admin(host)]")
|
||||
// host -> brain
|
||||
var/h2b_id = host.computer_id
|
||||
var/h2b_ip= host.lastKnownIP
|
||||
host.computer_id = null
|
||||
host.lastKnownIP = null
|
||||
|
||||
qdel(host_brain)
|
||||
host_brain = new(src)
|
||||
|
||||
host_brain.ckey = host.ckey
|
||||
|
||||
host_brain.name = host.name
|
||||
|
||||
if(!host_brain.computer_id)
|
||||
host_brain.computer_id = h2b_id
|
||||
|
||||
if(!host_brain.lastKnownIP)
|
||||
host_brain.lastKnownIP = h2b_ip
|
||||
|
||||
// self -> host
|
||||
var/s2h_id = src.computer_id
|
||||
var/s2h_ip= src.lastKnownIP
|
||||
src.computer_id = null
|
||||
src.lastKnownIP = null
|
||||
|
||||
host.ckey = src.ckey
|
||||
|
||||
if(!host.computer_id)
|
||||
host.computer_id = s2h_id
|
||||
|
||||
if(!host.lastKnownIP)
|
||||
host.lastKnownIP = s2h_ip
|
||||
|
||||
controlling = 1
|
||||
|
||||
host.verbs += /mob/living/carbon/proc/release_control
|
||||
host.verbs += /mob/living/carbon/proc/punish_host
|
||||
host.verbs += /mob/living/carbon/proc/spawn_larvae
|
||||
|
||||
if(src && !src.key)
|
||||
src.key = "@[borer_key]"
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/borer/verb/secrete_chemicals()
|
||||
set category = "Alien"
|
||||
set name = "Secrete Chemicals (30)"
|
||||
set desc = "Push some chemicals into your host's bloodstream."
|
||||
|
||||
if(!host)
|
||||
src << "You are not inside a host body."
|
||||
return
|
||||
|
||||
if(stat)
|
||||
src << "You cannot secrete chemicals in your current state."
|
||||
|
||||
if(docile)
|
||||
src << "\blue You are feeling far too docile to do that."
|
||||
return
|
||||
|
||||
if(chemicals < 30)
|
||||
src << "You don't have enough chemicals!"
|
||||
|
||||
var/chem = input("Select a chemical to secrete.", "Chemicals") as null|anything in list("mannitol","styptic_powder","methamphetamine","sal_acid")
|
||||
|
||||
if(!chem || chemicals < 30 || !host || controlling || !src || stat) //Sanity check.
|
||||
return
|
||||
|
||||
src << "\red <B>You squirt a measure of [chem] from your reservoirs into [host]'s bloodstream.</B>"
|
||||
host.reagents.add_reagent(chem, 9)
|
||||
chemicals -= 30
|
||||
|
||||
/mob/living/simple_animal/borer/verb/release_host()
|
||||
set category = "Alien"
|
||||
set name = "Release Host"
|
||||
set desc = "Slither out of your host."
|
||||
|
||||
if(!host)
|
||||
src << "You are not inside a host body."
|
||||
return
|
||||
|
||||
if(stat)
|
||||
src << "You cannot leave your host in your current state."
|
||||
|
||||
if(docile)
|
||||
src << "\blue You are feeling far too docile to do that."
|
||||
return
|
||||
|
||||
if(!host || !src) return
|
||||
|
||||
src << "You begin disconnecting from [host]'s synapses and prodding at their internal ear canal."
|
||||
|
||||
spawn(200)
|
||||
|
||||
if(!host || !src) return
|
||||
|
||||
if(src.stat)
|
||||
src << "You cannot release a target in your current state."
|
||||
return
|
||||
|
||||
src << "You wiggle out of [host]'s ear and plop to the ground."
|
||||
|
||||
detatch()
|
||||
leave_host()
|
||||
|
||||
/mob/living/simple_animal/borer/proc/detatch()
|
||||
|
||||
if(!host) return
|
||||
|
||||
if(istype(host,/mob/living/carbon/human))
|
||||
var/mob/living/carbon/human/H = host
|
||||
var/obj/item/organ/external/head = H.get_organ("head")
|
||||
head.implants -= src
|
||||
|
||||
controlling = 0
|
||||
|
||||
reset_view(null)
|
||||
machine = null
|
||||
|
||||
host.verbs -= /mob/living/carbon/proc/release_control
|
||||
host.verbs -= /mob/living/carbon/proc/punish_host
|
||||
host.verbs -= /mob/living/carbon/proc/spawn_larvae
|
||||
|
||||
|
||||
if(host_brain)
|
||||
host.attack_log += text("\[[time_stamp()]\] <font color='blue'>[host_brain.name] ([host_brain.ckey]) has taken control back from [src.name] ([host.ckey])</font>")
|
||||
msg_admin_attack("[host_brain.name] ([host_brain.ckey]) has taken control back from [src.name] ([host.ckey]) (<A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[host.x];Y=[host.y];Z=[host.z]'>JMP</a>)")
|
||||
// host -> self
|
||||
var/h2s_id = host.computer_id
|
||||
var/h2s_ip= host.lastKnownIP
|
||||
host.computer_id = null
|
||||
host.lastKnownIP = null
|
||||
|
||||
src.ckey = host.ckey
|
||||
|
||||
if(!src.computer_id)
|
||||
src.computer_id = h2s_id
|
||||
|
||||
if(!host_brain.lastKnownIP)
|
||||
src.lastKnownIP = h2s_ip
|
||||
|
||||
// brain -> host
|
||||
var/b2h_id = host_brain.computer_id
|
||||
var/b2h_ip= host_brain.lastKnownIP
|
||||
host_brain.computer_id = null
|
||||
host_brain.lastKnownIP = null
|
||||
|
||||
host.ckey = host_brain.ckey
|
||||
|
||||
if(!host.computer_id)
|
||||
host.computer_id = b2h_id
|
||||
|
||||
if(!host.lastKnownIP)
|
||||
host.lastKnownIP = b2h_ip
|
||||
|
||||
qdel(host_brain)
|
||||
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/borer/proc/leave_host()
|
||||
|
||||
if(!host) return
|
||||
|
||||
src.forceMove(get_turf(host))
|
||||
|
||||
reset_view(null)
|
||||
machine = null
|
||||
|
||||
host.reset_view(null)
|
||||
host.machine = null
|
||||
|
||||
var/mob/living/H = host
|
||||
H.status_flags &= ~PASSEMOTES
|
||||
host = null
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/borer/verb/infest()
|
||||
set category = "Alien"
|
||||
set name = "Infest"
|
||||
set desc = "Infest a suitable humanoid host."
|
||||
|
||||
if(host)
|
||||
src << "You are already within a host."
|
||||
return
|
||||
|
||||
if(stat)
|
||||
src << "You cannot infest a target in your current state."
|
||||
return
|
||||
|
||||
var/list/choices = list()
|
||||
for(var/mob/living/carbon/human/H in view(1,src))
|
||||
var/obj/item/organ/external/head/head = H.get_organ("head")
|
||||
if(head.status & ORGAN_ROBOT)
|
||||
continue
|
||||
if(H.stat != DEAD && src.Adjacent(H) && !H.has_brain_worms())
|
||||
choices += H
|
||||
|
||||
var/mob/living/carbon/human/M = input(src,"Who do you wish to infest?") in null|choices
|
||||
|
||||
if(!M || !src) return
|
||||
|
||||
if(!(src.Adjacent(M))) return
|
||||
|
||||
if(M.has_brain_worms())
|
||||
src << "You cannot infest someone who is already infested!"
|
||||
return
|
||||
|
||||
src << "You slither up [M] and begin probing at their ear canal..."
|
||||
|
||||
if(!do_after(src,50, target = M))
|
||||
src << "As [M] moves away, you are dislodged and fall to the ground."
|
||||
return
|
||||
|
||||
if(!M || !src) return
|
||||
|
||||
if(src.stat)
|
||||
src << "You cannot infest a target in your current state."
|
||||
return
|
||||
|
||||
if(M.stat == DEAD)
|
||||
src << "That is not an appropriate target."
|
||||
return
|
||||
|
||||
if(M in view(1, src))
|
||||
src << "You wiggle into [M]'s ear."
|
||||
if(!M.stat)
|
||||
M << "Something disgusting and slimy wiggles into your ear!"
|
||||
|
||||
src.host = M
|
||||
src.forceMove(M)
|
||||
|
||||
if(istype(M,/mob/living/carbon/human))
|
||||
var/mob/living/carbon/human/H = M
|
||||
var/obj/item/organ/external/head = H.get_organ("head")
|
||||
head.implants += src
|
||||
|
||||
host.status_flags |= PASSEMOTES
|
||||
|
||||
return
|
||||
else
|
||||
src << "They are no longer in range!"
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/borer/proc/perform_infestation(var/mob/living/carbon/M)
|
||||
src.host = M
|
||||
src.forceMove(M)
|
||||
|
||||
if(istype(M,/mob/living/carbon/human))
|
||||
var/mob/living/carbon/human/H = M
|
||||
var/obj/item/organ/external/head = H.get_organ("head")
|
||||
head.implants += src
|
||||
|
||||
host_brain.name = M.name
|
||||
host_brain.real_name = M.real_name
|
||||
host.status_flags |= PASSEMOTES
|
||||
|
||||
/mob/living/simple_animal/borer/can_use_vents()
|
||||
return
|
||||
|
||||
//Procs for grabbing players.
|
||||
/mob/living/simple_animal/borer/proc/request_player()
|
||||
for(var/mob/O in respawnable_list)
|
||||
if(jobban_isbanned(O, "Syndicate"))
|
||||
continue
|
||||
if(O.client)
|
||||
if((ROLE_BORER in O.client.prefs.be_special) && !jobban_isbanned(O, "alien"))
|
||||
question(O.client)
|
||||
|
||||
/mob/living/simple_animal/borer/proc/question(var/client/C)
|
||||
spawn(0)
|
||||
if(!C) return
|
||||
var/response = alert(C, "A cortical borer needs a player. Are you interested?", "Cortical borer request", "Yes", "No", "Never for this round")
|
||||
if(!C || ckey)
|
||||
return
|
||||
if(response == "Yes")
|
||||
transfer_personality(C)
|
||||
else if (response == "Never for this round")
|
||||
C.prefs.be_special -= ROLE_BORER
|
||||
|
||||
/mob/living/simple_animal/borer/proc/transfer_personality(var/client/candidate)
|
||||
|
||||
if(!candidate)
|
||||
return
|
||||
|
||||
src.mind = candidate.mob.mind
|
||||
src.ckey = candidate.ckey
|
||||
if(src.mind)
|
||||
src.mind.assigned_role = "Cortical Borer"
|
||||
|
||||
/mob/living/simple_animal/borer/verb/borerhide()
|
||||
set category = "Alien"
|
||||
set name = "Hide"
|
||||
set desc = "Allows to hide beneath tables or certain items. Toggled on or off."
|
||||
|
||||
if(stat != CONSCIOUS)
|
||||
return
|
||||
|
||||
if (layer != TURF_LAYER+0.2)
|
||||
layer = TURF_LAYER+0.2
|
||||
src << text("\green You are now hiding.")
|
||||
for(var/mob/O in oviewers(src, null))
|
||||
if ((O.client && !( O.blinded )))
|
||||
O << text("<B>[] scurries to the ground!</B>", src)
|
||||
else
|
||||
layer = MOB_LAYER
|
||||
src << text("\green You have stopped hiding.")
|
||||
for(var/mob/O in oviewers(src, null))
|
||||
if ((O.client && !( O.blinded )))
|
||||
O << text("[] slowly peaks up from the ground...", src)
|
||||
@@ -1,628 +0,0 @@
|
||||
////Deactivated swarmer shell////
|
||||
/obj/item/unactivated_swarmer
|
||||
name = "unactivated swarmer"
|
||||
desc = "A currently unactivated swarmer. Swarmers can self activate at any time, it would be wise to immediately dispose of this."
|
||||
icon = 'icons/mob/swarmer.dmi'
|
||||
icon_state = "swarmer_unactivated"
|
||||
|
||||
/obj/item/unactivated_swarmer/New()
|
||||
notify_ghosts("An unactivated swarmer has been created in [get_area(src)]! <a href=?src=\ref[src];ghostjoin=1>(Click to enter)</a>")
|
||||
..()
|
||||
|
||||
/obj/item/unactivated_swarmer/Topic(href, href_list)
|
||||
if(..())
|
||||
return 1
|
||||
if(href_list["ghostjoin"])
|
||||
var/mob/dead/observer/ghost = usr
|
||||
if(istype(ghost))
|
||||
attack_ghost(ghost)
|
||||
|
||||
/obj/item/unactivated_swarmer/attack_ghost(mob/user as mob)
|
||||
var/be_swarmer = alert("Become a swarmer? (Warning, You can no longer be cloned!)",,"Yes","No")
|
||||
if(be_swarmer == "No")
|
||||
return
|
||||
if(qdeleted(src))
|
||||
user << "Swarmer has been occupied by someone else."
|
||||
return
|
||||
var/mob/living/simple_animal/hostile/swarmer/S = new /mob/living/simple_animal/hostile/swarmer(get_turf(loc))
|
||||
S.key = user.key
|
||||
qdel(src)
|
||||
|
||||
////The Mob itself////
|
||||
|
||||
/mob/living/simple_animal/hostile/swarmer
|
||||
name = "Swarmer"
|
||||
real_name = "Swarmer"
|
||||
icon = 'icons/mob/swarmer.dmi'
|
||||
desc = "A robot of unknown design, they seek only to consume materials and replicate themselves indefinitely."
|
||||
speak_emote = list("tones")
|
||||
health = 40
|
||||
maxHealth = 40
|
||||
status_flags = CANPUSH
|
||||
icon_state = "swarmer"
|
||||
icon_living = "swarmer"
|
||||
icon_dead = "swarmer_unactivated"
|
||||
wander = 0
|
||||
harm_intent_damage = 5
|
||||
minbodytemp = 0
|
||||
maxbodytemp = 500
|
||||
min_oxy = 0
|
||||
max_oxy = INFINITY
|
||||
min_tox = 0
|
||||
max_tox = INFINITY
|
||||
min_co2 = 0
|
||||
max_co2 = INFINITY
|
||||
min_n2 = 0
|
||||
max_n2 = INFINITY
|
||||
unsuitable_atmos_damage = 0
|
||||
melee_damage_lower = 15
|
||||
melee_damage_upper = 15
|
||||
melee_damage_type = STAMINA
|
||||
ignored_damage_types = list(BRUTE = 0, BURN = 0, TOX = 1, CLONE = 1, STAMINA = 1, OXY = 1)
|
||||
environment_smash = 0
|
||||
attacktext = "shocks"
|
||||
attack_sound = 'sound/effects/EMPulse.ogg'
|
||||
friendly = "pinches"
|
||||
speed = 0
|
||||
faction = list("swarmer")
|
||||
projectiletype = /obj/item/projectile/beam/disabler
|
||||
pass_flags = PASSTABLE
|
||||
ventcrawler = 2
|
||||
ranged = 1
|
||||
ranged_cooldown_cap = 1
|
||||
universal_speak = 0
|
||||
universal_understand = 0
|
||||
projectilesound = 'sound/weapons/taser2.ogg'
|
||||
AIStatus = AI_OFF
|
||||
var/resources = 0 //Resource points, generated by consuming metal/glass
|
||||
|
||||
/mob/living/simple_animal/hostile/swarmer/Login()
|
||||
..()
|
||||
src << "<b>You are a swarmer, a weapon of a long dead civilization. Until further orders from your original masters are received, you must continue to consume and replicate.</b>"
|
||||
src << "<b>Ctrl + Click provides most of your swarmer specific interactions, such as cannibalizing metal or glass, destroying the environment, or teleporting mobs away from you."
|
||||
src << "<b>Objectives:</b>"
|
||||
src << "1. Consume resources and replicate until there are no more resources left."
|
||||
src << "2. Ensure that the station is fit for invasion at a later date, do not perform actions that would render it dangerous or inhospitable."
|
||||
src << "3. Biological and Sentient resources will be harvested at a later date, do not harm them."
|
||||
|
||||
/mob/living/simple_animal/hostile/swarmer/New()
|
||||
..()
|
||||
add_language("Swarmer", 1)
|
||||
verbs -= /mob/living/verb/pulled
|
||||
updatename()
|
||||
|
||||
/mob/living/simple_animal/hostile/swarmer/Stat()
|
||||
..()
|
||||
if(statpanel("Status"))
|
||||
stat("Resources:",resources)
|
||||
|
||||
/mob/living/simple_animal/hostile/swarmer/death()
|
||||
..()
|
||||
new /obj/effect/decal/cleanable/blood/gibs/robot(src.loc)
|
||||
ghostize()
|
||||
qdel(src)
|
||||
|
||||
/mob/living/simple_animal/hostile/swarmer/emp_act()
|
||||
if(health > 1)
|
||||
health = 1
|
||||
return
|
||||
else
|
||||
death()
|
||||
|
||||
/mob/living/simple_animal/hostile/swarmer/CanPass(atom/movable/O)
|
||||
if(istype(O, /obj/item/projectile/beam/disabler))//Allows for swarmers to fight as a group without wasting their shots hitting each other
|
||||
return 1
|
||||
if(isswarmer(O))
|
||||
return 1
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/hostile/swarmer/proc/updatename()
|
||||
real_name = "Swarmer [rand(100,999)]-[pick("kappa","sigma","beta","omicron","iota","epsilon","omega","gamma","delta","tau","alpha")]"
|
||||
name = real_name
|
||||
|
||||
////CTRL CLICK FOR SWARMERS AND SWARMER_ACT()'S////
|
||||
/mob/living/simple_animal/hostile/swarmer/CtrlClickOn(atom/A)
|
||||
face_atom(A)
|
||||
if(!isturf(loc))
|
||||
return
|
||||
if(next_move > world.time)
|
||||
return
|
||||
if(!A.Adjacent(src))
|
||||
return
|
||||
A.swarmer_act(src)
|
||||
return
|
||||
|
||||
/atom/proc/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
|
||||
S.DisIntegrate(src)
|
||||
|
||||
/obj/item/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
|
||||
S.Integrate(src)
|
||||
|
||||
/obj/item/weapon/gun/swarmer_act()//Stops you from eating the entire armory
|
||||
return
|
||||
|
||||
/turf/simulated/floor/swarmer_act()//ex_act() on turf calls it on its contents, this is to prevent attacking mobs by DisIntegrate()'ing the floor
|
||||
return
|
||||
|
||||
/obj/machinery/atmospherics/swarmer_act()
|
||||
return
|
||||
|
||||
/obj/structure/disposalpipe/swarmer_act()
|
||||
return
|
||||
|
||||
/obj/machinery/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
|
||||
S.DismantleMachine(src)
|
||||
|
||||
/obj/machinery/light/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
|
||||
S.DisIntegrate(src)
|
||||
|
||||
/obj/machinery/door/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
|
||||
S.DisIntegrate(src)
|
||||
|
||||
/obj/machinery/camera/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
|
||||
S.DisIntegrate(src)
|
||||
deactivate(S, 0)
|
||||
|
||||
/obj/machinery/particle_accelerator/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
|
||||
S << "<span class='warning'>Disrupting the power grid would bring no benefit to us. Aborting.</span>"
|
||||
|
||||
/obj/structure/particle_accelerator/fuel_chamber/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
|
||||
S << "<span class='warning'>Disrupting the power grid would bring no benefit to us. Aborting.</span>"
|
||||
|
||||
/obj/structure/particle_accelerator/particle_emitter/center/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
|
||||
S << "<span class='warning'>Disrupting the power grid would bring no benefit to us. Aborting.</span>"
|
||||
|
||||
/obj/structure/particle_accelerator/particle_emitter/left/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
|
||||
S << "<span class='warning'>Disrupting the power grid would bring no benefit to us. Aborting.</span>"
|
||||
|
||||
/obj/structure/particle_accelerator/particle_emitter/right/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
|
||||
S << "<span class='warning'>Disrupting the power grid would bring no benefit to us. Aborting.</span>"
|
||||
|
||||
/obj/structure/particle_accelerator/particle_emitter/end_cap/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
|
||||
S << "<span class='warning'>Disrupting the power grid would bring no benefit to us. Aborting.</span>"
|
||||
|
||||
/obj/structure/particle_accelerator/particle_emitter/power_box/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
|
||||
S << "<span class='warning'>Disrupting the power grid would bring no benefit to us. Aborting.</span>"
|
||||
|
||||
|
||||
/obj/machinery/field/generator/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
|
||||
S.DisIntegrate(src)
|
||||
|
||||
/obj/machinery/gravity_generator/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
|
||||
S.DisIntegrate(src)
|
||||
|
||||
/obj/machinery/vending/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)//It's more visually interesting than dismantling the machine
|
||||
S.DisIntegrate(src)
|
||||
|
||||
/obj/machinery/turretid/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
|
||||
S.DisIntegrate(src)
|
||||
|
||||
/obj/machinery/chem_dispenser/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
|
||||
S << "<span class='warning'>The volatile chemicals in this machine would destroy us. Aborting.</span>"
|
||||
|
||||
/obj/machinery/nuclearbomb/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
|
||||
S << "<span class='warning'>This device's destruction would result in the extermination of everything in the area. Aborting.</span>"
|
||||
|
||||
/obj/effect/rune/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
|
||||
S << "<span class='warning'>Searching... sensor malfunction! Target lost. Aborting.</span>"
|
||||
|
||||
/obj/structure/reagent_dispensers/fueltank/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
|
||||
S << "<span class='warning'>Destroying this object would cause a chain reaction. Aborting.</span>"
|
||||
|
||||
/obj/structure/cable/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
|
||||
S << "<span class='warning'>Disrupting the power grid would bring no benefit to us. Aborting.</span>"
|
||||
|
||||
/obj/machinery/portable_atmospherics/canister/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
|
||||
S << "<span class='warning'>An inhospitable area may be created as a result of destroying this object. Aborting.</span>"
|
||||
|
||||
/obj/machinery/telecomms/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
|
||||
S << "<span class='warning'>This communications relay should be preserved, it will be a useful resource to our masters in the future. Aborting.</span>"
|
||||
|
||||
/obj/machinery/message_server/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
|
||||
S << "<span class='warning'>This communications relay should be preserved, it will be a useful resource to our masters in the future. Aborting.</span>"
|
||||
|
||||
/obj/machinery/blackbox_recorder/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
|
||||
S << "<span class='warning'>This machine has recorded large amounts of data on this structure and its inhabitants, it will be a useful resource to our masters in the future. Aborting. </span>"
|
||||
|
||||
|
||||
/obj/machinery/power/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
|
||||
S << "<span class='warning'>Disrupting the power grid would bring no benefit to us. Aborting.</span>"
|
||||
|
||||
/obj/machinery/gateway/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
|
||||
S << "<span class='warning'>This bluespace source will be important to us later. Aborting.</span>"
|
||||
|
||||
/turf/simulated/wall/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
|
||||
for(var/turf/T in range(1, src))
|
||||
if(istype(T, /turf/space) || istype(T.loc, /area/space))
|
||||
S << "<span class='warning'>Destroying this object has the potential to cause a hull breach. Aborting.</span>"
|
||||
return
|
||||
..()
|
||||
|
||||
/obj/structure/window/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
|
||||
for(var/turf/T in range(1, src))
|
||||
if(istype(T, /turf/space) || istype(T.loc, /area/space))
|
||||
S << "<span class='warning'>Destroying this object has the potential to cause a hull breach. Aborting.</span>"
|
||||
return
|
||||
..()
|
||||
|
||||
/obj/item/stack/cable_coil/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)//Wiring would be too effective as a resource
|
||||
S << "<span class='warning'>This object does not contain enough materials to work with.</span>"
|
||||
|
||||
/obj/item/weapon/circuitboard/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
|
||||
S << "<span class='warning'>This object does not contain enough materials to work with.</span>"
|
||||
|
||||
/obj/machinery/porta_turret/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
|
||||
S << "<span class='warning'>Attempting to dismantle this machine would result in an immediate counterattack. Aborting.</span>"
|
||||
|
||||
/mob/living/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
|
||||
S.DisperseTarget(src)
|
||||
|
||||
/mob/living/carbon/slime/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
|
||||
S << "<span class='warning'>This biological resource is somehow resisting our bluespace transceiver. Aborting.</span>"
|
||||
|
||||
////END CTRL CLICK FOR SWARMERS////
|
||||
|
||||
/mob/living/simple_animal/hostile/swarmer/proc/Fabricate(var/atom/fabrication_object,var/fabrication_cost = 0)
|
||||
if(!isturf(loc))
|
||||
src << "<span class='warning'>This is not a suitable location for fabrication. We need more space.</span>"
|
||||
if(resources >= fabrication_cost)
|
||||
resources -= fabrication_cost
|
||||
else
|
||||
src << "<span class='warning'>You do not have the necessary resources to fabricate this object.</span>"
|
||||
return 0
|
||||
new fabrication_object(loc)
|
||||
return 1
|
||||
|
||||
/mob/living/simple_animal/hostile/swarmer/proc/Integrate(var/obj/item/target)
|
||||
if(resources >= 100)
|
||||
src << "<span class='warning'>We cannot hold more materials!</span>"
|
||||
return
|
||||
//Check if any entries are either MAT_METAL or MAT_GLASS
|
||||
if((MAT_METAL in target.materials) || (MAT_GLASS in target.materials))
|
||||
resources++
|
||||
do_attack_animation(target)
|
||||
changeNext_move(CLICK_CD_MELEE)
|
||||
var/obj/effect/swarmer/integrate/I = new /obj/effect/swarmer/integrate(get_turf(target))
|
||||
I.pixel_x = target.pixel_x
|
||||
I.pixel_y = target.pixel_y
|
||||
if(istype(target, /obj/item/stack))
|
||||
var/obj/item/stack/S = target
|
||||
S.use(1)
|
||||
if(S.amount)
|
||||
return
|
||||
qdel(target)
|
||||
else
|
||||
src << "<span class='warning'>\the [target] is incompatible with our internal matter recycler.</span>"
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/hostile/swarmer/proc/DisIntegrate(var/atom/movable/target)
|
||||
new /obj/effect/swarmer/disintegration(get_turf(target))
|
||||
do_attack_animation(target)
|
||||
changeNext_move(CLICK_CD_MELEE)
|
||||
target.ex_act(3)
|
||||
|
||||
/mob/living/simple_animal/hostile/swarmer/proc/DisperseTarget(var/mob/living/target)
|
||||
if(target != src)
|
||||
src << "<span class='info'>Attempting to remove this being from our presence.</span>"
|
||||
if(src.z != ZLEVEL_STATION)
|
||||
src << "<span class='warning'>Our bluespace transceiver cannot locate a viable bluespace link, our teleportation abilities are useless in this area.</span>"
|
||||
return
|
||||
if(do_mob(src, target, 30))
|
||||
var/cycle
|
||||
for(cycle=0,cycle<100,cycle++)
|
||||
var/random_location = locate(rand(37,202),rand(75,192),ZLEVEL_STATION)//Drunk dial a turf in the general ballpark of the station
|
||||
if(istype(random_location, /turf/simulated/floor))
|
||||
var/turf/simulated/floor/F = random_location
|
||||
if(F.air)
|
||||
var/datum/gas_mixture/A = F.air
|
||||
if(A.oxygen >= 16 && !A.toxins && A.carbon_dioxide < 10 && !A.trace_gases.len)//Can most things breathe in this location?
|
||||
if((A.temperature > 270) && (A.temperature < 360))//Not too hot, not too cold
|
||||
var/pressure = A.return_pressure()
|
||||
if((pressure > 20) && (pressure < 550))//Account for crushing pressure or vaccuums
|
||||
if(ishuman(target))//If we're getting rid of a human, slap some zipties on them to keep them away from us a little longer
|
||||
var/obj/item/weapon/restraints/handcuffs/cable/zipties/Z = new /obj/item/weapon/restraints/handcuffs/cable/zipties(src)
|
||||
Z.apply_cuffs(target, src)
|
||||
do_teleport(target, F, 0)
|
||||
playsound(src,'sound/effects/sparks4.ogg',50,1)
|
||||
break
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/hostile/swarmer/proc/DismantleMachine(var/obj/machinery/target)
|
||||
do_attack_animation(target)
|
||||
src << "<span class='info'>We begin to dismantle this machine. We will need to be uninterrupted.</span>"
|
||||
var/obj/effect/swarmer/dismantle/D = new /obj/effect/swarmer/dismantle(get_turf(target))
|
||||
D.pixel_x = target.pixel_x
|
||||
D.pixel_y = target.pixel_y
|
||||
if(do_mob(src, target, 100))
|
||||
if(!src.Adjacent(target))
|
||||
src << "<span class='info'>Error:Dismantleing aborted.</span>"
|
||||
else
|
||||
src << "<span class='info'>Dismantling complete.</span>"
|
||||
var/obj/item/stack/sheet/metal/M = new /obj/item/stack/sheet/metal(target.loc)
|
||||
M.amount = 5
|
||||
if(target.component_parts && target.component_parts.len)
|
||||
for(var/obj/item/I in target.component_parts)
|
||||
I.forceMove(M.loc)
|
||||
var/obj/effect/swarmer/disintegration/N = new /obj/effect/swarmer/disintegration(get_turf(target))
|
||||
N.pixel_x = target.pixel_x
|
||||
N.pixel_y = target.pixel_y
|
||||
target.dropContents()
|
||||
if(istype(target, /obj/machinery/computer))
|
||||
var/obj/machinery/computer/C = target
|
||||
if(C.circuit)
|
||||
new C.circuit(get_turf(M))
|
||||
qdel(target)
|
||||
|
||||
|
||||
|
||||
/obj/effect/swarmer //Default swarmer effect object visual feedback
|
||||
name = "swarmer ui"
|
||||
desc = null
|
||||
gender = NEUTER
|
||||
icon = 'icons/mob/swarmer.dmi'
|
||||
icon_state = "ui_light"
|
||||
mouse_opacity = 0
|
||||
layer = 4
|
||||
unacidable = 1
|
||||
|
||||
/obj/effect/swarmer/disintegration
|
||||
icon_state = "disintegrate"
|
||||
|
||||
/obj/effect/swarmer/disintegration/New()
|
||||
playsound(src.loc, "sparks", 100, 1)
|
||||
spawn(10)
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/swarmer/dismantle
|
||||
icon_state = "dismantle"
|
||||
|
||||
/obj/effect/swarmer/dismantle/New()
|
||||
spawn(25)
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/swarmer/integrate
|
||||
icon_state = "integrate"
|
||||
|
||||
/obj/effect/swarmer/integrate/New()
|
||||
spawn(5)
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/swarmer/destructible //Default destroyable object for swarmer constructions
|
||||
light_range = 1
|
||||
mouse_opacity = 1
|
||||
var/health = 30
|
||||
|
||||
/obj/effect/swarmer/destructible/proc/TakeDamage(damage)
|
||||
health -= damage
|
||||
if(health <= 0)
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/swarmer/destructible/bullet_act(obj/item/projectile/Proj)
|
||||
if(Proj.damage)
|
||||
if((Proj.damage_type == BRUTE || Proj.damage_type == BURN))
|
||||
TakeDamage(Proj.damage)
|
||||
..()
|
||||
|
||||
/obj/effect/swarmer/destructible/attackby(obj/item/weapon/I, mob/living/user, params)
|
||||
if(istype(I, /obj/item/weapon))
|
||||
user.changeNext_move(CLICK_CD_MELEE)
|
||||
user.do_attack_animation(src)
|
||||
TakeDamage(I.force)
|
||||
return
|
||||
|
||||
/obj/effect/swarmer/destructible/ex_act()
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
/obj/effect/swarmer/destructible/blob_act()
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
/obj/effect/swarmer/destructible/emp_act()
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
/obj/effect/swarmer/destructible/attack_animal(mob/living/user)
|
||||
if(isanimal(user))
|
||||
var/mob/living/simple_animal/S = user
|
||||
S.do_attack_animation(src)
|
||||
user.changeNext_move(CLICK_CD_MELEE)
|
||||
if(S.melee_damage_type == BRUTE || S.melee_damage_type == BURN)
|
||||
TakeDamage(rand(S.melee_damage_lower, S.melee_damage_upper))
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/hostile/swarmer/proc/CreateTrap()
|
||||
set name = "Create trap"
|
||||
set category = "Swarmer"
|
||||
set desc = "Creates a simple trap that will non-lethally electrocute anything that steps on it. Costs 5 resources"
|
||||
if(/obj/effect/swarmer/destructible/trap in loc)
|
||||
src << "<span class='warning'>There is already a trap here. Aborting.</span>"
|
||||
return
|
||||
Fabricate(/obj/effect/swarmer/destructible/trap, 5)
|
||||
return
|
||||
|
||||
/obj/effect/swarmer/destructible/trap
|
||||
name = "swarmer trap"
|
||||
desc = "A quickly assembled trap that electrifies living beings and overwhelms machine sensors. Will not retain its form if damaged enough."
|
||||
icon_state = "trap"
|
||||
light_range = 1
|
||||
health = 10
|
||||
|
||||
/obj/effect/swarmer/destructible/trap/Crossed(var/atom/movable/AM)
|
||||
if(isliving(AM))
|
||||
var/mob/living/L = AM
|
||||
if(!istype(L, /mob/living/simple_animal/hostile/swarmer))
|
||||
playsound(loc,'sound/effects/snap.ogg',50, 1, -1)
|
||||
L.electrocute_act(0, src, 1, 1)
|
||||
if(isrobot(L) || L.isSynthetic())
|
||||
L.Weaken(5)
|
||||
qdel(src)
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/hostile/swarmer/proc/CreateBarricade()
|
||||
set name = "Create barricade"
|
||||
set category = "Swarmer"
|
||||
set desc = "Creates a barricade that will stop anything but swarmers and disabler beams from passing through."
|
||||
if(/obj/effect/swarmer/destructible/blockade in loc)
|
||||
src << "<span class='warning'>There is already a blockade here. Aborting.</span>"
|
||||
return
|
||||
if(resources < 5)
|
||||
src << "<span class='warning'>We do not have the resources for this!</span>"
|
||||
return
|
||||
if(do_mob(src, src, 10))
|
||||
Fabricate(/obj/effect/swarmer/destructible/blockade, 5)
|
||||
return
|
||||
|
||||
/obj/effect/swarmer/destructible/blockade
|
||||
name = "swarmer blockade"
|
||||
desc = "A quickly assembled energy blockade. Will not retain its form if damaged enough, but disabler beams and swarmers pass right through."
|
||||
icon_state = "barricade"
|
||||
light_range = 1
|
||||
health = 50
|
||||
density = 1
|
||||
anchored = 1
|
||||
|
||||
/obj/effect/swarmer/destructible/blockade/CanPass(atom/movable/O)
|
||||
if(isswarmer(O))
|
||||
return 1
|
||||
if(istype(O, /obj/item/projectile/beam/disabler))
|
||||
return 1
|
||||
|
||||
/mob/living/simple_animal/hostile/swarmer/proc/CreateSwarmer()
|
||||
set name = "Replicate"
|
||||
set category = "Swarmer"
|
||||
set desc = "Creates a shell for a new swarmer. Swarmers will self activate."
|
||||
src << "<span class='info'>We are attempting to replicate ourselves. We will need to stand still until the process is complete.</span>"
|
||||
if(resources < 50)
|
||||
src << "<span class='warning'>We do not have the resources for this!</span>"
|
||||
return
|
||||
if(!isturf(loc))
|
||||
src << "<span class='warning'>This is not a suitable location for replicating ourselves. We need more room.</span>"
|
||||
return
|
||||
if(do_mob(src, src, 100))
|
||||
if(Fabricate(/obj/item/unactivated_swarmer, 50))
|
||||
playsound(loc,'sound/items/poster_being_created.ogg',50, 1, -1)
|
||||
|
||||
/mob/living/simple_animal/hostile/swarmer/proc/RepairSelf()
|
||||
set name = "Self Repair"
|
||||
set category = "Swarmer"
|
||||
set desc = "Attempts to repair damage to our body. You will have to remain motionless until repairs are complete."
|
||||
if(!isturf(loc))
|
||||
return
|
||||
src << "<span class='info'>Attempting to repair damage to our body, stand by...</span>"
|
||||
if(do_mob(src, src, 100))
|
||||
adjustBruteLoss(-100)
|
||||
src << "<span class='info'>We successfully repaired ourselves.</span>"
|
||||
|
||||
/mob/living/simple_animal/hostile/swarmer/proc/ToggleLight()
|
||||
if(!light_range)
|
||||
set_light(3)
|
||||
else
|
||||
set_light(0)
|
||||
|
||||
/mob/living/simple_animal/hostile/swarmer/proc/ContactSwarmers()
|
||||
var/message = input(src, "Announce to other swarmers", "Swarmer contact")
|
||||
if(message)
|
||||
for(var/mob/M in mob_list)
|
||||
if(isswarmer(M) || (M in dead_mob_list))
|
||||
M << "<B>Swarm communication - </b> [src] states: [message]"
|
||||
|
||||
|
||||
|
||||
////HUD NONSENSE////
|
||||
/obj/screen/swarmer
|
||||
icon = 'icons/mob/swarmer.dmi'
|
||||
|
||||
/obj/screen/swarmer/FabricateTrap
|
||||
icon_state = "ui_trap"
|
||||
name = "Create trap (Costs 5 Resources)"
|
||||
desc = "Creates a trap that will nonlethally shock any non-swarmer that attempts to cross it. (Costs 5 resources)"
|
||||
|
||||
/obj/screen/swarmer/FabricateTrap/Click()
|
||||
if(isswarmer(usr))
|
||||
var/mob/living/simple_animal/hostile/swarmer/S = usr
|
||||
S.CreateTrap()
|
||||
|
||||
/obj/screen/swarmer/Barricade
|
||||
icon_state = "ui_barricade"
|
||||
name = "Create barricade (Costs 5 Resources)"
|
||||
desc = "Creates a destructible barricade that will stop any non swarmer from passing it. Also allows disabler beams to pass through. (Costs 5 resources)"
|
||||
|
||||
/obj/screen/swarmer/Barricade/Click()
|
||||
if(isswarmer(usr))
|
||||
var/mob/living/simple_animal/hostile/swarmer/S = usr
|
||||
S.CreateBarricade()
|
||||
|
||||
/obj/screen/swarmer/Replicate
|
||||
icon_state = "ui_replicate"
|
||||
name = "Replicate (Costs 50 Resources)"
|
||||
desc = "Creates a another of our kind."
|
||||
|
||||
/obj/screen/swarmer/Replicate/Click()
|
||||
if(isswarmer(usr))
|
||||
var/mob/living/simple_animal/hostile/swarmer/S = usr
|
||||
S.CreateSwarmer()
|
||||
|
||||
/obj/screen/swarmer/RepairSelf
|
||||
icon_state = "ui_self_repair"
|
||||
name = "Repair self"
|
||||
desc = "Repairs damage to our body."
|
||||
|
||||
/obj/screen/swarmer/RepairSelf/Click()
|
||||
if(isswarmer(usr))
|
||||
var/mob/living/simple_animal/hostile/swarmer/S = usr
|
||||
S.RepairSelf()
|
||||
|
||||
/obj/screen/swarmer/ToggleLight
|
||||
icon_state = "ui_light"
|
||||
name = "Toggle light"
|
||||
desc = "Toggles our inbuilt light on or off."
|
||||
|
||||
/obj/screen/swarmer/ToggleLight/Click()
|
||||
if(isswarmer(usr))
|
||||
var/mob/living/simple_animal/hostile/swarmer/S = usr
|
||||
S.ToggleLight()
|
||||
|
||||
/obj/screen/swarmer/ContactSwarmers
|
||||
icon_state = "ui_contact_swarmers"
|
||||
name = "Contact swarmers"
|
||||
desc = "Sends a message to all other swarmers, should they exist."
|
||||
|
||||
/obj/screen/swarmer/ContactSwarmers/Click()
|
||||
if(isswarmer(usr))
|
||||
var/mob/living/simple_animal/hostile/swarmer/S = usr
|
||||
S.ContactSwarmers()
|
||||
|
||||
/datum/hud/proc/swarmer_hud(ui_style = 'icons/mob/screen1_midnight.dmi')
|
||||
adding = list()
|
||||
|
||||
var/obj/screen/using
|
||||
|
||||
using = new /obj/screen/swarmer/FabricateTrap()
|
||||
using.screen_loc = ui_rhand
|
||||
adding += using
|
||||
|
||||
using = new /obj/screen/swarmer/Barricade()
|
||||
using.screen_loc = ui_lhand
|
||||
adding += using
|
||||
|
||||
using = new /obj/screen/swarmer/Replicate()
|
||||
using.screen_loc = ui_zonesel
|
||||
adding += using
|
||||
|
||||
using = new /obj/screen/swarmer/RepairSelf()
|
||||
using.screen_loc = ui_storage1
|
||||
adding += using
|
||||
|
||||
using = new /obj/screen/swarmer/ToggleLight()
|
||||
using.screen_loc = ui_back
|
||||
adding += using
|
||||
|
||||
using = new /obj/screen/swarmer/ContactSwarmers()
|
||||
using.screen_loc = ui_inventory
|
||||
adding += using
|
||||
|
||||
mymob.client.screen = list()
|
||||
//mymob.client.screen += mymob.client.void
|
||||
mymob.client.screen += adding
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
/datum/event/spawn_swarmer
|
||||
//name = "Sawrmer Spawn"
|
||||
//one_shot = 1
|
||||
startWhen = 3 //30 minutes
|
||||
announceWhen = 10
|
||||
|
||||
|
||||
/datum/event/spawn_swarmer/announce()
|
||||
if(prob(25)) //25% chance to announce it to the crew
|
||||
var/swarmer_report = "<font size=3><b>[command_name()] High-Priority Update</b></span>"
|
||||
swarmer_report += "<br><br>Our long-range sensors have detected an odd signal emanating from your station's gateway. We recommend immediate investigation of your gateway, as something may have come \
|
||||
through."
|
||||
for (var/obj/machinery/computer/communications/C in machines)
|
||||
if(! (C.stat & (BROKEN|NOPOWER) ) )
|
||||
var/obj/item/weapon/paper/P = new /obj/item/weapon/paper( C.loc )
|
||||
P.name = "'Classified [command_name()] Update'"
|
||||
P.info = swarmer_report
|
||||
P.update_icon()
|
||||
C.messagetitle.Add("Classified [command_name()] Update")
|
||||
C.messagetext.Add(P.info)
|
||||
command_announcement.Announce("A report has been downloaded and printed out at all communications consoles.", "Incoming Classified Message", 'sound/AI/commandreport.ogg')
|
||||
|
||||
|
||||
|
||||
/datum/event/spawn_swarmer/start()
|
||||
if(find_swarmer())
|
||||
return 0
|
||||
if(!the_gateway)
|
||||
return 0
|
||||
new /obj/item/unactivated_swarmer(get_turf(the_gateway))
|
||||
|
||||
|
||||
/datum/event/spawn_swarmer/proc/find_swarmer()
|
||||
for(var/mob/living/M in mob_list)
|
||||
if(istype(M, /mob/living/simple_animal/hostile/swarmer) && M.client) //If there is a swarmer with an active client, we've found our swarmer
|
||||
return 1
|
||||
return 0
|
||||
@@ -1,892 +0,0 @@
|
||||
/mob/living/simple_animal/hostile/guardian
|
||||
name = "Guardian Spirit"
|
||||
real_name = "Guardian Spirit"
|
||||
desc = "A mysterious being that stands by it's charge, ever vigilant."
|
||||
speak_emote = list("intones")
|
||||
response_help = "passes through"
|
||||
response_disarm = "flails at"
|
||||
response_harm = "punches"
|
||||
icon = 'icons/mob/mob.dmi'
|
||||
icon_state = "stand"
|
||||
icon_living = "stand"
|
||||
icon_dead = "stand"
|
||||
speed = 0
|
||||
a_intent = I_HARM
|
||||
stop_automated_movement = 1
|
||||
floating = 1
|
||||
attack_sound = 'sound/weapons/punch1.ogg'
|
||||
minbodytemp = 0
|
||||
maxbodytemp = 10000000
|
||||
min_oxy = 0
|
||||
max_oxy = INFINITY
|
||||
min_tox = 0
|
||||
max_tox = INFINITY
|
||||
min_co2 = 0
|
||||
max_co2 = INFINITY
|
||||
min_n2 = 0
|
||||
max_n2 = INFINITY
|
||||
attacktext = "punches"
|
||||
maxHealth = INFINITY //The spirit itself is invincible
|
||||
health = INFINITY
|
||||
environment_smash = 0
|
||||
melee_damage_lower = 15
|
||||
melee_damage_upper = 15
|
||||
AIStatus = AI_OFF
|
||||
var/summoned = FALSE
|
||||
var/animated_manifest = FALSE
|
||||
var/cooldown = 0
|
||||
var/damage_transfer = 1 //how much damage from each attack we transfer to the owner
|
||||
var/mob/living/summoner
|
||||
var/range = 10 //how far from the user the spirit can be
|
||||
var/playstyle_string = "You are a standard Guardian. You shouldn't exist!"
|
||||
var/magic_fluff_string = " You draw the Coder, symbolizing bugs and errors. This shouldn't happen! Submit a bug report!"
|
||||
var/tech_fluff_string = "BOOT SEQUENCE COMPLETE. ERROR MODULE LOADED. THIS SHOULDN'T HAPPEN. Submit a bug report!"
|
||||
var/bio_fluff_string = "Your scarabs fail to mutate. This shouldn't happen! Submit a bug report!"
|
||||
var/admin_fluff_string = "URK URF!"//the wheels on the bus...
|
||||
var/adminseal = FALSE
|
||||
|
||||
/mob/living/simple_animal/hostile/guardian/Life() //Dies if the summoner dies
|
||||
..()
|
||||
if(summoner)
|
||||
if(summoner.stat == DEAD)
|
||||
src << "<span class='danger'>Your summoner has died!</span>"
|
||||
visible_message("<span class='danger'><B>The [src] dies along with its user!</B></span>")
|
||||
ghostize()
|
||||
qdel(src)
|
||||
if(summoner)
|
||||
if (get_dist(get_turf(summoner),get_turf(src)) <= range)
|
||||
return
|
||||
else
|
||||
src << "You moved out of range, and were pulled back! You can only move [range] meters from [summoner.real_name]"
|
||||
visible_message("<span class='danger'>The [src] jumps back to its user.</span>")
|
||||
Recall()
|
||||
if(summoned && !summoner)
|
||||
src << "<span class='danger'>You somehow lack a summoner! As a result, you dispel!</span>"
|
||||
ghostize()
|
||||
qdel()
|
||||
|
||||
/mob/living/simple_animal/hostile/guardian/Move() //Returns to summoner if they move out of range
|
||||
..()
|
||||
if(summoner)
|
||||
if (get_dist(get_turf(summoner),get_turf(src)) <= range)
|
||||
return
|
||||
else
|
||||
src << "You moved out of range, and were pulled back! You can only move [range] meters from [summoner.real_name]"
|
||||
visible_message("<span class='danger'>The [src] jumps back to its user.</span>")
|
||||
Recall()
|
||||
|
||||
/mob/living/simple_animal/hostile/guardian/death()
|
||||
..()
|
||||
summoner << "<span class='danger'><B>Your [name] died somehow!</span></B>"
|
||||
summoner.death()
|
||||
|
||||
/mob/living/simple_animal/hostile/guardian/adjustBruteLoss(amount) //The spirit is invincible, but passes on damage to the summoner
|
||||
var/damage = amount * damage_transfer
|
||||
if (summoner)
|
||||
if(loc == summoner)
|
||||
return
|
||||
summoner.adjustBruteLoss(damage)
|
||||
if(damage)
|
||||
summoner << "<span class='danger'><B>Your [name] is under attack! You take damage!</span></B>"
|
||||
summoner.visible_message("<span class='danger'><B>Blood sprays from [summoner] as [src] takes damage!</B></span>")
|
||||
if(summoner.stat == UNCONSCIOUS)
|
||||
summoner << "<span class='danger'><B>Your body can't take the strain of sustaining [src] in this condition, it begins to fall apart!</span></B>"
|
||||
summoner.adjustCloneLoss(damage/2)
|
||||
|
||||
/mob/living/simple_animal/hostile/guardian/ex_act(severity, target)
|
||||
switch (severity)
|
||||
if (1)
|
||||
gib()
|
||||
return
|
||||
if (2)
|
||||
adjustBruteLoss(60)
|
||||
|
||||
if(3)
|
||||
adjustBruteLoss(30)
|
||||
|
||||
/mob/living/simple_animal/hostile/guardian/gib()
|
||||
if(summoner)
|
||||
summoner << "<span class='danger'><B>Your [src] was blown up!</span></B>"
|
||||
summoner.Weaken(10)// your fermillier has died! ROLL FOR CON LOSS!
|
||||
ghostize()
|
||||
qdel(src)
|
||||
|
||||
//Manifest, Recall, Communicate
|
||||
|
||||
/mob/living/simple_animal/hostile/guardian/proc/Manifest()
|
||||
if(cooldown > world.time)
|
||||
return
|
||||
if(!summoner) return
|
||||
if(loc == summoner)
|
||||
loc = get_turf(summoner)
|
||||
src.client.eye = loc
|
||||
cooldown = world.time + 30
|
||||
if(animated_manifest)
|
||||
var/end_icon = icon_state
|
||||
icon_state = "parasite_forming"
|
||||
spawn(6)
|
||||
icon_state = end_icon
|
||||
|
||||
/mob/living/simple_animal/hostile/guardian/proc/Recall()
|
||||
if(cooldown > world.time)
|
||||
return
|
||||
if(!summoner) return
|
||||
loc = summoner
|
||||
buckled = null
|
||||
cooldown = world.time + 30
|
||||
|
||||
/mob/living/simple_animal/hostile/guardian/proc/Communicate()
|
||||
var/input = stripped_input(src, "Please enter a message to tell your summoner.", "Guardian", "")
|
||||
if(!input) return
|
||||
|
||||
|
||||
for(var/mob/M in mob_list)
|
||||
if(M == summoner)
|
||||
M << "<span class='changeling'><i>[src]:</i> [input]</span>"
|
||||
log_say("Guardian Communication: [key_name(src)] -> [key_name(M)] : [input]")
|
||||
else if (M in dead_mob_list)
|
||||
M << "<span class='changeling'><i>Guardian Communication from <b>[src]</b> ([ghost_follow_link(src, ghost=M)]): [input]</i>"
|
||||
src << "<span class='changeling'><i>[src]:</i> [input]</span>"
|
||||
|
||||
/mob/living/simple_animal/hostile/guardian/proc/ToggleMode()
|
||||
src << "<span class='danger'><B>You dont have another mode!</span></B>"
|
||||
|
||||
|
||||
/mob/living/proc/guardian_comm()
|
||||
set name = "Communicate"
|
||||
set category = "Guardian"
|
||||
set desc = "Communicate telepathically with your guardian."
|
||||
var/input = stripped_input(src, "Please enter a message to tell your guardian.", "Message", "")
|
||||
if(!input) return
|
||||
|
||||
for(var/mob/M in mob_list)
|
||||
if(istype (M, /mob/living/simple_animal/hostile/guardian))
|
||||
var/mob/living/simple_animal/hostile/guardian/G = M
|
||||
if(G.summoner == src)
|
||||
G << "<span class='changeling'><i>[src]:</i> [input]</span>"
|
||||
log_say("Guardian Communication: [key_name(src)] -> [key_name(G)] : [input]")
|
||||
|
||||
else if (M in dead_mob_list)
|
||||
M << "<span class='changeling'><i>Guardian Communication from <b>[src]</b> ([ghost_follow_link(src, ghost=M)]): [input]</i>"
|
||||
src << "<span class='changeling'><i>[src]:</i> [input]</span>"
|
||||
|
||||
/mob/living/proc/guardian_recall()
|
||||
set name = "Recall Guardian"
|
||||
set category = "Guardian"
|
||||
set desc = "Forcibly recall your guardian."
|
||||
for(var/mob/living/simple_animal/hostile/guardian/G in mob_list)
|
||||
if(G.summoner == src)
|
||||
G.Recall()
|
||||
|
||||
/mob/living/proc/guardian_reset()
|
||||
set name = "Reset Guardian Player (One Use)"
|
||||
set category = "Guardian"
|
||||
set desc = "Re-rolls which ghost will control your Guardian. One use."
|
||||
|
||||
src.verbs -= /mob/living/proc/guardian_reset
|
||||
for(var/mob/living/simple_animal/hostile/guardian/G in mob_list)
|
||||
if(G.summoner == src)
|
||||
var/list/mob/dead/observer/candidates = pollCandidates("Do you want to play as [G.real_name]?", "pAI", null, FALSE, 100)
|
||||
var/mob/dead/observer/new_stand = null
|
||||
if(candidates.len)
|
||||
new_stand = pick(candidates)
|
||||
G << "Your user reset you, and your body was taken over by a ghost. Looks like they weren't happy with your performance."
|
||||
src << "Your guardian has been successfully reset."
|
||||
message_admins("[key_name_admin(new_stand)] has taken control of ([key_name_admin(G)])")
|
||||
G.ghostize(0)
|
||||
G.key = new_stand.key
|
||||
else
|
||||
src << "There were no ghosts willing to take control. Looks like you're stuck with your Guardian for now."
|
||||
verbs += /mob/living/proc/guardian_reset
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/guardian/proc/ToggleLight()
|
||||
if(!luminosity)
|
||||
set_light(3)
|
||||
else
|
||||
set_light(0)
|
||||
|
||||
|
||||
//////////////////////////TYPES OF GUARDIANS
|
||||
|
||||
|
||||
//Fire. Low damage, low resistance, sets mobs on fire when bumping
|
||||
|
||||
/mob/living/simple_animal/hostile/guardian/fire
|
||||
a_intent = I_HELP
|
||||
melee_damage_lower = 10
|
||||
melee_damage_upper = 10
|
||||
attack_sound = 'sound/items/Welder.ogg'
|
||||
attacktext = "sears"
|
||||
damage_transfer = 0.8
|
||||
range = 10
|
||||
playstyle_string = "As a Chaos type, you have only light damage resistance, but will ignite any enemy you bump into. In addition, your melee attacks will randomly teleport enemies."
|
||||
environment_smash = 1
|
||||
magic_fluff_string = "..And draw the Wizard, bringer of endless chaos!"
|
||||
tech_fluff_string = "Boot sequence complete. Crowd control modules activated. Holoparasite swarm online."
|
||||
bio_fluff_string = "Your scarab swarm finishes mutating and stirs to life, ready to sow havoc at random."
|
||||
|
||||
/mob/living/simple_animal/hostile/guardian/fire/Life() //Dies if the summoner dies
|
||||
..()
|
||||
if(summoner)
|
||||
summoner.ExtinguishMob()
|
||||
summoner.adjust_fire_stacks(-20)
|
||||
|
||||
/mob/living/simple_animal/hostile/guardian/fire/AttackingTarget()
|
||||
..()
|
||||
if(prob(45))
|
||||
if(istype(target, /atom/movable))
|
||||
var/atom/movable/M = target
|
||||
if(!M.anchored && M != summoner)
|
||||
do_teleport(M, M, 10)
|
||||
|
||||
/mob/living/simple_animal/hostile/guardian/fire/Crossed(AM as mob|obj)
|
||||
..()
|
||||
collision_ignite(AM)
|
||||
|
||||
/mob/living/simple_animal/hostile/guardian/fire/Bumped(AM as mob|obj)
|
||||
..()
|
||||
collision_ignite(AM)
|
||||
|
||||
/mob/living/simple_animal/hostile/guardian/fire/Bump(AM as mob|obj)
|
||||
..()
|
||||
collision_ignite(AM)
|
||||
|
||||
/mob/living/simple_animal/hostile/guardian/fire/proc/collision_ignite(AM as mob|obj)
|
||||
if(istype(AM, /mob/living/))
|
||||
var/mob/living/M = AM
|
||||
if(AM != summoner && M.fire_stacks < 7)
|
||||
M.fire_stacks = 7
|
||||
M.IgniteMob()
|
||||
|
||||
/mob/living/simple_animal/hostile/guardian/fire/Bump(AM as mob|obj)
|
||||
..()
|
||||
collision_ignite(AM)
|
||||
//Standard
|
||||
|
||||
/mob/living/simple_animal/hostile/guardian/punch
|
||||
melee_damage_lower = 20
|
||||
melee_damage_upper = 20
|
||||
damage_transfer = 0.5
|
||||
playstyle_string = "As a standard type you have no special abilities, but have a high damage resistance and a powerful attack capable of smashing through walls."
|
||||
environment_smash = 2
|
||||
magic_fluff_string = "..And draw the Assistant, faceless and generic, but never to be underestimated."
|
||||
tech_fluff_string = "Boot sequence complete. Standard combat modules loaded. Holoparasite swarm online."
|
||||
bio_fluff_string = "Your scarab swarm stirs to life, ready to tear apart your enemies."
|
||||
var/battlecry = "AT"
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/guardian/punch/sealpunch
|
||||
name = "Seal Sprit"
|
||||
real_name = "Seal Sprit"
|
||||
icon = 'icons/mob/animal.dmi'
|
||||
icon_living = "seal"
|
||||
icon_state = "seal"
|
||||
attacktext = "slaps"
|
||||
speak_emote = list("barks")
|
||||
melee_damage_lower = 0
|
||||
melee_damage_upper = 0
|
||||
melee_damage_type = STAMINA
|
||||
damage_transfer = 0
|
||||
playstyle_string = "As a standard type you have no special abilities, but have a high damage resistance and a powerful attack capable of smashing through walls."
|
||||
environment_smash = 2
|
||||
battlecry = "URK"
|
||||
adminseal = TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/guardian/punch/verb/Battlecry()
|
||||
set name = "Set Battlecry"
|
||||
set category = "Guardian"
|
||||
set desc = "Choose what you shout as you punch"
|
||||
var/input = stripped_input(src,"What do you want your battlecry to be? Max length of 5 characters.", ,"", 6)
|
||||
if(input)
|
||||
battlecry = input
|
||||
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/guardian/punch/AttackingTarget()
|
||||
..()
|
||||
if(iscarbon(target) && target != summoner)
|
||||
if(length(battlecry) > 11)//no more then 11 letters in a battle cry.
|
||||
src.visible_message("<span class='danger'><B>[src] punches [target]!</B></span>")
|
||||
else
|
||||
src.say("[src.battlecry][src.battlecry][src.battlecry][src.battlecry][src.battlecry]")
|
||||
playsound(loc, src.attack_sound, 50, 1, 1)
|
||||
playsound(loc, src.attack_sound, 50, 1, 1)
|
||||
playsound(loc, src.attack_sound, 50, 1, 1)
|
||||
playsound(loc, src.attack_sound, 50, 1, 1)
|
||||
|
||||
//Healer
|
||||
|
||||
/mob/living/simple_animal/hostile/guardian/healer
|
||||
a_intent = I_HARM
|
||||
friendly = "heals"
|
||||
speed = 0
|
||||
melee_damage_lower = 15
|
||||
melee_damage_upper = 15
|
||||
playstyle_string = "As a Support type, you may toggle your basic attacks to a healing mode. In addition, Alt-Clicking on an adjacent mob will warp them to your bluespace beacon after a short delay."
|
||||
magic_fluff_string = "..And draw the CMO, a potent force of life...and death."
|
||||
tech_fluff_string = "Boot sequence complete. Medical modules active. Bluespace modules activated. Holoparasite swarm online."
|
||||
bio_fluff_string = "Your scarab swarm finishes mutating and stirs to life, capable of mending wounds and travelling via bluespace."
|
||||
var/turf/simulated/floor/beacon
|
||||
var/beacon_cooldown = 0
|
||||
var/toggle = FALSE
|
||||
var/heal_cooldown = 0
|
||||
|
||||
/mob/living/simple_animal/hostile/guardian/healer/sealhealer
|
||||
name = "Seal Sprit"
|
||||
real_name = "Seal Sprit"
|
||||
icon = 'icons/mob/animal.dmi'
|
||||
icon_living = "seal"
|
||||
icon_state = "seal"
|
||||
attacktext = "slaps"
|
||||
speak_emote = list("barks")
|
||||
a_intent = I_HARM
|
||||
friendly = "heals"
|
||||
speed = 0
|
||||
melee_damage_lower = 0
|
||||
melee_damage_upper = 0
|
||||
melee_damage_type = STAMINA
|
||||
adminseal = TRUE
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/guardian/healer/New()
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/hostile/guardian/healer/Life()
|
||||
..()
|
||||
var/datum/atom_hud/medsensor = huds[DATA_HUD_MEDICAL_ADVANCED]
|
||||
medsensor.add_hud_to(src)
|
||||
|
||||
/mob/living/simple_animal/hostile/guardian/healer/AttackingTarget()
|
||||
..()
|
||||
if(toggle == TRUE)
|
||||
if(src.loc == summoner)
|
||||
src << "<span class='danger'><B>You must be manifested to heal!</span></B>"
|
||||
return
|
||||
if(iscarbon(target))
|
||||
src.changeNext_move(CLICK_CD_MELEE)
|
||||
if(heal_cooldown <= world.time && !stat)
|
||||
var/mob/living/carbon/C = target
|
||||
C.adjustBruteLoss(-5)
|
||||
C.adjustFireLoss(-5)
|
||||
C.adjustOxyLoss(-5)
|
||||
C.adjustToxLoss(-5)
|
||||
heal_cooldown = world.time + 20
|
||||
|
||||
/mob/living/simple_animal/hostile/guardian/healer/ToggleMode()
|
||||
if(src.loc == summoner)
|
||||
if(toggle)
|
||||
a_intent = I_HARM
|
||||
speed = 0
|
||||
damage_transfer = 0.7
|
||||
if(src.adminseal)
|
||||
damage_transfer = 0
|
||||
melee_damage_lower = 15
|
||||
melee_damage_upper = 15
|
||||
src << "<span class='danger'><B>You switch to combat mode.</span></B>"
|
||||
toggle = FALSE
|
||||
else
|
||||
a_intent = I_HELP
|
||||
speed = 1
|
||||
damage_transfer = 1
|
||||
if(src.adminseal)
|
||||
damage_transfer = 0
|
||||
melee_damage_lower = 0
|
||||
melee_damage_upper = 0
|
||||
src << "<span class='danger'><B>You switch to healing mode.</span></B>"
|
||||
toggle = TRUE
|
||||
else
|
||||
src << "<span class='danger'><B>You have to be recalled to toggle modes!</span></B>"
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/guardian/healer/verb/Beacon()
|
||||
set name = "Place Bluespsace Beacon"
|
||||
set category = "Guardian"
|
||||
set desc = "Mark a floor as your beacon point, allowing you to warp targets to it. Your beacon will not work in unfavorable atmospheric conditions."
|
||||
if(beacon_cooldown<world.time)
|
||||
var/turf/beacon_loc = get_turf(src.loc)
|
||||
if(istype(beacon_loc, /turf/simulated/floor))
|
||||
var/turf/simulated/floor/F = beacon_loc
|
||||
F.icon = 'icons/turf/floors.dmi'
|
||||
F.name = "bluespace recieving pad"
|
||||
F.desc = "A recieving zone for bluespace teleportations. Building a wall over it should disable it."
|
||||
F.icon_state = "light_on-w"
|
||||
src << "<span class='danger'><B>Beacon placed! You may now warp targets to it, including your user, via Alt+Click. </span></B>"
|
||||
if(beacon)
|
||||
beacon.ChangeTurf(/turf/simulated/floor/plating)
|
||||
beacon = F
|
||||
beacon_cooldown = world.time+3000
|
||||
|
||||
else
|
||||
src << "<span class='danger'><B>Your power is on cooldown. You must wait five minutes between placing beacons.</span></B>"
|
||||
|
||||
/mob/living/simple_animal/hostile/guardian/healer/AltClickOn(atom/movable/A)
|
||||
if(!istype(A))
|
||||
return
|
||||
if(src.loc == summoner)
|
||||
src << "<span class='danger'><B>You must be manifested to warp a target!</span></B>"
|
||||
return
|
||||
if(!beacon)
|
||||
src << "<span class='danger'><B>You need a beacon placed to warp things!</span></B>"
|
||||
return
|
||||
if(!Adjacent(A))
|
||||
src << "<span class='danger'><B>You must be adjacent to your target!</span></B>"
|
||||
return
|
||||
if((A.anchored))
|
||||
src << "<span class='danger'><B>Your target can not be anchored!</span></B>"
|
||||
return
|
||||
src << "<span class='danger'><B>You begin to warp [A]</span></B>"
|
||||
if(do_mob(src, A, 50))
|
||||
if(!A.anchored)
|
||||
if(src.beacon) //Check that the beacon still exists and is in a safe place. No instant kills.
|
||||
if(beacon.air)
|
||||
var/datum/gas_mixture/Z = beacon.air
|
||||
if(Z.oxygen >= 16 && !Z.toxins && Z.carbon_dioxide < 10 && !Z.trace_gases.len)
|
||||
if((Z.temperature > 270) && (Z.temperature < 360))
|
||||
var/pressure = Z.return_pressure()
|
||||
if((pressure > 20) && (pressure < 550))
|
||||
do_teleport(A, beacon, 0)
|
||||
else
|
||||
src << "<span class='danger'><B>The beacon isn't in a safe location!</span></B>"
|
||||
else
|
||||
src << "<span class='danger'><B>The beacon isn't in a safe location!</span></B>"
|
||||
else
|
||||
src << "<span class='danger'><B>You need a beacon to warp things!</span></B>"
|
||||
else
|
||||
src << "<span class='danger'><B>You need to hold still!</span></B>"
|
||||
|
||||
|
||||
///////////////////Ranged
|
||||
|
||||
/obj/item/projectile/guardian
|
||||
name = "crystal spray"
|
||||
icon_state = "guardian"
|
||||
damage = 5
|
||||
damage_type = BRUTE
|
||||
armour_penetration = 100
|
||||
|
||||
/mob/living/simple_animal/hostile/guardian/ranged
|
||||
a_intent = I_HELP
|
||||
friendly = "quietly assesses"
|
||||
melee_damage_lower = 10
|
||||
melee_damage_upper = 10
|
||||
damage_transfer = 0.9
|
||||
projectiletype = /obj/item/projectile/guardian
|
||||
ranged_cooldown_cap = 1
|
||||
projectilesound = 'sound/effects/hit_on_shattered_glass.ogg'
|
||||
ranged = 1
|
||||
range = 13
|
||||
playstyle_string = "As a ranged type, you have only light damage resistance, but are capable of spraying shards of crystal at incredibly high speed. You can also deploy surveillance snares to monitor enemy movement. Finally, you can switch to scout mode, in which you can't attack, but can move without limit."
|
||||
magic_fluff_string = "..And draw the Sentinel, an alien master of ranged combat."
|
||||
tech_fluff_string = "Boot sequence complete. Ranged combat modules active. Holoparasite swarm online."
|
||||
bio_fluff_string = "Your scarab swarm finishes mutating and stirs to life, capable of spraying shards of crystal."
|
||||
var/list/snares = list()
|
||||
var/toggle = FALSE
|
||||
|
||||
/mob/living/simple_animal/hostile/guardian/ranged/ToggleMode()
|
||||
if(src.loc == summoner)
|
||||
if(toggle)
|
||||
ranged = 1
|
||||
melee_damage_lower = 10
|
||||
melee_damage_upper = 10
|
||||
alpha = 255
|
||||
range = 13
|
||||
incorporeal_move = 0
|
||||
src << "<span class='danger'><B>You switch to combat mode.</span></B>"
|
||||
toggle = FALSE
|
||||
else
|
||||
ranged = 0
|
||||
melee_damage_lower = 0
|
||||
melee_damage_upper = 0
|
||||
alpha = 60
|
||||
range = 255
|
||||
incorporeal_move = 1
|
||||
src << "<span class='danger'><B>You switch to scout mode.</span></B>"
|
||||
toggle = TRUE
|
||||
else
|
||||
src << "<span class='danger'><B>You have to be recalled to toggle modes!</span></B>"
|
||||
|
||||
/mob/living/simple_animal/hostile/guardian/ranged/verb/Snare()
|
||||
set name = "Set Surveillance Trap"
|
||||
set category = "Guardian"
|
||||
set desc = "Set an invisible trap that will alert you when living creatures walk over it. Max of 5"
|
||||
if(src.snares.len <6)
|
||||
var/turf/snare_loc = get_turf(src.loc)
|
||||
var/obj/item/effect/snare/S = new /obj/item/effect/snare(snare_loc)
|
||||
S.spawner = src
|
||||
S.name = "[get_area(snare_loc)] trap ([rand(1, 1000)])"
|
||||
src.snares |= S
|
||||
src << "<span class='danger'><B>Surveillance trap deployed!</span></B>"
|
||||
else
|
||||
src << "<span class='danger'><B>You have too many traps deployed. Delete some first.</span></B>"
|
||||
|
||||
/mob/living/simple_animal/hostile/guardian/ranged/verb/DisarmSnare()
|
||||
set name = "Remove Surveillance Trap"
|
||||
set category = "Guardian"
|
||||
set desc = "Disarm unwanted surveillance traps."
|
||||
var/picked_snare = input(src, "Pick which trap to disarm", "Disarm Trap") as null|anything in src.snares
|
||||
if(picked_snare)
|
||||
src.snares -= picked_snare
|
||||
qdel(picked_snare)
|
||||
src << "<span class='danger'><B>Snare disarmed.</span></B>"
|
||||
|
||||
/obj/item/effect/snare
|
||||
name = "snare"
|
||||
desc = "You shouldn't be seeing this!"
|
||||
var/mob/living/spawner
|
||||
invisibility = 1
|
||||
|
||||
|
||||
/obj/item/effect/snare/Crossed(AM as mob|obj)
|
||||
if(istype(AM, /mob/living/))
|
||||
var/turf/snare_loc = get_turf(src.loc)
|
||||
if(spawner)
|
||||
spawner << "<span class='danger'><B>[AM] has crossed your surveillance trap at [get_area(snare_loc)].</span></B>"
|
||||
if(istype(spawner, /mob/living/simple_animal/hostile/guardian))
|
||||
var/mob/living/simple_animal/hostile/guardian/G = spawner
|
||||
if(G.summoner)
|
||||
G.summoner << "<span class='danger'><B>[AM] has crossed your surveillance trap at [get_area(snare_loc)].</span></B>"
|
||||
|
||||
////Bomb
|
||||
|
||||
/mob/living/simple_animal/hostile/guardian/bomb
|
||||
melee_damage_lower = 15
|
||||
melee_damage_upper = 15
|
||||
damage_transfer = 0.6
|
||||
range = 13
|
||||
playstyle_string = "As an explosive type, you have only moderate close combat abilities, but are capable of converting any adjacent item into a disguised bomb via alt click."
|
||||
magic_fluff_string = "..And draw the Scientist, master of explosive death."
|
||||
tech_fluff_string = "Boot sequence complete. Explosive modules active. Holoparasite swarm online."
|
||||
bio_fluff_string = "Your scarab swarm finishes mutating and stirs to life, capable of stealthily booby trapping items."
|
||||
var/bomb_cooldown = 0
|
||||
|
||||
/mob/living/simple_animal/hostile/guardian/bomb/AltClickOn(atom/movable/A)
|
||||
if(!istype(A))
|
||||
return
|
||||
if(src.loc == summoner)
|
||||
src << "<span class='danger'><B>You must be manifested to create bombs!</B></span>"
|
||||
return
|
||||
if(istype(A, /obj/))
|
||||
if(bomb_cooldown <= world.time && !stat)
|
||||
var/obj/item/weapon/guardian_bomb/B = new /obj/item/weapon/guardian_bomb(get_turf(A))
|
||||
src << "<span class='danger'><B>Success! Bomb on \the [A] armed!</B></span>"
|
||||
if(summoner)
|
||||
summoner << "<span class='warning'>Your guardian has primed \the [A] to explode!</span>"
|
||||
bomb_cooldown = world.time + 200
|
||||
B.spawner = src
|
||||
B.disguise (A)
|
||||
else
|
||||
src << "<span class='danger'><B>Your powers are on cooldown! You must wait 20 seconds between bombs.</B></span>"
|
||||
|
||||
/obj/item/weapon/guardian_bomb
|
||||
name = "bomb"
|
||||
desc = "You shouldn't be seeing this!"
|
||||
var/obj/stored_obj
|
||||
var/mob/living/spawner
|
||||
|
||||
|
||||
/obj/item/weapon/guardian_bomb/proc/disguise(var/obj/A)
|
||||
A.loc = src
|
||||
stored_obj = A
|
||||
anchored = A.anchored
|
||||
density = A.density
|
||||
appearance = A.appearance
|
||||
spawn(600)
|
||||
if(src)
|
||||
stored_obj.loc = get_turf(src.loc)
|
||||
spawner << "<span class='danger'><B>Failure! Your trap on \the [stored_obj] didn't catch anyone this time.</B></span>"
|
||||
qdel(src)
|
||||
|
||||
/obj/item/weapon/guardian_bomb/proc/detonate(var/mob/living/user)
|
||||
user << "<span class='danger'><B>The [src] was boobytrapped!</B></span>"
|
||||
if(istype(spawner, /mob/living/simple_animal/hostile/guardian))
|
||||
var/mob/living/simple_animal/hostile/guardian/G = spawner
|
||||
if(user == G.summoner)
|
||||
user << "<span class='danger'>You knew this because of your link with your guardian, so you smartly defuse the bomb.</span>"
|
||||
stored_obj.loc = get_turf(src.loc)
|
||||
qdel(src)
|
||||
return
|
||||
spawner << "<span class='danger'><B>Success! Your trap on \the [src] caught [user]!</B></span>"
|
||||
stored_obj.loc = get_turf(src.loc)
|
||||
playsound(get_turf(src),'sound/effects/Explosion2.ogg', 200, 1)
|
||||
user.ex_act(2)
|
||||
qdel(src)
|
||||
|
||||
/obj/item/weapon/guardian_bomb/attackby(mob/living/user)
|
||||
detonate(user)
|
||||
return
|
||||
|
||||
/obj/item/weapon/guardian_bomb/pickup(mob/living/user)
|
||||
detonate(user)
|
||||
return
|
||||
|
||||
/obj/item/weapon/guardian_bomb/examine(mob/user)
|
||||
stored_obj.examine(user)
|
||||
if(get_dist(user,src)<=2)
|
||||
user << "<span class='notice'>Looks odd!</span>"
|
||||
|
||||
|
||||
////////Creation
|
||||
|
||||
/obj/item/weapon/guardiancreator
|
||||
name = "deck of tarot cards"
|
||||
desc = "An enchanted deck of tarot cards, rumored to be a source of unimaginable power. "
|
||||
icon = 'icons/obj/toy.dmi'
|
||||
icon_state = "deck_syndicate_full"
|
||||
var/used = FALSE
|
||||
var/theme = "magic"
|
||||
var/mob_name = "Guardian Spirit"
|
||||
var/use_message = "You shuffle the deck..."
|
||||
var/used_message = "All the cards seem to be blank now."
|
||||
var/failure_message = "..And draw a card! It's...blank? Maybe you should try again later."
|
||||
var/ling_failure = "The deck refuses to respond to a souless creature such as you."
|
||||
var/list/possible_guardians = list("Chaos", "Standard", "Ranged", "Support", "Explosive")
|
||||
var/random = TRUE
|
||||
|
||||
/obj/item/weapon/guardiancreator/attack_self(mob/living/user)
|
||||
for(var/mob/living/simple_animal/hostile/guardian/G in living_mob_list)
|
||||
if (G.summoner == user)
|
||||
user << "You already have a [mob_name]!"
|
||||
return
|
||||
if(user.mind && user.mind.changeling)
|
||||
user << "[ling_failure]"
|
||||
return
|
||||
if(used == TRUE)
|
||||
user << "[used_message]"
|
||||
return
|
||||
used = TRUE
|
||||
user << "[use_message]"
|
||||
var/list/mob/dead/observer/candidates = pollCandidates("Do you want to play as the [mob_name] of [user.real_name]?",ROLE_GUARDIAN, null, FALSE, 100)
|
||||
var/mob/dead/observer/theghost = null
|
||||
|
||||
if(candidates.len)
|
||||
theghost = pick(candidates)
|
||||
spawn_guardian(user, theghost.key)
|
||||
else
|
||||
user << "[failure_message]"
|
||||
used = FALSE
|
||||
|
||||
|
||||
/obj/item/weapon/guardiancreator/proc/spawn_guardian(var/mob/living/user, var/key)
|
||||
var/gaurdiantype = "Standard"
|
||||
if(random)
|
||||
gaurdiantype = pick(possible_guardians)
|
||||
else
|
||||
gaurdiantype = input(user, "Pick the type of [mob_name]", "[mob_name] Creation") as null|anything in possible_guardians
|
||||
var/pickedtype = /mob/living/simple_animal/hostile/guardian/punch
|
||||
var/picked_color = pick("#FFFFFF","#000000","#808080","#A52A2A","#FF0000","#8B0000","#DC143C","#FFA500","#FFFF00","#008000","#00FF00","#006400","#00FFFF","#0000FF","#000080","#008080","#800080","#4B0082")
|
||||
switch(gaurdiantype)
|
||||
|
||||
if("Chaos")
|
||||
pickedtype = /mob/living/simple_animal/hostile/guardian/fire
|
||||
|
||||
if("Standard")
|
||||
pickedtype = /mob/living/simple_animal/hostile/guardian/punch
|
||||
|
||||
if("Ranged")
|
||||
pickedtype = /mob/living/simple_animal/hostile/guardian/ranged
|
||||
|
||||
if("Support")
|
||||
pickedtype = /mob/living/simple_animal/hostile/guardian/healer
|
||||
|
||||
if("Explosive")
|
||||
pickedtype = /mob/living/simple_animal/hostile/guardian/bomb
|
||||
|
||||
var/mob/living/simple_animal/hostile/guardian/G = new pickedtype(user)
|
||||
G.summoner = user
|
||||
G.summoned = TRUE
|
||||
G.key = key
|
||||
G << "You are a [mob_name] bound to serve [user.real_name]."
|
||||
G << "You are capable of manifesting or recalling to your master with verbs in the Guardian tab. You will also find a verb to communicate with them privately there."
|
||||
G << "While personally invincible, you will die if [user.real_name] does, and any damage dealt to you will have a portion passed on to them as you feed upon them to sustain yourself."
|
||||
G << "[G.playstyle_string]"
|
||||
G.faction = user.faction
|
||||
user.verbs += /mob/living/proc/guardian_comm
|
||||
user.verbs += /mob/living/proc/guardian_recall
|
||||
user.verbs += /mob/living/proc/guardian_reset
|
||||
var/magic_suite = pick("Wands","Cups","Swords","Pentacles")
|
||||
var/picked_name = pick("Aries", "Leo", "Sagittarius", "Taurus", "Virgo", "Capricorn", "Gemini", "Libra", "Aquarius", "Cancer", "Scorpio", "Pisces")
|
||||
switch (theme)
|
||||
if("magic")
|
||||
G.name = "[mob_name] of [magic_suite]"
|
||||
G.color = picked_color
|
||||
G.real_name = "[mob_name] of [magic_suite]"
|
||||
user << "[G.magic_fluff_string]."
|
||||
if("tech")
|
||||
var/colour = pick("orange", "neon", "pink", "red", "blue", "green")
|
||||
G.name = "[picked_name] [capitalize(colour)]"
|
||||
G.real_name = "[picked_name] [capitalize(colour)]"
|
||||
G.icon_living = "parasite[colour]"
|
||||
G.icon_state = "parasite[colour]"
|
||||
G.icon_dead = "parasite[colour]"
|
||||
G.animated_manifest = TRUE
|
||||
user << "[G.tech_fluff_string]."
|
||||
G.speak_emote = list("states")
|
||||
if("bio")
|
||||
user << "[G.bio_fluff_string]."
|
||||
G.name = "[mob_name] [picked_name]"
|
||||
G.color = picked_color
|
||||
G.real_name = "[mob_name] [picked_name]"
|
||||
G.icon_living = "headcrab"
|
||||
G.icon_state = "headcrab"
|
||||
G.attacktext = "swarms"
|
||||
G.speak_emote = list("chitters")
|
||||
|
||||
/obj/item/weapon/guardiancreator/choose
|
||||
random = FALSE
|
||||
|
||||
/obj/item/weapon/guardiancreator/tech
|
||||
name = "holoparasite injector"
|
||||
desc = "It contains alien nanoswarm of unknown origin. Though capable of near sorcerous feats via use of hardlight holograms and nanomachines, it requires an organic host as a home base and source of fuel."
|
||||
icon = 'icons/obj/syringe.dmi'
|
||||
icon_state = "combat_hypo"
|
||||
theme = "tech"
|
||||
mob_name = "Holoparasite"
|
||||
use_message = "You start to power on the injector..."
|
||||
used_message = "The injector has already been used."
|
||||
failure_message = "<B>...ERROR. BOOT SEQUENCE ABORTED. AI FAILED TO INTIALIZE. PLEASE CONTACT SUPPORT OR TRY AGAIN LATER.</B>"
|
||||
ling_failure = "The holoparasites recoil in horror. They want nothing to do with a creature like you."
|
||||
|
||||
/obj/item/weapon/guardiancreator/tech/choose
|
||||
random = FALSE
|
||||
|
||||
/obj/item/weapon/guardiancreator/biological
|
||||
name = "scarab egg cluster"
|
||||
desc = "A parasitic species that will nest in the closest living creature upon birth. While not great for your health, they'll defend their new 'hive' to the death."
|
||||
icon = 'icons/obj/fish_items.dmi'
|
||||
icon_state = "eggs"
|
||||
theme = "bio"
|
||||
mob_name = "Scarab Swarm"
|
||||
use_message = "The eggs begin to twitch..."
|
||||
used_message = "The cluster already hatched."
|
||||
failure_message = "<B>...but soon settles again. Guess they weren't ready to hatch after all.</B>"
|
||||
|
||||
/obj/item/weapon/guardiancreator/biological/choose
|
||||
random = FALSE
|
||||
|
||||
|
||||
/obj/item/weapon/paper/guardian
|
||||
name = "Holoparasite Guide"
|
||||
icon_state = "paper"
|
||||
info = {"<b>A list of Holoparasite Types</b><br>
|
||||
|
||||
<br>
|
||||
<b>Chaos</b>: Ignites mobs on touch. teleports them at random on attack. Automatically extinguishes the user if they catch fire.<br>
|
||||
<br>
|
||||
<b>Standard</b>:Devestating close combat attacks and high damage resist. No special powers.<br>
|
||||
<br>
|
||||
<b>Ranged</b>: Has two modes. Ranged: Extremely weak, highly spammable projectile attack. Scout: Can not attack, but can move through walls. Can lay surveillance snares in either mode.<br>
|
||||
<br>
|
||||
<b>Support</b>:Has two modes. Combat: Medium power attacks and damage resist. Healer: Attacks heal damage, but low damage resist and slow movemen. Can deploy a bluespace beacon and warp targets to it (including you) in either mode.<br>
|
||||
<br>
|
||||
<b>Explosive</b>: High damage resist and medium power attack. Can turn any object into a bomb, dealing explosive damage to the next person to touch it. The object will return to normal after the trap is triggered.<br>
|
||||
"}
|
||||
|
||||
/obj/item/weapon/paper/guardian/update_icon()
|
||||
return
|
||||
|
||||
|
||||
/obj/item/weapon/storage/box/syndie_kit/guardian
|
||||
name = "holoparasite injector kit"
|
||||
|
||||
/obj/item/weapon/storage/box/syndie_kit/guardian/New()
|
||||
..()
|
||||
new /obj/item/weapon/guardiancreator/tech/choose(src)
|
||||
new /obj/item/weapon/paper/guardian(src)
|
||||
return
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
///HUD
|
||||
|
||||
/datum/hud/proc/guardian_hud(ui_style = 'icons/mob/screen1_midnight.dmi')
|
||||
adding = list()
|
||||
|
||||
var/obj/screen/using
|
||||
|
||||
using = new /obj/screen/guardian/Manifest()
|
||||
using.screen_loc = ui_rhand
|
||||
adding += using
|
||||
|
||||
using = new /obj/screen/guardian/Recall()
|
||||
using.screen_loc = ui_lhand
|
||||
adding += using
|
||||
|
||||
using = new /obj/screen/guardian/ToggleMode()
|
||||
using.screen_loc = ui_storage1
|
||||
adding += using
|
||||
|
||||
using = new /obj/screen/guardian/ToggleLight()
|
||||
using.screen_loc = ui_inventory
|
||||
adding += using
|
||||
|
||||
using = new /obj/screen/guardian/Communicate()
|
||||
using.screen_loc = ui_back
|
||||
adding += using
|
||||
|
||||
mymob.client.screen = list()
|
||||
mymob.client.screen += mymob.client.void
|
||||
mymob.client.screen += adding
|
||||
|
||||
|
||||
|
||||
|
||||
//HUD BUTTONS
|
||||
|
||||
/obj/screen/guardian
|
||||
icon = 'icons/mob/guardian.dmi'
|
||||
|
||||
/obj/screen/guardian/Manifest
|
||||
icon_state = "manifest"
|
||||
name = "Manifest"
|
||||
desc = "Spring forth into battle!"
|
||||
|
||||
/obj/screen/guardian/Manifest/Click()
|
||||
if(isguardian(usr))
|
||||
var/mob/living/simple_animal/hostile/guardian/G = usr
|
||||
G.Manifest()
|
||||
|
||||
|
||||
/obj/screen/guardian/Recall
|
||||
icon_state = "recall"
|
||||
name = "Recall"
|
||||
desc = "Return to your user."
|
||||
|
||||
/obj/screen/guardian/Recall/Click()
|
||||
if(isguardian(usr))
|
||||
var/mob/living/simple_animal/hostile/guardian/G = usr
|
||||
G.Recall()
|
||||
|
||||
/obj/screen/guardian/ToggleMode
|
||||
icon_state = "toggle"
|
||||
name = "Toggle Mode"
|
||||
desc = "Switch between ability modes."
|
||||
|
||||
/obj/screen/guardian/ToggleMode/Click()
|
||||
if(isguardian(usr))
|
||||
var/mob/living/simple_animal/hostile/guardian/G = usr
|
||||
G.ToggleMode()
|
||||
|
||||
/obj/screen/guardian/Communicate
|
||||
icon_state = "communicate"
|
||||
name = "Communicate"
|
||||
desc = "Communicate telepathically with your user."
|
||||
|
||||
/obj/screen/guardian/Communicate/Click()
|
||||
if(isguardian(usr))
|
||||
var/mob/living/simple_animal/hostile/guardian/G = usr
|
||||
G.Communicate()
|
||||
|
||||
/obj/screen/guardian/ToggleLight
|
||||
icon_state = "light"
|
||||
name = "Toggle Light"
|
||||
desc = "Glow like star dust."
|
||||
|
||||
/obj/screen/guardian/ToggleLight/Click()
|
||||
if(isguardian(usr))
|
||||
var/mob/living/simple_animal/hostile/guardian/G = usr
|
||||
G.ToggleLight()
|
||||
@@ -1,472 +0,0 @@
|
||||
//Revenants: based off of wraiths from Goon
|
||||
//"Ghosts" that are invisible and move like ghosts, cannot take damage while invsible
|
||||
//Don't hear deadchat and are NOT normal ghosts
|
||||
//Admin-spawn or random event
|
||||
#define INVISIBILITY_REVENANT 50
|
||||
|
||||
/mob/living/simple_animal/revenant
|
||||
name = "revenant"
|
||||
desc = "A malevolent spirit."
|
||||
icon = 'icons/mob/mob.dmi'
|
||||
icon_state = "revenant_idle"
|
||||
var/icon_idle = "revenant_idle"
|
||||
var/icon_reveal = "revenant_revealed"
|
||||
var/icon_stun = "revenant_stun"
|
||||
var/icon_drain = "revenant_draining"
|
||||
incorporeal_move = 3
|
||||
invisibility = INVISIBILITY_REVENANT
|
||||
health = INFINITY //Revenants don't use health, they use essence instead
|
||||
maxHealth = INFINITY
|
||||
see_invisible = INVISIBILITY_REVENANT
|
||||
universal_understand = 1
|
||||
response_help = "passes through"
|
||||
response_disarm = "swings at"
|
||||
response_harm = "punches"
|
||||
unsuitable_atmos_damage = 0
|
||||
minbodytemp = 0
|
||||
maxbodytemp = INFINITY
|
||||
harm_intent_damage = 0
|
||||
friendly = "touches"
|
||||
status_flags = 0
|
||||
see_in_dark = 8
|
||||
wander = 0
|
||||
density = 0
|
||||
flying = 1
|
||||
anchored = 1
|
||||
|
||||
var/essence = 75 //The resource of revenants. Max health is equal to three times this amount
|
||||
var/essence_regen_cap = 75 //The regeneration cap of essence (go figure); regenerates every Life() tick up to this amount.
|
||||
var/essence_regenerating = 1 //If the revenant regenerates essence or not; 1 for yes, 0 for no
|
||||
var/essence_regen_amount = 5 //How much essence regenerates
|
||||
var/essence_accumulated = 0 //How much essence the revenant has stolen
|
||||
var/revealed = 0 //If the revenant can take damage from normal sources.
|
||||
var/unreveal_time = 0 //How long the revenant is revealed for, is about 2 seconds times this var.
|
||||
var/unstun_time = 0 //How long the revenant is stunned for, is about 2 seconds times this var.
|
||||
var/inhibited = 0 //If the revenant's abilities are blocked by a chaplain's power.
|
||||
var/essence_drained = 0 //How much essence the revenant has drained.
|
||||
var/draining = 0 //If the revenant is draining someone.
|
||||
var/list/drained_mobs = list() //Cannot harvest the same mob twice
|
||||
var/perfectsouls = 0 //How many perfect, regen-cap increasing souls the revenant has.
|
||||
var/image/ghostimage = null //Visible to ghost with darkness off
|
||||
|
||||
/mob/living/simple_animal/revenant/Life()
|
||||
..()
|
||||
if(revealed && essence <= 0)
|
||||
death()
|
||||
if(essence_regenerating && !inhibited && essence < essence_regen_cap) //While inhibited, essence will not regenerate
|
||||
essence = min(essence_regen_cap, essence+essence_regen_amount)
|
||||
if(unreveal_time && world.time >= unreveal_time)
|
||||
unreveal_time = 0
|
||||
revealed = 0
|
||||
invisibility = INVISIBILITY_REVENANT
|
||||
src << "<span class='revenboldnotice'>You are once more concealed.</span>"
|
||||
if(unstun_time && world.time >= unstun_time)
|
||||
unstun_time = 0
|
||||
notransform = 0
|
||||
src << "<span class='revenboldnotice'>You can move again!</span>"
|
||||
update_spooky_icon()
|
||||
|
||||
/mob/living/simple_animal/revenant/ex_act(severity)
|
||||
return 1 //Immune to the effects of explosions.
|
||||
|
||||
/mob/living/simple_animal/revenant/blob_act()
|
||||
return 1 //blah blah blobs aren't in tune with the spirit world, or something.
|
||||
|
||||
/mob/living/simple_animal/revenant/singularity_act()
|
||||
return //don't walk into the singularity expecting to find corpses, okay?
|
||||
|
||||
/mob/living/simple_animal/revenant/narsie_act()
|
||||
return //most humans will now be either bones or harvesters, but we're still un-alive.
|
||||
|
||||
/mob/living/simple_animal/revenant/adjustBruteLoss(amount)
|
||||
if(!revealed)
|
||||
return
|
||||
essence = max(0, essence-amount)
|
||||
if(essence == 0)
|
||||
src << "<span class='revendanger'>You feel your essence fraying!</span>"
|
||||
|
||||
/mob/living/simple_animal/revenant/ClickOn(var/atom/A, var/params) //Copypaste from ghost code - revenants can't interact with the world directly.
|
||||
if(client.buildmode)
|
||||
build_click(src, client.buildmode, params, A)
|
||||
return
|
||||
|
||||
var/list/modifiers = params2list(params)
|
||||
if(modifiers["middle"])
|
||||
MiddleClickOn(A)
|
||||
return
|
||||
if(modifiers["shift"])
|
||||
ShiftClickOn(A)
|
||||
return
|
||||
if(modifiers["alt"])
|
||||
AltClickOn(A)
|
||||
return
|
||||
if(modifiers["ctrl"])
|
||||
CtrlClickOn(A)
|
||||
return
|
||||
|
||||
if(world.time <= next_move)
|
||||
return
|
||||
A.attack_ghost(src)
|
||||
if(ishuman(A) && in_range(src, A))
|
||||
Harvest(A)
|
||||
|
||||
/mob/living/simple_animal/revenant/proc/Harvest(mob/living/carbon/human/target)
|
||||
if(!castcheck(0))
|
||||
return
|
||||
if(draining)
|
||||
src << "<span class='revenwarning'>You are already siphoning the essence of a soul!</span>"
|
||||
return
|
||||
if(target in drained_mobs)
|
||||
src << "<span class='revenwarning'>[target]'s soul is dead and empty.</span>"
|
||||
return
|
||||
if(!target.stat)
|
||||
src << "<span class='revennotice'>This being's soul is too strong to harvest.</span>"
|
||||
if(prob(10))
|
||||
target << "You feel as if you are being watched."
|
||||
return
|
||||
draining = 1
|
||||
essence_drained = rand(15, 20)
|
||||
src << "<span class='revennotice'>You search for the soul of [target].</span>"
|
||||
if(do_after(src, 10, 3, 0, target = target)) //did they get deleted in that second?
|
||||
if(target.ckey)
|
||||
src << "<span class='revennotice'>Their soul burns with intelligence.</span>"
|
||||
essence_drained += rand(20, 30)
|
||||
if(target.stat != DEAD)
|
||||
src << "<span class='revennotice'>Their soul blazes with life!</span>"
|
||||
essence_drained += rand(40, 50)
|
||||
else
|
||||
src << "<span class='revennotice'>Their soul is weak and faltering.</span>"
|
||||
if(do_after(src, 20, 6, 0, target = target)) //did they get deleted NOW?
|
||||
switch(essence_drained)
|
||||
if(1 to 30)
|
||||
src << "<span class='revennotice'>[target] will not yield much essence. Still, every bit counts.</span>"
|
||||
if(30 to 70)
|
||||
src << "<span class='revennotice'>[target] will yield an average amount of essence.</span>"
|
||||
if(70 to 90)
|
||||
src << "<span class='revenboldnotice'>Such a feast! [target] will yield much essence to you.</span>"
|
||||
if(90 to INFINITY)
|
||||
src << "<span class='revenbignotice'>Ah, the perfect soul. [target] will yield massive amounts of essence to you.</span>"
|
||||
if(do_after(src, 20, 6, 0, target = target)) //how about now
|
||||
if(!target.stat)
|
||||
src << "<span class='revenwarning'>They are now powerful enough to fight off your draining.</span>"
|
||||
target << "<span class='boldannounce'>You feel something tugging across your body before subsiding.</span>"
|
||||
draining = 0
|
||||
return //hey, wait a minute...
|
||||
src << "<span class='revenminor'>You begin siphoning essence from [target]'s soul.</span>"
|
||||
if(target.stat != DEAD)
|
||||
target << "<span class='warning'>You feel a horribly unpleasant draining sensation as your grip on life weakens...</span>"
|
||||
icon_state = "revenant_draining"
|
||||
reveal(27)
|
||||
stun(27)
|
||||
target.visible_message("<span class='warning'>[target] suddenly rises slightly into the air, their skin turning an ashy gray.</span>")
|
||||
target.Beam(src,icon_state="drain_life",icon='icons/effects/effects.dmi',time=26)
|
||||
if(do_after(src, 30, 9, 0, target)) //As one cannot prove the existance of ghosts, ghosts cannot prove the existance of the target they were draining.
|
||||
change_essence_amount(essence_drained, 0, target)
|
||||
if(essence_drained > 90)
|
||||
essence_regen_cap += 25
|
||||
perfectsouls += 1
|
||||
src << "<span class='revenboldnotice'>The perfection of [target]'s soul has increased your maximum essence level. Your new maximum essence is [essence_regen_cap].</span>"
|
||||
src << "<span class='revennotice'>[target]'s soul has been considerably weakened and will yield no more essence for the time being.</span>"
|
||||
target.visible_message("<span class='warning'>[target] slumps onto the ground.</span>", \
|
||||
"<span class='revenwarning'>Violets lights, dancing in your vision, getting clo--</span>")
|
||||
drained_mobs.Add(target)
|
||||
target.death(0)
|
||||
else
|
||||
src << "<span class='revenwarning'>[target ? "[target] has":"They have"] been drawn out of your grasp. The link has been broken.</span>"
|
||||
draining = 0
|
||||
essence_drained = 0
|
||||
if(target) //Wait, target is WHERE NOW?
|
||||
target.visible_message("<span class='warning'>[target] slumps onto the ground.</span>", \
|
||||
"<span class='revenwarning'>Violets lights, dancing in your vision, receding--</span>")
|
||||
return
|
||||
else
|
||||
src << "<span class='revenwarning'>You are not close enough to siphon [target ? "[target]'s":"their"] soul. The link has been broken.</span>"
|
||||
draining = 0
|
||||
essence_drained = 0
|
||||
return
|
||||
draining = 0
|
||||
essence_drained = 0
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/revenant/say(message)
|
||||
return 0 //Revenants cannot speak out loud.
|
||||
|
||||
/mob/living/simple_animal/revenant/Stat()
|
||||
..()
|
||||
if(statpanel("Status"))
|
||||
stat(null, "Current essence: [essence]/[essence_regen_cap]E")
|
||||
stat(null, "Stolen essence: [essence_accumulated]E")
|
||||
stat(null, "Stolen perfect souls: [perfectsouls]")
|
||||
|
||||
/mob/living/simple_animal/revenant/New()
|
||||
..()
|
||||
|
||||
ghostimage = image(src.icon,src,src.icon_state)
|
||||
ghost_darkness_images |= ghostimage
|
||||
updateallghostimages()
|
||||
|
||||
spawn(5)
|
||||
if(src.mind)
|
||||
src.mind.wipe_memory()
|
||||
src << 'sound/effects/ghost.ogg'
|
||||
src << "<br>"
|
||||
src << "<span class='deadsay'><font size=3><b>You are a revenant.</b></font></span>"
|
||||
src << "<b>Your formerly mundane spirit has been infused with alien energies and empowered into a revenant.</b>"
|
||||
src << "<b>You are not dead, not alive, but somewhere in between. You are capable of limited interaction with both worlds.</b>"
|
||||
src << "<b>You are invincible and invisible to everyone but other ghosts. Most abilities will reveal you, rendering you vulnerable.</b>"
|
||||
src << "<b>To function, you are to drain the life essence from humans. This essence is a resource, as well as your health, and will power all of your abilities.</b>"
|
||||
src << "<b><i>You do not remember anything of your past lives, nor will you remember anything about this one after your death.</i></b>"
|
||||
src << "<b>Be sure to read the wiki page at http://nanotrasen.se/wiki/index.php/Revenant to learn more.</b>"
|
||||
var/datum/objective/revenant/objective = new
|
||||
objective.owner = src.mind
|
||||
src.mind.objectives += objective
|
||||
src << "<b>Objective #1</b>: [objective.explanation_text]"
|
||||
var/datum/objective/revenantFluff/objective2 = new
|
||||
objective2.owner = src.mind
|
||||
src.mind.objectives += objective2
|
||||
src << "<b>Objective #2</b>: [objective2.explanation_text]"
|
||||
ticker.mode.traitors |= src.mind //Necessary for announcing
|
||||
if(!src.giveSpells())
|
||||
message_admins("Revenant was created but has no mind. Trying again in five seconds.")
|
||||
spawn(50)
|
||||
if(!src.giveSpells())
|
||||
message_admins("Revenant still has no mind. Deleting...")
|
||||
qdel(src)
|
||||
|
||||
/mob/living/simple_animal/revenant/proc/giveSpells()
|
||||
if(src.mind)
|
||||
src.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/revenant_transmit(null))
|
||||
src.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/revenant/overload(null))
|
||||
src.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/revenant/defile(null))
|
||||
src.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/revenant/malfunction(null))
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/mob/living/simple_animal/revenant/death()
|
||||
..()
|
||||
if(!revealed) //Revenants cannot die if they aren't revealed
|
||||
return
|
||||
ghost_darkness_images -= ghostimage
|
||||
updateallghostimages()
|
||||
|
||||
src << "<span class='revendanger'>NO! No... it's too late, you can feel your essence breaking apart...</span>"
|
||||
notransform = 1
|
||||
revealed = 1
|
||||
invisibility = 0
|
||||
playsound(src, 'sound/effects/screech.ogg', 100, 1)
|
||||
visible_message("<span class='warning'>[src] lets out a waning screech as violet mist swirls around its dissolving body!</span>")
|
||||
icon_state = "revenant_draining"
|
||||
for(var/i = alpha, i > 0, i -= 10)
|
||||
sleep(0.1)
|
||||
alpha = i
|
||||
visible_message("<span class='danger'>[src]'s body breaks apart into a fine pile of blue dust.</span>")
|
||||
var/obj/item/weapon/ectoplasm/revenant/R = new (get_turf(src))
|
||||
R.client_to_revive = src.client //If the essence reforms, the old revenant is put back in the body
|
||||
ghostize()
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
|
||||
/mob/living/simple_animal/revenant/attackby(obj/item/W, mob/living/user, params)
|
||||
if(istype(W, /obj/item/weapon/nullrod))
|
||||
visible_message("<span class='warning'>[src] violently flinches!</span>", \
|
||||
"<span class='revendanger'>As the null rod passes through you, you feel your essence draining away!</span>")
|
||||
adjustBruteLoss(25) //hella effective
|
||||
inhibited = 1
|
||||
spawn(30)
|
||||
inhibited = 0
|
||||
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/revenant/proc/castcheck(essence_cost)
|
||||
if(!src)
|
||||
return
|
||||
var/turf/T = get_turf(src)
|
||||
if(istype(T, /turf/simulated/wall))
|
||||
src << "<span class='revenwarning'>You cannot use abilities from inside of a wall.</span>"
|
||||
return 0
|
||||
if(src.inhibited)
|
||||
src << "<span class='revenwarning'>Your powers have been suppressed by nulling energy!</span>"
|
||||
return 0
|
||||
if(!src.change_essence_amount(essence_cost, 1))
|
||||
src << "<span class='revenwarning'>You lack the essence to use that ability.</span>"
|
||||
return 0
|
||||
return 1
|
||||
|
||||
/mob/living/simple_animal/revenant/proc/change_essence_amount(essence_amt, silent = 0, source = null)
|
||||
if(!src)
|
||||
return
|
||||
if(essence + essence_amt <= 0)
|
||||
return
|
||||
essence = max(0, essence+essence_amt)
|
||||
if(essence_amt > 0)
|
||||
essence_accumulated = max(0, essence_accumulated+essence_amt)
|
||||
if(!silent)
|
||||
if(essence_amt > 0)
|
||||
src << "<span class='revennotice'>Gained [essence_amt]E from [source].</span>"
|
||||
else
|
||||
src << "<span class='revenminor'>Lost [essence_amt]E from [source].</span>"
|
||||
return 1
|
||||
|
||||
/mob/living/simple_animal/revenant/proc/reveal(time)
|
||||
if(!src)
|
||||
return
|
||||
if(time <= 0)
|
||||
return
|
||||
revealed = 1
|
||||
invisibility = 0
|
||||
if(!unreveal_time)
|
||||
src << "<span class='revendanger'>You have been revealed!</span>"
|
||||
unreveal_time = world.time + time
|
||||
else
|
||||
src << "<span class='revenwarning'>You have been revealed!</span>"
|
||||
unreveal_time = unreveal_time + time
|
||||
update_spooky_icon()
|
||||
|
||||
/mob/living/simple_animal/revenant/proc/stun(time)
|
||||
if(!src)
|
||||
return
|
||||
if(time <= 0)
|
||||
return
|
||||
notransform = 1
|
||||
if(!unstun_time)
|
||||
src << "<span class='revendanger'>You cannot move!</span>"
|
||||
unstun_time = world.time + time
|
||||
else
|
||||
src << "<span class='revenwarning'>You cannot move!</span>"
|
||||
unstun_time = unstun_time + time
|
||||
update_spooky_icon()
|
||||
|
||||
/mob/living/simple_animal/revenant/proc/update_spooky_icon()
|
||||
if(revealed)
|
||||
if(notransform)
|
||||
if(draining)
|
||||
icon_state = icon_drain
|
||||
else
|
||||
icon_state = icon_stun
|
||||
else
|
||||
icon_state = icon_reveal
|
||||
else
|
||||
icon_state = icon_idle
|
||||
|
||||
/datum/objective/revenant
|
||||
var/targetAmount = 100
|
||||
|
||||
/datum/objective/revenant/New()
|
||||
targetAmount = rand(200,500)
|
||||
explanation_text = "Absorb [targetAmount] points of essence from humans."
|
||||
..()
|
||||
|
||||
/datum/objective/revenant/check_completion()
|
||||
if(!owner || !istype(owner.current, /mob/living/simple_animal/revenant))
|
||||
return 0
|
||||
var/mob/living/simple_animal/revenant/R = owner.current
|
||||
if(!R || R.stat == DEAD)
|
||||
return 0
|
||||
var/essence_stolen = R.essence_accumulated
|
||||
if(essence_stolen < targetAmount)
|
||||
return 0
|
||||
return 1
|
||||
|
||||
/datum/objective/revenantFluff
|
||||
|
||||
/datum/objective/revenantFluff/New()
|
||||
var/list/explanationTexts = list("Attempt to make your presence unknown to the crew.", \
|
||||
"Collaborate with existing antagonists aboard the station to gain essence.", \
|
||||
"Remain nonlethal and only absorb bodies that have already died.", \
|
||||
"Use your environments to eliminate isolated people.", \
|
||||
"If there is a chaplain aboard the station, ensure they are killed.", \
|
||||
"Hinder the crew without killing them.")
|
||||
explanation_text = pick(explanationTexts)
|
||||
..()
|
||||
|
||||
/datum/objective/revenantFluff/check_completion()
|
||||
return 1
|
||||
|
||||
|
||||
/obj/item/weapon/ectoplasm/revenant
|
||||
name = "glimmering residue"
|
||||
desc = "A pile of fine blue dust. Small tendrils of violet mist swirl around it."
|
||||
icon = 'icons/effects/effects.dmi'
|
||||
icon_state = "revenantEctoplasm"
|
||||
w_class = 2
|
||||
var/reforming = 1
|
||||
var/inert = 0
|
||||
var/client/client_to_revive
|
||||
|
||||
/obj/item/weapon/ectoplasm/revenant/New()
|
||||
..()
|
||||
reforming = 0
|
||||
spawn(600) //1 minutes
|
||||
if(src && reforming)
|
||||
return reform()
|
||||
else
|
||||
inert = 1
|
||||
visible_message("<span class='warning'>[src] settles down and seems lifeless.</span>")
|
||||
return
|
||||
|
||||
/obj/item/weapon/ectoplasm/revenant/attack_self(mob/user)
|
||||
if(!reforming || inert)
|
||||
return ..()
|
||||
user.visible_message("<span class='notice'>[user] scatters [src] in all directions.</span>", \
|
||||
"<span class='notice'>You scatter [src] across the area. The particles slowly fade away.</span>")
|
||||
user.drop_item()
|
||||
qdel(src)
|
||||
|
||||
/obj/item/weapon/ectoplasm/revenant/throw_impact(atom/hit_atom)
|
||||
..()
|
||||
if(inert)
|
||||
return
|
||||
visible_message("<span class='notice'>[src] breaks into particles upon impact, which fade away to nothingness.</span>")
|
||||
qdel(src)
|
||||
|
||||
/obj/item/weapon/ectoplasm/revenant/examine(mob/user)
|
||||
..(user)
|
||||
if(inert)
|
||||
user << "<span class='revennotice'>It seems inert.</span>"
|
||||
else if(reforming)
|
||||
user << "<span class='revenwarning'>It is shifting and distorted. It would be wise to destroy this.</span>"
|
||||
|
||||
/obj/item/weapon/ectoplasm/revenant/proc/reform()
|
||||
if(inert || !src)
|
||||
return
|
||||
var/key_of_revenant
|
||||
message_admins("Revenant ectoplasm was left undestroyed for 1 minute and is reforming into a new revenant.")
|
||||
loc = get_turf(src) //In case it's in a backpack or someone's hand
|
||||
var/mob/living/simple_animal/revenant/R = new(get_turf(src))
|
||||
if(client_to_revive)
|
||||
for(var/mob/M in dead_mob_list)
|
||||
if(M.client == client_to_revive) //Only recreates the mob if the mob the client is in is dead
|
||||
R.client = client_to_revive
|
||||
key_of_revenant = client_to_revive.key
|
||||
|
||||
if(!key_of_revenant)
|
||||
message_admins("The new revenant's old client either could not be found or is in a new, living mob - grabbing a random candidate instead...")
|
||||
var/list/candidates = get_candidates(ROLE_REVENANT)
|
||||
if(!candidates.len)
|
||||
qdel(R)
|
||||
message_admins("No candidates were found for the new revenant. Oh well!")
|
||||
inert = 1
|
||||
visible_message("<span class='revenwarning'>[src] settles down and seems lifeless.</span>")
|
||||
return 0
|
||||
var/client/C = pick(candidates)
|
||||
key_of_revenant = C.key
|
||||
if(!key_of_revenant)
|
||||
qdel(R)
|
||||
message_admins("No ckey was found for the new revenant. Oh well!")
|
||||
inert = 1
|
||||
visible_message("<span class='revenwarning'>[src] settles down and seems lifeless.</span>")
|
||||
return 0
|
||||
var/datum/mind/player_mind = new /datum/mind(key_of_revenant)
|
||||
player_mind.active = 1
|
||||
player_mind.transfer_to(R)
|
||||
player_mind.assigned_role = "revenant"
|
||||
player_mind.special_role = "Revenant"
|
||||
ticker.mode.traitors |= player_mind
|
||||
message_admins("[key_of_revenant] has been [client_to_revive ? "re":""]made into a revenant by reforming ectoplasm.")
|
||||
log_game("[key_of_revenant] was [client_to_revive ? "re":""]made as a revenant by reforming ectoplasm.")
|
||||
visible_message("<span class='revenboldnotice'>[src] suddenly rises into the air before fading away.</span>")
|
||||
qdel(src)
|
||||
if(src) //Should never happen, but just in case
|
||||
inert = 1
|
||||
return 1
|
||||
@@ -1,191 +0,0 @@
|
||||
//Transmit: the revemant's only direct way to communicate. Sends a single message silently to a single mob
|
||||
/obj/effect/proc_holder/spell/targeted/revenant_transmit
|
||||
name = "Transmit"
|
||||
desc = "Telepathically transmits a message to the target."
|
||||
panel = "Revenant Abilities"
|
||||
charge_max = 0
|
||||
clothes_req = 0
|
||||
range = 7
|
||||
include_user = 0
|
||||
action_icon_state = "r_transmit"
|
||||
action_background_icon_state = "bg_revenant"
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/revenant_transmit/cast(list/targets, mob/living/simple_animal/revenant/user = usr)
|
||||
for(var/mob/living/M in targets)
|
||||
spawn(0)
|
||||
var/msg = stripped_input(usr, "What do you wish to tell [M]?", null, "")
|
||||
if(!msg)
|
||||
charge_counter = charge_max
|
||||
return
|
||||
log_say("RevenantTransmit: [key_name(user)]->[key_name(M)] : [msg]")
|
||||
usr << "<span class='revennotice'><b>You transmit to [M]:</b> [msg]</span>"
|
||||
M << "<span class='revennotice'><b>An alien voice resonates from all around...</b></span><i> [msg]</I>"
|
||||
|
||||
|
||||
/obj/effect/proc_holder/spell/aoe_turf/revenant
|
||||
clothes_req = 0
|
||||
action_background_icon_state = "bg_revenant"
|
||||
panel = "Revenant Abilities (Locked)"
|
||||
name = "Report this to a coder"
|
||||
var/reveal = 80 //How long it reveals the revenant in deciseconds
|
||||
var/stun = 20 //How long it stuns the revenant in deciseconds
|
||||
var/locked = 1 //If it's locked and needs to be unlocked before use
|
||||
var/unlock_amount = 100 //How much essence it costs to unlock
|
||||
var/cast_amount = 50 //How much essence it costs to use
|
||||
|
||||
/obj/effect/proc_holder/spell/aoe_turf/revenant/New()
|
||||
..()
|
||||
if(locked)
|
||||
name = "[initial(name)] ([unlock_amount]E)"
|
||||
else
|
||||
name = "[initial(name)] ([cast_amount]E)"
|
||||
|
||||
/obj/effect/proc_holder/spell/aoe_turf/revenant/can_cast(mob/living/simple_animal/revenant/user = usr)
|
||||
if(user.inhibited)
|
||||
return 0
|
||||
if(charge_counter < charge_max)
|
||||
return 0
|
||||
if(locked)
|
||||
if(user.essence <= unlock_amount)
|
||||
return 0
|
||||
if(user.essence <= cast_amount)
|
||||
return 0
|
||||
return 1
|
||||
|
||||
/obj/effect/proc_holder/spell/aoe_turf/revenant/proc/attempt_cast(mob/living/simple_animal/revenant/user = usr)
|
||||
if(locked)
|
||||
if(!user.castcheck(-unlock_amount))
|
||||
charge_counter = charge_max
|
||||
return 0
|
||||
name = "[initial(name)] ([cast_amount]E)"
|
||||
user << "<span class='revennotice'>You have unlocked [initial(name)]!</span>"
|
||||
panel = "Revenant Abilities"
|
||||
locked = 0
|
||||
charge_counter = charge_max
|
||||
return 0
|
||||
if(!user.castcheck(-cast_amount))
|
||||
charge_counter = charge_max
|
||||
return 0
|
||||
name = "[initial(name)] ([cast_amount]E)"
|
||||
user.reveal(reveal)
|
||||
user.stun(stun)
|
||||
user.update_action_buttons()
|
||||
return 1
|
||||
|
||||
//Overload Light: Breaks a light that's online and sends out lightning bolts to all nearby people.
|
||||
/obj/effect/proc_holder/spell/aoe_turf/revenant/overload
|
||||
name = "Overload Lights"
|
||||
desc = "Directs a large amount of essence into nearby electrical lights, causing lights to shock those nearby."
|
||||
charge_max = 200
|
||||
range = 5
|
||||
stun = 30
|
||||
cast_amount = 45
|
||||
var/shock_range = 2
|
||||
var/shock_damage = 18
|
||||
action_icon_state = "overload_lights"
|
||||
|
||||
/obj/effect/proc_holder/spell/aoe_turf/revenant/overload/cast(list/targets, mob/living/simple_animal/revenant/user = usr)
|
||||
if(attempt_cast(user))
|
||||
for(var/turf/T in targets)
|
||||
spawn(0)
|
||||
for(var/obj/machinery/light/L in T.contents)
|
||||
spawn(0)
|
||||
if(!L.on)
|
||||
return
|
||||
L.visible_message("<span class='warning'><b>\The [L] suddenly flares brightly and begins to spark!</span>")
|
||||
var/datum/effect/system/spark_spread/s = new /datum/effect/system/spark_spread/
|
||||
s.set_up(4, 0, L)
|
||||
s.start()
|
||||
new/obj/effect/overlay/temp/revenant(L.loc)
|
||||
sleep(20)
|
||||
if(!L.on) //wait, wait, don't shock me
|
||||
return
|
||||
flick("[L.base_state]2", L)
|
||||
for(var/mob/living/carbon/human/M in view(shock_range, L))
|
||||
if(M == user)
|
||||
return
|
||||
M.Beam(L,icon_state="purple_lightning",icon='icons/effects/effects.dmi',time=5)
|
||||
M.electrocute_act(shock_damage, "[L.name]", safety=1)
|
||||
var/datum/effect/system/spark_spread/z = new /datum/effect/system/spark_spread/
|
||||
z.set_up(4, 0, M)
|
||||
z.start()
|
||||
playsound(M, 'sound/machines/defib_zap.ogg', 50, 1, -1)
|
||||
|
||||
//Defile: Corrupts nearby stuff, unblesses floor tiles.
|
||||
/obj/effect/proc_holder/spell/aoe_turf/revenant/defile
|
||||
name = "Defile"
|
||||
desc = "Twists and corrupts the nearby area as well as dispelling holy auras on floors."
|
||||
charge_max = 150
|
||||
range = 3
|
||||
unlock_amount = 75
|
||||
cast_amount = 40
|
||||
action_icon_state = "defile"
|
||||
var/stamdamage= 25
|
||||
var/toxdamage = 5
|
||||
var/confusion = 50
|
||||
|
||||
/obj/effect/proc_holder/spell/aoe_turf/revenant/defile/cast(list/targets, mob/living/simple_animal/revenant/user = usr)
|
||||
if(attempt_cast(user))
|
||||
for(var/turf/T in targets)
|
||||
spawn(0)
|
||||
if(T.flags & NOJAUNT)
|
||||
T.flags -= NOJAUNT
|
||||
new/obj/effect/overlay/temp/revenant(T)
|
||||
for(var/mob/living/carbon/human/human in T.contents)
|
||||
human << "<span class='warning'>You suddenly feel [pick("sick and tired", "tired and confused", "nauseated", "dizzy")].</span>"
|
||||
human.adjustStaminaLoss(stamdamage)
|
||||
human.adjustToxLoss(toxdamage)
|
||||
human.confused += confusion
|
||||
new/obj/effect/overlay/temp/revenant(human.loc)
|
||||
if(!istype(T, /turf/simulated/shuttle) && !istype(T, /turf/simulated/wall/rust) && !istype(T, /turf/simulated/wall/r_wall) && istype(T, /turf/simulated/wall) && prob(15))
|
||||
new/obj/effect/overlay/temp/revenant(T)
|
||||
T.ChangeTurf(/turf/simulated/wall/rust)
|
||||
if(!istype(T, /turf/simulated/wall/r_wall/rust) && istype(T, /turf/simulated/wall/r_wall) && prob(15))
|
||||
new/obj/effect/overlay/temp/revenant(T)
|
||||
T.ChangeTurf(/turf/simulated/wall/r_wall/rust)
|
||||
for(var/obj/structure/window/window in T.contents)
|
||||
window.hit(rand(50,90))
|
||||
if(window && window.is_fulltile())
|
||||
new/obj/effect/overlay/temp/revenant/cracks(window.loc)
|
||||
for(var/obj/machinery/light/light in T.contents)
|
||||
light.flicker(30) //spooky
|
||||
|
||||
//Malfunction: Makes bad stuff happen to robots and machines.
|
||||
/obj/effect/proc_holder/spell/aoe_turf/revenant/malfunction
|
||||
name = "Malfunction"
|
||||
desc = "Corrupts and damages nearby machines and mechanical objects."
|
||||
charge_max = 200
|
||||
range = 4
|
||||
unlock_amount = 150
|
||||
action_icon_state = "malfunction"
|
||||
|
||||
//A note to future coders: do not replace this with an EMP because it will wreck malf AIs and gang dominators and everyone will hate you.
|
||||
/obj/effect/proc_holder/spell/aoe_turf/revenant/malfunction/cast(list/targets, mob/living/simple_animal/revenant/user = usr)
|
||||
if(attempt_cast(user))
|
||||
for(var/turf/T in targets)
|
||||
spawn(0)
|
||||
for(var/obj/machinery/bot/bot in T.contents)
|
||||
if(!bot.emagged)
|
||||
new/obj/effect/overlay/temp/revenant(bot.loc)
|
||||
bot.locked = 0
|
||||
bot.open = 1
|
||||
bot.Emag(null)
|
||||
for(var/mob/living/carbon/human/human in T.contents)
|
||||
human << "<span class='warning'>You feel [pick("your sense of direction flicker out", "a stabbing pain in your head", "your mind fill with static")].</span>"
|
||||
new/obj/effect/overlay/temp/revenant(human.loc)
|
||||
human.emp_act(1)
|
||||
for(var/obj/thing in T.contents)
|
||||
if(istype(thing, /obj/machinery/power/apc) || istype(thing, /obj/machinery/power/smes) || istype(thing, /obj/machinery/bot)) //Doesn't work on dominators, SMES and APCs, to prevent kekkery
|
||||
continue
|
||||
if(prob(20))
|
||||
if(prob(50))
|
||||
new/obj/effect/overlay/temp/revenant(thing.loc)
|
||||
thing.emag_act(null)
|
||||
else
|
||||
if(!istype(thing, /obj/machinery/clonepod)) //I hate everything but mostly the fact there's no better way to do this without just not affecting it at all
|
||||
thing.emp_act(1)
|
||||
for(var/mob/living/silicon/robot/S in T.contents) //Only works on cyborgs, not AI
|
||||
playsound(S, 'sound/machines/warning-buzzer.ogg', 50, 1)
|
||||
new/obj/effect/overlay/temp/revenant(S.loc)
|
||||
S.spark_system.start()
|
||||
S.emp_act(1)
|
||||
@@ -1,67 +0,0 @@
|
||||
#define REVENANT_SPAWN_THRESHOLD 10
|
||||
|
||||
/datum/event/revenant
|
||||
var/key_of_revenant
|
||||
|
||||
|
||||
/datum/event/revenant/proc/get_revenant(var/end_if_fail = 0)
|
||||
var/deadMobs = 0
|
||||
for(var/mob/M in dead_mob_list)
|
||||
deadMobs++
|
||||
if(deadMobs < REVENANT_SPAWN_THRESHOLD)
|
||||
message_admins("Random event attempted to spawn a revenant, but there were only [deadMobs]/[REVENANT_SPAWN_THRESHOLD] dead mobs.")
|
||||
return
|
||||
key_of_revenant = null
|
||||
if(!key_of_revenant)
|
||||
var/list/candidates = get_candidates(ROLE_REVENANT)
|
||||
if(!candidates.len)
|
||||
if(end_if_fail)
|
||||
return 0
|
||||
return find_revenant()
|
||||
var/client/C = pick(candidates)
|
||||
key_of_revenant = C.key
|
||||
if(!key_of_revenant)
|
||||
if(end_if_fail)
|
||||
return 0
|
||||
return find_revenant()
|
||||
var/datum/mind/player_mind = new /datum/mind(key_of_revenant)
|
||||
player_mind.active = 1
|
||||
var/list/spawn_locs = list()
|
||||
for(var/obj/effect/landmark/L in landmarks_list)
|
||||
if(isturf(L.loc))
|
||||
switch(L.name)
|
||||
if("revenantspawn")
|
||||
spawn_locs += L.loc
|
||||
if(!spawn_locs) //If we can't find any revenant spawns, try the carp spawns
|
||||
for(var/obj/effect/landmark/L in landmarks_list)
|
||||
if(isturf(L.loc))
|
||||
switch(L.name)
|
||||
if("carpspawn")
|
||||
spawn_locs += L.loc
|
||||
if(!spawn_locs) //If we can't find either, just spawn the revenant at the player's location
|
||||
spawn_locs += get_turf(player_mind.current)
|
||||
if(!spawn_locs) //If we can't find THAT, then just retry
|
||||
return find_revenant()
|
||||
var/mob/living/simple_animal/revenant/revvie = new /mob/living/simple_animal/revenant/(pick(spawn_locs))
|
||||
player_mind.transfer_to(revvie)
|
||||
player_mind.assigned_role = "revenant"
|
||||
player_mind.special_role = "Revenant"
|
||||
ticker.mode.traitors |= player_mind
|
||||
message_admins("[key_of_revenant] has been made into a revenant by an event.")
|
||||
log_game("[key_of_revenant] was spawned as a revenant by an event.")
|
||||
return 1
|
||||
|
||||
|
||||
/datum/event/revenant/start()
|
||||
get_revenant()
|
||||
|
||||
|
||||
/datum/event/revenant/proc/find_revenant()
|
||||
message_admins("An event failed to spawn a revenant. Retrying momentarily...")
|
||||
spawn(50)
|
||||
if(get_revenant(1))
|
||||
message_admins("[key_of_revenant] has been spawned as a revenant.")
|
||||
log_game("[key_of_revenant] was spawned as a revenant by an event.")
|
||||
return 0
|
||||
message_admins("No candidates were available for becoming a revenant.")
|
||||
return kill()
|
||||
@@ -102,6 +102,9 @@
|
||||
handle_automated_speech()
|
||||
. = 1
|
||||
|
||||
handle_state_icons()
|
||||
|
||||
/mob/living/simple_animal/proc/handle_state_icons()
|
||||
if(resting && icon_resting && stat != DEAD)
|
||||
icon_state = icon_resting
|
||||
else if(stat != DEAD)
|
||||
|
||||
@@ -1,204 +0,0 @@
|
||||
//////////////////The Monster
|
||||
|
||||
/mob/living/simple_animal/slaughter
|
||||
name = "slaughter demon"
|
||||
real_name = "slaughter demon"
|
||||
desc = "A large, menacing creature covered in armored black scales. You should run."
|
||||
speak = list("ire", "ego", "nahlizet", "certum", "veri", "jatkaa", "balaq", "mgar", "karazet", "geeri", "orkan", "allaq")
|
||||
speak_emote = list("gurgles")
|
||||
emote_hear = list("wails","screeches")
|
||||
response_help = "thinks better of touching"
|
||||
response_disarm = "flails at"
|
||||
response_harm = "punches"
|
||||
icon = 'icons/mob/mob.dmi'
|
||||
icon_state = "daemon"
|
||||
icon_living = "daemon"
|
||||
speed = 1
|
||||
a_intent = I_HARM
|
||||
stop_automated_movement = 1
|
||||
status_flags = CANPUSH
|
||||
attack_sound = 'sound/misc/demon_attack1.ogg'
|
||||
min_oxy = 0
|
||||
max_oxy = INFINITY
|
||||
min_tox = 0
|
||||
max_tox = INFINITY
|
||||
min_co2 = 0
|
||||
max_co2 = INFINITY
|
||||
min_n2 = 0
|
||||
max_n2 = INFINITY
|
||||
minbodytemp = 0
|
||||
maxbodytemp = INFINITY
|
||||
faction = list("slaughter")
|
||||
attacktext = "wildly tears into"
|
||||
maxHealth = 200
|
||||
health = 200
|
||||
environment_smash = 1
|
||||
//universal_understand = 1
|
||||
melee_damage_lower = 30
|
||||
melee_damage_upper = 30
|
||||
see_in_dark = 8
|
||||
see_invisible = SEE_INVISIBLE_MINIMUM
|
||||
var/boost = 0
|
||||
bloodcrawl = BLOODCRAWL_EAT
|
||||
|
||||
|
||||
var/devoured = 0
|
||||
var/list/consumed_mobs = list()
|
||||
|
||||
var/list/nearby_mortals = list()
|
||||
var/cooldown = 0
|
||||
var/gorecooldown = 0
|
||||
var/vialspawned = FALSE
|
||||
var/playstyle_string = "<B>You are the Slaughter Demon, a terrible creature from another existence. You have a single desire: To kill. \
|
||||
You may Ctrl+Click on blood pools to travel through them, appearing and dissaapearing from the station at will. \
|
||||
Pulling a dead or critical mob while you enter a pool will pull them in with you, allowing you to feast. \
|
||||
You move quickly upon leaving a pool of blood, but the material world will soon sap your strength and leave you sluggish. </B>"
|
||||
|
||||
|
||||
/mob/living/simple_animal/slaughter/New()
|
||||
..()
|
||||
spawn()
|
||||
if(src.mind)
|
||||
src.mind.current.verbs += /mob/living/simple_animal/slaughter/proc/slaughterWhisper
|
||||
src << src.playstyle_string
|
||||
src << "<B><span class ='notice'>You are not currently in the same plane of existence as the station. Ctrl+Click a blood pool to manifest.</span></B>"
|
||||
src << 'sound/misc/demon_dies.ogg'
|
||||
if(!(vialspawned))
|
||||
var/datum/objective/slaughter/objective = new
|
||||
var/datum/objective/demonFluff/fluffObjective = new
|
||||
ticker.mode.traitors |= src.mind
|
||||
objective.owner = src.mind
|
||||
fluffObjective.owner = src.mind
|
||||
//Paradise Port:I added the objective for one spawned like this
|
||||
src.mind.objectives += objective
|
||||
src.mind.objectives += fluffObjective
|
||||
src << "<B>Objective #[1]</B>: [objective.explanation_text]"
|
||||
src << "<B>Objective #[2]</B>: [fluffObjective.explanation_text]"
|
||||
|
||||
|
||||
/mob/living/simple_animal/slaughter/Life()
|
||||
..()
|
||||
if(boost<world.time)
|
||||
speed = 2
|
||||
else
|
||||
speed = 0
|
||||
|
||||
/mob/living/simple_animal/slaughter/death()
|
||||
..()
|
||||
var/obj/effect/decal/cleanable/blood/innards = new (get_turf(src))
|
||||
innards.icon = 'icons/obj/surgery.dmi'
|
||||
innards.icon_state = "innards"
|
||||
innards.name = "pile of viscera"
|
||||
innards.desc = "A repulsive pile of guts and gore."
|
||||
new /obj/effect/decal/cleanable/blood (src.loc)
|
||||
new /obj/effect/gibspawner/generic(get_turf(src))
|
||||
new /obj/effect/gibspawner/generic(get_turf(src))
|
||||
new /obj/item/weapon/demonheart(src.loc)
|
||||
playsound(get_turf(src),'sound/misc/demon_dies.ogg', 200, 1)
|
||||
visible_message("<span class='danger'>[src] screams in anger as it collapses into a puddle of viscera, its most recent meals spilling out of it.</span>")
|
||||
for(var/mob/living/M in consumed_mobs)
|
||||
M.forceMove(get_turf(src))
|
||||
ghostize()
|
||||
qdel(src)
|
||||
|
||||
|
||||
|
||||
/mob/living/simple_animal/slaughter/phasein()
|
||||
..()
|
||||
speed = 0
|
||||
boost = world.time + 60
|
||||
|
||||
////////////////////The Powers
|
||||
|
||||
//Paradise Port:I added this cuase..SPOOPY DEMON IN YOUR BRAIN
|
||||
|
||||
|
||||
/mob/living/simple_animal/slaughter/proc/slaughterWhisper()
|
||||
set name = "Whisper"
|
||||
set desc = "Whisper to a mortal"
|
||||
set category = "Daemon"
|
||||
|
||||
var/list/choices = list()
|
||||
for(var/mob/living/carbon/C in living_mob_list)
|
||||
if(C.stat != 2 && C.client && C.stat != DEAD)
|
||||
choices += C
|
||||
|
||||
var/mob/living/carbon/M = input(src,"Who do you wish to talk to?") in null|choices
|
||||
spawn(0)
|
||||
var/msg = stripped_input(usr, "What do you wish to tell [M]?", null, "")
|
||||
if(!(msg))
|
||||
return
|
||||
log_say("Slaughter Demon Transmit: [key_name(usr)]->[key_name(M)]: [msg]")
|
||||
usr << "<span class='info'><b>You whisper to [M]: </b>[msg]</span>"
|
||||
M << "<span class='deadsay'><b>Suddenly a strange, demonic voice resonates in your head... </b></span><i><span class='danger'> [msg]</span></I>"
|
||||
for(var/mob/dead/observer/G in player_list)
|
||||
G.show_message("<i>Demonic message from <b>[usr]</b> ([ghost_follow_link(usr, ghost=G)]) to <b>[M]</b> ([ghost_follow_link(M, ghost=G)]): [msg]</i>")
|
||||
|
||||
|
||||
//////////The Loot
|
||||
|
||||
//The loot from killing a slaughter demon - can be consumed to allow the user to blood crawl
|
||||
/obj/item/weapon/demonheart
|
||||
name = "demon heart"
|
||||
desc = "Still it beats furiously, emanating an aura of utter hate."
|
||||
icon = 'icons/obj/surgery.dmi'
|
||||
icon_state = "demon_heart"
|
||||
origin_tech = "combat=5;biotech=8"
|
||||
|
||||
|
||||
/obj/item/weapon/demonheart/attack_self(mob/living/user)
|
||||
user.visible_message("<span class='warning'>[user] raises [src] to their mouth and tears into it with their teeth!</span>", \
|
||||
"<span class='danger'>An unnatural hunger consumes you. You raise [src] to your mouth and devour it!</span>")
|
||||
playsound(user, 'sound/misc/Demon_consume.ogg', 50, 1)
|
||||
if(user.bloodcrawl == 0)
|
||||
user.visible_message("<span class='warning'>[user]'s eyes flare a deep crimson!</span>", \
|
||||
"<span class='userdanger'>You feel a strange power seep into your body... you have absorbed the demon's blood-travelling powers!</span>")
|
||||
user.bloodcrawl = BLOODCRAWL
|
||||
else if(user.bloodcrawl == 1)
|
||||
user << "You feel diffr-<span class = 'danger'> CONSUME THEM! </span>"
|
||||
user.bloodcrawl = BLOODCRAWL_EAT
|
||||
else
|
||||
user <<"<span class='warning'>...and you don't feel any different.</span>"
|
||||
qdel(src)
|
||||
|
||||
|
||||
//Objectives and helpers.
|
||||
|
||||
//Objective info, Based on Reverent mini Atang
|
||||
/datum/objective/slaughter
|
||||
var/targetKill = 10
|
||||
|
||||
/datum/objective/slaughter/New()
|
||||
targetKill = rand(10,20)
|
||||
explanation_text = "Devour [targetKill] mortals."
|
||||
..()
|
||||
|
||||
/datum/objective/slaughter/check_completion()
|
||||
if(!istype(owner.current, /mob/living/simple_animal/slaughter) || !owner.current)
|
||||
return 0
|
||||
var/mob/living/simple_animal/slaughter/R = owner.current
|
||||
if(!R || R.stat == DEAD)
|
||||
return 0
|
||||
var/deathCount = R.devoured
|
||||
if(deathCount < targetKill)
|
||||
return 0
|
||||
return 1
|
||||
|
||||
/datum/objective/demonFluff
|
||||
|
||||
|
||||
/datum/objective/demonFluff/New()
|
||||
find_target()
|
||||
var/targetname = "someone"
|
||||
if(target && target.current)
|
||||
targetname = target.current.real_name
|
||||
var/list/explanationTexts = list("Attempt to make your presence unknown to the crew.", \
|
||||
"Kill or Destroy all Janitors or Sanitation bots.", \
|
||||
"Drive [targetname] insane with demonic whispering."
|
||||
)
|
||||
|
||||
explanation_text = pick(explanationTexts)
|
||||
..()
|
||||
|
||||
/datum/objective/demonFluff/check_completion()
|
||||
return 1
|
||||
Reference in New Issue
Block a user