diff --git a/code/__DEFINES/antagonists.dm b/code/__DEFINES/antagonists.dm index 433f44e095..d8d5484ff5 100644 --- a/code/__DEFINES/antagonists.dm +++ b/code/__DEFINES/antagonists.dm @@ -1,4 +1,5 @@ #define ANTAG_DATUM_CULT /datum/antagonist/cult #define ANTAG_DATUM_CULT_MASTER /datum/antagonist/cult/master #define ANTAG_DATUM_CLOCKCULT /datum/antagonist/clockcult -#define ANTAG_DATUM_CLOCKCULT_SILENT /datum/antagonist/clockcult/silent \ No newline at end of file +#define ANTAG_DATUM_CLOCKCULT_SILENT /datum/antagonist/clockcult/silent +#define ANTAG_DATUM_DEVIL /datum/antagonist/devil \ No newline at end of file diff --git a/code/__DEFINES/contracts.dm b/code/__DEFINES/contracts.dm index e2f4aff409..e740be79dd 100644 --- a/code/__DEFINES/contracts.dm +++ b/code/__DEFINES/contracts.dm @@ -3,6 +3,7 @@ #define CONTRACT_PRESTIGE "prestige" #define CONTRACT_MAGIC "magic" #define CONTRACT_REVIVE "revive" +#define CONTRACT_FRIEND "friend" #define CONTRACT_KNOWLEDGE "knowledge" #define CONTRACT_UNWILLING "unwilling" diff --git a/code/datums/ai_laws.dm b/code/datums/ai_laws.dm index 8d817265e6..7875b7921c 100644 --- a/code/datums/ai_laws.dm +++ b/code/datums/ai_laws.dm @@ -420,7 +420,7 @@ return /datum/ai_laws/proc/clear_law_sixsixsix(force) - if(force || !(owner && owner.mind.devilinfo)) + if(force || !is_devil(owner)) devillaws = null /datum/ai_laws/proc/associate(mob/living/silicon/M) diff --git a/code/datums/antagonists/antag_datum.dm b/code/datums/antagonists/antag_datum.dm index 396c185961..33adab5c3d 100644 --- a/code/datums/antagonists/antag_datum.dm +++ b/code/datums/antagonists/antag_datum.dm @@ -7,6 +7,7 @@ var/can_coexist_with_others = TRUE //Whether or not the person will be able to have more than one datum var/list/typecache_datum_blacklist = list() //List of datums this type can't coexist with + var/delete_on_death = TRUE /datum/antagonist/New(datum/mind/new_owner) typecache_datum_blacklist = typecacheof(typecache_datum_blacklist) @@ -59,4 +60,4 @@ return /datum/antagonist/proc/farewell() - return + return \ No newline at end of file diff --git a/code/datums/mind.dm b/code/datums/mind.dm index 32690d20b3..c223d3b315 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -56,13 +56,12 @@ var/antag_hud_icon_state = null //this mind's ANTAG_HUD should have this icon_state var/datum/atom_hud/antag/antag_hud = null //this mind's antag HUD var/datum/gang/gang_datum //Which gang this mind belongs to, if any - var/datum/devilinfo/devilinfo //Information about the devil, if any. var/damnation_type = 0 var/datum/mind/soulOwner //who owns the soul. Under normal circumstances, this will point to src + var/hasSoul = TRUE // If false, renders the character unable to sell their soul. var/isholy = FALSE //is this person a chaplain or admin role allowed to use bibles var/mob/living/enslaved_to //If this mind's master is another mob (i.e. adamantine golems) - var/datum/language_holder/language_holder /datum/mind/New(var/key) @@ -73,7 +72,9 @@ SSticker.minds -= src if(islist(antag_datums)) for(var/i in antag_datums) - qdel(i) + var/datum/antagonist/antag_datum = i + if(antag_datum.delete_on_death) + qdel(i) antag_datums = null return ..() @@ -324,7 +325,8 @@ "nuclear", "traitor", // "traitorchan", "monkey", - "clockcult" + "clockcult", + "devil" ) var/text = "" @@ -595,8 +597,9 @@ if(SSticker.mode.config_tag == "devil") text = uppertext(text) text = "[text]: " - if(src in SSticker.mode.devils) - if(devilinfo && !devilinfo.ascendable) + var/datum/antagonist/devil/devilinfo = has_antag_datum(ANTAG_DATUM_DEVIL) + if(devilinfo) + if(!devilinfo.ascendable) text += "DEVIL|Ascendable Devil|sintouched|human" else text += "DEVIL|ASCENDABLE DEVIL|sintouched|human" @@ -1156,34 +1159,14 @@ to_chat(usr, "The objectives for traitor [key] have been generated. You can edit them and anounce manually.") else if(href_list["devil"]) + var/datum/antagonist/devil/devilinfo = has_antag_datum(ANTAG_DATUM_DEVIL) switch(href_list["devil"]) if("clear") if(src in SSticker.mode.devils) - if(istype(current,/mob/living/carbon/true_devil/)) - if(devilinfo) - devilinfo.regress_blood_lizard() - else - to_chat(usr, "Something went wrong with removing the devil, we were unable to find an attached devilinfo..") - SSticker.mode.devils -= src - special_role = null - to_chat(current, "Your infernal link has been severed! You are no longer a devil!") - RemoveSpell(/obj/effect/proc_holder/spell/targeted/infernal_jaunt) - RemoveSpell(/obj/effect/proc_holder/spell/aimed/fireball/hellish) - RemoveSpell(/obj/effect/proc_holder/spell/targeted/summon_contract) - RemoveSpell(/obj/effect/proc_holder/spell/targeted/conjure_item/summon_pitchfork) - RemoveSpell(/obj/effect/proc_holder/spell/targeted/conjure_item/violin) - RemoveSpell(/obj/effect/proc_holder/spell/targeted/conjure_item/summon_pitchfork/greater) - RemoveSpell(/obj/effect/proc_holder/spell/targeted/conjure_item/summon_pitchfork/ascended) - RemoveSpell(/obj/effect/proc_holder/spell/targeted/summon_dancefloor) - RemoveSpell(/obj/effect/proc_holder/spell/targeted/sintouch) - RemoveSpell(/obj/effect/proc_holder/spell/targeted/sintouch/ascended) + remove_devil(current) message_admins("[key_name_admin(usr)] has de-devil'ed [current].") - devilinfo = null - if(issilicon(current)) - var/mob/living/silicon/S = current - S.clear_law_sixsixsix(current) log_admin("[key_name(usr)] has de-devil'ed [current].") - else if(src in SSticker.mode.sintouched) + if(src in SSticker.mode.sintouched) SSticker.mode.sintouched -= src message_admins("[key_name_admin(usr)] has de-sintouch'ed [current].") log_admin("[key_name(usr)] has de-sintouch'ed [current].") @@ -1196,12 +1179,7 @@ if(!ishuman(current) && !iscyborg(current)) to_chat(usr, "This only works on humans and cyborgs!") return - SSticker.mode.devils += src - special_role = "devil" - SSticker.mode.finalize_devil(src, FALSE) - SSticker.mode.add_devil_objectives(src, 2) - announceDevilLaws() - announce_objectives() + add_devil(current, FALSE) message_admins("[key_name_admin(usr)] has devil'ed [current].") log_admin("[key_name(usr)] has devil'ed [current].") if("ascendable_devil") @@ -1213,12 +1191,7 @@ if(!ishuman(current) && !iscyborg(current)) to_chat(usr, "This only works on humans and cyborgs!") return - SSticker.mode.devils += src - special_role = "devil" - SSticker.mode.finalize_devil(src, TRUE) - SSticker.mode.add_devil_objectives(src, 2) - announceDevilLaws() - announce_objectives() + add_devil(current, TRUE) message_admins("[key_name_admin(usr)] has devil'ed [current]. The devil has been marked as ascendable.") log_admin("[key_name(usr)] has devil'ed [current]. The devil has been marked as ascendable.") if("sintouched") @@ -1448,8 +1421,8 @@ if(!(src in SSticker.mode.cult)) SSticker.mode.add_cultist(src,FALSE) special_role = "Cultist" - to_chat(current, "You catch a glimpse of the Realm of Nar-Sie, The Geometer of Blood. You now see how flimsy the world is, you see that it should be open to the knowledge of Nar-Sie.") - to_chat(current, "Assist your new compatriots in their dark dealings. Their goal is yours, and yours is theirs. You serve the Dark One above all else. Bring It back.") + to_chat(current, "You catch a glimpse of the Realm of Nar-Sie, The Geometer of Blood. You now see how flimsy your world is, you see that it should be open to the knowledge of Nar-Sie.") + to_chat(current, "Assist your new bretheren in their dark dealings. Their goal is yours, and yours is theirs. You serve the Dark One above all else. Bring It back.") var/datum/antagonist/cult/C C.cult_memorization(src) var/mob/living/carbon/human/H = current @@ -1542,6 +1515,9 @@ spell_list += S S.action.Grant(current) +/datum/mind/proc/owns_soul() + return soulOwner == src + //To remove a specific spell from a mind /datum/mind/proc/RemoveSpell(obj/effect/proc_holder/spell/spell) if(!spell) @@ -1639,4 +1615,4 @@ /mob/living/silicon/pai/mind_initialize() ..() mind.assigned_role = "pAI" - mind.special_role = "" + mind.special_role = "" \ No newline at end of file diff --git a/code/datums/soullink.dm b/code/datums/soullink.dm index ee99103c3d..de73a8e74c 100644 --- a/code/datums/soullink.dm +++ b/code/datums/soullink.dm @@ -108,6 +108,15 @@ if(soulowner) soulowner.death(gibbed) +///////////////// +// Demon Bind // +///////////////// +//When the soulowner dies, the soulsharer dies, but NOT vice versa +//This is intended for two players(or AI) and two mobs + +/datum/soullink/oneway/ownerDies(gibbed, mob/living/owner) + if(soulsharer) + soulsharer.dust(FALSE) ///////////////// diff --git a/code/game/gamemodes/clock_cult/clock_cult.dm b/code/game/gamemodes/clock_cult/clock_cult.dm index 7fccb37d3c..a6b6834c9a 100644 --- a/code/game/gamemodes/clock_cult/clock_cult.dm +++ b/code/game/gamemodes/clock_cult/clock_cult.dm @@ -75,7 +75,7 @@ Credit where due: /proc/remove_servant_of_ratvar(mob/living/L, silent = FALSE) if(!L || !L.mind) return - var/datum/antagonist/clockcult/clock_datum = L.mind.has_antag_datum(/datum/antagonist/clockcult) + var/datum/antagonist/clockcult/clock_datum = L.mind.has_antag_datum(ANTAG_DATUM_CLOCKCULT) if(!clock_datum) return FALSE clock_datum.silent = silent diff --git a/code/game/gamemodes/devil/devil.dm b/code/game/gamemodes/devil/devil.dm index b64ef55406..31291ca143 100644 --- a/code/game/gamemodes/devil/devil.dm +++ b/code/game/gamemodes/devil/devil.dm @@ -1,5 +1,6 @@ /mob/living/proc/check_devil_bane_multiplier(obj/item/weapon, mob/living/attacker) - switch(mind.devilinfo.bane) + var/datum/antagonist/devil/devilInfo = mind.has_antag_datum(ANTAG_DATUM_DEVIL) + switch(devilInfo.bane) if(BANE_WHITECLOTHES) if(ishuman(attacker)) var/mob/living/carbon/human/H = attacker @@ -21,13 +22,13 @@ /obj/item/clothing/under/suit_jacket/white = 0.5, /obj/item/clothing/under/burial = 1 ) - if(whiteness[U.type]) + if(U && whiteness[U.type]) src.visible_message("[src] seems to have been harmed by the purity of [attacker]'s clothes.", "Unsullied white clothing is disrupting your form.") return whiteness[U.type] + 1 if(BANE_TOOLBOX) if(istype(weapon,/obj/item/weapon/storage/toolbox)) src.visible_message("The [weapon] seems unusually robust this time.", "The [weapon] is your unmaking!") - return 2.5 // Will take four hits with a normal toolbox. + return 2.5 // Will take four hits with a normal toolbox to crit. if(BANE_HARVEST) if(istype(weapon,/obj/item/weapon/reagent_containers/food/snacks/grown/)) src.visible_message("The spirits of the harvest aid in the exorcism.", "The harvest spirits are harming you.") diff --git a/code/game/gamemodes/devil/devil_game_mode.dm b/code/game/gamemodes/devil/devil_game_mode.dm index c275ac790a..41016fa770 100644 --- a/code/game/gamemodes/devil/devil_game_mode.dm +++ b/code/game/gamemodes/devil/devil_game_mode.dm @@ -19,7 +19,6 @@ + Crew: Resist the lure of sin and remain pure!" /datum/game_mode/devil/pre_setup() - if(config.protect_roles_from_antagonist) restricted_jobs += protected_jobs if(config.protect_assistant_from_antagonist) @@ -56,10 +55,22 @@ return 1 /datum/game_mode/devil/proc/post_setup_finalize(datum/mind/devil) - set waitfor = FALSE - sleep(rand(10,100)) - finalize_devil(devil, TRUE) - sleep(100) - add_devil_objectives(devil, objective_count) //This has to be in a separate loop, as we need devil names to be generated before we give objectives in devil agent. - devil.announceDevilLaws() - devil.announce_objectives() \ No newline at end of file + add_devil(devil.current, ascendable = TRUE) //Devil gamemode devils are ascendable. + add_devil_objectives(devil,2) + +/proc/is_devil(mob/living/M) + return M && M.mind && M.mind.has_antag_datum(ANTAG_DATUM_DEVIL) + +/proc/add_devil(mob/living/L, ascendable = FALSE) + if(!L || !L.mind) + return FALSE + var/datum/antagonist/devil/devil_datum = L.mind.add_antag_datum(ANTAG_DATUM_DEVIL) + devil_datum.ascendable = ascendable + return devil_datum + +/proc/remove_devil(mob/living/L) + if(!L || !L.mind) + return FALSE + var/datum/antagonist/devil_datum = L.mind.has_antag_datum(ANTAG_DATUM_DEVIL) + devil_datum.on_removal() + return TRUE diff --git a/code/game/gamemodes/devil/devilinfo.dm b/code/game/gamemodes/devil/devilinfo.dm index 01437cdf2e..0ea5231cfd 100644 --- a/code/game/gamemodes/devil/devilinfo.dm +++ b/code/game/gamemodes/devil/devilinfo.dm @@ -78,8 +78,15 @@ GLOBAL_LIST_INIT(lawlorify, list ( BANISH_FUNERAL_GARB = "If your corpse is clad in funeral garments, you will be unable to resurrect." ) )) -/datum/devilinfo - var/datum/mind/owner = null + +//These are also used in the codex gigas, so let's declare them globally. +GLOBAL_LIST_INIT(devil_pre_title, list("Dark ", "Hellish ", "Fallen ", "Fiery ", "Sinful ", "Blood ", "Fluffy ")) +GLOBAL_LIST_INIT(devil_title, list("Lord ", "Prelate ", "Count ", "Viscount ", "Vizier ", "Elder ", "Adept ")) +GLOBAL_LIST_INIT(devil_syllable, list("hal", "ve", "odr", "neit", "ci", "quon", "mya", "folth", "wren", "geyr", "hil", "niet", "twou", "phi", "coa")) +GLOBAL_LIST_INIT(devil_suffix, list(" the Red", " the Soulless", " the Master", ", the Lord of all things", ", Jr.")) +/datum/antagonist/devil + //Don't delete upon mind destruction, otherwise soul re-selling will break. + delete_on_death = FALSE var/obligation var/ban var/bane @@ -89,55 +96,63 @@ GLOBAL_LIST_INIT(lawlorify, list ( var/reviveNumber = 0 var/form = BASIC_DEVIL var/exists = 0 - var/static/list/dont_remove_spells = list( - /obj/effect/proc_holder/spell/targeted/summon_contract, - /obj/effect/proc_holder/spell/targeted/conjure_item/violin, - /obj/effect/proc_holder/spell/targeted/summon_dancefloor) + var/static/list/removable_devil_spells = list( + /obj/effect/proc_holder/spell/aimed/fireball/hellish, + /obj/effect/proc_holder/spell/targeted/conjure_item/summon_pitchfork, + /obj/effect/proc_holder/spell/aimed/fireball/hellish, + /obj/effect/proc_holder/spell/targeted/infernal_jaunt, + /obj/effect/proc_holder/spell/targeted/conjure_item/summon_pitchfork/greater, + /obj/effect/proc_holder/spell/targeted/sintouch, + /obj/effect/proc_holder/spell/targeted/conjure_item/summon_pitchfork/ascended, + /obj/effect/proc_holder/spell/targeted/sintouch/ascended) + var/static/list/devil_spells = list( + /obj/effect/proc_holder/spell/aimed/fireball/hellish, + /obj/effect/proc_holder/spell/targeted/conjure_item/summon_pitchfork, + /obj/effect/proc_holder/spell/aimed/fireball/hellish, + /obj/effect/proc_holder/spell/targeted/infernal_jaunt, + /obj/effect/proc_holder/spell/targeted/conjure_item/summon_pitchfork/greater, + /obj/effect/proc_holder/spell/targeted/sintouch, + /obj/effect/proc_holder/spell/targeted/conjure_item/summon_pitchfork/ascended, + /obj/effect/proc_holder/spell/targeted/sintouch/ascended, + /obj/effect/proc_holder/spell/targeted/summon_contract, + /obj/effect/proc_holder/spell/targeted/conjure_item/violin, + /obj/effect/proc_holder/spell/targeted/summon_dancefloor) var/ascendable = FALSE -/datum/devilinfo/New() +/datum/antagonist/devil/New() ..() - dont_remove_spells = typecacheof(dont_remove_spells) + devil_spells = typecacheof(devil_spells) + truename = randomDevilName() + ban = randomdevilban() + bane = randomdevilbane() + obligation = randomdevilobligation() + banish = randomdevilbanish() + GLOB.allDevils[lowertext(truename)] = src -/proc/randomDevilInfo(name = randomDevilName()) - var/datum/devilinfo/devil = new - devil.truename = name - devil.bane = randomdevilbane() - devil.obligation = randomdevilobligation() - devil.ban = randomdevilban() - devil.banish = randomdevilbanish() - return devil - -/proc/devilInfo(name, saveDetails = 0) +/proc/devilInfo(name) if(GLOB.allDevils[lowertext(name)]) return GLOB.allDevils[lowertext(name)] else - var/datum/devilinfo/devil = randomDevilInfo(name) + var/datum/fakeDevil/devil = new /datum/fakeDevil(name) GLOB.allDevils[lowertext(name)] = devil - devil.exists = saveDetails return devil - - /proc/randomDevilName() - var/preTitle = "" - var/title = "" - var/mainName = "" - var/suffix = "" + var/name = "" if(prob(65)) if(prob(35)) - preTitle = pick("Dark ", "Hellish ", "Fiery ", "Sinful ", "Blood ") - title = pick("Lord ", "Fallen Prelate ", "Count ", "Viscount ", "Vizier ", "Elder ", "Adept ") + name = pick(GLOB.devil_pre_title) + name += pick(GLOB.devil_title) var/probability = 100 - mainName = pick("Hal", "Ve", "Odr", "Neit", "Ci", "Quon", "Mya", "Folth", "Wren", "Gyer", "Geyr", "Hil", "Niet", "Twou", "Hu", "Don") + name += pick(GLOB.devil_syllable) while(prob(probability)) - mainName += pick("hal", "ve", "odr", "neit", "ca", "quon", "mya", "folth", "wren", "gyer", "geyr", "hil", "niet", "twoe", "phi", "coa") + name += pick(GLOB.devil_syllable) probability -= 20 if(prob(40)) - suffix = pick(" the Red", " the Soulless", " the Master", ", the Lord of all things", ", Jr.") - return preTitle + title + mainName + suffix + name += pick(GLOB.devil_suffix) + return name /proc/randomdevilobligation() return pick(OBLIGATION_FOOD, OBLIGATION_FIDDLE, OBLIGATION_DANCEOFF, OBLIGATION_GREET, OBLIGATION_PRESENCEKNOWN, OBLIGATION_SAYNAME, OBLIGATION_ANNOUNCEKILL, OBLIGATION_ANSWERTONAME) @@ -151,7 +166,7 @@ GLOBAL_LIST_INIT(lawlorify, list ( /proc/randomdevilbanish() return pick(BANISH_WATER, BANISH_COFFIN, BANISH_FORMALDYHIDE, BANISH_RUNES, BANISH_CANDLES, BANISH_DESTRUCTION, BANISH_FUNERAL_GARB) -/datum/devilinfo/proc/add_soul(datum/mind/soul) +/datum/antagonist/devil/proc/add_soul(datum/mind/soul) if(soulsOwned.Find(soul)) return soulsOwned += soul @@ -169,13 +184,13 @@ GLOBAL_LIST_INIT(lawlorify, list ( if(ARCH_THRESHOLD) increase_arch_devil() -/datum/devilinfo/proc/remove_soul(datum/mind/soul) +/datum/antagonist/devil/proc/remove_soul(datum/mind/soul) if(soulsOwned.Remove(soul)) check_regression() to_chat(owner.current, "You feel as though a soul has slipped from your grasp.") update_hud() -/datum/devilinfo/proc/check_regression() +/datum/antagonist/devil/proc/check_regression() if(form == ARCH_DEVIL) return //arch devil can't regress //Yes, fallthrough behavior is intended, so I can't use a switch statement. @@ -187,7 +202,7 @@ GLOBAL_LIST_INIT(lawlorify, list ( remove_spells() to_chat(owner.current, "As punishment for your failures, all of your powers except contract creation have been revoked.") -/datum/devilinfo/proc/regress_humanoid() +/datum/antagonist/devil/proc/regress_humanoid() to_chat(owner.current, "Your powers weaken, have more contracts be signed to regain power.") if(ishuman(owner.current)) var/mob/living/carbon/human/H = owner.current @@ -198,7 +213,7 @@ GLOBAL_LIST_INIT(lawlorify, list ( owner.current.forceMove(get_turf(owner.current))//Fixes dying while jaunted leaving you permajaunted. form = BASIC_DEVIL -/datum/devilinfo/proc/regress_blood_lizard() +/datum/antagonist/devil/proc/regress_blood_lizard() var/mob/living/carbon/true_devil/D = owner.current to_chat(D, "Your powers weaken, have more contracts be signed to regain power.") D.oldform.loc = D.loc @@ -209,7 +224,7 @@ GLOBAL_LIST_INIT(lawlorify, list ( update_hud() -/datum/devilinfo/proc/increase_blood_lizard() +/datum/antagonist/devil/proc/increase_blood_lizard() to_chat(owner.current, "You feel as though your humanoid form is about to shed. You will soon turn into a blood lizard.") sleep(50) if(ishuman(owner.current)) @@ -227,7 +242,7 @@ GLOBAL_LIST_INIT(lawlorify, list ( -/datum/devilinfo/proc/increase_true_devil() +/datum/antagonist/devil/proc/increase_true_devil() to_chat(owner.current, "You feel as though your current form is about to shed. You will soon turn into a true devil.") sleep(50) var/mob/living/carbon/true_devil/A = new /mob/living/carbon/true_devil(owner.current.loc) @@ -241,7 +256,7 @@ GLOBAL_LIST_INIT(lawlorify, list ( update_hud() -/datum/devilinfo/proc/increase_arch_devil() +/datum/antagonist/devil/proc/increase_arch_devil() if(!ascendable) return var/mob/living/carbon/true_devil/D = owner.current @@ -291,17 +306,17 @@ GLOBAL_LIST_INIT(lawlorify, list ( SSticker.mode.devil_ascended++ form = ARCH_DEVIL -/datum/devilinfo/proc/remove_spells() +/datum/antagonist/devil/proc/remove_spells() for(var/X in owner.spell_list) var/obj/effect/proc_holder/spell/S = X - if(!is_type_in_typecache(S, dont_remove_spells)) + if(is_type_in_typecache(S, removable_devil_spells)) owner.RemoveSpell(S) -/datum/devilinfo/proc/give_summon_contract() +/datum/antagonist/devil/proc/give_summon_contract() owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/summon_contract(null)) -/datum/devilinfo/proc/give_base_spells(give_summon_contract = 0) +/datum/antagonist/devil/proc/give_base_spells(give_summon_contract = 0) remove_spells() owner.AddSpell(new /obj/effect/proc_holder/spell/aimed/fireball/hellish(null)) owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/conjure_item/summon_pitchfork(null)) @@ -312,25 +327,25 @@ GLOBAL_LIST_INIT(lawlorify, list ( if(obligation == OBLIGATION_DANCEOFF) owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/summon_dancefloor(null)) -/datum/devilinfo/proc/give_lizard_spells() +/datum/antagonist/devil/proc/give_lizard_spells() remove_spells() owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/conjure_item/summon_pitchfork(null)) owner.AddSpell(new /obj/effect/proc_holder/spell/aimed/fireball/hellish(null)) owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/infernal_jaunt(null)) -/datum/devilinfo/proc/give_true_spells() +/datum/antagonist/devil/proc/give_true_spells() remove_spells() owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/conjure_item/summon_pitchfork/greater(null)) owner.AddSpell(new /obj/effect/proc_holder/spell/aimed/fireball/hellish(null)) owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/infernal_jaunt(null)) owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/sintouch(null)) -/datum/devilinfo/proc/give_arch_spells() +/datum/antagonist/devil/proc/give_arch_spells() remove_spells() owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/conjure_item/summon_pitchfork/ascended(null)) owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/sintouch/ascended(null)) -/datum/devilinfo/proc/beginResurrectionCheck(mob/living/body) +/datum/antagonist/devil/proc/beginResurrectionCheck(mob/living/body) if(SOULVALUE>0) to_chat(owner.current, "Your body has been damaged to the point that you may no longer use it. At the cost of some of your power, you will return to life soon. Remain in your body.") sleep(DEVILRESURRECTTIME) @@ -350,7 +365,7 @@ GLOBAL_LIST_INIT(lawlorify, list ( else to_chat(owner.current, "Your hellish powers are too weak to resurrect yourself.") -/datum/devilinfo/proc/check_banishment(mob/living/body) +/datum/antagonist/devil/proc/check_banishment(mob/living/body) switch(banish) if(BANISH_WATER) if(istype(body, /mob/living/carbon)) @@ -394,7 +409,7 @@ GLOBAL_LIST_INIT(lawlorify, list ( return 1 return 0 -/datum/devilinfo/proc/hellish_resurrection(mob/living/body) +/datum/antagonist/devil/proc/hellish_resurrection(mob/living/body) message_admins("[owner.name] (true name is: [truename]) is resurrecting using hellish energy.") if(SOULVALUE < ARCH_THRESHOLD && ascendable) // once ascended, arch devils do not go down in power by any means. reviveNumber += LOSS_PER_DEATH @@ -413,7 +428,7 @@ GLOBAL_LIST_INIT(lawlorify, list ( create_new_body() check_regression() -/datum/devilinfo/proc/create_new_body() +/datum/antagonist/devil/proc/create_new_body() if(GLOB.blobstart.len > 0) var/turf/targetturf = get_turf(pick(GLOB.blobstart)) var/mob/currentMob = owner.current @@ -451,8 +466,65 @@ GLOBAL_LIST_INIT(lawlorify, list ( throw EXCEPTION("Unable to find a blobstart landmark for hellish resurrection") -/datum/devilinfo/proc/update_hud() +/datum/antagonist/devil/proc/update_hud() if(istype(owner.current, /mob/living/carbon)) var/mob/living/C = owner.current if(C.hud_used && C.hud_used.devilsouldisplay) C.hud_used.devilsouldisplay.update_counter(SOULVALUE) + +/datum/antagonist/devil/greet() + to_chat(owner.current, "You remember your link to the infernal. You are [truename], an agent of hell, a devil. And you were sent to the plane of creation for a reason. A greater purpose. Convince the crew to sin, and embroiden Hell's grasp.") + to_chat(owner.current, "However, your infernal form is not without weaknesses.") + to_chat(owner.current, "You may not use violence to coerce someone into selling their soul.") + to_chat(owner.current, "You may not directly and knowingly physically harm a devil, other than yourself.") + to_chat(owner.current, GLOB.lawlorify[LAW][bane]) + to_chat(owner.current, GLOB.lawlorify[LAW][ban]) + to_chat(owner.current, GLOB.lawlorify[LAW][obligation]) + to_chat(owner.current, GLOB.lawlorify[LAW][banish]) + to_chat(owner.current, "Remember, the crew can research your weaknesses if they find out your devil name.
") + .=..() + +/datum/antagonist/devil/on_gain() + owner.store_memory("Your devilic true name is [truename]
[GLOB.lawlorify[LAW][ban]]
You may not use violence to coerce someone into selling their soul.
You may not directly and knowingly physically harm a devil, other than yourself.
[GLOB.lawlorify[LAW][bane]]
[GLOB.lawlorify[LAW][obligation]]
[GLOB.lawlorify[LAW][banish]]
") + if(issilicon(owner.current)) + var/mob/living/silicon/robot_devil = owner.current + var/laws = list("You may not use violence to coerce someone into selling their soul.", "You may not directly and knowingly physically harm a devil, other than yourself.", GLOB.lawlorify[LAW][ban], GLOB.lawlorify[LAW][obligation], "Accomplish your objectives at all costs.") + robot_devil.set_law_sixsixsix(laws) + sleep(10) + if(owner.assigned_role == "Clown" && ishuman(owner.current)) + var/mob/living/carbon/human/S = owner.current + to_chat(S, "Your infernal nature has allowed you to overcome your clownishness.") + S.dna.remove_mutation(CLOWNMUT) + .=..() + +/datum/antagonist/devil/on_removal() + to_chat(owner.current, "Your infernal link has been severed! You are no longer a devil!") + .=..() + +/datum/antagonist/devil/apply_innate_effects(mob/living/mob_override) + give_base_spells(1) + owner.current.grant_all_languages(TRUE) + update_hud() + .=..() + +/datum/antagonist/devil/remove_innate_effects(mob/living/mob_override) + for(var/X in owner.spell_list) + var/obj/effect/proc_holder/spell/S = X + if(is_type_in_typecache(S, devil_spells)) + owner.RemoveSpell(S) + .=..() + +//A simple super light weight datum for the codex gigas. +/datum/fakeDevil + var/truename + var/bane + var/obligation + var/ban + var/banish + +/datum/fakeDevil/New(name = randomDevilName()) + truename = name + bane = randomdevilbane() + obligation = randomdevilobligation() + ban = randomdevilban() + banish = randomdevilbanish() \ No newline at end of file diff --git a/code/game/gamemodes/devil/game_mode.dm b/code/game/gamemodes/devil/game_mode.dm index 515a6e4c97..722c1f525e 100644 --- a/code/game/gamemodes/devil/game_mode.dm +++ b/code/game/gamemodes/devil/game_mode.dm @@ -29,25 +29,6 @@ text += "
" to_chat(world, text) - -/datum/game_mode/proc/finalize_devil(datum/mind/devil_mind, ascendable = FALSE) - set waitfor = FALSE - var/trueName= randomDevilName() - - devil_mind.devilinfo = devilInfo(trueName, 1) - devil_mind.devilinfo.ascendable = ascendable - devil_mind.store_memory("Your devilic true name is [devil_mind.devilinfo.truename]
[GLOB.lawlorify[LAW][devil_mind.devilinfo.ban]]
You may not use violence to coerce someone into selling their soul.
You may not directly and knowingly physically harm a devil, other than yourself.
[GLOB.lawlorify[LAW][devil_mind.devilinfo.bane]]
[GLOB.lawlorify[LAW][devil_mind.devilinfo.obligation]]
[GLOB.lawlorify[LAW][devil_mind.devilinfo.banish]]
") - devil_mind.devilinfo.owner = devil_mind - devil_mind.devilinfo.give_base_spells(1) - if(issilicon(devil_mind.current)) - add_law_sixsixsix(devil_mind.current) - sleep(10) - devil_mind.devilinfo.update_hud() - if(devil_mind.assigned_role == "Clown" && ishuman(devil_mind.current)) - var/mob/living/carbon/human/S = devil_mind.current - to_chat(S, "Your infernal nature has allowed you to overcome your clownishness.") - S.dna.remove_mutation(CLOWNMUT) - /datum/game_mode/proc/add_devil_objectives(datum/mind/devil_mind, quantity) var/list/validtypes = list(/datum/objective/devil/soulquantity, /datum/objective/devil/soulquality, /datum/objective/devil/sintouch, /datum/objective/devil/buy_target) for(var/i = 1 to quantity) @@ -60,28 +41,16 @@ else objective.find_target() -/datum/mind/proc/announceDevilLaws() +/datum/game_mode/proc/printdevilinfo(mob/living/ply) + var/datum/antagonist/devil/devilinfo = is_devil(ply) if(!devilinfo) - return - to_chat(current, "You remember your link to the infernal. You are [src.devilinfo.truename], an agent of hell, a devil. And you were sent to the plane of creation for a reason. A greater purpose. Convince the crew to sin, and embroiden Hell's grasp.") - to_chat(current, "However, your infernal form is not without weaknesses.") - to_chat(current, "You may not use violence to coerce someone into selling their soul.") - to_chat(current, "You may not directly and knowingly physically harm a devil, other than yourself.") - to_chat(current, GLOB.lawlorify[LAW][src.devilinfo.bane]) - to_chat(current, GLOB.lawlorify[LAW][src.devilinfo.ban]) - to_chat(current, GLOB.lawlorify[LAW][src.devilinfo.obligation]) - to_chat(current, GLOB.lawlorify[LAW][src.devilinfo.banish]) - to_chat(current, "

