Merge branch '13113'

This commit is contained in:
silicons
2020-08-16 18:53:35 -07:00
100 changed files with 3832 additions and 185 deletions

View File

@@ -14,6 +14,8 @@ GLOBAL_LIST_EMPTY(antagonists)
var/list/objectives = list()
var/antag_memory = ""//These will be removed with antag datum
var/antag_moodlet //typepath of moodlet that the mob will gain with their status
var/antag_hud_type
var/antag_hud_name
/// If above 0, this is the multiplier for the speed at which we hijack the shuttle. Do not directly read, use hijack_speed().
var/hijack_speed = 0
@@ -77,6 +79,17 @@ GLOBAL_LIST_EMPTY(antagonists)
hud.leave_hud(mob_override)
set_antag_hud(mob_override, null)
// Handles adding and removing the clumsy mutation from clown antags. Gets called in apply/remove_innate_effects
/datum/antagonist/proc/handle_clown_mutation(mob/living/mob_override, message, removing = TRUE)
var/mob/living/carbon/human/H = mob_override
if(H && istype(H) && owner.assigned_role == "Clown")
if(removing) // They're a clown becoming an antag, remove clumsy
H.dna.remove_mutation(CLOWNMUT)
if(!silent && message)
to_chat(H, "<span class='boldnotice'>[message]</span>")
else
H.dna.add_mutation(CLOWNMUT) // We're removing their antag status, add back clumsy
//Assign default team and creates one for one of a kind team antagonists
/datum/antagonist/proc/create_team(datum/team/team)
return

View File

@@ -0,0 +1,229 @@
/datum/antagonist/heretic
name = "Heretic"
roundend_category = "Heretics"
antagpanel_category = "Heretic"
antag_moodlet = /datum/mood_event/heretics
job_rank = ROLE_HERETIC
antag_hud_type = ANTAG_HUD_HERETIC
antag_hud_name = "heretic"
var/give_equipment = TRUE
var/list/researched_knowledge = list()
var/total_sacrifices = 0
var/ascended = FALSE
/datum/antagonist/heretic/admin_add(datum/mind/new_owner,mob/admin)
give_equipment = TRUE
new_owner.add_antag_datum(src)
message_admins("[key_name_admin(admin)] has heresized [key_name_admin(new_owner)].")
log_admin("[key_name(admin)] has heresized [key_name(new_owner)].")
/datum/antagonist/heretic/greet()
owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/ecult_op.ogg', 100, FALSE, pressure_affected = FALSE)//subject to change
to_chat(owner, "<span class='boldannounce'>You are the Heretic!</span><br>\
<B>The old ones gave you these tasks to fulfill:</B>")
owner.announce_objectives()
to_chat(owner, "<span class='cult'>The book whispers, the forbidden knowledge walks once again!<br>\
Your book allows you to research abilities, but be careful, you cannot undo what has been done.<br>\
You gain charges by either collecting influences or sacrificing people tracked by the living heart<br> \
You can find a basic guide at : https://tgstation13.org/wiki/Heresy_101 </span>")
/datum/antagonist/heretic/on_gain()
var/mob/living/current = owner.current
if(ishuman(current))
forge_primary_objectives()
gain_knowledge(/datum/eldritch_knowledge/spell/basic)
gain_knowledge(/datum/eldritch_knowledge/living_heart)
gain_knowledge(/datum/eldritch_knowledge/codex_cicatrix)
gain_knowledge(/datum/eldritch_knowledge/eldritch_blade)
current.log_message("has been converted to the cult of the forgotten ones!", LOG_ATTACK, color="#960000")
GLOB.reality_smash_track.AddMind(owner)
START_PROCESSING(SSprocessing,src)
if(give_equipment)
equip_cultist()
owner.teach_crafting_recipe(/datum/crafting_recipe/heretic/codex)
return ..()
/datum/antagonist/heretic/on_removal()
for(var/X in researched_knowledge)
var/datum/eldritch_knowledge/EK = researched_knowledge[X]
EK.on_lose(owner.current)
if(!silent)
to_chat(owner.current, "<span class='userdanger'>Your mind begins to flare as the otherwordly knowledge escapes your grasp!</span>")
owner.current.log_message("has renounced the cult of the old ones!", LOG_ATTACK, color="#960000")
GLOB.reality_smash_track.RemoveMind(owner)
STOP_PROCESSING(SSprocessing,src)
return ..()
/datum/antagonist/heretic/proc/equip_cultist()
var/mob/living/carbon/H = owner.current
if(!istype(H))
return
. += ecult_give_item(/obj/item/forbidden_book, H)
. += ecult_give_item(/obj/item/living_heart, H)
/datum/antagonist/heretic/proc/ecult_give_item(obj/item/item_path, mob/living/carbon/human/H)
var/list/slots = list(
"backpack" = SLOT_IN_BACKPACK,
"left pocket" = SLOT_L_STORE,
"right pocket" = SLOT_R_STORE
)
var/T = new item_path(H)
var/item_name = initial(item_path.name)
var/where = H.equip_in_one_of_slots(T, slots)
if(!where)
to_chat(H, "<span class='userdanger'>Unfortunately, you weren't able to get a [item_name]. This is very bad and you should adminhelp immediately (press F1).</span>")
return FALSE
else
to_chat(H, "<span class='danger'>You have a [item_name] in your [where].</span>")
if(where == "backpack")
SEND_SIGNAL(H.back, COMSIG_TRY_STORAGE_SHOW, H)
return TRUE
/datum/antagonist/heretic/process()
for(var/X in researched_knowledge)
var/datum/eldritch_knowledge/EK = researched_knowledge[X]
EK.on_life(owner.current)
/datum/antagonist/heretic/proc/forge_primary_objectives()
var/list/assasination = list()
var/list/protection = list()
for(var/i in 1 to 2)
var/pck = pick("assasinate","protect")
switch(pck)
if("assasinate")
var/datum/objective/assassinate/A = new
A.owner = owner
var/list/owners = A.get_owners()
A.find_target(owners,protection)
assasination += A.target
objectives += A
if("protect")
var/datum/objective/protect/P = new
P.owner = owner
var/list/owners = P.get_owners()
P.find_target(owners,assasination)
protection += P.target
objectives += P
var/datum/objective/sacrifice_ecult/SE = new
SE.owner = owner
SE.update_explanation_text()
objectives += SE
var/datum/objective/escape/escape_objective = new
escape_objective.owner = owner
objectives += escape_objective
/datum/antagonist/heretic/apply_innate_effects(mob/living/mob_override)
. = ..()
var/mob/living/current = owner.current
if(mob_override)
current = mob_override
add_antag_hud(antag_hud_type, antag_hud_name, current)
handle_clown_mutation(current, mob_override ? null : "Knowledge described in the book allowed you to overcome your clownish nature, allowing you to use complex items effectively.")
current.faction |= "heretics"
/datum/antagonist/heretic/remove_innate_effects(mob/living/mob_override)
. = ..()
var/mob/living/current = owner.current
if(mob_override)
current = mob_override
remove_antag_hud(antag_hud_type, current)
handle_clown_mutation(current, removing = FALSE)
current.faction -= "heretics"
/datum/antagonist/heretic/get_admin_commands()
. = ..()
.["Equip"] = CALLBACK(src,.proc/equip_cultist)
/datum/antagonist/heretic/roundend_report()
var/list/parts = list()
var/cultiewin = TRUE
parts += printplayer(owner)
parts += "<b>Sacrifices Made:</b> [total_sacrifices]"
if(length(objectives))
var/count = 1
for(var/o in objectives)
var/datum/objective/objective = o
if(objective.check_completion())
parts += "<b>Objective #[count]</b>: [objective.explanation_text] <span class='greentext'>Success!</b></span>"
else
parts += "<b>Objective #[count]</b>: [objective.explanation_text] <span class='redtext'>Fail.</span>"
cultiewin = FALSE
count++
if(ascended)
parts += "<span class='greentext big'>HERETIC HAS ASCENDED!</span>"
else
if(cultiewin)
parts += "<span class='greentext'>The heretic was successful!</span>"
else
parts += "<span class='redtext'>The heretic has failed.</span>"
parts += "<b>Knowledge Researched:</b> "
var/list/knowledge_message = list()
var/list/knowledge = get_all_knowledge()
for(var/X in knowledge)
var/datum/eldritch_knowledge/EK = knowledge[X]
knowledge_message += "[EK.name]"
parts += knowledge_message.Join(", ")
return parts.Join("<br>")
////////////////
// Knowledge //
////////////////
/datum/antagonist/heretic/proc/gain_knowledge(datum/eldritch_knowledge/EK)
if(get_knowledge(EK))
return FALSE
var/datum/eldritch_knowledge/initialized_knowledge = new EK
researched_knowledge[initialized_knowledge.type] = initialized_knowledge
initialized_knowledge.on_gain(owner.current)
return TRUE
/datum/antagonist/heretic/proc/get_researchable_knowledge()
var/list/researchable_knowledge = list()
var/list/banned_knowledge = list()
for(var/X in researched_knowledge)
var/datum/eldritch_knowledge/EK = researched_knowledge[X]
researchable_knowledge |= EK.next_knowledge
banned_knowledge |= EK.banned_knowledge
banned_knowledge |= EK.type
researchable_knowledge -= banned_knowledge
return researchable_knowledge
/datum/antagonist/heretic/proc/get_knowledge(wanted)
return researched_knowledge[wanted]
/datum/antagonist/heretic/proc/get_all_knowledge()
return researched_knowledge
////////////////
// Objectives //
////////////////
/datum/objective/sacrifice_ecult
name = "sacrifice"
/datum/objective/sacrifice_ecult/update_explanation_text()
. = ..()
target_amount = rand(2,4)
explanation_text = "Sacrifice at least [target_amount] people."
/datum/objective/sacrifice_ecult/check_completion()
if(!owner)
return FALSE
var/datum/antagonist/heretic/cultie = owner.has_antag_datum(/datum/antagonist/heretic)
if(!cultie)
return FALSE
return cultie.total_sacrifices >= target_amount

View File

@@ -0,0 +1,145 @@
/obj/item/forbidden_book
name = "Codex Cicatrix"
desc = "Book describing the secrets of the veil."
icon = 'icons/obj/eldritch.dmi'
icon_state = "book"
item_state = "book"
w_class = WEIGHT_CLASS_SMALL
///Last person that touched this
var/mob/living/last_user
///how many charges do we have?
var/charge = 0
///Where we cannot create the rune?
var/static/list/blacklisted_turfs = typecacheof(list(/turf/closed,/turf/open/space,/turf/open/lava))
/obj/item/forbidden_book/Destroy()
last_user = null
. = ..()
/obj/item/forbidden_book/examine(mob/user)
. = ..()
if(!IS_HERETIC(user))
return
. += "The Tome holds [charge] charges."
. += "Use it on the floor to create a transmutation rune, used to perform rituals."
. += "Hit an influence in the black part with it to gain a charge."
. += "Hit a transmutation rune to destroy it."
/obj/item/forbidden_book/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
. = ..()
if(!proximity_flag || !IS_HERETIC(user))
return
if(istype(target,/obj/effect/eldritch))
remove_rune(target,user)
if(istype(target,/obj/effect/reality_smash))
get_power_from_influence(target,user)
if(istype(target,/turf/open))
draw_rune(target,user)
///Gives you a charge and destroys a corresponding influence
/obj/item/forbidden_book/proc/get_power_from_influence(atom/target, mob/user)
var/obj/effect/reality_smash/RS = target
to_chat(target, "<span class='danger'>You start drawing power from influence...</span>")
if(do_after(user,10 SECONDS,TRUE,RS))
qdel(RS)
charge += 1
///Draws a rune on a selected turf
/obj/item/forbidden_book/proc/draw_rune(atom/target,mob/user)
for(var/turf/T in range(1,target))
if(is_type_in_typecache(T, blacklisted_turfs))
to_chat(target, "<span class='warning'>The terrain doesn't support runes!</span>")
return
var/A = get_turf(target)
to_chat(user, "<span class='danger'>You start drawing a rune...</span>")
if(do_after(user,30 SECONDS,FALSE, user))
new /obj/effect/eldritch/big(A)
///Removes runes from the selected turf
/obj/item/forbidden_book/proc/remove_rune(atom/target,mob/user)
to_chat(user, "<span class='danger'>You start removing a rune...</span>")
if(do_after(user,2 SECONDS,FALSE, user))
qdel(target)
/obj/item/forbidden_book/ui_interact(mob/user, datum/tgui/ui = null)
if(!IS_HERETIC(user))
return FALSE
last_user = user
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
icon_state = "book_open"
flick("book_opening", src)
ui = new(user, src, "ForbiddenLore", name)
ui.open()
/obj/item/forbidden_book/ui_data(mob/user)
var/datum/antagonist/heretic/cultie = user.mind.has_antag_datum(/datum/antagonist/heretic)
var/list/to_know = list()
for(var/Y in cultie.get_researchable_knowledge())
to_know += new Y
var/list/known = cultie.get_all_knowledge()
var/list/data = list()
var/list/lore = list()
data["charges"] = charge
for(var/X in to_know)
lore = list()
var/datum/eldritch_knowledge/EK = X
lore["type"] = EK.type
lore["name"] = EK.name
lore["cost"] = EK.cost
lore["disabled"] = EK.cost <= charge ? FALSE : TRUE
lore["path"] = EK.route
lore["state"] = "Research"
lore["flavour"] = EK.gain_text
lore["desc"] = EK.desc
data["to_know"] += list(lore)
for(var/X in known)
lore = list()
var/datum/eldritch_knowledge/EK = known[X]
lore["name"] = EK.name
lore["cost"] = EK.cost
lore["disabled"] = TRUE
lore["path"] = EK.route
lore["state"] = "Researched"
lore["flavour"] = EK.gain_text
lore["desc"] = EK.desc
data["to_know"] += list(lore)
if(!length(data["to_know"]))
data["to_know"] = null
return data
/obj/item/forbidden_book/ui_act(action, params)
. = ..()
if(.)
return
switch(action)
if("research")
var/datum/antagonist/heretic/cultie = last_user.mind.has_antag_datum(/datum/antagonist/heretic)
var/ekname = params["name"]
for(var/X in cultie.get_researchable_knowledge())
var/datum/eldritch_knowledge/EK = X
if(initial(EK.name) != ekname)
continue
if(cultie.gain_knowledge(EK))
charge -= text2num(params["cost"])
return TRUE
update_icon() // Not applicable to all objects.
/obj/item/forbidden_book/ui_close(mob/user)
flick("book_closing",src)
icon_state = initial(icon_state)
return ..()
/obj/item/forbidden_book/debug
charge = 100

View File

