Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lich/Necromancer evil update #1137

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
6 changes: 5 additions & 1 deletion code/__DEFINES/role_preferences.dm
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#define ROLE_DELF "Dark Elf"
#define ROLE_PREBEL "Peasant Rebel"
#define ROLE_ZIZOIDCULTIST "Zizoid Cultist"
#define ROLE_LICH "Lich"

#define ROLE_SYNDICATE "Syndicate"
#define ROLE_TRAITOR "Traitor"
Expand Down Expand Up @@ -45,6 +46,8 @@
#define ROLE_LAVALAND "Lavaland"
#define ROLE_INTERNAL_AFFAIRS "Internal Affairs Agent"

#define ROLE_NECRO_SKELETON "Necromancer Skeleton"

//Missing assignment means it's not a gamemode specific role, IT'S NOT A BUG OR ERROR.
//The gamemode specific ones are just so the gamemodes can query whether a player is old enough
//(in game days played) to play that role
Expand All @@ -69,7 +72,8 @@ GLOBAL_LIST_INIT(special_roles_rogue, list(
ROLE_BANDIT = /datum/antagonist/bandit,
ROLE_ZIZOIDCULTIST = /datum/antagonist/zizocultist,
// ROLE_WEREWOLF = /datum/antagonist/werewolf,
ROLE_NBEAST = /datum/antagonist/vampirelord
ROLE_NBEAST = /datum/antagonist/vampirelord,
ROLE_LICH = /datum/antagonist/lich
))

//Job defines for what happens when you fail to qualify for any job during job selection
Expand Down
6 changes: 5 additions & 1 deletion code/__DEFINES/traits.dm
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#define TRAIT_RETARD_ANATOMY "Inhumen Anatomy" //can't wear hats and shoes
#define TRAIT_NASTY_EATER "Inhumen Digestion" //can eat rotten food, organs, poison berries, and drink murky water
#define TRAIT_NOFALLDAMAGE1 "Minor fall damage immunity"
#define TRAIT_DEATHSIGHT "Veiled Whispers" // Is notified when a player character dies, but not told exactly where or how.
#define TRAIT_ROT_EATER "Blessing of Pestra" //can eat rotten food
#define TRAIT_ORGAN_EATER "Blessing of Graggar"
#define TRAIT_SOUL_EXAMINE "Blessing of Necra" //can check bodies to see if they have departed
Expand Down Expand Up @@ -63,6 +64,7 @@
#define TRAIT_IWASREVIVED "iwasrevived" //prevents PQ gain from reviving the same person twice
#define TRAIT_IWASUNZOMBIFIED "iwasunzombified" //prevents PQ gain from curing a zombie twice
#define TRAIT_ZIZOID_HUNTED "zizoidhunted" // Used to signal character has been marked by death by the Zizoid cult
#define TRAIT_CABAL "Of the Cabal" //Zizo cultists recognize each other too

// JOB RELATED TRAITS

Expand Down Expand Up @@ -114,7 +116,9 @@ GLOBAL_LIST_INIT(roguetraits, list(
TRAIT_INTRAINING = "I'm going to be a knight someday! I can use training dummies more effectively than others.",
TRAIT_MALUMFIRE = "My hands are blessed by Malum to forge items of superb quality.",
TRAIT_MOB_FIRE_IMMUNE = span_info("I am not easily burned by flames."),
TRAIT_KAIZOKU = "Whether by birth or by learning, I've inherited the Islander ways instead of Imperial culture.",
TRAIT_DEATHSIGHT = span_info("I can feel when someone nearby draws the Undermaiden's attention."),
TRAIT_CABAL = span_info("In secret, I have studied the ways of Zizo's ascension, and know of others of the Cabal."),
TRAIT_KAIZOKU = "Whether by birth or by learning, I've inherited the Islander ways instead of Imperial culture."
))

// trait accessor defines
Expand Down
4 changes: 3 additions & 1 deletion code/_globalvars/lists/poll_ignore.dm
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#define POLL_IGNORE_SPLITPERSONALITY "split_personality"
#define POLL_IGNORE_CONTRACTOR_SUPPORT "contractor_support"
#define POLL_IGNORE_ACADEMY_WIZARD "academy_wizard"
#define POLL_IGNORE_NECROMANCER_SKELETON "necromancer_skeleton"


