Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions code/__DEFINES/spell_defines.dm
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,13 @@
#define GLOW_INTENSITY_HIGH 3 // Large AOE
#define GLOW_INTENSITY_VERY_HIGH 4 // Greater Fireball or Massive AOE / T4 spells

//Gods - Ascendant
#define GLOW_COLOR_GRAGGAR "#19345E" //Graggar Dark Blue
#define GLOW_COLOR_ZIZO "#b76bff" //Graggar Dark Purple
#define GLOW_COLOR_BAOTHA "#ff008c" //Baotha Violent Rose
#define GLOW_COLOR_MATTHIOS "#ffd900" //Matthios Golden


// Constants for enchantment effects (used by fit_clothing, gems, etc.)
#define FORCE_BLADE_ENCHANT 2
#define DURABILITY_ENCHANT 3
Expand Down
2 changes: 1 addition & 1 deletion code/__DEFINES/traits.dm
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,7 @@ GLOBAL_LIST_INIT(roguetraits, list(
TRAIT_LIMPDICK = span_crit("My soldier refuses to rise to attention! Curses!"),
TRAIT_SEEDKNOW = span_info("I know which seeds grow which crops."),
TRAIT_PERFECT_TRACKER = span_info("I am a master at pursuing those I hunt. I can discern every last detail within a spotted track, and any attempts to hide said-tracks will fail to deceive me."),//Hearthstone port.
TRAIT_ZIZOSIGHT = span_info("Zizo blesses my eyes to be unburdened by the night."), //Hearthstone change.
TRAIT_ZIZOSIGHT = span_info("Zizo blesses my eyes to be unburdened by the night. I can also somewhat judge if a corpse can be reanimated or not."), //Hearthstone change.
TRAIT_CIVILIZEDBARBARIAN = span_info("My rigorous training in the martial arts has turned me into a living weapon. No limb is out of reach for my fists and feet, and my unarmed strikes are now stronger (+4 Unarmed Damage). My parrying with bracers, knuckles, or bandages is significantly more effective."),
TRAIT_COMICSANS = span_sans("I am cursed with a odd voice."),
TRAIT_SQUIRE_REPAIR = span_info("Trained at my Master's side, I can restore any kind of gears with time and polish them until they gleam like new."),
Expand Down
124 changes: 124 additions & 0 deletions code/controllers/subsystem/rogue/spawned_mobs.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
#define SPAWNED_MOBS_DEFAULT_LIFESPAN 10 MINUTES

GLOBAL_LIST_INIT(spawnmob_lifespan, list(
"Necromancer" = 15 MINUTES,
"Lich" = 60 MINUTES
))

GLOBAL_LIST_INIT(spawnmob_lifespan_override, list())

SUBSYSTEM_DEF(spawned_mobs)
name = "Spawned Mob Cull"
wait = 30 SECONDS
flags = SS_BACKGROUND | SS_NO_INIT
runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME
var/list/tracked_mobs = list()
var/list/currentrun = list()

/datum/controller/subsystem/spawned_mobs/stat_entry()
..("T:[length(tracked_mobs)]")

/datum/controller/subsystem/spawned_mobs/fire(resumed = FALSE)
if(!resumed)
currentrun = list()
for(var/datum/weakref/mobref as anything in tracked_mobs)
currentrun += mobref

while(currentrun.len)
var/datum/weakref/mobref = currentrun[currentrun.len]
currentrun.len--

var/expires = tracked_mobs[mobref]
if(!expires)
if(MC_TICK_CHECK)
return
continue

var/mob/living/target = mobref.resolve()
if(!target || QDELETED(target) || target.stat == DEAD || target.client)
unregister_mob(mobref, target)
if(MC_TICK_CHECK)
return
continue

if(expires <= world.time)
unregister_mob(mobref, target)
target.visible_message(span_warning("[target] unravels as the power binding it expires!"))
target.death(FALSE)

if(MC_TICK_CHECK)
return

/datum/controller/subsystem/spawned_mobs/proc/get_role_lifespan(role)
if(role && GLOB.spawnmob_lifespan[role])
return GLOB.spawnmob_lifespan[role]

/datum/controller/subsystem/spawned_mobs/proc/get_type_lifespan(mob/living/target)
var/current_type = target?.type
while(current_type)
if(GLOB.spawnmob_lifespan_override[current_type])
return GLOB.spawnmob_lifespan_override[current_type]
current_type = type2parent(current_type)

/datum/controller/subsystem/spawned_mobs/proc/get_lifespan(mob/living/target, mob/living/summoner, lifespan)
if(isnum(lifespan))
return lifespan

var/type_lifespan = get_type_lifespan(target)
if(type_lifespan)
return type_lifespan

var/role_lifespan = get_role_lifespan(summoner?.advjob)
if(role_lifespan)
return role_lifespan

role_lifespan = get_role_lifespan(summoner?.job)
if(role_lifespan)
return role_lifespan

role_lifespan = get_role_lifespan(summoner?.mind?.assigned_role)
if(role_lifespan)
return role_lifespan

return SPAWNED_MOBS_DEFAULT_LIFESPAN

/datum/controller/subsystem/spawned_mobs/proc/register_mob(mob/living/target, mob/living/summoner, lifespan)
if(!target || target.client)
return FALSE

var/timer = get_lifespan(target, summoner, lifespan)
if(!isnum(timer) || timer <= 0 || timer == INFINITY)
return FALSE

var/datum/weakref/mobref = WEAKREF(target)
if(!tracked_mobs[mobref])
RegisterSignal(target, COMSIG_PARENT_EXAMINE, PROC_REF(on_mob_examine))
tracked_mobs[mobref] = world.time + timer
return TRUE

/datum/controller/subsystem/spawned_mobs/proc/unregister_mob(datum/weakref/mobref, mob/living/target)
tracked_mobs -= mobref
if(target)
UnregisterSignal(target, COMSIG_PARENT_EXAMINE)

/datum/controller/subsystem/spawned_mobs/proc/get_remaining_lifespan(mob/living/target)
if(!target || target.client || target.stat == DEAD)
return 0

var/expires = tracked_mobs[WEAKREF(target)]
if(!expires)
return 0

return max(0, expires - world.time)

/datum/controller/subsystem/spawned_mobs/proc/on_mob_examine(mob/living/source, mob/user, list/examine_list)
var/remaining_lifespan = get_remaining_lifespan(source)
if(!remaining_lifespan)
return

examine_list += span_notice("A fading force binds [source] together. It will last for [DisplayTimeText(remaining_lifespan)].")

/proc/apply_mob_lifespan(mob/living/target, mob/living/summoner, lifespan)
return SSspawned_mobs.register_mob(target, summoner, lifespan)

#undef SPAWNED_MOBS_DEFAULT_LIFESPAN
2 changes: 2 additions & 0 deletions code/datums/actions/action_cooldown.dm
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@
var/active_icon_state
/// Timer for retriggering the spell
var/retrigger_timer
/// This will make it so spells that are of the "same type" cannot be obtained. This is mostly for "Lesser" variants to not stack with the normal ones.
var/exclusive_group = null

/datum/action/cooldown/New(Target)
. = ..()
Expand Down
4 changes: 4 additions & 0 deletions code/datums/components/summoning.dm
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
var/spawn_text
var/spawn_sound
var/list/faction
var/spawn_lifespan

var/last_spawned_time = 0
var/list/spawned_mobs = list()
Expand All @@ -21,6 +22,7 @@
src.spawn_text = spawn_text
src.spawn_sound = spawn_sound
src.faction = faction
src.spawn_lifespan = spawn_lifespan

/datum/component/summoning/RegisterWithParent()
if(ismachinery(parent) || isstructure(parent) || isgun(parent)) // turrets, etc
Expand Down Expand Up @@ -60,6 +62,8 @@
spawned_mobs += L
if(faction != null)
L.faction = faction
if(spawn_lifespan)
apply_mob_lifespan(L, summoner, spawn_lifespan)
RegisterSignal(L, COMSIG_MOB_DEATH, PROC_REF(on_spawned_death)) // so we can remove them from the list, etc (for mobs with corpses)
playsound(spawn_location,spawn_sound, 50, TRUE)
spawn_location.visible_message("<span class='danger'>[L] [spawn_text].</span>")
Expand Down
130 changes: 112 additions & 18 deletions code/datums/gods/patrons/inhumen/resurrect_inhumen.dm
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
alt_required_items = list()
required_items = list()
sound = 'sound/magic/slimesquish.ogg'
chargedloop = /datum/looping_sound/invokelightning
chargedloop = /datum/looping_sound/invokeascendant
harms_undead = FALSE
recharge_time = 2 MINUTES //Anastasis Equivalent
overlay_icon = 'icons/mob/actions/matthiosmiracles.dmi'
Expand All @@ -26,7 +26,7 @@
alt_required_items = list(/obj/item/organ/heart = 1)
required_items = list(/obj/item/organ/heart = 1)
sound = 'sound/magic/slimesquish.ogg'
chargedloop = /datum/looping_sound/invokelightning
chargedloop = /datum/looping_sound/invokeascendant
harms_undead = FALSE
overlay_icon = 'icons/mob/actions/graggarmiracles.dmi'
overlay_state = "revival"
Expand All @@ -41,7 +41,7 @@
alt_required_items = list(/obj/item/natural/thorn = 3)
required_items = list(/obj/item/natural/thorn = 7)
sound = 'sound/magic/slimesquish.ogg'
chargedloop = /datum/looping_sound/invokelightning
chargedloop = /datum/looping_sound/invokeascendant
harms_undead = FALSE
overlay_icon = 'icons/mob/actions/baothamiracles.dmi'
overlay_state = "revival"
Expand All @@ -51,19 +51,19 @@
req_items = list() // temp. baothans dont have a holy symbol. apparently one is being commed so this is just the stopgap.

/obj/effect/proc_holder/spell/invoked/resurrect/zizo
name = "Zizoid Rebirth"
desc = "Revive a fallen ally by siphoning their potential. You gain their strength, whilst they gain a second chance.\
name = "Hollow Rebirth"
desc = "Revive a fallen subject while siphoning their potential and destroying some of their Lux as a toll. You gain their strength, whilst they gain a second chance.\
If they die, you will lose their stolen strength."
sound = 'sound/magic/slimesquish.ogg'
chargedloop = /datum/looping_sound/invokelightning
chargedloop = /datum/looping_sound/invokeascendant
harms_undead = FALSE
overlay_icon = 'icons/mob/actions/zizomiracles.dmi'
overlay_state = "revival"
action_icon_state = "revival"
recharge_time = 5 MINUTES // halved compared to others
action_icon = 'icons/mob/actions/zizomiracles.dmi'
required_items = list(/obj/item/heart_blood_vial/filled = 3)
alt_required_items = list(/obj/item/heart_blood_vial/filled = 1)
// We apply zizo's debuff differently
// We apply zizo's revival differently from this point onward
zizo = TRUE
debuff_type = null
required_structure = /obj/structure/fluff/psycross/zizocross

Expand Down Expand Up @@ -483,19 +483,104 @@
// check if parent returns TRUE
if(.)
var/mob/living/carbon/human/target = targets[1]

user.apply_status_effect(/datum/status_effect/buff/zizo_tithe, tithe_distribution, target)
target.apply_status_effect(/datum/status_effect/debuff/zizo_drain, tithe_distribution)

to_chat(user, span_nicegreen("The victim's essence flows into you as they gasp for air."))
to_chat(target, span_userdanger("You are alive, but Zizo has taken his tithe from your soul."))
var/found_zizo_cross = FALSE

for(var/atom/A in oview(1, target))
if(istype(A, /obj/structure/fluff/psycross/zizocross))
found_zizo_cross = TRUE
break

if(istype(A, /turf))
var/turf/T = A
for(var/obj/O in T.contents)
if(istype(O, /obj/structure/fluff/psycross/zizocross))
found_zizo_cross = TRUE
break

if(found_zizo_cross)
break

// A proper Zizo cross stabilizes the rite and prevents undeath complications
if(found_zizo_cross)
to_chat(target, span_warning("Your stolen Lux writhes violently, but the unholy cross steadies your Lux before undeath can fully take hold."))
else
if(!target.has_status_effect(/datum/status_effect/debuff/zizo_temp_undeath))
target.apply_status_effect(/datum/status_effect/debuff/zizo_temp_undeath)
to_chat(target, span_userdanger("You feel your rekindled Lux torn from within, leaving you hollowed as undeath threatens to gnaw at your fading soul."))
else
playsound(user.loc, 'sound/misc/smelter_sound.ogg', 50, FALSE)
to_chat(target, span_userdanger("Your fading Lux collapses inward far too soon. Flesh sloughs from bone as undeath tightens its grip upon you."))
target.apply_status_effect(/datum/status_effect/debuff/devitalised)

to_chat(user, span_nicegreen("You wrench the victim's rekindled Lux into yourself, leaving them hollowed and starving for life."))

/atom/movable/screen/alert/status_effect/debuff/zizo_temp_undeath
name = "Embrace of Zizo"
desc = "You feel your very essence struggling against the hold of Undeath... Your mind is beseethed with dark, evil thoughts, and all you feel is hunger..."

/datum/status_effect/debuff/zizo_temp_undeath
id = "zizo_temp_undeath"
duration = 15 MINUTES
tick_interval = 1 MINUTES // every minute, starve, if you manage to fill your belly, duration is reduced by 5 minutes
alert_type = /atom/movable/screen/alert/status_effect/debuff/zizo_temp_undeath

/datum/status_effect/debuff/zizo_temp_undeath/on_creation()
. = ..()
to_chat(owner, span_warning("Hungry... Hungry... HUNGRY. I AM STARVING. I NEED TO EAT. I NEED TO EAT!"))
ADD_TRAIT(owner, TRAIT_ROTMAN, "zizo_temp_undeath")
ADD_TRAIT(owner, TRAIT_NASTY_EATER, "zizo_temp_undeath")
ADD_TRAIT(owner, TRAIT_STRONGBITE, "zizo_temp_undeath")
to_chat(owner, span_necrosis("My limbs... I am rotten under my skin. Anything can remove them-- Anything can reattach them...?"))
ADD_TRAIT(owner, TRAIT_EASYDISMEMBER, "zizo_temp_undeath")
ADD_TRAIT(owner, TRAIT_LIMBATTACHMENT, "zizo_temp_undeath")
ADD_TRAIT(owner, TRAIT_SILVER_WEAK, "zizo_temp_undeath")
ADD_TRAIT(owner, TRAIT_DEATHLESS, "zizo_temp_undeath")
ADD_TRAIT(owner, TRAIT_ZOMBIE_IMMUNE, "zizo_temp_undeath")
to_chat(owner, span_boldred("THIS WORLD IS WRONG. EVERYTHING IS WRONG. WE LIVE IN A CORPSE. THE DECAYING CORPSE OF A DEAD GOD!"))
ADD_TRAIT(owner, TRAIT_PSYCHOSIS, "zizo_temp_undeath")
ADD_TRAIT(owner, TRAIT_NOMOOD, "zizo_temp_undeath")

/datum/status_effect/debuff/zizo_temp_undeath/tick()
. = ..()
var/mob/living/carbon/human/H = owner
if(!istype(H))
return
if(H.stat == DEAD)
return
var/very_hongry = pick("HUNGRY...", "Hungry...", "Hungry! Hungry!", "I NEED TO EAT!", "I'm STARVING!!", "Need to eat... anything... I'll eat anything. I'm so hungry.")
if(H.nutrition >= NUTRITION_LEVEL_FED)
duration -= 5 MINUTES
to_chat(owner, span_warning("You feel some of your Lux react to being full... your reserves drain rapidly and your stomach quickly empties."))
to_chat(owner, span_green("I am recovering faster..."))

to_chat(owner, span_warning(very_hongry))
H.nutrition = 0

/datum/status_effect/debuff/zizo_temp_undeath/on_remove()
. = ..()
to_chat(owner, span_boldgreen("...You feel the corroded part of your Lux finally recover, giving you some well-deserved clarity back. What the hell was that?"))
REMOVE_TRAIT(owner, TRAIT_ROTMAN, "zizo_temp_undeath")
REMOVE_TRAIT(owner, TRAIT_NASTY_EATER, "zizo_temp_undeath")
REMOVE_TRAIT(owner, TRAIT_STRONGBITE, "zizo_temp_undeath")
REMOVE_TRAIT(owner, TRAIT_EASYDISMEMBER, "zizo_temp_undeath")
REMOVE_TRAIT(owner, TRAIT_LIMBATTACHMENT, "zizo_temp_undeath")
REMOVE_TRAIT(owner, TRAIT_SILVER_WEAK, "zizo_temp_undeath")
REMOVE_TRAIT(owner, TRAIT_DEATHLESS, "zizo_temp_undeath")
REMOVE_TRAIT(owner, TRAIT_ZOMBIE_IMMUNE, "zizo_temp_undeath")
REMOVE_TRAIT(owner, TRAIT_PSYCHOSIS, "zizo_temp_undeath")
REMOVE_TRAIT(owner, TRAIT_NOMOOD, "zizo_temp_undeath")

/atom/movable/screen/alert/status_effect/debuff/zizo_drain
name = "Zizo's drain"
desc = "Zizo has deemed my return worthy, but at a dear expense."
name = "Syphoned Lux"
desc = "Half of your very rekindled Lux has been syphoned away and the leftovers profaned..."

/atom/movable/screen/alert/status_effect/buff/zizo_tithe
name = "Zizo's tithe"
desc = "Zizo has boosted my capabilities with their vitality."
name = "Lux Syphon"
desc = "You are invigorated with the rekindled Lux of another. A thousand more, and perhaps you will reach Her first step to Ascension."

// THE BOON - Caster
/datum/status_effect/buff/zizo_tithe
Expand All @@ -512,14 +597,23 @@
return ..()

/datum/status_effect/buff/zizo_tithe/on_remove()
UnregisterSignal(victim, COMSIG_LIVING_DEATH)

if(victim)
UnregisterSignal(victim, COMSIG_LIVING_DEATH)
. = ..()

/datum/status_effect/buff/zizo_tithe/proc/cancel_early()
SIGNAL_HANDLER

var/mob/living/carbon/human/H = owner
H.remove_status_effect(/datum/status_effect/buff/zizo_tithe)
var/mob/living/carbon/human/caster = owner
var/mob/living/carbon/human/target = victim

if(caster)
caster.remove_status_effect(/datum/status_effect/buff/zizo_tithe)

if(target)
target.remove_status_effect(/datum/status_effect/debuff/zizo_drain)
target.remove_status_effect(/datum/status_effect/debuff/zizo_temp_undeath)

// THE DRAIN - Victim
/datum/status_effect/debuff/zizo_drain
Expand Down
Loading
Loading