@@ -0,0 +1,289 @@
/obj/effect/eldritch
name = "Generic rune"
desc = "Weird combination of shapes and symbols etched into the floor itself. The indentation is filled with thick black tar-like fluid."
anchored = TRUE
icon_state = ""
resistance_flags = FIRE_PROOF | UNACIDABLE | ACID_PROOF
layer = SIGIL_LAYER
///Used mainly for summoning ritual to prevent spamming the rune to create millions of monsters.
var/is_in_use = FALSE
/obj/effect/eldritch/attack_hand(mob/living/user)
. = ..()
if(.)
return
try_activate(user)
/obj/effect/eldritch/proc/try_activate(mob/living/user)
if(!IS_HERETIC(user))
return
if(!is_in_use)
INVOKE_ASYNC(src, .proc/activate , user)
/obj/effect/eldritch/attacked_by(obj/item/I, mob/living/user)
. = ..()
if(istype(I,/obj/item/nullrod))
qdel(src)
/obj/effect/eldritch/proc/activate(mob/living/user)
is_in_use = TRUE
// Have fun trying to read this proc.
var/datum/antagonist/heretic/cultie = user.mind.has_antag_datum(/datum/antagonist/heretic)
var/list/knowledge = cultie.get_all_knowledge()
var/list/atoms_in_range = list()
for(var/A in range(1, src))
var/atom/atom_in_range = A
if(istype(atom_in_range,/area))
continue
if(istype(atom_in_range,/turf)) // we dont want turfs
continue
if(istype(atom_in_range,/mob/living))
var/mob/living/living_in_range = atom_in_range
if(living_in_range.stat != DEAD || living_in_range == user) // we only accept corpses, no living beings allowed.
continue
atoms_in_range += atom_in_range
for(var/X in knowledge)
var/datum/eldritch_knowledge/current_eldritch_knowledge = knowledge[X]
//has to be done so that we can freely edit the local_required_atoms without fucking up the eldritch knowledge
var/list/local_required_atoms = list()
if(!current_eldritch_knowledge.required_atoms || current_eldritch_knowledge.required_atoms.len == 0)
continue
local_required_atoms += current_eldritch_knowledge.required_atoms
var/list/selected_atoms = list()
if(!current_eldritch_knowledge.recipe_snowflake_check(atoms_in_range,drop_location(),selected_atoms))
continue
for(var/LR in local_required_atoms)
var/list/local_required_atom_list = LR
for(var/LAIR in atoms_in_range)
var/atom/local_atom_in_range = LAIR
if(is_type_in_list(local_atom_in_range,local_required_atom_list))
selected_atoms |= local_atom_in_range
local_required_atoms -= list(local_required_atom_list)
if(length(local_required_atoms) > 0)
continue
flick("[icon_state]_active",src)
playsound(user, 'sound/magic/castsummon.ogg', 75, TRUE)
//we are doing this since some on_finished_recipe subtract the atoms from selected_atoms making them invisible permanently.
var/list/atoms_to_disappear = selected_atoms.Copy()
for(var/to_disappear in atoms_to_disappear)
var/atom/atom_to_disappear = to_disappear
//temporary so we dont have to deal with the bs of someone picking those up when they may be deleted
atom_to_disappear.invisibility = INVISIBILITY_ABSTRACT
if(current_eldritch_knowledge.on_finished_recipe(user,selected_atoms,loc))
current_eldritch_knowledge.cleanup_atoms(selected_atoms)
is_in_use = FALSE
for(var/to_appear in atoms_to_disappear)
var/atom/atom_to_appear = to_appear
//we need to reappear the item just in case the ritual didnt consume everything... or something.
atom_to_appear.invisibility = initial(atom_to_appear.invisibility)
return
is_in_use = FALSE
to_chat(user,"<span class='warning'>Your ritual failed! You used either wrong components or are missing something important!</span>")
/obj/effect/eldritch/big
name = "transmutation circle"
icon = 'icons/effects/96x96.dmi'
icon_state = "eldritch_rune1"
pixel_x = -32 //So the big ol' 96x96 sprite shows up right
pixel_y = -32
/**
* #Reality smash tracker
*
* Stupid fucking list holder, DONT create new ones, it will break the game, this is automnatically created whenever eldritch cultists are created.
*
* Tracks relevant data, generates relevant data, useful tool
*/
/datum/reality_smash_tracker
///list of tracked reality smashes
var/list/smashes = list()
///List of mobs with ability to see the smashes
var/list/targets = list()
/datum/reality_smash_tracker/Destroy(force, ...)
if(GLOB.reality_smash_track == src)
stack_trace("/datum/reality_smash_tracker was deleted. Heretics may no longer access any influences. Fix it or call coder support")
QDEL_LIST(smashes)
targets.Cut()
return ..()
/**
* Automatically fixes the target and smash network
*
* Fixes any bugs that are caused by late Generate() or exchanging clients
*/
/datum/reality_smash_tracker/proc/ReworkNetwork()
listclearnulls(smashes)
for(var/mind in targets)
if(isnull(mind))
stack_trace("A null somehow landed in a list of minds")
continue
for(var/X in smashes)
var/obj/effect/reality_smash/reality_smash = X
reality_smash.AddMind(mind)
/**
* Generates a set amount of reality smashes based on the N value
*
* Automatically creates more reality smashes
*/
/datum/reality_smash_tracker/proc/_Generate()
var/targ_len = length(targets)
var/smash_len = length(smashes)
var/number = targ_len * 6 - smash_len
for(var/i in 0 to number)
var/turf/chosen_location = get_safe_random_station_turf()
//we also dont want them close to each other, at least 1 tile of seperation
var/obj/effect/reality_smash/what_if_i_have_one = locate() in range(1, chosen_location)
var/obj/effect/broken_illusion/what_if_i_had_one_but_got_used = locate() in range(1, chosen_location)
if(what_if_i_have_one || what_if_i_had_one_but_got_used) //we dont want to spawn
continue
var/obj/effect/reality_smash/RS = new/obj/effect/reality_smash(chosen_location)
smashes += RS
ReworkNetwork()
/**
* Adds a mind to the list of people that can see the reality smashes
*
* Use this whenever you want to add someone to the list
*/
/datum/reality_smash_tracker/proc/AddMind(var/datum/mind/M)
RegisterSignal(M.current,COMSIG_MOB_CLIENT_LOGIN,.proc/ReworkNetwork)
targets |= M
_Generate()
for(var/X in smashes)
var/obj/effect/reality_smash/reality_smash = X
reality_smash.AddMind(M)
/**
* Removes a mind from the list of people that can see the reality smashes
*
* Use this whenever you want to remove someone from the list
*/
/datum/reality_smash_tracker/proc/RemoveMind(var/datum/mind/M)
UnregisterSignal(M.current,COMSIG_MOB_CLIENT_LOGIN)
targets -= M
for(var/obj/effect/reality_smash/RS in smashes)
RS.RemoveMind(M)
/obj/effect/broken_illusion
name = "pierced reality"
icon = 'icons/effects/eldritch.dmi'
icon_state = "pierced_illusion"
anchored = TRUE
resistance_flags = FIRE_PROOF | UNACIDABLE | ACID_PROOF
/obj/effect/broken_illusion/attack_hand(mob/living/user)
if(!ishuman(user))
return ..()
var/mob/living/carbon/human/human_user = user
if(IS_HERETIC(human_user))
to_chat(human_user,"<span class='boldwarning'>You know better than to tempt forces out of your control.</span>")
else
var/obj/item/bodypart/arm = human_user.get_active_hand()
if(prob(25))
to_chat(human_user,"<span class='userdanger'>An otherwordly presence tears your arm apart into atoms as you try to touch the hole in the very fabric of reality!</span>")
arm.dismember()
qdel(arm)
else
to_chat(human_user,"<span class='danger'>You pull your hand away from the hole as eldritch energy flails out, trying to latch onto existence itself!</span>")
/obj/effect/broken_illusion/attack_tk(mob/user)
if(!ishuman(user))
return
var/mob/living/carbon/human/human_user = user
if(IS_HERETIC(human_user))
to_chat(human_user,"<span class='boldwarning'>You know better than to tempt forces out of your control.</span>")
else
//a very elaborate way to suicide
to_chat(human_user,"<span class='userdanger'>Eldritch energy lashes out, piercing your fragile mind, tearing it to pieces!</span>")
human_user.ghostize()
var/obj/item/bodypart/head/head = locate() in human_user.bodyparts
if(head)
head.dismember()
qdel(head)
else
human_user.gib()
var/datum/effect_system/reagents_explosion/explosion = new()
explosion.set_up(1, get_turf(human_user), 1, 0)
explosion.start()
/obj/effect/broken_illusion/examine(mob/user)
if(!IS_HERETIC(user) && ishuman(user))
var/mob/living/carbon/human/human_user = user
to_chat(human_user,"<span class='userdanger'>Your brain hurts when you look at this!</span>")
human_user.adjustOrganLoss(ORGAN_SLOT_BRAIN,30)
. = ..()
/obj/effect/reality_smash
name = "/improper reality smash"
icon = 'icons/effects/eldritch.dmi'
anchored = TRUE
resistance_flags = FIRE_PROOF | UNACIDABLE | ACID_PROOF
///We cannot use icon_state since this is invisible, functions the same way but with custom behaviour.
var/image_state = "reality_smash"
///Who can see us?
var/list/minds = list()
///Tracked image
var/image/img
/obj/effect/reality_smash/Initialize()
. = ..()
img = image(icon, src, image_state, OBJ_LAYER)
generate_name()
/obj/effect/reality_smash/Destroy()
on_destroy()
return ..()
///Custom effect that happens on destruction
/obj/effect/reality_smash/proc/on_destroy()
for(var/cm in minds)
var/datum/mind/cultie = cm
if(cultie.current?.client)
cultie.current.client.images -= img
//clear the list
minds -= cultie
GLOB.reality_smash_track.smashes -= src
img = null
new /obj/effect/broken_illusion(drop_location())
///Makes the mind able to see this effect
/obj/effect/reality_smash/proc/AddMind(var/datum/mind/cultie)
minds |= cultie
if(cultie.current.client)
cultie.current.client.images |= img
///Makes the mind not able to see this effect
/obj/effect/reality_smash/proc/RemoveMind(var/datum/mind/cultie)
minds -= cultie
if(cultie.current.client)
cultie.current.client.images -= img
///Generates random name
/obj/effect/reality_smash/proc/generate_name()
var/static/list/prefix = list("Omniscient","Thundering","Enlightening","Intrusive","Rejectful","Atomized","Subtle","Rising","Lowering","Fleeting","Towering","Blissful","Arrogant","Threatening","Peaceful","Aggressive")
var/static/list/postfix = list("Flaw","Presence","Crack","Heat","Cold","Memory","Reminder","Breeze","Grasp","Sight","Whisper","Flow","Touch","Veil","Thought","Imperfection","Blemish","Blush")
name = pick(prefix) + " " + pick(postfix)

View File

@@ -0,0 +1,142 @@
/obj/item/living_heart
name = "living heart"
desc = "Link to the worlds beyond."
icon = 'icons/obj/eldritch.dmi'
icon_state = "living_heart"
w_class = WEIGHT_CLASS_SMALL
///Target
var/mob/living/carbon/human/target
/obj/item/living_heart/attack_self(mob/user)
. = ..()
if(!IS_HERETIC(user))
return
if(!target)
to_chat(user,"<span class='warning'>No target could be found. Put the living heart on the rune and use the rune to recieve a target.</span>")
return
var/dist = get_dist(user.loc,target.loc)
var/dir = get_dir(user.loc,target.loc)
switch(dist)
if(0 to 15)
to_chat(user,"<span class='warning'>[target.real_name] is near you. They are to the [dir2text(dir)] of you!</span>")
if(16 to 31)
to_chat(user,"<span class='warning'>[target.real_name] is somewhere in your vicinty. They are to the [dir2text(dir)] of you!</span>")
if(32 to 127)
to_chat(user,"<span class='warning'>[target.real_name] is far away from you. They are to the [dir2text(dir)] of you!</span>")
else
to_chat(user,"<span class='warning'>[target.real_name] is beyond our reach.</span>")
if(target.stat == DEAD)
to_chat(user,"<span class='warning'>[target.real_name] is dead. Bring them onto a transmutation rune!</span>")
/obj/item/melee/sickly_blade
name = "eldritch blade"
desc = "A sickly green crescent blade, decorated with an ornamental eye. You feel like you're being watched..."
icon = 'icons/obj/eldritch.dmi'
icon_state = "eldritch_blade"
item_state = "eldritch_blade"
lefthand_file = 'icons/mob/inhands/64x64_lefthand.dmi'
righthand_file = 'icons/mob/inhands/64x64_righthand.dmi'
inhand_x_dimension = 64
inhand_y_dimension = 64
flags_1 = CONDUCT_1
sharpness = SHARP_EDGED
w_class = WEIGHT_CLASS_NORMAL
force = 17
throwforce = 10
hitsound = 'sound/weapons/bladeslice.ogg'
attack_verb = list("attacked", "slashed", "stabbed", "sliced", "tore", "lacerated", "ripped", "diced", "rended")
/obj/item/melee/sickly_blade/attack(mob/living/M, mob/living/user)
if(!IS_HERETIC(user))
to_chat(user,"<span class='danger'>You feel a pulse of some alien intellect lash out at your mind!</span>")
var/mob/living/carbon/human/human_user = user
human_user.AdjustParalyzed(5 SECONDS)
return FALSE
return ..()
/obj/item/melee/sickly_blade/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
. = ..()
var/datum/antagonist/heretic/cultie = user.mind.has_antag_datum(/datum/antagonist/heretic)
if(!cultie || !proximity_flag)
return
var/list/knowledge = cultie.get_all_knowledge()
for(var/X in knowledge)
var/datum/eldritch_knowledge/eldritch_knowledge_datum = knowledge[X]
eldritch_knowledge_datum.on_eldritch_blade(target,user,proximity_flag,click_parameters)
/obj/item/melee/sickly_blade/rust
name = "rusted blade"
desc = "This crescent blade is decrepit, wasting to dust. Yet still it bites, catching flesh with jagged, rotten teeth."
icon_state = "rust_blade"
item_state = "rust_blade"
embedding = list("pain_mult" = 4, "embed_chance" = 75, "fall_chance" = 10, "ignore_throwspeed_threshold" = TRUE)
throwforce = 17
/obj/item/melee/sickly_blade/ash
name = "ashen blade"
desc = "Molten and unwrought, a hunk of metal warped to cinders and slag. Unmade, it aspires to be more than it is, and shears soot-filled wounds with a blunt edge."
icon_state = "ash_blade"
item_state = "ash_blade"
force = 20
/obj/item/melee/sickly_blade/flesh
name = "flesh blade"
desc = "A crescent blade born from a fleshwarped creature. Keenly aware, it seeks to spread to others the excruciations it has endured from dead origins."
icon_state = "flesh_blade"
item_state = "flesh_blade"
wound_bonus = 5
bare_wound_bonus = 15
/obj/item/clothing/neck/eldritch_amulet
name = "warm eldritch medallion"
desc = "A strange medallion. Peering through the crystalline surface, the world around you melts away. You see your own beating heart, and the pulse of a thousand others."
icon = 'icons/obj/eldritch.dmi'
icon_state = "eye_medalion"
w_class = WEIGHT_CLASS_SMALL
///What trait do we want to add upon equipiing
var/trait = TRAIT_THERMAL_VISION
/obj/item/clothing/neck/eldritch_amulet/equipped(mob/user, slot)
. = ..()
if(ishuman(user) && user.mind && slot == SLOT_NECK && IS_HERETIC(user))
ADD_TRAIT(user, trait, CLOTHING_TRAIT)
user.update_sight()
/obj/item/clothing/neck/eldritch_amulet/dropped(mob/user)
. = ..()
REMOVE_TRAIT(user, trait, CLOTHING_TRAIT)
user.update_sight()
/obj/item/clothing/neck/eldritch_amulet/piercing
name = "piercing eldritch medallion"
desc = "A strange medallion. Peering through the crystalline surface, the light refracts into new and terrifying spectrums of color. You see yourself, reflected off cascading mirrors, warped into improbable shapes."
trait = TRAIT_XRAY_VISION
/obj/item/clothing/head/hooded/cult_hoodie/eldritch
name = "ominous hood"
icon_state = "eldritch"
desc = "A torn, dust-caked hood. Strange eyes line the inside."
flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDEFACIALHAIR
flags_cover = HEADCOVERSEYES | HEADCOVERSMOUTH
flash_protect = 2
/obj/item/clothing/suit/hooded/cultrobes/eldritch
name = "ominous armor"
desc = "A ragged, dusty set of robes. Strange eyes line the inside."
icon_state = "eldritch_armor"
item_state = "eldritch_armor"
flags_inv = HIDESHOES|HIDEJUMPSUIT
body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS
allowed = list(/obj/item/melee/sickly_blade, /obj/item/forbidden_book)
hoodtype = /obj/item/clothing/head/hooded/cult_hoodie/eldritch
// slightly better than normal cult robes
armor = list("melee" = 50, "bullet" = 50, "laser" = 50,"energy" = 50, "bomb" = 35, "bio" = 20, "rad" = 0, "fire" = 20, "acid" = 20)
/obj/item/reagent_containers/glass/beaker/eldritch
name = "flask of eldritch essence"
desc = "Toxic to the close minded. Healing to those with knowledge of the beyond."
icon = 'icons/obj/eldritch.dmi'
icon_state = "eldrich_flask"
list_reagents = list(/datum/reagent/eldritch = 50)

View File

@@ -0,0 +1,303 @@
/**
* #Eldritch Knwoledge
*
* Datum that makes eldritch cultist interesting.
*
* Eldritch knowledge aren't instantiated anywhere roundstart, and are initalized and destroyed as the round goes on.
*/
/datum/eldritch_knowledge
///Name of the knowledge
var/name = "Basic knowledge"
///Description of the knowledge
var/desc = "Basic knowledge of forbidden arts."
///What shows up
var/gain_text = ""
///Cost of knowledge in souls
var/cost = 0
///Next knowledge in the research tree
var/list/next_knowledge = list()
///What knowledge is incompatible with this. This will simply make it impossible to research knowledges that are in banned_knowledge once this gets researched.
var/list/banned_knowledge = list()
///Used with rituals, how many items this needs
var/list/required_atoms = list()
///What do we get out of this
var/list/result_atoms = list()
///What path is this on defaults to "Side"
var/route = PATH_SIDE
/datum/eldritch_knowledge/New()
. = ..()
var/list/temp_list
for(var/X in required_atoms)
var/atom/A = X
temp_list += list(typesof(A))
required_atoms = temp_list
/**
* What happens when this is assigned to an antag datum
*
* This proc is called whenever a new eldritch knowledge is added to an antag datum
*/
/datum/eldritch_knowledge/proc/on_gain(mob/user)
to_chat(user, "<span class='warning'>[gain_text]</span>")
return
/**
* What happens when you loose this
*
* This proc is called whenever antagonist looses his antag datum, put cleanup code in here
*/
/datum/eldritch_knowledge/proc/on_lose(mob/user)
return
/**
* What happens every tick
*
* This proc is called on SSprocess in eldritch cultist antag datum. SSprocess happens roughly every second
*/
/datum/eldritch_knowledge/proc/on_life(mob/user)
return
/**
* Special check for recipes
*
* If you are adding a more complex summoning or something that requires a special check that parses through all the atoms in an area override this.
*/
/datum/eldritch_knowledge/proc/recipe_snowflake_check(list/atoms,loc)
return TRUE
/**
* What happens once the recipe is succesfully finished
*
* By default this proc creates atoms from result_atoms list. Override this is you want something else to happen.
*/
/datum/eldritch_knowledge/proc/on_finished_recipe(mob/living/user,list/atoms,loc)
if(result_atoms.len == 0)
return FALSE
for(var/A in result_atoms)
new A(loc)
return TRUE
/**
* Used atom cleanup
*
* Overide this proc if you dont want ALL ATOMS to be destroyed. useful in many situations.
*/
/datum/eldritch_knowledge/proc/cleanup_atoms(list/atoms)
for(var/X in atoms)
var/atom/A = X
if(!isliving(A))
atoms -= A
qdel(A)
return
/**
* Mansus grasp act
*
* Gives addtional effects to mansus grasp spell
*/
/datum/eldritch_knowledge/proc/on_mansus_grasp(atom/target, mob/user, proximity_flag, click_parameters)
return FALSE
/**
* Sickly blade act
*
* Gives addtional effects to sickly blade weapon
*/
/datum/eldritch_knowledge/proc/on_eldritch_blade(target,user,proximity_flag,click_parameters)
return
//////////////
///Subtypes///
//////////////
/datum/eldritch_knowledge/spell
var/obj/effect/proc_holder/spell/spell_to_add
/datum/eldritch_knowledge/spell/on_gain(mob/user)
var/obj/effect/proc_holder/S = new spell_to_add
user.mind.AddSpell(S)
return ..()
/datum/eldritch_knowledge/spell/on_lose(mob/user)
user.mind.RemoveSpell(spell_to_add)
return ..()
/datum/eldritch_knowledge/curse
var/timer = 5 MINUTES
var/list/fingerprints = list()
/datum/eldritch_knowledge/curse/recipe_snowflake_check(list/atoms, loc)
fingerprints = list()
for(var/X in atoms)
var/atom/A = X
fingerprints |= A.fingerprints
listclearnulls(fingerprints)
if(fingerprints.len == 0)
return FALSE
return TRUE
/datum/eldritch_knowledge/curse/on_finished_recipe(mob/living/user,list/atoms,loc)
var/list/compiled_list = list()
for(var/H in GLOB.human_list)
var/mob/living/carbon/human/human_to_check = H
if(fingerprints[md5(human_to_check.dna.uni_identity)])
compiled_list |= human_to_check.real_name
compiled_list[human_to_check.real_name] = human_to_check
if(compiled_list.len == 0)
to_chat(user, "<span class='warning'>The items don't posses required fingerprints.</span>")
return FALSE
var/chosen_mob = input("Select the person you wish to curse","Your target") as null|anything in sortList(compiled_list, /proc/cmp_mob_realname_dsc)
if(!chosen_mob)
return FALSE
curse(compiled_list[chosen_mob])
addtimer(CALLBACK(src, .proc/uncurse, compiled_list[chosen_mob]),timer)
return TRUE
/datum/eldritch_knowledge/curse/proc/curse(mob/living/chosen_mob)
return
/datum/eldritch_knowledge/curse/proc/uncurse(mob/living/chosen_mob)
return
/datum/eldritch_knowledge/summon
//Mob to summon
var/mob/living/mob_to_summon
/datum/eldritch_knowledge/summon/on_finished_recipe(mob/living/user,list/atoms,loc)
//we need to spawn the mob first so that we can use it in pollCandidatesForMob, we will move it from nullspace down the code
var/mob/living/summoned = new mob_to_summon(loc)
message_admins("[summoned.name] is being summoned by [user.real_name] in [loc]")
var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as [summoned.name]", ROLE_HERETIC, null, FALSE, 100, summoned)
if(!LAZYLEN(candidates))
to_chat(user,"<span class='warning'>No ghost could be found...</span>")
qdel(summoned)
return FALSE
var/mob/dead/observer/C = pick(candidates)
log_game("[key_name_admin(C)] has taken control of ([key_name_admin(summoned)]), their master is [user.real_name]")
summoned.ghostize(FALSE)
summoned.key = C.key
summoned.mind.add_antag_datum(/datum/antagonist/heretic_monster)
var/datum/antagonist/heretic_monster/heretic_monster = summoned.mind.has_antag_datum(/datum/antagonist/heretic_monster)
var/datum/antagonist/heretic/master = user.mind.has_antag_datum(/datum/antagonist/heretic)
heretic_monster.set_owner(master)
return TRUE
//Ascension knowledge
/datum/eldritch_knowledge/final
var/finished = FALSE
/datum/eldritch_knowledge/final/recipe_snowflake_check(list/atoms, loc,selected_atoms)
if(finished)
return FALSE
var/counter = 0
for(var/mob/living/carbon/human/H in atoms)
selected_atoms |= H
counter++
if(counter == 3)
return TRUE
return FALSE
/datum/eldritch_knowledge/final/on_finished_recipe( mob/living/user, list/atoms, loc)
finished = TRUE
return TRUE
/datum/eldritch_knowledge/final/cleanup_atoms(list/atoms)
. = ..()
for(var/mob/living/carbon/human/H in atoms)
atoms -= H
H.gib()
///////////////
///Base lore///
///////////////
/datum/eldritch_knowledge/spell/basic
name = "Break of Dawn"
desc = "Starts your journey in the mansus. Allows you to select a target using a living heart on a transmutation rune."
gain_text = "Gates of Mansus open up to your mind."
next_knowledge = list(/datum/eldritch_knowledge/base_rust,/datum/eldritch_knowledge/base_ash,/datum/eldritch_knowledge/base_flesh)
cost = 0
spell_to_add = /obj/effect/proc_holder/spell/targeted/touch/mansus_grasp
required_atoms = list(/obj/item/living_heart)
route = "Start"
/datum/eldritch_knowledge/spell/basic/recipe_snowflake_check(list/atoms, loc)
. = ..()
for(var/obj/item/living_heart/LH in atoms)
if(!LH.target)
return TRUE
if(LH.target in atoms)
return TRUE
return FALSE
/datum/eldritch_knowledge/spell/basic/on_finished_recipe(mob/living/user, list/atoms, loc)
. = TRUE
var/mob/living/carbon/carbon_user = user
for(var/obj/item/living_heart/LH in atoms)
if(LH.target && LH.target.stat == DEAD)
to_chat(carbon_user,"<span class='danger'>Your patrons accepts your offer...</span>")
var/mob/living/carbon/human/H = LH.target
H.become_husk()
LH.target = null
var/datum/antagonist/heretic/EC = carbon_user.mind.has_antag_datum(/datum/antagonist/heretic)
EC.total_sacrifices++
for(var/X in carbon_user.get_all_gear())
if(!istype(X,/obj/item/forbidden_book))
continue
var/obj/item/forbidden_book/FB = X
FB.charge++
FB.charge++
break
if(!LH.target)
var/datum/objective/A = new
A.owner = user.mind
var/datum/mind/targeted = A.find_target()//easy way, i dont feel like copy pasting that entire block of code
LH.target = targeted.current
qdel(A)
if(LH.target)
to_chat(user,"<span class='warning'>Your new target has been selected, go and sacrifice [LH.target.real_name]!</span>")
else
to_chat(user,"<span class='warning'>target could not be found for living heart.</span>")
/datum/eldritch_knowledge/spell/basic/cleanup_atoms(list/atoms)
return
/datum/eldritch_knowledge/living_heart
name = "Living Heart"
desc = "Allows you to create additional living hearts, using a heart, a pool of blood and a poppy. Living hearts when used on a transmutation rune will grant you a person to hunt and sacrifice on the rune. Every sacrifice gives you an additional charge in the book."
gain_text = "Disconnected, yet it still beats."
cost = 0
required_atoms = list(/obj/item/organ/heart,/obj/effect/decal/cleanable/blood,/obj/item/reagent_containers/food/snacks/grown/poppy)
result_atoms = list(/obj/item/living_heart)
route = "Start"
/datum/eldritch_knowledge/codex_cicatrix
name = "Codex Cicatrix"
desc = "Allows you to create a spare Codex Cicatrix if you have lost one, using a bible, human skin, a pen and a pair of eyes."
gain_text = "Their hands are at your throat, yet you see them not."
cost = 0
required_atoms = list(/obj/item/organ/eyes,/obj/item/stack/sheet/animalhide/human,/obj/item/storage/book/bible,/obj/item/pen)
result_atoms = list(/obj/item/forbidden_book)
route = "Start"
/datum/eldritch_knowledge/eldritch_blade
name = "Eldritch Blade"
desc = "Allows you to create a sickly, eldritch blade by transmuting a glass shard and a metal rod atop a transmutation rune."
gain_text = "The first step starts with sacrifice."
cost = 0
required_atoms = list(/obj/item/shard,/obj/item/stack/rods)
result_atoms = list(/obj/item/melee/sickly_blade)
route = "Start"

