diff --git a/_maps/map_files/RandomRuins/SpaceRuins/intactemptyship.dmm b/_maps/map_files/RandomRuins/SpaceRuins/intactemptyship.dmm index a00c71b1e94..89383c9e77c 100644 --- a/_maps/map_files/RandomRuins/SpaceRuins/intactemptyship.dmm +++ b/_maps/map_files/RandomRuins/SpaceRuins/intactemptyship.dmm @@ -126,6 +126,11 @@ /obj/structure/bed, /turf/simulated/floor/mineral/titanium/purple, /area/ruin/space/powered) +"Q" = ( +/obj/structure/table/wood, +/obj/item/blank_tarot_card, +/turf/simulated/floor/mineral/titanium/purple, +/area/ruin/space/powered) (1,1,1) = {" a @@ -277,7 +282,7 @@ b j r w -n +Q j b a diff --git a/_maps/map_files/RandomRuins/SpaceRuins/wizardcrash.dmm b/_maps/map_files/RandomRuins/SpaceRuins/wizardcrash.dmm index d1f0175e1f4..8434558c253 100644 --- a/_maps/map_files/RandomRuins/SpaceRuins/wizardcrash.dmm +++ b/_maps/map_files/RandomRuins/SpaceRuins/wizardcrash.dmm @@ -167,6 +167,7 @@ /area/ruin/space/unpowered) "aF" = ( /obj/structure/table/wood, +/obj/item/blank_tarot_card, /turf/simulated/floor/wood{ icon_state = "wood-broken6" }, diff --git a/code/__DEFINES/status_effects.dm b/code/__DEFINES/status_effects.dm index 4f185e0f70a..d34fb486829 100644 --- a/code/__DEFINES/status_effects.dm +++ b/code/__DEFINES/status_effects.dm @@ -18,6 +18,8 @@ #define STATUS_EFFECT_SHADOW_MEND /datum/status_effect/shadow_mend //Quick, powerful heal that deals damage afterwards. Heals 15 brute/burn every second for 3 seconds. #define STATUS_EFFECT_VOID_PRICE /datum/status_effect/void_price //The price of healing yourself with void energy. Deals 3 brute damage every 3 seconds for 30 seconds. +#define STATUS_EFFECT_SHADOW_MEND_DEVIL /datum/status_effect/shadow_mend/devil //Tarot version, hurts others over self + #define STATUS_EFFECT_HIPPOCRATIC_OATH /datum/status_effect/hippocraticOath //Gives you an aura of healing as well as regrowing the Rod of Asclepius if lost #define STATUS_EFFECT_REGENERATIVE_CORE /datum/status_effect/regenerative_core @@ -37,6 +39,8 @@ #define STATUS_EFFECT_BLOODDRUNK /datum/status_effect/blooddrunk //Stun immunity and greatly reduced damage taken +#define STATUS_EFFECT_BLOODDRUNK_CHARIOT /datum/status_effect/blooddrunk/chariot //adds pacifism + #define STATUS_EFFECT_DASH /datum/status_effect/dash // Grants the ability to dash, expiring after a few secodns /// Rapid burn/brute/oxy/blood healing from the cling ability @@ -62,6 +66,12 @@ #define STATUS_EFFECT_BEARSERKER_RAGE /datum/status_effect/bearserker_rage +#define STATUS_EFFECT_XRAY /datum/status_effect/xray // Xray vision for 2 minutes + +#define STATUS_EFFECT_BADASS /datum/status_effect/badass // Badass trait for 2 minutes. + +#define STATUS_EFFECT_REVERSED_SUN /datum/status_effect/reversed_sun // Weaker eternal darkness, nightvision, but nearsight + ///////////// // DEBUFFS // ///////////// @@ -114,6 +124,8 @@ #define STATUS_EFFECT_PEPPERSPRAYED /datum/status_effect/pepper_spray +#define STATUS_EFFECT_REVERSED_HIGH_PRIESTESS /datum/status_effect/reversed_high_priestess //Bubblegum will chase the person hit by the effect, grabbing people at random. This can and WILL include the caster. + //#define STATUS_EFFECT_NECROPOLIS_CURSE /datum/status_effect/necropolis_curse //#define CURSE_BLINDING 1 //makes the edges of the target's screen obscured //#define CURSE_SPAWNING 2 //spawns creatures that attack the target only diff --git a/code/datums/status_effects/buffs.dm b/code/datums/status_effects/buffs.dm index 646b40e4d26..38f94e4ce89 100644 --- a/code/datums/status_effects/buffs.dm +++ b/code/datums/status_effects/buffs.dm @@ -62,6 +62,11 @@ id = "shadow_mend" duration = 3 SECONDS alert_type = /atom/movable/screen/alert/status_effect/shadow_mend + /// If this is true, the status effect will try to apply the debuff to others, rather than the user + var/devil = FALSE + +/datum/status_effect/shadow_mend/devil + devil = TRUE /atom/movable/screen/alert/status_effect/shadow_mend name = "Shadow Mend" @@ -78,10 +83,25 @@ owner.adjustFireLoss(-15) /datum/status_effect/shadow_mend/on_remove() - owner.visible_message("The violet light around [owner] glows black!", "The tendrils around you cinch tightly and reap their toll...") - playsound(owner, 'sound/magic/teleport_diss.ogg', 50, 1) - owner.apply_status_effect(STATUS_EFFECT_VOID_PRICE) + if(!devil) + owner.visible_message("The violet light around [owner] glows black!", "The tendrils around you cinch tightly and reap their toll...") + playsound(owner, 'sound/magic/teleport_diss.ogg', 50, TRUE) + owner.apply_status_effect(STATUS_EFFECT_VOID_PRICE) + return + var/found_someone = FALSE + + for(var/mob/living/L in oview(9, owner)) + found_someone = TRUE + playsound(owner, 'sound/magic/teleport_diss.ogg', 50, TRUE) + L.Beam(owner, "grabber_beam", time = 1 SECONDS, maxdistance = 9) + L.apply_status_effect(STATUS_EFFECT_VOID_PRICE) + if(found_someone) + owner.visible_message("The violet light around [owner] glows black... and shoots off to those around [owner.p_them()]!", "The tendrils around you cinch tightly... but then unwravel and fly at others!") + else + owner.visible_message("The violet light around [owner] glows black!", "The tendrils around you cinch tightly and reap their toll...") + playsound(owner, 'sound/magic/teleport_diss.ogg', 50, TRUE) + owner.apply_status_effect(STATUS_EFFECT_VOID_PRICE) /datum/status_effect/void_price id = "void_price" @@ -110,6 +130,13 @@ tick_interval = 0 alert_type = /atom/movable/screen/alert/status_effect/blooddrunk var/blooddrunk_damage_mod_remove = 4 // Damage is multiplied by this at the end of the status effect. Modify this one, it changes the _add + /// If this is the chariot subtype, which grants pacifism while the effect is active. + var/chariot = FALSE + +/datum/status_effect/blooddrunk/chariot + duration = 10 SECONDS + chariot = TRUE + blooddrunk_damage_mod_remove = 6 /atom/movable/screen/alert/status_effect/blooddrunk name = "Blood-Drunk" @@ -120,6 +147,8 @@ . = ..() if(.) ADD_TRAIT(owner, TRAIT_IGNOREDAMAGESLOWDOWN, "blooddrunk") + if(chariot) + ADD_TRAIT(owner, TRAIT_PACIFISM, "blooddrunk") if(ishuman(owner)) var/mob/living/carbon/human/H = owner var/blooddrunk_damage_mod_add = 1 / blooddrunk_damage_mod_remove // Damage is multiplied by this at the start of the status effect. Don't modify this one directly. @@ -144,6 +173,7 @@ H.physiology.stamina_mod *= blooddrunk_damage_mod_remove add_attack_logs(owner, owner, "lost blood-drunk stun immunity", ATKLOG_ALL) REMOVE_TRAIT(owner, TRAIT_IGNOREDAMAGESLOWDOWN, "blooddrunk") + REMOVE_TRAIT(owner, TRAIT_PACIFISM, "blooddrunk") if(islist(owner.stun_absorption) && owner.stun_absorption["blooddrunk"]) owner.remove_stun_absorption("blooddrunk") @@ -183,7 +213,7 @@ H.physiology.stamina_mod *= 0.5 H.physiology.stun_mod *= 0.5 var/datum/antagonist/vampire/V = owner.mind.has_antag_datum(/datum/antagonist/vampire) - if(V.get_ability(/datum/vampire_passive/blood_swell_upgrade)) + if(V?.get_ability(/datum/vampire_passive/blood_swell_upgrade)) bonus_damage_applied = TRUE H.physiology.melee_bonus += 10 H.dna.species.punchstunthreshold += 8 //higher chance to stun but not 100% @@ -776,3 +806,70 @@ var/mob/living/carbon/human/H = owner H.physiology.stamina_mod /= 0.75 add_attack_logs(owner, owner, "lost bearserker rage resistances", ATKLOG_ALL) + +/datum/status_effect/xray + id = "xray" + alert_type = null + status_type = STATUS_EFFECT_REFRESH + duration = 2 MINUTES + tick_interval = 0 + +/datum/status_effect/xray/on_apply() + . = ..() + ADD_TRAIT(owner, TRAIT_XRAY_VISION, "XRAY_BUFF") + ADD_TRAIT(owner, TRAIT_NIGHT_VISION, "XRAY_BUFF") + owner.update_sight() + +/datum/status_effect/xray/on_remove() + . = ..() + REMOVE_TRAIT(owner, TRAIT_XRAY_VISION, "XRAY_BUFF") + REMOVE_TRAIT(owner, TRAIT_NIGHT_VISION, "XRAY_BUFF") + owner.update_sight() + +/datum/status_effect/badass + id = "badass" + alert_type = null + status_type = STATUS_EFFECT_REFRESH + duration = 2 MINUTES + tick_interval = 0 + +/datum/status_effect/badass/on_apply() + . = ..() + ADD_TRAIT(owner, TRAIT_BADASS, "BADDASS_BUFF") + +/datum/status_effect/badass/on_remove() + . = ..() + REMOVE_TRAIT(owner, TRAIT_BADASS, "BADDASS_BUFF") + +/datum/status_effect/reversed_sun + id = "reversed_sun" + alert_type = null + status_type = STATUS_EFFECT_REFRESH + duration = 1 MINUTES + tick_interval = 0.2 SECONDS + +/datum/status_effect/reversed_sun/on_apply() + . = ..() + owner.become_nearsighted("REVERSED_SUN") + ADD_TRAIT(owner, TRAIT_NIGHT_VISION, "REVERSED_SUN") + owner.update_sight() + owner.set_light(7, -5, "#ddd6cf") + +/datum/status_effect/reversed_sun/on_remove() + . = ..() + owner.remove_light() + owner.cure_nearsighted("REVERSED_SUN") + REMOVE_TRAIT(owner, TRAIT_NIGHT_VISION, "REVERSED_SUN") + owner.update_sight() + +/datum/status_effect/reversed_sun/tick() + for(var/atom/movable/AM in oview(8, owner)) + if(isliving(AM)) + var/mob/living/L = AM + if(L.affects_vampire(owner)) + L.adjust_bodytemperature(-1.5 * TEMPERATURE_DAMAGE_COEFFICIENT) + continue + if(istype(AM, /obj/item/projectile)) + var/obj/item/projectile/P = AM + if(P.flag == ENERGY || P.flag == LASER) + P.damage *= 0.85 diff --git a/code/datums/status_effects/debuffs.dm b/code/datums/status_effects/debuffs.dm index 9edf7eb42ad..e65da3535cd 100644 --- a/code/datums/status_effects/debuffs.dm +++ b/code/datums/status_effects/debuffs.dm @@ -1322,3 +1322,29 @@ desc = "Real winners quit before they reach the ultimate prize." #undef DEFAULT_MAX_CURSE_COUNT + +/datum/status_effect/reversed_high_priestess + id = "reversed_high_priestess" + duration = 1 MINUTES + status_type = STATUS_EFFECT_REFRESH + tick_interval = 6 SECONDS + alert_type = /atom/movable/screen/alert/status_effect/bubblegum_curse + +/datum/status_effect/reversed_high_priestess/tick() + . = ..() + new /obj/effect/bubblegum_warning(get_turf(owner)) + +/obj/effect/bubblegum_warning + name = "bloody rift" + desc = "You feel like even being *near* this is a bad idea" + icon = 'icons/obj/biomass.dmi' + icon_state = "rift" + color = "red" + +/obj/effect/bubblegum_warning/Initialize() + . = ..() + addtimer(CALLBACK(src, PROC_REF(slap_someone)), 2.5 SECONDS) //A chance to run away + +/obj/effect/bubblegum_warning/proc/slap_someone() + new /obj/effect/abstract/bubblegum_rend_helper(get_turf(src), null, 10) + qdel(src) diff --git a/code/datums/uplink_items/uplink_traitor.dm b/code/datums/uplink_items/uplink_traitor.dm index db79ccb1a6c..ea331744b39 100644 --- a/code/datums/uplink_items/uplink_traitor.dm +++ b/code/datums/uplink_items/uplink_traitor.dm @@ -305,6 +305,17 @@ excludefrom = list(UPLINK_TYPE_NUCLEAR, UPLINK_TYPE_SST) job = list("Head of Personnel", "Quartermaster", "Cargo Technician", "Librarian", "Coroner", "Psychiatrist", "Virologist") +// Tarot card generator, librarian and Chaplain. + +/datum/uplink_item/jobspecific/tarot_generator + name = "Enchanted tarot card deck" + desc = "A magic tarot card deck \"borrowed\" from a Wizard federation storage unit. \ + Capable of producing magic tarot cards of the 22 major arcana, and their reversed versions. Each card has a different effect. \ + Throw the card at someone to use it on them, or use it in hand to apply it to yourself. Unlimited uses, 25 second cooldown, can have up to 3 cards in the world." + reference = "tarot" + item = /obj/item/tarot_generator + cost = 55 //This can do a lot of stuff, but is quite random. As such, higher price. + job = list("Chaplain", "Librarian") //--------------------------// // Species Restricted Gear // diff --git a/code/game/gamemodes/cult/cult_structures.dm b/code/game/gamemodes/cult/cult_structures.dm index 481d2dbfc02..e298a454a26 100644 --- a/code/game/gamemodes/cult/cult_structures.dm +++ b/code/game/gamemodes/cult/cult_structures.dm @@ -318,7 +318,7 @@ GLOBAL_LIST_INIT(blacklisted_pylon_turfs, typecacheof(list( selection_title = "Archives" creation_message = "You invoke the dark magic of the tomes creating a %ITEM%!" choosable_items = list("Shuttle Curse" = /obj/item/shuttle_curse, "Zealot's Blindfold" = /obj/item/clothing/glasses/hud/health/night/cultblind, - "Veil Shifter" = /obj/item/cult_shift, "Reality sunderer" = /obj/item/portal_amulet) //Add void torch to veil shifter spawn + "Veil Shifter" = /obj/item/cult_shift, "Reality sunderer" = /obj/item/portal_amulet, "Blank Tarot Card" = /obj/item/blank_tarot_card) /obj/structure/cult/functional/archives/Initialize(mapload) . = ..() diff --git a/code/game/gamemodes/wizard/magic_tarot.dm b/code/game/gamemodes/wizard/magic_tarot.dm new file mode 100644 index 00000000000..e3efcfa8128 --- /dev/null +++ b/code/game/gamemodes/wizard/magic_tarot.dm @@ -0,0 +1,885 @@ +/obj/item/tarot_generator + name = "Enchanted tarot card deck" + desc = "This tarot card box has quite the array of runes and artwork on it." + icon = 'icons/obj/playing_cards.dmi' + icon_state = "tarot_box" + w_class = WEIGHT_CLASS_SMALL + /// What is the maximum number of cards the tarot generator can have in the world at a time? + var/maximum_cards = 3 + /// List of cards we have created, to check against maximum, and so we can purge them from the pack. + var/list/our_card_list = list() + ///How long the cooldown is each time we draw a card before we can draw another? + var/our_card_cooldown_time = 25 SECONDS + COOLDOWN_DECLARE(card_cooldown) + +/obj/item/tarot_generator/wizard + maximum_cards = 5 + our_card_cooldown_time = 12 SECONDS // A minute for a full hand of 5 cards + +/obj/item/tarot_generator/attack_self(mob/user) + if(!COOLDOWN_FINISHED(src, card_cooldown)) + to_chat(user, "[src]'s magic is still recovering from the last card, wait [round(COOLDOWN_TIMELEFT(src, card_cooldown) / 10)] more second\s!") + return + if(length(our_card_list) >= maximum_cards) + to_chat(user, "[src]'s magic can only support up to [maximum_cards] in the world at once, use or destroy some!") + return + var/obj/item/magic_tarot_card/MTC = new /obj/item/magic_tarot_card(get_turf(src), src) + our_card_list += MTC + user.put_in_hands(MTC) + to_chat(user, "You draw [MTC.name]... [MTC.card_desc]") //No period on purpose. + COOLDOWN_START(src, card_cooldown, our_card_cooldown_time) + +/obj/item/tarot_generator/examine(mob/user) + . = ..() + . += "Alt-Shift-Click to destroy all cards it has produced." + . += "It has [length(our_card_list)] card\s in the world right now." + if(!COOLDOWN_FINISHED(src, card_cooldown)) + . += "You may draw another card again in [round(COOLDOWN_TIMELEFT(src, card_cooldown) / 10)] second\s." + +/obj/item/tarot_generator/AltShiftClick(mob/user) + for(var/obj/item/magic_tarot_card/MTC in our_card_list) + MTC.dust() + to_chat(user, "You dispell the cards [src] had created.") + +// Booster packs filled with 3, 5, or 7 playing cards! Used by the wizard space ruin, or rarely in lavaland tendril chests. +/obj/item/tarot_card_pack + name = "\improper Enchanted Arcana Pack" + desc = "A pack of 3 Enchanted tarot cards. Collect them all!" + icon = 'icons/obj/playing_cards.dmi' + icon_state = "pack" + ///How many cards in a pack. 3 in base, 5 in jumbo, 7 in mega + var/cards = 3 + +/obj/item/tarot_card_pack/attack_self(mob/user) + user.visible_message("[user] tears open [src].", \ + "You tear open [src]!") + playsound(loc, 'sound/items/poster_ripped.ogg', 50, TRUE) + for(var/i in 1 to cards) + new /obj/item/magic_tarot_card(get_turf(src)) + qdel(src) + +/obj/item/tarot_card_pack/jumbo + name = "\improper Jumbo Arcana Pack" + desc = "A Jumbo card pack from your friend Jimbo!" + icon_state = "jumbopack" + cards = 5 + +/obj/item/tarot_card_pack/mega + name = "\improper MEGA Arcana Pack" + desc = "Sadly, you won't find a Joker for an angel room, or a Soul card in here either." + icon_state = "megapack" + cards = 7 + +// Blank tarot cards. Made by the cult, however also good for space ruins potentially, where one feels a card pack would be too much? +/obj/item/blank_tarot_card + name = "blank tarot card" + desc = "A blank tarot card." + icon = 'icons/obj/playing_cards.dmi' + icon_state = "tarot_blank" + w_class = WEIGHT_CLASS_TINY + throw_speed = 3 + throw_range = 10 + throwforce = 0 + force = 0 + resistance_flags = FLAMMABLE + /// If a person can choose what the card produces. No cost if they can choose. + var/let_people_choose = FALSE + +/obj/item/blank_tarot_card/examine(mob/user) + . = ..() + if(!let_people_choose) + . += "With a bit of Ink, a work of art could be created. Will you provide your Ink?" + else + . += "We have the Ink... Could you provide your Vision instead?" + +/obj/item/blank_tarot_card/attack_self(mob/user) + if(!ishuman(user)) + return + if(!let_people_choose) + var/mob/living/carbon/human/H = user + if(H.dna && (NO_BLOOD in H.dna.species.species_traits)) + to_chat(user, "No blood to provide?... Then no Ink for the art...") + return + if(H.blood_volume <= 100) //Shouldn't happen, they should be dead, but failsafe. Not bleeding as then they could recover the blood with blood rites + return + H.blood_volume -= 100 + H.drop_item() + var/obj/item/magic_tarot_card/MTC = new /obj/item/magic_tarot_card(get_turf(src)) + user.put_in_hands(MTC) + to_chat(user, "Your blood flows into [src]... And your Ink makes a work of art! [MTC.name]... [MTC.card_desc]") //No period on purpose. + qdel(src) + return + var/tarot_type + var/tarot_name + var/list/card_by_name = list() + for(var/T in subtypesof(/datum/tarot) - /datum/tarot/reversed) + var/datum/tarot/temp = T + card_by_name[temp.name] = T + + tarot_name = tgui_input_list(user, "Choose the Work of Art to create.", "Art Creation", card_by_name) + tarot_type = card_by_name[tarot_name] + if(tarot_type) + user.drop_item() + var/obj/item/magic_tarot_card/MTC = new /obj/item/magic_tarot_card(get_turf(src), null, tarot_type) + user.put_in_hands(MTC) + to_chat(user, "You put your Vision into [src], and your Vision makes a work of Art! [MTC.name]... [MTC.card_desc]") //No period on purpose. + qdel(src) + +/obj/item/blank_tarot_card/choose //For admins mainly, to spawn a specific tarot card. Not recommended for ruins. + let_people_choose = TRUE + +/obj/item/magic_tarot_card + name = "XXII - The Unknown" + desc = "A beautiful tarot card. However, it feels like... more?" + icon = 'icons/obj/playing_cards.dmi' + icon_state = "tarot_the_unknown" + w_class = WEIGHT_CLASS_TINY + throw_speed = 3 + throw_range = 10 + throwforce = 0 + force = 0 + resistance_flags = FLAMMABLE + /// The deck that created us. Notifies it we have been deleted on use. + var/obj/item/tarot_generator/creator_deck + /// Our magic tarot card datum that lets the tarot card do stuff on use, or hitting someone + var/datum/tarot/our_tarot + /// Our fancy description given to use by the tarot datum. + var/card_desc = "Untold answers... wait what? This is a bug, report this as an issue on github!" + ///Is the card face down? Shows the card back, hides the examine / name. + var/face_down = FALSE + +/obj/item/magic_tarot_card/Initialize(mapload, obj/item/tarot_generator/source, datum/tarot/chosen_tarot) + . = ..() + if(source) + creator_deck = source + if(chosen_tarot) + our_tarot = new chosen_tarot + if(!istype(our_tarot)) + var/tarotpath = pick(subtypesof(/datum/tarot) - /datum/tarot/reversed) + our_tarot = new tarotpath + name = our_tarot.name + card_desc = our_tarot.desc + icon_state = "tarot_[our_tarot.card_icon]" + +/obj/item/magic_tarot_card/Destroy() + if(creator_deck) + creator_deck.our_card_list -= src + return ..() + +/obj/item/magic_tarot_card/examine(mob/user) + . = ..() + if(!face_down) + . += "[card_desc]" + . += "Alt-Shift-Click to flip the card over." + +/obj/item/magic_tarot_card/attack_self(mob/user) + if(our_tarot) + INVOKE_ASYNC(our_tarot, TYPE_PROC_REF(/datum/tarot, activate), user) + poof() + +/obj/item/magic_tarot_card/throw_at(atom/target, range, speed, mob/thrower, spin, diagonals_first, datum/callback/callback, force, dodgeable) + if(face_down) + flip() + . = ..() + +/obj/item/magic_tarot_card/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum) + . = ..() + if(isliving(hit_atom) && our_tarot) + INVOKE_ASYNC(our_tarot, TYPE_PROC_REF(/datum/tarot, activate), hit_atom) + poof() + +/obj/item/magic_tarot_card/AltShiftClick(mob/user) + flip() + +/obj/item/magic_tarot_card/proc/flip() + if(!face_down) + icon_state = "cardback[our_tarot.reversed ? "?" : ""]" + name = "Enchanted tarot card" + face_down = TRUE + else + name = our_tarot.name + icon_state = "tarot_[our_tarot.card_icon]" + face_down = FALSE + +/obj/item/magic_tarot_card/proc/poof() + new /obj/effect/temp_visual/revenant(get_turf(src)) + qdel(src) + +/obj/item/magic_tarot_card/proc/dust() + visible_message("[src] disintegrates into dust!") + new /obj/effect/temp_visual/revenant(get_turf(src)) + qdel(src) + +/datum/tarot + /// Name used for the card + var/name = "XXII - The Unknown." + /// Desc used for the card description of the card + var/desc = "Untold answers... wait what? This is a bug, report this as an issue on github!" + /// What icon is used for the card? + var/card_icon = "the_unknown" + /// Are we reversed? Used for the card back. + var/reversed = FALSE + +/datum/tarot/proc/activate(mob/living/target) + stack_trace("A bugged tarot card was spawned and used. Please make an issue report! Type was [src.type]") + +/datum/tarot/reversed + name = "XXII - The Unknown?" + desc = "Untold answers... wait what? This is a bug, report this as an issue on github! This one was a reversed arcana!" + card_icon = "the_unknown?" + reversed = TRUE + +/datum/tarot/the_fool + name = "0 - The Fool" + desc = "Where journey begins." + card_icon = "the_fool" + +/datum/tarot/the_fool/activate(mob/living/target) + target.forceMove(pick(GLOB.latejoin)) + to_chat(target, "You are abruptly pulled through space!") + +/datum/tarot/the_magician + name = "I - The Magician" + desc = "May you never miss your goal." + card_icon = "the_magician" + +/datum/tarot/the_magician/activate(mob/living/target) + target.apply_status_effect(STATUS_EFFECT_BADASS) + to_chat(target, "You feel badass.") + +/datum/tarot/the_high_priestess + name = "II - The High Priestess" + desc = "Mother is watching you." + card_icon = "the_high_priestess" + +/datum/tarot/the_high_priestess/activate(mob/living/target) + new /obj/effect/abstract/bubblegum_rend_helper(get_turf(target), target, 20) + +/obj/effect/abstract/bubblegum_rend_helper + name = "bubblegum_rend_helper" + +/obj/effect/abstract/bubblegum_rend_helper/Initialize(mapload, mob/living/owner, damage) + . = ..() + INVOKE_ASYNC(src, PROC_REF(rend), owner, damage) + +/obj/effect/abstract/bubblegum_rend_helper/proc/rend(mob/living/owner, damage) + if(!owner) + for(var/mob/living/L in shuffle(view(9, src))) + owner = L + break + owner.Immobilize(3 SECONDS) + for(var/i in 1 to 3) + var/turf/first_turf = get_turf(owner) + new /obj/effect/decal/cleanable/blood/bubblegum(first_turf) + if(prob(50)) + new /obj/effect/temp_visual/bubblegum_hands/rightsmack(first_turf) + else + new /obj/effect/temp_visual/bubblegum_hands/leftsmack(first_turf) + sleep(6) + var/turf/second_turf = get_turf(owner) + to_chat(owner, "Something huge rends you!") + playsound(second_turf, 'sound/misc/demon_attack1.ogg', 100, TRUE, -1) + owner.adjustBruteLoss(damage) + qdel(src) + +/datum/tarot/the_empress + name = "III - The Empress" + desc = "May your rage bring power." + card_icon = "the_empress" + +/datum/tarot/the_empress/activate(mob/living/target) + if(ishuman(target)) + var/mob/living/carbon/human/H = target + H.reagents.add_reagent("mephedrone", 4.5) + H.reagents.add_reagent("mitocholide", 12) + +/datum/tarot/the_emperor + name = "IV - The Emperor" + desc = "Challenge me!" + card_icon = "the_emperor" + +/datum/tarot/the_emperor/activate(mob/living/target) + var/list/L = list() + for(var/turf/T in get_area_turfs(/area/station/command/bridge)) + if(is_blocked_turf(T)) + continue + L.Add(T) + + if(!length(L)) + to_chat(target, "Huh. No bridge? Well, that sucks.") + return + + target.forceMove(pick(L)) + to_chat(target, "You are abruptly pulled through space!") + +/datum/tarot/the_hierophant + name = "V - The Hierophant" + desc = "Two prayers for the lost." + card_icon = "the_hierophant" + +/datum/tarot/the_hierophant/activate(mob/living/target) + if(!ishuman(target)) + return + var/mob/living/carbon/human/H = target + if(!H.wear_suit) + return + H.wear_suit.setup_hierophant_shielding() + H.update_appearance(UPDATE_ICON) + +/datum/tarot/the_lovers + name = "VI - The Lovers" + desc = "May you prosper and be in good health." + card_icon = "the_lovers" + +/datum/tarot/the_lovers/activate(mob/living/target) + if(ishuman(target)) + var/mob/living/carbon/human/H = target + H.adjustBruteLoss(-40, robotic = TRUE) + H.adjustFireLoss(-40, robotic = TRUE) + H.blood_volume = min(H.blood_volume + 100, BLOOD_VOLUME_NORMAL) + else + target.adjustBruteLoss(-40) + target.adjustFireLoss(-40) + target.adjustOxyLoss(-40) + target.adjustToxLoss(-40) + +/datum/tarot/the_chariot + name = "VII - The Chariot" + desc = "May nothing stand before you." + card_icon = "the_chariot" + +/datum/tarot/the_chariot/activate(mob/living/target) + target.apply_status_effect(STATUS_EFFECT_BLOOD_RUSH) + target.apply_status_effect(STATUS_EFFECT_BLOODDRUNK_CHARIOT) + +/datum/tarot/justice + name = "VIII - Justice" + desc = "May your future become balanced." + card_icon = "justice" + +/datum/tarot/justice/activate(mob/living/target) + var/turf/target_turf = get_turf(target) + new /obj/item/storage/firstaid/regular(target_turf) + new /obj/item/grenade/chem_grenade/waterpotassium(target_turf) + new /obj/item/card/emag/magic_key(target_turf) + new /obj/item/stack/spacecash/c100(target_turf) + +/datum/tarot/the_hermit + name = "IX - The Hermit" + desc = "May you see what life has to offer." + card_icon = "the_hermit" + +/datum/tarot/the_hermit/activate(mob/living/target) + var/list/viable_vendors = list() + for(var/obj/machinery/economy/vending/candidate in GLOB.machines) + if(!is_station_level(candidate.z)) + continue + viable_vendors += candidate + + if(!length(viable_vendors)) + to_chat(target, "No vending machines? Well, with luck cargo will have something to offer. If you go there yourself.") + return + + target.forceMove(get_turf(pick(viable_vendors))) + to_chat(target, "You are abruptly pulled through space!") + +/datum/tarot/wheel_of_fortune + name = "X - Wheel of Fortune" + desc = "Spin the wheel of destiny." + card_icon = "wheel_of_fortune" + +/datum/tarot/wheel_of_fortune/activate(mob/living/target) + var/list/static/bad_vendors = list( + /obj/machinery/economy/vending/liberationstation, + /obj/machinery/economy/vending/toyliberationstation, + /obj/machinery/economy/vending/wallmed + ) + var/turf/target_turf = get_turf(target) + var/vendorpath = pick(subtypesof(/obj/machinery/economy/vending) - bad_vendors) + new vendorpath(target_turf) + +/datum/tarot/strength + name = "XI - Strength" + desc = "May your power bring rage." + card_icon = "strength" + +/datum/tarot/strength/activate(mob/living/target) + target.apply_status_effect(STATUS_EFFECT_VAMPIRE_GLADIATOR) + target.apply_status_effect(STATUS_EFFECT_BLOOD_SWELL) + +/datum/tarot/the_hanged_man + name = "XII - The Hanged Man" + desc = "May you find enlightenment." + card_icon = "the_hanged_man" + +/datum/tarot/the_hanged_man/activate(mob/living/target) + if(target.flying) + return + target.flying = TRUE + addtimer(VARSET_CALLBACK(target, flying, FALSE), 60 SECONDS) + +/datum/tarot/death + name = "XIII - Death" + desc = "Lay waste to all that oppose you." + card_icon = "death" + +/datum/tarot/death/activate(mob/living/target) + for(var/mob/living/L in oview(9, target)) + L.adjustBruteLoss(20) + L.adjustFireLoss(20) + +/datum/tarot/temperance + name = "XIV - Temperance" + desc = "May you be pure in heart." + card_icon = "temperance" + +/datum/tarot/temperance/activate(mob/living/target) + if(!ishuman(target)) + return + var/mob/living/carbon/human/H = target + var/obj/item/organ/internal/body_egg/egg = H.get_int_organ(/obj/item/organ/internal/body_egg) + if(egg) + egg.remove(H) + H.vomit() + egg.forceMove(get_turf(H)) + H.reagents.add_reagent("mutadone", 1) + for(var/obj/item/organ/internal/I in H.internal_organs) + I.heal_internal_damage(60) + H.apply_status_effect(STATUS_EFFECT_PANACEA) + for(var/thing in H.viruses) + var/datum/disease/D = thing + if(D.severity == NONTHREAT) + continue + D.cure() + +/datum/tarot/the_devil + name = "XV - The Devil" + desc = "Revel in the power of darkness." + card_icon = "the_devil" + +/datum/tarot/the_devil/activate(mob/living/target) + target.apply_status_effect(STATUS_EFFECT_SHADOW_MEND_DEVIL) + +/datum/tarot/the_tower + name = "XVI - The Tower" + desc = "Destruction brings creation." + card_icon = "the_tower" + +/datum/tarot/the_tower/activate(mob/living/target) + var/obj/item/grenade/clusterbuster/ied/bakoom = new(get_turf(target)) + bakoom.prime() + +/// I'm sorry matt, this is very funny. +/datum/tarot/the_stars + name = "XVII - The Stars" + desc = "May you find what you desire." + card_icon = "the_stars" + +/datum/tarot/the_stars/activate(mob/living/target) + var/list/L = list() + for(var/turf/T in get_area_turfs(/area/station/security/evidence)) + if(is_blocked_turf(T)) + continue + L.Add(T) + + if(!length(L)) + to_chat(target, "Huh. No evidence? Well, that means they can't charge you with a crime, right?") + return + + target.forceMove(pick(L)) + to_chat(target, "You are abruptly pulled through space!") + for(var/obj/structure/closet/C in shuffle(view(9, target))) + if(istype(C, /obj/structure/closet/secure_closet)) + var/obj/structure/closet/secure_closet/SC = C + SC.locked = FALSE + C.open() + break //Only open one locker + +/datum/tarot/the_moon + name = "XVIII - The Moon" + desc = "May you find all you have lost." + card_icon = "the_moon" + +/datum/tarot/the_moon/activate(mob/living/target) + var/list/funny_ruin_list = list() + var/turf/target_turf = get_turf(target) + for(var/I in GLOB.ruin_landmarks) + var/obj/effect/landmark/ruin/ruin_landmark = I + if(ruin_landmark.z == target_turf.z) + funny_ruin_list += ruin_landmark + + if(length(funny_ruin_list)) + var/turf/T = get_turf(pick(funny_ruin_list)) + target.forceMove(T) + to_chat(target, "You are abruptly pulled through space!") + T.ChangeTurf(/turf/simulated/floor/plating) //we give them plating so they are not trapped in a wall, and a pickaxe to avoid being trapped in a wall + new /obj/item/pickaxe/emergency(T) + target.update_parallax_contents() + return + //We did not find a ruin on the same level. Well. I hope you have a space suit, but we'll go space ruins as they are mostly sorta kinda safer. + for(var/I in GLOB.ruin_landmarks) + var/obj/effect/landmark/ruin/ruin_landmark = I + if(!is_mining_level(ruin_landmark.z)) + funny_ruin_list += ruin_landmark + + if(!length(funny_ruin_list)) + to_chat(target, "Huh. No space ruins? Well, this card is RUINED!") + + var/turf/T = get_turf(pick(funny_ruin_list)) + target.forceMove(T) + to_chat(target, "You are abruptly pulled through space!") + T.ChangeTurf(/turf/simulated/floor/plating) //we give them plating so they are not trapped in a wall, and a pickaxe to avoid being trapped in a wall + new /obj/item/pickaxe/emergency(T) + target.update_parallax_contents() + return + +/datum/tarot/the_sun + name = "XIX - The Sun" + desc = "May the light heal and enlighten you." + card_icon = "the_sun" + +/datum/tarot/the_sun/activate(mob/living/target) + target.revive() + +/datum/tarot/judgement + name = "XX - Judgement" + desc = "Judge lest ye be judged." + card_icon = "judgement" + +/datum/tarot/judgement/activate(mob/living/target) + notify_ghosts("[target] has used a judgment card. Judge them. Or not, up to you.", enter_link = "(Click to judge)", source = target, action = NOTIFY_FOLLOW) + +/datum/tarot/the_world + name = "XXI - The World" + desc = "Open your eyes and see." + card_icon = "the_world" + +/datum/tarot/the_world/activate(mob/living/target) + var/datum/effect_system/smoke_spread/bad/smoke = new() + smoke.set_up(10, FALSE, target) + smoke.start() + target.apply_status_effect(STATUS_EFFECT_XRAY) + +//////////////////////////////// +////////REVERSED ARCANA///////// +//////////////////////////////// + +/datum/tarot/reversed/the_fool + name = "0 - The Fool?" + desc = "Let go and move on." + card_icon = "the_fool?" + +/datum/tarot/reversed/the_fool/activate(mob/living/target) + if(!ishuman(target)) + return + var/mob/living/carbon/human/H = target + for(var/obj/item/I in H) + if(istype(/obj/item/bio_chip, I)) + continue + H.unEquip(I) + +/datum/tarot/reversed/the_magician + name = "I - The Magician?" + desc = "May no harm come to you." + card_icon = "the_magician?" + +/datum/tarot/reversed/the_magician/activate(mob/living/target) + var/list/thrown_atoms = list() + var/sparkle_path = /obj/effect/temp_visual/gravpush + for(var/turf/T in range(5, target)) //Done this way so things don't get thrown all around hilariously. + for(var/atom/movable/AM in T) + thrown_atoms += AM + + for(var/atom/movable/AM as anything in thrown_atoms) + if(AM == target || AM.anchored || (ismob(AM) && !isliving(AM))) + continue + + var/throw_target = get_edge_target_turf(target, get_dir(target, get_step_away(AM, target))) + var/dist_from_user = get_dist(target, AM) + if(dist_from_user == 0) + if(isliving(AM)) + var/mob/living/M = AM + M.Weaken(6 SECONDS) + M.adjustBruteLoss(10) + to_chat(M, "You're slammed into the floor by [name]!") + add_attack_logs(target, M, "[M] was thrown by [target]'s [name]", ATKLOG_ALMOSTALL) + else + new sparkle_path(get_turf(AM), get_dir(target, AM)) + if(isliving(AM)) + var/mob/living/M = AM + to_chat(M, "You're thrown back by [name]!") + add_attack_logs(target, M, "[M] was thrown by [target]'s [name]", ATKLOG_ALMOSTALL) + INVOKE_ASYNC(AM, TYPE_PROC_REF(/atom/movable, throw_at), throw_target, ((clamp((3 - (clamp(dist_from_user - 2, 0, dist_from_user))), 3, 3))), 1) //So stuff gets tossed around at the same time. + +/datum/tarot/reversed/the_high_priestess + name = "II - The High Priestess?" + desc = "Run." + card_icon = "the_high_priestess?" + +/datum/tarot/reversed/the_high_priestess/activate(mob/living/target) + target.visible_message("WHO DARES TO TRY TO USE MY POWER IN A CARD?") + target.apply_status_effect(STATUS_EFFECT_REVERSED_HIGH_PRIESTESS) + +/datum/tarot/reversed/the_empress + name = "III - The Empress?" + desc = "May your love bring protection." + card_icon = "the_empress?" + +/datum/tarot/reversed/the_empress/activate(mob/living/target) + for(var/mob/living/L in oview(9, target)) + L.apply_status_effect(STATUS_EFFECT_PACIFIED) + +/datum/tarot/reversed/the_emperor + name = "IV - The Emperor?" + desc = "May you find a worthy opponent." + card_icon = "the_emperor?" + +/datum/tarot/reversed/the_emperor/activate(mob/living/target) + var/list/L = list() + var/list/heads = SSticker.mode.get_all_heads() + for(var/datum/mind/head in heads) + if(ishuman(head.current)) + L.Add(head.current) + + if(!length(L)) + to_chat(target, "Huh. No command members? I hope you didn't kill them all already...") + return + + target.forceMove(get_turf(pick(L))) + to_chat(target, "You are abruptly pulled through space!") + +/datum/tarot/reversed/the_hierophant + name = "V - The Hierophant?" + desc = "Two prayers for the forgotten." + card_icon = "the_hierophant?" + +/datum/tarot/reversed/the_hierophant/activate(mob/living/target) + var/active_chasers = 0 + for(var/mob/living/M in shuffle(orange(7, target))) + if(M.stat == DEAD) //Let us not have dead mobs be used to make a disco inferno. + continue + if(active_chasers >= 2) + return + var/obj/effect/temp_visual/hierophant/chaser/C = new(get_turf(target), target, M, 1, FALSE) + C.moving = 2 + C.standard_moving_before_recalc = 2 + C.moving_dir = text2dir(pick("NORTH", "SOUTH", "EAST", "WEST")) + active_chasers++ + +/datum/tarot/reversed/the_lovers + name = "VI - The Lovers?" + desc = "May your heart shatter to pieces." + card_icon = "the_lovers?" + +/datum/tarot/reversed/the_lovers/activate(mob/living/target) + if(!ishuman(target)) + return + var/mob/living/carbon/human/H = target + H.apply_damage(20, BRUTE, BODY_ZONE_CHEST) + H.bleed(120) + var/obj/item/organ/external/chest = H.get_organ(BODY_ZONE_CHEST) + chest.fracture() + var/datum/organ/heart/datum_heart = H.get_int_organ_datum(ORGAN_DATUM_HEART) + var/obj/item/organ/internal/our_heart = datum_heart.linked_organ + our_heart.receive_damage(20, TRUE) + +/datum/tarot/reversed/the_chariot + name = "VII - The Chariot?" + desc = "May nothing walk past you." + card_icon = "the_chariot?" + +/datum/tarot/reversed/the_chariot/activate(mob/living/target) + target.Stun(4 SECONDS) + new /obj/structure/closet/statue/indestructible(get_turf(target), target) + +/datum/tarot/reversed/justice + name = "VIII - Justice?" + desc = "May your sins come back to torment you." + card_icon = "justice?" + +/datum/tarot/reversed/justice/activate(mob/living/target) + var/list/static/ignored_supply_pack_types = list( + /datum/supply_packs/abstract, + /datum/supply_packs/abstract/shuttle + ) + var/chosen = pick(SSeconomy.supply_packs - ignored_supply_pack_types) + var/datum/supply_packs/the_pack = new chosen() + var/spawn_location = get_turf(target) + var/obj/structure/closet/crate/crate = the_pack.create_package(spawn_location) + crate.name = "magic [crate.name]" + qdel(the_pack) + +/datum/tarot/reversed/the_hermit + name = "IX - The Hermit?" + desc = "May you see the value of all things in life." + card_icon = "the_hermit?" + +/datum/tarot/reversed/the_hermit/activate(mob/living/target) //Someone can improve this in the future (hopefully comment will not be here in 10 years.) + for(var/obj/item/I in view(7, target)) + if(istype(I, /obj/item/gun)) + new /obj/item/stack/spacecash/c200(get_turf(I)) + qdel(I) + continue + if(istype(I, /obj/item/grenade)) + new /obj/item/stack/spacecash/c50(get_turf(I)) + qdel(I) + if(istype(I, /obj/item/clothing/suit/armor)) + new /obj/item/stack/spacecash/c100(get_turf(I)) + qdel(I) + if(istype(I, /obj/item/melee/baton)) + new /obj/item/stack/spacecash/c100(get_turf(I)) + qdel(I) + +/datum/tarot/reversed/wheel_of_fortune + name = "X - Wheel of Fortune?" + desc = "Throw the dice of fate." + card_icon = "wheel_of_fortune?" + +/datum/tarot/reversed/wheel_of_fortune/activate(mob/living/target) + var/obj/item/dice/d20/fate/one_use/gonna_roll_a_one = new /obj/item/dice/d20/fate/one_use(get_turf(target)) + gonna_roll_a_one.diceroll(target) + +/datum/tarot/reversed/strength + name = "XI - Strength?" + desc = "May you break their resolve." + card_icon = "strength?" + +/datum/tarot/reversed/strength/activate(mob/living/target) + for(var/mob/living/M in oview(9, target)) + M.Hallucinate(2 MINUTES) + new /obj/effect/hallucination/delusion(get_turf(M), M) + M.adjustBrainLoss(30) + +/datum/tarot/reversed/the_hanged_man + name = "XII - The Hanged Man?" + desc = "May your greed know no bounds." + card_icon = "the_hanged_man?" + +/datum/tarot/reversed/the_hanged_man/activate(mob/living/target) + var/obj/structure/cursed_slot_machine/pull_the_lever_kronk = new /obj/structure/cursed_slot_machine(get_turf(target)) + if(ishuman(target)) + var/mob/living/carbon/human/WRONG_LEVER = target + pull_the_lever_kronk.attack_hand(WRONG_LEVER) + +/datum/tarot/reversed/death + name = "XIII - Death?" + desc = "May life spring forth from the fallen." + card_icon = "death?" + +/datum/tarot/reversed/death/activate(mob/living/target) + new /obj/structure/constructshell(get_turf(target)) + new /obj/item/soulstone/anybody(get_turf(target)) + +/datum/tarot/reversed/temperance + name = "XIV - Temperance?" + desc = "May your hunger be satiated." + card_icon = "temperance?" + +/datum/tarot/reversed/temperance/activate(mob/living/target) + if(!ishuman(target)) + return + var/mob/living/carbon/human/H = target + for(var/i in 1 to 5) + var/datum/reagents/R = new /datum/reagents(10) + R.add_reagent(get_unrestricted_random_reagent_id(), 10) + R.reaction(H, REAGENT_INGEST) + R.trans_to(H, 10) + target.visible_message("[target] consumes 5 pills rapidly!") + +/datum/tarot/reversed/the_devil + name = "XV - The Devil?" + desc = "Bask in the light of your mercy." + card_icon = "the_devil?" + +/datum/tarot/reversed/the_devil/activate(mob/living/target) + var/obj/item/grenade/clusterbuster/i_hate_nians = new(get_turf(target)) + i_hate_nians.prime() + +/datum/tarot/reversed/the_tower + name = "XVI - The Tower?" + desc = "Creation brings destruction." + card_icon = "the_tower?" + +/datum/tarot/reversed/the_tower/activate(mob/living/target) + for(var/turf/T in RANGE_TURFS(9, target)) + if(locate(/mob/living) in T) + continue + if(istype(T, /turf/simulated/wall/indestructible)) + continue + if(prob(66)) + continue + T.ChangeTurf(/turf/simulated/mineral/random/labormineral) + +/datum/tarot/reversed/the_stars + name = "XVII - The Stars?" + desc = "May your loss bring fortune." + card_icon = "the_stars?" + +/datum/tarot/reversed/the_stars/activate(mob/living/target) //Heavy clone damage hit, but gain 2 cards. Not teathered to the card producer. Could lead to card stacking, but would require the sun to fix easily + if(!ishuman(target)) + return + var/mob/living/carbon/human/H = target + H.adjustCloneLoss(50) + for(var/obj/item/organ/external/E in shuffle(H.bodyparts)) + switch(rand(1,3)) + if(1) + E.fracture() + if(2) + E.cause_internal_bleeding() + if(3) + E.cause_burn_wound() + break // I forgot the break the first time. Very funny. + + H.drop_l_hand() + H.drop_r_hand() + var/obj/item/magic_tarot_card/MTC = new /obj/item/magic_tarot_card(get_turf(src)) + var/obj/item/magic_tarot_card/MPC = new /obj/item/magic_tarot_card(get_turf(src)) + H.put_in_hands(MTC) + H.put_in_hands(MPC) + +/datum/tarot/reversed/the_moon + name = "XVIII - The Moon?" + desc = "May you remember lost memories." + card_icon = "the_moon?" + +/datum/tarot/reversed/the_moon/activate(mob/living/target) + for(var/mob/living/L in view(5, target)) //Shorter range as this kinda can give away antagonists, though that is also funny. + target.mind.show_memory(L, 0) //Safe code? Bank accounts? PDA codes? It's yours my friend, as long as you have enough tarots + +/datum/tarot/reversed/the_sun + name = "XIX - The Sun?" + desc = "May the darkness swallow all around you." + card_icon = "the_sun?" + +/datum/tarot/reversed/the_sun/activate(mob/living/target) + target.apply_status_effect(STATUS_EFFECT_REVERSED_SUN) + +/datum/tarot/reversed/judgement + name = "XX - Judgement?" + desc = "May you redeem those found wanting" //Who wants more, but ghosts for something interesting + card_icon = "judgement?" + +/datum/tarot/reversed/judgement/activate(mob/living/target) + var/datum/event_container/EC = SSevents.event_containers[EVENT_LEVEL_MODERATE] + var/decrease = 5 MINUTES + EC.next_event_time -= decrease + log_and_message_admins("decreased timer for [GLOB.severity_to_string[EC.severity]] events by 5 minutes by use of a [src].") + +/datum/tarot/reversed/the_world + name = "XXI - The World?" + desc = "Step into the abyss." + card_icon = "the_world?" + +/datum/tarot/reversed/the_world/activate(mob/living/target) + var/list/L = list() + for(var/turf/T in get_area_turfs(/area/mine/outpost)) //Lavaland is the abyss, but also too hot to send people too. Mining base should be fair! + if(is_blocked_turf(T)) + continue + L.Add(T) + + if(!length(L)) + to_chat(target, "Hmm. No base? A miner issue.") + return + + target.forceMove(pick(L)) + to_chat(target, "You are abruptly pulled through space!") diff --git a/code/game/gamemodes/wizard/rightandwrong.dm b/code/game/gamemodes/wizard/rightandwrong.dm index 48e603a0994..0b2c52f3660 100644 --- a/code/game/gamemodes/wizard/rightandwrong.dm +++ b/code/game/gamemodes/wizard/rightandwrong.dm @@ -79,7 +79,9 @@ GLOBAL_LIST_INIT(summoned_magic, list( /obj/item/scrying, /obj/item/clothing/suit/space/hardsuit/wizard, /obj/item/immortality_talisman, - /obj/item/melee/ghost_sword)) + /obj/item/melee/ghost_sword, + /obj/item/tarot_card_pack, + /obj/item/tarot_card_pack/jumbo)) GLOBAL_LIST_INIT(summoned_special_magic, list( /obj/item/gun/magic/staff/animate, @@ -87,7 +89,8 @@ GLOBAL_LIST_INIT(summoned_special_magic, list( /obj/item/contract, /obj/item/gun/magic/staff/chaos, /obj/item/necromantic_stone, - /obj/item/blood_contract)) + /obj/item/blood_contract, + /obj/item/tarot_generator)) //everything above except for single use spellbooks, because they are counted separately (and are for basic bitches anyways) GLOBAL_LIST_INIT(summoned_magic_objectives, list( @@ -100,7 +103,8 @@ GLOBAL_LIST_INIT(summoned_magic_objectives, list( /obj/item/necromantic_stone, /obj/item/scrying, /obj/item/spellbook, - /obj/item/storage/belt/wands/full)) + /obj/item/storage/belt/wands/full, + /obj/item/tarot_generator)) // If true, it's the probability of triggering "survivor" antag. GLOBAL_VAR_INIT(summon_guns_triggered, FALSE) diff --git a/code/game/gamemodes/wizard/spellbook.dm b/code/game/gamemodes/wizard/spellbook.dm index 743079d34e5..d175fcbf6ad 100644 --- a/code/game/gamemodes/wizard/spellbook.dm +++ b/code/game/gamemodes/wizard/spellbook.dm @@ -483,6 +483,15 @@ cost = 1 category = "Artefacts" +/datum/spellbook_entry/item/tarot_generator + name = "Enchanted tarot card deck" + desc = "An magic tarot card deck, enchanted with special Ink. \ + Capable of producing magic tarot cards of the 22 major arcana, both normal and reversed. Each card has a different effect. \ + Throw the card at someone to use it on them, or use it in hand to apply it to yourself. Unlimited uses, 12 second cooldown, can have up to 5 cards in the world." + item_path = /obj/item/tarot_generator/wizard + cost = 2 + category = "Artefacts" + //Weapons and Armors /datum/spellbook_entry/item/battlemage name = "Battlemage Armor" diff --git a/code/game/objects/effects/temporary_visuals/cult_visuals.dm b/code/game/objects/effects/temporary_visuals/cult_visuals.dm index a1b2d4320a9..3f6d09dbaf6 100644 --- a/code/game/objects/effects/temporary_visuals/cult_visuals.dm +++ b/code/game/objects/effects/temporary_visuals/cult_visuals.dm @@ -9,6 +9,13 @@ name = "blood sparks" icon_state = "bloodsparkles" +/obj/effect/temp_visual/cult/sparks/hierophant + icon = 'icons/effects/effects.dmi' + randomdir = TRUE + duration = 12 + name = "purple sparks" + icon_state = "hierophant_blast" + /obj/effect/temp_visual/dir_setting/cult/phase name = "phase glow" duration = 12 diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm index 49c45f27fe8..18b6d11151a 100644 --- a/code/game/objects/items/stacks/sheets/sheet_types.dm +++ b/code/game/objects/items/stacks/sheets/sheet_types.dm @@ -514,7 +514,7 @@ GLOBAL_LIST_INIT(cult_recipes, list ( new /datum/stack_recipe/cult("runed girder (used to make cult walls)", /obj/structure/girder/cult, 1, time = 1 SECONDS, one_per_turf = TRUE, on_floor = TRUE, cult_structure = TRUE), new /datum/stack_recipe/cult("pylon (heals nearby cultists)", /obj/structure/cult/functional/pylon, 4, time = 4 SECONDS, one_per_turf = TRUE, on_floor = TRUE, cult_structure = TRUE), new /datum/stack_recipe/cult("forge (crafts shielded robes, flagellant's robes, and mirror shields)", /obj/structure/cult/functional/forge, 3, time = 4 SECONDS, one_per_turf = TRUE, on_floor = TRUE, cult_structure = TRUE), - new /datum/stack_recipe/cult("archives (crafts zealot's blindfolds, shuttle curse orbs, veil shifters, and reality sunderers)", /obj/structure/cult/functional/archives, 3, time = 4 SECONDS, one_per_turf = TRUE, on_floor = TRUE, cult_structure = TRUE), + new /datum/stack_recipe/cult("archives (crafts zealot's blindfolds, shuttle curse orbs, veil shifters, reality sunderers, and blank tarot cards)", /obj/structure/cult/functional/archives, 3, time = 4 SECONDS, one_per_turf = TRUE, on_floor = TRUE, cult_structure = TRUE), new /datum/stack_recipe/cult("altar (crafts eldritch whetstones, construct shells, and flasks of unholy water)", /obj/structure/cult/functional/altar, 3, time = 4 SECONDS, one_per_turf = TRUE, on_floor = TRUE, cult_structure = TRUE), )) diff --git a/code/game/objects/items/weapons/cards_ids.dm b/code/game/objects/items/weapons/cards_ids.dm index 7a825263df9..cc9c370b973 100644 --- a/code/game/objects/items/weapons/cards_ids.dm +++ b/code/game/objects/items/weapons/cards_ids.dm @@ -47,6 +47,21 @@ return A.emag_act(user) +/obj/item/card/emag/magic_key + name = "magic key" + desc = "It's a magic key, that will open one door!" + icon_state = "magic_key" + origin_tech = "magnets=2" + +/obj/item/card/emag/magic_key/afterattack(atom/target, mob/user, proximity) + if(!istype(target, /obj/machinery/door)) + return + var/obj/machinery/door/D = target + D.locked = FALSE + update_icon() + . = ..() + qdel(src) + /obj/item/card/cmag desc = "It's a card coated in a slurry of electromagnetic bananium." name = "jestographic sequencer" diff --git a/code/game/objects/items/weapons/grenades/clusterbuster.dm b/code/game/objects/items/weapons/grenades/clusterbuster.dm index f08704aa25d..a03f07be8b0 100644 --- a/code/game/objects/items/weapons/grenades/clusterbuster.dm +++ b/code/game/objects/items/weapons/grenades/clusterbuster.dm @@ -227,6 +227,11 @@ desc = "For when you need to knock out EVERYONE." payload = /obj/item/grenade/gas/knockout +/obj/item/grenade/clusterbuster/ied + name = "\improper IED Cluster Grenade" + desc = "For when you need to do something between everything and nothing." + payload = /obj/item/grenade/iedcasing + ////////////Clusterbuster of Clusterbusters//////////// //As a note: be extrodinarily careful about make the payload clusterbusters as it can quickly destroy the MC/Server diff --git a/code/game/objects/items/weapons/storage/backpack.dm b/code/game/objects/items/weapons/storage/backpack.dm index 453c0e0c8cd..dbc5d3f5ced 100644 --- a/code/game/objects/items/weapons/storage/backpack.dm +++ b/code/game/objects/items/weapons/storage/backpack.dm @@ -720,7 +720,8 @@ /obj/item/warp_cube/red = 1, /obj/item/reagent_containers/drinks/everfull = 2, /obj/item/clothing/suit/space/hardsuit/wizard = 2, - /obj/item/immortality_talisman = 1 ) //spells recharge when invincible + /obj/item/immortality_talisman = 1, //spells recharge when invincible + /obj/item/tarot_generator/wizard = 2) var/obj/item/pickeda = pick(list_a) value += list_a[pickeda] new pickeda(src) diff --git a/code/game/objects/structures/crates_lockers/closets/statue.dm b/code/game/objects/structures/crates_lockers/closets/statue.dm index 5dffb626cf7..0be43090cc9 100644 --- a/code/game/objects/structures/crates_lockers/closets/statue.dm +++ b/code/game/objects/structures/crates_lockers/closets/statue.dm @@ -117,3 +117,17 @@ user.dust() dump_contents() visible_message("[src] shatters!") + +/obj/structure/closet/statue/indestructible + resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF + timer = 240 SECONDS_TO_LIFE_CYCLES + +/obj/structure/closet/statue/indestructible/ex_act(severity) + return //No delimbing them + +/obj/structure/closet/statue/indestructible/shatter(mob/user) + return //No. Failsafe. + +/obj/structure/closet/statue/indestructible/singularity_act() + return //I mean maybe but no. + diff --git a/code/modules/awaymissions/mission_code/ruins/wizardcrash.dm b/code/modules/awaymissions/mission_code/ruins/wizardcrash.dm index c872499557d..be522b5ebb3 100644 --- a/code/modules/awaymissions/mission_code/ruins/wizardcrash.dm +++ b/code/modules/awaymissions/mission_code/ruins/wizardcrash.dm @@ -18,8 +18,12 @@ /obj/item/guardiancreator = 1, // jackpot. /obj/item/spellbook/oneuse/knock = 1, // tresspassing charges incoming /obj/item/gun/magic/wand/resurrection = 1, // medbay's best friend + /obj/item/tarot_generator = 1, // A little bit of everything, all of the time. /obj/item/spellbook/oneuse/charge = 20, // and now for less useful stuff to dilute the good loot chances /obj/item/spellbook/oneuse/summonitem = 20, /obj/item/spellbook/oneuse/forcewall = 10, - /obj/item/book/granter/spell/summon_cheese = 20 // hungry wizard stuff + /obj/item/tarot_card_pack = 10, + /obj/item/tarot_card_pack/jumbo = 6, + /obj/item/tarot_card_pack/mega = 4, + /obj/item/book/granter/spell/summon_cheese = 15 // hungry wizard stuff ) diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm index 852149ec771..a339ad902a0 100644 --- a/code/modules/clothing/clothing.dm +++ b/code/modules/clothing/clothing.dm @@ -611,6 +611,23 @@ /obj/item/clothing/suit/proc/setup_shielding() return +///Hierophant card shielding. Saves me time. +/obj/item/clothing/suit/proc/setup_hierophant_shielding() + var/datum/component/shielded/shield = GetComponent(/datum/component/shielded) + if(!shield) + AddComponent(/datum/component/shielded, recharge_start_delay = 0 SECONDS, shield_icon = "shield-hierophant", run_hit_callback = CALLBACK(src, PROC_REF(hierophant_shield_damaged))) + return + if(shield.shield_icon == "shield-hierophant") //If the hierophant shield has been used, recharge it. Otherwise, it's a shielded component we don't want to touch + shield.current_charges = 3 + +/// A proc for callback when the shield breaks, since I am stupid and want custom effects. +/obj/item/clothing/suit/proc/hierophant_shield_damaged(mob/living/wearer, attack_text, new_current_charges) + wearer.visible_message("[attack_text] is deflected in a burst of dark-purple sparks!") + new /obj/effect/temp_visual/cult/sparks/hierophant(get_turf(wearer)) + playsound(wearer,'sound/magic/blind.ogg', 200, TRUE, -2) + if(new_current_charges == 0) + wearer.visible_message("The runed shield around [wearer] suddenly disappears!") + //Proc that opens and closes jackets. /obj/item/clothing/suit/proc/adjustsuit(mob/user) if(ignore_suitadjust) diff --git a/code/modules/mining/lavaland/necropolis_chests.dm b/code/modules/mining/lavaland/necropolis_chests.dm index 65386ffc6de..099d24c5e85 100644 --- a/code/modules/mining/lavaland/necropolis_chests.dm +++ b/code/modules/mining/lavaland/necropolis_chests.dm @@ -69,6 +69,18 @@ if(23) new /obj/item/borg/upgrade/modkit/lifesteal(src) new /obj/item/bedsheet/cult(src) + if(24) + switch(rand(1, 11)) + if(1) + new /obj/item/blank_tarot_card(src) + if(2 to 5) + new /obj/item/tarot_card_pack(src) + if(6 to 8) + new /obj/item/tarot_card_pack/jumbo(src) + if(9, 10) + new /obj/item/tarot_card_pack/mega(src) + if(11) + new /obj/item/tarot_generator(src) // ~1/250? Seems reasonable //KA modkit design discs /obj/item/disk/design_disk/modkit_disk diff --git a/code/modules/reagents/chemistry/reagents_holder.dm b/code/modules/reagents/chemistry/reagents_holder.dm index 851788b90d8..4d68ff36daa 100644 --- a/code/modules/reagents/chemistry/reagents_holder.dm +++ b/code/modules/reagents/chemistry/reagents_holder.dm @@ -969,6 +969,17 @@ var/picked_reagent = pick(random_reagents) return picked_reagent +/// Returns a random reagent ID, with real non blacklisted balance boosting action! +/proc/get_unrestricted_random_reagent_id() + var/static/list/random_reagents + if(!length(random_reagents)) + random_reagents = list() + for(var/datum/reagent/thing as anything in subtypesof(/datum/reagent)) + var/R = initial(thing.id) + random_reagents += R + var/picked_reagent = pick(random_reagents) + return picked_reagent + /datum/reagents/proc/get_reagent_from_id(id) var/datum/reagent/result = null for(var/A in reagent_list) diff --git a/code/modules/station_goals/bluespace_tap.dm b/code/modules/station_goals/bluespace_tap.dm index cfa51561e12..3f88756eeb3 100644 --- a/code/modules/station_goals/bluespace_tap.dm +++ b/code/modules/station_goals/bluespace_tap.dm @@ -116,7 +116,11 @@ /obj/item/bedsheet/cult = 2, /obj/item/bedsheet/wiz = 2, /obj/item/stack/sheet/mineral/tranquillite/fifty = 3, - /obj/item/clothing/gloves/combat = 5 + /obj/item/clothing/gloves/combat = 5, + /obj/item/blank_tarot_card = 5, + /obj/item/tarot_card_pack = 5, + /obj/item/tarot_card_pack/jumbo = 3, + /obj/item/tarot_card_pack/mega = 2 ) /obj/effect/spawner/lootdrop/bluespace_tap/organic diff --git a/icons/effects/effects.dmi b/icons/effects/effects.dmi index d2419382171..656a8380279 100644 Binary files a/icons/effects/effects.dmi and b/icons/effects/effects.dmi differ diff --git a/icons/obj/card.dmi b/icons/obj/card.dmi index 7596aae9be0..3818dd761e9 100644 Binary files a/icons/obj/card.dmi and b/icons/obj/card.dmi differ diff --git a/icons/obj/playing_cards.dmi b/icons/obj/playing_cards.dmi index 866cf0a5fc4..58d9508af72 100644 Binary files a/icons/obj/playing_cards.dmi and b/icons/obj/playing_cards.dmi differ diff --git a/paradise.dme b/paradise.dme index be76cb94d91..6774197686a 100644 --- a/paradise.dme +++ b/paradise.dme @@ -752,6 +752,7 @@ #include "code\game\gamemodes\vampire\vampire_gamemode.dm" #include "code\game\gamemodes\wizard\artefact.dm" #include "code\game\gamemodes\wizard\godhand.dm" +#include "code\game\gamemodes\wizard\magic_tarot.dm" #include "code\game\gamemodes\wizard\raginmages.dm" #include "code\game\gamemodes\wizard\rightandwrong.dm" #include "code\game\gamemodes\wizard\soulstone.dm"