diff --git a/code/game/gamemodes/cult/ritual.dm b/code/game/gamemodes/cult/ritual.dm index 4bf743ef3d7..8e288c39a70 100644 --- a/code/game/gamemodes/cult/ritual.dm +++ b/code/game/gamemodes/cult/ritual.dm @@ -1,300 +1,698 @@ //This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32 -#define CULT_ELDERGOD "eldergod" -#define CULT_SLAUGHTER "slaughter" + +var/cultwords = list() +var/rune_to_english = list() +var/runedec = 0 +var/engwords = list("travel", "blood", "join", "hell", "destroy", "technology", "self", "see", "other", "hide") + +/client/proc/check_words() // -- Urist + set category = "Admin" + set name = "Check Rune Words" + set desc = "Check the rune-word meaning" + + if(!check_rights(R_ADMIN)) + return + + if(!cultwords["travel"]) + runerandom() + for(var/word in engwords) + to_chat(usr, "[cultwords[word]] is [word]") + + log_and_message_admins("checked the rune words.") + feedback_add_details("admin_verb","CRW") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/proc/runerandom() //randomizes word meaning + var/list/runewords=list("ire","ego","nahlizet","certum","veri","jatkaa","mgar","balaq", "karazet", "geeri") ///"orkan" and "allaq" removed. + for(var/word in engwords) + var/runeword = pick(runewords) + cultwords[word] = runeword + rune_to_english[runeword] = word + runewords-=cultwords[word] + + +/obj/effect/rune + desc = "" + anchored = 1 + icon = 'icons/obj/rune.dmi' + icon_state = "1" + var/visibility = 0 + var/view_range = 7 + unacidable = 1 + layer = TURF_LAYER + + var/word1 + var/word2 + var/word3 +// Places these combos are mentioned: this file - twice in the rune code, once in imbued tome, once in tome's HTML runes.dm - in the imbue rune code. If you change a combination - dont forget to change it everywhere. + +// travel self [word] - Teleport to random [rune with word destination matching] +// travel other [word] - Portal to rune with word destination matching - kinda doesnt work. At least the icon. No idea why. +// see blood Hell - Create a new tome +// join blood self - Incorporate person over the rune into the group +// Hell join self - Summon TERROR +// destroy see technology - EMP rune +// travel blood self - Drain blood +// see Hell join - See invisible +// blood join Hell - Raise dead + +// hide see blood - Hide nearby runes +// blood see hide - Reveal nearby runes - The point of this rune is that its reversed obscure rune. So you always know the words to reveal the rune once oyu have obscured it. + +// Hell travel self - Leave your body and ghost around +// blood see travel - Manifest a ghost into a mortal body +// Hell tech join - Imbue a rune into a talisman +// Hell blood join - Sacrifice rune +// destroy travel self - Wall rune +// join other self - Summon cultist rune +// travel technology other - Freeing rune // other blood travel was freedom join other + +// hide other see - Deafening rune // was destroy see hear +// destroy see other - Blinding rune +// destroy see blood - BLOOD BOIL + +// self other technology - Communication rune //was other hear blood +// join hide technology - stun rune. Rune color: bright pink. + +/obj/effect/rune/New() + ..() + var/image/blood = image(loc = src) + blood.override = 1 + for(var/mob/living/silicon/ai/AI in player_list) + AI.client.images += blood + cult_viewpoints += src + +/obj/effect/rune/Destroy() + cult_viewpoints -= src + return ..() + +/obj/effect/rune/examine(mob/user) + ..(user) + if(!iscultist(user) && !isSpirit(user)) + to_chat(user, "A strange collection of symbols drawn in blood.") + return + if(!desc) + to_chat(user, "A spell circle drawn in blood. It reads: [word1] [word2] [word3].") + else + to_chat(user, "Explosive Runes inscription in blood. It reads: [desc].") + + +/obj/effect/rune/attackby(I as obj, user as mob, params) + if(istype(I, /obj/item/weapon/tome) && iscultist(user)) + to_chat(user, "You retrace your steps, carefully undoing the lines of the rune.") + qdel(src) + return + else if(istype(I, /obj/item/weapon/nullrod)) + to_chat(user, "\blue You disrupt the vile magic with the deadening field of \the [I]!") + qdel(src) + return + return + +// This is for the seer rune, so you don't get permanent ghost sight +/obj/effect/rune/Uncrossed(atom/movable/O) + if(isliving(O)) + var/mob/living/L = O + L.update_sight() + +/obj/effect/rune/proc/get_word_string() + if(word1 == cultwords["travel"]) + if(word2 == cultwords["self"]) + return "teleport" + if(word2 == cultwords["other"]) + return "itemport" + return "[rune_to_english[word1]]_[rune_to_english[word2]]_[rune_to_english[word3]]" + + +/obj/effect/rune + var/list/effect_dictionary = list( "teleport"=/obj/effect/rune/proc/teleportRune, + "itemport"=/obj/effect/rune/proc/itemportRune, + "see_blood_hell"=/obj/effect/rune/proc/tomesummon, + "hell_destroy_other"=/obj/effect/rune/proc/armor, + "join_blood_self"=/obj/effect/rune/proc/convert, + "hell_join_self"=/obj/effect/rune/proc/tearreality, + "destroy_see_technology"=/obj/effect/rune/proc/empRune, + "travel_blood_self"=/obj/effect/rune/proc/drain, + "see_hell_join"=/obj/effect/rune/proc/seer, + "blood_join_hell"=/obj/effect/rune/proc/raise, + "hide_see_blood"=/obj/effect/rune/proc/obscureRune, + "hell_travel_self"=/obj/effect/rune/proc/ajourney, + "blood_see_travel"=/obj/effect/rune/proc/manifest, + "hell_technology_join"=/obj/effect/rune/proc/talisman, + "hell_blood_join"=/obj/effect/rune/proc/sacrifice, + "blood_see_hide"=/obj/effect/rune/proc/revealrunesrune, + "destroy_travel_self"=/obj/effect/rune/proc/wall, + "travel_technology_other"=/obj/effect/rune/proc/freedom, + "join_other_self"=/obj/effect/rune/proc/cultsummon, + "hide_other_see"=/obj/effect/rune/proc/deafen, + "destroy_see_other"=/obj/effect/rune/proc/blind, + "destroy_see_blood"=/obj/effect/rune/proc/bloodboil, + "self_other_technology"=/obj/effect/rune/proc/communicate, + "join_hide_technology"=/obj/effect/rune/proc/runestun ) + +/obj/effect/rune/attack_hand(mob/living/user as mob) + if(!iscultist(user)) + to_chat(user, "You can't mouth the arcane scratchings without fumbling over them.") + return + if(istype(user.wear_mask, /obj/item/clothing/mask/muzzle)) + to_chat(user, "You are unable to speak the words of the rune.") + return + if(user.silent) // checking if we've been muted somehow + to_chat(user, "You are unable to speak at all! You cannot say the words of the rune.") + if(!word1 || !word2 || !word3 || prob(user.getBrainLoss())) + return fizzle() + + var/word_string = get_word_string() + if(word_string in effect_dictionary) + cult_log("of type [effect_dictionary[word_string]] activated by [key_name_admin(user)].") + return call(src,effect_dictionary[word_string])() + return fizzle() + /obj/effect/rune/proc/fizzle() if(istype(src,/obj/effect/rune)) usr.say(pick("Hakkrutju gopoenjim.", "Nherasai pivroiashan.", "Firjji prhiv mazenhor.", "Tanah eh wakantahe.", "Obliyae na oraie.", "Miyf hon vnor'c.", "Wakabai hij fen juswix.")) else usr.whisper(pick("Hakkrutju gopoenjim.", "Nherasai pivroiashan.", "Firjji prhiv mazenhor.", "Tanah eh wakantahe.", "Obliyae na oraie.", "Miyf hon vnor'c.", "Wakabai hij fen juswix.")) - for (var/mob/V in viewers(src)) + for(var/mob/V in viewers(src)) V.show_message("\red The markings pulse with a small burst of light, then fall dark.", 3, "\red You hear a faint fizzle.", 2) return /obj/effect/rune/proc/check_icon() - icon = get_rune_cult(invocation) + icon = get_uristrune_cult(word1, word2, word3) /obj/item/weapon/tome name = "arcane tome" - desc = "An old, dusty tome with frayed edges and a sinister-looking cover." icon_state ="tome" - throw_speed = 2 + throw_speed = 1 throw_range = 5 w_class = 2 - var/scribereduct = 0 - var/canbypass = 0 //ADMINBUS + var/notedat = "" + var/tomedat = "" + var/list/words = list("ire" = "ire", "ego" = "ego", "nahlizet" = "nahlizet", "certum" = "certum", "veri" = "veri", "jatkaa" = "jatkaa", "balaq" = "balaq", "mgar" = "mgar", "karazet" = "karazet", "geeri" = "geeri") -/obj/item/weapon/tome/accursed - name = "accursed tome" - desc = "An arcane tome still empowered with a shadow of its former consecration." - scribereduct = 30 //faster because it's made by corrupting a bible + tomedat = {" + + + + +

The scriptures of Nar-Sie, The One Who Sees, The Geometer of Blood.

-/obj/item/weapon/tome/imbued //Admin-only tome, allows instant drawing of runes - name = "imbued arcane tome" - desc = "An arcane tome granted by the Geometer itself." - scribereduct = 50 - canbypass = 1 + The book is written in an unknown dialect, there are lots of pictures of various complex geometric shapes. You find some notes in english that give you basic understanding of the many runes written in the book. The notes give you an understanding what the words for the runes should be. However, you do not know how to write all these words in this dialect.
+ Below is the summary of the runes.
-/obj/item/weapon/tome/New() - icon_state = ticker.mode.cultdat.tome_icon - ..() +

Contents

+

+ Teleport self: Travel Self (word)
+ Teleport other: Travel Other (word)
+ Summon new tome: See Blood Hell
+ Convert a person: Join Blood Self
+ Summon Nar-Sie: Hell Join Self
+ Disable technology: Destroy See Technology
+ Drain blood: Travel Blood Self
+ Raise dead: Blood Join Hell
+ Hide runes: Hide See Blood
+ Reveal hidden runes: Blood See Hide
+ Leave your body: Hell travel self
+ Ghost Manifest: Blood See Travel
+ Imbue a talisman: Hell Technology Join
+ Sacrifice: Hell Blood Join
+ Create a wall: Destroy Travel Self
+ Summon cultist: Join Other Self
+ Free a cultist: Travel technology other
+ Deafen: Hide Other See
+ Blind: Destroy See Other
+ Blood Boil: Destroy See Blood
+ Communicate: Self Other Technology
+ Stun: Join Hide Technology
+ Summon Cultist Armor: Hell Destroy Other
+ See Invisible: See Hell Join
+

+

Rune Descriptions

+

Teleport self

+ Teleport rune is a special rune, as it only needs two words, with the third word being destination. Basically, when you have two runes with the same destination, invoking one will teleport you to the other one. If there are more than 2 runes, you will be teleported to a random one. Runes with different third words will create separate networks. You can imbue this rune into a talisman, giving you a great escape mechanism.
+

Teleport other

+ Teleport other allows for teleportation for any movable object to another rune with the same third word. You need 3 cultists chanting the invocation for this rune to work.
+

Summon new tome

+ Invoking this rune summons a new arcane tome. +

Convert a person

+ This rune opens target's mind to the realm of Nar-Sie, which usually results in this person joining the cult. However, some people (mostly the ones who posess high authority) have strong enough will to stay true to their old ideals.
+

Summon Nar-Sie

+ The ultimate rune. It summons the Avatar of Nar-Sie himself, tearing a huge hole in reality and consuming everything around it. Summoning it is the final goal of any cult.
+

Disable Technology

+ Invoking this rune creates a strong electromagnetic pulse in a small radius, making it basically analogic to an EMP grenade. You can imbue this rune into a talisman, making it a decent defensive item.
+

Drain Blood

+ This rune instantly heals you of some brute damage at the expense of a person placed on top of the rune. Whenever you invoke a drain rune, ALL drain runes on the station are activated, draining blood from anyone located on top of those runes. This includes yourself, though the blood you drain from yourself just comes back to you. This might help you identify this rune when studying words. One drain gives up to 25HP per each victim, but you can repeat it if you need more. Draining only works on living people, so you might need to recharge your "Battery" once its empty. Drinking too much blood at once might cause blood hunger.
+

Raise Dead

+ This rune allows for the resurrection of any dead person. You will need a dead human body and a living human sacrifice. Make 2 raise dead runes. Put a living, awake human on top of one, and a dead body on the other one. When you invoke the rune, the life force of the living human will be transferred into the dead body, allowing a ghost standing on top of the dead body to enter it, instantly and fully healing it. Use other runes to ensure there is a ghost ready to be resurrected.
+

Hide runes

+ This rune makes all nearby runes completely invisible. They are still there and will work if activated somehow, but you cannot invoke them directly if you do not see them.
+

Reveal runes

+ This rune is made to reverse the process of hiding a rune. It reveals all hidden runes in a rather large area around it. +

Leave your body

+ This rune gently rips your soul out of your body, leaving it intact. You can observe the surroundings as a ghost as well as communicate with other ghosts. Your body takes damage while you are there, so ensure your journey is not too long, or you might never come back.
+

Manifest a ghost

+ Unlike the Raise Dead rune, this rune does not require any special preparations or vessels. Instead of using full lifeforce of a sacrifice, it will drain YOUR lifeforce. Stand on the rune and invoke it. If theres a ghost standing over the rune, it will materialise, and will live as long as you dont move off the rune or die. You can put a paper with a name on the rune to make the new body look like that person.
+

Imbue a talisman

+ This rune allows you to imbue the magic of some runes into paper talismans. Create an imbue rune, then an appropriate rune beside it. Put an empty piece of paper on the imbue rune and invoke it. You will now have a one-use talisman with the power of the target rune. Using a talisman drains some health, so be careful with it. You can imbue a talisman with power of the following runes: summon tome, reveal, conceal, teleport, tisable technology, communicate, deafen, blind and stun.
+

Sacrifice

+ Sacrifice rune allows you to sacrifice a living thing or a body to the Geometer of Blood. Monkeys and dead humans are the most basic sacrifices, they might or might not be enough to gain His favor. A living human is what a real sacrifice should be, however, you will need 3 people chanting the invocation to sacrifice a living person. +

Create a wall

+ Invoking this rune solidifies the air above it, creating an an invisible wall. To remove the wall, simply invoke the rune again. +

Summon cultist

+ This rune allows you to summon a fellow cultist to your location. The target cultist must be unhandcuffed ant not buckled to anything. You also need to have 3 people chanting at the rune to succesfully invoke it. Invoking it takes heavy strain on the bodies of all chanting cultists.
+

Free a cultist

+ This rune unhandcuffs and unbuckles any cultist of your choice, no matter where he is. You need to have 3 people invoking the rune for it to work. Invoking it takes heavy strain on the bodies of all chanting cultists.
+

Deafen

+ This rune temporarily deafens all non-cultists around you.
+

Blind

+ This rune temporarily blinds all non-cultists around you. Very robust. Use together with the deafen rune to leave your enemies completely helpless.
+

Blood boil

+ This rune boils the blood all non-cultists in visible range. The damage is enough to instantly critically hurt any person. You need 3 cultists invoking the rune for it to work. This rune is unreliable and may cause unpredicted effect when invoked. It also drains significant amount of your health when succesfully invoked.
+

Communicate

+ Invoking this rune allows you to relay a message to all cultists on the station and nearby space objects. +

Stun

+ Unlike other runes, this ons is supposed to be used in talisman form. When invoked directly, it simply releases some dark energy, briefly stunning everyone around. When imbued into a talisman, you can force all of its energy into one person, stunning him so hard he cant even speak. However, effect wears off rather fast.
+

Equip Armor

+ When this rune is invoked, either from a rune or a talisman, it will equip the user with the armor of the followers of Nar-Sie. To use this rune to its fullest extent, make sure you are not wearing any form of headgear, armor, gloves or shoes, and make sure you are not holding anything in your hands.
+

See Invisible

+ When invoked when standing on it, this rune allows the user to see the the world beyond as long as he does not move.
+ + + "} -/obj/item/weapon/tome/examine(mob/user) - ..() - if(iscultist(user) || user.stat == DEAD) - to_chat(user, "The scriptures of [ticker.mode.cultdat.entity_title3]. Allows the scribing of runes and access to the knowledge archives of the cult of [ticker.mode.cultdat.entity_name].") - to_chat(user, "Striking another cultist with it will purge holy water from them.") - to_chat(user, "Striking a noncultist, however, will sear their flesh.") -/obj/item/weapon/tome/attack(mob/living/M, mob/living/user) - if(!istype(M)) - return - if(!iscultist(user)) - return ..() - if(iscultist(M)) - if(M.reagents && M.reagents.has_reagent("holywater")) //allows cultists to be rescued from the clutches of ordained religion - to_chat(user, "You remove the taint from [M].") - var/holy2unholy = M.reagents.get_reagent_amount("holywater") - M.reagents.del_reagent("holywater") - M.reagents.add_reagent("unholywater",holy2unholy) - add_logs(user, M, "smacked", src, " removing the holy water from them") - return - M.take_organ_damage(0, 15) //Used to be a random between 5 and 20 - playsound(M, 'sound/weapons/sear.ogg', 50, 1) - M.visible_message("[user] strikes [M] with the arcane tome!", \ - "[user] strikes you with the tome, searing your flesh!") - flick("tome_attack", src) - user.do_attack_animation(M) - add_logs(user, M, "smacked", src) - -/obj/item/weapon/tome/attack_self(mob/user) - if(!iscultist(user)) - to_chat(user, "[src] seems full of unintelligible shapes, scribbles, and notes. Is this some sort of joke?") - return - open_tome(user) - -/obj/item/weapon/tome/proc/open_tome(mob/user) - var/choice = alert(user,"You open the tome...",,"Scribe Rune","More Information","Cancel") - switch(choice) - if("More Information") - read_tome(user) - if("Scribe Rune") - scribe_rune(user) - if("Cancel") + Topic(href,href_list[]) + if(src.loc == usr) + var/number = text2num(href_list["number"]) + if(usr.stat|| usr.restrained()) + return + switch(href_list["action"]) + if("clear") + words[words[number]] = words[number] + if("change") + words[words[number]] = input("Enter the translation for [words[number]]", "Word notes") in engwords + for(var/w in words) + if((words[w] == words[words[number]]) && (w != words[number])) + words[w] = w + notedat = {" +
Word translation notes
+ [words[1]] is [words[words[1]]] Clear
+ [words[2]] is [words[words[2]]] Clear
+ [words[3]] is [words[words[3]]] Clear
+ [words[4]] is [words[words[4]]] Clear
+ [words[5]] is [words[words[5]]] Clear
+ [words[6]] is [words[words[6]]] Clear
+ [words[7]] is [words[words[7]]] Clear
+ [words[8]] is [words[words[8]]] Clear
+ [words[9]] is [words[words[9]]] Clear
+ [words[10]] is [words[words[10]]] Clear
+ "} + usr << browse("[notedat]", "window=notes") +// call(/obj/item/weapon/tome/proc/edit_notes)() + else + usr << browse(null, "window=notes") return -/obj/item/weapon/tome/proc/read_tome(mob/user) - var/text = list() - text = jointext(text, "
Archives of [ticker.mode.cultdat.entity_title1]



") - text = jointext(text, "A rune's name and effects can be revealed by examining the rune.<

") - text = jointext(text, "Rite of Binding
This rune is one of the most important runes the cult has, being the only way to create new talismans. A blank sheet of paper must be on top of the rune. After \ - invoking it and choosing which talisman you desire, the paper will be converted, after some delay into a talisman.

") +// proc/edit_notes() FUCK IT. Cant get it to work properly. - K0000 +// to_chat(world, "its been called! [usr]") +// notedat = {" +//
Word translation notes
+// [words[1]] is [words[words[1]]] Clear
+// [words[2]] is [words[words[2]]] Clear
+// [words[3]] is [words[words[3]]] Clear
+// [words[4]] is [words[words[4]]] Clear
+// [words[5]] is [words[words[5]]] Clear
+// [words[6]] is [words[words[6]]] Clear
+// [words[7]] is [words[words[7]]] Clear
+// [words[8]] is [words[words[8]]] Clear
+// [words[9]] is [words[words[9]]] Clear
+// [words[10]] is [words[words[10]]] Clear
+// "} +// to_chat(usr, "whatev") +// usr << browse(null, "window=tank") - text = jointext(text, "Teleport
This rune is unique in that it requires a keyword before the scribing can begin. When invoked, it will find any other Teleport runes; \ - If any are found, the user can choose which rune to send to. Upon activation, the rune teleports everything above it to the selected rune.

") + attack(mob/living/M as mob, mob/living/user as mob) - text = jointext(text, "Rite of Enlightenment
This rune is critical to the success of the cult. It will allow you to convert normal crew members into cultists. \ - To do this, simply place the crew member upon the rune and invoke it. This rune requires two invokers to use. If the target to be converted is loyalty-implanted or a certain assignment, they will \ - be unable to be converted. People [ticker.mode.cultdat.entity_title3] wishes sacrificed will also be ineligible for conversion, and anyone with a shielding presence like the null rod will not be converted.
\ - Successful conversions will produce a tome for the new cultist.

") + M.attack_log += text("\[[time_stamp()]\] Has had the [name] used on him by [key_name(user)]") + user.attack_log += text("\[[time_stamp()]\] Used [name] on [key_name(M)]") + msg_admin_attack("[key_name_admin(user)] used [name] on [key_name_admin(M)]") + if(!iscarbon(M)) + M.LAssailant = null + else + M.LAssailant = user + if(istype(M,/mob/dead)) + M.invisibility = 0 + user.visible_message( \ + "\red [user] drags the ghost to our plan of reality!", \ + "\red You drag the ghost to our plan of reality!" \ + ) + return + if(!istype(M)) + return + if(!iscultist(user)) + return ..() + if(iscultist(M)) + if(M.reagents && M.reagents.has_reagent("holywater")) //allows cultists to be rescued from the clutches of ordained religion + to_chat(user, "You remove the taint from [M].") + var/holy2unholy = M.reagents.get_reagent_amount("holywater") + M.reagents.del_reagent("holywater") + M.reagents.add_reagent("unholywater",holy2unholy) + add_logs(user, M, "smacked", src, " removing the holy water from them") + return + M.take_organ_damage(0,rand(5,20)) //really lucky - 5 hits for a crit + for(var/mob/O in viewers(M, null)) + O.show_message(text("[] beats [] with the arcane tome!", user, M), 1) + to_chat(M, "\red You feel searing heat inside!") - text = jointext(text, "Rite of Tribute
This rune is necessary to achieve your goals. Simply place any dead creature upon the rune and invoke it (this will not \ - target cultists!). If this creature has a mind, a soulstone will be created and the creature's soul transported to it. Sacrificing the dead can be done alone, but sacrificing living crew or your cult's target will require 3 cultists. \ - Soulstones used on construct shells will move that soul into a powerful construct of your choice.

") - text = jointext(text, "Rite of Resurrection
This rune requires two corpses. To perform the ritual, place the corpse you wish to revive onto \ - the rune and the offering body adjacent to it. When the rune is invoked, the body to be sacrificed will turn to dust, the life force flowing into the revival target. Assuming the target is not moved \ - within a few seconds, they will be brought back to life, healed of all ailments.

") + attack_self(mob/living/user as mob) + usr = user + if(!usr.canmove || usr.stat || usr.restrained()) + return - text = jointext(text, "Rite of Disruption
Robotic lifeforms have time and time again been the downfall of fledgling cults. This rune may allow you to gain the upper \ - hand against these pests. By using the rune, a large electromagnetic pulse will be emitted from the rune's location. The size of the EMP will grow significantly for each additional adjacent cultist when the \ - rune is activated.

") + if(!cultwords["travel"]) + runerandom() + if(iscultist(user)) + var/C = 0 + for(var/obj/effect/rune/N in world) + C++ + if(!istype(user.loc,/turf)) + to_chat(user, "\red You do not have enough space to write a proper rune.") + return - text = jointext(text, "Astral Communion
This rune is perhaps the most ingenious rune that is usable by a single person. Upon invoking the rune, the \ - user's spirit will be ripped from their body. In this state, the user's physical body will be locked in place to the rune itself - any attempts to move it will result in the rune pulling it back. \ - The body will also take constant damage while in this form, and may even die. The user's spirit will contain their consciousness, and will allow them to freely wander the station as a ghost. This may \ - also be used to commune with the dead.

") - text = jointext(text, "Rite of the Corporeal Shield
While simple, this rune serves an important purpose in defense and hindering passage. When invoked, the \ - rune will draw a small amount of life force from the user and make the space above the rune completely dense, rendering it impassable to all but the most complex means. The rune may be invoked again to \ - undo this effect and allow passage again.

") - text = jointext(text,"Rite of Joined Souls
This rune allows the cult to free other cultists with ease. When invoked, it will allow the user to summon a single cultist to the rune from \ - any location. It requires two invokers, and will damage each invoker slightly.

") - text = jointext(text, "Blood Boil
When invoked, this rune will do a massive amount of damage to all non-cultist viewers, but it will also emit a small explosion upon invocation. \ - It requires three invokers.

") - - text = jointext(text, "Leeching
When invoked, this rune will transfer lifeforce from the victim to the invoker.

") - - text = jointext(text, "Rite of Spectral Manifestation
This rune allows you to summon spirits as humanoid fighters. When invoked, a spirit above the rune will be brought to life as a human, wearing nothing, that seeks only to serve you and [ticker.mode.cultdat.entity_title3]. \ - However, the spirit's link to reality is fragile - you must remain on top of the rune, and you will slowly take damage. Upon stepping off the rune, all summoned spirits will dissipate, dropping their items to the ground. You may manifest \ - multiple spirits with one rune, but you will rapidly take damage in doing so.

") - - text = jointext(text, "Ritual of Dimensional Rending
This rune is necessary to achieve your goals. On attempting to scribe it, it will produce shields around you and alert everyone you are attempting to scribe it; it takes a very long time to scribe, \ - and does massive damage to the one attempting to scribe it.
Invoking it requires 9 invokers and the sacrifice of a specific crewmember, and once invoked, will summon [ticker.mode.cultdat.entity_title3], [ticker.mode.cultdat.entity_name]. \ - This will complete your objectives.


") - - text = jointext(text, "Talisman of Teleportation
The talisman form of the Teleport rune will transport the invoker to a selected Teleport rune once.

") - - text = jointext(text, "Talisman of Fabrication
This talisman is the main way of creating construct shells. To use it, one must strike 30 sheets of metal with the talisman. The sheets will then be twisted into a construct shell, ready to recieve a soul to occupy it.

") - - text = jointext(text, "Talisman of Tome Summoning
This talisman will produce a single tome at your feet.

") - - text = jointext(text, "Talisman of Veiling/Revealing
This talisman will hide runes on its first use, and on the second, will reveal runes.

") - - text = jointext(text, "Talisman of Disguising
This talisman will permanently disguise all nearby runes as crayon runes.

") - - text = jointext(text, "Talisman of Electromagnetic Pulse
This talisman will EMP anything else nearby. It disappears after one use.

") - - text = jointext(text, "Talisman of Stunning
Attacking a target will knock them down for a long duration in addition to inhibiting their speech. \ - Robotic lifeforms will suffer the effects of a heavy electromagnetic pulse instead.

") - - text = jointext(text, "Talisman of Armaments
The Talisman of Arming will equip the user with armored robes, a backpack, an eldritch longsword, an empowered bola, and a pair of boots. Any items that cannot \ - be equipped will not be summoned. Attacking a fellow cultist with it will instead equip them.

") - - text = jointext(text, "Talisman of Horrors
The Talisman of Horror must be applied directly to the victim, it will shatter your victim's mind with visions of the endtimes that may incapitate them.

") - - text = jointext(text, "Talisman of Shackling
The Talisman of Shackling must be applied directly to the victim, it has 4 uses and cuffs victims with magic shackles that disappear when removed.

") - - text = jointext(text, "In addition to these runes, the cult has a small selection of equipment and constructs.

") - - text = jointext(text, "Equipment:

") - - text = jointext(text, "Cult Blade
Cult blades are sharp weapons that, notably, cannot be used by noncultists. These blades are produced by the Talisman of Arming.

") - - text = jointext(text, "Cult Bola
Cult bolas are strong bolas, useful for snaring targets. These bolas are produced by the Talisman of Arming.

") - - text = jointext(text, "Cult Robes
Cult robes are heavily armored robes. These robes are produced by the Talisman of Arming.

") - - text = jointext(text, "Soulstone
A soulstone is a simple piece of magic, produced either via the starter talisman or by sacrificing humans. Using it on an unconscious or dead human, or on a Shade, will trap their soul in the stone, allowing its use in construct shells. \ -
The soul within can also be released as a Shade by using it in-hand.

") - - text = jointext(text, "Construct Shell
A construct shell is useless on its own, but placing a filled soulstone within it allows you to produce your choice of a Wraith, a Juggernaut, or an Artificer. \ -
Each construct has uses, detailed below in Constructs. Construct shells can be produced via the starter talisman or the Rite of Fabrication.

") - - text = jointext(text, "Constructs:

") - - text = jointext(text, "Shade
While technically not a construct, the Shade is produced when released from a soulstone. It is quite fragile and has weak melee attacks, but is fully healed when recaptured by a soulstone.

") - - text = jointext(text, "Wraith
The Wraith is a fast, lethal melee attacker which can jaunt through walls. However, it is only slightly more durable than a shade.

") - - text = jointext(text, "Juggernaut
The Juggernaut is a slow, but durable, melee attacker which can produce temporary forcewalls. It will also reflect most lethal energy weapons.

") - - text = jointext(text,"Artificer
The Artificer is a weak and fragile construct, able to heal other constructs, produce more soulstones and construct shells, \ - construct fortifying cult walls and flooring, and finally, it can release a few indiscriminate stunning missiles.

") - - text = jointext(text, "Harvester
If you see one, know that you have done all you can and your life is void.