View File

@@ -0,0 +1,668 @@
/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/shift/ash
name = "Ashen Passage"
desc = "Low range spell allowing you to pass through a few walls."
school = "transmutation"
invocation = "DULK'ES PRE'ZIMAS"
invocation_type = "whisper"
charge_max = 150
range = -1
action_icon = 'icons/mob/actions/actions_ecult.dmi'
action_icon_state = "ash_shift"
action_background_icon_state = "bg_ecult"
jaunt_in_time = 13
jaunt_duration = 10
jaunt_in_type = /obj/effect/temp_visual/dir_setting/ash_shift
jaunt_out_type = /obj/effect/temp_visual/dir_setting/ash_shift/out
/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/shift/ash/long
jaunt_duration = 50
/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/shift/ash/play_sound()
return
/obj/effect/temp_visual/dir_setting/ash_shift
name = "ash_shift"
icon = 'icons/mob/mob.dmi'
icon_state = "ash_shift2"
duration = 13
/obj/effect/temp_visual/dir_setting/ash_shift/out
icon_state = "ash_shift"
/obj/effect/proc_holder/spell/targeted/touch/mansus_grasp
name = "Mansus Grasp"
desc = "Touch spell that allows you to channel the power of the Old Gods through you."
hand_path = /obj/item/melee/touch_attack/mansus_fist
school = "evocation"
charge_max = 150
clothes_req = FALSE
action_icon = 'icons/mob/actions/actions_ecult.dmi'
action_icon_state = "mansus_grasp"
action_background_icon_state = "bg_ecult"
/obj/item/melee/touch_attack/mansus_fist
name = "Mansus Grasp"
desc = "A sinister looking aura that distorts the flow of reality around it. Causes knockdown, major stamina damage aswell as some Brute. It gains additional beneficial effects with certain knowledges you can research."
icon_state = "disintegrate"
item_state = "disintegrate"
catchphrase = "T'IESA SIE'KTI VISATA"
/obj/item/melee/touch_attack/mansus_fist/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
if(!proximity_flag || target == user)
return
playsound(user, 'sound/items/welder.ogg', 75, TRUE)
if(ishuman(target))
var/mob/living/carbon/human/tar = target
if(tar.anti_magic_check())
tar.visible_message("<span class='danger'>Spell bounces off of [target]!</span>","<span class='danger'>The spell bounces off of you!</span>")
return ..()
var/datum/mind/M = user.mind
var/datum/antagonist/heretic/cultie = M.has_antag_datum(/datum/antagonist/heretic)
var/use_charge = FALSE
if(iscarbon(target))
use_charge = TRUE
var/mob/living/carbon/C = target
C.adjustBruteLoss(15)
C.DefaultCombatKnockdown(50, override_stamdmg = 0)
C.adjustStaminaLoss(60)
var/list/knowledge = cultie.get_all_knowledge()
for(var/X in knowledge)
var/datum/eldritch_knowledge/EK = knowledge[X]
if(EK.on_mansus_grasp(target, user, proximity_flag, click_parameters))
use_charge = TRUE
if(use_charge)
return ..()
/obj/effect/proc_holder/spell/aoe_turf/rust_conversion
name = "Aggressive Spread"
desc = "Spreads rust onto nearby turfs."
school = "transmutation"
charge_max = 300 //twice as long as mansus grasp
clothes_req = FALSE
invocation = "PLI'STI MINO DOMI'KA"
invocation_type = "whisper"
range = 3
action_icon = 'icons/mob/actions/actions_ecult.dmi'
action_icon_state = "corrode"
action_background_icon_state = "bg_ecult"
/obj/effect/proc_holder/spell/aoe_turf/rust_conversion/cast(list/targets, mob/user = usr)
playsound(user, 'sound/items/welder.ogg', 75, TRUE)
for(var/turf/T in targets)
///What we want is the 3 tiles around the user and the tile under him to be rusted, so min(dist,1)-1 causes us to get 0 for these tiles, rest of the tiles are based on chance
var/chance = 100 - (max(get_dist(T,user),1)-1)*100/(range+1)
if(!prob(chance))
continue
T.rust_heretic_act()
/obj/effect/proc_holder/spell/aoe_turf/rust_conversion/small
name = "Rust Conversion"
desc = "Spreads rust onto nearby turfs."
range = 2
/obj/effect/proc_holder/spell/targeted/touch/blood_siphon
name = "Blood Siphon"
desc = "Touch spell that heals you while damaging the enemy, has a chance to transfer wounds between you and your enemy."
hand_path = /obj/item/melee/touch_attack/blood_siphon
school = "evocation"
charge_max = 150
clothes_req = FALSE
invocation_type = "none"
action_icon = 'icons/mob/actions/actions_ecult.dmi'
action_icon_state = "blood_siphon"
action_background_icon_state = "bg_ecult"
/obj/item/melee/touch_attack/blood_siphon
name = "Blood Siphon"
desc = "A sinister looking aura that distorts the flow of reality around it."
icon_state = "disintegrate"
item_state = "disintegrate"
catchphrase = "SUN'AI'KINI'MAS"
/obj/item/melee/touch_attack/blood_siphon/afterattack(atom/target, mob/user, proximity_flag, proximity)
if(!proximity_flag)
return
playsound(user, 'sound/effects/curseattack.ogg', 75, TRUE)
if(ishuman(target))
var/mob/living/carbon/human/tar = target
if(tar.anti_magic_check())
tar.visible_message("<span class='danger'>Spell bounces off of [target]!</span>","<span class='danger'>The spell bounces off of you!</span>")
return ..()
var/mob/living/carbon/C2 = user
if(isliving(target))
var/mob/living/L = target
L.adjustBruteLoss(20)
C2.adjustBruteLoss(-20)
if(iscarbon(target))
var/mob/living/carbon/C1 = target
for(var/obj/item/bodypart/bodypart in C2.bodyparts)
for(var/i in bodypart.wounds)
var/datum/wound/iter_wound = i
if(prob(50))
continue
var/obj/item/bodypart/target_bodypart = locate(bodypart.type) in C1.bodyparts
if(!target_bodypart)
continue
iter_wound.remove_wound()
iter_wound.apply_wound(target_bodypart)
C1.blood_volume -= 20
if(C2.blood_volume < BLOOD_VOLUME_MAXIMUM) //we dont want to explode after all
C2.blood_volume += 20
return ..()
/obj/effect/proc_holder/spell/aimed/rust_wave
name = "Patron's Reach"
desc = "Channels energy into your gauntlet - firing it results in a wave of rust being created in it's wake."
projectile_type = /obj/item/projectile/magic/spell/rust_wave
charge_max = 350
clothes_req = FALSE
action_icon = 'icons/mob/actions/actions_ecult.dmi'
base_icon_state = "rust_wave"
action_icon_state = "rust_wave"
action_background_icon_state = "bg_ecult"
sound = 'sound/effects/curse5.ogg'
active_msg = "You extend your hand out, preparing to send out a wave of rust."
deactive_msg = "You extinguish that energy, for now..."
invocation = "RUD'ZI VAR'ZTAS"
invocation_type = "whisper"
/obj/item/projectile/magic/spell/rust_wave
name = "rust bolt"
icon_state = "eldritch_projectile"
alpha = 180
damage = 30
damage_type = TOX
nodamage = 0
hitsound = 'sound/effects/curseattack.ogg'
range = 15
/obj/item/projectile/magic/spell/rust_wave/Moved(atom/OldLoc, Dir)
. = ..()
playsound(src, 'sound/items/welder.ogg', 75, TRUE)
var/list/turflist = list()
var/turf/T1
turflist += get_turf(src)
T1 = get_step(src,turn(dir,90))
turflist += T1
turflist += get_step(T1,turn(dir,90))
T1 = get_step(src,turn(dir,-90))
turflist += T1
turflist += get_step(T1,turn(dir,-90))
for(var/X in turflist)
if(!X || prob(25))
continue
var/turf/T = X
T.rust_heretic_act()
/obj/effect/proc_holder/spell/aimed/rust_wave/short
name = "Small Patron's Reach"
projectile_type = /obj/item/projectile/magic/spell/rust_wave/short
/obj/item/projectile/magic/spell/rust_wave/short
range = 7
/obj/effect/proc_holder/spell/pointed/cleave
name = "Cleave"
desc = "Causes severe bleeding on a target and people around them"
school = "transmutation"
charge_max = 350
clothes_req = FALSE
invocation = "PLES'TI VI'RIBUS"
invocation_type = "whisper"
range = 9
action_icon = 'icons/mob/actions/actions_ecult.dmi'
action_icon_state = "cleave"
action_background_icon_state = "bg_ecult"
/obj/effect/proc_holder/spell/pointed/cleave/cast(list/targets, mob/user)
if(!targets.len)
to_chat(user, "<span class='warning'>No target found in range!</span>")
return FALSE
if(!can_target(targets[1], user))
return FALSE
for(var/mob/living/carbon/human/C in range(1,targets[1]))
targets |= C
for(var/X in targets)
var/mob/living/carbon/human/target = X
if(target == user)
continue
if(target.anti_magic_check())
to_chat(user, "<span class='warning'>The spell had no effect!</span>")
target.visible_message("<span class='danger'>[target]'s veins flash with fire, but their magic protection repulses the blaze!</span>", \
"<span class='danger'>Your veins flash with fire, but your magic protection repels the blaze!</span>")
continue
target.visible_message("<span class='danger'>[target]'s veins are shredded from within as an unholy blaze erupts from their blood!</span>", \
"<span class='danger'>Your veins burst from within and unholy flame erupts from your blood!</span>")
var/obj/item/bodypart/bodypart = pick(target.bodyparts)
var/datum/wound/slash/critical/crit_wound = new
crit_wound.apply_wound(bodypart)
target.adjustFireLoss(20)
new /obj/effect/temp_visual/cleave(target.drop_location())
/obj/effect/proc_holder/spell/pointed/cleave/can_target(atom/target, mob/user, silent)
. = ..()
if(!.)
return FALSE
if(!istype(target,/mob/living/carbon/human))
if(!silent)
to_chat(user, "<span class='warning'>You are unable to cleave [target]!</span>")
return FALSE
return TRUE
/obj/effect/proc_holder/spell/pointed/cleave/long
charge_max = 650
/obj/effect/proc_holder/spell/pointed/touch/mad_touch
name = "Touch of Madness"
desc = "Touch spell that drains your enemies sanity."
school = "transmutation"
charge_max = 150
clothes_req = FALSE
invocation_type = "none"
range = 2
action_icon = 'icons/mob/actions/actions_ecult.dmi'
action_icon_state = "mad_touch"
action_background_icon_state = "bg_ecult"
/obj/effect/proc_holder/spell/pointed/touch/mad_touch/can_target(atom/target, mob/user, silent)
. = ..()
if(!.)
return FALSE
if(!istype(target,/mob/living/carbon/human))
if(!silent)
to_chat(user, "<span class='warning'>You are unable to touch [target]!</span>")
return FALSE
return TRUE
/obj/effect/proc_holder/spell/pointed/touch/mad_touch/cast(list/targets, mob/user)
. = ..()
for(var/mob/living/carbon/target in targets)
if(ishuman(targets))
var/mob/living/carbon/human/tar = target
if(tar.anti_magic_check())
tar.visible_message("<span class='danger'>Spell bounces off of [target]!</span>","<span class='danger'>The spell bounces off of you!</span>")
return
if(target.mind && !target.mind.has_antag_datum(/datum/antagonist/heretic))
to_chat(user,"<span class='warning'>[target.name] has been cursed!</span>")
SEND_SIGNAL(target, COMSIG_ADD_MOOD_EVENT, "gates_of_mansus", /datum/mood_event/gates_of_mansus)
/obj/effect/proc_holder/spell/pointed/ash_final
name = "Nightwatcher's Rite"
desc = "Powerful spell that releases 5 streams of fire away from you."
school = "transmutation"
invocation = "IGNIS'INTI"
invocation_type = "whisper"
charge_max = 300
range = 15
clothes_req = FALSE
action_icon = 'icons/mob/actions/actions_ecult.dmi'
action_icon_state = "flames"
action_background_icon_state = "bg_ecult"
/obj/effect/proc_holder/spell/pointed/ash_final/cast(list/targets, mob/user)
for(var/X in targets)
var/T
T = line_target(-25, range, X, user)
INVOKE_ASYNC(src, .proc/fire_line, user,T)
T = line_target(10, range, X, user)
INVOKE_ASYNC(src, .proc/fire_line, user,T)
T = line_target(0, range, X, user)
INVOKE_ASYNC(src, .proc/fire_line, user,T)
T = line_target(-10, range, X, user)
INVOKE_ASYNC(src, .proc/fire_line, user,T)
T = line_target(25, range, X, user)
INVOKE_ASYNC(src, .proc/fire_line, user,T)
return ..()
/obj/effect/proc_holder/spell/pointed/ash_final/proc/line_target(offset, range, atom/at , atom/user)
if(!at)
return
var/angle = ATAN2(at.x - user.x, at.y - user.y) + offset
var/turf/T = get_turf(user)
for(var/i in 1 to range)
var/turf/check = locate(user.x + cos(angle) * i, user.y + sin(angle) * i, user.z)
if(!check)
break
T = check
return (getline(user, T) - get_turf(user))
/obj/effect/proc_holder/spell/pointed/ash_final/proc/fire_line(atom/source, list/turfs)
var/list/hit_list = list()
for(var/turf/T in turfs)
if(istype(T, /turf/closed))
break
for(var/mob/living/L in T.contents)
if(L.anti_magic_check())
L.visible_message("<span class='danger'>Spell bounces off of [L]!</span>","<span class='danger'>The spell bounces off of you!</span>")
continue
if(L in hit_list || L == source)
continue
hit_list += L
L.adjustFireLoss(20)
to_chat(L, "<span class='userdanger'>You're hit by [source]'s fire breath!</span>")
new /obj/effect/hotspot(T)
T.hotspot_expose(700,50,1)
// deals damage to mechs
for(var/obj/mecha/M in T.contents)
if(M in hit_list)
continue
hit_list += M
M.take_damage(45, BURN, "melee", 1)
sleep(1.5)
/obj/effect/proc_holder/spell/targeted/shapeshift/eldritch
invocation_type = "none"
clothes_req = FALSE
action_background_icon_state = "bg_ecult"
sound = 'sound/magic/enter_blood.ogg'
possible_shapes = list(/mob/living/simple_animal/mouse,\
/mob/living/simple_animal/pet/dog/corgi,\
/mob/living/simple_animal/hostile/carp,\
/mob/living/simple_animal/bot/secbot, \
/mob/living/simple_animal/pet/fox,\
/mob/living/simple_animal/pet/cat )
/obj/effect/proc_holder/spell/targeted/emplosion/eldritch
name = "Energetic Pulse"
invocation_type = "none"
clothes_req = FALSE
action_background_icon_state = "bg_ecult"
range = -1
include_user = TRUE
charge_max = 300
emp_heavy = 6
emp_light = 10
sound = 'sound/effects/lingscreech.ogg'
/obj/effect/proc_holder/spell/aoe_turf/fire_cascade
name = "Fire Cascade"
desc = "creates hot turfs around you."
school = "transmutation"
charge_max = 300 //twice as long as mansus grasp
clothes_req = FALSE
invocation = "IGNIS'SAVARIN"
invocation_type = "whisper"
range = 4
action_icon = 'icons/mob/actions/actions_ecult.dmi'
action_icon_state = "fire_ring"
action_background_icon_state = "bg_ecult"
/obj/effect/proc_holder/spell/aoe_turf/fire_cascade/cast(list/targets, mob/user = usr)
INVOKE_ASYNC(src, .proc/fire_cascade, user,range)
/obj/effect/proc_holder/spell/aoe_turf/fire_cascade/proc/fire_cascade(atom/centre,max_range)
playsound(get_turf(centre), 'sound/items/welder.ogg', 75, TRUE)
var/_range = 1
for(var/i = 0, i <= max_range,i++)
for(var/turf/T in spiral_range_turfs(_range,centre))
new /obj/effect/hotspot(T)
T.hotspot_expose(700,50,1)
for(var/mob/living/livies in T.contents - centre)
livies.adjustFireLoss(10)
_range++
sleep(3)
/obj/effect/proc_holder/spell/aoe_turf/fire_cascade/big
range = 6
/obj/effect/proc_holder/spell/targeted/telepathy/eldritch
invocation = ""
invocation_type = "whisper"
clothes_req = FALSE
action_background_icon_state = "bg_ecult"
/obj/effect/proc_holder/spell/targeted/fire_sworn
name = "Oath of Fire"
desc = "For a minute you will passively create a ring of fire around you."
invocation = "IGNIS'AISTRA'LISTRE"
invocation_type = "whisper"
clothes_req = FALSE
action_background_icon_state = "bg_ecult"
range = -1
include_user = TRUE
charge_max = 700
action_icon = 'icons/mob/actions/actions_ecult.dmi'
action_icon_state = "fire_ring"
///how long it lasts
var/duration = 1 MINUTES
///who casted it right now
var/mob/current_user
///Determines if you get the fire ring effect
var/has_fire_ring = FALSE
/obj/effect/proc_holder/spell/targeted/fire_sworn/cast(list/targets, mob/user)
. = ..()
current_user = user
has_fire_ring = TRUE
addtimer(CALLBACK(src, .proc/remove, user), duration, TIMER_OVERRIDE|TIMER_UNIQUE)
/obj/effect/proc_holder/spell/targeted/fire_sworn/proc/remove()
has_fire_ring = FALSE
/obj/effect/proc_holder/spell/targeted/fire_sworn/process()
. = ..()
if(!has_fire_ring)
return
for(var/turf/T in range(1,current_user))
new /obj/effect/hotspot(T)
T.hotspot_expose(700,50,1)
for(var/mob/living/livies in T.contents - current_user)
livies.adjustFireLoss(5)
/obj/effect/proc_holder/spell/targeted/worm_contract
name = "Force Contract"
desc = "Forces all the worm parts to collapse onto a single turf"
invocation_type = "none"
clothes_req = FALSE
action_background_icon_state = "bg_ecult"
range = -1
include_user = TRUE
charge_max = 300
action_icon = 'icons/mob/actions/actions_ecult.dmi'
action_icon_state = "worm_contract"
/obj/effect/proc_holder/spell/targeted/worm_contract/cast(list/targets, mob/user)
. = ..()
if(!istype(user,/mob/living/simple_animal/hostile/eldritch/armsy))
to_chat(user, "<span class='userdanger'>You try to contract your muscles but nothing happens...</span>")
var/mob/living/simple_animal/hostile/eldritch/armsy/armsy = user
armsy.contract_next_chain_into_single_tile()
/obj/effect/temp_visual/cleave
icon = 'icons/effects/eldritch.dmi'
icon_state = "cleave"
duration = 6
/obj/effect/temp_visual/eldritch_smoke
icon = 'icons/effects/eldritch.dmi'
icon_state = "smoke"
duration = 10
/obj/effect/proc_holder/spell/targeted/fiery_rebirth
name = "Nightwatcher's Rebirth"
desc = "Drains nearby alive people that are engulfed in flames. It heals 10 of each damage type per person. If a person is in critical condition it finishes them off."
invocation = "PETHRO'MINO'IGNI"
invocation_type = "whisper"
clothes_req = FALSE
action_background_icon_state = "bg_ecult"
range = -1
include_user = TRUE
charge_max = 600
action_icon = 'icons/mob/actions/actions_ecult.dmi'
action_icon_state = "smoke"
/obj/effect/proc_holder/spell/targeted/fiery_rebirth/cast(list/targets, mob/user)
if(!ishuman(user))
return
var/mob/living/carbon/human/human_user = user
for(var/mob/living/carbon/target in view(7,user))
if(target.stat == DEAD || !target.on_fire)
continue
//This is essentially a death mark, use this to finish your opponent quicker.
if(target.InCritical())
target.death()
target.adjustFireLoss(20)
new /obj/effect/temp_visual/eldritch_smoke(target.drop_location())
human_user.ExtinguishMob()
human_user.adjustBruteLoss(-10, FALSE)
human_user.adjustFireLoss(-10, FALSE)
human_user.adjustStaminaLoss(-10, FALSE)
human_user.adjustToxLoss(-10, FALSE)
human_user.adjustOxyLoss(-10)
/obj/effect/proc_holder/spell/pointed/manse_link
name = "Mansus Link"
desc = "Piercing through reality, connecting minds. This spell allows you to add people to a mansus net, allowing them to communicate with eachother"
school = "transmutation"
charge_max = 300
clothes_req = FALSE
invocation = "SUSEI' METO MIN'TIS"
invocation_type = "whisper"
range = 10
action_icon = 'icons/mob/actions/actions_ecult.dmi'
action_icon_state = "mansus_link"
action_background_icon_state = "bg_ecult"
/obj/effect/proc_holder/spell/pointed/manse_link/can_target(atom/target, mob/user, silent)
if(!isliving(target))
return FALSE
return TRUE
/obj/effect/proc_holder/spell/pointed/manse_link/cast(list/targets, mob/user)
var/mob/living/simple_animal/hostile/eldritch/raw_prophet/originator = user
var/mob/living/target = targets[1]
to_chat(originator, "<span class='notice'>You begin linking [target]'s mind to yours...</span>")
to_chat(target, "<span class='warning'>You feel your mind being pulled... connected... intertwined with the very fabric of reality...</span>")
if(!do_after(originator, 6 SECONDS, target))
return
if(!originator.link_mob(target))
to_chat(originator, "<span class='warning'>You can't seem to link [target]'s mind...</span>")
to_chat(target, "<span class='warning'>The foreign presence leaves your mind.</span>")
return
to_chat(originator, "<span class='notice'>You connect [target]'s mind to your mansus link!</span>")
/datum/action/innate/mansus_speech
name = "Mansus Link"
desc = "Send a psychic message to everyone connected to your mansus link."
button_icon_state = "link_speech"
icon_icon = 'icons/mob/actions/actions_slime.dmi'
background_icon_state = "bg_ecult"
var/mob/living/simple_animal/hostile/eldritch/raw_prophet/originator
/datum/action/innate/mansus_speech/New(_originator)
. = ..()
originator = _originator
/datum/action/innate/mansus_speech/Activate()
var/mob/living/living_owner = owner
if(!originator?.linked_mobs[living_owner])
CRASH("Uh oh the mansus link got somehow activated without it being linked to a raw prophet or the mob not being in a list of mobs that should be able to do it.")
var/message = sanitize(input("Message:", "Telepathy from the Manse") as text|null)
if(QDELETED(living_owner))
return
if(!originator?.linked_mobs[living_owner])
to_chat(living_owner, "<span class='warning'>The link seems to have been severed...</span>")
Remove(living_owner)
return
if(message)
var/msg = "<i><font color=#568b00>\[Mansus Link\] <b>[living_owner]:</b> [message]</font></i>"
log_directed_talk(living_owner, originator, msg, LOG_SAY, "Mansus Link")
to_chat(originator.linked_mobs, msg)
for(var/dead_mob in GLOB.dead_mob_list)
var/link = FOLLOW_LINK(dead_mob, living_owner)
to_chat(dead_mob, "[link] [msg]")
/obj/effect/proc_holder/spell/pointed/trigger/blind/eldritch
range = 10
invocation = "AK'LIS"
action_background_icon_state = "bg_ecult"
/obj/effect/temp_visual/dir_setting/entropic
icon = 'icons/effects/160x160.dmi'
icon_state = "entropic_plume"
duration = 3 SECONDS
/obj/effect/temp_visual/dir_setting/entropic/setDir(dir)
. = ..()
switch(dir)
if(NORTH)
pixel_x = -64
if(SOUTH)
pixel_x = -64
pixel_y = -128
if(EAST)
pixel_y = -64
if(WEST)
pixel_y = -64
pixel_x = -128
/obj/effect/temp_visual/glowing_rune
icon = 'icons/effects/eldritch.dmi'
icon_state = "small_rune_1"
duration = 1 MINUTES
layer = LOW_SIGIL_LAYER
/obj/effect/temp_visual/glowing_rune/Initialize()
. = ..()
pixel_y = rand(-6,6)
pixel_x = rand(-6,6)
icon_state = "small_rune_[rand(12)]"
update_icon()
/obj/effect/proc_holder/spell/cone/staggered/entropic_plume
name = "Entropic Plume"
desc = "Spews forth a disorienting plume that causes enemies to strike each other, briefly blinds them(increasing with range) and poisons them(decreasing with range). Also spreads rust in the path of the plume."
school = "illusion"
invocation = "RU'KAS NU'DYTI"
invocation_type = "whisper"
clothes_req = FALSE
action_background_icon_state = "bg_ecult"
action_icon = 'icons/mob/actions/actions_ecult.dmi'
action_icon_state = "entropic_plume"
charge_max = 300
cone_levels = 5
respect_density = TRUE
/obj/effect/proc_holder/spell/cone/staggered/entropic_plume/cast(list/targets,mob/user = usr)
. = ..()
new /obj/effect/temp_visual/dir_setting/entropic(get_step(user,user.dir), user.dir)
/obj/effect/proc_holder/spell/cone/staggered/entropic_plume/do_turf_cone_effect(turf/target_turf, level)
. = ..()
target_turf.rust_heretic_act()
/obj/effect/proc_holder/spell/cone/staggered/entropic_plume/do_mob_cone_effect(mob/living/victim, level)
. = ..()
if(victim.anti_magic_check() || IS_HERETIC(victim) || victim.mind?.has_antag_datum(/datum/antagonist/heretic_monster))
return
victim.apply_status_effect(STATUS_EFFECT_AMOK)
victim.apply_status_effect(STATUS_EFFECT_CLOUDSTRUCK, (level*10))
if(iscarbon(victim))
var/mob/living/carbon/carbon_victim = victim
carbon_victim.reagents.add_reagent(/datum/reagent/eldritch, min(1, 6-level))
/obj/effect/proc_holder/spell/cone/staggered/entropic_plume/calculate_cone_shape(current_level)
if(current_level == cone_levels)
return 5
else if(current_level == cone_levels-1)
return 3
else
return 2