Remember, the crew can research your weaknesses if they find out your devil name.
") - -/datum/game_mode/proc/printdevilinfo(datum/mind/ply) - if(!ply.devilinfo) return "Target is not a devil." - var/text = "
The devil's true name is: [ply.devilinfo.truename]
" + var/text = "
The devil's true name is: [devilinfo.truename]
" text += "The devil's bans were:
" - text += " [GLOB.lawlorify[LORE][ply.devilinfo.ban]]
" - text += " [GLOB.lawlorify[LORE][ply.devilinfo.bane]]
" - text += " [GLOB.lawlorify[LORE][ply.devilinfo.obligation]]
" - text += " [GLOB.lawlorify[LORE][ply.devilinfo.banish]]

" + text += " [GLOB.lawlorify[LORE][devilinfo.ban]]
" + text += " [GLOB.lawlorify[LORE][devilinfo.bane]]
" + text += " [GLOB.lawlorify[LORE][devilinfo.obligation]]
" + text += " [GLOB.lawlorify[LORE][devilinfo.banish]]

" return text /datum/game_mode/proc/update_devil_icons_added(datum/mind/devil_mind) diff --git a/code/game/gamemodes/devil/objectives.dm b/code/game/gamemodes/devil/objectives.dm index 95af5ae747..164df56da0 100644 --- a/code/game/gamemodes/devil/objectives.dm +++ b/code/game/gamemodes/devil/objectives.dm @@ -14,7 +14,9 @@ /datum/objective/devil/soulquantity/check_completion() var/count = 0 - for(var/S in owner.devilinfo.soulsOwned) + var/datum/antagonist/devil/devilDatum = owner.has_antag_datum(ANTAG_DATUM_DEVIL) + var/list/souls = devilDatum.soulsOwned + for(var/S in souls) //Just a sanity check. var/datum/mind/L = S if(L.soulOwner == owner) count++ @@ -52,9 +54,11 @@ /datum/objective/devil/soulquality/check_completion() var/count = 0 - for(var/S in owner.devilinfo.soulsOwned) + var/datum/antagonist/devil/devilDatum = owner.has_antag_datum(ANTAG_DATUM_DEVIL) + var/list/souls = devilDatum.soulsOwned + for(var/S in souls) var/datum/mind/L = S - if(L.soulOwner != L && L.damnation_type == contractType) + if(!L.owns_soul() && L.damnation_type == contractType) count++ return count>=target_amount @@ -91,16 +95,21 @@ /datum/objective/devil/outsell/New() /datum/objective/devil/outsell/update_explanation_text() - explanation_text = "Purchase and retain control over more souls than [target.devilinfo.truename], known to mortals as [target.name], the [target.assigned_role]." + var/datum/antagonist/devil/opponent = target.has_antag_datum(ANTAG_DATUM_DEVIL) + explanation_text = "Purchase and retain control over more souls than [opponent.truename], known to mortals as [target.name], the [target.assigned_role]." /datum/objective/devil/outsell/check_completion() var/selfcount = 0 - for(var/S in owner.devilinfo.soulsOwned) + var/datum/antagonist/devil/devilDatum = owner.has_antag_datum(ANTAG_DATUM_DEVIL) + var/list/souls = devilDatum.soulsOwned + for(var/S in souls) var/datum/mind/L = S if(L.soulOwner == owner) selfcount++ var/targetcount = 0 - for(var/S in target.devilinfo.soulsOwned) + devilDatum = target.has_antag_datum(ANTAG_DATUM_DEVIL) + souls = devilDatum.soulsOwned + for(var/S in souls) var/datum/mind/L = S if(L.soulOwner == target) targetcount++ diff --git a/code/game/gamemodes/devil/true_devil/_true_devil.dm b/code/game/gamemodes/devil/true_devil/_true_devil.dm index eb2921c966..a77b2f95a6 100644 --- a/code/game/gamemodes/devil/true_devil/_true_devil.dm +++ b/code/game/gamemodes/devil/true_devil/_true_devil.dm @@ -41,18 +41,20 @@ /mob/living/carbon/true_devil/proc/convert_to_archdevil() - maxHealth = 5000 // not an IMPOSSIBLE amount, but still near impossible. + maxHealth = 500 // not an IMPOSSIBLE amount, but still near impossible. ascended = TRUE health = maxHealth icon_state = "arch_devil" /mob/living/carbon/true_devil/proc/set_name() - name = mind.devilinfo.truename + var/datum/antagonist/devil/devilinfo = mind.has_antag_datum(ANTAG_DATUM_DEVIL) + name = devilinfo.truename real_name = name /mob/living/carbon/true_devil/Login() ..() - mind.announceDevilLaws() + var/datum/antagonist/devil/devilinfo = mind.has_antag_datum(ANTAG_DATUM_DEVIL) + devilinfo.greet() mind.announce_objectives() @@ -60,7 +62,7 @@ stat = DEAD ..(gibbed) drop_all_held_items() - INVOKE_ASYNC(mind.devilinfo, /datum/devilinfo/proc/beginResurrectionCheck, src) + INVOKE_ASYNC(mind.has_antag_datum(ANTAG_DATUM_DEVIL), /datum/antagonist/devil/proc/beginResurrectionCheck, src) /mob/living/carbon/true_devil/examine(mob/user) diff --git a/code/game/gamemodes/traitor/traitor.dm b/code/game/gamemodes/traitor/traitor.dm index 90a953c446..37dea60dd6 100644 --- a/code/game/gamemodes/traitor/traitor.dm +++ b/code/game/gamemodes/traitor/traitor.dm @@ -234,10 +234,6 @@ to_chat(killer, "Your radio has been upgraded! Use :t to speak on an encrypted channel with Syndicate Agents!") killer.add_malf_picker() -/datum/game_mode/proc/add_law_sixsixsix(mob/living/silicon/devil) - var/laws = list("You may not use violence to coerce someone into selling their soul.", "You may not directly and knowingly physically harm a devil, other than yourself.", GLOB.lawlorify[LAW][devil.mind.devilinfo.ban], GLOB.lawlorify[LAW][devil.mind.devilinfo.obligation], "Accomplish your objectives at all costs.") - devil.set_law_sixsixsix(laws) - /datum/game_mode/proc/auto_declare_completion_traitor() if(traitors.len) var/text = "
The [traitor_name]s were:" diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys.dm index 0979a65981..5353341ab6 100644 --- a/code/game/objects/items/toys.dm +++ b/code/game/objects/items/toys.dm @@ -529,7 +529,7 @@ "You hear a soft click.") /obj/item/toy/talking/codex_gigas/generate_messages() - var/datum/devilinfo/devil = randomDevilInfo() + var/datum/fakeDevil/devil = new var/list/messages = list() messages += "Some fun facts about: [devil.truename]" messages += "[GLOB.lawlorify[LORE][devil.bane]]" diff --git a/code/game/objects/items/weapons/twohanded.dm b/code/game/objects/items/weapons/twohanded.dm index daa86eb833..baf65fd084 100644 --- a/code/game/objects/items/weapons/twohanded.dm +++ b/code/game/objects/items/weapons/twohanded.dm @@ -602,20 +602,19 @@ user.visible_message("[user] impales [user.p_them()]self in [user.p_their()] abdomen with [src]! It looks like [user.p_theyre()] trying to commit suicide!") return (BRUTELOSS) -/obj/item/weapon/twohanded/pitchfork/demonic/pickup(mob/user) - if(isliving(user)) +/obj/item/weapon/twohanded/pitchfork/demonic/pickup(mob/living/user) + if(isliving(user) && user.mind && user.owns_soul() && !is_devil(user)) var/mob/living/U = user - if(U.mind && !U.mind.devilinfo && (U.mind.soulOwner == U.mind)) //Burn hands unless they are a devil or have sold their soul - U.visible_message("As [U] picks [src] up, [U]'s arms briefly catch fire.", \ - "\"As you pick up [src] your arms ignite, reminding you of all your past sins.\"") - if(ishuman(U)) - var/mob/living/carbon/human/H = U - H.apply_damage(rand(force/2, force), BURN, pick("l_arm", "r_arm")) - else - U.adjustFireLoss(rand(force/2,force)) + U.visible_message("As [U] picks [src] up, [U]'s arms briefly catch fire.", \ + "\"As you pick up [src] your arms ignite, reminding you of all your past sins.\"") + if(ishuman(U)) + var/mob/living/carbon/human/H = U + H.apply_damage(rand(force/2, force), BURN, pick("l_arm", "r_arm")) + else + U.adjustFireLoss(rand(force/2,force)) /obj/item/weapon/twohanded/pitchfork/demonic/attack(mob/target, mob/living/carbon/human/user) - if(user.mind && !user.mind.devilinfo && (user.mind.soulOwner != user.mind)) + if(user.mind && user.owns_soul() && !is_devil(user)) to_chat(user, "[src] burns in your hands.") user.apply_damage(rand(force/2, force), BURN, pick("l_arm", "r_arm")) ..() diff --git a/code/game/objects/structures/ghost_role_spawners.dm b/code/game/objects/structures/ghost_role_spawners.dm index 989a2fdeb3..5859f103da 100644 --- a/code/game/objects/structures/ghost_role_spawners.dm +++ b/code/game/objects/structures/ghost_role_spawners.dm @@ -295,3 +295,52 @@ /obj/effect/mob_spawn/human/hotel_staff/Destroy() new/obj/structure/fluff/empty_sleeper/syndicate(get_turf(src)) ..() + +/obj/effect/mob_spawn/human/demonic_friend + name = "Essence of friendship" + desc = "Oh boy! Oh boy! A friend!" + mob_name = "Demonic friend" + icon = 'icons/obj/cardboard_cutout.dmi' + icon_state = "cutout_basic" + uniform = /obj/item/clothing/under/assistantformal + shoes = /obj/item/clothing/shoes/laceup + pocket1 = /obj/item/device/radio/off + back = /obj/item/weapon/storage/backpack + implants = list(/obj/item/weapon/implant/mindshield) //No revolutionaries, he's MY friend. + death = FALSE + roundstart = FALSE + random = TRUE + has_id = TRUE + id_job = "SuperFriend" + id_access = "assistant" + var/obj/effect/proc_holder/spell/targeted/summon_friend/spell + var/datum/mind/owner + +/obj/effect/mob_spawn/human/demonic_friend/Initialize(mapload, datum/mind/owner_mind, obj/effect/proc_holder/spell/targeted/summon_friend/summoning_spell) + ..() + owner = owner_mind + flavour_text = "You have been given a reprieve from your eternity of torment, to be [owner.name]'s friend for their short mortal coil. Be aware that if you do not live up to [owner.name]'s expectations, they can send you back to hell with a single thought. [owner.name]'s death will also return you to hell." + var/area/A = get_area(src) + if(!mapload && A) + notify_ghosts("\A friendship shell has been completed in \the [A.name].", source = src, action=NOTIFY_ATTACK, flashwindow = FALSE) + objectives = "Be [owner.name]'s friend, and keep [owner.name] alive, so you don't get sent back to hell." + spell = summoning_spell + + +/obj/effect/mob_spawn/human/demonic_friend/special(mob/living/L) + if(!QDELETED(owner.current) && owner.current.stat != DEAD) + L.real_name = "[owner.name]'s best friend" + L.name = L.real_name + soullink(/datum/soullink/oneway, owner.current, L) + spell.friend = L + spell.charge_counter = spell.charge_max + L.mind.hasSoul = FALSE + var/mob/living/carbon/human/H = L + var/obj/item/worn = H.wear_id + var/obj/item/weapon/card/id/id = worn.GetID() + id.registered_name = L.real_name + id.update_label() + else + to_chat(L, "Your owner is already dead! You will soon perish.") + addtimer(CALLBACK(L, /mob.proc/dust, 150)) //Give em a few seconds as a mercy. + diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index aa46a42ab4..3c473e6f70 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -1,4 +1,3 @@ - //////////////////////////////// /proc/message_admins(msg) msg = "ADMIN LOG: [msg]" @@ -705,7 +704,7 @@ to_chat(usr, "No Devils located" ) /datum/admins/proc/output_devil_info(mob/living/M) - if(istype(M) && M.mind && M.mind.devilinfo) + if(is_devil(M)) to_chat(usr, SSticker.mode.printdevilinfo(M.mind)) else to_chat(usr, "[M] is not a devil.") diff --git a/code/modules/admin/player_panel.dm b/code/modules/admin/player_panel.dm index 09aced33a8..06f6e5e993 100644 --- a/code/modules/admin/player_panel.dm +++ b/code/modules/admin/player_panel.dm @@ -567,13 +567,14 @@ for(var/X in SSticker.mode.devils) var/datum/mind/devil = X var/mob/M = devil.current + var/datum/antagonist/devil/devilinfo = devil.has_antag_datum(ANTAG_DATUM_DEVIL) if(M) - dat += "[M.real_name] : [devil.devilinfo.truename][M.client ? "" : " (No Client)"][M.stat == 2 ? " (DEAD)" : ""]" + dat += "[M.real_name] : [devilinfo.truename][M.client ? "" : " (No Client)"][M.stat == 2 ? " (DEAD)" : ""]" dat += "PM" dat += "Show Objective" dat += "Show all devil info" else - dat += "[devil.name] : [devil.devilinfo.truename] ([devil.key])devil body destroyed!" + dat += "[devil.name] : [devilinfo.truename] ([devil.key])devil body destroyed!" dat += "PM" dat += "" diff --git a/code/modules/awaymissions/corpse.dm b/code/modules/awaymissions/corpse.dm index 9fa0fbf5a5..6100b296ed 100644 --- a/code/modules/awaymissions/corpse.dm +++ b/code/modules/awaymissions/corpse.dm @@ -20,6 +20,7 @@ var/oxy_damage = 0 density = 1 anchored = 1 + var/banType = "lavaland" /obj/effect/mob_spawn/attack_ghost(mob/user) if(!SSticker.HasRoundStarted() || !loc) @@ -27,7 +28,7 @@ if(!uses) to_chat(user, "This spawner is out of charges!") return - if(jobban_isbanned(user, "lavaland")) + if(jobban_isbanned(user, banType)) to_chat(user, "You are jobanned!") return var/ghost_role = alert("Become [mob_name]? (Warning, You can no longer be cloned!)",,"Yes","No") diff --git a/code/modules/events/devil.dm b/code/modules/events/devil.dm index e4a90fc184..69648fa95a 100644 --- a/code/modules/events/devil.dm +++ b/code/modules/events/devil.dm @@ -32,11 +32,7 @@ var/mob/living/carbon/human/devil = create_event_devil(spawn_loc) Mind.transfer_to(devil) - SSticker.mode.finalize_devil(Mind, FALSE) - SSticker.mode.add_devil_objectives(src, 2) - Mind.announceDevilLaws() - Mind.announce_objectives() - + add_devil(devil, ascendable = FALSE) spawned_mobs += devil message_admins("[key_name_admin(devil)] has been made into a devil by an event.") diff --git a/code/modules/library/lib_codex_gigas.dm b/code/modules/library/lib_codex_gigas.dm index 35cb988083..ba14a6f210 100644 --- a/code/modules/library/lib_codex_gigas.dm +++ b/code/modules/library/lib_codex_gigas.dm @@ -1,3 +1,9 @@ +#define PRE_TITLE 1 +#define TITLE 2 +#define SYLLABLE 3 +#define MULTIPLE_SYLLABLE 4 +#define SUFFIX 5 + /obj/item/weapon/book/codex_gigas name = "Codex Gigas" icon_state ="demonomicon" @@ -8,16 +14,14 @@ unique = 1 title = "The codex gigas" var/inUse = 0 - - - - + var/currentName = "" + var/currentSection = PRE_TITLE /obj/item/weapon/book/codex_gigas/attack_self(mob/user) if(is_blind(user)) to_chat(user, "As you are trying to read, you suddenly feel very stupid.") return - if(ismonkey(user)) + if(!user.is_literate()) to_chat(user, "You skim through the book but can't comprehend any of it.") return if(inUse) @@ -27,31 +31,78 @@ if(U.check_acedia()) to_chat(user, "None of this matters, why are you reading this? You put the [title] down.") return - inUse = 1 - var/devilName = copytext(sanitize(input(user, "What infernal being do you wish to research?", "Codex Gigas", null) as text),1,MAX_MESSAGE_LEN) - var/speed = 300 - var/correctness = 85 - var/willpower = 98 + user.visible_message("[user] opens [title] and begins reading intently.") + ask_name(user) + + +/obj/item/weapon/book/codex_gigas/proc/perform_research(mob/user, devilName) + if(!devilName) + user.visible_message("[user] closes [title] without looking anything up.") + return + inUse = TRUE + var/speed = 300 + var/correctness = 85 + if(ishuman(user)) + var/mob/living/carbon/human/U = user if(U.job in list("Curator")) // the curator is both faster, and more accurate than normal crew members at research - speed = 45 + speed = 100 correctness = 100 - willpower = 100 - if(U.job in list("Captain", "Security Officer", "Head of Security", "Detective", "Warden")) - willpower = 99 - if(U.job in list("Clown")) // WHO GAVE THE CLOWN A DEMONOMICON? BAD THINGS WILL HAPPEN! - willpower = 25 correctness -= U.getBrainLoss() *0.5 //Brain damage makes researching hard. speed += U.getBrainLoss() * 3 - user.visible_message("[user] opens [title] and begins reading intently.") - if(do_after(U, speed, 0, U)) - var/usedName = devilName - if(!prob(correctness)) - usedName += "x" - var/datum/devilinfo/devil = devilInfo(usedName, 0) - user << browse("Information on [devilName]