") - - var/datum/browser/popup = new(user, "tome", "", 800, 600) - popup.set_content(text) - popup.open() - return 1 - -/obj/item/weapon/tome/proc/finale_runes_ok(mob/living/user,/obj/effect/rune/rune_to_scribe) - - if(ticker.mode.name == "cult") - if(!canbypass == 1)//not an admin-tome, check things - var/datum/game_mode/cult/cult_mode = ticker.mode - if(!cult_mode.narsie_condition_cleared) - to_chat(user, "There is still more to do before unleashing [cult_mode.cultdat.entity_name] power!") - return 0 - if(!cult_mode.eldergod) - to_chat(user, "\"I am already here. There is no need to try to summon me now.\"") - return 0 - if(cult_mode.demons_summoned) - to_chat(user, "\"We are already here. There is no need to try to summon us now.\"") - return 0 - if(!(CULT_ELDERGOD in cult_mode.objectives) || !(CULT_SLAUGHTER in cult_mode.objectives)) - to_chat(user, "[cult_mode.cultdat.entity_name]'s power does not wish to be unleashed!") - return 0 - var/confirm_final = alert(user, "This is the FINAL step to summon your dietys power, it is a long, painful ritual and the crew will be alerted to your presence", "Are you prepared for the final battle?", "My life for Nar-Sie!", "No") - if(confirm_final == "No") - to_chat(user, "You decide to prepare further before scribing the rune.") + if(C>=26+runedec+ticker.mode.cult.len) //including the useless rune at the secret room, shouldn't count against the limit of 25 runes - Urist + alert("The cloth of reality can't take that much of a strain. Remove some runes first!") return else - return 1 - else//the game mode is not cult..but we ARE a cultist...ALL ON THE ADMINBUS - if(!canbypass == 1)//not an admin-tome, check things - var/confirm_final = alert(user, "This is the FINAL step to summon your dietys power, it is a long, painful ritual and the crew will be alerted to your presence", "Are you prepared for the final battle?", "My life for Nar-Sie!", "No") - if(confirm_final == "No") - to_chat(user, "You decide to prepare further before scribing the rune.") - return 0 - else - return 1 + switch(alert("You open the tome",,"Read it","Scribe a rune", "Notes")) //Fuck the "Cancel" option. Rewrite the whole tome interface yourself if you want it to work better. And input() is just ugly. - K0000 + if("Cancel") + return + if("Read it") + if(usr.get_active_hand() != src) + return + user << browse("[tomedat]", "window=Arcane Tome") + return + if("Notes") + if(usr.get_active_hand() != src) + return + notedat = {" +
Word translation notes
+ [words[1]] is [words[words[1]]] Clear
+ [words[2]] is [words[words[2]]] Clear
+ [words[3]] is [words[words[3]]] Clear
+ [words[4]] is [words[words[4]]] Clear
+ [words[5]] is [words[words[5]]] Clear
+ [words[6]] is [words[words[6]]] Clear
+ [words[7]] is [words[words[7]]] Clear
+ [words[8]] is [words[words[8]]] Clear
+ [words[9]] is [words[words[9]]] Clear
+ [words[10]] is [words[words[10]]] Clear
+ "} +// call(/obj/item/weapon/tome/proc/edit_notes)() + user << browse("[notedat]", "window=notes") + return + if(usr.get_active_hand() != src) + return -/obj/item/weapon/tome/proc/scribe_rune(mob/living/user) - var/turf/runeturf = get_turf(user) - var/chosen_keyword - var/obj/effect/rune/rune_to_scribe - var/entered_rune_name - var/list/possible_runes = list() - var/list/shields = list() - if(locate(/obj/effect/rune) in runeturf) - to_chat(user, "There is already a rune here.") - return - for(var/T in subtypesof(/obj/effect/rune) - /obj/effect/rune/malformed) - var/obj/effect/rune/R = T - if(initial(R.cultist_name)) - possible_runes.Add(initial(R.cultist_name)) //This is to allow the menu to let cultists select runes by name rather than by object path. I don't know a better way to do this - if(!possible_runes.len) - return - entered_rune_name = input(user, "Choose a rite to scribe.", "Sigils of Power") as null|anything in possible_runes - if(!Adjacent(user) || !src || qdeleted(src) || user.incapacitated()) - return - for(var/T in typesof(/obj/effect/rune)) - var/obj/effect/rune/R = T - if(initial(R.cultist_name) == entered_rune_name) - rune_to_scribe = R - if(initial(R.req_keyword)) - var/the_keyword = stripped_input(usr, "Please enter a keyword for the rune.", "Enter Keyword", "") - if(!the_keyword) + var/list/dictionary = list ( + "convert" = list("join","blood","self"), + "wall" = list("destroy","travel","self"), + "blood boil" = list("destroy","see","blood"), + "blood drain" = list("travel","blood","self"), + "raise dead" = list("blood","join","hell"), + "summon narsie" = list("hell","join","self"), + "communicate" = list("self","other","technology"), + "emp" = list("destroy","see","technology"), + "manifest" = list("blood","see","travel"), + "summon tome" = list("see","blood","hell"), + "see invisible" = list("see","hell","join"), + "hide" = list("hide","see","blood"), + "reveal" = list("blood","see","hide"), + "astral journey" = list("hell","travel","self"), + "imbue" = list("hell","technology","join"), + "sacrifice" = list("hell","blood","join"), + "summon cultist" = list("join","other","self"), + "free cultist" = list("travel","technology","other"), + "deafen" = list("hide","other","see"), + "blind" = list("destroy","see","other"), + "stun" = list("join","hide","technology"), + "armor" = list("hell","destroy","other"), + "teleport" = list("travel","self"), + "teleport other" = list("travel","other") + ) + + var/list/english = list() + + var/list/scribewords = list("none") + + for(var/entry in words) + if(words[entry] != entry) + english += list(words[entry] = entry) + + for(var/entry in dictionary) + var/list/required = dictionary[entry] + if(length(english&required) == required.len) + scribewords += entry + + var/chosen_rune = null + + if(usr) + chosen_rune = input ("Choose a rune to scribe.") in scribewords + if(!chosen_rune) return - chosen_keyword = the_keyword - break - if(!rune_to_scribe) - return - runeturf = get_turf(user) //we may have moved. adjust as needed... - if(locate(/obj/effect/rune) in runeturf) - to_chat(user, "There is already a rune here.") - return - if(!Adjacent(user) || !src || qdeleted(src) || user.incapacitated()) - return - if(ispath(rune_to_scribe, /obj/effect/rune/narsie) || ispath(rune_to_scribe, /obj/effect/rune/slaughter))//may need to change this - Fethas - if(finale_runes_ok(user,rune_to_scribe)) - command_announcement.Announce("Figments from an eldritch god are being summoned somwhere on the station from an unknown dimension. Disrupt the ritual at all costs!","Central Command Higher Dimensionsal Affairs", 'sound/AI/spanomalies.ogg') - for(var/B in spiral_range_turfs(1, user, 1)) - var/turf/T = B - var/obj/machinery/shield/N = new(T) - N.name = "Rune-Scriber's Shield" - N.desc = "A potent shield summoned by cultists to protect them while they prepare the final ritual" - N.icon_state = "shield-cult" - N.health = 60 - shields |= N + if(chosen_rune == "none") + to_chat(user, "\red You decide against scribing a rune, perhaps you should take this time to study your notes.") + return + if(chosen_rune == "teleport") + dictionary[chosen_rune] += input ("Choose a destination word") in english + if(chosen_rune == "teleport other") + dictionary[chosen_rune] += input ("Choose a destination word") in english - var/mob/living/carbon/human/H = user - var/dam_zone = pick("head", "chest", "groin", "l_arm", "l_hand", "r_arm", "r_hand", "l_leg", "l_foot", "r_leg", "r_foot") - var/obj/item/organ/external/affecting = H.get_organ(ran_zone(dam_zone)) - user.visible_message("[user] cuts open their \The [affecting] and begins writing in their own blood!", "You slice open your [affecting] and begin drawing a sigil of [ticker.mode.cultdat.entity_title3].") - user.apply_damage(initial(rune_to_scribe.scribe_damage), BRUTE , affecting) - if(!do_after(user, initial(rune_to_scribe.scribe_delay)-scribereduct, target = get_turf(user))) - for(var/V in shields) - var/obj/machinery/shield/S = V - if(S && !qdeleted(S)) - qdel(S) - return - if(locate(/obj/effect/rune) in runeturf) - to_chat(user, "There is already a rune here.") - return - user.visible_message("[user] creates a strange circle in their own blood.", \ - "You finish drawing the arcane markings of [ticker.mode.cultdat.entity_title3].") - for(var/V in shields) - var/obj/machinery/shield/S = V - if(S && !qdeleted(S)) - qdel(S) - var/obj/effect/rune/R = new rune_to_scribe(runeturf, chosen_keyword) - R.blood_DNA = list() - R.blood_DNA[H.dna.unique_enzymes] = H.dna.b_type - R.add_hiddenprint(H) - to_chat(user, "The [lowertext(initial(rune_to_scribe.cultist_name))] rune [initial(rune_to_scribe.cultist_desc)]") + if(usr.get_active_hand() != src) + return + + for(var/mob/V in viewers(src)) + V.show_message("\red [user] slices open a finger and begins to chant and paint symbols on the floor.", 3, "\red You hear chanting.", 2) + to_chat(user, "\red You slice open one of your fingers and begin drawing a rune on the floor whilst chanting the ritual that binds your life essence with the dark arcane energies flowing through the surrounding world.") + user.take_overall_damage((rand(9)+1)/10) // 0.1 to 1.0 damage + if(do_after(user, 50, target = user)) + if(usr.get_active_hand() != src) + return + var/mob/living/carbon/human/H = user + var/obj/effect/rune/R = new /obj/effect/rune(user.loc) + to_chat(user, "\red You finish drawing the arcane markings of the Geometer.") + var/list/required = dictionary[chosen_rune] + R.word1 = english[required[1]] + R.word2 = english[required[2]] + R.word3 = english[required[3]] + R.check_icon() + R.blood_DNA = list() + R.blood_DNA[H.dna.unique_enzymes] = H.dna.b_type + R.add_hiddenprint(H) + return + else + to_chat(user, "The book seems full of illegible scribbles. Is this a joke?") + return + + attackby(obj/item/weapon/tome/T as obj, mob/living/user as mob, params) + if(istype(T, /obj/item/weapon/tome)) // sanity check to prevent a runtime error + switch(alert("Copy the runes from your tome?",,"Copy", "Cancel")) + if("cancel") + return + // var/list/nearby = viewers(1,src) //- Fuck this as well. No clue why this doesnt work. -K0000 + // if(T.loc != user) + // return + // for(var/mob/M in nearby) + // if(M == user) + for(var/entry in words) + words[entry] = T.words[entry] + to_chat(user, "You copy the translation notes from your tome.") + + + examine(mob/user) + if(!iscultist(user)) + to_chat(user, "An old, dusty tome with frayed edges and a sinister looking cover.") + else + to_chat(user, "The scriptures of Nar-Sie, The One Who Sees, The Geometer of Blood. Contains the details of every ritual his followers could think of. Most of these are useless, though.") + +/obj/item/weapon/tome/imbued //admin tome, spawns working runes without waiting + w_class = 2 + var/cultistsonly = 1 + attack_self(mob/user as mob) + if(src.cultistsonly && !iscultist(usr)) + return + if(!cultwords["travel"]) + runerandom() + if(user) + var/r + if(!istype(user.loc,/turf)) + to_chat(user, "\red You do not have enough space to write a proper rune.") + var/list/runes = list("teleport", "itemport", "tome", "armor", "convert", "tear in reality", "emp", "drain", "seer", "raise", "obscure", "reveal", "astral journey", "manifest", "imbue talisman", "sacrifice", "wall", "freedom", "cultsummon", "deafen", "blind", "bloodboil", "communicate", "stun") + r = input("Choose a rune to scribe", "Rune Scribing") in runes //not cancellable. + var/obj/effect/rune/R = new /obj/effect/rune + if(istype(user, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = user + R.blood_DNA = list() + R.blood_DNA[H.dna.unique_enzymes] = H.dna.b_type + switch(r) + if("teleport") + var/list/words = list("ire", "ego", "nahlizet", "certum", "veri", "jatkaa", "balaq", "mgar", "karazet", "geeri") + var/beacon + if(usr) + beacon = input("Select the last rune", "Rune Scribing") in words + R.word1=cultwords["travel"] + R.word2=cultwords["self"] + R.word3=beacon + R.loc = user.loc + R.check_icon() + if("itemport") + var/list/words = list("ire", "ego", "nahlizet", "certum", "veri", "jatkaa", "balaq", "mgar", "karazet", "geeri") + var/beacon + if(usr) + beacon = input("Select the last rune", "Rune Scribing") in words + R.word1=cultwords["travel"] + R.word2=cultwords["other"] + R.word3=beacon + R.loc = user.loc + R.check_icon() + if("tome") + R.word1=cultwords["see"] + R.word2=cultwords["blood"] + R.word3=cultwords["hell"] + R.loc = user.loc + R.check_icon() + if("armor") + R.word1=cultwords["hell"] + R.word2=cultwords["destroy"] + R.word3=cultwords["other"] + R.loc = user.loc + R.check_icon() + if("convert") + R.word1=cultwords["join"] + R.word2=cultwords["blood"] + R.word3=cultwords["self"] + R.loc = user.loc + R.check_icon() + if("tear in reality") + R.word1=cultwords["hell"] + R.word2=cultwords["join"] + R.word3=cultwords["self"] + R.loc = user.loc + R.check_icon() + if("emp") + R.word1=cultwords["destroy"] + R.word2=cultwords["see"] + R.word3=cultwords["technology"] + R.loc = user.loc + R.check_icon() + if("drain") + R.word1=cultwords["travel"] + R.word2=cultwords["blood"] + R.word3=cultwords["self"] + R.loc = user.loc + R.check_icon() + if("seer") + R.word1=cultwords["see"] + R.word2=cultwords["hell"] + R.word3=cultwords["join"] + R.loc = user.loc + R.check_icon() + if("raise") + R.word1=cultwords["blood"] + R.word2=cultwords["join"] + R.word3=cultwords["hell"] + R.loc = user.loc + R.check_icon() + if("obscure") + R.word1=cultwords["hide"] + R.word2=cultwords["see"] + R.word3=cultwords["blood"] + R.loc = user.loc + R.check_icon() + if("astral journey") + R.word1=cultwords["hell"] + R.word2=cultwords["travel"] + R.word3=cultwords["self"] + R.loc = user.loc + R.check_icon() + if("manifest") + R.word1=cultwords["blood"] + R.word2=cultwords["see"] + R.word3=cultwords["travel"] + R.loc = user.loc + R.check_icon() + if("imbue talisman") + R.word1=cultwords["hell"] + R.word2=cultwords["technology"] + R.word3=cultwords["join"] + R.loc = user.loc + R.check_icon() + if("sacrifice") + R.word1=cultwords["hell"] + R.word2=cultwords["blood"] + R.word3=cultwords["join"] + R.loc = user.loc + R.check_icon() + if("reveal") + R.word1=cultwords["blood"] + R.word2=cultwords["see"] + R.word3=cultwords["hide"] + R.loc = user.loc + R.check_icon() + if("wall") + R.word1=cultwords["destroy"] + R.word2=cultwords["travel"] + R.word3=cultwords["self"] + R.loc = user.loc + R.check_icon() + if("freedom") + R.word1=cultwords["travel"] + R.word2=cultwords["technology"] + R.word3=cultwords["other"] + R.loc = user.loc + R.check_icon() + if("cultsummon") + R.word1=cultwords["join"] + R.word2=cultwords["other"] + R.word3=cultwords["self"] + R.loc = user.loc + R.check_icon() + if("deafen") + R.word1=cultwords["hide"] + R.word2=cultwords["other"] + R.word3=cultwords["see"] + R.loc = user.loc + R.check_icon() + if("blind") + R.word1=cultwords["destroy"] + R.word2=cultwords["see"] + R.word3=cultwords["other"] + R.loc = user.loc + R.check_icon() + if("bloodboil") + R.word1=cultwords["destroy"] + R.word2=cultwords["see"] + R.word3=cultwords["blood"] + R.loc = user.loc + R.check_icon() + if("communicate") + R.word1=cultwords["self"] + R.word2=cultwords["other"] + R.word3=cultwords["technology"] + R.loc = user.loc + R.check_icon() + if("stun") + R.word1=cultwords["join"] + R.word2=cultwords["hide"] + R.word3=cultwords["technology"] + R.loc = user.loc + R.check_icon() diff --git a/code/game/gamemodes/cult/runes.dm b/code/game/gamemodes/cult/runes.dm index 50b659cfd3d..ff08b31e700 100644 --- a/code/game/gamemodes/cult/runes.dm +++ b/code/game/gamemodes/cult/runes.dm @@ -1,1002 +1,1046 @@ -/var/list/sacrificed = list() -var/list/non_revealed_runes = (subtypesof(/obj/effect/rune) - /obj/effect/rune/malformed) - -/* -This file contains runes. -Runes are used by the cult to cause many different effects and are paramount to their success. -They are drawn with an arcane tome in blood, and are distinguishable to cultists and normal crew by examining. -Fake runes can be drawn in crayon to fool people. -Runes can either be invoked by one's self or with many different cultists. Each rune has a specific incantation that the cultists will say when invoking it. -To draw a rune, use an arcane tome. -*/ - -/obj/effect/rune - name = "rune" - var/cultist_name = "basic rune" - desc = "An odd collection of symbols drawn in what seems to be blood." - var/cultist_desc = "a basic rune with no function." //This is shown to cultists who examine the rune in order to determine its true purpose. - anchored = 1 - icon = 'icons/obj/rune.dmi' - icon_state = "1" - var/visibility = 0 - var/view_range = 7 - unacidable = 1 - layer = TURF_LAYER - - var/invocation = "Aiy ele-mayo!" //This is said by cultists when the rune is invoked. - var/req_cultists = 1 //The amount of cultists required around the rune to invoke it. If only 1, any cultist can invoke it. - var/rune_in_use = 0 // Used for some runes, this is for when you want a rune to not be usable when in use. - - var/scribe_delay = 50 //how long the rune takes to create - var/scribe_damage = 0.1 //how much damage you take doing it - - var/allow_excess_invokers = 0 //if we allow excess invokers when being invoked - var/construct_invoke = 1 //if constructs can invoke it - - var/req_keyword = 0 //If the rune requires a keyword - go figure amirite - var/keyword //The actual keyword for the rune +var/list/sacrificed = list() -/obj/effect/rune/New(loc, set_keyword) - ..() - if(set_keyword) - keyword = set_keyword - check_icon() - var/image/blood = image(loc = src) - blood.override = 1 - for(var/mob/living/silicon/ai/AI in player_list) - AI.client.images += blood +/////////////////////////////////////////FIRST RUNE +/obj/effect/rune/proc/teleportRune() + return teleport(src.word3) -/obj/effect/rune/examine(mob/user) - ..() - if(iscultist(user) || user.stat == DEAD) //If they're a cultist or a ghost, tell them the effects - to_chat(user, "Name: [cultist_name]") - to_chat(user, "Effects: [capitalize(cultist_desc)]") - to_chat(user, "Required Acolytes: [req_cultists]") - if(req_keyword && keyword) - to_chat(user, "Keyword: [keyword]") - -/obj/effect/rune/attackby(obj/I, mob/user, params) - if(istype(I, /obj/item/weapon/tome) && iscultist(user)) - to_chat(user, "You carefully erase the [lowertext(cultist_name)] rune.") - qdel(src) - return - else if(istype(I, /obj/item/weapon/nullrod)) - if(iscultist(user))//cultist..what are doing..cultist..staph... - user.drop_item() - user.visible_message("[I] suddenly glows with white light, forcing [user] to drop it in pain!", \ - "[I] suddenly glows with a white light that sears your hand, forcing you to drop it!") - return - to_chat(user,"You disrupt the magic of [src] with [I].") - qdel(src) - return - -/obj/effect/rune/attack_hand(mob/living/user) - if(!iscultist(user)) - to_chat(user, "You aren't able to understand the words of [src].") - return - var/list/invokers = can_invoke(user) - if(invokers.len >= req_cultists) - invoke(invokers) - else - fail_invoke(user) - - -/obj/effect/rune/attack_animal(mob/living/simple_animal/M) - if(istype(M, /mob/living/simple_animal/shade) || istype(M, /mob/living/simple_animal/hostile/construct)) - if(construct_invoke || !iscultist(M)) //if you're not a cult construct we want the normal fail message - attack_hand(M) - else - to_chat(M, "You are unable to invoke the rune!") - -/obj/effect/rune/proc/talismanhide() //for talisman of revealing/hiding - visible_message("[src] fades away.") - invisibility = INVISIBILITY_OBSERVER - alpha = 100 //To help ghosts distinguish hidden runes - -/obj/effect/rune/proc/talismanreveal() //for talisman of revealing/hiding - invisibility = 0 - visible_message("[src] suddenly appears!") - alpha = initial(alpha) - -/obj/effect/rune/proc/talismanfake() //for rune disguising - var/runenum = pick(1,2,3,4,5,6) - visible_message("[src] takes on a waxy apperance!") - icon = 'icons/effects/crayondecal.dmi' - icon_state = "rune[runenum]" - color = rgb(255, 0, 0) - -/* -There are a few different procs each rune runs through when a cultist activates it. -can_invoke() is called when a cultist activates the rune with an empty hand. If there are multiple cultists, this rune determines if the required amount is nearby. -invoke() is the rune's actual effects. -fail_invoke() is called when the rune fails, via not enough people around or otherwise. Typically this just has a generic 'fizzle' effect. -structure_check() searches for nearby cultist structures required for the invocation. Proper structures are pylons, forges, archives, and altars. -*/ - -/obj/effect/rune/proc/can_invoke(var/mob/living/user) - //This proc determines if the rune can be invoked at the time. If there are multiple required cultists, it will find all nearby cultists. - var/list/invokers = list() //people eligible to invoke the rune - var/list/chanters = list() //people who will actually chant the rune when passed to invoke() - if(user) - chanters |= user - invokers |= user - if(req_cultists > 1 || allow_excess_invokers) - for(var/mob/living/L in range(1, src)) - if(iscultist(L)) - if(L == user) - continue - if(ishuman(L)) - var/mob/living/carbon/human/H = L - if(!H.can_speak()) - continue - if(L.stat) - continue - invokers |= L - if(invokers.len >= req_cultists) - if(allow_excess_invokers) - chanters |= invokers - else - invokers -= user - shuffle(invokers) - for(var/i in 0 to req_cultists) - var/L = pick_n_take(invokers) - chanters |= L - return chanters - -/obj/effect/rune/proc/invoke(var/list/invokers) - //This proc contains the effects of the rune as well as things that happen afterwards. If you want it to spawn an object and then delete itself, have both here. - if(invocation) - for(var/M in invokers) - var/mob/living/L = M - L.say(invocation) - L.changeNext_move(CLICK_CD_MELEE)//THIS IS WHY WE CAN'T HAVE NICE THINGS - do_invoke_glow() - -/obj/effect/rune/proc/do_invoke_glow() - var/oldtransform = transform - spawn(0) //animate is a delay, we want to avoid being delayed - animate(src, transform = matrix()*2, alpha = 0, time = 5) //fade out - animate(transform = oldtransform, alpha = 255, time = 0) - -/obj/effect/rune/proc/fail_invoke(var/mob/living/user) - //This proc contains the effects of a rune if it is not invoked correctly, through either invalid wording or not enough cultists. By default, it's just a basic fizzle. - visible_message("The markings pulse with a small flash of red light, then fall dark.") - spawn(0) //animate is a delay, we want to avoid being delayed - animate(src, color = rgb(255, 0, 0), time = 0) - animate(src, color = initial(color), time = 5) - -//Malformed Rune: This forms if a rune is not drawn correctly. Invoking it does nothing but hurt the user. -/obj/effect/rune/malformed - cultist_name = "malformed rune" - cultist_desc = "a senseless rune written in gibberish. No good can come from invoking this." - invocation = "Ra'sha yoka!" - -/obj/effect/rune/malformed/invoke(var/list/invokers) - ..() - for(var/M in invokers) - var/mob/living/L = M - to_chat(M, "You feel your life force draining. [ticker.mode.cultdat.entity_title3] is displeased.") - L.apply_damage(30, BRUTE) - qdel(src) - -/mob/proc/null_rod_check() //The null rod, if equipped, will protect the holder from the effects of most runes - var/obj/item/weapon/nullrod/N = locate() in src - if(N) - return N - return 0 - -//Rite of Binding: A paper on top of the rune to a talisman. -/obj/effect/rune/imbue - cultist_name = "Rite of Binding" - cultist_desc = "transforms paper into powerful magic talismans." - invocation = "H'drak v'loso, mir'kanas verbot!" - icon_state = "3" - -/obj/effect/rune/imbue/invoke(var/list/invokers) - var/mob/living/user = invokers[1] //the first invoker is always the user - var/turf/T = get_turf(src) - var/list/papers_on_rune = list() - var/entered_talisman_name - var/obj/item/weapon/paper/talisman/talisman_type - var/list/possible_talismans = list() - for(var/obj/item/weapon/paper/P in T) - if(!P.info) - papers_on_rune.Add(P) - if(!papers_on_rune.len) - to_chat(user, "There must be a blank paper on top of [src]!") - fail_invoke() - log_game("Talisman Creation rune failed - no blank papers on rune") - return - if(rune_in_use) - to_chat(user, "[src] can only support one ritual at a time!") - fail_invoke() - log_game("Talisman Creation rune failed - already in use") - return - var/obj/item/weapon/paper/paper_to_imbue = pick(papers_on_rune) - for(var/I in subtypesof(/obj/item/weapon/paper/talisman) - /obj/item/weapon/paper/talisman/malformed - /obj/item/weapon/paper/talisman/supply - /obj/item/weapon/paper/talisman/supply/weak) - var/obj/item/weapon/paper/talisman/J = I - var/talisman_cult_name = initial(J.cultist_name) - if(talisman_cult_name) - possible_talismans[talisman_cult_name] = J //This is to allow the menu to let cultists select talismans by name - entered_talisman_name = input(user, "Choose a talisman to imbue.", "Talisman Choices") as null|anything in possible_talismans - talisman_type = possible_talismans[entered_talisman_name] - if(!Adjacent(user) || !src || qdeleted(src) || user.incapacitated() || rune_in_use || !talisman_type) - return - ..() - visible_message("Dark power begins to channel into the paper!.") - rune_in_use = 1 - if(!do_after(user, 100, target = get_turf(user))) - rune_in_use = 0 - return - new talisman_type(get_turf(src)) - visible_message("[src] glows with power, and bloody images form themselves on [paper_to_imbue].") - qdel(paper_to_imbue) - rune_in_use = 0 - -var/list/teleport_runes = list() -/obj/effect/rune/teleport - cultist_name = "Teleport" - cultist_desc = "warps everything above it to another chosen teleport rune." - invocation = "Sas'so c'arta forbici!" - icon_state = "2" - req_keyword = 1 - var/listkey - -/obj/effect/rune/teleport/New(loc, set_keyword) - ..() - var/area/A = get_area(src) - var/locname = initial(A.name) - listkey = set_keyword ? "[set_keyword] [locname]":"[locname]" - teleport_runes += src - -/obj/effect/rune/teleport/Destroy() - teleport_runes -= src - return ..() - -/obj/effect/rune/teleport/invoke(var/list/invokers) - var/mob/living/user = invokers[1] //the first invoker is always the user - var/list/potential_runes = list() - var/list/teleportnames = list() - var/list/duplicaterunecount = list() - for(var/R in teleport_runes) - var/obj/effect/rune/teleport/T = R - var/resultkey = T.listkey - if(resultkey in teleportnames) - duplicaterunecount[resultkey]++ - resultkey = "[resultkey] ([duplicaterunecount[resultkey]])" - else - teleportnames.Add(resultkey) - duplicaterunecount[resultkey] = 1 - if(T != src && (!is_level_reachable(T.z))) - potential_runes[resultkey] = T - - if(!potential_runes.len) - to_chat(user, "There are no valid runes to teleport to!") - log_game("Teleport rune failed - no other teleport runes") - fail_invoke() - return - - if(!is_level_reachable(user.z)) - to_chat(user, "You are not in the right dimension!") - log_game("Teleport rune failed - user in away mission") - fail_invoke() - return - - var/input_rune_key = input(user, "Choose a rune to teleport to.", "Rune to Teleport to") as null|anything in potential_runes //we know what key they picked - var/obj/effect/rune/teleport/actual_selected_rune = potential_runes[input_rune_key] //what rune does that key correspond to? - if(!Adjacent(user) || !src || qdeleted(src) || user.incapacitated() || !actual_selected_rune) - fail_invoke() - return - - var/turf/T = get_turf(src) - var/movedsomething = 0 - var/moveuserlater = 0 - for(var/atom/movable/A in T) - if(A == user) - moveuserlater = 1 - movedsomething = 1 +/obj/effect/rune/proc/teleport(var/key) + var/mob/living/user = usr + var/allrunesloc[] + allrunesloc = new/list() + var/index = 0 +// var/tempnum = 0 + for(var/obj/effect/rune/R in world) + if(R == src) continue - if(!A.anchored) - movedsomething = 1 - A.forceMove(get_turf(actual_selected_rune)) - if(movedsomething) - ..() - visible_message("There is a sharp crack of inrushing air, and everything above the rune disappears!") - to_chat(user, "You[moveuserlater ? "r vision blurs, and you suddenly appear somewhere else":" send everything above the rune away"].") - if(moveuserlater) - user.forceMove(get_turf(actual_selected_rune)) - else - fail_invoke() - - -//Rite of Enlightenment: Converts a normal crewmember to the cult. Faster for every cultist nearby. -/obj/effect/rune/convert - cultist_name = "Rite of Enlightenment" - cultist_desc = "converts a normal crewmember on top of it to the cult. Does not work on loyalty-implanted crew." - invocation = "Mah'weyh pleggh at e'ntrath!" - icon_state = "3" - req_cultists = 2 - -/obj/effect/rune/convert/do_invoke_glow() - return - -/obj/effect/rune/convert/invoke(var/list/invokers) - var/list/convertees = list() - var/turf/T = get_turf(src) - for(var/mob/living/M in T.contents) - if(!iscultist(M) && !isloyal(M)) - convertees.Add(M) - if(!convertees.len) - fail_invoke() - log_game("Convert rune failed - no eligible convertees") - return - var/mob/living/new_cultist = pick(convertees) - if(!is_convertable_to_cult(new_cultist.mind) || new_cultist.null_rod_check()) - for(var/M in invokers) - to_chat(M, "Something is shielding [new_cultist]'s mind!") - if(is_sacrifice_target(new_cultist.mind)) - to_chat(M, "\"I desire this one for myself. SACRIFICE THEM!\"") - fail_invoke() - log_game("Convert rune failed - convertee could not be converted") - return - ..() - new_cultist.visible_message("[new_cultist] writhes in pain as the markings below them glow a bloody red!", \ - "AAAAAAAAAAAAAA-") - ticker.mode.add_cultist(new_cultist.mind, 1) - new /obj/item/weapon/tome(get_turf(src)) - new_cultist.mind.special_role = "Cultist" - to_chat(new_cultist, "Your blood pulses. Your head throbs. The world goes red. All at once you are aware of a horrible, horrible, truth. The veil of reality has been ripped away \ - and something evil takes root.") - to_chat(new_cultist, "Assist your new compatriots in their dark dealings. Your goal is theirs, and theirs is yours. You serve [ticker.mode.cultdat.entity_title3] above all else. Bring it back.\ - ") - -//Rite of Tribute: Sacrifices a crew member to Nar-Sie. Places them into a soul shard if they're in their body. -/obj/effect/rune/sacrifice - cultist_name = "Rite of Tribute" - cultist_desc = "sacrifices a crew member to your god. May place them into a soul shard if their spirit remains in their body." - icon_state = "3" - allow_excess_invokers = 1 - invocation = "Barhah hra zar'garis!" - rune_in_use = 0 - -/obj/effect/rune/sacrifice/New() - ..() - cultist_desc = "sacrifices a crew member to [ticker.mode.cultdat.entity_title3]. May place them into a soul shard if their spirit remains in their body." - -/obj/effect/rune/sacrifice/invoke(var/list/invokers) - if(rune_in_use) - return - rune_in_use = 1 - var/mob/living/user = invokers[1] //the first invoker is always the user - var/turf/T = get_turf(src) - var/list/possible_targets = list() - for(var/mob/living/M in T.contents) - if(M.mind) - if(M.mind in sacrificed) - continue - if(!iscultist(M)) - possible_targets.Add(M) - var/mob/offering - if(possible_targets.len > 1) //If there's more than one target, allow choice - offering = input(user, "Choose an offering to sacrifice.", "Unholy Tribute") as null|anything in possible_targets - if(!Adjacent(user) || !src || qdeleted(src) || user.incapacitated()) - return - else if(possible_targets.len) //Otherwise, if there's a target at all, pick the only one - offering = possible_targets[possible_targets.len] - if(!offering) - rune_in_use = 0 - return - if(((ishuman(offering) || isrobot(offering)) && offering.stat != DEAD) || is_sacrifice_target(offering.mind)) //Requires three people to sacrifice living targets - if(invokers.len < 3) - for(var/M in invokers) - to_chat(M, "[offering] is too greatly linked to the world! You need three acolytes!") - fail_invoke() - log_game("Sacrifice rune failed - not enough acolytes and target is living") - rune_in_use = 0 - return - visible_message("[src] pulses blood red!") - color = rgb(126, 23, 23) - ..() - sac(invokers, offering) - color = initial(color) - -/obj/effect/rune/sacrifice/proc/sac(var/list/invokers, mob/living/T) - var/sacrifice_fulfilled - if(T) - if(istype(T, /mob/living/simple_animal/pet/corgi)) - for(var/M in invokers) - var/mob/living/L = M - to_chat(L, "\"Even I have standards, such as they are!\"") - if(L.reagents) - L.reagents.add_reagent("hell_water", 2) - if(T.mind) - sacrificed.Add(T.mind) - if(is_sacrifice_target(T.mind)) - sacrifice_fulfilled = 1 - new /obj/effect/overlay/temp/cult/sac(loc) - for(var/M in invokers) - if(sacrifice_fulfilled) - to_chat(M, "\"Yes! This is the one I desire! You have done well.\"") - else - if(ishuman(T) || isrobot(T)) - to_chat(M, "\"I accept this sacrifice.\"") - else - to_chat(M, "\"I accept this meager sacrifice.\"") - if(T.mind) - var/obj/item/device/soulstone/stone = new /obj/item/device/soulstone(get_turf(src)) - stone.invisibility = INVISIBILITY_MAXIMUM //so it's not picked up during transfer_soul() - if(!stone.transfer_soul("VICTIM", T, usr)) //If it cannot be added - qdel(stone) - if(stone) - stone.invisibility = 0 - if(!T) - rune_in_use = 0 - return - if(isrobot(T)) - playsound(T, 'sound/effects/EMPulse.ogg', 100, 1) - T.dust() //To prevent the MMI from remaining + if(R.word1 == cultwords["travel"] && R.word2 == cultwords["self"] && R.word3 == key && is_teleport_allowed(R.z)) + index++ + allrunesloc.len = index + allrunesloc[index] = R.loc + if(index >= 5) + to_chat(user, "\red You feel pain, as rune disappears in reality shift caused by too much wear of space-time fabric") + if(istype(user, /mob/living)) + user.take_overall_damage(5, 0) + qdel(src) + if(allrunesloc && index != 0) + if(istype(src,/obj/effect/rune)) + user.say("Sas[pick("'","`")]so c'arta forbici!")//Only you can stop auto-muting else - playsound(T, 'sound/magic/Disintegrate.ogg', 100, 1) - T.gib() - rune_in_use = 0 - -//Ritual of Dimensional Rending: Calls forth the avatar of Nar-Sie upon the station. -/obj/effect/rune/narsie - cultist_name = "Tear Reality (God)" - cultist_desc = "tears apart dimensional barriers, calling forth your god. Requires 9 invokers." - invocation = "TOK-LYR RQA-NAP G'OLT-ULOFT!!" - req_cultists = 9 - icon = 'icons/effects/96x96.dmi' - color = rgb(125,23,23) - icon_state = "rune_large" - pixel_x = -32 //So the big ol' 96x96 sprite shows up right - pixel_y = -32 - mouse_opacity = 1 //we're huge and easy to click - scribe_delay = 450 //how long the rune takes to create - scribe_damage = 40.1 //how much damage you take doing it - var/used - -/obj/effect/rune/narsie/New() - ..() - cultist_name = "Summon [ticker.mode.cultdat.entity_name]" - cultist_desc = "tears apart dimensional barriers, calling forth [ticker.mode.cultdat.entity_title3]. Requires 9 invokers." - - -/obj/effect/rune/narsie/check_icon() - return - -/obj/effect/rune/narsie/talismanhide() //can't hide this, and you wouldn't want to - return - -/obj/effect/rune/narsie/invoke(var/list/invokers) - if(used) + user.whisper("Sas[pick("'","`")]so c'arta forbici!") + user.visible_message("\red [user] disappears in a flash of red light!", \ + "\red You feel as your body gets dragged through the dimension of Nar-Sie!", \ + "\red You hear a sickening crunch and sloshing of viscera.") + user.loc = allrunesloc[rand(1,index)] return - var/mob/living/user = invokers[1] - if(istype(ticker.mode.name, "cult")) - var/datum/game_mode/cult/cult_mode = ticker.mode - if(!is_station_level(user.z)) - message_admins("[user.real_name]([user.ckey]) tried to summon Nar-Sie off station") - for(var/M in invokers) - var/mob/living/L = M - to_chat(L, "\"YOUR SOUL BURNS WITH YOUR ARROGANCE!!!\"") - if(L.reagents) - L.reagents.add_reagent("hell_water", 10) - L.Weaken(7) - L.Stun(7) - fail_invoke() - log_game("Summon Nar-Sie rune failed - off station Z level") - return - if(!cult_mode.eldergod) - for(var/M in invokers) - to_chat(M, "[ticker.mode.cultdat.entity_name] is already on this plane!") - log_game("Summon Nar-Sie rune failed - already summoned") - return - //BEGIN THE SUMMONING - used = 1 - color = rgb(255, 0, 0) - ..() - world << 'sound/effects/dimensional_rend.ogg' - to_chat(world, "The veil... is... TORN!!!--") - icon_state = "rune_large_distorted" - var/turf/T = get_turf(src) - sleep(40) - new /obj/singularity/narsie/large(T) //Causes Nar-Sie to spawn even if the rune has been removed - cult_mode.eldergod = 0 - -/obj/effect/rune/narsie/attackby(obj/I, mob/user, params) //Since the narsie rune takes a long time to make, add logging to removal. - if((istype(I, /obj/item/weapon/tome) && iscultist(user))) - user.visible_message("[user.name] begins erasing the [src]...", "You begin erasing the [src]...") - if(do_after(user, 50, target = src)) //Prevents accidental erasures. - log_game("Summon Narsie rune erased by [user.mind.key] (ckey) with a tome") - message_admins("[key_name_admin(user)] erased a Narsie rune with a tome") - ..() - return + if(istype(src,/obj/effect/rune)) + return fizzle() //Use friggin manuals, Dorf, your list was of zero length. else - if(istype(I, /obj/item/weapon/nullrod)) //Begone foul magiks. You cannot hinder me. - log_game("Summon Narsie rune erased by [user.mind.key] (ckey) using a null rod") - message_admins("[key_name_admin(user)] erased a Narsie rune with a null rod") - ..() - return - - - -/obj/effect/rune/slaughter - cultist_name = "Call Forth The Slaughter (Demons)" - cultist_desc = "Calls forth the doom of a eldrtich being. Three slaughter demons will appear to wreak havoc on the station." - invocation = null - req_cultists = 9 - color = rgb(125,23,23) - scribe_delay = 450 - scribe_damage = 40.1 //how much damage you take doing it - icon = 'icons/effects/96x96.dmi' - icon_state = "rune_large" - pixel_x = -32 - pixel_y = -32 - - var/used = 0 - -/obj/effect/rune/slaughter/check_icon() - return - -/obj/effect/rune/slaughter/talismanhide() //can't hide this, and you wouldn't want to - return - -/obj/effect/rune/slaughter/attackby(obj/I, mob/user, params) //Since the narsie rune takes a long time to make, add logging to removal. - if((istype(I, /obj/item/weapon/tome) && iscultist(user))) - user.visible_message("[user.name] begins erasing the [src]...", "You begin erasing the [src]...") - if(do_after(user, 50, target = src)) //Prevents accidental erasures. - log_game("Summon demon rune erased by [user.mind.key] (ckey) with a tome") - message_admins("[key_name_admin(user)] erased a demon rune with a tome") - ..() - return - else - if(istype(I, /obj/item/weapon/nullrod)) //Begone foul magiks. You cannot hinder me. - log_game("Summon demon rune erased by [user.mind.key] (ckey) using a null rod") - message_admins("[key_name_admin(user)] erased a demon rune with a null rod") - ..() - return - - -/obj/effect/rune/slaughter/invoke(var/list/invokers) - if(used) + call(/obj/effect/rune/proc/fizzle)() return - var/mob/living/user = invokers[1] - if(istype(ticker.mode.name, "cult")) - var/datum/game_mode/cult/cult_mode = ticker.mode - if(!(CULT_SLAUGHTER in cult_mode.objectives)) - message_admins("[usr.real_name]([user.ckey]) tried to summon demons when the objective was wrong") - for(var/M in invokers) - var/mob/living/L = M - to_chat(L, "\"YOUR SOUL BURNS WITH YOUR ARROGANCE!!!\"") - if(L.reagents) - L.reagents.add_reagent("hell_water", 10) - L.Weaken(7) - L.Stun(7) - fail_invoke() - log_game("Summon Demons rune failed - improper objective") - return - if(!is_station_level(user.z)) - message_admins("[user.real_name]([user.ckey]) tried to summon demons off station") - for(var/M in invokers) - var/mob/living/L = M - to_chat(L, "\"YOUR SOUL BURNS WITH YOUR ARROGANCE!!!\"") - if(L.reagents) - L.reagents.add_reagent("hell_water", 10) - L.Weaken(7) - L.Stun(7) - fail_invoke() - log_game("Summon demons rune failed - off station Z level") - return - if(cult_mode.demons_summoned) - for(var/M in invokers) - to_chat(M, "Demons are already on this plane!") - log_game("Summon Demons rune failed - already summoned") + +/obj/effect/rune/proc/itemportRune() + return itemport(src.word3) +/obj/effect/rune/proc/itemport(var/key) +// var/allrunesloc[] +// allrunesloc = new/list() +// var/index = 0 +// var/tempnum = 0 + var/culcount = 0 + var/runecount = 0 + var/obj/effect/rune/IP = null + var/mob/living/user = usr + for(var/obj/effect/rune/R in world) + if(R == src) + continue + if(R.word1 == cultwords["travel"] && R.word2 == cultwords["other"] && R.word3 == key) + IP = R + runecount++ + if(runecount >= 2) + to_chat(user, "\red You feel pain, as rune disappears in reality shift caused by too much wear of space-time fabric") + if(istype(user, /mob/living)) + user.take_overall_damage(5, 0) + qdel(src) + for(var/mob/living/carbon/C in orange(1,src)) + if(iscultist(C) && !C.stat) + culcount++ + if(culcount>=3) + user.say("Sas[pick("'","`")]so c'arta forbici tarem!") + user.visible_message("\red You feel air moving from the rune - like as it was swapped with somewhere else.", \ + "\red You feel air moving from the rune - like as it was swapped with somewhere else.", \ + "\red You smell ozone.") + for(var/obj/O in src.loc) + if(!O.anchored) + O.loc = IP.loc + for(var/mob/M in src.loc) + M.loc = IP.loc + return + + return fizzle() + + +/////////////////////////////////////////SECOND RUNE + +/obj/effect/rune/proc/tomesummon() + if(istype(src,/obj/effect/rune)) + usr.say("N[pick("'","`")]ath reth sh'yro eth d'raggathnor!") + else + usr.whisper("N[pick("'","`")]ath reth sh'yro eth d'raggathnor!") + usr.visible_message("\red Rune disappears with a flash of red light, and in its place now a book lies.", \ + "\red You are blinded by the flash of red light! After you're able to see again, you see that now instead of the rune there's a book.", \ + "\red You hear a pop and smell ozone.") + if(istype(src,/obj/effect/rune)) + new /obj/item/weapon/tome(src.loc) + else + new /obj/item/weapon/tome(usr.loc) + qdel(src) + return + + + +/////////////////////////////////////////THIRD RUNE + +/obj/effect/rune/proc/convert() + for(var/mob/living/carbon/M in src.loc) + if(iscultist(M)) + continue + if(M.stat==2) + continue + usr.say("Mah[pick("'","`")]weyh pleggh at e'ntrath!") + M.visible_message("\red [M] writhes in pain as the markings below him glow a bloody red.", \ + "\red AAAAAAHHHH!.", \ + "\red You hear an anguished scream.") + cult_log("[key_name_admin(usr)] tried to convert [key_name_admin(M)]") + if(is_convertable_to_cult(M.mind)) + ticker.mode.add_cultist(M.mind) + M.mind.special_role = SPECIAL_ROLE_CULTIST + to_chat(M, "Your blood pulses. Your head throbs. The world goes red. All at once you are aware of a horrible, horrible truth. The veil of reality has been ripped away and in the festering wound left behind something sinister takes root.") + to_chat(M, "Assist your new compatriots in their dark dealings. Their goal is yours, and yours is theirs. You serve the Dark One above all else. Bring It back.") + return 1 + else + to_chat(M, "Your blood pulses. Your head throbs. The world goes red. All at once you are aware of a horrible, horrible truth. The veil of reality has been ripped away and in the festering wound left behind something sinister takes root.") + to_chat(M, "And you were able to force it out of your mind. You now know the truth, there's something horrible out there, stop it and its minions at all costs.") + return 0 + + return fizzle() + + + +/////////////////////////////////////////FOURTH RUNE + +/obj/effect/rune/proc/tearreality() + var/cultist_count = 0 + for(var/mob/M in range(1,src)) + if(iscultist(M) && !M.stat) + M.say("Tok-lyr rqa'nap g[pick("'","`")]lt-ulotf!") + cultist_count += 1 + if(cultist_count >= 9) + cult_log("THE CULT HAS SUMMONED NAR'SIE. GGNORE") + new /obj/singularity/narsie/large(src.loc) + if(ticker.mode.name == "cult") + ticker.mode:eldergod = 0 + return + else + return fizzle() + +/////////////////////////////////////////FIFTH RUNE +/obj/effect/rune/proc/empRune() + emp(src.loc,3) + +/obj/effect/rune/proc/emp(var/U,var/range_red) //range_red - var which determines by which number to reduce the default emp range, U is the source loc, needed because of talisman emps which are held in hand at the moment of using and that apparently messes things up -- Urist + if(istype(src,/obj/effect/rune)) + usr.say("Ta'gh fara[pick("'","`")]qha fel d'amar det!") + else + usr.whisper("Ta'gh fara[pick("'","`")]qha fel d'amar det!") + playsound(U, 'sound/items/Welder2.ogg', 25, 1) + var/turf/T = get_turf(U) + if(T) + T.hotspot_expose(700,125) + var/rune = src // detaching the proc - in theory + empulse(U, (range_red - 2), range_red) + qdel(rune) + return + +/////////////////////////////////////////SIXTH RUNE + +/obj/effect/rune/proc/drain() + var/drain = 0 + for(var/obj/effect/rune/R in world) + if(R.word1==cultwords["travel"] && R.word2==cultwords["blood"] && R.word3==cultwords["self"]) + for(var/mob/living/carbon/D in R.loc) + if(D.stat!=2) + cult_log("[key_name_admin(usr)] has drained blood from [key_name_admin(D)]") + var/bdrain = rand(1,25) + to_chat(D, "\red You feel weakened.") + D.take_overall_damage(bdrain, 0) + drain += bdrain + if(!drain) + return fizzle() + usr.say ("Yu[pick("'","`")]gular faras desdae. Havas mithum javara. Umathar uf'kal thenar!") + usr.visible_message("\red Blood flows from the rune into [usr]!", \ + "\red The blood starts flowing from the rune and into your frail mortal body. You feel... empowered.", \ + "\red You hear a liquid flowing.") + var/mob/living/user = usr + if(user.bhunger) + user.bhunger = max(user.bhunger-2*drain,0) + if(drain>=50) + user.visible_message("\red [user]'s eyes give off eerie red glow!", \ + "\red ...but it wasn't nearly enough. You crave, crave for more. The hunger consumes you from within.", \ + "\red You hear a heartbeat.") + user.bhunger += drain + src = user + spawn() + for(,user.bhunger>0,user.bhunger--) + sleep(50) + user.take_overall_damage(3, 0) + return + user.heal_organ_damage(drain%5, 0) + drain-=drain%5 + for(,drain>0,drain-=5) + sleep(2) + user.heal_organ_damage(5, 0) + return + + + + + + +/////////////////////////////////////////SEVENTH RUNE + +/obj/effect/rune/proc/seer() + if(usr.loc==src.loc) + // No. Bad cultcode. Bad. + var/mob/living/carbon/human/H = usr + if(usr.seer==1) + usr.say("Rash'tla sektath mal[pick("'","`")]zua. Zasan therium viortia.") + to_chat(usr, "\red The world beyond fades from your vision.") + usr.see_invisible = SEE_INVISIBLE_LIVING + usr.seer = 0 + else if(usr.see_invisible!=SEE_INVISIBLE_LIVING) + to_chat(usr, "\red The world beyond flashes your eyes but disappears quickly, as if something is disrupting your vision.") + usr.see_invisible = SEE_INVISIBLE_OBSERVER + usr.seer = 0 + else + usr.say("Rash'tla sektath mal[pick("'","`")]zua. Zasan therium vivira. Itonis al'ra matum!") + to_chat(usr, "\red The world beyond opens to your eyes.") + usr.see_invisible = SEE_INVISIBLE_OBSERVER + usr.seer = 1 + H.update_sight() + return + return fizzle() + +/////////////////////////////////////////EIGHTH RUNE + +/obj/effect/rune/proc/raise() + var/mob/living/carbon/human/corpse_to_raise + var/mob/living/carbon/human/body_to_sacrifice + + var/is_sacrifice_target = 0 + for(var/mob/living/carbon/human/M in src.loc) + if(M.stat == DEAD) + if(ticker.mode.name == "cult" && M.mind == ticker.mode:sacrifice_target) + is_sacrifice_target = 1 + else + corpse_to_raise = M + if(M.key) + M.ghostize(1) //kick them out of their body + break + if(!corpse_to_raise) + if(is_sacrifice_target) + to_chat(usr, "\red The Geometer of blood wants this mortal for himself.") + return fizzle() + + + is_sacrifice_target = 0 + find_sacrifice: + for(var/obj/effect/rune/R in world) + if(R.word1==cultwords["blood"] && R.word2==cultwords["join"] && R.word3==cultwords["hell"]) + for(var/mob/living/carbon/human/N in R.loc) + if(ticker.mode.name == "cult" && N.mind && N.mind == ticker.mode:sacrifice_target) + is_sacrifice_target = 1 + else + if(N.stat!= DEAD) + body_to_sacrifice = N + break find_sacrifice + + if(!body_to_sacrifice) + if(is_sacrifice_target) + to_chat(usr, "\red The Geometer of blood wants that corpse for himself.") + else + to_chat(usr, "\red The sacrifical corpse is not dead. You must free it from this world of illusions before it may be used.") + return fizzle() + + var/mob/dead/observer/ghost + for(var/mob/dead/observer/O in loc) + if(!O.client) continue + if(O.mind && O.mind.current && O.mind.current.stat != DEAD) continue + ghost = O + break + + if(!ghost) + to_chat(usr, "\red You require a restless spirit which clings to this world. Beckon their prescence with the sacred chants of Nar-Sie.") + return fizzle() + + corpse_to_raise.revive() + + corpse_to_raise.key = ghost.key //the corpse will keep its old mind! but a new player takes ownership of it (they are essentially possessed) + //This means, should that player leave the body, the original may re-enter + usr.say("Pasnar val'keriam usinar. Savrae ines amutan. Yam'toth remium il'tarat!") + corpse_to_raise.visible_message("\red [corpse_to_raise]'s eyes glow with a faint red as he stands up, slowly starting to breathe again.", \ + "\red Life... I'm alive again...", \ + "\red You hear a faint, slightly familiar whisper.") + body_to_sacrifice.visible_message("\red [body_to_sacrifice] is torn apart, a black smoke swiftly dissipating from his remains!", \ + "\red You feel as your blood boils, tearing you apart.", \ + "\red You hear a thousand voices, all crying in pain.") + body_to_sacrifice.gib() + +// if(ticker.mode.name == "cult") +// ticker.mode:add_cultist(corpse_to_raise.mind) +// else +// ticker.mode.cult |= corpse_to_raise.mind + + to_chat(corpse_to_raise, "Your blood pulses. Your head throbs. The world goes red. All at once you are aware of a horrible, horrible truth. The veil of reality has been ripped away and in the festering wound left behind something sinister takes root.") + to_chat(corpse_to_raise, "Assist your new compatriots in their dark dealings. Their goal is yours, and yours is theirs. You serve the Dark One above all else. Bring It back.") + return + + + + + +/////////////////////////////////////////NINETH RUNE + +/obj/effect/rune/proc/obscureRune() + return obscure(4) +/obj/effect/rune/proc/obscure(var/rad) + var/S=0 + for(var/obj/effect/rune/R in orange(rad,src)) + if(R!=src) + R.invisibility=INVISIBILITY_OBSERVER + S=1 + if(S) + if(istype(src,/obj/effect/rune)) + usr.say("Kla[pick("'","`")]atu barada nikt'o!") + for(var/mob/V in viewers(src)) + V.show_message("\red The rune turns into gray dust, veiling the surrounding runes.", 3) + qdel(src) + else + usr.whisper("Kla[pick("'","`")]atu barada nikt'o!") + to_chat(usr, "\red Your talisman turns into gray dust, veiling the surrounding runes.") + for(var/mob/V in orange(1,src)) + if(V!=usr) + V.show_message("\red Dust emanates from [usr]'s hands for a moment.", 3) + + return + if(istype(src,/obj/effect/rune)) + return fizzle() + else + call(/obj/effect/rune/proc/fizzle)() + return + +/////////////////////////////////////////TENTH RUNE + +/obj/effect/rune/proc/ajourney() //some bits copypastaed from admin tools - Urist + if(usr.loc==src.loc) + var/mob/living/carbon/human/L = usr + usr.say("Fwe[pick("'","`")]sh mah erl nyag r'ya!") + usr.visible_message("\red [usr]'s eyes glow blue as \he freezes in place, absolutely motionless.", \ + "\red The shadow that is your spirit separates itself from your body. You are now in the realm beyond. While this is a great sight, being here strains your mind and body. Hurry...", \ + "\red You hear only complete silence for a moment.") + usr.ghostize(1) + L.ajourn = 1 + while(L) + if(L.key) + L.ajourn=0 return - //BEGIN THE SLAUGHTER - used = 1 - for(var/mob/living/M in range(1,src)) + else + L.take_organ_damage(10, 0) + sleep(100) + return fizzle() + + + + +/////////////////////////////////////////ELEVENTH RUNE + +/obj/effect/rune/proc/manifest() + var/obj/effect/rune/this_rune = src + src = null + if(usr.loc!=this_rune.loc) + return this_rune.fizzle() + var/mob/dead/observer/ghost + for(var/mob/dead/observer/O in this_rune.loc) + if(!O.client) continue + if(O.mind && O.mind.current && O.mind.current.stat != DEAD) continue + ghost = O + break + if(!ghost) + return this_rune.fizzle() + if(jobban_isbanned(ghost, ROLE_CULTIST) || jobban_isbanned(ghost,"Syndicate")) + return this_rune.fizzle() + + usr.say("Gal'h'rfikk harfrandid mud[pick("'","`")]gib!") + var/mob/living/carbon/human/dummy/D = new(this_rune.loc) + usr.visible_message("\red A shape forms in the center of the rune. A shape of... a man.", \ + "\red A shape forms in the center of the rune. A shape of... a man.", \ + "\red You hear liquid flowing.") + D.real_name = "Unknown" + var/chose_name = 0 + for(var/obj/item/weapon/paper/P in this_rune.loc) + if(P.info) + D.real_name = copytext(P.info, findtext(P.info,">")+1, findtext(P.info,"<",2) ) + chose_name = 1 + break + if(!chose_name) + D.real_name = "[pick(first_names_male)] [pick(last_names)]" + D.universal_speak = 1 + D.status_flags &= ~GODMODE + + D.key = ghost.key + + if(ticker.mode.name == "cult") + ticker.mode:add_cultist(D.mind) + else + ticker.mode.cult+=D.mind + + D.mind.special_role = SPECIAL_ROLE_CULTIST + to_chat(D, "Your blood pulses. Your head throbs. The world goes red. All at once you are aware of a horrible, horrible truth. The veil of reality has been ripped away and in the festering wound left behind something sinister takes root.") + to_chat(D, "Assist your new compatriots in their dark dealings. Their goal is yours, and yours is theirs. You serve the Dark One above all else. Bring It back.") + + var/mob/living/user = usr + while(this_rune && user && user.stat==CONSCIOUS && user.client && user.loc==this_rune.loc) + user.take_organ_damage(1, 0) + sleep(30) + if(D) + D.visible_message("\red [D] slowly dissipates into dust and bones.", \ + "\red You feel pain, as bonds formed between your soul and this homunculus break.", \ + "\red You hear faint rustle.") + D.dust() + return + + + + + +/////////////////////////////////////////TWELFTH RUNE + +/obj/effect/rune/proc/talisman()//only hide, emp, teleport, deafen, blind and tome runes can be imbued atm + var/obj/item/weapon/paper/newtalisman + var/unsuitable_newtalisman = 0 + for(var/obj/item/weapon/paper/P in src.loc) + if(!P.info) + newtalisman = P + break + else + unsuitable_newtalisman = 1 + if(!newtalisman) + if(unsuitable_newtalisman) + to_chat(usr, "\red The blank is tainted. It is unsuitable.") + return fizzle() + + var/obj/effect/rune/imbued_from + var/obj/item/weapon/paper/talisman/T + for(var/obj/effect/rune/R in orange(1,src)) + if(R==src) + continue + if(R.word1==cultwords["travel"] && R.word2==cultwords["self"]) //teleport + T = new(src.loc) + T.imbue = "[R.word3]" + T.info = "[R.word3]" + imbued_from = R + break + if(R.word1==cultwords["see"] && R.word2==cultwords["blood"] && R.word3==cultwords["hell"]) //tome + T = new(src.loc) + T.imbue = "newtome" + imbued_from = R + break + if(R.word1==cultwords["destroy"] && R.word2==cultwords["see"] && R.word3==cultwords["technology"]) //emp + T = new(src.loc) + T.imbue = "emp" + imbued_from = R + break + if(R.word1==cultwords["blood"] && R.word2==cultwords["see"] && R.word3==cultwords["destroy"]) //conceal + T = new(src.loc) + T.imbue = "conceal" + imbued_from = R + break + if(R.word1==cultwords["hell"] && R.word2==cultwords["destroy"] && R.word3==cultwords["other"]) //armor + T = new(src.loc) + T.imbue = "armor" + imbued_from = R + break + if(R.word1==cultwords["blood"] && R.word2==cultwords["see"] && R.word3==cultwords["hide"]) //reveal + T = new(src.loc) + T.imbue = "revealrunes" + imbued_from = R + break + if(R.word1==cultwords["hide"] && R.word2==cultwords["other"] && R.word3==cultwords["see"]) //deafen + T = new(src.loc) + T.imbue = "deafen" + imbued_from = R + break + if(R.word1==cultwords["destroy"] && R.word2==cultwords["see"] && R.word3==cultwords["other"]) //blind + T = new(src.loc) + T.imbue = "blind" + imbued_from = R + break + if(R.word1==cultwords["self"] && R.word2==cultwords["other"] && R.word3==cultwords["technology"]) //communicate + T = new(src.loc) + T.imbue = "communicate" + imbued_from = R + break + if(R.word1==cultwords["join"] && R.word2==cultwords["hide"] && R.word3==cultwords["technology"]) //stun + T = new(src.loc) + T.imbue = "runestun" + imbued_from = R + break + if(imbued_from) + for(var/mob/V in viewers(src)) + V.show_message("\red The runes turn into dust, which then forms into an arcane image on the paper.", 3) + usr.say("H'drak v[pick("'","`")]loso, mir'kanas verbot!") + qdel(imbued_from) + qdel(newtalisman) + else + return fizzle() + +/////////////////////////////////////////THIRTEENTH RUNE + +/obj/effect/rune/proc/mend() + var/mob/living/user = usr + src = null + user.say("Uhrast ka'hfa heldsagen ver[pick("'","`")]lot!") + user.take_overall_damage(200, 0) + runedec+=10 + user.visible_message("\red [user] keels over dead, his blood glowing blue as it escapes his body and dissipates into thin air.", \ + "\red In the last moment of your humble life, you feel an immense pain as fabric of reality mends... with your blood.", \ + "\red You hear faint rustle.") + for(,user.stat==2) + sleep(600) + if(!user) + return + runedec-=10 + return + + +/////////////////////////////////////////FOURTEETH RUNE + +// returns 0 if the rune is not used. returns 1 if the rune is used. +/obj/effect/rune/proc/communicate() + . = 1 // Default output is 1. If the rune is deleted it will return 1 + var/input = stripped_input(usr, "Please choose a message to tell to the other acolytes.", "Voice of Blood", "") + if(!input) + if(istype(src)) + fizzle() + return 0 + else + return 0 + + // record this + //cult_log("[key_name(usr,0)] says : [input]") + + + var/F = investigate_subject2file("cult") + if(!F) + return 0 + to_chat(F, "[time2text(world.timeofday,"hh:mm")] \ref[usr] ([usr.x],[usr.y],[usr.z]) || [usr] communicates: [input]
") + + var/obj/cult_viewpoint/vp = getCultViewpoint(usr) + if(!vp) + return 0 + + var/displayName = vp.get_display_name() + var/cultName = vp.get_cult_name() + + if(istype(src,/obj/effect/rune)) + usr.say("O bidai nabora se[pick("'","`")]sma!") + else + usr.whisper("O bidai nabora se[pick("'","`")]sma!") + + if(istype(src,/obj/effect/rune)) + usr.say("[input]") + else + usr.whisper("[input]") + + log_say("Cult Message: [key_name(usr)]: [input]") + for(var/datum/mind/H in ticker.mode.cult) + if(H.current) + to_chat(H.current, "[cultName]: [input]") + + for(var/mob/spirit/spirit in spirits) + to_chat(spirit, "[displayName]: [input]") + + + for(var/mob/dead/observer/G in player_list) + G.show_message("[displayName] ([cultName]) ([ghost_follow_link(usr, ghost=G)]): [input]") + + qdel(src) + return 1 + +/////////////////////////////////////////FIFTEENTH RUNE + +/obj/effect/rune/proc/sacrifice() + var/list/mob/living/carbon/human/cultsinrange = list() + var/list/mob/living/carbon/human/victims = list() + for(var/mob/living/carbon/human/V in src.loc)//Checks for non-cultist humans to sacrifice + if(ishuman(V)) + if(!(iscultist(V))) + victims += V//Checks for cult status and mob type + for(var/obj/item/I in src.loc)//Checks for MMIs/brains/Intellicards + if(istype(I,/obj/item/organ/internal/brain)) + var/obj/item/organ/internal/brain/B = I + victims += B.brainmob + else if(istype(I,/obj/item/device/mmi)) + var/obj/item/device/mmi/B = I + victims += B.brainmob + else if(istype(I,/obj/item/device/aicard)) + for(var/mob/living/silicon/ai/A in I) + victims += A + for(var/mob/living/carbon/C in orange(1,src)) + if(iscultist(C) && !C.stat) + cultsinrange += C + C.say("Barhah hra zar[pick("'","`")]garis!") + for(var/mob/H in victims) + if(ticker.mode.name == "cult") + if(H.mind == ticker.mode:sacrifice_target) + if(cultsinrange.len >= 3) + sacrificed += H.mind + if(isrobot(H)) + H.dust()//To prevent the MMI from remaining + else + H.gib() + to_chat(usr, "\red The Geometer of Blood accepts this sacrifice, your objective is now complete.") + else + to_chat(usr, "\red Your target's earthly bonds are too strong. You need more cultists to succeed in this ritual.") + else + if(cultsinrange.len >= 3) + if(H.stat !=2) + if(prob(80)) + to_chat(usr, "\red The Geometer of Blood accepts this sacrifice.") + ticker.mode:grant_runeword(usr) + else + to_chat(usr, "\red The Geometer of blood accepts this sacrifice.") + to_chat(usr, "\red However, this soul was not enough to gain His favor.") + if(isrobot(H)) + H.dust()//To prevent the MMI from remaining + else + H.gib() + else + if(prob(40)) + to_chat(usr, "\red The Geometer of blood accepts this sacrifice.") + ticker.mode:grant_runeword(usr) + else + to_chat(usr, "\red The Geometer of blood accepts this sacrifice.") + to_chat(usr, "\red However, a mere dead body is not enough to satisfy Him.") + if(isrobot(H)) + H.dust()//To prevent the MMI from remaining + else + H.gib() + else + if(H.stat !=2) + to_chat(usr, "\red The victim is still alive, you will need more cultists chanting for the sacrifice to succeed.") + else + if(prob(40)) + to_chat(usr, "\red The Geometer of blood accepts this sacrifice.") + ticker.mode:grant_runeword(usr) + else + to_chat(usr, "\red The Geometer of blood accepts this sacrifice.") + to_chat(usr, "\red However, a mere dead body is not enough to satisfy Him.") + if(isrobot(H)) + H.dust()//To prevent the MMI from remaining + else + H.gib() + else + if(cultsinrange.len >= 3) + if(H.stat !=2) + if(prob(80)) + to_chat(usr, "\red The Geometer of Blood accepts this sacrifice.") + ticker.mode:grant_runeword(usr) + else + to_chat(usr, "\red The Geometer of blood accepts this sacrifice.") + to_chat(usr, "\red However, this soul was not enough to gain His favor.") + if(isrobot(H)) + H.dust()//To prevent the MMI from remaining + else + H.gib() + else + if(prob(40)) + to_chat(usr, "\red The Geometer of blood accepts this sacrifice.") + ticker.mode:grant_runeword(usr) + else + to_chat(usr, "\red The Geometer of blood accepts this sacrifice.") + to_chat(usr, "\red However, a mere dead body is not enough to satisfy Him.") + if(isrobot(H)) + H.dust()//To prevent the MMI from remaining + else + H.gib() + else + if(H.stat !=2) + to_chat(usr, "\red The victim is still alive, you will need more cultists chanting for the sacrifice to succeed.") + else + if(prob(40)) + to_chat(usr, "\red The Geometer of blood accepts this sacrifice.") + ticker.mode:grant_runeword(usr) + else + to_chat(usr, "\red The Geometer of blood accepts this sacrifice.") + to_chat(usr, "\red However, a mere dead body is not enough to satisfy Him.") + if(isrobot(H)) + H.dust()//To prevent the MMI from remaining + else + H.gib() + +/////////////////////////////////////////SIXTEENTH RUNE + +/obj/effect/rune/proc/revealrunesrune() + revealrunes(src) + +/obj/effect/rune/proc/revealrunes(var/obj/W as obj) + var/go=0 + var/rad + var/S=0 + if(istype(W,/obj/effect/rune)) + rad = 6 + go = 1 + if(istype(W,/obj/item/weapon/paper/talisman)) + rad = 4 + go = 1 + if(istype(W,/obj/item/weapon/storage/bible)) + rad = 1 + go = 1 + if(go) + for(var/obj/effect/rune/R in orange(rad,src)) + if(R!=src) + R:visibility=15 + S=1 + if(S) + if(istype(W,/obj/item/weapon/storage/bible)) + to_chat(usr, "\red Arcane markings suddenly glow from underneath a thin layer of dust!") + return + if(istype(W,/obj/effect/rune)) + usr.say("Nikt[pick("'","`")]o barada kla'atu!") + for(var/mob/V in viewers(src)) + V.show_message("\red The rune turns into red dust, reveaing the surrounding runes.", 3) + qdel(src) + return + if(istype(W,/obj/item/weapon/paper/talisman)) + usr.whisper("Nikt[pick("'","`")]o barada kla'atu!") + to_chat(usr, "\red Your talisman turns into red dust, revealing the surrounding runes.") + for(var/mob/V in orange(1,usr.loc)) + if(V!=usr) + V.show_message("\red Red dust emanates from [usr]'s hands for a moment.", 3) + return + return + if(istype(W,/obj/effect/rune)) + return fizzle() + if(istype(W,/obj/item/weapon/paper/talisman)) + call(/obj/effect/rune/proc/fizzle)() + return + +/////////////////////////////////////////SEVENTEENTH RUNE + +/obj/effect/rune/proc/wall() + usr.say("Khari[pick("'","`")]d! Eske'te tannin!") + src.density = !src.density + var/mob/living/user = usr + user.take_organ_damage(2, 0) + if(src.density) + to_chat(usr, "\red Your blood flows into the rune, and you feel that the very space over the rune thickens.") + else + to_chat(usr, "\red Your blood flows into the rune, and you feel as the rune releases its grasp on space.") + return + +/////////////////////////////////////////EIGHTTEENTH RUNE + +/obj/effect/rune/proc/freedom() + var/mob/living/user = usr + var/list/mob/living/carbon/cultists = new + for(var/datum/mind/H in ticker.mode.cult) + if(istype(H.current,/mob/living/carbon)) + cultists+=H.current + var/list/mob/living/carbon/users = new + for(var/mob/living/carbon/C in orange(1,src)) + if(iscultist(C) && !C.stat) + users+=C + if(users.len>=3) + var/mob/living/carbon/cultist = input("Choose the one who you want to free", "Followers of Geometer") as null|anything in (cultists - users) + if(!cultist) + return fizzle() + if(cultist == user) //just to be sure. + return + if(!(cultist.buckled || \ + cultist.handcuffed || \ + istype(cultist.wear_mask, /obj/item/clothing/mask/muzzle) || \ + (istype(cultist.loc, /obj/structure/closet)&&cultist.loc:welded) || \ + (istype(cultist.loc, /obj/structure/closet/secure_closet)&&cultist.loc:locked) || \ + (istype(cultist.loc, /obj/machinery/dna_scannernew)&&cultist.loc:locked) \ + )) + to_chat(user, "\red The [cultist] is already free.") + return + cultist.buckled = null + if(cultist.handcuffed) + cultist.handcuffed.loc = cultist.loc + cultist.handcuffed = null + cultist.update_handcuffed() + if(cultist.legcuffed) + cultist.legcuffed.loc = cultist.loc + cultist.legcuffed = null + cultist.update_inv_legcuffed() + if(istype(cultist.wear_mask, /obj/item/clothing/mask/muzzle)) + cultist.unEquip(cultist.wear_mask) + if(istype(cultist.loc, /obj/structure/closet)&&cultist.loc:welded) + cultist.loc:welded = 0 + if(istype(cultist.loc, /obj/structure/closet/secure_closet)&&cultist.loc:locked) + cultist.loc:locked = 0 + if(istype(cultist.loc, /obj/machinery/dna_scannernew)&&cultist.loc:locked) + cultist.loc:locked = 0 + for(var/mob/living/carbon/C in users) + user.take_overall_damage(15, 0) + C.say("Khari[pick("'","`")]d! Gual'te nikka!") + qdel(src) + return fizzle() + +/////////////////////////////////////////NINETEENTH RUNE + +/obj/effect/rune/proc/cultsummon() + var/mob/living/user = usr + var/list/mob/living/carbon/cultists = new + for(var/datum/mind/H in ticker.mode.cult) + if(istype(H.current,/mob/living/carbon)) + cultists+=H.current + var/list/mob/living/carbon/users = new + for(var/mob/living/carbon/C in orange(1,src)) + if(iscultist(C) && !C.stat) + users+=C + if(users.len>=3) + var/mob/living/carbon/cultist = input("Choose the one who you want to summon", "Followers of Geometer") as null|anything in (cultists - user) + if(!cultist) + return fizzle() + if(cultist == user) //just to be sure. + return + if(cultist.buckled || cultist.handcuffed || (!isturf(cultist.loc) && !istype(cultist.loc, /obj/structure/closet))) + to_chat(user, "\red You cannot summon the [cultist], for his shackles of blood are strong") + return fizzle() + cultist.loc = src.loc + cultist.lying = 1 + cultist.regenerate_icons() + for(var/mob/living/carbon/human/C in orange(1,src)) + if(iscultist(C) && !C.stat) + C.say("N'ath reth sh'yro eth d[pick("'","`")]rekkathnor!") + C.take_overall_damage(25, 0) + user.visible_message("\red Rune disappears with a flash of red light, and in its place now a body lies.", \ + "\red You are blinded by the flash of red light! After you're able to see again, you see that now instead of the rune there's a body.", \ + "\red You hear a pop and smell ozone.") + qdel(src) + return fizzle() + +/////////////////////////////////////////TWENTIETH RUNES + +/obj/effect/rune/proc/deafen() + if(istype(src,/obj/effect/rune)) + var/affected = 0 + for(var/mob/living/carbon/C in range(7,src)) + if(iscultist(C)) + continue + var/obj/item/weapon/nullrod/N = locate() in C + if(N) + continue + C.AdjustEarDeaf(50) + C.show_message("\red The world around you suddenly becomes quiet.", 3) + affected++ + if(prob(1)) + C.disabilities |= DEAF + if(affected) + usr.say("Sti[pick("'","`")] kaliedir!") + to_chat(usr, "\red The world becomes quiet as the deafening rune dissipates into fine dust.") + qdel(src) + else + return fizzle() + else + var/affected = 0 + for(var/mob/living/carbon/C in range(7,usr)) + if(iscultist(C)) + continue + var/obj/item/weapon/nullrod/N = locate() in C + if(N) + continue + C.AdjustEarDeaf(30) + //talismans is weaker. + C.show_message("\red The world around you suddenly becomes quiet.", 3) + affected++ + if(affected) + usr.whisper("Sti[pick("'","`")] kaliedir!") + to_chat(usr, "\red Your talisman turns into gray dust, deafening everyone around.") + for(var/mob/V in orange(1,src)) + if(!(iscultist(V))) + V.show_message("\red Dust flows from [usr]'s hands for a moment, and the world suddenly becomes quiet..", 3) + return + +/obj/effect/rune/proc/blind() + if(istype(src,/obj/effect/rune)) + var/affected = 0 + for(var/mob/living/carbon/C in viewers(src)) + if(iscultist(C)) + continue + var/obj/item/weapon/nullrod/N = locate() in C + if(N) + continue + C.AdjustEyeBlurry(50) + C.AdjustEyeBlind(20) + if(prob(5)) + C.BecomeNearsighted() + if(prob(10)) + C.BecomeBlind() + C.show_message("\red Suddenly you see red flash that blinds you.", 3) + affected++ + if(affected) + usr.say("Sti[pick("'","`")] kaliesin!") + to_chat(usr, "\red The rune flashes, blinding those who not follow the Nar-Sie, and dissipates into fine dust.") + qdel(src) + else + return fizzle() + else + var/affected = 0 + for(var/mob/living/carbon/C in view(2,usr)) + if(iscultist(C)) + continue + var/obj/item/weapon/nullrod/N = locate() in C + if(N) + continue + C.AdjustEyeBlurry(30) + C.AdjustEyeBlind(10) + //talismans is weaker. + affected++ + C.show_message("\red You feel a sharp pain in your eyes, and the world disappears into darkness..", 3) + if(affected) + usr.whisper("Sti[pick("'","`")] kaliesin!") + to_chat(usr, "\red Your talisman turns into gray dust, blinding those who not follow the Nar-Sie.") + return + + +/obj/effect/rune/proc/bloodboil() //cultists need at least one DANGEROUS rune. Even if they're all stealthy. +/* + var/list/mob/living/carbon/cultists = new + for(var/datum/mind/H in ticker.mode.cult) + if(istype(H.current,/mob/living/carbon)) + cultists+=H.current +*/ + var/culcount = 0 //also, wording for it is old wording for obscure rune, which is now hide-see-blood. +// var/list/cultboil = list(cultists-usr) //and for this words are destroy-see-blood. + for(var/mob/living/carbon/C in orange(1,src)) + if(iscultist(C) && !C.stat) + culcount++ + if(culcount>=3) + for(var/mob/living/carbon/M in viewers(usr)) if(iscultist(M)) - M.say("TOK-LYR RQA-NAP SHA-NEX!!") - world << 'sound/effects/dimensional_rend.ogg' - to_chat(world, "A hellish cacaphony bombards from all around as something awful tears through the world...") - icon_state = "rune_large_distorted" - sleep(55) - to_chat(world, "\"LIBREATE TE EX INFERIS!\"")//Fethas note:I COULDN'T HELP IT OKAY?! - visible_message("[src] melts away into blood, and three horrific figures emerge from within!") - var/turf/T = get_turf(src) - new /mob/living/simple_animal/slaughter/cult(T) - new /mob/living/simple_animal/slaughter/cult(T, pick(NORTH, EAST, SOUTH, WEST)) - new /mob/living/simple_animal/slaughter/cult(T, pick(NORTHEAST, SOUTHEAST, NORTHWEST, SOUTHWEST)) - cult_mode.demons_summoned = 1 - shuttle_master.emergency.request(null, 0.5,null) - cult_mode.third_phase() + continue + var/obj/item/weapon/nullrod/N = locate() in M + if(N) + continue + cult_log(": Blood Boil damaged [key_name_admin(M)].") + M.take_overall_damage(51,51) + to_chat(M, "\red Your blood boils!") + if(prob(5)) + spawn(5) + M.gib() + for(var/obj/effect/rune/R in view(src)) + if(prob(10)) + explosion(R.loc, -1, 0, 1, 5) + for(var/mob/living/carbon/human/C in orange(1,src)) + if(iscultist(C) && !C.stat) + C.say("Dedo ol[pick("'","`")]btoh!") + C.take_overall_damage(15, 0) + qdel(src) + else + return fizzle() + return + +// WIP rune, I'll wait for Rastaf0 to add limited blood. + +/obj/effect/rune/proc/burningblood() + var/culcount = 0 + for(var/mob/living/carbon/C in orange(1,src)) + if(iscultist(C) && !C.stat) + culcount++ + if(culcount >= 5) + for(var/obj/effect/rune/R in world) + if(R.blood_DNA == src.blood_DNA) + for(var/mob/living/M in orange(2,R)) + M.take_overall_damage(0,15) + if(R.invisibility>M.see_invisible) + to_chat(M, "\red Aargh it burns!") + else + to_chat(M, "\red Rune suddenly ignites, burning you!") + var/turf/T = get_turf(R) + T.hotspot_expose(700,125) + for(var/obj/effect/decal/cleanable/blood/B in world) + if(B.blood_DNA == src.blood_DNA) + for(var/mob/living/M in orange(1,B)) + M.take_overall_damage(0,5) + to_chat(M, "\red Blood suddenly ignites, burning you!") + var/turf/T = get_turf(B) + T.hotspot_expose(700,125) + qdel(B) qdel(src) +////////// Rune 24 (counting burningblood, which kinda doesnt work yet.) -//Rite of Resurrection: Requires two corpses. Revives one and gibs the other. -/obj/effect/rune/raise_dead - cultist_name = "Rite of Resurrection" - cultist_desc = "requires two corpses, one on the rune and one adjacent to the rune. The one on the rune is brought to life, the other is turned to ash." - invocation = null //Depends on the name of the user - see below - icon_state = "1" +/obj/effect/rune/proc/runestun(var/mob/living/T as mob) + if(istype(src,/obj/effect/rune)) ///When invoked as rune, flash and stun everyone around. + usr.say("Fuu ma[pick("'","`")]jin!") + for(var/mob/living/L in viewers(src)) -/obj/effect/rune/raise_dead/invoke(var/list/invokers) - var/turf/T = get_turf(src) - var/mob/living/mob_to_sacrifice - var/mob/living/mob_to_revive - var/list/potential_sacrifice_mobs = list() - var/list/potential_revive_mobs = list() - var/mob/living/user = invokers[1] - if(rune_in_use) + if(iscarbon(L)) + var/mob/living/carbon/C = L + C.flash_eyes() + if(C.stuttering < 1 && (!(HULK in C.mutations))) + C.stuttering = 1 + C.Weaken(1) + C.Stun(1) + C.show_message("\red The rune explodes in a bright flash.", 3) + + else if(issilicon(L)) + var/mob/living/silicon/S = L + S.Weaken(5) + S.show_message("\red BZZZT... The rune has exploded in a bright flash.", 3) + qdel(src) + else ///When invoked as talisman, stun and mute the target mob. + usr.say("Dream sign ''Evil sealing talisman'[pick("'","`")]!") + var/obj/item/weapon/nullrod/N = locate() in T + if(N) + for(var/mob/O in viewers(T, null)) + O.show_message(text("[] invokes a talisman at [], but they are unaffected!", usr, T), 1) + else + for(var/mob/O in viewers(T, null)) + O.show_message(text("[] invokes a talisman at []", usr, T), 1) + + if(issilicon(T)) + T.Weaken(10) + + else if(iscarbon(T)) + var/mob/living/carbon/C = T + C.flash_eyes() + if(!(HULK in C.mutations)) + C.AdjustSilence(15) + C.Weaken(10) + C.Stun(10) return - for(var/mob/living/M in orange(1,src)) - if(M.stat == DEAD && !iscultist(M)) - potential_sacrifice_mobs.Add(M) - if(!potential_sacrifice_mobs.len) - to_chat(user, "There are no eligible sacrifices nearby!") - log_game("Raise Dead rune failed - no catalyst corpse") - return - mob_to_sacrifice = input(user, "Choose a corpse to sacrifice.", "Corpse to Sacrifice") as null|anything in potential_sacrifice_mobs - if(!Adjacent(user) || !src || qdeleted(src) || user.incapacitated() || !mob_to_revive || !mob_to_sacrifice || rune_in_use) - return - for(var/mob/living/M in T.contents) - if(M.stat == DEAD) - potential_revive_mobs.Add(M) - if(!potential_revive_mobs.len) - to_chat(user, "There is no eligible revival target on the rune!") - log_game("Raise Dead rune failed - no corpse to revived") - return - mob_to_revive = input(user, "Choose a corpse to revive.", "Corpse to Revive") as null|anything in potential_revive_mobs - if(!Adjacent(user) || !src || qdeleted(src) || user.incapacitated() || rune_in_use) - return - if(!in_range(mob_to_sacrifice,src)) - to_chat(user, "The sacrificial target has been moved!") - fail_invoke() - log_game("Raise Dead rune failed - catalyst corpse moved") - return - if(!(mob_to_revive in T.contents)) - to_chat(user, "The corpse to revive has been moved!") - fail_invoke() - log_game("Raise Dead rune failed - revival target moved") - return - if(mob_to_sacrifice.stat != DEAD) - to_chat(user, "The sacrificial target must be dead!") - fail_invoke() - log_game("Raise Dead rune failed - catalyst corpse is not dead") - return - rune_in_use = 1 - if(user.name == "Herbert West") - user.say("To life, to life, I bring them!") + +/////////////////////////////////////////TWENTY-FIFTH RUNE + +/obj/effect/rune/proc/armor() + var/mob/living/carbon/human/user = usr + if(istype(src,/obj/effect/rune)) + usr.say("N'ath reth sh'yro eth d[pick("'","`")]raggathnor!") else - user.say("Pasnar val'keriam usinar. Savrae ines amutan. Yam'toth remium il'tarat!") - ..() - mob_to_sacrifice.visible_message("[mob_to_sacrifice]'s body rises into the air, connected to [mob_to_revive] by a glowing tendril!") - mob_to_revive.Beam(mob_to_sacrifice,icon_state="sendbeam",icon='icons/effects/effects.dmi',time=20) - sleep(20) - if(!mob_to_sacrifice || !in_range(mob_to_sacrifice, src)) - mob_to_sacrifice.visible_message("[mob_to_sacrifice] disintegrates into a pile of bones") - return - mob_to_sacrifice.dust() - if(!mob_to_revive || mob_to_revive.stat != DEAD) - visible_message("The glowing tendril snaps against the rune with a shocking crack.") - rune_in_use = 0 - return - mob_to_revive.revive() //This does remove disabilities and such, but the rune might actually see some use because of it! - to_chat(mob_to_revive, "\"PASNAR SAVRAE YAM'TOTH. Arise.\"") - mob_to_revive.visible_message("[mob_to_revive] draws in a huge breath, red light shining from their eyes.", \ - "You awaken suddenly from the void. You're alive!") - rune_in_use = 0 + usr.whisper("N'ath reth sh'yro eth d[pick("'","`")]raggathnor!") + usr.visible_message("\red The rune disappears with a flash of red light, and a set of armor appears on [usr]...", \ + "\red You are blinded by the flash of red light! After you're able to see again, you see that you are now wearing a set of armor.") + user.equip_to_slot_or_del(new /obj/item/clothing/suit/hooded/cultrobes/alt(user), slot_wear_suit) + user.equip_to_slot_or_del(new /obj/item/clothing/shoes/cult(user), slot_shoes) + user.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/cultpack(user), slot_back) + //the above update their overlay icons cache but do not call update_icons() + //the below calls update_icons() at the end, which will update overlay icons by using the (now updated) cache + user.put_in_hands(new /obj/item/weapon/melee/cultblade(user)) //put in hands or on floor -/obj/effect/rune/raise_dead/fail_invoke() - ..() - for(var/mob/living/M in range(1,src)) - if(M.stat == DEAD) - M.visible_message("[M] twitches.") - - -//Rite of Disruption: Emits an EMP blast. -/obj/effect/rune/emp - cultist_name = "Rite of Disruption" - cultist_desc = "emits a large electromagnetic pulse, increasing in size for each cultist invoking it, hindering electronics and disabling silicons." - invocation = "Ta'gh fara'qha fel d'amar det!" - icon_state = "5" - allow_excess_invokers = 1 - -/obj/effect/rune/emp/invoke(var/list/invokers) - var/turf/E = get_turf(src) - ..() - visible_message("[src] glows blue for a moment before vanishing.") - switch(invokers.len) - if(1 to 2) - playsound(E, 'sound/items/Welder2.ogg', 25, 1) - for(var/M in invokers) - to_chat(M, "You feel a minute vibration pass through you...") - if(3 to 6) - playsound(E, 'sound/effects/EMPulse.ogg', 50, 1) - for(var/M in invokers) - to_chat(M, "Your hair stands on end as a shockwave eminates from the rune!") - if(7 to INFINITY) - playsound(E, 'sound/effects/EMPulse.ogg', 100, 1) - for(var/M in invokers) - var/mob/living/L = M - to_chat(L, "You chant in unison and a colossal burst of energy knocks you backward!") - L.Weaken(2) - qdel(src) //delete before pulsing because it's a delay reee - empulse(E, 9*invokers.len, 12*invokers.len) // Scales now, from a single room to most of the station depending on # of chanters - -//Rite of Astral Communion: Separates one's spirit from their body. They will take damage while it is active. -/obj/effect/rune/astral - cultist_name = "Astral Communion" - cultist_desc = "severs the link between one's spirit and body. This effect is taxing and one's physical body will take damage while this is active." - invocation = "Fwe'sh mah erl nyag r'ya!" - icon_state = "6" - rune_in_use = 0 //One at a time, please! - construct_invoke = 0 - var/mob/living/affecting = null - -/obj/effect/rune/astral/examine(mob/user) - ..() - if(affecting) - to_chat(user, "A translucent field encases [user] above the rune!") - -/obj/effect/rune/astral/can_invoke(mob/living/user) - if(rune_in_use) - to_chat(user, "[src] cannot support more than one body!") - log_game("Astral Communion rune failed - more than one user") - return list() - var/turf/T = get_turf(src) - if(!user in T.contents) - to_chat(user, "You must be standing on top of [src]!") - log_game("Astral Communion rune failed - user not standing on rune") - return list() - return ..() - -/obj/effect/rune/astral/invoke(var/list/invokers) - var/mob/living/user = invokers[1] - ..() - var/turf/T = get_turf(src) - rune_in_use = 1 - affecting = user - user.color = "#7e1717" - user.visible_message("[user] freezes statue-still, glowing an unearthly red.", \ - "You see what lies beyond. All is revealed. While this is a wondrous experience, your physical form will waste away in this state. Hurry...") - user.ghostize(1) - while(user) - if(!affecting) - visible_message("[src] pulses gently before falling dark.") - affecting = null //In case it's assigned to a number or something - rune_in_use = 0 - return - affecting.apply_damage(1, BRUTE) - if(!(user in T.contents)) - user.visible_message("A spectral tendril wraps around [user] and pulls them back to the rune!") - Beam(user,icon_state="drainbeam",icon='icons/effects/effects.dmi',time=2) - user.forceMove(get_turf(src)) //NO ESCAPE :^) - if(user.key) - user.visible_message("[user] slowly relaxes, the glow around them dimming.", \ - "You are re-united with your physical form. [src] releases its hold over you.") - user.color = initial(user.color) - user.Weaken(3) - rune_in_use = 0 - affecting = null - return - if(user.stat == UNCONSCIOUS) - if(prob(10)) - var/mob/dead/observer/G = user.get_ghost() - if(G) - to_chat(G, "You feel the link between you and your body weakening... you must hurry!") - if(user.stat == DEAD) - user.color = initial(user.color) - rune_in_use = 0 - affecting = null - var/mob/dead/observer/G = user.get_ghost() - if(G) - to_chat(G, "You suddenly feel your physical form pass on. [src]'s exertion has killed you!") - return - sleep(10) - rune_in_use = 0 - - -//Rite of the Corporeal Shield: When invoked, becomes solid and cannot be passed. Invoke again to undo. -/obj/effect/rune/wall - cultist_name = "Rite of the Corporeal Shield" - cultist_desc = "when invoked, makes an invisible wall to block passage. Can be invoked again to reverse this." - invocation = "Khari'd! Eske'te tannin!" - icon_state = "1" - -/obj/effect/rune/wall/examine(mob/user) - ..() - if(density) - to_chat(user, "There is a barely perceptible shimmering of the air above [src].") - -/obj/effect/rune/wall/invoke(var/list/invokers) - var/mob/living/user = invokers[1] - ..() - density = !density - user.visible_message("[user] places their hands on [src], and [density ? "the air above it begins to shimmer" : "the shimmer above it fades"].", \ - "You channel your life energy into [src], [density ? "preventing" : "allowing"] passage above it.") - if(iscarbon(user)) - var/mob/living/carbon/C = user - C.apply_damage(2, BRUTE, pick("l_arm", "r_arm")) - - -//Rite of Joined Souls: Summons a single cultist. -/obj/effect/rune/summon - cultist_name = "Rite of Joined Souls" - cultist_desc = "summons a single cultist to the rune. Requires 2 invokers." - invocation = "N'ath reth sh'yro eth d'rekkathnor!" - req_cultists = 2 - allow_excess_invokers = 1 - icon_state = "5" - -/obj/effect/rune/summon/invoke(var/list/invokers) - var/mob/living/user = invokers[1] - var/list/cultists = list() - for(var/datum/mind/M in ticker.mode.cult) - if(!(M.current in invokers) && M.current.stat != DEAD) - cultists |= M.current - var/mob/living/cultist_to_summon = input(user, "Who do you wish to call to [src]?", "Followers of [ticker.mode.cultdat.entity_title3]") as null|anything in cultists - if(!Adjacent(user) || !src || qdeleted(src) || user.incapacitated()) - return - if(!cultist_to_summon) - to_chat(user, "You require a summoning target!") - fail_invoke() - log_game("Summon Cultist rune failed - no target") - return - if(!iscultist(cultist_to_summon)) - to_chat(user, "[cultist_to_summon] is not a follower of [ticker.mode.cultdat.entity_title3]!") - fail_invoke() - log_game("Summon Cultist rune failed - no target") - return - if(!is_level_reachable(cultist_to_summon.z)) - to_chat(user, "[cultist_to_summon] is not in our dimension!") - fail_invoke() - log_game("Summon Cultist rune failed - target in away mission") - return - cultist_to_summon.visible_message("[cultist_to_summon] suddenly disappears in a flash of red light!", \ - "Overwhelming vertigo consumes you as you are hurled through the air!") - ..() - visible_message("A foggy shape materializes atop [src] and solidifes into [cultist_to_summon]!") - user.apply_damage(10, BRUTE, "head") - cultist_to_summon.forceMove(get_turf(src)) qdel(src) - -//Rite of Boiling Blood: Deals extremely high amounts of damage to non-cultists nearby -/obj/effect/rune/blood_boil - cultist_name = "Boil Blood" - cultist_desc = "boils the blood of non-believers who can see the rune, dealing extreme amounts of damage. Requires 3 invokers." - invocation = "Dedo ol'btoh!" - icon_state = "4" - construct_invoke = 0 - req_cultists = 3 - -/obj/effect/rune/blood_boil/do_invoke_glow() return - -/obj/effect/rune/blood_boil/invoke(var/list/invokers) - ..() - var/turf/T = get_turf(src) - visible_message("[src] briefly bubbles before exploding!") - for(var/mob/living/carbon/C in viewers(T)) - if(!iscultist(C)) - var/obj/item/weapon/nullrod/N = C.null_rod_check() - if(N) - to_chat(C, "\The [N] suddenly burns hotly before returning to normal!") - continue - to_chat(C, "Your blood boils in your veins!") - C.take_overall_damage(45,45) - C.Stun(7) - for(var/M in invokers) - var/mob/living/L = M - L.apply_damage(15, BRUTE, pick("l_arm", "r_arm")) - to_chat(L,"[src] saps your strength!") - qdel(src) - explosion(T, -1, 0, 1, 5) - -//Deals brute damage to all targets on the rune and heals the invoker for each target drained. -/obj/effect/rune/leeching - cultist_name = "Drain Life" - cultist_desc = "drains the life of all targets on the rune, restoring life to the user." - invocation = "Yu'gular faras desdae. Umathar uf'kal thenar!" - icon_state = "3" - -/obj/effect/rune/leeching/can_invoke(mob/living/user) - if(world.time <= user.next_move) - return list() - var/turf/T = get_turf(src) - var/list/potential_targets = list() - for(var/mob/living/carbon/M in T.contents - user) - if(M.stat != DEAD) - potential_targets += M - if(!potential_targets.len) - to_chat(user, "There must be at least one valid target on the rune!") - log_game("Leeching rune failed - no valid targets") - return list() - return ..() - -/obj/effect/rune/leeching/invoke(var/list/invokers) - var/mob/living/user = invokers[1] - user.changeNext_move(CLICK_CD_MELEE) - ..() - var/turf/T = get_turf(src) - for(var/mob/living/carbon/M in T.contents - user) - if(M.stat != DEAD) - var/drained_amount = rand(10,20) - M.apply_damage(drained_amount, BRUTE, "chest") - user.adjustBruteLoss(-drained_amount) - to_chat(M, "You feel extremely weak.") - user.Beam(T,icon_state="drainbeam",icon='icons/effects/effects.dmi',time=5) - user.visible_message("Blood flows from the rune into [user]!", \ - "Blood flows into you, healing your wounds and revitalizing your spirit.") - - -//Rite of Spectral Manifestation: Summons a ghost on top of the rune as a cultist human with no items. User must stand on the rune at all times, and takes damage for each summoned ghost. -/obj/effect/rune/manifest - cultist_name = "Rite of Spectral Manifestation" - cultist_desc = "manifests a spirit as a servant of your god. The invoker must not move from atop the rune, and will take damage for each summoned spirit." - invocation = "Gal'h'rfikk harfrandid mud'gib!" //how the fuck do you pronounce this - icon_state = "6" - construct_invoke = 0 - color = rgb(200, 0, 0) - -/obj/effect/rune/manifest/New(loc) - ..() - cultist_desc = "manifests a spirit as a servant of [ticker.mode.cultdat.entity_title3]. The invoker must not move from atop the rune, and will take damage for each summoned spirit." - - notify_ghosts("Manifest rune created in [get_area(src)].", 'sound/effects/ghost2.ogg', source = src) - -/obj/effect/rune/manifest/can_invoke(mob/living/user) - if(!(user in get_turf(src))) - to_chat(user,"You must be standing on [src]!") - fail_invoke() - log_game("Manifest rune failed - user not standing on rune") - return list() - var/list/ghosts_on_rune = list() - for(var/mob/dead/observer/O in get_turf(src)) - if(O.client && !jobban_isbanned(O, ROLE_CULTIST)) - ghosts_on_rune |= O - if(!ghosts_on_rune.len) - to_chat(user, "There are no spirits near [src]!") - fail_invoke() - log_game("Manifest rune failed - no nearby ghosts") - return list() - return ..() - -/obj/effect/rune/manifest/invoke(var/list/invokers) - var/mob/living/user = invokers[1] - var/list/ghosts_on_rune = list() - for(var/mob/dead/observer/O in get_turf(src)) - if(O.client && !jobban_isbanned(O, ROLE_CULTIST)) - ghosts_on_rune |= O - var/mob/dead/observer/ghost_to_spawn = pick(ghosts_on_rune) - var/mob/living/carbon/human/new_human = new(get_turf(src)) - new_human.real_name = ghost_to_spawn.real_name - new_human.alpha = 150 //Makes them translucent - ..() - visible_message("A cloud of red mist forms above [src], and from within steps... a man.") - to_chat(user, "Your blood begins flowing into [src]. You must remain in place and conscious to maintain the forms of those summoned. This will hurt you slowly but surely...") - var/obj/machinery/shield/N = new(get_turf(src)) - N.name = "Invoker's Shield" - N.desc = "A weak shield summoned by cultists to protect them while they carry out delicate rituals" - N.color = "red" - N.health = 20 - N.mouse_opacity = 0 - new_human.key = ghost_to_spawn.key - ticker.mode.add_cultist(new_human.mind, 0) - to_chat(new_human, "You are a servant of [ticker.mode.cultdat.entity_title3]. You have been made semi-corporeal by the cult of [ticker.mode.cultdat.entity_name], and you are to serve them at all costs.") - - while(user in get_turf(src)) - if(user.stat) - break - user.apply_damage(0.1, BRUTE) - sleep(3) - - qdel(N) - if(new_human) - new_human.visible_message("[new_human] suddenly dissolves into bones and ashes.", \ - "Your link to the world fades. Your form breaks apart.") - for(var/obj/I in new_human) - new_human.unEquip(I) - new_human.dust() \ No newline at end of file diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index d13273eaae1..680ae07ff93 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -1,1161 +1,2805 @@ -/* - New methods: - pulse - sends a pulse into a wire for hacking purposes - cut - cuts a wire and makes any necessary state changes - mend - mends a wire and makes any necessary state changes - canAIControl - 1 if the AI can control the airlock, 0 if not (then check canAIHack to see if it can hack in) - canAIHack - 1 if the AI can hack into the airlock to recover control, 0 if not. Also returns 0 if the AI does not *need* to hack it. - arePowerSystemsOn - 1 if the main or backup power are functioning, 0 if not. Does not check whether the power grid is charged or an APC has equipment on or anything like that. (Check (stat & NOPOWER) for that) - requiresIDs - 1 if the airlock is requiring IDs, 0 if not - isAllPowerCut - 1 if the main and backup power both have cut wires. - regainMainPower - handles the effect of main power coming back on. - loseMainPower - handles the effect of main power going offline. Usually (if one isn't already running) spawn a thread to count down how long it will be offline - counting down won't happen if main power was completely cut along with backup power, though, the thread will just sleep. - loseBackupPower - handles the effect of backup power going offline. - regainBackupPower - handles the effect of main power coming back on. - shock - has a chance of electrocuting its target. -*/ - - -// Wires for the airlock are located in the datum folder, inside the wires datum folder. - - -/obj/machinery/door/airlock - name = "airlock" - icon = 'icons/obj/doors/Doorint.dmi' - icon_state = "door_closed" - power_channel = ENVIRON - - var/aiControlDisabled = 0 //If 1, AI control is disabled until the AI hacks back in and disables the lock. If 2, the AI has bypassed the lock. If -1, the control is enabled but the AI had bypassed it earlier, so if it is disabled again the AI would have no trouble getting back in. - var/hackProof = 0 // if 1, this door can't be hacked by the AI - var/electrified_until = 0 // World time when the door is no longer electrified. -1 if it is permanently electrified until someone fixes it. - var/main_power_lost_until = 0 //World time when main power is restored. - var/backup_power_lost_until = -1 //World time when backup power is restored. - var/electrified_timer = null - var/main_power_timer = null - var/backup_power_timer = null - var/spawnPowerRestoreRunning = 0 - var/welded = null - var/locked = 0 - var/lights = 1 // bolt lights show by default - var/datum/wires/airlock/wires = null - var/aiDisabledIdScanner = 0 - var/aiHacking = 0 - var/obj/machinery/door/airlock/closeOther = null - var/closeOtherId = null - var/lockdownbyai = 0 - var/assembly_type = /obj/structure/door_assembly - var/mineral = null - var/justzap = 0 - var/safe = 1 - normalspeed = 1 - var/obj/item/weapon/airlock_electronics/electronics = null - var/hasShocked = 0 //Prevents multiple shocks from happening - var/frozen = 0 //special condition for airlocks that are frozen shut, this will look weird on not normal airlocks because of a lack of special overlays. - autoclose = 1 - explosion_block = 1 - var/doorOpen = 'sound/machines/airlock.ogg' - var/doorClose = 'sound/machines/airlock.ogg' - var/doorDeni = 'sound/machines/DeniedBeep.ogg' // i'm thinkin' Deni's - var/boltUp = 'sound/machines/BoltsUp.ogg' - var/boltDown = 'sound/machines/BoltsDown.ogg' - var/is_special = 0 - - -/obj/machinery/door/airlock/command - name = "Airlock" - icon = 'icons/obj/doors/Doorcom.dmi' - assembly_type = /obj/structure/door_assembly/door_assembly_com - -/obj/machinery/door/airlock/security - name = "Airlock" - icon = 'icons/obj/doors/Doorsec.dmi' - assembly_type = /obj/structure/door_assembly/door_assembly_sec - -/obj/machinery/door/airlock/engineering - name = "Airlock" - icon = 'icons/obj/doors/Dooreng.dmi' - assembly_type = /obj/structure/door_assembly/door_assembly_eng - -/obj/machinery/door/airlock/medical - name = "Airlock" - icon = 'icons/obj/doors/Doormed.dmi' - assembly_type = /obj/structure/door_assembly/door_assembly_med - -/obj/machinery/door/airlock/maintenance - name = "Maintenance Access" - icon = 'icons/obj/doors/Doormaint.dmi' - assembly_type = /obj/structure/door_assembly/door_assembly_mai - -/obj/machinery/door/airlock/external - name = "External Airlock" - icon = 'icons/obj/doors/Doorext.dmi' - assembly_type = /obj/structure/door_assembly/door_assembly_ext - -/obj/machinery/door/airlock/glass - name = "Glass Airlock" - icon = 'icons/obj/doors/Doorglass.dmi' - opacity = 0 - glass = 1 - doorOpen = 'sound/machines/windowdoor.ogg' - doorClose = 'sound/machines/windowdoor.ogg' - -/obj/machinery/door/airlock/centcom - name = "Airlock" - icon = 'icons/obj/doors/Doorele.dmi' - opacity = 0 - -/obj/machinery/door/airlock/vault - name = "Vault" - icon = 'icons/obj/doors/vault.dmi' - opacity = 1 - assembly_type = /obj/structure/door_assembly/door_assembly_highsecurity //Until somebody makes better sprites. - explosion_block = 2 - -/obj/machinery/door/airlock/freezer - name = "Freezer Airlock" - icon = 'icons/obj/doors/Doorfreezer.dmi' - opacity = 1 - assembly_type = /obj/structure/door_assembly/door_assembly_fre - -/obj/machinery/door/airlock/hatch - name = "Airtight Hatch" - icon = 'icons/obj/doors/Doorhatchele.dmi' - opacity = 1 - assembly_type = /obj/structure/door_assembly/door_assembly_hatch - -/obj/machinery/door/airlock/hatch/gamma - name = "Gamma Level Hatch" - hackProof = 1 - aiControlDisabled = 1 - unacidable = 1 - is_special = 1 - -/obj/machinery/door/airlock/maintenance_hatch - name = "Maintenance Hatch" - icon = 'icons/obj/doors/Doorhatchmaint2.dmi' - opacity = 1 - assembly_type = /obj/structure/door_assembly/door_assembly_mhatch - -/obj/machinery/door/airlock/glass_command - name = "Maintenance Hatch" - icon = 'icons/obj/doors/Doorcomglass.dmi' - opacity = 0 - assembly_type = /obj/structure/door_assembly/door_assembly_com - glass = 1 - -/obj/machinery/door/airlock/glass_engineering - name = "Maintenance Hatch" - icon = 'icons/obj/doors/Doorengglass.dmi' - opacity = 0 - assembly_type = /obj/structure/door_assembly/door_assembly_eng - glass = 1 - -/obj/machinery/door/airlock/glass_security - name = "Maintenance Hatch" - icon = 'icons/obj/doors/Doorsecglass.dmi' - opacity = 0 - assembly_type = /obj/structure/door_assembly/door_assembly_sec - glass = 1 - -/obj/machinery/door/airlock/glass_medical - name = "Maintenance Hatch" - icon = 'icons/obj/doors/Doormedglass.dmi' - opacity = 0 - assembly_type = /obj/structure/door_assembly/door_assembly_med - glass = 1 - -/obj/machinery/door/airlock/mining - name = "Mining Airlock" - icon = 'icons/obj/doors/Doormining.dmi' - assembly_type = /obj/structure/door_assembly/door_assembly_min - -/obj/machinery/door/airlock/atmos - name = "Atmospherics Airlock" - icon = 'icons/obj/doors/Dooratmo.dmi' - assembly_type = /obj/structure/door_assembly/door_assembly_atmo - -/obj/machinery/door/airlock/research - name = "Airlock" - icon = 'icons/obj/doors/Doorresearch.dmi' - assembly_type = /obj/structure/door_assembly/door_assembly_research - -/obj/machinery/door/airlock/glass_research - name = "Maintenance Hatch" - icon = 'icons/obj/doors/Doorresearchglass.dmi' - opacity = 0 - assembly_type = /obj/structure/door_assembly/door_assembly_research - glass = 1 - heat_proof = 1 - -/obj/machinery/door/airlock/glass_mining - name = "Maintenance Hatch" - icon = 'icons/obj/doors/Doorminingglass.dmi' - opacity = 0 - assembly_type = /obj/structure/door_assembly/door_assembly_min - glass = 1 - -/obj/machinery/door/airlock/glass_atmos - name = "Maintenance Hatch" - icon = 'icons/obj/doors/Dooratmoglass.dmi' - opacity = 0 - assembly_type = /obj/structure/door_assembly/door_assembly_atmo - glass = 1 - -/obj/machinery/door/airlock/gold - name = "Gold Airlock" - icon = 'icons/obj/doors/Doorgold.dmi' - mineral = "gold" - -/obj/machinery/door/airlock/silver - name = "Silver Airlock" - icon = 'icons/obj/doors/Doorsilver.dmi' - mineral = "silver" - -/obj/machinery/door/airlock/diamond - name = "Diamond Airlock" - icon = 'icons/obj/doors/Doordiamond.dmi' - mineral = "diamond" - -/obj/machinery/door/airlock/uranium - name = "Uranium Airlock" - desc = "And they said I was crazy." - icon = 'icons/obj/doors/Dooruranium.dmi' - mineral = "uranium" - var/event_step = 20 - -/obj/machinery/door/airlock/uranium/New() - ..() - addtimer(src, "radiate", event_step) - -/obj/machinery/door/airlock/uranium/proc/radiate() - if(prob(50)) - for(var/mob/living/L in range (3,src)) - L.apply_effect(15,IRRADIATE,0) - addtimer(src, "radiate", event_step) - -/obj/machinery/door/airlock/plasma - name = "plasma airlock" - desc = "No way this can end badly." - icon = 'icons/obj/doors/Doorplasma.dmi' - mineral = "plasma" - -/obj/machinery/door/airlock/plasma/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume) - if(exposed_temperature > 300) - PlasmaBurn(exposed_temperature) - -/obj/machinery/door/airlock/plasma/proc/ignite(exposed_temperature) - if(exposed_temperature > 300) - PlasmaBurn(exposed_temperature) - -/obj/machinery/door/airlock/plasma/proc/PlasmaBurn(temperature) - atmos_spawn_air(SPAWN_HEAT | SPAWN_TOXINS, 500) - new/obj/structure/door_assembly( src.loc ) - qdel(src) - -/obj/machinery/door/airlock/plasma/BlockSuperconductivity() //we don't stop the heat~ - return 0 - -/obj/machinery/door/airlock/bananium - name = "Bananium Airlock" - icon = 'icons/obj/doors/Doorbananium.dmi' - mineral = "bananium" - doorOpen = 'sound/items/bikehorn.ogg' - doorClose = 'sound/items/bikehorn.ogg' - -/obj/machinery/door/airlock/tranquillite - name = "Tranquillite Airlock" - icon = 'icons/obj/doors/Doorfreezer.dmi' - mineral = "tranquillite" - doorOpen = null - doorClose = null - -/obj/machinery/door/airlock/sandstone - name = "Sandstone Airlock" - icon = 'icons/obj/doors/Doorsand.dmi' - mineral = "sandstone" - -/obj/machinery/door/airlock/science - name = "Airlock" - icon = 'icons/obj/doors/Doorsci.dmi' - assembly_type = /obj/structure/door_assembly/door_assembly_science - -/obj/machinery/door/airlock/glass_science - name = "Glass Airlocks" - icon = 'icons/obj/doors/Doorsciglass.dmi' - opacity = 0 - assembly_type = /obj/structure/door_assembly/door_assembly_science - glass = 1 - -/obj/machinery/door/airlock/highsecurity - name = "High Tech Security Airlock" - icon = 'icons/obj/doors/hightechsecurity.dmi' - assembly_type = /obj/structure/door_assembly/door_assembly_highsecurity - explosion_block = 2 - -/obj/machinery/door/airlock/highsecurity/red - name = "Secure Armory Airlock" - hackProof = 1 - aiControlDisabled = 1 - -/obj/machinery/door/airlock/shuttle - name = "shuttle airlock" - icon = 'icons/obj/doors/doorshuttle.dmi' - assembly_type = /obj/structure/door_assembly/door_assembly_shuttle - -/obj/machinery/door/airlock/alien - name = "Alien Airlock" - desc = "A mysterious alien airlock with a complicated opening mechanism." - hackProof = 1 - icon = 'icons/obj/doors/Doorplasma.dmi' - is_special = 1 - -/obj/machinery/door/airlock/alien/bumpopen(mob/living/user as mob) - if(istype(user,/mob/living/carbon/alien) || isrobot(user) || isAI(user)) - ..(user) - else - to_chat(user, "You do not know how to operate this airlock's mechanism.") - return - -/obj/machinery/door/airlock/alien/attackby(C as obj, mob/user as mob, params) - if(isalien(user) || isrobot(user) || isAI(user)) - ..(C, user) - else - to_chat(user, "You do not know how to operate this airlock's mechanism.") - return - -//Cult Doors -/obj/machinery/door/airlock/cult - name = "engraved airlock" - icon = 'icons/obj/doors/Doorcult.dmi' - hackProof = 1 - aiControlDisabled = 1 - assembly_type = /obj/structure/door_assembly/door_assembly_cult - var/friendly = FALSE - var/openingoverlaytype = /obj/effect/overlay/temp/cult/door/unruned - -/obj/machinery/door/airlock/cult/narsie_act() - return - -/obj/machinery/door/airlock/cult/friendly //non cutlist can use - friendly = TRUE - -/obj/machinery/door/airlock/cult/runed - name = "runed airlock" - icon = 'icons/obj/doors/Doorcultruned.dmi' - openingoverlaytype = /obj/effect/overlay/temp/cult/door/unruned - assembly_type = /obj/structure/door_assembly/door_assembly_cultruned - -/obj/machinery/door/airlock/cult/bumpopen(mob/living/M as mob) - - if(friendly || iscultist(M) || istype(M, /mob/living/simple_animal/shade) || istype(M,/mob/living/simple_animal/hostile/construct)) - new openingoverlaytype(loc) - ..(M) - else - new /obj/effect/overlay/temp/cult/sac(loc) - var/atom/throwtarget - throwtarget = get_edge_target_turf(src, get_dir(src, get_step_away(M, src))) - M << pick(sound('sound/hallucinations/turn_around1.ogg',0,1,50), sound('sound/hallucinations/turn_around2.ogg',0,1,50)) - M.Weaken(2) - M.throw_at(throwtarget, 5, 1,src) - return - -/obj/machinery/door/airlock/cult/attackby(C as obj, mob/M as mob, params) - - if(friendly || iscultist(M) || istype(M, /mob/living/simple_animal/shade) || istype(M,/mob/living/simple_animal/hostile/construct)) - new openingoverlaytype(loc) - ..(M) - else - new /obj/effect/overlay/temp/cult/sac(loc) - var/atom/throwtarget - throwtarget = get_edge_target_turf(src, get_dir(src, get_step_away(M, src))) - M << pick(sound('sound/hallucinations/turn_around1.ogg',0,1,50), sound('sound/hallucinations/turn_around2.ogg',0,1,50)) - M.Weaken(2) - M.throw_at(throwtarget, 5, 1,src) - return - - - -/* -About the new airlock wires panel: -* An airlock wire dialog can be accessed by the normal way or by using wirecutters or a multitool on the door while the wire-panel is open. This would show the following wires, which you can either wirecut/mend or send a multitool pulse through. There are 9 wires. -* one wire from the ID scanner. Sending a pulse through this flashes the red light on the door (if the door has power). If you cut this wire, the door will stop recognizing valid IDs. (If the door has 0000 access, it still opens and closes, though) -* two wires for power. Sending a pulse through either one causes a breaker to trip, disabling the door for 10 seconds if backup power is connected, or 1 minute if not (or until backup power comes back on, whichever is shorter). Cutting either one disables the main door power, but unless backup power is also cut, the backup power re-powers the door in 10 seconds. While unpowered, the door may be \red open, but bolts-raising will not work. Cutting these wires may electrocute the user. -* one wire for door bolts. Sending a pulse through this drops door bolts (whether the door is powered or not) or raises them (if it is). Cutting this wire also drops the door bolts, and mending it does not raise them. If the wire is cut, trying to raise the door bolts will not work. -* two wires for backup power. Sending a pulse through either one causes a breaker to trip, but this does not disable it unless main power is down too (in which case it is disabled for 1 minute or however long it takes main power to come back, whichever is shorter). Cutting either one disables the backup door power (allowing it to be crowbarred open, but disabling bolts-raising), but may electocute the user. -* one wire for opening the door. Sending a pulse through this while the door has power makes it open the door if no access is required. -* one wire for AI control. Sending a pulse through this blocks AI control for a second or so (which is enough to see the AI control light on the panel dialog go off and back on again). Cutting this prevents the AI from controlling the door unless it has hacked the door through the power connection (which takes about a minute). If both main and backup power are cut, as well as this wire, then the AI cannot operate or hack the door at all. -* one wire for electrifying the door. Sending a pulse through this electrifies the door for 30 seconds. Cutting this wire electrifies the door, so that the next person to touch the door without insulated gloves gets electrocuted. (Currently it is also STAYING electrified until someone mends the wire) -* one wire for controling door safetys. When active, door does not close on someone. When cut, door will ruin someone's shit. When pulsed, door will immedately ruin someone's shit. -* one wire for controlling door speed. When active, dor closes at normal rate. When cut, door does not close manually. When pulsed, door attempts to close every tick. -*/ -// You can find code for the airlock wires in the wire datum folder. - - -/obj/machinery/door/airlock/Destroy() - qdel(wires) - wires = null - if(main_power_timer) - deltimer(main_power_timer) - main_power_timer = null - if(backup_power_timer) - deltimer(backup_power_timer) - backup_power_timer = null - if(electrified_timer) - deltimer(electrified_timer) - electrified_timer = null - return ..() - -/obj/machinery/door/airlock/bumpopen(mob/living/user as mob) //Airlocks now zap you when you 'bump' them open when they're electrified. --NeoFite - if(!issilicon(usr)) - if(src.isElectrified()) - if(!src.justzap) - if(src.shock(user, 100)) - src.justzap = 1 - spawn (10) - src.justzap = 0 - return - else /*if(src.justzap)*/ - return - else if(user.hallucination > 50 && prob(10) && src.operating == 0) - to_chat(user, "You feel a powerful shock course through your body!") - user.adjustStaminaLoss(50) - user.AdjustStunned(5) - return - ..(user) - -/obj/machinery/door/airlock/bumpopen(mob/living/simple_animal/user as mob) - ..(user) - - -/obj/machinery/door/airlock/autoclose() - autoclose_timer = 0 - if(!qdeleted(src) && !density && !operating && !locked && !welded && autoclose) - close() - return - -/obj/machinery/door/airlock/proc/isElectrified() - if(src.electrified_until != 0) - return 1 - return 0 - -/obj/machinery/door/airlock/proc/isWireCut(var/wireIndex) - // You can find the wires in the datum folder. - return wires.IsIndexCut(wireIndex) - -/obj/machinery/door/airlock/proc/canAIControl() - return ((src.aiControlDisabled!=1) && (!src.isAllPowerLoss())); - -/obj/machinery/door/airlock/proc/canAIHack() - return ((src.aiControlDisabled==1) && (!hackProof) && (!src.isAllPowerLoss())); - -/obj/machinery/door/airlock/proc/arePowerSystemsOn() - if(stat & (NOPOWER|BROKEN)) - return 0 - return (src.main_power_lost_until==0 || src.backup_power_lost_until==0) - -/obj/machinery/door/airlock/requiresID() - return !(src.isWireCut(AIRLOCK_WIRE_IDSCAN) || aiDisabledIdScanner) - -/obj/machinery/door/airlock/proc/isAllPowerLoss() - if(stat & (NOPOWER|BROKEN)) - return 1 - if(mainPowerCablesCut() && backupPowerCablesCut()) - return 1 - return 0 - -/obj/machinery/door/airlock/proc/mainPowerCablesCut() - return src.isWireCut(AIRLOCK_WIRE_MAIN_POWER1) || src.isWireCut(AIRLOCK_WIRE_MAIN_POWER2) - -/obj/machinery/door/airlock/proc/backupPowerCablesCut() - return src.isWireCut(AIRLOCK_WIRE_BACKUP_POWER1) || src.isWireCut(AIRLOCK_WIRE_BACKUP_POWER2) - -/obj/machinery/door/airlock/proc/loseMainPower() - main_power_lost_until = mainPowerCablesCut() ? -1 : world.time + SecondsToTicks(60) - if(main_power_lost_until > 0) - main_power_timer = addtimer(src, "regainMainPower", SecondsToTicks(60), 1) - - // If backup power is permanently disabled then activate in 10 seconds if possible, otherwise it's already enabled or a timer is already running - if(backup_power_lost_until == -1 && !backupPowerCablesCut()) - backup_power_lost_until = world.time + SecondsToTicks(10) - backup_power_timer = addtimer(src, "regainBackupPower", SecondsToTicks(10), 1) - - // Disable electricity if required - if(electrified_until && isAllPowerLoss()) - electrify(0) - -/obj/machinery/door/airlock/proc/loseBackupPower() - backup_power_lost_until = backupPowerCablesCut() ? -1 : world.time + SecondsToTicks(60) - if(backup_power_lost_until > 0) - backup_power_timer = addtimer(src, "regainBackupPower", SecondsToTicks(60), 1) - - // Disable electricity if required - if(electrified_until && isAllPowerLoss()) - electrify(0) - -/obj/machinery/door/airlock/proc/regainMainPower() - main_power_timer = null - - if(!mainPowerCablesCut()) - main_power_lost_until = 0 - // If backup power is currently active then disable, otherwise let it count down and disable itself later - if(!backup_power_lost_until) - backup_power_lost_until = -1 - update_icon() - -/obj/machinery/door/airlock/proc/regainBackupPower() - backup_power_timer = null - - if(!backupPowerCablesCut()) - // Restore backup power only if main power is offline, otherwise permanently disable - backup_power_lost_until = main_power_lost_until == 0 ? -1 : 0 - update_icon() - -/obj/machinery/door/airlock/proc/electrify(var/duration, var/feedback = 0) - if(electrified_timer) - deltimer(electrified_timer) - electrified_timer = null - - var/message = "" - if(isWireCut(AIRLOCK_WIRE_ELECTRIFY) && arePowerSystemsOn()) - message = text("The electrification wire is cut - Door permanently electrified.") - electrified_until = -1 - else if(duration && !arePowerSystemsOn()) - message = text("The door is unpowered - Cannot electrify the door.") - electrified_until = 0 - else if(!duration && electrified_until != 0) - message = "The door is now un-electrified." - electrified_until = 0 - else if(duration) //electrify door for the given duration seconds - if(usr) - shockedby += text("\[[time_stamp()]\] - [usr](ckey:[usr.ckey])") - usr.attack_log += text("\[[time_stamp()]\] Electrified the [name] at [x] [y] [z]") - else - shockedby += text("\[[time_stamp()]\] - EMP)") - message = "The door is now electrified [duration == -1 ? "permanently" : "for [duration] second\s"]." - electrified_until = duration == -1 ? -1 : world.time + SecondsToTicks(duration) - if(duration != -1) - electrified_timer = addtimer(src, "electrify", SecondsToTicks(duration), 1, 0) - - if(feedback && message) - to_chat(usr, message) - -// shock user with probability prb (if all connections & power are working) -// returns 1 if shocked, 0 otherwise -// The preceding comment was borrowed from the grille's shock script -/obj/machinery/door/airlock/shock(mob/user, prb) - if(!arePowerSystemsOn()) - return 0 - if(hasShocked) - return 0 //Already shocked someone recently? - if(..()) - hasShocked = 1 - sleep(10) - hasShocked = 0 - return 1 - else - return 0 - -/obj/machinery/door/airlock/update_icon() - if(overlays) overlays.Cut() - overlays = list() - if(emergency && arePowerSystemsOn()) - overlays += image('icons/obj/doors/doorint.dmi', "elights") - if(density) - if(locked && lights) - icon_state = "door_locked" - else - icon_state = "door_closed" - if(p_open || welded || frozen) - if(p_open) - overlays += image(icon, "panel_open") - if(welded) - overlays += image(icon, "welded") - if(frozen) - overlays += image(icon, "frozen") - - else - icon_state = "door_open" - - return - - -/obj/machinery/door/airlock/do_animate(animation) - switch(animation) - if("opening") - if(overlays) overlays.Cut() - if(p_open) - spawn(2) // The only work around that works. Downside is that the door will be gone for a millisecond. - flick("o_door_opening", src) //can not use flick due to BYOND bug updating overlays right before flicking - update_icon() - else - flick("door_opening", src)//[stat ? "_stat":] - update_icon() - if("closing") - if(overlays) overlays.Cut() - if(p_open) - spawn(2) - flick("o_door_closing", src) - update_icon() - else - flick("door_closing", src) - update_icon() - if("spark") - if(density) - flick("door_spark", src) - if("deny") - if(density && src.arePowerSystemsOn()) - playsound(src, doorDeni, 50, 0, 3) - flick("door_deny", src) - return - -/obj/machinery/door/airlock/attack_ai(mob/user as mob) - ui_interact(user) - -/obj/machinery/door/airlock/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - var/data[0] - - data["main_power_loss"] = round(main_power_lost_until > 0 ? max(main_power_lost_until - world.time, 0) / 10 : main_power_lost_until, 1) - data["backup_power_loss"] = round(backup_power_lost_until > 0 ? max(backup_power_lost_until - world.time, 0) / 10 : backup_power_lost_until, 1) - data["electrified"] = round(electrified_until > 0 ? max(electrified_until - world.time, 0) / 10 : electrified_until, 1) - data["open"] = !density - - var/commands[0] - commands[++commands.len] = list("name" = "IdScan", "command"= "idscan", "active" = !aiDisabledIdScanner, "enabled" = "Enabled", "disabled" = "Disable", "danger" = 0, "act" = 1) - commands[++commands.len] = list("name" = "Bolts", "command"= "bolts", "active" = !locked, "enabled" = "Raised", "disabled" = "Dropped", "danger" = 0, "act" = 0) - commands[++commands.len] = list("name" = "Bolt Lights", "command"= "lights", "active" = lights, "enabled" = "Enabled", "disabled" = "Disable", "danger" = 0, "act" = 1) - commands[++commands.len] = list("name" = "Safeties", "command"= "safeties", "active" = safe, "enabled" = "Nominal", "disabled" = "Overridden", "danger" = 1, "act" = 0) - commands[++commands.len] = list("name" = "Timing", "command"= "timing", "active" = normalspeed, "enabled" = "Nominal", "disabled" = "Overridden", "danger" = 1, "act" = 0) - commands[++commands.len] = list("name" = "Door State", "command"= "open", "active" = density, "enabled" = "Closed", "disabled" = "Opened", "danger" = 0, "act" = 0) - commands[++commands.len] = list("name" = "Emergency Access", "command"= "emergency", "active" = !emergency, "enabled" = "Disabled", "disabled" = "Enabled", "danger" = 0, "act" = 0) - - data["commands"] = commands - - ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) - if(!ui) - ui = new(user, src, ui_key, "door_control.tmpl", "Door Controls - [src]", 600, 375) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) - -/obj/machinery/door/airlock/proc/hack(mob/user as mob) - if(src.aiHacking==0) - src.aiHacking=1 - spawn(20) - //TODO: Make this take a minute - to_chat(user, "Airlock AI control has been blocked. Beginning fault-detection.") - sleep(50) - if(src.canAIControl()) - to_chat(user, "Alert cancelled. Airlock control has been restored without our assistance.") - src.aiHacking=0 - return - else if(!src.canAIHack(user)) - to_chat(user, "We've lost our connection! Unable to hack airlock.") - src.aiHacking=0 - return - to_chat(user, "Fault confirmed: airlock control wire disabled or cut.") - sleep(20) - to_chat(user, "Attempting to hack into airlock. This may take some time.") - sleep(200) - if(src.canAIControl()) - to_chat(user, "Alert cancelled. Airlock control has been restored without our assistance.") - src.aiHacking=0 - return - else if(!src.canAIHack(user)) - to_chat(user, "We've lost our connection! Unable to hack airlock.") - src.aiHacking=0 - return - to_chat(user, "Upload access confirmed. Loading control program into airlock software.") - sleep(170) - if(src.canAIControl()) - to_chat(user, "Alert cancelled. Airlock control has been restored without our assistance.") - src.aiHacking=0 - return - else if(!src.canAIHack(user)) - to_chat(user, "We've lost our connection! Unable to hack airlock.") - src.aiHacking=0 - return - to_chat(user, "Transfer complete. Forcing airlock to execute program.") - sleep(50) - //disable blocked control - src.aiControlDisabled = 2 - to_chat(user, "Receiving control information from airlock.") - sleep(10) - //bring up airlock dialog - src.aiHacking = 0 - if(user) - src.attack_ai(user) - -/obj/machinery/door/airlock/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) - if(src.isElectrified()) - if(istype(mover, /obj/item)) - var/obj/item/i = mover - if(i.materials[MAT_METAL]) - var/datum/effect/system/spark_spread/s = new /datum/effect/system/spark_spread - s.set_up(5, 1, src) - s.start() - return ..() - -/obj/machinery/door/airlock/attack_hand(mob/user as mob) - if(!istype(user, /mob/living/silicon)) - if(src.isElectrified()) - if(src.shock(user, 100)) - return - - if(ishuman(user) && prob(40) && src.density) - var/mob/living/carbon/human/H = user - if(H.getBrainLoss() >= 60) - playsound(src.loc, 'sound/effects/bang.ogg', 25, 1) - if(!istype(H.head, /obj/item/clothing/head/helmet)) - visible_message("\red [user] headbutts the airlock.") - var/obj/item/organ/external/affecting = H.get_organ("head") - H.Stun(5) - H.Weaken(5) - if(affecting.take_damage(10, 0)) - H.UpdateDamageIcon() - else - visible_message("\red [user] headbutts the airlock. Good thing they're wearing a helmet.") - return - - if(src.p_open) - wires.Interact(user) - else - ..(user) - return - -/obj/machinery/door/airlock/CanUseTopic(var/mob/user) - if(!issilicon(user)) - return STATUS_CLOSE - - if(operating < 0) //emagged - to_chat(user, "Unable to interface: Internal error.") - return STATUS_CLOSE - if(!src.canAIControl()) - if(src.canAIHack(user)) - src.hack(user) - else - if(src.isAllPowerLoss()) //don't really like how this gets checked a second time, but not sure how else to do it. - to_chat(user, "Unable to interface: Connection timed out.") - else - to_chat(user, "Unable to interface: Connection refused.") - return STATUS_CLOSE - - return ..() - -/obj/machinery/door/airlock/Topic(href, href_list, var/nowindow = 0) - if(..()) - return 1 - - var/activate = text2num(href_list["activate"]) - switch(href_list["command"]) - if("idscan") - if(src.isWireCut(AIRLOCK_WIRE_IDSCAN)) - to_chat(usr, "The IdScan wire has been cut - IdScan feature permanently disabled.") - else if(activate && src.aiDisabledIdScanner) - src.aiDisabledIdScanner = 0 - to_chat(usr, "IdScan feature has been enabled.") - else if(!activate && !src.aiDisabledIdScanner) - src.aiDisabledIdScanner = 1 - to_chat(usr, "IdScan feature has been disabled.") - if("main_power") - if(!main_power_lost_until) - src.loseMainPower() - if("backup_power") - if(!backup_power_lost_until) - src.loseBackupPower() - if("bolts") - if(src.isWireCut(AIRLOCK_WIRE_DOOR_BOLTS)) - to_chat(usr, "The door bolt control wire has been cut - Door bolts permanently dropped.") - else if(activate && src.lock()) - to_chat(usr, "The door bolts have been dropped.") - else if(!activate && src.unlock()) - to_chat(usr, "The door bolts have been raised.") - if("electrify_temporary") - if(activate && src.isWireCut(AIRLOCK_WIRE_ELECTRIFY)) - to_chat(usr, text("The electrification wire is cut - Door permanently electrified.")) - else if(!activate && electrified_until != 0) - to_chat(usr, "The door is now un-electrified.") - electrify(0) - else if(activate) //electrify door for 30 seconds - shockedby += text("\[[time_stamp()]\][usr](ckey:[usr.ckey])") - usr.attack_log += text("\[[time_stamp()]\] Electrified the [name] at [x] [y] [z]") - to_chat(usr, "The door is now electrified for thirty seconds.") - electrify(30) - if("electrify_permanently") - if(src.isWireCut(AIRLOCK_WIRE_ELECTRIFY)) - to_chat(usr, text("The electrification wire is cut - Cannot electrify the door.")) - else if(!activate && electrified_until != 0) - to_chat(usr, "The door is now un-electrified.") - electrify(0) - else if(activate) - shockedby += text("\[[time_stamp()]\][usr](ckey:[usr.ckey])") - usr.attack_log += text("\[[time_stamp()]\] Electrified the [name] at [x] [y] [z]") - to_chat(usr, "The door is now electrified.") - electrify(-1) - if("open") - if(src.welded) - to_chat(usr, text("The airlock has been welded shut!")) - else if(src.locked) - to_chat(usr, text("The door bolts are down!")) - else if(activate && density) - open() - else if(!activate && !density) - close() - if("safeties") - // Safeties! We don't need no stinking safeties! - if(src.isWireCut(AIRLOCK_WIRE_SAFETY)) - to_chat(usr, text("The safety wire is cut - Cannot secure the door.")) - else if(activate && src.safe) - safe = 0 - else if(!activate && !src.safe) - safe = 1 - if("timing") - // Door speed control - if(src.isWireCut(AIRLOCK_WIRE_SPEED)) - to_chat(usr, text("The timing wire is cut - Cannot alter timing.")) - else if(activate && src.normalspeed) - normalspeed = 0 - else if(!activate && !src.normalspeed) - normalspeed = 1 - if("lights") - // Bolt lights - if(src.isWireCut(AIRLOCK_WIRE_LIGHT)) - to_chat(usr, "The bolt lights wire has been cut - The door bolt lights are permanently disabled.") - else if(!activate && src.lights) - lights = 0 - to_chat(usr, "The door bolt lights have been disabled.") - else if(activate && !src.lights) - lights = 1 - to_chat(usr, "The door bolt lights have been enabled.") - if("emergency") - // Emergency access - if(src.emergency) - emergency = 0 - to_chat(usr, "Emergency access has been disabled.") - else - emergency = 1 - to_chat(usr, "Emergency access has been enabled.") - - update_icon() - return 1 - -/obj/machinery/door/airlock/attackby(C as obj, mob/user as mob, params) -// to_chat(world, text("airlock attackby src [] obj [] mob []", src, C, user)) - if(!istype(usr, /mob/living/silicon)) - if(src.isElectrified()) - if(src.shock(user, 75)) - return - if(istype(C, /obj/item/device/detective_scanner) || istype(C, /obj/item/taperoll)) - return - - src.add_fingerprint(user) - if((istype(C, /obj/item/weapon/weldingtool) && !( src.operating ) && src.density)) - var/obj/item/weapon/weldingtool/W = C - if(W.remove_fuel(0,user)) - if(frozen) - frozen = 0 - if(!src.welded) - src.welded = 1 - else - src.welded = null - src.update_icon() - return - else - return - else if(istype(C, /obj/item/weapon/screwdriver)) - src.p_open = !( src.p_open ) - src.update_icon() - else if(istype(C, /obj/item/weapon/wirecutters)) - return src.attack_hand(user) - else if(istype(C, /obj/item/device/multitool)) - return src.attack_hand(user) - else if(istype(C, /obj/item/device/assembly/signaler)) - return src.attack_hand(user) - else if(istype(C, /obj/item/weapon/pai_cable)) // -- TLE - var/obj/item/weapon/pai_cable/cable = C - cable.plugin(src, user) - else if(istype(C, /obj/item/weapon/crowbar) || istype(C, /obj/item/weapon/twohanded/fireaxe) ) - var/beingcrowbarred = null - if(istype(C, /obj/item/weapon/crowbar) ) - beingcrowbarred = 1 //derp, Agouri - else - beingcrowbarred = 0 - if( beingcrowbarred && src.p_open && (operating == -1 || (density && welded && operating != 1 && !src.arePowerSystemsOn() && !src.locked)) ) - playsound(src.loc, 'sound/items/Crowbar.ogg', 100, 1) - user.visible_message("[user] removes the electronics from the airlock assembly.", "You start to remove electronics from the airlock assembly.") - if(do_after(user,40, target = src)) - to_chat(user, "\blue You removed the airlock electronics!") - - var/obj/structure/door_assembly/da = new assembly_type(src.loc) - da.anchored = 1 - if(mineral) - da.glass = mineral - //else if(glass) - else if(glass && !da.glass) - da.glass = 1 - da.state = 1 - da.created_name = src.name - da.update_state() - - var/obj/item/weapon/airlock_electronics/ae - if(!electronics) - ae = new/obj/item/weapon/airlock_electronics( src.loc ) - if(!src.req_access) - src.check_access() - if(src.req_access.len) - ae.conf_access = src.req_access - else if(src.req_one_access.len) - ae.conf_access = src.req_one_access - ae.one_access = 1 - else - ae = electronics - electronics = null - ae.loc = src.loc - if(operating == -1) - ae.icon_state = "door_electronics_smoked" - operating = 0 - - qdel(src) - return - else if(arePowerSystemsOn()) - to_chat(user, "\blue The airlock's motors resist your efforts to force it.") - else if(locked) - to_chat(user, "\blue The airlock's bolts prevent it from being forced.") - else if( !welded && !operating ) - if(density) - if(beingcrowbarred == 0) //being fireaxe'd - var/obj/item/weapon/twohanded/fireaxe/F = C - if(F.wielded) - spawn(0) open(1) - else - to_chat(user, "\red You need to be wielding \the [C] to do that.") - else - spawn(0) open(1) - else - if(beingcrowbarred == 0) - var/obj/item/weapon/twohanded/fireaxe/F = C - if(F.wielded) - spawn(0) close(1) - else - to_chat(user, "\red You need to be wielding \the [C] to do that.") - else - spawn(0) close(1) - else - ..() - return - -/obj/machinery/door/airlock/plasma/attackby(C as obj, mob/user as mob, params) - if(is_hot(C) > 300) - message_admins("Plasma airlock ignited by [key_name_admin(user)] in ([x],[y],[z] - JMP)") - log_game("Plasma wall ignited by [key_name(user)] in ([x],[y],[z])") - ignite(is_hot(C)) - ..() - -/obj/machinery/door/airlock/open(var/forced=0) - if( operating || welded || locked ) - return 0 - if(!forced) - if( !arePowerSystemsOn() || isWireCut(AIRLOCK_WIRE_OPEN_DOOR) ) - return 0 - use_power(360) //360 W seems much more appropriate for an actuator moving an industrial door capable of crushing people - if(forced) - playsound(src.loc, 'sound/machines/airlockforced.ogg', 30, 1) - else - playsound(src.loc, doorOpen, 30, 1) - if(src.closeOther != null && istype(src.closeOther, /obj/machinery/door/airlock/) && !src.closeOther.density) - src.closeOther.close() - return ..() - -/obj/machinery/door/airlock/close(var/forced=0, var/override = 0) - if((operating & !override) || welded || locked) - return - if(!forced) - //despite the name, this wire is for general door control. - //Bolts are already covered by the check for locked, above - if( !arePowerSystemsOn() || isWireCut(AIRLOCK_WIRE_OPEN_DOOR) ) - return - if(safe) - for(var/turf/turf in locs) - if(locate(/mob/living) in turf) - // playsound(src.loc, 'sound/machines/buzz-two.ogg', 50, 0) //THE BUZZING IT NEVER STOPS -Pete - spawn (60) - autoclose() - return - - use_power(360) //360 W seems much more appropriate for an actuator moving an industrial door capable of crushing people - if(forced) - playsound(src.loc, 'sound/machines/airlockforced.ogg', 30, 1) - else - playsound(src.loc, doorClose, 30, 1) - var/obj/structure/window/killthis = (locate(/obj/structure/window) in get_turf(src)) - if(killthis) - killthis.ex_act(2)//Smashin windows - - if(density) - return 1 - operating = 1 - do_animate("closing") - src.layer = 3.1 - if(!override) sleep(5) - src.density = 1 - if(!safe) - crush() - if(!override) sleep(5) - update_icon() - if(visible && !glass) - set_opacity(1) - operating = 0 - air_update_turf(1) - update_freelook_sight() - if(safe) - if(locate(/mob/living) in get_turf(src)) - open() - - return - -/obj/machinery/door/airlock/proc/lock(var/forced=0) - if(locked) - return 0 - - if(operating && !forced) return 0 - - src.locked = 1 - playsound(src, boltDown, 30, 0, 3) - update_icon() - return 1 - -/obj/machinery/door/airlock/proc/unlock(var/forced=0) - if(!src.locked) - return - - if(!forced) - if(operating || !src.arePowerSystemsOn() || isWireCut(AIRLOCK_WIRE_DOOR_BOLTS)) return - - src.locked = 0 - playsound(src,boltUp, 30, 0, 3) - update_icon() - return 1 - -/obj/machinery/door/airlock/New() - ..() - wires = new(src) - if(src.closeOtherId != null) - spawn (5) - for(var/obj/machinery/door/airlock/A in airlocks) - if(A.closeOtherId == src.closeOtherId && A != src) - src.closeOther = A - break - if(frozen) - welded = 1 - update_icon() - -/obj/machinery/door/airlock/hatch/gamma/attackby(C as obj, mob/user as mob, params) -// to_chat(world, text("airlock attackby src [] obj [] mob []", src, C, user)) - if(!istype(usr, /mob/living/silicon)) - if(src.isElectrified()) - if(src.shock(user, 75)) - return - if(istype(C, /obj/item/device/detective_scanner) || istype(C, /obj/item/taperoll)) - return - - if(istype(C, /obj/item/weapon/grenade/plastic/c4)) - to_chat(user, "The hatch is coated with a product that prevents the shaped charge from sticking!") - return - - if(istype(C, /obj/item/mecha_parts/mecha_equipment/rcd) || istype(C, /obj/item/weapon/rcd)) - to_chat(user, "The hatch is made of an advanced compound that cannot be deconstructed using an RCD.") - return - - src.add_fingerprint(user) - if((istype(C, /obj/item/weapon/weldingtool) && !( src.operating > 0 ) && src.density)) - var/obj/item/weapon/weldingtool/W = C - if(W.remove_fuel(0,user)) - if(frozen) - frozen = 0 - if(!src.welded) - src.welded = 1 - else - src.welded = null - src.update_icon() - return - else - return - - -/obj/machinery/door/airlock/highsecurity/red/attackby(C as obj, mob/user as mob, params) -// to_chat(world, text("airlock attackby src [] obj [] mob []", src, C, user)) - if(!istype(usr, /mob/living/silicon)) - if(src.isElectrified()) - if(src.shock(user, 75)) - return - if(istype(C, /obj/item/device/detective_scanner) || istype(C, /obj/item/taperoll)) - return - - src.add_fingerprint(user) - if((istype(C, /obj/item/weapon/weldingtool) && !( src.operating > 0 ) && src.density)) - var/obj/item/weapon/weldingtool/W = C - if(W.remove_fuel(0,user)) - if(frozen) - frozen = 0 - if(!src.welded) - src.welded = 1 - else - src.welded = null - src.update_icon() - return - else - return - -/obj/machinery/door/airlock/CanAStarPass(var/obj/item/weapon/card/id/ID) -//Airlock is passable if it is open (!density), bot has access, and is not bolted shut) - return !density || (check_access(ID) && !locked && arePowerSystemsOn()) - -/obj/machinery/door/airlock/emp_act(var/severity) - if(prob(40/severity)) - var/duration = world.time + SecondsToTicks(30 / severity) - if(duration > electrified_until) - electrify(duration) - ..() - -/obj/machinery/door/airlock/power_change() //putting this is obj/machinery/door itself makes non-airlock doors turn invisible for some reason - ..() - if(stat & NOPOWER) - // If we lost power, disable electrification - // Keeping door lights on, runs on internal battery or something. - electrified_until = 0 - update_icon() - -/obj/machinery/door/airlock/proc/prison_open() - if(arePowerSystemsOn()) - src.unlock() - src.open() - src.lock() - -/obj/machinery/door/airlock/hostile_lockdown(mob/origin) - // Must be powered and have working AI wire. - if(canAIControl(src) && !stat) - locked = FALSE //For airlocks that were bolted open. - safe = FALSE //DOOR CRUSH - close() - lock() //Bolt it! - electrified_until = -1 //Shock it! - if(origin) - shockedby += "\[[time_stamp()]\][origin](ckey:[origin.ckey])" - - -/obj/machinery/door/airlock/disable_lockdown() - // Must be powered and have working AI wire. - if(canAIControl(src) && !stat) - unlock() - electrified_until = 0 - open() - safe = TRUE - -/obj/machinery/door/airlock/narsie_act() - var/turf/T = get_turf(src) - var/runed = prob(20) - if(prob(20)) - if(runed) - new/obj/machinery/door/airlock/cult(T) - else - new/obj/machinery/door/airlock/cult/runed(T) - qdel(src) + + + + + + + + + + + + + + + + + + + + + + History for code/game/machinery/doors/airlock.dm - ParadiseSS13/Paradise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Skip to content + + + + + + + + + + + + + +
+ +
+
+ + +
+
+
+ +
+
+ + + +
    + +
  • +
    + +
    + + + + Watch + + + + +
    + +
    +
    +
    +
  • + +
  • + +
    + +
    + + +
    +
    + + +
    + +
  • + +
  • +
    + +
    + +
  • +
