From e29c2bd2ca0b4d6d5ea639b370e5ec50eb9dfa26 Mon Sep 17 00:00:00 2001 From: Antoonij <42318445+Antoonij@users.noreply.github.com> Date: Mon, 6 Jan 2025 20:15:30 +0100 Subject: [PATCH] add: Updated Devil gamemode (#5944) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * let's do first step to rework that piece of .. * step 2 - remove fucken devilinfo from mind * step 3 - eat zuzya (clean mind and living procs) * toy gigax, fake devil datum * UPD * UPD * some fixes * UPD * попытка зарезолвить конфликт дубль 1 * дубль 2 * fastfix * double 3 * Delete code/game/gamemodes/devil/devilinfo.dm * CLRF to LF * Resurrection rework * catsmile * fix inconsistent * fix.. again * improve * resurrection bugfixes * полностью модульные бейны * фикс пробелов * fixes. again * fix nr2 * again * omagad is THAT objectivos????? * fix * UPD * forgotten moments fixed * identitation fix * fix again * ranks are now separated datum * fix * fix again * forgotten things * some fixes * NO_DEATH TRAIT * bugfixes + rewrite toy gigas * whoops. * UPD + bugfix * fastfix * fastfix and trailing * metabolism UPD * the last fix, i hope * попытка исправить cast * resurrection rework * fix * fix again... * UPD * модульная информация о димоне * fixes * UPD * fix inconsistent * the last fixes * UPD * fix inconsistent * cleanup * runtime fixes * Global list liquidation - full modular devil bans, devil obligations * inconsistent fix * fix * UPD * fastfix * UPD * UPD * fix inconsistent * fix again * rewrite codex gigas + resolve merge conflict * rewrite sintouched to antagonist datum * dme * inconsistent * last fixes * rewrite sintouched give objectives * les go final * fix * fix inconsistent * fix * i love inconsistent * finallyyyyyyyy * тепеь финал * forgotten moments and ama ready * clean unused * forgotten moments * forgotten moments fix * improve * improve x2 * fix * wtf * Rewrite add reagent signal * early* * improve * first fixes * fix vocal cords * more fixes * упс * optimize * fiix * mor fix * get_all_objectives * OnUnarmedAttack * 1 * 2 * 3 * conflicts * fix * fix x2 * dme * smol fix *
* improve * fix inconsistent * fix x2 * trailing.... --- code/__DEFINES/contracts.dm | 37 -- code/__DEFINES/dcs/signals.dm | 10 + code/__DEFINES/devil.dm | 87 +++ code/__DEFINES/gamemode.dm | 94 +-- code/__DEFINES/role_preferences.dm | 2 +- code/__DEFINES/traits/declarations.dm | 1 + code/_globalvars/traits.dm | 1 + code/datums/components/ritual_object.dm | 5 +- code/datums/diseases/ectoplasmic.dm | 2 +- code/datums/elements/devil_banishment.dm | 51 ++ code/datums/elements/devil_regen.dm | 113 ++++ code/datums/mind.dm | 76 +-- code/datums/rituals.dm | 2 +- .../spell_handler/devil_spell_handler.dm | 10 + code/datums/spells/devil.dm | 357 ++++++++--- code/game/gamemodes/devil/devil.dm | 48 -- .../devil/devil_agent/devil_agent.dm | 38 -- code/game/gamemodes/devil/devil_game_mode.dm | 66 --- code/game/gamemodes/devil/devilinfo.dm | 560 ------------------ code/game/gamemodes/devil/game_mode.dm | 103 ---- code/game/gamemodes/devil/objectives.dm | 149 ++--- .../gamemodes/devil/true_devil/inventory.dm | 2 - .../miniantags/sintouched/objectives.dm | 11 - .../objects/effects/decals/Cleanable/misc.dm | 18 + code/game/objects/items/toys.dm | 45 +- code/game/objects/items/weapons/twohanded.dm | 8 +- .../antagonists}/devil/contracts/friend.dm | 0 code/modules/antagonists/devil/devil.dm | 205 +++++++ code/modules/antagonists/devil/devil_ban.dm | 71 +++ code/modules/antagonists/devil/devil_bane.dm | 191 ++++++ .../modules/antagonists/devil/devil_banish.dm | 90 +++ code/modules/antagonists/devil/devil_info.dm | 66 +++ .../antagonists/devil/devil_obligation.dm | 94 +++ .../modules/antagonists/devil/devil_outfit.dm | 30 + code/modules/antagonists/devil/devil_pawn.dm | 7 + code/modules/antagonists/devil/devil_rank.dm | 123 ++++ .../modules/antagonists/devil/devil_ritual.dm | 88 +++ .../modules/antagonists/devil/helper_procs.dm | 14 + .../antagonists}/devil/imp/imp.dm | 11 +- code/modules/antagonists/devil/sintouched.dm | 43 ++ .../devil/true_devil/_true_devil.dm | 81 +-- code/modules/library/codex_gigas.dm | 97 +-- code/modules/mob/living/carbon/carbon.dm | 5 - code/modules/mob/living/carbon/human/human.dm | 40 -- .../mob/living/carbon/human/human_defense.dm | 17 +- code/modules/mob/living/death.dm | 8 +- code/modules/mob/living/living.dm | 33 +- code/modules/paperwork/contract.dm | 63 +- code/modules/reagents/chemistry/holder.dm | 22 +- code/modules/reagents/chemistry/reagents.dm | 7 +- .../reagents/chemistry/reagents/misc.dm | 10 - code/modules/surgery/organs/vocal_cords.dm | 15 +- paradise.dme | 31 +- 53 files changed, 1918 insertions(+), 1440 deletions(-) create mode 100644 code/__DEFINES/devil.dm create mode 100644 code/datums/elements/devil_banishment.dm create mode 100644 code/datums/elements/devil_regen.dm create mode 100644 code/datums/spell_handler/devil_spell_handler.dm delete mode 100644 code/game/gamemodes/devil/devil.dm delete mode 100644 code/game/gamemodes/devil/devil_agent/devil_agent.dm delete mode 100644 code/game/gamemodes/devil/devil_game_mode.dm delete mode 100644 code/game/gamemodes/devil/devilinfo.dm delete mode 100644 code/game/gamemodes/devil/true_devil/inventory.dm rename code/{game/gamemodes => modules/antagonists}/devil/contracts/friend.dm (100%) create mode 100644 code/modules/antagonists/devil/devil.dm create mode 100644 code/modules/antagonists/devil/devil_ban.dm create mode 100644 code/modules/antagonists/devil/devil_bane.dm create mode 100644 code/modules/antagonists/devil/devil_banish.dm create mode 100644 code/modules/antagonists/devil/devil_info.dm create mode 100644 code/modules/antagonists/devil/devil_obligation.dm create mode 100644 code/modules/antagonists/devil/devil_outfit.dm create mode 100644 code/modules/antagonists/devil/devil_pawn.dm create mode 100644 code/modules/antagonists/devil/devil_rank.dm create mode 100644 code/modules/antagonists/devil/devil_ritual.dm create mode 100644 code/modules/antagonists/devil/helper_procs.dm rename code/{game/gamemodes => modules/antagonists}/devil/imp/imp.dm (74%) create mode 100644 code/modules/antagonists/devil/sintouched.dm rename code/{game/gamemodes => modules/antagonists}/devil/true_devil/_true_devil.dm (72%) diff --git a/code/__DEFINES/contracts.dm b/code/__DEFINES/contracts.dm index 26351cfbac2..b333b769108 100644 --- a/code/__DEFINES/contracts.dm +++ b/code/__DEFINES/contracts.dm @@ -19,40 +19,3 @@ #define CONTRACT_FOOD "Food" #define CONTRACT_SPACE "Space Gear" #define CONTRACT_CALAMITY "Calamity" - -#define BANE_SALT "salt" -#define BANE_LIGHT "light" -#define BANE_IRON "iron" -#define BANE_WHITECLOTHES "whiteclothes" -#define BANE_SILVER "silver" -#define BANE_HARVEST "harvest" -#define BANE_TOOLBOX "toolbox" - -#define OBLIGATION_FOOD "food" -#define OBLIGATION_FIDDLE "fiddle" -#define OBLIGATION_DANCEOFF "danceoff" -#define OBLIGATION_GREET "greet" -#define OBLIGATION_PRESENCEKNOWN "presenceknown" -#define OBLIGATION_SAYNAME "sayname" -#define OBLIGATION_ANNOUNCEKILL "announcekill" -#define OBLIGATION_ANSWERTONAME "answername" - -#define BAN_HURTWOMAN "hurtwoman" -#define BAN_HURTMAN "hurtman" -#define BAN_CHAPEL "chapel" -#define BAN_HURTPRIEST "hurtpriest" -#define BAN_AVOIDWATER "avoidwater" -#define BAN_STRIKEUNCONCIOUS "strikeunconcious" -#define BAN_HURTLIZARD "hurtlizard" -#define BAN_HURTANIMAL "hurtanimal" - -#define BANISH_WATER "water" -#define BANISH_COFFIN "coffin" -#define BANISH_FORMALDYHIDE "embalm" -#define BANISH_RUNES "runes" -#define BANISH_CANDLES "candles" -#define BANISH_DESTRUCTION "destruction" -#define BANISH_FUNERAL_GARB "funeral" - -#define LORE 1 -#define LAW 2 diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm index f2c8df77b11..008f501e8dd 100644 --- a/code/__DEFINES/dcs/signals.dm +++ b/code/__DEFINES/dcs/signals.dm @@ -553,6 +553,9 @@ #define COMSIG_LIVING_SHOCK_PREVENTED "living_shock_prevented" ///sent by stuff like stunbatons and tasers: () #define COMSIG_LIVING_MINOR_SHOCK "living_minor_shock" +/// Source: /mob/living/proc/flash_eyes(intensity, override_blindness_check, affect_silicon, visual, type) +#define COMSIG_LIVING_EARLY_FLASH_EYES "living_flash_eyes" + #define STOP_FLASHING_EYES (1<<0) ///from base of mob/living/revive() (full_heal, admin_revive) #define COMSIG_LIVING_REVIVE "living_revive" ///from base of /mob/living/regenerate_limbs(): (noheal, excluded_limbs) @@ -582,6 +585,8 @@ ///From living/Life(). (deltatime, times_fired) #define COMSIG_LIVING_LIFE "living_life" ///from base of mob/living/death(): (gibbed) +#define COMSIG_LIVING_EARLY_DEATH "living_early_death" +///from base of mob/living/death(): (gibbed) #define COMSIG_LIVING_DEATH "living_death" //sent from mobs when they exit their body as a ghost #define COMSIG_LIVING_GHOSTIZED "ghostized" @@ -1008,6 +1013,11 @@ ///from base of obj/item/reagent_containers/food/snacks/attack(): (mob/living/eater, mob/feeder) #define COMSIG_FOOD_EATEN "food_eaten" +/// Reagents +/// Source: /datum/reagents/proc/add_reagent (datum/reagents, reagent_id, amount, data, reagtemp, no_react, chem_temp) +#define COMSIG_EARLY_REAGENT_ADDED "reagent_early_added" + #define COMPONENT_PREVENT_ADD_REAGENT (1<<0) + //Gibs ///from base of /obj/effect/decal/cleanable/blood/gibs/streak(): (list/directions, list/diseases) diff --git a/code/__DEFINES/devil.dm b/code/__DEFINES/devil.dm new file mode 100644 index 00000000000..f58afda46b9 --- /dev/null +++ b/code/__DEFINES/devil.dm @@ -0,0 +1,87 @@ +GLOBAL_LIST_INIT(whiteness, list( + /obj/item/clothing/under/color/white = 2, + /obj/item/clothing/under/rank/bartender = 1, + /obj/item/clothing/under/rank/chef = 1, + /obj/item/clothing/under/rank/chief_engineer = 1, + /obj/item/clothing/under/rank/scientist = 1, + /obj/item/clothing/under/rank/chemist = 1, + /obj/item/clothing/under/rank/chief_medical_officer = 1, + /obj/item/clothing/under/rank/geneticist = 1, + /obj/item/clothing/under/rank/virologist = 1, + /obj/item/clothing/under/rank/nursesuit = 1, + /obj/item/clothing/under/rank/medical = 1, + /obj/item/clothing/under/rank/psych = 1, + /obj/item/clothing/under/rank/orderly = 1, + /obj/item/clothing/under/rank/security/brigphys = 1, + /obj/item/clothing/under/rank/internalaffairs = 1, + /obj/item/clothing/under/rank/ntrep = 1, + /obj/item/clothing/under/det = 1, + /obj/item/clothing/under/wedding/bride_white = 1, + /obj/item/clothing/under/mafia/white = 1, + /obj/item/clothing/under/noble_clothes = 1, + /obj/item/clothing/under/sl_suit = 1, + /obj/item/clothing/under/burial = 1 +)) + +#define ENRAGED_THRESHOLD 4 +#define BLOOD_THRESHOLD 7 +#define TRUE_THRESHOLD 10 + +#define BASIC_DEVIL_REGEN_THRESHOLD 10 SECONDS +#define ENRAGED_DEVIL_REGEN_THRESHOLD 10 SECONDS +#define BLOOD_LIZARD_REGEN_THRESHOLD 5 SECONDS +#define TRUE_DEVIL_REGEN_THRESHOLD 3 SECONDS + +#define BASIC_DEVIL_REGEN_AMOUNT 20 +#define ENRAGED_DEVIL_REGEN_AMOUNT 40 +#define BLOOD_LIZARD_REGEN_AMOUNT 60 +#define TRUE_DEVIL_REGEN_AMOUNT 80 + +#define BASIC_DEVIL_RANK /datum/devil_rank/basic_devil +#define ENRAGED_DEVIL_RANK /datum/devil_rank/enraged_devil +#define BLOOD_LIZARD_RANK /datum/devil_rank/blood_lizard +#define TRUE_DEVIL_RANK /datum/devil_rank/true_devil + +#define BANE_SALT "salt" +#define BANE_LIGHT "light" +#define BANE_IRON "iron" +#define BANE_WHITECLOTHES "whiteclothes" +#define BANE_SILVER "silver" +#define BANE_HARVEST "harvest" +#define BANE_TOOLBOX "toolbox" + +#define OBLIGATION_FOOD "food" +#define OBLIGATION_FIDDLE "fiddle" +#define OBLIGATION_DANCEOFF "danceoff" +#define OBLIGATION_GREET "greet" +#define OBLIGATION_PRESENCEKNOWN "presenceknown" +#define OBLIGATION_SAYNAME "sayname" +#define OBLIGATION_ANNOUNCEKILL "announcekill" +#define OBLIGATION_ANSWERTONAME "answername" + +#define BAN_HURTWOMAN "hurtwoman" +#define BAN_HURTMAN "hurtman" +#define BAN_CHAPEL "chapel" +#define BAN_HURTPRIEST "hurtpriest" +#define BAN_AVOIDWATER "avoidwater" +#define BAN_STRIKEUNCONCIOUS "strikeunconcious" +#define BAN_HURTLIZARD "hurtlizard" +#define BAN_HURTANIMAL "hurtanimal" + +#define BANISH_WATER "water" +#define BANISH_COFFIN "coffin" +#define BANISH_FORMALDYHIDE "embalm" +#define BANISH_RUNES "runes" +#define BANISH_CANDLES "candles" +#define BANISH_DESTRUCTION "destruction" +#define BANISH_FUNERAL_GARB "funeral" + +#define BANE_TOOLBOX_DAMAGE_MODIFIER 2.5 +#define BANE_HARVEST_DAMAGE_MULTIPLIER 2 + +GLOBAL_LIST_EMPTY(allDevils) +//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.")) diff --git a/code/__DEFINES/gamemode.dm b/code/__DEFINES/gamemode.dm index 1457c5bc039..121121aa158 100644 --- a/code/__DEFINES/gamemode.dm +++ b/code/__DEFINES/gamemode.dm @@ -25,50 +25,52 @@ #define GAMEMODE_IS_WIZARD (SSticker && istype(SSticker.mode, /datum/game_mode/wizard)) #define GAMEMODE_IS_RAGIN_MAGES (SSticker && istype(SSticker.mode, /datum/game_mode/wizard/raginmages)) -//special roles +// special roles // Distinct from the ROLE_X defines because some antags have multiple special roles but only one ban type -#define SPECIAL_ROLE_ABDUCTOR_AGENT "Abductor Agent" -#define SPECIAL_ROLE_ABDUCTOR_SCIENTIST "Abductor Scientist" -#define SPECIAL_ROLE_BLOB "Blob" -#define SPECIAL_ROLE_BLOB_OVERMIND "Blob Overmind" -#define SPECIAL_ROLE_BLOB_MINION "Blob Minion" -#define SPECIAL_ROLE_BORER "Borer" -#define SPECIAL_ROLE_CARP "Space Carp" -#define SPECIAL_ROLE_CHANGELING "Changeling" -#define SPECIAL_ROLE_CULTIST "Cultist" -#define SPECIAL_ROLE_CLOCKER "Clockwork cultist" -#define SPECIAL_ROLE_DEATHSQUAD "Death Commando" -#define SPECIAL_ROLE_ERT "Response Team" -#define SPECIAL_ROLE_FREE_GOLEM "Free Golem" -#define SPECIAL_ROLE_GOLEM "Golem" -#define SPECIAL_ROLE_HEAD_REV "Head Revolutionary" -#define SPECIAL_ROLE_HEADSLUG "HeadSlug" -#define SPECIAL_ROLE_HONKSQUAD "Honksquad" -#define SPECIAL_ROLE_REV "Revolutionary" -#define SPECIAL_ROLE_MORPH "Morph" -#define SPECIAL_ROLE_MULTIVERSE "Multiverse Traveller" -#define SPECIAL_ROLE_NUKEOPS "Syndicate" -#define SPECIAL_ROLE_PYROCLASTIC_SLIME "Pyroclastic Anomaly Slime" -#define SPECIAL_ROLE_RAIDER "Vox Raider" -#define SPECIAL_ROLE_REVENANT "Revenant" -#define SPECIAL_ROLE_SHADOWLING "Shadowling" -#define SPECIAL_ROLE_SHADOWLING_THRALL "Shadowling Thrall" -#define SPECIAL_ROLE_DEMON "Demon" -#define SPECIAL_ROLE_SUPER "Super" -#define SPECIAL_ROLE_SYNDICATE_DEATHSQUAD "Syndicate Commando" -#define SPECIAL_ROLE_TRAITOR "Traitor" -#define SPECIAL_ROLE_VAMPIRE "Vampire" -#define SPECIAL_ROLE_VAMPIRE_THRALL "Vampire Thrall" -#define SPECIAL_ROLE_WIZARD "Wizard" -#define SPECIAL_ROLE_WIZARD_APPRENTICE "Wizard Apprentice" -#define SPECIAL_ROLE_XENOMORPH "Xenomorph" -#define SPECIAL_ROLE_XENOMORPH_QUEEN "Xenomorph Queen" -#define SPECIAL_ROLE_XENOMORPH_HUNTER "Xenomorph Hunter" -#define SPECIAL_ROLE_XENOMORPH_DRONE "Xenomorph Drone" -#define SPECIAL_ROLE_XENOMORPH_SENTINEL "Xenomorph Sentinel" -#define SPECIAL_ROLE_XENOMORPH_LARVA "Xenomorph Larva" -#define SPECIAL_ROLE_SPACE_NINJA "Space Ninja" -#define SPECIAL_ROLE_THIEF "Thief" -#define SPECIAL_ROLE_SPACE_DRAGON "Space Dragon" -#define SPECIAL_ROLE_EVENTMISC "Event Role" -#define SPECIAL_ROLE_MALFAI "Malfunctioning AI" +#define SPECIAL_ROLE_ABDUCTOR_AGENT "Abductor Agent" +#define SPECIAL_ROLE_ABDUCTOR_SCIENTIST "Abductor Scientist" +#define SPECIAL_ROLE_BLOB "Blob" +#define SPECIAL_ROLE_BLOB_OVERMIND "Blob Overmind" +#define SPECIAL_ROLE_BLOB_MINION "Blob Minion" +#define SPECIAL_ROLE_BORER "Borer" +#define SPECIAL_ROLE_CARP "Space Carp" +#define SPECIAL_ROLE_CHANGELING "Changeling" +#define SPECIAL_ROLE_CULTIST "Cultist" +#define SPECIAL_ROLE_CLOCKER "Clockwork cultist" +#define SPECIAL_ROLE_DEATHSQUAD "Death Commando" +#define SPECIAL_ROLE_ERT "Response Team" +#define SPECIAL_ROLE_FREE_GOLEM "Free Golem" +#define SPECIAL_ROLE_GOLEM "Golem" +#define SPECIAL_ROLE_HEAD_REV "Head Revolutionary" +#define SPECIAL_ROLE_HEADSLUG "HeadSlug" +#define SPECIAL_ROLE_HONKSQUAD "Honksquad" +#define SPECIAL_ROLE_REV "Revolutionary" +#define SPECIAL_ROLE_MORPH "Morph" +#define SPECIAL_ROLE_MULTIVERSE "Multiverse Traveller" +#define SPECIAL_ROLE_NUKEOPS "Syndicate" +#define SPECIAL_ROLE_PYROCLASTIC_SLIME "Pyroclastic Anomaly Slime" +#define SPECIAL_ROLE_RAIDER "Vox Raider" +#define SPECIAL_ROLE_REVENANT "Revenant" +#define SPECIAL_ROLE_SHADOWLING "Shadowling" +#define SPECIAL_ROLE_SHADOWLING_THRALL "Shadowling Thrall" +#define SPECIAL_ROLE_DEMON "Demon" +#define SPECIAL_ROLE_SUPER "Super" +#define SPECIAL_ROLE_SYNDICATE_DEATHSQUAD "Syndicate Commando" +#define SPECIAL_ROLE_TRAITOR "Traitor" +#define SPECIAL_ROLE_VAMPIRE "Vampire" +#define SPECIAL_ROLE_VAMPIRE_THRALL "Vampire Thrall" +#define SPECIAL_ROLE_WIZARD "Wizard" +#define SPECIAL_ROLE_WIZARD_APPRENTICE "Wizard Apprentice" +#define SPECIAL_ROLE_XENOMORPH "Xenomorph" +#define SPECIAL_ROLE_XENOMORPH_QUEEN "Xenomorph Queen" +#define SPECIAL_ROLE_XENOMORPH_HUNTER "Xenomorph Hunter" +#define SPECIAL_ROLE_XENOMORPH_DRONE "Xenomorph Drone" +#define SPECIAL_ROLE_XENOMORPH_SENTINEL "Xenomorph Sentinel" +#define SPECIAL_ROLE_XENOMORPH_LARVA "Xenomorph Larva" +#define SPECIAL_ROLE_SPACE_NINJA "Space Ninja" +#define SPECIAL_ROLE_THIEF "Thief" +#define SPECIAL_ROLE_SPACE_DRAGON "Space Dragon" +#define SPECIAL_ROLE_EVENTMISC "Event Role" +#define SPECIAL_ROLE_MALFAI "Malfunctioning AI" +#define SPECIAL_ROLE_SINTOUCHED "Sintouched" +#define SPECIAL_ROLE_DEVIL_PAWN "Devil's pawn" diff --git a/code/__DEFINES/role_preferences.dm b/code/__DEFINES/role_preferences.dm index 0285fecd7bf..a0429a5cb97 100644 --- a/code/__DEFINES/role_preferences.dm +++ b/code/__DEFINES/role_preferences.dm @@ -66,7 +66,7 @@ GLOBAL_LIST_INIT(special_roles, list( ROLE_CULTIST = /datum/game_mode/cult, // Cultist ROLE_CLOCKER = /datum/game_mode/clockwork, // Clockwork Cultist ROLE_DEMON, // Demons (Slaughter/Laughter/Shadow) - ROLE_DEVIL = /datum/game_mode/devil/devil_agents, // Devil + ROLE_DEVIL, // Devil ROLE_GSPIDER, // Giant spider ROLE_GUARDIAN, // Guardian ROLE_ELITE, // Lavaland Elite diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm index 718a34a9308..2f24d20b028 100644 --- a/code/__DEFINES/traits/declarations.dm +++ b/code/__DEFINES/traits/declarations.dm @@ -48,6 +48,7 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai //mob traits #define TRAIT_GODMODE "godmode" #define TRAIT_PACIFISM "pacifism" +#define TRAIT_NO_DEATH "nodeath" #define TRAIT_WATERBREATH "waterbreathing" #define TRAIT_BLOODCRAWL "bloodcrawl" #define TRAIT_BLOODCRAWL_EAT "bloodcrawl_eat" diff --git a/code/_globalvars/traits.dm b/code/_globalvars/traits.dm index 94b555a43c1..f61699a0c5e 100644 --- a/code/_globalvars/traits.dm +++ b/code/_globalvars/traits.dm @@ -91,6 +91,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_NEARSIGHTED" = TRAIT_NEARSIGHTED, "TRAIT_NEGATES_GRAVITY" = TRAIT_NEGATES_GRAVITY, "TRAIT_NO_BIOCHIPS" = TRAIT_NO_BIOCHIPS, + "TRAIT_NO_DEATH" = TRAIT_NO_DEATH, "TRAIT_NO_BLOOD" = TRAIT_NO_BLOOD, "TRAIT_NO_BLOOD_RESTORE" = TRAIT_NO_BLOOD_RESTORE, "TRAIT_NO_BREATH" = TRAIT_NO_BREATH, diff --git a/code/datums/components/ritual_object.dm b/code/datums/components/ritual_object.dm index 31064e438db..f67fbd8b9aa 100644 --- a/code/datums/components/ritual_object.dm +++ b/code/datums/components/ritual_object.dm @@ -22,6 +22,7 @@ src.allowed_categories = allowed_categories src.allowed_species = allowed_species src.allowed_special_role = allowed_special_role + get_rituals() /datum/component/ritual_object/RegisterWithParent() @@ -62,7 +63,7 @@ if(allowed_species && !is_type_in_list(human.dna.species, allowed_species)) return - if(allowed_special_role && !is_type_in_list(human.mind?.special_role, allowed_special_role)) + if(allowed_special_role && !LAZYIN(allowed_special_role, human.mind?.special_role)) return active_ui = TRUE @@ -111,7 +112,7 @@ if(ritual.allowed_species && !is_type_in_list(human.dna.species, ritual.allowed_species)) continue - if(ritual.allowed_special_role && !is_type_in_list(human.mind?.special_role, ritual.allowed_special_role)) + if(ritual.allowed_special_role && !LAZYIN(ritual.allowed_special_role, human.mind?.special_role)) continue LAZYADD(rituals_list, ritual.name) diff --git a/code/datums/diseases/ectoplasmic.dm b/code/datums/diseases/ectoplasmic.dm index 06b17032931..8d6ecf3b649 100644 --- a/code/datums/diseases/ectoplasmic.dm +++ b/code/datums/diseases/ectoplasmic.dm @@ -47,7 +47,7 @@ create_effect = TRUE if(5) if(prob(SYMPTOM_ACTIVATION_PROB * 10)) - human.influenceSin() + human.mind?.add_antag_datum(/datum/antagonist/sintouched) to_chat(human, span_revenbignotice("You suddenly feel your soul become corrupted.")) else human.apply_damage(80, STAMINA) diff --git a/code/datums/elements/devil_banishment.dm b/code/datums/elements/devil_banishment.dm new file mode 100644 index 00000000000..4fefe4d79d9 --- /dev/null +++ b/code/datums/elements/devil_banishment.dm @@ -0,0 +1,51 @@ +/datum/element/devil_banishment + element_flags = ELEMENT_DETACH_ON_HOST_DESTROY|ELEMENT_BESPOKE + id_arg_index = 2 + + var/linked_timer + +/datum/element/devil_banishment/Attach(datum/target) + . = ..() + var/mob/living/carbon/human = target + + if(!istype(human) || !human.mind?.has_antag_datum(/datum/antagonist/devil)) + return ELEMENT_INCOMPATIBLE + + RegisterSignal(human, COMSIG_LIVING_EARLY_DEATH, PROC_REF(pre_death)) + +/datum/element/devil_banishment/Detach(datum/target) + . = ..() + + UnregisterSignal(target, COMSIG_LIVING_EARLY_DEATH) + +/datum/element/devil_banishment/proc/pre_death(datum/source, gibbed) + SIGNAL_HANDLER + + if(gibbed || linked_timer) + return + + var/mob/living/carbon/human = source + var/datum/antagonist/devil/devil = human?.mind?.has_antag_datum(/datum/antagonist/devil) + + if(!devil?.info) + return + + playsound(get_turf(human), 'sound/magic/vampire_anabiosis.ogg', 50, 0, TRUE) + linked_timer = addtimer(CALLBACK(src, PROC_REF(try_banishment), human, devil), devil.rank.regen_threshold / 2, TIMER_LOOP | TIMER_STOPPABLE | TIMER_DELETE_ME) + +/datum/element/devil_banishment/proc/try_banishment(mob/living/carbon/human, datum/antagonist/devil/devil) + if(human.health >= human.maxHealth) + stop_banishment_check() + return + + if(!devil.info.banish.check_banishment()) + return + + human.dust() + +/datum/element/devil_banishment/proc/stop_banishment_check() + if(!linked_timer) + return + + deltimer(linked_timer) + linked_timer = null diff --git a/code/datums/elements/devil_regen.dm b/code/datums/elements/devil_regen.dm new file mode 100644 index 00000000000..1d5de2d95bb --- /dev/null +++ b/code/datums/elements/devil_regen.dm @@ -0,0 +1,113 @@ +/datum/element/devil_regeneration + element_flags = ELEMENT_DETACH_ON_HOST_DESTROY|ELEMENT_BESPOKE + id_arg_index = 2 + + var/linked_timer + var/list/sounds = list('sound/magic/demon_consume.ogg', 'sound/effects/attackblob.ogg') + +/datum/element/devil_regeneration/Attach(datum/target) + . = ..() + var/mob/living/carbon/human = target + + if(!istype(human) || !human.mind?.has_antag_datum(/datum/antagonist/devil)) + return ELEMENT_INCOMPATIBLE + + RegisterSignal(human, COMSIG_CARBON_LOSE_ORGAN, PROC_REF(start_regen_bodypart)) + RegisterSignal(human, COMSIG_LIVING_EARLY_DEATH, PROC_REF(pre_death)) + + var/obj/item/organ/internal/brain/brain = human.get_organ_slot(INTERNAL_ORGAN_BRAIN) + brain?.decoy_brain = TRUE + +/datum/element/devil_regeneration/Detach(datum/target) + . = ..() + + UnregisterSignal(target, COMSIG_CARBON_LOSE_ORGAN) + UnregisterSignal(target, COMSIG_LIVING_EARLY_DEATH) + + if(!iscarbon(target)) + return + + var/mob/living/carbon/carbon = target + var/obj/item/organ/internal/brain/brain = carbon.get_organ_slot(INTERNAL_ORGAN_BRAIN) + + brain?.decoy_brain = FALSE + +/datum/element/devil_regeneration/proc/start_regen_bodypart(datum/source, obj/item/organ/organ) + SIGNAL_HANDLER + + var/obj/item/organ/external/external = organ + if(!istype(external)) + return + + var/mob/living/carbon/human = source + var/datum/antagonist/devil/devil = human?.mind?.has_antag_datum(/datum/antagonist/devil) + + if(!devil) + return + + addtimer(CALLBACK(src, PROC_REF(regen_bodypart), human, external, devil), devil.rank.regen_threshold) + +/datum/element/devil_regeneration/proc/regen_bodypart( + mob/living/carbon/human, + obj/item/organ/external/external, + datum/antagonist/devil/devil + ) + external = new external(human) + human.heal_overall_damage(devil.rank.regen_amount, devil.rank.regen_amount) + + playsound(get_turf(human), pick(sounds), 50, 0, TRUE) + update_status(human) + +/datum/element/devil_regeneration/proc/pre_death(datum/source, gibbed) + SIGNAL_HANDLER + + if(gibbed || linked_timer) + return + + var/mob/living/carbon/human = source + var/datum/antagonist/devil/devil = human?.mind?.has_antag_datum(/datum/antagonist/devil) + + if(!devil) + return + + to_chat(human, span_revenbignotice("Сверхъестественные силы предотвращают вашу смерть.")) + playsound(get_turf(human), 'sound/magic/vampire_anabiosis.ogg', 50, 0, TRUE) + + linked_timer = addtimer(CALLBACK(src, PROC_REF(apply_regeneration), human, devil), devil.rank.regen_threshold, TIMER_LOOP | TIMER_STOPPABLE | TIMER_DELETE_ME) + +/datum/element/devil_regeneration/proc/on_revive() + if(!linked_timer) + return + + deltimer(linked_timer) + linked_timer = null + +/datum/element/devil_regeneration/proc/apply_regeneration(mob/living/carbon/human, datum/antagonist/devil/devil) + if(human.health >= human.maxHealth) + on_revive() + + human.setOxyLoss(0) + human.heal_damages( + devil.rank.regen_amount, + devil.rank.regen_amount, + devil.rank.regen_amount, + devil.rank.regen_amount, + devil.rank.regen_amount, + devil.rank.regen_amount, + devil.rank.regen_amount, + devil.rank.regen_amount, + devil.rank.regen_amount, + TRUE, + TRUE + ) + + if(ishuman(human)) + var/mob/living/carbon/human/mob = human + mob.check_and_regenerate_organs() + + playsound(get_turf(human), pick(sounds), 50, 0, TRUE) + update_status(human) + +/datum/element/devil_regeneration/proc/update_status(mob/living/carbon/human) + human.updatehealth() + human.UpdateDamageIcon() diff --git a/code/datums/mind.dm b/code/datums/mind.dm index 40dd4d2881b..2b24f9b19df 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -62,7 +62,6 @@ 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/mindslaves/som //stands for slave or master...hush.. - 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 @@ -504,16 +503,15 @@ /datum/mind/proc/memory_edit_devil(mob/living/H) . = _memory_edit_header("devil", list("devilagents")) if(src in SSticker.mode.devils) + var/datum/antagonist/devil/devilinfo = has_antag_datum(/datum/antagonist/devil) if(!devilinfo) . += "No devilinfo found! Yell at a coder!" - else if(!devilinfo.ascendable) - . += "DEVIL|Ascendable Devil|sintouched|no" else - . += "DEVIL|ASCENDABLE DEVIL|sintouched|no" + . += "DEVIL|sintouched|no" else if(src in SSticker.mode.sintouched) - . += "devil|Ascendable Devil|SINTOUCHED|no" + . += "devil|SINTOUCHED|no" else - . += "devil|Ascendable Devil|sintouched|NO" + . += "devil|sintouched|NO" . += _memory_edit_role_enabled(ROLE_DEVIL) @@ -1906,47 +1904,24 @@ if("clear") if(src in SSticker.mode.devils) log_admin("[key_name(usr)] has de-devil'ed [current].") + else if(src in SSticker.mode.sintouched) message_admins("[key_name_admin(usr)] has de-sintouch'ed [current].") log_admin("[key_name(usr)] has de-sintouch'ed [current].") + remove_devil_role() if("devil") - if(devilinfo) - devilinfo.ascendable = FALSE - message_admins("[key_name_admin(usr)] has made [current] unable to ascend as a devil.") - log_admin("[key_name_admin(usr)] has made [current] unable to ascend as a devil.") - return - if(!ishuman(current) && !isrobot(current)) - to_chat(usr, "This only works on humans and cyborgs!") - return - SSticker.mode.devils += src - special_role = "devil" - SSticker.mode.update_devil_icons_added(src) - SSticker.mode.finalize_devil(src, FALSE) - SSticker.mode.forge_devil_objectives(src, 2) - SSticker.mode.greet_devil(src) + if(has_antag_datum(/datum/antagonist/devil)) + return + + add_antag_datum(/datum/antagonist/devil) message_admins("[key_name_admin(usr)] has devil'ed [current].") log_admin("[key_name(usr)] has devil'ed [current].") - if("ascendable_devil") - if(devilinfo) - devilinfo.ascendable = TRUE - message_admins("[key_name_admin(usr)] has made [current] able to ascend as a devil.") - log_admin("[key_name_admin(usr)] has made [current] able to ascend as a devil.") - return - if(!ishuman(current) && !isrobot(current)) - to_chat(usr, "This only works on humans and cyborgs!") - return - SSticker.mode.devils += src - special_role = "devil" - SSticker.mode.update_devil_icons_added(src) - SSticker.mode.finalize_devil(src, TRUE) - SSticker.mode.forge_devil_objectives(src, 2) - SSticker.mode.greet_devil(src) - 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") - var/mob/living/carbon/human/H = current - H.influenceSin() + if(has_antag_datum(/datum/antagonist/sintouched)) + return + + add_antag_datum(/datum/antagonist/sintouched) message_admins("[key_name_admin(usr)] has sintouch'ed [current].") log_admin("[key_name(usr)] has sintouch'ed [current].") @@ -2703,27 +2678,10 @@ /datum/mind/proc/remove_devil_role() if(src in SSticker.mode.devils) - if(istype(current,/mob/living/carbon/true_devil/)) - else - SSticker.mode.devils -= src - SSticker.mode.update_devil_icons_removed(src) - special_role = null - RemoveSpell(/obj/effect/proc_holder/spell/infernal_jaunt) - RemoveSpell(/obj/effect/proc_holder/spell/fireball/hellish) - RemoveSpell(/obj/effect/proc_holder/spell/summon_contract) - RemoveSpell(/obj/effect/proc_holder/spell/conjure_item/pitchfork) - RemoveSpell(/obj/effect/proc_holder/spell/conjure_item/pitchfork/greater) - RemoveSpell(/obj/effect/proc_holder/spell/conjure_item/pitchfork/ascended) - RemoveSpell(/obj/effect/proc_holder/spell/conjure_item/violin) - RemoveSpell(/obj/effect/proc_holder/spell/summon_dancefloor) - RemoveSpell(/obj/effect/proc_holder/spell/sintouch) - RemoveSpell(/obj/effect/proc_holder/spell/sintouch/ascended) - if(issilicon(current)) - var/mob/living/silicon/S = current - S.laws.clear_sixsixsix_laws() - devilinfo = null + remove_antag_datum(/datum/antagonist/devil) + else if(src in SSticker.mode.sintouched) - SSticker.mode.sintouched -= src + remove_antag_datum(/datum/antagonist/sintouched) /datum/mind/proc/remove_contractor_role() diff --git a/code/datums/rituals.dm b/code/datums/rituals.dm index 592bfdde4a9..954fdda83e5 100644 --- a/code/datums/rituals.dm +++ b/code/datums/rituals.dm @@ -75,7 +75,7 @@ if(NONE) failed = TRUE - if(start_cooldown) + if(start_cooldown && cooldown_after_cast) COOLDOWN_START(src, ritual_cooldown, cooldown_after_cast) if(cause_disaster && prob(disaster_prob)) diff --git a/code/datums/spell_handler/devil_spell_handler.dm b/code/datums/spell_handler/devil_spell_handler.dm new file mode 100644 index 00000000000..303d661e959 --- /dev/null +++ b/code/datums/spell_handler/devil_spell_handler.dm @@ -0,0 +1,10 @@ +/datum/spell_handler/devil + +/datum/spell_handler/devil/can_cast(mob/living/carbon/user, charge_check, show_message, obj/effect/proc_holder/spell/spell) + if(!istype(user)) + return FALSE + + if(!user.mind?.has_antag_datum(/datum/antagonist/devil)) + return FALSE + + return TRUE diff --git a/code/datums/spells/devil.dm b/code/datums/spells/devil.dm index d2a513dd5a7..1df5e792bf1 100644 --- a/code/datums/spells/devil.dm +++ b/code/datums/spells/devil.dm @@ -1,9 +1,12 @@ /obj/effect/proc_holder/spell/conjure_item/pitchfork name = "Summon Pitchfork" desc = "A devil's weapon of choice. Use this to summon/unsummon your pitchfork." + item_type = /obj/item/twohanded/pitchfork/demonic + action_icon_state = "pitchfork" action_background_icon_state = "bg_demon" + human_req = FALSE /obj/effect/proc_holder/spell/conjure_item/pitchfork/greater @@ -15,27 +18,35 @@ /obj/effect/proc_holder/spell/conjure_item/violin - item_type = /obj/item/instrument/violin/golden + name = "Summon golden violin" desc = "A devil's instrument of choice. Use this to summon/unsummon your golden violin." + + item_type = /obj/item/instrument/violin/golden + invocation_type = "whisper" invocation = "I ain't have this much fun since Georgia." + action_icon_state = "golden_violin" - name = "Summon golden violin" action_background_icon_state = "bg_demon" /obj/effect/proc_holder/spell/summon_contract name = "Summon infernal contract" desc = "Skip making a contract by hand, just do it by magic." + invocation_type = "whisper" invocation = "Just sign on the dotted line." - selection_activated_message = "You prepare a detailed contract. Click on a target to summon the contract in his hands." - selection_deactivated_message = "You archive the contract for later use." + + selection_activated_message = span_notice("You prepare a detailed contract. Click on a target to summon the contract in his hands.") + selection_deactivated_message = span_notice("You archive the contract for later use.") + clothes_req = FALSE human_req = FALSE + school = "conjuration" base_cooldown = 15 SECONDS cooldown_min = 1 SECONDS + action_icon_state = "spell_default" action_background_icon_state = "bg_demon" need_active_overlay = TRUE @@ -57,41 +68,50 @@ /obj/effect/proc_holder/spell/summon_contract/cast(list/targets, mob/user = usr) for(var/target in targets) var/mob/living/carbon/C = target - if(C.mind && user.mind) - if(C.stat == DEAD) - if(user.drop_from_active_hand()) - var/obj/item/paper/contract/infernal/revive/contract = new(user.loc, C.mind, user.mind) - user.put_in_hands(contract) - else - var/obj/item/paper/contract/infernal/contract - var/contractTypeName = input(user, "What type of contract?") in list (CONTRACT_POWER, CONTRACT_WEALTH, CONTRACT_PRESTIGE, CONTRACT_MAGIC, CONTRACT_KNOWLEDGE, CONTRACT_FRIENDSHIP) //TODO: Refactor this to be less boilerplate-y - switch(contractTypeName) - if(CONTRACT_POWER) - contract = new /obj/item/paper/contract/infernal/power(C.loc, C.mind, user.mind) - if(CONTRACT_WEALTH) - contract = new /obj/item/paper/contract/infernal/wealth(C.loc, C.mind, user.mind) - if(CONTRACT_PRESTIGE) - contract = new /obj/item/paper/contract/infernal/prestige(C.loc, C.mind, user.mind) - if(CONTRACT_MAGIC) - contract = new /obj/item/paper/contract/infernal/magic(C.loc, C.mind, user.mind) - if(CONTRACT_KNOWLEDGE) - contract = new /obj/item/paper/contract/infernal/knowledge(C.loc, C.mind, user.mind) - if(CONTRACT_FRIENDSHIP) - contract = new /obj/item/paper/contract/infernal/friendship(C.loc, C.mind, user.mind) - C.put_in_hands(contract) + if(!C.mind || !user.mind) + to_chat(user, span_notice("[C] seems to not be sentient. You are unable to summon a contract for them.")) + continue + + if(C.stat == DEAD) + if(!user.drop_from_active_hand()) + continue + + var/obj/item/paper/contract/infernal/revive/contract = new(user.loc, C.mind, user.mind) + user.put_in_hands(contract) else - to_chat(user,"[C] seems to not be sentient. You are unable to summon a contract for them.") + var/obj/item/paper/contract/infernal/contract + var/contractTypeName = input(user, "What type of contract?") in list (CONTRACT_POWER, CONTRACT_WEALTH, CONTRACT_PRESTIGE, CONTRACT_MAGIC, CONTRACT_KNOWLEDGE, CONTRACT_FRIENDSHIP) // no todo: contracts are deprecated and soon will be deleted + + switch(contractTypeName) + if(CONTRACT_POWER) + contract = new /obj/item/paper/contract/infernal/power(C.loc, C.mind, user.mind) + if(CONTRACT_WEALTH) + contract = new /obj/item/paper/contract/infernal/wealth(C.loc, C.mind, user.mind) + if(CONTRACT_PRESTIGE) + contract = new /obj/item/paper/contract/infernal/prestige(C.loc, C.mind, user.mind) + if(CONTRACT_MAGIC) + contract = new /obj/item/paper/contract/infernal/magic(C.loc, C.mind, user.mind) + if(CONTRACT_KNOWLEDGE) + contract = new /obj/item/paper/contract/infernal/knowledge(C.loc, C.mind, user.mind) + if(CONTRACT_FRIENDSHIP) + contract = new /obj/item/paper/contract/infernal/friendship(C.loc, C.mind, user.mind) + + C.put_in_hands(contract) /obj/effect/proc_holder/spell/fireball/hellish name = "Hellfire" desc = "This spell launches hellfire at the target." + school = "evocation" base_cooldown = 8 SECONDS + clothes_req = FALSE human_req = FALSE + invocation = "Your very soul will catch fire!" invocation_type = "shout" + fireball_type = /obj/item/projectile/magic/fireball/infernal action_background_icon_state = "bg_demon" @@ -99,88 +119,111 @@ /obj/effect/proc_holder/spell/infernal_jaunt name = "Infernal Jaunt" desc = "Use hellfire to phase out of existence." + base_cooldown = 20 SECONDS cooldown_min = 0 + overlay = null + action_icon_state = "jaunt" action_background_icon_state = "bg_demon" + phase_allowed = TRUE + clothes_req = FALSE human_req = FALSE /obj/effect/proc_holder/spell/infernal_jaunt/create_new_targeting() return new /datum/spell_targeting/self +/obj/effect/proc_holder/spell/infernal_jaunt/can_cast(mob/living/user, charge_check, show_message) + . = ..() + if(!.) + return FALSE + + if(!istype(user)) + return FALSE /obj/effect/proc_holder/spell/infernal_jaunt/cast(list/targets, mob/living/user = usr) - if(istype(user)) - if(istype(user.loc, /obj/effect/dummy/slaughter)) - var/continuing = 0 - if(istype(get_area(user), /area/shuttle)) // Can always phase in in a shuttle. - continuing = TRUE - 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) - continuing = TRUE - break - if(continuing) - to_chat(user,"You are now phasing in.") - if(do_after(user, 15 SECONDS, user, NONE)) - user.infernalphasein(src) - else - to_chat(user,"You can only re-appear near a potential signer or on a shuttle.") - revert_cast() - return ..() + if(istype(user.loc, /obj/effect/dummy/slaughter)) + var/continuing = 0 + if(istype(get_area(user), /area/shuttle)) // Can always phase in in a shuttle. + continuing = TRUE else - user.fakefire() - to_chat(user,"You begin to phase back into sinful flames.") + 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) + continuing = TRUE + break + if(continuing) + to_chat(user, span_warning("You are now phasing in.")) if(do_after(user, 15 SECONDS, user, NONE)) - ADD_TRAIT(user, TRAIT_NO_TRANSFORM, UNIQUE_TRAIT_SOURCE(src)) - user.infernalphaseout(src) - else - to_chat(user,"You must remain still while exiting.") - user.ExtinguishMob() - cooldown_handler.start_recharge() - return - revert_cast() + user.infernalphasein(src) + else + to_chat(user, span_warning("You can only re-appear near a potential signer or on a shuttle.")) + revert_cast() + return ..() + else + user.fakefire() + to_chat(user, span_warning("You begin to phase back into sinful flames.")) + if(do_after(user, 15 SECONDS, user, NONE)) + ADD_TRAIT(user, TRAIT_NO_TRANSFORM, UNIQUE_TRAIT_SOURCE(src)) + user.infernalphaseout(src) + else + to_chat(user, span_warning("You must remain still while exiting.")) + user.ExtinguishMob() + + cooldown_handler.start_recharge() + return /mob/living/proc/infernalphaseout(obj/effect/proc_holder/spell/infernal_jaunt/spell) dust_animation() - visible_message("[src] disappears in a flashfire!") + + visible_message(span_warning("[src] disappears in a flashfire!")) playsound(get_turf(src), 'sound/misc/enter_blood.ogg', 100, 1, -1) + var/obj/effect/dummy/slaughter/s_holder = new(loc) + ExtinguishMob() forceMove(s_holder) + holder = s_holder + REMOVE_TRAIT(src, TRAIT_NO_TRANSFORM, UNIQUE_TRAIT_SOURCE(spell)) fakefireextinguish() /mob/living/proc/infernalphasein(obj/effect/proc_holder/spell/infernal_jaunt/spell) if(HAS_TRAIT(src, TRAIT_NO_TRANSFORM)) - to_chat(src,"You're too busy to jaunt in.") + to_chat(src, span_warning("You're too busy to jaunt in.")) return FALSE + fakefire() forceMove(get_turf(src)) - visible_message("[src] appears in a firey blaze!") + + visible_message(span_warning("[src] appears in a firey blaze!")) playsound(get_turf(src), 'sound/misc/exit_blood.ogg', 100, 1, -1) - spawn(1.5 SECONDS) - fakefireextinguish(TRUE) + + addtimer(CALLBACK(src, PROC_REF(fakefireextinguish), TRUE), 1.5 SECONDS) /obj/effect/proc_holder/spell/sintouch name = "Sin Touch" desc = "Subtly encourage someone to sin." + base_cooldown = 180 SECONDS cooldown_min = 0 + clothes_req = FALSE human_req = FALSE overlay = null + action_icon_state = "sintouch" action_background_icon_state = "bg_demon" + invocation = "TASTE SIN AND INDULGE!!" invocation_type = "shout" + var/max_targets = 3 @@ -191,25 +234,29 @@ /obj/effect/proc_holder/spell/sintouch/create_new_targeting() - var/datum/spell_targeting/targeted/T = new() - T.selection_type = SPELL_SELECTION_RANGE - T.random_target = TRUE - T.target_priority = SPELL_TARGET_RANDOM - T.use_turf_of_user = TRUE - T.range = 2 - T.max_targets = 3 - return T + var/datum/spell_targeting/targeted/targeting = new() + + targeting.selection_type = SPELL_SELECTION_RANGE + targeting.random_target = TRUE + targeting.target_priority = SPELL_TARGET_RANDOM + targeting.use_turf_of_user = TRUE + + targeting.range = 2 + targeting.max_targets = 3 + + return targeting /obj/effect/proc_holder/spell/sintouch/sintouch/cast(list/targets, mob/living/user = usr) - for(var/mob/living/carbon/human/H in targets) - if(!H.mind) + for(var/mob/living/carbon/human/human in targets) + if(!human.mind) continue - for(var/datum/objective/sintouched/A in H.mind.objectives) + + if(human.mind.has_antag_datum(/datum/antagonist/sintouched)) continue - H.influenceSin() - H.Weaken(4 SECONDS) + human.mind.add_antag_datum(/datum/antagonist/sintouched) + human.Weaken(4 SECONDS) /obj/effect/proc_holder/spell/summon_dancefloor name = "Summon Dancefloor" @@ -218,15 +265,13 @@ human_req = FALSE school = "conjuration" base_cooldown = 1 SECONDS - cooldown_min = 5 SECONDS //5 seconds, so the smoke can't be spammed + cooldown_min = 5 SECONDS // 5 seconds, so the smoke can't be spammed action_icon_state = "funk" action_background_icon_state = "bg_demon" var/list/dancefloor_turfs var/list/dancefloor_turfs_types var/dancefloor_exists = FALSE -// var/datum/effect_system/smoke_spread/transparent/dancefloor_devil/smoke - /obj/effect/proc_holder/spell/summon_dancefloor/create_new_targeting() return new /datum/spell_targeting/self @@ -236,13 +281,6 @@ LAZYINITLIST(dancefloor_turfs) LAZYINITLIST(dancefloor_turfs_types) -/* - if(!smoke) - smoke = new() - smoke.set_up(0, get_turf(user)) - smoke.start() -*/ - if(dancefloor_exists) dancefloor_exists = FALSE for(var/i in 1 to dancefloor_turfs.len) @@ -252,12 +290,15 @@ var/list/funky_turfs = RANGE_TURFS(1, user) for(var/turf/T in funky_turfs) if(T.density) - to_chat(user, "You're too close to a wall.") + to_chat(user, span_warning("You're too close to a wall.")) return + dancefloor_exists = TRUE var/i = 1 + dancefloor_turfs.len = funky_turfs.len dancefloor_turfs_types.len = funky_turfs.len + for(var/t in funky_turfs) var/turf/T = t dancefloor_turfs[i] = T @@ -265,12 +306,148 @@ T.ChangeTurf((i % 2 == 0) ? /turf/simulated/floor/light/colour_cycle/dancefloor_a : /turf/simulated/floor/light/colour_cycle/dancefloor_b) i++ +/obj/effect/proc_holder/spell/aoe/devil_fire + name = "Devil fire" + desc = "Призывает огненные волны в радиусе заклинания." + action_icon_state = "explosion_old" + + base_cooldown = 60 SECONDS + aoe_range = 10 + + clothes_req = FALSE + human_req = FALSE + + var/fire_prob = 50 + var/slow_time = 5 SECONDS + +/obj/effect/proc_holder/spell/aoe/devil_fire/create_new_targeting() + var/datum/spell_targeting/aoe/targeting = new() + + targeting.range = aoe_range + targeting.allowed_type = /atom + + return targeting + +/obj/effect/proc_holder/spell/aoe/devil_fire/cast(list/targets, mob/user = usr) + for(var/mob/living/living in targets) + living.Slowed(slow_time) + + for(var/turf/turf in targets) + if(turf == get_turf(user)) + continue + + if(!prob(fire_prob)) + continue + + new /obj/effect/hotspot(turf) + turf.hotspot_expose(2000, 50, 1) + + playsound(get_turf(user), 'sound/magic/blind.ogg', 50, TRUE) + +/obj/effect/proc_holder/spell/dark_conversion + name = "Dark conversion" + desc = "Превращает гуманоида в тенечеловека и искажает его восприятие реальности." + + action_icon = 'icons/mob/actions/actions_cult.dmi' + action_icon_state = "horror" + + base_cooldown = 300 SECONDS + var/cast_time = 5 SECONDS + + clothes_req = FALSE + human_req = FALSE + +/obj/effect/proc_holder/spell/dark_conversion/create_new_targeting() + var/datum/spell_targeting/aoe/targeting = new() + + targeting.range = 5 + targeting.allowed_type = /mob/living/carbon/human + + return targeting + +/obj/effect/proc_holder/spell/dark_conversion/create_new_handler() + var/datum/spell_handler/devil/devil = new + return devil + +/obj/effect/proc_holder/spell/dark_conversion/valid_target(mob/living/carbon/human/target, mob/user) + return target.mind && !isshadowperson(target) + +/obj/effect/proc_holder/spell/dark_conversion/cast(list/targets, mob/user = usr) + var/mob/living/carbon/human/human = targets[1] + var/mob/living/carbon/carbon = user + var/datum/antagonist/devil/devil = carbon.mind?.has_antag_datum(/datum/antagonist/devil) + + carbon.say("INF' [devil.info.truename] NO") + playsound(get_turf(carbon), 'sound/magic/narsie_attack.ogg', 100, TRUE) + + human.Knockdown(0.1 SECONDS) + + if(!do_after(user, cast_time, user, NONE)) + revert_cast(user) + return + + make_shadow(human) + +/obj/effect/proc_holder/spell/dark_conversion/proc/make_shadow(mob/living/carbon/human/human) + human.set_species(/datum/species/shadow) + human.store_memory("Вы - создание тьмы. Старайтесь сохранить свою истинную форму и выполнить свои задания.", TRUE) + + var/datum/objective/assassinate/kill = new + kill.owner = human.mind + kill.find_target() + + LAZYADD(human.mind.objectives, kill) + LAZYADD(human.faction, "hell") + + human.mind.prepare_announce_objectives() + playsound(human, 'sound/magic/mutate.ogg', 100, TRUE) + +/obj/effect/proc_holder/spell/sacrifice_circle + name = "Create sacrifice circle" + desc = "Создает руну для жертвоприношений." + + action_icon = 'icons/mob/actions/actions_cult.dmi' + action_icon_state = "sintouch" + + base_cooldown = 900 SECONDS + var/cast_time = 5 SECONDS + + clothes_req = FALSE + human_req = FALSE + +/obj/effect/proc_holder/spell/sacrifice_circle/create_new_targeting() + return new /datum/spell_targeting/self + +/obj/effect/proc_holder/spell/sacrifice_circle/create_new_handler() + var/datum/spell_handler/devil/devil = new + return devil + +/obj/effect/proc_holder/spell/sacrifice_circle/cast(list/targets, mob/user = usr) + playsound(get_turf(user), 'sound/magic/cult_spell.ogg', 100, TRUE) + + if(!do_after(user, cast_time, user, NONE)) + revert_cast(user) + return + + create_rune(user) + +/obj/effect/proc_holder/spell/sacrifice_circle/proc/create_rune(mob/user) + var/mob/living/carbon/carbon = user + var/datum/antagonist/devil/devil = carbon.mind?.has_antag_datum(/datum/antagonist/devil) + + if(!devil) + return + + var/obj/effect/decal/cleanable/devil/devil_rune = new(get_turf(carbon)) + playsound(get_turf(carbon), 'sound/magic/invoke_general.ogg', 100, TRUE) -/* -/datum/effect_system/smoke_spread/transparent/dancefloor_devil - effect_type = /obj/effect/particle_effect/smoke/transparent/dancefloor_devil + devil_rune.AddComponent( \ + /datum/component/ritual_object, \ + allowed_categories = /datum/ritual/devil, \ + allowed_special_role = list(ROLE_DEVIL), \ + ) + devil_rune.devil = devil + devil_rune.update_appearance(UPDATE_DESC) -/obj/effect/particle_effect/smoke/transparent/dancefloor_devil - lifetime = 2 -*/ + return diff --git a/code/game/gamemodes/devil/devil.dm b/code/game/gamemodes/devil/devil.dm deleted file mode 100644 index d6927753ed9..00000000000 --- a/code/game/gamemodes/devil/devil.dm +++ /dev/null @@ -1,48 +0,0 @@ -GLOBAL_LIST_INIT(whiteness, list( - /obj/item/clothing/under/color/white = 2, - /obj/item/clothing/under/rank/bartender = 1, - /obj/item/clothing/under/rank/chef = 1, - /obj/item/clothing/under/rank/chief_engineer = 1, - /obj/item/clothing/under/rank/scientist = 1, - /obj/item/clothing/under/rank/chemist = 1, - /obj/item/clothing/under/rank/chief_medical_officer = 1, - /obj/item/clothing/under/rank/geneticist = 1, - /obj/item/clothing/under/rank/virologist = 1, - /obj/item/clothing/under/rank/nursesuit = 1, - /obj/item/clothing/under/rank/medical = 1, - /obj/item/clothing/under/rank/psych = 1, - /obj/item/clothing/under/rank/orderly = 1, - /obj/item/clothing/under/rank/security/brigphys = 1, - /obj/item/clothing/under/rank/internalaffairs = 1, - /obj/item/clothing/under/rank/ntrep = 1, - /obj/item/clothing/under/det = 1, - /obj/item/clothing/under/wedding/bride_white = 1, - /obj/item/clothing/under/mafia/white = 1, - /obj/item/clothing/under/noble_clothes = 1, - /obj/item/clothing/under/sl_suit = 1, - /obj/item/clothing/under/burial = 1 -)) - - - -/mob/living/proc/check_devil_bane_multiplier(obj/item/weapon, mob/living/attacker) - switch(mind.devilinfo.bane) - if(BANE_WHITECLOTHES) - if(ishuman(attacker)) - var/mob/living/carbon/human/H = attacker - if(H.w_uniform && istype(H.w_uniform, /obj/item/clothing/under)) - var/obj/item/clothing/under/U = H.w_uniform - if(GLOB.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 GLOB.whiteness[U.type] + 1 - if(BANE_TOOLBOX) - if(istype(weapon,/obj/item/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. - if(BANE_HARVEST) - if(istype(weapon,/obj/item/reagent_containers/food/snacks/grown/) || istype(weapon,/obj/item/grown)) - src.visible_message("The spirits of the harvest aid in the exorcism.", "The harvest spirits are harming you.") - src.Weaken(4 SECONDS) - qdel(weapon) - return 2 - return 1 diff --git a/code/game/gamemodes/devil/devil_agent/devil_agent.dm b/code/game/gamemodes/devil/devil_agent/devil_agent.dm deleted file mode 100644 index e9a1d998a7a..00000000000 --- a/code/game/gamemodes/devil/devil_agent/devil_agent.dm +++ /dev/null @@ -1,38 +0,0 @@ -/datum/game_mode/devil/devil_agents - name = "Devil Agents" - config_tag = "devilagents" - required_players = 25 - required_enemies = 3 - recommended_enemies = 8 - - traitors_possible = 10 //hard limit on traitors if scaling is turned off - num_modifier = 4 - objective_count = 2 - - var/list/target_list = list() - var/list/late_joining_list = list() - minimum_devils = 3 - -/datum/game_mode/devil/devil_agents/post_setup() - var/i = 0 - for(var/datum/mind/devil in devils) - i++ - if(i + 1 > devils.len) - i = 0 - target_list[devil] = devils[i + 1] - ..() - -/datum/game_mode/devil/devil_agents/forge_devil_objectives(datum/mind/devil_mind, quantity) - ..(devil_mind, quantity - give_outsell_objective(devil_mind)) - -/datum/game_mode/devil/devil_agents/proc/give_outsell_objective(datum/mind/devil) - //If you override this method, have it return the number of objectives added. - if(target_list.len && target_list[devil]) // Is a double agent - var/datum/mind/target_mind = target_list[devil] - var/datum/objective/devil/outsell/outsellobjective = new - outsellobjective.owner = devil - outsellobjective.target = target_mind - outsellobjective.update_explanation_text() - devil.objectives += outsellobjective - return 1 - return 0 diff --git a/code/game/gamemodes/devil/devil_game_mode.dm b/code/game/gamemodes/devil/devil_game_mode.dm deleted file mode 100644 index 563bac3e3e0..00000000000 --- a/code/game/gamemodes/devil/devil_game_mode.dm +++ /dev/null @@ -1,66 +0,0 @@ -/datum/game_mode/devil - name = "devil" - config_tag = "devil" - protected_jobs = list(JOB_TITLE_OFFICER, JOB_TITLE_WARDEN, JOB_TITLE_DETECTIVE, JOB_TITLE_REPRESENTATIVE, JOB_TITLE_PILOT, JOB_TITLE_JUDGE, - JOB_TITLE_LAWYER, JOB_TITLE_LIBRARIAN, JOB_TITLE_CHAPLAIN, JOB_TITLE_HOS, JOB_TITLE_CAPTAIN, JOB_TITLE_BRIGDOC, - JOB_TITLE_CCOFFICER, JOB_TITLE_CCSPECOPS, JOB_TITLE_AI, JOB_TITLE_CYBORG, JOB_TITLE_CCFIELD, JOB_TITLE_CCSUPREME) - required_players = 2 - required_enemies = 1 - recommended_enemies = 4 - - var/traitors_possible = 4 //hard limit on devils if scaling is turned off - var/num_modifier = 0 // Used for gamemodes, that are a child of traitor, that need more than the usual. - var/objective_count = 2 - var/minimum_devils = 1 -// var/devil_scale_coefficient = 10 - -/datum/game_mode/devil/announce() - to_chat(world, {"The current game mode is - Devil!
) - Devils: Purchase souls and tempt the crew to sin!
- Crew: Resist the lure of sin and remain pure!"}) - -/datum/game_mode/devil/pre_setup() - - if(CONFIG_GET(flag/protect_roles_from_antagonist)) - restricted_jobs += protected_jobs - - var/list/possible_devils = get_players_for_role(ROLE_DEVIL) - var/num_devils = 0 - if(!possible_devils.len) - return 0 - if(CONFIG_GET(number/traitor_scaling)) - num_devils = max(1, round((num_players())/(CONFIG_GET(number/traitor_scaling)))+1) - else - num_devils = max(1, min(num_players(), traitors_possible)) - add_game_logs("Number of devils chosen: [num_devils]") - - for(var/j = 0, j < num_devils, j++) - if (!possible_devils.len) - break - var/datum/mind/devil = pick(possible_devils) - devils += devil - devil.special_role = ROLE_DEVIL - devil.restricted_roles = restricted_jobs - - add_game_logs("[devil.key] has been selected as a [config_tag]", devil) - possible_devils.Remove(devil) - - if(devils.len < required_enemies) - return 0 - return 1 - - -/datum/game_mode/devil/post_setup() - for(var/datum/mind/devil in devils) - spawn(rand(10, 100)) - finalize_devil(devil, TRUE) - spawn(100) - forge_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.devilinfo.announce_laws(devil.current) - var/obj_count = 1 - to_chat(devil.current, " Your current objectives:") - for(var/datum/objective/objective in devil.objectives) - to_chat(devil.current, "Objective #[obj_count]: [objective.explanation_text]") - obj_count++ - ..() - return 1 diff --git a/code/game/gamemodes/devil/devilinfo.dm b/code/game/gamemodes/devil/devilinfo.dm deleted file mode 100644 index 5c00d4b57a9..00000000000 --- a/code/game/gamemodes/devil/devilinfo.dm +++ /dev/null @@ -1,560 +0,0 @@ -#define BLOOD_THRESHOLD 3 //How many souls are needed per stage. -#define TRUE_THRESHOLD 7 -#define ARCH_THRESHOLD 12 - -#define BASIC_DEVIL 0 -#define BLOOD_LIZARD 1 -#define TRUE_DEVIL 2 -#define ARCH_DEVIL 3 - -#define LOSS_PER_DEATH 2 - -#define SOULVALUE (soulsOwned.len-reviveNumber) - -#define DEVILRESURRECTTIME 600 - -GLOBAL_LIST_EMPTY(allDevils) -GLOBAL_LIST_INIT(lawlorify, list ( - LORE = list( - OBLIGATION_FOOD = "This devil seems to always offer it's victims food before slaughtering them.", - OBLIGATION_FIDDLE = "This devil will never turn down a musical challenge.", - OBLIGATION_DANCEOFF = "This devil will never turn down a dance off.", - OBLIGATION_GREET = "This devil seems to only be able to converse with people it knows the name of.", - OBLIGATION_PRESENCEKNOWN = "This devil seems to be unable to attack from stealth.", - OBLIGATION_SAYNAME = "He will always chant his name upon killing someone.", - OBLIGATION_ANNOUNCEKILL = "This devil always loudly announces his kills for the world to hear.", - OBLIGATION_ANSWERTONAME = "This devil always responds to his truename.", - BANE_SILVER = "Silver seems to gravely injure this devil.", - BANE_SALT = "Throwing salt at this devil will hinder his ability to use infernal powers temporarily.", - BANE_LIGHT = "Bright flashes will disorient the devil, likely causing him to flee.", - BANE_IRON = "Cold iron will slowly injure him, until he can purge it from his system.", - BANE_WHITECLOTHES = "Wearing clean white clothing will help ward off this devil.", - BANE_HARVEST = "Presenting the labors of a harvest will disrupt the devil.", - BANE_TOOLBOX = "That which holds the means of creation also holds the means of the devil's undoing.", - BAN_HURTWOMAN = "This devil seems to prefer hunting men.", - BAN_CHAPEL = "This devil avoids holy ground.", - BAN_HURTPRIEST = "The anointed clergy appear to be immune to his powers.", - BAN_AVOIDWATER = "The devil seems to have some sort of aversion to water, though it does not appear to harm him.", - BAN_STRIKEUNCONCIOUS = "This devil only shows interest in those who are awake.", - BAN_HURTLIZARD = "This devil will not strike an Unathi first.", - BAN_HURTANIMAL = "This devil avoids hurting animals.", - BANISH_WATER = "To banish the devil, you must infuse it's body with holy water.", - BANISH_COFFIN = "This devil will return to life if it's remains are not placed within a coffin.", - BANISH_FORMALDYHIDE = "To banish the devil, you must inject it's lifeless body with embalming fluid.", - BANISH_RUNES = "This devil will resurrect after death, unless it's remains are within a rune.", - BANISH_CANDLES = "A large number of nearby lit candles will prevent it from resurrecting.", - BANISH_DESTRUCTION = "It's corpse must be utterly destroyed to prevent resurrection.", - BANISH_FUNERAL_GARB = "If clad in funeral garments, this devil will be unable to resurrect. Should the clothes not fit, lay them gently on top of the devil's corpse." - ), - LAW = list( - OBLIGATION_FOOD = "When not acting in self defense, you must always offer your victim food before harming them.", - OBLIGATION_FIDDLE = "When not in immediate danger, if you are challenged to a musical duel, you must accept it. You are not obligated to duel the same person twice.", - OBLIGATION_DANCEOFF = "When not in immediate danger, if you are challenged to a dance off, you must accept it. You are not obligated to face off with the same person twice.", - OBLIGATION_GREET = "You must always greet other people by their last name before talking with them.", - OBLIGATION_PRESENCEKNOWN = "You must always make your presence known before attacking.", - OBLIGATION_SAYNAME = "You must always say your true name after you kill someone.", - OBLIGATION_ANNOUNCEKILL = "Upon killing someone, you must make your deed known to all within earshot, over comms if reasonably possible.", - OBLIGATION_ANSWERTONAME = "If you are not under attack, you must always respond to your true name.", - BAN_HURTWOMAN = "You must never harm a female outside of self defense.", - BAN_CHAPEL = "You must never attempt to enter the chapel.", - BAN_HURTPRIEST = "You must never attack a priest.", - BAN_AVOIDWATER = "You must never willingly touch a wet surface.", - BAN_STRIKEUNCONCIOUS = "You must never strike an unconscious person.", - BAN_HURTLIZARD = "You must never harm an Unathi outside of self defense.", - BAN_HURTANIMAL = "You must never harm a non-sentient creature or robot outside of self defense.", - BANE_SILVER = "Silver, in all of it's forms shall be your downfall.", - BANE_SALT = "Salt will disrupt your magical abilities.", - BANE_LIGHT = "Blinding lights will prevent you from using offensive powers for a time.", - BANE_IRON = "Cold wrought iron shall act as poison to you.", - BANE_WHITECLOTHES = "Those clad in pristine white garments will strike you true.", - BANE_HARVEST = "The fruits of the harvest shall be your downfall.", - BANE_TOOLBOX = "Toolboxes are bad news for you, for some reason.", - BANISH_WATER = "If your corpse is filled with holy water, you will be unable to resurrect.", - BANISH_COFFIN = "If your corpse is in a coffin, you will be unable to resurrect.", - BANISH_FORMALDYHIDE = "If your corpse is embalmed, you will be unable to resurrect.", - BANISH_RUNES = "If your corpse is placed within a rune, you will be unable to resurrect.", - BANISH_CANDLES = "If your corpse is near lit candles, you will be unable to resurrect.", - BANISH_DESTRUCTION = "If your corpse is destroyed, you will be unable to resurrect.", - BANISH_FUNERAL_GARB = "If your corpse is clad in funeral garments, you will be unable to resurrect." - ) - )) - -/datum/devilinfo - var/datum/mind/owner = null - var/obligation - var/ban - var/bane - var/banish - var/truename - var/list/datum/mind/soulsOwned = new - var/datum/dna/humanform = null - var/reviveNumber = 0 - var/form = BASIC_DEVIL - var/exists = 0 - var/static/list/dont_remove_spells = list( - /obj/effect/proc_holder/spell/summon_contract, - /obj/effect/proc_holder/spell/conjure_item/violin, - /obj/effect/proc_holder/spell/summon_dancefloor) - var/ascendable = FALSE - -/datum/devilinfo/New() - ..() - dont_remove_spells = typecacheof(dont_remove_spells) - -/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) - if(GLOB.allDevils[lowertext(name)]) - return GLOB.allDevils[lowertext(name)] - else - var/datum/devilinfo/devil = randomDevilInfo(name) - GLOB.allDevils[lowertext(name)] = devil - devil.exists = saveDetails - return devil - - - -/proc/randomDevilName() - var/preTitle = "" - var/title = "" - var/mainName = "" - var/suffix = "" - if(prob(65)) - if(prob(35)) - preTitle = pick("Dark ", "Hellish ", "Fiery ", "Sinful ", "Blood ") - title = pick("Lord ", "Fallen Prelate ", "Count ", "Viscount ", "Vizier ", "Elder ", "Adept ") - var/probability = 100 - mainName = pick("Hal", "Ve", "Odr", "Neit", "Ci", "Quon", "Mya", "Folth", "Wren", "Gyer", "Geyr", "Hil", "Niet", "Twou", "Hu", "Don") - while(prob(probability)) - mainName += pick("hal", "ve", "odr", "neit", "ca", "quon", "mya", "folth", "wren", "gyer", "geyr", "hil", "niet", "twoe", "phi", "coa") - probability -= 20 - if(prob(40)) - suffix = pick(" the Red", " the Soulless", " the Master", ", the Lord of all things", ", Jr.") - return preTitle + title + mainName + suffix - -/proc/randomdevilobligation() - return pick(OBLIGATION_FOOD, OBLIGATION_FIDDLE, OBLIGATION_DANCEOFF, OBLIGATION_GREET, OBLIGATION_PRESENCEKNOWN, OBLIGATION_SAYNAME, OBLIGATION_ANNOUNCEKILL, OBLIGATION_ANSWERTONAME) - -/proc/randomdevilban() - return pick(BAN_HURTWOMAN, BAN_CHAPEL, BAN_HURTPRIEST, BAN_AVOIDWATER, BAN_STRIKEUNCONCIOUS, BAN_HURTLIZARD, BAN_HURTANIMAL) - -/proc/randomdevilbane() - return pick(BANE_SALT, BANE_LIGHT, BANE_IRON, BANE_WHITECLOTHES, BANE_SILVER, BANE_HARVEST, BANE_TOOLBOX) - -/proc/randomdevilbanish() - return pick(BANISH_WATER, BANISH_COFFIN, BANISH_FORMALDYHIDE, BANISH_RUNES, BANISH_CANDLES, BANISH_DESTRUCTION, BANISH_FUNERAL_GARB) - -/datum/devilinfo/proc/link_with_mob(mob/living/L) - if(ishuman(L)) - var/mob/living/carbon/human/H = L - humanform = H.dna.Clone() - owner = L.mind - give_base_spells(1) - -/datum/devilinfo/proc/add_soul(datum/mind/soul) - if(soulsOwned.Find(soul)) - return - soulsOwned += soul - owner.current.set_nutrition(NUTRITION_LEVEL_FULL) - to_chat(owner.current, "You feel satiated as you received a new soul.") - update_hud() - switch(SOULVALUE) - if(0) - to_chat(owner.current, "Your hellish powers have been restored.") - give_base_spells() - if(BLOOD_THRESHOLD) - 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) - increase_blood_lizard() - if(TRUE_THRESHOLD) - 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) - increase_true_devil() - if(ARCH_THRESHOLD) - arch_devil_prelude() - increase_arch_devil() - -/datum/devilinfo/proc/remove_soul(datum/mind/soul) - if(soulsOwned.Remove(soul)) - to_chat(owner.current, "You feel as though a soul has slipped from your grasp.") - check_regression() - update_hud() - -/datum/devilinfo/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. - if(form == TRUE_DEVIL && SOULVALUE < TRUE_THRESHOLD) - regress_blood_lizard() - if(form == BLOOD_LIZARD && SOULVALUE < BLOOD_THRESHOLD) - regress_humanoid() - if(SOULVALUE < 0) - 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() - 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 - if(humanform) - H.set_species(humanform.species) - H.dna = humanform.Clone() - H.sync_organ_dna(assimilate = 0) - else - H.set_species(/datum/species/human) - // TODO: Add some appearance randomization here or something - humanform = H.dna.Clone() - H.regenerate_icons() - else - owner.current.color = "" - give_base_spells() - if(istype(owner.current.loc, /obj/effect/dummy/slaughter)) - owner.current.forceMove(get_turf(owner.current))//Fixes dying while jaunted leaving you permajaunted. - form = BASIC_DEVIL - -/datum/devilinfo/proc/regress_blood_lizard() - var/mob/living/carbon/true_devil/devil = owner.current - to_chat(devil, span_warning("Your powers weaken, have more contracts be signed to regain power.")) - devil.oldform.loc = devil.loc - owner.transfer_to(devil.oldform) - REMOVE_TRAIT(devil.oldform, TRAIT_GODMODE, UNIQUE_TRAIT_SOURCE(src)) - give_lizard_spells() - qdel(devil) - form = BLOOD_LIZARD - update_hud() - - -/datum/devilinfo/proc/increase_blood_lizard() - if(ishuman(owner.current)) - var/mob/living/carbon/human/H = owner.current - var/list/language_temp = LAZYLEN(H.languages) ? H.languages.Copy() : null - H.set_species(/datum/species/unathi) - if(language_temp) - H.languages = language_temp - H.underwear = "Nude" - H.undershirt = "Nude" - H.socks = "Nude" - H.change_skin_color(80, 16, 16) //A deep red - H.regenerate_icons() - else //Did the devil get hit by a staff of transmutation? - owner.current.color = "#501010" - give_lizard_spells() - form = BLOOD_LIZARD - - - -/datum/devilinfo/proc/increase_true_devil() - var/mob/living/carbon/true_devil/ascended = new /mob/living/carbon/true_devil(owner.current.loc, owner.current) - ascended.faction |= "hell" - // Put the old body in stasis - ADD_TRAIT(owner.current, TRAIT_GODMODE, UNIQUE_TRAIT_SOURCE(src)) - owner.current.loc = ascended - ascended.oldform = owner.current - owner.transfer_to(ascended) - ascended.set_name() - give_true_spells() - form = TRUE_DEVIL - update_hud() - -/datum/devilinfo/proc/arch_devil_prelude() - if(!ascendable) - return - var/mob/living/carbon/true_devil/D = owner.current - to_chat(D, "You feel as though your form is about to ascend.") - sleep(50) - if(!D) - return - D.visible_message("[D]'s skin begins to erupt with spikes.", \ - "Your flesh begins creating a shield around yourself.") - sleep(100) - if(!D) - return - D.visible_message("The horns on [D]'s head slowly grow and elongate.", \ - "Your body continues to mutate. Your telepathic abilities grow.") - sleep(90) - if(!D) - return - D.visible_message("[D]'s body begins to violently stretch and contort.", \ - "You begin to rend apart the final barriers to ultimate power.") - sleep(40) - if(!D) - return - to_chat(D, "Yes!") - sleep(10) - if(!D) - return - to_chat(D, "YES!!") - sleep(10) - if(!D) - return - to_chat(D, "YE--") - sleep(1) - if(!D) - return - to_chat(world, "SLOTH, WRATH, GLUTTONY, ACEDIA, ENVY, GREED, PRIDE! FIRES OF HELL AWAKEN!!") - world << 'sound/hallucinations/veryfar_noise.ogg' - sleep(50) - if(!SSticker.mode.devil_ascended) - SSshuttle.emergency.request(null, 0.3) - SSticker.mode.devil_ascended++ - -/datum/devilinfo/proc/increase_arch_devil() - if(!ascendable) - return - var/mob/living/carbon/true_devil/D = owner.current - if(!istype(D)) - return - give_arch_spells() - D.convert_to_archdevil() - if(istype(D.loc, /obj/effect/dummy/slaughter)) - D.forceMove(get_turf(D)) - var/area/A = get_area(owner.current) - if(A) - notify_ghosts("An arch devil has ascended in [A.name]. Reach out to the devil to start climbing the infernal corporate ladder.", title = "Arch Devil Ascended", source = owner.current, action = NOTIFY_ATTACK) - form = ARCH_DEVIL - -/datum/devilinfo/proc/remove_spells() - for(var/obj/effect/proc_holder/spell/spell as anything in owner.spell_list) - if(!is_type_in_typecache(spell, dont_remove_spells)) - owner.RemoveSpell(spell) - -/datum/devilinfo/proc/give_summon_contract() - owner.AddSpell(new /obj/effect/proc_holder/spell/summon_contract(null)) - - -/datum/devilinfo/proc/give_base_spells(give_summon_contract = 0) - remove_spells() - owner.AddSpell(new /obj/effect/proc_holder/spell/fireball/hellish(null)) - owner.AddSpell(new /obj/effect/proc_holder/spell/conjure_item/pitchfork(null)) - if(give_summon_contract) - give_summon_contract() - if(obligation == OBLIGATION_FIDDLE) - owner.AddSpell(new /obj/effect/proc_holder/spell/conjure_item/violin(null)) - if(obligation == OBLIGATION_DANCEOFF) - owner.AddSpell(new /obj/effect/proc_holder/spell/summon_dancefloor(null)) - -/datum/devilinfo/proc/give_lizard_spells() - remove_spells() - owner.AddSpell(new /obj/effect/proc_holder/spell/conjure_item/pitchfork(null)) - owner.AddSpell(new /obj/effect/proc_holder/spell/fireball/hellish(null)) - owner.AddSpell(new /obj/effect/proc_holder/spell/infernal_jaunt(null)) - -/datum/devilinfo/proc/give_true_spells() - remove_spells() - owner.AddSpell(new /obj/effect/proc_holder/spell/conjure_item/pitchfork/greater(null)) - owner.AddSpell(new /obj/effect/proc_holder/spell/fireball/hellish(null)) - owner.AddSpell(new /obj/effect/proc_holder/spell/infernal_jaunt(null)) - owner.AddSpell(new /obj/effect/proc_holder/spell/sintouch(null)) - -/datum/devilinfo/proc/give_arch_spells() - remove_spells() - owner.AddSpell(new /obj/effect/proc_holder/spell/conjure_item/pitchfork/ascended(null)) - owner.AddSpell(new /obj/effect/proc_holder/spell/sintouch/ascended(null)) - -/datum/devilinfo/proc/beginResurrectionCheck(mob/living/body) - if(owner.current != body) - body = owner.current - 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.") - addtimer(CALLBACK(src, "activateResurrection", body), DEVILRESURRECTTIME) - else - to_chat(owner.messageable_mob(), "Your hellish powers are too weak to resurrect yourself.") - -/datum/devilinfo/proc/activateResurrection(mob/living/body) - if(QDELETED(body) || body.stat == DEAD) - if(SOULVALUE > 0) - if(check_banishment(body)) - to_chat(owner.messageable_mob(), "Unfortunately, the mortals have finished a ritual that prevents your resurrection.") - return -1 - else - to_chat(owner.messageable_mob(), "WE LIVE AGAIN!") - return hellish_resurrection(body) - else - to_chat(owner.messageable_mob(), "Unfortunately, the power that stemmed from your contracts has been extinguished. You no longer have enough power to resurrect.") - return -1 - else - to_chat(owner.current, "You seem to have resurrected without your hellish powers.") - -/datum/devilinfo/proc/check_banishment(mob/living/body) - switch(banish) - if(BANISH_WATER) - if(!QDELETED(body) && iscarbon(body)) - var/mob/living/carbon/H = body - return H.reagents.has_reagent("holy water") - return 0 - if(BANISH_COFFIN) - return (!QDELETED(body) && istype(body.loc, /obj/structure/closet/coffin)) - if(BANISH_FORMALDYHIDE) - if(!QDELETED(body) && iscarbon(body)) - var/mob/living/carbon/H = body - return H.reagents.has_reagent("formaldehyde") - return 0 - if(BANISH_RUNES) - if(!QDELETED(body)) - for(var/obj/effect/decal/cleanable/crayon/R in range(0,body)) - if (R.name == "rune") - return 1 - return 0 - if(BANISH_CANDLES) - if(!QDELETED(body)) - var/count = 0 - for(var/obj/item/candle/C in range(1,body)) - count += C.lit - if(count>=4) - return 1 - return 0 - if(BANISH_DESTRUCTION) - if(!QDELETED(body)) - return 0 - return 1 - if(BANISH_FUNERAL_GARB) - if(!QDELETED(body) && iscarbon(body)) - var/mob/living/carbon/human/H = body - if(H.w_uniform && istype(H.w_uniform, /obj/item/clothing/under/burial)) - return 1 - return 0 - else - for(var/obj/item/clothing/under/burial/B in range(0,body)) - if(B.loc == get_turf(B)) //Make sure it's not in someone's inventory or something. - return 1 - return 0 - -/datum/devilinfo/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 - update_hud() - if(!QDELETED(body)) - body.revive() - if(!body.client) - var/mob/dead/observer/O = owner.get_ghost() - O.reenter_corpse() - if(istype(body.loc, /obj/effect/dummy/slaughter)) - body.forceMove(get_turf(body))//Fixes dying while jaunted leaving you permajaunted. - if(istype(body, /mob/living/carbon/true_devil)) - var/mob/living/carbon/true_devil/D = body - if(D.oldform) - D.oldform.revive() // Heal the old body too, so the devil doesn't resurrect, then immediately regress into a dead body. - if(body.stat == DEAD) // Not sure why this would happen - create_new_body() - else if(GLOB.blobstart.len > 0) - // teleport the body so repeated beatdowns aren't an option) - body.forceMove(get_turf(pick(GLOB.blobstart))) - // give them the devil lawyer outfit in case they got stripped - if(ishuman(body)) - var/mob/living/carbon/human/H = body - H.equipOutfit(/datum/outfit/devil_lawyer) - else - create_new_body() - check_regression() - -/datum/devilinfo/proc/create_new_body() - if(GLOB.blobstart.len > 0) - var/turf/targetturf = get_turf(pick(GLOB.blobstart)) - var/mob/currentMob = owner.current - if(QDELETED(currentMob)) - currentMob = owner.get_ghost() - if(!currentMob) - message_admins("[owner.name]'s devil resurrection failed due to client logoff. Aborting.") - return -1 - if(currentMob.mind != owner) - message_admins("[owner.name]'s devil resurrection failed due to becoming a new mob. Aborting.") - return -1 - var/mob/living/carbon/human/H = new /mob/living/carbon/human(targetturf) - owner.transfer_to(H) - if(isobserver(currentMob)) - var/mob/dead/observer/O = currentMob - O.reenter_corpse() - if(humanform) - H.set_species(humanform.species) - H.dna = humanform.Clone() - - H.dna.UpdateSE() - H.dna.UpdateUI() - - H.sync_organ_dna(1) // It's literally a fresh body as you can get, so all organs properly belong to it - H.UpdateAppearance() - else - // gibbed cyborg or similar - create a randomized "humanform" appearance - H.scramble_appearance() - humanform = H.dna.Clone() - - - H.equipOutfit(/datum/outfit/devil_lawyer) - give_base_spells(TRUE) - if(SOULVALUE >= BLOOD_THRESHOLD) - increase_blood_lizard() - if(SOULVALUE >= TRUE_THRESHOLD) //Yes, BOTH this and the above if statement are to run if soulpower is high enough. - increase_true_devil() - if(SOULVALUE >= ARCH_THRESHOLD && ascendable) - increase_arch_devil() - else - throw EXCEPTION("Unable to find a blobstart landmark for hellish resurrection") - -/datum/devilinfo/proc/update_hud() - if(iscarbon(owner.current)) - var/mob/living/C = owner.current - if(C.hud_used && C.hud_used.devilsouldisplay) - C.hud_used.devilsouldisplay.update_counter(SOULVALUE) - -// SECTION: Messages and explanations - -/datum/devilinfo/proc/announce_laws() - var/list/messages = list() - messages.Add("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.") - messages.Add("However, your infernal form is not without weaknesses.") - messages.Add("You may not use violence to coerce someone into selling their soul.") - messages.Add("You may not directly and knowingly physically harm a devil, other than yourself.") - messages.Add(GLOB.lawlorify[LAW][bane]) - messages.Add(GLOB.lawlorify[LAW][ban]) - messages.Add(GLOB.lawlorify[LAW][obligation]) - messages.Add(GLOB.lawlorify[LAW][banish]) - messages.Add("