View File

@@ -0,0 +1,43 @@
///Tracking reasons
/datum/antagonist/heretic_monster
name = "Eldritch Horror"
roundend_category = "Heretics"
antagpanel_category = "Heretic Beast"
antag_moodlet = /datum/mood_event/heretics
job_rank = ROLE_HERETIC
antag_hud_type = ANTAG_HUD_HERETIC
antag_hud_name = "heretic_beast"
var/datum/antagonist/master
/datum/antagonist/heretic_monster/admin_add(datum/mind/new_owner,mob/admin)
new_owner.add_antag_datum(src)
message_admins("[key_name_admin(admin)] has heresized [key_name_admin(new_owner)].")
log_admin("[key_name(admin)] has heresized [key_name(new_owner)].")
/datum/antagonist/heretic_monster/greet()
owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/ecult_op.ogg', 100, FALSE, pressure_affected = FALSE)//subject to change
to_chat(owner, "<span class='boldannounce'>You became an Eldritch Horror!</span>")
/datum/antagonist/heretic_monster/on_removal()
if(owner)
to_chat(owner, "<span class='boldannounce'>Your master is no longer [master.owner.current.real_name]</span>")
owner = null
return ..()
/datum/antagonist/heretic_monster/proc/set_owner(datum/antagonist/_master)
master = _master
var/datum/objective/master_obj = new
master_obj.owner = src
master_obj.explanation_text = "Assist your master in any way you can!"
objectives += master_obj
owner.announce_objectives()
to_chat(owner, "<span class='boldannounce'>Your master is [master.owner.current.real_name]</span>")
return
/datum/antagonist/heretic_monster/apply_innate_effects(mob/living/mob_override)
. = ..()
add_antag_hud(antag_hud_type, antag_hud_name, owner.current)
/datum/antagonist/heretic_monster/remove_innate_effects(mob/living/mob_override)
. = ..()
remove_antag_hud(antag_hud_type, owner.current)

View File

@@ -0,0 +1,183 @@
/datum/eldritch_knowledge/base_ash
name = "Nightwatcher's Secret"
desc = "Inducts you into the Path of Ash. Allows you to transmute a match with an eldritch blade into an ashen blade."
gain_text = "The City guard knows their watch. If you ask them at night they may tell you about the ashy lantern."
banned_knowledge = list(/datum/eldritch_knowledge/base_rust,/datum/eldritch_knowledge/base_flesh,/datum/eldritch_knowledge/final/rust_final,/datum/eldritch_knowledge/final/flesh_final)
next_knowledge = list(/datum/eldritch_knowledge/ashen_grasp)
required_atoms = list(/obj/item/melee/sickly_blade,/obj/item/match)
result_atoms = list(/obj/item/melee/sickly_blade/ash)
cost = 1
route = PATH_ASH
/datum/eldritch_knowledge/spell/ashen_shift
name = "Ashen Shift"
gain_text = "Ash is all the same, how can one man master it all?"
desc = "A short range jaunt that will enable you to escape from danger."
cost = 1
spell_to_add = /obj/effect/proc_holder/spell/targeted/ethereal_jaunt/shift/ash
next_knowledge = list(/datum/eldritch_knowledge/ash_mark,/datum/eldritch_knowledge/essence,/datum/eldritch_knowledge/ashen_eyes)
route = PATH_ASH
/datum/eldritch_knowledge/ashen_grasp
name = "Grasp of Ash"
gain_text = "Gates have opened, minds have flooded, yet I remain."
desc = "Empowers your mansus grasp to knock enemies down and throw them away."
cost = 1
next_knowledge = list(/datum/eldritch_knowledge/spell/ashen_shift)
route = PATH_ASH
/datum/eldritch_knowledge/ashen_grasp/on_mansus_grasp(atom/target, mob/user, proximity_flag, click_parameters)
. = ..()
if(!iscarbon(target))
return
var/mob/living/carbon/C = target
var/datum/status_effect/eldritch/E = C.has_status_effect(/datum/status_effect/eldritch/rust) || C.has_status_effect(/datum/status_effect/eldritch/ash) || C.has_status_effect(/datum/status_effect/eldritch/flesh)
if(E)
. = TRUE
E.on_effect()
for(var/X in user.mind.spell_list)
if(!istype(X,/obj/effect/proc_holder/spell/targeted/touch/mansus_grasp))
continue
var/obj/effect/proc_holder/spell/targeted/touch/mansus_grasp/MG = X
MG.charge_counter = min(round(MG.charge_counter + MG.charge_max * 0.75),MG.charge_max) // refunds 75% of charge.
var/atom/throw_target = get_edge_target_turf(C, user.dir)
if(!C.anchored)
. = TRUE
C.throw_at(throw_target, rand(4,8), 14, user)
return
/datum/eldritch_knowledge/ashen_eyes
name = "Ashen Eyes"
gain_text = "Piercing eyes may guide me through the mundane."
desc = "Allows you to craft thermal vision amulet by transmutating eyes with a glass shard."
cost = 1
next_knowledge = list(/datum/eldritch_knowledge/spell/ashen_shift,/datum/eldritch_knowledge/flesh_ghoul)
required_atoms = list(/obj/item/organ/eyes,/obj/item/shard)
result_atoms = list(/obj/item/clothing/neck/eldritch_amulet)
/datum/eldritch_knowledge/ash_mark
name = "Mark of Ash"
gain_text = "Spread the famine."
desc = "Your sickly blade now applies ash mark on hit. Use your mansus grasp to proc the mark. Mark of Ash causes stamina damage, and fire loss, and spreads to a nearby carbon. Damage decreases with how many times the mark has spread."
cost = 2
next_knowledge = list(/datum/eldritch_knowledge/curse/blindness)
banned_knowledge = list(/datum/eldritch_knowledge/rust_mark,/datum/eldritch_knowledge/flesh_mark)
route = PATH_ASH
/datum/eldritch_knowledge/ash_mark/on_eldritch_blade(target,user,proximity_flag,click_parameters)
. = ..()
if(isliving(target))
var/mob/living/living_target = target
living_target.apply_status_effect(/datum/status_effect/eldritch/ash,5)
/datum/eldritch_knowledge/curse/blindness
name = "Curse of Blindness"
gain_text = "The blind man walks through the world, unnoticed by the masses."
desc = "Curse someone with 2 minutes of complete blindness by sacrificing a pair of eyes, a screwdriver and a pool of blood, with an object that the victim has touched with their bare hands."
cost = 1
required_atoms = list(/obj/item/organ/eyes,/obj/item/screwdriver,/obj/effect/decal/cleanable/blood)
next_knowledge = list(/datum/eldritch_knowledge/curse/corrosion,/datum/eldritch_knowledge/ash_blade_upgrade,/datum/eldritch_knowledge/curse/paralysis)
timer = 2 MINUTES
route = PATH_ASH
/datum/eldritch_knowledge/curse/blindness/curse(mob/living/chosen_mob)
. = ..()
chosen_mob.become_blind(MAGIC_TRAIT)
/datum/eldritch_knowledge/curse/blindness/uncurse(mob/living/chosen_mob)
. = ..()
chosen_mob.cure_blind(MAGIC_TRAIT)
/datum/eldritch_knowledge/spell/flame_birth
name = "Fiery Rebirth"
gain_text = "Nightwatcher was a man of principles, and yet he arose from the chaos he vowed to protect from."
desc = "Drains nearby alive people that are engulfed in flames. It heals 10 of each damage type per person. If a person is in critical condition it finishes them off."
cost = 1
spell_to_add = /obj/effect/proc_holder/spell/targeted/fiery_rebirth
next_knowledge = list(/datum/eldritch_knowledge/spell/cleave,/datum/eldritch_knowledge/summon/ashy,/datum/eldritch_knowledge/final/ash_final)
route = PATH_ASH
/datum/eldritch_knowledge/ash_blade_upgrade
name = "Blazing Steel"
gain_text = "May the sun burn the heretics."
desc = "Your blade of choice will now add firestacks."
cost = 2
next_knowledge = list(/datum/eldritch_knowledge/spell/flame_birth)
banned_knowledge = list(/datum/eldritch_knowledge/rust_blade_upgrade,/datum/eldritch_knowledge/flesh_blade_upgrade)
route = PATH_ASH
/datum/eldritch_knowledge/ash_blade_upgrade/on_eldritch_blade(target,user,proximity_flag,click_parameters)
. = ..()
if(iscarbon(target))
var/mob/living/carbon/C = target
C.adjust_fire_stacks(1)
C.IgniteMob()
/datum/eldritch_knowledge/curse/corrosion
name = "Curse of Corrosion"
gain_text = "Cursed land, cursed man, cursed mind."
desc = "Curse someone for 2 minutes of vomiting and major organ damage. Using a wirecutter, a spill of blood, a heart, left arm and a right arm, and an item that the victim touched with their bare hands."
cost = 1
required_atoms = list(/obj/item/wirecutters,/obj/effect/decal/cleanable/blood,/obj/item/organ/heart,/obj/item/bodypart/l_arm,/obj/item/bodypart/r_arm)
next_knowledge = list(/datum/eldritch_knowledge/curse/blindness,/datum/eldritch_knowledge/spell/area_conversion)
timer = 2 MINUTES
/datum/eldritch_knowledge/curse/corrosion/curse(mob/living/chosen_mob)
. = ..()
chosen_mob.apply_status_effect(/datum/status_effect/corrosion_curse)
/datum/eldritch_knowledge/curse/corrosion/uncurse(mob/living/chosen_mob)
. = ..()
chosen_mob.remove_status_effect(/datum/status_effect/corrosion_curse)
/datum/eldritch_knowledge/curse/paralysis
name = "Curse of Paralysis"
gain_text = "Corrupt their flesh, make them bleed."
desc = "Curse someone for 5 minutes of inability to walk. Using a knife, pool of blood, left leg, right leg, a hatchet and an item that the victim touched with their bare hands. "
cost = 1
required_atoms = list(/obj/item/kitchen/knife,/obj/effect/decal/cleanable/blood,/obj/item/bodypart/l_leg,/obj/item/bodypart/r_leg,/obj/item/hatchet)
next_knowledge = list(/datum/eldritch_knowledge/curse/blindness,/datum/eldritch_knowledge/summon/raw_prophet)
timer = 5 MINUTES
/datum/eldritch_knowledge/curse/paralysis/curse(mob/living/chosen_mob)
. = ..()
ADD_TRAIT(chosen_mob,TRAIT_PARALYSIS_L_LEG,MAGIC_TRAIT)
ADD_TRAIT(chosen_mob,TRAIT_PARALYSIS_R_LEG,MAGIC_TRAIT)
chosen_mob.update_mobility()
/datum/eldritch_knowledge/curse/paralysis/uncurse(mob/living/chosen_mob)
. = ..()
REMOVE_TRAIT(chosen_mob,TRAIT_PARALYSIS_L_LEG,MAGIC_TRAIT)
REMOVE_TRAIT(chosen_mob,TRAIT_PARALYSIS_R_LEG,MAGIC_TRAIT)
chosen_mob.update_mobility()
/datum/eldritch_knowledge/spell/cleave
name = "Blood Cleave"
gain_text = "At first I was unfamiliar with these instruments of war, but the priest told me how to use them."
desc = "Grants a spell that will inflict wounds and bleeding upon the target, as well as in a short radius around them."
cost = 1
spell_to_add = /obj/effect/proc_holder/spell/pointed/cleave
next_knowledge = list(/datum/eldritch_knowledge/spell/entropic_plume,/datum/eldritch_knowledge/spell/flame_birth)
/datum/eldritch_knowledge/final/ash_final
name = "Ashlord's Rite"
gain_text = "The forgotten lords have spoken! The Lord of Ash has come! Fear the flame!"
desc = "Bring three corpses onto a transmutation rune, after ascending you will become immune to fire, space, temperature and other environmental hazards. You will develop resistance to all other damages. You will be granted two spells, one which can bring forth a cascade of massive fire, and another which will surround your body in precious flames for a minute."
required_atoms = list(/mob/living/carbon/human)
cost = 5
route = PATH_ASH
var/list/trait_list = list(TRAIT_RESISTHEAT,TRAIT_NOBREATH,TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_NOFIRE,TRAIT_RADIMMUNE,TRAIT_GENELESS,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER,TRAIT_BOMBIMMUNE)
/datum/eldritch_knowledge/final/ash_final/on_finished_recipe(mob/living/user, list/atoms, loc)
priority_announce("$^@&#*$^@(#&$(@&#^$&#^@# Fear the blaze, for Ashbringer [user.real_name] has come! $^@&#*$^@(#&$(@&#^$&#^@#","#$^@&#*$^@(#&$(@&#^$&#^@#", 'sound/announcer/classic/spanomalies.ogg')
user.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/fire_cascade/big)
user.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/fire_sworn)
var/mob/living/carbon/human/H = user
H.physiology.brute_mod *= 0.5
H.physiology.burn_mod *= 0.5
var/datum/antagonist/heretic/ascension = H.mind.has_antag_datum(/datum/antagonist/heretic)
ascension.ascended = TRUE
for(var/X in trait_list)
ADD_TRAIT(user,X,MAGIC_TRAIT)
return ..()

