Adds Shadow demons (#19732)

* reshuffle

* shared base type

* moves this to the base type

* the monster

* event

* FUCK

* better sprites

* refactors bloodcrawl, more nice sprites

* review stuff

* Apply suggestions from code review

Co-authored-by: Sirryan2002 <80364400+Sirryan2002@users.noreply.github.com>

* heart of darkness

* pre TM tweaks

* ARGH

* hopefully fixes double hits

* tweaks

* derp

* tweaks

* TEMP RUNTIME REMOVE LATER

* fixes

* runtime fixes

* cig runtime fix

* review + another runtime fix

* re adds sprite

* removes runtime

* oop I forgor

* DRUNK CODING

* SPRITES

Co-authored-by: Sirryan2002 <80364400+Sirryan2002@users.noreply.github.com>
This commit is contained in:
Charlie
2022-12-29 17:26:37 +00:00
committed by GitHub
parent 7be765d5ef
commit 8ef4aa727e
48 changed files with 563 additions and 312 deletions

View File

@@ -37,7 +37,7 @@
#define SPECIAL_ROLE_NUKEOPS "Syndicate"
#define SPECIAL_ROLE_PYROCLASTIC_SLIME "Pyroclastic Anomaly Slime"
#define SPECIAL_ROLE_REVENANT "Revenant"
#define SPECIAL_ROLE_SLAUGHTER_DEMON "Slaughter Demon"
#define SPECIAL_ROLE_DEMON "Demon"
#define SPECIAL_ROLE_SUPER "Super"
#define SPECIAL_ROLE_SYNDICATE_DEATHSQUAD "Syndicate Commando"
#define SPECIAL_ROLE_TRAITOR "Traitor"

View File

@@ -244,7 +244,8 @@
#define isnymph(A) (istype((A), /mob/living/simple_animal/diona))
#define ishostile(A) (istype((A), /mob/living/simple_animal/hostile))
#define isterrorspider(A) (istype((A), /mob/living/simple_animal/hostile/poison/terror_spider))
#define isslaughterdemon(A) (istype((A), /mob/living/simple_animal/slaughter))
#define isslaughterdemon(A) (istype((A), /mob/living/simple_animal/demon/slaughter))
#define isdemon(A) (istype((A), /mob/living/simple_animal/demon))
#define issilicon(A) (istype((A), /mob/living/silicon))
#define isAI(A) (istype((A), /mob/living/silicon/ai))

View File

@@ -28,7 +28,7 @@
#define ROLE_TRADER "trader"
#define ROLE_VAMPIRE "vampire"
// Role tags for EVERYONE!
#define ROLE_DEMON "slaughter demon"
#define ROLE_DEMON "demon"
#define ROLE_SENTIENT "sentient animal"
#define ROLE_POSIBRAIN "positronic brain"
#define ROLE_GUARDIAN "guardian"

View File

@@ -8,8 +8,9 @@
/datum/spell_targeting/aoe/choose_targets(mob/user, obj/effect/proc_holder/spell/spell, params, atom/clicked_atom)
var/list/targets = list()
var/spell_center = use_turf_of_user ? get_turf(user) : user
for(var/atom/target in view_or_range(range, user, selection_type))
for(var/atom/target in view_or_range(range, spell_center, selection_type))
if(valid_target(target, user, spell, FALSE))
targets += target
if(inner_radius >= 0)

View File

@@ -9,12 +9,13 @@
action_icon_state = "bloodcrawl"
action_background_icon_state = "bg_demon"
panel = "Demon"
var/allowed_type = /obj/effect/decal/cleanable
var/phased = FALSE
/obj/effect/proc_holder/spell/bloodcrawl/create_new_targeting()
var/datum/spell_targeting/targeted/T = new()
T.selection_type = SPELL_SELECTION_RANGE
T.allowed_type = /obj/effect/decal/cleanable
T.allowed_type = allowed_type
T.random_target = TRUE
T.range = 1
T.use_turf_of_user = TRUE
@@ -31,11 +32,241 @@
return FALSE
/obj/effect/proc_holder/spell/bloodcrawl/cast(list/targets, mob/living/user)
var/obj/effect/decal/cleanable/target = targets[1] // TODO Test this spell
var/atom/target = targets[1]
if(phased)
if(user.phasein(target))
if(phasein(target, user))
phased = FALSE
else
if(user.phaseout(target))
if(phaseout(target, user))
phased = TRUE
cooldown_handler.start_recharge()
//Travel through pools of blood. Slaughter Demon powers for everyone!
#define BLOODCRAWL 1
#define BLOODCRAWL_EAT 2
/obj/item/bloodcrawl
name = "blood crawl"
desc = "You are unable to hold anything while in this form."
icon = 'icons/effects/blood.dmi'
flags = NODROP|ABSTRACT
/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"
density = FALSE
anchored = TRUE
invisibility = 60
resistance_flags = LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
/obj/effect/dummy/slaughter/relaymove(mob/user, direction)
forceMove(get_step(src, direction))
/obj/effect/dummy/slaughter/ex_act()
return
/obj/effect/dummy/slaughter/bullet_act()
return
/obj/effect/dummy/slaughter/singularity_act()
return
/obj/effect/proc_holder/spell/bloodcrawl/proc/block_hands(mob/living/carbon/C)
if(C.l_hand || C.r_hand)
to_chat(C, "<span class='warning'>You may not hold items while blood crawling!</span>")
return FALSE
var/obj/item/bloodcrawl/B1 = new(C)
var/obj/item/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()
return TRUE
/obj/effect/proc_holder/spell/bloodcrawl/proc/sink_animation(atom/A, mob/living/L)
var/turf/mob_loc = get_turf(L)
visible_message("<span class='danger'>[L] sinks into [A].</span>")
playsound(mob_loc, 'sound/misc/enter_blood.ogg', 100, 1, -1)
var/atom/movable/overlay/animation = new(mob_loc)
animation.name = "odd blood"
animation.density = FALSE
animation.anchored = TRUE
animation.icon = 'icons/mob/mob.dmi'
animation.icon_state = "jaunt"
animation.layer = 5
animation.master = mob_loc
animation.dir = L.dir
QDEL_IN(animation, 0.6 SECONDS)
/obj/effect/proc_holder/spell/bloodcrawl/proc/handle_consumption(mob/living/L, mob/living/victim, atom/A, obj/effect/dummy/slaughter/holder)
if(!HAS_TRAIT(L, TRAIT_BLOODCRAWL_EAT))
return
if(!istype(victim))
return
if(victim.stat == CONSCIOUS)
A.visible_message("<span class='warning'>[victim] kicks free of [A] just before entering it!</span>")
L.stop_pulling()
return
victim.forceMove(holder)
victim.emote("scream")
A.visible_message("<span class='warning'><b>[L] drags [victim] into [A]!</b></span>")
L.stop_pulling()
to_chat(L, "<b>You begin to feast on [victim]. You can not move while you are doing this.</b>")
A.visible_message("<span class='warning'><B>Loud eating sounds come from the blood...</b></span>")
var/sound
if(isslaughterdemon(L))
var/mob/living/simple_animal/demon/slaughter/SD = L
sound = SD.feast_sound
else
sound = 'sound/misc/demon_consume.ogg'
for(var/i in 1 to 3)
playsound(get_turf(L), sound, 100, 1)
sleep(3 SECONDS)
if(!victim)
to_chat(L, "<span class='danger'>You happily devour... nothing? Your meal vanished at some point!</span>")
return
if(ishuman(victim) || isrobot(victim))
to_chat(L, "<span class='warning'>You devour [victim]. Your health is fully restored.</span>")
L.adjustBruteLoss(-1000)
L.adjustFireLoss(-1000)
L.adjustOxyLoss(-1000)
L.adjustToxLoss(-1000)
else
to_chat(L, "<span class='warning'>You devour [victim], but this measly meal barely sates your appetite!</span>")
L.adjustBruteLoss(-25)
L.adjustFireLoss(-25)
if(isslaughterdemon(L))
var/mob/living/simple_animal/demon/slaughter/demon = L
demon.devoured++
to_chat(victim, "<span class='userdanger'>You feel teeth sink into your flesh, and the--</span>")
victim.adjustBruteLoss(1000)
victim.forceMove(demon)
demon.consumed_mobs.Add(victim)
if(ishuman(victim))
var/mob/living/carbon/human/H = victim
if(H.w_uniform && istype(H.w_uniform, /obj/item/clothing/under))
var/obj/item/clothing/under/U = H.w_uniform
U.sensor_mode = SENSOR_OFF
else
victim.ghostize()
qdel(victim)
/obj/effect/proc_holder/spell/bloodcrawl/proc/post_phase_in(mob/living/L, obj/effect/dummy/slaughter/holder)
L.notransform = FALSE
/obj/effect/proc_holder/spell/bloodcrawl/proc/phaseout(obj/effect/decal/cleanable/B, mob/living/L)
if(iscarbon(L) && !block_hands(L))
return FALSE
L.notransform = TRUE
INVOKE_ASYNC(src, PROC_REF(async_phase), B, L)
return TRUE
/obj/effect/proc_holder/spell/bloodcrawl/proc/async_phase(obj/effect/decal/cleanable/B, mob/living/L)
var/turf/mobloc = get_turf(L)
sink_animation(B, L)
var/obj/effect/dummy/slaughter/holder = new /obj/effect/dummy/slaughter(mobloc)
L.forceMove(holder)
L.ExtinguishMob()
handle_consumption(L, L.pulling, B, holder)
post_phase_in(L, holder)
/obj/effect/proc_holder/spell/bloodcrawl/proc/rise_animation(turf/tele_loc, mob/living/L, atom/A)
var/atom/movable/overlay/animation = new(tele_loc)
animation.name = "odd blood"
animation.density = FALSE
animation.anchored = TRUE
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 = tele_loc
animation.dir = L.dir
if(prob(25) && isdemon(L))
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(tele_loc, pick(voice),50, 1, -1)
A.visible_message("<span class='warning'><b>[L] rises out of [A]!</b>")
playsound(get_turf(tele_loc), 'sound/misc/exit_blood.ogg', 100, 1, -1)
QDEL_IN(animation, 0.6 SECONDS)
/obj/effect/proc_holder/spell/bloodcrawl/proc/unblock_hands(mob/living/carbon/C)
if(!istype(C))
return
for(var/obj/item/bloodcrawl/BC in C)
qdel(BC)
/obj/effect/proc_holder/spell/bloodcrawl/proc/rise_message(atom/A)
A.visible_message("<span class='warning'>[A] starts to bubble...</span>")
/obj/effect/proc_holder/spell/bloodcrawl/proc/post_phase_out(atom/A, mob/living/L)
if(isslaughterdemon(L))
var/mob/living/simple_animal/demon/slaughter/S = L
S.speed = 0
S.boost = world.time + 6 SECONDS
L.color = A.color
addtimer(VARSET_CALLBACK(L, color, null), 6 SECONDS)
/obj/effect/proc_holder/spell/bloodcrawl/proc/phasein(atom/A, mob/living/L)
if(L.notransform)
to_chat(L, "<span class='warning'>Finish eating first!</span>")
return FALSE
rise_message(A)
if(!do_after(L, 2 SECONDS, target = A))
return FALSE
if(!A)
return FALSE
var/turf/tele_loc = isturf(A) ? A : A.loc
var/holder = L.loc
L.forceMove(tele_loc)
L.client.eye = L
rise_animation(tele_loc, L, A)
unblock_hands(L)
QDEL_NULL(holder)
post_phase_out(A, L)
return TRUE
/obj/effect/proc_holder/spell/bloodcrawl/shadow_crawl
name = "Shadow Crawl"
desc = "Use darkness to phase out of existence."
allowed_type = /turf
action_background_icon_state = "shadow_demon_bg"
action_icon_state = "shadow_crawl"
/obj/effect/proc_holder/spell/bloodcrawl/shadow_crawl/valid_target(turf/target, user)
return target.get_lumcount() < 0.2
/obj/effect/proc_holder/spell/bloodcrawl/shadow_crawl/rise_message(atom/A)
return
/obj/effect/proc_holder/spell/bloodcrawl/shadow_crawl/rise_animation(turf/tele_loc, mob/living/L, atom/A)
return
/obj/effect/proc_holder/spell/bloodcrawl/shadow_crawl/handle_consumption(mob/living/L, mob/living/victim, atom/A, obj/effect/dummy/slaughter/holder)
return
/obj/effect/proc_holder/spell/bloodcrawl/shadow_crawl/sink_animation(atom/A, mob/living/L)
A.visible_message("<span class='danger'>[L] sinks into the shadows...</span>")
/obj/effect/proc_holder/spell/bloodcrawl/shadow_crawl/post_phase_in(mob/living/L, obj/effect/dummy/slaughter/holder)
..()
if(!istype(L, /mob/living/simple_animal/demon/shadow))
return
var/mob/living/simple_animal/demon/shadow/S = L
S.RegisterSignal(holder, COMSIG_MOVABLE_MOVED, TYPE_PROC_REF(/mob/living/simple_animal/demon/shadow, check_darkness))

View File

@@ -47,7 +47,7 @@
var/title
var/large = FALSE
var/living_message
if(istype(user, /mob/living/simple_animal/slaughter/cult)) //Harbringers of the Slaughter
if(istype(user, /mob/living/simple_animal/demon/slaughter/cult)) //Harbringers of the Slaughter
title = "<b>Harbringer of the Slaughter</b>"
large = TRUE
else

View File

@@ -303,7 +303,7 @@
if(curselimit > 1)
to_chat(user, "<span class='notice'>We have exhausted our ability to curse the shuttle.</span>")
return
if(locate(/obj/singularity/narsie) in GLOB.poi_list || locate(/mob/living/simple_animal/slaughter/cult) in GLOB.mob_list)
if(locate(/obj/singularity/narsie) in GLOB.poi_list || locate(/mob/living/simple_animal/demon/slaughter/cult) in GLOB.mob_list)
to_chat(user, "<span class='danger'>Nar'Sie or her avatars are already on this plane, there is no delaying the end of all things.</span>")
return

View File

@@ -0,0 +1,36 @@
/mob/living/simple_animal/demon
name = "a generic demon"
desc = "you shouldnt be reading this, file a github report"
speak_emote = list("gurgles")
emote_hear = list("wails","screeches")
response_help = "thinks better of touching"
response_disarm = "flails at"
response_harm = "punches"
speed = 1
a_intent = INTENT_HARM
mob_biotypes = MOB_ORGANIC | MOB_HUMANOID
stop_automated_movement = TRUE
status_flags = CANPUSH
attack_sound = 'sound/misc/demon_attack1.ogg'
death_sound = 'sound/misc/demon_dies.ogg'
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)
minbodytemp = 0
maxbodytemp = INFINITY
faction = list("demon")
attacktext = "wildly tears into"
maxHealth = 200
health = 200
environment_smash = ENVIRONMENT_SMASH_STRUCTURES
obj_damage = 50
melee_damage_lower = 30
melee_damage_upper = 30
see_in_dark = 8
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
del_on_death = TRUE
var/datum/action/innate/demon/whisper/whisper_action
/mob/living/simple_animal/demon/Initialize(mapload)
. = ..()
whisper_action = new()
whisper_action.Grant(src)