GLOBAL_LIST_INIT(poll_ignore_desc, list(
Expand All @@ -42,7 +43,8 @@ GLOBAL_LIST_INIT(poll_ignore_desc, list(
POLL_IGNORE_IMAGINARYFRIEND = "Imaginary Friend",
POLL_IGNORE_SPLITPERSONALITY = "Split Personality",
POLL_IGNORE_CONTRACTOR_SUPPORT = "Contractor Support Unit",
POLL_IGNORE_ACADEMY_WIZARD = "Academy Wizard Defender"
POLL_IGNORE_ACADEMY_WIZARD = "Academy Wizard Defender",
POLL_IGNORE_NECROMANCER_SKELETON = "Necromancer Skeleton"
))
GLOBAL_LIST_INIT(poll_ignore, init_poll_ignore())

Expand Down
2 changes: 2 additions & 0 deletions code/game/gamemodes/game_mode.dm
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,15 @@
var/setup_error //What stopepd setting up the mode.

var/list/datum/mind/villains = list() //Murders Runtimes via shoving this into parent
var/list/datum/mind/liches = list()
var/list/datum/mind/vampires = list()
var/list/datum/mind/deathknights = list() // Ditto as villains mind list.
var/list/datum/mind/werewolves = list()
var/list/datum/mind/bandits = list()
var/list/datum/mind/cultists = list()

var/list/datum/mind/pre_villains = list()
var/list/datum/mind/pre_liches = list()
var/list/datum/mind/pre_werewolves = list()
var/list/datum/mind/pre_vampires = list()
var/list/datum/mind/pre_bandits = list()
Expand Down
29 changes: 28 additions & 1 deletion code/game/gamemodes/roguetown/roguetown.dm
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// This mode will become the main basis for the typical roguetown round. Based off of chaos mode.
GLOBAL_LIST_INIT(roguegamemodes, list("Rebellion", "Vampire Lord", "Extended", "Bandits", "CANCEL")) // This is mainly used for forcemgamemodes
GLOBAL_LIST_INIT(roguegamemodes, list("Rebellion", "Vampire Lord", "Extended", "Bandits", "Lich", "CANCEL")) // This is mainly used for forcemgamemodes

/datum/game_mode/chaosmode
name = "roguemode"
Expand Down Expand Up @@ -169,6 +169,26 @@ GLOBAL_LIST_INIT(roguegamemodes, list("Rebellion", "Vampire Lord", "Extended", "
else
return TRUE

/datum/game_mode/chaosmode/proc/pick_lich()
restricted_jobs = list("King", "Queen", "Merchant", "Priest")
antag_candidates = get_players_for_role(ROLE_LICH)
var/datum/mind/lichman = pick_n_take(antag_candidates)
if(lichman)
var/blockme = FALSE
if(!(lichman in allantags))
blockme = TRUE
if(blockme)
return
allantags -= lichman
pre_liches += lichman
lichman.special_role = ROLE_LICH
lichman.restricted_roles = restricted_jobs.Copy()
testing("[key_name(lichman)] has been selected as the [lichman.special_role]")
log_game("[key_name(lichman)] has been selected as the [lichman.special_role]")
for(var/antag in pre_liches)
GLOB.pre_setup_antags |= antag
restricted_jobs = list()

/datum/game_mode/chaosmode/proc/pick_bandits()
//BANDITS
banditgoal = rand(200,400)
Expand Down Expand Up @@ -415,6 +435,13 @@ GLOBAL_LIST_INIT(roguegamemodes, list("Rebellion", "Vampire Lord", "Extended", "
GLOB.pre_setup_antags -= cultist
cultists += cultist

///////////////// LICH
for(var/datum/mind/lichman in pre_liches)
var/datum/antagonist/new_antag = new /datum/antagonist/lich()
addtimer(CALLBACK(lichman, TYPE_PROC_REF(/datum/mind, add_antag_datum), new_antag), rand(10,100))
GLOB.pre_setup_antags -= lichman
liches += lichman

///////////////// WWOLF
for(var/datum/mind/werewolf in pre_werewolves)
var/datum/antagonist/new_antag = new /datum/antagonist/werewolf()
Expand Down
3 changes: 2 additions & 1 deletion code/modules/admin/sql_ban_system.dm
Original file line number Diff line number Diff line change
Expand Up @@ -254,9 +254,10 @@
var/list/long_job_lists = list("Peasants" = GLOB.peasant_positions,
"Towners" = GLOB.towner_positions,
"Apprentices" = GLOB.apprentices_positions,
"Ghost and Other Roles" = list(ROLE_NECRO_SKELETON),
"Antagonist Positions" = list(ROLE_VILLAIN, ROLE_WEREWOLF,
ROLE_VAMPIRE, ROLE_NBEAST, ROLE_BANDIT,
ROLE_DELF, ROLE_PREBEL, ROLE_ZIZOIDCULTIST))
ROLE_DELF, ROLE_PREBEL, ROLE_ZIZOIDCULTIST, ROLE_LICH))
for(var/department in long_job_lists)
output += "<div class='column'><label class='rolegroup long [ckey(department)]'><input type='checkbox' name='[department]' class='hidden' [usr.client.prefs.tgui_fancy ? " onClick='toggle_checkboxes(this, \"_com\")'" : ""]>[department]</label><div class='content'>"
break_counter = 0
Expand Down
192 changes: 192 additions & 0 deletions code/modules/antagonists/roguetown/villain/lich.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
/datum/antagonist/lich
name = "Lich"
roundend_category = "Lich"
antagpanel_category = "Lich"
job_rank = ROLE_LICH
confess_lines = list(
"I WILL LIVE ETERNAL!",
"I AM BEHIND SEVEN PHYLACTERIES!",
"YOU CANNOT KILL ME!",
)
var/list/phylacteries = list()
var/out_of_lives = FALSE

/mob/living/carbon/human
/// List of minions that this mob has control over. Used for things like the Lich's "Command Undead" spell.
var/list/mob/minions = list()

/datum/antagonist/lich/on_gain()
var/datum/game_mode/C = SSticker.mode
C.liches |= owner
. = ..()
owner.special_role = name
skele_look()
equip_lich()
greet()
return ..()

/datum/antagonist/lich/greet()
to_chat(owner.current, span_userdanger("The secret of immortality is mine, but this is not enough. A thousand lichdoms have risen and fallen over the eras. Mine will be the one to last."))
owner.announce_objectives()
..()

/datum/antagonist/lich/proc/skele_look()
var/mob/living/carbon/human/L = owner.current
L.hairstyle = "Bald"
L.facial_hairstyle = "Shaved"
L.update_body()
L.update_hair()
L.update_body_parts(redraw = TRUE)

/datum/antagonist/lich/proc/equip_lich()
owner.unknow_all_people()
for(var/datum/mind/MF in get_minds())
owner.become_unknown_to(MF)
var/mob/living/carbon/human/L = owner.current
ADD_TRAIT(L, TRAIT_NOROGSTAM, "[type]")
ADD_TRAIT(L, TRAIT_NOHUNGER, "[type]")
ADD_TRAIT(L, TRAIT_NOBREATH, "[type]")
ADD_TRAIT(L, TRAIT_NOPAIN, "[type]")
ADD_TRAIT(L, TRAIT_TOXIMMUNE, "[type]")
ADD_TRAIT(L, TRAIT_STEELHEARTED, "[type]")
ADD_TRAIT(L, TRAIT_NOSLEEP, "[type]")
ADD_TRAIT(L, TRAIT_VAMPMANSION, "[type]")
ADD_TRAIT(L, TRAIT_NOMOOD, "[type]")
ADD_TRAIT(L, TRAIT_NOLIMBDISABLE, "[type]")
ADD_TRAIT(L, TRAIT_SHOCKIMMUNE, "[type]")
ADD_TRAIT(L, TRAIT_LIMBATTACHMENT, "[type]")
ADD_TRAIT(L, TRAIT_SEEPRICES, "[type]")
ADD_TRAIT(L, TRAIT_CRITICAL_RESISTANCE, "[type]")
ADD_TRAIT(L, TRAIT_HEAVYARMOR, "[type]")
ADD_TRAIT(L, TRAIT_CABAL, "[type]")
ADD_TRAIT(L, TRAIT_DEATHSIGHT, "[type]")
L.cmode_music = 'sound/music/combat_cult.ogg'
L.faction = list("undead")
if(L.charflaw)
QDEL_NULL(L.charflaw)
L.mob_biotypes |= MOB_UNDEAD
var/obj/item/organ/eyes/eyes = L.getorganslot(ORGAN_SLOT_EYES)
if(eyes)
eyes.Remove(L,1)
QDEL_NULL(eyes)
eyes = new /obj/item/organ/eyes/night_vision/zombie
eyes.Insert(L)
for(var/obj/item/bodypart/B in L.bodyparts)
B.skeletonize(FALSE)
L.equipOutfit(/datum/outfit/job/roguetown/lich)
L.set_patron(/datum/patron/inhumen/zizo)

/datum/outfit/job/roguetown/lich/pre_equip(mob/living/carbon/human/H)
..()
head = /obj/item/clothing/head/roguetown/helmet/skullcap/cult
pants = /obj/item/clothing/under/roguetown/chainlegs
shoes = /obj/item/clothing/shoes/roguetown/shortboots
neck = /obj/item/clothing/neck/roguetown/chaincoif
armor = /obj/item/clothing/suit/roguetown/shirt/robe/necromancer
shirt = /obj/item/clothing/suit/roguetown/shirt/tunic/ucolored
wrists = /obj/item/clothing/wrists/roguetown/bracers
gloves = /obj/item/clothing/gloves/roguetown/chain
belt = /obj/item/storage/belt/rogue/leather/black
backl = /obj/item/storage/backpack/rogue/satchel
beltr = /obj/item/reagent_containers/glass/bottle/rogue/manapot
beltl = /obj/item/rogueweapon/knife/dagger/steel
r_hand = /obj/item/rogueweapon/polearm/woodstaff

H.mind.adjust_skillrank(/datum/skill/misc/reading, 6, TRUE)
H.mind?.adjust_skillrank(/datum/skill/craft/alchemy, 5, TRUE)
H.mind.adjust_skillrank(/datum/skill/magic/arcane, 5, TRUE)
H.mind.adjust_skillrank(/datum/skill/misc/riding, 4, TRUE)
H.mind.adjust_skillrank(/datum/skill/combat/polearms, 1, TRUE)
H.mind.adjust_skillrank(/datum/skill/combat/wrestling, 3, TRUE)
H.mind.adjust_skillrank(/datum/skill/combat/unarmed, 1, TRUE)
H.mind.adjust_skillrank(/datum/skill/misc/swimming, 1, TRUE)
H.mind.adjust_skillrank(/datum/skill/misc/climbing, 1, TRUE)
H.mind.adjust_skillrank(/datum/skill/misc/athletics, 1, TRUE)
H.mind.adjust_skillrank(/datum/skill/combat/swords, 2, TRUE)
H.mind.adjust_skillrank(/datum/skill/combat/knives, 5, TRUE)
H.mind.adjust_skillrank(/datum/skill/craft/crafting, 1, TRUE)
//H.mind.adjust_skillrank(/datum/skill/misc/medicine, 4, TRUE)

H.change_stat("strength", -1)
H.change_stat("intelligence", 5)
H.change_stat("constitution", 5)
H.change_stat("endurance", -1)
H.change_stat("speed", -1)

H.mind.AddSpell(new /obj/effect/proc_holder/spell/self/command_undead)
H.mind.AddSpell(new /obj/effect/proc_holder/spell/invoked/strengthen_undead)
H.mind.AddSpell(new /obj/effect/proc_holder/spell/invoked/raise_undead)
H.mind.AddSpell(new /obj/effect/proc_holder/spell/invoked/projectile/fireball)
H.mind.AddSpell(new /obj/effect/proc_holder/spell/invoked/projectile/bloodlightning)
H.mind.AddSpell(new /obj/effect/proc_holder/spell/invoked/eyebite)
H.mind.AddSpell(new /obj/effect/proc_holder/spell/invoked/projectile/sickness)
H.mind.AddSpell(new /obj/effect/proc_holder/spell/invoked/projectile/fetch)
H.ambushable = FALSE

addtimer(CALLBACK(H, TYPE_PROC_REF(/mob/living/carbon/human, choose_name_popup), "LICH"), 5 SECONDS)

/datum/outfit/job/roguetown/lich/post_equip(mob/living/carbon/human/H)
..()
var/datum/antagonist/lich/lichman = H.mind.has_antag_datum(/datum/antagonist/lich)
for(var/i in 1 to 3)
var/obj/item/phylactery/new_phylactery = new(H.loc)
lichman.phylacteries += new_phylactery
new_phylactery.possessor = lichman
H.equip_to_slot_or_del(new_phylactery,SLOT_IN_BACKPACK, TRUE)

/datum/antagonist/lich/proc/consume_phylactery(timer = 10 SECONDS)
for(var/obj/item/phylactery/phyl in phylacteries)
phyl.be_consumed(timer)
phylacteries -= phyl
return TRUE

/datum/antagonist/lich/proc/rise_anew()
var/mob/living/carbon/human/bigbad = owner.current
bigbad.revive(TRUE, TRUE)

for(var/obj/item/bodypart/B in bigbad.bodyparts)
B.skeletonize(FALSE)

bigbad.faction = list("undead")
if(bigbad.charflaw)
QDEL_NULL(bigbad.charflaw)
bigbad.mob_biotypes |= MOB_UNDEAD
var/obj/item/organ/eyes/eyes = bigbad.getorganslot(ORGAN_SLOT_EYES)
if(eyes)
eyes.Remove(bigbad,1)
QDEL_NULL(eyes)
eyes = new /obj/item/organ/eyes/night_vision/zombie
eyes.Insert(bigbad)


/obj/item/phylactery
name = "phylactery"
desc = "Looks like it is filled with some intense power."
icon = 'icons/obj/wizard.dmi'
icon_state = "soulstone"
item_state = "electronic"
lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi'
righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
layer = HIGH_OBJ_LAYER
w_class = WEIGHT_CLASS_TINY
light_color = "#003300"
var/datum/antagonist/lich/possessor

var/resurrections = 0
var/datum/mind/mind
var/respawn_time = 1800

var/static/active_phylacteries = 0

/obj/item/phylactery/Initialize(mapload, datum/mind/newmind)
. = ..()
filters += filter(type="drop_shadow", x=0, y=0, size=1, offset=2, color=rgb(rand(1,255),rand(1,255),rand(1,255)))

/obj/item/phylactery/proc/be_consumed(timer)
var/offset = prob(50) ? -2 : 2
animate(src, pixel_x = pixel_x + offset, time = 0.2, loop = -1) //start shaking
visible_message(span_warning("[src] begins to glow and shake violently!"))
spawn(timer)
possessor.owner.current.forceMove(get_turf(src))
possessor.rise_anew()
qdel(src)
5 changes: 0 additions & 5 deletions code/modules/antagonists/wizard/equipment/spellbook.dm
Original file line number Diff line number Diff line change
Expand Up @@ -197,11 +197,6 @@
category = "Assistance"
cost = 1

/datum/spellbook_entry/lichdom
name = "Bind Soul"
spell_type = /obj/effect/proc_holder/spell/targeted/lichdom
category = "Defensive"

/datum/spellbook_entry/teslablast
name = "Tesla Blast"
spell_type = /obj/effect/proc_holder/spell/targeted/tesla
Expand Down
12 changes: 12 additions & 0 deletions code/modules/mob/living/carbon/human/death.dm
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,18 @@
dust(just_ash=TRUE,drop_items=TRUE)
return

var/datum/antagonist/lich/L = mind.has_antag_datum(/datum/antagonist/lich)
if (L && !L.out_of_lives)
if(L.consume_phylactery())
visible_message(span_warning("[src]'s body begins to shake violently, as eldritch forces begin to whisk them away!"))
to_chat(src, span_userdanger("Death is not the end for me. I begin to rise again."))
playsound(src, 'sound/magic/antimagic.ogg', 100, FALSE)
else
to_chat(src, span_userdanger("No, NO! This cannot be!"))
L.out_of_lives = TRUE
gib()
return

if(!gibbed)
if(!is_in_roguetown(src))
zombie_check()
Expand Down
Loading
Loading