+ +

+ + /Paradise + +

+ +
+ +
+ +
+
+ + +
+ +
+ +
+
+ Commits on Dec 24, 2016 +
+ +
    +
  1. + +
    +
    + + @Aurorablade + +
    +
    +
    +

    + Merge remote-tracking branch 'refs/remotes/ParadiseSS13/master' into DWI + + +

    + + +
    + Aurorablade + committed + + + Dec 24, 2016 + + + + +
    + + + +
    + +
    +
    + +
    + +
  2. +
+
+ Commits on Dec 14, 2016 +
+ +
    +
  1. + +
    +
    + + @Aurorablade + +
    +
    +
    +

    + dammit tiger + + +

    + + +
    + Aurorablade + committed + + + Dec 14, 2016 + + + + +
    + + + +
    + +
    +
    + +
    + +
  2. +
  3. + +
    +
    + + @Aurorablade + +
    +
    +
    +

    + i probaly still didi it wrong + + +

    + + +
    + Aurorablade + committed + + + Dec 14, 2016 + + + + +
    + + + +
    + +
    +
    + +
    + +
  4. +
  5. + +
    +
    + + @Aurorablade + +
    +
    +
    +

    + fox box airlock + + +

    + + +
    + Aurorablade + committed + + + Dec 14, 2016 + + + + +
    + + + +
    + +
    +
    + +
    + +
  6. +
  7. + +
    +
    + + @tigercat2000 + +
    +
    +
    +

    + NanoUI Update: Seperate UI Data into ui_data() proc + + +

    + +
    This commit changes how NanoUI's live data updating system works.
    +Previously, data for the template was directly gathered in the
    +ui_interact proc. Now, it is seperated into the proc `ui_data`.
    +
    +To players, this does absolutely nothing.
    +To coders, this opens up the potential for a much more complicated and
    +fancy graphical updating system in the future, because the data is
    +available on-demand without ever having to call
    +nanomanager.try_update_ui.
    + +
    + tigercat2000 + committed + + + Dec 14, 2016 + + + + +
    + + + +
    + +
    +
    + +
    + +
  8. +