View File

@@ -0,0 +1,122 @@
/mob/living/simple_animal/demon/shadow
name = "shadow demon"
desc = "A creature that's barely tangible, you can feel its gaze piercing you"
icon = 'icons/mob/mob.dmi'
icon_state = "shadow_demon"
icon_living = "shadow_demon"
move_resist = MOVE_FORCE_STRONG
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_VISIBLE // so they can tell where the darkness is
loot = list(/obj/item/organ/internal/heart/demon/shadow)
var/thrown_alert = FALSE
/mob/living/simple_animal/demon/shadow/Life(seconds, times_fired)
. = ..()
var/lum_count = check_darkness()
var/damage_mod = istype(loc, /obj/effect/dummy/slaughter) ? 0.5 : 1
if(lum_count > 0.2)
adjustBruteLoss(40 * damage_mod) // 10 seconds in light
SEND_SOUND(src, sound('sound/weapons/sear.ogg'))
to_chat(src, "<span class='biggerdanger'>The light scalds you!</span>")
else
adjustBruteLoss(-20)
/mob/living/simple_animal/demon/shadow/hitby(atom/movable/AM, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum)
if(isliving(AM)) // when a living creature is thrown at it, dont knock it back
return
..()
/mob/living/simple_animal/demon/shadow/Initialize(mapload)
. = ..()
AddSpell(new /obj/effect/proc_holder/spell/fireball/shadow_grapple)
var/obj/effect/proc_holder/spell/bloodcrawl/shadow_crawl/S = new
AddSpell(S)
if(istype(loc, /obj/effect/dummy/slaughter))
S.phased = TRUE
RegisterSignal(loc, COMSIG_MOVABLE_MOVED, TYPE_PROC_REF(/mob/living/simple_animal/demon/shadow, check_darkness))
RegisterSignal(src, COMSIG_MOVABLE_MOVED, PROC_REF(check_darkness))
/mob/living/simple_animal/demon/shadow/proc/check_darkness()
var/turf/T = get_turf(src)
var/lum_count = T.get_lumcount()
if(lum_count > 0.2)
if(!thrown_alert)
thrown_alert = TRUE
throw_alert("light", /obj/screen/alert/lightexposure)
alpha = 255
else
if(thrown_alert)
thrown_alert = FALSE
clear_alert("light")
alpha = 125
return lum_count
/obj/effect/proc_holder/spell/fireball/shadow_grapple
name = "Shadow Grapple"
desc = "Fire one of your hands, if it hits a person it pulls them in. If you hit a structure you get pulled to the structure."
base_cooldown = 10 SECONDS
fireball_type = /obj/item/projectile/magic/shadow_hand
selection_activated_message = "<span class='notice'>You raise your hand, full of demonic energy! <b>Left-click to cast at a target!</b></span>"
selection_deactivated_message = "<span class='notice'>You re-absorb the energy...for now.</span>"
action_background_icon_state = "shadow_demon_bg"
action_icon_state = "shadow_grapple"
panel = "Demon"
sound = null
invocation_type = "none"
invocation = null
/obj/effect/proc_holder/spell/fireball/shadow_grapple/update_icon_state()
return
/obj/item/projectile/magic/shadow_hand
name = "shadow hand"
icon_state = "shadow_hand"
plane = FLOOR_PLANE
var/hit = FALSE
/obj/item/projectile/magic/shadow_hand/fire(setAngle)
if(firer)
firer.Beam(src, icon_state = "grabber_beam", time = INFINITY, maxdistance = INFINITY, beam_sleep_time = 1, beam_type = /obj/effect/ebeam/floor)
return ..()
/obj/item/projectile/magic/shadow_hand/on_hit(atom/target, blocked, hit_zone)
if(hit)
return
hit = TRUE // to prevent double hits from the pull
. = ..()
if(!isliving(target))
firer.throw_at(get_step(target, get_dir(target, firer)), 50, 10)
else
var/mob/living/L = target
L.Immobilize(2 SECONDS)
L.apply_damage(40, BRUTE, BODY_ZONE_CHEST)
L.throw_at(get_step(firer, get_dir(firer, target)), 50, 10)
target.extinguish_light(TRUE)
/obj/effect/ebeam/floor
plane = FLOOR_PLANE
/obj/item/organ/internal/heart/demon/shadow
name = "heart of darkness"
desc = "It still beats furiously, emitting an aura of fear."
color = COLOR_BLACK
/obj/item/organ/internal/heart/demon/shadow/attack_self(mob/living/user)
. = ..()
user.drop_item()
insert(user)
/obj/item/organ/internal/heart/demon/shadow/insert(mob/living/carbon/M, special = 0)
. = ..()
if(M.mind)
M.mind.AddSpell(new /obj/effect/proc_holder/spell/fireball/shadow_grapple)
/obj/item/organ/internal/heart/demon/shadow/remove(mob/living/carbon/M, special = 0)
..()
if(M.mind)
M.mind.RemoveSpell(/obj/effect/proc_holder/spell/fireball/shadow_grapple)