View File

@@ -0,0 +1,252 @@
/datum/eldritch_knowledge/base_flesh
name = "Principle of Hunger"
desc = "Inducts you into the Path of Flesh. Allows you to transmute a pool of blood with your eldritch blade into a Blade of Flesh."
gain_text = "Hundred's of us starved, but I.. I found the strength in my greed."
banned_knowledge = list(/datum/eldritch_knowledge/base_ash,/datum/eldritch_knowledge/base_rust,/datum/eldritch_knowledge/final/ash_final,/datum/eldritch_knowledge/final/rust_final)
next_knowledge = list(/datum/eldritch_knowledge/flesh_grasp)
required_atoms = list(/obj/item/melee/sickly_blade,/obj/effect/decal/cleanable/blood)
result_atoms = list(/obj/item/melee/sickly_blade/flesh)
cost = 1
route = PATH_FLESH
/datum/eldritch_knowledge/flesh_ghoul
name = "Imperfect Ritual"
desc = "Allows you to resurrect the dead as voiceless dead by sacrificing them on the transmutation rune with a poppy. Voiceless dead are mute and have 50 HP. You can only have 2 at a time."
gain_text = "I found notes... notes of a ritual, scraps, unfinished, and yet... I still did it."
cost = 1
required_atoms = list(/mob/living/carbon/human,/obj/item/reagent_containers/food/snacks/grown/poppy)
next_knowledge = list(/datum/eldritch_knowledge/flesh_mark,/datum/eldritch_knowledge/armor,/datum/eldritch_knowledge/ashen_eyes)
route = PATH_FLESH
var/max_amt = 2
var/current_amt = 0
var/list/ghouls = list()
/datum/eldritch_knowledge/flesh_ghoul/on_finished_recipe(mob/living/user,list/atoms,loc)
var/mob/living/carbon/human/humie = locate() in atoms
if(QDELETED(humie) || humie.stat != DEAD)
return
if(length(ghouls) >= max_amt)
return
if(HAS_TRAIT(humie,TRAIT_HUSK))
return
humie.grab_ghost()
if(!humie.mind || !humie.client)
var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as a [humie.real_name], a voiceless dead.", ROLE_HERETIC, null, ROLE_HERETIC, 50,humie)
if(!LAZYLEN(candidates))
return
var/mob/dead/observer/C = pick(candidates)
message_admins("[key_name_admin(C)] has taken control of ([key_name_admin(humie)]) to replace an AFK player.")
humie.ghostize(0)
humie.key = C.key
ADD_TRAIT(humie,TRAIT_MUTE,MAGIC_TRAIT)
log_game("[key_name_admin(humie)] has become a voiceless dead, their master is [user.real_name]")
humie.revive(full_heal = TRUE, admin_revive = TRUE)
humie.setMaxHealth(75)
humie.health = 75 // Voiceless dead are much tougher than ghouls
humie.become_husk()
humie.faction |= "heretics"
var/datum/antagonist/heretic_monster/heretic_monster = humie.mind.add_antag_datum(/datum/antagonist/heretic_monster)
var/datum/antagonist/heretic/master = user.mind.has_antag_datum(/datum/antagonist/heretic)
heretic_monster.set_owner(master)
atoms -= humie
RegisterSignal(humie,COMSIG_MOB_DEATH,.proc/remove_ghoul)
ghouls += humie
/datum/eldritch_knowledge/flesh_ghoul/proc/remove_ghoul(datum/source)
var/mob/living/carbon/human/humie = source
ghouls -= humie
humie.mind.remove_antag_datum(/datum/antagonist/heretic_monster)
UnregisterSignal(source,COMSIG_MOB_DEATH)
/datum/eldritch_knowledge/flesh_grasp
name = "Grasp of Flesh"
gain_text = "'My newfound desire, it drove me to do great things,' The Priest said."
desc = "Empowers your Mansus Grasp to be able to create a single ghoul out of a dead player. You cannot raise the same person twice. Ghouls have only 50 HP and look like husks."
cost = 1
next_knowledge = list(/datum/eldritch_knowledge/flesh_ghoul)
var/ghoul_amt = 6
var/list/spooky_scaries
route = PATH_FLESH
/datum/eldritch_knowledge/flesh_grasp/on_mansus_grasp(atom/target, mob/user, proximity_flag, click_parameters)
. = ..()
if(!ishuman(target) || target == user)
return
var/mob/living/carbon/human/human_target = target
var/datum/status_effect/eldritch/eldritch_effect = human_target.has_status_effect(/datum/status_effect/eldritch/rust) || human_target.has_status_effect(/datum/status_effect/eldritch/ash) || human_target.has_status_effect(/datum/status_effect/eldritch/flesh)
if(eldritch_effect)
. = TRUE
eldritch_effect.on_effect()
if(iscarbon(target))
var/mob/living/carbon/carbon_target = target
var/obj/item/bodypart/bodypart = pick(carbon_target.bodyparts)
var/datum/wound/slash/severe/crit_wound = new
crit_wound.apply_wound(bodypart)
if(QDELETED(human_target) || human_target.stat != DEAD)
return
human_target.grab_ghost()
if(!human_target.mind || !human_target.client)
to_chat(user, "<span class='warning'>There is no soul connected to this body...</span>")
return
if(HAS_TRAIT(human_target, TRAIT_HUSK))
to_chat(user, "<span class='warning'>You cannot revive a dead ghoul!</span>")
return
if(LAZYLEN(spooky_scaries) >= ghoul_amt)
to_chat(user, "<span class='warning'>Your patron cannot support more ghouls on this plane!</span>")
return
LAZYADD(spooky_scaries, human_target)
log_game("[key_name_admin(human_target)] has become a ghoul, their master is [user.real_name]")
//we change it to true only after we know they passed all the checks
. = TRUE
RegisterSignal(human_target,COMSIG_MOB_DEATH,.proc/remove_ghoul)
human_target.revive(full_heal = TRUE, admin_revive = TRUE)
human_target.setMaxHealth(40)
human_target.health = 40
human_target.become_husk()
human_target.faction |= "heretics"
var/datum/antagonist/heretic_monster/heretic_monster = human_target.mind.add_antag_datum(/datum/antagonist/heretic_monster)
var/datum/antagonist/heretic/master = user.mind.has_antag_datum(/datum/antagonist/heretic)
heretic_monster.set_owner(master)
return
/datum/eldritch_knowledge/flesh_grasp/proc/remove_ghoul(datum/source)
var/mob/living/carbon/human/humie = source
spooky_scaries -= humie
humie.mind.remove_antag_datum(/datum/antagonist/heretic_monster)
UnregisterSignal(source, COMSIG_MOB_DEATH)
/datum/eldritch_knowledge/flesh_mark
name = "Mark of Flesh"
gain_text = "I saw them, the marked ones. The screams... the silence."
desc = "Your sickly blade now applies a mark of flesh to those cut by it. Once marked, using your Mansus Grasp upon them will cause additional bleeding from the target."
cost = 2
next_knowledge = list(/datum/eldritch_knowledge/summon/raw_prophet)
banned_knowledge = list(/datum/eldritch_knowledge/rust_mark,/datum/eldritch_knowledge/ash_mark)
route = PATH_FLESH
/datum/eldritch_knowledge/flesh_mark/on_eldritch_blade(target,user,proximity_flag,click_parameters)
. = ..()
if(isliving(target))
var/mob/living/living_target = target
living_target.apply_status_effect(/datum/status_effect/eldritch/flesh)
/datum/eldritch_knowledge/flesh_blade_upgrade
name = "Bleeding Steel"
gain_text = "It rained blood, that's when I understood the gravekeeper's advice."
desc = "Your blade will now cause additional bleeding to those hit by it."
cost = 2
next_knowledge = list(/datum/eldritch_knowledge/summon/stalker)
banned_knowledge = list(/datum/eldritch_knowledge/ash_blade_upgrade,/datum/eldritch_knowledge/rust_blade_upgrade)
route = PATH_FLESH
/datum/eldritch_knowledge/flesh_blade_upgrade/on_eldritch_blade(target,user,proximity_flag,click_parameters)
. = ..()
if(iscarbon(target))
var/mob/living/carbon/carbon_target = target
var/obj/item/bodypart/bodypart = pick(carbon_target.bodyparts)
var/datum/wound/slash/severe/crit_wound = new
crit_wound.apply_wound(bodypart)
/datum/eldritch_knowledge/summon/raw_prophet
name = "Raw Ritual"
gain_text = "The uncanny man walks alone in the valley, I was able to call his aid."
desc = "You can now summon a Raw Prophet using eyes, a left arm, right arm and a pool of blood using a transmutation circle. Raw prophets have increased seeing range, and can see through walls. They can jaunt long distances, though they are fragile."
cost = 1
required_atoms = list(/obj/item/organ/eyes,/obj/item/bodypart/l_arm,/obj/item/bodypart/r_arm,/obj/effect/decal/cleanable/blood)
mob_to_summon = /mob/living/simple_animal/hostile/eldritch/raw_prophet
next_knowledge = list(/datum/eldritch_knowledge/flesh_blade_upgrade,/datum/eldritch_knowledge/spell/blood_siphon,/datum/eldritch_knowledge/curse/paralysis)
route = PATH_FLESH
/datum/eldritch_knowledge/summon/stalker
name = "Lonely Ritual"
gain_text = "I was able to combine my greed and desires to summon an eldritch beast I have not seen before."
desc = "You can now summon a Stalker using a knife, a flower, a pen and a piece of paper using a transmutation circle. Stalkers possess the ability to shapeshift into various forms while assuming the vigor and powers of that form."
cost = 1
required_atoms = list(/obj/item/kitchen/knife,/obj/item/reagent_containers/food/snacks/grown/poppy,/obj/item/pen,/obj/item/paper)
mob_to_summon = /mob/living/simple_animal/hostile/eldritch/stalker
next_knowledge = list(/datum/eldritch_knowledge/summon/ashy,/datum/eldritch_knowledge/summon/rusty,/datum/eldritch_knowledge/final/flesh_final)
route = PATH_FLESH
/datum/eldritch_knowledge/summon/ashy
name = "Ashen Ritual"
gain_text = "I combined principle of hunger with desire of destruction. The eyeful lords have noticed me."
desc = "You can now summon an Ashen One by transmuting a pile of ash, a head and a book using a transmutation circle. They possess the ability to jaunt short distances and create a cascade of flames."
cost = 1
required_atoms = list(/obj/effect/decal/cleanable/ash,/obj/item/bodypart/head,/obj/item/book)
mob_to_summon = /mob/living/simple_animal/hostile/eldritch/ash_spirit
next_knowledge = list(/datum/eldritch_knowledge/summon/stalker,/datum/eldritch_knowledge/spell/flame_birth)
/datum/eldritch_knowledge/summon/rusty
name = "Rusted Ritual"
gain_text = "I combined principle of hunger with desire of corruption. The rusted hills call my name."
desc = "You can now summon a Rust Walker transmuting a vomit pool, a head, and a book using a transmutation circle. Rust Walkers possess the ability to spread rust and can fire bolts of rust to further corrode the area."
cost = 1
required_atoms = list(/obj/effect/decal/cleanable/vomit,/obj/item/bodypart/head,/obj/item/book)
mob_to_summon = /mob/living/simple_animal/hostile/eldritch/rust_spirit
next_knowledge = list(/datum/eldritch_knowledge/summon/stalker,/datum/eldritch_knowledge/spell/entropic_plume)
/datum/eldritch_knowledge/spell/blood_siphon
name = "Blood Siphon"
gain_text = "Our blood is all the same after all, the owl told me."
desc = "You are granted a spell that drains some of the targets health, and returns it to you. It also has a chance to transfer any wounds you possess onto the target."
cost = 1
spell_to_add = /obj/effect/proc_holder/spell/targeted/touch/blood_siphon
next_knowledge = list(/datum/eldritch_knowledge/summon/raw_prophet,/datum/eldritch_knowledge/spell/area_conversion)
/datum/eldritch_knowledge/final/flesh_final
name = "Priest's Final Hymn"
gain_text = "Man of this world. Hear me! For the time of the lord of arms has come!"
desc = "Bring three corpses to a transmutation rune to either ascend as The Lord of the Night or summon a single Terror of the Night, however you cannot ascend more than once."
required_atoms = list(/mob/living/carbon/human)
cost = 5
route = PATH_FLESH
/datum/eldritch_knowledge/final/flesh_final/on_finished_recipe(mob/living/user, list/atoms, loc)
var/alert_ = alert(user,"Do you want to ascend as the lord of the night or just summon a terror of the night?","...","Yes","No")
user.SetImmobilized(10 HOURS) // no way someone will stand 10 hours in a spot, just so he can move while the alert is still showing.
switch(alert_)
if("No")
var/mob/living/summoned = new /mob/living/simple_animal/hostile/eldritch/armsy(loc)
message_admins("[summoned.name] is being summoned by [user.real_name] in [loc]")
var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as a [summoned.real_name]", ROLE_HERETIC, null, ROLE_HERETIC, 100,summoned)
user.SetImmobilized(0)
if(LAZYLEN(candidates) == 0)
to_chat(user,"<span class='warning'>No ghost could be found...</span>")
qdel(summoned)
return FALSE
var/mob/dead/observer/ghost_candidate = pick(candidates)
priority_announce("$^@&#*$^@(#&$(@&#^$&#^@# Fear the dark, for vassal of arms has ascended! Terror of the night has come! $^@&#*$^@(#&$(@&#^$&#^@#","#$^@&#*$^@(#&$(@&#^$&#^@#", 'sound/announcer/classic/spanomalies.ogg')
log_game("[key_name_admin(ghost_candidate)] has taken control of ([key_name_admin(summoned)]).")
summoned.ghostize(FALSE)
summoned.key = ghost_candidate.key
summoned.mind.add_antag_datum(/datum/antagonist/heretic_monster)
var/datum/antagonist/heretic_monster/monster = summoned.mind.has_antag_datum(/datum/antagonist/heretic_monster)
var/datum/antagonist/heretic/master = user.mind.has_antag_datum(/datum/antagonist/heretic)
monster.set_owner(master)
master.ascended = TRUE
if("Yes")
var/mob/living/summoned = new /mob/living/simple_animal/hostile/eldritch/armsy/prime(loc,TRUE,10)
summoned.ghostize(0)
user.SetImmobilized(0)
priority_announce("$^@&#*$^@(#&$(@&#^$&#^@# Fear the dark, for king of arms has ascended! Lord of the night has come! $^@&#*$^@(#&$(@&#^$&#^@#","#$^@&#*$^@(#&$(@&#^$&#^@#", 'sound/announcer/classic/spanomalies.ogg')
log_game("[user.real_name] ascended as [summoned.real_name]")
var/mob/living/carbon/carbon_user = user
var/datum/antagonist/heretic/ascension = carbon_user.mind.has_antag_datum(/datum/antagonist/heretic)
ascension.ascended = TRUE
carbon_user.mind.transfer_to(summoned, TRUE)
carbon_user.gib()
return ..()

View File