+
+ Commits on Dec 6, 2016 +
+ +
    +
  1. + +
    +
    + + @Aurorablade + +
    +
    +
    +

    + Merge remote-tracking branch 'refs/remotes/ParadiseSS13/master' into DWI + + +

    + + +
    + Aurorablade + committed + + + Dec 6, 2016 + + + + +
    + + + +
    + +
    +
    + +
    + +
  2. +
  3. + +
    +
    + + @Markolie + +
    +
    +
    +

    + Fix AI crew monitor tracking and door electrification + + +

    + + +
    + Markolie + committed + + + Dec 6, 2016 + + + + +
    + + + +
    + +
    +
    + +
    + +
  4. +
+
+ Commits on Sep 17, 2016 +
+ +
    +
  1. + +
    +
    + + @Aurorablade + +
    +
    +
    +

    + Merge branch 'master' of https://github.com/ParadiseSS13/Paradise int… + + +

    + +
    …o DWI
    + +
    + Aurorablade + committed + + + Sep 17, 2016 + + + + +
    + + + +
    + +
    +
    + +
    + +
  2. +
+
+ Commits on Sep 12, 2016 +
+ +
    +
  1. + +
    +
    + + @GeneralChaos81 + +
    +
    +
    +

    + Redo of clown/mime door fix. + + +

    + + +
    + GeneralChaos81 + committed + + + Sep 12, 2016 + + + + +
    + + + +
    + +
    +
    + +
    + +
  2. +