Remember, the crew can research your weaknesses if they find out your devil name.
") - return messages - -#undef BLOOD_THRESHOLD -#undef TRUE_THRESHOLD -#undef ARCH_THRESHOLD -#undef BASIC_DEVIL -#undef BLOOD_LIZARD -#undef TRUE_DEVIL -#undef ARCH_DEVIL -#undef LOSS_PER_DEATH -#undef SOULVALUE -#undef DEVILRESURRECTTIME - -/datum/outfit/devil_lawyer - name = "Devil Lawyer" - uniform = /obj/item/clothing/under/lawyer/black - shoes = /obj/item/clothing/shoes/laceup - back = /obj/item/storage/backpack - l_hand = /obj/item/storage/briefcase - l_pocket = /obj/item/pen - l_ear = /obj/item/radio/headset - - id = /obj/item/card/id - -/datum/outfit/devil_lawyer/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) - var/obj/item/card/id/W = H.wear_id - if(!istype(W) || W.assignment) // either doesn't have a card, or the card is already written to - return - var/name_to_use = H.real_name - if(H.mind && H.mind.devilinfo) - // Having hell create an ID for you causes its risks - name_to_use = H.mind.devilinfo.truename - - W.name = "[name_to_use]'s ID Card (Lawyer)" - W.registered_name = name_to_use - W.assignment = "Lawyer" - W.rank = W.assignment - W.age = H.age - W.sex = capitalize(H.gender) - W.access = list(ACCESS_MAINT_TUNNELS, ACCESS_SYNDICATE, ACCESS_EXTERNAL_AIRLOCKS) - W.photo = get_id_photo(H) diff --git a/code/game/gamemodes/devil/game_mode.dm b/code/game/gamemodes/devil/game_mode.dm index a6c785fbd56..fc38bd056c9 100644 --- a/code/game/gamemodes/devil/game_mode.dm +++ b/code/game/gamemodes/devil/game_mode.dm @@ -1,106 +1,3 @@ /datum/game_mode var/list/datum/mind/sintouched = list() var/list/datum/mind/devils = list() - var/devil_ascended = 0 // Number of arch devils on station - -/datum/game_mode/proc/auto_declare_completion_sintouched() - var/text = "" - if(!length(sintouched)) - return - - text += "
The sintouched were:" - var/list/sintouchedUnique = uniqueList(sintouched) - for(var/S in sintouchedUnique) - var/datum/mind/sintouched_mind = S - text += printplayer(sintouched_mind) - text += printobjectives(sintouched_mind) - text += "
" - - text += "
" - - to_chat(world,text) - -/datum/game_mode/proc/auto_declare_completion_devils() - var/text = "" - if(!length(devils)) - return - - text += "
The devils were:" - for(var/D in devils) - var/datum/mind/devil = D - text += printplayer(devil) - text += printdevilinfo(devil) - text += printobjectives(devil) - text += "
" - - text += "
" - - to_chat(world,text) - - -/datum/game_mode/proc/finalize_devil(datum/mind/devil_mind, ascendable = FALSE) - var/trueName= randomDevilName() - devil_mind.devilinfo = devilInfo(trueName, 1) - devil_mind.devilinfo.ascendable = ascendable - devil_mind.store_memory("Your diabolical 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.link_with_mob(devil_mind.current) - if(devil_mind.assigned_role == JOB_TITLE_CLOWN) - to_chat(devil_mind.current, "Your infernal nature allows you to wield weapons without harming yourself.") - devil_mind.current.force_gene_block(GLOB.clumsyblock, FALSE) - // Don't give them another action if they already have one. - if(!(locate(/datum/action/innate/toggle_clumsy) in devil_mind.current.actions)) - var/datum/action/innate/toggle_clumsy/toggle_clumsy = new - toggle_clumsy.Grant(devil_mind.current) - - spawn(10) - devil_mind.devilinfo.update_hud() - if(issilicon(devil_mind.current)) - var/mob/living/silicon/S = devil_mind.current - S.laws.set_sixsixsix_law("You may not use violence to coerce someone into selling their soul.") - S.laws.set_sixsixsix_law("You may not directly and knowingly physically harm a devil, other than yourself.") - S.laws.set_sixsixsix_law("[GLOB.lawlorify[LAW][devil_mind.devilinfo.ban]]") - S.laws.set_sixsixsix_law("[GLOB.lawlorify[LAW][devil_mind.devilinfo.obligation]]") - S.laws.set_sixsixsix_law("Accomplish your objectives at all costs.") - -// unsure about the second "quantity" arg and how it fits with the antag refactor -/datum/game_mode/proc/forge_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) - var/type = pick(validtypes) - var/datum/objective/devil/objective = new type(null) - objective.owner = devil_mind - devil_mind.objectives += objective - if(!istype(objective, /datum/objective/devil/buy_target)) - validtypes -= type //prevent duplicate objectives, EXCEPT for buy_target. - else - objective.find_target() - -/datum/game_mode/proc/greet_devil(datum/mind/devil_mind) - if(!devil_mind.devilinfo) - return - var/list/messages = list() - messages.Add(devil_mind.devilinfo.announce_laws()) - messages.Add(devil_mind.prepare_announce_objectives()) - to_chat(devil_mind.current, chat_box_red(messages.Join("
"))) - - -/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]
" - 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]]