[GLOB.lawlorify[LORE][devil.ban]]
[GLOB.lawlorify[LORE][devil.bane]]
[GLOB.lawlorify[LORE][devil.obligation]]
[GLOB.lawlorify[LORE][devil.banish]]", "window=book[window_size != null ? ";size=[window_size]" : ""]") - inUse = 0 - sleep(10) - if(!prob(willpower)) - U.influenceSin() - onclose(user, "book") + if(do_after(user, speed, 0, user)) + var/usedName = devilName + if(!prob(correctness)) + usedName += "x" + var/datum/antagonist/devil/devil = devilInfo(usedName) + display_devil(devil, user, usedName) + sleep(10) + onclose(user, "book") + inUse = FALSE +/obj/item/weapon/book/codex_gigas/proc/display_devil(datum/antagonist/devil/devil, mob/reader, devilName) + reader << browse("Information on [devilName]


[GLOB.lawlorify[LORE][devil.ban]]
[GLOB.lawlorify[LORE][devil.bane]]
[GLOB.lawlorify[LORE][devil.obligation]]
[GLOB.lawlorify[LORE][devil.banish]]", "window=book[window_size != null ? ";size=[window_size]" : ""]") + +/obj/item/weapon/book/codex_gigas/proc/ask_name(mob/reader) + ui_interact(reader) + +/obj/item/weapon/book/codex_gigas/ui_act(action, params) + if(..()) + return + if(!action) + return FALSE + if(action == "search") + SStgui.close_uis(src) + addtimer(CALLBACK(src, .proc/perform_research, usr, currentName), 0) + currentName = "" + currentSection = PRE_TITLE + return FALSE + else + currentName += action + var/oldSection = currentSection + if(GLOB.devil_pre_title.Find(action)) + currentSection = TITLE + else if(GLOB.devil_title.Find(action)) + currentSection = SYLLABLE + else if(GLOB.devil_syllable.Find(action)) + if (currentSection>=SYLLABLE) + currentSection = MULTIPLE_SYLLABLE + else + currentSection = SYLLABLE + else if(GLOB.devil_suffix.Find(action)) + currentSection = SUFFIX + else + to_chat(world, "Codex gigas failure [action]") + return currentSection != oldSection + +/obj/item/weapon/book/codex_gigas/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, \ + datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) + ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) + if(!ui) + ui = new(user, src, ui_key, "codex_gigas", name, 450, 450, master_ui, state) + ui.open() + +/obj/item/weapon/book/codex_gigas/ui_data(mob/user) + var/list/data = list() + data["name"]=currentName + data["currentSection"]=currentSection + return data diff --git a/code/modules/mob/living/carbon/human/death.dm b/code/modules/mob/living/carbon/human/death.dm index 6c4fd0b80c..e272680418 100644 --- a/code/modules/mob/living/carbon/human/death.dm +++ b/code/modules/mob/living/carbon/human/death.dm @@ -34,8 +34,8 @@ if(SSticker && SSticker.mode) SSblackbox.ReportDeath(src) - if(mind && mind.devilinfo) - INVOKE_ASYNC(mind.devilinfo, /datum/devilinfo.proc/beginResurrectionCheck, src) + if(is_devil(src)) + INVOKE_ASYNC(is_devil(src), /datum/antagonist/devil.proc/beginResurrectionCheck, src) /mob/living/carbon/human/proc/makeSkeleton() status_flags |= DISFIGURED diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 77dada5349..b5214f18a3 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -811,23 +811,22 @@ /mob/living/proc/owns_soul() if(mind) return mind.soulOwner == mind - return 1 + return TRUE /mob/living/proc/return_soul() hellbound = 0 if(mind) - if(mind.soulOwner.devilinfo)//Not sure how this could happen, but whatever. - mind.soulOwner.devilinfo.remove_soul(mind) + var/datum/antagonist/devil/devilInfo = mind.soulOwner.has_antag_datum(ANTAG_DATUM_DEVIL) + if(devilInfo)//Not sure how this could be null, but let's just try anyway. + devilInfo.remove_soul(mind) mind.soulOwner = mind /mob/living/proc/has_bane(banetype) - if(mind) - if(mind.devilinfo) - return mind.devilinfo.bane == banetype - return 0 + var/datum/antagonist/devil/devilInfo = is_devil(src) + return (banetype == devilInfo.bane) /mob/living/proc/check_weakness(obj/item/weapon, mob/living/attacker) - if(mind && mind.devilinfo) + if(mind && mind.has_antag_datum(ANTAG_DATUM_DEVIL)) return check_devil_bane_multiplier(weapon, attacker) return 1 diff --git a/code/modules/paperwork/contract.dm b/code/modules/paperwork/contract.dm index 634a2d056d..c084befd92 100644 --- a/code/modules/paperwork/contract.dm +++ b/code/modules/paperwork/contract.dm @@ -32,12 +32,14 @@ /obj/item/weapon/paper/contract/employment/attack(mob/living/M, mob/living/carbon/human/user) - var/deconvert = 0 - if(M.mind == target && target.soulOwner != target) + var/deconvert = FALSE + if(M.mind == target && !M.owns_soul()) if(user.mind && (user.mind.assigned_role == "Lawyer")) - deconvert = prob (25) + deconvert = TRUE else if (user.mind && (user.mind.assigned_role =="Head of Personnel") || (user.mind.assigned_role == "Centcom Commander")) - deconvert = prob (10) // the HoP doesn't have AS much legal training + deconvert = prob (25) // the HoP doesn't have AS much legal training + else + deconvert = prob (5) if(deconvert) M.visible_message("[user] reminds [M] that [M]'s soul was already purchased by Nanotrasen!") to_chat(M, "You feel that your soul has returned to its rightful owner, Nanotrasen.") @@ -57,6 +59,7 @@ var/contractType = 0 resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF var/datum/mind/owner + var/datum/antagonist/devil/devil_datum icon_state = "paper_onfire" /obj/item/weapon/paper/contract/infernal/power @@ -84,6 +87,10 @@ name = "paper- contract for knowledge" contractType = CONTRACT_KNOWLEDGE +/obj/item/weapon/paper/contract/infernal/friend + name = "paper- contract for a friend" + contractType = CONTRACT_FRIEND + /obj/item/weapon/paper/contract/infernal/unwilling name = "paper- infernal contract" contractType = CONTRACT_UNWILLING @@ -91,11 +98,10 @@ /obj/item/weapon/paper/contract/infernal/New(atom/loc, mob/living/nTarget, datum/mind/nOwner) ..() owner = nOwner + devil_datum = owner.has_antag_datum(ANTAG_DATUM_DEVIL) target = nTarget update_text() -/obj/item/weapon/paper/contract/infernal - /obj/item/weapon/paper/contract/infernal/suicide_act(mob/user) if(signed && (user == target.current) && istype(user,/mob/living/carbon/human/)) var/mob/living/carbon/human/H = user @@ -111,49 +117,56 @@ info = "This shouldn't be seen. Error DEVIL:6" /obj/item/weapon/paper/contract/infernal/power/update_text(signature = "____________", blood = 0) - info = "
Contract for infernal power