+
+ Commits on Sep 1, 2016 +
+ +
    +
  1. + +
    +
    + + @Aurorablade + +
    +
    +
    +

    + cultdoors + + +

    + + +
    + Aurorablade + committed + + + Sep 1, 2016 + + + + +
    + + + +
    + +
    +
    + +
    + +
  2. +
+
+ Commits on Aug 23, 2016 +
+ +
    +
  1. + +
    +
    + + @Crazylemon64 + +
    +
    +
    +

    + Moves airlocks to the `addtimer` system + + +

    + + +
    + Crazylemon64 + committed + + + Aug 23, 2016 + +
    + +
    + +
  2. +
+
+ Commits on Aug 12, 2016 +
+ +
    +
  1. + +
    +
    + + @tigercat2000 + +
    +
    +
    +

    + /tg/ mecha - Part 1 + + +

    + +
    Start of porting the /tg/station mecha update.
    +This commit only cleans up the code and adds the proper dependencies for
    +the mecha.
    +
    + - Removes relative pathing from /datum/events
    + - Updated Process_Spacemove() to use
    +   atom/movable/proc/get_spacemove_backup()
    +   - Basically just makes launching off of unanchored objects in space an
    +     OOP behaviour
    + - Removed styling atrocities and relative pathing from most of the mecha files.
    +  - Notable exceptions:
    +   - code/game/mecha/mech_bay.dm
    +   - code/game/mecha/mech_fabricator.dm
    +   - code/game/mecha/mecha_construction_paths.dm
    +   - code/game/mecha/mecha_parts.dm
    +   - code/game/mecha/mecha_wreckage.dm
    +   - code/game/mecha/paintkits.dm
    + - Removed dyndomove/dyndoattackby/dyndobulletact. No more icky dynamic
    +   calls. Replaced by specific code for the 3 modules that used it.
    + - Refactored module cooldown. It now uses addtimer, and power usage is
    +   hooked directly into the cooldown calls.
    + - Added atom/movable/proc/has_buckled_mobs(). Currently not that useful,
    +   but, necessary for porting the multi-buckling system from /tg/.
    + - Split code/game/mecha/equipment/tools/tools.dm into multiple files.
    + - Removed snowflake behaviour from exosuit drill. It now calls
    +   turf.drill_act(src).
    +  - Different from /tg/: Allows you to drill any wall/floor normally.
    + - Drill no longer gibs mobs. It deals 80 organ damage instead.
    + - Drill can be used to harvest dead mobs.
    + - Removed all global_iterator systems from mecha and mecha equipment.
    +   Everything now uses object processing.
    + - Mecha now have a turn sound variable and step sound variable. Updated
    +   all subtypes to use these instead of snowflake domove procs.
    + - Removed mecha_do_after, mecha now uses the normal do_after.
    + - Removed enter_after, same as above.
    + - /obj/mecha/Process_Spacemove no longer strangely calls the user's
    +   spacemove.
    + - /obj/mecha/return_pressure now uses return_air instead of copypasted
    +   cabin air detection.
    + - Same for /obj/mecha/return_temperature
    + - Added /obj/mecha/Exited. Basically, properly clears occupant refs,
    +   even if they teleport out/otherwise exit improperly.
    + - Added hooks for mecha action buttons; Didn't implement them yet.
    + - Moved mecha UI to code/game/mecha/mecha_topic.dm
    + - Fixed turfs not updating atmos when ChangeTurf(/turf/space) is used.
    + - Updated visible_message and audible_message. Both now use
    +   get_mobs_in_view() to ensure that mobs inside containers can see
    +   messages.
    + - Removed /obj/item/mecha_parts/mecha_equipment/tool subtype. It had no
    +   use. Any subtypes are now just subtypes of
    +   /obj/item/mecha_parts/mecha_equipment.
    + +
    + tigercat2000 + committed + + + Aug 12, 2016 + + + + +
    + + + +
    + +
    +
    + +
    + +
  2. +
