Resolved conflicts.
@@ -2122,6 +2122,7 @@
|
||||
/obj/machinery/light/small{
|
||||
dir = 8
|
||||
},
|
||||
/obj/machinery/portable_atmospherics/canister/nitrous_oxide,
|
||||
/turf/open/floor/plating/warnplate{
|
||||
dir = 8
|
||||
},
|
||||
@@ -6665,9 +6666,6 @@
|
||||
/area/hallway/primary/fore)
|
||||
"anS" = (
|
||||
/obj/machinery/hologram/holopad,
|
||||
/mob/living/simple_animal/bot/secbot/beepsky{
|
||||
name = "Officer Beepsky"
|
||||
},
|
||||
/turf/open/floor/plasteel,
|
||||
/area/hallway/primary/fore)
|
||||
"anT" = (
|
||||
@@ -7153,10 +7151,7 @@
|
||||
},
|
||||
/area/shuttle/labor)
|
||||
"apb" = (
|
||||
/obj/machinery/door/airlock/glass_security{
|
||||
name = "N2O Storage";
|
||||
req_access_txt = "3"
|
||||
},
|
||||
/obj/structure/plasticflaps,
|
||||
/turf/open/floor/plating,
|
||||
/area/security/processing)
|
||||
"apc" = (
|
||||
@@ -7478,7 +7473,10 @@
|
||||
/turf/open/space,
|
||||
/area/space/nearstation)
|
||||
"apR" = (
|
||||
/obj/machinery/portable_atmospherics/canister/nitrous_oxide,
|
||||
/obj/item/weapon/paper{
|
||||
info = "01001001 00100000 01101000 01101111 01110000 01100101 00100000 01111001 01101111 01110101 00100000 01110011 01110100 01100001 01111001 00100000 01110011 01100001 01100110 01100101 00101110 00100000 01001100 01101111 01110110 01100101 00101100 00100000 01101101 01101111 01101101 00101110";
|
||||
name = "Note from Beepsky's Mom"
|
||||
},
|
||||
/turf/open/floor/plating,
|
||||
/area/security/processing)
|
||||
"apS" = (
|
||||
@@ -7928,6 +7926,11 @@
|
||||
/obj/machinery/light/small{
|
||||
dir = 4
|
||||
},
|
||||
/obj/structure/table,
|
||||
/obj/machinery/cell_charger,
|
||||
/obj/item/weapon/stock_parts/cell/potato{
|
||||
name = "\improper Beepsky's emergency battery"
|
||||
},
|
||||
/turf/open/floor/plating,
|
||||
/area/security/processing)
|
||||
"aqT" = (
|
||||
@@ -60466,6 +60469,13 @@
|
||||
/obj/item/clothing/under/burial,
|
||||
/turf/open/floor/plasteel/grimy,
|
||||
/area/chapel/office)
|
||||
"cCa" = (
|
||||
/obj/item/weapon/bedsheet/red,
|
||||
/mob/living/simple_animal/bot/secbot/beepsky{
|
||||
name = "Officer Beepsky"
|
||||
},
|
||||
/turf/open/floor/plating,
|
||||
/area/security/processing)
|
||||
|
||||
(1,1,1) = {"
|
||||
aaa
|
||||
@@ -84463,9 +84473,9 @@ aiT
|
||||
ant
|
||||
akI
|
||||
aos
|
||||
aiU
|
||||
apR
|
||||
aiT
|
||||
apR
|
||||
cCa
|
||||
arP
|
||||
asT
|
||||
aqR
|
||||
|
||||
@@ -72,6 +72,8 @@
|
||||
|
||||
#define isguardian(A) (istype(A, /mob/living/simple_animal/hostile/guardian))
|
||||
|
||||
#define isumbra(A) (istype(A, /mob/living/simple_animal/umbra))
|
||||
|
||||
#define islimb(A) (istype(A, /obj/item/bodypart))
|
||||
|
||||
#define isbot(A) (istype(A, /mob/living/simple_animal/bot))
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
#define ROLE_GANG "gangster"
|
||||
#define ROLE_SHADOWLING "shadowling"
|
||||
#define ROLE_ABDUCTOR "abductor"
|
||||
#define ROLE_REVENANT "revenant"
|
||||
#define ROLE_HOG_GOD "hand of god: god"
|
||||
#define ROLE_HOG_CULTIST "hand of god: cultist"
|
||||
#define ROLE_DEVIL "devil"
|
||||
@@ -45,7 +44,6 @@ var/global/list/special_roles = list(
|
||||
ROLE_MONKEY = /datum/game_mode/monkey,
|
||||
ROLE_GANG = /datum/game_mode/gang,
|
||||
ROLE_SHADOWLING = /datum/game_mode/shadowling,
|
||||
ROLE_REVENANT,
|
||||
ROLE_ABDUCTOR = /datum/game_mode/abduction,
|
||||
ROLE_HOG_GOD = /datum/game_mode/hand_of_god,
|
||||
ROLE_HOG_CULTIST = /datum/game_mode/hand_of_god,
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#define MAX_MESSAGE_LEN 1024
|
||||
#define MAX_NAME_LEN 26
|
||||
#define MAX_BROADCAST_LEN 512
|
||||
#define MAX_CHARTER_LEN 50
|
||||
|
||||
//MINOR TWEAKS/MISC
|
||||
#define AGE_MIN 17 //youngest a character can be
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
|
||||
/datum/hud/revenant/New(mob/owner)
|
||||
..()
|
||||
|
||||
healths = new /obj/screen/healths/revenant()
|
||||
infodisplay += healths
|
||||
|
||||
/mob/living/simple_animal/revenant/create_mob_hud()
|
||||
if(client && !hud_used)
|
||||
hud_used = new /datum/hud/revenant(src)
|
||||
@@ -455,13 +455,6 @@
|
||||
screen_loc = ui_health
|
||||
mouse_opacity = 0
|
||||
|
||||
/obj/screen/healths/revenant
|
||||
name = "essence"
|
||||
icon = 'icons/mob/actions.dmi'
|
||||
icon_state = "bg_revenant"
|
||||
screen_loc = ui_health
|
||||
mouse_opacity = 0
|
||||
|
||||
/obj/screen/healthdoll
|
||||
name = "health doll"
|
||||
screen_loc = ui_healthdoll
|
||||
|
||||
@@ -2,8 +2,10 @@ This folder contains all "mini-antagonists" - antagonists that can still spice u
|
||||
Currently, that list consists of:
|
||||
-Abductors
|
||||
-Swarmers
|
||||
-Prophets of sin
|
||||
-The Jungle Fever virus (infected monkey bites human, human becomes another infected monkey)
|
||||
-Morphs
|
||||
-Revenants
|
||||
-Sintouched crewmembers
|
||||
-Slaughter demons
|
||||
-Umbras (formerly revenants)
|
||||
Please update this if you add another mini-antagonist.
|
||||
|
||||
@@ -1,385 +0,0 @@
|
||||
|
||||
//Harvest; activated ly clicking the target, will try to drain their essence.
|
||||
/mob/living/simple_animal/revenant/ClickOn(atom/A, params) //revenants can't interact with the world directly.
|
||||
A.examine(src)
|
||||
if(ishuman(A))
|
||||
if(A in drained_mobs)
|
||||
src << "<span class='revenwarning'>[A]'s soul is dead and empty.</span>" //feedback at any range
|
||||
else if(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.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, rand(10, 20), 0, 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, rand(15, 20), 0, 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, rand(15, 25), 0, 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
|
||||
essence_drained = 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>"
|
||||
reveal(46)
|
||||
stun(46)
|
||||
target.visible_message("<span class='warning'>[target] suddenly rises slightly into the air, their skin turning an ashy gray.</span>")
|
||||
var/datum/beam/B = Beam(target,icon_state="drain_life",icon='icons/effects/effects.dmi',time=46)
|
||||
if(do_after(src, 46, 0, target)) //As one cannot prove the existance of ghosts, ghosts cannot prove the existance of the target they were draining.
|
||||
qdel(B)
|
||||
change_essence_amount(essence_drained, 0, target)
|
||||
if(essence_drained <= 90 && target.stat != DEAD)
|
||||
essence_regen_cap += 5
|
||||
src << "<span class='revenboldnotice'>The absorption of [target]'s living soul has increased your maximum essence level. Your new maximum essence is [essence_regen_cap].</span>"
|
||||
if(essence_drained > 90)
|
||||
essence_regen_cap += 15
|
||||
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
|
||||
qdel(B)
|
||||
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
|
||||
|
||||
//Toggle night vision: lets the revenant toggle its night vision
|
||||
/obj/effect/proc_holder/spell/targeted/night_vision/revenant
|
||||
charge_max = 0
|
||||
panel = "Revenant Abilities"
|
||||
message = "<span class='revennotice'>You toggle your night vision.</span>"
|
||||
action_icon_state = "r_nightvision"
|
||||
action_background_icon_state = "bg_revenant"
|
||||
|
||||
//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]")
|
||||
user << "<span class='revenboldnotice'>You transmit to [M]:</span> <span class='revennotice'>[msg]</span>"
|
||||
M << "<span class='revenboldnotice'>An alien voice resonates from all around...</span> <span class='revennotice'>[msg]</span>"
|
||||
for(var/ded in dead_mob_list)
|
||||
if(!isobserver(ded))
|
||||
continue
|
||||
var/follow_rev = FOLLOW_LINK(ded, user)
|
||||
var/follow_whispee = FOLLOW_LINK(ded, M)
|
||||
ded << "[follow_rev] \
|
||||
<span class='name'>[user]</span> \
|
||||
<span class='revenboldnotice'>Revenant Transmit --></span> \
|
||||
[follow_whispee] \
|
||||
<span class='name'>[M]</span> \
|
||||
<span class='revennotice'>[msg]</span>"
|
||||
|
||||
|
||||
|
||||
/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(!istype(user)) //Badmins, no. Badmins, don't do it.
|
||||
if(charge_counter < charge_max)
|
||||
return 0
|
||||
return 1
|
||||
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(!istype(user)) //If you're not a revenant, it works. Please, please, please don't give this to a non-revenant.
|
||||
name = "[initial(name)]"
|
||||
if(locked)
|
||||
panel = "Revenant Abilities"
|
||||
locked = 0
|
||||
return 1
|
||||
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)
|
||||
if(action)
|
||||
action.UpdateButtonIcon()
|
||||
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 = 40
|
||||
var/shock_range = 2
|
||||
var/shock_damage = 20
|
||||
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()
|
||||
PoolOrNew(/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)
|
||||
continue
|
||||
L.Beam(M,icon_state="purple_lightning",icon='icons/effects/effects.dmi',time=5)
|
||||
M.electrocute_act(shock_damage, L, 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 = 4
|
||||
stun = 10
|
||||
reveal = 40
|
||||
unlock_amount = 75
|
||||
cast_amount = 30
|
||||
action_icon_state = "defile"
|
||||
|
||||
/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
|
||||
PoolOrNew(/obj/effect/overlay/temp/revenant, T)
|
||||
if(!istype(T, /turf/open/floor/plating) && !istype(T, /turf/open/floor/engine/cult) && istype(T, /turf/open/floor) && prob(15))
|
||||
var/turf/open/floor/floor = T
|
||||
if(floor.intact)
|
||||
floor.builtin_tile.loc = floor
|
||||
floor.broken = 0
|
||||
floor.burnt = 0
|
||||
floor.make_plating(1)
|
||||
if(T.type == /turf/closed/wall && prob(15))
|
||||
PoolOrNew(/obj/effect/overlay/temp/revenant, T)
|
||||
T.ChangeTurf(/turf/closed/wall/rust)
|
||||
if(T.type == /turf/closed/wall/r_wall && prob(10))
|
||||
PoolOrNew(/obj/effect/overlay/temp/revenant, T)
|
||||
T.ChangeTurf(/turf/closed/wall/r_wall/rust)
|
||||
for(var/obj/structure/closet/closet in T.contents)
|
||||
closet.open()
|
||||
for(var/obj/structure/bodycontainer/corpseholder in T.contents)
|
||||
if(corpseholder.connected.loc == corpseholder)
|
||||
corpseholder.open()
|
||||
for(var/obj/machinery/dna_scannernew/dna in T.contents)
|
||||
dna.open_machine()
|
||||
for(var/obj/structure/window/window in T.contents)
|
||||
window.take_damage(rand(30,80))
|
||||
if(window && window.fulltile)
|
||||
PoolOrNew(/obj/effect/overlay/temp/revenant/cracks, window.loc)
|
||||
for(var/obj/machinery/light/light in T.contents)
|
||||
light.flicker(20) //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
|
||||
cast_amount = 45
|
||||
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/mob/living/simple_animal/bot/bot in T.contents)
|
||||
if(!bot.emagged)
|
||||
PoolOrNew(/obj/effect/overlay/temp/revenant, bot.loc)
|
||||
bot.locked = 0
|
||||
bot.open = 1
|
||||
bot.emag_act()
|
||||
for(var/mob/living/carbon/human/human in T.contents)
|
||||
if(human == user)
|
||||
continue
|
||||
human << "<span class='revenwarning'>You feel [pick("your sense of direction flicker out", "a stabbing pain in your head", "your mind fill with static")].</span>"
|
||||
PoolOrNew(/obj/effect/overlay/temp/revenant, human.loc)
|
||||
human.emp_act(1)
|
||||
for(var/obj/thing in T.contents)
|
||||
if(istype(thing, /obj/machinery/dominator) || istype(thing, /obj/machinery/power/apc) || istype(thing, /obj/machinery/power/smes)) //Doesn't work on dominators, SMES and APCs, to prevent kekkery
|
||||
continue
|
||||
if(prob(20))
|
||||
if(prob(50))
|
||||
PoolOrNew(/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)
|
||||
PoolOrNew(/obj/effect/overlay/temp/revenant, S.loc)
|
||||
S.spark_system.start()
|
||||
S.emp_act(1)
|
||||
|
||||
//Blight: Infects nearby humans and in general messes living stuff up.
|
||||
/obj/effect/proc_holder/spell/aoe_turf/revenant/blight
|
||||
name = "Blight"
|
||||
desc = "Causes nearby living things to waste away."
|
||||
charge_max = 200
|
||||
range = 3
|
||||
reveal = 50
|
||||
cast_amount = 50
|
||||
unlock_amount = 200
|
||||
action_icon_state = "blight"
|
||||
|
||||
/obj/effect/proc_holder/spell/aoe_turf/revenant/blight/cast(list/targets, mob/living/simple_animal/revenant/user = usr)
|
||||
if(attempt_cast(user))
|
||||
for(var/turf/T in targets)
|
||||
spawn(0)
|
||||
for(var/mob/living/mob in T.contents)
|
||||
if(mob == user)
|
||||
continue
|
||||
PoolOrNew(/obj/effect/overlay/temp/revenant, mob.loc)
|
||||
if(iscarbon(mob))
|
||||
if(ishuman(mob))
|
||||
var/mob/living/carbon/human/H = mob
|
||||
if(H.dna && H.dna.species)
|
||||
H.dna.species.handle_mutant_bodyparts(H,"#1d2953")
|
||||
H.dna.species.handle_hair(H,"#1d2953")
|
||||
var/old_color = H.color
|
||||
H.color = "#1d2953"
|
||||
spawn(20)
|
||||
if(H && H.dna && H.dna.species)
|
||||
H.dna.species.handle_mutant_bodyparts(H)
|
||||
H.dna.species.handle_hair(H)
|
||||
H.color = old_color
|
||||
var/blightfound = 0
|
||||
for(var/datum/disease/revblight/blight in H.viruses)
|
||||
blightfound = 1
|
||||
if(blight.stage < 5)
|
||||
blight.stage++
|
||||
if(!blightfound)
|
||||
H.AddDisease(new /datum/disease/revblight)
|
||||
H << "<span class='revenminor'>You feel [pick("suddenly sick", "a surge of nausea", "like your skin is <span class='italics'>wrong</span>")].</span>"
|
||||
else
|
||||
if(mob.reagents)
|
||||
mob.reagents.add_reagent("plasma", 5)
|
||||
else
|
||||
mob.adjustToxLoss(5)
|
||||
for(var/obj/effect/spacevine/vine in T.contents) //Fucking with botanists, the ability.
|
||||
vine.color = "#823abb"
|
||||
PoolOrNew(/obj/effect/overlay/temp/revenant, vine.loc)
|
||||
spawn(10)
|
||||
if(vine)
|
||||
qdel(vine)
|
||||
for(var/obj/effect/glowshroom/shroom in T.contents)
|
||||
shroom.color = "#823abb"
|
||||
PoolOrNew(/obj/effect/overlay/temp/revenant, shroom.loc)
|
||||
spawn(10)
|
||||
if(shroom)
|
||||
qdel(shroom)
|
||||
for(var/obj/machinery/hydroponics/tray in T.contents)
|
||||
PoolOrNew(/obj/effect/overlay/temp/revenant, tray.loc)
|
||||
tray.pestlevel = rand(8, 10)
|
||||
tray.weedlevel = rand(8, 10)
|
||||
tray.toxic = rand(45, 55)
|
||||
@@ -1,68 +0,0 @@
|
||||
/datum/disease/revblight
|
||||
name = "Unnatural Wasting"
|
||||
max_stages = 5
|
||||
stage_prob = 10
|
||||
spread_flags = NON_CONTAGIOUS
|
||||
cure_text = "Holy water or extensive rest."
|
||||
spread_text = "A burst of unholy energy"
|
||||
cures = list("holywater")
|
||||
cure_chance = 50 //higher chance to cure, because revenants are assholes
|
||||
agent = "Unholy Forces"
|
||||
viable_mobtypes = list(/mob/living/carbon/human)
|
||||
disease_flags = CURABLE
|
||||
permeability_mod = 1
|
||||
severity = BIOHAZARD
|
||||
var/stagedamage = 0 //Highest stage reached.
|
||||
var/finalstage = 0 //Because we're spawning off the cure in the final stage, we need to check if we've done the final stage's effects.
|
||||
|
||||
/datum/disease/revblight/cure()
|
||||
if(affected_mob)
|
||||
affected_mob << "<span class='notice'>You feel better.</span>"
|
||||
if(affected_mob.dna && affected_mob.dna.species)
|
||||
affected_mob.dna.species.handle_mutant_bodyparts(affected_mob)
|
||||
..()
|
||||
|
||||
/datum/disease/revblight/stage_act()
|
||||
if(!finalstage && affected_mob.lying && prob(stage*5))
|
||||
cure()
|
||||
return
|
||||
if(!finalstage && prob(stage*3))
|
||||
affected_mob << "<span class='revennotice'>You suddenly feel [pick("sick and tired", "disoriented", "tired and confused", "nauseated", "faint", "dizzy")]...</span>"
|
||||
affected_mob.confused += 10
|
||||
affected_mob.adjustStaminaLoss(10)
|
||||
PoolOrNew(/obj/effect/overlay/temp/revenant, affected_mob.loc)
|
||||
if(!finalstage && stagedamage < stage)
|
||||
stagedamage++
|
||||
affected_mob.adjustToxLoss(stage*3) //should, normally, do about 45 toxin damage.
|
||||
PoolOrNew(/obj/effect/overlay/temp/revenant, affected_mob.loc)
|
||||
if(!finalstage && prob(45))
|
||||
affected_mob.adjustStaminaLoss(stage*2)
|
||||
..() //So we don't increase a stage before applying the stage damage.
|
||||
switch(stage)
|
||||
if(2)
|
||||
if(prob(5))
|
||||
affected_mob.emote("pale")
|
||||
if(3)
|
||||
if(prob(10))
|
||||
affected_mob.emote(pick("pale","shiver"))
|
||||
if(4)
|
||||
if(prob(15))
|
||||
affected_mob.emote(pick("pale","shiver","cries"))
|
||||
if(5)
|
||||
if(!finalstage)
|
||||
finalstage = 1
|
||||
affected_mob << "<span class='revenbignotice'>You feel like [pick("nothing's worth it anymore", "nobody ever needed your help", "nothing you did mattered", "everything you tried to do was worthless")].</span>"
|
||||
affected_mob.adjustStaminaLoss(45)
|
||||
PoolOrNew(/obj/effect/overlay/temp/revenant, affected_mob.loc)
|
||||
if(affected_mob.dna && affected_mob.dna.species)
|
||||
affected_mob.dna.species.handle_mutant_bodyparts(affected_mob,"#1d2953")
|
||||
affected_mob.dna.species.handle_hair(affected_mob,"#1d2953")
|
||||
affected_mob.visible_message("<span class='warning'>[affected_mob] looks terrifyingly gaunt...</span>", "<span class='revennotice'>You suddenly feel like your skin is <span class='italics'>wrong</span>...</span>")
|
||||
var/old_color = affected_mob.color
|
||||
affected_mob.color = "#1d2953"
|
||||
spawn(100)
|
||||
if(affected_mob)
|
||||
affected_mob = old_color
|
||||
cure()
|
||||
else
|
||||
return
|
||||
@@ -1,63 +0,0 @@
|
||||
#define REVENANT_SPAWN_THRESHOLD 20
|
||||
|
||||
/datum/round_event_control/revenant
|
||||
name = "Spawn Revenant" // Did you mean 'griefghost'?
|
||||
typepath = /datum/round_event/ghost_role/revenant
|
||||
weight = 7
|
||||
max_occurrences = 1
|
||||
earliest_start = 12000 //Meant to mix things up early-game.
|
||||
min_players = 5
|
||||
|
||||
|
||||
/datum/round_event/ghost_role/revenant
|
||||
var/force_spawn
|
||||
role_name = "revenant"
|
||||
|
||||
/datum/round_event/ghost_role/revenant/New(my_force_spawn = FALSE)
|
||||
..()
|
||||
force_spawn = my_force_spawn
|
||||
|
||||
/datum/round_event/ghost_role/revenant/spawn_role()
|
||||
if(!force_spawn)
|
||||
var/deadMobs = 0
|
||||
for(var/mob/M in dead_mob_list)
|
||||
deadMobs++
|
||||
if(deadMobs < REVENANT_SPAWN_THRESHOLD)
|
||||
message_admins("Event attempted to spawn a revenant, but there were only [deadMobs]/[REVENANT_SPAWN_THRESHOLD] dead mobs.")
|
||||
return WAITING_FOR_SOMETHING
|
||||
|
||||
var/list/mob/dead/observer/candidates = get_candidates("revenant", null, ROLE_REVENANT)
|
||||
if(!candidates.len)
|
||||
return NOT_ENOUGH_PLAYERS
|
||||
|
||||
var/mob/dead/observer/selected = popleft(candidates)
|
||||
|
||||
var/datum/mind/player_mind = new /datum/mind(selected.key)
|
||||
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 give up and cry
|
||||
return MAP_ERROR
|
||||
|
||||
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("[player_mind.key] has been made into a revenant by an event.")
|
||||
log_game("[player_mind.key] was spawned as a revenant by an event.")
|
||||
spawned_mobs += revvie
|
||||
return SUCCESSFUL_SPAWN
|
||||
@@ -0,0 +1,369 @@
|
||||
#define UMBRA_INVISIBILITY 50
|
||||
#define UMBRA_VITAE_DRAIN_RATE 0.01 //How much vitae is drained per tick to sustain the umbra. Set this to higher values to make umbras need to harvest vitae more often.
|
||||
#define UMBRA_MAX_HARVEST_COOLDOWN 3000 //In deciseconds, how long it takes for a harvested target to become eligible for draining again.
|
||||
#define UMBRA_POSSESSION_THRESHOLD_WARNING 60 //In ticks, how long it takes before a possessed human starts showing signs of possession
|
||||
#define UMBRA_POSSESSION_THRESHOLD_DANGER 150 //In ticks, how long it takes before a possessed human starts forcing out the umbra
|
||||
#define UMBRA_POSSESSION_THRESHOLD_FORCED_OUT 155 //In ticks, how long it takes before a possessed human forces out the umbra
|
||||
|
||||
/*
|
||||
|
||||
Umbras are residual entities created by the dying who possess enough anger or determination that they never fully pass on.
|
||||
Physically, they're incorporeal and invisible. Umbras are formed of a steadily-decaying electromagnetic field with a drive to sustain itself.
|
||||
Umbras do this by feeding on a substance, found in the dead or dying, known as vitae.
|
||||
|
||||
Vitae is most closely comparable to adrenaline in that is produced by creatures at times of distress. For this reason, almost all dead creatures have vitae in one way or another.
|
||||
Biologically, it's indistinguishable from normal blood, but vitae is what allows creatures to survive grievous wounds or cling to life in critical condition. It provides a large amount of energy.
|
||||
It's for this reason that umbras desire it. Vitae serves as a potent energy source to a living thing, and umbras can use the energy of this vitae to sustain themselves.
|
||||
Without enough vitae, the field that sustains an umbra will break down and weaken. If the umbra has no vitae at all, it will permanently dissipate.
|
||||
|
||||
Umbras are not without their weaknesses. Despite being invisible to the naked eye and untouchable, certain things can restrict, weaken, or outright harm them.
|
||||
Piles of salt on the ground will prevent an umbra's passage, making areas encircled in it completely inaccessible to even the most determined umbra.
|
||||
In addition, objects and artifacts of a holy nature can force an umbra to manifest or draw away some of the energy that it's gleaned through vitae.
|
||||
|
||||
When an umbra dies, two things can occur. If the umbra died from passive vitae drain, it will be dead forever, with no way to bring it back.
|
||||
However, if the umbra is slain forcibly and still has vitae, the vitae possesses enough power to coalesce a part of the umbra into umbral ashes.
|
||||
These "ashes" will, given around a full minute, re-form into another umbra. This umbra typically possesses the memories and consciousness of the old one, but may be a completely new mind as well.
|
||||
Although these umbral ashes make umbras resilient, they can be killed permanently by scattering the ashes or destroying them, thus separating the vitae from the umbra's remains.
|
||||
|
||||
*/
|
||||
|
||||
/mob/living/simple_animal/umbra
|
||||
name = "umbra"
|
||||
real_name = "umbra"
|
||||
desc = "A translucent, cobalt-blue apparition floating several feet in the air."
|
||||
invisibility = UMBRA_INVISIBILITY
|
||||
icon = 'icons/mob/mob.dmi'
|
||||
icon_state = "umbra"
|
||||
icon_living = "umbra"
|
||||
layer = GHOST_LAYER
|
||||
alpha = 175 //To show invisibility
|
||||
health = 100
|
||||
maxHealth = 100
|
||||
healable = 0
|
||||
damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0)
|
||||
healable = FALSE
|
||||
friendly = "passes through"
|
||||
speak_emote = list("murmurs")
|
||||
emote_hear = list("murmurs")
|
||||
languages = ALL
|
||||
incorporeal_move = 3
|
||||
flying = TRUE
|
||||
stop_automated_movement = TRUE
|
||||
wander = FALSE
|
||||
sight = SEE_SELF
|
||||
see_invisible = SEE_INVISIBLE_NOLIGHTING
|
||||
see_in_dark = 8
|
||||
minbodytemp = 0
|
||||
maxbodytemp = INFINITY
|
||||
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
|
||||
var/vitae = 10 //The amount of vitae captured by the umbra
|
||||
var/vitae_cap = 100 //How much vitae a single umbra can hold
|
||||
var/breaking_apart = FALSE //If the umbra is currently dying
|
||||
var/harvesting = FALSE //If the umbra is harvesting a soul
|
||||
var/list/recently_drained = list() //Mobs that have been drained in the last five minutes by the umbra
|
||||
var/list/total_drained = list() //Mobs that have been drained, period
|
||||
var/mob/living/carbon/human/possessed //The human that an umbra is inside of, if applicable
|
||||
var/time_possessing = 0 //How long an umbra has been in possession of a single target.
|
||||
var/list/lobotomized = list() //Mobs that have had their memories stolen by the umbra
|
||||
var/playstyle_string = "<span class='umbra_large'><b>You are an umbra,</b></span><b> and you aren't quite sure how you're alive. You don't remember much, but you remember slipping away, \
|
||||
lsoing your hold on life. You died, but here you are... somehow. You can't be quite sure how this happened, but you're pretty sure that it won't last long. Already you feel this strange \
|
||||
form of life weakening. You need to find a way to sustain yourself, and you think you might have an idea.\n\
|
||||
\n\
|
||||
You seem to be invisible and incorporeal, so you don't think that anyone can see, feel, or otherwise perceive you right now, but there has to be some way that you managed not to just fully \
|
||||
die and instead ended up like this. You think that if you find a corpse, or perhaps someone still alive but in critical condition, you'd be able to drain whatever kept you in this state \
|
||||
from them. At first the idea sounds horrible - stealing their very life force - but as you continue to weaken it sounds more and more appealing... you think it'd be as simple as interacting \
|
||||
with them. Something in the back of your mind tells you to call this life force <i>vitae</i>.\n\
|
||||
\n\
|
||||
In any case, you can definitely feel something else. You feel partially alive, but partially dead. Perhaps somewhere in between. Nonetheless, you might be able to influence both realms. \
|
||||
You can see clearly in the dark, and you seem to have a sort of limited telepathic capabilities, plus some other things. You'll have to experiment with your new form to find out what you \
|
||||
exactly you can do."
|
||||
|
||||
|
||||
//Creation, destruction, life, and death
|
||||
/mob/living/simple_animal/umbra/New()
|
||||
..()
|
||||
if(prob(1))
|
||||
name = "grief ghost"
|
||||
real_name = "grief ghost"
|
||||
desc = "You wonder how something that produces so much salt can be weak to it."
|
||||
AddSpell(new/obj/effect/proc_holder/spell/targeted/night_vision/umbra(null))
|
||||
AddSpell(new/obj/effect/proc_holder/spell/targeted/discordant_whisper(null))
|
||||
AddSpell(new/obj/effect/proc_holder/spell/targeted/possess(null))
|
||||
AddSpell(new/obj/effect/proc_holder/spell/targeted/thoughtsteal(null))
|
||||
|
||||
/mob/living/simple_animal/umbra/Life()
|
||||
..()
|
||||
if(!possessed)
|
||||
adjust_vitae(-UMBRA_VITAE_DRAIN_RATE, TRUE, "passive drain")
|
||||
time_possessing = 0
|
||||
else
|
||||
if(possessed.reagents && possessed.reagents.has_reagent("sodiumchloride"))
|
||||
unpossess(TRUE)
|
||||
visible_message("<span class='warning'>[src] appears from nowhere, twitching and flickering!</span>", "<span class='userdanger'>AAAH! SALT!</span>")
|
||||
immobilize(30)
|
||||
reveal(50)
|
||||
return
|
||||
if(possessed.stat == DEAD)
|
||||
unpossess()
|
||||
return
|
||||
adjust_vitae(UMBRA_VITAE_DRAIN_RATE, TRUE, "passive gain")
|
||||
time_possessing++
|
||||
switch(time_possessing)
|
||||
if(0 to UMBRA_POSSESSION_THRESHOLD_WARNING)
|
||||
if(prob(1))
|
||||
possessed << "<span class='warning'>You feel [pick("watched", "not wholly yourself", "an intense craving for salt", "singularly odd", \
|
||||
"a horrible dread in your heart")].</span>"
|
||||
if(UMBRA_POSSESSION_THRESHOLD_WARNING to UMBRA_POSSESSION_THRESHOLD_DANGER)
|
||||
if(prob(2))
|
||||
possessed << "<span class='warning'>[pick("Another mind briefly touches yours, then fades", "Your vision briefly flares violet", "You feel a brief pain in your chest", \
|
||||
"A murmur from within your mind, too quiet to understand", "You become uneasy for no explainable reason")].</span>"
|
||||
if(prob(5))
|
||||
possessed.emote("twitch")
|
||||
if(UMBRA_POSSESSION_THRESHOLD_DANGER to UMBRA_POSSESSION_THRESHOLD_FORCED_OUT)
|
||||
possessed << "<span class='userdanger'>GET OUT GET OUT GET OUT</span>"
|
||||
possessed.confused = max(3, possessed.confused)
|
||||
possessed.emote(pick("moan", "groan", "shiver", "twitch", "cry"))
|
||||
flash_color(possessed, flash_color = "#5000A0", flash_time = 10)
|
||||
if(UMBRA_POSSESSION_THRESHOLD_FORCED_OUT to INFINITY)
|
||||
src << "<span class='userdanger'>You can't stay any longer - you retreat from [possessed]'s body!</span>"
|
||||
unpossess(TRUE)
|
||||
return
|
||||
if(time_possessing == UMBRA_POSSESSION_THRESHOLD_WARNING)
|
||||
src << "<span class='warning'>[possessed] is starting to catch on to your presence. Be wary.</span>"
|
||||
else if(time_possessing == UMBRA_POSSESSION_THRESHOLD_DANGER)
|
||||
src << "<span class='userdanger'>[possessed] has noticed your presence and is forcing you out!</span>"
|
||||
possessed << "<span class='userdanger'>There's something in your head! You start trying to force it out--</span>"
|
||||
else if(time_possessing == UMBRA_POSSESSION_THRESHOLD_FORCED_OUT)
|
||||
src << "<span class='userdanger'>You can't stay any longer! You flee from [possessed]...</span>"
|
||||
unpossess()
|
||||
adjustBruteLoss(-1) //Vitae slowly heals the umbra as well
|
||||
adjustFireLoss(-1)
|
||||
if(!vitae)
|
||||
death()
|
||||
|
||||
/mob/living/simple_animal/umbra/Stat()
|
||||
..()
|
||||
if(statpanel("Status"))
|
||||
stat(null, "Vitae: [vitae]/[vitae_cap]")
|
||||
stat(null, "Vitae Cost/Tick: [UMBRA_VITAE_DRAIN_RATE]")
|
||||
var/drained_mobs = ""
|
||||
var/length = recently_drained.len
|
||||
for(var/mob/living/L in recently_drained)
|
||||
if(!L)
|
||||
recently_drained -= L
|
||||
length--
|
||||
else
|
||||
drained_mobs += "[L.real_name][length > 1 ? ", " : ""]"
|
||||
length--
|
||||
stat(null, "Recently Drained Creatures: [drained_mobs ? "[drained_mobs]" : "None"]")
|
||||
if(possessed)
|
||||
stat(null, "Time in [possessed]: [time_possessing]/[UMBRA_POSSESSION_THRESHOLD_FORCED_OUT]")
|
||||
|
||||
/mob/living/simple_animal/umbra/death()
|
||||
if(breaking_apart)
|
||||
return
|
||||
..(1)
|
||||
unpossess(TRUE)
|
||||
breaking_apart = TRUE
|
||||
notransform = TRUE
|
||||
invisibility = FALSE
|
||||
visible_message("<span class='warning'>An [name] appears from nowhere and begins to disintegrate!</span>", \
|
||||
"<span class='userdanger'>You feel your will faltering, and your form begins to break apart!</span>")
|
||||
flick("umbra_disintegrate", src)
|
||||
sleep(12)
|
||||
if(vitae)
|
||||
visible_message("<span class='warning'>[src] breaks apart into a pile of ashes!</span>", \
|
||||
"<span class='umbra_emphasis'><font size=3>You'll</font> be <font size=1>back...</font></span>")
|
||||
var/obj/item/umbral_ashes/P = new(get_turf(src))
|
||||
P.umbra_key = key
|
||||
P.umbra_vitae = vitae
|
||||
else
|
||||
visible_message("<span class='warning'>[src] breaks apart and fades away!</span>")
|
||||
qdel(src)
|
||||
|
||||
/mob/living/simple_animal/umbra/proc/reveal(time, silent) //Makes the umbra visible for the designated amount of deciseconds
|
||||
if(!time)
|
||||
return
|
||||
if(!silent)
|
||||
src << "<span class='warning'>You've become visible!</span>"
|
||||
alpha = 255
|
||||
invisibility = FALSE
|
||||
spawn(time)
|
||||
alpha = initial(alpha)
|
||||
if(!silent)
|
||||
src << "<span class='umbra'>You've become invisible again!</span>"
|
||||
invisibility = UMBRA_INVISIBILITY
|
||||
|
||||
/mob/living/simple_animal/umbra/proc/immobilize(time, silent) //Immobilizes the umbra for the designated amount of deciseconds
|
||||
if(!time)
|
||||
return
|
||||
if(!silent)
|
||||
src << "<span class='warning'>You can't move!</span>"
|
||||
notransform = TRUE
|
||||
spawn(time)
|
||||
if(!silent)
|
||||
src << "<span class='umbra'>You can move again!</span>"
|
||||
notransform = FALSE
|
||||
|
||||
|
||||
//Actions and interaction
|
||||
/mob/living/simple_animal/umbra/say() //Umbras can't directly speak
|
||||
src << "<span class='warning'>You lack the power to speak out loud! Use Discordant Whisper instead.</span>"
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/umbra/attack_ghost(mob/dead/observer/O)
|
||||
if(key)
|
||||
return
|
||||
if(alert(O, "Become an umbra? You won't be clonable!",,"Yes", "No") == "No" || !O)
|
||||
return
|
||||
occupy(O)
|
||||
notify_ghosts("The umbra at [get_area(src)] has been taken control of by [O].", source = src, action = NOTIFY_ORBIT)
|
||||
src << playstyle_string
|
||||
|
||||
/mob/living/simple_animal/umbra/ClickOn(atom/A, params)
|
||||
A.examine(src)
|
||||
if(isliving(A) && Adjacent(A))
|
||||
var/mob/living/L = A
|
||||
if(L.health > 0 && L.stat != DEAD)
|
||||
src << "<span class='warning'>[L] has no vitae to drain!</span>"
|
||||
return
|
||||
else if(L in recently_drained)
|
||||
src << "<span class='warning'>[L]'s body is still recuperating! You can't risk draining any more vitae!</span>"
|
||||
return
|
||||
else if(harvesting)
|
||||
src << "<span class='warning'>You're already trying to harvest vitae!</span>"
|
||||
return
|
||||
harvest_vitae(L)
|
||||
|
||||
/mob/living/simple_animal/umbra/proc/harvest_vitae(mob/living/L) //How umbras drain vitae from their targets
|
||||
if(!L || L.health || L in recently_drained)
|
||||
return
|
||||
harvesting = TRUE
|
||||
src << "<span class='umbra'>You search for any vitae in [L]...</span>"
|
||||
if(!do_after(src, 30, target = L))
|
||||
harvesting = FALSE
|
||||
return
|
||||
if(L.hellbound)
|
||||
src << "<span class='warning'>[L] seems to be incapable of producing vitae!</span>"
|
||||
harvesting = FALSE
|
||||
return
|
||||
if(!L.stat)
|
||||
src << "<span class='warning'>[L] is conscious again and their vitae is receding!</span>"
|
||||
L << "<span class='warning'>You're being watched.</span>"
|
||||
harvesting = FALSE
|
||||
return
|
||||
var/vitae_yield = 1 //A bit of essence even if it's a weak soul
|
||||
var/vitae_information = "<span class='umbra'>[L]'s vitae is "
|
||||
if(ishuman(L))
|
||||
vitae_information += "of the highest quality, "
|
||||
vitae_yield += rand(10, 15)
|
||||
if(L.mind)
|
||||
if(!(L.mind in ticker.mode.devils))
|
||||
vitae_information += "in copious amounts, "
|
||||
else
|
||||
vitae_information += "coming from multiple sources, "
|
||||
for(var/i in 1 to (L.mind.devilinfo.soulsOwned.len))
|
||||
vitae_yield += rand(5, 10) //You can drain all the souls that a devil has stolen!
|
||||
vitae_yield += rand(10, 15)
|
||||
if(L.stat == UNCONSCIOUS)
|
||||
vitae_information += "still being produced, "
|
||||
vitae_yield += rand(20, 25) //Significant bonus if the target is in critical condition instead of dead
|
||||
else if(L.stat == DEAD)
|
||||
vitae_information += "stagnant, "
|
||||
vitae_yield += rand(1, 10)
|
||||
vitae_information += "and ready for harvest. You'll absorb around [vitae_yield] vitae - "
|
||||
switch(vitae_yield)
|
||||
if(0 to 15)
|
||||
vitae_information += "not much, but everything counts."
|
||||
if(15 to 30)
|
||||
vitae_information += "decent, but not great."
|
||||
if(30 to 45)
|
||||
vitae_information += "about what you could expect."
|
||||
if(45 to 60)
|
||||
vitae_information += "a good bit, more than you've come to expect."
|
||||
if(75 to vitae_cap)
|
||||
vitae_information += "<i>a bounty, more than you could ever dream of!</i>"
|
||||
vitae_information += " Now, then...</span>"
|
||||
src << vitae_information
|
||||
if(!do_after(src, 30, target = L))
|
||||
harvesting = FALSE
|
||||
return
|
||||
if(L.hellbound)
|
||||
src << "<span class='warning'>[L] seems to have lost their vitae!</span>"
|
||||
harvesting = FALSE
|
||||
return
|
||||
if(!L.stat)
|
||||
src << "<span class='warning'>[L] is conscious again and their vitae is receding!</span>"
|
||||
L << "<span class='warning'>A chill runs across your body.</span>"
|
||||
harvesting = FALSE
|
||||
return
|
||||
immobilize(50)
|
||||
reveal(50)
|
||||
visible_message("<span class='warning'>[src] flickers into existence and reaches out towards [L]...</span>")
|
||||
L.visible_message("<span class='warning'>...who rises into the air, shuddering as purple light streams out of their body!</span>")
|
||||
animate(L, pixel_y = 5, time = 10)
|
||||
Beam(L, icon_state = "drain_life", icon = 'icons/effects/effects.dmi', time = 50)
|
||||
sleep(50)
|
||||
adjust_vitae(vitae_yield, FALSE, "[L]. They won't yield any more for the time being")
|
||||
recently_drained |= L
|
||||
total_drained |= L
|
||||
visible_message("<span class='warning'>[src] winks out of existence, releasing its hold on [L]...</span>")
|
||||
L.visible_message("<span class='warning'>...who falls unceremoniously back to the ground.</span>")
|
||||
animate(L, pixel_y = 0, time = 10)
|
||||
addtimer(src, "harvest_cooldown", rand(UMBRA_MAX_HARVEST_COOLDOWN - 600, UMBRA_MAX_HARVEST_COOLDOWN), L)
|
||||
harvesting = FALSE
|
||||
return 1
|
||||
|
||||
/mob/living/simple_animal/umbra/proc/harvest_cooldown(mob/living/L) //After a while, mobs that have already been drained can be harvested again
|
||||
if(!L)
|
||||
return
|
||||
src << "<span class='umbra'>You think that [L]'s body should be strong enough to produce vitae again.</span>"
|
||||
recently_drained -= L
|
||||
|
||||
/mob/living/simple_animal/umbra/singularity_act() //Umbras are immune to most things that are catastrophic to normal humans
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/umbra/narsie_act()
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/umbra/ratvar_act()
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/umbra/blob_act(obj/effect/blob/B)
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/umbra/ex_act(severity)
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/umbra/emp_act(severity)
|
||||
src << "<span class='umbra_bold'>You feel the energy of an electromagnetic pulse revitalizing you!</span>" //As they're composed of an EM field, umbras are strengthened by EMPs
|
||||
adjust_vitae(50 - (severity * 10), TRUE)
|
||||
|
||||
|
||||
//Helper procs
|
||||
/mob/living/simple_animal/umbra/proc/adjust_vitae(amount, silent, source)
|
||||
vitae = min(max(0, vitae + amount), vitae_cap)
|
||||
if(!silent)
|
||||
src << "<span class='umbra'>[amount > 0 ? "Gained" : "Lost"] [amount] vitae[source ? " from [source]" : ""].</span>"
|
||||
return vitae
|
||||
|
||||
/mob/living/simple_animal/umbra/proc/unpossess(silent)
|
||||
if(!possessed)
|
||||
return
|
||||
if(!silent)
|
||||
src << "<span class='umbra'>You free yourself from [possessed]'s body.</span>"
|
||||
if(time_possessing >= UMBRA_POSSESSION_THRESHOLD_WARNING)
|
||||
possessed << "<span class='warning'>You feel a horrible presence depart from you...</span>"
|
||||
loc = get_turf(possessed)
|
||||
possessed = null
|
||||
time_possessing = 0
|
||||
notransform = FALSE
|
||||
|
||||
/mob/living/simple_animal/umbra/proc/occupy(mob/dead/observer/O)
|
||||
if(!O)
|
||||
return
|
||||
key = O.key
|
||||
mind.special_role = "Umbra"
|
||||
var/datum/objective/umbra/lobotomize/L = new
|
||||
mind.objectives += L
|
||||
src << "<b>Objective #1:</b> [L.explanation_text]"
|
||||
@@ -0,0 +1,117 @@
|
||||
//Unlike revenants, abilities used by umbras generally don't cost any vitae.
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/night_vision/umbra //Toggle Nightvision: Self-explanatory
|
||||
panel = "Umbral Evocation"
|
||||
message = "<span class='umbra'>You toggle your night vision.</span>"
|
||||
charge_max = 0
|
||||
action_icon_state = "umbral_sight"
|
||||
action_background_icon_state = "bg_umbra"
|
||||
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/discordant_whisper //Discordant Whisper: Sends a single, silent message to a creature that the umbra can see. Doesn't work on dead targets.
|
||||
name = "Discordant Whisper"
|
||||
desc = "Telepathically sends a single message to a target within range. Nobody else can perceive this message, and it works on unconscious and deafened targets."
|
||||
panel = "Umbral Evocation"
|
||||
range = 7
|
||||
charge_max = 50
|
||||
clothes_req = FALSE
|
||||
include_user = FALSE
|
||||
action_icon_state = "discordant_whisper"
|
||||
action_background_icon_state = "bg_umbra"
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/discordant_whisper/cast(list/targets, mob/living/simple_animal/umbra/user)
|
||||
if(!isumbra(user))
|
||||
revert_cast()
|
||||
return
|
||||
var/mob/living/target = targets[1]
|
||||
if(target.stat == DEAD)
|
||||
user << "<span class='warning'>You can't send thoughts to the dead!</span>"
|
||||
revert_cast()
|
||||
return
|
||||
var/message = stripped_input(user, "Enter a message to transmit to [target].", "Discordant Whisper")
|
||||
if(!message || !target)
|
||||
revert_cast()
|
||||
return
|
||||
log_say("UmbraWhisper: [key_name(user)] -> [key_name(target)]: [message]")
|
||||
user << "<span class='umbra_bold'>You whisper to [target]:</span> <span class='umbra'>\"[message]\"</span>"
|
||||
target << "<span class='umbra_emphasis'>You hear an otherworldly voice...</span> <span class='umbra'>\"[message]\"</span>"
|
||||
for(var/mob/dead/observer/O in dead_mob_list)
|
||||
var/f1 = FOLLOW_LINK(O, user)
|
||||
var/f2 = FOLLOW_LINK(O, target)
|
||||
O << "[f1] <span class='umbra_bold'>[user] (Umbra Whisper):</span> <span class='umbra'>\"[message]\"</span> to [f2] <span class='name'>[target]</span>"
|
||||
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/possess //Possess: Occupies the body of a sapient and living human, slowly training vitae while they're conscious.
|
||||
name = "Possess/Unpossess"
|
||||
desc = "Enters and merges with the body of a nearby human. While inside of this human, you will very slowly generate vitae."
|
||||
panel = "Umbral Evocation"
|
||||
range = 1
|
||||
charge_max = 600
|
||||
clothes_req = FALSE
|
||||
include_user = FALSE
|
||||
action_icon_state = "possess"
|
||||
action_background_icon_state = "bg_umbra"
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/possess/cast(list/targets, mob/living/simple_animal/umbra/user)
|
||||
if(!isumbra(user))
|
||||
revert_cast()
|
||||
return
|
||||
if(!user.possessed)
|
||||
var/mob/living/carbon/human/target = targets[1]
|
||||
if(!ishuman(target))
|
||||
user << "<span class='warning'>Only humans can produce enough vitae to sustain you in this manner!</span>"
|
||||
revert_cast()
|
||||
return
|
||||
user.possessed = target
|
||||
user.loc = target
|
||||
user << "<span class='umbra_emphasis'>You silently enter [user.possessed]'s body and begin leeching vitae. You won't be able to do this for very long.</span>"
|
||||
user.notransform = TRUE
|
||||
else
|
||||
user.unpossess()
|
||||
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/thoughtsteal //Thoughtsteal: Paralyzes and deals temporary brain damage to a target as the umbra drains it of vitae.
|
||||
name = "Thoughtsteal"
|
||||
desc = "Immobilizes a target as you copy their memories, gaining the knowledge of whatever they know."
|
||||
panel = "Umbral Evocation"
|
||||
range = 1
|
||||
charge_max = 450
|
||||
clothes_req = FALSE
|
||||
include_user = FALSE
|
||||
action_icon_state = "thoughtsteal"
|
||||
action_background_icon_state = "bg_umbra"
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/thoughtsteal/cast(list/targets, mob/living/simple_animal/umbra/user)
|
||||
if(!isumbra(user))
|
||||
revert_cast()
|
||||
return
|
||||
var/mob/living/target = targets[1]
|
||||
if(target in user.lobotomized)
|
||||
user << "<span class='warning'>You've already stolen [target]'s memories!</span>"
|
||||
revert_cast()
|
||||
return
|
||||
if(target.stat == DEAD)
|
||||
user << "<span class='warning'>You can't glean any knowledge from a dead brain!</span>"
|
||||
revert_cast()
|
||||
return
|
||||
if(!target.mind)
|
||||
user << "<span class='warning'>[target] is mindless and incapable of higher thought!</span>"
|
||||
revert_cast()
|
||||
return
|
||||
user.visible_message("<span class='warning'>[user] appears from nowhere, stretching out towards [target]!</span>", "<span class='umbra'>You try to copy [target]'s memories...</span>")
|
||||
target.visible_message("<span class='warning'>A blue beam arcs into [target]'s head, immobilizing them!</span>", "<span class='userdanger'>Your mind freezes. You can't move. \
|
||||
You can't think.</span>")
|
||||
user.Beam(target, icon = 'icons/effects/beam.dmi', icon_state = "b_beam", time = 50)
|
||||
user.immobilize(50)
|
||||
user.reveal(50)
|
||||
target.Stun(5)
|
||||
if(!do_after(user, 50, target = target))
|
||||
return
|
||||
user.visible_message("<span class='warning'>A chunk of biomatter travels along the beam and into [user]!</span>", \
|
||||
"<span class='umbra_bold'>Sweet, sweet thoughts. A lifetime of memories surges through you.</span>")
|
||||
target.visible_message("<span class='warning'>[target] silently collapses, motionless.</span>", "<span class='userdanger'>Your mind blanks. Your thoughts have fled. Slowly, they begin to \
|
||||
return... but you feel <i>wrong.</i></span>")
|
||||
target.mind.show_memory(user, 0)
|
||||
user.mind.memory += "<b><i>[target.real_name]'s Memories:</i></b>\n[target.mind.memory]\n\n"
|
||||
target.Weaken(5)
|
||||
user.lobotomized |= target
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
|
||||
Possible objectives:
|
||||
1. Steal the memories of # humans. (# = round population / 4)
|
||||
|
||||
*/
|
||||
|
||||
/datum/objective/umbra
|
||||
explanation_text = "Be an umbra."
|
||||
|
||||
/datum/objective/umbra/check_completion()
|
||||
return 1
|
||||
|
||||
/datum/objective/umbra/lobotomize
|
||||
explanation_text = "Steal the memories of several humans."
|
||||
|
||||
/datum/objective/umbra/lobotomize/New()
|
||||
target_amount = round(ticker.mode.num_players() / 4)
|
||||
explanation_text = "Steal the memories of [target_amount] humans."
|
||||
..()
|
||||
|
||||
/datum/objective/umbra/lobotomize/check_completion()
|
||||
if(!isumbra(owner.current))
|
||||
return 0
|
||||
var/mob/living/simple_animal/umbra/U = owner.current
|
||||
if(U.lobotomized.len >= target_amount)
|
||||
return 1
|
||||
return 0
|
||||
@@ -0,0 +1,17 @@
|
||||
/datum/round_event_control/spawn_umbra
|
||||
name = "Spawn Umbra"
|
||||
typepath = /datum/round_event/ghost_role/umbra
|
||||
weight = 15
|
||||
earliest_start = 6000
|
||||
max_occurrences = 3
|
||||
|
||||
/datum/round_event/ghost_role/umbra
|
||||
minimum_required = 1
|
||||
role_name = "umbra"
|
||||
|
||||
/datum/round_event/ghost_role/umbra/spawn_role()
|
||||
message_admins("An unoccupied umbra was created by a random event.")
|
||||
var/mob/living/simple_animal/umbra/U = new(pick(xeno_spawn))
|
||||
var/image/alert_overlay = image('icons/mob/mob.dmi', "umbra")
|
||||
notify_ghosts("An umbra has formed in [get_area(U)]. Interact with it to take control of it.", null, source = U, alert_overlay = alert_overlay)
|
||||
return SUCCESSFUL_SPAWN
|
||||
@@ -0,0 +1,44 @@
|
||||
#define UMBRA_ASHES_REFORM_TIME 600 //In deciseconds, how long ashes take to reform
|
||||
|
||||
/obj/item/umbral_ashes
|
||||
name = "umbral ashes"
|
||||
desc = "A shimmering pile of blue ashes with a glowing purple core."
|
||||
icon = 'icons/obj/magic.dmi'
|
||||
icon_state = "umbral_ashes"
|
||||
w_class = 2
|
||||
gender = PLURAL
|
||||
origin_tech = "materials=6;bluespace=4;biotech=6" //Good origin tech if you think you have enough time to get them to research
|
||||
var/umbra_key //The key of the umbra that these ashes came from
|
||||
var/umbra_vitae //The vitae of the umbra that these ashes came from
|
||||
|
||||
/obj/item/umbral_ashes/New()
|
||||
..()
|
||||
addtimer(src, "reform", UMBRA_ASHES_REFORM_TIME)
|
||||
|
||||
/obj/item/umbral_ashes/attack_self(mob/living/user)
|
||||
user.visible_message("<span class='warning'>[user] scatters [src]!</span>", "<span class='notice'>You scatter [src], which tremble and fade away.</span>")
|
||||
user.drop_item()
|
||||
qdel(src)
|
||||
return 1
|
||||
|
||||
/obj/item/umbral_ashes/proc/reform()
|
||||
if(!src)
|
||||
return
|
||||
visible_message("<span class='warning'>[src] hover into the air and reform!</span>")
|
||||
flick("umbral_ashes_reforming", src)
|
||||
animate(src, alpha = 0, time = 12)
|
||||
sleep(12)
|
||||
var/mob/living/simple_animal/umbra/U = new(get_turf(src))
|
||||
U.key = umbra_key
|
||||
if(!U.client)
|
||||
U.key = null
|
||||
var/image/alert_overlay = image('icons/mob/mob.dmi', "umbra")
|
||||
notify_ghosts("An umbra has re-formed in [get_area(U)]. Interact with it to take control of it.", null, source = U, alert_overlay = alert_overlay)
|
||||
else
|
||||
U << "<span class='umbra_emphasis'>Back... you're back. You can't remember what you were supposed to be doing here. Now... where were we?</span>"
|
||||
if(umbra_vitae)
|
||||
U.vitae = umbra_vitae
|
||||
U.alpha = 0
|
||||
animate(U, alpha = initial(U.alpha), time = 10) //To give a fade-in effect for the newly-spawned
|
||||
qdel(src)
|
||||
return 1
|
||||
@@ -158,4 +158,10 @@
|
||||
/obj/effect/decal/cleanable/shreds/New()
|
||||
pixel_x = rand(-5, 5)
|
||||
pixel_y = rand(-5, 5)
|
||||
..()
|
||||
..()
|
||||
|
||||
/obj/effect/decal/cleanable/salt
|
||||
name = "salt pile"
|
||||
desc = "A sizable pile of table salt. Someone must be upset."
|
||||
icon = 'icons/effects/tomatodecal.dmi'
|
||||
icon_state = "salt_pile"
|
||||
|
||||
@@ -254,17 +254,10 @@
|
||||
icon_state = "sigilactiveoverlay"
|
||||
alpha = 0
|
||||
|
||||
|
||||
/obj/effect/overlay/temp/revenant
|
||||
/obj/effect/overlay/temp/purple_sparkles
|
||||
name = "spooky lights"
|
||||
icon_state = "purplesparkles"
|
||||
|
||||
/obj/effect/overlay/temp/revenant/cracks
|
||||
name = "glowing cracks"
|
||||
icon_state = "purplecrack"
|
||||
duration = 6
|
||||
|
||||
|
||||
/obj/effect/overlay/temp/emp
|
||||
name = "emp sparks"
|
||||
icon_state = "empdisable"
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
user << "The crew has already settled into the shift. It probably wouldn't be good to rename the station right now."
|
||||
return
|
||||
|
||||
var/new_name = input(user, "What do you want to name [station_name()]? Keep in mind particularly terrible names may attract the attention of your employers.") as text|null
|
||||
var/new_name = stripped_input(user, message="What do you want to name [station_name()]? Keep in mind particularly terrible names may attract the attention of your employers.", max_length=MAX_CHARTER_LEN)
|
||||
if(new_name)
|
||||
world.name = new_name
|
||||
station_name = new_name
|
||||
|
||||
@@ -119,13 +119,6 @@
|
||||
else
|
||||
message_admins("[key_name_admin(usr)] tried to create an abductor team. Unfortunatly there were not enough candidates available.")
|
||||
log_admin("[key_name(usr)] failed to create an abductor team.")
|
||||
if("15")
|
||||
if(src.makeRevenant())
|
||||
message_admins("[key_name(usr)] created a revenant.")
|
||||
log_admin("[key_name(usr)] created a revenant.")
|
||||
else
|
||||
message_admins("[key_name_admin(usr)] tried to create a revenant. Unfortunately, there were no candidates available.")
|
||||
log_admin("[key_name(usr)] failed to create a revenant.")
|
||||
if("16")
|
||||
if(src.makeShadowling())
|
||||
message_admins("[key_name(usr)] created a shadowling.")
|
||||
@@ -1608,7 +1601,7 @@
|
||||
|
||||
else if(href_list["adminchecklaws"])
|
||||
output_ai_laws()
|
||||
|
||||
|
||||
else if(href_list["admincheckdevilinfo"])
|
||||
output_devil_info()
|
||||
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
<a href='?src=\ref[src];makeAntag=7'>Make Nuke Team (Requires Ghosts)</a><br>
|
||||
<a href='?src=\ref[src];makeAntag=13'>Make Centcom Response Team (Requires Ghosts)</a><br>
|
||||
<a href='?src=\ref[src];makeAntag=14'>Make Abductor Team (Requires Ghosts)</a><br>
|
||||
<a href='?src=\ref[src];makeAntag=15'>Make Revenant (Requires Ghost)</a><br>
|
||||
"}
|
||||
|
||||
var/datum/browser/popup = new(usr, "oneclickantag", "Quick-Create Antagonist", 400, 400)
|
||||
@@ -514,9 +513,6 @@
|
||||
new /datum/round_event/ghost_role/abductor
|
||||
return 1
|
||||
|
||||
/datum/admins/proc/makeRevenant()
|
||||
new /datum/round_event/ghost_role/revenant
|
||||
|
||||
//Shadowling
|
||||
/datum/admins/proc/makeShadowling()
|
||||
var/datum/game_mode/shadowling/temp = new
|
||||
|
||||
@@ -49,9 +49,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
||||
var/B_gang = 4096
|
||||
var/B_shadowling = 8192
|
||||
var/B_abductor = 16384
|
||||
var/B_revenant = 32768
|
||||
|
||||
var/list/archived = list(B_traitor,B_operative,B_changeling,B_wizard,B_malf,B_rev,B_alien,B_pai,B_cultist,B_blob,B_ninja,B_monkey,B_gang,B_shadowling,B_abductor,B_revenant)
|
||||
var/list/archived = list(B_traitor,B_operative,B_changeling,B_wizard,B_malf,B_rev,B_alien,B_pai,B_cultist,B_blob,B_ninja,B_monkey,B_gang,B_shadowling,B_abductor)
|
||||
|
||||
be_special = list()
|
||||
|
||||
@@ -89,8 +88,6 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
||||
be_special += ROLE_SHADOWLING
|
||||
if(16384)
|
||||
be_special += ROLE_ABDUCTOR
|
||||
if(32768)
|
||||
be_special += ROLE_REVENANT
|
||||
|
||||
|
||||
/datum/preferences/proc/update_preferences(current_version)
|
||||
|
||||
@@ -133,6 +133,16 @@
|
||||
desc = "Salt. From dead crew, presumably."
|
||||
return (TOXLOSS)
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/condiment/saltshaker/afterattack(obj/target, mob/living/user, proximity)
|
||||
if(!proximity || !isturf(target))
|
||||
return
|
||||
if(!reagents.has_reagent("sodiumchloride", 2))
|
||||
user << "<span class='warning'>You don't have enough salt to make a pile!</span>"
|
||||
return
|
||||
user.visible_message("<span class='notice'>[user] shakes some salt onto [target].</span>", "<span class='notice'>You shake some salt onto [target].</span>")
|
||||
reagents.remove_reagent("sodiumchloride", 2)
|
||||
new/obj/effect/decal/cleanable/salt(target)
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/condiment/peppermill
|
||||
name = "pepper mill"
|
||||
desc = "Often used to flavor food or make people sneeze."
|
||||
|
||||
@@ -445,8 +445,9 @@ It's fairly easy to fix if dealing with single letters but not so much with comp
|
||||
|
||||
/proc/offer_control(mob/M)
|
||||
M << "Control of your mob has been offered to dead players."
|
||||
log_admin("[key_name(usr)] has offered control of ([key_name(M)]) to ghosts.")
|
||||
message_admins("[key_name_admin(usr)] has offered control of ([key_name_admin(M)]) to ghosts")
|
||||
if(usr)
|
||||
log_admin("[key_name(usr)] has offered control of ([key_name(M)]) to ghosts.")
|
||||
message_admins("[key_name_admin(usr)] has offered control of ([key_name_admin(M)]) to ghosts")
|
||||
var/poll_message = "Do you want to play as [M.real_name]?"
|
||||
if(M.mind && M.mind.assigned_role)
|
||||
poll_message = "[poll_message] Job:[M.mind.assigned_role]."
|
||||
|
||||
@@ -224,16 +224,23 @@
|
||||
anim(mobloc,mob,'icons/mob/mob.dmi',,"shadow",,L.dir)
|
||||
L.loc = get_step(L, direct)
|
||||
L.setDir(direct)
|
||||
if(3) //Incorporeal move, but blocked by holy-watered tiles
|
||||
if(3) //Incorporeal move, but blocked by holy-watered tiles and salt piles. Used by umbras.
|
||||
if(!isumbra(L))
|
||||
L.incorporeal_move = 1
|
||||
return
|
||||
var/mob/living/simple_animal/umbra/U = L
|
||||
var/turf/open/floor/stepTurf = get_step(L, direct)
|
||||
for(var/obj/effect/decal/cleanable/salt/S in stepTurf)
|
||||
U << "<span class='warning'>[S] bars your passage!</span>"
|
||||
U.reveal(2, TRUE)
|
||||
U.immobilize(2, TRUE)
|
||||
return
|
||||
if(stepTurf.flags & NOJAUNT)
|
||||
L << "<span class='warning'>Holy energies block your path.</span>"
|
||||
L.notransform = 1
|
||||
spawn(2)
|
||||
L.notransform = 0
|
||||
U << "<span class='warning'>Holy energies block your path!</span>"
|
||||
U.immobilize(2, TRUE)
|
||||
else
|
||||
L.loc = get_step(L, direct)
|
||||
L.setDir(direct)
|
||||
U.loc = get_step(L, direct)
|
||||
U.setDir(direct)
|
||||
return 1
|
||||
|
||||
|
||||
|
||||
@@ -539,7 +539,7 @@
|
||||
/datum/reagent/blob/adaptive_nexuses/reaction_mob(mob/living/M, method=TOUCH, reac_volume, show_message, touch_protection, mob/camera/blob/O)
|
||||
reac_volume = ..()
|
||||
if(O && ishuman(M) && M.stat == UNCONSCIOUS)
|
||||
PoolOrNew(/obj/effect/overlay/temp/revenant, get_turf(M))
|
||||
PoolOrNew(/obj/effect/overlay/temp/purple_sparkles, get_turf(M))
|
||||
var/points = rand(5, 10)
|
||||
O.add_points(points)
|
||||
O << "<span class='notice'>Gained [points] resources from the death of [M].</span>"
|
||||
|
||||
@@ -247,12 +247,19 @@
|
||||
reagent_state = SOLID
|
||||
color = "#FFFFFF" // rgb: 255,255,255
|
||||
|
||||
/datum/reagent/consumable/sodiumchloride/reaction_mob(mob/living/M, method=TOUCH, reac_volume)//Splashing people with welding fuel to make them easy to ignite!
|
||||
/datum/reagent/consumable/sodiumchloride/reaction_mob(mob/living/M, method=TOUCH, reac_volume)
|
||||
if(!istype(M))
|
||||
return
|
||||
if(M.has_bane(BANE_SALT))
|
||||
M.mind.disrupt_spells(-200)
|
||||
|
||||
/datum/reagent/consumable/sodiumchloride/reaction_turf(turf/T, reac_volume) //Creates an umbra-blocking salt pile
|
||||
if(!istype(T))
|
||||
return
|
||||
if(reac_volume < 1)
|
||||
return
|
||||
new/obj/effect/decal/cleanable/salt(T)
|
||||
|
||||
/datum/reagent/consumable/blackpepper
|
||||
name = "Black Pepper"
|
||||
id = "blackpepper"
|
||||
|
||||
@@ -63,14 +63,6 @@
|
||||
if(created_volume >= 150)
|
||||
playsound(get_turf(holder.my_atom), 'sound/effects/pray.ogg', 80, 0, round(created_volume/48))
|
||||
strengthdiv = 8
|
||||
for(var/mob/living/simple_animal/revenant/R in get_hearers_in_view(7,get_turf(holder.my_atom)))
|
||||
var/diety = ticker.Bible_deity_name
|
||||
if(!ticker.Bible_deity_name)
|
||||
diety = "Christ"
|
||||
R << "<span class='userdanger'>The power of [diety] compels you!</span>"
|
||||
R.stun(20)
|
||||
R.reveal(100)
|
||||
sleep(20)
|
||||
for(var/mob/living/carbon/C in get_hearers_in_view(round(created_volume/48,1),get_turf(holder.my_atom)))
|
||||
if(iscultist(C) || is_handofgod_cultist(C) || C.dna.species.id == "shadowling" || C.dna.species.id == "l_shadowling")
|
||||
C << "<span class='userdanger'>The divine explosion sears you!</span>"
|
||||
|
||||
@@ -74,12 +74,17 @@
|
||||
<li class="tweak">Sigil of Submission is now a Script instead of a Driver; It's unlocked one tier up, so you have to rely on the Drivers you have until you get Scripts, instead of spamming both Driver sigils for free converts.</li>
|
||||
<li class="rscadd">To replace Sigil of Submission in the Driver tier; Added Taunting Tirade, which is a chanted scripture with a very fast invocation, which, on chanting, confuses, dizzies, and briefly stuns nearby non-servants and allows the invoker a brief time to relocate before continuing the chant.</li>
|
||||
<li class="rscadd">Ghosts can now see the Gateway to the Celestial Derelict's remaining time as a countdown.</li>
|
||||
<li class="tweak">Anima Fragments are now slightly slower if not at maximum health and no longer drop a soul vessel when destroyed.</li>
|
||||
</ul>
|
||||
<h3 class="author">Quiltyquilty updated:</h3>
|
||||
<ul class="changes bgimages16">
|
||||
<li class="rscdel">Patches now hold only 40u.</li>
|
||||
<li class="rscdel">Patches in first aid kits now only contain 20u of chemicals.</li>
|
||||
</ul>
|
||||
<h3 class="author">coiax updated:</h3>
|
||||
<ul class="changes bgimages16">
|
||||
<li class="rscadd">Polymorphed mobs now have the same name, and where possible, the same equipment as their previous form.</li>
|
||||
</ul>
|
||||
|
||||
<h2 class="date">14 June 2016</h2>
|
||||
<h3 class="author">Joan updated:</h3>
|
||||
|
||||
@@ -5628,6 +5628,11 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
|
||||
a brief time to relocate before continuing the chant.
|
||||
- rscadd: Ghosts can now see the Gateway to the Celestial Derelict's remaining time
|
||||
as a countdown.
|
||||
- tweak: Anima Fragments are now slightly slower if not at maximum health and no
|
||||
longer drop a soul vessel when destroyed.
|
||||
Quiltyquilty:
|
||||
- rscdel: Patches now hold only 40u.
|
||||
- rscdel: Patches in first aid kits now only contain 20u of chemicals.
|
||||
coiax:
|
||||
- rscadd: Polymorphed mobs now have the same name, and where possible, the same
|
||||
equipment as their previous form.
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
author: "Xhuis"
|
||||
delete-after: True
|
||||
changes:
|
||||
- tweak: "Revenants have been renamed to umbras and have undergone some tweaks."
|
||||
@@ -1,4 +0,0 @@
|
||||
author: "coiax"
|
||||
delete-after: True
|
||||
changes:
|
||||
- rscadd: "Polymorphed mobs now have the same name, and where possible, the same equipment as their previous form."
|
||||
@@ -1,4 +0,0 @@
|
||||
author: "Joan"
|
||||
delete-after: True
|
||||
changes:
|
||||
- tweak: "Anima Fragments are now slightly slower if not at maximum health and no longer drop a soul vessel when destroyed."
|
||||
@@ -0,0 +1,4 @@
|
||||
author: "Quiltyquilty"
|
||||
delete-after: True
|
||||
changes:
|
||||
- rscadd: "Beepsky now has his own home in the labor shuttle room."
|
||||
|
Before Width: | Height: | Size: 421 KiB After Width: | Height: | Size: 418 KiB |
|
Before Width: | Height: | Size: 8.1 KiB After Width: | Height: | Size: 8.6 KiB |
|
Before Width: | Height: | Size: 82 KiB After Width: | Height: | Size: 78 KiB |
|
Before Width: | Height: | Size: 242 KiB After Width: | Height: | Size: 252 KiB |
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 18 KiB |
@@ -73,6 +73,18 @@ h1.alert, h2.alert {color: #000000;}
|
||||
.holoparasite {color: #35333a;}
|
||||
.holoparasitebold {color: #35333a; font-weight: bold;}
|
||||
|
||||
.revennotice {color: #1d2953;}
|
||||
.revenboldnotice {color: #1d2953; font-weight: bold;}
|
||||
.revenbignotice {color: #1d2953; font-weight: bold; font-size: 3;}
|
||||
.revenminor {color: #823abb}
|
||||
.revenwarning {color: #760fbb; font-style: italic;}
|
||||
.revendanger {color: #760fbb; font-weight: bold; font-size: 3;}
|
||||
.umbra {color: #5000A0;}
|
||||
.umbra_bold {color: #5000A0; font-weight: bold;}
|
||||
.umbra_italics {color: #5000A0; font-style: italic;}
|
||||
.umbra_emphasis {color: #5000A0; font-weight: bold; font-style: italic;}
|
||||
.umbra_large {color: #5000A0; font-size: 3;}
|
||||
|
||||
.brass {color: #BE8700;}
|
||||
.heavy_brass {color: #BE8700; font-weight: bold; font-style: italic;}
|
||||
.large_brass {color: #BE8700; font-size: 3;}
|
||||
@@ -91,13 +103,6 @@ h1.alert, h2.alert {color: #000000;}
|
||||
.neovgre {color: #13143F; font-weight: bold; font-style: italic;}
|
||||
.neovgre_small {color: #13143F;}
|
||||
|
||||
.revennotice {color: #1d2953;}
|
||||
.revenboldnotice {color: #1d2953; font-weight: bold;}
|
||||
.revenbignotice {color: #1d2953; font-weight: bold; font-size: 3;}
|
||||
.revenminor {color: #823abb}
|
||||
.revenwarning {color: #760fbb; font-style: italic;}
|
||||
.revendanger {color: #760fbb; font-weight: bold; font-size: 3;}
|
||||
|
||||
.newscaster {color: #800000;}
|
||||
.ghostalert {color: #5c00e6; font-style: italic; font-weight: bold;}
|
||||
|
||||
|
||||
@@ -120,7 +120,6 @@
|
||||
#include "code\_onclick\hud\monkey.dm"
|
||||
#include "code\_onclick\hud\movable_screen_objects.dm"
|
||||
#include "code\_onclick\hud\other_mobs.dm"
|
||||
#include "code\_onclick\hud\revenanthud.dm"
|
||||
#include "code\_onclick\hud\robot.dm"
|
||||
#include "code\_onclick\hud\screen_objects.dm"
|
||||
#include "code\_onclick\hud\swarmer.dm"
|
||||
@@ -366,13 +365,14 @@
|
||||
#include "code\game\gamemodes\miniantags\hades\hades.dm"
|
||||
#include "code\game\gamemodes\miniantags\monkey\monkey.dm"
|
||||
#include "code\game\gamemodes\miniantags\morph\morph.dm"
|
||||
#include "code\game\gamemodes\miniantags\revenant\revenant.dm"
|
||||
#include "code\game\gamemodes\miniantags\revenant\revenant_abilities.dm"
|
||||
#include "code\game\gamemodes\miniantags\revenant\revenant_blight.dm"
|
||||
#include "code\game\gamemodes\miniantags\revenant\revenant_spawn_event.dm"
|
||||
#include "code\game\gamemodes\miniantags\sintouched\objectives.dm"
|
||||
#include "code\game\gamemodes\miniantags\slaughter\slaughter.dm"
|
||||
#include "code\game\gamemodes\miniantags\slaughter\slaughterevent.dm"
|
||||
#include "code\game\gamemodes\miniantags\umbra\umbra.dm"
|
||||
#include "code\game\gamemodes\miniantags\umbra\umbra_abilities.dm"
|
||||
#include "code\game\gamemodes\miniantags\umbra\umbra_objectives.dm"
|
||||
#include "code\game\gamemodes\miniantags\umbra\umbra_spawn_event.dm"
|
||||
#include "code\game\gamemodes\miniantags\umbra\umbral_ashes.dm"
|
||||
#include "code\game\gamemodes\nuclear\nuclear.dm"
|
||||
#include "code\game\gamemodes\nuclear\nuclear_challenge.dm"
|
||||
#include "code\game\gamemodes\nuclear\nuclearbomb.dm"
|
||||
|
||||