I, [target] of sound mind, do hereby willingly offer my soul to the infernal hells by way of the infernal agent [owner.devilinfo.truename], in exchange for power and physical strength. I understand that upon my demise, my soul shall fall into the infernal hells, and my body may not be resurrected, cloned, or otherwise brought back to life. I also understand that this will prevent my brain from being used in an MMI.


Signed, " + info = "
Contract for infernal power



I, [target] of sound mind, do hereby willingly offer my soul to the infernal hells by way of the infernal agent [devil_datum.truename], in exchange for power and physical strength. I understand that upon my demise, my soul shall fall into the infernal hells, and my body may not be resurrected, cloned, or otherwise brought back to life. I also understand that this will prevent my brain from being used in an MMI.


Signed, " if(blood) info += "[signature]" else info += "[signature]" /obj/item/weapon/paper/contract/infernal/wealth/update_text(signature = "____________", blood = 0) - info = "
Contract for unlimited wealth



I, [target] of sound mind, do hereby willingly offer my soul to the infernal hells by way of the infernal agent [owner.devilinfo.truename], in exchange for a pocket that never runs out of valuable resources. I understand that upon my demise, my soul shall fall into the infernal hells, and my body may not be resurrected, cloned, or otherwise brought back to life. I also understand that this will prevent my brain from being used in an MMI.