@@ -0,0 +1,209 @@
/datum/eldritch_knowledge/base_rust
name = "Blacksmith's Tale"
desc = "Inducts you into the Path of Rust. Allows you to transmute an eldritch blade with any trash item into a Blade of Rust."
gain_text = "'Let me tell you a story,' The Blacksmith said as he gazed into his rusty blade."
banned_knowledge = list(/datum/eldritch_knowledge/base_ash,/datum/eldritch_knowledge/base_flesh,/datum/eldritch_knowledge/final/ash_final,/datum/eldritch_knowledge/final/flesh_final)
next_knowledge = list(/datum/eldritch_knowledge/rust_fist)
required_atoms = list(/obj/item/melee/sickly_blade,/obj/item/trash)
result_atoms = list(/obj/item/melee/sickly_blade/rust)
cost = 1
route = PATH_RUST
/datum/eldritch_knowledge/rust_fist
name = "Grasp of Rust"
desc = "Empowers your Mansus Grasp to deal 500 damage to non-living matter and rust any structure it touches. Destroys already rusted structures."
gain_text = "Rust grows on the ceiling of the mansus."
cost = 1
next_knowledge = list(/datum/eldritch_knowledge/rust_regen)
var/rust_force = 500
var/static/list/blacklisted_turfs = typecacheof(list(/turf/closed,/turf/open/space,/turf/open/lava,/turf/open/chasm,/turf/open/floor/plating/rust))
route = PATH_RUST
/datum/eldritch_knowledge/rust_fist/on_mansus_grasp(atom/target, mob/user, proximity_flag, click_parameters)
. = ..()
if(ishuman(target))
var/mob/living/carbon/human/H = target
var/datum/status_effect/eldritch/E = H.has_status_effect(/datum/status_effect/eldritch/rust) || H.has_status_effect(/datum/status_effect/eldritch/ash) || H.has_status_effect(/datum/status_effect/eldritch/flesh)
if(E)
E.on_effect()
H.adjustOrganLoss(pick(ORGAN_SLOT_BRAIN,ORGAN_SLOT_EARS,ORGAN_SLOT_EYES,ORGAN_SLOT_LIVER,ORGAN_SLOT_LUNGS,ORGAN_SLOT_STOMACH,ORGAN_SLOT_HEART),25)
target.rust_heretic_act()
target.emp_act(EMP_HEAVY)
return TRUE
/datum/eldritch_knowledge/spell/area_conversion
name = "Aggressive Spread"
desc = "Spreads rust to nearby turfs. Destroys already rusted walls."
gain_text = "All wise men know not to touch the bound king."
cost = 1
spell_to_add = /obj/effect/proc_holder/spell/aoe_turf/rust_conversion
next_knowledge = list(/datum/eldritch_knowledge/rust_blade_upgrade,/datum/eldritch_knowledge/curse/corrosion,/datum/eldritch_knowledge/spell/blood_siphon,/datum/eldritch_knowledge/spell/rust_wave)
route = PATH_RUST
/datum/eldritch_knowledge/spell/rust_wave
name = "Patron's Reach"
desc = "You can now send a bolt of rust that corrupts the immediate area, and poisons the first target hit."
gain_text = "Messengers of hope fear the rustbringer."
cost = 1
spell_to_add = /obj/effect/proc_holder/spell/aimed/rust_wave
route = PATH_RUST
/datum/eldritch_knowledge/rust_regen
name = "Leeching Walk"
desc = "Passively heals you when you are on rusted tiles."
gain_text = "'The strength was unparalleled, unnatural.' The Blacksmith was smiling."
cost = 1
next_knowledge = list(/datum/eldritch_knowledge/rust_mark,/datum/eldritch_knowledge/armor,/datum/eldritch_knowledge/essence)
route = PATH_RUST
/datum/eldritch_knowledge/rust_regen/on_life(mob/user)
. = ..()
var/turf/user_loc_turf = get_turf(user)
if(!istype(user_loc_turf, /turf/open/floor/plating/rust) || !isliving(user))
return
var/mob/living/living_user = user
living_user.adjustBruteLoss(-3, FALSE)
living_user.adjustFireLoss(-3, FALSE)
living_user.adjustToxLoss(-3, FALSE)
living_user.adjustOxyLoss(-1, FALSE)
living_user.adjustStaminaLoss(-6)
/datum/eldritch_knowledge/rust_mark
name = "Mark of Rust"
desc = "Your eldritch blade now applies a rust mark. Rust marks have a chance to deal between 0 to 200 damage to 75% of enemies items. To activate the mark use your Mansus Grasp on it."
gain_text = "Lords of the depths help those in dire need at a cost."
cost = 2
next_knowledge = list(/datum/eldritch_knowledge/spell/area_conversion)
banned_knowledge = list(/datum/eldritch_knowledge/ash_mark,/datum/eldritch_knowledge/flesh_mark)
route = PATH_RUST
/datum/eldritch_knowledge/rust_mark/on_eldritch_blade(target,user,proximity_flag,click_parameters)
. = ..()
if(isliving(target))
var/mob/living/living_target = target
living_target.apply_status_effect(/datum/status_effect/eldritch/rust)
/datum/eldritch_knowledge/rust_blade_upgrade
name = "Toxic Steel"
gain_text = "Let the blade guide you through the flesh."
desc = "Your blade of choice will now add toxin to enemies bloodstream."
cost = 2
next_knowledge = list(/datum/eldritch_knowledge/spell/entropic_plume)
banned_knowledge = list(/datum/eldritch_knowledge/ash_blade_upgrade,/datum/eldritch_knowledge/flesh_blade_upgrade)
route = PATH_RUST
/datum/eldritch_knowledge/rust_blade_upgrade/on_eldritch_blade(target,user,proximity_flag,click_parameters)
. = ..()
if(iscarbon(target))
var/mob/living/carbon/carbon_target = target
carbon_target.reagents.add_reagent(/datum/reagent/eldritch, 5)
/datum/eldritch_knowledge/spell/entropic_plume
name = "Entropic Plume"
desc = "You can now send a befuddling plume that blinds, poisons and makes enemies strike each other, while also converting the immediate area into rust."
gain_text = "Messengers of hope fear the rustbringer."
cost = 1
spell_to_add = /obj/effect/proc_holder/spell/cone/staggered/entropic_plume
next_knowledge = list(/datum/eldritch_knowledge/final/rust_final,/datum/eldritch_knowledge/spell/cleave,/datum/eldritch_knowledge/summon/rusty)
route = PATH_RUST
/datum/eldritch_knowledge/armor
name = "Armorer's Ritual"
desc = "You can now create eldritch armor using a built table and a gas mask on top of a transmutation rune."
gain_text = "For I am the heir to the throne of doom."
cost = 1
next_knowledge = list(/datum/eldritch_knowledge/rust_regen,/datum/eldritch_knowledge/flesh_ghoul)
required_atoms = list(/obj/structure/table,/obj/item/clothing/mask/gas)
result_atoms = list(/obj/item/clothing/suit/hooded/cultrobes/eldritch)
/datum/eldritch_knowledge/essence
name = "Priest's Ritual"
desc = "You can now transmute a tank of water into a bottle of eldritch fluid."
gain_text = "This is an old recipe, i got it from an owl."
cost = 1
next_knowledge = list(/datum/eldritch_knowledge/rust_regen,/datum/eldritch_knowledge/spell/ashen_shift)
required_atoms = list(/obj/structure/reagent_dispensers/watertank)
result_atoms = list(/obj/item/reagent_containers/glass/beaker/eldritch)
/datum/eldritch_knowledge/final/rust_final
name = "Rustbringer's Oath"
desc = "Bring three corpses onto a transmutation rune. After you finish the ritual, rust will now automatically spread from the rune. Your healing on rust is also tripled, while you become more resilient overall."
gain_text = "Champion of rust. Corruptor of steel. Fear the dark for Rustbringer has come!"
cost = 5
required_atoms = list(/mob/living/carbon/human)
route = PATH_RUST
/datum/eldritch_knowledge/final/rust_final/on_finished_recipe(mob/living/user, list/atoms, loc)
var/mob/living/carbon/human/H = user
H.physiology.brute_mod *= 0.5
H.physiology.burn_mod *= 0.5
priority_announce("$^@&#*$^@(#&$(@&#^$&#^@# Fear the decay, for Rustbringer [user.real_name] has come! $^@&#*$^@(#&$(@&#^$&#^@#","#$^@&#*$^@(#&$(@&#^$&#^@#", 'sound/announcer/classic/spanomalies.ogg')
new /datum/rust_spread(loc)
var/datum/antagonist/heretic/ascension = H.mind.has_antag_datum(/datum/antagonist/heretic)
ascension.ascended = TRUE
return ..()
/datum/eldritch_knowledge/final/rust_final/on_life(mob/user)
. = ..()
if(!finished)
return
var/mob/living/carbon/human/human_user = user
human_user.adjustBruteLoss(-6, FALSE)
human_user.adjustFireLoss(-6, FALSE)
human_user.adjustToxLoss(-6, FALSE)
human_user.adjustOxyLoss(-6, FALSE)
human_user.adjustStaminaLoss(-20)
/**
* #Rust spread datum
*
* Simple datum that automatically spreads rust around it
*
* Simple implementation of automatically growing entity
*/
/datum/rust_spread
var/list/edge_turfs = list()
var/list/turfs = list()
var/static/list/blacklisted_turfs = typecacheof(list(/turf/open/indestructible,/turf/closed/indestructible,/turf/open/space,/turf/open/lava,/turf/open/chasm))
var/spread_per_tick = 6
/datum/rust_spread/New(loc)
. = ..()
var/turf/turf_loc = get_turf(loc)
turf_loc.rust_heretic_act()
turfs += turf_loc
START_PROCESSING(SSprocessing,src)
/datum/rust_spread/Destroy(force, ...)
STOP_PROCESSING(SSprocessing,src)
return ..()
/datum/rust_spread/process()
compile_turfs()
var/turf/T
for(var/i in 0 to spread_per_tick)
T = pick(edge_turfs)
T.rust_heretic_act()
turfs += get_turf(T)
/**
* Compile turfs
*
* Recreates all edge_turfs as well as normal turfs.
*/
/datum/rust_spread/proc/compile_turfs()
edge_turfs = list()
for(var/X in turfs)
if(!istype(X,/turf/closed/wall/rust) && !istype(X,/turf/closed/wall/r_wall/rust) && !istype(X,/turf/open/floor/plating/rust))
turfs -=X
continue
for(var/turf/T in range(1,X))
if(T in turfs)
continue
if(is_type_in_typecache(T,blacklisted_turfs))
continue
edge_turfs += T

View File

@@ -161,12 +161,12 @@
/datum/spellbook_entry/blind
name = "Blind"
spell_type = /obj/effect/proc_holder/spell/targeted/trigger/blind
spell_type = /obj/effect/proc_holder/spell/pointed/trigger/blind
cost = 1
/datum/spellbook_entry/mindswap
name = "Mindswap"
spell_type = /obj/effect/proc_holder/spell/targeted/mind_transfer
spell_type = /obj/effect/proc_holder/spell/pointed/mind_transfer
category = "Mobility"
/datum/spellbook_entry/forcewall
@@ -246,7 +246,7 @@
/datum/spellbook_entry/barnyard
name = "Barnyard Curse"
spell_type = /obj/effect/proc_holder/spell/targeted/barnyardcurse
spell_type = /obj/effect/proc_holder/spell/pointed/barnyardcurse
/datum/spellbook_entry/charge
name = "Charge"

View File

@@ -177,7 +177,7 @@
to_chat(owner, "<B>Your service has not gone unrewarded, however. Studying under [master.current.real_name], you have learned livesaving survival spells. You are able to cast charge and forcewall.")
if(APPRENTICE_ROBELESS)
owner.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/knock(null))
owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/mind_transfer(null))
owner.AddSpell(new /obj/effect/proc_holder/spell/pointed/mind_transfer(null))
to_chat(owner, "<B>Your service has not gone unrewarded, however. Studying under [master.current.real_name], you have learned stealthy, robeless spells. You are able to cast knock and mindswap.")
if(APPRENTICE_MARTIAL)
owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/touch/nuclear_fist(null))

View File

@@ -94,7 +94,7 @@
shuffle_inplace(mobs)
var/obj/effect/proc_holder/spell/targeted/mind_transfer/swapper = new /obj/effect/proc_holder/spell/targeted/mind_transfer
var/obj/effect/proc_holder/spell/pointed/mind_transfer/swapper = new /obj/effect/proc_holder/spell/pointed/mind_transfer
while(mobs.len > 1)
var/mob/living/carbon/human/H = pick(mobs)
mobs -= H

View File

@@ -476,5 +476,19 @@
hand_bodyparts[i] = BP
..() //Don't redraw hands until we have organs for them
//GetAllContents that is reasonable and not stupid
/mob/living/carbon/proc/get_all_gear()
var/list/processing_list = get_equipped_items(include_pockets = TRUE) + held_items
listclearnulls(processing_list) // handles empty hands
var/i = 0
while(i < length(processing_list) )
var/atom/A = processing_list[++i]
if(SEND_SIGNAL(A, COMSIG_CONTAINS_STORAGE))
var/list/item_stuff = list()
SEND_SIGNAL(A, COMSIG_TRY_STORAGE_RETURN_INVENTORY, item_stuff)
processing_list += item_stuff
return processing_list
/mob/canReachInto(atom/user, atom/target, list/next, view_only, obj/item/tool)
return ..() && (user == src)

View File

@@ -299,10 +299,10 @@
/mob/living/carbon/human/ex_act(severity, target, origin)
if(origin && istype(origin, /datum/spacevine_mutation) && isvineimmune(src))
if(TRAIT_BOMBIMMUNE in dna.species.species_traits)
return
..()
if (!severity)
if (!severity || QDELETED(src))
return
var/brute_loss = 0
var/burn_loss = 0

View File

@@ -57,7 +57,7 @@
/mob/living/Bump(atom/A)
if(..()) //we are thrown onto something
return
if (buckled || now_pushing)
if(buckled || now_pushing)
return
if(ismob(A))
var/mob/M = A

View File

@@ -430,3 +430,6 @@
/mob/living/silicon/handle_high_gravity(gravity)
return
/mob/living/silicon/rust_heretic_act()
adjustBruteLoss(500)

View File

@@ -1058,3 +1058,6 @@ Pass a positive integer as an argument to override a bot's default speed.
if(I)
I.icon_state = null
path.Cut(1, 2)
/mob/living/silicon/rust_heretic_act()
adjustBruteLoss(500)

View File