View File

@@ -1,42 +1,15 @@
//////////////////The Monster
/mob/living/simple_animal/slaughter
/mob/living/simple_animal/demon/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 = INTENT_HARM
mob_biotypes = MOB_ORGANIC | MOB_HUMANOID
stop_automated_movement = TRUE
status_flags = CANPUSH
attack_sound = 'sound/misc/demon_attack1.ogg'
var/feast_sound = 'sound/misc/demon_consume.ogg'
death_sound = 'sound/misc/demon_dies.ogg'
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)
minbodytemp = 0
maxbodytemp = INFINITY
faction = list("slaughter")
attacktext = "wildly tears into"
maxHealth = 200
health = 200
environment_smash = 1
obj_damage = 50
melee_damage_lower = 30
melee_damage_upper = 30
see_in_dark = 8
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
var/boost = 0
var/feast_sound = 'sound/misc/demon_consume.ogg'
var/devoured = 0
var/list/consumed_mobs = list()
@@ -44,7 +17,7 @@
var/cooldown = 0
var/gorecooldown = 0
var/vialspawned = FALSE
loot = list(/obj/effect/decal/cleanable/blood/innards, /obj/effect/decal/cleanable/blood, /obj/effect/gibspawner/generic, /obj/effect/gibspawner/generic, /obj/item/organ/internal/heart/demon)
loot = list(/obj/effect/decal/cleanable/blood/innards, /obj/effect/decal/cleanable/blood, /obj/effect/gibspawner/generic, /obj/effect/gibspawner/generic, /obj/item/organ/internal/heart/demon/slaughter)
var/playstyle_string = "<B>You are the Slaughter Demon, a terrible creature from another existence. You have a single desire: to kill. \
You may use the blood crawl icon when on blood pools to travel through them, appearing and dissapearing 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. \
@@ -52,30 +25,26 @@
del_on_death = TRUE
deathmessage = "screams in anger as it collapses into a puddle of viscera!"
var/datum/action/innate/demon/whisper/whisper_action
/mob/living/simple_animal/slaughter/New()
/mob/living/simple_animal/demon/slaughter/New()
..()
remove_from_all_data_huds()
ADD_TRAIT(src, TRAIT_BLOODCRAWL_EAT, "bloodcrawl_eat")
var/obj/effect/proc_holder/spell/bloodcrawl/bloodspell = new
AddSpell(bloodspell)
whisper_action = new()
whisper_action.Grant(src)
if(istype(loc, /obj/effect/dummy/slaughter))
bloodspell.phased = TRUE
addtimer(CALLBACK(src, PROC_REF(attempt_objectives)), 5 SECONDS)
/mob/living/simple_animal/slaughter/Life(seconds, times_fired)
/mob/living/simple_animal/demon/slaughter/Life(seconds, times_fired)
..()
if(boost < world.time)
speed = 1
else
speed = 0
/mob/living/simple_animal/slaughter/proc/attempt_objectives()
/mob/living/simple_animal/demon/slaughter/proc/attempt_objectives()
if(mind)
to_chat(src, src.playstyle_string)
to_chat(src, "<B><span class ='notice'>You are not currently in the same plane of existence as the station. Use the blood crawl action at a blood pool to manifest.</span></B>")
@@ -100,28 +69,24 @@
name = "pile of viscera"
desc = "A repulsive pile of guts and gore."
/mob/living/simple_animal/slaughter/Destroy()
/mob/living/simple_animal/demon/slaughter/Destroy()
// Only execute the below if we successfully died
for(var/mob/living/M in consumed_mobs)
release_consumed(M)
. = ..()
/mob/living/simple_animal/slaughter/proc/release_consumed(mob/living/M)
/mob/living/simple_animal/demon/slaughter/proc/release_consumed(mob/living/M)
M.forceMove(get_turf(src))
/mob/living/simple_animal/slaughter/phasein()
. = ..()
speed = 0
boost = world.time + 60
// Midround slaughter demon, less tanky
/mob/living/simple_animal/slaughter/lesser
/mob/living/simple_animal/demon/slaughter/lesser
maxHealth = 130
health = 130
// Cult slaughter demon
/mob/living/simple_animal/slaughter/cult //Summoned as part of the cult objective "Bring the Slaughter"
/mob/living/simple_animal/demon/slaughter/cult //Summoned as part of the cult objective "Bring the Slaughter"
name = "harbinger of the slaughter"
real_name = "harbinger of the Slaughter"
desc = "An awful creature from beyond the realms of madness."
@@ -163,10 +128,10 @@
return 0
to_chat(user, "<span class='danger'>You sense a terrified soul at [A]. <b>Show [A.p_them()] the error of [A.p_their()] ways.</b></span>")
/mob/living/simple_animal/slaughter/cult/New()
/mob/living/simple_animal/demon/slaughter/cult/New()
..()
spawn(5)
var/list/demon_candidates = SSghost_spawns.poll_candidates("Do you want to play as a slaughter demon?", ROLE_DEMON, TRUE, 10 SECONDS, source = /mob/living/simple_animal/slaughter/cult)
var/list/demon_candidates = SSghost_spawns.poll_candidates("Do you want to play as a slaughter demon?", ROLE_DEMON, TRUE, 10 SECONDS, source = /mob/living/simple_animal/demon/slaughter/cult)
if(!demon_candidates.len)
visible_message("<span class='warning'>[src] disappears in a flash of red light!</span>")
qdel(src)
@@ -174,7 +139,7 @@
if(QDELETED(src)) // Just in case
return
var/mob/M = pick(demon_candidates)
var/mob/living/simple_animal/slaughter/cult/S = src
var/mob/living/simple_animal/demon/slaughter/cult/S = src
if(!M || !M.client)
visible_message("<span class='warning'>[src] disappears in a flash of red light!</span>")
qdel(src)
@@ -240,7 +205,7 @@
//////////The Loot
//The loot from killing a slaughter demon - can be consumed to allow the user to blood crawl
// Demon heart base type
/obj/item/organ/internal/heart/demon
name = "demon heart"
desc = "Still it beats furiously, emanating an aura of utter hate."
@@ -254,11 +219,22 @@
/obj/item/organ/internal/heart/demon/prepare_eat()
return // Just so people don't accidentally waste it
/obj/item/organ/internal/heart/demon/Stop()
return 0 // Always beating.
/obj/item/organ/internal/heart/demon/attack_self(mob/living/user)
user.visible_message("<span class='warning'>[user] raises [src] to [user.p_their()] mouth and tears into it with [user.p_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)
//////////The Loot
//The loot from killing a slaughter demon - can be consumed to allow the user to blood crawl
/// SLAUGHTER DEMON HEART
/obj/item/organ/internal/heart/demon/slaughter/attack_self(mob/living/user)
..()
// Eating the heart for the first time. Gives basic bloodcrawling. This is the only time we need to insert the heart.
if(!HAS_TRAIT(user, TRAIT_BLOODCRAWL))
user.visible_message("<span class='warning'>[user]'s eyes flare a deep crimson!</span>", \
@@ -279,23 +255,19 @@
to_chat(user, "<span class='warning'>...and you don't feel any different.</span>")
qdel(src)
/obj/item/organ/internal/heart/demon/insert(mob/living/carbon/M, special = 0)
/obj/item/organ/internal/heart/demon/slaughter/insert(mob/living/carbon/M, special = 0)
. = ..()
if(M.mind)
M.mind.AddSpell(new /obj/effect/proc_holder/spell/bloodcrawl(null))
/obj/item/organ/internal/heart/demon/remove(mob/living/carbon/M, special = 0)
/obj/item/organ/internal/heart/demon/slaughter/remove(mob/living/carbon/M, special = 0)
..()
if(M.mind)
REMOVE_TRAIT(M, TRAIT_BLOODCRAWL, "bloodcrawl")
REMOVE_TRAIT(M, TRAIT_BLOODCRAWL_EAT, "bloodcrawl_eat")
M.mind.RemoveSpell(/obj/effect/proc_holder/spell/bloodcrawl)
/obj/item/organ/internal/heart/demon/Stop()
return 0 // Always beating.
/mob/living/simple_animal/slaughter/laughter
/mob/living/simple_animal/demon/slaughter/laughter
// The laughter demon! It's everyone's best friend! It just wants to hug
// them so much, it wants to hug everyone at once!
name = "laughter demon"
@@ -324,7 +296,7 @@
deathmessage = "fades out, as all of its friends are released from its prison of hugs."
loot = list(/mob/living/simple_animal/pet/cat/kitten{name = "Laughter"})
/mob/living/simple_animal/slaughter/laughter/release_consumed(mob/living/M)
/mob/living/simple_animal/demon/slaughter/laughter/release_consumed(mob/living/M)
if(M.revive())
M.grab_ghost(force = TRUE)
playsound(get_turf(src), feast_sound, 50, 1, -1)
@@ -348,7 +320,7 @@
for(var/datum/mind/M in get_owners())
if(!isslaughterdemon(M.current) || QDELETED(M.current))
continue
var/mob/living/simple_animal/slaughter/R = M.current
var/mob/living/simple_animal/demon/slaughter/R = M.current
kill_count += R.devoured
if(kill_count >= targetKill)
return TRUE

View File

@@ -1,180 +0,0 @@
//Travel through pools of blood. Slaughter Demon powers for everyone!
#define BLOODCRAWL 1
#define BLOODCRAWL_EAT 2
/mob/living/proc/phaseout(obj/effect/decal/cleanable/B)
if(iscarbon(src))
var/mob/living/carbon/C = src
if(C.l_hand || C.r_hand)
to_chat(C, "<span class='warning'>You may not hold items while blood crawling!</span>")
return 0
var/obj/item/bloodcrawl/B1 = new(C)
var/obj/item/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(loc)
notransform = TRUE
spawn(0)
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 = FALSE
animation.anchored = TRUE
animation.icon = 'icons/mob/mob.dmi'
animation.icon_state = "jaunt"
animation.layer = 5
animation.master = holder
animation.dir = dir
ExtinguishMob()
if(pulling && HAS_TRAIT(src, TRAIT_BLOODCRAWL_EAT))
if(isliving(pulling))
var/mob/living/victim = pulling
if(victim.stat == CONSCIOUS)
visible_message("<span class='warning'>[victim] kicks free of [B] just before entering it!</span>")
stop_pulling()
else
victim.forceMove(holder)//holder
victim.emote("scream")
visible_message("<span class='warning'><b>[src] drags [victim] into [B]!</b></span>")
kidnapped = victim
stop_pulling()
flick("jaunt",animation)
src.holder = holder
forceMove(holder)
if(kidnapped)
to_chat(src, "<B>You begin to feast on [kidnapped]. You can not move while you are doing this.</B>")
visible_message("<span class='warning'><B>Loud eating sounds come from the blood...</B></span>")
sleep(6)
if(animation)
qdel(animation)
var/sound
if(isslaughterdemon(src))
var/mob/living/simple_animal/slaughter/SD = src
sound = SD.feast_sound
else
sound = 'sound/misc/demon_consume.ogg'
for(var/i in 1 to 3)
playsound(get_turf(src), sound, 100, 1)
sleep(30)
if(kidnapped)
if(ishuman(kidnapped) || isrobot(kidnapped))
to_chat(src, "<span class='warning'>You devour [kidnapped]. Your health is fully restored.</span>")
adjustBruteLoss(-1000)
adjustFireLoss(-1000)
adjustOxyLoss(-1000)
adjustToxLoss(-1000)
else
to_chat(src, "<span class='warning'>You devour [kidnapped], but this measly meal barely sates your appetite!</span>")
adjustBruteLoss(-25)
adjustFireLoss(-25)
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++
to_chat(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)
if(ishuman(kidnapped))
var/mob/living/carbon/human/H = kidnapped
if(H.w_uniform && istype(H.w_uniform, /obj/item/clothing/under))
var/obj/item/clothing/under/U = H.w_uniform
U.sensor_mode = SENSOR_OFF
else
kidnapped.ghostize()
qdel(kidnapped)
else
to_chat(src, "<span class='danger'>You happily devour... nothing? Your meal vanished at some point!</span>")
else
sleep(6)
if(animation)
qdel(animation)
notransform = FALSE
return 1
/obj/item/bloodcrawl
name = "blood crawl"
desc = "You are unable to hold anything while in this form."
icon = 'icons/effects/blood.dmi'
flags = NODROP|ABSTRACT
/mob/living/proc/phasein(obj/effect/decal/cleanable/B)
if(notransform)
to_chat(src, "<span class='warning'>Finish eating first!</span>")
return 0
B.visible_message("<span class='warning'>[B] starts to bubble...</span>")
if(!do_after(src, 20, target = B))
return
if(!B)
return
forceMove(B.loc)
client.eye = src
var/atom/movable/overlay/animation = new /atom/movable/overlay( B.loc )
animation.name = "odd blood"
animation.density = FALSE
animation.anchored = TRUE
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 = dir
if(prob(25) && isslaughterdemon(src))
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)
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_NULL(holder)
if(iscarbon(src))
var/mob/living/carbon/C = src
for(var/obj/item/bloodcrawl/BC in C)
C.flags = null
C.unEquip(BC)
qdel(BC)
var/oldcolor = color
color = B.color
sleep(6)//wait for animation to finish
if(animation)
qdel(animation)
spawn(30)
color = oldcolor
return 1
/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"
density = FALSE
anchored = TRUE
invisibility = 60
resistance_flags = LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
/obj/effect/dummy/slaughter/relaymove(mob/user, direction)
forceMove(get_step(src,direction))
/obj/effect/dummy/slaughter/ex_act()
return
/obj/effect/dummy/slaughter/bullet_act()
return
/obj/effect/dummy/slaughter/singularity_act()
return

View File

@@ -30,7 +30,7 @@
return FALSE
return TRUE
/obj/machinery/computer/extinguish_light()
/obj/machinery/computer/extinguish_light(force = FALSE)
set_light(0)
underlays.Cut()
visible_message("<span class='danger'>[src] grows dim, its screen barely readable.</span>")

View File

@@ -97,7 +97,7 @@
else
set_light(1, LIGHTING_MINIMUM_POWER)
/obj/machinery/door/firedoor/extinguish_light()
/obj/machinery/door/firedoor/extinguish_light(force = FALSE)
set_light(0)
update_icon(UPDATE_OVERLAYS)

View File

@@ -26,7 +26,7 @@
set_light(0)
update_icon(UPDATE_OVERLAYS)
/obj/machinery/dye_generator/extinguish_light()
/obj/machinery/dye_generator/extinguish_light(force = FALSE)
set_light(0)
underlays.Cut()

View File

@@ -145,7 +145,7 @@
update_icon(UPDATE_ICON_STATE)
return TRUE
/obj/machinery/floodlight/extinguish_light()
/obj/machinery/floodlight/extinguish_light(force = FALSE)
on = FALSE
set_light(0)
update_icon(UPDATE_ICON_STATE)

View File

@@ -785,7 +785,7 @@
if(shoot_inventory && prob(shoot_chance))
throw_item()
/obj/machinery/economy/vending/extinguish_light()
/obj/machinery/economy/vending/extinguish_light(force = FALSE)
set_light(0)
underlays.Cut()

View File

@@ -13,7 +13,7 @@
var/floor = 0
var/obj/item/seeds/myseed = /obj/item/seeds/glowshroom
/obj/structure/glowshroom/extinguish_light()
/obj/structure/glowshroom/extinguish_light(force = FALSE)
visible_message("<span class='warning'>[src] withers away!</span>")
qdel(src)
@@ -29,7 +29,7 @@
icon_state = "shadowshroom"
myseed = /obj/item/seeds/glowshroom/shadowshroom
/obj/structure/glowshroom/shadowshroom/extinguish_light()
/obj/structure/glowshroom/shadowshroom/extinguish_light(force = FALSE)
return
/obj/structure/glowshroom/Destroy()

View File

@@ -141,6 +141,13 @@
if(lit)
set_light(CANDLE_LUM * 2)
/obj/item/candle/extinguish_light(force)
if(!force)
return
infinite = FALSE
wax = 1 // next process will burn it out
#undef TALL_CANDLE
#undef MID_CANDLE
#undef SHORT_CANDLE

View File

@@ -82,7 +82,7 @@
else
return ..()
/obj/item/flashlight/extinguish_light()
/obj/item/flashlight/extinguish_light(force = FALSE)
if(on)
on = FALSE
update_brightness()
@@ -283,8 +283,12 @@
new T(loc)
qdel(src) // return INITIALIZE_HINT_QDEL <-- Doesn't work
/obj/item/flashlight/flare/extinguish_light()
visible_message("<span class='danger'>[src] dims slightly before scattering the shadows around it.</span>")
/obj/item/flashlight/flare/extinguish_light(force = FALSE)
if(force)
fuel = 0
visible_message("<span class='danger'>[src] burns up rapidly!</span>")
else
visible_message("<span class='danger'>[src] dims slightly before scattering the shadows around it.</span>")
/obj/item/flashlight/flare/torch
name = "torch"
@@ -321,8 +325,12 @@
/obj/item/flashlight/slime/attack_self(mob/user)
return //Bio-luminescence does not toggle.
/obj/item/flashlight/slime/extinguish_light()
visible_message("<span class='danger'>[src] dims slightly before scattering the shadows around it.</span>")
/obj/item/flashlight/slime/extinguish_light(force = FALSE)
if(force)
visible_message("<span class='danger'>[src] withers away.</span>")
qdel(src)
else
visible_message("<span class='danger'>[src] dims slightly before scattering the shadows around it.</span>")
/obj/item/flashlight/emp
origin_tech = "magnets=3;syndicate=1"

View File

@@ -329,7 +329,7 @@
M.emp_act(severity)
..()
/obj/item/paicard/extinguish_light()
/obj/item/paicard/extinguish_light(force = FALSE)
if(pai)
pai.extinguish_light()
set_light(0)

View File

@@ -72,6 +72,13 @@
reagents.add_reagent("fuel", 1)
..()
/obj/item/weldingtool/extinguish_light(force)
if(!force)
return
if(!tool_enabled)
return
remove_fuel(maximum_fuel)
/obj/item/weldingtool/attack_self(mob/user)
if(tool_enabled) //Turn off the welder if it's on
to_chat(user, "<span class='notice'>You switch off [src].</span>")

View File

@@ -189,6 +189,11 @@ LIGHTERS ARE IN LIGHTERS.DM
smoke()
/obj/item/clothing/mask/cigarette/extinguish_light(force)
if(!force)
return
die()
/obj/item/clothing/mask/cigarette/attack_self(mob/user)
if(lit)
user.visible_message("<span class='notice'>[user] calmly drops and treads on [src], putting it out instantly.</span>")
@@ -362,6 +367,9 @@ LIGHTERS ARE IN LIGHTERS.DM
chem_volume = 200
list_reagents = list("nicotine" = 200)
/obj/item/clothing/mask/cigarette/pipe/die()
return
/obj/item/clothing/mask/cigarette/pipe/light(flavor_text = null)
if(!lit)
lit = TRUE

View File

@@ -69,10 +69,16 @@
force = 0
attack_verb = null //human_defense.dm takes care of it
show_off_message(user)
if(user)
show_off_message(user)
set_light(0)
STOP_PROCESSING(SSobj, src)
/obj/item/lighter/extinguish_light(force)
if(!force)
return
turn_off_lighter()
/obj/item/lighter/proc/show_off_message(mob/living/user)
to_chat(user, "<span class='notice'>You shut off [src].")
@@ -124,6 +130,9 @@
/obj/item/lighter/zippo/turn_off_lighter(mob/living/user)
. = ..()
if(!user)
return
if(world.time > next_off_message)
user.visible_message("<span class='rose'>You hear a quiet click, as [user] shuts off [src] without even looking at what [user.p_theyre()] doing. Wow.")
playsound(src.loc, 'sound/items/zippoclose.ogg', 25, 1)
@@ -201,6 +210,11 @@
..()
matchignite()
/obj/item/match/extinguish_light(force)
if(!force)
return
matchburnout()
/obj/item/match/proc/matchignite()
if(!lit && !burnt)
lit = TRUE

View File

@@ -103,8 +103,7 @@
A.addStaticPower(100, STATIC_LIGHT)
update_icon()
/turf/simulated/floor/light/extinguish_light()
/turf/simulated/floor/light/extinguish_light(force = FALSE)
toggle_light(FALSE)
visible_message("<span class='danger'>[src] flickers and falls dark.</span>")

View File

@@ -165,7 +165,7 @@
var/veil_msg = "<span class='warning'>You sense a dark presence lurking \
just beyond the veil...</span>"
var/objective_verb = "Kill"
var/mob/living/demon_type = /mob/living/simple_animal/slaughter
var/mob/living/demon_type = /mob/living/simple_animal/demon/slaughter
/obj/item/antag_spawner/slaughter_demon/attack_self(mob/user)
if(level_blocks_magic(user.z)) //this is to make sure the wizard does NOT summon a demon from the Den..
@@ -179,7 +179,7 @@
to_chat(user, "<span class='notice'>You break the seal on the bottle, calling upon the dire spirits of the underworld...</span>")
var/type = "slaughter"
if(demon_type == /mob/living/simple_animal/slaughter/laughter)
if(demon_type == /mob/living/simple_animal/demon/slaughter/laughter)
type = "laughter"
var/list/candidates = SSghost_spawns.poll_candidates("Do you want to play as a [type] demon summoned by [user.real_name]?", ROLE_DEMON, TRUE, 10 SECONDS, source = demon_type)
@@ -196,9 +196,8 @@
/obj/item/antag_spawner/slaughter_demon/spawn_antag(client/C, turf/T, type = "", mob/user)
var/obj/effect/dummy/slaughter/holder = new /obj/effect/dummy/slaughter(T)
var/mob/living/simple_animal/slaughter/S = new demon_type(holder)
var/mob/living/simple_animal/demon/slaughter/S = new demon_type(holder)
S.vialspawned = TRUE
S.holder = holder
S.key = C.key
S.mind.assigned_role = S.name
S.mind.special_role = S.name
@@ -226,7 +225,7 @@
veil_msg = "<span class='warning'>You sense an adorable presence \
lurking just beyond the veil...</span>"
objective_verb = "Hug and tickle"
demon_type = /mob/living/simple_animal/slaughter/laughter
demon_type = /mob/living/simple_animal/demon/slaughter/laughter
///////////MORPH

View File

@@ -44,10 +44,10 @@
/obj/item/clothing/head/hardhat/proc/turn_off(mob/user)
set_light(0)
/obj/item/clothing/head/hardhat/extinguish_light(mob/living/user)
/obj/item/clothing/head/hardhat/extinguish_light(force = FALSE)
if(on)
on = FALSE
turn_off(user)
turn_off()
update_icon(UPDATE_ICON_STATE)
visible_message("<span class='danger'>[src]'s light fades and turns off.</span>")

View File

@@ -68,7 +68,7 @@
var/datum/action/A = X
A.UpdateButtonIcon()
/obj/item/clothing/head/helmet/space/hardsuit/extinguish_light()
/obj/item/clothing/head/helmet/space/hardsuit/extinguish_light(force = FALSE)
if(on)
toggle_light()
visible_message("<span class='danger'>[src]'s light fades and turns off.</span>")

View File

@@ -82,7 +82,7 @@
set_light(brightness_on)
/obj/item/clothing/head/helmet/space/plasmaman/extinguish_light()
/obj/item/clothing/head/helmet/space/plasmaman/extinguish_light(force = FALSE)
if(on)
toggle_light()

View File

@@ -197,6 +197,7 @@ GLOBAL_LIST_EMPTY(event_last_fired)
new /datum/event_meta(EVENT_LEVEL_MAJOR, "Traders", /datum/event/traders, 85, is_one_shot = TRUE),
new /datum/event_meta(EVENT_LEVEL_MAJOR, "Terror Spiders", /datum/event/spider_terror, 20, list(ASSIGNMENT_SECURITY = 4), TRUE),
new /datum/event_meta(EVENT_LEVEL_MAJOR, "Slaughter Demon", /datum/event/spawn_slaughter, 10, is_one_shot = TRUE),
new /datum/event_meta(EVENT_LEVEL_MAJOR, "Shadow Demon", /datum/event/spawn_slaughter/shadow, 50, is_one_shot = TRUE)
//new /datum/event_meta(EVENT_LEVEL_MAJOR, "Floor Cluwne", /datum/event/spawn_floor_cluwne, 15, is_one_shot = TRUE)
)