" - return text - -/datum/game_mode/proc/update_devil_icons_added(datum/mind/devil_mind) - var/datum/atom_hud/antag/hud = GLOB.huds[ANTAG_HUD_DEVIL] - hud.join_hud(devil_mind.current) - set_antag_hud(devil_mind.current, "huddevil") - -/datum/game_mode/proc/update_devil_icons_removed(datum/mind/devil_mind) - var/datum/atom_hud/antag/hud = GLOB.huds[ANTAG_HUD_DEVIL] - hud.leave_hud(devil_mind.current) - set_antag_hud(devil_mind.current, null) diff --git a/code/game/gamemodes/devil/objectives.dm b/code/game/gamemodes/devil/objectives.dm index 835a16c4593..655920bb6de 100644 --- a/code/game/gamemodes/devil/objectives.dm +++ b/code/game/gamemodes/devil/objectives.dm @@ -1,112 +1,87 @@ /datum/objective/devil -/datum/objective/devil/soulquantity +/datum/objective/devil/sacrifice + var/list/target_minds = list() needs_target = FALSE - explanation_text = "You shouldn't see this text. Error:DEVIL1" - target_amount = 4 + check_cryo = FALSE + target_amount = 12 + explanation_text = "" -/datum/objective/devil/soulquantity/New() - target_amount = pick(6, 7, 8) - update_explanation_text() +/datum/objective/devil/sacrifice/proc/forge() + if(!get_targets()) + return FALSE -/datum/objective/devil/proc/update_explanation_text() - //Intentionally empty + for(var/datum/mind/mind in target_minds) + explanation_text += "Принесите в жертву [mind.name], [mind.assigned_role].\n
" -/datum/objective/devil/soulquantity/update_explanation_text() - explanation_text = "Purchase, and retain control over at least [target_amount] souls." + return TRUE -/datum/objective/devil/soulquantity/check_completion() - var/count = 0 - for(var/S in owner.devilinfo.soulsOwned) - var/datum/mind/L = S - if(L.soulOwner == owner) - count++ - return count >= target_amount +/datum/objective/devil/sacrifice/proc/get_targets() + var/list/command_minds = list() + var/list/security_minds = list() + var/list/other_minds = list() + for(var/datum/mind/mind in SSticker.minds) + if(mind == owner) + continue + if(!ishuman(mind.current) \ + || mind.current.stat == DEAD \ + || mind.offstation_role) + continue -/datum/objective/devil/soulquality - needs_target = FALSE - explanation_text = "You shouldn't see this text. Error:DEVIL2" - var/contractType - var/contractName - -/datum/objective/devil/soulquality/New() - contractType = pick(CONTRACT_POWER, CONTRACT_WEALTH, CONTRACT_PRESTIGE, CONTRACT_MAGIC, CONTRACT_REVIVE, CONTRACT_KNOWLEDGE) - target_amount = pick(1, 2) - switch(contractType) - if(CONTRACT_POWER) - contractName = "for power" - if(CONTRACT_WEALTH) - contractName = "for wealth" - if(CONTRACT_PRESTIGE) - contractName = "for prestige" - if(CONTRACT_MAGIC) - contractName = "for magic" - if(CONTRACT_REVIVE) - contractName = "of revival" - if(CONTRACT_KNOWLEDGE) - contractName = "for knowledge" - update_explanation_text() - -/datum/objective/devil/soulquality/update_explanation_text() - explanation_text = "Have mortals sign at least [target_amount] contracts [contractName]." - -/datum/objective/devil/soulquality/check_completion() - var/count = 0 - for(var/S in owner.devilinfo.soulsOwned) - var/datum/mind/L = S - if(L.soulOwner != L && L.damnation_type == contractType) - count++ - return count >= target_amount + if(LAZYIN(GLOB.command_positions, mind.assigned_role)) + LAZYADD(command_minds, mind) + else if(LAZYIN(GLOB.security_positions, mind.assigned_role)) + LAZYADD(security_minds, mind) + else + LAZYADD(other_minds, mind) -/datum/objective/devil/sintouch - needs_target = FALSE - explanation_text = "You shouldn't see this text. Error:DEVIL3" + var/command_target_count = ceil(target_amount / 12) + var/security_target_count = floor(target_amount / 4) + var/other_target_count = target_amount - command_target_count - security_target_count -/datum/objective/devil/sintouch/New() - target_amount = pick(4, 5) - explanation_text = "Ensure at least [target_amount] mortals are sintouched." + if(LAZYLEN(command_minds) < command_target_count || LAZYLEN(security_minds) < security_target_count || LAZYLEN(other_minds) < other_target_count) + return FALSE -/datum/objective/devil/sintouch/check_completion() - return target_amount <= SSticker.mode.sintouched.len + for(var/i in 1 to command_target_count) + LAZYADD(target_minds, pick_n_take(command_minds)) + + for(var/i in 1 to security_target_count) + LAZYADD(target_minds, pick_n_take(security_minds)) + for(var/i in 1 to other_target_count) + LAZYADD(target_minds, pick_n_take(other_minds)) + return TRUE -/datum/objective/devil/buy_target - explanation_text = "You shouldn't see this text. Error:DEVIL4" +/datum/objective/devil/sacrifice/check_completion() + var/list/collected_minds = list() -/datum/objective/devil/buy_target/New() - find_target() - update_explanation_text() + for(var/datum/mind/mind as anything in target_minds) + if(mind.hasSoul) + continue -/datum/objective/devil/buy_target/update_explanation_text() - if(target) - explanation_text = "Purchase and retain the soul of [target.name], the [target.assigned_role]." - else - explanation_text = "Free objective." + LAZYADD(collected_minds, mind) -/datum/objective/devil/buy_target/check_completion() - return target.soulOwner == owner + return LAZYLEN(collected_minds) > target_amount +/datum/objective/devil/sintouch + needs_target = FALSE + explanation_text = "You shouldn't see this text. Error:DEVIL3" + +/datum/objective/devil/sintouch/New() + target_amount = pick(4, 5) + explanation_text = "Ensure at least [target_amount] mortals are sintouched." -/datum/objective/devil/outsell - explanation_text = "You shouldn't see this text. Error:DEVIL5" +/datum/objective/devil/sintouch/check_completion() + return target_amount <= SSticker.mode.sintouched.len -/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]." +/datum/objective/devil/ascend + explanation_text = "Ascend to your true form." + needs_target = FALSE -/datum/objective/devil/outsell/check_completion() - var/selfcount = 0 - for(var/S in owner.devilinfo.soulsOwned) - var/datum/mind/L = S - if(L.soulOwner == owner) - selfcount++ - var/targetcount = 0 - for(var/S in target.devilinfo.soulsOwned) - var/datum/mind/L = S - if(L.soulOwner == target) - targetcount++ - return selfcount > targetcount +/datum/objective/devil/ascend/check_completion() + return isdevil(owner) diff --git a/code/game/gamemodes/devil/true_devil/inventory.dm b/code/game/gamemodes/devil/true_devil/inventory.dm deleted file mode 100644 index a1ab62fb623..00000000000 --- a/code/game/gamemodes/devil/true_devil/inventory.dm +++ /dev/null @@ -1,2 +0,0 @@ -// empty now - diff --git a/code/game/gamemodes/miniantags/sintouched/objectives.dm b/code/game/gamemodes/miniantags/sintouched/objectives.dm index be5ebe4b8cd..5c4288bacd8 100644 --- a/code/game/gamemodes/miniantags/sintouched/objectives.dm +++ b/code/game/gamemodes/miniantags/sintouched/objectives.dm @@ -3,17 +3,6 @@ needs_target = FALSE var/mob/living/carbon/human/user -/* NO ERP OBJECTIVE FOR YOU. -/datum/objective/sintouched/lust - dangerrating = 3 // it's not AS dangerous. - -/datum/objective/sintouched/lust/New() - var/mob/dead/D = pick(dead_mob_list) - if(prob(50) && D) - explanation_text = "You know that [D] has perished.... and you think [D] is kinda cute. Make sure everyone knows how HOT [D]'s lifeless body is." - else - explanation_text = "Go get married, then immediately cheat on your new spouse." */ - /datum/objective/sintouched/proc/on_apply() return diff --git a/code/game/objects/effects/decals/Cleanable/misc.dm b/code/game/objects/effects/decals/Cleanable/misc.dm index a288263f7a4..c8952e664e5 100644 --- a/code/game/objects/effects/decals/Cleanable/misc.dm +++ b/code/game/objects/effects/decals/Cleanable/misc.dm @@ -286,3 +286,21 @@ /obj/effect/decal/cleanable/ashrune/is_cleanable() return FALSE + +/obj/effect/decal/cleanable/devil + name = "Sinister rune" + desc = "Безобразно выглядящая руна, писанная кровью." + + icon = 'icons/effects/crayondecal.dmi' + icon_state = "rune6" + color = "#661b1b" + + anchored = TRUE + mergeable_decal = FALSE + mouse_opacity = MOUSE_OPACITY_ICON + + var/datum/antagonist/devil/devil + +/obj/effect/decal/cleanable/devil/update_desc() + . = ..() + desc = "[initial(desc)][devil ? " На руне видна подпись: [devil.info?.truename]." : null]" diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys.dm index 70577d1b582..12bb19865ed 100644 --- a/code/game/objects/items/toys.dm +++ b/code/game/objects/items/toys.dm @@ -1639,30 +1639,35 @@ icon = 'icons/obj/library.dmi' icon_state = "demonomicon" w_class = WEIGHT_CLASS_SMALL - var/cooldown = FALSE + COOLDOWN_DECLARE(cooldown) /obj/item/toy/codex_gigas/attack_self(mob/user) - if(!cooldown) - user.visible_message( - "[user] presses the button on \the [src].", - "You press the button on \the [src].", - "You hear a soft click.") - var/list/messages = list() - var/datum/devilinfo/devil = randomDevilInfo() - messages += "Some fun facts about: [devil.truename]" - messages += "[GLOB.lawlorify[LORE][devil.bane]]" - messages += "[GLOB.lawlorify[LORE][devil.obligation]]" - messages += "[GLOB.lawlorify[LORE][devil.ban]]" - messages += "[GLOB.lawlorify[LORE][devil.banish]]" - playsound(loc, 'sound/machines/click.ogg', 20, 1) - cooldown = TRUE - for(var/message in messages) - user.loc.visible_message("[bicon(src)] [message]") - sleep(10) - spawn(20) - cooldown = FALSE + if(!COOLDOWN_FINISHED(src, cooldown)) return + user.visible_message( + span_notice("[user] presses the button on \the [src]."), \ + span_notice("You press the button on \the [src]."), \ + span_sinister("You hear a soft click.")) + + var/list/messages = list() + var/datum/devilinfo/devil = new + + LAZYADD(messages, "Some fun facts about: [devil.truename]") + LAZYADD(messages, devil.bane.law) + LAZYADD(messages, devil.ban.law) + LAZYADD(messages, devil.obligation.law) + LAZYADD(messages, devil.banish.law) + + playsound(loc, 'sound/machines/click.ogg', 20, 1) + COOLDOWN_START(src, cooldown, 2 SECONDS) + + for(var/message in messages) + user.loc.visible_message(span_danger("[bicon(src)] [message]")) + sleep(1 SECONDS) + + return + /obj/item/toy/owl name = "owl action figure" desc = "An action figure modeled after 'The Owl', defender of justice." diff --git a/code/game/objects/items/weapons/twohanded.dm b/code/game/objects/items/weapons/twohanded.dm index dd6bf4beb0f..b2be8e3a924 100644 --- a/code/game/objects/items/weapons/twohanded.dm +++ b/code/game/objects/items/weapons/twohanded.dm @@ -861,9 +861,9 @@ . = ..() if(isliving(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 the [src] your arms ignite, reminding you of all your past sins.\"") + if(!U.mind?.has_antag_datum(/datum/antagonist/devil) && (U.mind.soulOwner == U.mind)) //Burn hands unless they are a devil or have sold their soul + U.visible_message(span_warning("As [U] picks [src] up, [U]'s arms briefly catch fire."), \ + span_warning("\"As you pick up the [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(BODY_ZONE_L_ARM, BODY_ZONE_R_ARM)) @@ -876,7 +876,7 @@ if(!ATTACK_CHAIN_SUCCESS_CHECK(.) || !HAS_TRAIT(src, TRAIT_WIELDED)) return . - if(!user.mind || user.mind.devilinfo || (user.mind.soulOwner == user.mind)) + if(user.mind?.has_antag_datum(/datum/antagonist/devil) || (user.mind.soulOwner == user.mind)) return . to_chat(user, span_warning("The [name] burns in your hands!")) diff --git a/code/game/gamemodes/devil/contracts/friend.dm b/code/modules/antagonists/devil/contracts/friend.dm similarity index 100% rename from code/game/gamemodes/devil/contracts/friend.dm rename to code/modules/antagonists/devil/contracts/friend.dm diff --git a/code/modules/antagonists/devil/devil.dm b/code/modules/antagonists/devil/devil.dm new file mode 100644 index 00000000000..1bf5fefadb5 --- /dev/null +++ b/code/modules/antagonists/devil/devil.dm @@ -0,0 +1,205 @@ +/datum/antagonist/devil + name = "Devil" + roundend_category = "devils" + job_rank = ROLE_DEVIL + special_role = ROLE_DEVIL + antag_hud_type = ANTAG_HUD_DEVIL + + var/datum/devilinfo/info = new + var/list/soulsOwned + var/datum/devil_rank/rank + +/datum/antagonist/devil/can_be_owned(datum/mind/new_owner) + . = ..() + if(!.) + return FALSE + + var/datum/mind/tested = new_owner || owner + if(!tested || !iscarbon(tested.current)) + return FALSE + + return TRUE + +/datum/antagonist/devil/Destroy(force) + QDEL_NULL(rank) + QDEL_NULL(info) + LAZYNULL(soulsOwned) + + return ..() + +/datum/antagonist/devil/proc/add_soul(datum/mind/soul) + if((!istype(soul)) || (LAZYIN(soulsOwned, soul))) + return + + LAZYADD(soulsOwned, soul) + to_chat(owner.current, span_warning("Вы поглощаете душу и насыщаетесь ею.")) + + owner.current.set_nutrition(NUTRITION_LEVEL_FULL) + soul.hasSoul = FALSE + + try_update_rank() + update_hud() + +/datum/antagonist/devil/proc/remove_soul(datum/mind/soul) + LAZYREMOVE(soulsOwned, soul) + to_chat(owner.current, span_warning("Вы чувствуете, как часть ваших сил угасает")) + update_hud() + +/datum/antagonist/devil/proc/try_update_rank() + if(!rank.required_souls || !rank.next_rank_type) + return FALSE + + if(LAZYLEN(soulsOwned) < rank.required_souls) + return FALSE + + if(!init_new_rank(rank.next_rank_type, TRUE)) + return FALSE + + return TRUE // rank updated. + +/datum/antagonist/devil/proc/init_new_rank(typepath, remove_spells = FALSE) + if(rank && remove_spells) + rank.remove_spells() + + if(typepath) + rank = new typepath() + + if(!rank) + return FALSE // something bad occured, but we prevent runtimes + + rank.link_rank(owner.current) + rank.apply_rank() + rank.give_spells() + + return TRUE + +/datum/antagonist/devil/proc/remove_spells() + rank.remove_spells() + info.obligation.remove_spells() + +/datum/antagonist/devil/proc/update_hud() + var/mob/living/living = owner.current + + if(!living.hud_used?.devilsouldisplay) + living.hud_used.devilsouldisplay = new /atom/movable/screen/devil/soul_counter(null, living.hud_used) + living.hud_used.infodisplay += living.hud_used.devilsouldisplay + + living.hud_used?.devilsouldisplay.update_counter(LAZYLEN(soulsOwned)) + +/datum/antagonist/devil/proc/remove_hud() + var/mob/living/living = owner.current + + if(!living.hud_used?.devilsouldisplay) + return + + living.hud_used.infodisplay -= living.hud_used.devilsouldisplay + qdel(living.hud_used.devilsouldisplay) + +/datum/antagonist/devil/greet() + var/list/messages = list() + LAZYADD(messages, span_warning("Вы - [info.truename], агент ада, дьявол.\n\ + Вы прибыли сюда, преследуя важную цель.\n\ + Склоните экипаж к грехопадению и укрепите влияние ада.")) + LAZYADD(messages, "Вы никак не можете навредить другим дьяволам.") + LAZYADD(messages, info.bane.law) + LAZYADD(messages, info.ban.law) + LAZYADD(messages, info.obligation.law) + LAZYADD(messages, info.banish.law) + LAZYADD(messages, "[span_warning("Помните, экипаж может найти ваши слабости, если раскроет ваше истинное имя!")]
") + return messages + +/datum/antagonist/devil/on_gain() + init_devil() + + . = ..() + + if(!.) + return FALSE + + var/mob/living/carbon/human/human = owner.current + human.store_memory("Your devilic true name is [info.truename]
[info.ban.law].
You may not directly and knowingly physically harm a devil, other than yourself.
[info.bane.law]
[info.obligation.law]
[info.banish.law]
") + + update_hud() + +/datum/antagonist/devil/proc/init_devil() + GLOB.allDevils[lowertext(info.truename)] = src + rank = new BASIC_DEVIL_RANK() + + return + +/datum/antagonist/devil/proc/init_bane() + info.bane.link_bane(owner.current) + info.bane.init_bane() + + return + +/datum/antagonist/devil/proc/init_obligation() + info.obligation.link_obligation(owner.current) + info.obligation.apply_obligation_effect() + info.obligation.give_spells() + + return + +/datum/antagonist/devil/proc/init_ban() + info.ban.link_ban(owner.current) + info.ban.apply_ban_effect() + + return + +/datum/antagonist/devil/give_objectives() + add_objective(/datum/objective/devil/ascend) + add_objective(/datum/objective/devil/sintouch) + forge_sacrifice_objective() + +/datum/antagonist/devil/proc/forge_sacrifice_objective() + var/datum/objective/devil/sacrifice/sacrifice = new + + if(!sacrifice.forge()) + addtimer(CALLBACK(src, PROC_REF(forge_sacrifice_objective)), 1 MINUTES) + qdel(sacrifice) + return + + add_objective(sacrifice) + +/datum/antagonist/devil/add_owner_to_gamemode() + LAZYADD(SSticker.mode.devils, owner) + +/datum/antagonist/devil/remove_owner_from_gamemode() + LAZYREMOVE(SSticker.mode.devils, owner) + +/datum/antagonist/devil/farewell() + to_chat(owner.current, span_userdanger("Ваша связь с адом пропадает. Вы более не дьявол!")) + +/datum/antagonist/devil/apply_innate_effects(mob/living/mob_override) + . = ..() + owner.current.AddElement(/datum/element/devil_regeneration) + owner.current.AddElement(/datum/element/devil_banishment) // handles devil banishes + + init_new_rank() + init_bane() + + init_obligation() + init_ban() + + update_hud() + info.banish.link_banish(owner.current) + + LAZYADD(owner.current.faction, "hell") + ADD_TRAIT(owner.current, TRAIT_NO_DEATH, UNIQUE_TRAIT_SOURCE(src)) + +/datum/antagonist/devil/remove_innate_effects() + . = ..() + owner.current.RemoveElement(/datum/element/devil_regeneration) + owner.current.RemoveElement(/datum/element/devil_banishment) + + remove_spells() + remove_hud() + + info.banish.remove_banish() + info.bane.remove_bane() + + info.obligation.remove_obligation() + info.ban.remove_ban() + + LAZYREMOVE(owner.current.faction, "hell") + REMOVE_TRAIT(owner.current, TRAIT_NO_DEATH, UNIQUE_TRAIT_SOURCE(src)) diff --git a/code/modules/antagonists/devil/devil_ban.dm b/code/modules/antagonists/devil/devil_ban.dm new file mode 100644 index 00000000000..255503bb810 --- /dev/null +++ b/code/modules/antagonists/devil/devil_ban.dm @@ -0,0 +1,71 @@ +/datum/devil_ban + var/name + + var/desc + var/law + + var/mob/living/carbon/owner + var/datum/antagonist/devil/devil + +/datum/devil_ban/proc/link_ban(mob/living/carbon/carbon) + owner = carbon + devil = carbon.mind?.has_antag_datum(/datum/antagonist/devil) + +/datum/devil_ban/proc/remove_ban() + remove_ban_effect() + + owner = null + devil = null + +/datum/devil_ban/Destroy(force) + remove_ban() + + return ..() + +/datum/devil_ban/proc/apply_ban_effect() + return + +/datum/devil_ban/proc/remove_ban_effect() + return + +/datum/devil_ban/hurtwoman + name = BAN_HURTWOMAN + + desc = "This devil seems to prefer hunting men." + law = "You must never harm a female outside of self defense." + +/datum/devil_ban/chapel + name = BAN_CHAPEL + + desc = "This devil avoids holy ground." + law = "You must never attempt to enter the chapel." + +/datum/devil_ban/hurtpriest + name = BAN_HURTPRIEST + + desc = "The annointed clergy appear to be immune to his powers." + law = "You must never attack a priest." + +/datum/devil_ban/avoidwater + name = BAN_AVOIDWATER + + desc = "The devil seems to have some sort of aversion to water, though it does not appear to harm him." + law = "You must never willingly touch a wet surface." + +/datum/devil_ban/strikeunconscious + name = BAN_STRIKEUNCONCIOUS + + desc = "This devil only shows interest in those who are awake." + law = "You must never strike an unconscious person." + +/datum/devil_ban/hurtlizard + name = BAN_HURTLIZARD + + desc = "This devil will not strike a lizardman first." + law = "You must never harm a lizardman outside of self defense." + +/datum/devil_ban/hurtanimal + name = BAN_HURTANIMAL + + desc = "This devil avoids hurting animals." + law = "You must never harm a non-sentient creature or robot outside of self defense." diff --git a/code/modules/antagonists/devil/devil_bane.dm b/code/modules/antagonists/devil/devil_bane.dm new file mode 100644 index 00000000000..a0697128476 --- /dev/null +++ b/code/modules/antagonists/devil/devil_bane.dm @@ -0,0 +1,191 @@ +/datum/devil_bane + var/name + + var/desc + var/law + + var/mob/living/carbon/owner + var/datum/antagonist/devil/devil + + var/bonus_damage = 1 + +/datum/devil_bane/Destroy(force) + remove_bane() + + owner = null + devil = null + + return ..() + +/datum/devil_bane/proc/remove_bane() + return + +/datum/devil_bane/proc/link_bane(mob/living/carbon/carbon) + owner = carbon + devil = owner.mind?.has_antag_datum(/datum/antagonist/devil) + +/datum/devil_bane/proc/init_bane() + return + +/datum/devil_bane/toolbox + name = BANE_TOOLBOX + + law = "Toolboxes are bad news for you, for some reason." + desc = "That which holds the means of creation also holds the means of the devil's undoing." + + bonus_damage = BANE_TOOLBOX_DAMAGE_MODIFIER + +/datum/devil_bane/toolbox/init_bane() + RegisterSignal(owner, COMSIG_PARENT_ATTACKBY, PROC_REF(toolbox_attack)) + +/datum/devil_bane/toolbox/remove_bane() + UnregisterSignal(owner, COMSIG_PARENT_ATTACKBY) + +/datum/devil_bane/toolbox/proc/toolbox_attack(datum/source, obj/item/item, mob/attacker, params) + SIGNAL_HANDLER + + if(!istype(item, /obj/item/storage/toolbox)) + return + + owner.apply_damage(item.force * bonus_damage) + item.visible_message( + span_warning("The [item] seems unusually robust this time."), + span_notice("The [item] is [owner] unmaking!")) + +/datum/devil_bane/whiteclothes + name = BANE_WHITECLOTHES + + desc = "Wearing clean white clothing will help ward off this devil." + law = "Those clad in pristine white garments will strike you true." + +/datum/devil_bane/whiteclothes/init_bane() + RegisterSignal(owner, COMSIG_PARENT_ATTACKBY, PROC_REF(whiteclothes_attack)) + +/datum/devil_bane/whiteclothes/remove_bane() + UnregisterSignal(owner, COMSIG_PARENT_ATTACKBY) + +/datum/devil_bane/whiteclothes/proc/whiteclothes_attack(datum/source, obj/item/item, mob/attacker, params) + SIGNAL_HANDLER + + if(!ishuman(attacker)) + return + + var/mob/living/carbon/human/hunter = attacker + if(!istype(hunter.w_uniform, /obj/item/clothing/under)) + return + + var/obj/item/clothing/under/uniform = hunter.w_uniform + if(!GLOB.whiteness[uniform.type]) + return + + owner.apply_damage(bonus_damage * (item.force * (GLOB.whiteness[uniform.type] + 1))) + item.visible_message(span_warning("[owner] seems to have been harmed by the purity of [attacker]'s clothes."), + span_notice("Unsullied white clothing is disrupting [owner] form.")) + +/datum/devil_bane/harvest + name = BANE_HARVEST + + law = "The fruits of the harvest shall be your downfall." + desc = "Presenting the labors of a harvest will disrupt the devil." + + bonus_damage = BANE_HARVEST_DAMAGE_MULTIPLIER + +/datum/devil_bane/harvest/init_bane() + RegisterSignal(owner, COMSIG_PARENT_ATTACKBY, PROC_REF(harvest_attack)) + +/datum/devil_bane/harvest/remove_bane() + UnregisterSignal(owner, COMSIG_PARENT_ATTACKBY) + +/datum/devil_bane/harvest/proc/harvest_attack(datum/source, obj/item/item, mob/attacker, params) + SIGNAL_HANDLER + + if(!istype(item, /obj/item/reagent_containers/food/snacks/grown) || !istype(item, /obj/item/grown)) + return + + owner.apply_damage(item.force * bonus_damage) + item.visible_message( + span_warning("The spirits of the harvest aid in the exorcism."), + span_notice("The harvest spirits are harming [owner].")) + + qdel(item) + +/datum/devil_bane/light + name = BANE_LIGHT + + desc = "Bright flashes will disorient the devil, likely causing him to flee." + law = "Blinding lights will prevent you from using offensive powers for a time." + +/datum/devil_bane/light/init_bane() + RegisterSignal(owner, COMSIG_LIVING_EARLY_FLASH_EYES, PROC_REF(flash_eyes)) + +/datum/devil_bane/light/remove_bane() + UnregisterSignal(owner, COMSIG_LIVING_EARLY_FLASH_EYES) + +/datum/devil_bane/light/proc/flash_eyes(datum/source, intensity, override_blindness_check, affect_silicon, visual, type) + SIGNAL_HANDLER + + var/damage = intensity - owner.check_eye_prot() + + if(!damage) + owner.mind?.disrupt_spells(0) + return + + owner.mind?.disrupt_spells(-500) + +/datum/devil_bane/silver + name = BANE_SILVER + + desc = "Silver seems to gravely injure this devil." + law = "Silver, in all of its forms shall be your downfall." + +/datum/devil_bane/silver/init_bane() + RegisterSignal(owner, COMSIG_EARLY_REAGENT_ADDED, PROC_REF(check_reagents)) + +/datum/devil_bane/silver/remove_bane() + UnregisterSignal(owner, COMSIG_EARLY_REAGENT_ADDED) + +/datum/devil_bane/silver/proc/check_reagents( + datum/source, + reagent_id, + amount, + data, + reagtemp, + no_react, + chem_temp + ) + SIGNAL_HANDLER + + if(reagent_id != "silver") + return + + owner.reagents?.add_reagent("toxin", amount * bonus_damage) + +/datum/devil_bane/iron + name = BANE_IRON + + desc = "Cold iron will slowly injure him, until he can purge it from his system." + law = "Cold wrought iron shall act as poison to you." + + bonus_damage = 1 + +/datum/devil_bane/iron/init_bane() + RegisterSignal(owner.reagents, COMSIG_EARLY_REAGENT_ADDED, PROC_REF(check_reagents)) + +/datum/devil_bane/iron/remove_bane() + UnregisterSignal(owner.reagents, COMSIG_EARLY_REAGENT_ADDED) + +/datum/devil_bane/iron/proc/check_reagents( + datum/source, + reagent_id, + amount, + data, + reagtemp, + no_react, + chem_temp + ) + SIGNAL_HANDLER + + if(reagent_id != "iron") + return + + owner.reagents?.add_reagent("toxin", amount * bonus_damage) diff --git a/code/modules/antagonists/devil/devil_banish.dm b/code/modules/antagonists/devil/devil_banish.dm new file mode 100644 index 00000000000..daea633cb7b --- /dev/null +++ b/code/modules/antagonists/devil/devil_banish.dm @@ -0,0 +1,90 @@ +/datum/devil_banish + var/name + + var/desc + var/law + + var/mob/living/carbon/owner + var/datum/antagonist/devil/devil + +/datum/devil_banish/proc/link_banish(mob/living/carbon/carbon) + owner = carbon + devil = carbon.mind?.has_antag_datum(/datum/antagonist/devil) + +/datum/devil_banish/proc/remove_banish() + owner = null + devil = null + +/datum/devil_banish/Destroy(force) + remove_banish() + + return ..() + +/datum/devil_banish/proc/check_banishment() + return + +/datum/devil_banish/water + name = BANISH_WATER + + desc = "Чтобы изгнать дьявола, вы должны наполнить его тело святой водой." + law = "Если ваше тело наполнено святой водой, вы не сможете воскреснуть." + +/datum/devil_banish/water/check_banishment() + return owner.reagents?.has_reagent("holy water") + +/datum/devil_banish/coffin + name = BANISH_COFFIN + + desc = "Этот дьявол вернётся к жизни, если его останки не будут помещены в гроб." + law = "Если ваше тело находится в гробу, вы не сможете воскреснуть." + +/datum/devil_banish/coffin/check_banishment() + return owner.loc && istype(owner.loc, /obj/structure/closet/coffin) + +/datum/devil_banish/formaldehyde + name = BANISH_FORMALDYHIDE + + desc = "Чтобы изгнать дьявола, вы должны ввести в его безжизненное тело бальзамирующую жидкость." + law = "Если ваше тело забальзамировано, вы не сможете воскреснуть." + +/datum/devil_banish/formaldehyde/check_banishment() + return owner.reagents?.has_reagent("formaldehyde") + +/datum/devil_banish/rune + name = BANISH_RUNES + + desc = "Этот дьявол воскреснет после смерти, если его рядом не будет руны." + law = "Если ваше тело находится возле руны, вы не сможете воскреснуть." + +/datum/devil_banish/rune/check_banishment() + return locate(/obj/effect/decal/cleanable/crayon) in range(1, owner) + +/datum/devil_banish/candle + name = BANISH_CANDLES + + desc = "Большое количество зажжённых поблизости свечей помешает дьяволу воскреснуть." + law = "Если ваше тело находится рядом с зажжёнными свечами, вы не сможете воскреснуть." + +/datum/devil_banish/candle/check_banishment() + var/count = 0 + + for(var/obj/item/candle/candle in range(1, owner)) + count += candle.lit + + return count >= 4 + +/datum/devil_banish/funeral + name = BANISH_FUNERAL_GARB + + desc = "Если этот дьявол одет в траурные одежды, либо она лежит рядом с ним, то он не сможет воскреснуть." + law = "Если ваше тело облачено в траурные одежды, вы не сможете воскреснуть." + +/datum/devil_banish/funeral/check_banishment() + if(!ishuman(owner)) // can be true devil + return FALSE + + var/mob/living/carbon/human/human = owner + if(human.w_uniform && istype(human.w_uniform, /obj/item/clothing/under/burial)) + return TRUE + + return locate(/obj/item/clothing/under/burial) in range(1, human) diff --git a/code/modules/antagonists/devil/devil_info.dm b/code/modules/antagonists/devil/devil_info.dm new file mode 100644 index 00000000000..6e3c52927af --- /dev/null +++ b/code/modules/antagonists/devil/devil_info.dm @@ -0,0 +1,66 @@ +/datum/devilinfo + /// Devil's truename + var/truename + /// Ban of our devil. + var/datum/devil_ban/ban + /// Obligation of our devil. + var/datum/devil_obligation/obligation + /// Banish of our devil. Used to dust him. Works only with devil_banishment element + var/datum/devil_banish/banish + /// Bane of our devil. Used to make devil weaker + var/datum/devil_bane/bane + +/datum/devilinfo/New(name = randomDevilName()) + truename = name + + randomdevilbane() + randomdevilobligation() + + randomdevilban() + randomdevilbanish() + +/datum/devilinfo/Destroy(force) + QDEL_NULL(banish) + QDEL_NULL(bane) + + QDEL_NULL(ban) + QDEL_NULL(obligation) + + return ..() + +/datum/devilinfo/proc/randomDevilName() + var/name = "" + + if(prob(65)) + if(prob(35)) + name = pick(GLOB.devil_pre_title) + + name += pick(GLOB.devil_title) + + var/probability = 100 + name += pick(GLOB.devil_syllable) + + while(prob(probability)) + name += pick(GLOB.devil_syllable) + probability -= 20 + + if(prob(40)) + name += pick(GLOB.devil_suffix) + + return name + +/datum/devilinfo/proc/randomdevilobligation() + var/new_obligation = pick(subtypesof(/datum/devil_obligation)) + obligation = new new_obligation() + +/datum/devilinfo/proc/randomdevilban() + var/new_ban = pick(subtypesof(/datum/devil_ban)) + ban = new new_ban() + +/datum/devilinfo/proc/randomdevilbane() + var/new_bane = pick(subtypesof(/datum/devil_bane)) + bane = new new_bane() + +/datum/devilinfo/proc/randomdevilbanish() + var/new_banish = pick(subtypesof(/datum/devil_banish)) + banish = new new_banish() diff --git a/code/modules/antagonists/devil/devil_obligation.dm b/code/modules/antagonists/devil/devil_obligation.dm new file mode 100644 index 00000000000..d34d40c715e --- /dev/null +++ b/code/modules/antagonists/devil/devil_obligation.dm @@ -0,0 +1,94 @@ +/datum/devil_obligation + var/name + + var/desc + var/law + + var/mob/living/carbon/owner + var/datum/antagonist/devil/devil + + var/list/obligation_spells + +/datum/devil_obligation/proc/link_obligation(mob/living/carbon/carbon) + owner = carbon + devil = carbon.mind?.has_antag_datum(/datum/antagonist/devil) + +/datum/devil_obligation/proc/remove_obligation() + remove_obligation_effect() + + owner = null + devil = null + +/datum/devil_obligation/Destroy(force) + remove_obligation() + + return ..() + +/datum/devil_obligation/proc/give_spells() + for(var/obj/effect/proc_holder/spell/spell as anything in obligation_spells) + owner.mind?.AddSpell(spell) + +/datum/devil_obligation/proc/remove_spells() + for(var/obj/effect/proc_holder/spell/spell as anything in owner.mind?.spell_list) + if(!is_type_in_list(spell, obligation_spells)) + continue + + owner.mind?.RemoveSpell(spell) + +/datum/devil_obligation/proc/apply_obligation_effect() + return + +/datum/devil_obligation/proc/remove_obligation_effect() + return + +/datum/devil_obligation/food + name = OBLIGATION_FOOD + + desc = "Этот дьявол всегда предлагает его жертвам еду, прежде чем убивает их." + law = "Пока вы не самообороняетесь, вы должны предлагать вашим жертвам еду, прежде чем вредить им." + + obligation_spells = list(/obj/effect/proc_holder/spell/conjure_item/violin) + +/datum/devil_obligation/fiddle + name = OBLIGATION_FIDDLE + + desc = "Этот дьявол никогда не откажется от музыкального поединка" + law = "Пока вы не находитесь в опасности, при предложении музыкального поединка, то вы обязаны его принять." + +/datum/devil_obligation/danceoff + name = OBLIGATION_DANCEOFF + + desc = "Этот дьявол никогда не откажется от танцевального поединка." + law = "Когда вам ничего не угрожает и вас вызвали на танцевальный поединок, то вы обязаны его принять." + + obligation_spells = list(/obj/effect/proc_holder/spell/summon_dancefloor) + +/datum/devil_obligation/greet + name = OBLIGATION_GREET + + desc = "Этот дьявол, похоже, может общаться только с теми, чьи имена он знает." + law = "Вы должны всегда здороваться с людьми, называя их по фамилии, прежде чем заговорить с ними." + +/datum/devil_obligation/presenceknown + name = OBLIGATION_PRESENCEKNOWN + + desc = "Этот дьявол, похоже, не может нападать из-за укрытия." + law = "Вы должны всегда заявлять о своем присутствии перед атакой." + +/datum/devil_obligation/sayname + name = OBLIGATION_SAYNAME + + desc = "Он всегда произносит свое имя, убивая кого-либо." + law = "Вы должны всегда произносить свое истинное имя после того, как убьете кого-либо." + +/datum/devil_obligation/announcekill + name = OBLIGATION_ANNOUNCEKILL + + desc = "Этот дьявол всегда громко объявляет о своих убийствах, чтобы это услышал весь мир." + law = "Убив кого-либо, вы должны известить всех в пределах слышимости о своем поступке, через связь, если это возможно." + +/datum/devil_obligation/answertotruename + name = OBLIGATION_ANSWERTONAME + + desc = "Этот дьявол всегда отвечает на свое истинное имя." + law = "Если на вас не нападают, вы должны всегда откликаться на свое истинное имя." diff --git a/code/modules/antagonists/devil/devil_outfit.dm b/code/modules/antagonists/devil/devil_outfit.dm new file mode 100644 index 00000000000..df8a40f9a32 --- /dev/null +++ b/code/modules/antagonists/devil/devil_outfit.dm @@ -0,0 +1,30 @@ +/datum/outfit/devil_lawyer + name = "Devil Lawyer" + uniform = /obj/item/clothing/under/lawyer/black + shoes = /obj/item/clothing/shoes/laceup + back = /obj/item/storage/backpack + l_hand = /obj/item/storage/briefcase + l_pocket = /obj/item/pen + l_ear = /obj/item/radio/headset + id = /obj/item/card/id + +/datum/outfit/devil_lawyer/post_equip(mob/living/carbon/human/human, visualsOnly = FALSE) + var/obj/item/card/id/id = human.wear_id + + if(!istype(id) || id.assignment) // either doesn't have a card, or the card is already written to + return + + var/name_to_use = human.real_name + var/datum/antagonist/devil/devilinfo = human.mind?.has_antag_datum(/datum/antagonist/devil) + + if(devilinfo) + name_to_use = devilinfo.info.truename // Having hell create an ID for you causes its risks + + id.name = "[name_to_use]'s ID Card (Lawyer)" + id.registered_name = name_to_use + id.assignment = "Lawyer" + id.rank = id.assignment + id.age = human.age + id.sex = capitalize(human.gender) + id.access = list(ACCESS_MAINT_TUNNELS, ACCESS_SYNDICATE, ACCESS_EXTERNAL_AIRLOCKS) + id.photo = get_id_photo(human) diff --git a/code/modules/antagonists/devil/devil_pawn.dm b/code/modules/antagonists/devil/devil_pawn.dm new file mode 100644 index 00000000000..40adf208303 --- /dev/null +++ b/code/modules/antagonists/devil/devil_pawn.dm @@ -0,0 +1,7 @@ +/// Devil's allies/creations should be marked with this datum +/datum/antagonist/devil_pawn + name = "Devil's pawn" + special_role = SPECIAL_ROLE_DEVIL_PAWN + give_objectives = FALSE + silent = TRUE + show_in_roundend = FALSE diff --git a/code/modules/antagonists/devil/devil_rank.dm b/code/modules/antagonists/devil/devil_rank.dm new file mode 100644 index 00000000000..86de4a02615 --- /dev/null +++ b/code/modules/antagonists/devil/devil_rank.dm @@ -0,0 +1,123 @@ +/datum/devil_rank + /// Antagonist datum of our owner + var/datum/antagonist/devil/devil + /// Which spells we'll give to rank owner when rank is applied + var/list/rank_spells + /// Regeneration things for devil. Used in devil elements + var/regen_threshold + var/regen_amount + /// just OOP thing. Ranks without this designated as last rank. + var/next_rank_type + /// How many souls we need to ascend to next rank. + var/required_souls + +/datum/devil_rank/Destroy(force) + remove_spells() + + devil = null + + return ..() + +/datum/devil_rank/proc/link_rank(mob/living/carbon/carbon) + devil = carbon.mind?.has_antag_datum(/datum/antagonist/devil) + +/datum/devil_rank/proc/remove_spells() + if(!devil.owner) + return + + for(var/obj/effect/proc_holder/spell/spell as anything in devil.owner.spell_list) + if(!is_type_in_list(spell, rank_spells)) + continue + + devil.owner.RemoveSpell(spell) + +/datum/devil_rank/proc/apply_rank(mob/living/carbon/carbon) + return + +/datum/devil_rank/proc/give_spells() + if(!devil.owner) + return + + for(var/obj/effect/proc_holder/spell/spell as anything in rank_spells) + devil.owner.AddSpell(new spell) + +/datum/devil_rank/basic_devil + regen_threshold = BASIC_DEVIL_REGEN_THRESHOLD + regen_amount = BASIC_DEVIL_REGEN_AMOUNT + + next_rank_type = ENRAGED_DEVIL_RANK + required_souls = ENRAGED_THRESHOLD + + rank_spells = list(/obj/effect/proc_holder/spell/sacrifice_circle) + +/datum/devil_rank/enraged_devil + regen_threshold = ENRAGED_DEVIL_REGEN_THRESHOLD + regen_amount = ENRAGED_DEVIL_REGEN_AMOUNT + + next_rank_type = BLOOD_LIZARD_RANK + required_souls = BLOOD_THRESHOLD + + rank_spells = list( + /obj/effect/proc_holder/spell/sacrifice_circle, + /obj/effect/proc_holder/spell/conjure_item/pitchfork, + /obj/effect/proc_holder/spell/aoe/devil_fire, + /obj/effect/proc_holder/spell/dark_conversion + ) + +/datum/devil_rank/blood_lizard + regen_threshold = BLOOD_LIZARD_REGEN_THRESHOLD + regen_amount = BLOOD_LIZARD_REGEN_AMOUNT + + next_rank_type = TRUE_DEVIL_RANK + required_souls = TRUE_THRESHOLD + + rank_spells = list( + /obj/effect/proc_holder/spell/sacrifice_circle, + /obj/effect/proc_holder/spell/conjure_item/pitchfork, + /obj/effect/proc_holder/spell/fireball/hellish, + /obj/effect/proc_holder/spell/aoe/devil_fire, + /obj/effect/proc_holder/spell/infernal_jaunt, + /obj/effect/proc_holder/spell/dark_conversion, + /obj/effect/proc_holder/spell/aoe/devil_fire + ) + +/datum/devil_rank/blood_lizard/apply_rank() + var/mob/living/carbon/human/human = devil.owner.current + var/list/language_temp = LAZYLEN(human.languages) ? human.languages.Copy() : null + + human.set_species(/datum/species/unathi) + if(language_temp) + human.languages = language_temp + + human.underwear = "Nude" + human.undershirt = "Nude" + human.socks = "Nude" + human.change_skin_color(80, 16, 16) //A deep red + human.regenerate_icons() + + return + +/datum/devil_rank/true_devil + regen_threshold = TRUE_DEVIL_REGEN_THRESHOLD + regen_amount = TRUE_DEVIL_REGEN_AMOUNT + + rank_spells = list( + /obj/effect/proc_holder/spell/conjure_item/pitchfork/greater, + /obj/effect/proc_holder/spell/fireball/hellish, + /obj/effect/proc_holder/spell/aoe/devil_fire, + /obj/effect/proc_holder/spell/infernal_jaunt, + /obj/effect/proc_holder/spell/sintouch, + /obj/effect/proc_holder/spell/dark_conversion, + /obj/effect/proc_holder/spell/aoe/devil_fire + ) + +/datum/devil_rank/true_devil/apply_rank() + to_chat(devil.owner.current, span_revenbignotice("Вы чувствуете, как ваше тело меняется.")) + var/mob/living/carbon/true_devil/true_devil = new /mob/living/carbon/true_devil(get_turf(devil.owner.current)) + + devil.owner.current.forceMove(true_devil) + true_devil.oldform = devil.owner.current + devil.owner.transfer_to(true_devil) + true_devil.set_name() + + return diff --git a/code/modules/antagonists/devil/devil_ritual.dm b/code/modules/antagonists/devil/devil_ritual.dm new file mode 100644 index 00000000000..48171b71c07 --- /dev/null +++ b/code/modules/antagonists/devil/devil_ritual.dm @@ -0,0 +1,88 @@ +/datum/ritual/devil + allowed_special_role = list(ROLE_DEVIL) + cooldown_after_cast = null + disaster_prob = 0 + fail_chance = 0 + +/datum/ritual/devil/imp + name = "Imp summoning ritual" + required_things = list( + /obj/item/wirecutters = 3, + /obj/item/organ/internal/kidneys = 2, + /obj/item/organ/internal/heart = 1, + /obj/effect/decal/cleanable/vomit = 2 + ) + +/datum/ritual/devil/imp/del_things() + for(var/obj/obj in used_things) // no type ignore for future. + qdel(obj) + + return + +/datum/ritual/devil/imp/do_ritual(mob/living/carbon/human/invoker) + var/list/candidates = SSghost_spawns.poll_candidates("Вы хотите сыграть за беса?", SPECIAL_ROLE_DEVIL_PAWN, TRUE) + + if(!LAZYLEN(candidates)) + return RITUAL_FAILED_ON_PROCEED + + var/mob/mob = pick(candidates) + var/mob/living/simple_animal/imp/imp = new(get_turf(ritual_object)) + + imp.key = mob.key + imp.master_commander = invoker + + improve_imp(imp, invoker) + + return RITUAL_SUCCESSFUL + +/datum/ritual/devil/imp/proc/improve_imp(mob/living/simple_animal/imp/imp, mob/living/carbon/human/invoker) + var/datum/antagonist/devil/devil = invoker.mind?.has_antag_datum(/datum/antagonist/devil) + + imp.universal_speak = TRUE + imp.sentience_act() + + imp.mind.store_memory("Я подчиняюсь призывателю [imp.master_commander.name], также известному как [devil.info.truename].") + imp.mind.add_antag_datum(/datum/antagonist/devil_pawn) + +/datum/ritual/devil/sacrifice + name = "Sacrifice ritual" + ritual_should_del_things = FALSE + required_things = list( + /mob/living/carbon/human = 1 + ) + +/datum/ritual/devil/sacrifice/check_contents(mob/living/carbon/human/invoker) + . = ..() + + if(!.) + return FALSE + + var/mob/living/carbon/human/human = locate() in used_things + + if(!human.mind || !human.mind.hasSoul) + ritual_object.balloon_alert("цель без души!") + return FALSE + + var/datum/objective/devil/sacrifice/sacrifice = locate() in invoker.mind?.get_all_objectives() + + if(sacrifice && !LAZYIN(sacrifice.target_minds, human.mind)) + ritual_object.balloon_alert("не имеет ценности!") + return FALSE + + var/datum/antagonist/devil/devil = invoker.mind?.has_antag_datum(/datum/antagonist/devil) + + if(LAZYIN(devil.soulsOwned, human.mind)) + return FALSE // Error occured / Admin changed hasSoul. + + return TRUE + +/datum/ritual/devil/sacrifice/do_ritual(mob/living/carbon/human/invoker) + var/mob/living/carbon/human/human = locate() in used_things + var/datum/antagonist/devil/devil = invoker.mind?.has_antag_datum(/datum/antagonist/devil) + + if(!devil || !human || !human.mind) + return RITUAL_FAILED_ON_PROCEED + + devil.add_soul(human.mind) + + return RITUAL_SUCCESSFUL diff --git a/code/modules/antagonists/devil/helper_procs.dm b/code/modules/antagonists/devil/helper_procs.dm new file mode 100644 index 00000000000..ec11f8b851f --- /dev/null +++ b/code/modules/antagonists/devil/helper_procs.dm @@ -0,0 +1,14 @@ +/mob/living/proc/owns_soul() + if(!mind) + return FALSE + + return mind.soulOwner == mind + +/proc/devilInfo(name) + if(GLOB.allDevils[lowertext(name)]) + return GLOB.allDevils[lowertext(name)] + + var/datum/devilinfo/devilinfo = new /datum/devilinfo(name) + GLOB.allDevils[lowertext(name)] = devilinfo + + return devilinfo diff --git a/code/game/gamemodes/devil/imp/imp.dm b/code/modules/antagonists/devil/imp/imp.dm similarity index 74% rename from code/game/gamemodes/devil/imp/imp.dm rename to code/modules/antagonists/devil/imp/imp.dm index 3afb4e1c28c..b1281dafc01 100644 --- a/code/game/gamemodes/devil/imp/imp.dm +++ b/code/modules/antagonists/devil/imp/imp.dm @@ -28,10 +28,6 @@ melee_damage_upper = 15 nightvision = 8 lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE - var/playstyle_string = "You are an imp, a mischevious creature from hell. You are the lowest rank on the hellish totem pole \ - Though you are not obligated to help, perhaps by aiding a higher ranking devil, you might just get a promotion. However, you are incapable \ - of intentionally harming a fellow devil." - /mob/living/simple_animal/imp/ComponentInitialize() AddComponent( \ @@ -47,8 +43,9 @@ /mob/living/simple_animal/imp/death(gibbed) - ..(1) + . = ..(TRUE) + playsound(get_turf(src),'sound/misc/demon_dies.ogg', 200, 1) - visible_message("[src] screams in agony as it sublimates into a sulfurous smoke.") - ghostize() + visible_message(span_danger("[src] screams in agony as it sublimates into a sulfurous smoke.")) + qdel(src) diff --git a/code/modules/antagonists/devil/sintouched.dm b/code/modules/antagonists/devil/sintouched.dm new file mode 100644 index 00000000000..590991225a5 --- /dev/null +++ b/code/modules/antagonists/devil/sintouched.dm @@ -0,0 +1,43 @@ +/datum/antagonist/sintouched + name = "Sintouched" + special_role = SPECIAL_ROLE_SINTOUCHED + +/datum/antagonist/sintouched/can_be_owned(datum/mind/new_owner) + . = ..() + if(!.) + return FALSE + + var/datum/mind/tested = new_owner || owner + + if(!tested || !ishuman(tested.current)) + return FALSE + + return TRUE + +/datum/antagonist/sintouched/give_objectives() + var/list/sins = list() + + for(var/datum/objective/sintouched/sin as anything in subtypesof(/datum/objective/sintouched)) + if(!sin.explanation_text) + continue + + LAZYADD(sins, sin) + + add_objective(pick(sins)) + +/datum/antagonist/sintouched/add_owner_to_gamemode() + LAZYADD(SSticker.mode.sintouched, owner) + +/datum/antagonist/sintouched/remove_owner_from_gamemode() + LAZYREMOVE(SSticker.mode.sintouched, owner) + +/datum/antagonist/sintouched/apply_innate_effects(mob/living/mob_override) + . = ..() + + var/mob/living/carbon/human/human = mob_override || owner.current + + for(var/datum/objective/sintouched/sin_objective in owner.objectives) + sin_objective.init_sin(human) + +/datum/antagonist/sintouched/on_body_transfer(mob/living/old_body, mob/living/new_body) + return // No. diff --git a/code/game/gamemodes/devil/true_devil/_true_devil.dm b/code/modules/antagonists/devil/true_devil/_true_devil.dm similarity index 72% rename from code/game/gamemodes/devil/true_devil/_true_devil.dm rename to code/modules/antagonists/devil/true_devil/_true_devil.dm index 6a02726016a..12b4942d6e8 100644 --- a/code/game/gamemodes/devil/true_devil/_true_devil.dm +++ b/code/modules/antagonists/devil/true_devil/_true_devil.dm @@ -12,41 +12,37 @@ status_flags = CANPUSH universal_understand = TRUE universal_speak = TRUE //The devil speaks all languages meme - hud_type = /datum/hud/devil - var/ascended = FALSE var/mob/living/oldform + var/datum/antagonist/devil/devilinfo + hud_type = /datum/hud/devil -/mob/living/carbon/true_devil/New(loc, mob/living/carbon/dna_source) +/mob/living/carbon/true_devil/Initialize(mapload, mob/living/carbon/dna_source) if(dna_source) dna = dna_source.dna.Clone() else dna = new + devilinfo = mind?.has_antag_datum(/datum/antagonist/devil) new /obj/item/organ/internal/brain(src) new /obj/item/organ/internal/ears(src) - ..() + + . = ..() // Determines if mob has and can use his hands like a human /mob/living/carbon/true_devil/real_human_being() return TRUE - -/mob/living/carbon/true_devil/proc/convert_to_archdevil() - maxHealth = 5000 // not an IMPOSSIBLE amount, but still near impossible. - ascended = TRUE - health = maxHealth - icon_state = "arch_devil" - /mob/living/carbon/true_devil/set_name() - name = mind.devilinfo.truename + name = devilinfo.info.truename real_name = name /mob/living/carbon/true_devil/Login() ..() var/list/messages = list() - if(mind.devilinfo) - messages.Add(mind.devilinfo.announce_laws(src)) - messages.Add(mind.prepare_announce_objectives()) + + LAZYADD(messages, devilinfo?.greet()) + LAZYADD(messages, mind.prepare_announce_objectives()) + to_chat(mind.current, chat_box_red(messages.Join("
"))) @@ -94,12 +90,6 @@ /mob/living/carbon/true_devil/assess_threat() return 666 -/mob/living/carbon/true_devil/flash_eyes(intensity = 1, override_blindness_check, affect_silicon, visual, type = /atom/movable/screen/fullscreen/flash) - if(mind && has_bane(BANE_LIGHT)) - mind.disrupt_spells(-500) - return ..() //flashes don't stop devils UNLESS it's their bane. - - /mob/living/carbon/true_devil/proceed_attack_results(obj/item/I, mob/living/user, params, def_zone) . = ATTACK_CHAIN_PROCEED_SUCCESS @@ -107,7 +97,6 @@ if(!I.force) return . - apply_damage(I.force * check_weakness(I, user), I.damtype, def_zone, sharp = is_sharp(I), used_weapon = I) if(QDELETED(src)) return ATTACK_CHAIN_BLOCKED_ALL @@ -123,29 +112,8 @@ /mob/living/carbon/true_devil/Process_Spacemove(movement_dir = NONE, continuous_move = FALSE) return TRUE - -/mob/living/carbon/true_devil/singularity_act() - if(ascended) - return 0 - return ..() - -/mob/living/carbon/true_devil/attack_ghost(mob/dead/observer/user as mob) - if(ascended || user.mind.soulOwner == src.mind) - var/mob/living/simple_animal/imp/S = new(get_turf(loc)) - S.key = user.key - S.mind.assigned_role = "MODE" - S.mind.special_role = "Imp" - var/datum/objective/newobjective = new - newobjective.explanation_text = "Try to get a promotion to a higher infernal rank." - S.mind.objectives += newobjective - to_chat(S,S.playstyle_string) - to_chat(S,"Objective #1: [newobjective.explanation_text]") - return - else - return ..() - /mob/living/carbon/true_devil/resist_fire() - //They're immune to fire. + return /mob/living/carbon/true_devil/attack_hand(mob/living/carbon/human/M) if(..()) @@ -158,7 +126,7 @@ adjustBruteLoss(damage) add_attack_logs(M, src, "attacked") if(INTENT_DISARM) - if(body_position == STANDING_UP && !ascended) //No stealing the arch devil's pitchfork. + if(body_position == STANDING_UP) //No stealing the arch devil's pitchfork. if(prob(5)) // Weaken knocks people over // Paralyse knocks people out @@ -186,17 +154,14 @@ return TRUE /mob/living/carbon/true_devil/ex_act(severity, ex_target) - if(!ascended) - var/b_loss - switch (severity) - if (1) - b_loss = 500 - if (2) - b_loss = 150 - if(3) - b_loss = 30 - if(has_bane(BANE_LIGHT)) - b_loss *=2 - adjustBruteLoss(b_loss) + var/b_loss + switch(severity) + if(1) + b_loss = 500 + if(2) + b_loss = 150 + if(3) + b_loss = 30 + + adjustBruteLoss(b_loss) return ..() - diff --git a/code/modules/library/codex_gigas.dm b/code/modules/library/codex_gigas.dm index ef54b64f626..e97cd7646fc 100644 --- a/code/modules/library/codex_gigas.dm +++ b/code/modules/library/codex_gigas.dm @@ -7,50 +7,71 @@ author = "Forces beyond your comprehension" unique = TRUE title = "The codex gigas" - var/inUse = 0 - + var/inUse = FALSE /obj/item/book/codex_gigas/attack_self(mob/user) if(!user.has_vision()) return + if(inUse) to_chat(user,"Someone else is reading it.") return + if(!user.is_literate()) - to_chat(user,"You don't know how to read.") + to_chat(user, span_notice("You don't know how to read.")) + return + + if(!ishuman(user)) + return + + var/mob/living/carbon/human/human = user + + if(locate(/datum/objective/sintouched/acedia) in human.mind?.objectives) + to_chat(user, span_notice("None of this matters, why are you reading this? You put the [title] down.")) + return + + inUse = TRUE + + 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 = 30 SECONDS + var/correctness = 85 + var/willpower = 95 + + if(human.job in list(JOB_TITLE_LIBRARIAN)) // the librarian is both faster, and more accurate than normal crew members at research + speed = 4.5 SECONDS + correctness = 100 + willpower = 100 + + if(human.job in list(JOB_TITLE_CHAPLAIN)) // the librarian is both faster, and more accurate than normal crew members at research + speed = 30 SECONDS + correctness = 100 + + if(human.job in list(JOB_TITLE_CAPTAIN, JOB_TITLE_OFFICER, JOB_TITLE_HOS, JOB_TITLE_DETECTIVE, JOB_TITLE_WARDEN)) + willpower = 99 + + if(human.job in list(JOB_TITLE_CLOWN)) // WHO GAVE THE CLOWN A DEMONOMICON? BAD THINGS WILL HAPPEN! + willpower = 25 + + correctness -= human.getBrainLoss() *0.5 //Brain damage makes researching hard. + speed += human.getBrainLoss() * 0.3 SECONDS + user.visible_message("[user] opens [title] and begins reading intently.") + + if(!do_after(human, speed, human, DEFAULT_DOAFTER_IGNORE | DA_IGNORE_HELD_ITEM)) return - if(ishuman(user)) - var/mob/living/carbon/human/U = user - 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 = 30 SECONDS - var/correctness = 85 - var/willpower = 95 - if(U.job in list(JOB_TITLE_LIBRARIAN)) // the librarian is both faster, and more accurate than normal crew members at research - speed = 4.5 SECONDS - correctness = 100 - willpower = 100 - if(U.job in list(JOB_TITLE_CHAPLAIN)) // the librarian is both faster, and more accurate than normal crew members at research - speed = 30 SECONDS - correctness = 100 - if(U.job in list(JOB_TITLE_CAPTAIN, JOB_TITLE_OFFICER, JOB_TITLE_HOS, JOB_TITLE_DETECTIVE, JOB_TITLE_WARDEN)) - willpower = 99 - if(U.job in list(JOB_TITLE_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() * 0.3 SECONDS - user.visible_message("[user] opens [title] and begins reading intently.") - if(do_after(U, speed, U, DEFAULT_DOAFTER_IGNORE|DA_IGNORE_HELD_ITEM)) - 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") - inUse = 0 - sleep(10) - if(!prob(willpower)) - U.influenceSin() - onclose(user, "book") + + var/usedName = devilName + + if(!prob(correctness)) + usedName += "x" + + var/datum/antagonist/devil/devil = devilInfo(usedName) + user << browse("Information on [devilName]


[devil.info.ban.desc]
[devil.info.bane.desc]
[devil.info.obligation.desc]
[devil.info.banish.desc]", "window=book") + + inUse = FALSE + addtimer(CALLBACK(src, PROC_REF(close), human, willpower), 10 SECONDS) + +/obj/item/book/codex_gigas/proc/close(mob/living/carbon/human/human, willpower) + if(!prob(willpower)) + human.mind?.add_antag_datum(/datum/antagonist/sintouched) + + onclose(human, "book") diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index a7047e55786..bbf221d5e01 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -396,16 +396,11 @@ else to_chat(src, span_warning("Ваши глаза начинают изрядно болеть. Это определенно не очень хорошо!")) - if(mind && has_bane(BANE_LIGHT)) - mind.disrupt_spells(-500) return TRUE else if(damage == 0) // just enough protection if(prob(20)) to_chat(src, span_notice("Что-то яркое вспыхнуло на периферии вашего зрения!")) - if(mind && has_bane(BANE_LIGHT)) - mind.disrupt_spells(0) - /mob/living/carbon/proc/create_dna() if(!dna) diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 8fe2746464a..79dec817b22 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -1774,46 +1774,6 @@ Eyes need to have significantly high darksight to shine unless the mob has the X if(LAZYIN(mind.curses, "high_rp")) // Probably need to make a new proc to handle curses in case if there will be new ones curse_high_rp() -/mob/living/carbon/human/proc/influenceSin() - if(!mind) - return - - var/datum/objective/sintouched/sin_objective - - switch(rand(1,7))//traditional seven deadly sins... except lust. - if(1) // acedia - add_game_logs("[src] was influenced by the sin of Acedia.", src) - sin_objective = new /datum/objective/sintouched/acedia - if(2) // Gluttony - add_game_logs("[src] was influenced by the sin of gluttony.", src) - sin_objective = new /datum/objective/sintouched/gluttony - if(3) // Greed - add_game_logs("[src] was influenced by the sin of greed.", src) - sin_objective = new /datum/objective/sintouched/greed - if(4) // sloth - add_game_logs("[src] was influenced by the sin of sloth.", src) - sin_objective = new /datum/objective/sintouched/sloth - if(5) // Wrath - add_game_logs("[src] was influenced by the sin of wrath.", src) - sin_objective = new /datum/objective/sintouched/wrath - if(6) // Envy - add_game_logs("[src] was influenced by the sin of envy.", src) - sin_objective = new /datum/objective/sintouched/envy - if(7) // Pride - add_game_logs("[src] was influenced by the sin of pride.", src) - sin_objective = new /datum/objective/sintouched/pride - - sin_objective.init_sin(src) - LAZYADD(SSticker.mode.sintouched, mind) - LAZYADD(mind.objectives, sin_objective) - - var/obj_count = 1 - to_chat(src, span_notice("Your current objectives:")) - - for(var/datum/objective/objective in mind.objectives) - to_chat(src, "Objective #[obj_count]: [objective.explanation_text]") - obj_count++ - /mob/living/carbon/human/is_literate() return getBrainLoss() < 100 diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index 7f463abfa0c..24a0cf757e6 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -510,24 +510,23 @@ emp_act if(weapon_sharp && prob(getarmor(user.zone_selected, MELEE))) weapon_sharp = FALSE - var/cached_force = I.force * check_weakness(I, user) // this can destroy some species (damn nucleo-bombers), so from now on we cannot count on its existance - var/apply_damage_result = apply_damage(cached_force, I.damtype, affecting, armor, weapon_sharp, I) + var/apply_damage_result = apply_damage(I.force, I.damtype, affecting, armor, weapon_sharp, I) var/IM_ALIVE = !QDELETED(src) var/list/all_objectives = user.mind?.get_all_objectives() if(all_objectives) for(var/datum/objective/pain_hunter/objective in all_objectives) if(mind == objective.target) - objective.take_damage(cached_force, I.damtype) + objective.take_damage(I.force, I.damtype) if(!IM_ALIVE) return . var/bloody = FALSE - if(apply_damage_result && I.damtype == BRUTE && prob(25 + cached_force * 2)) + if(apply_damage_result && I.damtype == BRUTE && prob(25 + I.force * 2)) I.add_mob_blood(src) //Make the weapon bloody, not the person. - if(prob(cached_force * 2)) //blood spatter! + if(prob(I.force * 2)) //blood spatter! bloody = TRUE add_splatter_floor() if(get_dist(user, src) <= 1) //people with TK won't get smeared with blood @@ -536,14 +535,14 @@ emp_act switch(hit_area) if(BODY_ZONE_HEAD)//Harder to score a stun but if you do it lasts a bit longer if(apply_damage_result && stat == CONSCIOUS && armor < 50) - if(prob(cached_force)) + if(prob(I.force)) visible_message( span_combatdanger("[src] has been knocked down!"), span_combatuserdanger("[src] has been knocked down!"), ) apply_effect(4 SECONDS, KNOCKDOWN, armor) AdjustConfused(30 SECONDS) - if(mind?.special_role == SPECIAL_ROLE_REV && prob(cached_force + ((100 - health)/2)) && src != user && I.damtype == BRUTE) + if(mind?.special_role == SPECIAL_ROLE_REV && prob(I.force + ((100 - health)/2)) && src != user && I.damtype == BRUTE) SSticker.mode.remove_revolutionary(mind) if(bloody)//Apply blood @@ -558,7 +557,7 @@ emp_act update_inv_glasses() if(BODY_ZONE_CHEST)//Easier to score a stun but lasts less time - if(apply_damage_result && stat == CONSCIOUS && prob(cached_force + 10)) + if(apply_damage_result && stat == CONSCIOUS && prob(I.force + 10)) visible_message( span_combatdanger("[src] has been knocked down!"), span_combatuserdanger("[src] has been knocked down!"), @@ -573,7 +572,7 @@ emp_act w_uniform.add_mob_blood(src) update_inv_w_uniform() - if(apply_damage_result && (cached_force > 10 || (cached_force >= 5 && prob(33)))) + if(apply_damage_result && (I.force > 10 || (I.force >= 5 && prob(33)))) forcesay(GLOB.hit_appends) //forcesay checks stat already . |= dna.species.spec_proceed_attack_results(I, src, user, affecting) diff --git a/code/modules/mob/living/death.dm b/code/modules/mob/living/death.dm index dc484ceedcb..275345c0147 100644 --- a/code/modules/mob/living/death.dm +++ b/code/modules/mob/living/death.dm @@ -40,12 +40,14 @@ return TRUE /mob/living/proc/can_die() - return !(stat == DEAD || HAS_TRAIT(src, TRAIT_GODMODE)) + return !(stat == DEAD || HAS_TRAIT(src, TRAIT_GODMODE) || HAS_TRAIT(src, TRAIT_NO_DEATH)) // Returns true if mob transitioned from live to dead // Do a check with `can_die` beforehand if you need to do any // handling before `stat` is set /mob/living/death(gibbed) + SEND_SIGNAL(src, COMSIG_LIVING_EARLY_DEATH, gibbed) + if(stat == DEAD || !can_die()) // Whew! Good thing I'm indestructible! (or already dead) return FALSE @@ -103,10 +105,6 @@ SSticker.mode.check_win() clear_alert("succumb") - - if(mind && mind.devilinfo) // Expand this into a general-purpose death-response system when appropriate - mind.devilinfo.beginResurrectionCheck(src) - SEND_SIGNAL(src, COMSIG_LIVING_DEATH, gibbed) // u no we dead return TRUE diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 0618bc649d7..50d50476a21 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -1266,6 +1266,10 @@ /mob/living/proc/flash_eyes(intensity = 1, override_blindness_check, affect_silicon, visual, type = /atom/movable/screen/fullscreen/flash) if(HAS_TRAIT(src, TRAIT_GODMODE)) return FALSE + + if(SEND_SIGNAL(src, COMSIG_LIVING_EARLY_FLASH_EYES, intensity, override_blindness_check, affect_silicon, visual, type) & STOP_FLASHING_EYES) + return FALSE + if(check_eye_prot() < intensity && (override_blindness_check || !HAS_TRAIT(src, TRAIT_BLIND))) overlay_fullscreen("flash", type) addtimer(CALLBACK(src, PROC_REF(clear_fullscreen), "flash", 25), 25) @@ -1647,35 +1651,6 @@ ..() update_z(new_turf?.z) -/mob/living/proc/owns_soul() - if(mind) - return mind.soulOwner == mind - return 1 - -/mob/living/proc/return_soul() - if(mind) - if(mind.soulOwner.devilinfo)//Not sure how this could happen, but whatever. - mind.soulOwner.devilinfo.remove_soul(mind) - mind.soulOwner = mind - mind.damnation_type = 0 - -/mob/living/proc/has_bane(banetype) - if(mind) - if(mind.devilinfo) - return mind.devilinfo.bane == banetype - return 0 - -/mob/living/proc/check_weakness(obj/item/weapon, mob/living/attacker) - if(mind && mind.devilinfo) - return check_devil_bane_multiplier(weapon, attacker) - return 1 - -/mob/living/proc/check_acedia() - if(src.mind && src.mind.objectives) - for(var/datum/objective/sintouched/acedia/A in src.mind.objectives) - return 1 - return 0 - /mob/living/proc/fakefireextinguish() return diff --git a/code/modules/paperwork/contract.dm b/code/modules/paperwork/contract.dm index 2a8eaffcab1..d1b51b7a0c3 100644 --- a/code/modules/paperwork/contract.dm +++ b/code/modules/paperwork/contract.dm @@ -38,35 +38,11 @@
Кроме того, Раб соглашается передать право на владение своей душой отделу лояльности Вездесущего и полезного наблюдателя за человечеством.\
В случае, если передача души Раба невозможна, Раб вносит вместо неё залог.
Подписано,
[target]" - -/obj/item/paper/contract/employment/attack(mob/living/victim, mob/living/user, params, def_zone, skip_attack_anim = FALSE) - . = ..() - if(!ATTACK_CHAIN_SUCCESS_CHECK(.)) - return . - - var/deconvert = 0 - if(victim.mind == target && target.soulOwner != target) - if(user.mind && (user.mind.assigned_role == JOB_TITLE_LAWYER)) - deconvert = 60 - else if (user.mind && (user.mind.assigned_role == JOB_TITLE_HOP) || (user.mind.assigned_role == "Centcom Commander") || (user.mind.assigned_role == JOB_TITLE_JUDGE)) - deconvert = 40 - else if(user.mind && (user.mind.assigned_role == JOB_TITLE_CAPTAIN)) - deconvert = 25 - else - deconvert = 0.0001 - - if(prob(deconvert)) - victim.visible_message( - span_notice("Благодаря [user] [victim] вспоминает, что душа [victim] уже приобретена НаноТрейзен!"), - span_boldnotice("Вы чувствуете, как Ваша душа возвращается к её правомочному владельцу — НаноТрейзен."), - ) - victim.return_soul() - - /obj/item/paper/contract/infernal var/contractType = 0 resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF - var/datum/mind/owner + var/datum/antagonist/devil/devilinfo + var/mob/living/carbon/human/owner icon_state = "evil_contract" /obj/item/paper/contract/infernal/power @@ -103,6 +79,7 @@ /obj/item/paper/contract/infernal/New(atom/loc, mob/living/nTarget, datum/mind/nOwner) ..() + devilinfo = nOwner.has_antag_datum(/datum/antagonist/devil) owner = nOwner target = nTarget update_text() @@ -122,56 +99,56 @@ info = "This shouldn't be seen. Error DEVIL:6" /obj/item/paper/contract/infernal/power/update_text(var/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 [devilinfo.info.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/paper/contract/infernal/wealth/update_text(var/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 [devilinfo.info.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/paper/contract/infernal/prestige/update_text(var/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 [devilinfo.info.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/paper/contract/infernal/magic/update_text(var/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 [devilinfo.info.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/paper/contract/infernal/revive/update_text(var/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 [devilinfo.info.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/paper/contract/infernal/knowledge/update_text(var/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 [devilinfo.info.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/paper/contract/infernal/friendship/update_text(var/signature = "____________", blood = 0) - info = "
Contract for friendship



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 true unconditional friendship. 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 friendship



I, [target] of sound mind, do hereby willingly offer my soul to the infernal hells by way of the infernal agent [devilinfo.info.truename], in exchange for true unconditional friendship. 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/paper/contract/infernal/unwilling/update_text(var/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 [devilinfo.info.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 @@ -276,16 +253,22 @@ /obj/item/paper/contract/infernal/proc/FulfillContract(mob/living/carbon/human/user = target.current, blood = 0) signed = 1 + if(!user.mind) - return 0 - if(user.mind.soulOwner != user.mind && user.mind.soulOwner.devilinfo) //They already sold their soul to someone else? - user.mind.soulOwner.devilinfo.remove_soul(user.mind) //Then they lose their claim. + return FALSE + + var/datum/antagonist/devil/devilinfo = user.mind.has_antag_datum(/datum/antagonist/devil) + if(user.mind.soulOwner != user.mind && devilinfo) //They already sold their soul to someone else? + devilinfo.remove_soul(user.mind) //Then they lose their claim. + user.mind.soulOwner = owner user.mind.damnation_type = contractType - owner.devilinfo.add_soul(user.mind) + 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.") + to_chat(user, span_notice("A profound emptiness washes over you as you lose ownership of your soul.")) + to_chat(user, span_boldnotice("This does NOT make you an antagonist if you were not already.")) + return 1 /obj/item/paper/contract/infernal/power/FulfillContract(mob/living/carbon/human/user = target.current, blood = 0) diff --git a/code/modules/reagents/chemistry/holder.dm b/code/modules/reagents/chemistry/holder.dm index e30257381bf..a1f4b1299a8 100644 --- a/code/modules/reagents/chemistry/holder.dm +++ b/code/modules/reagents/chemistry/holder.dm @@ -633,11 +633,16 @@ /datum/reagents/proc/add_reagent(reagent, amount, list/data=null, reagtemp = T20C, no_react = FALSE) if(!isnum(amount)) return TRUE + update_total() - if(total_volume + amount > maximum_volume) amount = (maximum_volume - total_volume) //Doesnt fit in. Make it disappear. Shouldnt happen. Will happen. + if(total_volume + amount > maximum_volume) amount = (maximum_volume - total_volume) // Doesnt fit in. Make it disappear. Shouldnt happen. Will happen. + if(amount <= 0) return FALSE - chem_temp = clamp((chem_temp * total_volume + reagtemp * amount) / (total_volume + amount), temperature_min, temperature_max) //equalize with new chems + + chem_temp = clamp((chem_temp * total_volume + reagtemp * amount) / (total_volume + amount), temperature_min, temperature_max) // equalize with new chems + if(SEND_SIGNAL(src, COMSIG_EARLY_REAGENT_ADDED, reagent, amount, data, reagtemp, no_react, chem_temp) & COMPONENT_PREVENT_ADD_REAGENT) + return FALSE var/list/cached_reagents = reagent_list for(var/A in cached_reagents) @@ -645,34 +650,43 @@ if(R.id == reagent) R.volume += amount update_total() + if(my_atom) my_atom.on_reagent_change() + R.on_merge(data) + if(!no_react) temperature_react() handle_reactions() + return FALSE var/datum/reagent/D = (ispath(reagent))? new reagent() : GLOB.chemical_reagents_list[reagent] if(D) - var/datum/reagent/R = new D.type() cached_reagents += R R.holder = src R.volume = amount R.on_new(data) + if(data) R.data = data if(isliving(my_atom)) - R.on_mob_add(my_atom) //Must occur befor it could posibly run on_mob_delete + R.on_mob_add(my_atom) // Must occur befor it could posibly run on_mob_delete + update_total() + if(my_atom) my_atom.on_reagent_change() + if(!no_react) temperature_react() handle_reactions() + return FALSE + else warning("[my_atom] attempted to add a reagent called '[reagent]' which doesn't exist. ([usr])") diff --git a/code/modules/reagents/chemistry/reagents.dm b/code/modules/reagents/chemistry/reagents.dm index 96b7e362f07..88a9482c900 100644 --- a/code/modules/reagents/chemistry/reagents.dm +++ b/code/modules/reagents/chemistry/reagents.dm @@ -49,8 +49,8 @@ /datum/reagent/proc/reaction_temperature(exposed_temperature, exposed_volume) //By default we do nothing. return -/datum/reagent/proc/reaction_mob(mob/living/M, method = REAGENT_TOUCH, volume, show_message = TRUE) //Some reagents transfer on touch, others don't; dependent on if they penetrate the skin or not. - if(holder) //for catching rare runtimes +/datum/reagent/proc/reaction_mob(mob/living/M, method = REAGENT_TOUCH, volume, show_message = TRUE) // Some reagents transfer on touch, others don't; dependent on if they penetrate the skin or not. + if(holder) // for catching rare runtimes if(method == REAGENT_TOUCH && penetrates_skin && M.reagents && volume >= 1) M.reagents.add_reagent(id, volume) @@ -58,7 +58,8 @@ var/can_become_addicted = M.reagents.reaction_check(M, src) if(can_become_addicted) if(count_by_type(M.reagents.addiction_list, addict_supertype) > 0) - to_chat(M, "You feel slightly better, but for how long?") //sate_addiction handles this now, but kept this for the feed back. + to_chat(M, span_notice("You feel slightly better, but for how long?")) // sate_addiction handles this now, but kept this for the feed back. + return TRUE /datum/reagent/proc/reaction_obj(obj/O, volume) diff --git a/code/modules/reagents/chemistry/reagents/misc.dm b/code/modules/reagents/chemistry/reagents/misc.dm index 1ed293df123..5d0eda7a673 100644 --- a/code/modules/reagents/chemistry/reagents/misc.dm +++ b/code/modules/reagents/chemistry/reagents/misc.dm @@ -117,11 +117,6 @@ color = "#D0D0D0" // rgb: 208, 208, 208 taste_description = "sub-par bling" -/datum/reagent/silver/reaction_mob(mob/living/M, method=REAGENT_TOUCH, volume) - if(M.has_bane(BANE_SILVER)) - M.reagents.add_reagent("toxin", volume) - . = ..() - /datum/reagent/aluminum name = "Aluminum" id = "aluminum" @@ -169,11 +164,6 @@ return ..() -/datum/reagent/iron/reaction_mob(mob/living/M, method=REAGENT_TOUCH, volume) - if(M.has_bane(BANE_IRON) && holder && holder.chem_temp < 150) //If the target is weak to cold iron, then poison them. - M.reagents.add_reagent("toxin", volume) - ..() - //foam /datum/reagent/fluorosurfactant name = "Fluorosurfactant" diff --git a/code/modules/surgery/organs/vocal_cords.dm b/code/modules/surgery/organs/vocal_cords.dm index e82c771914b..d62ce9e5a6b 100644 --- a/code/modules/surgery/organs/vocal_cords.dm +++ b/code/modules/surgery/organs/vocal_cords.dm @@ -186,12 +186,15 @@ GLOBAL_DATUM_INIT(multispin_words, /regex, regex("like a record baby")) 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 - 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) + var/datum/antagonist/devil/devilinfo = L.mind?.has_antag_datum(/datum/antagonist/devil) + + if(devilinfo && findtext(message, devilinfo?.info.truename)) + var/start = findtext(message, devilinfo.info.truename) + listeners = list(L) // let's be honest you're never going to find two devils with the same name + 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(devilinfo.info.truename), LAZYLEN(message) + 1) + if(findtext(message, L.real_name) == 1) specific_listeners += L //focus on those with the specified name //Cut out the name so it doesn't trigger commands diff --git a/paradise.dme b/paradise.dme index 3c7a9937128..2593ce0b4b0 100644 --- a/paradise.dme +++ b/paradise.dme @@ -57,6 +57,7 @@ #include "code\__DEFINES\crafting.dm" #include "code\__DEFINES\criminal_status.dm" #include "code\__DEFINES\cult.dm" +#include "code\__DEFINES\devil.dm" #include "code\__DEFINES\directional.dm" #include "code\__DEFINES\diseases.dm" #include "code\__DEFINES\dmjit.dm" @@ -587,14 +588,16 @@ #include "code\datums\diseases\viruses\advance\symptoms\youth.dm" #include "code\datums\elements\_element.dm" #include "code\datums\elements\connect_loc.dm" +#include "code\datums\elements\devil_regen.dm" +#include "code\datums\elements\devil_banishment.dm" #include "code\datums\elements\falling_hazard.dm" #include "code\datums\elements\footstep.dm" #include "code\datums\elements\give_turf_traits.dm" #include "code\datums\elements\light_blocking.dm" #include "code\datums\elements\movetype_handler.dm" #include "code\datums\elements\openspace_item_click_handler.dm" -#include "code\datums\elements\reagent_attack.dm" #include "code\datums\elements\ridable.dm" +#include "code\datums\elements\reagent_attack.dm" #include "code\datums\elements\simple_flying.dm" #include "code\datums\elements\squish.dm" #include "code\datums\elements\strippable.dm" @@ -642,6 +645,7 @@ #include "code\datums\spell_cooldown\spell_charges.dm" #include "code\datums\spell_cooldown\spell_cooldown.dm" #include "code\datums\spell_handler\alien_spell_handler.dm" +#include "code\datums\spell_handler\devil_spell_handler.dm" #include "code\datums\spell_handler\morph_spell_handler.dm" #include "code\datums\spell_handler\spell_handler.dm" #include "code\datums\spell_handler\vampire_spell_handler.dm" @@ -818,16 +822,8 @@ #include "code\game\gamemodes\cult\cult_structures.dm" #include "code\game\gamemodes\cult\ritual.dm" #include "code\game\gamemodes\cult\runes.dm" -#include "code\game\gamemodes\devil\devil.dm" -#include "code\game\gamemodes\devil\devil_game_mode.dm" -#include "code\game\gamemodes\devil\devilinfo.dm" #include "code\game\gamemodes\devil\game_mode.dm" #include "code\game\gamemodes\devil\objectives.dm" -#include "code\game\gamemodes\devil\contracts\friend.dm" -#include "code\game\gamemodes\devil\devil_agent\devil_agent.dm" -#include "code\game\gamemodes\devil\imp\imp.dm" -#include "code\game\gamemodes\devil\true_devil\_true_devil.dm" -#include "code\game\gamemodes\devil\true_devil\inventory.dm" #include "code\game\gamemodes\extended\extended.dm" #include "code\game\gamemodes\heist\heist.dm" #include "code\game\gamemodes\malfunction\Malf_Modules.dm" @@ -1661,8 +1657,8 @@ #include "code\modules\antagonists\blob\structures\storage.dm" #include "code\modules\antagonists\borer\borer_action.dm" #include "code\modules\antagonists\borer\borer_datum.dm" -#include "code\modules\antagonists\borer\borer_focus.dm" #include "code\modules\antagonists\borer\borer_rank.dm" +#include "code\modules\antagonists\borer\borer_focus.dm" #include "code\modules\antagonists\borer\borer_reagent.dm" #include "code\modules\antagonists\borer\borer_spell.dm" #include "code\modules\antagonists\changeling\changeling_datum.dm" @@ -1691,6 +1687,21 @@ #include "code\modules\antagonists\changeling\powers\swap_form.dm" #include "code\modules\antagonists\changeling\powers\tiny_prick.dm" #include "code\modules\antagonists\changeling\powers\transform.dm" +#include "code\modules\antagonists\devil\devil.dm" +#include "code\modules\antagonists\devil\sintouched.dm" +#include "code\modules\antagonists\devil\devil_banish.dm" +#include "code\modules\antagonists\devil\devil_bane.dm" +#include "code\modules\antagonists\devil\devil_ban.dm" +#include "code\modules\antagonists\devil\devil_info.dm" +#include "code\modules\antagonists\devil\devil_pawn.dm" +#include "code\modules\antagonists\devil\imp\imp.dm" +#include "code\modules\antagonists\devil\devil_obligation.dm" +#include "code\modules\antagonists\devil\devil_rank.dm" +#include "code\modules\antagonists\devil\devil_ritual.dm" +#include "code\modules\antagonists\devil\devil_outfit.dm" +#include "code\modules\antagonists\devil\helper_procs.dm" +#include "code\modules\antagonists\devil\contracts\friend.dm" +#include "code\modules\antagonists\devil\true_devil\_true_devil.dm" #include "code\modules\antagonists\malf_ai\malf_ai_datum.dm" #include "code\modules\antagonists\space_dragon\action.dm" #include "code\modules\antagonists\space_dragon\carp.dm"