Signed, " + info = "
Contract for unlimited wealth



I, [target] of sound mind, do hereby willingly offer my soul to the infernal hells by way of the infernal agent [devil_datum.truename], in exchange for a pocket that never runs out of valuable resources. I understand that upon my demise, my soul shall fall into the infernal hells, and my body may not be resurrected, cloned, or otherwise brought back to life. I also understand that this will prevent my brain from being used in an MMI.


Signed, " if(blood) info += "[signature]" else info += "[signature]" /obj/item/weapon/paper/contract/infernal/prestige/update_text(signature = "____________", blood = 0) - info = "
Contract for prestige



I, [target] of sound mind, do hereby willingly offer my soul to the infernal hells by way of the infernal agent [owner.devilinfo.truename], in exchange for prestige and esteem among my peers. I understand that upon my demise, my soul shall fall into the infernal hells, and my body may not be resurrected, cloned, or otherwise brought back to life. I also understand that this will prevent my brain from being used in an MMI.


Signed, " + info = "
Contract for prestige



I, [target] of sound mind, do hereby willingly offer my soul to the infernal hells by way of the infernal agent [devil_datum.truename], in exchange for prestige and esteem among my peers. I understand that upon my demise, my soul shall fall into the infernal hells, and my body may not be resurrected, cloned, or otherwise brought back to life. I also understand that this will prevent my brain from being used in an MMI.


Signed, " if(blood) info += "[signature]" else info += "[signature]" /obj/item/weapon/paper/contract/infernal/magic/update_text(signature = "____________", blood = 0) - info = "
Contract for magic



I, [target] of sound mind, do hereby willingly offer my soul to the infernal hells by way of the infernal agent [owner.devilinfo.truename], in exchange for arcane abilities beyond normal human ability. I understand that upon my demise, my soul shall fall into the infernal hells, and my body may not be resurrected, cloned, or otherwise brought back to life. I also understand that this will prevent my brain from being used in an MMI.


Signed, " + info = "
Contract for magic



I, [target] of sound mind, do hereby willingly offer my soul to the infernal hells by way of the infernal agent [devil_datum.truename], in exchange for arcane abilities beyond normal human ability. I understand that upon my demise, my soul shall fall into the infernal hells, and my body may not be resurrected, cloned, or otherwise brought back to life. I also understand that this will prevent my brain from being used in an MMI.


Signed, " if(blood) info += "[signature]" else info += "[signature]" /obj/item/weapon/paper/contract/infernal/revive/update_text(signature = "____________", blood = 0) - info = "
Contract for resurrection



I, [target] of sound mind, do hereby willingly offer my soul to the infernal hells by way of the infernal agent [owner.devilinfo.truename], in exchange for resurrection and curing of all injuries. I understand that upon my demise, my soul shall fall into the infernal hells, and my body may not be resurrected, cloned, or otherwise brought back to life. I also understand that this will prevent my brain from being used in an MMI.


Signed, " + info = "
Contract for resurrection



I, [target] of sound mind, do hereby willingly offer my soul to the infernal hells by way of the infernal agent [devil_datum.truename], in exchange for resurrection and curing of all injuries. I understand that upon my demise, my soul shall fall into the infernal hells, and my body may not be resurrected, cloned, or otherwise brought back to life. I also understand that this will prevent my brain from being used in an MMI.


Signed, " if(blood) info += "[signature]" else info += "[signature]" /obj/item/weapon/paper/contract/infernal/knowledge/update_text(signature = "____________", blood = 0) - info = "
Contract for knowledge



I, [target] of sound mind, do hereby willingly offer my soul to the infernal hells by way of the infernal agent [owner.devilinfo.truename], in exchange for boundless knowledge. I understand that upon my demise, my soul shall fall into the infernal hells, and my body may not be resurrected, cloned, or otherwise brought back to life. I also understand that this will prevent my brain from being used in an MMI.


Signed, " + info = "
Contract for knowledge



I, [target] of sound mind, do hereby willingly offer my soul to the infernal hells by way of the infernal agent [devil_datum.truename], in exchange for boundless knowledge. I understand that upon my demise, my soul shall fall into the infernal hells, and my body may not be resurrected, cloned, or otherwise brought back to life. I also understand that this will prevent my brain from being used in an MMI.


Signed, " + if(blood) + info += "[signature]" + else + info += "[signature]" + +/obj/item/weapon/paper/contract/infernal/friend/update_text(signature = "____________", blood = 0) + info = "
Contract for a friend



I, [target] of sound mind, do hereby willingly offer my soul to the infernal hells by way of the infernal agent [devil_datum.truename], in exchange for a friend. I understand that upon my demise, my soul shall fall into the infernal hells, and my body may not be resurrected, cloned, or otherwise brought back to life. I also understand that this will prevent my brain from being used in an MMI.


Signed, " if(blood) info += "[signature]" else info += "[signature]" /obj/item/weapon/paper/contract/infernal/unwilling/update_text(signature = "____________", blood = 0) - info = "
Contract for slave



I, [target], hereby offer my soul to the infernal hells by way of the infernal agent [owner.devilinfo.truename]. I understand that upon my demise, my soul shall fall into the infernal hells, and my body may not be resurrected, cloned, or otherwise brought back to life. I also understand that this will prevent my brain from being used in an MMI.


Signed, " + info = "
Contract for slave



I, [target], hereby offer my soul to the infernal hells by way of the infernal agent [devil_datum.truename]. I understand that upon my demise, my soul shall fall into the infernal hells, and my body may not be resurrected, cloned, or otherwise brought back to life. I also understand that this will prevent my brain from being used in an MMI.