View File

@@ -1,9 +1,9 @@
/datum/event/spawn_slaughter
var/key_of_slaughter
var/demon = /mob/living/simple_animal/slaughter/lesser
var/mob/living/simple_animal/demon/demon = /mob/living/simple_animal/demon/slaughter/lesser
/datum/event/spawn_slaughter/proc/get_slaughter()
var/list/candidates = SSghost_spawns.poll_candidates("Do you want to play as a slaughter demon?", ROLE_DEMON, TRUE, source = /mob/living/simple_animal/slaughter)
var/list/candidates = SSghost_spawns.poll_candidates("Do you want to play as a [initial(demon.name)]?", ROLE_DEMON, TRUE, source = demon)
if(!length(candidates))
kill()
return
@@ -17,25 +17,41 @@
var/datum/mind/player_mind = new /datum/mind(key_of_slaughter)
player_mind.active = TRUE
var/list/spawn_locs = list()
var/turf/spawn_loc = get_spawn_loc(player_mind.current)
var/obj/effect/dummy/slaughter/holder = new /obj/effect/dummy/slaughter(spawn_loc)
var/mob/living/simple_animal/demon/S = new demon(holder)
player_mind.transfer_to(S)
player_mind.assigned_role = "Demon"
player_mind.special_role = SPECIAL_ROLE_DEMON
message_admins("[key_name_admin(S)] has been made into a [S.name] by an event.")
log_game("[key_name_admin(S)] was spawned as a [S.name] by an event.")
/datum/event/spawn_slaughter/proc/get_spawn_loc(mob/player)
RETURN_TYPE(/turf)
var/list/spawn_centers = list()
for(var/obj/effect/landmark/spawner/rev/L in GLOB.landmarks_list)
spawn_locs += get_turf(L)
if(!spawn_locs) //If we can't find a good place, 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 give up
spawn_centers += get_turf(L)
if(!spawn_centers) //If we can't find a good place, just spawn the revenant at the player's location
spawn_centers += get_turf(player)
if(!spawn_centers) //If we can't find THAT, then give up
kill()
return
var/obj/effect/dummy/slaughter/holder = new /obj/effect/dummy/slaughter(pick(spawn_locs))
var/mob/living/simple_animal/slaughter/S = new demon(holder)
S.holder = holder
player_mind.transfer_to(S)
player_mind.assigned_role = "Slaughter Demon"
player_mind.special_role = SPECIAL_ROLE_SLAUGHTER_DEMON
message_admins("[key_name_admin(S)] has been made into a Slaughter Demon by an event.")
log_game("[key_name_admin(S)] was spawned as a Slaughter Demon by an event.")
return pick(spawn_centers)
/datum/event/spawn_slaughter/start()
INVOKE_ASYNC(src, PROC_REF(get_slaughter))
/datum/event/spawn_slaughter/greater
demon = /mob/living/simple_animal/slaughter
demon = /mob/living/simple_animal/demon/slaughter
/datum/event/spawn_slaughter/shadow
demon = /mob/living/simple_animal/demon/shadow
/datum/event/spawn_slaughter/shadow/get_spawn_loc()
var/turf/spawn_center = ..()
for(var/turf/T in range(50, spawn_center))
if(T.get_lumcount()) // if the turf is not pitch black
continue
return T // return the first turf that is dark nearby.
kill()