@@ -0,0 +1,386 @@
/mob/living/simple_animal/hostile/eldritch
name = "Demon"
real_name = "Demon"
desc = ""
gender = NEUTER
mob_biotypes = NONE
speak_emote = list("screams")
response_help_continuous = "thinks better of touching"
response_help_simple = "think better of touching"
response_disarm_continuous = "flails at"
response_disarm_simple = "flail at"
response_harm_continuous = "reaps"
response_harm_simple = "tears"
speak_chance = 1
icon = 'icons/mob/eldritch_mobs.dmi'
speed = 0
a_intent = INTENT_HARM
stop_automated_movement = 1
AIStatus = AI_OFF
attack_sound = 'sound/weapons/punch1.ogg'
see_in_dark = 7
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0)
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
minbodytemp = 0
maxbodytemp = INFINITY
healable = 0
movement_type = GROUND
pressure_resistance = 100
del_on_death = TRUE
deathmessage = "implodes into itself"
faction = list("heretics")
simple_mob_flags = SILENCE_RANGED_MESSAGE
///Innate spells that are supposed to be added when a beast is created
var/list/spells_to_add
/mob/living/simple_animal/hostile/eldritch/Initialize()
. = ..()
add_spells()
/**
* Add_spells
*
* Goes through spells_to_add and adds each spell to the mind.
*/
/mob/living/simple_animal/hostile/eldritch/proc/add_spells()
for(var/spell in spells_to_add)
AddSpell(new spell())
/mob/living/simple_animal/hostile/eldritch/raw_prophet
name = "Raw Prophet"
real_name = "Raw Prophet"
desc = "Abomination made from severed limbs."
icon_state = "raw_prophet"
status_flags = CANPUSH
icon_living = "raw_prophet"
melee_damage_lower = 5
melee_damage_upper = 10
maxHealth = 50
health = 50
sight = SEE_MOBS|SEE_OBJS|SEE_TURFS
spells_to_add = list(/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/shift/ash/long,/obj/effect/proc_holder/spell/pointed/manse_link,/obj/effect/proc_holder/spell/targeted/telepathy/eldritch,/obj/effect/proc_holder/spell/pointed/trigger/blind/eldritch)
var/list/linked_mobs = list()
/mob/living/simple_animal/hostile/eldritch/raw_prophet/Initialize()
. = ..()
link_mob(src)
/mob/living/simple_animal/hostile/eldritch/raw_prophet/Login()
. = ..()
client.change_view(10)
/mob/living/simple_animal/hostile/eldritch/raw_prophet/proc/link_mob(mob/living/mob_linked)
if(QDELETED(mob_linked) || mob_linked.stat == DEAD)
return FALSE
if(HAS_TRAIT(mob_linked, TRAIT_MINDSHIELD)) //mindshield implant, no dice
return FALSE
if(mob_linked.anti_magic_check(FALSE, FALSE, TRUE, 0))
return FALSE
if(linked_mobs[mob_linked])
return FALSE
to_chat(mob_linked, "<span class='notice'>You feel something new enter your sphere of mind, you hear whispers of people far away, screeches of horror and a humming of welcome to [src]'s Mansus Link.</span>")
var/datum/action/innate/mansus_speech/action = new(src)
linked_mobs[mob_linked] = action
action.Grant(mob_linked)
RegisterSignal(mob_linked, list(COMSIG_MOB_DEATH, COMSIG_PARENT_QDELETING) , .proc/unlink_mob)
return TRUE
/mob/living/simple_animal/hostile/eldritch/raw_prophet/proc/unlink_mob(mob/living/mob_linked)
if(!linked_mobs[mob_linked])
return
UnregisterSignal(mob_linked, list(COMSIG_MOB_DEATH, COMSIG_PARENT_QDELETING))
var/datum/action/innate/mansus_speech/action = linked_mobs[mob_linked]
action.Remove(mob_linked)
qdel(action)
to_chat(mob_linked, "<span class='notice'>Your mind shatters as the [src]'s Mansus Link leaves your mind.</span>")
mob_linked.emote("Scream")
//micro stun
mob_linked.AdjustParalyzed(0.5 SECONDS)
linked_mobs -= mob_linked
/mob/living/simple_animal/hostile/eldritch/raw_prophet/death(gibbed)
for(var/linked_mob in linked_mobs)
unlink_mob(linked_mob)
return ..()
/mob/living/simple_animal/hostile/eldritch/armsy
name = "Terror of the Night"
real_name = "Armsy"
desc = "Abomination made from severed limbs."
icon_state = "armsy_start"
icon_living = "armsy_start"
maxHealth = 200
health = 200
obj_damage = 80
melee_damage_lower = 10
melee_damage_upper = 15
move_resist = MOVE_FORCE_OVERPOWERING+1
movement_type = GROUND
environment_smash = ENVIRONMENT_SMASH_RWALLS
sight = SEE_MOBS
spells_to_add = list(/obj/effect/proc_holder/spell/targeted/worm_contract)
ranged = TRUE
///Previous segment in the chain
var/mob/living/simple_animal/hostile/eldritch/armsy/back
///Next segment in the chain
var/mob/living/simple_animal/hostile/eldritch/armsy/front
///Your old location
var/oldloc
///Allow / disallow pulling
var/allow_pulling = FALSE
///How many arms do we have to eat to expand?
var/stacks_to_grow = 2
///Currently eaten arms
var/current_stacks = 0
//I tried Initalize but it didnt work, like at all. This proc just wouldnt fire if it was Initalize instead of New
/mob/living/simple_animal/hostile/eldritch/armsy/Initialize(mapload,spawn_more = TRUE,len = 6)
. = ..()
if(len < 3)
stack_trace("Eldritch Armsy created with invalid len ([len]). Reverting to 3.")
len = 3 //code breaks below 3, let's just not allow it.
oldloc = loc
RegisterSignal(src,COMSIG_MOVABLE_MOVED,.proc/update_chain_links)
if(!spawn_more)
return
allow_pulling = TRUE
///next link
var/mob/living/simple_animal/hostile/eldritch/armsy/next
///previous link
var/mob/living/simple_animal/hostile/eldritch/armsy/prev
///current link
var/mob/living/simple_animal/hostile/eldritch/armsy/current
for(var/i in 0 to len)
prev = current
//i tried using switch, but byond is really fucky and it didnt work as intended. Im sorry
if(i == 0)
current = new type(drop_location(),FALSE)
current.icon_state = "armsy_mid"
current.icon_living = "armsy_mid"
current.front = src
current.AIStatus = AI_OFF
back = current
else if(i < len)
current = new type(drop_location(),FALSE)
prev.back = current
prev.icon_state = "armsy_mid"
prev.icon_living = "armsy_mid"
prev.front = next
prev.AIStatus = AI_OFF
else
prev.icon_state = "armsy_end"
prev.icon_living = "armsy_end"
prev.front = next
prev.AIStatus = AI_OFF
next = prev
//we are literally a vessel of otherworldly destruction, we bring our own gravity unto this plane
/mob/living/simple_animal/hostile/eldritch/armsy/has_gravity(turf/T)
return TRUE
/mob/living/simple_animal/hostile/eldritch/armsy/can_be_pulled()
return FALSE
///Updates chain links to force move onto a single tile
/mob/living/simple_animal/hostile/eldritch/armsy/proc/contract_next_chain_into_single_tile()
if(back)
back.forceMove(loc)
back.contract_next_chain_into_single_tile()
return
///Updates the next mob in the chain to move to our last location, fixed the worm if somehow broken.
/mob/living/simple_animal/hostile/eldritch/armsy/proc/update_chain_links()
gib_trail()
if(back && back.loc != oldloc)
back.Move(oldloc)
// self fixing properties if somehow broken
if(front && loc != front.oldloc)
forceMove(front.oldloc)
oldloc = loc
/mob/living/simple_animal/hostile/eldritch/armsy/proc/gib_trail()
if(front) // head makes gibs
return
var/chosen_decal = pick(typesof(/obj/effect/decal/cleanable/blood/tracks))
var/obj/effect/decal/cleanable/blood/gibs/decal = new chosen_decal(drop_location())
decal.setDir(dir)
/mob/living/simple_animal/hostile/eldritch/armsy/Destroy()
if(front)
front.icon_state = "armsy_end"
front.icon_living = "armsy_end"
front.back = null
if(back)
QDEL_NULL(back) // chain destruction baby
return ..()
/mob/living/simple_animal/hostile/eldritch/armsy/BiologicalLife(seconds, times_fired)
adjustBruteLoss(-2)
/mob/living/simple_animal/hostile/eldritch/armsy/proc/heal()
if(health == maxHealth)
if(back)
back.heal()
return
else
current_stacks++
if(current_stacks >= stacks_to_grow)
var/mob/living/simple_animal/hostile/eldritch/armsy/prev = new type(drop_location(),spawn_more = FALSE)
icon_state = "armsy_mid"
icon_living = "armsy_mid"
back = prev
prev.icon_state = "armsy_end"
prev.icon_living = "armsy_end"
prev.front = src
prev.AIStatus = AI_OFF
current_stacks = 0
adjustBruteLoss(-maxHealth * 0.5, FALSE)
adjustFireLoss(-maxHealth * 0.5 ,FALSE)
/mob/living/simple_animal/hostile/eldritch/armsy/Shoot(atom/targeted_atom)
target = targeted_atom
AttackingTarget()
/mob/living/simple_animal/hostile/eldritch/armsy/AttackingTarget()
if(istype(target,/obj/item/bodypart/r_arm) || istype(target,/obj/item/bodypart/l_arm))
qdel(target)
heal()
return
if(target == back || target == front)
return
if(back)
back.target = target
back.AttackingTarget()
if(!Adjacent(target))
return
do_attack_animation(target)
//have fun
//if(istype(target,/turf/closed/wall))
//var/turf/closed/wall = target
//wall.ScrapeAway()
if(iscarbon(target))
var/mob/living/carbon/C = target
if(HAS_TRAIT(C, TRAIT_NODISMEMBER))
return
var/list/parts = list()
for(var/X in C.bodyparts)
var/obj/item/bodypart/bodypart = X
if(bodypart.body_part != HEAD && bodypart.body_part != CHEST)
if(bodypart.dismemberable)
parts += bodypart
if(length(parts) && prob(10))
var/obj/item/bodypart/bodypart = pick(parts)
bodypart.dismember()
return ..()
/mob/living/simple_animal/hostile/eldritch/armsy/prime
name = "Lord of the Night"
real_name = "Master of Decay"
maxHealth = 400
health = 400
melee_damage_lower = 20
melee_damage_upper = 25
/mob/living/simple_animal/hostile/eldritch/armsy/prime/Initialize(mapload,spawn_more = TRUE,len = 9)
. = ..()
var/matrix/matrix_transformation = matrix()
matrix_transformation.Scale(1.4,1.4)
transform = matrix_transformation
/mob/living/simple_animal/hostile/eldritch/armsy/primeproc/heal()
if(health == maxHealth)
if(back)
back.heal()
return
else
current_stacks++
if(current_stacks >= stacks_to_grow)
var/mob/living/simple_animal/hostile/eldritch/armsy/prev = new type(drop_location(),spawn_more = FALSE)
icon_state = "armsy_mid"
icon_living = "armsy_mid"
back = prev
prev.icon_state = "armsy_end"
prev.icon_living = "armsy_end"
prev.front = src
prev.AIStatus = AI_OFF
current_stacks = 0
var/matrix/matrix_transformation = matrix()
matrix_transformation.Scale(1.4,1.4)
transform = matrix_transformation
adjustBruteLoss(-maxHealth * 0.5, FALSE)
adjustFireLoss(-maxHealth * 0.5 ,FALSE)
/mob/living/simple_animal/hostile/eldritch/rust_spirit
name = "Rust Walker"
real_name = "Rusty"
desc = "Incomprehensible abomination actively seeping life out of it's surrounding."
icon_state = "rust_walker_s"
status_flags = CANPUSH
icon_living = "rust_walker_s"
maxHealth = 75
health = 75
melee_damage_lower = 15
melee_damage_upper = 20
sight = SEE_TURFS
spells_to_add = list(/obj/effect/proc_holder/spell/aoe_turf/rust_conversion/small,/obj/effect/proc_holder/spell/aimed/rust_wave/short)
/mob/living/simple_animal/hostile/eldritch/rust_spirit/setDir(newdir, ismousemovement)
. = ..()
if(newdir == NORTH)
icon_state = "rust_walker_n"
else if(newdir == SOUTH)
icon_state = "rust_walker_s"
update_icon()
/mob/living/simple_animal/hostile/eldritch/rust_spirit/Moved()
. = ..()
playsound(src, 'sound/effects/footstep/rustystep1.ogg', 100, TRUE)
/mob/living/simple_animal/hostile/eldritch/rust_spirit/Life()
if(stat == DEAD)
return ..()
var/turf/T = get_turf(src)
if(istype(T,/turf/open/floor/plating/rust))
adjustBruteLoss(-3, FALSE)
adjustFireLoss(-3, FALSE)
return ..()
/mob/living/simple_animal/hostile/eldritch/ash_spirit
name = "Ash Man"
real_name = "Ashy"
desc = "Incomprehensible abomination actively seeping life out of it's surrounding."
icon_state = "ash_walker"
status_flags = CANPUSH
icon_living = "ash_walker"
maxHealth = 75
health = 75
melee_damage_lower = 15
melee_damage_upper = 20
sight = SEE_TURFS
spells_to_add = list(/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/shift/ash,/obj/effect/proc_holder/spell/pointed/cleave/long,/obj/effect/proc_holder/spell/aoe_turf/fire_cascade)
/mob/living/simple_animal/hostile/eldritch/stalker
name = "Flesh Stalker"
real_name = "Flesh Stalker"
desc = "Abomination made from severed limbs."
icon_state = "stalker"
status_flags = CANPUSH
icon_living = "stalker"
maxHealth = 150
health = 150
melee_damage_lower = 15
melee_damage_upper = 20
sight = SEE_MOBS
spells_to_add = list(/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/shift/ash,/obj/effect/proc_holder/spell/targeted/shapeshift/eldritch,/obj/effect/proc_holder/spell/targeted/emplosion/eldritch)

View File

@@ -146,6 +146,8 @@
var/bare_wound_bonus = 0
//If the attacks from this are sharp
var/sharpness = SHARP_NONE
//Generic flags
var/simple_mob_flags = NONE
/mob/living/simple_animal/Initialize()
. = ..()

View File

@@ -2301,6 +2301,32 @@
M.adjustStaminaLoss(-0.25*REM) // the more wounds, the more stamina regen
..()
datum/reagent/eldritch
name = "Eldritch Essence"
description = "Strange liquid that defies the laws of physics"
taste_description = "Ag'hsj'saje'sh"
color = "#1f8016"
/datum/reagent/eldritch/on_mob_life(mob/living/carbon/M)
if(IS_HERETIC(M))
M.drowsyness = max(M.drowsyness-5, 0)
M.AdjustAllImmobility(-40, FALSE)
M.adjustStaminaLoss(-15, FALSE)
M.adjustToxLoss(-3, FALSE)
M.adjustOxyLoss(-3, FALSE)
M.adjustBruteLoss(-3, FALSE)
M.adjustFireLoss(-3, FALSE)
if(ishuman(M) && M.blood_volume < BLOOD_VOLUME_NORMAL)
M.blood_volume += 3
else
M.adjustOrganLoss(ORGAN_SLOT_BRAIN, 3, 150)
M.adjustToxLoss(2, FALSE)
M.adjustFireLoss(2, FALSE)
M.adjustOxyLoss(2, FALSE)
M.adjustBruteLoss(2, FALSE)
holder.remove_reagent(type, 1)
return TRUE
/datum/reagent/cellulose
name = "Cellulose Fibers"
description = "A crystaline polydextrose polymer, plants swear by this stuff."

View File

@@ -224,7 +224,15 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th
/obj/effect/proc_holder/spell/proc/choose_targets(mob/user = usr) //depends on subtype - /targeted or /aoe_turf
return
/obj/effect/proc_holder/spell/proc/can_target(mob/living/target)
/**
* can_target: Checks if we are allowed to cast the spell on a target.
*
* Arguments:
* * target The atom that is being targeted by the spell.
* * user The mob using the spell.
* * silent If the checks should not give any feedback messages.
*/
/obj/effect/proc_holder/spell/proc/can_target(atom/target, mob/user, silent = FALSE)
return TRUE
/obj/effect/proc_holder/spell/proc/start_recharge()
@@ -296,6 +304,13 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th
/obj/effect/proc_holder/spell/proc/cast(list/targets,mob/user = usr)
return
/obj/effect/proc_holder/spell/proc/view_or_range(distance = world.view, center=usr, type="view")
switch(type)
if("view")
. = view(distance,center)
if("range")
. = range(distance,center)
/obj/effect/proc_holder/spell/proc/revert_cast(mob/user = usr) //resets recharge or readds a charge
switch(charge_type)
if("recharge")
@@ -345,7 +360,7 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th
switch(max_targets)
if(0) //unlimited
for(var/mob/living/target in view_or_range(range, user, selection_type))
if(!can_target(target))
if(!can_target(target, user, TRUE))
continue
targets += target
if(1) //single target can be picked
@@ -357,7 +372,7 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th
for(var/mob/living/M in view_or_range(range, user, selection_type))
if(!include_user && user == M)
continue
if(!can_target(M))
if(!can_target(M, user, TRUE))
continue
possible_targets += M
@@ -365,7 +380,7 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th
//Adds a safety check post-input to make sure those targets are actually in range.
var/mob/M
if(!random_target)
M = input("Choose the target for the spell.", "Targeting") as null|mob in possible_targets
M = input("Choose the target for the spell.", "Targeting") as null|mob in sortNames(possible_targets)
else
switch(random_target_priority)
if(TARGET_RANDOM)
@@ -385,7 +400,7 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th
else
var/list/possible_targets = list()
for(var/mob/living/target in view_or_range(range, user, selection_type))
if(!can_target(target))
if(!can_target(target, user, TRUE))
continue
possible_targets += target
for(var/i=1,i<=max_targets,i++)
@@ -411,7 +426,7 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th
var/list/targets = list()
for(var/turf/target in view_or_range(range,user,selection_type))
if(!can_target(target))
if(!can_target(target, user, TRUE))
continue
if(!(target in view_or_range(inner_radius,user,selection_type)))
targets += target

View File

@@ -0,0 +1,117 @@
/obj/effect/proc_holder/spell/cone
name = "Cone of Nothing"
desc = "Does nothing in a cone! Wow!"
school = "evocation"
charge_max = 100
clothes_req = FALSE
invocation = "FUKAN NOTHAN"
invocation_type = "shout"
sound = 'sound/magic/forcewall.ogg'
action_icon_state = "shield"
range = -1
cooldown_min = 0.5 SECONDS
///This controls how many levels the cone has, increase this value to make a bigger cone.
var/cone_levels = 3
///This value determines if the cone penetrates walls.
var/respect_density = FALSE
/obj/effect/proc_holder/spell/cone/choose_targets(mob/user = usr)
perform(null, user=user)
///This proc creates a list of turfs that are hit by the cone
/obj/effect/proc_holder/spell/cone/proc/cone_helper(var/turf/starter_turf, var/dir_to_use, var/cone_levels = 3)
var/list/turfs_to_return = list()
var/turf/turf_to_use = starter_turf
var/turf/left_turf
var/turf/right_turf
var/right_dir
var/left_dir
switch(dir_to_use)
if(NORTH)
left_dir = WEST
right_dir = EAST
if(SOUTH)
left_dir = EAST
right_dir = WEST
if(EAST)
left_dir = NORTH
right_dir = SOUTH
if(WEST)
left_dir = SOUTH
right_dir = NORTH
for(var/i in 1 to cone_levels)
var/list/level_turfs = list()
turf_to_use = get_step(turf_to_use, dir_to_use)
level_turfs += turf_to_use
if(i != 1)
left_turf = get_step(turf_to_use, left_dir)
level_turfs += left_turf
right_turf = get_step(turf_to_use, right_dir)
level_turfs += right_turf
for(var/left_i in 1 to i -calculate_cone_shape(i))
if(left_turf.density && respect_density)
break
left_turf = get_step(left_turf, left_dir)
level_turfs += left_turf
for(var/right_i in 1 to i -calculate_cone_shape(i))
if(right_turf.density && respect_density)
break
right_turf = get_step(right_turf, right_dir)
level_turfs += right_turf
turfs_to_return += list(level_turfs)
if(i == cone_levels)
continue
if(turf_to_use.density && respect_density)
break
return turfs_to_return
/obj/effect/proc_holder/spell/cone/cast(list/targets,mob/user = usr)
var/list/cone_turfs = cone_helper(get_turf(user), user.dir, cone_levels)
for(var/list/turf_list in cone_turfs)
do_cone_effects(turf_list)
///This proc does obj, mob and turf cone effects on all targets in a list
/obj/effect/proc_holder/spell/cone/proc/do_cone_effects(list/target_turf_list, level)
for(var/target_turf in target_turf_list)
if(!target_turf) //if turf is no longer there
continue
do_turf_cone_effect(target_turf, level)
if(isopenturf(target_turf))
var/turf/open/open_turf = target_turf
for(var/movable_content in open_turf)
if(isobj(movable_content))
do_obj_cone_effect(movable_content, level)
else if(isliving(movable_content))
do_mob_cone_effect(movable_content, level)
///This proc deterimines how the spell will affect turfs.
/obj/effect/proc_holder/spell/cone/proc/do_turf_cone_effect(turf/target_turf, level)
return
///This proc deterimines how the spell will affect objects.
/obj/effect/proc_holder/spell/cone/proc/do_obj_cone_effect(obj/target_obj, level)
return
///This proc deterimines how the spell will affect mobs.
/obj/effect/proc_holder/spell/cone/proc/do_mob_cone_effect(mob/living/target_mob, level)
return
///This proc adjusts the cones width depending on the level.
/obj/effect/proc_holder/spell/cone/proc/calculate_cone_shape(current_level)
var/end_taper_start = round(cone_levels * 0.8)
if(current_level > end_taper_start)
return (current_level % end_taper_start) * 2 //someone more talented and probably come up with a better formula.
else
return 2
///This type of cone gradually affects each level of the cone instead of affecting the entire area at once.
/obj/effect/proc_holder/spell/cone/staggered
/obj/effect/proc_holder/spell/cone/staggered/cast(list/targets,mob/user = usr)
var/level_counter = 0
var/list/cone_turfs = cone_helper(get_turf(user), user.dir, cone_levels)
for(var/list/turf_list in cone_turfs)
level_counter++
addtimer(CALLBACK(src, .proc/do_cone_effects, turf_list, level_counter), 2 * level_counter)

View File

@@ -49,8 +49,8 @@
var/projectile_type = text2path(proj_type)
projectile = new projectile_type(user)
else if(istype(proj_type, /obj/effect/proc_holder/spell))
projectile = new /obj/effect/proc_holder/spell/targeted/trigger(user)
var/obj/effect/proc_holder/spell/targeted/trigger/T = projectile
projectile = new /obj/effect/proc_holder/spell/pointed/trigger(user)
var/obj/effect/proc_holder/spell/pointed/trigger/T = projectile
T.linked_spells += proj_type
else
projectile = new proj_type(user)

View File

@@ -17,7 +17,7 @@
action_icon_state = "jaunt"
/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/cast(list/targets,mob/user = usr) //magnets, so mostly hardcoded
playsound(get_turf(user), 'sound/magic/ethereal_enter.ogg', 50, 1, -1)
play_sound("enter",user)
for(var/mob/living/target in targets)
INVOKE_ASYNC(src, .proc/do_jaunt, target)
@@ -42,7 +42,7 @@
ADD_TRAIT(target, TRAIT_MOBILITY_NOMOVE, src)
target.update_mobility()
holder.reappearing = 1
playsound(get_turf(target), 'sound/magic/ethereal_exit.ogg', 50, 1, -1)
play_sound("exit",target)
sleep(25 - jaunt_in_time)
new jaunt_in_type(mobloc, holder.dir)
target.setDir(holder.dir)
@@ -63,6 +63,13 @@
steam.set_up(10, 0, mobloc)
steam.start()
/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/proc/play_sound(type,mob/living/target)
switch(type)
if("enter")
playsound(get_turf(target), 'sound/magic/ethereal_enter.ogg', 50, TRUE, -1)
if("exit")
playsound(get_turf(target), 'sound/magic/ethereal_exit.ogg', 50, TRUE, -1)
/obj/effect/dummy/phased_mob/spell_jaunt
name = "water"
icon = 'icons/effects/effects.dmi'

View File