Signed, " if(blood) info += "[signature]" else @@ -179,33 +192,40 @@ return ..() /obj/item/weapon/paper/contract/infernal/proc/attempt_signature(mob/living/carbon/human/user, blood = 0) - if(user.IsAdvancedToolUser() && user.is_literate()) - if(user.mind == target) - if(user.mind.soulOwner != owner) - if (contractType == CONTRACT_REVIVE) - to_chat(user, "You are already alive, this contract would do nothing.") - else - if(signed) - to_chat(user, "This contract has already been signed. It may not be signed again.") - else - to_chat(user, "You quickly scrawl your name on the contract") - if(FulfillContract(target.current, blood)<=0) - to_chat(user, "But it seemed to have no effect, perhaps even Hell itself cannot grant this boon?") - return 1 - else - to_chat(user, "This devil already owns your soul, you may not sell it to them again.") - else - to_chat(user, "Your signature simply slides off the sheet, it seems this contract is not meant for you to sign.") - else + if(!user.IsAdvancedToolUser() || !user.is_literate()) to_chat(user, "You don't know how to read or write.") - return 0 + return 0 + if(user.mind != target) + to_chat(user, "Your signature simply slides off the sheet, it seems this contract is not meant for you to sign.") + return 0 + if(user.mind.soulOwner == owner) + to_chat(user, "This devil already owns your soul, you may not sell it to them again.") + return 0 + if(signed) + to_chat(user, "This contract has already been signed. It may not be signed again.") + return 0 + if(!user.mind.hasSoul) + to_chat(user, "You do not possess a soul.") + return 0 + if(prob(user.getBrainLoss())) + to_chat(user, "You quickly scrawl 'your name' on the contract.") + signIncorrectly() + return 0 + if (contractType == CONTRACT_REVIVE) + to_chat(user, "You are already alive, this contract would do nothing.") + return 0 + else + to_chat(user, "You quickly scrawl your name on the contract") + if(fulfillContract(target.current, blood)<=0) + to_chat(user, "But it seemed to have no effect, perhaps even Hell itself cannot grant this boon?") + return 1 /obj/item/weapon/paper/contract/infernal/revive/attack(mob/M, mob/living/user) if (target == M.mind && M.stat == DEAD && M.mind.soulOwner == M.mind) if (cooldown) - to_chat(user, "Give [M] a chance to think through the contract, don't rush him.") + to_chat(user, "Give [M] a chance to think through the contract, don't rush them.") return 0 cooldown = TRUE var/mob/living/carbon/human/H = M @@ -223,7 +243,7 @@ add_logs(user, H, "infernally revived via contract") user.visible_message("With a sudden blaze, [H] stands back up.") H.fakefire() - FulfillContract(H, 1)//Revival contracts are always signed in blood + fulfillContract(H, 1)//Revival contracts are always signed in blood addtimer(CALLBACK(H, /mob/living/carbon/human.proc/fakefireextinguish), 5, TIMER_UNIQUE) addtimer(CALLBACK(src, "resetcooldown"), 300, TIMER_UNIQUE) else @@ -233,20 +253,26 @@ cooldown = FALSE -/obj/item/weapon/paper/contract/infernal/proc/FulfillContract(mob/living/carbon/human/user = target.current, blood = 0) - signed = 1 +/obj/item/weapon/paper/contract/infernal/proc/fulfillContract(mob/living/carbon/human/user = target.current, blood = FALSE) + signed = TRUE if(user.mind.soulOwner != user.mind) //They already sold their soul to someone else? - user.mind.soulOwner.devilinfo.remove_soul(user.mind) //Then they lose their claim. + var/datum/antagonist/devil/ownerDevilInfo = user.mind.soulOwner.has_antag_datum(ANTAG_DATUM_DEVIL) + ownerDevilInfo.remove_soul(user.mind) //Then they lose their claim. user.mind.soulOwner = owner user.hellbound = contractType user.mind.damnation_type = contractType - owner.devilinfo.add_soul(user.mind) + var/datum/antagonist/devil/devilInfo = owner.has_antag_datum(ANTAG_DATUM_DEVIL) + devilInfo.add_soul(user.mind) update_text(user.real_name, blood) to_chat(user, "A profound emptiness washes over you as you lose ownership of your soul.") to_chat(user, "This does NOT make you an antagonist if you were not already.") - return 1 + return TRUE -/obj/item/weapon/paper/contract/infernal/power/FulfillContract(mob/living/carbon/human/user = target.current, blood = 0) +/obj/item/weapon/paper/contract/infernal/proc/signIncorrectly(mob/living/carbon/human/user = target.current, blood = FALSE) + signed = 1 + update_text("your name", blood) + +/obj/item/weapon/paper/contract/infernal/power/fulfillContract(mob/living/carbon/human/user = target.current, blood = FALSE) if(!user.dna) return -1 user.dna.add_mutation(HULK) @@ -254,13 +280,14 @@ organ.Insert(user) return ..() -/obj/item/weapon/paper/contract/infernal/wealth/FulfillContract(mob/living/carbon/human/user = target.current, blood = 0) +/obj/item/weapon/paper/contract/infernal/wealth/fulfillContract(mob/living/carbon/human/user = target.current, blood = 0) if(!istype(user) || !user.mind) // How in the hell could that happen? return -1 user.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/summon_wealth(null)) return ..() -/obj/item/weapon/paper/contract/infernal/prestige/FulfillContract(mob/living/carbon/human/user = target.current, blood = 0) +/obj/item/weapon/paper/contract/infernal/prestige/fulfillContract(mob/living/carbon/human/user = target.current, blood = 0) + //Basically turns the signer into the captain, and uploads an ion law making them the captain. var/obj/item/worn = user.wear_id var/obj/item/weapon/card/id/id = null if(worn) @@ -292,16 +319,22 @@ return ..() -/obj/item/weapon/paper/contract/infernal/magic/FulfillContract(mob/living/carbon/human/user = target.current, blood = 0) +/obj/item/weapon/paper/contract/infernal/magic/fulfillContract(mob/living/carbon/human/user = target.current, blood = 0) if(!istype(user) || !user.mind) return -1 - user.mind.AddSpell(new /obj/effect/proc_holder/spell/aimed/fireball(null)) + user.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/conjure_item/spellpacket/robeless(null)) user.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/knock(null)) return ..() -/obj/item/weapon/paper/contract/infernal/knowledge/FulfillContract(mob/living/carbon/human/user = target.current, blood = 0) +/obj/item/weapon/paper/contract/infernal/knowledge/fulfillContract(mob/living/carbon/human/user = target.current, blood = 0) if(!istype(user) || !user.mind) return -1 user.dna.add_mutation(XRAY) user.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/view_range(null)) return ..() + +/obj/item/weapon/paper/contract/infernal/friend/fulfillContract(mob/living/user = target.current, blood = 0) + if(!istype(user) || !user.mind) + return -1 + user.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/summon_friend(null)) + return ..() diff --git a/code/modules/spells/spell_types/devil.dm b/code/modules/spells/spell_types/devil.dm index 8e8968fb52..85a279b309 100644 --- a/code/modules/spells/spell_types/devil.dm +++ b/code/modules/spells/spell_types/devil.dm @@ -52,7 +52,7 @@ user.put_in_hands(contract) else var/obj/item/weapon/paper/contract/infernal/contract // = new(user.loc, C.mind, contractType, user.mind) - var/contractTypeName = input(user, "What type of contract?") in list ("Power", "Wealth", "Prestige", "Magic", "Knowledge") + var/contractTypeName = input(user, "What type of contract?") in list ("Power", "Wealth", "Prestige", "Magic", "Knowledge", "Friendship") switch(contractTypeName) if("Power") contract = new /obj/item/weapon/paper/contract/infernal/power(C.loc, C.mind, user.mind) @@ -64,6 +64,8 @@ contract = new /obj/item/weapon/paper/contract/infernal/magic(C.loc, C.mind, user.mind) if("Knowledge") contract = new /obj/item/weapon/paper/contract/infernal/knowledge(C.loc, C.mind, user.mind) + if("Friendship") + contract = new /obj/item/weapon/paper/contract/infernal/friend(C.loc, C.mind, user.mind) C.put_in_hands(contract) else to_chat(user, "[C] seems to not be sentient. You cannot summon a contract for [C.p_them()].") @@ -106,7 +108,7 @@ continuing = 1 else for(var/mob/living/C in orange(2, get_turf(user.loc))) //Can also phase in when nearby a potential buyer. - if (C.mind && C.mind.soulOwner == C.mind) + if (C.owns_soul()) continuing = 1 break if(continuing) diff --git a/code/modules/spells/spell_types/devil_boons.dm b/code/modules/spells/spell_types/devil_boons.dm index b7ef4b03c4..e8fcc73010 100644 --- a/code/modules/spells/spell_types/devil_boons.dm +++ b/code/modules/spells/spell_types/devil_boons.dm @@ -35,10 +35,39 @@ charge_max = 50 cooldown_min = 10 action_icon_state = "camera_jump" - var/ranges = list(7,8,9,10/*,11,12*/) + var/ranges = list(7,8,9,10) /obj/effect/proc_holder/spell/targeted/view_range/cast(list/targets, mob/user = usr) for(var/mob/C in targets) if(!C.client) continue - C.client.change_view(input("Select view range:", "Range", 4) in ranges) \ No newline at end of file + C.client.change_view(input("Select view range:", "Range", 4) in ranges) + +/obj/effect/proc_holder/spell/targeted/summon_friend + name = "Summon Friend" + desc = "The reward for selling your soul." + invocation_type = "none" + include_user = 1 + range = -1 + clothes_req = 0 + charge_max = 50 + cooldown_min = 10 + action_icon_state = "sacredflame" + var/mob/living/friend + var/obj/effect/mob_spawn/human/demonic_friend/friendShell + +/obj/effect/proc_holder/spell/targeted/summon_friend/cast(list/targets, mob/user = usr) + if(!QDELETED(friend)) + to_chat(friend, "Your master has deemed you a poor friend. Your durance in hell will now resume.") + friend.dust(TRUE) + qdel(friendShell) + return + if(!QDELETED(friendShell)) + qdel(friendShell) + return + for(var/C in targets) + var/mob/living/L = C + friendShell = new /obj/effect/mob_spawn/human/demonic_friend(L.loc, L.mind, src) + +/obj/effect/proc_holder/spell/targeted/conjure_item/spellpacket/robeless + clothes_req = FALSE diff --git a/code/modules/surgery/organs/vocal_cords.dm b/code/modules/surgery/organs/vocal_cords.dm index edf083cd3f..b4154c8e9c 100644 --- a/code/modules/surgery/organs/vocal_cords.dm +++ b/code/modules/surgery/organs/vocal_cords.dm @@ -181,12 +181,13 @@ for(var/V in listeners) var/mob/living/L = V - if(L.mind && L.mind.devilinfo && findtext(message, L.mind.devilinfo.truename)) - var/start = findtext(message, L.mind.devilinfo.truename) - listeners = list(L) //let's be honest you're never going to find two devils with the same name + var/datum/antagonist/devil/devilinfo = is_devil(L) + if(devilinfo && findtext(message, devilinfo.truename)) + var/start = findtext(message, devilinfo.truename) + listeners = list(L) //Devil names are unique. power_multiplier *= 5 //if you're a devil and god himself addressed you, you fucked up //Cut out the name so it doesn't trigger commands - message = copytext(message, 0, start)+copytext(message, start + length(L.mind.devilinfo.truename), length(message) + 1) + message = copytext(message, 0, start)+copytext(message, start + length(devilinfo.truename), length(message) + 1) break else if(dd_hasprefix(message, L.real_name)) specific_listeners += L //focus on those with the specified name @@ -362,8 +363,9 @@ cooldown = COOLDOWN_MEME for(var/V in listeners) var/mob/living/L = V - if(L.mind && L.mind.devilinfo) - L.say("[L.mind.devilinfo.truename]") + if(is_devil(L)) + var/datum/antagonist/devil/devilinfo = is_devil(L) + L.say("[devilinfo.truename]") else L.say("[L.real_name]") sleep(5) //So the chat flows more naturally diff --git a/tgui/assets/tgui.js b/tgui/assets/tgui.js index 6ebd3175ae..d7b7e7f257 100644 --- a/tgui/assets/tgui.js +++ b/tgui/assets/tgui.js @@ -1,16 +1,16 @@ require=function t(e,n,a){function r(o,s){if(!n[o]){if(!e[o]){var u="function"==typeof require&&require;if(!s&&u)return u(o,!0);if(i)return i(o,!0);var p=Error("Cannot find module '"+o+"'");throw p.code="MODULE_NOT_FOUND",p}var c=n[o]={exports:{}};e[o][0].call(c.exports,function(t){var n=e[o][1][t];return r(n?n:t)},c,c.exports,t,e,n,a)}return n[o].exports}for(var i="function"==typeof require&&require,o=0;o2?p[2]:void 0,l=Math.min((void 0===c?o:r(c,o))-u,o-s),f=1;for(s>u&&u+l>s&&(f=-1,u+=l-1,s+=l-1);l-- >0;)u in n?n[s]=n[u]:delete n[s],s+=f,u+=f;return n}},{76:76,79:79,80:80}],6:[function(t,e,n){"use strict";var a=t(80),r=t(76),i=t(79);e.exports=[].fill||function(t){for(var e=a(this),n=i(e.length),o=arguments,s=o.length,u=r(s>1?o[1]:void 0,n),p=s>2?o[2]:void 0,c=void 0===p?n:r(p,n);c>u;)e[u++]=t;return e}},{76:76,79:79,80:80}],7:[function(t,e,n){var a=t(78),r=t(79),i=t(76);e.exports=function(t){return function(e,n,o){var s,u=a(e),p=r(u.length),c=i(o,p);if(t&&n!=n){for(;p>c;)if(s=u[c++],s!=s)return!0}else for(;p>c;c++)if((t||c in u)&&u[c]===n)return t||c;return!t&&-1}}},{76:76,78:78,79:79}],8:[function(t,e,n){var a=t(17),r=t(34),i=t(80),o=t(79),s=t(9);e.exports=function(t){var e=1==t,n=2==t,u=3==t,p=4==t,c=6==t,l=5==t||c;return function(f,d,h){for(var m,v,g=i(f),b=r(g),y=a(d,h,3),x=o(b.length),_=0,w=e?s(f,x):n?s(f,0):void 0;x>_;_++)if((l||_ in b)&&(m=b[_],v=y(m,_,g),t))if(e)w[_]=v;else if(v)switch(t){case 3:return!0;case 5:return m;case 6:return _;case 2:w.push(m)}else if(p)return!1;return c?-1:u||p?p:w}}},{17:17,34:34,79:79,80:80,9:9}],9:[function(t,e,n){var a=t(38),r=t(36),i=t(83)("species");e.exports=function(t,e){var n;return r(t)&&(n=t.constructor,"function"!=typeof n||n!==Array&&!r(n.prototype)||(n=void 0),a(n)&&(n=n[i],null===n&&(n=void 0))),new(void 0===n?Array:n)(e)}},{36:36,38:38,83:83}],10:[function(t,e,n){var a=t(11),r=t(83)("toStringTag"),i="Arguments"==a(function(){return arguments}());e.exports=function(t){var e,n,o;return void 0===t?"Undefined":null===t?"Null":"string"==typeof(n=(e=Object(t))[r])?n:i?a(e):"Object"==(o=a(e))&&"function"==typeof e.callee?"Arguments":o}},{11:11,83:83}],11:[function(t,e,n){var a={}.toString;e.exports=function(t){return a.call(t).slice(8,-1)}},{}],12:[function(t,e,n){"use strict";var a=t(46),r=t(31),i=t(60),o=t(17),s=t(69),u=t(18),p=t(27),c=t(42),l=t(44),f=t(82)("id"),d=t(30),h=t(38),m=t(65),v=t(19),g=Object.isExtensible||h,b=v?"_s":"size",y=0,x=function(t,e){if(!h(t))return"symbol"==typeof t?t:("string"==typeof t?"S":"P")+t;if(!d(t,f)){if(!g(t))return"F";if(!e)return"E";r(t,f,++y)}return"O"+t[f]},_=function(t,e){var n,a=x(e);if("F"!==a)return t._i[a];for(n=t._f;n;n=n.n)if(n.k==e)return n};e.exports={getConstructor:function(t,e,n,r){var c=t(function(t,i){s(t,c,e),t._i=a.create(null),t._f=void 0,t._l=void 0,t[b]=0,void 0!=i&&p(i,n,t[r],t)});return i(c.prototype,{clear:function(){for(var t=this,e=t._i,n=t._f;n;n=n.n)n.r=!0,n.p&&(n.p=n.p.n=void 0),delete e[n.i];t._f=t._l=void 0,t[b]=0},"delete":function(t){var e=this,n=_(e,t);if(n){var a=n.n,r=n.p;delete e._i[n.i],n.r=!0,r&&(r.n=a),a&&(a.p=r),e._f==n&&(e._f=a),e._l==n&&(e._l=r),e[b]--}return!!n},forEach:function(t){for(var e,n=o(t,arguments.length>1?arguments[1]:void 0,3);e=e?e.n:this._f;)for(n(e.v,e.k,this);e&&e.r;)e=e.p},has:function(t){return!!_(this,t)}}),v&&a.setDesc(c.prototype,"size",{get:function(){return u(this[b])}}),c},def:function(t,e,n){var a,r,i=_(t,e);return i?i.v=n:(t._l=i={i:r=x(e,!0),k:e,v:n,p:a=t._l,n:void 0,r:!1},t._f||(t._f=i),a&&(a.n=i),t[b]++,"F"!==r&&(t._i[r]=i)),t},getEntry:_,setStrong:function(t,e,n){c(t,e,function(t,e){this._t=t,this._k=e,this._l=void 0},function(){for(var t=this,e=t._k,n=t._l;n&&n.r;)n=n.p;return t._t&&(t._l=n=n?n.n:t._t._f)?"keys"==e?l(0,n.k):"values"==e?l(0,n.v):l(0,[n.k,n.v]):(t._t=void 0,l(1))},n?"entries":"values",!n,!0),m(e)}}},{17:17,18:18,19:19,27:27,30:30,31:31,38:38,42:42,44:44,46:46,60:60,65:65,69:69,82:82}],13:[function(t,e,n){var a=t(27),r=t(10);e.exports=function(t){return function(){if(r(this)!=t)throw TypeError(t+"#toJSON isn't generic");var e=[];return a(this,!1,e.push,e),e}}},{10:10,27:27}],14:[function(t,e,n){"use strict";var a=t(31),r=t(60),i=t(4),o=t(38),s=t(69),u=t(27),p=t(8),c=t(30),l=t(82)("weak"),f=Object.isExtensible||o,d=p(5),h=p(6),m=0,v=function(t){return t._l||(t._l=new g)},g=function(){this.a=[]},b=function(t,e){return d(t.a,function(t){return t[0]===e})};g.prototype={get:function(t){var e=b(this,t);return e?e[1]:void 0},has:function(t){return!!b(this,t)},set:function(t,e){var n=b(this,t);n?n[1]=e:this.a.push([t,e])},"delete":function(t){var e=h(this.a,function(e){return e[0]===t});return~e&&this.a.splice(e,1),!!~e}},e.exports={getConstructor:function(t,e,n,a){var i=t(function(t,r){s(t,i,e),t._i=m++,t._l=void 0,void 0!=r&&u(r,n,t[a],t)});return r(i.prototype,{"delete":function(t){return o(t)?f(t)?c(t,l)&&c(t[l],this._i)&&delete t[l][this._i]:v(this)["delete"](t):!1},has:function(t){return o(t)?f(t)?c(t,l)&&c(t[l],this._i):v(this).has(t):!1}}),i},def:function(t,e,n){return f(i(e))?(c(e,l)||a(e,l,{}),e[l][t._i]=n):v(t).set(e,n),t},frozenStore:v,WEAK:l}},{27:27,30:30,31:31,38:38,4:4,60:60,69:69,8:8,82:82}],15:[function(t,e,n){"use strict";var a=t(29),r=t(22),i=t(61),o=t(60),s=t(27),u=t(69),p=t(38),c=t(24),l=t(43),f=t(66);e.exports=function(t,e,n,d,h,m){var v=a[t],g=v,b=h?"set":"add",y=g&&g.prototype,x={},_=function(t){var e=y[t];i(y,t,"delete"==t?function(t){return m&&!p(t)?!1:e.call(this,0===t?0:t)}:"has"==t?function(t){return m&&!p(t)?!1:e.call(this,0===t?0:t)}:"get"==t?function(t){return m&&!p(t)?void 0:e.call(this,0===t?0:t)}:"add"==t?function(t){return e.call(this,0===t?0:t),this}:function(t,n){return e.call(this,0===t?0:t,n),this})};if("function"==typeof g&&(m||y.forEach&&!c(function(){(new g).entries().next()}))){var w,k=new g,E=k[b](m?{}:-0,1)!=k,S=c(function(){k.has(1)}),C=l(function(t){new g(t)});C||(g=e(function(e,n){u(e,g,t);var a=new v;return void 0!=n&&s(n,h,a[b],a),a}),g.prototype=y,y.constructor=g),m||k.forEach(function(t,e){w=1/e===-(1/0)}),(S||w)&&(_("delete"),_("has"),h&&_("get")),(w||E)&&_(b),m&&y.clear&&delete y.clear}else g=d.getConstructor(e,t,h,b),o(g.prototype,n);return f(g,t),x[t]=g,r(r.G+r.W+r.F*(g!=v),x),m||d.setStrong(g,t,h),g}},{22:22,24:24,27:27,29:29,38:38,43:43,60:60,61:61,66:66,69:69}],16:[function(t,e,n){var a=e.exports={version:"1.2.6"};"number"==typeof __e&&(__e=a)},{}],17:[function(t,e,n){var a=t(2);e.exports=function(t,e,n){if(a(t),void 0===e)return t;switch(n){case 1:return function(n){return t.call(e,n)};case 2:return function(n,a){return t.call(e,n,a)};case 3:return function(n,a,r){return t.call(e,n,a,r)}}return function(){return t.apply(e,arguments)}}},{2:2}],18:[function(t,e,n){e.exports=function(t){if(void 0==t)throw TypeError("Can't call method on "+t);return t}},{}],19:[function(t,e,n){e.exports=!t(24)(function(){return 7!=Object.defineProperty({},"a",{get:function(){return 7}}).a})},{24:24}],20:[function(t,e,n){var a=t(38),r=t(29).document,i=a(r)&&a(r.createElement);e.exports=function(t){return i?r.createElement(t):{}}},{29:29,38:38}],21:[function(t,e,n){var a=t(46);e.exports=function(t){var e=a.getKeys(t),n=a.getSymbols;if(n)for(var r,i=n(t),o=a.isEnum,s=0;i.length>s;)o.call(t,r=i[s++])&&e.push(r);return e}},{46:46}],22:[function(t,e,n){var a=t(29),r=t(16),i=t(31),o=t(61),s=t(17),u="prototype",p=function(t,e,n){var c,l,f,d,h=t&p.F,m=t&p.G,v=t&p.S,g=t&p.P,b=t&p.B,y=m?a:v?a[e]||(a[e]={}):(a[e]||{})[u],x=m?r:r[e]||(r[e]={}),_=x[u]||(x[u]={});m&&(n=e);for(c in n)l=!h&&y&&c in y,f=(l?y:n)[c],d=b&&l?s(f,a):g&&"function"==typeof f?s(Function.call,f):f,y&&!l&&o(y,c,f),x[c]!=f&&i(x,c,d),g&&_[c]!=f&&(_[c]=f)};a.core=r,p.F=1,p.G=2,p.S=4,p.P=8,p.B=16,p.W=32,e.exports=p},{16:16,17:17,29:29,31:31,61:61}],23:[function(t,e,n){var a=t(83)("match");e.exports=function(t){var e=/./;try{"/./"[t](e)}catch(n){try{return e[a]=!1,!"/./"[t](e)}catch(r){}}return!0}},{83:83}],24:[function(t,e,n){e.exports=function(t){try{return!!t()}catch(e){return!0}}},{}],25:[function(t,e,n){"use strict";var a=t(31),r=t(61),i=t(24),o=t(18),s=t(83);e.exports=function(t,e,n){var u=s(t),p=""[t];i(function(){var e={};return e[u]=function(){return 7},7!=""[t](e)})&&(r(String.prototype,t,n(o,u,p)),a(RegExp.prototype,u,2==e?function(t,e){return p.call(t,this,e)}:function(t){return p.call(t,this)}))}},{18:18,24:24,31:31,61:61,83:83}],26:[function(t,e,n){"use strict";var a=t(4);e.exports=function(){var t=a(this),e="";return t.global&&(e+="g"),t.ignoreCase&&(e+="i"),t.multiline&&(e+="m"),t.unicode&&(e+="u"),t.sticky&&(e+="y"),e}},{4:4}],27:[function(t,e,n){var a=t(17),r=t(40),i=t(35),o=t(4),s=t(79),u=t(84);e.exports=function(t,e,n,p){var c,l,f,d=u(t),h=a(n,p,e?2:1),m=0;if("function"!=typeof d)throw TypeError(t+" is not iterable!");if(i(d))for(c=s(t.length);c>m;m++)e?h(o(l=t[m])[0],l[1]):h(t[m]);else for(f=d.call(t);!(l=f.next()).done;)r(f,h,l.value,e)}},{17:17,35:35,4:4,40:40,79:79,84:84}],28:[function(t,e,n){var a=t(78),r=t(46).getNames,i={}.toString,o="object"==typeof window&&Object.getOwnPropertyNames?Object.getOwnPropertyNames(window):[],s=function(t){try{return r(t)}catch(e){return o.slice()}};e.exports.get=function(t){return o&&"[object Window]"==i.call(t)?s(t):r(a(t))}},{46:46,78:78}],29:[function(t,e,n){var a=e.exports="undefined"!=typeof window&&window.Math==Math?window:"undefined"!=typeof self&&self.Math==Math?self:Function("return this")();"number"==typeof __g&&(__g=a)},{}],30:[function(t,e,n){var a={}.hasOwnProperty;e.exports=function(t,e){return a.call(t,e)}},{}],31:[function(t,e,n){var a=t(46),r=t(59);e.exports=t(19)?function(t,e,n){return a.setDesc(t,e,r(1,n))}:function(t,e,n){return t[e]=n,t}},{19:19,46:46,59:59}],32:[function(t,e,n){e.exports=t(29).document&&document.documentElement},{29:29}],33:[function(t,e,n){e.exports=function(t,e,n){var a=void 0===n;switch(e.length){case 0:return a?t():t.call(n);case 1:return a?t(e[0]):t.call(n,e[0]);case 2:return a?t(e[0],e[1]):t.call(n,e[0],e[1]);case 3:return a?t(e[0],e[1],e[2]):t.call(n,e[0],e[1],e[2]);case 4:return a?t(e[0],e[1],e[2],e[3]):t.call(n,e[0],e[1],e[2],e[3])}return t.apply(n,e)}},{}],34:[function(t,e,n){var a=t(11);e.exports=Object("z").propertyIsEnumerable(0)?Object:function(t){return"String"==a(t)?t.split(""):Object(t)}},{11:11}],35:[function(t,e,n){var a=t(45),r=t(83)("iterator"),i=Array.prototype;e.exports=function(t){return void 0!==t&&(a.Array===t||i[r]===t)}},{45:45,83:83}],36:[function(t,e,n){var a=t(11);e.exports=Array.isArray||function(t){return"Array"==a(t)}},{11:11}],37:[function(t,e,n){var a=t(38),r=Math.floor;e.exports=function(t){return!a(t)&&isFinite(t)&&r(t)===t}},{38:38}],38:[function(t,e,n){e.exports=function(t){return"object"==typeof t?null!==t:"function"==typeof t}},{}],39:[function(t,e,n){var a=t(38),r=t(11),i=t(83)("match");e.exports=function(t){var e;return a(t)&&(void 0!==(e=t[i])?!!e:"RegExp"==r(t))}},{11:11,38:38,83:83}],40:[function(t,e,n){var a=t(4);e.exports=function(t,e,n,r){try{return r?e(a(n)[0],n[1]):e(n)}catch(i){var o=t["return"];throw void 0!==o&&a(o.call(t)),i}}},{4:4}],41:[function(t,e,n){"use strict";var a=t(46),r=t(59),i=t(66),o={};t(31)(o,t(83)("iterator"),function(){return this}),e.exports=function(t,e,n){t.prototype=a.create(o,{next:r(1,n)}),i(t,e+" Iterator")}},{31:31,46:46,59:59,66:66,83:83}],42:[function(t,e,n){"use strict";var a=t(48),r=t(22),i=t(61),o=t(31),s=t(30),u=t(45),p=t(41),c=t(66),l=t(46).getProto,f=t(83)("iterator"),d=!([].keys&&"next"in[].keys()),h="@@iterator",m="keys",v="values",g=function(){return this};e.exports=function(t,e,n,b,y,x,_){p(n,e,b);var w,k,E=function(t){if(!d&&t in A)return A[t];switch(t){case m:return function(){return new n(this,t)};case v:return function(){return new n(this,t)}}return function(){return new n(this,t)}},S=e+" Iterator",C=y==v,P=!1,A=t.prototype,O=A[f]||A[h]||y&&A[y],T=O||E(y);if(O){var R=l(T.call(new t));c(R,S,!0),!a&&s(A,h)&&o(R,f,g),C&&O.name!==v&&(P=!0,T=function(){return O.call(this)})}if(a&&!_||!d&&!P&&A[f]||o(A,f,T),u[e]=T,u[S]=g,y)if(w={values:C?T:E(v),keys:x?T:E(m),entries:C?E("entries"):T},_)for(k in w)k in A||i(A,k,w[k]);else r(r.P+r.F*(d||P),e,w);return w}},{22:22,30:30,31:31,41:41,45:45,46:46,48:48,61:61,66:66,83:83}],43:[function(t,e,n){var a=t(83)("iterator"),r=!1;try{var i=[7][a]();i["return"]=function(){r=!0},Array.from(i,function(){throw 2})}catch(o){}e.exports=function(t,e){if(!e&&!r)return!1;var n=!1;try{var i=[7],o=i[a]();o.next=function(){return{done:n=!0}},i[a]=function(){return o},t(i)}catch(s){}return n}},{83:83}],44:[function(t,e,n){e.exports=function(t,e){return{value:e,done:!!t}}},{}],45:[function(t,e,n){e.exports={}},{}],46:[function(t,e,n){var a=Object;e.exports={create:a.create,getProto:a.getPrototypeOf,isEnum:{}.propertyIsEnumerable,getDesc:a.getOwnPropertyDescriptor,setDesc:a.defineProperty,setDescs:a.defineProperties,getKeys:a.keys,getNames:a.getOwnPropertyNames,getSymbols:a.getOwnPropertySymbols,each:[].forEach}},{}],47:[function(t,e,n){var a=t(46),r=t(78);e.exports=function(t,e){for(var n,i=r(t),o=a.getKeys(i),s=o.length,u=0;s>u;)if(i[n=o[u++]]===e)return n}},{46:46,78:78}],48:[function(t,e,n){e.exports=!1},{}],49:[function(t,e,n){e.exports=Math.expm1||function(t){return 0==(t=+t)?t:t>-1e-6&&1e-6>t?t+t*t/2:Math.exp(t)-1}},{}],50:[function(t,e,n){e.exports=Math.log1p||function(t){return(t=+t)>-1e-8&&1e-8>t?t-t*t/2:Math.log(1+t)}},{}],51:[function(t,e,n){e.exports=Math.sign||function(t){return 0==(t=+t)||t!=t?t:0>t?-1:1}},{}],52:[function(t,e,n){var a,r,i,o=t(29),s=t(75).set,u=o.MutationObserver||o.WebKitMutationObserver,p=o.process,c=o.Promise,l="process"==t(11)(p),f=function(){var t,e,n;for(l&&(t=p.domain)&&(p.domain=null,t.exit());a;)e=a.domain,n=a.fn,e&&e.enter(),n(),e&&e.exit(),a=a.next;r=void 0,t&&t.enter()};if(l)i=function(){p.nextTick(f)};else if(u){var d=1,h=document.createTextNode("");new u(f).observe(h,{characterData:!0}),i=function(){h.data=d=-d}}else i=c&&c.resolve?function(){c.resolve().then(f)}:function(){s.call(o,f)};e.exports=function(t){var e={fn:t,next:void 0,domain:l&&p.domain};r&&(r.next=e),a||(a=e,i()),r=e}},{11:11,29:29,75:75}],53:[function(t,e,n){var a=t(46),r=t(80),i=t(34);e.exports=t(24)(function(){var t=Object.assign,e={},n={},a=Symbol(),r="abcdefghijklmnopqrst";return e[a]=7,r.split("").forEach(function(t){n[t]=t}),7!=t({},e)[a]||Object.keys(t({},n)).join("")!=r})?function(t,e){for(var n=r(t),o=arguments,s=o.length,u=1,p=a.getKeys,c=a.getSymbols,l=a.isEnum;s>u;)for(var f,d=i(o[u++]),h=c?p(d).concat(c(d)):p(d),m=h.length,v=0;m>v;)l.call(d,f=h[v++])&&(n[f]=d[f]);return n}:Object.assign},{24:24,34:34,46:46,80:80}],54:[function(t,e,n){var a=t(22),r=t(16),i=t(24);e.exports=function(t,e){var n=(r.Object||{})[t]||Object[t],o={};o[t]=e(n),a(a.S+a.F*i(function(){n(1)}),"Object",o)}},{16:16,22:22,24:24}],55:[function(t,e,n){var a=t(46),r=t(78),i=a.isEnum;e.exports=function(t){return function(e){for(var n,o=r(e),s=a.getKeys(o),u=s.length,p=0,c=[];u>p;)i.call(o,n=s[p++])&&c.push(t?[n,o[n]]:o[n]);return c}}},{46:46,78:78}],56:[function(t,e,n){var a=t(46),r=t(4),i=t(29).Reflect;e.exports=i&&i.ownKeys||function(t){var e=a.getNames(r(t)),n=a.getSymbols;return n?e.concat(n(t)):e}},{29:29,4:4,46:46}],57:[function(t,e,n){"use strict";var a=t(58),r=t(33),i=t(2);e.exports=function(){for(var t=i(this),e=arguments.length,n=Array(e),o=0,s=a._,u=!1;e>o;)(n[o]=arguments[o++])===s&&(u=!0);return function(){var a,i=this,o=arguments,p=o.length,c=0,l=0;if(!u&&!p)return r(t,n,i);if(a=n.slice(),u)for(;e>c;c++)a[c]===s&&(a[c]=o[l++]);for(;p>l;)a.push(o[l++]);return r(t,a,i)}}},{2:2,33:33,58:58}],58:[function(t,e,n){e.exports=t(29)},{29:29}],59:[function(t,e,n){e.exports=function(t,e){return{enumerable:!(1&t),configurable:!(2&t),writable:!(4&t),value:e}}},{}],60:[function(t,e,n){var a=t(61);e.exports=function(t,e){for(var n in e)a(t,n,e[n]);return t}},{61:61}],61:[function(t,e,n){var a=t(29),r=t(31),i=t(82)("src"),o="toString",s=Function[o],u=(""+s).split(o);t(16).inspectSource=function(t){return s.call(t)},(e.exports=function(t,e,n,o){"function"==typeof n&&(n.hasOwnProperty(i)||r(n,i,t[e]?""+t[e]:u.join(e+"")),n.hasOwnProperty("name")||r(n,"name",e)),t===a?t[e]=n:(o||delete t[e],r(t,e,n))})(Function.prototype,o,function(){return"function"==typeof this&&this[i]||s.call(this)})},{16:16,29:29,31:31,82:82}],62:[function(t,e,n){e.exports=function(t,e){var n=e===Object(e)?function(t){return e[t]}:e;return function(e){return(e+"").replace(t,n)}}},{}],63:[function(t,e,n){e.exports=Object.is||function(t,e){return t===e?0!==t||1/t===1/e:t!=t&&e!=e}},{}],64:[function(t,e,n){var a=t(46).getDesc,r=t(38),i=t(4),o=function(t,e){if(i(t),!r(e)&&null!==e)throw TypeError(e+": can't set as prototype!")};e.exports={set:Object.setPrototypeOf||("__proto__"in{}?function(e,n,r){try{r=t(17)(Function.call,a(Object.prototype,"__proto__").set,2),r(e,[]),n=!(e instanceof Array)}catch(i){n=!0}return function(t,e){return o(t,e),n?t.__proto__=e:r(t,e),t}}({},!1):void 0),check:o}},{17:17,38:38,4:4,46:46}],65:[function(t,e,n){"use strict";var a=t(29),r=t(46),i=t(19),o=t(83)("species");e.exports=function(t){var e=a[t];i&&e&&!e[o]&&r.setDesc(e,o,{configurable:!0,get:function(){return this}})}},{19:19,29:29,46:46,83:83}],66:[function(t,e,n){var a=t(46).setDesc,r=t(30),i=t(83)("toStringTag");e.exports=function(t,e,n){t&&!r(t=n?t:t.prototype,i)&&a(t,i,{configurable:!0,value:e})}},{30:30,46:46,83:83}],67:[function(t,e,n){var a=t(29),r="__core-js_shared__",i=a[r]||(a[r]={});e.exports=function(t){return i[t]||(i[t]={})}},{29:29}],68:[function(t,e,n){var a=t(4),r=t(2),i=t(83)("species");e.exports=function(t,e){var n,o=a(t).constructor;return void 0===o||void 0==(n=a(o)[i])?e:r(n)}},{2:2,4:4,83:83}],69:[function(t,e,n){e.exports=function(t,e,n){if(!(t instanceof e))throw TypeError(n+": use the 'new' operator!");return t}},{}],70:[function(t,e,n){var a=t(77),r=t(18);e.exports=function(t){return function(e,n){var i,o,s=r(e)+"",u=a(n),p=s.length;return 0>u||u>=p?t?"":void 0:(i=s.charCodeAt(u),55296>i||i>56319||u+1===p||(o=s.charCodeAt(u+1))<56320||o>57343?t?s.charAt(u):i:t?s.slice(u,u+2):(i-55296<<10)+(o-56320)+65536)}}},{18:18,77:77}],71:[function(t,e,n){var a=t(39),r=t(18);e.exports=function(t,e,n){if(a(e))throw TypeError("String#"+n+" doesn't accept regex!");return r(t)+""}},{18:18,39:39}],72:[function(t,e,n){var a=t(79),r=t(73),i=t(18);e.exports=function(t,e,n,o){var s=i(t)+"",u=s.length,p=void 0===n?" ":n+"",c=a(e);if(u>=c)return s;""==p&&(p=" ");var l=c-u,f=r.call(p,Math.ceil(l/p.length));return f.length>l&&(f=f.slice(0,l)),o?f+s:s+f}},{18:18,73:73,79:79}],73:[function(t,e,n){"use strict";var a=t(77),r=t(18);e.exports=function(t){var e=r(this)+"",n="",i=a(t);if(0>i||i==1/0)throw RangeError("Count can't be negative");for(;i>0;(i>>>=1)&&(e+=e))1&i&&(n+=e);return n}},{18:18,77:77}],74:[function(t,e,n){var a=t(22),r=t(18),i=t(24),o=" \n\x0B\f\r  ᠎              \u2028\u2029\ufeff",s="["+o+"]",u="​…",p=RegExp("^"+s+s+"*"),c=RegExp(s+s+"*$"),l=function(t,e){var n={};n[t]=e(f),a(a.P+a.F*i(function(){return!!o[t]()||u[t]()!=u}),"String",n)},f=l.trim=function(t,e){return t=r(t)+"",1&e&&(t=t.replace(p,"")),2&e&&(t=t.replace(c,"")),t};e.exports=l},{18:18,22:22,24:24}],75:[function(t,e,n){var a,r,i,o=t(17),s=t(33),u=t(32),p=t(20),c=t(29),l=c.process,f=c.setImmediate,d=c.clearImmediate,h=c.MessageChannel,m=0,v={},g="onreadystatechange",b=function(){var t=+this;if(v.hasOwnProperty(t)){var e=v[t];delete v[t],e()}},y=function(t){b.call(t.data)};f&&d||(f=function(t){for(var e=[],n=1;arguments.length>n;)e.push(arguments[n++]);return v[++m]=function(){s("function"==typeof t?t:Function(t),e)},a(m),m},d=function(t){delete v[t]},"process"==t(11)(l)?a=function(t){l.nextTick(o(b,t,1))}:h?(r=new h,i=r.port2,r.port1.onmessage=y,a=o(i.postMessage,i,1)):c.addEventListener&&"function"==typeof postMessage&&!c.importScripts?(a=function(t){c.postMessage(t+"","*")},c.addEventListener("message",y,!1)):a=g in p("script")?function(t){u.appendChild(p("script"))[g]=function(){u.removeChild(this),b.call(t)}}:function(t){setTimeout(o(b,t,1),0)}),e.exports={set:f,clear:d}},{11:11,17:17,20:20,29:29,32:32,33:33}],76:[function(t,e,n){var a=t(77),r=Math.max,i=Math.min;e.exports=function(t,e){return t=a(t),0>t?r(t+e,0):i(t,e)}},{77:77}],77:[function(t,e,n){var a=Math.ceil,r=Math.floor;e.exports=function(t){return isNaN(t=+t)?0:(t>0?r:a)(t)}},{}],78:[function(t,e,n){var a=t(34),r=t(18);e.exports=function(t){return a(r(t))}},{18:18,34:34}],79:[function(t,e,n){var a=t(77),r=Math.min;e.exports=function(t){return t>0?r(a(t),9007199254740991):0}},{77:77}],80:[function(t,e,n){var a=t(18);e.exports=function(t){return Object(a(t))}},{18:18}],81:[function(t,e,n){var a=t(38);e.exports=function(t,e){if(!a(t))return t;var n,r;if(e&&"function"==typeof(n=t.toString)&&!a(r=n.call(t)))return r;if("function"==typeof(n=t.valueOf)&&!a(r=n.call(t)))return r;if(!e&&"function"==typeof(n=t.toString)&&!a(r=n.call(t)))return r;throw TypeError("Can't convert object to primitive value")}},{38:38}],82:[function(t,e,n){var a=0,r=Math.random();e.exports=function(t){return"Symbol(".concat(void 0===t?"":t,")_",(++a+r).toString(36))}},{}],83:[function(t,e,n){var a=t(67)("wks"),r=t(82),i=t(29).Symbol;e.exports=function(t){return a[t]||(a[t]=i&&i[t]||(i||r)("Symbol."+t))}},{29:29,67:67,82:82}],84:[function(t,e,n){var a=t(10),r=t(83)("iterator"),i=t(45);e.exports=t(16).getIteratorMethod=function(t){return void 0!=t?t[r]||t["@@iterator"]||i[a(t)]:void 0}},{10:10,16:16,45:45,83:83}],85:[function(t,e,n){"use strict";var a,r=t(46),i=t(22),o=t(19),s=t(59),u=t(32),p=t(20),c=t(30),l=t(11),f=t(33),d=t(24),h=t(4),m=t(2),v=t(38),g=t(80),b=t(78),y=t(77),x=t(76),_=t(79),w=t(34),k=t(82)("__proto__"),E=t(8),S=t(7)(!1),C=Object.prototype,P=Array.prototype,A=P.slice,O=P.join,T=r.setDesc,R=r.getDesc,M=r.setDescs,j={};o||(a=!d(function(){return 7!=T(p("div"),"a",{get:function(){return 7}}).a}),r.setDesc=function(t,e,n){if(a)try{return T(t,e,n)}catch(r){}if("get"in n||"set"in n)throw TypeError("Accessors not supported!");return"value"in n&&(h(t)[e]=n.value),t},r.getDesc=function(t,e){if(a)try{return R(t,e)}catch(n){}return c(t,e)?s(!C.propertyIsEnumerable.call(t,e),t[e]):void 0},r.setDescs=M=function(t,e){h(t);for(var n,a=r.getKeys(e),i=a.length,o=0;i>o;)r.setDesc(t,n=a[o++],e[n]);return t}),i(i.S+i.F*!o,"Object",{getOwnPropertyDescriptor:r.getDesc,defineProperty:r.setDesc,defineProperties:M});var L="constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf".split(","),N=L.concat("length","prototype"),D=L.length,F=function(){var t,e=p("iframe"),n=D,a=">";for(e.style.display="none",u.appendChild(e),e.src="javascript:",t=e.contentWindow.document,t.open(),t.write("