+
+ Commits on Aug 11, 2016 +
+ +
    +
  1. + +
    +
    + + @monster860 + +
    +
    +
    +

    + Makes boldnotice and danger classes be be used + + +

    + + +
    + monster860 + committed + + + Aug 9, 2016 + + + + +
    + + + +
    + +
    +
    + +
    + +
  2. +
+
+ Commits on Aug 7, 2016 +
+ +
    +
  1. + +
    +
    + + @Fox-McCloud + +
    +
    +
    +

    + Malf AI Powers Update + + +

    + + +
    + Fox-McCloud + committed + + + Aug 7, 2016 + + + + +
    + + + +
    + +
    +
    + +
    + +
  2. +
+
+ Commits on Aug 2, 2016 +
+ +
    +
  1. + +
    +
    + + @Fox-McCloud + +
    +
    +
    +

    + Removs Airlock World Calls + + +

    + + +
    + Fox-McCloud + committed + + + Aug 2, 2016 + + + + +
    + + + +
    + +
    +
    + +
    + +
  2. +
+
+ Commits on Jul 13, 2016 +
+ +
    +
  1. + +
    +
    + + @DaveTheHeadcrab + +
    +
    +
    +

    + Plastic Explosives Update + + +

    + + +
    + DaveTheHeadcrab + committed + + + Jul 13, 2016 + + + + +
    + + + +
    + +
    +
    + +
    + +
  2. +
+
+ Commits on Jul 7, 2016 +
+ +
    +
  1. + +
    +
    + + @tigercat2000 + +
    +
    +
    +

    + Mass replace + + +

    + + +
    + tigercat2000 + committed + + + Jul 7, 2016 + + + + +
    + + + +
    + +
    +
    + +
    + +
  2. +
+
+ Commits on Jul 6, 2016 +
+ +
    +
  1. + +
    +
    + + @TullyBurnalot + +
    +
    +
    +

    + Fixed Mime Doors + + +

    + +
    It's not Tranquilite.
    +
    +It's not Tranqillite.
    +
    +It's Tranquillite.
    + +
    + TullyBurnalot + committed + + + Jul 6, 2016 + + + + +
    + + + +
    + +
    +
    + +
    + +
  2. +
  3. + +
    +
    + + @TullyBurnalot + +
    +
    +
    +

    + Fixed Clown/Mime Door Deconstruction + + +

    + +
    Fixes #4689
    +
    +- Deconstructing Clown Doors now gives Bananiums
    +- Deconstructing Mime Doors now gives Tranquilite
    +- Invisibility drives installed
    +
    +🆑
    +tweak: Deconstructing Clown Doors gives Bananium
    +tweat: Deconstructing Mime Doors gives Tranquilite
    + +
    + TullyBurnalot + committed + + + Jul 6, 2016 + +
    + +
    + +
  4. +
+
+ Commits on May 26, 2016 +
+ +
    +
  1. + +
    +
    + + @CrAzYPiLoT-SS13 + +
    +
    +
    +

    + Goddammit + + +

    + + +
    + CrAzYPiLoT-SS13 + committed + + + May 26, 2016 + + + + +
    + + + +
    + +
    +
    + +
    + +
  2. +
+
+ Commits on May 13, 2016 +
+ +
    +
  1. + +
    +
    + + @AugRob + +
    +
    +
    +

    + Add screwdriver sound when opening airlock panels + + +

    + + +
    + AugRob + committed + + + May 13, 2016 + + + + +
    + + + +
    + +
    +
    + +
    + +
  2. +
+
+ Commits on Apr 14, 2016 +
+ +
    +
  1. + +
    +
    + + @Fox-McCloud + +
    +
    +
    +

    + remove extras + + +

    + + +
    + Fox-McCloud + committed + + + Apr 14, 2016 + + + + +
    + + + +
    + +
    +
    + +
    + +
  2. +
+
+ Commits on Apr 9, 2016 +
+ +
    +
  1. + +
    +
    + + @Fox-McCloud + +
    +
    +
    +

    + people like weird shit + + +

    + + +
    + Fox-McCloud + committed + + + Apr 9, 2016 + + + + +
    + + + +
    + +
    +
    + +
    + +
  2. +
+
+ Commits on Apr 8, 2016 +
+ +
    +
  1. + +
    +
    + + @Fox-McCloud + +
    +
    +
    +

    + New Airlock Sounds + + +

    + + +
    + Fox-McCloud + committed + + + Apr 8, 2016 + + + + +
    + + + +
    + +
    +
    + +
    + +
  2. +
+
+ Commits on Apr 5, 2016 +
+ +
    +
  1. + +
    +
    + + @tigercat2000 + +
    +
    +
    +

    + Reduce lines by removing blank lines added by PJ's script + + +

    + + +
    + tigercat2000 + committed + + + Apr 5, 2016 + + + + +
    + + + +
    + +
    +
    + +
    + +
  2. +
  3. + +
    +
    + + @tigercat2000 + +
    +
    +
    +

    + Replace most (if not all) output << operators with to_chat(user, mess… + + +

    + +
    …age)
    +
    +Currently, to_chat is literally just a proc that does user << message.
    +But it'll let us do output modification in the future, especially for
    +something like Goon's HTML chat.
    +
    +Big thanks to PJB for his to_chat script, see
    +d3athrow/vgstation13#6625 for more details.
    + +
    + tigercat2000 + committed + + + Apr 5, 2016 + + + + +
    + + + +
    + +
    +
    + +
    + +
  4. +
+
+ Commits on Mar 28, 2016 +
+ +
    +
  1. + +
    +
    + + @Tastyfish + +
    +
    +
    +

    + Ports tg simple_animal bots + + +

    + + +
    + Tastyfish + committed + + + Mar 21, 2016 + + + + +
    + + + +
    + +
    +
    + +
    + +
  2. +
+
+ Commits on Mar 11, 2016 +
+ +
    +
  1. + +
    +
    + + @Tastyfish + +
    +
    +
    +

    + Makes doors not process unless controlled by an airlock controller, f… + + +

    + +
    …ixes fire alarm processing leak
    + +
    + Tastyfish + committed + + + Mar 11, 2016 + + + + +
    + + + +
    + +
    +
    + +
    + +
  2. +
+
+ Commits on Mar 6, 2016 +
+ +
    +
  1. + +
    +
    + + @Tastyfish + +
    +
    +
    +

    + Adds tranquillite + + +

    + +
    Changes Recitence to be approx on par with Honker
    +Adds invisible wall barrier
    + +
    + Tastyfish + committed + + + Mar 4, 2016 + + + + +
    + + + +
    + +
    +
    + +
    + +
  2. +
+
+ Commits on Feb 28, 2016 +
+ +
    +
  1. + +
    +
    + + @Tastyfish + +
    +
    +
    +

    + Fixes a bunch of things to not circumvent SetStun/SetWeaken/SetParaly… + + +

    + +
    …se that has no business doing so.
    + +
    + Tastyfish + committed + + + Feb 28, 2016 + + + + +
    + + + +
    + +
    +
    + +
    + +
  2. +
+
+ Commits on Jan 30, 2016 +
+ +
    +
  1. + +
    +
    + + @VampyrBytes + +
    +
    +
    +

    + Fixes #3425 + + +

    + +
    There were a couple of things going on... the spawn(-1) which should
    +have meant that the door shut straight away was being negated by the
    +sleeps. Also, If the door had just been used, it would still be marked
    +as operating and so wouldn't shut
    + +
    + VampyrBytes + committed + + + Jan 30, 2016 + + + + +
    + + + +
    + +
    +
    + +
    + +
  2. +
