[Cult 4] "NAR-SIE'S HOLIDAYS" , aka "The End of Cult 3.0" (#30672)

* day 1

* day 1.1

* day 2

* day 3

* day 4

* day 5

* day 5.1

* day 6

* day 6.1

* day 7

* day 7.1

* day 8

* day 9

* day 10

* day 11

* day 11.1

* 11.1.1

* day 12

* and on the 13th day, he looked upon his work, and was pleased with what he saw

* 13.1

* day 14

* day 15

* day 16

* day 16.1

* fixing conflicts after rebasing post-Europa removal

* day 17

* day 17.1

* day 18

* day 18.1

* day 19

* day 19.1

* day 20

* day 20.1

* day 21

* day 21.1
This commit is contained in:
DeityLink
2021-10-09 01:32:34 +02:00
committed by GitHub
parent e6cc249f61
commit a7ddac5c97
135 changed files with 3949 additions and 2825 deletions

View File

@@ -111,7 +111,8 @@
step(controlled,direction)
controlled.dir = direction
if (blade.loc != start)
blade.blood = max(blade.blood-1,0)
if (!blade.linked_cultist || (get_dist(get_turf(blade.linked_cultist),get_turf(controller)) > 5))
blade.blood = max(blade.blood-1,0)
move_delay = 1
spawn(blade.movespeed)
move_delay = 0

View File

@@ -0,0 +1,98 @@
/datum/body_archive // basically /datum/mind scans its mob when first created, allowing the original body to be re-created if needed
var/mob_type
var/datum/dna2/record/dna_records
/datum/body_archive/New(var/mob/source)
if (!source)
qdel(src)
return
..()
mob_type = source.type
if (ishuman(source))
var/mob/living/carbon/human/H = source
var/datum/organ/internal/brain/Brain = H.internal_organs_by_name["brain"]
var/datum/dna2/record/R = new /datum/dna2/record()
if(!isnull(Brain.owner_dna) && Brain.owner_dna != H.dna)
R.dna = Brain.owner_dna.Clone()
else
R.dna = H.dna.Clone()
R.ckey = H.ckey
R.id= copytext(md5(R.dna.real_name), 2, 6)
R.name=R.dna.real_name
R.types=DNA2_BUF_UI|DNA2_BUF_UE|DNA2_BUF_SE
R.languages = H.languages.Copy()
R.attack_log = H.attack_log.Copy()
R.default_language = H.default_language
R.times_cloned = H.times_cloned
R.talkcount = H.talkcount
dna_records = R
/////////////////////////////////////////////
/mob/proc/reset_body(var/datum/body_archive/archive)
if (!archive)
if (mind && mind.body_archive)
archive = mind.body_archive
else
return
var/mob/new_mob
// can't just do a /mob/living/carbon/human/reset_body() since the mob might have changed to a non-human since then
if (archive.mob_type in typesof(/mob/living/carbon/human))
var/datum/dna2/record/R = archive.dna_records
var/mob/living/carbon/human/H = new /mob/living/carbon/human(loc, R.dna.species, delay_ready_dna = TRUE)
H.times_cloned = 0
H.talkcount = R.talkcount
if(isplasmaman(H))
H.fire_sprite = "Plasmaman"
H.dna = R.dna.Clone()
H.dna.flavor_text = R.dna.flavor_text
H.dna.species = R.dna.species
if(H.dna.species != "Human")
H.set_species(H.dna.species, TRUE)
H.check_mutations = TRUE
H.updatehealth()
has_been_shade -= mind
mind.transfer_to(H)
H.ckey = R.ckey
if (H.mind.miming)
H.add_spell(new /spell/aoe_turf/conjure/forcewall/mime, "grey_spell_ready")
if (H.mind.miming == MIMING_OUT_OF_CHOICE)
H.add_spell(new /spell/targeted/oathbreak/)
if (isvampire(H))
var/datum/role/vampire/V = isvampire(H)
V.check_vampire_upgrade()
V.update_vamp_hud()
H.UpdateAppearance()
H.set_species(R.dna.species)
H.dna.mutantrace = R.dna.mutantrace
H.update_mutantrace()
for(var/datum/language/L in R.languages)
H.add_language(L.name)
if (L == R.default_language)
H.default_language = R.default_language
H.attack_log = R.attack_log
H.real_name = H.dna.real_name
H.name = H.real_name
H.flavor_text = H.dna.flavor_text
if(H.mind)
H.mind.suiciding = FALSE
H.update_name()
if (H.client)
H.client.eye = H.client.mob
H.client.perspective = MOB_PERSPECTIVE
H.updatehealth()
domutcheck(H)
new_mob = H
else
new_mob = new archive.mob_type(loc)
mind.transfer_to(new_mob)
drop_all()
qdel(src)
return new_mob

View File

@@ -29,6 +29,7 @@
var/stat_allowed = CONSCIOUS
var/hands_needed = 0//how many hands do you need to perform the emote
var/static/list/emote_list = list()
var/replace_pronouns = TRUE
/datum/emote/New()
if(key_third_person)
@@ -99,7 +100,7 @@
if(findtext(message, "%s"))
message = replacetext(message, "%s", "")
return message
else
else if (replace_pronouns)
switch(H.gender)
if(MALE)
if(findtext(message, "their"))

View File

@@ -359,14 +359,8 @@
var/datum/faction/bloodcult/cult = find_active_faction_by_type(/datum/faction/bloodcult)
if (!cult)
cult = ticker.mode.CreateFaction(/datum/faction/bloodcult, null, 1)
var/leader = 1
for(var/mob/M in assigned)
var/datum/role/cultist/newCultist
if (leader) // First of the gang
newCultist = new /datum/role/cultist/chief
leader = 0
else
newCultist = new
var/datum/role/cultist/newCultist = new
newCultist.AssignToRole(M.mind,1)
cult.HandleRecruitedRole(newCultist)
newCultist.Greet(GREET_ROUNDSTART)

View File

@@ -374,7 +374,7 @@
* /raisestructure
* /communication
* /summontome
* /conjuretalisman
* /paraphernalia
* /conversion
* /stun
* /blind

File diff suppressed because it is too large Load Diff

View File

@@ -87,16 +87,10 @@
takeDamage(Proj.damage)
return ..()
/obj/structure/cult/attackby(var/obj/item/weapon/W, var/mob/user)
if (istype(W, /obj/item/weapon/grab))
var/obj/item/weapon/grab/G = W
if(iscarbon(G.affecting))
MouseDropTo(G.affecting,user)
qdel(W)
else if (istype(W))
/obj/structure/cult/attackby(var/obj/item/weapon/W, var/mob/user, params)
if (istype(W))
if(user.a_intent == I_HELP || W.force == 0)
visible_message("<span class='warning'>\The [user] gently taps \the [src] with \the [W].</span>")
MouseDropTo(W,user)
else
user.delayNextAttack(8)
user.do_attack_animation(src, W)
@@ -206,6 +200,7 @@
var/lock_type = /datum/locking_category/buckle/bed
var/altar_task = ALTARTASK_NONE
var/gem_delay = 300
var/narsie_message_cooldown = 0
var/list/watching_mobs = list()
var/list/watcher_maps = list()
@@ -248,7 +243,7 @@
..()
/obj/structure/cult/altar/attackby(var/obj/item/I, var/mob/user)
/obj/structure/cult/altar/attackby(var/obj/item/I, var/mob/user, params)
if (altar_task)
return ..()
if(istype(I,/obj/item/weapon/melee/soulblade) || (istype(I,/obj/item/weapon/melee/cultblade) && !istype(I,/obj/item/weapon/melee/cultblade/nocult)))
@@ -289,6 +284,9 @@
return 1
var/obj/item/weapon/grab/G = I
if(iscarbon(G.affecting))
if (blade)
to_chat(user,"<span class='warning'>You must remove \the [blade] planted on \the [src] first.</span>")
return 1
var/mob/living/carbon/C = G.affecting
C.unlock_from()
if (!do_after(user,C,15))
@@ -300,6 +298,10 @@
qdel(G)
to_chat(user, "<span class='warning'>You move \the [C] on top of \the [src]</span>")
return 1
if(user.drop_item(I, loc))
if((I.loc == loc) && params)
I.setPixelOffsetsFromParams(params, user, pixel_x, pixel_y)
return 1
..()
/obj/structure/cult/altar/update_icon()
@@ -387,6 +389,7 @@
O.forceMove(loc)
to_chat(user, "<span class='warning'>You move \the [O] on top of \the [src]</span>")
return 1
/obj/structure/cult/altar/proc/checkPosition()
@@ -437,19 +440,36 @@
stopWatching(user)
return
if (altar_task)
if (altar_task == ALTARTASK_SACRIFICE)
if (user in contributors)
return
if (!user.checkTattoo(TATTOO_SILENT))
if (prob(5))
user.say("Let me show you the dance of my people!","C")
else
user.say("Barhah hra zar'garis!","C")
contributors.Add(user)
if (user.client)
user.client.images |= progbar
switch (altar_task)
if (ALTARTASK_GEM)
to_chat(user, "<span class='warning'>You must wait before the Altar's current task is over.</span>")
if (ALTARTASK_SACRIFICE)
if (user in contributors)
return
if (!user.checkTattoo(TATTOO_SILENT))
if (prob(5))
user.say("Let me show you the dance of my people!","C")
else
user.say("Barhah hra zar'garis!","C")
contributors.Add(user)
if (user.client)
user.client.images |= progbar
return
if(is_locking(lock_type))
var/mob/M = get_locked(lock_type)[1]
if(M != user)
if (do_after(user,src,20))
M.visible_message("<span class='notice'>\The [M] was freed from \the [src] by \the [user]!</span>","You were freed from \the [src] by \the [user].")
unlock_atom(M)
if (blade)
blade.forceMove(loc)
blade.attack_hand(user)
to_chat(user, "<span class='warning'>You remove \the [blade] from \the [src]</span>")
blade = null
playsound(loc, 'sound/weapons/blade1.ogg', 50, 1)
update_icon()
// TODO UPHEAVAL PART 2, might bring back sacrifices later, for now you can still stab people on altars
/*
var/choices = list(
list("Remove Blade", "radial_altar_remove", "Pull the blade off, freeing the victim."),
list("Sacrifice", "radial_altar_sacrifice", "Initiate the sacrifice ritual. The ritual can only proceed if the proper victim has been nailed to the altar."),
@@ -472,44 +492,50 @@
playsound(loc, 'sound/weapons/blade1.ogg', 50, 1)
update_icon()
if ("Sacrifice")
// First we'll check for any blockers around it since we'll dance using forceMove to allow up to 8 dancers without them bumping into each others
// Of course this means that walls and objects placed AFTER the start of the dance can be crossed by dancing but that's good enough.
for (var/turf/T in orange(1,src))
if (T.density)
to_chat(user, "<span class='warning'>The [T] would hinder the ritual. Either dismantle it or use an altar located in a more spacious area.</span>")
return
var/atom/A = T.has_dense_content()
if (A && (A != src) && !ismob(A)) // mobs get a free pass
to_chat(user, "<span class='warning'>\The [A] would hinder the ritual. Either move it or use an altar located in a more spacious area.</span>")
return
var/datum/faction/bloodcult/cult = find_active_faction_by_type(/datum/faction/bloodcult)
if (cult)
var/datum/objective/bloodcult_sacrifice/O = locate() in cult.objective_holder.objectives
if (O && is_locking(lock_type))
var/mob/victim = get_locked(lock_type)[1]
if (victim == O.sacrifice_target || (victim.mind && victim.mind == O.sacrifice_mind))
altar_task = ALTARTASK_SACRIFICE
timeleft = 30
timetotal = timeleft
update_icon()
contributors.Add(user)
update_progbar()
if (user.client)
user.client.images |= progbar
var/image/I = image('icons/obj/cult.dmi',"build")
I.pixel_y = 8
src.overlays += I
if (!user.checkTattoo(TATTOO_SILENT))
if (prob(5))
user.say("Let me show you the dance of my people!","C")
if (is_locking(lock_type))
altar_task = ALTARTASK_SACRIFICE
timeleft = 30
timetotal = timeleft
update_icon()
contributors.Add(user)
update_progbar()
if (user.client)
user.client.images |= progbar
var/image/I = image('icons/obj/cult.dmi',"build")
I.pixel_y = 8
src.overlays += I
if (!user.checkTattoo(TATTOO_SILENT))
if (prob(5))
user.say("Let me show you the dance of my people!","C")
else
user.say("Barhah hra zar'garis!","C")
if (user.client)
user.client.images |= progbar
/*
for(var/mob/M in range(src,40))
if (M.z == z && M.client)
if (get_dist(M,src)<=20)
M.playsound_local(src, get_sfx("explosion"), 50, 1)
shake_camera(M, 2, 1)
else
user.say("Barhah hra zar'garis!","C")
if (user.client)
user.client.images |= progbar
safe_space()
for(var/mob/M in range(src,40))
if (M.z == z && M.client)
if (get_dist(M,src)<=20)
M.playsound_local(src, get_sfx("explosion"), 50, 1)
shake_camera(M, 2, 1)
else
M.playsound_local(src, 'sound/effects/explosionfar.ogg', 50, 1)
shake_camera(M, 1, 1)
spawn()
dance_start()
else
to_chat(user, "<span class='sinister'>This isn't the One.</span>")
M.playsound_local(src, 'sound/effects/explosionfar.ogg', 50, 1)
shake_camera(M, 1, 1)
*/
spawn()
dance_start()
*/
else if (blade)
blade.forceMove(loc)
blade.attack_hand(user)
@@ -522,7 +548,7 @@
var/choices = list(
list("Consult Roster", "radial_altar_roster", "Check the names and status of all of the cult's members."),
list("Look through Veil", "radial_altar_map", "Check the veil for tears to locate other occult constructions."),
list("Commune with Nar-Sie", "radial_altar_commune", "Obtain guidance from Nar-Sie to help you complete your objectives."),
list("Commune with Nar-Sie", "radial_altar_commune", "Make contact with Nar-Sie."),
list("Conjure Soul Gem", "radial_altar_gem", "Order the altar to sculpt you a Soul Gem, to capture the soul of your enemies."),
)
var/task = show_radial_menu(user,loc,choices,'icons/obj/cult_radial3.dmi',"radial-cult2")
@@ -537,6 +563,14 @@
for (var/datum/role/cultist/C in cult.members)
var/datum/mind/M = C.antag
var/conversion = ""
var/cult_role = ""
switch (C.cultist_role)
if (CULTIST_ROLE_ACOLYTE)
cult_role = "Acolyte"
if (CULTIST_ROLE_MENTOR)
cult_role = "Mentor"
else
cult_role = "Herald"
if (C.conversion.len > 0)
conversion = pick(C.conversion)
var/origin_text = ""
@@ -560,7 +594,7 @@
extra = " - <span style='color:#FFFF00'>CRITICAL</span>"
else if (H.isDead())
extra = " - <span style='color:#FF0000'>DEAD</span>"
dat += "<li><b>[M.name]</b></li> - [origin_text][extra]"
dat += "<li><b>[M.name] ([cult_role])</b></li> - [origin_text][extra]"
for(var/obj/item/weapon/handcuffs/cult/cuffs in cult.bindings)
if (iscarbon(cuffs.loc))
var/mob/living/carbon/C = cuffs.loc
@@ -574,7 +608,7 @@
extra = " - <span style='color:#FF0000'>DEAD</span>"
dat += "<li><span style='color:#FFFF00'><b>[C.real_name]</b></span></li> - Prisoner of [gaoler.name][extra]"
dat += {"</ul></body>"}
user << browse("<TITLE>Cult Roster</TITLE>[dat]", "window=cultroster;size=500x300")
user << browse("<TITLE>Cult Roster</TITLE>[dat]", "window=cultroster;size=600x400")
onclose(user, "cultroster")
if ("Look through Veil")
if(user.hud_used && user.hud_used.holomap_obj)
@@ -598,47 +632,19 @@
user.client.images |= watcher_maps["\ref[user]"]
user.register_event(/event/face, src, /obj/structure/cult/altar/proc/checkPosition)
if ("Commune with Nar-Sie")
switch(veil_thickness)
if (CULT_MENDED)
to_chat(user, "...nothing but silence...")
if (CULT_PROLOGUE)
to_chat(user, "<span class='game say'><span class='danger'>Nar-Sie</span> murmurs, <span class='sinister'>How interesting...</span></span>")
if (CULT_ACT_I)
to_chat(user, "<span class='game say'><span class='danger'>Nar-Sie</span> murmurs, <span class='sinister'>The conversion rune is <span class='danger'>Join Blood Self</span>, but you now have many new runes at your disposal to help you in your task, therefore I recommend you first summon an Arcane Tome to easily scribe them. The rune that conjures a tome is <span class='danger'>See Blood Hell</span>.</span></span>")
if (CULT_ACT_II)
var/datum/faction/bloodcult/cult = find_active_faction_by_type(/datum/faction/bloodcult)
if (cult)
var/datum/objective/bloodcult_sacrifice/O = locate() in cult.objective_holder.objectives
if (O && !O.IsFulfilled())
if (!O.sacrifice_target || !O.sacrifice_target.loc)//if there's no target or its body was destroyed, immediate reroll
replace_target()
return
else
var/turf/T = get_turf(O.sacrifice_target)
var/datum/shuttle/S = is_on_shuttle(T)
if ((T.z == CENTCOMM_Z) && (emergency_shuttle.shuttle == S || emergency_shuttle.escape_pods.Find(S)))
to_chat(user,"<b>\The [O.sacrifice_target] has fled the station along with the rest of the crew. Unless we can bring them back in time with a Path rune or sacrifice him where he stands, it's over.</b>")
return
else if (T.z != STATION_Z)//if the target fled the station, offer to reroll the target. May or not add penalties for that later.
var/choice = alert(user,"The target has fled the station, do you wish for another sacrifice target to be selected?","[name]","Yes","No")
if (choice == "Yes")
replace_target(user)
return
else
to_chat(user,"<b>\The [O.sacrifice_target] is in [get_area_name(O, 1)].</b>")
to_chat(user, "<span class='game say'><span class='danger'>Nar-Sie</span> murmurs, <span class='sinister'>To perform the sacrifice, you'll have to forge a cult blade first. It doesn't matter if the target is alive of not, lay their body down on the altar and plant the blade on their stomach. Next, touch the altar to perform the next step of the ritual. The more of you, the quicker it will be done.</span></span>")
if (CULT_ACT_III)
to_chat(user, "<span class='game say'><span class='danger'>Nar-Sie</span> murmurs, <span class='sinister'>The crew is now aware of our presence, prepare to draw blood. Your priority is to spill as much blood as you can all over the station, bloody trails left by foot steps count toward this goal. How you obtain the blood, I leave to your ambition, but remember that if the crew destroys every blood stones, you will be doomed.</span></span>")
if (CULT_ACT_IV)
to_chat(user, "<span class='game say'><span class='danger'>Nar-Sie</span> murmurs, <span class='sinister'>One of the blood stones has become my anchor in this plane, you can touch any other stone to locate it. Touch the anchor to perform the Tear Reality ritual before the crew breaks it.</span></span>")
if (CULT_EPILOGUE)
to_chat(user, "<span class='game say'><span class='danger'>Nar-Sie</span> murmurs, <span class='sinister'>Remarkable work, [user.real_name], I greatly enjoyed observing this game. Your work is over now, but I may have more in store for you in the future. In the meanwhile, bask in your victory.</span></span>")
/* TODO: I'll finish that up someday
var/dat = {"<body style="color:#FFFFFF" bgcolor="#110000"><ul>"}
dat += {"</ul></body>"}
user << browse("<TITLE>Nar-Sie's Tips</TITLE>[dat]", "window=narsietips;size=500x300")
onclose(user, "narsietips")
*/
if(narsie_message_cooldown)
to_chat(user, "<span class='warning'>This altar has already sent a message in the past 30 seconds, wait a moment.</span>")
return
var/input = stripped_input(user, "Please choose a message to transmit to Nar-Sie through the veil. Know that he can be fickle, and abuse of this ritual will leave your body asunder. Communion does not guarantee a response. There is a 30 second delay before you may commune again, be clear, full and concise.", "To abort, send an empty message.", "")
if(!input || !Adjacent(user))
return
NarSie_announce(input, usr)
to_chat(usr, "<span class='notice'>Your communion has been received.</span>")
var/turf/T = get_turf(usr)
log_say("[key_name(usr)] (@[T.x],[T.y],[T.z]) has communed with Nar-Sie: [input]")
narsie_message_cooldown = 1
spawn(30 SECONDS)
narsie_message_cooldown = 0
if ("Conjure Soul Gem")
altar_task = ALTARTASK_GEM
update_icon()
@@ -655,26 +661,6 @@
var/obj/item/soulstone/gem/gem = new (loc)
gem.pixel_y = 4
/obj/structure/cult/altar/proc/replace_target(var/mob/user)
var/datum/faction/bloodcult/cult = find_active_faction_by_type(/datum/faction/bloodcult)
if (cult)
var/datum/objective/bloodcult_sacrifice/O = locate() in cult.objective_holder.objectives
if (O && !O.IsFulfilled())
if (O.replace_target(user))
for(var/datum/role/cultist/C in cult.members)
var/mob/M = C.antag.current
if (M && iscultist(M))
to_chat(M,"<b>A new target has been assigned. [O.explanation_text]</b>")
if (M == O.sacrifice_target)
to_chat(M,"<b>There is no greater honor than purposefuly relinquishing your body for the coming of Nar-Sie.</b>")
to_chat(M,"<b>Should the target's body be annihilated, or should they flee the station, you may commune with Nar-Sie at an altar to have him designate a new target.</b>")
else
for(var/datum/role/cultist/C in cult.members)
var/mob/M = C.antag.current
if (M && iscultist(M))
to_chat(M,"<b>There are no elligible targets aboard the station, how did you guys even manage that one?</b>")//if there's literally no humans aboard the station
to_chat(M,"<b>There needs to be humans aboard the station, cultist or not, for a target to be selected.</b>")
/obj/structure/cult/altar/noncultist_act(var/mob/user)//Non-cultists can still remove blades planted on altars.
if(is_locking(lock_type))
var/mob/M = get_locked(lock_type)[1]
@@ -749,7 +735,6 @@
var/datum/role/cultist/newCultist = cult.HandleRecruitedMind(shadeMob.mind, TRUE)
newCultist.Greet(GREET_SOULBLADE)
newCultist.conversion.Add("altar")
cult_risk()//risk of exposing the cult early if too many soul blades created
/obj/structure/cult/altar/dance_start()//This is executed at the end of the sacrifice ritual
@@ -770,6 +755,14 @@
blade.shade = new_shade
blade.update_icon()
blade = null
for(var/mob/living/L in dview(world.view, loc, INVISIBILITY_MAXIMUM))
if (L.client)
L.playsound_local(loc, 'sound/effects/convert_failure.ogg', 75, 0, -4)
playsound(loc, get_sfx("soulstone"), 50,1)
var/obj/effect/cult_ritual/conversion/anim = new(loc)
anim.icon_state = ""
flick("rune_convert_refused",anim)
anim.Die()
if (!iscultist(new_shade))
var/datum/role/cultist/newCultist = new
@@ -790,17 +783,6 @@
playsound(src, get_sfx("soulstone"), 50,1)
else
M.gib()
var/turf/T = loc
var/datum/faction/bloodcult/cult = find_active_faction_by_type(/datum/faction/bloodcult)
if (cult)
if (emergency_shuttle.direction == 2) // Going to centcomm
cult.minor_victory()
else
cult.stage(CULT_ACT_III,T)
else
message_admins("Blood Cult: A sacrifice was completed...but we cannot find the cult faction...")//failsafe in case of admin varedit fuckery
qdel(src)
#undef ALTARTASK_NONE
#undef ALTARTASK_GEM
@@ -831,9 +813,10 @@ var/list/cult_spires = list()
/obj/structure/cult/spire/New()
..()
cult_spires.Add(src)
cult_spires += src
set_light(1)
stage = clamp(veil_thickness, 1, 3)
//TODO (UPHEAVAL PART 2) appearance changes with cult score
stage = 1
flick("spire[stage]-spawn",src)
spawn(10)
update_stage()
@@ -847,12 +830,12 @@ var/list/cult_spires = list()
holomap_markers[HOLOMAP_MARKER_CULT_SPIRE+"_\ref[src]"] = holomarker
/obj/structure/cult/spire/Destroy()
cult_spires.Remove(src)
cult_spires -= src
holomap_markers -= HOLOMAP_MARKER_CULT_SPIRE+"_\ref[src]"
..()
/obj/structure/cult/spire/proc/upgrade()
var/new_stage = clamp(veil_thickness, 1, 3)
var/new_stage = clamp(stage, 1, 3)
if (new_stage>stage)
stage = new_stage
alpha = 255
@@ -885,7 +868,7 @@ var/list/cult_spires = list()
I_base.layer = BELOW_PROJECTILE_LAYER
I_base.appearance_flags |= RESET_COLOR//we don't want the stone to pulse
var/image/I_spire = image('icons/obj/cult_64x64.dmi',"spire[stage]-light")
I_spire.plane = relative_plane(ABOVE_LIGHTING_PLANE)
I_spire.plane = ABOVE_LIGHTING_PLANE
I_spire.layer = NARSIE_GLOW
overlays += I_base
overlays += I_spire
@@ -916,6 +899,9 @@ var/list/cult_spires = list()
if (!.)
return
// For now spires work as cult telecomms relay. Might give them another role later, maybe soul gem production instead of altars
/*
if (!ishuman(user))
to_chat(user,"<span class='warning'>Only humans can bear the arcane markings granted by this [name].</span>")
return
@@ -983,6 +969,7 @@ var/list/cult_spires = list()
if (available_tattoos.len > 0)
cultist_act(user)
break
*/
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// //Spawned from the Raise Structure rune. Available from Act II
@@ -1061,7 +1048,7 @@ var/list/cult_spires = list()
I_base.layer = BELOW_PROJECTILE_LAYER
I_base.appearance_flags |= RESET_ALPHA //we don't want the stone to pulse
var/image/I_lave = image('icons/obj/cult_64x64.dmi',"forge-lightmask")
I_lave.plane = relative_plane(ABOVE_LIGHTING_PLANE)
I_lave.plane = ABOVE_LIGHTING_PLANE
I_lave.layer = NARSIE_GLOW
I_lave.blend_mode = BLEND_ADD
overlays += I_base
@@ -1112,11 +1099,11 @@ var/list/cult_spires = list()
forger = null
template = null
else
anim(target = loc, a_icon = 'icons/obj/cult_64x64.dmi', flick_anim = "forge-work", lay = NARSIE_GLOW, plane = ABOVE_LIGHTING_PLANE)
anim(target = loc, a_icon = 'icons/obj/cult_64x64.dmi', flick_anim = "forge-work", lay = NARSIE_GLOW, offX = pixel_x, offY = pixel_y, plane = ABOVE_LIGHTING_PLANE)
playsound(L, 'sound/effects/forge.ogg', 50, 0, -4)
forging.overlays.len = 0
var/image/I = image('icons/obj/cult_64x64.dmi',"[forging.icon_state]-mask")
I.plane = relative_plane(ABOVE_LIGHTING_PLANE)
I.plane = ABOVE_LIGHTING_PLANE
I.layer = NARSIE_GLOW
I.blend_mode = BLEND_ADD
I.alpha = (timeleft/timetotal)*255
@@ -1161,7 +1148,7 @@ var/list/cult_spires = list()
I_base.layer = BELOW_PROJECTILE_LAYER
I_base.appearance_flags |= RESET_ALPHA //we don't want the stone to pulse
var/image/I_lave = image('icons/obj/cult_64x64.dmi',"forge-lightmask")
I_lave.plane = relative_plane(ABOVE_LIGHTING_PLANE)
I_lave.plane = ABOVE_LIGHTING_PLANE
I_lave.layer = NARSIE_GLOW
I_lave.blend_mode = BLEND_ADD
overlays += I_base
@@ -1172,6 +1159,10 @@ var/list/cult_spires = list()
var/obj/item/clothing/mask/cigarette/fag = I
fag.light("<span class='notice'>\The [user] lights \the [fag] by bringing its tip close to \the [src]'s molten flow.</span>")
return 1
if(istype(I,/obj/item/candle))
var/obj/item/candle/stick = I
stick.light("<span class='notice'>\The [user] lights \the [stick] by bringing its wick close to \the [src]'s molten flow.</span>")
return 1
if(istype(I,/obj/item/weapon/talisman) || istype(I,/obj/item/weapon/paper) || istype(I,/obj/item/weapon/tome))
I.ashify_item(user)
return 1
@@ -1262,7 +1253,7 @@ var/list/cult_spires = list()
..()
icon_state = i_forge
var/image/I = image('icons/obj/cult_64x64.dmi',"[i_forge]-mask")
I.plane = relative_plane(ABOVE_LIGHTING_PLANE)
I.plane = ABOVE_LIGHTING_PLANE
I.layer = NARSIE_GLOW
I.blend_mode = BLEND_ADD
overlays += I
@@ -1325,6 +1316,7 @@ var/list/cult_spires = list()
if (3)
takeDamage(20)
/*
var/list/bloodstone_list = list()
/obj/structure/cult/bloodstone
@@ -1511,10 +1503,6 @@ var/list/bloodstone_list = list()
watching_mobs -= user
/datum/station_holomap/cult/initialize_holomap(var/turf/T, var/isAI=null, var/mob/user=null, var/cursor_icon = "bloodstone-here")
station_map = image(extraMiniMaps[HOLOMAP_EXTRA_CULTMAP])
cursor = image('icons/holomap_markers.dmi', cursor_icon)
/obj/structure/cult/bloodstone/update_icon()
icon_state = "bloodstone-0"
var/datum/faction/bloodcult/cult = find_active_faction_by_type(/datum/faction/bloodcult)
@@ -1624,6 +1612,7 @@ var/list/bloodstone_list = list()
takeDamage(50)
if (3)
takeDamage(10)
*/
/obj/structure/cult/proc/safe_space()
for(var/turf/T in range(5,src))

View File

@@ -1,109 +0,0 @@
var/runesets_initialized = 0
var/list/datum/runeset/global_runesets = list()
/datum/runeset //Abstract base class
var/identifier //Key mapped to this runeset in runesets. Also used to sync runewords and runesets
var/list/rune_list = list() //List of all runes, used for various purposes.
var/list/words = list()
var/list/words_english = list()
var/list/words_rune = list()
var/list/words_icons = list()
/proc/initialize_runesets()
if(runesets_initialized)
return
for(var/runeset_cast in subtypesof(/datum/runeset))
var/datum/runeset/rune_set = new runeset_cast()
for(var/wordset_cast in subtypesof(/datum/runeword))
var/datum/runeword/word_set = new wordset_cast()
if(rune_set.identifier == word_set.identifier)
global_runesets[rune_set.identifier] = rune_set
for(var/word_info in subtypesof(word_set))
var/datum/runeword/new_word = new word_info()
if(new_word.english)
rune_set.words[new_word.english] = new_word
global_runesets[rune_set.identifier] = rune_set
runesets_initialized = 1
/datum/runeset/blood_cult //Real cultists
identifier = "blood_cult"
//Hard-coded lists, used by various things for ease of access. Should probably code the initialize_runesets to automatically make these, but whatever.
words_english = list("travel", "blood", "join", "hell", "destroy", "technology", "self", "see", "other", "hide")
words_rune = list("ire","ego","nahlizet","certum","veri","jatkaa","mgar","balaq", "karazet", "geeri")
words_icons = list("rune-1","rune-2","rune-4","rune-8","rune-16","rune-32","rune-64","rune-128", "rune-256", "rune-512")
/datum/runeword
var/identifier
var/english
var/rune
var/icon = 'icons/effects/uristrunes.dmi'
var/icon_state = ""
/datum/runeword/blood_cult
identifier = "blood_cult"
icon = 'icons/effects/uristrunes.dmi'
icon_state = ""
var/color //Used by path rune markers
/datum/runeword/blood_cult/travel
english = "travel"
rune = "ire"
icon_state = "rune-1"
color = "yellow"
/datum/runeword/blood_cult/blood
english = "blood"
rune = "ego"
icon_state = "rune-2"
color = "maroon"
/datum/runeword/blood_cult/join
english = "join"
rune = "nahlizet"
icon_state = "rune-4"
color = "green"
/datum/runeword/blood_cult/hell
english = "hell"
rune = "certum"
icon_state = "rune-8"
color = "red"
/datum/runeword/blood_cult/destroy
english = "destroy"
rune = "veri"
icon_state = "rune-16"
color = "purple"
/datum/runeword/blood_cult/technology
english = "technology"
rune = "jatkaa"
icon_state = "rune-32"
color = "blue"
/datum/runeword/blood_cult/self
english = "self"
rune = "mgar"
icon_state = "rune-64"
color = null
/datum/runeword/blood_cult/see
english = "see"
rune = "balaq"
icon_state = "rune-128"
color = "fuchsia"
/datum/runeword/blood_cult/other
english = "other"
rune = "karazet"
icon_state = "rune-256"
color = "teal"
/datum/runeword/blood_cult/hide
english = "hide"
rune = "geeri"
icon_state = "rune-512"
color = "silver"

View File

@@ -1,4 +1,28 @@
///////////////////////////////////////VISUAL EFFECTS//////////////////////////////////////////////
// Based on holopad rays. Causes a Shadow to move from T to C
// "sprite" var can be replaced to use another icon_state from icons/effects/96x96.dmi
/proc/shadow(var/atom/C,var/turf/T,var/sprite="rune_blind")
var/disty = C.y - T.y
var/distx = C.x - T.x
var/newangle
if(!disty)
if(distx >= 0)
newangle = 90
else
newangle = 270
else
newangle = arctan(distx/disty)
if(disty < 0)
newangle += 180
else if(distx < 0)
newangle += 360
var/matrix/M1 = matrix()
var/matrix/M2 = turn(M1.Scale(1,sqrt(distx*distx+disty*disty)),newangle)
return anim(target = C, a_icon = 'icons/effects/96x96.dmi', flick_anim = sprite, lay = NARSIE_GLOW, offX = -WORLD_ICON_SIZE, offY = -WORLD_ICON_SIZE, plane = ABOVE_LIGHTING_PLANE, trans = M2)
///////////////////////////////////////CULT RITUALS////////////////////////////////////////////////
//Effects spawned by rune spells
@@ -80,6 +104,9 @@
/obj/effect/afterimage/red
image_color = "red"
/obj/effect/afterimage/black
image_color = "black"
/obj/effect/afterimage/New(var/turf/loc, var/atom/model, var/fadout = 5)
..()
if(model)

View File

@@ -1,40 +1,28 @@
var/list/failure_lines_by_dept = list(
COMMAND_POSITIONS = list(
"You have failed to lead them. You would have failed to follow." = 3,
"And so ends your 'authority.'" = 3,
"This is what passes as command these days." = 3,
),
ENGINEERING_POSITIONS = list(
"Our craft is more complex than your pathetic tinkering." = 3,
"These machines were beyond your skill anyway." = 3,
),
MEDICAL_POSITIONS = list(
"Your refusal helps no one. The blood will still flow." = 3,
"There is no cure for this." = 3,
"Nothing can heal the veil." = 3,
),
SCIENCE_POSITIONS = list(
"Your closed mind dishonours you." = 3,
"Our secrets were beyond your understanding." = 3,
"My science was not for weaklings such as you." = 3,
),
CIVILIAN_POSITIONS = list(
"A little job in life, and a forgotten death." = 3,
"This refusal is but a footnote on my story." = 3,
"You refused the only opportunity you had to make a difference." = 3,
),
CARGO_POSITION = list(
"I care little for the hoarders of your kind." = 3,
"As expected for a glorified crate handler." = 3,
),
SECURITY_POSITION = list(
"You already failed." = 3,
"This refusal does not erase your failure." = 3,
"Your stubbornness amuses me. I already won." = 3,
"I could have freed you." = 3,
"You will always remain on the weaker side." = 3,
),
)
/*
Disabling those for now.
On one hand I'd rather keep Nar-Sie talking as an admin-only thing
On the other hand those don't quite portray the love of blood and chaos that Nar-Sie is associated with, aside from one or two lines those are very generic.
As for Conversion Failure lines, they're pretty much deprecated since conversion failures no longer kill their victims
Also since we might want to try converting them again later no need for Nar-Sie to be this petty, that's not a good image
/* -- Flavour text for refusing/accepting conversion.
-- Possible context (static) :
=> Dept (weighted 3)
=> Specific job (weighted 5)
=> Race (weighted 3)
=> Specific special role (weighted 5)
-- Possible context (dynamic) :
=> The guy that converted you is from the same dept (weighted 3)
=> Your boss is in the cult (CMO for medbay, ...)
=> Your underlings are in the cult
=> Your colleagues are in the cult
=> Cult has a few/a lot of alive members
*/
var/list/acceptance_lines_by_dept = list(
COMMAND_POSITIONS = list(
@@ -82,18 +70,6 @@ var/list/acceptance_lines_by_dept = list(
),
)
var/list/failure_lines_by_specific_job = list(
"Paramedic" = list(
"You will not save anyone from where I sent you." = 5,
),
"Trader" = list(
"I offered you a home, and you refused." = 5,
),
"Captain" = list(
"Do you feel in charge?" = 5,
),
)
var/list/acceptance_lines_by_specific_job = list(
"Trader" = list(
"And here ends your wandering." = 5,
@@ -101,12 +77,6 @@ var/list/acceptance_lines_by_specific_job = list(
),
)
var/list/failure_lines_by_specific_race = list(
/datum/species/plasmaman = list(
"Your loyalty to the company that twisted you into the living dead is amusing." = 3,
)
)
var/list/acceptance_lines_by_specific_race = list(
/datum/species/plasmaman = list(
"The pain ends now." = 3,
@@ -169,12 +139,6 @@ var/list/acceptance_lines_by_specific_role = list(
// Context lines
var/list/failure_lines_few_cultists = list(
"With or without you, my faithful shall triumph." = 3,
"Do you truly think you won?" = 3,
"I have no need of a coward in times like this." = 3,
)
var/list/acceptance_lines_few_cultists = list(
"Be the hand I need in these times." = 3,
"You have been chosen." = 3,
@@ -186,25 +150,6 @@ var/list/acceptance_lines_numerous_cultists = list(
"Nothing will resist our might." = 3,
)
var/list/failure_lines_numerous_cultists = list(
"Your refusal changes nothing." = 3,
"You will get to see this station fail from the first row." = 3,
)
var/list/acceptance_lines_thin_veil = list(
"Soon you will see the fruits of our efforts." = 3,
)
var/list/failure_lines_thin_veil = list(
"You chose to witness the end, rather than act." = 5,
"Can't you see how pointless it is to resist at this point?" = 5,
)
#define failure_lines_same_dept list( \
"[converter.gender == MALE ? "He" : "She"] tried to save you." = 5, \
"You betrayed your friend." = 5, \
"Your arrogance must have disappointed your friend." = 5, \
)
#define acceptance_lines_same_dept list( \
"[converter.gender == MALE ? "He" : "She"] judged you well." = 5, \
@@ -213,21 +158,6 @@ var/list/failure_lines_thin_veil = list(
)
/* -- Flavour text for refusing/accepting conversion.
-- Possible context (static) :
=> Dept (weighted 3)
=> Specific job (weighted 5)
=> Race (weighted 3)
=> Specific special role (weighted 5)
-- Possible context (dynamic) :
=> The guy that converted you is from the same dept (weighted 3)
=> Your boss is in the cult (CMO for medbay, ...)
=> Your underlings are in the cult
=> Your colleagues are in the cult
=> Cult is near the end (Act III or higher)
=> Cult has a few/a lot of alive members
*/
var/list/all_depts_list = list(
COMMAND_POSITIONS,
ENGINEERING_POSITIONS,
@@ -237,6 +167,130 @@ var/list/all_depts_list = list(
CARGO_POSITIONS,
SECURITY_POSITIONS,
)
/datum/faction/bloodcult/proc/send_flavour_text_accept(var/mob/victim, var/mob/converter)
// -- Static context
// Default lines
var/list/valid_lines = list(
"Another one joins the fold." = 1,
"With each new one, the veil gets thinner." = 1,
"All are welcome." = 1,
)
// The departement
var/victim_job = victim?.mind.assigned_role
var/converter_job = converter?.mind.assigned_role
for (var/list/L in acceptance_lines_by_dept)
if (victim_job in L)
valid_lines += acceptance_lines_by_dept[L]
// The specific job
valid_lines += acceptance_lines_by_specific_job[victim_job]
// The roles he may add
if (victim.mind)
for (var/role in victim.mind.antag_roles)
valid_lines += acceptance_lines_by_specific_role[role]
// The race
if (ishuman(victim))
var/mob/living/carbon/human/dude = victim
valid_lines += acceptance_lines_by_specific_race[dude.species.type]
// -- Dynamic context
// Cultist count
var/cultists = 0
for (var/datum/role/R in members)
if (R.antag && R.antag.current && !R.antag.current.stat) // If he's alive
cultists++
// Not a lot of cultists...
if (cultists < 3)
valid_lines += acceptance_lines_few_cultists
// Or a lot of them !
else if (cultists > 10)
valid_lines += acceptance_lines_numerous_cultists
// Converter and victim are of the same dept
for (var/list/dept in all_depts_list)
if ((victim_job in dept) && (converter_job in dept))
valid_lines += acceptance_lines_same_dept
var/chosen_line = pickweight(valid_lines)
to_chat(victim, "<span class='game say'><span class='danger'>Nar-Sie</span> murmurs, <span class='sinister'>[chosen_line]</span>")
var/list/failure_lines_by_dept = list(
COMMAND_POSITIONS = list(
"You have failed to lead them. You would have failed to follow." = 3,
"And so ends your 'authority.'" = 3,
"This is what passes as command these days." = 3,
),
ENGINEERING_POSITIONS = list(
"Our craft is more complex than your pathetic tinkering." = 3,
"These machines were beyond your skill anyway." = 3,
),
MEDICAL_POSITIONS = list(
"Your refusal helps no one. The blood will still flow." = 3,
"There is no cure for this." = 3,
"Nothing can heal the veil." = 3,
),
SCIENCE_POSITIONS = list(
"Your closed mind dishonours you." = 3,
"Our secrets were beyond your understanding." = 3,
"My science was not for weaklings such as you." = 3,
),
CIVILIAN_POSITIONS = list(
"A little job in life, and a forgotten death." = 3,
"This refusal is but a footnote on my story." = 3,
"You refused the only opportunity you had to make a difference." = 3,
),
CARGO_POSITION = list(
"I care little for the hoarders of your kind." = 3,
"As expected for a glorified crate handler." = 3,
),
SECURITY_POSITION = list(
"You already failed." = 3,
"This refusal does not erase your failure." = 3,
"Your stubbornness amuses me. I already won." = 3,
"I could have freed you." = 3,
"You will always remain on the weaker side." = 3,
),
)
var/list/failure_lines_by_specific_job = list(
"Paramedic" = list(
"You will not save anyone from where I sent you." = 5,
),
"Trader" = list(
"I offered you a home, and you refused." = 5,
),
"Captain" = list(
"Do you feel in charge?" = 5,
),
)
var/list/failure_lines_by_specific_race = list(
/datum/species/plasmaman = list(
"Your loyalty to the company that twisted you into the living dead is amusing." = 3,
)
)
var/list/failure_lines_few_cultists = list(
"With or without you, my faithful shall triumph." = 3,
"Do you truly think you won?" = 3,
"I have no need of a coward in times like this." = 3,
)
var/list/failure_lines_numerous_cultists = list(
"Your refusal changes nothing." = 3,
"You will get to see this station fail from the first row." = 3,
)
#define failure_lines_same_dept list( \
"[converter.gender == MALE ? "He" : "She"] tried to save you." = 5, \
"You betrayed your friend." = 5, \
"Your arrogance must have disappointed your friend." = 5, \
)
/datum/faction/bloodcult/proc/send_flavour_text_refuse(var/mob/victim, var/mob/converter)
// -- Static context
@@ -283,10 +337,6 @@ var/list/all_depts_list = list(
for (var/list/dept in all_depts_list)
if ((victim_job in dept) && (converter_job in dept))
valid_lines += failure_lines_same_dept
// Act
if (veil_thickness >= CULT_ACT_III)
valid_lines += failure_lines_thin_veil
if(victim.mind && victim.mind.assigned_role == "Chaplain")
var/list/cult_blood_chaplain = list("cult", "narsie", "nar'sie", "narnar", "nar-sie")
var/list/cult_clock_chaplain = list("ratvar", "clockwork", "ratvarism")
@@ -302,55 +352,4 @@ var/list/all_depts_list = list(
to_chat(victim, "<span class='game say'><span class='danger'>Nar-Sie</span> murmurs, <span class='sinister'>[chosen_line]</span>")
//to_chat(converter, "Nar-Sie murmurs to [victim]... <span class='warning'>[chosen_line]</span>")
/datum/faction/bloodcult/proc/send_flavour_text_accept(var/mob/victim, var/mob/converter)
// -- Static context
// Default lines
var/list/valid_lines = list(
"Another one joins the fold." = 1,
"With each new one, the veil gets thinner." = 1,
"All are welcome." = 1,
)
// The departement
var/victim_job = victim?.mind.assigned_role
var/converter_job = converter?.mind.assigned_role
for (var/list/L in acceptance_lines_by_dept)
if (victim_job in L)
valid_lines += acceptance_lines_by_dept[L]
// The specific job
valid_lines += acceptance_lines_by_specific_job[victim_job]
// The roles he may add
if (victim.mind)
for (var/role in victim.mind.antag_roles)
valid_lines += acceptance_lines_by_specific_role[role]
// The race
if (ishuman(victim))
var/mob/living/carbon/human/dude = victim
valid_lines += acceptance_lines_by_specific_race[dude.species.type]
// -- Dynamic context
// Cultist count
var/cultists = 0
for (var/datum/role/R in members)
if (R.antag && R.antag.current && !R.antag.current.stat) // If he's alive
cultists++
// Not a lot of cultists...
if (cultists < 3)
valid_lines += acceptance_lines_few_cultists
// Or a lot of them !
else if (cultists > 10)
valid_lines += acceptance_lines_numerous_cultists
// Converter and victim are of the same dept
for (var/list/dept in all_depts_list)
if ((victim_job in dept) && (converter_job in dept))
valid_lines += acceptance_lines_same_dept
// Act
if (veil_thickness >= CULT_ACT_III)
valid_lines += acceptance_lines_thin_veil
var/chosen_line = pickweight(valid_lines)
to_chat(victim, "<span class='game say'><span class='danger'>Nar-Sie</span> murmurs, <span class='sinister'>[chosen_line]</span>")
//to_chat(converter, "Nar-Sie murmurs to [victim]... <span class='warning'>[chosen_line]</span>")
*/

View File

@@ -1,5 +1,7 @@
#define PAGE_FOREWORD 0
#define PAGE_LORE1 101
#define PAGE_LORE2 102
#define PAGE_LORE3 103
var/list/arcane_tomes = list()
@@ -71,46 +73,47 @@ var/list/arcane_tomes = list()
/obj/item/weapon/tome/proc/tome_text()
var/page_data = null
var/dat = {"<title>arcane tome</title><body style="color:#5C1D12" background="tomebg.png">
var/dat = {"<title>arcane tome</title><body style="color:#FFFFFF" bgcolor="#110000">
<style>
label {display: inline-block; width: 50px;text-align: right;float: left;margin: 0 0 0 -45px;}
label {display: inline-block; width: 50px;text-align: right;float: left;margin: 0 0 0 10px;}
ul {list-style-type: none;}
li:before {content: "-";padding-left: 4px;}
a {text-decoration: none; color:#5C1D12}
.column {float: left; width: 250px; padding: 0px; height: 300px;}
a {text-decoration: none; color:#FFEC66}
.column {float: left; width: 400px; padding: 0px; height: 300px;}
.row:after {content: ""; display: table; clear: both;}
</style>
<div class="row">
<div class="column">
<div align="center" style="margin: 0 0 0 -10px;"><div style="font-size:20px"><b>The scriptures of <font color=#AE250F>Nar-Sie</b></font></div>The Geometer of Blood</div>
<div class="column" style="font-size:18px">
<div align="center" style="margin: 0 0 0 -10px;"><div style="font-size:30px"><b>The scriptures of <font color=#FF250F>Nar-Sie</b></font></div>The Geometer of Blood</div>
<ul>
<a href='byond://?src=\ref[src];page=[PAGE_FOREWORD]'><label> * </label> <li> Foreword</a> </li>"}
var i = 1
for(var/subtype in subtypesof(/datum/rune_spell/blood_cult))
var/datum/rune_spell/blood_cult/instance = subtype
if (initial(instance.Act_restriction) <= veil_thickness)
dat += "<a href='byond://?src=\ref[src];page=[i]'><label> \Roman[i] </label> <li> [initial(instance.name)] </li></a>"
if (i == current_page)
var/datum/runeword/word1 = initial(instance.word1)
var/datum/runeword/word2 = initial(instance.word2)
var/datum/runeword/word3 = initial(instance.word3)
page_data = {"<div align="center"><b>\Roman[i]<br>[initial(instance.name)]</b><br><i>[initial(word1.english)], [initial(word2.english)], [word3 ? "[initial(word3.english)]" : "<any>"]</i></div><br>"}
page_data += initial(instance.page)
else
dat += "<label> \Roman[i] </label> <li> __________ </li>"
for(var/subtype in subtypesof(/datum/rune_spell))
var/datum/rune_spell/instance = subtype
if (initial(instance.secret))
continue
dat += "<a href='byond://?src=\ref[src];page=[i]'><label> \Roman[i] </label> <li> [initial(instance.name)] </li></a>"
if (i == current_page)
var/datum/rune_word/word1 = initial(instance.word1)
var/datum/rune_word/word2 = initial(instance.word2)
var/datum/rune_word/word3 = initial(instance.word3)
page_data = {"<div align="center"><b>\Roman[i]<br>[initial(instance.name)]</b><br><i>[initial(word1.english)], [initial(word2.english)], [word3 ? "[initial(word3.english)]" : "<any>"]</i></div><br>"}
page_data += initial(instance.page)
i++
dat += {"<a href='byond://?src=\ref[src];page=[PAGE_LORE1]'><label> * </label> <li> about this tome and our goal </li></a>
dat += {"<a href='byond://?src=\ref[src];page=[PAGE_LORE1]'><label> * </label> <li> Addendum I </li></a>
<a href='byond://?src=\ref[src];page=[PAGE_LORE2]'><label> * </label> <li> Addendum II </li></a>
<a href='byond://?src=\ref[src];page=[PAGE_LORE3]'><label> * </label> <li> Addendum III </li></a>
</ul></div>
<div class="column"> <div align="left"> <b><ul>"}
<div style="font-size:18px" class="column"> <div align="left"> <b><ul>"}
for (var/obj/item/weapon/talisman/T in talismans)
dat += {"<label> * </label><li> <a style="color:#AE250F" href='byond://?src=\ref[src];talisman=\ref[T]'>[T.talisman_name()][(T.uses > 1) ? " [T.uses] uses" : ""]</a> <a style="color:#AE250F" href='byond://?src=\ref[src];remove=\ref[T]'>(x)</a> </li>"}
dat += {"<label> * </label><li> <a style="color:#FFEC66" href='byond://?src=\ref[src];talisman=\ref[T]'>[T.talisman_name()][(T.uses > 1) ? " [T.uses] uses" : ""]</a> <a style="color:#AE250F" href='byond://?src=\ref[src];remove=\ref[T]'>(x)</a> </li>"}
dat += {"</ul></b></div><div style="margin: 0px 20px;" align="justify">"}
dat += {"</ul></b></div><div align="justify">"}
if (page_data)
dat += page_data
@@ -125,18 +128,33 @@ var/list/arcane_tomes = list()
var/dat = null
switch (current_page)
if (PAGE_FOREWORD)
dat = {"<div align="center"><b>Foreword</b></div><br>
This tome in your hands is both a guide to the ways of the devotes to Nar-Sie, and a tool to help them performing the cult's rituals.
Inside are gathered notes on the various rituals, which you can read to study their use, and learn their runes. You don't have to learn
the runes by heart however, as keeping this tome open allows you to immediately remember them when tracing words. Additional pieces of lore
are available in the latter pages, aiming to satisfy the curiosity of the assiduous cultists.
"}
dat = {"<div align="center"><b>Foreword</b></div><br>"}
dat += "<i>Written over the ages by a collection of arch-cultists, under the guidance of the geometer himself.</i>\
<br><br>Touch a chapter to read it."
if (PAGE_LORE1)
dat = {"<div align="center"><b>About this tome and our goal</b></div><br>
This tome was written under the guidance of Nar-Sie, by devotes who have left behind their flesh enveloppes and taken residence in the realm of the Geometer of Blood.
Our goal is to help our kin in the physical world, that is you, achieve the Tear Reality ritual, so that you can all join us and bring along lots of value, in other words blood.
This goal has been achieved countless times before by different beings in different place, and this tome has been updated thanks to the knowledge of those who joined us.
"}
dat = {"<div align="center"><b>Addendum I: "From the other side of the veil"</b></div><br>"}
dat += "<i>It is by chance that humanity stumbled upon the realm of Nar-Sie some centuries ago, \
although while some of those so called wizards called it a happy little accident, few of them know that the dice was loaded from the start.\
<br><br>Nar-Sie threw some artifacts adrift in the bluespace, waiting for some intelligent life to pick them up and trace their way back to him. \
For you see, Nar-Sie loves two things about humans, the blood that flows from their veins, and the dramatic circumstances around which said blood ends up flowing from their gaping wounds.\
<br><br>How did he know about humanity's existence before they even reached him you might ask? It's quite simple, he could hear the drumming of our heartbeats all the way from the other side of the veil.</i>"
if (PAGE_LORE2)
dat = {"<div align="center"><b>Addendum II: "From whom the blood spills"</b></div><br>"}
dat += "<i>After contact was made between the planes, it was a matter of time before some people would appear who would actively seek Nar-Sie.\
<br><br>Either because his love of drama and chaos resonated with them, and they wanted to become his heralds, performing sacrifices for his amusement, \
or because they were in awe with his... \"otherworldlyness?\" People who had lived until now grounded in reality, and became quite fascinated with something mystic, yet tangible.\
<br><br>And of course, then came those who seeked to defy him. Either in the name of their own gods, or out of their own sense of morality, but little do those know, \
Nar-Sie loves them equally, and doesn't care too much from whom the blood spills.</i>"
if (PAGE_LORE3)
dat = {"<div align="center"><b>Addendum III: "The geometer's calling card"</b></div><br>"}
dat += "<i>A common misconception about Nar-Sie is about his title, why is he the Geometer of Blood? Nobody dared ask him directly by fear of offending him, so for a long time, \
many cultists just assumed that he was really into geometry, and his powers manifesting from blood drawings of precise patterns would corroborate this hypothesis.\
<br><br>Some cultists eventually took it upon themselves to commune with him to get an answer, after performing some sacrifices for good measure. The answer was unexpected, and shed more light on the cult's origins. \
They learned that after the wizards cut their way into his plane, it took some time for them to run into him, just like humans aren't aware of every single ant living in their garden. \
But when they did arrive upon him, his gigantic form twisted upon the scenery gave them the image of a geometer moth.\
<br><br>And just like moths tend to be attracted by light, they saw that Nar-Sie was attracted by blood, so they called him the Geometer of Blood, a title very much to his liking.\
<br><br>As humanity ventures deeper and deeper into the darkness of space and toys with powers they understand less and less, Nar-Sie feels them coming closer and closer to him, and wants now to hasten the process. \
His cult sends heralds to let humanity know how much he likes them (their blood mostly), and until he's ready to invite them into his realm, they leave blood-splattered space stations across the stars as his calling card.</i>"
return dat
/obj/item/weapon/tome/Topic(href, href_list)
@@ -163,7 +181,7 @@ var/list/arcane_tomes = list()
usr.put_in_hands(T)
usr << browse_rsc('icons/tomebg.png', "tomebg.png")
usr << browse(tome_text(), "window=arcanetome;size=537x375")
usr << browse(tome_text(), "window=arcanetome;size=900x600")
/obj/item/weapon/tome/attack(var/mob/living/M, var/mob/living/user)
M.attack_log += text("\[[time_stamp()]\] <font color='orange'>Has had the [name] used on him by [user.name] ([user.ckey])</font>")
@@ -206,7 +224,7 @@ var/list/arcane_tomes = list()
/obj/item/weapon/tome/pickup(var/mob/user)
if(iscultist(user) && state == TOME_OPEN)
usr << browse_rsc('icons/tomebg.png', "tomebg.png")
usr << browse(tome_text(), "window=arcanetome;size=537x375")
usr << browse(tome_text(), "window=arcanetome;size=900x600")
/obj/item/weapon/tome/dropped(var/mob/user)
usr << browse(null, "window=arcanetome")
@@ -234,7 +252,7 @@ var/list/arcane_tomes = list()
playsound(user, "pageturn", 50, 1, -5)
state = TOME_OPEN
usr << browse_rsc('icons/tomebg.png', "tomebg.png")
usr << browse(tome_text(), "window=arcanetome;size=537x375")
usr << browse(tome_text(), "window=arcanetome;size=900x600")
else
icon_state = "tome"
item_state = "tome"
@@ -270,20 +288,31 @@ var/list/arcane_tomes = list()
to_chat(user, "<span class='notice'>You slip \the [I] into \the [src].</span>")
if (state == TOME_OPEN)
usr << browse_rsc('icons/tomebg.png', "tomebg.png")
usr << browse(tome_text(), "window=arcanetome;size=537x375")
usr << browse(tome_text(), "window=arcanetome;size=900x600")
else
to_chat(user, "<span class='warning'>This tome cannot contain any more talismans. Use or remove some first.</span>")
/obj/item/weapon/tome/AltClick(var/mob/user)
var/list/choices = list()
var/datum/rune_spell/blood_cult/instance
var/datum/rune_spell/instance
var/list/choice_to_talisman = list()
var/image/talisman_image
var/blood_messages = 0
var/blanks = 0
for(var/obj/item/weapon/talisman/T in talismans)
talisman_image = new(T)
instance = T.spell_type
choices += list(list(T, talisman_image, initial(instance.desc_talisman), T.talisman_name()))
choice_to_talisman[initial(instance.name)] = T
if (T.blood_text)
choices += list(list("Bloody Message[blood_messages ? " #[blood_messages+1]" : ""]", talisman_image, "A ghost has scribled a message on this talisman."))
choice_to_talisman["Bloody Message[blood_messages ? " #[blood_messages+1]" : ""]"] = T
blood_messages++
else if (T.spell_type)
instance = T.spell_type
choices += list(list(T.talisman_name(), talisman_image, initial(instance.desc_talisman)))
choice_to_talisman[T.talisman_name()] = T
else
choices += list(list("Blank Talisman[blanks ? " #[blanks+1]" : ""]", talisman_image, "Just an empty talisman."))
choice_to_talisman["Blank Talisman[blanks ? " #[blanks+1]" : ""]"] = T
blanks++
if (state == TOME_CLOSED)
icon_state = "tome-open"
@@ -292,7 +321,7 @@ var/list/arcane_tomes = list()
playsound(user, "pageturn", 50, 1, -5)
state = TOME_OPEN
var/choice = show_radial_menu(user,loc,choices,'icons/obj/cult_radial3.dmi', "radial-cult2")
if(!choice_to_talisman[choice])
if(!choice)
return
var/obj/item/weapon/talisman/chosen_talisman = choice_to_talisman[choice]
if(!usr.held_items.Find(src))
@@ -307,6 +336,8 @@ var/list/arcane_tomes = list()
#undef PAGE_FOREWORD
#undef PAGE_LORE1
#undef PAGE_LORE2
#undef PAGE_LORE3
///////////////////////////////////////TALISMAN////////////////////////////////////////////////
@@ -343,7 +374,7 @@ var/list/arcane_tomes = list()
ignite()
/obj/item/weapon/talisman/proc/talisman_name()
var/datum/rune_spell/blood_cult/instance = spell_type
var/datum/rune_spell/instance = spell_type
if (blood_text)
return "\[blood message\]"
if (instance)
@@ -367,7 +398,7 @@ var/list/arcane_tomes = list()
to_chat(user, "<span class='info'>This one, however, seems pretty unremarkable.</span>")
return
var/datum/rune_spell/blood_cult/instance = spell_type
var/datum/rune_spell/instance = spell_type
if (iscultist(user) || isobserver(user))
if (attuned_rune)
@@ -392,7 +423,7 @@ var/list/arcane_tomes = list()
/obj/item/weapon/talisman/attack(var/mob/living/target, var/mob/living/user)
if(iscultist(user) && spell_type)
var/datum/rune_spell/blood_cult/instance = spell_type
var/datum/rune_spell/instance = spell_type
if (initial(instance.touch_cast))
new spell_type(user, src, "touch", target)
qdel(src)
@@ -415,7 +446,7 @@ var/list/arcane_tomes = list()
var/obj/item/weapon/tome/T = loc
T.talismans.Remove(src)
user << browse_rsc('icons/tomebg.png', "tomebg.png")
user << browse(T.tome_text(), "window=arcanetome;size=537x375")
user << browse(T.tome_text(), "window=arcanetome;size=900x600")
user.put_in_hands(src)
return
@@ -437,7 +468,7 @@ var/list/arcane_tomes = list()
T.talismans.Remove(src)
qdel(src)
/obj/item/weapon/talisman/proc/imbue(var/mob/user, var/obj/effect/rune/blood_cult/R)
/obj/item/weapon/talisman/proc/imbue(var/mob/user, var/obj/effect/rune/R)
if (!user || !R)
return
@@ -445,7 +476,7 @@ var/list/arcane_tomes = list()
to_chat(user, "<span class='warning'>Cannot imbue a talisman that has been written on.</span>")
return
var/datum/rune_spell/blood_cult/spell = get_rune_spell(user,null,"examine",R.word1, R.word2, R.word3)
var/datum/rune_spell/spell = get_rune_spell(user,null,"examine",R.word1, R.word2, R.word3)
if(initial(spell.talisman_absorb) == RUNE_CANNOT)//placing a talisman on a Conjure Talisman rune to try and fax it
user.drop_item(src)
src.forceMove(get_turf(R))
@@ -462,10 +493,6 @@ var/list/arcane_tomes = list()
to_chat(user, "<span class='warning'>There is no power in those runes. \The [src] isn't reacting to it.</span>")
return
if (initial(spell.Act_restriction) > veil_thickness)
to_chat(user, "<span class='danger'>The veil is still too thick for \the [src] to draw power from this rune.</span>")
return
//blood markings
overlays += image(icon,"talisman-[R.word1.icon_state]a")
overlays += image(icon,"talisman-[R.word2.icon_state]a")
@@ -479,21 +506,19 @@ var/list/arcane_tomes = list()
uses = initial(spell.talisman_uses)
var/talisman_interaction = initial(spell.talisman_absorb)
var/datum/rune_spell/blood_cult/active_spell = R.active_spell
var/datum/rune_spell/active_spell = R.active_spell
if(!istype(R))
return
if (active_spell)//some runes may change their interaction type dynamically (ie: Path Exit runes)
talisman_interaction = active_spell.talisman_absorb
if (istype(active_spell,/datum/rune_spell/blood_cult/portalentrance))
var/datum/rune_spell/blood_cult/portalentrance/entrance = active_spell
if (istype(active_spell,/datum/rune_spell/portalentrance))
var/datum/rune_spell/portalentrance/entrance = active_spell
if (entrance.network)
var/datum/runeset/rune_set = global_runesets["blood_cult"]
word_pulse(rune_set.words[entrance.network])
else if (istype(active_spell,/datum/rune_spell/blood_cult/portalexit))
var/datum/rune_spell/blood_cult/portalentrance/exit = active_spell
word_pulse(rune_words[entrance.network])
else if (istype(active_spell,/datum/rune_spell/portalexit))
var/datum/rune_spell/portalentrance/exit = active_spell
if (exit.network)
var/datum/runeset/rune_set = global_runesets["blood_cult"]
word_pulse(rune_set.words[exit.network])
word_pulse(rune_words[exit.network])
switch(talisman_interaction)
if (RUNE_CAN_ATTUNE)
@@ -508,7 +533,7 @@ var/list/arcane_tomes = list()
message_admins("Error! ([key_name(user)]) managed to imbue a Conjure Talisman rune. That shouldn't be possible!")
return
/obj/item/weapon/talisman/proc/word_pulse(var/datum/runeword/W)
/obj/item/weapon/talisman/proc/word_pulse(var/datum/rune_word/W)
var/image/I1 = image(icon,"talisman-[W.icon_state]a")
animate(I1, color = list(2,0.67,0.27,0,0.27,2,0.67,0,0.67,0.27,2,0,0,0,0,1,0,0,0,0), time = 5, loop = -1)
animate(color = list(1.875,0.56,0.19,0,0.19,1.875,0.56,0,0.56,0.19,1.875,0,0,0,0,1,0,0,0,0), time = 1)
@@ -665,6 +690,8 @@ var/list/arcane_tomes = list()
var/movespeed = 2//smaller = faster
health = 40
var/maxHealth = 40
var/reflector = FALSE
var/mob/living/linked_cultist = null
/obj/item/weapon/melee/soulblade/Destroy()
var/turf/T = get_turf(src)
@@ -692,6 +719,13 @@ var/list/arcane_tomes = list()
shade = null
..()
/obj/item/weapon/melee/soulblade/attack_hand(var/mob/living/user)
if (shade)
if (iscultist(user) && (linked_cultist != user))
linked_cultist = user
to_chat(shade, "<spawn class='notice'>You have made contact with [user]. As long as you remain within 5 tiles of them, you can move by yourself without losing blood, and regenerate blood slowly passively.</span>")
..()
/obj/item/weapon/melee/soulblade/salt_act()
qdel(src)
@@ -787,13 +821,6 @@ var/list/arcane_tomes = list()
to_chat(user, "<span class='warning'>\The [src] is unable to rip this soul. Such a powerful soul, it must be coveted by some powerful being.</span>")
return
var/datum/faction/bloodcult/cult = find_active_faction_by_type(/datum/faction/bloodcult)
if (cult)
var/datum/objective/bloodcult_sacrifice/O = locate() in cult.objective_holder.objectives
if (O && (target == O.sacrifice_target || (target.mind && target.mind == O.sacrifice_mind)))
to_chat(user, "<span class='warning'>\The [src] is unable to rip this soul. Such a powerful soul, it must be coveted by some powerful being.</span>")
return
var/datum/soul_capture/capture_datum = new()
capture_datum.init_datum(user, target, src)
qdel(capture_datum)
@@ -808,6 +835,7 @@ var/list/arcane_tomes = list()
if (blood >= 5)
blood = max(0,blood-5)
update_icon()
var/turf/starting = get_turf(user)
var/turf/target = get_turf(A)
var/obj/item/projectile/bloodslash/BS = new (starting)
@@ -843,15 +871,30 @@ var/list/arcane_tomes = list()
if (C.take_blood(null,5))//same cost as spin, basically negates the cost, but doesn't let you farm corpses. It lets you make a mess out of them however.
blood = min(100,blood+5)
to_chat(user, "<span class='warning'>You steal a bit of their blood, but not much.</span>")
update_icon()
if (shade)
shade.DisplayUI("Soulblade")
else if (M.isBloodedAnimal())
var/mob/living/simple_animal/SA = M
if (SA.stat != DEAD)
blood = min(100,blood+10)
to_chat(user, "<span class='warning'>You steal some of their blood!</span>")
else
blood = min(100,blood+5)
to_chat(user, "<span class='warning'>You steal a bit of their blood, but not much.</span>")
update_icon()
if (shade)
shade.DisplayUI("Soulblade")
/obj/item/weapon/melee/soulblade/setPixelOffsetsFromParams(params, mob/user, base_pixx = 0, base_pixy = 0, clamp = TRUE)
..(params, user, -16, -16, FALSE) // clamp has to be false or we can't put the blade in the left and lower portions of a table
/obj/item/weapon/melee/soulblade/pickup(var/mob/living/user)
..()
if(!iscultist(user))
to_chat(user, "<span class='warning'>An overwhelming feeling of dread comes over you as you pick up \the [src]. It would be wise to rid yourself of this, quickly.</span>")
user.Dizzy(120)
update_icon()
/obj/item/weapon/melee/soulblade/dropped(var/mob/user)
..()
@@ -878,6 +921,11 @@ var/list/arcane_tomes = list()
if (istype(loc,/mob/living/carbon))
var/mob/living/carbon/C = loc
C.update_inv_hands()
if (iscultist(C))
var/image/I = image('icons/mob/hud.dmi', src, "consthealth[10*round((blood/maxblood)*10)]")
I.pixel_x = 16
I.pixel_y = 16
overlays += I
/obj/item/weapon/melee/soulblade/throw_at(var/atom/targ, var/range, var/speed, var/override = 1, var/fly_speed = 0)
@@ -921,7 +969,7 @@ var/list/arcane_tomes = list()
/obj/item/weapon/melee/soulblade/Cross(var/atom/movable/mover, var/turf/target, var/height=1.5, var/air_group = 0)
if(istype(mover, /obj/item/projectile))
if (prob(60))
if (prob(60) || reflector)
return 0
return ..()
@@ -950,8 +998,14 @@ var/list/arcane_tomes = list()
takeDamage(O.throwforce)
/obj/item/weapon/melee/soulblade/bullet_act(var/obj/item/projectile/P)
. = ..()
takeDamage(P.damage)
if (reflector)
if(!istype(P, /obj/item/projectile/beam)) //has seperate logic
P.reflected = 1
P.rebound(src)
return PROJECTILE_COLLISION_REBOUND // complete projectile permutation
else
. = ..()
takeDamage(P.damage)
/obj/item/weapon/melee/soulblade/proc/capture_shade(var/mob/living/simple_animal/shade/target, var/mob/user)
if(shade)
@@ -1101,6 +1155,9 @@ var/list/arcane_tomes = list()
actions_types = list(/datum/action/item_action/toggle_anon)
var/anon_mode = FALSE
/obj/item/clothing/head/culthood/NoiseDampening() // those hoods cover the ears
return TRUE
/obj/item/clothing/head/culthood/attack_self(var/mob/user)
if (!iscultist(user))
return
@@ -1175,6 +1232,31 @@ var/list/arcane_tomes = list()
/obj/item/clothing/shoes/cult/salt_act()
acid_melt()
///////////////////////////////////////CULT GLOVES////////////////////////////////////////////////
/obj/item/clothing/gloves/black/cult
name = "cult gloves"
desc = "These gloves are quite comfortable, and will keep you warm!"
inhand_states = list("left_hand" = 'icons/mob/in-hand/left/cultstuff.dmi', "right_hand" = 'icons/mob/in-hand/right/cultstuff.dmi')
icon_state = "cult"
item_state = "cultgloves"
_color = "cult"
siemens_coefficient = 0.7
heat_conductivity = INS_GLOVES_HEAT_CONDUCTIVITY
max_heat_protection_temperature = GLOVES_MAX_HEAT_PROTECTION_TEMPERATURE
species_fit = list(VOX_SHAPED, INSECT_SHAPED)
mech_flags = MECH_SCAN_FAIL
/obj/item/clothing/gloves/black/cult/get_cult_power()
return 10
/obj/item/clothing/gloves/black/cult/cultify()
return
/obj/item/clothing/gloves/black/cult/salt_act()
acid_melt()
///////////////////////////////////////CULT ROBES////////////////////////////////////////////////
/obj/item/clothing/suit/cultrobes
@@ -1362,15 +1444,13 @@ var/list/arcane_tomes = list()
mech_flags = MECH_SCAN_FAIL
/obj/item/weapon/bloodcult_pamphlet/attack_self(var/mob/user)
if (iscultist(user))
return
var/datum/faction/bloodcult/cult = find_active_faction_by_type(/datum/faction/bloodcult)
if (!cult)
cult = ticker.mode.CreateFaction(/datum/faction/bloodcult, null, 1)
cult.OnPostSetup()
var/datum/role/cultist/newCultist
if (cult.members.len > 0)
newCultist = new /datum/role/cultist()
else
newCultist = new /datum/role/cultist/chief()
var/datum/role/cultist/newCultist = new /datum/role/cultist()
newCultist.AssignToRole(user.mind,1)
cult.HandleRecruitedRole(newCultist)
newCultist.OnPostSetup()
@@ -1390,7 +1470,7 @@ var/list/arcane_tomes = list()
/obj/item/weapon/bloodcult_pamphlet/salt_act()
ignite()
//Jaunter: creates a pylon on spawn, lets you teleport to it on use
//Jaunter: creates a pylon on spawn, lets you teleport to it on use. That's an item I made to test and debug cult blood jaunts
/obj/item/weapon/bloodcult_jaunter
name = "test jaunter"
desc = ""
@@ -1576,6 +1656,7 @@ var/list/arcane_tomes = list()
/obj/item/clothing/head/culthood,
/obj/item/clothing/shoes/cult,
/obj/item/clothing/suit/cultrobes,
/obj/item/clothing/gloves/black/cult,
)
var/list/stored_gear = list()
@@ -1655,5 +1736,40 @@ var/list/arcane_tomes = list()
/obj/item/weapon/blood_tesseract/cultify()
return
/obj/item/weapon/handcuffs/cult/salt_act()
/obj/item/weapon/blood_tesseract/salt_act()
throw_impact()
///////////////////////////////////////BLOOD CANDLE////////////////////////////////////////////////
/obj/item/candle/blood
name = "blood candle"
desc = "A candle made out of blood moth wax, burns much longer than regular candles. Used for moody lighting and occult rituals."
icon = 'icons/obj/candle.dmi'
icon_state = "bloodcandle"
wax = 1200 // 20 minutes
trashtype = /obj/item/trash/blood_candle
/obj/item/candle/blood/update_icon()
overlays.len = 0
var/i
if(wax > 800)
i = 1
else if(wax > 400)
i = 2
else i = 3
icon_state = "bloodcandle[i]"
if (lit)
var/image/I = image(icon,src,"[icon_state]_lit")
I.blend_mode = BLEND_ADD
if (isturf(loc))
I.plane = ABOVE_LIGHTING_PLANE
else
I.plane = ABOVE_HUD_PLANE // inventory
overlays += I
/obj/item/trash/blood_candle
name = "blood candle"
desc = "A candle made out of blood moth wax, burns much longer than regular candles. Used for moody lighting and occult rituals."
icon = 'icons/obj/candle.dmi'
icon_state = "bloodcandle4"

View File

@@ -0,0 +1,229 @@
/*
* /proc/prepare_cult_holomap
* /datum/station_holomap/cult/initialize_holomap
* /obj/item/proc/get_cult_power
* /mob/proc/get_cult_power
* /mob/proc/occult_muted
* /mob/proc/get_convertibility
* /mob/living/carbon/get_convertibility
* /mob/living/carbon/proc/update_convertibility
* /mob/living/carbon/proc/implant_pop
* /mob/living/carbon/proc/boxify
* ///proc/spawn_bloodstones
*/
//Instead of updating in realtime, cult holomaps update every time you check them again, saves some CPU.
/proc/prepare_cult_holomap()
var/image/I = image(extraMiniMaps[HOLOMAP_EXTRA_CULTMAP])
for(var/marker in holomap_markers)
var/datum/holomap_marker/holomarker = holomap_markers[marker]
var/image/markerImage = image(holomarker.icon,holomarker.id)
markerImage.color = holomarker.color
if(holomarker.z == map.zMainStation && holomarker.filter & HOLOMAP_FILTER_CULT)
if(map.holomap_offset_x.len >= map.zMainStation)
markerImage.pixel_x = holomarker.x-8+map.holomap_offset_x[map.zMainStation]
markerImage.pixel_y = holomarker.y-8+map.holomap_offset_y[map.zMainStation]
else
markerImage.pixel_x = holomarker.x-8
markerImage.pixel_y = holomarker.y-8
markerImage.appearance_flags = RESET_COLOR
I.overlays += markerImage
return I
/datum/station_holomap/cult/initialize_holomap(var/turf/T, var/isAI=null, var/mob/user=null, var/cursor_icon = "bloodstone-here")
station_map = image(extraMiniMaps[HOLOMAP_EXTRA_CULTMAP])
cursor = image('icons/holomap_markers.dmi', cursor_icon)
/obj/item/proc/get_cult_power()
return 0
var/static/list/valid_cultpower_slots = list(
slot_wear_suit,
slot_head,
slot_shoes,
)//might add more slots later as I add more items that could fit in them
/* get_cult_power
returns: the combined cult power of every item worn by src.
*/
/mob/proc/get_cult_power()
var/power = 0
for (var/slot in valid_cultpower_slots)
var/obj/item/I = get_item_by_slot(slot)
if (istype(I))
power += I.get_cult_power()
return power
/mob/proc/occult_muted()
if (reagents && reagents.has_reagent(HOLYWATER))
return 1
if (is_implanted(/obj/item/weapon/implant/holy))
return 1
return 0
/mob/proc/get_convertibility()
if (!mind || isDead())
return CONVERTIBLE_NOMIND
if (iscultist(src))
return CONVERTIBLE_ALREADY
return 0
/mob/living/carbon/get_convertibility()
var/convertibility = ..()
if (!convertibility)
//TODO: chaplain stuff
//this'll do in the meantime
if (mind.assigned_role == "Chaplain")
return CONVERTIBLE_NEVER
var/acceptance = "Never"
if (client)
acceptance = get_role_desire_str(client.prefs.roles[CULTIST])
if (jobban_isbanned(src, CULTIST) || isantagbanned(src) || (acceptance == "Never"))
return CONVERTIBLE_NEVER
if (is_loyalty_implanted())
return CONVERTIBLE_IMPLANT
if (acceptance == "Always" || acceptance == "Yes")
return CONVERTIBLE_ALWAYS
return CONVERTIBLE_CHOICE
return convertibility//no mind, dead, or already a cultist
/mob/living/carbon/proc/update_convertibility()
var/convertibility = get_convertibility()
var/image/I = image('icons/mob/hud.dmi', src, "hudblank")
switch(convertibility)
if (CONVERTIBLE_ALWAYS)
I.icon_state = "convertible"
if (CONVERTIBLE_CHOICE)
I.icon_state = "maybeconvertible"
if (CONVERTIBLE_IMPLANT)
I.icon_state = "unconvertible"
if (CONVERTIBLE_NEVER)
I.icon_state = "unconvertible2"
I.pixel_y = 16 * PIXEL_MULTIPLIER
I.plane = ANTAG_HUD_PLANE
I.appearance_flags |= RESET_COLOR|RESET_ALPHA
//inspired from the rune color matrix because boy am I proud of it
animate(I, color = list(2,0.67,0.27,0,0.27,2,0.67,0,0.67,0.27,2,0,0,0,0,1,0,0,0,0), time = 2)//9
animate(color = list(1.875,0.56,0.19,0,0.19,1.875,0.56,0,0.56,0.19,1.875,0,0,0,0,1,0,0,0,0), time = 1.7)//8
animate(color = list(1.75,0.45,0.12,0,0.12,1.75,0.45,0,0.45,0.12,1.75,0,0,0,0,1,0,0,0,0), time = 1.4)//7
animate(color = list(1.625,0.35,0.06,0,0.06,1.625,0.35,0,0.35,0.06,1.625,0,0,0,0,1,0,0,0,0), time = 1.1)//6
animate(color = list(1.5,0.27,0,0,0,1.5,0.27,0,0.27,0,1.5,0,0,0,0,1,0,0,0,0), time = 0.8)//5
animate(color = list(1.375,0.19,0,0,0,1.375,0.19,0,0.19,0,1.375,0,0,0,0,1,0,0,0,0), time = 0.5)//4
animate(color = list(1.25,0.12,0,0,0,1.25,0.12,0,0.12,0,1.25,0,0,0,0,1,0,0,0,0), time = 0.2)//3
animate(color = list(1.125,0.06,0,0,0,1.125,0.06,0,0.06,0,1.125,0,0,0,0,1,0,0,0,0), time = 0.1)//2
animate(color = list(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0), time = 5)//1
hud_list[CONVERSION_HUD] = I
/mob/living/carbon/proc/implant_pop()
for(var/obj/item/weapon/implant/loyalty/I in src)
if (I.imp_in)
to_chat(src, "<span class='sinister'>Your blood pushes back against the loyalty implant, it will visibly pop out within seconds!</span>")
spawn(10 SECONDS)
if (I.remove())
visible_message("<span class='warning'>\The [I] pops out of \the [src]'s head.</span>")
/mob/living/carbon/proc/boxify(var/delete_body = TRUE, var/new_anim = TRUE, var/box_state = "cult")//now its own proc so admins may atomProcCall it if they so desire.
var/turf/T = get_turf(src)
for(var/mob/living/M in dview(world.view, T, INVISIBILITY_MAXIMUM))
if (M.client)
M.playsound_local(T, 'sound/effects/convert_failure.ogg', 75, 0, -4)
if (new_anim)
var/obj/effect/cult_ritual/conversion/anim = new(T)
anim.icon_state = ""
flick("rune_convert_failure",anim)
anim.Die()
var/obj/item/weapon/storage/cult/coffer = new(T)
coffer.icon_state = box_state
var/obj/item/weapon/reagent_containers/food/drinks/cult/cup = new(coffer)
if (istype(src,/mob/living/carbon/human) && dna)
take_blood(cup, cup.volume)//Up to 60u
cup.on_reagent_change()//so we get the reagentsfillings overlay
new/obj/item/weapon/skull(coffer)
if (ismonkey(src))
var/list/skulless_monkeys = list(
/mob/living/carbon/monkey/mushroom,
/mob/living/carbon/monkey/diona,
/mob/living/carbon/monkey/rock,
)
var/mob/living/carbon/monkey/M = src
if (!(M.species_type in skulless_monkeys))
take_blood(cup, cup.volume)//Up to 60u
new/obj/item/weapon/skull(coffer)
if (isslime(src))
cup.reagents.add_reagent(SLIMEJELLY, 50)
if (isalien(src))//w/e
cup.reagents.add_reagent(RADIUM, 50)
for(var/obj/item/weapon/implant/loyalty/I in src)
I.remove(src)
for(var/obj/item/I in src)
u_equip(I)
if(I)
I.forceMove(T)
I.reset_plane_and_layer()
I.dropped(src)
I.forceMove(coffer)
if (delete_body)
qdel(src)
/* Used in Cult 3.0 to get bloodstone spawn location. Might use that bit of code for something else later so I'll keep it there in the meantime.
/proc/spawn_bloodstones(var/turf/source = null)
//Called at the beginning of ACT III, this is basically the cult's declaration of war on the crew
//Spawns 4 structures, one in each quarters of the station
//When spawning, those structures break and convert stuff around them, and add a wall layer in case of space exposure.
var/list/places_to_spawn = list()
for (var/i = 1 to 4)
for (var/j = 10; j > 0; j--)
/*
the value of i governs which corner of the map the bloodstone will try to spawn in.
from 1 to 4, the corners will be selected in this order: North-West, South-East, North-East, South-West
the higher j, the further away from the center of the map will the bloodstone be. it tries 10 times per bloodstone, and searches each time closer to the center
*/
var/coordX = map.center_x+j*4*(((round(i/2) % 2) == 0) ? -1 : 1 )
var/coordY = map.center_y+j*4*(((i % 2) == 0) ? -1 : 1 )
var/turf/T = get_turf(pick(range(j*3,locate(coordX,coordY,map.zMainStation))))
if (!T)
message_admins("Blood Cult: !ERROR! spawn_bloodstones() tried to select a null turf at [map.nameLong]. Debug info: i = [i], j = [j]")
log_admin("Blood Cult: !ERROR! spawn_bloodstones() tried to select a null turf at [map.nameLong]. Debug info: i = [i], j = [j]")
else if(!is_type_in_list(T,list(/turf/space,/turf/unsimulated,/turf/simulated/shuttle)))
//Adding some blacklisted areas, specifically solars
if (!istype(T.loc,/area/solar) && is_type_in_list(T.loc,the_station_areas))
places_to_spawn += T
break
//A 5th bloodstone will spawn if a proper turf was given as arg (up to 100 tiles from the station center, and not in space or on a shuttle)
if (source && (source.z == map.zMainStation) && !isspace(source.loc) && !is_on_shuttle(source) && get_dist(locate(map.center_x,map.center_y,map.zMainStation),source)<100)
places_to_spawn.Add(source)
for (var/T in places_to_spawn)
new /obj/structure/cult/bloodstone(T)
//Cultists can use those bloodstones to locate the rest of them, they work just like station holomaps
for(var/obj/structure/cult/bloodstone/B in bloodstone_list)
if (!B.loc)
qdel(B)
message_admins("Blood Cult: !ERROR! A blood stone was somehow spawned in nullspace. It has been destroyed.")
log_admin("Blood Cult: !ERROR! A blood stone was somehow spawned in nullspace. It has been destroyed.")
*/

View File

@@ -435,7 +435,7 @@ var/list/astral_projections = list()
var/image/I = image('icons/role_HUD_icons.dmi', loc = imageloc, icon_state = hud_icon)
I.pixel_x = 20 * PIXEL_MULTIPLIER
I.pixel_y = 20 * PIXEL_MULTIPLIER
I.plane = relative_plane(ANTAG_HUD_PLANE)
I.plane = ANTAG_HUD_PLANE
client.images += I

View File

@@ -109,6 +109,13 @@
blade.attack_hand(M)
blade = null
qdel(src)
else if (!M.get_inactive_hand())//cultists can catch the blade on the fly
blade.forceMove(loc)
M.swap_hand() // guarrantees
blade.attack_hand(M)
M.swap_hand()
blade = null
qdel(src)
else
A.attackby(blade,shade)
else

View File

@@ -1,10 +1,12 @@
var/list/runes = list()
var/list/rune_appearances_cache = list()
/obj/effect/rune //Abstract, currently only supports blood as a reagent without some serious overriding.
name = "rune"
desc = "A strange collection of symbols drawn in blood."
anchored = 1
icon = 'icons/effects/uristrunes.dmi'
icon = 'icons/effects/deityrunes.dmi'
icon_state = ""
layer = RUNE_LAYER
plane = ABOVE_TURF_PLANE
@@ -13,12 +15,12 @@
//Whether the rune is pulsating
var/animated = 0
var/activated = 0 // how many times the rune was activated. goes back to 0 if a word is erased.
//A rune is made of up to 3 words.
var/runeset_identifier = "base"
var/datum/runeword/word1
var/datum/runeword/word2
var/datum/runeword/word3
var/datum/rune_word/word1
var/datum/rune_word/word2
var/datum/rune_word/word3
//An image we'll show to the AI instead of the rune
var/image/blood_image
@@ -47,10 +49,16 @@
if(AI.client)
AI.client.images += blood_image
var/datum/runeset/rune_set = global_runesets[runeset_identifier]
rune_set.rune_list.Add(src)
runes += src
..()
//adding to holomaps
var/datum/holomap_marker/holomarker = new()
holomarker.id = HOLOMAP_MARKER_CULT_RUNE
holomarker.filter = HOLOMAP_FILTER_CULT
holomarker.x = src.x
holomarker.y = src.y
holomarker.z = src.z
holomap_markers[HOLOMAP_MARKER_CULT_RUNE+"_\ref[src]"] = holomarker
/obj/effect/rune/Destroy()
@@ -60,9 +68,15 @@
qdel(blood_image)
blood_image = null
word1 = null
word2 = null
word3 = null
if (word1)
erase_word(word1.english,blood1)
word1 = null
if (word2)
erase_word(word2.english,blood2)
word2 = null
if (word3)
erase_word(word3.english,blood3)
word3 = null
blood1 = null
blood2 = null
@@ -72,22 +86,58 @@
active_spell.abort()
active_spell = null
var/datum/runeset/rune_set = global_runesets[runeset_identifier]
rune_set.rune_list.Remove(src)
runes -= src
//removing from holomaps
holomap_markers -= HOLOMAP_MARKER_CULT_RUNE+"_\ref[src]"
..()
/obj/effect/rune/ErasableRune()
if (activated)
return FALSE
return TRUE
/obj/effect/rune/examine(var/mob/user)
..()
var/datum/rune_spell/rune_name = get_rune_spell(null, null, "examine", word1,word2,word3)
//By default everyone can read a rune, so add extra functionality in child classes if that is not wanted.
if(can_read_rune(user) || isobserver(user))
var/datum/rune_spell/rune_name = get_rune_spell(null, null, "examine", word1,word2,word3)
to_chat(user, "<span class='info'>It reads: <i>[word1 ? "[word1.rune]" : ""][word2 ? " [word2.rune]" : ""][word3 ? " [word3.rune]" : ""]</i>. [rune_name ? " That's a <b>[initial(rune_name.name)]</b> rune." : "It doesn't match any rune spells."]</span>")
if(rune_name)
to_chat(user, initial(rune_name.desc))
if (istype(active_spell,/datum/rune_spell/portalentrance))
var/datum/rune_spell/portalentrance/PE = active_spell
if (PE.network)
to_chat(user, "<span class='info'>This entrance was attuned to the <b>[PE.network]</b> path.</span>")
if (istype(active_spell,/datum/rune_spell/portalexit))
var/datum/rune_spell/portalexit/PE = active_spell
if (PE.network)
to_chat(user, "<span class='info'>This exit was attuned to the <b>[PE.network]</b> path.</span>")
//"Cult" chaplains can read the words, but they have to figure out the spell themselves. Also has a chance to trigger a taunt from Nar-Sie.
else if(istype(user, /mob/living/carbon/human) && (user.mind.assigned_role == "Chaplain"))
var/list/cult_blood_chaplain = list("cult", "narsie", "nar'sie", "narnar", "nar-sie")
var/list/cult_clock_chaplain = list("ratvar", "clockwork", "ratvarism")
if (religion_name in cult_blood_chaplain)
to_chat(user, "<span class='info'>It reads: <i>[word1.rune] [word2.rune] [word3.rune]</i>. What spell was that already?...</span>")
if (prob(5))
spawn(50)
to_chat(user, "<span class='game say'><span class='danger'>???-???</span> murmurs, <span class='sinister'>[pick(\
"Your toys won't get you much further",\
"Bitter that you weren't chosen?",\
"I dig your style, but I crave for your blood.",\
"Shall we gamble then? Obviously blood is the only acceptable bargaining chip")].</span></span>")
//RIP Velard
else if (religion_name in cult_clock_chaplain)
to_chat(user, "<span class='info'>It reads a bunch of stupid shit.</span>")
if (prob(5))
spawn(50)
to_chat(user, "<span class='game say'><span class='danger'>???-???</span> murmurs, <span class='sinister'>[pick(\
"Oh just fuck off",)].</span></span>")
/obj/effect/rune/proc/can_read_rune(var/mob/user) //Overload for specific criteria.
return 1
return iscultist(user)
/obj/effect/rune/cultify()
return
@@ -99,6 +149,30 @@
active_spell.salt_act(T)
qdel(src)
/obj/effect/rune/proc/write_word(var/word,var/datum/reagent/blood/blood)
if (!word)
return
var/turf/T = get_turf(src)
var/write_color = DEFAULT_BLOOD
if (blood && blood.data["blood_colour"])
write_color = blood.data["blood_colour"]
anim(target = T, a_icon = 'icons/effects/deityrunes.dmi', flick_anim = "[word]-write", lay = layer+0.1, col = write_color, plane = plane)
/obj/effect/rune/proc/erase_word(var/word,var/datum/reagent/blood/blood)
if (!word)
return
var/turf/T = get_turf(src)
var/erase_color = DEFAULT_BLOOD
if (blood && blood.data["blood_colour"])
erase_color = blood.data["blood_colour"]
anim(target = T, a_icon = 'icons/effects/deityrunes.dmi', flick_anim = "[word]-erase", lay = layer+0.1, col = erase_color, plane = plane)
/obj/effect/rune/proc/cast_word(var/word)
if (!word)
return
var/atom/movable/overlay/A = anim(target = get_turf(src), a_icon = 'icons/effects/deityrunes.dmi', a_icon_state = "[word]-tear", lay = layer+0.2, plane = plane)
animate(A, alpha = 0,time = 5)
/obj/effect/rune/ex_act(var/severity)
switch (severity)
if (1)
@@ -113,96 +187,78 @@
/obj/effect/rune/blob_act()
return
/obj/effect/rune/update_icon()
/obj/effect/rune/update_icon(var/draw_up_to = 3)
var/datum/rune_spell/spell = get_rune_spell(null, null, "examine", word1, word2, word3)
if(spell) // && initial(spell.Act_restriction) <= veil_thickness) Add to bloodcult
if (active_spell)
return
overlays.len = 0
if(spell && activated)
animated = 1
draw_up_to = 3
else
animated = 0
var/lookup = ""
if (word1)
lookup += "[word1.icon_state]-[animated]-[blood1.data["blood_colour"]]"
if (word2)
lookup += "-[word2.icon_state]-[animated]-[blood2.data["blood_colour"]]"
if (word3)
lookup += "-[word3.icon_state]-[animated]-[blood3.data["blood_colour"]]"
lookup += "[word1.english]-[animated]-[blood1.data["blood_colour"]]"
if (word2 && draw_up_to >= 2)
lookup += "-[word2.english]-[animated]-[blood2.data["blood_colour"]]"
if (word3 && draw_up_to >= 3)
lookup += "-[word3.english]-[animated]-[blood3.data["blood_colour"]]"
if (lookup in uristrune_cache)
icon = uristrune_cache[lookup]
var/image/rune_render
if (lookup in rune_appearances_cache)
rune_render = image(rune_appearances_cache[lookup])
else
var/icon/I1 = icon('icons/effects/uristrunes.dmi', "")
var/image/I1 = image('icons/effects/deityrunes.dmi',src,"")
if (word1)
I1 = make_iconcache(word1,blood1,animated)
var/icon/I2 = icon('icons/effects/uristrunes.dmi', "")
if (word2)
I2 = make_iconcache(word2,blood2,animated)
var/icon/I3 = icon('icons/effects/uristrunes.dmi', "")
if (word3)
I3 = make_iconcache(word3,blood3,animated)
I1.icon_state = word1.english
if (blood1.data["blood_colour"])
I1.color = blood1.data["blood_colour"]
var/image/I2 = image('icons/effects/deityrunes.dmi',src,"")
if (word2 && draw_up_to >= 2)
I2.icon_state = word2.english
if (blood2.data["blood_colour"])
I2.color = blood2.data["blood_colour"]
var/image/I3 = image('icons/effects/deityrunes.dmi',src,"")
if (word3 && draw_up_to >= 3)
I3.icon_state = word3.english
if (blood3.data["blood_colour"])
I3.color = blood3.data["blood_colour"]
var/icon/I = icon('icons/effects/uristrunes.dmi', "")
I.Blend(I1, ICON_OVERLAY)
I.Blend(I2, ICON_OVERLAY)
I.Blend(I3, ICON_OVERLAY)
icon = I
uristrune_cache[lookup] = I
rune_render = image('icons/effects/deityrunes.dmi',src,"")
rune_render.overlays += I1
rune_render.overlays += I2
rune_render.overlays += I3
if(animated)
if (word1)
var/image/I = image('icons/effects/deityrunes.dmi',src,"[word1.english]-tear")
I.color = "black"
I.appearance_flags = RESET_COLOR
rune_render.overlays += I
if (word2)
var/image/I = image('icons/effects/deityrunes.dmi',src,"[word2.english]-tear")
I.color = "black"
I.appearance_flags = RESET_COLOR
rune_render.overlays += I
if (word3)
var/image/I = image('icons/effects/deityrunes.dmi',src,"[word3.english]-tear")
I.color = "black"
I.appearance_flags = RESET_COLOR
rune_render.overlays += I
rune_appearances_cache[lookup] = rune_render
overlays += rune_render
if(animated)
idle_pulse()
else
animate(src)
/obj/effect/rune/proc/make_iconcache(var/datum/runeword/word, var/datum/reagent/blood/blood, var/animated) //For caching rune icons
var/icon/I = icon('icons/effects/uristrunes.dmi', "")
if (!blood)
blood = new
var/lookupword = "[word.icon_state]-[animated]-[blood.data["blood_colour"]]"
if(lookupword in uristrune_cache)
I = uristrune_cache[lookupword]
else
I.Blend(icon('icons/effects/uristrunes.dmi', word.icon_state), ICON_OVERLAY)
var/finalblood = blood.data["blood_colour"]
var/list/blood_hsl = rgb2hsl(GetRedPart(finalblood),GetGreenPart(finalblood),GetBluePart(finalblood))
if(blood_hsl.len)
var/list/blood_rgb = hsl2rgb(blood_hsl[1],blood_hsl[2],50)//producing a color that is neither too bright nor too dark
if(blood_rgb.len)
finalblood = rgb(blood_rgb[1],blood_rgb[2],blood_rgb[3])
var/bc1 = finalblood
var/bc2 = finalblood
bc1 += "C8"
bc2 += "64"
I.SwapColor(rgb(0, 0, 0, 100), bc1)
I.SwapColor(rgb(0, 0, 0, 50), bc1)
for(var/x = 1, x <= WORLD_ICON_SIZE, x++)
for(var/y = 1, y <= WORLD_ICON_SIZE, y++)
var/p = I.GetPixel(x, y)
if(p == null)
var/n = I.GetPixel(x, y + 1)
var/s = I.GetPixel(x, y - 1)
var/e = I.GetPixel(x + 1, y)
var/w = I.GetPixel(x - 1, y)
if(n == "#000000" || s == "#000000" || e == "#000000" || w == "#000000")
I.DrawBox(bc1, x, y)
else
var/ne = I.GetPixel(x + 1, y + 1)
var/se = I.GetPixel(x + 1, y - 1)
var/nw = I.GetPixel(x - 1, y + 1)
var/sw = I.GetPixel(x - 1, y - 1)
if(ne == "#000000" || se == "#000000" || nw == "#000000" || sw == "#000000")
I.DrawBox(bc2, x, y)
I.MapColors(0.5,0,0,0,0.5,0,0,0,0.5)//we'll darken that color a bit
return I
/obj/effect/rune/proc/idle_pulse()
//This masterpiece of a color matrix stack produces a nice animation no matter which color the rune is.
animate(src, color = list(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0), time = 10, loop = -1)//1
@@ -241,9 +297,6 @@
else
animate(src)
/obj/effect/rune/attackby(obj/I, mob/user)
..()
/obj/effect/rune/Crossed(var/atom/movable/mover)
if (ismob(mover))
@@ -285,7 +338,20 @@
bleeding = user.check_bodypart_bleeding(HANDS)
user.assume_contact_diseases(virus2,src,block,bleeding)
/obj/effect/rune/proc/trigger(var/mob/living/user)
/obj/effect/rune/attackby(obj/I, mob/user)
..()
if(isholyweapon(I))
to_chat(user, "<span class='notice'>You disrupt the vile magic with the deadening field of \the [I]!</span>")
qdel(src)
return
if(istype(I, /obj/item/weapon/tome) || istype(I, /obj/item/weapon/melee/cultblade) || istype(I, /obj/item/weapon/melee/soulblade) || istype(I, /obj/item/weapon/melee/blood_dagger))
trigger(user)
if(istype(I, /obj/item/weapon/talisman))
var/obj/item/weapon/talisman/T = I
T.imbue(user,src)
return
/obj/effect/rune/proc/trigger(var/mob/living/user, var/talisman_trigger=0)
user.delayNextAttack(5)
if(!iscultist(user))
@@ -298,14 +364,13 @@
to_chat(user, "<span class='danger'>You find yourself unable to focus your mind on the arcane words of the rune.</span>")
return
if(!user.checkTattoo(TATTOO_SILENT))
if(user.is_wearing_item(/obj/item/clothing/mask/muzzle, slot_wear_mask))
to_chat(user, "<span class='danger'>You are unable to speak the words of the rune because of \the [user.wear_mask].</span>")
return
if(user.is_mute())
to_chat(user, "<span class='danger'>You don't have the ability to perform rituals without voicing the incantations. There has to be some way...</span>")
to_chat(user, "<span class='danger'>You don't have the ability to perform rituals without voicing the incantations, there has to be some way...</span>")
return
if(!word1 || !word2 || !word3 || prob(user.getBrainLoss()))
@@ -313,18 +378,25 @@
add_hiddenprint(user)
if (active_spell)
active_spell.midcast(user)
if(active_spell)//rune is already channeling a spell? let's see if we can interact with it somehow.
if(talisman_trigger)
var/datum/rune_spell/active_spell_typecast = active_spell
if(!istype(active_spell_typecast))
return
active_spell_typecast.midcast_talisman(user)
else
active_spell.midcast(user)
return
reveal()
reveal()//concealed rune get automatically revealed upon use (either through using Seer or an attuned talisman). Placed after midcast: exception for Path talismans.
active_spell = get_rune_spell(user, src, "ritual", word1, word2, word3)
if (!active_spell)
return fizzle(user)
else if (active_spell.destroying_self)
active_spell = null
else
if (active_spell.destroying_self)
active_spell = null
/obj/effect/rune/proc/fizzle(var/mob/living/user)
var/silent = user.checkTattoo(TATTOO_SILENT)
@@ -338,17 +410,33 @@
/obj/effect/rune/proc/conceal()
if(active_spell && !active_spell.can_conceal)
active_spell.abort(RITUALABORT_CONCEAL)
animate(src, alpha = 0, time = 5)
alpha = 0
if (word1)
erase_word(word1.english,blood1)
if (word2)
erase_word(word2.english,blood2)
if (word3)
erase_word(word3.english,blood3)
spawn(6)
invisibility=INVISIBILITY_OBSERVER
alpha = 127
/obj/effect/rune/proc/reveal() //Returns 1 if rune was revealed from a invisible state.
if(invisibility != 0)
alpha = 0
invisibility=0
animate(src, alpha = 255, time = 5)
one_pulse()
if (!(active_spell?.custom_rune))
overlays.len = 0
if (word1)
write_word(word1.english,blood1)
if (word2)
write_word(word2.english,blood2)
if (word3)
write_word(word3.english,blood3)
spawn(8)
alpha = 255
update_icon()
else
alpha = 255
conceal_cooldown = 1
spawn(100)
if (src && loc)
@@ -385,131 +473,7 @@
if(istype(V))
virus2["[V.uniqueID]-[V.subID]"] = V.getcopy()
/////////////////////////BLOOD CULT RUNES//////////////////////
/obj/effect/rune/blood_cult
desc = "A strange collection of symbols drawn in blood."
runeset_identifier = "blood_cult"
/obj/effect/rune/blood_cult/New()
..()
var/datum/holomap_marker/holomarker = new()
holomarker.id = HOLOMAP_MARKER_CULT_RUNE
holomarker.filter = HOLOMAP_FILTER_CULT
holomarker.x = src.x
holomarker.y = src.y
holomarker.z = src.z
holomap_markers[HOLOMAP_MARKER_CULT_RUNE+"_\ref[src]"] = holomarker
/obj/effect/rune/blood_cult/Destroy()
..()
holomap_markers -= HOLOMAP_MARKER_CULT_RUNE+"_\ref[src]" //Add to blood cult rune
/obj/effect/rune/blood_cult/attackby(obj/I, mob/user)
..()
if(isholyweapon(I))
to_chat(user, "<span class='notice'>You disrupt the vile magic with the deadening field of \the [I]!</span>")
qdel(src)
return
if(istype(I, /obj/item/weapon/tome) || istype(I, /obj/item/weapon/melee/cultblade) || istype(I, /obj/item/weapon/melee/soulblade))
trigger(user)
if(istype(I, /obj/item/weapon/talisman))
var/obj/item/weapon/talisman/T = I
T.imbue(user,src)
return
/obj/effect/rune/blood_cult/trigger(var/mob/living/user, var/talisman_trigger=0)
user.delayNextAttack(5)
if(!iscultist(user))
to_chat(user, "<span class='danger'>You can't mouth the arcane scratchings without fumbling over them.</span>")
return
if(iscarbon(user))
var/mob/living/carbon/C = user
if (C.occult_muted())
to_chat(user, "<span class='danger'>You find yourself unable to focus your mind on the arcane words of the rune.</span>")
return
if(!user.checkTattoo(TATTOO_SILENT))
if(user.is_wearing_item(/obj/item/clothing/mask/muzzle, slot_wear_mask))
to_chat(user, "<span class='danger'>You are unable to speak the words of the rune because of \the [user.wear_mask].</span>")
return
if(user.is_mute())
to_chat(user, "<span class='danger'>You don't have the ability to perform rituals without voicing the incantations, there has to be some way...</span>")
return
if(!word1 || !word2 || !word3 || prob(user.getBrainLoss()))
return fizzle(user)
add_hiddenprint(user)
if(active_spell)//rune is already channeling a spell? let's see if we can interact with it somehow.
if(talisman_trigger)
var/datum/rune_spell/blood_cult/active_spell_typecast = active_spell
if(!istype(active_spell_typecast))
return
active_spell_typecast.midcast_talisman(user)
else
active_spell.midcast(user)
return
reveal()//concealed rune get automatically revealed upon use (either through using Seer or an attuned talisman). Placed after midcast: exception for Path talismans.
active_spell = get_rune_spell(user, src, "ritual", word1, word2, word3)
if (!active_spell)
return fizzle(user)
else if (active_spell.destroying_self)
active_spell = null
/obj/effect/rune/blood_cult/can_read_rune(var/mob/user) //Overload for specific criteria.
return iscultist(user)
/obj/effect/rune/blood_cult/examine(var/mob/user)
..()
if(can_read_rune(user) || isobserver(user))
var/datum/rune_spell/blood_cult/rune_name = get_rune_spell(null, null, "examine", word1,word2,word3)
if(rune_name)
if (initial(rune_name.Act_restriction) <= veil_thickness)
to_chat(user, initial(rune_name.desc))
if (istype(active_spell,/datum/rune_spell/blood_cult/portalentrance))
var/datum/rune_spell/blood_cult/portalentrance/PE = active_spell
if (PE.network)
to_chat(user, "<span class='info'>This entrance was attuned to the <b>[PE.network]</b> path.</span>")
if (istype(active_spell,/datum/rune_spell/blood_cult/portalexit))
var/datum/rune_spell/blood_cult/portalexit/PE = active_spell
if (PE.network)
to_chat(user, "<span class='info'>This exit was attuned to the <b>[PE.network]</b> path.</span>")
else
to_chat(user, "<span class='danger'>The veil is still too thick for you to draw power from this rune.</span>")
//"Cult" chaplains can read the words, but they have to figure out the spell themselves. Also has a chance to trigger a taunt from Nar-Sie.
else if(istype(user, /mob/living/carbon/human) && (user.mind.assigned_role == "Chaplain"))
var/list/cult_blood_chaplain = list("cult", "narsie", "nar'sie", "narnar", "nar-sie")
var/list/cult_clock_chaplain = list("ratvar", "clockwork", "ratvarism")
if (religion_name in cult_blood_chaplain)
to_chat(user, "<span class='info'>It reads: <i>[word1.rune] [word2.rune] [word3.rune]</i>. What spell was that already?...</span>")
if (prob(5))
spawn(50)
to_chat(user, "<span class='game say'><span class='danger'>???-???</span> murmurs, <span class='sinister'>[pick(\
"Your toys won't get you much further",\
"Bitter that you weren't chosen?",\
"I dig your style, but I crave for your blood.",\
"Shall we gamble then? Obviously blood is the only acceptable bargaining chip")].</span></span>")
//RIP Velard
else if (religion_name in cult_clock_chaplain)
to_chat(user, "<span class='info'>It reads a bunch of stupid shit.</span>")
if (prob(5))
spawn(50)
to_chat(user, "<span class='game say'><span class='danger'>???-???</span> murmurs, <span class='sinister'>[pick(\
"Oh just fuck off",)].</span></span>")
/proc/write_rune_word(var/turf/T, var/word = null, var/datum/reagent/blood/source, var/mob/caster = null)
/proc/write_rune_word(var/turf/T, var/datum/rune_word/word = null, var/datum/reagent/blood/source, var/mob/caster = null)
if (!word)
return RUNE_WRITE_CANNOT
@@ -522,10 +486,8 @@
var/newrune = FALSE
var/obj/effect/rune/rune = locate() in T
if(!rune)
var/datum/runeword/rune_typecast = word
if(rune_typecast.identifier == "blood_cult") //Lazy fix because I'm not sure how to modularize this automatically. Fix if you want to.//WHYYYYYYYYYYY
rune = new /obj/effect/rune/blood_cult(T)
newrune = TRUE
rune = new /obj/effect/rune(T)
newrune = TRUE
if (rune.word1 && rune.word2 && rune.word3)
return RUNE_WRITE_CANNOT
@@ -536,6 +498,8 @@
message_admins("BLOODCULT: [key_name(caster)] has created a new rune at [formatJumpTo(T)].")
rune.add_hiddenprint(caster)
rune.write_word(word.english,source)
if (!rune.word1)
rune.word1 = word
rune.blood1 = new()
@@ -553,6 +517,8 @@
rune.blood1.data["blood_DNA"] = "O+"
if (source.data["virus2"])
rune.blood1.data["virus2"] = virus_copylist(source.data["virus2"])
spawn (8)
rune.update_icon(1)
else if (!rune.word2)
rune.word2 = word
@@ -571,6 +537,8 @@
rune.blood2.data["blood_DNA"] = "O+"
if (source.data["virus2"])
rune.blood2.data["virus2"] = virus_copylist(source.data["virus2"])
spawn (8)
rune.update_icon(2)
else if (!rune.word3)
rune.word3 = word
@@ -589,15 +557,15 @@
rune.blood3.data["blood_DNA"] = "O+"
if (source.data["virus2"])
rune.blood3.data["virus2"] = virus_copylist(source.data["virus2"])
spawn (8)
rune.update_icon(3)
rune.manage_diseases(source)
rune.update_icon()
if (rune.blood3)
return RUNE_WRITE_COMPLETE
return RUNE_WRITE_CONTINUE
/proc/erase_rune_word(var/turf/T)
var/obj/effect/rune/rune = locate() in T
if(!rune)
@@ -606,6 +574,7 @@
var/word_erased
if(rune.word3)
rune.erase_word(rune.word3.english, rune.blood3)
word_erased = rune.word3.rune
rune.word3 = null
rune.blood3 = null
@@ -615,11 +584,13 @@
rune.active_spell = null
rune.overlays.len = 0
else if(rune.word2)
rune.erase_word(rune.word2.english, rune.blood2)
word_erased = rune.word2.rune
rune.word2 = null
rune.blood2 = null
rune.update_icon()
else if(rune.word1)
rune.erase_word(rune.word1.english, rune.blood1)
word_erased = rune.word1.rune
rune.word1 = null
rune.blood1 = null
@@ -628,4 +599,18 @@
message_admins("Error! Trying to erase a word from a rune with no words!")
qdel(rune)
return null
rune.activated = 0
return word_erased
/proc/write_full_rune(var/turf/T, var/spell_type, var/datum/reagent/blood/source, var/mob/caster = null)
if (!spell_type)
return
var/datum/rune_spell/spell_instance = spell_type
var/datum/rune_word/word1_instance = initial(spell_instance.word1)
var/datum/rune_word/word2_instance = initial(spell_instance.word2)
var/datum/rune_word/word3_instance = initial(spell_instance.word3)
write_rune_word(T, rune_words[initial(word1_instance.english)], source, caster)
write_rune_word(T, rune_words[initial(word2_instance.english)], source, caster)
write_rune_word(T, rune_words[initial(word3_instance.english)], source, caster)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,95 @@
// Rune Spells that aren't listed when the player tries to draw a guided rune.
////////////////////////////////////////////////////////////////////
// //
// SUMMON TOME //
// //
////////////////////////////////////////////////////////////////////
//Reason: Redundant with paraphernalia. No harm in keeping the rune somewhat usable until another use is found for that word combination.
/datum/rune_spell/summontome
secret = TRUE
name = "Summon Tome"
desc = "Bring forth an arcane tome filled with Nar-Sie's knowledge."
desc_talisman = "Turns into an arcane tome upon use."
invocation = "N'ath reth sh'yro eth d'raggathnor!"
word1 = /datum/rune_word/see
word2 = /datum/rune_word/blood
word3 = /datum/rune_word/hell
cost_invoke = 4
page = ""
/datum/rune_spell/summontome/cast()
var/obj/effect/rune/R = spell_holder
R.one_pulse()
if (pay_blood())
spell_holder.visible_message("<span class='rose'>The rune's symbols merge into each others, and an Arcane Tome takes form in their place</span>")
var/turf/T = get_turf(spell_holder)
var/obj/item/weapon/tome/AT = new (T)
anim(target = AT, a_icon = 'icons/effects/effects.dmi', flick_anim = "tome_spawn")
qdel(spell_holder)
else
qdel(src)
/datum/rune_spell/summontome/cast_talisman()//The talisman simply turns into a tome.
var/turf/T = get_turf(spell_holder)
var/obj/item/weapon/tome/AT = new (T)
if (spell_holder == activator.get_active_hand())
activator.drop_item(spell_holder, T)
activator.put_in_active_hand(AT)
else//are we using the talisman from a tome?
activator.put_in_hands(AT)
flick("tome_spawn",AT)
qdel(src)
////////////////////////////////////////////////////////////////////
// //
// STREAM //
// //
////////////////////////////////////////////////////////////////////
//Reason: we don't want a new cultist player to use this rune by accident, better leave it to savvy ones
/datum/rune_spell/stream
secret = TRUE
name = "Stream"
desc = "Start or stop streaming on Spess.TV."
desc_talisman = "Start or stop streaming on Spess.TV."
invocation = "L'k' c'mm'nt 'n' s'bscr'b! P'g ch'mp! Kappah!"
word1 = /datum/rune_word/other
word2 = /datum/rune_word/see
word3 = /datum/rune_word/self
page = "This rune lets you start (or stop) streaming on Spess.TV so that you can let your audience watch and cheer for you while you slay infidels in the name of Nar-sie. #Sponsored"
/datum/rune_spell/stream/cast()
var/datum/role/streamer/streamer = activator.mind.GetRole(STREAMER)
if(!streamer)
streamer = new /datum/role/streamer
streamer.team = ESPORTS_CULTISTS
if(!streamer.AssignToRole(activator.mind, 1))
streamer.Drop()
return
streamer.OnPostSetup()
streamer.Greet(GREET_DEFAULT)
streamer.AnnounceObjectives()
streamer.team = ESPORTS_CULTISTS
if(!streamer.camera)
streamer.set_camera(new /obj/machinery/camera/arena/spesstv(activator))
streamer.toggle_streaming()
qdel(src)
/*
Hall of fame of previous deprecated runes, might redesign later, noting their old word combinations there so I can easily retrieve them later.
MANIFEST GHOST: Blood See Travel
SACRIFICE: Hell Blood Join
DRAIN BLOOD: Travel Blood Self
BLOOD BOIL: Destroy See Blood
TEAR REALITY: Hell Join Self
*/

View File

@@ -1,11 +1,14 @@
var/list/uristrune_cache = list()
/spell/cult
panel = "Cult"
override_base = "cult"
user_type = USER_TYPE_CULT
/spell/cult/trace_rune //Abstract, base for all blood-based rune systems
////////////////////BLOOD CULT DRAW RUNE////////////////////////
// Those two spells replaced by the Cultist mind UI abilities. Keeping those commented out for now so I can more easily salvage some of it code later.
/*
/spell/cult/trace_rune
name = "Trace Rune"
desc = "(1 BLOOD) Use available blood to write down words. Three words form a rune."
hud_state = "cult_word"
@@ -21,52 +24,17 @@ var/list/uristrune_cache = list()
cast_delay = 15
var/list/data = list()
var/runeset_identifier = null
var/datum/runeword/word = null
var/datum/rune_word/word = null
var/obj/effect/rune/rune = null
var/datum/rune_spell/spell = null
var/continue_drawing = 0
var/blood_cost = 1
/spell/cult/trace_rune/choose_targets(var/mob/user = usr)
return list(user)
/spell/cult/trace_rune/before_channel(mob/user)
if(continue_drawing) //Resets the current spell (tome selection) if continue_drawing is not 1.
continue_drawing = 0
else
spell = null
return 0
/spell/cult/trace_rune/spell_do_after(var/mob/user, var/delay, var/numticks = 3)
return ..()
//Each variant of rune is handled in their respective class.
/spell/cult/trace_rune/cast(var/list/targets, var/mob/living/carbon/user)
if(rune)
if(rune.word1 && rune.word2 && rune.word3)
to_chat(user, "<span class='warning'>You cannot add more than 3 words to a rune.</span>")
return
else if(rune.runeset_identifier != runeset_identifier)
to_chat(user, "<span class='warning'>This type of rune is incompatible with the one on the ground.</span>")
return
var/datum/runeset/rune_set = global_runesets[runeset_identifier]
if(write_rune_word(get_turf(user), rune_set.words[word], data["blood"], caster = user) == RUNE_WRITE_CONTINUE)
continue_drawing = 1
perform(user) //Recursion for drawing runes in a row with tome.
////////////////////BLOOD CULT DRAW RUNE////////////////////////
/spell/cult/trace_rune/blood_cult
name = "Trace Rune"
desc = "(1 BLOOD) Use available blood to write down words. Three words form a rune."
cast_delay = 15
runeset_identifier = "blood_cult"
/spell/cult/trace_rune/blood_cult/before_channel(mob/user)
if(continue_drawing) //Resets the current spell (tome selection) if continue_drawing is not 1.
continue_drawing = 0
else
@@ -81,8 +49,7 @@ var/list/uristrune_cache = list()
to_chat(user,"<span class='danger'>You find yourself unable to focus your mind on the words of Nar-Sie.</span>")
return muted
/spell/cult/trace_rune/blood_cult/spell_do_after(var/mob/user, var/delay, var/numticks = 3)
/spell/cult/trace_rune/spell_do_after(var/mob/user, var/delay, var/numticks = 3)
if(block) //Part of class spell, gets reset back to 0 after done casting. Prevents spamming.
return 0
block = 1
@@ -109,7 +76,7 @@ var/list/uristrune_cache = list()
to_chat(user, "<span class='warning'>Without reading the tome, you have trouble continuing to draw the arcane words.</span>")
return 0
else
var/datum/runeword/blood_cult/instance
var/datum/rune_word/instance
if(!rune)
instance = initial(spell.word1)
else if (rune.word1.type != initial(spell.word1))
@@ -130,11 +97,10 @@ var/list/uristrune_cache = list()
else if(tome) //Else if they want to begin starting to draw with the help of a tome, grab all the available runes they can draw
var/list/available_runes = list()
var/i = 1
for(var/blood_spell in subtypesof(/datum/rune_spell/blood_cult))
var/datum/rune_spell/blood_cult/instance = blood_spell
if(initial(instance.Act_restriction) <= veil_thickness)
available_runes.Add("\Roman[i]-[initial(instance.name)]")
available_runes["\Roman[i]-[initial(instance.name)]"] = instance
for(var/blood_spell in subtypesof(/datum/rune_spell))
var/datum/rune_spell/instance = blood_spell
available_runes.Add("\Roman[i]-[initial(instance.name)]")
available_runes["\Roman[i]-[initial(instance.name)]"] = instance
i++
if(tome.state == TOME_CLOSED)
tome.icon_state = "tome-open"
@@ -144,7 +110,7 @@ var/list/uristrune_cache = list()
tome.state = TOME_OPEN
var/spell_name = input(user,"Draw a rune with the help of the Arcane Tome.", "Trace Complete Rune", null) as null|anything in available_runes
spell = available_runes[spell_name]
var/datum/runeword/blood_cult/instance
var/datum/rune_word/instance
if(!rune)
instance = initial(spell.word1)
else if (rune.word1.type != initial(spell.word1))
@@ -165,8 +131,7 @@ var/list/uristrune_cache = list()
else //Otherwise they want to begin drawing each word manually
var/datum/runeset/rune_set = global_runesets[runeset_identifier]
word = input(user,"Choose a word to add to the rune.", "Trace Rune Word", null) as null|anything in rune_set.words
word = input(user,"Choose a word to add to the rune.", "Trace Rune Word", null) as null|anything in rune_words_english
if (!word)
return 0
@@ -184,21 +149,16 @@ var/list/uristrune_cache = list()
"<span class='warning'>You hear some chanting.</span>")
if(!user.checkTattoo(TATTOO_SILENT))
var/datum/runeset/rune_set = global_runesets[runeset_identifier]
var/datum/runeword/rune_word = rune_set.words[word]
var/datum/rune_word/rune_word = rune_words[word]
user.whisper("...[rune_word.rune]...")
return ..()
/spell/cult/trace_rune/blood_cult/cast(var/list/targets, var/mob/living/carbon/user)
/spell/cult/trace_rune/cast(var/list/targets, var/mob/living/carbon/user)
if(rune)
if(rune.word1 && rune.word2 && rune.word3)
to_chat(user, "<span class='warning'>You cannot add more than 3 words to a rune.</span>")
return
else if(rune.runeset_identifier != runeset_identifier)
to_chat(user, "<span class='warning'>This type of rune is incompatible with the one on the ground.</span>")
return
var/datum/runeset/rune_set = global_runesets[runeset_identifier]
if(write_rune_word(get_turf(user), rune_set.words[word], data["blood"], caster = user) == RUNE_WRITE_CONTINUE)
if(write_rune_word(get_turf(user), rune_words[word], data["blood"], caster = user) == RUNE_WRITE_CONTINUE)
continue_drawing = 1
perform(user) //Recursion for drawing runes in a row with tome.
else
@@ -241,8 +201,9 @@ var/list/uristrune_cache = list()
to_chat(user, "<span class='notice'>You retrace your steps, carefully undoing the lines of the [removed_word] rune.</span>")
else
to_chat(user, "<span class='warning'>There aren't any rune words left to erase.</span>")
*/
// TODO UPHEAVAL PART 2, make this spell available again as a ritual reward. Though instead of using this code it'll probably be activated through mind UI
//SPELL III
/spell/cult/blood_dagger
name = "Blood Dagger"
@@ -296,6 +257,7 @@ var/list/uristrune_cache = list()
"<span class='warning'>You squeeze the blood in your hand, and it takes the shape of a dagger.</span>")
playsound(H, 'sound/weapons/bloodyslice.ogg', 30, 0,-2)
// TODO UPHEAVAL PART 2, not sure what to do with this spell really, it always kinda sucked and tomes as a whole need an overhaul
var/list/arcane_pockets = list()
//SPELL IV
/spell/cult/arcane_dimension

View File

@@ -1,4 +1,6 @@
// Tattoos are currently unobtainable and being reworked. Blood Daggers and Cult Chat will be available to cultists in other ways until then.
/datum/cult_tattoo
var/name = "cult tattoo"
var/desc = ""
@@ -29,16 +31,18 @@
///////////////////////////
var/list/blood_communion = list()
/datum/cult_tattoo/bloodpool
/datum/cult_tattoo/bloodpool // doesn't actually do anything right now beside give you a cool tattoo
name = TATTOO_POOL
desc = "All blood costs reduced by 20%. Tributes are split with other bearers of this mark."
icon_state = "bloodpool"
tier = 1
/*
/datum/cult_tattoo/bloodpool/getTattoo(var/mob/M)
..()
if (iscultist(M))
blood_communion.Add(iscultist(M))
*/
/datum/cult_tattoo/silent
name = TATTOO_SILENT
@@ -46,7 +50,7 @@ var/list/blood_communion = list()
icon_state = "silent"
tier = 1
/datum/cult_tattoo/dagger
/datum/cult_tattoo/dagger // now available to all cultists by default
name = TATTOO_DAGGER
desc = "Materialize a sharp dagger in your hand for a small cost in blood. Use to retrieve."
icon_state = "dagger"
@@ -64,7 +68,7 @@ var/list/blood_communion = list()
// //
///////////////////////////
/datum/cult_tattoo/holy
/datum/cult_tattoo/holy // doesn't actually do anything right now beside give you a cool tattoo
name = TATTOO_HOLY
desc = "Holy water will now only slow you down a bit, and no longer prevent you from casting."
icon_state = "holy"
@@ -81,7 +85,7 @@ var/list/blood_communion = list()
if (iscultist(M))
M.add_spell(new /spell/cult/arcane_dimension, "cult_spell_ready", /obj/abstract/screen/movable/spell_master/bloodcult)
/datum/cult_tattoo/chat
/datum/cult_tattoo/chat // functionality moved to Spires
name = TATTOO_CHAT
desc = "Chat with the cult using :x."
icon_state = "chat"
@@ -99,6 +103,7 @@ var/list/blood_communion = list()
icon_state = "manifest"
tier = 3
/*
/datum/cult_tattoo/manifest/getTattoo(var/mob/M)
..()
var/mob/living/carbon/human/H = bearer
@@ -121,6 +126,7 @@ var/list/blood_communion = list()
H.status_flags &= ~CANPARALYSE
H.regenerate_icons()
H.update_dna_from_appearance()
*/
/datum/cult_tattoo/fast
name = TATTOO_FAST

View File

@@ -0,0 +1,486 @@
//When cultists need to pay in blood to use their spells, they have a few options at their disposal:
// * If their hands are bloody, they can use the few units of blood on them.
// * If there is a blood splatter on the ground that still has a certain amount of fresh blood in it, they can use that?
// * If they are grabbing another person, they can stab their nails in their vessels to draw some blood from them
// * If they are standing above a bleeding person, they can dip their fingers into their wounds.
// * If they are holding a container that has blood in it (such as a beaker or a blood pack), they can pour/squeeze blood from them
// * If they are standing above a container that has blood in it, they can dip their fingers into them
// * Finally if there are no alternative blood sources, you can always use your own blood.
/* get_available_blood
user: the mob (generally a cultist) trying to spend blood
amount_needed: the amount of blood required
returns: a /list with information on nearby available blood. For use by use_available_blood().
*/
/proc/get_available_blood(var/mob/user, var/amount_needed = 0)
var/data = list(
BLOODCOST_TARGET_BLEEDER = null,
BLOODCOST_AMOUNT_BLEEDER = 0,
BLOODCOST_TARGET_GRAB = null,
BLOODCOST_AMOUNT_GRAB = 0,
BLOODCOST_TARGET_HANDS = null,
BLOODCOST_AMOUNT_HANDS = 0,
BLOODCOST_TARGET_HELD = null,
BLOODCOST_AMOUNT_HELD = 0,
BLOODCOST_LID_HELD = 0,
BLOODCOST_TARGET_SPLATTER = null,
BLOODCOST_AMOUNT_SPLATTER = 0,
BLOODCOST_TARGET_BLOODPACK = null,
BLOODCOST_AMOUNT_BLOODPACK = 0,
BLOODCOST_HOLES_BLOODPACK = 0,
BLOODCOST_TARGET_CONTAINER = null,
BLOODCOST_AMOUNT_CONTAINER = 0,
BLOODCOST_LID_CONTAINER = 0,
BLOODCOST_TARGET_USER = null,
BLOODCOST_AMOUNT_USER = 0,
BLOODCOST_RESULT = "",
BLOODCOST_TOTAL = 0,
BLOODCOST_USER = null,
)
var/turf/T = get_turf(user)
var/amount_gathered = 0
data[BLOODCOST_RESULT] = user
if (amount_needed == 0)//the cost was probably 1u, and already paid for by blood communion from another cultist
data[BLOODCOST_RESULT] = BLOODCOST_TRIBUTE
return data
//Is there blood on our hands?
var/mob/living/carbon/human/H_user = user
if (istype (H_user) && H_user.blood_DNA?.len)
data[BLOODCOST_TARGET_HANDS] = H_user
var/blood_gathered = min(amount_needed,H_user.bloody_hands)
data[BLOODCOST_AMOUNT_HANDS] = blood_gathered
amount_gathered += blood_gathered
if (amount_gathered >= amount_needed)
data[BLOODCOST_RESULT] = BLOODCOST_TARGET_HANDS
return data
//Is there a fresh blood splatter on the turf?
for (var/obj/effect/decal/cleanable/blood/B in T)
var/blood_volume = B.amount
if (blood_volume && B.counts_as_blood)
data[BLOODCOST_TARGET_SPLATTER] = B
var/blood_gathered = min(amount_needed-amount_gathered,blood_volume)
data[BLOODCOST_AMOUNT_SPLATTER] = blood_gathered
amount_gathered += blood_gathered
if (amount_gathered >= amount_needed)
data[BLOODCOST_RESULT] = BLOODCOST_TARGET_SPLATTER
return data
//Is the cultist currently grabbing a bleeding mob/corpse that still has blood in it?
var/obj/item/weapon/grab/Grab = locate() in user
if (Grab)
if(ishuman(Grab.affecting))
var/mob/living/carbon/human/H = Grab.affecting
if(!(H.species.anatomy_flags & NO_BLOOD))
var/blood_volume = round(H.vessel.get_reagent_amount(BLOOD))
var/blood_gathered = min(amount_needed-amount_gathered,blood_volume)
data[BLOODCOST_TARGET_GRAB] = H
data[BLOODCOST_AMOUNT_GRAB] = blood_gathered
amount_gathered += blood_gathered
if(ismonkey(Grab.affecting) || isalien(Grab.affecting))//Unlike humans, monkeys take oxy damage when blood is taken from them.
var/mob/living/carbon/C = Grab.affecting
if(!C.isDead())
var/blood_volume = round(max(0,C.health))
var/blood_gathered = min(amount_needed-amount_gathered,blood_volume)
data[BLOODCOST_TARGET_GRAB] = C
data[BLOODCOST_AMOUNT_GRAB] = blood_gathered
amount_gathered += blood_gathered
if (amount_gathered >= amount_needed)
data[BLOODCOST_RESULT] = BLOODCOST_TARGET_GRAB
return data
//Is there a bleeding mob/corpse on the turf that still has blood in it?
for (var/mob/living/carbon/human/H in T)
if(H.species.anatomy_flags & NO_BLOOD)
continue
if(user != H)
for(var/datum/organ/external/org in H.organs)
if(org.status & ORGAN_BLEEDING)
var/blood_volume = round(H.vessel.get_reagent_amount(BLOOD))
var/blood_gathered = min(amount_needed-amount_gathered,blood_volume)
data[BLOODCOST_TARGET_BLEEDER] = H
data[BLOODCOST_AMOUNT_BLEEDER] = blood_gathered
amount_gathered += blood_gathered
break
if (data[BLOODCOST_TARGET_BLEEDER])
break
if (amount_gathered >= amount_needed)
data[BLOODCOST_RESULT] = BLOODCOST_TARGET_BLEEDER
return data
for(var/obj/item/weapon/reagent_containers/G_held in H_user.held_items) //Accounts for if the person has multiple grasping organs
if (!istype(G_held) || !round(G_held.reagents.get_reagent_amount(BLOOD)))
continue
if(istype(G_held, /obj/item/weapon/reagent_containers/blood)) //Bloodbags have their own functionality
var/obj/item/weapon/reagent_containers/blood/blood_pack = G_held
var/blood_volume = round(blood_pack.reagents.get_reagent_amount(BLOOD))
if (blood_volume)
data[BLOODCOST_TARGET_BLOODPACK] = blood_pack
if (blood_pack.holes)
var/blood_gathered = min(amount_needed-amount_gathered,blood_volume)
data[BLOODCOST_AMOUNT_BLOODPACK] = blood_gathered
amount_gathered += blood_gathered
else
data[BLOODCOST_HOLES_BLOODPACK] = 1
if (amount_gathered >= amount_needed)
data[BLOODCOST_RESULT] = BLOODCOST_TARGET_BLOODPACK
return data
else
var/blood_volume = round(G_held.reagents.get_reagent_amount(BLOOD))
if (blood_volume)
data[BLOODCOST_TARGET_HELD] = G_held
if (G_held.is_open_container())
var/blood_gathered = min(amount_needed-amount_gathered,blood_volume)
data[BLOODCOST_AMOUNT_HELD] = blood_gathered
amount_gathered += blood_gathered
else
data[BLOODCOST_LID_HELD] = 1
if (amount_gathered >= amount_needed)
data[BLOODCOST_RESULT] = BLOODCOST_TARGET_HELD
return data
//Is there a reagent container on the turf that has blood in it?
for (var/obj/item/weapon/reagent_containers/G in T)
var/blood_volume = round(G.reagents.get_reagent_amount(BLOOD))
if (blood_volume)
data[BLOODCOST_TARGET_CONTAINER] = G
if (G.is_open_container())
var/blood_gathered = min(amount_needed-amount_gathered,blood_volume)
data[BLOODCOST_AMOUNT_CONTAINER] = blood_gathered
amount_gathered += blood_gathered
break
else
data[BLOODCOST_LID_CONTAINER] = 1
if (amount_gathered >= amount_needed)
data[BLOODCOST_RESULT] = BLOODCOST_TARGET_CONTAINER
return data
//Does the user have blood? (the user can pay in blood without having to bleed first)
if(istype(H_user))
if(!(H_user.species.anatomy_flags & NO_BLOOD))
var/blood_volume = round(H_user.vessel.get_reagent_amount(BLOOD))
var/blood_gathered = min(amount_needed-amount_gathered,blood_volume)
data[BLOODCOST_TARGET_USER] = H_user
data[BLOODCOST_AMOUNT_USER] = blood_gathered
amount_gathered += blood_gathered
else//non-human trying to draw runes eh? let's see...
if (ismonkey(user) || isalien(user))
var/mob/living/carbon/C_user = user
if (!C_user.isDead())
var/blood_volume = round(max(0,C_user.health))//Unlike humans, monkeys take oxy damage when blood is taken from them.
var/blood_gathered = min(amount_needed-amount_gathered,blood_volume)
data[BLOODCOST_TARGET_USER] = C_user
data[BLOODCOST_AMOUNT_USER] = blood_gathered
amount_gathered += blood_gathered
else if (isconstruct(user))
var/mob/living/simple_animal/construct/C_user = user
if (!C_user.purge)//Constructs can use runes for free as long as they aren't getting purged by holy water or null rods
data[BLOODCOST_TARGET_USER] = C_user
data[BLOODCOST_AMOUNT_USER] = amount_needed
amount_gathered = amount_needed
if (amount_gathered >= amount_needed)
data[BLOODCOST_RESULT] = BLOODCOST_TARGET_USER
return data
data[BLOODCOST_RESULT] = BLOODCOST_FAILURE
return data
/* use_available_blood
user: the mob (generally a cultist) trying to spend blood
amount_needed: the amount of blood required
previous_result: the result of the previous call of this proc if any, to prevent the same flavor text from displaying every single call of this proc in a row
tribute: set to 1 when called by a contributor to Blood Communion
returns: a /list with information on the success/failure of the proc, and in the former case, information the blood that was used (color, type, dna)
*/
/proc/use_available_blood(var/mob/user, var/amount_needed = 0,var/previous_result = "", var/tribute = 0, var/feedback = TRUE)
//Blood Communion
var/communion = 0
var/communion_data = null
var/total_accumulated = 0
var/total_needed = amount_needed
if (!tribute && iscultist(user))
var/datum/role/cultist/mycultist = iscultist(user)
if (mycultist in blood_communion)
communion = 1
amount_needed = max(1,round(amount_needed * 4 / 5))//saving 20% blood
var/list/tributers = list()
for (var/datum/role/cultist/cultist in blood_communion)
if (cultist.antag && cultist.antag.current)
var/mob/living/L = cultist.antag.current
if (istype(L) && L != user)
tributers.Add(L)
var/total_per_tribute = max(1,round(amount_needed/max(1,tributers.len+1)))
var/tributer_size = tributers.len
for (var/i = 1 to tributer_size)
var/mob/living/L = pick(tributers)//so it's not always the first one that pays the first blood unit.
tributers.Remove(L)
var/data = use_available_blood(L, total_per_tribute, "", 1)
if (data[BLOODCOST_RESULT] != BLOODCOST_FAILURE)
total_accumulated += data[BLOODCOST_TOTAL]
if (total_accumulated >= amount_needed - total_per_tribute)//could happen if the cost is less than 1 per tribute
communion_data = data//in which case, the blood will carry the data that paid for it
break
//Getting nearby blood sources
var/list/data = get_available_blood(user, amount_needed-total_accumulated)
var/datum/reagent/blood/blood
//Flavour text and blood data transfer
switch (data[BLOODCOST_RESULT])
if (BLOODCOST_TRIBUTE)//if the drop of blood was paid for through blood communion, let's get the reference to the blood they used because we can
blood = new()
if (communion_data && communion_data[BLOODCOST_RESULT])
switch(communion_data[BLOODCOST_RESULT])
if (BLOODCOST_TARGET_HANDS)
var/mob/living/carbon/human/HU = communion_data[BLOODCOST_USER]
blood.data["blood_colour"] = HU.bloody_hands_data["blood_colour"]
if (HU.blood_DNA && HU.blood_DNA.len)
var/blood_DNA = pick(HU.blood_DNA)
blood.data["blood_DNA"] = blood_DNA
blood.data["blood_type"] = HU.blood_DNA[blood_DNA]
//can't get virus data from bloody hands because it'd be a pain in the ass to code for minimal use
if (BLOODCOST_TARGET_SPLATTER)
var/obj/effect/decal/cleanable/blood/B = communion_data[BLOODCOST_TARGET_SPLATTER]
blood = new()
blood.data["blood_colour"] = B.basecolor
if (B.blood_DNA.len)
var/blood_DNA = pick(B.blood_DNA)
blood.data["blood_DNA"] = blood_DNA
blood.data["blood_type"] = B.blood_DNA[blood_DNA]
blood.data["virus2"] = virus_copylist(B.virus2)
if (BLOODCOST_TARGET_GRAB)
var/mob/living/carbon/CA = communion_data[BLOODCOST_TARGET_GRAB]
if (isliving(CA))
blood.apply_blood_data(CA.get_blood_data())
if (BLOODCOST_TARGET_BLEEDER)
var/mob/living/carbon/CA = communion_data[BLOODCOST_TARGET_BLEEDER]
if (isliving(CA))
blood.apply_blood_data(CA.get_blood_data())
if (BLOODCOST_TARGET_HELD)
var/obj/item/weapon/reagent_containers/G = communion_data[BLOODCOST_TARGET_HELD]
blood = locate() in G.reagents.reagent_list
if (BLOODCOST_TARGET_BLOODPACK)
var/obj/item/weapon/reagent_containers/blood/B = communion_data[BLOODCOST_TARGET_BLOODPACK]
blood = locate() in B.reagents.reagent_list
if (BLOODCOST_TARGET_CONTAINER)
var/obj/item/weapon/reagent_containers/G = communion_data[BLOODCOST_TARGET_CONTAINER]
blood = locate() in G.reagents.reagent_list
if (BLOODCOST_TARGET_USER)
var/mob/living/carbon/CA = communion_data[BLOODCOST_USER]
if (iscarbon(CA))
blood.apply_blood_data(CA.get_blood_data())
if (isconstruct(CA))//constructs can't get the blood communion tattoo but just in case they do later
blood.data["blood_colour"] = "#CC0E00"
if (feedback && !tribute && previous_result != BLOODCOST_TRIBUTE)
user.visible_message("<span class='warning'>Drips of blood seem to appear out of thin air around \the [user], and fall onto the floor!</span>",
"<span class='rose'>An ally has lent you a drip of their blood for your ritual.</span>",
"<span class='warning'>You hear a liquid flowing.</span>")
if (BLOODCOST_TARGET_HANDS)
var/mob/living/carbon/human/H = user
blood = new()
blood.data["blood_colour"] = H.bloody_hands_data["blood_colour"]
if (H.blood_DNA?.len && H.bloody_hands > 0)
var/blood_DNA = pick(H.blood_DNA)
blood.data["blood_DNA"] = blood_DNA
blood.data["blood_type"] = H.blood_DNA[blood_DNA]
//can't get virus data from bloody hands because it'd be a pain in the ass to code for minimal use
if (feedback && !tribute && previous_result != BLOODCOST_TARGET_HANDS)
user.visible_message("<span class='warning'>The blood on \the [user]'s hands drips onto the floor!</span>",
"<span class='rose'>You let the blood smeared on your hands join the pool of your summoning.</span>",
"<span class='warning'>You hear a liquid flowing.</span>")
if (BLOODCOST_TARGET_SPLATTER)
var/obj/effect/decal/cleanable/blood/B = data[BLOODCOST_TARGET_SPLATTER]
blood = new()
blood.data["blood_colour"] = B.basecolor
if (B.blood_DNA.len)
var/blood_DNA = pick(B.blood_DNA)
blood.data["blood_DNA"] = blood_DNA
blood.data["blood_type"] = B.blood_DNA[blood_DNA]
blood.data["virus2"] = virus_copylist(B.virus2)
if (feedback && !tribute && previous_result != BLOODCOST_TARGET_SPLATTER)
user.visible_message("<span class='warning'>The blood on the floor below \the [user] starts moving!</span>",
"<span class='rose'>You redirect the flow of blood inside the splatters on the floor toward the pool of your summoning.</span>",
"<span class='warning'>You hear a liquid flowing.</span>")
if (BLOODCOST_TARGET_GRAB)
var/mob/living/carbon/C = data[BLOODCOST_TARGET_GRAB]
if (iscarbon(C))
blood = new()
blood.apply_blood_data(C.get_blood_data())
if (feedback && !tribute && previous_result != BLOODCOST_TARGET_GRAB)
user.visible_message("<span class='warning'>\The [user] stabs their nails inside \the [data[BLOODCOST_TARGET_GRAB]], drawing blood from them!</span>",
"<span class='rose'>You stab your nails inside \the [data[BLOODCOST_TARGET_GRAB]] to draw some blood from them.</span>",
"<span class='warning'>You hear a liquid flowing.</span>")
if (BLOODCOST_TARGET_BLEEDER)
var/mob/living/carbon/C = data[BLOODCOST_TARGET_BLEEDER]
if (iscarbon(C))
blood = new()
blood.apply_blood_data(C.get_blood_data())
if (feedback && !tribute && previous_result != BLOODCOST_TARGET_BLEEDER)
user.visible_message("<span class='warning'>\The [user] dips their fingers inside \the [data[BLOODCOST_TARGET_BLEEDER]]'s wounds!</span>",
"<span class='rose'>You dip your fingers inside \the [data[BLOODCOST_TARGET_BLEEDER]]'s wounds to draw some blood from them.</span>",
"<span class='warning'>You hear a liquid flowing.</span>")
if (BLOODCOST_TARGET_HELD)
var/obj/item/weapon/reagent_containers/G = data[BLOODCOST_TARGET_HELD]
blood = locate() in G.reagents.reagent_list
if (!tribute && previous_result != BLOODCOST_TARGET_HELD)
user.visible_message("<span class='warning'>\The [user] tips \the [data[BLOODCOST_TARGET_HELD]], pouring blood!</span>",
"<span class='rose'>You tip \the [data[BLOODCOST_TARGET_HELD]] to pour the blood contained inside.</span>",
"<span class='warning'>You hear a liquid flowing.</span>")
if (BLOODCOST_TARGET_BLOODPACK)
var/obj/item/weapon/reagent_containers/blood/B = data[BLOODCOST_TARGET_BLOODPACK]
blood = locate() in B.reagents.reagent_list
if (feedback && !tribute && previous_result != BLOODCOST_TARGET_BLOODPACK)
user.visible_message("<span class='warning'>\The [user] squeezes \the [data[BLOODCOST_TARGET_BLOODPACK]], pouring blood!</span>",
"<span class='rose'>You squeeze \the [data[BLOODCOST_TARGET_BLOODPACK]] to pour the blood contained inside.</span>",
"<span class='warning'>You hear a liquid flowing.</span>")
if (BLOODCOST_TARGET_CONTAINER)
var/obj/item/weapon/reagent_containers/G = data[BLOODCOST_TARGET_CONTAINER]
blood = locate() in G.reagents.reagent_list
if (feedback && !tribute && previous_result != BLOODCOST_TARGET_CONTAINER)
user.visible_message("<span class='warning'>\The [user] dips their fingers inside \the [data[BLOODCOST_TARGET_CONTAINER]], covering them in blood!</span>",
"<span class='rose'>You dip your fingers inside \the [data[BLOODCOST_TARGET_CONTAINER]], covering them in blood.</span>",
"<span class='warning'>You hear a liquid flowing.</span>")
if (BLOODCOST_TARGET_USER)
blood = new()
if (!tribute)
if (data[BLOODCOST_HOLES_BLOODPACK])
to_chat(user, "<span class='warning'>You must puncture \the [data[BLOODCOST_TARGET_BLOODPACK]] before you can squeeze blood from it!</span>")
else if (data[BLOODCOST_LID_HELD])
to_chat(user, "<span class='warning'>Remove \the [data[BLOODCOST_TARGET_HELD]]'s lid first!</span>")
else if (data[BLOODCOST_LID_CONTAINER])
to_chat(user, "<span class='warning'>Remove \the [data[BLOODCOST_TARGET_CONTAINER]]'s lid first!</span>")
if (iscarbon(user))
var/mob/living/carbon/C_user = user
blood.apply_blood_data(C_user.get_blood_data())
if (isconstruct(user))
blood.data["blood_colour"] = "#CC0E00"//not like constructs can write runes by themselves currently, but they might do at some point
if (feedback && !tribute && (previous_result != BLOODCOST_TARGET_USER))
if (iscarbon(user))//if the user is holding a sharp weapon, they get a custom message
var/obj/item/weapon/W = user.get_active_hand()
if (W && W.sharpness_flags & SHARP_BLADE)
to_chat(user, "<span class='rose'>You slice open your finger with \the [W] to let a bit of blood flow.</span>")
else
var/obj/item/weapon/W2 = user.get_inactive_hand()
if (W2 && W2.sharpness_flags & SHARP_BLADE)
to_chat(user, "<span class='rose'>You slice open your finger with \the [W] to let a bit of blood flow.</span>")
else
to_chat(user, "<span class='rose'>You bite your finger and let the blood pearl up.</span>")
else if (isconstruct(user))
to_chat(user, "<span class='rose'>Your shell's connection past the veil lets you perform the ritual without the need for a local source of blood.</span>")
if (BLOODCOST_FAILURE)
if (!tribute)
if (data[BLOODCOST_HOLES_BLOODPACK])
to_chat(user, "<span class='danger'>You must puncture \the [data[BLOODCOST_TARGET_BLOODPACK]] before you can squeeze blood from it!</span>")
else if (data[BLOODCOST_LID_HELD])
to_chat(user, "<span class='danger'>Remove \the [data[BLOODCOST_TARGET_HELD]]'s lid first!</span>")
else if (data[BLOODCOST_LID_CONTAINER])
to_chat(user, "<span class='danger'>Remove \the [data[BLOODCOST_TARGET_HELD]]'s lid first!</span>")
else
to_chat(user, "<span class='danger'>There is no blood available. Not even in your own body!</span>")
//Blood is only consumed if there is enough of it
if (!data[BLOODCOST_FAILURE])
if (data[BLOODCOST_TARGET_HANDS])
data[BLOODCOST_TOTAL] += data[BLOODCOST_AMOUNT_HANDS]
var/mob/living/carbon/human/H = user
H.bloody_hands = max(0, H.bloody_hands - data[BLOODCOST_AMOUNT_HANDS])
if (!H.bloody_hands)
H.clean_blood()
H.update_inv_gloves()
if (data[BLOODCOST_TARGET_SPLATTER])
data[BLOODCOST_TOTAL] += data[BLOODCOST_AMOUNT_SPLATTER]
var/obj/effect/decal/cleanable/blood/B = data[BLOODCOST_TARGET_SPLATTER]
B.amount = max(0 , B.amount - data[BLOODCOST_AMOUNT_SPLATTER])
if (data[BLOODCOST_TARGET_GRAB])
data[BLOODCOST_TOTAL] += data[BLOODCOST_AMOUNT_GRAB]
if (ishuman(data[BLOODCOST_TARGET_GRAB]))
var/mob/living/carbon/human/H = data[BLOODCOST_TARGET_GRAB]
H.vessel.remove_reagent(BLOOD, data[BLOODCOST_AMOUNT_GRAB])
H.take_overall_damage(data[BLOODCOST_AMOUNT_GRAB] ? 0.1 : 0)
else if (ismonkey(data[BLOODCOST_TARGET_GRAB]))
var/mob/living/carbon/monkey/M = data[BLOODCOST_TARGET_GRAB]
M.adjustOxyLoss(data[BLOODCOST_AMOUNT_GRAB])
else if (isalien(data[BLOODCOST_TARGET_GRAB]))
var/mob/living/carbon/alien/A = data[BLOODCOST_TARGET_GRAB]
A.adjustBruteLoss(data[BLOODCOST_AMOUNT_GRAB])
if (data[BLOODCOST_TARGET_BLEEDER])
data[BLOODCOST_TOTAL] += data[BLOODCOST_AMOUNT_BLEEDER]
var/mob/living/carbon/human/H = data[BLOODCOST_TARGET_BLEEDER]
H.vessel.remove_reagent(BLOOD, data[BLOODCOST_AMOUNT_BLEEDER])
H.take_overall_damage(data[BLOODCOST_AMOUNT_BLEEDER] ? 0.1 : 0)
if (data[BLOODCOST_TARGET_HELD])
data[BLOODCOST_TOTAL] += data[BLOODCOST_AMOUNT_HELD]
var/obj/item/weapon/reagent_containers/G = data[BLOODCOST_TARGET_HELD]
G.reagents.remove_reagent(BLOOD, data[BLOODCOST_AMOUNT_HELD])
if (data[BLOODCOST_TARGET_BLOODPACK])
data[BLOODCOST_TOTAL] += data[BLOODCOST_AMOUNT_BLOODPACK]
var/obj/item/weapon/reagent_containers/G = data[BLOODCOST_TARGET_BLOODPACK]
G.reagents.remove_reagent(BLOOD, data[BLOODCOST_AMOUNT_BLOODPACK])
if (data[BLOODCOST_TARGET_CONTAINER])
data[BLOODCOST_TOTAL] += data[BLOODCOST_AMOUNT_CONTAINER]
var/obj/item/weapon/reagent_containers/G = data[BLOODCOST_TARGET_CONTAINER]
G.reagents.remove_reagent(BLOOD, data[BLOODCOST_AMOUNT_CONTAINER])
if (data[BLOODCOST_TARGET_USER])
data[BLOODCOST_TOTAL] += data[BLOODCOST_AMOUNT_USER]
if (ishuman(user))
var/mob/living/carbon/human/H = user
var/blood_before = H.vessel.get_reagent_amount(BLOOD)
H.vessel.remove_reagent(BLOOD, data[BLOODCOST_AMOUNT_USER])
var/blood_after = H.vessel.get_reagent_amount(BLOOD)
if (blood_before > BLOOD_VOLUME_SAFE && blood_after < BLOOD_VOLUME_SAFE)
to_chat(user, "<span class='sinister'>You start looking pale.</span>")
else if (blood_before > BLOOD_VOLUME_WARN && blood_after < BLOOD_VOLUME_WARN)
to_chat(user, "<span class='sinister'>You feel weak from the lack of blood.</span>")
else if (blood_before > BLOOD_VOLUME_OKAY && blood_after < BLOOD_VOLUME_OKAY)
to_chat(user, "<span class='sinister'>You are about to pass out from the lack of blood.</span>")
else if (blood_before > BLOOD_VOLUME_BAD && blood_after < BLOOD_VOLUME_BAD)
to_chat(user, "<span class='sinister'>You have trouble focusing, things will go bad if you keep using your blood.</span>")
else if (blood_before > BLOOD_VOLUME_SURVIVE && blood_after < BLOOD_VOLUME_SURVIVE)
to_chat(user, "<span class='sinister'>It will be all over soon.</span>")
H.take_overall_damage(data[BLOODCOST_AMOUNT_USER] ? 0.1 : 0)
else if (ismonkey(user) || isalien(user))
var/mob/living/carbon/C = user
var/blood_before = C.health
if (ismonkey(C))
C.adjustOxyLoss(data[BLOODCOST_AMOUNT_USER])
else if (isalien(C))
C.adjustBruteLoss(data[BLOODCOST_AMOUNT_USER])
C.updatehealth()
var/blood_after = C.health
if (blood_before > (C.maxHealth*5/6) && blood_after < (C.maxHealth*5/6))
to_chat(user, "<span class='sinister'>You start looking pale.</span>")
else if (blood_before > (C.maxHealth*4/6) && blood_after < (C.maxHealth*4/6))
to_chat(user, "<span class='sinister'>You feel weak from the lack of blood.</span>")
else if (blood_before > (C.maxHealth*3/6) && blood_after < (C.maxHealth*3/6))
to_chat(user, "<span class='sinister'>You are about to pass out from the lack of blood.</span>")
else if (blood_before > (C.maxHealth*2/6) && blood_after < (C.maxHealth*2/6))
to_chat(user, "<span class='sinister'>You have trouble focusing, things will go bad if you keep using your blood.</span>")
else if (blood_before > (C.maxHealth*1/6) && blood_after < (C.maxHealth*1/6))
to_chat(user, "<span class='sinister'>It will be all over soon.</span>")
if (communion && data[BLOODCOST_TOTAL] + total_accumulated >= amount_needed)
data[BLOODCOST_TOTAL] = max(data[BLOODCOST_TOTAL], total_needed)
data["blood"] = blood
return data

View File

@@ -0,0 +1,103 @@
var/rune_words_initialized = 0
var/list/rune_words = list()//datums go in here
var/list/rune_words_english = list("travel", "blood", "join", "hell", "destroy", "technology", "self", "see", "other", "hide")
var/list/rune_words_rune = list("ire","ego","nahlizet","certum","veri","jatkaa","mgar","balaq", "karazet", "geeri")
var/list/rune_words_icons = list("rune-1","rune-2","rune-4","rune-8","rune-16","rune-32","rune-64","rune-128", "rune-256", "rune-512")
/datum/rune_word
var/english = "word"//don't change those
var/rune = "zek'kon"
var/icon = 'icons/effects/uristrunes.dmi'
var/icon_state = ""
var/color//used by path rune markers
var/offset_x = 0
var/offset_y = 0
/proc/initialize_rune_words()
if (rune_words_initialized)
return
for(var/subtype in subtypesof(/datum/rune_word))
var/datum/rune_word/new_word = new subtype()
rune_words[new_word.english] = new_word
rune_words_initialized = 1
/datum/rune_word/travel
english = "travel"
rune = "ire"
icon_state = "rune-1"
color = "yellow"
offset_x = 6
offset_y = -5
/datum/rune_word/blood
english = "blood"
rune = "ego"
icon_state = "rune-2"
color = "maroon"
offset_x = 0
offset_y = 5
/datum/rune_word/join
english = "join"
rune = "nahlizet"
icon_state = "rune-4"
color = "green"
offset_x = 2
offset_y = 1
/datum/rune_word/hell
english = "hell"
rune = "certum"
icon_state = "rune-8"
color = "red"
offset_x = 0
offset_y = 10
/datum/rune_word/destroy
english = "destroy"
rune = "veri"
icon_state = "rune-16"
color = "purple"
offset_x = 10
offset_y = 3
/datum/rune_word/technology
english = "technology"
rune = "jatkaa"
icon_state = "rune-32"
color = "blue"
offset_x = -10
offset_y = 1
/datum/rune_word/self
english = "self"
rune = "mgar"
icon_state = "rune-64"
color = null
offset_x = -6
offset_y = -9
/datum/rune_word/see
english = "see"
rune = "balaq"
icon_state = "rune-128"
color = "fuchsia"
offset_x = 10
offset_y = -11
/datum/rune_word/other
english = "other"
rune = "karazet"
icon_state = "rune-256"
color = "teal"
offset_x = -8
offset_y = 8
/datum/rune_word/hide
english = "hide"
rune = "geeri"
icon_state = "rune-512"
color = "silver"
offset_x = -2
offset_y = -1

View File

@@ -25,27 +25,6 @@
var/isbroken = 0
light_range = 5
light_color = LIGHT_COLOR_RED
var/last_check = 0
/*
/obj/structure/cult_legacy/pylon/New()
..()
processing_objects.Add(src)
/obj/structure/cult_legacy/pylon/Destroy()
processing_objects.Remove(src)
..()
/obj/structure/cult_legacy/pylon/process()
if(!isbroken && world.time > last_check + 3 SECONDS)
last_check = world.time
for(var/mob/living/simple_animal/construct/C in view(src, 3))
if(C.health < C.maxHealth)
if(prob(15))
src.visible_message("<span class='sinister'>\the [src] mends some of \the <EM>[C]'s</EM> wounds.</span>")
make_tracker_effects(get_turf(src), C)
C.health = min(C.maxHealth, C.health + 3) //Not quite as good as artificers
*/
/obj/structure/cult_legacy/pylon/attack_hand(mob/M as mob)
attackpylon(M, 5)

View File

@@ -53,12 +53,8 @@ var/global/list/narsie_list = list()
world << sound('sound/effects/wind/wind_5_1.ogg')
if(narnar)
narsie_spawn_animation()
var/datum/faction/bloodcult/cult = find_active_faction_by_type(/datum/faction/bloodcult)
if (cult)
cult.stage(CULT_EPILOGUE)
if(!narsie_cometh)//so we don't initiate Hell more than one time.
if (emergency_shuttle && !cult)//in case of Cult 3.0, the round will end after about 5 minutes
if (emergency_shuttle)
emergency_shuttle.incall()
emergency_shuttle.can_recall = 0
if(emergency_shuttle.endtime > world.timeofday + 1800 && emergency_shuttle.location != 1 && !emergency_shuttle.departed)

View File

@@ -1,4 +1,22 @@
/datum/objective/bloodcult
name = "Cultist of Nar-Sie"
explanation_text = "Set up secret temples dedicated to Nar-Sie, the Geometer of Blood, harbringer of gunk and chaos. Spread your influence among the crew without getting caught by security. Convert the willing and torment the others. Above all, ensure that at least one of you remains alive to spread the cult's influence to other space stations."
/datum/objective/bloodcult/IsFulfilled()
if (..())
return TRUE
var/datum/faction/bloodcult/cult = find_active_faction_by_type(/datum/faction/bloodcult)
if (cult && cult.members.len > 0)
for (var/datum/role/cultist/C in cult.members)
if (C.antag.current && !C.antag.current.isDead())
return TRUE
return FALSE
/* there might be useful bits of code here to use later so I'm leaving this commented out for convenience for now.
/datum/objective/bloodcult_reunion
explanation_text = "The Reunion: Meet up with your fellow cultists, and erect an altar aboard the station."
name = "Blood Cult: Prologue"
@@ -229,3 +247,4 @@
/datum/objective/bloodcult_feast/IsFulfilled()
return TRUE//might expand on that later after release, if I ever get to implement my rework of post-NarSie.
*/

View File

@@ -16,6 +16,16 @@
var/second_chance = 1
var/datum/deconversion_ritual/deconversion = null
//writing runes
var/rune_blood_cost = 1 // How much blood spent per rune word written
var/verbose = FALSE // Used by the rune writing UI to avoid message spam
var/cultist_role = CULTIST_ROLE_NONE // Because the role might change on the fly and we don't want to set everything again each time, better not start dealing with subtypes
var/time_role_changed_last = 0
var/datum/role/cultist/mentor = null
var/list/acolytes = list()
/datum/role/cultist/New(var/datum/mind/M, var/datum/faction/fac=null, var/new_id)
..()
wikiroute = role_wiki[CULTIST]
@@ -28,15 +38,6 @@
update_cult_hud()
antag.current.add_language(LANGUAGE_CULT)
if((ishuman(antag.current) || ismonkey(antag.current) || isalien(antag.current)) && !(locate(/spell/cult) in antag.current.spell_list))
antag.current.add_spell(new /spell/cult/trace_rune/blood_cult, "cult_spell_ready", /obj/abstract/screen/movable/spell_master/bloodcult)
antag.current.add_spell(new /spell/cult/erase_rune, "cult_spell_ready", /obj/abstract/screen/movable/spell_master/bloodcult)
antag.store_memory("A couple of runes appear clearly in your mind:")
antag.store_memory("<B>Raise Structure:</B> BLOOD, TECHNOLOGY, JOIN.")
antag.store_memory("<B>Communication:</B> SELF, OTHER, TECHNOLOGY.")
antag.store_memory("<B>Summon Tome:</B> SEE, BLOOD, HELL.")
antag.store_memory("<hr>")
/datum/role/cultist/RemoveFromRole(var/datum/mind/M)
antag.current.remove_language(LANGUAGE_CULT)
remove_cult_hud()
@@ -44,6 +45,7 @@
antag.current.remove_spell(spell_to_remove)
if (src in blood_communion)
blood_communion.Remove(src)
DropMentorship()
if (conversion.len > 0)
var/conv = pick(conversion)
switch (conv)
@@ -74,52 +76,13 @@
return
update_cult_hud()
antag.current.add_language(LANGUAGE_CULT)
if((ishuman(antag.current) || ismonkey(antag.current) || isalien(antag.current)) && !(locate(/spell/cult) in antag.current.spell_list))
antag.current.add_spell(new /spell/cult/trace_rune/blood_cult, "cult_spell_ready", /obj/abstract/screen/movable/spell_master/bloodcult)
antag.current.add_spell(new /spell/cult/erase_rune, "cult_spell_ready", /obj/abstract/screen/movable/spell_master/bloodcult)
/datum/role/cultist/process()
..()
if (holywarning_cooldown > 0)
holywarning_cooldown--
if (veil_thickness == CULT_MENDED && antag?.current)
if (ishuman(antag.current))
var/mob/living/carbon/human/H = antag.current
if(H.get_heart() && prob(10))
H.visible_message("<span class='danger'>\The [H]'s heart bursts out of \his chest!</span>","<span class='danger'>Your heart bursts out of your chest!</span>")
var/obj/item/organ/internal/blown_heart = H.remove_internal_organ(H,H.get_heart(),H.get_organ(LIMB_CHEST))
var/list/spawn_turfs = list()
for(var/turf/T in orange(1, H))
if(!T.density)
spawn_turfs.Add(T)
if(!spawn_turfs.len)
spawn_turfs.Add(get_turf(H))
var/mob/living/simple_animal/hostile/heart_attack = new(pick(spawn_turfs))
heart_attack.appearance = blown_heart.appearance
heart_attack.icon_dead = "heart-off"
heart_attack.environment_smash_flags = 0
heart_attack.melee_damage_lower = 15
heart_attack.melee_damage_upper = 15
heart_attack.health = 50
heart_attack.maxHealth = 50
heart_attack.stat_attack = 1
qdel(blown_heart)
else
H.eye_blurry = max(H.eye_blurry, 30)
H.Dizzy(30)
H.stuttering = max(H.stuttering, 30)
H.Jitter(30)
if (prob(70))
H.Knockdown(4)
else if (prob(70))
H.confused = 6
H.adjustOxyLoss(20)
H.adjustToxLoss(10)
else
if(isliving(antag.current))
var/mob/living/L = antag.current
L.adjustBruteLoss(rand(20,50))
if ((cultist_role == CULTIST_ROLE_ACOLYTE) && !mentor)
FindMentor()
/datum/role/cultist/Greet(var/greeting,var/custom)
if(!greeting)
@@ -163,9 +126,6 @@
to_chat(antag.current, "<span class='info'><a HREF='?src=\ref[antag.current];getwiki=[wikiroute]'>(Wiki Guide)</a></span>")
to_chat(antag.current, "<span class='sinister'>You find yourself to be well-versed in the runic alphabet of the cult.</span>")
to_chat(antag.current, "<span class='sinister'>A couple of runes linger vividly in your mind.</span><span class='info'> (check your notes).</span>")
spawn(1)
if (faction)
@@ -179,89 +139,117 @@
/datum/role/cultist/proc/update_cult_hud()
var/mob/M = antag?.current
if(M && M.client && M.hud_used)
if(!M.hud_used.cult_Act_display)
M.hud_used.cult_hud()
if (!(M.hud_used.cult_Act_display in M.client.screen))
M.client.screen += list(M.hud_used.cult_Act_display,M.hud_used.cult_tattoo_display)
M.hud_used.cult_Act_display.overlays.len = 0
M.hud_used.cult_tattoo_display.overlays.len = 0
var/current_act = max(-1,min(5,veil_thickness))
var/image/I_act = image('icons/mob/screen1_cult.dmi',"act")
I_act.appearance_flags |= RESET_COLOR
M.hud_used.cult_Act_display.overlays += I_act
var/image/I_tattoos = image('icons/mob/screen1_cult.dmi',"tattoos")
I_tattoos.appearance_flags |= RESET_COLOR
M.hud_used.cult_tattoo_display.overlays += I_tattoos
var/image/I_act_indicator = image('icons/mob/screen1_cult.dmi',"[current_act]")
if (current_act == CULT_MENDED)
I_act_indicator.appearance_flags |= RESET_COLOR
M.hud_used.cult_Act_display.overlays += I_act_indicator
var/image/I_arrow = image('icons/mob/screen1_cult.dmi',"[current_act]a")
I_arrow.appearance_flags |= RESET_COLOR
M.hud_used.cult_Act_display.overlays += I_arrow
switch (current_act)
if (CULT_MENDED)
M.hud_used.cult_Act_display.name = "..."
if (CULT_PROLOGUE)
M.hud_used.cult_Act_display.name = "Prologue: The Reunion"
if (CULT_ACT_I)
M.hud_used.cult_Act_display.name = "Act I: The Followers"
if (CULT_ACT_II)
M.hud_used.cult_Act_display.name = "Act II: The Sacrifice"
if (CULT_ACT_III)
M.hud_used.cult_Act_display.name = "Act III: The Blood Bath"
if (CULT_ACT_IV)
M.hud_used.cult_Act_display.name = "Act IV: The Tear in Reality"
if (CULT_EPILOGUE)
M.hud_used.cult_Act_display.name = "Epilogue: The Feast"
var/tattoos_names = ""
var/i = 0
for (var/T in tattoos)
var/datum/cult_tattoo/tattoo = tattoos[T]
if (tattoo)
M.hud_used.cult_tattoo_display.overlays += image('icons/mob/screen1_cult.dmi',"t_[tattoo.icon_state]")
tattoos_names += "[i ? ", " : ""][tattoo.name]"
i++
if (!tattoos_names)
tattoos_names = "none"
M.hud_used.cult_tattoo_display.name = "Arcane Tattoos: [tattoos_names]"
if (isshade(M))
if (istype(M.loc,/obj/item/weapon/melee/soulblade))
M.DisplayUI("Soulblade")
M.client.screen |= list(M.healths2)
else
M.client.screen -= list(M.healths2)
if(M)
M.DisplayUI("Cultist")
if (M.client && M.hud_used)
if (isshade(M))
if (istype(M.loc,/obj/item/weapon/melee/soulblade))
M.DisplayUI("Soulblade")
M.client.screen |= list(M.healths2)
else
M.client.screen -= list(M.healths2)
/datum/role/cultist/proc/remove_cult_hud()
var/mob/M = antag?.current
if(M && M.client && M.hud_used)
qdel(M.hud_used.cult_Act_display)
qdel(M.hud_used.cult_tattoo_display)
if(M)
M.HideUI("Cultist")
M.HideUI("Bloodcult Runes")
/mob/proc/occult_muted()
if (checkTattoo(TATTOO_HOLY))
return 0
if (reagents && reagents.has_reagent(HOLYWATER))
return 1
if (is_implanted(/obj/item/weapon/implant/holy))
return 1
return 0
/datum/role/cultist/extraPanelButtons()
var/dat = ""
if (mentor)
dat = "<br>Currently under the mentorship of <b>[mentor.antag.name]/([mentor.antag.key])</b><br>"
if (acolytes.len)
dat += "<br>Currently mentoring "
for (var/datum/role/cultist/acolyte in acolytes)
dat += "<b>[acolyte.antag.name]/([acolyte.antag.key])</b>, "
dat += "<br>"
return dat
/datum/role/cultist/proc/DropMentorship()
if (mentor)
to_chat(antag.current,"<span class='warning'>You have ended your mentorship under [mentor.antag.name].</span>")
to_chat(mentor.antag.current,"<span class='warning'>[antag.name] has ended their mentorship under you.</span>")
message_admins("[antag.key]/([antag.name]) has ended their mentorship under [mentor.antag.name]")
log_admin("[antag.key]/([antag.name]) has ended their mentorship under [mentor.antag.name]")
if (acolytes.len > 0)
for (var/datum/role/cultist/acolyte in acolytes)
to_chat(antag.current,"<span class='warning'>You have ended your mentorship of [acolyte.antag.name].</span>")
to_chat(acolyte.antag.current,"<span class='warning'>[antag.name] has ended their mentorship.</span>")
message_admins("[antag.key]/([antag.name]) has ended their mentorship of [acolyte.antag.name]")
log_admin("[antag.key]/([antag.name]) has ended their mentorship of [acolyte.antag.name]")
/datum/role/cultist/proc/ChangeCultistRole(var/new_role)
if (!new_role)
return
var/datum/faction/bloodcult/cult = faction
if ((cultist_role == CULTIST_ROLE_MENTOR) && cult)
cult.mentor_count--
cultist_role = new_role
DropMentorship()
switch(cultist_role)
if (CULTIST_ROLE_ACOLYTE)
message_admins("BLOODCULT: [antag.key]/([antag.name]) has become a cultist acolyte.")
log_admin("BLOODCULT: [antag.key]/([antag.name]) has become a cultist acolyte.")
logo_state = "cult-apprentice-logo"
FindMentor()
if (!mentor)
message_admins("BLOODCULT: [antag.key]/([antag.name]) couldn't find a mentor.")
log_admin("BLOODCULT: [antag.key]/([antag.name]) couldn't find a mentor.")
if (CULTIST_ROLE_HERALD)
message_admins("BLOODCULT: [antag.key]/([antag.name]) has become a cultist herald.")
log_admin("BLOODCULT: [antag.key]/([antag.name]) has become a cultist herald.")
logo_state = "cult-logo"
if (CULTIST_ROLE_MENTOR)
message_admins("BLOODCULT: [antag.key]/([antag.name]) has become a cultist mentor.")
log_admin("BLOODCULT: [antag.key]/([antag.name]) has become a cultist mentor.")
logo_state = "cult-master-logo"
if (cult)
cult.mentor_count++
else
logo_state = "cult-logo"
cultist_role = CULTIST_ROLE_NONE
if (cult)
cult.update_hud_icons()
if (antag.current)
antag.current.DisplayUI("Cultist Left Panel")
time_role_changed_last = world.time
/datum/role/cultist/proc/FindMentor()
var/datum/faction/bloodcult/cult = faction
if (!cult || !cult.mentor_count)
return
var/datum/role/cultist/potential_mentor
var/min_acolytes = ARBITRARILY_LARGE_NUMBER
for (var/datum/role/cultist/C in cult.members)
if (C.antag.current.isDead())
continue
if (C.cultist_role == CULTIST_ROLE_MENTOR)
if (C.acolytes.len < min_acolytes || (C.acolytes.len == min_acolytes && prob(50)))
min_acolytes = C.acolytes.len
potential_mentor = C
if (potential_mentor)
mentor = potential_mentor
potential_mentor.acolytes |= src
to_chat(antag.current, "<span class='sinister'>You are now in a mentorship under <span class='danger'>[mentor.name], the [mentor.antag.assigned_role=="MODE" ? (mentor.antag.special_role) : (mentor.antag.assigned_role)]</span>. Seek their help to learn the ways of our cult.</span>")
to_chat(mentor.antag.current, "<span class='sinister'>You are now mentoring <span class='danger'>[antag.name], the [antag.assigned_role=="MODE" ? (antag.special_role) : (antag.assigned_role)]</span>. </span>")
message_admins("[mentor.antag.key]/([mentor.antag.name]) is now mentoring [antag.name]")
log_admin("[mentor.antag.key]/([mentor.antag.name]) is now mentoring [antag.name]")
/datum/role/cultist/handle_reagent(var/reagent_id)
var/mob/living/carbon/human/H = antag.current
if (!istype(H))
return
var/unholy = H.checkTattoo(TATTOO_HOLY)
var/current_act = clamp(veil_thickness,CULT_MENDED,CULT_EPILOGUE)
if (reagent_id == INCENSE_HAREBELLS)
if (unholy)
H.eye_blurry = max(H.eye_blurry, 3)
return
else
H.eye_blurry = max(H.eye_blurry, 12)
H.Dizzy(12)
H.stuttering = max(H.stuttering, 12)
H.Jitter(12)
/* // TODO (UPHEAVAL PART 2) stronger effects the more cult points have been accumulated
switch (current_act)
if (CULT_MENDED)
H.dust()
@@ -310,19 +298,17 @@
H.confused = 6
H.adjustOxyLoss(20)
H.adjustToxLoss(10)
*/
/datum/role/cultist/handle_splashed_reagent(var/reagent_id)//also proc'd when holy water is drinked or ingested in any way
var/mob/living/carbon/human/H = antag.current
if (!istype(H))
return
var/unholy = H.checkTattoo(TATTOO_HOLY)
var/current_act = max(-1,min(5,veil_thickness))
if (reagent_id == HOLYWATER)
if (holywarning_cooldown <= 0)
holywarning_cooldown = 5
if (unholy)
to_chat(H, "<span class='warning'>You feel the unpleasant touch of holy water, but the mark on your back negates its most debilitating effects.</span>")
else
to_chat(H, "<span class='danger'>The cold touch of holy water makes your head spin, you're having trouble walking straight.</span>")
/* // TODO (UPHEAVAL PART 2) stronger effects the more cult points have been accumulated
switch (current_act)
if (CULT_MENDED)
to_chat(H, "<span class='danger'>The holy water permeates your skin and consumes your cursed blood like mercury digests gold.</span>")
@@ -339,11 +325,13 @@
if (CULT_EPILOGUE)
to_chat(H, "<span class='danger'>Even in these times, holy water proves itself capable of hindering your progression.</span>")
*/
if (reagent_id == HOLYWATER || reagent_id == INCENSE_HAREBELLS)
if (unholy)
H.eye_blurry = max(H.eye_blurry, 3)
return
else
H.eye_blurry = max(H.eye_blurry, 12)
H.Dizzy(12)
H.stuttering = max(H.stuttering, 12)
H.Jitter(12)
/* // TODO (UPHEAVAL PART 2) stronger effects the more cult points have been accumulated
switch (current_act)
if (CULT_MENDED)
H.dust()
@@ -392,14 +380,77 @@
H.confused = 6
H.adjustOxyLoss(20)
H.adjustToxLoss(10)
*/
/datum/role/cultist/chief
id = CHIEF_CULTIST
name = "Chief cultist"
logo_state = "cult-chief-logo"
/datum/role/cultist/proc/write_rune(var/word_to_draw)
var/mob/living/user = antag.current
/datum/role/cultist/chief/Greet(var/greeting,var/custom)
. = ..()
if (greeting)
to_chat(antag.current, "<span class='notice'>You are the chief cultist. You have been chosen by Nar-Sie to lead this cult to victory. Coordinate with your fellow acolytes, establish a plan, construct a base. Tear down the veil.</span>")
to_chat(antag.current, "<span class='notice'>You may speak with your fellow cultists by using ':x'.</span>")
if (user.incapacitated())
return
var/muted = user.occult_muted()
if (muted)
to_chat(user,"<span class='danger'>You find yourself unable to focus your mind on the words of Nar-Sie.</span>")
return
if(!istype(user.loc, /turf))
to_chat(user, "<span class='warning'>You do not have enough space to write a proper rune.</span>")
return
var/turf/T = get_turf(user)
var/obj/effect/rune/rune = locate() in T
if(rune)
if (rune.invisibility == INVISIBILITY_OBSERVER)
to_chat(user, "<span class='warning'>You can feel the presence of a concealed rune here. You have to reveal it before you can add more words to it.</span>")
return
else if (rune.word1 && rune.word2 && rune.word3)
to_chat(user, "<span class='warning'>You cannot add more than 3 words to a rune.</span>")
return
var/datum/rune_word/word = rune_words[word_to_draw]
var/list/rune_blood_data = use_available_blood(user, rune_blood_cost, feedback = verbose)
if (rune_blood_data[BLOODCOST_RESULT] == BLOODCOST_FAILURE)
return
if (verbose)
if(rune)
user.visible_message("<span class='warning'>\The [user] chants and paints more symbols on the floor.</span>",\
"<span class='warning'>You add another word to the rune.</span>",\
"<span class='warning'>You hear chanting.</span>")
else
user.visible_message("<span class='warning'>\The [user] begins to chant and paint symbols on the floor.</span>",\
"<span class='warning'>You begin drawing a rune on the floor.</span>",\
"<span class='warning'>You hear some chanting.</span>")
if(!user.checkTattoo(TATTOO_SILENT))
user.whisper("...[word.rune]...")
if(rune)
if(rune.word1 && rune.word2 && rune.word3)
to_chat(user, "<span class='warning'>You cannot add more than 3 words to a rune.</span>")
return
write_rune_word(get_turf(user), word, rune_blood_data["blood"], caster = user)
verbose = FALSE
/datum/role/cultist/proc/erase_rune()
var/mob/living/user = antag.current
if (!istype(user))
return
if (user.incapacitated())
return
var/turf/T = get_turf(user)
var/obj/effect/rune/rune = locate() in T
if (rune && rune.invisibility == INVISIBILITY_OBSERVER)
to_chat(user, "<span class='warning'>You can feel the presence of a concealed rune here, you have to reveal it before you can erase words from it.</span>")
return
var/removed_word = erase_rune_word(get_turf(user))
if (removed_word)
to_chat(user, "<span class='notice'>You retrace your steps, carefully undoing the lines of the [removed_word] rune.</span>")
else
to_chat(user, "<span class='warning'>There aren't any rune words left to erase.</span>")

View File

@@ -520,7 +520,7 @@
to_chat(mob, "<b>[voice_per_admin[user.ckey]]</b> [admin_voice_say] <span class='[admin_voice_style]'>\"[message]\"</span>")
for(var/mob/dead/observer/O in player_list)
to_chat(O, "<span class='game say'><b>[voice_per_admin[user.ckey]]</b> [admin_voice_say] <span class='[admin_voice_style]'>\"[message]\"</span></span>")
to_chat(O, "<span class='game say'><b>[voice_per_admin[user.ckey]]</b> [admin_voice_say] (to [mob]) <span class='[admin_voice_style]'>\"[message]\"</span></span>")
message_admins("Admin [key_name_admin(usr)] has talked to [key_name(mob)] as [voice_per_admin[user.ckey]].")
log_rolespeak("[key_name(usr)] as [voice_per_admin[user.ckey]] to [key_name(mob)]: \"[message]\"")

View File

@@ -596,47 +596,11 @@ The access requirements on the Asteroid Shuttles' consoles have now been revoked
//////////////BLOOD CULT
/datum/command_alert/cult_detected
name = "Occult Activity Detected - Please Investigate"
alert_title = "Occult Activity"
force_report = 1
/*
TODO (UPHEAVAL PART 2) Guess i'll add the future new announcements here
/datum/command_alert/cult_detected/announce()
message = "Irregularities in the fabric of space-time around [station_name()] appear to correlate with the propagation of occult activities. Remember that cult membership is strictly prohibited by Nanotrasen and exposes you to the death penalty, applicable immediately if evidence is made. We encourage the station's security department to investigate, and the rest of the crew to cooperate with them."
..()
*/
/datum/command_alert/bloodstones_raised
name = "Occult Activity Detected - Station Locked Down"
alert_title = "Occult Assault"
force_report = 1
theme = "endgame"
alertlevel = "red"
/datum/command_alert/bloodstones_raised/announce()
message = "Occult energies detected emanating from [station_name()]. Readings suggest an assault from the Cult of Nar-Sie. The station is now locked down under Directive 7-10, until destruction of all the bloodstones has been confirmed. Regroup with your station's security forces and approach the stones with caution, follow your superiors' directions."
..()
/datum/command_alert/bloodstones_anchor
name = "Occult Activity Critical - Breach of Space-Time Detected"
alert_title = "Occult Assault Critical"
force_report = 1
theme = "endgame"
alertlevel = "red"
/datum/command_alert/bloodstones_anchor/announce()
message = "Occult energies from [station_name()] are reaching a critical point. A breach through space has materialized on one of the bloodstones. It appears to be in [get_area_name(global_anchor_bloodstone, 1)]. Destroy it at all costs, do not let any cultist near it."
..()
/datum/command_alert/bloodstones_broken
name = "Occult Activity Ceased - Lock Down Lifted"
alert_title = "Occult Gone"
force_report = 1
stoptheme = 1
alertlevel = "blue"
/datum/command_alert/bloodstones_broken/announce()
message = "Destruction of the bloodstones confirmed. The Cult is no longer an immediate threat to Nanotrasen. Lock down of the station has been revoked."
..()
////////MISC STUFF

View File

@@ -33,6 +33,7 @@
var/active = 0
var/memory
var/datum/body_archive/body_archive
var/assigned_role
var/special_role
@@ -558,6 +559,8 @@
ticker.minds += mind
else
world.log << "## DEBUG: mind_initialize(): No ticker ready yet! Please inform Carn"
if (!mind.body_archive)
mind.body_archive = new(src)
if(!mind.name)
mind.name = real_name
mind.current = src

View File

@@ -447,7 +447,7 @@ var/list/all_supply_groups = list("Supplies","Clothing","Security","Hospitality"
group = "Supplies"
/datum/supply_packs/religious//you can only order default-looking bibles for now
name = "Religious Paraphernelia"
name = "Religious Paraphernalia"
contains = list(/obj/item/weapon/reagent_containers/food/drinks/bottle/holywater,
/obj/item/weapon/storage/bible,
/obj/item/weapon/storage/fancy/incensebox/harebells,