View File

@@ -115,7 +115,7 @@
if(old_stat != stat)
update_icon(UPDATE_OVERLAYS)
/obj/machinery/smartfridge/extinguish_light()
/obj/machinery/smartfridge/extinguish_light(force = FALSE)
set_light(0)
underlays.Cut()

View File

@@ -206,3 +206,9 @@
add_attack_logs(user, target, "[what_done] ([reagent_str] | [genes_str])")
/obj/item/reagent_containers/food/snacks/grown/extinguish_light(force = FALSE)
if(!force)
return
if(seed.get_gene(/datum/plant_gene/trait/glow/shadow))
return
set_light(0)

View File

@@ -61,3 +61,10 @@
if(seed)
for(var/datum/plant_gene/trait/T in seed.genes)
T.on_throw_impact(src, hit_atom)
/obj/item/grown/extinguish_light(force = FALSE)
if(!force)
return
if(seed.get_gene(/datum/plant_gene/trait/glow/shadow))
return
set_light(0)

View File

@@ -54,7 +54,7 @@
else
light = new/datum/light_source(src, .)
/atom/proc/extinguish_light()
/atom/proc/extinguish_light(force = FALSE)
return
// If we have opacity, make sure to tell (potentially) affected light sources.

View File

@@ -134,9 +134,9 @@
var/list/antag_serialized = serialized.Copy()
antag_serialized["antag"] = "Xenomorph"
antagonists += list(antag_serialized)
else if(isslaughterdemon(M))
else if(isdemon(M))
var/list/antag_serialized = serialized.Copy()
antag_serialized["antag"] = "Slaughter Demon"
antag_serialized["antag"] = "Demon"
antagonists += list(antag_serialized)
else
if(length(orbiters) >= 0.2 * length_of_ghosts) // If a bunch of people are orbiting an object, like the nuke disk.