+
+ Commits on Nov 22, 2015 +
+ +
    +
  1. + +
    +
    + + @Tastyfish + +
    +
    +
    +

    + refactored datum/effect/system because it was a complete mess + + +

    + + +
    + Tastyfish + committed + + + Nov 22, 2015 + + + + +
    + + + +
    + +
    +
    + +
    + +
  2. +
+
+ Commits on Oct 5, 2015 +
+ +
    +
  1. + +
    +
    + + @Fox-McCloud + +
    +
    +
    +

    + Removes Update Triggers File + + +

    + + +
    + Fox-McCloud + committed + + + Oct 5, 2015 + + + + +
    + + + +
    + +
    +
    + +
    + +
  2. +
+
+ Commits on Sep 21, 2015 +
+ +
    +
  1. + +
    +
    + + @Markolie + +
    +
    +
    +

    + Fix door crush bug + + +

    + + +
    + Markolie + committed + + + Sep 21, 2015 + + + + +
    + + + +
    + +
    +
    + +
    + +
  2. +
+
+ Commits on Sep 18, 2015 +
+ +
    +
  1. + +
    +
    + + @Fox-McCloud + +
    +
    +
    +

    + Fixes up a few Destroys + + +

    + + +
    + Fox-McCloud + committed + + + Sep 18, 2015 + + + + +
    + + + +
    + +
    +
    + +
    + +
  2. +
+
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ + + + + + + +
+ + + You can't perform that action at this time. +
+ + + + + + + + + +
+ + You signed in with another tab or window. Reload to refresh your session. + You signed out in another tab or window. Reload to refresh your session. +
+ + + + + diff --git a/code/game/objects/effects/overlays.dm b/code/game/objects/effects/overlays.dm index f90ad21ef6b..7e49136d3cf 100644 --- a/code/game/objects/effects/overlays.dm +++ b/code/game/objects/effects/overlays.dm @@ -98,60 +98,16 @@ icon_state = "admin" layer = 4.1 +/obj/effect/overlay/wall_rot + name = "Wallrot" + desc = "Ick..." + icon = 'icons/effects/wallrot.dmi' + anchored = 1 + density = 1 + layer = 5 + mouse_opacity = 0 -/obj/effect/overlay/temp/cult - randomdir = 0 - duration = 10 - icon = 'icons/effects/effects.dmi' - -/obj/effect/overlay/temp/cult/sparks - randomdir = 1 - name = "blood sparks" - icon_state = "bloodsparkles" - -/obj/effect/overlay/temp/cult/phase - name = "phase glow" - duration = 7 - icon_state = "cultin" - -/obj/effect/overlay/temp/cult/phase/New(loc, set_dir) +/obj/effect/overlay/wall_rot/New() ..() - if(set_dir) - dir = set_dir - -/obj/effect/overlay/temp/cult/phase/out - icon_state = "cultout" - -/obj/effect/overlay/temp/heal //color is white by default, set to whatever is needed - name = "healing glow" - icon = 'icons/effects/effects.dmi' - icon_state = "heal" - duration = 15 - -/obj/effect/overlay/temp/heal/New(loc, colour) - ..() - pixel_x = rand(-12, 12) - pixel_y = rand(-9, 0) - if(colour) - color = colour - -/obj/effect/overlay/temp/cult/sac - name = "maw of Nar-Sie" - icon_state = "sacconsume" - -/obj/effect/overlay/temp/cult/door - name = "unholy glow" - icon_state = "doorglow" - layer = 3.17 //above closed doors - -/obj/effect/overlay/temp/cult/door/unruned - icon_state = "unruneddoorglow" - -/obj/effect/overlay/temp/cult/turf - name = "unholy glow" - icon_state = "wallglow" - layer = TURF_LAYER + 0.07 - -/obj/effect/overlay/temp/cult/turf/open/floor - icon_state = "floorglow" - duration = 5 + pixel_x += rand(-10, 10) + pixel_y += rand(-10, 10) \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/species/species.dm b/code/modules/mob/living/carbon/human/species/species.dm index faef4840a51..fb3938043db 100644 --- a/code/modules/mob/living/carbon/human/species/species.dm +++ b/code/modules/mob/living/carbon/human/species/species.dm @@ -1,677 +1,3472 @@ -/* - Datum-based species. Should make for much cleaner and easier to maintain mutantrace code. -*/ - -/datum/species - var/name // Species name. - var/name_plural // Pluralized name (since "[name]s" is not always valid) - var/path // Species path - var/icobase = 'icons/mob/human_races/r_human.dmi' // Normal icon set. - var/deform = 'icons/mob/human_races/r_def_human.dmi' // Mutated icon set. - - // Damage overlay and masks. - var/damage_overlays = 'icons/mob/human_races/masks/dam_human.dmi' - var/damage_mask = 'icons/mob/human_races/masks/dam_mask_human.dmi' - var/blood_mask = 'icons/mob/human_races/masks/blood_human.dmi' - - var/eyes = "eyes_s" // Icon for eyes. - var/blurb = "A completely nondescript species." // A brief lore summary for use in the chargen screen. - var/butt_sprite = "human" - - var/primitive_form // Lesser form, if any (ie. monkey for humans) - var/greater_form // Greater form, if any, ie. human for monkeys. - var/tail // Name of tail image in species effects icon file. - var/unarmed //For empty hand harm-intent attack - var/unarmed_type = /datum/unarmed_attack - var/slowdown = 0 // Passive movement speed malus (or boost, if negative) - var/silent_steps = 0 // Stops step noises - - var/breath_type = "oxygen" // Non-oxygen gas breathed, if any. - var/poison_type = "plasma" // Poisonous air. - var/exhale_type = "carbon_dioxide" // Exhaled gas type. - - var/cold_level_1 = 260 // Cold damage level 1 below this point. - var/cold_level_2 = 200 // Cold damage level 2 below this point. - var/cold_level_3 = 120 // Cold damage level 3 below this point. - var/cold_env_multiplier = 1 // Damage multiplier for being in a cold environment - - var/heat_level_1 = 360 // Heat damage level 1 above this point. - var/heat_level_2 = 400 // Heat damage level 2 above this point. - var/heat_level_3 = 460 // Heat damage level 3 above this point; used for body temperature - var/hot_env_multiplier = 1 // Damage multiplier for being in a hot environment - var/heat_level_3_breathe = 1000 // Heat damage level 3 above this point; used for breathed air temperature - - var/body_temperature = 310.15 //non-IS_SYNTHETIC species will try to stabilize at this temperature. (also affects temperature processing) - var/reagent_tag //Used for metabolizing reagents. - - var/siemens_coeff = 1 //base electrocution coefficient - - var/darksight = 2 - var/hazard_high_pressure = HAZARD_HIGH_PRESSURE // Dangerously high pressure. - var/warning_high_pressure = WARNING_HIGH_PRESSURE // High pressure warning. - var/warning_low_pressure = WARNING_LOW_PRESSURE // Low pressure warning. - var/hazard_low_pressure = HAZARD_LOW_PRESSURE // Dangerously low pressure. - - var/list/atmos_requirements = list( - "min_oxy" = 16, - "max_oxy" = 0, - "min_nitro" = 0, - "max_nitro" = 0, - "min_tox" = 0, - "max_tox" = 0.005, - "min_co2" = 0, - "max_co2" = 10, - "sa_para" = 1, - "sa_sleep" = 5 - ) - - var/brute_mod = null // Physical damage reduction/malus. - var/burn_mod = null // Burn damage reduction/malus. - - var/total_health = 100 - var/punchdamagelow = 0 //lowest possible punch damage - var/punchdamagehigh = 9 //highest possible punch damage - var/punchstunthreshold = 9 //damage at which punches from this race will stun //yes it should be to the attacked race but it's not useful that way even if it's logical - var/list/default_genes = list() - - var/ventcrawler = 0 //Determines if the mob can go through the vents. - var/has_fine_manipulation = 1 // Can use small items. - - var/list/allowed_consumed_mobs = list() //If a species can consume mobs, put the type of mobs it can consume here. - - var/flags = 0 // Various specific features. - var/clothing_flags = 0 // Underwear and socks. - var/exotic_blood - var/bodyflags = 0 - var/dietflags = 0 // Make sure you set this, otherwise it won't be able to digest a lot of foods - - var/list/abilities = list() // For species-derived or admin-given powers - - var/blood_color = "#A10808" //Red. - var/flesh_color = "#FFC896" //Pink. - var/single_gib_type = /obj/effect/decal/cleanable/blood/gibs - var/remains_type = /obj/effect/decal/remains/human //What sort of remains is left behind when the species dusts - var/base_color //Used when setting species. - - //Used in icon caching. - var/race_key = 0 - var/icon/icon_template - var/is_small - var/show_ssd = 1 - var/virus_immune - var/can_revive_by_healing // Determines whether or not this species can be revived by simply healing them - - //Death vars. - var/death_message = "seizes up and falls limp, their eyes dead and lifeless..." - var/list/suicide_messages = list( - "is attempting to bite their tongue off!", - "is jamming their thumbs into their eye sockets!", - "is twisting their own neck!", - "is holding their breath!") - - // Language/culture vars. - var/default_language = "Galactic Common" // Default language is used when 'say' is used without modifiers. - var/language = "Galactic Common" // Default racial language, if any. - var/secondary_langs = list() // The names of secondary languages that are available to this species. - var/list/speech_sounds // A list of sounds to potentially play when speaking. - var/list/speech_chance // The likelihood of a speech sound playing. - var/scream_verb = "screams" - var/male_scream_sound = 'sound/goonstation/voice/male_scream.ogg' - var/female_scream_sound = 'sound/goonstation/voice/female_scream.ogg' - - //Default hair/headacc style vars. - var/default_hair //Default hair style for newly created humans unless otherwise set. - var/default_hair_colour - var/default_fhair //Default facial hair style for newly created humans unless otherwise set. - var/default_fhair_colour - var/default_headacc //Default head accessory style for newly created humans unless otherwise set. - var/default_headacc_colour - - //Defining lists of icon skin tones for species that have them. - var/list/icon_skin_tones = list() - - // Determines the organs that the species spawns with and - var/list/has_organ = list( // which required-organ checks are conducted. - "heart" = /obj/item/organ/internal/heart, - "lungs" = /obj/item/organ/internal/lungs, - "liver" = /obj/item/organ/internal/liver, - "kidneys" = /obj/item/organ/internal/kidneys, - "brain" = /obj/item/organ/internal/brain, - "appendix" = /obj/item/organ/internal/appendix, - "eyes" = /obj/item/organ/internal/eyes - ) - var/vision_organ // If set, this organ is required for vision. Defaults to "eyes" if the species has them. - var/list/has_limbs = list( - "chest" = list("path" = /obj/item/organ/external/chest), - "groin" = list("path" = /obj/item/organ/external/groin), - "head" = list("path" = /obj/item/organ/external/head), - "l_arm" = list("path" = /obj/item/organ/external/arm), - "r_arm" = list("path" = /obj/item/organ/external/arm/right), - "l_leg" = list("path" = /obj/item/organ/external/leg), - "r_leg" = list("path" = /obj/item/organ/external/leg/right), - "l_hand" = list("path" = /obj/item/organ/external/hand), - "r_hand" = list("path" = /obj/item/organ/external/hand/right), - "l_foot" = list("path" = /obj/item/organ/external/foot), - "r_foot" = list("path" = /obj/item/organ/external/foot/right) - ) - var/cyborg_type = "Cyborg" - var/list/proc/species_abilities = list() - -/datum/species/New() - //If the species has eyes, they are the default vision organ - if(!vision_organ && has_organ["eyes"]) - vision_organ = /obj/item/organ/internal/eyes - - unarmed = new unarmed_type() - -/datum/species/proc/get_random_name(var/gender) - var/datum/language/species_language = all_languages[language] - return species_language.get_random_name(gender) - -/datum/species/proc/create_organs(var/mob/living/carbon/human/H) //Handles creation of mob organs. - - for(var/obj/item/organ/internal/iorgan in H.internal_organs) - if(iorgan in H.internal_organs) - qdel(iorgan) - - for(var/obj/item/organ/organ in H.contents) - if(organ in H.organs) - qdel(organ) - - if(H.organs) H.organs.Cut() - if(H.organs_by_name) H.organs_by_name.Cut() - - H.organs = list() - H.internal_organs = list() - H.organs_by_name = list() - - for(var/limb_type in has_limbs) - var/list/organ_data = has_limbs[limb_type] - var/limb_path = organ_data["path"] - var/obj/item/organ/O = new limb_path(H) - organ_data["descriptor"] = O.name - - for(var/index in has_organ) - var/organ = has_organ[index] - // organ new code calls `insert` on its own - new organ(H) - - for(var/name in H.organs_by_name) - H.organs |= H.organs_by_name[name] - - for(var/obj/item/organ/external/O in H.organs) - O.owner = H - -/datum/species/proc/handle_breath(var/datum/gas_mixture/breath, var/mob/living/carbon/human/H) - var/breath_pressure = (breath.total_moles()*R_IDEAL_GAS_EQUATION*breath.temperature)/BREATH_VOLUME - - var/O2_used = 0 - var/N2_used = 0 - var/Tox_used = 0 - var/CO2_used = 0 - - //Partial pressure of the O2 in our breath - var/O2_pp = (breath.oxygen/breath.total_moles()) * breath_pressure - // Partial pressure of Nitrogen - var/N2_pp = (breath.nitrogen/breath.total_moles()) * breath_pressure - // Partial pressure of plasma - var/Tox_pp = (breath.toxins/breath.total_moles()) * breath_pressure - // Partial pressure of CO2 - var/CO2_pp = (breath.carbon_dioxide/breath.total_moles()) * breath_pressure - - if(O2_pp < atmos_requirements["min_oxy"]) - if(prob(20)) - spawn(0) - H.emote("gasp") - - H.failed_last_breath = 1 - if(O2_pp > 0) - var/ratio = atmos_requirements["min_oxy"] / O2_pp - H.adjustOxyLoss(min(5 * ratio, HUMAN_MAX_OXYLOSS)) - else - H.adjustOxyLoss(HUMAN_MAX_OXYLOSS) - H.throw_alert("oxy", /obj/screen/alert/oxy) - else if(atmos_requirements["max_oxy"] && O2_pp > atmos_requirements["max_oxy"]) - var/ratio = (breath.oxygen / atmos_requirements["max_oxy"]) * 1000 - H.adjustToxLoss(Clamp(ratio, MIN_PLASMA_DAMAGE, MAX_PLASMA_DAMAGE)) - H.throw_alert("oxy", /obj/screen/alert/too_much_oxy) - else - H.clear_alert("oxy") - if(atmos_requirements["min_oxy"]) //species breathes this gas, so, they got their air - H.failed_last_breath = 0 - H.adjustOxyLoss(-5) - O2_used = breath.oxygen / 6 - - if(N2_pp < atmos_requirements["min_nitro"]) - if(prob(20)) - spawn(0) - H.emote("gasp") - - H.failed_last_breath = 1 - if(N2_pp > 0) - var/ratio = atmos_requirements["min_nitro"] / N2_pp - H.adjustOxyLoss(min(5 * ratio, HUMAN_MAX_OXYLOSS)) - else - H.adjustOxyLoss(HUMAN_MAX_OXYLOSS) - H.throw_alert("nitro", /obj/screen/alert/nitro) - else if(atmos_requirements["max_nitro"] && N2_pp > atmos_requirements["max_nitro"]) - var/ratio = (breath.nitrogen / atmos_requirements["max_nitro"]) * 1000 - H.adjustToxLoss(Clamp(ratio, MIN_PLASMA_DAMAGE, MAX_PLASMA_DAMAGE)) - H.throw_alert("nitro", /obj/screen/alert/too_much_nitro) - else - H.clear_alert("nitro") - if(atmos_requirements["min_nitro"]) //species breathes this gas, so they got their air - H.failed_last_breath = 0 - H.adjustOxyLoss(-5) - N2_used = breath.nitrogen / 6 - - if(Tox_pp < atmos_requirements["min_tox"]) - if(prob(20)) - spawn(0) - H.emote("gasp") - - H.failed_last_breath = 1 - if(Tox_pp > 0) - var/ratio = atmos_requirements["min_tox"] / Tox_pp - H.adjustOxyLoss(min(5 * ratio, HUMAN_MAX_OXYLOSS)) - else - H.adjustOxyLoss(HUMAN_MAX_OXYLOSS) - H.throw_alert("tox_in_air", /obj/screen/alert/not_enough_tox) - else if(atmos_requirements["max_tox"] && Tox_pp > atmos_requirements["max_tox"]) - var/ratio = (breath.toxins / atmos_requirements["max_tox"]) * 10 - if(H.reagents) - H.reagents.add_reagent("plasma", Clamp(ratio, MIN_PLASMA_DAMAGE, MAX_PLASMA_DAMAGE)) - H.throw_alert("tox_in_air", /obj/screen/alert/tox_in_air) - else - H.clear_alert("tox_in_air") - if(atmos_requirements["min_tox"]) //species breathes this gas, so, they got their air - H.failed_last_breath = 0 - H.adjustOxyLoss(-5) - Tox_used = breath.toxins / 6 - - if(CO2_pp < atmos_requirements["min_co2"]) - if(prob(20)) - spawn(0) - H.emote("gasp") - - H.failed_last_breath = 1 - if(CO2_pp) - var/ratio = atmos_requirements["min_co2"] / CO2_pp - H.adjustOxyLoss(min(5 * ratio, HUMAN_MAX_OXYLOSS)) - else - H.adjustOxyLoss(HUMAN_MAX_OXYLOSS) - H.throw_alert("co2", /obj/screen/alert/not_enough_co2) - else if(atmos_requirements["max_co2"] && CO2_pp > atmos_requirements["max_co2"]) - if(!H.co2overloadtime) // If it's the first breath with too much CO2 in it, lets start a counter, then have them pass out after 12s or so. - H.co2overloadtime = world.time - else if(world.time - H.co2overloadtime > 120) - H.Paralyse(5) - H.adjustOxyLoss(3) // Lets hurt em a little, let them know we mean business - if(world.time - H.co2overloadtime > 300) // They've been in here 30s now, lets start to kill them for their own good! - H.adjustOxyLoss(8) - if(prob(20)) // Lets give them some chance to know somethings not right though I guess. - spawn(0) - H.emote("cough") - else - H.clear_alert("co2") - H.co2overloadtime = 0 - if(atmos_requirements["min_co2"]) //species breathes this gas, so they got their air - H.failed_last_breath = 0 - H.adjustOxyLoss(-5) - CO2_used = breath.carbon_dioxide / 6 - - breath.oxygen -= O2_used - breath.nitrogen -= N2_used - breath.toxins -= Tox_used - breath.carbon_dioxide -= CO2_used - breath.carbon_dioxide += O2_used - - - if(breath.trace_gases.len) // If there's some other shit in the air lets deal with it here. - for(var/datum/gas/sleeping_agent/SA in breath.trace_gases) - var/SA_pp = (SA.moles / breath.total_moles()) * breath_pressure - if(SA_pp > atmos_requirements["sa_para"]) // Enough to make us paralysed for a bit - H.Paralyse(3) // 3 gives them one second to wake up and run away a bit! - if(SA_pp > atmos_requirements["sa_sleep"]) // Enough to make us sleep as well - // This value is large because breaths are taken only once every 4 life ticks. - H.AdjustSleeping(8, bound_lower = 0, bound_upper = 10) - else if(SA_pp > 0.01) // There is sleeping gas in their lungs, but only a little, so give them a bit of a warning - if(prob(20)) - spawn(0) - H.emote(pick("giggle", "laugh")) - - handle_temperature(breath, H) - return 1 - -/datum/species/proc/handle_temperature(datum/gas_mixture/breath, var/mob/living/carbon/human/H) // called by human/life, handles temperatures - if(abs(310.15 - breath.temperature) > 50) // Hot air hurts :( - if(H.status_flags & GODMODE) return 1 //godmode - if(breath.temperature < cold_level_1) - if(prob(20)) - to_chat(H, "You feel your face freezing and an icicle forming in your lungs!") - else if(breath.temperature > heat_level_1) - if(prob(20)) - to_chat(H, "You feel your face burning and a searing heat in your lungs!") - - - - switch(breath.temperature) - if(-INFINITY to cold_level_3) - H.apply_damage(cold_env_multiplier*COLD_GAS_DAMAGE_LEVEL_3, BURN, "head", used_weapon = "Excessive Cold") - - if(cold_level_3 to cold_level_2) - H.apply_damage(cold_env_multiplier*COLD_GAS_DAMAGE_LEVEL_2, BURN, "head", used_weapon = "Excessive Cold") - - if(cold_level_2 to cold_level_1) - H.apply_damage(cold_env_multiplier*COLD_GAS_DAMAGE_LEVEL_1, BURN, "head", used_weapon = "Excessive Cold") - - if(heat_level_1 to heat_level_2) - H.apply_damage(hot_env_multiplier*HEAT_GAS_DAMAGE_LEVEL_1, BURN, "head", used_weapon = "Excessive Heat") - - if(heat_level_2 to heat_level_3_breathe) - H.apply_damage(hot_env_multiplier*HEAT_GAS_DAMAGE_LEVEL_2, BURN, "head", used_weapon = "Excessive Heat") - - if(heat_level_3_breathe to INFINITY) - H.apply_damage(hot_env_multiplier*HEAT_GAS_DAMAGE_LEVEL_3, BURN, "head", used_weapon = "Excessive Heat") - -/datum/species/proc/handle_post_spawn(var/mob/living/carbon/C) //Handles anything not already covered by basic species assignment. - grant_abilities(C) - return - -/datum/species/proc/updatespeciescolor(var/mob/living/carbon/human/H) //Handles changing icobase for species that have multiple skin colors. - return - -/datum/species/proc/grant_abilities(var/mob/living/carbon/human/H) - for(var/proc/ability in species_abilities) - H.verbs += ability - return - -/datum/species/proc/handle_pre_change(var/mob/living/carbon/human/H) - if(H.butcher_results)//clear it out so we don't butcher a actual human. - H.butcher_results = null - remove_abilities(H) - return - -/datum/species/proc/remove_abilities(var/mob/living/carbon/human/H) - for(var/proc/ability in species_abilities) - H.verbs -= ability - return - -// Do species-specific reagent handling here -// Return 1 if it should do normal processing too -// Return 0 if it shouldn't deplete and do its normal effect -// Other return values will cause weird badness -/datum/species/proc/handle_reagents(var/mob/living/carbon/human/H, var/datum/reagent/R) - return 1 - -// For special snowflake species effects -// (Slime People changing color based on the reagents they consume) -/datum/species/proc/handle_life(var/mob/living/carbon/human/H) - return 1 - -/datum/species/proc/handle_dna(var/mob/living/carbon/C, var/remove) //Handles DNA mutations, as that doesn't work at init. Make sure you call genemutcheck on any blocks changed here - return - -// Used for species-specific names (Vox, etc) -/datum/species/proc/makeName(var/gender,var/mob/living/carbon/human/H=null) - if(gender==FEMALE) return capitalize(pick(first_names_female)) + " " + capitalize(pick(last_names)) - else return capitalize(pick(first_names_male)) + " " + capitalize(pick(last_names)) - -/datum/species/proc/handle_death(var/mob/living/carbon/human/H) //Handles any species-specific death events (such as dionaea nymph spawns). - return - -/datum/species/proc/handle_attack_hand(var/mob/living/carbon/human/H, var/mob/living/carbon/human/M) //Handles any species-specific attackhand events. - return - -/datum/species/proc/say_filter(mob/M, message, datum/language/speaking) - return message - -/datum/species/proc/equip(var/mob/living/carbon/human/H) - return - -/datum/species/proc/can_understand(var/mob/other) - return - -// Called in life() when the mob has no client. -/datum/species/proc/handle_npc(var/mob/living/carbon/human/H) - return - -//Species unarmed attacks - -/datum/unarmed_attack - var/attack_verb = list("attack") // Empty hand hurt intent verb. - var/damage = 0 // How much flat bonus damage an attack will do. This is a *bonus* guaranteed damage amount on top of the random damage attacks do. - var/attack_sound = "punch" - var/miss_sound = 'sound/weapons/punchmiss.ogg' - var/sharp = 0 - var/edge = 0 - -/datum/unarmed_attack/punch - attack_verb = list("punch") - -/datum/unarmed_attack/punch/weak - attack_verb = list("flail") - -/datum/unarmed_attack/diona - attack_verb = list("lash", "bludgeon") - -/datum/unarmed_attack/claws - attack_verb = list("scratch", "claw") - attack_sound = 'sound/weapons/slice.ogg' - miss_sound = 'sound/weapons/slashmiss.ogg' - sharp = 1 - edge = 1 - -/datum/unarmed_attack/claws/armalis - attack_verb = list("slash", "claw") - damage = 6 - -/datum/species/proc/handle_can_equip(obj/item/I, slot, disable_warning = 0, mob/living/carbon/human/user) - return 0 - -/datum/species/proc/handle_vision(mob/living/carbon/human/H) - if(H.stat == DEAD) - H.sight |= (SEE_TURFS|SEE_MOBS|SEE_OBJS) - H.see_in_dark = 8 - if(!H.druggy) - H.see_invisible = SEE_INVISIBLE_LEVEL_TWO - return - - H.sight &= ~(SEE_TURFS|SEE_MOBS|SEE_OBJS) - - H.see_in_dark = darksight //set their variables to default, modify them later - H.see_invisible = SEE_INVISIBLE_LIVING - - if(H.mind && H.mind.vampire) - if(H.mind.vampire.get_ability(/datum/vampire_passive/full)) - H.sight |= SEE_TURFS|SEE_MOBS|SEE_OBJS - H.see_in_dark = 8 - H.see_invisible = SEE_INVISIBLE_MINIMUM - else if(H.mind.vampire.get_ability(/datum/vampire_passive/vision)) - H.sight |= SEE_MOBS - - - if(XRAY in H.mutations) - H.sight |= SEE_TURFS|SEE_MOBS|SEE_OBJS - H.see_in_dark = 8 - - H.see_invisible = SEE_INVISIBLE_MINIMUM - - //This checks how much the mob's eyewear impairs their vision - if(H.tinttotal >= TINT_IMPAIR) - if(tinted_weldhelh) - H.overlay_fullscreen("tint", /obj/screen/fullscreen/impaired, 2) - if(H.tinttotal >= TINT_BLIND) - H.EyeBlind(1) - else - H.clear_fullscreen("tint") - - var/minimum_darkness_view = INFINITY - if(H.glasses) - if(istype(H.glasses, /obj/item/clothing/glasses)) - var/obj/item/clothing/glasses/G = H.glasses - H.sight |= G.vision_flags - - if(G.darkness_view) - H.see_in_dark = G.darkness_view - minimum_darkness_view = G.darkness_view - - if(!G.see_darkness) - H.see_invisible = SEE_INVISIBLE_MINIMUM - - if(H.head) - if(istype(H.head, /obj/item/clothing/head)) - var/obj/item/clothing/head/hat = H.head - H.sight |= hat.vision_flags - - if(hat.darkness_view && hat.darkness_view < minimum_darkness_view) // Pick the lowest of the two darkness_views between the glasses and helmet. - H.see_in_dark = hat.darkness_view - - if(!hat.see_darkness) - H.see_invisible = SEE_INVISIBLE_MINIMUM - - //switch(hat.HUDType) - // if(SECHUD) - // process_sec_hud(H,1) - // if(MEDHUD) - // process_med_hud(H,1) - // if(ANTAGHUD) - // process_antag_hud(H) - - if(istype(H.back, /obj/item/weapon/rig)) ///ahhhg so snowflakey - var/obj/item/weapon/rig/rig = H.back - if(rig.visor) - if(!rig.helmet || (H.head && rig.helmet == H.head)) - if(rig.visor && rig.visor.vision && rig.visor.active && rig.visor.vision.glasses) - var/obj/item/clothing/glasses/G = rig.visor.vision.glasses - if(istype(G)) - H.see_in_dark = (G.darkness_view ? G.darkness_view : darksight) // Otherwise we keep our darkness view with togglable nightvision. - if(G.vision_flags) // MESONS - H.sight |= G.vision_flags - - if(!G.see_darkness) - H.see_invisible = SEE_INVISIBLE_MINIMUM - - //switch(G.HUDType) - // if(SECHUD) - // process_sec_hud(H,1) - // if(MEDHUD) - // process_med_hud(H,1) - // if(ANTAGHUD) - // process_antag_hud(H) - - if(H.vision_type) - H.see_in_dark = max(H.see_in_dark, H.vision_type.see_in_dark, darksight) - H.see_invisible = H.vision_type.see_invisible - if(H.vision_type.light_sensitive) - H.weakeyes = 1 - H.sight |= H.vision_type.sight_flags - - if(H.see_override) //Override all - H.see_invisible = H.see_override - - if(!H.client) - return 1 - - if(H.blinded || H.eye_blind) - H.overlay_fullscreen("blind", /obj/screen/fullscreen/blind) - H.throw_alert("blind", /obj/screen/alert/blind) - else - H.clear_fullscreen("blind") - H.clear_alert("blind") - - - if(H.disabilities & NEARSIGHTED) //this looks meh but saves a lot of memory by not requiring to add var/prescription - if(H.glasses) //to every /obj/item - var/obj/item/clothing/glasses/G = H.glasses - if(G.prescription) - H.clear_fullscreen("nearsighted") - else - H.overlay_fullscreen("nearsighted", /obj/screen/fullscreen/impaired, 1) - else - H.overlay_fullscreen("nearsighted", /obj/screen/fullscreen/impaired, 1) - else - H.clear_fullscreen("nearsighted") - - if(H.eye_blurry) - H.overlay_fullscreen("blurry", /obj/screen/fullscreen/blurry) - else - H.clear_fullscreen("blurry") - - if(H.druggy) - H.overlay_fullscreen("high", /obj/screen/fullscreen/high) - H.throw_alert("high", /obj/screen/alert/high) - else - H.clear_fullscreen("high") - H.clear_alert("high") - -/datum/species/proc/handle_hud_icons(mob/living/carbon/human/H) - if(!H.client) - return - if(H.healths) - if(H.stat == DEAD) - H.healths.icon_state = "health7" - else - switch(H.hal_screwyhud) - if(1) H.healths.icon_state = "health6" - if(2) H.healths.icon_state = "health7" - if(5) H.healths.icon_state = "health0" - else - switch(100 - ((flags & NO_PAIN) ? 0 : H.traumatic_shock) - H.staminaloss) - if(100 to INFINITY) H.healths.icon_state = "health0" - if(80 to 100) H.healths.icon_state = "health1" - if(60 to 80) H.healths.icon_state = "health2" - if(40 to 60) H.healths.icon_state = "health3" - if(20 to 40) H.healths.icon_state = "health4" - if(0 to 20) H.healths.icon_state = "health5" - else H.healths.icon_state = "health6" - - if(H.healthdoll) - if(H.stat == DEAD) - H.healthdoll.icon_state = "healthdoll_DEAD" - if(H.healthdoll.overlays.len) - H.healthdoll.overlays.Cut() - else - var/list/new_overlays = list() - var/list/cached_overlays = H.healthdoll.cached_healthdoll_overlays - // Use the dead health doll as the base, since we have proper "healthy" overlays now - H.healthdoll.icon_state = "healthdoll_DEAD" - for(var/obj/item/organ/external/O in H.organs) - var/damage = O.burn_dam + O.brute_dam - var/comparison = (O.max_damage/5) - var/icon_num = 0 - if(damage) - icon_num = 1 - if(damage > (comparison)) - icon_num = 2 - if(damage > (comparison*2)) - icon_num = 3 - if(damage > (comparison*3)) - icon_num = 4 - if(damage > (comparison*4)) - icon_num = 5 - new_overlays += "[O.limb_name][icon_num]" - H.healthdoll.overlays += (new_overlays - cached_overlays) - H.healthdoll.overlays -= (cached_overlays - new_overlays) - H.healthdoll.cached_healthdoll_overlays = new_overlays - - switch(H.nutrition) - if(NUTRITION_LEVEL_FULL to INFINITY) - H.throw_alert("nutrition", /obj/screen/alert/fat) - if(NUTRITION_LEVEL_HUNGRY to NUTRITION_LEVEL_FULL) - H.clear_alert("nutrition") - if(NUTRITION_LEVEL_STARVING to NUTRITION_LEVEL_HUNGRY) - H.throw_alert("nutrition", /obj/screen/alert/hungry) - else - H.throw_alert("nutrition", /obj/screen/alert/starving) - return 1 - -/* -Returns the path corresponding to the corresponding organ -It'll return null if the organ doesn't correspond, so include null checks when using this! -*/ -//Fethas Todo:Do i need to redo this? -/datum/species/proc/return_organ(var/organ_slot) - if(!(organ_slot in has_organ)) - return null - return has_organ[organ_slot] + + + + + + + + + + + + + + + + + + + + + + Paradise/species.dm at master · ParadiseSS13/Paradise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Skip to content + + + + + + + + + + + + + +
+ +
+
+ + +
+
+
+ +
+
+ + + +
    + +
  • +
    + +
    + + + + Watch + + + + +
    + +
    +
    +
    +
  • + +
  • + +
    + +
    + + +
    +
    + + +
    + +
  • + +
  • +
    + +
    + +
  • +