@@ -1,88 +0,0 @@
/obj/effect/proc_holder/spell/targeted/mind_transfer
name = "Mind Transfer"
desc = "This spell allows the user to switch bodies with a target."
school = "transmutation"
charge_max = 600
clothes_req = NONE
invocation = "GIN'YU CAPAN"
invocation_type = "whisper"
range = 1
cooldown_min = 200 //100 deciseconds reduction per rank
var/unconscious_amount_caster = 400 //how much the caster is stunned for after the spell
var/unconscious_amount_victim = 400 //how much the victim is stunned for after the spell
action_icon_state = "mindswap"
/*
Urist: I don't feel like figuring out how you store object spells so I'm leaving this for you to do.
Make sure spells that are removed from spell_list are actually removed and deleted when mind transferring.
Also, you never added distance checking after target is selected. I've went ahead and did that.
*/
/obj/effect/proc_holder/spell/targeted/mind_transfer/cast(list/targets, mob/living/user = usr, distanceoverride, silent = FALSE)
if(!targets.len)
if(!silent)
to_chat(user, "<span class='warning'>No mind found!</span>")
return
if(targets.len > 1)
if(!silent)
to_chat(user, "<span class='warning'>Too many minds! You're not a hive damnit!</span>")
return
var/mob/living/target = targets[1]
var/t_He = target.p_they(TRUE)
var/t_is = target.p_are()
if(!(target in oview(range)) && !distanceoverride)//If they are not in overview after selection. Do note that !() is necessary for in to work because ! takes precedence over it.
if(!silent)
to_chat(user, "<span class='warning'>[t_He] [t_is] too far away!</span>")
return
if(ismegafauna(target))
if(!silent)
to_chat(user, "<span class='warning'>This creature is too powerful to control!</span>")
return
if(target.stat == DEAD)
if(!silent)
to_chat(user, "<span class='warning'>You don't particularly want to be dead!</span>")
return
if(!target.key || !target.mind)
if(!silent)
to_chat(user, "<span class='warning'>[t_He] appear[target.p_s()] to be catatonic! Not even magic can affect [target.p_their()] vacant mind.</span>")
return
if(user.suiciding)
if(!silent)
to_chat(user, "<span class='warning'>You're killing yourself! You can't concentrate enough to do this!</span>")
return
var/datum/mind/TM = target.mind
if(target.anti_magic_check(TRUE, FALSE) || TM.has_antag_datum(/datum/antagonist/wizard) || TM.has_antag_datum(/datum/antagonist/cult) || TM.has_antag_datum(/datum/antagonist/clockcult) || TM.has_antag_datum(/datum/antagonist/changeling) || TM.has_antag_datum(/datum/antagonist/rev) || target.key[1] == "@")
if(!silent)
to_chat(user, "<span class='warning'>[target.p_their(TRUE)] mind is resisting your spell!</span>")
return
var/mob/living/victim = target//The target of the spell whos body will be transferred to.
var/mob/living/caster = user//The wizard/whomever doing the body transferring.
//MIND TRANSFER BEGIN
var/mob/dead/observer/ghost = victim.ghostize(FALSE, TRUE)
caster.mind.transfer_to(victim)
ghost.mind.transfer_to(caster)
if(ghost.key)
ghost.transfer_ckey(caster) //have to transfer the key since the mind was not active
qdel(ghost)
//MIND TRANSFER END
//Here we knock both mobs out for a time.
caster.Unconscious(unconscious_amount_caster)
victim.Unconscious(unconscious_amount_victim)
SEND_SOUND(caster, sound('sound/magic/mandswap.ogg'))
SEND_SOUND(victim, sound('sound/magic/mandswap.ogg'))// only the caster and victim hear the sounds, that way no one knows for sure if the swap happened
return TRUE

View File

@@ -1,51 +1,54 @@
/obj/effect/proc_holder/spell/targeted/barnyardcurse
/obj/effect/proc_holder/spell/pointed/barnyardcurse
name = "Curse of the Barnyard"
desc = "This spell dooms an unlucky soul to possess the speech and facial attributes of a barnyard animal."
school = "transmutation"
charge_type = "recharge"
charge_max = 150
charge_counter = 0
clothes_req = NONE
stat_allowed = 0
clothes_req = FALSE
stat_allowed = FALSE
invocation = "KN'A FTAGHU, PUCK 'BTHNK!"
invocation_type = "shout"
range = 7
cooldown_min = 30
selection_type = "range"
var/list/compatible_mobs = list(/mob/living/carbon/human, /mob/living/carbon/monkey)
ranged_mousepointer = 'icons/effects/mouse_pointers/barn_target.dmi'
action_icon_state = "barn"
active_msg = "You prepare to curse a target..."
deactive_msg = "You dispel the curse..."
/// List of mobs which are allowed to be a target of the spell
var/static/list/compatible_mobs_typecache = typecacheof(list(/mob/living/carbon/human, /mob/living/carbon/monkey))
/obj/effect/proc_holder/spell/targeted/barnyardcurse/cast(list/targets, mob/user = usr)
/obj/effect/proc_holder/spell/pointed/barnyardcurse/cast(list/targets, mob/user)
if(!targets.len)
to_chat(user, "<span class='notice'>No target found in range.</span>")
return
to_chat(user, "<span class='warning'>No target found in range!</span>")
return FALSE
if(!can_target(targets[1], user))
return FALSE
var/mob/living/carbon/target = targets[1]
if(!(target.type in compatible_mobs))
to_chat(user, "<span class='notice'>You are unable to curse [target]'s head!</span>")
return
if(!(target in oview(range)))
to_chat(user, "<span class='notice'>[target.p_theyre(TRUE)] too far away!</span>")
return
if(target.anti_magic_check())
to_chat(user, "<span class='warning'>The spell had no effect!</span>")
target.visible_message("<span class='danger'>[target]'s face bursts into flames, which instantly burst outward, leaving [target] unharmed!</span>", \
"<span class='danger'>Your face starts burning up, but the flames are repulsed by your anti-magic protection!</span>")
return
"<span class='danger'>Your face starts burning up, but the flames are repulsed by your anti-magic protection!</span>")
return FALSE
var/list/masks = list(/obj/item/clothing/mask/pig/cursed, /obj/item/clothing/mask/cowmask/cursed, /obj/item/clothing/mask/horsehead/cursed)
var/choice = pick(masks)
var/obj/item/clothing/mask/magichead = new choice(get_turf(target))
magichead.flags_inv = null
target.visible_message("<span class='danger'>[target]'s face bursts into flames, and a barnyard animal's head takes its place!</span>", \
"<span class='danger'>Your face burns up, and shortly after the fire you realise you have the face of a barnyard animal!</span>")
if(!target.dropItemToGround(target.wear_mask))
qdel(target.wear_mask)
target.equip_to_slot_if_possible(magichead, SLOT_WEAR_MASK, 1, 1)
target.equip_to_slot_if_possible(magichead, ITEM_SLOT_MASK, 1, 1)
target.flash_act()
/obj/effect/proc_holder/spell/pointed/barnyardcurse/can_target(atom/target, mob/user, silent)
. = ..()
if(!.)
return FALSE
if(!is_type_in_typecache(target, compatible_mobs_typecache))
if(!silent)
to_chat(user, "<span class='warning'>You are unable to curse [target]!</span>")
return FALSE
return TRUE

View File

@@ -0,0 +1,35 @@
/obj/effect/proc_holder/spell/pointed/trigger/blind
name = "Blind"
desc = "This spell temporarily blinds a single target."
school = "transmutation"
charge_max = 300
clothes_req = FALSE
invocation = "STI KALY"
invocation_type = "whisper"
message = "<span class='notice'>Your eyes cry out in pain!</span>"
cooldown_min = 50 //12 deciseconds reduction per rank
starting_spells = list("/obj/effect/proc_holder/spell/targeted/inflict_handler/blind", "/obj/effect/proc_holder/spell/targeted/genetic/blind")
ranged_mousepointer = 'icons/effects/mouse_pointers/blind_target.dmi'
action_icon_state = "blind"
active_msg = "You prepare to blind a target..."
/obj/effect/proc_holder/spell/targeted/inflict_handler/blind
amt_eye_blind = 10
amt_eye_blurry = 20
sound = 'sound/magic/blind.ogg'
/obj/effect/proc_holder/spell/targeted/genetic/blind
mutations = list(BLINDMUT)
duration = 300
charge_max = 400 // needs to be higher than the duration or it'll be permanent
sound = 'sound/magic/blind.ogg'
/obj/effect/proc_holder/spell/pointed/trigger/blind/can_target(atom/target, mob/user, silent)
. = ..()
if(!.)
return FALSE
if(!isliving(target))
if(!silent)
to_chat(user, "<span class='warning'>You can only blind living beings!</span>")
return FALSE
return TRUE

View File

@@ -0,0 +1,103 @@
/obj/effect/proc_holder/spell/pointed/mind_transfer
name = "Mind Transfer"
desc = "This spell allows the user to switch bodies with a target next to him."
school = "transmutation"
charge_max = 600
clothes_req = FALSE
invocation = "GIN'YU CAPAN"
invocation_type = "whisper"
range = 1
cooldown_min = 200 //100 deciseconds reduction per rank
ranged_mousepointer = 'icons/effects/mouse_pointers/mindswap_target.dmi'
action_icon_state = "mindswap"
active_msg = "You prepare to swap minds with a target..."
/// For how long is the caster stunned for after the spell
var/unconscious_amount_caster = 40 SECONDS
/// For how long is the victim stunned for after the spell
var/unconscious_amount_victim = 40 SECONDS
/obj/effect/proc_holder/spell/pointed/mind_transfer/cast(list/targets, mob/living/user, silent = FALSE)
if(!targets.len)
if(!silent)
to_chat(user, "<span class='warning'>No mind found!</span>")
return FALSE
if(targets.len > 1)
if(!silent)
to_chat(user, "<span class='warning'>Too many minds! You're not a hive damnit!</span>")
return FALSE
if(!can_target(targets[1], user, silent))
return FALSE
var/mob/living/victim = targets[1] //The target of the spell whos body will be transferred to.
var/datum/mind/VM = victim.mind
if(victim.anti_magic_check(TRUE, FALSE) || VM.has_antag_datum(/datum/antagonist/wizard) || VM.has_antag_datum(/datum/antagonist/cult) || VM.has_antag_datum(/datum/antagonist/changeling) || VM.has_antag_datum(/datum/antagonist/rev) || victim.key[1] == "@")
if(!silent)
to_chat(user, "<span class='warning'>[victim.p_their(TRUE)] mind is resisting your spell!</span>")
return FALSE
if(istype(victim, /mob/living/simple_animal/hostile/guardian))
var/mob/living/simple_animal/hostile/guardian/stand = victim
if(stand.summoner)
victim = stand.summoner
//You should not be able to enter one of the most powerful side-antags as a fucking wizard.
if(istype(victim,/mob/living/simple_animal/slaughter))
to_chat(user, "<span class='warning'>The devilish contract doesn't include the 'mind swappable' package, please try again another lifetime.</span>")
return
//MIND TRANSFER BEGIN
var/mob/dead/observer/ghost = victim.ghostize()
user.mind.transfer_to(victim)
ghost.mind.transfer_to(user)
if(ghost.key)
user.key = ghost.key //have to transfer the key since the mind was not active
qdel(ghost)
//MIND TRANSFER END
//Here we knock both mobs out for a time.
user.Unconscious(unconscious_amount_caster)
victim.Unconscious(unconscious_amount_victim)
SEND_SOUND(user, sound('sound/magic/mandswap.ogg'))
SEND_SOUND(victim, sound('sound/magic/mandswap.ogg')) // only the caster and victim hear the sounds, that way no one knows for sure if the swap happened
return TRUE
/obj/effect/proc_holder/spell/pointed/mind_transfer/can_target(atom/target, mob/user, silent)
. = ..()
if(!.)
return FALSE
if(!isliving(target))
if(!silent)
to_chat(user, "<span class='warning'>You can only swap minds with living beings!</span>")
return FALSE
if(user == target)
if(!silent)
to_chat(user, "<span class='warning'>You can't swap minds with yourself!</span>")
return FALSE
var/mob/living/victim = target
var/t_He = victim.p_they(TRUE)
if(ismegafauna(victim))
if(!silent)
to_chat(user, "<span class='warning'>This creature is too powerful to control!</span>")
return FALSE
if(victim.stat == DEAD)
if(!silent)
to_chat(user, "<span class='warning'>You don't particularly want to be dead!</span>")
return FALSE
if(!victim.key || !victim.mind)
if(!silent)
to_chat(user, "<span class='warning'>[t_He] appear[victim.p_s()] to be catatonic! Not even magic can affect [victim.p_their()] vacant mind.</span>")
return FALSE
if(user.suiciding)
if(!silent)
to_chat(user, "<span class='warning'>You're killing yourself! You can't concentrate enough to do this!</span>")
return FALSE
if(istype(victim, /mob/living/simple_animal/hostile/guardian))
var/mob/living/simple_animal/hostile/guardian/stand = victim
if(stand.summoner)
if(stand.summoner == user)
if(!silent)
to_chat(user, "<span class='warning'>Swapping minds with your own guardian would just put you back into your own head!</span>")
return FALSE
return TRUE

View File

@@ -0,0 +1,105 @@
/obj/effect/proc_holder/spell/pointed
name = "pointed spell"
ranged_mousepointer = 'icons/effects/mouse_pointers/throw_target.dmi'
action_icon_state = "projectile"
/// Message showing to the spell owner upon deactivating pointed spell.
var/deactive_msg = "You dispel the magic..."
/// Message showing to the spell owner upon activating pointed spell.
var/active_msg = "You prepare to use the spell on a target..."
/// Variable dictating if the user is allowed to cast a spell on himself.
var/self_castable = FALSE
/// Variable dictating if the spell will use turf based aim assist
var/aim_assist = TRUE
/obj/effect/proc_holder/spell/pointed/Trigger(mob/user, skip_can_cast = TRUE)
if(!istype(user))
return
var/msg
if(!can_cast(user))
msg = "<span class='warning'>You can no longer cast [name]!</span>"
remove_ranged_ability(msg)
return
if(active)
msg = "<span class='notice'>[deactive_msg]</span>"
remove_ranged_ability(msg)
else
msg = "<span class='notice'>[active_msg] <B>Left-click to activate spell on a target!</B></span>"
add_ranged_ability(user, msg, TRUE)
on_activation(user)
/obj/effect/proc_holder/spell/pointed/on_lose(mob/living/user)
remove_ranged_ability()
/obj/effect/proc_holder/spell/pointed/remove_ranged_ability(msg)
. = ..()
on_deactivation(ranged_ability_user)
/obj/effect/proc_holder/spell/pointed/add_ranged_ability(mob/living/user, msg, forced)
. = ..()
on_activation(user)
/**
* on_activation: What happens upon pointed spell activation.
*
* Arguments:
* * user The mob interacting owning the spell.
*/
/obj/effect/proc_holder/spell/pointed/proc/on_activation(mob/user)
return
/**
* on_activation: What happens upon pointed spell deactivation.
*
* Arguments:
* * user The mob interacting owning the spell.
*/
/obj/effect/proc_holder/spell/pointed/proc/on_deactivation(mob/user)
return
/obj/effect/proc_holder/spell/pointed/update_icon()
if(!action)
return
if(active)
action.button_icon_state = "[action_icon_state]1"
else
action.button_icon_state = "[action_icon_state]"
action.UpdateButtonIcon()
/obj/effect/proc_holder/spell/pointed/InterceptClickOn(mob/living/caller, params, atom/target)
if(..())
return TRUE
if(aim_assist && isturf(target))
var/list/possible_targets = list()
for(var/A in target)
if(intercept_check(caller, A, TRUE))
possible_targets += A
if(possible_targets.len == 1)
target = possible_targets[1]
if(!intercept_check(caller, target))
return TRUE
if(!cast_check(FALSE, caller))
return TRUE
perform(list(target), user = caller)
remove_ranged_ability()
return TRUE // Do not do any underlying actions after the spell cast
/**
* intercept_check: Specific spell checks for InterceptClickOn() targets.
*
* Arguments:
* * user The mob using the ranged spell via intercept.
* * target The atom that is being targeted by the spell via intercept.
* * silent If the checks should produce not any feedback messages for the user.
*/
/obj/effect/proc_holder/spell/pointed/proc/intercept_check(mob/user, atom/target, silent = FALSE)
if(!self_castable && target == user)
if(!silent)
to_chat(user, "<span class='warning'>You cannot cast the spell on yourself!</span>")
return FALSE
if(!(target in view_or_range(range, user, selection_type)))
if(!silent)
to_chat(user, "<span class='warning'>[target.p_theyre(TRUE)] too far away!</span>")
return FALSE
if(!can_target(target, user, silent))
return FALSE
return TRUE

View File

@@ -37,8 +37,8 @@
var/projectile_type = text2path(proj_type)
projectile = new projectile_type(user)
if(istype(proj_type, /obj/effect/proc_holder/spell))
projectile = new /obj/effect/proc_holder/spell/targeted/trigger(user)
var/obj/effect/proc_holder/spell/targeted/trigger/T = projectile
projectile = new /obj/effect/proc_holder/spell/pointed/trigger(user)
var/obj/effect/proc_holder/spell/pointed/trigger/T = projectile
T.linked_spells += proj_type
projectile.icon = proj_icon
projectile.icon_state = proj_icon_state

View File

@@ -1,30 +1,26 @@
/obj/effect/proc_holder/spell/targeted/trigger
/obj/effect/proc_holder/spell/pointed/trigger
name = "Trigger"
desc = "This spell triggers another spell or a few."
var/list/linked_spells = list() //those are just referenced by the trigger spell and are unaffected by it directly
var/list/starting_spells = list() //those are added on New() to contents from default spells and are deleted when the trigger spell is deleted to prevent memory leaks
/obj/effect/proc_holder/spell/targeted/trigger/Initialize()
/obj/effect/proc_holder/spell/pointed/trigger/Initialize()
. = ..()
for(var/spell in starting_spells)
var/spell_to_add = text2path(spell)
new spell_to_add(src) //should result in adding to contents, needs testing
/obj/effect/proc_holder/spell/targeted/trigger/Destroy()
/obj/effect/proc_holder/spell/pointed/trigger/Destroy()
for(var/spell in contents)
qdel(spell)
linked_spells = null
starting_spells = null
return ..()
/obj/effect/proc_holder/spell/targeted/trigger/cast(list/targets,mob/user = usr)
/obj/effect/proc_holder/spell/pointed/trigger/cast(list/targets,mob/user = usr)
playMagSound()
for(var/mob/living/target in targets)
for(var/obj/effect/proc_holder/spell/spell in contents)
spell.perform(list(target),0)
for(var/obj/effect/proc_holder/spell/spell in linked_spells)
spell.perform(list(target),0)
return

View File

@@ -207,40 +207,12 @@
summon_type = list(/mob/living/simple_animal/hostile/netherworld)
cast_sound = 'sound/magic/summonitems_generic.ogg'
/obj/effect/proc_holder/spell/targeted/trigger/blind
name = "Blind"
desc = "This spell temporarily blinds a single person and does not require wizard garb."
school = "transmutation"
charge_max = 300
clothes_req = NONE
invocation = "STI KALY"
invocation_type = "whisper"
message = "<span class='notice'>Your eyes cry out in pain!</span>"
cooldown_min = 50 //12 deciseconds reduction per rank
starting_spells = list("/obj/effect/proc_holder/spell/targeted/inflict_handler/blind","/obj/effect/proc_holder/spell/targeted/genetic/blind")
action_icon_state = "blind"
/obj/effect/proc_holder/spell/aoe_turf/conjure/creature/cult
name = "Summon Creatures (DANGEROUS)"
clothes_req = SPELL_CULT_GARB
charge_max = 5000
summon_amt = 2
/obj/effect/proc_holder/spell/targeted/inflict_handler/blind
amt_eye_blind = 10
amt_eye_blurry = 20
sound = 'sound/magic/blind.ogg'
/obj/effect/proc_holder/spell/targeted/genetic/blind
mutations = list(BLINDMUT)
duration = 300
sound = 'sound/magic/blind.ogg'
/obj/effect/proc_holder/spell/aoe_turf/repulse
name = "Repulse"
desc = "This spell throws everything around the user away."