View File

@@ -1966,7 +1966,7 @@ Eyes need to have significantly high darksight to shine unless the mob has the X
to_chat(src, "<span class='whisper'>[pick(GLOB.boo_phrases)]</span>")
return TRUE
/mob/living/carbon/human/extinguish_light()
/mob/living/carbon/human/extinguish_light(force = FALSE)
// Parent function handles stuff the human may be holding
..()

View File

@@ -1092,10 +1092,10 @@
/mob/living/proc/fakefire()
return
/mob/living/extinguish_light()
/mob/living/extinguish_light(force = FALSE)
for(var/atom/A in src)
if(A.light_range > 0)
A.extinguish_light()
A.extinguish_light(force)
/mob/living/vv_edit_var(var_name, var_value)
switch(var_name)

View File

@@ -42,8 +42,6 @@
var/mob_biotypes = MOB_ORGANIC
var/metabolism_efficiency = 1 //more or less efficiency to metabolize helpful/harmful reagents and regulate body temperature..
var/holder = null //The holder for blood crawling
var/ventcrawler = 0 //0 No vent crawling, 1 vent crawling in the nude, 2 vent crawling always
var/list/icon/pipes_shown = list()
var/last_played_vent

View File

@@ -515,7 +515,7 @@
CRASH("pAI without card")
loc = card
/mob/living/silicon/pai/extinguish_light()
/mob/living/silicon/pai/extinguish_light(force = FALSE)
flashlight_on = FALSE
set_light(0)
card.set_light(0)