+ +

+ + /Paradise + +

+ +
+ +
+ +
+
+ + + +Permalink + + + +
+ +
+ + + +
+ +
+ + Find file + + +
+ +
+ + +
+ Fetching contributors… +
+ +
+ + Cannot retrieve contributors at this time +
+
+ +
+
+
+ +
+ Raw + Blame + History +
+ + + + + +
+ +
+ +
+ +
+ 666 lines (556 sloc) + + 25.2 KB +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
/*
Datum-based species. Should make for much cleaner and easier to maintain mutantrace code.
*/
+
/datum/species
var/name // Species name.
var/name_plural // Pluralized name (since "[name]s" is not always valid)
var/path // Species path
var/icobase = 'icons/mob/human_races/r_human.dmi' // Normal icon set.
var/deform = 'icons/mob/human_races/r_def_human.dmi' // Mutated icon set.
+
// Damage overlay and masks.
var/damage_overlays = 'icons/mob/human_races/masks/dam_human.dmi'
var/damage_mask = 'icons/mob/human_races/masks/dam_mask_human.dmi'
var/blood_mask = 'icons/mob/human_races/masks/blood_human.dmi'
+
var/eyes = "eyes_s" // Icon for eyes.
var/blurb = "A completely nondescript species." // A brief lore summary for use in the chargen screen.
var/butt_sprite = "human"
+
var/primitive_form // Lesser form, if any (ie. monkey for humans)
var/greater_form // Greater form, if any, ie. human for monkeys.
var/tail // Name of tail image in species effects icon file.
var/unarmed //For empty hand harm-intent attack
var/unarmed_type = /datum/unarmed_attack
var/slowdown = 0 // Passive movement speed malus (or boost, if negative)
var/silent_steps = 0 // Stops step noises
+
var/breath_type = "oxygen" // Non-oxygen gas breathed, if any.
var/poison_type = "plasma" // Poisonous air.
var/exhale_type = "carbon_dioxide" // Exhaled gas type.
+
var/cold_level_1 = 260 // Cold damage level 1 below this point.
var/cold_level_2 = 200 // Cold damage level 2 below this point.
var/cold_level_3 = 120 // Cold damage level 3 below this point.
var/cold_env_multiplier = 1 // Damage multiplier for being in a cold environment
+
var/heat_level_1 = 360 // Heat damage level 1 above this point.
var/heat_level_2 = 400 // Heat damage level 2 above this point.
var/heat_level_3 = 460 // Heat damage level 3 above this point; used for body temperature
var/hot_env_multiplier = 1 // Damage multiplier for being in a hot environment
var/heat_level_3_breathe = 1000 // Heat damage level 3 above this point; used for breathed air temperature
+
var/body_temperature = 310.15 //non-IS_SYNTHETIC species will try to stabilize at this temperature. (also affects temperature processing)
var/reagent_tag //Used for metabolizing reagents.
+
var/siemens_coeff = 1 //base electrocution coefficient
+
var/invis_sight = SEE_INVISIBLE_LIVING
var/darksight = 2
var/hazard_high_pressure = HAZARD_HIGH_PRESSURE // Dangerously high pressure.
var/warning_high_pressure = WARNING_HIGH_PRESSURE // High pressure warning.
var/warning_low_pressure = WARNING_LOW_PRESSURE // Low pressure warning.
var/hazard_low_pressure = HAZARD_LOW_PRESSURE // Dangerously low pressure.
+
var/list/atmos_requirements = list(
"min_oxy" = 16,
"max_oxy" = 0,
"min_nitro" = 0,
"max_nitro" = 0,
"min_tox" = 0,
"max_tox" = 0.005,
"min_co2" = 0,
"max_co2" = 10,
"sa_para" = 1,
"sa_sleep" = 5
)
+
var/brute_mod = null // Physical damage reduction/malus.
var/burn_mod = null // Burn damage reduction/malus.
+
var/total_health = 100
var/punchdamagelow = 0 //lowest possible punch damage
var/punchdamagehigh = 9 //highest possible punch damage
var/punchstunthreshold = 9 //damage at which punches from this race will stun //yes it should be to the attacked race but it's not useful that way even if it's logical
var/list/default_genes = list()
+
var/ventcrawler = 0 //Determines if the mob can go through the vents.
var/has_fine_manipulation = 1 // Can use small items.
+
var/list/allowed_consumed_mobs = list() //If a species can consume mobs, put the type of mobs it can consume here.
+
var/flags = 0 // Various specific features.
var/clothing_flags = 0 // Underwear and socks.
var/exotic_blood
var/bodyflags = 0
var/dietflags = 0 // Make sure you set this, otherwise it won't be able to digest a lot of foods
+
var/list/abilities = list() // For species-derived or admin-given powers
+
var/blood_color = "#A10808" //Red.
var/flesh_color = "#FFC896" //Pink.
var/single_gib_type = /obj/effect/decal/cleanable/blood/gibs
var/remains_type = /obj/effect/decal/remains/human //What sort of remains is left behind when the species dusts
var/base_color //Used when setting species.
+
//Used in icon caching.
var/race_key = 0
var/icon/icon_template
var/is_small
var/show_ssd = 1
var/virus_immune
var/can_revive_by_healing // Determines whether or not this species can be revived by simply healing them
+
//Death vars.
var/death_message = "seizes up and falls limp, their eyes dead and lifeless..."
var/list/suicide_messages = list(
"is attempting to bite their tongue off!",
"is jamming their thumbs into their eye sockets!",
"is twisting their own neck!",
"is holding their breath!")
+
// Language/culture vars.
var/default_language = "Galactic Common" // Default language is used when 'say' is used without modifiers.
var/language = "Galactic Common" // Default racial language, if any.
var/secondary_langs = list() // The names of secondary languages that are available to this species.
var/list/speech_sounds // A list of sounds to potentially play when speaking.
var/list/speech_chance // The likelihood of a speech sound playing.
var/scream_verb = "screams"
var/male_scream_sound = 'sound/goonstation/voice/male_scream.ogg'
var/female_scream_sound = 'sound/goonstation/voice/female_scream.ogg'
+
//Default hair/headacc style vars.
var/default_hair //Default hair style for newly created humans unless otherwise set.
var/default_hair_colour
var/default_fhair //Default facial hair style for newly created humans unless otherwise set.
var/default_fhair_colour
var/default_headacc //Default head accessory style for newly created humans unless otherwise set.
var/default_headacc_colour
+
//Defining lists of icon skin tones for species that have them.
var/list/icon_skin_tones = list()
+
// Determines the organs that the species spawns with and
var/list/has_organ = list( // which required-organ checks are conducted.
"heart" = /obj/item/organ/internal/heart,
"lungs" = /obj/item/organ/internal/lungs,
"liver" = /obj/item/organ/internal/liver,
"kidneys" = /obj/item/organ/internal/kidneys,
"brain" = /obj/item/organ/internal/brain,
"appendix" = /obj/item/organ/internal/appendix,
"eyes" = /obj/item/organ/internal/eyes
)
var/vision_organ // If set, this organ is required for vision. Defaults to "eyes" if the species has them.
var/list/has_limbs = list(
"chest" = list("path" = /obj/item/organ/external/chest),
"groin" = list("path" = /obj/item/organ/external/groin),
"head" = list("path" = /obj/item/organ/external/head),
"l_arm" = list("path" = /obj/item/organ/external/arm),
"r_arm" = list("path" = /obj/item/organ/external/arm/right),
"l_leg" = list("path" = /obj/item/organ/external/leg),
"r_leg" = list("path" = /obj/item/organ/external/leg/right),
"l_hand" = list("path" = /obj/item/organ/external/hand),
"r_hand" = list("path" = /obj/item/organ/external/hand/right),
"l_foot" = list("path" = /obj/item/organ/external/foot),
"r_foot" = list("path" = /obj/item/organ/external/foot/right)
)
var/cyborg_type = "Cyborg"
var/list/proc/species_abilities = list()
+
/datum/species/New()
//If the species has eyes, they are the default vision organ
if(!vision_organ && has_organ["eyes"])
vision_organ = /obj/item/organ/internal/eyes
+
unarmed = new unarmed_type()
+
/datum/species/proc/get_random_name(var/gender)
var/datum/language/species_language = all_languages[language]
return species_language.get_random_name(gender)
+
/datum/species/proc/create_organs(var/mob/living/carbon/human/H) //Handles creation of mob organs.
+
for(var/obj/item/organ/internal/iorgan in H.internal_organs)
if(iorgan in H.internal_organs)
qdel(iorgan)
+
for(var/obj/item/organ/organ in H.contents)
if(organ in H.organs)
qdel(organ)
+
if(H.organs) H.organs.Cut()
if(H.organs_by_name) H.organs_by_name.Cut()
+
H.organs = list()
H.internal_organs = list()
H.organs_by_name = list()
+
for(var/limb_type in has_limbs)
var/list/organ_data = has_limbs[limb_type]
var/limb_path = organ_data["path"]
var/obj/item/organ/O = new limb_path(H)
organ_data["descriptor"] = O.name
+
for(var/index in has_organ)
var/organ = has_organ[index]
// organ new code calls `insert` on its own
new organ(H)
+
for(var/name in H.organs_by_name)
H.organs |= H.organs_by_name[name]
+
for(var/obj/item/organ/external/O in H.organs)
O.owner = H
+
/datum/species/proc/handle_breath(var/datum/gas_mixture/breath, var/mob/living/carbon/human/H)
var/breath_pressure = (breath.total_moles()*R_IDEAL_GAS_EQUATION*breath.temperature)/BREATH_VOLUME
+
var/O2_used = 0
var/N2_used = 0
var/Tox_used = 0
var/CO2_used = 0
+
//Partial pressure of the O2 in our breath
var/O2_pp = (breath.oxygen/breath.total_moles()) * breath_pressure
// Partial pressure of Nitrogen
var/N2_pp = (breath.nitrogen/breath.total_moles()) * breath_pressure
// Partial pressure of plasma
var/Tox_pp = (breath.toxins/breath.total_moles()) * breath_pressure
// Partial pressure of CO2
var/CO2_pp = (breath.carbon_dioxide/breath.total_moles()) * breath_pressure
+
if(O2_pp < atmos_requirements["min_oxy"])
if(prob(20))
spawn(0)
H.emote("gasp")
+
H.failed_last_breath = 1
if(O2_pp > 0)
var/ratio = atmos_requirements["min_oxy"] / O2_pp
H.adjustOxyLoss(min(5 * ratio, HUMAN_MAX_OXYLOSS))
else
H.adjustOxyLoss(HUMAN_MAX_OXYLOSS)
H.throw_alert("oxy", /obj/screen/alert/oxy)
else if(atmos_requirements["max_oxy"] && O2_pp > atmos_requirements["max_oxy"])
var/ratio = (breath.oxygen / atmos_requirements["max_oxy"]) * 1000
H.adjustToxLoss(Clamp(ratio, MIN_PLASMA_DAMAGE, MAX_PLASMA_DAMAGE))
H.throw_alert("oxy", /obj/screen/alert/too_much_oxy)
else
H.clear_alert("oxy")
if(atmos_requirements["min_oxy"]) //species breathes this gas, so, they got their air
H.failed_last_breath = 0
H.adjustOxyLoss(-5)
O2_used = breath.oxygen / 6
+
if(N2_pp < atmos_requirements["min_nitro"])
if(prob(20))
spawn(0)
H.emote("gasp")
+
H.failed_last_breath = 1
if(N2_pp > 0)
var/ratio = atmos_requirements["min_nitro"] / N2_pp
H.adjustOxyLoss(min(5 * ratio, HUMAN_MAX_OXYLOSS))
else
H.adjustOxyLoss(HUMAN_MAX_OXYLOSS)
H.throw_alert("nitro", /obj/screen/alert/nitro)
else if(atmos_requirements["max_nitro"] && N2_pp > atmos_requirements["max_nitro"])
var/ratio = (breath.nitrogen / atmos_requirements["max_nitro"]) * 1000
H.adjustToxLoss(Clamp(ratio, MIN_PLASMA_DAMAGE, MAX_PLASMA_DAMAGE))
H.throw_alert("nitro", /obj/screen/alert/too_much_nitro)
else
H.clear_alert("nitro")
if(atmos_requirements["min_nitro"]) //species breathes this gas, so they got their air
H.failed_last_breath = 0
H.adjustOxyLoss(-5)
N2_used = breath.nitrogen / 6
+
if(Tox_pp < atmos_requirements["min_tox"])
if(prob(20))
spawn(0)
H.emote("gasp")
+
H.failed_last_breath = 1
if(Tox_pp > 0)
var/ratio = atmos_requirements["min_tox"] / Tox_pp
H.adjustOxyLoss(min(5 * ratio, HUMAN_MAX_OXYLOSS))
else
H.adjustOxyLoss(HUMAN_MAX_OXYLOSS)
H.throw_alert("tox_in_air", /obj/screen/alert/not_enough_tox)
else if(atmos_requirements["max_tox"] && Tox_pp > atmos_requirements["max_tox"])
var/ratio = (breath.toxins / atmos_requirements["max_tox"]) * 10
if(H.reagents)
H.reagents.add_reagent("plasma", Clamp(ratio, MIN_PLASMA_DAMAGE, MAX_PLASMA_DAMAGE))
H.throw_alert("tox_in_air", /obj/screen/alert/tox_in_air)
else
H.clear_alert("tox_in_air")
if(atmos_requirements["min_tox"]) //species breathes this gas, so, they got their air
H.failed_last_breath = 0
H.adjustOxyLoss(-5)
Tox_used = breath.toxins / 6
+
if(CO2_pp < atmos_requirements["min_co2"])
if(prob(20))
spawn(0)
H.emote("gasp")
+
H.failed_last_breath = 1
if(CO2_pp)
var/ratio = atmos_requirements["min_co2"] / CO2_pp
H.adjustOxyLoss(min(5 * ratio, HUMAN_MAX_OXYLOSS))
else
H.adjustOxyLoss(HUMAN_MAX_OXYLOSS)
H.throw_alert("co2", /obj/screen/alert/not_enough_co2)
else if(atmos_requirements["max_co2"] && CO2_pp > atmos_requirements["max_co2"])
if(!H.co2overloadtime) // If it's the first breath with too much CO2 in it, lets start a counter, then have them pass out after 12s or so.
H.co2overloadtime = world.time
else if(world.time - H.co2overloadtime > 120)
H.Paralyse(5)
H.adjustOxyLoss(3) // Lets hurt em a little, let them know we mean business
if(world.time - H.co2overloadtime > 300) // They've been in here 30s now, lets start to kill them for their own good!
H.adjustOxyLoss(8)
if(prob(20)) // Lets give them some chance to know somethings not right though I guess.
spawn(0)
H.emote("cough")
else
H.clear_alert("co2")
H.co2overloadtime = 0
if(atmos_requirements["min_co2"]) //species breathes this gas, so they got their air
H.failed_last_breath = 0
H.adjustOxyLoss(-5)
CO2_used = breath.carbon_dioxide / 6
+
breath.oxygen -= O2_used
breath.nitrogen -= N2_used
breath.toxins -= Tox_used
breath.carbon_dioxide -= CO2_used
breath.carbon_dioxide += O2_used
+
+
if(breath.trace_gases.len) // If there's some other shit in the air lets deal with it here.
for(var/datum/gas/sleeping_agent/SA in breath.trace_gases)
var/SA_pp = (SA.moles / breath.total_moles()) * breath_pressure
if(SA_pp > atmos_requirements["sa_para"]) // Enough to make us paralysed for a bit
H.Paralyse(3) // 3 gives them one second to wake up and run away a bit!
if(SA_pp > atmos_requirements["sa_sleep"]) // Enough to make us sleep as well
// This value is large because breaths are taken only once every 4 life ticks.
H.AdjustSleeping(8, bound_lower = 0, bound_upper = 10)
else if(SA_pp > 0.01) // There is sleeping gas in their lungs, but only a little, so give them a bit of a warning
if(prob(20))
spawn(0)
H.emote(pick("giggle", "laugh"))
+
handle_temperature(breath, H)
return 1
+
/datum/species/proc/handle_temperature(datum/gas_mixture/breath, var/mob/living/carbon/human/H) // called by human/life, handles temperatures
if(abs(310.15 - breath.temperature) > 50) // Hot air hurts :(
if(H.status_flags & GODMODE) return 1 //godmode
if(breath.temperature < cold_level_1)
if(prob(20))
to_chat(H, "<span class='warning'>You feel your face freezing and an icicle forming in your lungs!</span>")
else if(breath.temperature > heat_level_1)
if(prob(20))
to_chat(H, "<span class='warning'>You feel your face burning and a searing heat in your lungs!</span>")
+
+
+
switch(breath.temperature)
if(-INFINITY to cold_level_3)
H.apply_damage(cold_env_multiplier*COLD_GAS_DAMAGE_LEVEL_3, BURN, "head", used_weapon = "Excessive Cold")
+
if(cold_level_3 to cold_level_2)
H.apply_damage(cold_env_multiplier*COLD_GAS_DAMAGE_LEVEL_2, BURN, "head", used_weapon = "Excessive Cold")
+
if(cold_level_2 to cold_level_1)
H.apply_damage(cold_env_multiplier*COLD_GAS_DAMAGE_LEVEL_1, BURN, "head", used_weapon = "Excessive Cold")
+
if(heat_level_1 to heat_level_2)
H.apply_damage(hot_env_multiplier*HEAT_GAS_DAMAGE_LEVEL_1, BURN, "head", used_weapon = "Excessive Heat")
+
if(heat_level_2 to heat_level_3_breathe)
H.apply_damage(hot_env_multiplier*HEAT_GAS_DAMAGE_LEVEL_2, BURN, "head", used_weapon = "Excessive Heat")
+
if(heat_level_3_breathe to INFINITY)
H.apply_damage(hot_env_multiplier*HEAT_GAS_DAMAGE_LEVEL_3, BURN, "head", used_weapon = "Excessive Heat")
+
/datum/species/proc/handle_post_spawn(var/mob/living/carbon/C) //Handles anything not already covered by basic species assignment.
grant_abilities(C)
return
+
/datum/species/proc/updatespeciescolor(var/mob/living/carbon/human/H) //Handles changing icobase for species that have multiple skin colors.
return
+
/datum/species/proc/grant_abilities(var/mob/living/carbon/human/H)
for(var/proc/ability in species_abilities)
H.verbs += ability
return
+
/datum/species/proc/handle_pre_change(var/mob/living/carbon/human/H)
if(H.butcher_results)//clear it out so we don't butcher a actual human.
H.butcher_results = null
remove_abilities(H)
return
+
/datum/species/proc/remove_abilities(var/mob/living/carbon/human/H)
for(var/proc/ability in species_abilities)
H.verbs -= ability
return
+
// Do species-specific reagent handling here
// Return 1 if it should do normal processing too
// Return 0 if it shouldn't deplete and do its normal effect
// Other return values will cause weird badness
/datum/species/proc/handle_reagents(var/mob/living/carbon/human/H, var/datum/reagent/R)
return 1
+
// For special snowflake species effects
// (Slime People changing color based on the reagents they consume)
/datum/species/proc/handle_life(var/mob/living/carbon/human/H)
return 1
+
/datum/species/proc/handle_dna(var/mob/living/carbon/C, var/remove) //Handles DNA mutations, as that doesn't work at init. Make sure you call genemutcheck on any blocks changed here
return
+
// Used for species-specific names (Vox, etc)
/datum/species/proc/makeName(var/gender,var/mob/living/carbon/human/H=null)
if(gender==FEMALE) return capitalize(pick(first_names_female)) + " " + capitalize(pick(last_names))
else return capitalize(pick(first_names_male)) + " " + capitalize(pick(last_names))
+
/datum/species/proc/handle_death(var/mob/living/carbon/human/H) //Handles any species-specific death events (such as dionaea nymph spawns).
return
+
/datum/species/proc/handle_attack_hand(var/mob/living/carbon/human/H, var/mob/living/carbon/human/M) //Handles any species-specific attackhand events.
return
+
/datum/species/proc/say_filter(mob/M, message, datum/language/speaking)
return message
+
/datum/species/proc/equip(var/mob/living/carbon/human/H)
return
+
/datum/species/proc/can_understand(var/mob/other)
return
+
// Called in life() when the mob has no client.
/datum/species/proc/handle_npc(var/mob/living/carbon/human/H)
return
+
//Species unarmed attacks
+
/datum/unarmed_attack
var/attack_verb = list("attack") // Empty hand hurt intent verb.
var/damage = 0 // How much flat bonus damage an attack will do. This is a *bonus* guaranteed damage amount on top of the random damage attacks do.
var/attack_sound = "punch"
var/miss_sound = 'sound/weapons/punchmiss.ogg'
var/sharp = 0
var/edge = 0
+
/datum/unarmed_attack/punch
attack_verb = list("punch")
+
/datum/unarmed_attack/punch/weak
attack_verb = list("flail")
+
/datum/unarmed_attack/diona
attack_verb = list("lash", "bludgeon")
+
/datum/unarmed_attack/claws
attack_verb = list("scratch", "claw")
attack_sound = 'sound/weapons/slice.ogg'
miss_sound = 'sound/weapons/slashmiss.ogg'
sharp = 1
edge = 1
+
/datum/unarmed_attack/claws/armalis
attack_verb = list("slash", "claw")
damage = 6
+
/datum/species/proc/handle_can_equip(obj/item/I, slot, disable_warning = 0, mob/living/carbon/human/user)
return 0
+
/datum/species/proc/handle_vision(mob/living/carbon/human/H)
// Right now this just handles blind, blurry, and similar states
if(H.blinded || H.eye_blind)
H.overlay_fullscreen("blind", /obj/screen/fullscreen/blind)
H.throw_alert("blind", /obj/screen/alert/blind)
else
H.clear_fullscreen("blind")
H.clear_alert("blind")
+
+
if(H.disabilities & NEARSIGHTED) //this looks meh but saves a lot of memory by not requiring to add var/prescription
if(H.glasses) //to every /obj/item
var/obj/item/clothing/glasses/G = H.glasses
if(G.prescription)
H.clear_fullscreen("nearsighted")
else
H.overlay_fullscreen("nearsighted", /obj/screen/fullscreen/impaired, 1)
else
H.overlay_fullscreen("nearsighted", /obj/screen/fullscreen/impaired, 1)
else
H.clear_fullscreen("nearsighted")
+
if(H.eye_blurry)
H.overlay_fullscreen("blurry", /obj/screen/fullscreen/blurry)
else
H.clear_fullscreen("blurry")
+
if(H.druggy)
H.overlay_fullscreen("high", /obj/screen/fullscreen/high)
H.throw_alert("high", /obj/screen/alert/high)
else
H.clear_fullscreen("high")
H.clear_alert("high")
+
/datum/species/proc/handle_hud_icons(mob/living/carbon/human/H)
if(!H.client)
return
if(H.healths)
if(H.stat == DEAD)
H.healths.icon_state = "health7"
else
switch(H.hal_screwyhud)
if(1) H.healths.icon_state = "health6"
if(2) H.healths.icon_state = "health7"
if(5) H.healths.icon_state = "health0"
else
switch(100 - ((flags & NO_PAIN) ? 0 : H.traumatic_shock) - H.staminaloss)
if(100 to INFINITY) H.healths.icon_state = "health0"
if(80 to 100) H.healths.icon_state = "health1"
if(60 to 80) H.healths.icon_state = "health2"
if(40 to 60) H.healths.icon_state = "health3"
if(20 to 40) H.healths.icon_state = "health4"
if(0 to 20) H.healths.icon_state = "health5"
else H.healths.icon_state = "health6"
+
if(H.healthdoll)
if(H.stat == DEAD)
H.healthdoll.icon_state = "healthdoll_DEAD"
if(H.healthdoll.overlays.len)
H.healthdoll.overlays.Cut()
else
var/list/new_overlays = list()
var/list/cached_overlays = H.healthdoll.cached_healthdoll_overlays
// Use the dead health doll as the base, since we have proper "healthy" overlays now
H.healthdoll.icon_state = "healthdoll_DEAD"
for(var/obj/item/organ/external/O in H.organs)
var/damage = O.burn_dam + O.brute_dam
var/comparison = (O.max_damage/5)
var/icon_num = 0
if(damage)
icon_num = 1
if(damage > (comparison))
icon_num = 2
if(damage > (comparison*2))
icon_num = 3
if(damage > (comparison*3))
icon_num = 4
if(damage > (comparison*4))
icon_num = 5
new_overlays += "[O.limb_name][icon_num]"
H.healthdoll.overlays += (new_overlays - cached_overlays)
H.healthdoll.overlays -= (cached_overlays - new_overlays)
H.healthdoll.cached_healthdoll_overlays = new_overlays
+
switch(H.nutrition)
if(NUTRITION_LEVEL_FULL to INFINITY)
H.throw_alert("nutrition", /obj/screen/alert/fat)
if(NUTRITION_LEVEL_HUNGRY to NUTRITION_LEVEL_FULL)
H.clear_alert("nutrition")
if(NUTRITION_LEVEL_STARVING to NUTRITION_LEVEL_HUNGRY)
H.throw_alert("nutrition", /obj/screen/alert/hungry)
else
H.throw_alert("nutrition", /obj/screen/alert/starving)
return 1
+
/*
Returns the path corresponding to the corresponding organ
It'll return null if the organ doesn't correspond, so include null checks when using this!
*/
//Fethas Todo:Do i need to redo this?
/datum/species/proc/return_organ(var/organ_slot)
if(!(organ_slot in has_organ))
return null
return has_organ[organ_slot]
+
+
/datum/species/proc/update_sight(mob/living/carbon/human/H)
H.sight = initial(H.sight)
H.see_in_dark = darksight
H.see_invisible = invis_sight
+
if(H.client.eye != H)
var/atom/A = H.client.eye
if(A.update_remote_sight(H)) //returns 1 if we override all other sight updates.
return
+
if(H.mind && H.mind.vampire)
if(H.mind.vampire.get_ability(/datum/vampire_passive/full))
H.sight |= SEE_TURFS|SEE_MOBS|SEE_OBJS
H.see_in_dark = 8
H.see_invisible = SEE_INVISIBLE_MINIMUM
else if(H.mind.vampire.get_ability(/datum/vampire_passive/vision))
H.sight |= SEE_MOBS
+
for(var/obj/item/organ/internal/cyberimp/eyes/E in H.internal_organs)
H.sight |= E.vision_flags
if(E.dark_view)
H.see_in_dark = E.dark_view
if(E.see_invisible)
H.see_invisible = min(H.see_invisible, E.see_invisible)
+
+
if(H.seer == 1)
var/obj/effect/rune/R = locate() in H.loc
if(R && R.word1 == cultwords["see"] && R.word2 == cultwords["hell"] && R.word3 == cultwords["join"])
H.see_invisible = SEE_INVISIBLE_OBSERVER
else
H.see_invisible = SEE_INVISIBLE_LIVING
H.seer = 0
+
var/lesser_darkview_bonus = INFINITY
// my glasses, I can't see without my glasses
if(H.glasses)
var/obj/item/clothing/glasses/G = H.glasses
H.sight |= G.vision_flags
lesser_darkview_bonus = G.darkness_view
if(G.invis_override)
H.see_invisible = G.invis_override
else
H.see_invisible = min(G.invis_view, H.see_invisible)
+
// better living through hat trading
if(H.head)
if(istype(H.head, /obj/item/clothing/head))
var/obj/item/clothing/head/hat = H.head
H.sight |= hat.vision_flags
+
if(hat.darkness_view) // Pick the lowest of the two darkness_views between the glasses and helmet.
lesser_darkview_bonus = min(hat.darkness_view,lesser_darkview_bonus)
+
if(hat.helmet_goggles_invis_view)
H.see_invisible = min(hat.helmet_goggles_invis_view, H.see_invisible)
+
if(istype(H.back, /obj/item/weapon/rig)) ///aghhh so snowflakey
var/obj/item/weapon/rig/rig = H.back
if(rig.visor)
if(!rig.helmet || (H.head && rig.helmet == H.head))
if(rig.visor && rig.visor.vision && rig.visor.active && rig.visor.vision.glasses)
var/obj/item/clothing/glasses/G = rig.visor.vision.glasses
if(istype(G))
H.see_in_dark = (G.darkness_view ? G.darkness_view : darksight) // Otherwise we keep our darkness view with togglable nightvision.
if(G.vision_flags) // MESONS
H.sight |= G.vision_flags
+
H.see_invisible = min(G.invis_view, H.see_invisible)
+
if(lesser_darkview_bonus != INFINITY)
H.see_in_dark = max(lesser_darkview_bonus, H.see_in_dark)
+
if(H.vision_type)
H.see_in_dark = max(H.see_in_dark, H.vision_type.see_in_dark, darksight)
H.see_invisible = H.vision_type.see_invisible
if(H.vision_type.light_sensitive)
H.weakeyes = 1
H.sight |= H.vision_type.sight_flags
+
if(XRAY in H.mutations)
H.sight |= (SEE_TURFS|SEE_MOBS|SEE_OBJS)
H.see_in_dark = max(H.see_in_dark, 8)
H.see_invisible = SEE_INVISIBLE_MINIMUM
+
if(H.see_override) //Override all
H.see_invisible = H.see_override
+ +
+ +
+ + + + +
+ +
+ + +
+
+ +
+ + + + + + + +
+ + + You can't perform that action at this time. +
+ + + + + + + + + +
+ + You signed in with another tab or window. Reload to refresh your session. + You signed out in another tab or window. Reload to refresh your session. +
+ + + + + diff --git a/icons/obj/doors/Doorcult.dmi b/icons/obj/doors/Doorcult.dmi index 2afae729838..f9f4aa92466 100644 Binary files a/icons/obj/doors/Doorcult.dmi and b/icons/obj/doors/Doorcult.dmi differ