mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-30 00:29:02 +01:00
Grand Ritual Finale: An end to death (#78497)
## About The Pull Request Adds a new Wizard Ritual Finale effect which makes everything immortal. By this I mean, 10 seconds after death a ghostly image of them will appear somewhere near where the corpse was and then 50 seconds after that the mob will return to life at that location. This applies to every mob, everywhere. This is likely to cause a little bit of disruption to the rest of the round, so you can only do it after at least 30 minutes have passed. After that the crew will have to figure out how to deal with their new gift of immortality. It will involve throwing people into chasms and lava, probably.  Here's a gif sped up for example purposes. You can escape from the cycle of death and rebirth via suicide, purely because it's pointless to try and force people to play the video game if they don't want to. Also I split all of these effects into their own files, the only new code for those is in `immortality.dm` shout out to Vekter for distracting Oranges while I posted this wizard-related PR so I didn't get disapprovingly reacted for posting magic shit (yet) ## Why It's Good For The Game This might be _too_ much but I want to see what would happen. It will allow us to simulate whether polite society can survive when violence has no consequences. ## Changelog 🆑 add: Wizards who complete the grand ritual can now gift everyone with eternal life /🆑
This commit is contained in:
@@ -892,6 +892,9 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
|
||||
/// For clarity, this trait should always be associated/tied to a reference to the mob that suicided- not anything else.
|
||||
#define TRAIT_SUICIDED "committed_suicide"
|
||||
|
||||
/// Trait given to a living mob to prevent wizards from making it immortal
|
||||
#define TRAIT_PERMANENTLY_MORTAL "permanently_mortal"
|
||||
|
||||
///Trait given to a mob with a ckey currently in a temporary body, allowing people to know someone will re-enter the round later.
|
||||
#define TRAIT_MIND_TEMPORARILY_GONE "temporarily_gone"
|
||||
|
||||
@@ -993,6 +996,8 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
|
||||
#define MOTOR_LACK_TRAIT "motor-lack"
|
||||
/// Trait associated with mafia
|
||||
#define MAFIA_TRAIT "mafia"
|
||||
/// Trait associated with ctf
|
||||
#define CTF_TRAIT "ctf"
|
||||
/// Trait associated with highlander
|
||||
#define HIGHLANDER_TRAIT "highlander"
|
||||
/// Trait given from playing pretend with baguettes
|
||||
|
||||
@@ -117,7 +117,7 @@
|
||||
if(!hud.mymob)
|
||||
continue
|
||||
HideFrom(hud.mymob)
|
||||
LAZYREMOVE(remove_from.actions, src) // We aren't always properly inserted into the viewers list, gotta make sure that action's cleared
|
||||
LAZYREMOVE(remove_from?.actions, src) // We aren't always properly inserted into the viewers list, gotta make sure that action's cleared
|
||||
viewers = list()
|
||||
|
||||
if(owner)
|
||||
|
||||
@@ -8,28 +8,29 @@
|
||||
/// List of refs to falling objects -> how many levels deep we've fallen
|
||||
var/static/list/falling_atoms = list()
|
||||
var/static/list/forbidden_types = typecacheof(list(
|
||||
/obj/singularity,
|
||||
/obj/energy_ball,
|
||||
/obj/narsie,
|
||||
/obj/docking_port,
|
||||
/obj/structure/lattice,
|
||||
/obj/structure/stone_tile,
|
||||
/obj/projectile,
|
||||
/obj/effect/projectile,
|
||||
/obj/effect/portal,
|
||||
/obj/effect/abstract,
|
||||
/obj/effect/hotspot,
|
||||
/obj/effect/landmark,
|
||||
/obj/effect/temp_visual,
|
||||
/obj/effect/light_emitter/tendril,
|
||||
/obj/effect/collapse,
|
||||
/obj/effect/particle_effect/ion_trails,
|
||||
/obj/effect/constructing_effect,
|
||||
/obj/effect/dummy/phased_mob,
|
||||
/obj/effect/mapping_helpers,
|
||||
/obj/effect/wisp,
|
||||
/obj/effect/ebeam,
|
||||
/obj/effect/fishing_lure,
|
||||
/obj/effect/constructing_effect,
|
||||
/obj/effect/hotspot,
|
||||
/obj/effect/landmark,
|
||||
/obj/effect/light_emitter/tendril,
|
||||
/obj/effect/mapping_helpers,
|
||||
/obj/effect/particle_effect/ion_trails,
|
||||
/obj/effect/portal,
|
||||
/obj/effect/projectile,
|
||||
/obj/effect/spectre_of_resurrection,
|
||||
/obj/effect/temp_visual,
|
||||
/obj/effect/wisp,
|
||||
/obj/energy_ball,
|
||||
/obj/narsie,
|
||||
/obj/projectile,
|
||||
/obj/singularity,
|
||||
/obj/structure/lattice,
|
||||
/obj/structure/stone_tile,
|
||||
))
|
||||
|
||||
/datum/component/chasm/Initialize(turf/target, mapload)
|
||||
|
||||
@@ -886,7 +886,7 @@ structure_check() searches for nearby cultist structures required for the invoca
|
||||
new_human.equipOutfit(/datum/outfit/ghost_cultist) //give them armor
|
||||
new_human.apply_status_effect(/datum/status_effect/cultghost) //ghosts can't summon more ghosts
|
||||
new_human.set_invis_see(SEE_INVISIBLE_OBSERVER)
|
||||
ADD_TRAIT(new_human, TRAIT_NOBREATH, INNATE_TRAIT)
|
||||
new_human.add_traits(list(TRAIT_NOBREATH, TRAIT_PERMANENTLY_MORTAL), INNATE_TRAIT) // permanently mortal can be removed once this is a bespoke kind of mob
|
||||
ghosts++
|
||||
playsound(src, 'sound/magic/exit_blood.ogg', 50, TRUE)
|
||||
visible_message(span_warning("A cloud of red mist forms above [src], and from within steps... a [new_human.gender == FEMALE ? "wo":""]man."))
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
/// Open all of the doors
|
||||
/datum/grand_finale/all_access
|
||||
name = "Connection"
|
||||
desc = "The ultimate use of your gathered power! Unlock every single door that they have! Nobody will be able to keep you out now, or anyone else for that matter!"
|
||||
icon = 'icons/mob/actions/actions_spells.dmi'
|
||||
icon_state = "knock"
|
||||
|
||||
/datum/grand_finale/all_access/trigger(mob/living/carbon/human/invoker)
|
||||
message_admins("[key_name(invoker)] removed all door access requirements")
|
||||
for(var/obj/machinery/door/target_door as anything in SSmachines.get_machines_by_type_and_subtypes(/obj/machinery/door))
|
||||
if(is_station_level(target_door.z))
|
||||
target_door.unlock()
|
||||
target_door.req_access = list()
|
||||
target_door.req_one_access = list()
|
||||
INVOKE_ASYNC(target_door, TYPE_PROC_REF(/obj/machinery/door/airlock, open))
|
||||
CHECK_TICK
|
||||
priority_announce("AULIE OXIN FIERA!!", null, 'sound/magic/knock.ogg', sender_override = "[invoker.real_name]")
|
||||
@@ -0,0 +1,60 @@
|
||||
#define DOOM_SINGULARITY "singularity"
|
||||
#define DOOM_TESLA "tesla"
|
||||
#define DOOM_METEORS "meteors"
|
||||
|
||||
/// Kill yourself and probably a bunch of other people
|
||||
/datum/grand_finale/armageddon
|
||||
name = "Annihilation"
|
||||
desc = "This crew have offended you beyond the realm of pranks. Make the ultimate sacrifice to teach them a lesson your elders can really respect. \
|
||||
YOU WILL NOT SURVIVE THIS."
|
||||
icon = 'icons/mob/simple/lavaland/lavaland_monsters.dmi'
|
||||
icon_state = "legion_head"
|
||||
minimum_time = 90 MINUTES // This will probably immediately end the round if it gets finished.
|
||||
ritual_invoke_time = 60 SECONDS // Really give the crew some time to interfere with this one.
|
||||
dire_warning = TRUE
|
||||
glow_colour = "#be000048"
|
||||
/// Things to yell before you die
|
||||
var/static/list/possible_last_words = list(
|
||||
"Flames and ruin!",
|
||||
"Dooooooooom!!",
|
||||
"HAHAHAHAHAHA!! AHAHAHAHAHAHAHAHAA!!",
|
||||
"Hee hee hee!! Hoo hoo hoo!! Ha ha haaa!!",
|
||||
"Ohohohohohoho!!",
|
||||
"Cower in fear, puny mortals!",
|
||||
"Tremble before my glory!",
|
||||
"Pick a god and pray!",
|
||||
"It's no use!",
|
||||
"If the gods wanted you to live, they would not have created me!",
|
||||
"God stays in heaven out of fear of what I have created!",
|
||||
"Ruination is come!",
|
||||
"All of creation, bend to my will!",
|
||||
)
|
||||
|
||||
/datum/grand_finale/armageddon/trigger(mob/living/carbon/human/invoker)
|
||||
priority_announce(pick(possible_last_words), null, 'sound/magic/voidblink.ogg', sender_override = "[invoker.real_name]")
|
||||
var/turf/current_location = get_turf(invoker)
|
||||
invoker.gib()
|
||||
|
||||
var/static/list/doom_options = list()
|
||||
if (!length(doom_options))
|
||||
doom_options = list(DOOM_SINGULARITY, DOOM_TESLA)
|
||||
if (!SSmapping.config.planetary)
|
||||
doom_options += DOOM_METEORS
|
||||
|
||||
switch(pick(doom_options))
|
||||
if (DOOM_SINGULARITY)
|
||||
var/obj/singularity/singulo = new(current_location)
|
||||
singulo.energy = 300
|
||||
if (DOOM_TESLA)
|
||||
var/obj/energy_ball/tesla = new (current_location)
|
||||
tesla.energy = 200
|
||||
if (DOOM_METEORS)
|
||||
var/datum/dynamic_ruleset/roundstart/meteor/meteors = new()
|
||||
meteors.meteordelay = 0
|
||||
var/datum/game_mode/dynamic/mode = SSticker.mode
|
||||
mode.execute_roundstart_rule(meteors) // Meteors will continue until morale is crushed.
|
||||
priority_announce("Meteors have been detected on collision course with the station.", "Meteor Alert", ANNOUNCER_METEORS)
|
||||
|
||||
#undef DOOM_SINGULARITY
|
||||
#undef DOOM_TESLA
|
||||
#undef DOOM_METEORS
|
||||
@@ -0,0 +1,113 @@
|
||||
/// Become the official Captain of the station
|
||||
/datum/grand_finale/usurp
|
||||
name = "Usurpation"
|
||||
desc = "The ultimate use of your gathered power! Rewrite time such that you have been Captain of this station the whole time."
|
||||
icon = 'icons/obj/card.dmi'
|
||||
icon_state = "card_gold"
|
||||
|
||||
/datum/grand_finale/usurp/trigger(mob/living/carbon/human/invoker)
|
||||
message_admins("[key_name(invoker)] has replaced the Captain")
|
||||
var/list/former_captains = list()
|
||||
var/list/other_crew = list()
|
||||
SEND_SOUND(world, sound('sound/magic/timeparadox2.ogg'))
|
||||
|
||||
for (var/mob/living/carbon/human/crewmate as anything in GLOB.human_list)
|
||||
if (!crewmate.mind)
|
||||
continue
|
||||
crewmate.Unconscious(3 SECONDS) // Everyone falls unconscious but not everyone gets told about a new captain
|
||||
if (crewmate == invoker || IS_HUMAN_INVADER(crewmate))
|
||||
continue
|
||||
to_chat(crewmate, span_notice("The world spins and dissolves. Your past flashes before your eyes, backwards.\n\
|
||||
Life strolls back into the ocean and shrinks into nothingness, planets explode into storms of solar dust, \
|
||||
the stars rush back to greet each other at the beginning of things and then... you snap back to the present. \n\
|
||||
Everything is just as it was and always has been. \n\n\
|
||||
A stray thought sticks in the forefront of your mind. \n\
|
||||
[span_hypnophrase("I'm so glad that [invoker.real_name] is our legally appointed Captain!")] \n\
|
||||
Is... that right?"))
|
||||
if (is_captain_job(crewmate.mind.assigned_role))
|
||||
former_captains += crewmate
|
||||
demote_to_assistant(crewmate)
|
||||
continue
|
||||
if (crewmate.stat != DEAD)
|
||||
other_crew += crewmate
|
||||
|
||||
dress_candidate(invoker)
|
||||
GLOB.manifest.modify(invoker.real_name, JOB_CAPTAIN, JOB_CAPTAIN)
|
||||
minor_announce("Captain [invoker.real_name] on deck!")
|
||||
|
||||
// Enlist some crew to try and restore the natural order
|
||||
for (var/mob/living/carbon/human/former_captain as anything in former_captains)
|
||||
create_vendetta(former_captain.mind, invoker.mind)
|
||||
for (var/mob/living/carbon/human/random_crewmate as anything in other_crew)
|
||||
if (prob(10))
|
||||
create_vendetta(random_crewmate.mind, invoker.mind)
|
||||
|
||||
/**
|
||||
* Anyone who thought they were Captain is in for a nasty surprise, and won't be very happy about it
|
||||
*/
|
||||
/datum/grand_finale/usurp/proc/demote_to_assistant(mob/living/carbon/human/former_captain)
|
||||
var/obj/effect/particle_effect/fluid/smoke/exit_poof = new(get_turf(former_captain))
|
||||
exit_poof.lifetime = 2 SECONDS
|
||||
|
||||
former_captain.unequip_everything()
|
||||
if(isplasmaman(former_captain))
|
||||
former_captain.equipOutfit(/datum/outfit/plasmaman)
|
||||
former_captain.internal = former_captain.get_item_for_held_index(2)
|
||||
else
|
||||
former_captain.equipOutfit(/datum/outfit/job/assistant)
|
||||
|
||||
GLOB.manifest.modify(former_captain.real_name, JOB_ASSISTANT, JOB_ASSISTANT)
|
||||
var/list/valid_turfs = list()
|
||||
// Used to be into prison but that felt a bit too mean
|
||||
for (var/turf/exile_turf as anything in get_area_turfs(/area/station/maintenance, subtypes = TRUE))
|
||||
if (isspaceturf(exile_turf) || exile_turf.is_blocked_turf())
|
||||
continue
|
||||
valid_turfs += exile_turf
|
||||
do_teleport(former_captain, pick(valid_turfs), no_effects = TRUE)
|
||||
var/obj/effect/particle_effect/fluid/smoke/enter_poof = new(get_turf(former_captain))
|
||||
enter_poof.lifetime = 2 SECONDS
|
||||
|
||||
/**
|
||||
* Does some item juggling to try to dress you as both a Wizard and Captain without deleting any items you have bought.
|
||||
* ID, headset, and uniform are forcibly replaced. Other slots are only filled if unoccupied.
|
||||
* We could forcibly replace shoes and gloves too but people might miss their insuls or... meown shoes?
|
||||
*/
|
||||
/datum/grand_finale/usurp/proc/dress_candidate(mob/living/carbon/human/invoker)
|
||||
// Won't be needing these
|
||||
var/obj/id = invoker.get_item_by_slot(ITEM_SLOT_ID)
|
||||
QDEL_NULL(id)
|
||||
var/obj/headset = invoker.get_item_by_slot(ITEM_SLOT_EARS)
|
||||
QDEL_NULL(headset)
|
||||
// We're about to take off your pants so those are going to fall out
|
||||
var/obj/item/pocket_L = invoker.get_item_by_slot(ITEM_SLOT_LPOCKET)
|
||||
var/obj/item/pocket_R = invoker.get_item_by_slot(ITEM_SLOT_RPOCKET)
|
||||
// In case we try to put a PDA there
|
||||
var/obj/item/belt = invoker.get_item_by_slot(ITEM_SLOT_BELT)
|
||||
belt?.moveToNullspace()
|
||||
|
||||
var/obj/pants = invoker.get_item_by_slot(ITEM_SLOT_ICLOTHING)
|
||||
QDEL_NULL(pants)
|
||||
invoker.equipOutfit(/datum/outfit/job/wizard_captain)
|
||||
// And put everything back!
|
||||
equip_to_slot_then_hands(invoker, ITEM_SLOT_BELT, belt)
|
||||
equip_to_slot_then_hands(invoker, ITEM_SLOT_LPOCKET, pocket_L)
|
||||
equip_to_slot_then_hands(invoker, ITEM_SLOT_RPOCKET, pocket_R)
|
||||
|
||||
/// An outfit which replaces parts of a wizard's clothes with captain's clothes but keeps the robes
|
||||
/datum/outfit/job/wizard_captain
|
||||
name = "Captain (Wizard Transformation)"
|
||||
jobtype = /datum/job/captain
|
||||
id = /obj/item/card/id/advanced/gold
|
||||
id_trim = /datum/id_trim/job/captain
|
||||
uniform = /obj/item/clothing/under/rank/captain/parade
|
||||
belt = /obj/item/modular_computer/pda/heads/captain
|
||||
ears = /obj/item/radio/headset/heads/captain/alt
|
||||
glasses = /obj/item/clothing/glasses/sunglasses
|
||||
gloves = /obj/item/clothing/gloves/captain
|
||||
shoes = /obj/item/clothing/shoes/laceup
|
||||
accessory = /obj/item/clothing/accessory/medal/gold/captain
|
||||
backpack_contents = list(
|
||||
/obj/item/melee/baton/telescopic = 1,
|
||||
/obj/item/station_charter = 1,
|
||||
)
|
||||
box = null
|
||||
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* Gives the wizard a defensive/mood buff and a Wabbajack, a juiced up chaos staff that will surely break something.
|
||||
* Everyone but the wizard goes crazy, suffers major brain damage, and is given a vendetta against the wizard.
|
||||
* Already insane people are instead cured of their madness, ignoring any other effects as the station around them loses its marbles.
|
||||
*/
|
||||
/datum/grand_finale/cheese
|
||||
// we don't set name, desc and others, thus we won't appear in the radial choice of a normal finale rune
|
||||
dire_warning = TRUE
|
||||
minimum_time = 45 MINUTES //i'd imagine speedrunning this would be crummy, but the wizard's average lifespan is barely reaching this point
|
||||
|
||||
/datum/grand_finale/cheese/trigger(mob/living/invoker)
|
||||
message_admins("[key_name(invoker)] has summoned forth The Wabbajack and cursed the crew with madness!")
|
||||
priority_announce("Danger: Extremely potent reality altering object has been summoned on station. Immediate evacuation advised. Brace for impact.", "Central Command Higher Dimensional Affairs", 'sound/effects/glassbr1.ogg')
|
||||
|
||||
for (var/mob/living/carbon/human/crewmate as anything in GLOB.human_list)
|
||||
if (isnull(crewmate.mind))
|
||||
continue
|
||||
if (crewmate == invoker) //everyone but the wizard is royally fucked, no matter who they are
|
||||
continue
|
||||
if (crewmate.has_trauma_type(/datum/brain_trauma/mild/hallucinations)) //for an already insane person, this is retribution
|
||||
to_chat(crewmate, span_boldwarning("Your surroundings suddenly fill with a cacophony of manic laughter and psychobabble..."))
|
||||
to_chat(crewmate, span_nicegreen("...but as the moment passes, you realise that whatever eldritch power behind the event happened to affect you \
|
||||
has resonated within the ruins of your already shattered mind, creating a singularity of mental instability! \
|
||||
As it collapses unto itself, you feel... at peace, finally."))
|
||||
if(crewmate.has_quirk(/datum/quirk/insanity))
|
||||
crewmate.remove_quirk(/datum/quirk/insanity)
|
||||
else
|
||||
crewmate.cure_trauma_type(/datum/brain_trauma/mild/hallucinations, TRAUMA_RESILIENCE_ABSOLUTE)
|
||||
else
|
||||
//everyone else gets to relish in madness
|
||||
//yes killing their mood will also trigger mood hallucinations
|
||||
create_vendetta(crewmate.mind, invoker.mind)
|
||||
to_chat(crewmate, span_boldwarning("Your surroundings suddenly fill with a cacophony of manic laughter and psychobabble. \n\
|
||||
You feel your inner psyche shatter into a myriad pieces of jagged glass of colors unknown to the universe, \
|
||||
infinitely reflecting a blinding, maddening light coming from the innermost sanctums of your destroyed mind. \n\
|
||||
After a brief pause which felt like a millenia, one phrase rebounds ceaselessly in your head, imbued with the false hope of absolution... \n\
|
||||
<b>[invoker] must die.</b>"))
|
||||
var/datum/brain_trauma/mild/hallucinations/added_trauma = new()
|
||||
added_trauma.resilience = TRAUMA_RESILIENCE_ABSOLUTE
|
||||
crewmate.adjustOrganLoss(ORGAN_SLOT_BRAIN, BRAIN_DAMAGE_DEATH - 25, BRAIN_DAMAGE_DEATH - 25) //you'd better hope chap didn't pick a hypertool
|
||||
crewmate.gain_trauma(added_trauma)
|
||||
crewmate.add_mood_event("wizard_ritual_finale", /datum/mood_event/madness_despair)
|
||||
|
||||
//drip our wizard out
|
||||
invoker.apply_status_effect(/datum/status_effect/blessing_of_insanity)
|
||||
invoker.add_mood_event("wizard_ritual_finale", /datum/mood_event/madness_elation)
|
||||
var/obj/item/gun/magic/staff/chaos/true_wabbajack/the_wabbajack = new
|
||||
invoker.put_in_active_hand(the_wabbajack)
|
||||
to_chat(invoker, span_mind_control("Your every single instinct and rational thought is screaming at you as [the_wabbajack] appears in your firm grip..."))
|
||||
@@ -0,0 +1,76 @@
|
||||
/// Dress the crew as magical clowns
|
||||
/datum/grand_finale/clown
|
||||
name = "Jubilation"
|
||||
desc = "The ultimate use of your gathered power! Rewrite time so that everyone went to clown college! Now they'll prank each other for you!"
|
||||
icon = 'icons/obj/clothing/masks.dmi'
|
||||
icon_state = "clown"
|
||||
glow_colour = "#ffff0048"
|
||||
|
||||
/datum/grand_finale/clown/trigger(mob/living/carbon/human/invoker)
|
||||
for(var/mob/living/carbon/human/victim as anything in GLOB.human_list)
|
||||
victim.Unconscious(3 SECONDS)
|
||||
if (!victim.mind || IS_HUMAN_INVADER(victim) || victim == invoker)
|
||||
continue
|
||||
if (HAS_TRAIT(victim, TRAIT_CLOWN_ENJOYER))
|
||||
victim.add_mood_event("clown_world", /datum/mood_event/clown_world)
|
||||
to_chat(victim, span_notice("The world spins and dissolves. Your past flashes before your eyes, backwards.\n\
|
||||
Life strolls back into the ocean and shrinks into nothingness, planets explode into storms of solar dust, \
|
||||
the stars rush back to greet each other at the beginning of things and then... you snap back to the present. \n\
|
||||
Everything is just as it was and always has been. \n\n\
|
||||
A stray thought sticks in the forefront of your mind. \n\
|
||||
[span_hypnophrase("I'm so glad that I work at Clown Research Station [station_name()]!")] \n\
|
||||
Is... that right?"))
|
||||
if (is_clown_job(victim.mind.assigned_role))
|
||||
var/datum/action/cooldown/spell/conjure_item/clown_pockets/new_spell = new(victim)
|
||||
new_spell.Grant(victim)
|
||||
continue
|
||||
if (!ismonkey(victim)) // Monkeys cannot yet wear clothes
|
||||
dress_as_magic_clown(victim)
|
||||
if (prob(15))
|
||||
create_vendetta(victim.mind, invoker.mind)
|
||||
|
||||
/**
|
||||
* Clown enjoyers who are effected by this become ecstatic, they have achieved their life's dream.
|
||||
* This moodlet is equivalent to the one for simply being a traitor.
|
||||
*/
|
||||
/datum/mood_event/clown_world
|
||||
mood_change = 4
|
||||
|
||||
/datum/mood_event/clown_world/add_effects(param)
|
||||
description = "I LOVE working at Clown Research Station [station_name()]!!"
|
||||
|
||||
/// Dress the passed mob as a magical clown, self-explanatory
|
||||
/datum/grand_finale/clown/proc/dress_as_magic_clown(mob/living/carbon/human/victim)
|
||||
var/obj/effect/particle_effect/fluid/smoke/poof = new(get_turf(victim))
|
||||
poof.lifetime = 2 SECONDS
|
||||
|
||||
var/obj/item/tank/internal = victim.internal
|
||||
// We're about to take off your pants so those are going to fall out
|
||||
var/obj/item/pocket_L = victim.get_item_by_slot(ITEM_SLOT_LPOCKET)
|
||||
var/obj/item/pocket_R = victim.get_item_by_slot(ITEM_SLOT_RPOCKET)
|
||||
var/obj/item/id = victim.get_item_by_slot(ITEM_SLOT_ID)
|
||||
var/obj/item/belt = victim.get_item_by_slot(ITEM_SLOT_BELT)
|
||||
|
||||
var/obj/pants = victim.get_item_by_slot(ITEM_SLOT_ICLOTHING)
|
||||
var/obj/mask = victim.get_item_by_slot(ITEM_SLOT_MASK)
|
||||
QDEL_NULL(pants)
|
||||
QDEL_NULL(mask)
|
||||
if(isplasmaman(victim))
|
||||
victim.equip_to_slot_if_possible(new /obj/item/clothing/under/plasmaman/clown/magic(), ITEM_SLOT_ICLOTHING, disable_warning = TRUE)
|
||||
victim.equip_to_slot_if_possible(new /obj/item/clothing/mask/gas/clown_hat/plasmaman(), ITEM_SLOT_MASK, disable_warning = TRUE)
|
||||
else
|
||||
victim.equip_to_slot_if_possible(new /obj/item/clothing/under/rank/civilian/clown/magic(), ITEM_SLOT_ICLOTHING, disable_warning = TRUE)
|
||||
victim.equip_to_slot_if_possible(new /obj/item/clothing/mask/gas/clown_hat(), ITEM_SLOT_MASK, disable_warning = TRUE)
|
||||
|
||||
var/obj/item/clothing/mask/gas/clown_hat/clown_mask = victim.get_item_by_slot(ITEM_SLOT_MASK)
|
||||
if (clown_mask)
|
||||
var/list/options = GLOB.clown_mask_options
|
||||
clown_mask.icon_state = options[pick(clown_mask.clownmask_designs)]
|
||||
victim.update_worn_mask()
|
||||
clown_mask.update_item_action_buttons()
|
||||
|
||||
equip_to_slot_then_hands(victim, ITEM_SLOT_LPOCKET, pocket_L)
|
||||
equip_to_slot_then_hands(victim, ITEM_SLOT_RPOCKET, pocket_R)
|
||||
equip_to_slot_then_hands(victim, ITEM_SLOT_ID, id)
|
||||
equip_to_slot_then_hands(victim, ITEM_SLOT_BELT, belt)
|
||||
victim.internal = internal
|
||||
@@ -0,0 +1,88 @@
|
||||
/**
|
||||
* A big final event to run when you complete seven rituals
|
||||
*/
|
||||
/datum/grand_finale
|
||||
/// Friendly name for selection menu
|
||||
var/name
|
||||
/// Tooltip description for selection menu
|
||||
var/desc
|
||||
/// An icon to display to represent the choice
|
||||
var/icon/icon
|
||||
/// Icon state to use to represent the choice
|
||||
var/icon_state
|
||||
/// Prevent especially dangerous options from being chosen until we're fine with the round ending
|
||||
var/minimum_time = 0
|
||||
/// Override the rune invocation time
|
||||
var/ritual_invoke_time = 30 SECONDS
|
||||
/// Provide an extremely loud radio message when this one starts
|
||||
var/dire_warning = FALSE
|
||||
/// Overrides the default colour you glow while channeling the rune, optional
|
||||
var/glow_colour
|
||||
|
||||
/**
|
||||
* Returns an entry for a radial menu for this choice.
|
||||
* Returns null if entry is abstract or invalid for current circumstances.
|
||||
*/
|
||||
/datum/grand_finale/proc/get_radial_choice()
|
||||
if (!name || !desc || !icon || !icon_state)
|
||||
return
|
||||
var/time_remaining_desc = ""
|
||||
if (minimum_time >= world.time - SSticker.round_start_time)
|
||||
time_remaining_desc = "<i>This ritual will be available to begin invoking in [DisplayTimeText(minimum_time - world.time - SSticker.round_start_time)]</i>"
|
||||
var/datum/radial_menu_choice/choice = new()
|
||||
choice.name = name
|
||||
choice.image = image(icon = icon, icon_state = icon_state)
|
||||
choice.info = desc + time_remaining_desc
|
||||
return choice
|
||||
|
||||
/**
|
||||
* Actually do the thing.
|
||||
* Arguments
|
||||
* * invoker - The wizard casting this.
|
||||
*/
|
||||
/datum/grand_finale/proc/trigger(mob/living/invoker)
|
||||
// Do something cool.
|
||||
|
||||
/// Tries to equip something into an inventory slot, then hands, then the floor.
|
||||
/datum/grand_finale/proc/equip_to_slot_then_hands(mob/living/carbon/human/invoker, slot, obj/item/item)
|
||||
if(!item)
|
||||
return
|
||||
if(!invoker.equip_to_slot_if_possible(item, slot, disable_warning = TRUE))
|
||||
invoker.put_in_hands(item)
|
||||
|
||||
/// They are not going to take this lying down.
|
||||
/datum/grand_finale/proc/create_vendetta(datum/mind/aggrieved_crewmate, datum/mind/wizard)
|
||||
aggrieved_crewmate.add_antag_datum(/datum/antagonist/wizard_prank_vendetta)
|
||||
var/datum/antagonist/wizard_prank_vendetta/antag_datum = aggrieved_crewmate.has_antag_datum(/datum/antagonist/wizard_prank_vendetta)
|
||||
var/datum/objective/assassinate/wizard_murder = new
|
||||
wizard_murder.owner = aggrieved_crewmate
|
||||
wizard_murder.target = wizard
|
||||
wizard_murder.explanation_text = "Kill [wizard.current.name], the one who did this."
|
||||
antag_datum.objectives += wizard_murder
|
||||
|
||||
to_chat(aggrieved_crewmate.current, span_warning("No! This isn't right!"))
|
||||
aggrieved_crewmate.announce_objectives()
|
||||
|
||||
/**
|
||||
* Antag datum to give to people who want to kill the wizard.
|
||||
* This doesn't preclude other people choosing to want to kill the wizard, just these people are rewarded for it.
|
||||
*/
|
||||
/datum/antagonist/wizard_prank_vendetta
|
||||
name = "\improper Wizard Prank Victim"
|
||||
roundend_category = "wizard prank victims"
|
||||
show_in_antagpanel = FALSE
|
||||
antagpanel_category = "Other"
|
||||
show_name_in_check_antagonists = TRUE
|
||||
count_against_dynamic_roll_chance = FALSE
|
||||
silent = TRUE
|
||||
|
||||
/// Give everyone magic items, its so simple it feels pointless to give it its own file
|
||||
/datum/grand_finale/magic
|
||||
name = "Evolution"
|
||||
desc = "The ultimate use of your gathered power! Give the crew their own magic, they'll surely realise that right and wrong have no meaning when you hold ultimate power!"
|
||||
icon = 'icons/obj/scrolls.dmi'
|
||||
icon_state = "scroll"
|
||||
|
||||
/datum/grand_finale/magic/trigger(mob/living/carbon/human/invoker)
|
||||
message_admins("[key_name(invoker)] summoned magic")
|
||||
summon_magic(survivor_probability = 20) // Wow, this one was easy!
|
||||
@@ -0,0 +1,277 @@
|
||||
/// Amount of time to wait after someone dies to steal their body from their killers
|
||||
#define IMMORTAL_PRE_ACTIVATION_TIME 10 SECONDS
|
||||
/// Amount of time it takes a mob to return to the living world
|
||||
#define IMMORTAL_RESURRECT_TIME 50 SECONDS
|
||||
|
||||
/**
|
||||
* Nobody will ever die ever again
|
||||
* Or if they do, they will be back
|
||||
*/
|
||||
/datum/grand_finale/immortality
|
||||
name = "Perpetuation"
|
||||
desc = "The ultimate use of your gathered power! Share with the crew the gift, or curse, of eternal life! \
|
||||
And why not just the crew? How about their pets too? And any other animals around here! \
|
||||
What if nobody died ever again!?"
|
||||
icon = 'icons/obj/mining_zones/artefacts.dmi'
|
||||
icon_state = "asclepius_active"
|
||||
glow_colour = COLOR_PALE_GREEN
|
||||
minimum_time = 30 MINUTES // This is enormously disruptive but doesn't technically in of itself end the round.
|
||||
|
||||
/datum/grand_finale/immortality/trigger(mob/living/carbon/human/invoker)
|
||||
new /obj/effect/temp_visual/immortality_blast(get_turf(invoker))
|
||||
SEND_SOUND(world, sound('sound/magic/teleport_diss.ogg'))
|
||||
for (var/mob/living/alive_guy as anything in GLOB.mob_living_list)
|
||||
new /obj/effect/temp_visual/immortality_pulse(get_turf(alive_guy))
|
||||
if (!alive_guy.mind)
|
||||
continue
|
||||
to_chat(alive_guy, span_notice("You feel <b>extremely</b> healthy."))
|
||||
RegisterSignal(SSdcs, COMSIG_GLOB_MOB_DEATH, PROC_REF(something_died))
|
||||
|
||||
/// Called when something passes into the great beyond, make it not do that
|
||||
/datum/grand_finale/immortality/proc/something_died(datum/source, mob/living/died, gibbed)
|
||||
SIGNAL_HANDLER
|
||||
if (died.stat != DEAD || HAS_TRAIT(died, TRAIT_PERMANENTLY_MORTAL) || died.flags_1 & HOLOGRAM_1)
|
||||
return
|
||||
var/body_type = died.type
|
||||
|
||||
var/turf/died_turf = get_turf(died)
|
||||
var/list/nearby_turfs = circle_view_turfs(died_turf, 2)
|
||||
var/list/nearby_safe_turfs = list()
|
||||
for (var/turf/check_turf as anything in nearby_turfs)
|
||||
if (check_turf.is_blocked_turf(exclude_mobs = TRUE, source_atom = died))
|
||||
nearby_turfs -= check_turf
|
||||
continue
|
||||
if (islava(check_turf) || ischasm(check_turf))
|
||||
continue
|
||||
nearby_safe_turfs += check_turf
|
||||
if (length(nearby_safe_turfs)) // If you're in the middle of a 5x5 chasm, tough luck I guess
|
||||
died_turf = pick(nearby_safe_turfs)
|
||||
else if (length(nearby_turfs))
|
||||
died_turf = pick(nearby_turfs)
|
||||
|
||||
var/saved_appearance = ishuman(died) ? new /datum/human_appearance_profile(died) : null
|
||||
|
||||
var/datum/mind/dead_mind = HAS_TRAIT(died, TRAIT_SUICIDED) ? null : died.mind // There is a way out of the cycle
|
||||
if (!isnull(dead_mind))
|
||||
to_chat(died, span_boldnotice("Your spirit surges! You will return to life in [DisplayTimeText(IMMORTAL_PRE_ACTIVATION_TIME + IMMORTAL_RESURRECT_TIME)]."))
|
||||
animate(died, alpha = died.alpha, time = IMMORTAL_PRE_ACTIVATION_TIME / 2, flags = ANIMATION_PARALLEL)
|
||||
animate(alpha = 0, time = IMMORTAL_PRE_ACTIVATION_TIME / 2, easing = SINE_EASING | EASE_IN)
|
||||
addtimer(CALLBACK(src, PROC_REF(reverse_death), died, dead_mind, died_turf, body_type, saved_appearance), IMMORTAL_PRE_ACTIVATION_TIME, TIMER_DELETE_ME)
|
||||
|
||||
/// Create a ghost ready for revival
|
||||
/datum/grand_finale/immortality/proc/reverse_death(mob/living/died, datum/mind/dead_mind, turf/died_turf, body_type, datum/human_appearance_profile/human_appearance)
|
||||
if (died.stat != DEAD)
|
||||
return
|
||||
var/ghost_type = ispath(body_type, /mob/living/carbon/human) ? /obj/effect/spectre_of_resurrection/human : /obj/effect/spectre_of_resurrection
|
||||
var/obj/effect/spectre_of_resurrection/ghost = new ghost_type(died_turf)
|
||||
var/mob/living/corpse = QDELETED(died) ? new body_type(ghost) : died
|
||||
if (!isnull(human_appearance))
|
||||
corpse.real_name = human_appearance.name
|
||||
corpse.alpha = initial(corpse.alpha)
|
||||
corpse.add_traits(list(TRAIT_NO_TELEPORT, TRAIT_AI_PAUSED), MAGIC_TRAIT)
|
||||
corpse.apply_status_effect(/datum/status_effect/grouped/stasis, MAGIC_TRAIT)
|
||||
ghost.set_up_resurrection(corpse, dead_mind, human_appearance)
|
||||
|
||||
|
||||
/// Store of data we use to recreate someone who was gibbed, like a simplified version of changeling profiles
|
||||
/datum/human_appearance_profile
|
||||
/// The name of the profile / the name of whoever this profile source.
|
||||
var/name = "human"
|
||||
/// The DNA datum associated with our profile from the profile source
|
||||
var/datum/dna/dna
|
||||
/// The age of the profile source.
|
||||
var/age
|
||||
/// The body type of the profile source.
|
||||
var/physique
|
||||
/// The quirks of the profile source.
|
||||
var/list/quirks = list()
|
||||
/// The hair and facial hair gradient styles of the profile source.
|
||||
var/list/hair_gradient_style = list("None", "None")
|
||||
/// The hair and facial hair gradient colours of the profile source.
|
||||
var/list/hair_gradient_colours = list(null, null)
|
||||
/// The TTS voice of the profile source
|
||||
var/voice
|
||||
/// The TTS filter of the profile filter
|
||||
var/voice_filter = ""
|
||||
|
||||
/datum/human_appearance_profile/New(mob/living/carbon/human/target)
|
||||
copy_from(target)
|
||||
|
||||
/// Copy the appearance data of the target
|
||||
/datum/human_appearance_profile/proc/copy_from(mob/living/carbon/human/target)
|
||||
target.dna.real_name = target.real_name
|
||||
dna = new target.dna.type()
|
||||
target.dna.copy_dna(dna)
|
||||
name = target.real_name
|
||||
age = target.age
|
||||
physique = target.physique
|
||||
|
||||
for(var/datum/quirk/target_quirk as anything in target.quirks)
|
||||
LAZYADD(quirks, new target_quirk.type)
|
||||
|
||||
hair_gradient_style = LAZYLISTDUPLICATE(target.grad_style)
|
||||
hair_gradient_colours = LAZYLISTDUPLICATE(target.grad_color)
|
||||
|
||||
voice = target.voice
|
||||
voice_filter = target.voice_filter
|
||||
|
||||
/// Make the targetted human look like this
|
||||
/datum/human_appearance_profile/proc/apply_to(mob/living/carbon/human/target)
|
||||
target.real_name = name
|
||||
target.age = age
|
||||
target.physique = physique
|
||||
target.grad_style = LAZYLISTDUPLICATE(hair_gradient_style)
|
||||
target.grad_color = LAZYLISTDUPLICATE(hair_gradient_colours)
|
||||
target.voice = voice
|
||||
target.voice_filter = voice_filter
|
||||
|
||||
for(var/datum/quirk/target_quirk as anything in quirks)
|
||||
target_quirk.add_to_holder(target)
|
||||
|
||||
dna.transfer_identity(target, TRUE)
|
||||
for(var/obj/item/bodypart/limb as anything in target.bodyparts)
|
||||
limb.update_limb(is_creating = TRUE)
|
||||
target.updateappearance(mutcolor_update = TRUE)
|
||||
target.domutcheck()
|
||||
target.regenerate_icons()
|
||||
|
||||
|
||||
/// A ghostly image of a mob showing where and what is going to respawn
|
||||
/obj/effect/spectre_of_resurrection
|
||||
name = "spectre"
|
||||
desc = "A frightening apparition, slowly growing more solid."
|
||||
icon_state = "blank_white"
|
||||
anchored = TRUE
|
||||
layer = MOB_LAYER
|
||||
plane = GAME_PLANE
|
||||
alpha = 0
|
||||
color = COLOR_PALE_GREEN
|
||||
light_range = 2
|
||||
light_color = COLOR_PALE_GREEN
|
||||
/// Who are we reviving?
|
||||
var/mob/living/corpse
|
||||
/// Who if anyone is playing as them?
|
||||
var/datum/mind/dead_mind
|
||||
|
||||
/obj/effect/spectre_of_resurrection/Initialize(mapload)
|
||||
. = ..()
|
||||
animate(src, alpha = 150, time = 2 SECONDS)
|
||||
|
||||
/// Prepare to revive someone
|
||||
/obj/effect/spectre_of_resurrection/proc/set_up_resurrection(mob/living/corpse, datum/mind/dead_mind, datum/human_appearance_profile/human_appearance)
|
||||
if (isnull(corpse))
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
src.corpse = corpse
|
||||
src.dead_mind = dead_mind
|
||||
corpse.forceMove(src)
|
||||
name = "spectre of [corpse]"
|
||||
setup_icon(corpse)
|
||||
DO_FLOATING_ANIM(src)
|
||||
|
||||
RegisterSignal(corpse, COMSIG_LIVING_REVIVE, PROC_REF(on_corpse_revived))
|
||||
RegisterSignal(corpse, COMSIG_QDELETING, PROC_REF(on_corpse_deleted))
|
||||
RegisterSignal(dead_mind, COMSIG_QDELETING, PROC_REF(on_mind_lost))
|
||||
addtimer(CALLBACK(src, PROC_REF(revive)), IMMORTAL_RESURRECT_TIME, TIMER_DELETE_ME)
|
||||
|
||||
/// Copy appearance from ressurecting mob
|
||||
/obj/effect/spectre_of_resurrection/proc/setup_icon(mob/living/corpse)
|
||||
icon = initial(corpse.icon)
|
||||
icon_state = initial(corpse.icon_state)
|
||||
|
||||
/obj/effect/spectre_of_resurrection/Destroy(force)
|
||||
QDEL_NULL(corpse)
|
||||
dead_mind = null
|
||||
return ..()
|
||||
|
||||
/obj/effect/spectre_of_resurrection/Exited(atom/movable/gone, direction)
|
||||
. = ..()
|
||||
if (gone != corpse)
|
||||
return // Weird but ok
|
||||
UnregisterSignal(corpse, list(COMSIG_LIVING_REVIVE, COMSIG_QDELETING))
|
||||
corpse = null
|
||||
qdel(src)
|
||||
|
||||
/// Bring our body back to life
|
||||
/obj/effect/spectre_of_resurrection/proc/revive()
|
||||
if (!isnull(dead_mind))
|
||||
if (dead_mind.current == corpse)
|
||||
dead_mind.grab_ghost(force = TRUE)
|
||||
else
|
||||
dead_mind.transfer_to(corpse, force_key_move = TRUE)
|
||||
corpse.revive(HEAL_ALL) // The signal is sent even if they weren't actually dead
|
||||
|
||||
/// Remove our stored corpse back to the living world
|
||||
/obj/effect/spectre_of_resurrection/proc/on_corpse_revived()
|
||||
SIGNAL_HANDLER
|
||||
if (isnull(corpse))
|
||||
return
|
||||
visible_message(span_boldnotice("[corpse] suddenly shudders to life!"))
|
||||
corpse.remove_traits(list(TRAIT_NO_TELEPORT, TRAIT_AI_PAUSED), MAGIC_TRAIT)
|
||||
corpse.remove_status_effect(/datum/status_effect/grouped/stasis, MAGIC_TRAIT)
|
||||
corpse.forceMove(loc)
|
||||
|
||||
/// If the body is destroyed then we can't come back, F
|
||||
/obj/effect/spectre_of_resurrection/proc/on_corpse_deleted()
|
||||
SIGNAL_HANDLER
|
||||
qdel(src)
|
||||
|
||||
/// If the mind is deleted somehow we just don't transfer it on revival
|
||||
/obj/effect/spectre_of_resurrection/proc/on_mind_lost()
|
||||
SIGNAL_HANDLER
|
||||
dead_mind = null
|
||||
|
||||
/// A ressurection spectre with extra behaviour for humans
|
||||
/obj/effect/spectre_of_resurrection/human
|
||||
/// Stored data used to restore someone to a fascimile of what they were before
|
||||
var/datum/human_appearance_profile/human_appearance
|
||||
|
||||
/obj/effect/spectre_of_resurrection/human/set_up_resurrection(mob/living/corpse, datum/mind/dead_mind, datum/human_appearance_profile/human_appearance)
|
||||
. = ..()
|
||||
src.human_appearance = human_appearance
|
||||
|
||||
// We just use a generic floating human appearance to save unecessary costly icon operations
|
||||
/obj/effect/spectre_of_resurrection/human/setup_icon(mob/living/corpse)
|
||||
return
|
||||
|
||||
// Apply stored human details
|
||||
/obj/effect/spectre_of_resurrection/human/on_corpse_revived()
|
||||
if (isnull(corpse))
|
||||
return
|
||||
human_appearance?.apply_to(corpse)
|
||||
return ..()
|
||||
|
||||
|
||||
/// Visual flair on the wizard when cast
|
||||
/obj/effect/temp_visual/immortality_blast
|
||||
name = "immortal wave"
|
||||
duration = 2.5 SECONDS
|
||||
icon = 'icons/effects/96x96.dmi'
|
||||
icon_state = "boh_tear"
|
||||
color = COLOR_PALE_GREEN
|
||||
pixel_x = -32
|
||||
pixel_y = -32
|
||||
|
||||
/obj/effect/temp_visual/immortality_blast/Initialize(mapload)
|
||||
. = ..()
|
||||
transform *= 0
|
||||
animate(src, transform = matrix(), time = 1.5 SECONDS, easing = ELASTIC_EASING)
|
||||
animate(transform = matrix() * 3, time = 1 SECONDS, alpha = 0, easing = SINE_EASING | EASE_OUT)
|
||||
|
||||
|
||||
/// Visual flair on living creatures who have become immortal
|
||||
/obj/effect/temp_visual/immortality_pulse
|
||||
name = "immortal pulse"
|
||||
duration = 1 SECONDS
|
||||
icon = 'icons/effects/anomalies.dmi'
|
||||
icon_state = "dimensional_overlay"
|
||||
color = COLOR_PALE_GREEN
|
||||
|
||||
/obj/effect/temp_visual/immortality_pulse/Initialize(mapload)
|
||||
. = ..()
|
||||
transform *= 0
|
||||
animate(src, transform = matrix() * 1.5, alpha = 0, time = 1 SECONDS, easing = SINE_EASING | EASE_OUT)
|
||||
|
||||
#undef IMMORTAL_PRE_ACTIVATION_TIME
|
||||
#undef IMMORTAL_RESURRECT_TIME
|
||||
@@ -0,0 +1,46 @@
|
||||
/// Completely transform the station
|
||||
/datum/grand_finale/midas
|
||||
name = "Transformation"
|
||||
desc = "The ultimate use of your gathered power! Turn their precious station into something much MORE precious, materially speaking!"
|
||||
icon = 'icons/obj/stack_objects.dmi'
|
||||
icon_state = "sheet-gold_2"
|
||||
glow_colour = "#dbdd4c48"
|
||||
var/static/list/permitted_transforms = list( // Non-dangerous only
|
||||
/datum/dimension_theme/gold,
|
||||
/datum/dimension_theme/meat,
|
||||
/datum/dimension_theme/pizza,
|
||||
/datum/dimension_theme/natural,
|
||||
)
|
||||
var/datum/dimension_theme/chosen_theme
|
||||
|
||||
// I sure hope this doesn't have performance implications
|
||||
/datum/grand_finale/midas/trigger(mob/living/carbon/human/invoker)
|
||||
var/theme_path = pick(permitted_transforms)
|
||||
chosen_theme = new theme_path()
|
||||
var/turf/start_turf = get_turf(invoker)
|
||||
var/greatest_dist = 0
|
||||
var/list/turfs_to_transform = list()
|
||||
for (var/turf/transform_turf as anything in GLOB.station_turfs)
|
||||
if (!chosen_theme.can_convert(transform_turf))
|
||||
continue
|
||||
var/dist = get_dist(start_turf, transform_turf)
|
||||
if (dist > greatest_dist)
|
||||
greatest_dist = dist
|
||||
if (!turfs_to_transform["[dist]"])
|
||||
turfs_to_transform["[dist]"] = list()
|
||||
turfs_to_transform["[dist]"] += transform_turf
|
||||
|
||||
if (chosen_theme.can_convert(start_turf))
|
||||
chosen_theme.apply_theme(start_turf)
|
||||
|
||||
for (var/iterator in 1 to greatest_dist)
|
||||
if(!turfs_to_transform["[iterator]"])
|
||||
continue
|
||||
addtimer(CALLBACK(src, PROC_REF(transform_area), turfs_to_transform["[iterator]"]), (5 SECONDS) * iterator)
|
||||
|
||||
/datum/grand_finale/midas/proc/transform_area(list/turfs)
|
||||
for (var/turf/transform_turf as anything in turfs)
|
||||
if (!chosen_theme.can_convert(transform_turf))
|
||||
continue
|
||||
chosen_theme.apply_theme(transform_turf)
|
||||
CHECK_TICK
|
||||
@@ -1,456 +0,0 @@
|
||||
#define DOOM_SINGULARITY "singularity"
|
||||
#define DOOM_TESLA "tesla"
|
||||
#define DOOM_METEORS "meteors"
|
||||
|
||||
/**
|
||||
* A big final event to run when you complete seven rituals
|
||||
*/
|
||||
/datum/grand_finale
|
||||
/// Friendly name for selection menu
|
||||
var/name
|
||||
/// Tooltip description for selection menu
|
||||
var/desc
|
||||
/// An icon to display to represent the choice
|
||||
var/icon/icon
|
||||
/// Icon state to use to represent the choice
|
||||
var/icon_state
|
||||
/// Prevent especially dangerous options from being chosen until we're fine with the round ending
|
||||
var/minimum_time = 0
|
||||
/// Override the rune invocation time
|
||||
var/ritual_invoke_time = 30 SECONDS
|
||||
/// Provide an extremely loud radio message when this one starts
|
||||
var/dire_warning = FALSE
|
||||
/// Overrides the default colour you glow while channeling the rune, optional
|
||||
var/glow_colour
|
||||
|
||||
/**
|
||||
* Returns an entry for a radial menu for this choice.
|
||||
* Returns null if entry is abstract or invalid for current circumstances.
|
||||
*/
|
||||
/datum/grand_finale/proc/get_radial_choice()
|
||||
if (!name || !desc || !icon || !icon_state)
|
||||
return
|
||||
var/time_remaining_desc = ""
|
||||
if (minimum_time >= world.time - SSticker.round_start_time)
|
||||
time_remaining_desc = "<i>This ritual will be available to begin invoking in [DisplayTimeText(minimum_time - world.time - SSticker.round_start_time)]</i>"
|
||||
var/datum/radial_menu_choice/choice = new()
|
||||
choice.name = name
|
||||
choice.image = image(icon = icon, icon_state = icon_state)
|
||||
choice.info = desc + time_remaining_desc
|
||||
return choice
|
||||
|
||||
/**
|
||||
* Actually do the thing.
|
||||
* Arguments
|
||||
* * invoker - The wizard casting this.
|
||||
*/
|
||||
/datum/grand_finale/proc/trigger(mob/living/invoker)
|
||||
// Do something cool.
|
||||
|
||||
/// Tries to equip something into an inventory slot, then hands, then the floor.
|
||||
/datum/grand_finale/proc/equip_to_slot_then_hands(mob/living/carbon/human/invoker, slot, obj/item/item)
|
||||
if(!item)
|
||||
return
|
||||
if(!invoker.equip_to_slot_if_possible(item, slot, disable_warning = TRUE))
|
||||
invoker.put_in_hands(item)
|
||||
|
||||
/// They are not going to take this lying down.
|
||||
/datum/grand_finale/proc/create_vendetta(datum/mind/aggrieved_crewmate, datum/mind/wizard)
|
||||
aggrieved_crewmate.add_antag_datum(/datum/antagonist/wizard_prank_vendetta)
|
||||
var/datum/antagonist/wizard_prank_vendetta/antag_datum = aggrieved_crewmate.has_antag_datum(/datum/antagonist/wizard_prank_vendetta)
|
||||
var/datum/objective/assassinate/wizard_murder = new
|
||||
wizard_murder.owner = aggrieved_crewmate
|
||||
wizard_murder.target = wizard
|
||||
wizard_murder.explanation_text = "Kill [wizard.current.name], the one who did this."
|
||||
antag_datum.objectives += wizard_murder
|
||||
|
||||
to_chat(aggrieved_crewmate.current, span_warning("No! This isn't right!"))
|
||||
aggrieved_crewmate.announce_objectives()
|
||||
|
||||
/**
|
||||
* Antag datum to give to people who want to kill the wizard.
|
||||
* This doesn't preclude other people choosing to want to kill the wizard, just these people are rewarded for it.
|
||||
*/
|
||||
/datum/antagonist/wizard_prank_vendetta
|
||||
name = "\improper Wizard Prank Victim"
|
||||
roundend_category = "wizard prank victims"
|
||||
show_in_antagpanel = FALSE
|
||||
antagpanel_category = "Other"
|
||||
show_name_in_check_antagonists = TRUE
|
||||
count_against_dynamic_roll_chance = FALSE
|
||||
silent = TRUE
|
||||
|
||||
/// Become the official Captain of the station
|
||||
/datum/grand_finale/usurp
|
||||
name = "Usurpation"
|
||||
desc = "The ultimate use of your gathered power! Rewrite time such that you have been Captain of this station the whole time."
|
||||
icon = 'icons/obj/card.dmi'
|
||||
icon_state = "card_gold"
|
||||
|
||||
/datum/grand_finale/usurp/trigger(mob/living/carbon/human/invoker)
|
||||
message_admins("[key_name(invoker)] has replaced the Captain")
|
||||
var/list/former_captains = list()
|
||||
var/list/other_crew = list()
|
||||
SEND_SOUND(world, sound('sound/magic/timeparadox2.ogg'))
|
||||
|
||||
for (var/mob/living/carbon/human/crewmate as anything in GLOB.human_list)
|
||||
if (!crewmate.mind)
|
||||
continue
|
||||
crewmate.Unconscious(3 SECONDS) // Everyone falls unconscious but not everyone gets told about a new captain
|
||||
if (crewmate == invoker || IS_HUMAN_INVADER(crewmate))
|
||||
continue
|
||||
to_chat(crewmate, span_notice("The world spins and dissolves. Your past flashes before your eyes, backwards.\n\
|
||||
Life strolls back into the ocean and shrinks into nothingness, planets explode into storms of solar dust, \
|
||||
the stars rush back to greet each other at the beginning of things and then... you snap back to the present. \n\
|
||||
Everything is just as it was and always has been. \n\n\
|
||||
A stray thought sticks in the forefront of your mind. \n\
|
||||
[span_hypnophrase("I'm so glad that [invoker.real_name] is our legally appointed Captain!")] \n\
|
||||
Is... that right?"))
|
||||
if (is_captain_job(crewmate.mind.assigned_role))
|
||||
former_captains += crewmate
|
||||
demote_to_assistant(crewmate)
|
||||
continue
|
||||
if (crewmate.stat != DEAD)
|
||||
other_crew += crewmate
|
||||
|
||||
dress_candidate(invoker)
|
||||
GLOB.manifest.modify(invoker.real_name, JOB_CAPTAIN, JOB_CAPTAIN)
|
||||
minor_announce("Captain [invoker.real_name] on deck!")
|
||||
|
||||
// Enlist some crew to try and restore the natural order
|
||||
for (var/mob/living/carbon/human/former_captain as anything in former_captains)
|
||||
create_vendetta(former_captain.mind, invoker.mind)
|
||||
for (var/mob/living/carbon/human/random_crewmate as anything in other_crew)
|
||||
if (prob(10))
|
||||
create_vendetta(random_crewmate.mind, invoker.mind)
|
||||
|
||||
/**
|
||||
* Anyone who thought they were Captain is in for a nasty surprise, and won't be very happy about it
|
||||
*/
|
||||
/datum/grand_finale/usurp/proc/demote_to_assistant(mob/living/carbon/human/former_captain)
|
||||
var/obj/effect/particle_effect/fluid/smoke/exit_poof = new(get_turf(former_captain))
|
||||
exit_poof.lifetime = 2 SECONDS
|
||||
|
||||
former_captain.unequip_everything()
|
||||
if(isplasmaman(former_captain))
|
||||
former_captain.equipOutfit(/datum/outfit/plasmaman)
|
||||
former_captain.internal = former_captain.get_item_for_held_index(2)
|
||||
else
|
||||
former_captain.equipOutfit(/datum/outfit/job/assistant)
|
||||
|
||||
GLOB.manifest.modify(former_captain.real_name, JOB_ASSISTANT, JOB_ASSISTANT)
|
||||
var/list/valid_turfs = list()
|
||||
// Used to be into prison but that felt a bit too mean
|
||||
for (var/turf/exile_turf as anything in get_area_turfs(/area/station/maintenance, subtypes = TRUE))
|
||||
if (isspaceturf(exile_turf) || exile_turf.is_blocked_turf())
|
||||
continue
|
||||
valid_turfs += exile_turf
|
||||
do_teleport(former_captain, pick(valid_turfs), no_effects = TRUE)
|
||||
var/obj/effect/particle_effect/fluid/smoke/enter_poof = new(get_turf(former_captain))
|
||||
enter_poof.lifetime = 2 SECONDS
|
||||
|
||||
/**
|
||||
* Does some item juggling to try to dress you as both a Wizard and Captain without deleting any items you have bought.
|
||||
* ID, headset, and uniform are forcibly replaced. Other slots are only filled if unoccupied.
|
||||
* We could forcibly replace shoes and gloves too but people might miss their insuls or... meown shoes?
|
||||
*/
|
||||
/datum/grand_finale/usurp/proc/dress_candidate(mob/living/carbon/human/invoker)
|
||||
// Won't be needing these
|
||||
var/obj/id = invoker.get_item_by_slot(ITEM_SLOT_ID)
|
||||
QDEL_NULL(id)
|
||||
var/obj/headset = invoker.get_item_by_slot(ITEM_SLOT_EARS)
|
||||
QDEL_NULL(headset)
|
||||
// We're about to take off your pants so those are going to fall out
|
||||
var/obj/item/pocket_L = invoker.get_item_by_slot(ITEM_SLOT_LPOCKET)
|
||||
var/obj/item/pocket_R = invoker.get_item_by_slot(ITEM_SLOT_RPOCKET)
|
||||
// In case we try to put a PDA there
|
||||
var/obj/item/belt = invoker.get_item_by_slot(ITEM_SLOT_BELT)
|
||||
belt?.moveToNullspace()
|
||||
|
||||
var/obj/pants = invoker.get_item_by_slot(ITEM_SLOT_ICLOTHING)
|
||||
QDEL_NULL(pants)
|
||||
invoker.equipOutfit(/datum/outfit/job/wizard_captain)
|
||||
// And put everything back!
|
||||
equip_to_slot_then_hands(invoker, ITEM_SLOT_BELT, belt)
|
||||
equip_to_slot_then_hands(invoker, ITEM_SLOT_LPOCKET, pocket_L)
|
||||
equip_to_slot_then_hands(invoker, ITEM_SLOT_RPOCKET, pocket_R)
|
||||
|
||||
/// An outfit which replaces parts of a wizard's clothes with captain's clothes but keeps the robes
|
||||
/datum/outfit/job/wizard_captain
|
||||
name = "Captain (Wizard Transformation)"
|
||||
jobtype = /datum/job/captain
|
||||
id = /obj/item/card/id/advanced/gold
|
||||
id_trim = /datum/id_trim/job/captain
|
||||
uniform = /obj/item/clothing/under/rank/captain/parade
|
||||
belt = /obj/item/modular_computer/pda/heads/captain
|
||||
ears = /obj/item/radio/headset/heads/captain/alt
|
||||
glasses = /obj/item/clothing/glasses/sunglasses
|
||||
gloves = /obj/item/clothing/gloves/captain
|
||||
shoes = /obj/item/clothing/shoes/laceup
|
||||
accessory = /obj/item/clothing/accessory/medal/gold/captain
|
||||
backpack_contents = list(
|
||||
/obj/item/melee/baton/telescopic = 1,
|
||||
/obj/item/station_charter = 1,
|
||||
)
|
||||
box = null
|
||||
|
||||
/// Dress the crew as magical clowns
|
||||
/datum/grand_finale/clown
|
||||
name = "Jubilation"
|
||||
desc = "The ultimate use of your gathered power! Rewrite time so that everyone went to clown college! Now they'll prank each other for you!"
|
||||
icon = 'icons/obj/clothing/masks.dmi'
|
||||
icon_state = "clown"
|
||||
glow_colour = "#ffff0048"
|
||||
|
||||
/datum/grand_finale/clown/trigger(mob/living/carbon/human/invoker)
|
||||
for(var/mob/living/carbon/human/victim as anything in GLOB.human_list)
|
||||
victim.Unconscious(3 SECONDS)
|
||||
if (!victim.mind || IS_HUMAN_INVADER(victim) || victim == invoker)
|
||||
continue
|
||||
if (HAS_TRAIT(victim, TRAIT_CLOWN_ENJOYER))
|
||||
victim.add_mood_event("clown_world", /datum/mood_event/clown_world)
|
||||
to_chat(victim, span_notice("The world spins and dissolves. Your past flashes before your eyes, backwards.\n\
|
||||
Life strolls back into the ocean and shrinks into nothingness, planets explode into storms of solar dust, \
|
||||
the stars rush back to greet each other at the beginning of things and then... you snap back to the present. \n\
|
||||
Everything is just as it was and always has been. \n\n\
|
||||
A stray thought sticks in the forefront of your mind. \n\
|
||||
[span_hypnophrase("I'm so glad that I work at Clown Research Station [station_name()]!")] \n\
|
||||
Is... that right?"))
|
||||
if (is_clown_job(victim.mind.assigned_role))
|
||||
var/datum/action/cooldown/spell/conjure_item/clown_pockets/new_spell = new(victim)
|
||||
new_spell.Grant(victim)
|
||||
continue
|
||||
if (!ismonkey(victim)) // Monkeys cannot yet wear clothes
|
||||
dress_as_magic_clown(victim)
|
||||
if (prob(15))
|
||||
create_vendetta(victim.mind, invoker.mind)
|
||||
|
||||
/**
|
||||
* Clown enjoyers who are effected by this become ecstatic, they have achieved their life's dream.
|
||||
* This moodlet is equivalent to the one for simply being a traitor.
|
||||
*/
|
||||
/datum/mood_event/clown_world
|
||||
mood_change = 4
|
||||
|
||||
/datum/mood_event/clown_world/add_effects(param)
|
||||
description = "I LOVE working at Clown Research Station [station_name()]!!"
|
||||
|
||||
/// Dress the passed mob as a magical clown, self-explanatory
|
||||
/datum/grand_finale/clown/proc/dress_as_magic_clown(mob/living/carbon/human/victim)
|
||||
var/obj/effect/particle_effect/fluid/smoke/poof = new(get_turf(victim))
|
||||
poof.lifetime = 2 SECONDS
|
||||
|
||||
var/obj/item/tank/internal = victim.internal
|
||||
// We're about to take off your pants so those are going to fall out
|
||||
var/obj/item/pocket_L = victim.get_item_by_slot(ITEM_SLOT_LPOCKET)
|
||||
var/obj/item/pocket_R = victim.get_item_by_slot(ITEM_SLOT_RPOCKET)
|
||||
var/obj/item/id = victim.get_item_by_slot(ITEM_SLOT_ID)
|
||||
var/obj/item/belt = victim.get_item_by_slot(ITEM_SLOT_BELT)
|
||||
|
||||
var/obj/pants = victim.get_item_by_slot(ITEM_SLOT_ICLOTHING)
|
||||
var/obj/mask = victim.get_item_by_slot(ITEM_SLOT_MASK)
|
||||
QDEL_NULL(pants)
|
||||
QDEL_NULL(mask)
|
||||
if(isplasmaman(victim))
|
||||
victim.equip_to_slot_if_possible(new /obj/item/clothing/under/plasmaman/clown/magic(), ITEM_SLOT_ICLOTHING, disable_warning = TRUE)
|
||||
victim.equip_to_slot_if_possible(new /obj/item/clothing/mask/gas/clown_hat/plasmaman(), ITEM_SLOT_MASK, disable_warning = TRUE)
|
||||
else
|
||||
victim.equip_to_slot_if_possible(new /obj/item/clothing/under/rank/civilian/clown/magic(), ITEM_SLOT_ICLOTHING, disable_warning = TRUE)
|
||||
victim.equip_to_slot_if_possible(new /obj/item/clothing/mask/gas/clown_hat(), ITEM_SLOT_MASK, disable_warning = TRUE)
|
||||
|
||||
var/obj/item/clothing/mask/gas/clown_hat/clown_mask = victim.get_item_by_slot(ITEM_SLOT_MASK)
|
||||
if (clown_mask)
|
||||
var/list/options = GLOB.clown_mask_options
|
||||
clown_mask.icon_state = options[pick(clown_mask.clownmask_designs)]
|
||||
victim.update_worn_mask()
|
||||
clown_mask.update_item_action_buttons()
|
||||
|
||||
equip_to_slot_then_hands(victim, ITEM_SLOT_LPOCKET, pocket_L)
|
||||
equip_to_slot_then_hands(victim, ITEM_SLOT_RPOCKET, pocket_R)
|
||||
equip_to_slot_then_hands(victim, ITEM_SLOT_ID, id)
|
||||
equip_to_slot_then_hands(victim, ITEM_SLOT_BELT, belt)
|
||||
victim.internal = internal
|
||||
|
||||
/// Give everyone magic items
|
||||
/datum/grand_finale/magic
|
||||
name = "Evolution"
|
||||
desc = "The ultimate use of your gathered power! Give the crew their own magic, they'll surely realise that right and wrong have no meaning when you hold ultimate power!"
|
||||
icon = 'icons/obj/scrolls.dmi'
|
||||
icon_state = "scroll"
|
||||
|
||||
/datum/grand_finale/magic/trigger(mob/living/carbon/human/invoker)
|
||||
message_admins("[key_name(invoker)] summoned magic")
|
||||
summon_magic(survivor_probability = 20) // Wow, this one was easy!
|
||||
|
||||
/// Open all of the doors
|
||||
/datum/grand_finale/all_access
|
||||
name = "Connection"
|
||||
desc = "The ultimate use of your gathered power! Unlock every single door that they have! Nobody will be able to keep you out now, or anyone else for that matter!"
|
||||
icon = 'icons/mob/actions/actions_spells.dmi'
|
||||
icon_state = "knock"
|
||||
|
||||
/datum/grand_finale/all_access/trigger(mob/living/carbon/human/invoker)
|
||||
message_admins("[key_name(invoker)] removed all door access requirements")
|
||||
for(var/obj/machinery/door/target_door as anything in SSmachines.get_machines_by_type_and_subtypes(/obj/machinery/door))
|
||||
if(is_station_level(target_door.z))
|
||||
target_door.unlock()
|
||||
target_door.req_access = list()
|
||||
target_door.req_one_access = list()
|
||||
INVOKE_ASYNC(target_door, TYPE_PROC_REF(/obj/machinery/door/airlock, open))
|
||||
CHECK_TICK
|
||||
priority_announce("AULIE OXIN FIERA!!", null, 'sound/magic/knock.ogg', sender_override = "[invoker.real_name]")
|
||||
|
||||
/// Completely transform the station
|
||||
/datum/grand_finale/midas
|
||||
name = "Transformation"
|
||||
desc = "The ultimate use of your gathered power! Turn their precious station into something much MORE precious, materially speaking!"
|
||||
icon = 'icons/obj/stack_objects.dmi'
|
||||
icon_state = "sheet-gold_2"
|
||||
glow_colour = "#dbdd4c48"
|
||||
var/static/list/permitted_transforms = list( // Non-dangerous only
|
||||
/datum/dimension_theme/gold,
|
||||
/datum/dimension_theme/meat,
|
||||
/datum/dimension_theme/pizza,
|
||||
/datum/dimension_theme/natural,
|
||||
)
|
||||
var/datum/dimension_theme/chosen_theme
|
||||
|
||||
// I sure hope this doesn't have performance implications
|
||||
/datum/grand_finale/midas/trigger(mob/living/carbon/human/invoker)
|
||||
var/theme_path = pick(permitted_transforms)
|
||||
chosen_theme = new theme_path()
|
||||
var/turf/start_turf = get_turf(invoker)
|
||||
var/greatest_dist = 0
|
||||
var/list/turfs_to_transform = list()
|
||||
for (var/turf/transform_turf as anything in GLOB.station_turfs)
|
||||
if (!chosen_theme.can_convert(transform_turf))
|
||||
continue
|
||||
var/dist = get_dist(start_turf, transform_turf)
|
||||
if (dist > greatest_dist)
|
||||
greatest_dist = dist
|
||||
if (!turfs_to_transform["[dist]"])
|
||||
turfs_to_transform["[dist]"] = list()
|
||||
turfs_to_transform["[dist]"] += transform_turf
|
||||
|
||||
if (chosen_theme.can_convert(start_turf))
|
||||
chosen_theme.apply_theme(start_turf)
|
||||
|
||||
for (var/iterator in 1 to greatest_dist)
|
||||
if(!turfs_to_transform["[iterator]"])
|
||||
continue
|
||||
addtimer(CALLBACK(src, PROC_REF(transform_area), turfs_to_transform["[iterator]"]), (5 SECONDS) * iterator)
|
||||
|
||||
/datum/grand_finale/midas/proc/transform_area(list/turfs)
|
||||
for (var/turf/transform_turf as anything in turfs)
|
||||
if (!chosen_theme.can_convert(transform_turf))
|
||||
continue
|
||||
chosen_theme.apply_theme(transform_turf)
|
||||
CHECK_TICK
|
||||
|
||||
/// Kill yourself and probably a bunch of other people
|
||||
/datum/grand_finale/armageddon
|
||||
name = "Annihilation"
|
||||
desc = "This crew have offended you beyond the realm of pranks. Make the ultimate sacrifice to teach them a lesson your elders can really respect. \
|
||||
YOU WILL NOT SURVIVE THIS."
|
||||
icon = 'icons/hud/screen_alert.dmi'
|
||||
icon_state = "wounded"
|
||||
minimum_time = 90 MINUTES // This will probably immediately end the round if it gets finished.
|
||||
ritual_invoke_time = 60 SECONDS // Really give the crew some time to interfere with this one.
|
||||
dire_warning = TRUE
|
||||
glow_colour = "#be000048"
|
||||
/// Things to yell before you die
|
||||
var/static/list/possible_last_words = list(
|
||||
"Flames and ruin!",
|
||||
"Dooooooooom!!",
|
||||
"HAHAHAHAHAHA!! AHAHAHAHAHAHAHAHAA!!",
|
||||
"Hee hee hee!! Hoo hoo hoo!! Ha ha haaa!!",
|
||||
"Ohohohohohoho!!",
|
||||
"Cower in fear, puny mortals!",
|
||||
"Tremble before my glory!",
|
||||
"Pick a god and pray!",
|
||||
"It's no use!",
|
||||
"If the gods wanted you to live, they would not have created me!",
|
||||
"God stays in heaven out of fear of what I have created!",
|
||||
"Ruination is come!",
|
||||
"All of creation, bend to my will!",
|
||||
)
|
||||
|
||||
/datum/grand_finale/armageddon/trigger(mob/living/carbon/human/invoker)
|
||||
priority_announce(pick(possible_last_words), null, 'sound/magic/voidblink.ogg', sender_override = "[invoker.real_name]")
|
||||
var/turf/current_location = get_turf(invoker)
|
||||
invoker.gib()
|
||||
|
||||
var/static/list/doom_options = list()
|
||||
if (!length(doom_options))
|
||||
doom_options = list(DOOM_SINGULARITY, DOOM_TESLA)
|
||||
if (!SSmapping.config.planetary)
|
||||
doom_options += DOOM_METEORS
|
||||
|
||||
switch(pick(doom_options))
|
||||
if (DOOM_SINGULARITY)
|
||||
var/obj/singularity/singulo = new(current_location)
|
||||
singulo.energy = 300
|
||||
if (DOOM_TESLA)
|
||||
var/obj/energy_ball/tesla = new (current_location)
|
||||
tesla.energy = 200
|
||||
if (DOOM_METEORS)
|
||||
var/datum/dynamic_ruleset/roundstart/meteor/meteors = new()
|
||||
meteors.meteordelay = 0
|
||||
var/datum/game_mode/dynamic/mode = SSticker.mode
|
||||
mode.execute_roundstart_rule(meteors) // Meteors will continue until morale is crushed.
|
||||
priority_announce("Meteors have been detected on collision course with the station.", "Meteor Alert", ANNOUNCER_METEORS)
|
||||
|
||||
/**
|
||||
* Gives the wizard a defensive/mood buff and a Wabbajack, a juiced up chaos staff that will surely break something.
|
||||
* Everyone but the wizard goes crazy, suffers major brain damage, and is given a vendetta against the wizard.
|
||||
* Already insane people are instead cured of their madness, ignoring any other effects as the station around them loses its marbles.
|
||||
*/
|
||||
/datum/grand_finale/cheese
|
||||
// we don't set name, desc and others, thus we won't appear in the radial choice of a normal finale rune
|
||||
dire_warning = TRUE
|
||||
minimum_time = 45 MINUTES //i'd imagine speedrunning this would be crummy, but the wizard's average lifespan is barely reaching this point
|
||||
|
||||
/datum/grand_finale/cheese/trigger(mob/living/invoker)
|
||||
message_admins("[key_name(invoker)] has summoned forth The Wabbajack and cursed the crew with madness!")
|
||||
priority_announce("Danger: Extremely potent reality altering object has been summoned on station. Immediate evacuation advised. Brace for impact.", "Central Command Higher Dimensional Affairs", 'sound/effects/glassbr1.ogg')
|
||||
|
||||
for (var/mob/living/carbon/human/crewmate as anything in GLOB.human_list)
|
||||
if (isnull(crewmate.mind))
|
||||
continue
|
||||
if (crewmate == invoker) //everyone but the wizard is royally fucked, no matter who they are
|
||||
continue
|
||||
if (crewmate.has_trauma_type(/datum/brain_trauma/mild/hallucinations)) //for an already insane person, this is retribution
|
||||
to_chat(crewmate, span_boldwarning("Your surroundings suddenly fill with a cacophony of manic laughter and psychobabble..."))
|
||||
to_chat(crewmate, span_nicegreen("...but as the moment passes, you realise that whatever eldritch power behind the event happened to affect you \
|
||||
has resonated within the ruins of your already shattered mind, creating a singularity of mental instability! \
|
||||
As it collapses unto itself, you feel... at peace, finally."))
|
||||
if(crewmate.has_quirk(/datum/quirk/insanity))
|
||||
crewmate.remove_quirk(/datum/quirk/insanity)
|
||||
else
|
||||
crewmate.cure_trauma_type(/datum/brain_trauma/mild/hallucinations, TRAUMA_RESILIENCE_ABSOLUTE)
|
||||
else
|
||||
//everyone else gets to relish in madness
|
||||
//yes killing their mood will also trigger mood hallucinations
|
||||
create_vendetta(crewmate.mind, invoker.mind)
|
||||
to_chat(crewmate, span_boldwarning("Your surroundings suddenly fill with a cacophony of manic laughter and psychobabble. \n\
|
||||
You feel your inner psyche shatter into a myriad pieces of jagged glass of colors unknown to the universe, \
|
||||
infinitely reflecting a blinding, maddening light coming from the innermost sanctums of your destroyed mind. \n\
|
||||
After a brief pause which felt like a millenia, one phrase rebounds ceaselessly in your head, imbued with the false hope of absolution... \n\
|
||||
<b>[invoker] must die.</b>"))
|
||||
var/datum/brain_trauma/mild/hallucinations/added_trauma = new()
|
||||
added_trauma.resilience = TRAUMA_RESILIENCE_ABSOLUTE
|
||||
crewmate.adjustOrganLoss(ORGAN_SLOT_BRAIN, BRAIN_DAMAGE_DEATH - 25, BRAIN_DAMAGE_DEATH - 25) //you'd better hope chap didn't pick a hypertool
|
||||
crewmate.gain_trauma(added_trauma)
|
||||
crewmate.add_mood_event("wizard_ritual_finale", /datum/mood_event/madness_despair)
|
||||
|
||||
//drip our wizard out
|
||||
invoker.apply_status_effect(/datum/status_effect/blessing_of_insanity)
|
||||
invoker.add_mood_event("wizard_ritual_finale", /datum/mood_event/madness_elation)
|
||||
var/obj/item/gun/magic/staff/chaos/true_wabbajack/the_wabbajack = new
|
||||
invoker.put_in_active_hand(the_wabbajack)
|
||||
to_chat(invoker, span_mind_control("Your every single instinct and rational thought is screaming at you as [the_wabbajack] appears in your firm grip..."))
|
||||
|
||||
#undef DOOM_SINGULARITY
|
||||
#undef DOOM_TESLA
|
||||
#undef DOOM_METEORS
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
var/can_respawn = TRUE
|
||||
///Reference to the game this player is participating in.
|
||||
var/datum/ctf_controller/ctf_game
|
||||
///Item dropped on death,
|
||||
///Item dropped on death,
|
||||
var/death_drop = /obj/effect/powerup/ammo/ctf
|
||||
///Reference to players ckey, used for sending messages to them relating to CTF.
|
||||
var/ckey_reference
|
||||
@@ -22,19 +22,20 @@
|
||||
var/datum/mind/true_parent = parent
|
||||
player_mob = true_parent.current
|
||||
ckey_reference = player_mob.ckey
|
||||
setup_dusting()
|
||||
|
||||
register_mob()
|
||||
|
||||
/datum/component/ctf_player/PostTransfer()
|
||||
if(!istype(parent, /datum/mind))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
var/datum/mind/true_parent = parent
|
||||
player_mob = true_parent.current
|
||||
setup_dusting()
|
||||
register_mob()
|
||||
|
||||
///CTF players are dusted upon taking damage that puts them into critical or leaving their body.
|
||||
/datum/component/ctf_player/proc/setup_dusting()
|
||||
/// Called when we get a new player mob, register signals and set up the mob.
|
||||
/datum/component/ctf_player/proc/register_mob()
|
||||
RegisterSignal(player_mob, COMSIG_MOB_AFTER_APPLY_DAMAGE, PROC_REF(damage_type_check))
|
||||
RegisterSignal(player_mob, COMSIG_MOB_GHOSTIZED, PROC_REF(ctf_dust))
|
||||
ADD_TRAIT(player_mob, TRAIT_PERMANENTLY_MORTAL, CTF_TRAIT)
|
||||
|
||||
///Stamina and oxygen damage will not dust a player by themself.
|
||||
/datum/component/ctf_player/proc/damage_type_check(datum/source, damage, damage_type)
|
||||
|
||||
@@ -61,6 +61,7 @@
|
||||
mobtype = pick(mobtype)
|
||||
our_mob = new mobtype(loc)
|
||||
our_mob.flags_1 |= HOLOGRAM_1
|
||||
ADD_TRAIT(our_mob, TRAIT_PERMANENTLY_MORTAL, INNATE_TRAIT)
|
||||
|
||||
// these vars are not really standardized but all would theoretically create stuff on death
|
||||
for(var/v in list("butcher_results","corpse","weapon1","weapon2","blood_volume") & our_mob.vars)
|
||||
|
||||
@@ -578,7 +578,7 @@ GLOBAL_LIST_INIT(mafia_role_by_alignment, setup_mafia_role_by_alignment())
|
||||
|
||||
for(var/datum/mafia_role/role as anything in all_roles)
|
||||
var/mob/living/carbon/human/H = new(get_turf(role.assigned_landmark))
|
||||
H.add_traits(list(TRAIT_NOFIRE, TRAIT_NOBREATH, TRAIT_CANNOT_CRYSTALIZE), MAFIA_TRAIT)
|
||||
H.add_traits(list(TRAIT_NOFIRE, TRAIT_NOBREATH, TRAIT_CANNOT_CRYSTALIZE, TRAIT_PERMANENTLY_MORTAL), MAFIA_TRAIT)
|
||||
H.equipOutfit(outfit_to_distribute)
|
||||
H.status_flags |= GODMODE
|
||||
RegisterSignal(H, COMSIG_ATOM_UPDATE_OVERLAYS, PROC_REF(display_votes))
|
||||
|
||||
@@ -88,6 +88,11 @@
|
||||
|
||||
/// If the blob changes to distributed neurons then you can control the spores
|
||||
/mob/living/basic/blob_minion/spore/minion/on_strain_updated(mob/camera/blob/overmind, datum/blobstrain/new_strain)
|
||||
if (isnull(overmind))
|
||||
REMOVE_TRAIT(src, TRAIT_PERMANENTLY_MORTAL, INNATE_TRAIT)
|
||||
else
|
||||
ADD_TRAIT(src, TRAIT_PERMANENTLY_MORTAL, INNATE_TRAIT)
|
||||
|
||||
if (istype(new_strain, /datum/blobstrain/reagent/distributed_neurons))
|
||||
AddComponent(\
|
||||
/datum/component/ghost_direct_control,\
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
|
||||
/mob/living/basic/blob_minion/zombie/Initialize(mapload)
|
||||
. = ..()
|
||||
ADD_TRAIT(src, TRAIT_PERMANENTLY_MORTAL, INNATE_TRAIT) // This mob doesn't function visually without a corpse and wouldn't respawn with one
|
||||
AddElement(/datum/element/swabable, CELL_LINE_TABLE_BLOBSPORE, CELL_VIRUS_TABLE_GENERIC_MOB, 1, 5)
|
||||
|
||||
/mob/living/basic/blob_minion/zombie/death(gibbed)
|
||||
|
||||
@@ -102,7 +102,7 @@
|
||||
|
||||
/mob/living/basic/hivelord_brood/Initialize(mapload)
|
||||
. = ..()
|
||||
add_traits(list(TRAIT_LAVA_IMMUNE, TRAIT_ASHSTORM_IMMUNE), INNATE_TRAIT)
|
||||
add_traits(list(TRAIT_LAVA_IMMUNE, TRAIT_ASHSTORM_IMMUNE, TRAIT_PERMANENTLY_MORTAL), INNATE_TRAIT)
|
||||
AddElement(/datum/element/simple_flying)
|
||||
AddComponent(/datum/component/swarming)
|
||||
AddComponent(/datum/component/clickbox, icon_state = "hivelord", max_scale = INFINITY)
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
|
||||
/mob/living/basic/legion_brood/Initialize(mapload)
|
||||
. = ..()
|
||||
add_traits(list(TRAIT_LAVA_IMMUNE, TRAIT_ASHSTORM_IMMUNE), INNATE_TRAIT)
|
||||
add_traits(list(TRAIT_LAVA_IMMUNE, TRAIT_ASHSTORM_IMMUNE, TRAIT_PERMANENTLY_MORTAL), INNATE_TRAIT)
|
||||
AddElement(/datum/element/simple_flying)
|
||||
AddComponent(/datum/component/swarming)
|
||||
AddComponent(/datum/component/clickbox, icon_state = "sphere", max_scale = 2)
|
||||
|
||||
@@ -198,6 +198,7 @@
|
||||
|
||||
for(var/i in 1 to worm_length)
|
||||
current = new type(drop_location(), FALSE)
|
||||
ADD_TRAIT(current, TRAIT_PERMANENTLY_MORTAL, INNATE_TRAIT)
|
||||
current.icon_state = "armsy_mid"
|
||||
current.icon_living = "armsy_mid"
|
||||
current.AIStatus = AI_OFF
|
||||
|
||||
@@ -113,6 +113,7 @@ GLOBAL_LIST_INIT(animatable_blacklist, list(/obj/structure/table, /obj/structure
|
||||
|
||||
/mob/living/simple_animal/hostile/mimic/copy/Initialize(mapload, obj/copy, mob/living/creator, destroy_original = 0, no_googlies = FALSE)
|
||||
. = ..()
|
||||
ADD_TRAIT(src, TRAIT_PERMANENTLY_MORTAL, INNATE_TRAIT) // They won't remember their original contents upon ressurection and would just be floating eyes
|
||||
if (no_googlies)
|
||||
overlay_googly_eyes = FALSE
|
||||
CopyObject(copy, creator, destroy_original)
|
||||
|
||||
@@ -108,7 +108,7 @@
|
||||
if(!COOLDOWN_FINISHED(src, crystalize_cooldown) || ethereal.stat != DEAD)
|
||||
return //Should probably not happen, but lets be safe.
|
||||
|
||||
if(ismob(location) || isitem(location) || HAS_TRAIT_FROM(src, TRAIT_HUSK, CHANGELING_DRAIN)) //Stops crystallization if they are eaten by a dragon, turned into a legion, consumed by his grace, etc.
|
||||
if(ismob(location) || isitem(location) || iseffect(location) || HAS_TRAIT_FROM(src, TRAIT_HUSK, CHANGELING_DRAIN)) //Stops crystallization if they are eaten by a dragon, turned into a legion, consumed by his grace, etc.
|
||||
to_chat(ethereal, span_warning("You were unable to finish your crystallization, for obvious reasons."))
|
||||
stop_crystalization_process(ethereal, FALSE)
|
||||
return
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 911 KiB After Width: | Height: | Size: 928 KiB |
+8
-1
@@ -3047,9 +3047,16 @@
|
||||
#include "code\modules\antagonists\wizard\equipment\spellbook_entries\summons.dm"
|
||||
#include "code\modules\antagonists\wizard\grand_ritual\fluff.dm"
|
||||
#include "code\modules\antagonists\wizard\grand_ritual\grand_ritual.dm"
|
||||
#include "code\modules\antagonists\wizard\grand_ritual\grand_ritual_finale.dm"
|
||||
#include "code\modules\antagonists\wizard\grand_ritual\grand_rune.dm"
|
||||
#include "code\modules\antagonists\wizard\grand_ritual\grand_side_effect.dm"
|
||||
#include "code\modules\antagonists\wizard\grand_ritual\finales\all_access.dm"
|
||||
#include "code\modules\antagonists\wizard\grand_ritual\finales\armageddon.dm"
|
||||
#include "code\modules\antagonists\wizard\grand_ritual\finales\captaincy.dm"
|
||||
#include "code\modules\antagonists\wizard\grand_ritual\finales\cheese.dm"
|
||||
#include "code\modules\antagonists\wizard\grand_ritual\finales\clown.dm"
|
||||
#include "code\modules\antagonists\wizard\grand_ritual\finales\grand_ritual_finale.dm"
|
||||
#include "code\modules\antagonists\wizard\grand_ritual\finales\immortality.dm"
|
||||
#include "code\modules\antagonists\wizard\grand_ritual\finales\midas.dm"
|
||||
#include "code\modules\antagonists\xeno\xeno.dm"
|
||||
#include "code\modules\art\paintings.dm"
|
||||
#include "code\modules\art\statues.dm"
|
||||
|
||||
Reference in New Issue
Block a user