View File

@@ -1473,7 +1473,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
overlays += "[base_icon]-shield"
/mob/living/silicon/robot/extinguish_light()
/mob/living/silicon/robot/extinguish_light(force = FALSE)
update_headlamp(1, 150)
/mob/living/silicon/robot/rejuvenate()

View File

@@ -390,7 +390,7 @@ GLOBAL_LIST_EMPTY(PDAs)
if(current_app)
current_app.program_process()
/obj/item/pda/extinguish_light()
/obj/item/pda/extinguish_light(force = FALSE)
var/datum/data/pda/utility/flashlight/FL = find_program(/datum/data/pda/utility/flashlight)
if(FL && FL.fon)
FL.start()

View File

@@ -941,7 +941,7 @@
limb.droplimb(0, DROPLIMB_BURN)
return FIRELOSS
/obj/machinery/light/extinguish_light()
/obj/machinery/light/extinguish_light(force = FALSE)
on = FALSE
extinguished = TRUE
emergency_mode = FALSE

View File

@@ -368,14 +368,11 @@
if(!gun_light)
return
var/mob/living/carbon/human/user = usr
if(!isturf(user.loc))
to_chat(user, "<span class='warning'>You cannot turn the light on while in this [user.loc]!</span>")
gun_light.on = !gun_light.on
to_chat(user, "<span class='notice'>You toggle the gun light [gun_light.on ? "on":"off"].</span>")
playsound(user, 'sound/weapons/empty.ogg', 100, 1)
var/mob/living/carbon/human/user = usr
if(user)
to_chat(user, "<span class='notice'>You toggle the gun light [gun_light.on ? "on":"off"].</span>")
playsound(src, 'sound/weapons/empty.ogg', 100, 1)
update_gun_light(user)
/obj/item/gun/proc/update_gun_light(mob/user = null)
@@ -401,7 +398,7 @@
knife_overlay = null
return TRUE
/obj/item/gun/extinguish_light()
/obj/item/gun/extinguish_light(force = FALSE)
if(gun_light?.on)
toggle_gunlight()
visible_message("<span class='danger'>[src]'s light fades and turns off.</span>")

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 134 KiB

After

Width:  |  Height:  |  Size: 135 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 194 KiB

After

Width:  |  Height:  |  Size: 196 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 40 KiB

View File

@@ -617,6 +617,9 @@
#include "code\game\gamemodes\miniantags\abduction\machinery\dispenser.dm"
#include "code\game\gamemodes\miniantags\abduction\machinery\experiment.dm"
#include "code\game\gamemodes\miniantags\abduction\machinery\pad.dm"
#include "code\game\gamemodes\miniantags\demons\demon.dm"
#include "code\game\gamemodes\miniantags\demons\shadow_demon\shadow_demon.dm"
#include "code\game\gamemodes\miniantags\demons\slaughter demon\slaughter.dm"
#include "code\game\gamemodes\miniantags\guardian\guardian.dm"
#include "code\game\gamemodes\miniantags\guardian\host_actions.dm"
#include "code\game\gamemodes\miniantags\guardian\types\assassin.dm"
@@ -638,8 +641,6 @@
#include "code\game\gamemodes\miniantags\revenant\revenant.dm"
#include "code\game\gamemodes\miniantags\revenant\revenant_abilities.dm"
#include "code\game\gamemodes\miniantags\revenant\revenant_spawn_event.dm"
#include "code\game\gamemodes\miniantags\slaughter\bloodcrawl.dm"
#include "code\game\gamemodes\miniantags\slaughter\slaughter.dm"
#include "code\game\gamemodes\nuclear\nuclear.dm"
#include "code\game\gamemodes\nuclear\nuclear_challenge.dm"
#include "code\game\gamemodes\nuclear\nuclearbomb.dm"