diff --git a/code/__DEFINES/cult.dm b/code/__DEFINES/cult.dm index 71d4ad3af9b..73ec1bc8d7c 100644 --- a/code/__DEFINES/cult.dm +++ b/code/__DEFINES/cult.dm @@ -4,6 +4,11 @@ #define RUNE_COLOR_OFFER "#FFFFFF" #define RUNE_COLOR_DARKRED "#7D1717" #define RUNE_COLOR_MEDIUMRED "#C80000" +#define RUNE_COLOR_BURNTORANGE "#CC5500" #define RUNE_COLOR_RED "#FF0000" #define RUNE_COLOR_EMP "#4D94FF" #define RUNE_COLOR_SUMMON "#00FF00" + +//blood magic +#define MAX_BLOODCHARGE 5 +#define RUNELESS_MAX_BLOODCHARGE 2 \ No newline at end of file diff --git a/code/_onclick/hud/alert.dm b/code/_onclick/hud/alert.dm index e4fb93c15ac..4379398a7d1 100644 --- a/code/_onclick/hud/alert.dm +++ b/code/_onclick/hud/alert.dm @@ -330,20 +330,20 @@ or shoot a gun to move around via Newton's 3rd Law of Motion." var/datum/objective/eldergod/summon_objective = locate() in antag.cult_team.objectives if(!summon_objective) return + desc = "The sacrifice is complete, summon Nar-Sie! The summoning can only take place in [english_list(summon_objective.summon_spots)]!" if(icon_state == "runed_sense1") return animate(src, transform = null, time = 1, loop = 0) angle = 0 cut_overlays() icon_state = "runed_sense1" - desc = "The sacrifice is complete, summon Nar-Sie! The summoning can only take place in [english_list(summon_objective.summon_spots)]!" add_overlay(narnar) return var/turf/P = get_turf(blood_target) var/turf/Q = get_turf(mob_viewer) - if(P.z != Q.z) //The target is on a different Z level, we cannot sense that far. + if(!P || !Q || (P.z != Q.z)) //The target is on a different Z level, we cannot sense that far. icon_state = "runed_sense2" - desc = "[blood_target] is no longer in your sector, you cannot sense its presence here." + desc = "You can no longer sense your target's presence." return desc = "You are currently tracking [blood_target] in [get_area_name(blood_target)]." var/target_angle = Get_Angle(Q, P) diff --git a/code/datums/action.dm b/code/datums/action.dm index 7c8feeed550..15f62b20b72 100644 --- a/code/datums/action.dm +++ b/code/datums/action.dm @@ -454,7 +454,34 @@ name = "Use [target.name]" button.name = name +/datum/action/item_action/cult_dagger + name = "Draw Blood Rune" + desc = "Use the ritual dagger to create a powerful blood rune" + icon_icon = 'icons/mob/actions/actions_cult.dmi' + button_icon_state = "draw" + buttontooltipstyle = "cult" + background_icon_state = "bg_demon" +/datum/action/item_action/cult_dagger/Grant(mob/M) + if(iscultist(M)) + ..() + button.screen_loc = "6:157,4:-2" + button.moved = "6:157,4:-2" + else + Remove(owner) + +/datum/action/item_action/cult_dagger/Trigger() + for(var/obj/item/H in owner.held_items) //In case we were already holding another dagger + if(istype(H, /obj/item/melee/cultblade/dagger)) + H.attack_self(owner) + return + var/obj/item/I = target + if(owner.can_equip(I, slot_hands)) + owner.temporarilyRemoveItemFromInventory(I) + owner.put_in_hands(I) + I.attack_self(owner) + else + to_chat(owner, "Your hands are full!") //Preset for spells diff --git a/code/datums/mind.dm b/code/datums/mind.dm index 1bcb122ebe7..abe7b0222ff 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -608,7 +608,7 @@ return objective.completed = !objective.completed log_admin("[key_name(usr)] toggled the win state for [current]'s objective: [objective.explanation_text]") - + else if (href_list["silicon"]) switch(href_list["silicon"]) if("unemag") diff --git a/code/datums/status_effects/debuffs.dm b/code/datums/status_effects/debuffs.dm index 22868f855f2..600b8d9679f 100644 --- a/code/datums/status_effects/debuffs.dm +++ b/code/datums/status_effects/debuffs.dm @@ -245,6 +245,10 @@ duration = -1 alert_type = null +/datum/status_effect/cultghost/on_apply() + owner.see_invisible = SEE_INVISIBLE_OBSERVER + owner.see_in_dark = 2 + /datum/status_effect/cultghost/tick() if(owner.reagents) owner.reagents.del_reagent("holywater") //can't be deconverted diff --git a/code/game/alternate_appearance.dm b/code/game/alternate_appearance.dm index 1a62a0fd5fe..484f11fc097 100644 --- a/code/game/alternate_appearance.dm +++ b/code/game/alternate_appearance.dm @@ -125,6 +125,32 @@ GLOBAL_LIST_EMPTY(active_alternate_appearances) /datum/atom_hud/alternate_appearance/basic/observers/mobShouldSee(mob/M) return isobserver(M) +/datum/atom_hud/alternate_appearance/basic/noncult + +/datum/atom_hud/alternate_appearance/basic/noncult/New() + ..() + for(var/mob in GLOB.player_list) + if(mobShouldSee(mob)) + add_hud_to(mob) + +/datum/atom_hud/alternate_appearance/basic/noncult/mobShouldSee(mob/M) + if(!iscultist(M)) + return TRUE + return FALSE + +/datum/atom_hud/alternate_appearance/basic/cult + +/datum/atom_hud/alternate_appearance/basic/cult/New() + ..() + for(var/mob in GLOB.player_list) + if(mobShouldSee(mob)) + add_hud_to(mob) + +/datum/atom_hud/alternate_appearance/basic/cult/mobShouldSee(mob/M) + if(iscultist(M)) + return TRUE + return FALSE + /datum/atom_hud/alternate_appearance/basic/blessedAware /datum/atom_hud/alternate_appearance/basic/blessedAware/New() @@ -140,4 +166,4 @@ GLOBAL_LIST_EMPTY(active_alternate_appearances) return TRUE if(isrevenant(M) || iseminence(M) || iswizard(M)) return TRUE - return FALSE \ No newline at end of file + return FALSE diff --git a/code/game/gamemodes/cult/blood_magic.dm b/code/game/gamemodes/cult/blood_magic.dm new file mode 100644 index 00000000000..04b56c9f7dd --- /dev/null +++ b/code/game/gamemodes/cult/blood_magic.dm @@ -0,0 +1,767 @@ +/datum/action/innate/cult/blood_magic //Blood magic handles the creation of blood spells (formerly talismans) + name = "Prepare Blood Magic" + button_icon_state = "carve" + desc = "Prepare blood magic by carving runes into your flesh. This rite is most effective with an empowering rune" + var/list/spells = list() + var/channeling = FALSE + +/datum/action/innate/cult/blood_magic/Grant() + ..() + button.screen_loc = "6:-29,4:-2" + button.moved = "6:-29,4:-2" + button.locked = TRUE + +/datum/action/innate/cult/blood_magic/Remove() + for(var/X in spells) + qdel(X) + ..() + +/datum/action/innate/cult/blood_magic/IsAvailable() + if(!iscultist(owner)) + return FALSE + return ..() + +/datum/action/innate/cult/blood_magic/proc/Positioning() + for(var/datum/action/innate/cult/blood_spell/B in spells) + var/pos = -29+spells.Find(B)*31 + B.button.screen_loc = "6:[pos],4:-2" + B.button.moved = B.button.screen_loc + B.button.locked = TRUE + +/datum/action/innate/cult/blood_magic/Activate() + var/rune = FALSE + var/limit = RUNELESS_MAX_BLOODCHARGE + for(var/obj/effect/rune/empower/R in range(1, owner)) + rune = TRUE + break + if(rune) + limit = MAX_BLOODCHARGE + if(spells.len >= limit) + if(rune) + to_chat(owner, "Your body has reached its limit, you cannot store more than [MAX_BLOODCHARGE] spells at once. Pick a spell to nullify.") + else + to_chat(owner, "Your body has reached its limit, you cannot have more than [RUNELESS_MAX_BLOODCHARGE] spells at once without an empowering rune! Pick a spell to nullify.") + var/nullify_spell = input(owner, "Choose a spell to remove.", "Current Spells") as null|anything in spells + if(nullify_spell) + qdel(nullify_spell) + return + var/entered_spell_name + var/datum/action/innate/cult/blood_spell/BS + var/list/possible_spells = list() + for(var/I in subtypesof(/datum/action/innate/cult/blood_spell)) + var/datum/action/innate/cult/blood_spell/J = I + var/cult_name = initial(J.name) + possible_spells[cult_name] = J + possible_spells += "(REMOVE SPELL)" + entered_spell_name = input(owner, "Pick a blood spell to prepare...", "Spell Choices") as null|anything in possible_spells + if(entered_spell_name == "(REMOVE SPELL)") + var/nullify_spell = input(owner, "Choose a spell to remove.", "Current Spells") as null|anything in spells + if(nullify_spell) + qdel(nullify_spell) + return + BS = possible_spells[entered_spell_name] + if(QDELETED(src) || owner.incapacitated() || !BS) + return + to_chat(owner,"You begin to carve unnatural symbols into your flesh!") + SEND_SOUND(owner, sound('sound/weapons/slice.ogg',0,1,10)) + if(!channeling) + channeling = TRUE + else + to_chat(owner, "You are already invoking blood magic!") + return + if(do_after(owner, 100 - rune*65, target = owner)) + if(ishuman(owner)) + var/mob/living/carbon/human/H = owner + H.bleed(30 - rune*25) + var/datum/action/innate/cult/blood_spell/new_spell = new BS(owner) + new_spell.Grant(owner, src) + spells += new_spell + Positioning() + to_chat(owner, "Your wounds glows with power, you have prepared a [new_spell.name] invocation!") + channeling = FALSE + +/datum/action/innate/cult/blood_spell //The next generation of talismans + name = "Blood Magic" + button_icon_state = "telerune" + desc = "Fear the Old Blood." + var/charges = 1 + var/magic_path = null + var/obj/item/melee/blood_magic/hand_magic + var/datum/action/innate/cult/blood_magic/all_magic + var/base_desc //To allow for updating tooltips + var/invocation + var/health_cost = 0 + +/datum/action/innate/cult/blood_spell/Grant(mob/living/owner, datum/action/innate/cult/blood_magic/BM) + if(health_cost) + desc += "
Deals [health_cost] damage to your arm per use." + base_desc = desc + desc += "
Has [charges] use\s remaining." + all_magic = BM + ..() + +/datum/action/innate/cult/blood_spell/Remove() + if(all_magic) + all_magic.spells -= src + if(hand_magic) + qdel(hand_magic) + hand_magic = null + ..() + +/datum/action/innate/cult/blood_spell/IsAvailable() + if(!iscultist(owner) || owner.incapacitated() || !charges) + return FALSE + return ..() + +/datum/action/innate/cult/blood_spell/Activate() + if(magic_path) //If this spell flows from the hand + if(!hand_magic) + hand_magic = new magic_path(owner, src) + if(!owner.put_in_hands(hand_magic)) + qdel(hand_magic) + hand_magic = null + to_chat(owner, "You have no empty hand for invoking blood magic!") + return + to_chat(owner, "Your old wounds glow again as you invoke the [name].") + return + if(hand_magic) + qdel(hand_magic) + hand_magic = null + to_chat(owner, "You snuff out the spell with your hand, saving its power for another time.") + + +//Cult Blood Spells +/datum/action/innate/cult/blood_spell/stun + name = "Stun" + desc = "A potent spell that will stun and mute victims upon contact." + button_icon_state = "hand" + magic_path = "/obj/item/melee/blood_magic/stun" + health_cost = 10 + +/datum/action/innate/cult/blood_spell/teleport + name = "Teleport" + desc = "A useful spell that teleport cultists to a chosen destination on contact." + button_icon_state = "tele" + magic_path = "/obj/item/melee/blood_magic/teleport" + health_cost = 7 + +/datum/action/innate/cult/blood_spell/emp + name = "Electromagnetic Pulse" + desc = "A large spell that immediately disables all electronics in the area." + button_icon_state = "emp" + health_cost = 10 + invocation = "Ta'gh fara'qha fel d'amar det!" + +/datum/action/innate/cult/blood_spell/emp/Activate() + owner.visible_message("[owner]'s hand flashes a bright blue!", \ + "You speak the cursed words, emitting an EMP blast from your hand.") + empulse(owner, 3, 6) + owner.whisper(invocation, language = /datum/language/common) + charges-- + if(charges<=0) + qdel(src) + +/datum/action/innate/cult/blood_spell/shackles + name = "Shadow Shackles" + desc = "A stealthy spell that will handcuff and temporarily silence your victim." + button_icon_state = "cuff" + charges = 4 + magic_path = "/obj/item/melee/blood_magic/shackles" + +/datum/action/innate/cult/blood_spell/construction + name = "Twisted Construction" + desc = "A sinister spell used to convert:
Plasteel into runed metal
25 metal into a construct shell
Cyborgs directly into constructs
Cyborg shells into construct shells
Airlocks into runed airlocks (harm intent)" + button_icon_state = "transmute" + charges = 50 + magic_path = "/obj/item/melee/blood_magic/construction" + +/datum/action/innate/cult/blood_spell/equipment + name = "Summon Equipment" + desc = "A crucial spell that enables you to summon either a ritual dagger or combat gear including armored robes, the nar'sien bola, and an eldritch longsword." + button_icon_state = "equip" + magic_path = "/obj/item/melee/blood_magic/armor" + charges = 1 + +/datum/action/innate/cult/blood_spell/equipment/Activate() + var/choice = alert(owner,"Choose your equipment type",,"Combat Equipment","Ritual Dagger","Cancel") + if(choice == "Ritual Dagger") + var/turf/T = get_turf(owner) + owner.visible_message("[owner]'s hand glows red for a moment.", \ + "Red light begins to shimmer and take form within your hand!") + var/obj/O = new /obj/item/melee/cultblade/dagger(T) + if(owner.put_in_hands(O)) + to_chat(owner, "A ritual dagger appears in your hand!") + else + owner.visible_message("A ritual dagger appears at [owner]'s feet!", \ + "A ritual dagger materializes at your feet.") + SEND_SOUND(owner, sound('sound/effects/magic.ogg',0,1,25)) + charges-- + desc = base_desc + desc += "
Has [charges] use\s remaining." + if(charges<=0) + qdel(src) + else if(choice == "Combat Equipment") + ..() + +/datum/action/innate/cult/blood_spell/horror + name = "Hallucinations" + desc = "A ranged yet stealthy spell that will break the mind of the victim with nightmarish hallucinations." + button_icon_state = "horror" + var/obj/effect/proc_holder/horror/PH + charges = 4 + +/datum/action/innate/cult/blood_spell/horror/New() + PH = new() + PH.attached_action = src + ..() + +/datum/action/innate/cult/blood_spell/horror/Destroy() + var/obj/effect/proc_holder/horror/destroy = PH + . = ..() + if(destroy && !QDELETED(destroy)) + QDEL_NULL(destroy) + +/datum/action/innate/cult/blood_spell/horror/Activate() + PH.toggle(owner) //the important bit + return TRUE + +/obj/effect/proc_holder/horror + active = FALSE + ranged_mousepointer = 'icons/effects/cult_target.dmi' + var/datum/action/innate/cult/blood_spell/attached_action + +/obj/effect/proc_holder/horror/Destroy() + var/datum/action/innate/cult/blood_spell/AA = attached_action + . = ..() + if(AA && !QDELETED(AA)) + QDEL_NULL(AA) + +/obj/effect/proc_holder/horror/proc/toggle(mob/user) + if(active) + remove_ranged_ability("You dispel the magic...") + else + add_ranged_ability(user, "You prepare to horrify a target...") + +/obj/effect/proc_holder/horror/InterceptClickOn(mob/living/caller, params, atom/target) + if(..()) + return + if(ranged_ability_user.incapacitated() || !iscultist(caller)) + remove_ranged_ability() + return + var/turf/T = get_turf(ranged_ability_user) + if(!isturf(T)) + return FALSE + if(target in view(7, get_turf(ranged_ability_user))) + if(!ishuman(target) || iscultist(target)) + return + var/mob/living/carbon/human/H = target + H.hallucination = max(H.hallucination, 240) + SEND_SOUND(ranged_ability_user, sound('sound/effects/ghost.ogg',0,1,50)) + var/image/C = image('icons/effects/cult_effects.dmi',H,"bloodsparkles", ABOVE_MOB_LAYER) + add_alt_appearance(/datum/atom_hud/alternate_appearance/basic/cult, "cult_apoc", C, FALSE) + addtimer(CALLBACK(H,/atom/.proc/remove_alt_appearance,"cult_apoc",TRUE), 2400, TIMER_OVERRIDE|TIMER_UNIQUE) + to_chat(ranged_ability_user,"[H] has been cursed with living nightmares!") + attached_action.charges-- + attached_action.desc = attached_action.base_desc + attached_action.desc += "
Has [attached_action.charges] use\s remaining." + attached_action.UpdateButtonIcon() + if(attached_action.charges <= 0) + remove_mousepointer(ranged_ability_user.client) + remove_ranged_ability("You have exhausted the spell's power!") + qdel(src) + +/datum/action/innate/cult/blood_spell/veiling + name = "Conceal Runes" + desc = "A multi-function spell that alternates between hiding and revealing nearby runes." + invocation = "Kla'atu barada nikt'o!" + button_icon_state = "gone" + charges = 10 + var/revealing = FALSE //if it reveals or not + +/datum/action/innate/cult/blood_spell/veiling/Activate() + if(!revealing) + owner.visible_message("Thin grey dust falls from [owner]'s hand!", \ + "You invoke the veiling spell, hiding nearby runes.") + charges-- + SEND_SOUND(owner, sound('sound/magic/smoke.ogg',0,1,25)) + owner.whisper(invocation, language = /datum/language/common) + for(var/obj/effect/rune/R in range(5,owner)) + R.conceal() + for(var/obj/structure/destructible/cult/S in range(5,owner)) + S.conceal() + for(var/turf/open/floor/engine/cult/T in range(5,owner)) + T.realappearance.alpha = 0 + revealing = TRUE + name = "Reveal Runes" + button_icon_state = "back" + else + owner.visible_message("A flash of light shines from [owner]'s hand!", \ + "You invoke the counterspell, revealing nearby runes.") + charges-- + owner.whisper(invocation, language = /datum/language/common) + SEND_SOUND(owner, sound('sound/magic/enter_blood.ogg',0,1,25)) + for(var/obj/effect/rune/R in range(7,owner)) //More range in case you weren't standing in exactly the same spot + R.reveal() + for(var/obj/structure/destructible/cult/S in range(7,owner)) + S.reveal() + for(var/turf/open/floor/engine/cult/T in range(7,owner)) + T.realappearance.alpha = initial(T.realappearance.alpha) + revealing = FALSE + name = "Conceal Runes" + button_icon_state = "gone" + if(charges<= 0) + qdel(src) + desc = base_desc + desc += "
Has [charges] use\s remaining." + UpdateButtonIcon() + +/datum/action/innate/cult/blood_spell/manipulation + name = "Blood Rites" + desc = "A complex spell that allows you to gather blood and use it for healing or other powerful spells." + invocation = "Fel'th Dol Ab'orod!" + button_icon_state = "manip" + charges = 5 + magic_path = "/obj/item/melee/blood_magic/manipulator" + + +// The "magic hand" items +/obj/item/melee/blood_magic + name = "\improper magical aura" + desc = "Sinister looking aura that distorts the flow of reality around it." + icon = 'icons/obj/items_and_weapons.dmi' + icon_state = "disintegrate" + item_state = null + flags_1 = ABSTRACT_1 | NODROP_1 | DROPDEL_1 + w_class = WEIGHT_CLASS_HUGE + throwforce = 0 + throw_range = 0 + throw_speed = 0 + var/invocation + var/uses = 1 + var/health_cost = 0 //The amount of health taken from the user when invoking the spell + var/datum/action/innate/cult/blood_spell/source + +/obj/item/melee/blood_magic/New(loc, spell) + source = spell + uses = source.charges + health_cost = source.health_cost + ..() + +/obj/item/melee/blood_magic/Destroy() + if(!QDELETED(source)) + if(uses <= 0) + source.hand_magic = null + qdel(source) + source = null + else + source.hand_magic = null + source.charges = uses + source.desc = source.base_desc + source.desc += "
Has [uses] use\s remaining." + source.UpdateButtonIcon() + ..() + +/obj/item/melee/blood_magic/attack_self(mob/living/user) + afterattack(user, user, TRUE) + +/obj/item/melee/blood_magic/attack(mob/living/M, mob/living/carbon/user) + if(!iscarbon(user) || !iscultist(user)) + uses = 0 + qdel(src) + return + add_logs(user, M, "used a cult spell on", source.name, "") + M.lastattacker = user.real_name + M.lastattackerckey = user.ckey + +/obj/item/melee/blood_magic/afterattack(atom/target, mob/living/carbon/user, proximity) + if(invocation) + user.whisper(invocation, language = /datum/language/common) + if(health_cost) + if(user.active_hand_index == 1) + user.apply_damage(health_cost, BRUTE, "l_arm") + else + user.apply_damage(health_cost, BRUTE, "r_arm") + if(uses <= 0) + qdel(src) + else if(source) + source.desc = source.base_desc + source.desc += "
Has [uses] use\s remaining." + source.UpdateButtonIcon() + +//Stun +/obj/item/melee/blood_magic/stun + color = "#ff0000" // red + invocation = "Fuu ma'jin!" + +/obj/item/melee/blood_magic/stun/afterattack(atom/target, mob/living/carbon/user, proximity) + if(!isliving(target) || !proximity) + return + var/mob/living/L = target + if(iscultist(target)) + return + if(iscultist(user)) + user.visible_message("[user] holds up their hand, which explodes in a flash of red light!", \ + "You stun [L] with the spell!") + var/obj/item/nullrod/N = locate() in L + if(N) + target.visible_message("[L]'s holy weapon absorbs the light!", \ + "Your holy weapon absorbs the blinding light!") + else + L.Knockdown(180) + L.flash_act(1,1) + if(issilicon(target)) + var/mob/living/silicon/S = L + S.emp_act(EMP_HEAVY) + else if(iscarbon(target)) + var/mob/living/carbon/C = L + C.silent += 6 + C.stuttering += 15 + C.cultslurring += 15 + C.Jitter(15) + if(is_servant_of_ratvar(L)) + L.adjustBruteLoss(15) + uses-- + ..() + +//Teleportation +/obj/item/melee/blood_magic/teleport + color = RUNE_COLOR_TELEPORT + desc = "A potent spell that teleport cultists on contact." + invocation = "Sas'so c'arta forbici!" + +/obj/item/melee/blood_magic/teleport/afterattack(atom/target, mob/living/carbon/user, proximity) + if(!iscultist(target) || !proximity) + to_chat(user, "You can only teleport adjacent cultists with this spell!") + return + if(iscultist(user)) + var/list/potential_runes = list() + var/list/teleportnames = list() + for(var/R in GLOB.teleport_runes) + var/obj/effect/rune/teleport/T = R + potential_runes[avoid_assoc_duplicate_keys(T.listkey, teleportnames)] = T + + if(!potential_runes.len) + to_chat(user, "There are no valid runes to teleport to!") + log_game("Teleport talisman failed - no other teleport runes") + return + + var/turf/T = get_turf(src) + if(is_away_level(T.z)) + to_chat(user, "You are not in the right dimension!") + log_game("Teleport spell failed - user in away mission") + 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(QDELETED(src) || !user || !user.is_holding(src) || user.incapacitated() || !actual_selected_rune || !proximity) + return + var/turf/dest = get_turf(actual_selected_rune) + if(is_blocked_turf(dest, TRUE)) + to_chat(user, "The target rune is blocked. Attempting to teleport to it would be massively unwise.") + return + uses-- + user.visible_message("Dust flows from [user]'s hand, and [user.p_they()] disappear[user.p_s()] with a sharp crack!", \ + "You speak the words of the talisman and find yourself somewhere else!", "You hear a sharp crack.") + var/mob/living/L = target + L.forceMove(dest) + dest.visible_message("There is a boom of outrushing air as something appears above the rune!", null, "You hear a boom.") + ..() + +//Shackles +/obj/item/melee/blood_magic/shackles + name = "Shadow Shackles" + desc = "Allows you to bind a victim and temporarily silence them." + invocation = "In'totum Lig'abis!" + color = "#000000" // black + +/obj/item/melee/blood_magic/shackles/afterattack(atom/target, mob/living/carbon/user, proximity) + if(iscultist(user) && iscarbon(target) && proximity) + var/mob/living/carbon/C = target + if(C.get_num_arms() >= 2 || C.get_arm_ignore()) + CuffAttack(C, user) + else + user.visible_message("This victim doesn't have enough arms to complete the restraint!") + return + ..() + +/obj/item/melee/blood_magic/shackles/proc/CuffAttack(mob/living/carbon/C, mob/living/user) + if(!C.handcuffed) + playsound(loc, 'sound/weapons/cablecuff.ogg', 30, 1, -2) + C.visible_message("[user] begins restraining [C] with dark magic!", \ + "[user] begins shaping a dark magic around your wrists!") + if(do_mob(user, C, 30)) + if(!C.handcuffed) + C.handcuffed = new /obj/item/restraints/handcuffs/energy/cult/used(C) + C.update_handcuffed() + C.silent += 5 + to_chat(user, "You shackle [C].") + add_logs(user, C, "shackled") + uses-- + else + to_chat(user, "[C] is already bound.") + else + to_chat(user, "You fail to shackle [C].") + else + to_chat(user, "[C] is already bound.") + + +/obj/item/restraints/handcuffs/energy/cult //For the shackling spell + name = "shadow shackles" + desc = "Shackles that bind the wrists with sinister magic." + trashtype = /obj/item/restraints/handcuffs/energy/used + flags_1 = DROPDEL_1 + +/obj/item/restraints/handcuffs/energy/cult/used/dropped(mob/user) + user.visible_message("[user]'s shackles shatter in a discharge of dark magic!", \ + "Your [src] shatters in a discharge of dark magic!") + . = ..() + + +//Construction: Creates a construct shell out of 25 metal sheets, or converts plasteel into runed metal +/obj/item/melee/blood_magic/construction + name = "Twisted Construction" + desc = "Corrupts metal and plasteel into more sinister forms." + invocation = "Ethra p'ni dedol!" + color = "#000000" // black + +/obj/item/melee/blood_magic/construction/afterattack(atom/target, mob/user, proximity_flag, click_parameters) + if(proximity_flag && iscultist(user)) + var/turf/T = get_turf(target) + if(istype(target, /obj/item/stack/sheet/metal)) + var/obj/item/stack/sheet/candidate = target + if(candidate.use(25)) + uses-=25 + to_chat(user, "A dark cloud eminates from your hand and swirls around the metal, twisting it into a construct shell!") + new /obj/structure/constructshell(T) + SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25)) + else + to_chat(user, "You need more metal to produce a construct shell!") + else if(istype(target, /obj/item/stack/sheet/plasteel)) + var/obj/item/stack/sheet/plasteel/candidate = target + var/quantity = min(candidate.amount, uses) + uses -= quantity + new /obj/item/stack/sheet/runed_metal(T,quantity) + candidate.use(quantity) + to_chat(user, "A dark cloud eminates from you hand and swirls around the plasteel, transforming it into runed metal!") + SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25)) + else if(istype(target,/mob/living/silicon/robot)) + var/mob/living/silicon/robot/candidate = target + if(candidate.mmi) + user.visible_message("A dark cloud eminates from [user]'s hand and swirls around [candidate]!") + playsound(T, 'sound/machines/airlock_alien_prying.ogg', 80, 1) + var/prev_color = candidate.color + candidate.color = "black" + if(do_after(user, 90, target = candidate)) + candidate.emp_act(EMP_HEAVY) + var/construct_class = alert(user, "Please choose which type of construct you wish to create.",,"Juggernaut","Wraith","Artificer") + user.visible_message("The dark cloud receedes from what was formerly [candidate], revealing a\n [construct_class]!") + switch(construct_class) + if("Juggernaut") + makeNewConstruct(/mob/living/simple_animal/hostile/construct/armored, candidate, user, 0, T) + if("Wraith") + makeNewConstruct(/mob/living/simple_animal/hostile/construct/wraith, candidate, user, 0, T) + if("Artificer") + makeNewConstruct(/mob/living/simple_animal/hostile/construct/builder, candidate, user, 0, T) + SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25)) + uses -= 50 + candidate.mmi = null + qdel(candidate) + else + candidate.color = prev_color + else + uses -= 50 + to_chat(user, "A dark cloud eminates from you hand and swirls around [candidate] - twisting it into a construct shell!") + new /obj/structure/constructshell(T) + SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25)) + else if(istype(target,/obj/machinery/door/airlock)) + target.narsie_act() + uses -= 50 + user.visible_message("Black ribbons suddenly eminate from [user]'s hand and cling to the airlock - twisting and corrupting it!") + SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25)) + else + to_chat(user, "The spell will not work on [target]!") + ..() + +//Armor: Gives the target a basic cultist combat loadout +/obj/item/melee/blood_magic/armor + name = "Sinister Armaments" + desc = "A spell that will equip the target with cultist equipment if there is a slot to equip it to." + color = "#33cc33" // green + +/obj/item/melee/blood_magic/armor/afterattack(atom/target, mob/living/carbon/user, proximity) + if(iscarbon(target) && proximity) + uses-- + var/mob/living/carbon/C = target + C.visible_message("Otherworldly armor suddenly appears on [C]!") + C.equip_to_slot_or_del(new /obj/item/clothing/under/color/black,slot_w_uniform) + C.equip_to_slot_or_del(new /obj/item/clothing/head/culthood/alt(user), slot_head) + C.equip_to_slot_or_del(new /obj/item/clothing/suit/cultrobes/alt(user), slot_wear_suit) + C.equip_to_slot_or_del(new /obj/item/clothing/shoes/cult/alt(user), slot_shoes) + C.equip_to_slot_or_del(new /obj/item/storage/backpack/cultpack(user), slot_back) + if(C == user) + qdel(src) //Clears the hands + C.put_in_hands(new /obj/item/melee/cultblade(user)) + C.put_in_hands(new /obj/item/restraints/legcuffs/bola/cult(user)) + ..() + +/obj/item/melee/blood_magic/manipulator + name = "Blood Rite" + desc = "A spell that will absorb blood from anything you touch.
Touching cultists and constructs can heal them.
Clicking the hand will potentially let you focus the spell into something stronger." + color = "#7D1717" + +/obj/item/melee/blood_magic/manipulator/afterattack(atom/target, mob/living/carbon/human/user, proximity) + if(proximity) + if(ishuman(target)) + var/mob/living/carbon/human/H = target + if(NOBLOOD in H.dna.species.species_traits) + to_chat(user,"Blood rites do not work on species with no blood!") + return + if(iscultist(H)) + if(H.stat == DEAD) + to_chat(user,"Only a revive rune can bring back the dead!") + return + if(H.blood_volume < BLOOD_VOLUME_SAFE) + var/restore_blood = BLOOD_VOLUME_SAFE - H.blood_volume + if(uses*2 < restore_blood) + H.blood_volume += uses*2 + to_chat(user,"You use the last of your blood rites to restore what blood you could!") + uses = 0 + return ..() + else + H.blood_volume = BLOOD_VOLUME_SAFE + uses -= round(restore_blood/2) + to_chat(user,"Your blood rites have restored [H == user ? "your" : "their"] blood to safe levels!") + var/overall_damage = H.getBruteLoss() + H.getFireLoss() + H.getToxLoss() + H.getOxyLoss() + if(overall_damage == 0) + to_chat(user,"That cultist doesn't require healing!") + else + var/ratio = uses/overall_damage + if(H == user) + to_chat(user,"Your blood healing is far less efficient when used on yourself!") + ratio *= 0.35 // Healing is half as effective if you can't perform a full heal + uses -= round(overall_damage) // Healing is 65% more "expensive" even if you can still perform the full heal + if(ratio>1) + ratio = 1 + uses -= round(overall_damage) + H.visible_message("[H] is fully healed by [H==user ? "their":"[H]'s"]'s blood magic!") + else + H.visible_message("[H] is partially healed by [H==user ? "their":"[H]'s"] blood magic.") + uses = 0 + ratio *= -1 + H.adjustOxyLoss((overall_damage*ratio) * (H.getOxyLoss() / overall_damage), 0) + H.adjustToxLoss((overall_damage*ratio) * (H.getToxLoss() / overall_damage), 0) + H.adjustFireLoss((overall_damage*ratio) * (H.getFireLoss() / overall_damage), 0) + H.adjustBruteLoss((overall_damage*ratio) * (H.getBruteLoss() / overall_damage), 0) + H.updatehealth() + playsound(get_turf(H), 'sound/magic/staff_healing.ogg', 25) + new /obj/effect/temp_visual/cult/sparks(get_turf(H)) + user.Beam(H,icon_state="sendbeam",time=15) + else + if(H.stat == DEAD) + to_chat(user,"Their blood has stopped flowing, you'll have to find another way to extract it.") + return + if(H.cultslurring) + to_chat(user,"Their blood has been tainted by an even stronger form of blood magic, it's no use to us like this!") + return + if(H.blood_volume > BLOOD_VOLUME_SAFE) + H.blood_volume -= 100 + uses += 50 + user.Beam(H,icon_state="drainbeam",time=10) + playsound(get_turf(H), 'sound/magic/enter_blood.ogg', 50) + H.visible_message("[user] has drained some of [H]'s blood!") + to_chat(user,"Your blood rite gains 50 charges from draining [H]'s blood.") + new /obj/effect/temp_visual/cult/sparks(get_turf(H)) + else + to_chat(user,"They're missing too much blood - you cannot drain them further!") + return + if(isconstruct(target)) + var/mob/living/simple_animal/M = target + var/missing = M.maxHealth - M.health + if(missing) + if(uses > missing) + M.adjustHealth(-missing) + M.visible_message("[M] is fully-healed by [user]'s blood magic!") + uses -= missing + else + M.adjustHealth(-uses) + M.visible_message("[M] is healed by [user]'sblood magic!") + uses = 0 + playsound(get_turf(M), 'sound/magic/staff_healing.ogg', 25) + user.Beam(M,icon_state="sendbeam",time=10) + if(istype(target, /obj/effect/decal/cleanable/blood)) + blood_draw(target, user) + ..() + +/obj/item/melee/blood_magic/manipulator/proc/blood_draw(atom/target, mob/living/carbon/human/user) + var/temp = 0 + var/turf/T = get_turf(target) + if(T) + for(var/obj/effect/decal/cleanable/blood/B in view(T, 2)) + if(B.blood_state == "blood") + if(B.bloodiness == 100) //Bonus for "pristine" bloodpools, also to prevent cheese with footprint spam + temp += 30 + else + temp += max((B.bloodiness**2)/800,0.5) + new /obj/effect/temp_visual/cult/turf/floor(get_turf(B)) + qdel(B) + for(var/obj/effect/decal/cleanable/trail_holder/TH in view(T, 2)) + qdel(TH) + var/obj/item/clothing/shoes/shoecheck = user.shoes + if(shoecheck && shoecheck.bloody_shoes["blood"]) + temp += shoecheck.bloody_shoes["blood"]/20 + shoecheck.bloody_shoes["blood"] = 0 + if(temp) + user.Beam(T,icon_state="drainbeam",time=15) + new /obj/effect/temp_visual/cult/sparks(get_turf(user)) + playsound(T, 'sound/magic/enter_blood.ogg', 50) + to_chat(user, "Your blood rite has gained [round(temp)] charge\s from blood sources around you!") + uses += round(temp) + +/obj/item/melee/blood_magic/manipulator/attack_self(mob/living/user) + if(iscultist(user)) + var/list/options = list("Blood Spear (200)", "Blood Bolt Barrage (400)", "Blood Beam (600)") + var/choice = input(user, "Choose a greater blood rite...", "Greater Blood Rites") as null|anything in options + if(!choice) + to_chat(user, "You decide against conducting a greater blood rite.") + return + switch(choice) + if("Blood Spear (200)") + if(uses < 200) + to_chat(user, "You need 200 charges to perform this rite.") + else + uses -= 200 + var/turf/T = get_turf(user) + qdel(src) + var/datum/action/innate/cult/spear/S = new(user) + var/obj/item/twohanded/cult_spear/rite = new(T) + S.Grant(user, rite) + rite.spear_act = S + if(user.put_in_hands(rite)) + to_chat(user, "A [rite.name] appears in your hand!") + else + user.visible_message("A [rite.name] appears at [user]'s feet!", \ + "A [rite.name] materializes at your feet.") + if("Blood Bolt Barrage (400)") + if(uses < 400) + to_chat(user, "You need 400 charges to perform this rite.") + else + var/obj/rite = new /obj/item/gun/ballistic/shotgun/boltaction/enchanted/arcane_barrage/blood() + uses -= 400 + qdel(src) + if(user.put_in_hands(rite)) + to_chat(user, "Your hands glow with power!") + else + to_chat(user, "You need a free hand for this rite!") + qdel(rite) + if("Blood Beam (600)") + if(uses < 600) + to_chat(user, "You need 600 charges to perform this rite.") + else + var/obj/rite = new /obj/item/blood_beam() + uses -= 600 + qdel(src) + if(user.put_in_hands(rite)) + to_chat(user, "Your hands glow with POWER OVERWHELMING!!!") + else + to_chat(user, "You need a free hand for this rite!") + qdel(rite) diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index 0d19fff8f40..325adb30b73 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -208,19 +208,22 @@ /obj/machinery/door/airlock/narsie_act() var/turf/T = get_turf(src) - var/runed = prob(20) var/obj/machinery/door/airlock/cult/A - if(glass) - if(runed) - A = new/obj/machinery/door/airlock/cult/glass(T) + if(GLOB.cult_narsie) + var/runed = prob(20) + if(glass) + if(runed) + A = new/obj/machinery/door/airlock/cult/glass(T) + else + A = new/obj/machinery/door/airlock/cult/unruned/glass(T) else - A = new/obj/machinery/door/airlock/cult/unruned/glass(T) + if(runed) + A = new/obj/machinery/door/airlock/cult(T) + else + A = new/obj/machinery/door/airlock/cult/unruned(T) + A.name = name else - if(runed) - A = new/obj/machinery/door/airlock/cult(T) - else - A = new/obj/machinery/door/airlock/cult/unruned(T) - A.name = name + A = new /obj/machinery/door/airlock/cult/weak(T) qdel(src) /obj/machinery/door/airlock/ratvar_act() //Airlocks become pinion airlocks that only allow servants diff --git a/code/game/machinery/doors/airlock_types.dm b/code/game/machinery/doors/airlock_types.dm index c0ebce67b07..2874e6bf1b0 100644 --- a/code/game/machinery/doors/airlock_types.dm +++ b/code/game/machinery/doors/airlock_types.dm @@ -406,6 +406,7 @@ hackProof = TRUE aiControlDisabled = TRUE req_access = list(ACCESS_BLOODCULT) + damage_deflection = 10 var/openingoverlaytype = /obj/effect/temp_visual/cult/door var/friendly = FALSE @@ -435,6 +436,9 @@ /obj/machinery/door/airlock/cult/narsie_act() return +/obj/machinery/door/airlock/cult/emp_act(severity) + return + /obj/machinery/door/airlock/cult/friendly friendly = TRUE @@ -461,6 +465,13 @@ /obj/machinery/door/airlock/cult/unruned/glass/friendly friendly = TRUE +/obj/machinery/door/airlock/cult/weak + name = "brittle cult airlock" + desc = "An airlock hastily corrupted by blood magic, it is unusually brittle in this state." + normal_integrity = 180 + damage_deflection = 5 + armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 0, fire = 0, acid = 0) + //Pinion airlocks: Clockwork doors that only let servants of Ratvar through. /obj/machinery/door/airlock/clockwork name = "pinion airlock" diff --git a/code/game/machinery/shieldgen.dm b/code/game/machinery/shieldgen.dm index b98500a4950..dde4bb180cc 100644 --- a/code/game/machinery/shieldgen.dm +++ b/code/game/machinery/shieldgen.dm @@ -59,10 +59,12 @@ color = "#FF0000" max_integrity = 20 mouse_opacity = MOUSE_OPACITY_TRANSPARENT + layer = ABOVE_MOB_LAYER /obj/structure/emergency_shield/invoker/emp_act(severity) return + /obj/machinery/shieldgen name = "anti-breach shielding projector" desc = "Used to seal minor hull breaches." diff --git a/code/game/objects/effects/forcefields.dm b/code/game/objects/effects/forcefields.dm index edf7b4f5194..add653238ed 100644 --- a/code/game/objects/effects/forcefields.dm +++ b/code/game/objects/effects/forcefields.dm @@ -6,6 +6,12 @@ opacity = 0 density = TRUE CanAtmosPass = ATMOS_PASS_DENSITY + var/timeleft = 300 //Set to 0 for permanent forcefields (ugh) + +/obj/effect/forcefield/New() + ..() + if(timeleft) + QDEL_IN(src, timeleft) /obj/effect/forcefield/singularity_pull() return @@ -15,6 +21,8 @@ name = "glowing wall" icon = 'icons/effects/cult_effects.dmi' icon_state = "cultshield" + CanAtmosPass = ATMOS_PASS_NO + timeleft = 200 ///////////Mimewalls/////////// @@ -22,11 +30,6 @@ icon_state = "empty" name = "invisible wall" desc = "You have a bad feeling about this." - var/timeleft = 300 - -/obj/effect/forcefield/mime/New() - ..() - QDEL_IN(src, timeleft) /obj/effect/forcefield/mime/advanced name = "invisible blockade" diff --git a/code/game/objects/effects/temporary_visuals/cult.dm b/code/game/objects/effects/temporary_visuals/cult.dm index a6497634352..3a174948712 100644 --- a/code/game/objects/effects/temporary_visuals/cult.dm +++ b/code/game/objects/effects/temporary_visuals/cult.dm @@ -48,6 +48,11 @@ icon_state = "floorglow" duration = 5 +/obj/effect/temp_visual/cult/portal + icon_state = "space" + duration = 600 + layer = ABOVE_OBJ_LAYER + //visuals for runes being magically created /obj/effect/temp_visual/cult/rune_spawn icon_state = "runeouter" diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm index 03183359336..fb1780b6d75 100644 --- a/code/game/objects/items/stacks/sheets/sheet_types.dm +++ b/code/game/objects/items/stacks/sheets/sheet_types.dm @@ -344,6 +344,9 @@ GLOBAL_LIST_INIT(runed_metal_recipes, list ( \ /obj/item/stack/sheet/runed_metal/fifty amount = 50 +/obj/item/stack/sheet/runed_metal/ten + amount = 10 + /obj/item/stack/sheet/runed_metal/five amount = 5 diff --git a/code/game/objects/structures/girders.dm b/code/game/objects/structures/girders.dm index 190dab7011b..84a6cc1b9ee 100644 --- a/code/game/objects/structures/girders.dm +++ b/code/game/objects/structures/girders.dm @@ -346,7 +346,7 @@ /obj/structure/girder/cult/attackby(obj/item/W, mob/user, params) add_fingerprint(user) - if(istype(W, /obj/item/tome) && iscultist(user)) //Cultists can demolish cult girders instantly with their tomes + if(istype(W, /obj/item/melee/cultblade/dagger) && iscultist(user)) //Cultists can demolish cult girders instantly with their tomes user.visible_message("[user] strikes [src] with [W]!", "You demolish [src].") var/obj/item/stack/sheet/runed_metal/R = new(get_turf(src)) R.amount = 1 diff --git a/code/game/turfs/simulated/floor/reinf_floor.dm b/code/game/turfs/simulated/floor/reinf_floor.dm index f53e62dba71..60382b90526 100644 --- a/code/game/turfs/simulated/floor/reinf_floor.dm +++ b/code/game/turfs/simulated/floor/reinf_floor.dm @@ -109,14 +109,17 @@ /turf/open/floor/engine/cult name = "engraved floor" + desc = "The air hangs heavy over this sinister flooring." icon_state = "plating" - var/obj/effect/clockwork/overlay/floor/bloodcult/realappearence + CanAtmosPass = ATMOS_PASS_NO + var/obj/effect/clockwork/overlay/floor/bloodcult/realappearance + /turf/open/floor/engine/cult/Initialize() . = ..() new /obj/effect/temp_visual/cult/turf/floor(src) - realappearence = new /obj/effect/clockwork/overlay/floor/bloodcult(src) - realappearence.linked = src + realappearance = new /obj/effect/clockwork/overlay/floor/bloodcult(src) + realappearance.linked = src /turf/open/floor/engine/cult/Destroy() be_removed() @@ -128,8 +131,8 @@ return ..() /turf/open/floor/engine/cult/proc/be_removed() - qdel(realappearence) - realappearence = null + qdel(realappearance) + realappearance = null /turf/open/floor/engine/cult/ratvar_act() . = ..() diff --git a/code/game/turfs/simulated/wall/misc_walls.dm b/code/game/turfs/simulated/wall/misc_walls.dm index a06f7c9458f..73ec2515f4d 100644 --- a/code/game/turfs/simulated/wall/misc_walls.dm +++ b/code/game/turfs/simulated/wall/misc_walls.dm @@ -57,23 +57,24 @@ girder_type = /obj/structure/destructible/clockwork/wall_gear baseturfs = /turf/open/floor/clockwork/reebe var/heated - var/obj/effect/clockwork/overlay/wall/realappearence + var/obj/effect/clockwork/overlay/wall/realappearance /turf/closed/wall/clockwork/Initialize() . = ..() new /obj/effect/temp_visual/ratvar/wall(src) new /obj/effect/temp_visual/ratvar/beam(src) - realappearence = new /obj/effect/clockwork/overlay/wall(src) - realappearence.linked = src + realappearance = new /obj/effect/clockwork/overlay/wall(src) + realappearance.linked = src /turf/closed/wall/clockwork/Destroy() - if(realappearence) - qdel(realappearence) - realappearence = null + if(realappearance) + qdel(realappearance) + realappearance = null if(heated) var/mob/camera/eminence/E = get_eminence() if(E) E.superheated_walls-- + return ..() /turf/closed/wall/clockwork/ReplaceWithLattice() @@ -136,14 +137,14 @@ heated = TRUE hardness = -100 //Lower numbers are tougher, so this makes the wall essentially impervious to smashing slicing_duration = 150 - animate(realappearence, color = "#FFC3C3", time = 5) + animate(realappearance, color = "#FFC3C3", time = 5) else name = initial(name) visible_message("[src] cools down.") heated = FALSE hardness = initial(hardness) slicing_duration = initial(slicing_duration) - animate(realappearence, color = initial(realappearence.color), time = 25) + animate(realappearance, color = initial(realappearance.color), time = 25) /turf/closed/wall/vault diff --git a/code/modules/antagonists/cult/cult.dm b/code/modules/antagonists/cult/cult.dm index 3b9fa7b8c48..1c90834cbd3 100644 --- a/code/modules/antagonists/cult/cult.dm +++ b/code/modules/antagonists/cult/cult.dm @@ -6,6 +6,7 @@ antagpanel_category = "Cult" var/datum/action/innate/cult/comm/communion = new var/datum/action/innate/cult/mastervote/vote = new + var/datum/action/innate/cult/blood_magic/magic = new job_rank = ROLE_CULTIST var/ignore_implant = FALSE var/give_equipment = FALSE @@ -58,7 +59,7 @@ var/mob/living/current = owner.current add_objectives() if(give_equipment) - equip_cultist() + equip_cultist(TRUE) SSticker.mode.cult += owner // Only add after they've been given objectives SSticker.mode.update_cult_icons_added(owner) current.log_message("Has been converted to the cult of Nar'Sie!", INDIVIDUAL_ATTACK_LOG) @@ -67,18 +68,16 @@ current.client.images += cult_team.blood_target_image -/datum/antagonist/cult/proc/equip_cultist(tome=FALSE) +/datum/antagonist/cult/proc/equip_cultist(metal=TRUE) var/mob/living/carbon/H = owner.current if(!istype(H)) return if (owner.assigned_role == "Clown") to_chat(owner, "Your training has allowed you to overcome your clownish nature, allowing you to wield weapons without harming yourself.") H.dna.remove_mutation(CLOWNMUT) - - if(tome) - . += cult_give_item(/obj/item/tome, H) - else - . += cult_give_item(/obj/item/paper/talisman/supply, H) + . += cult_give_item(/obj/item/melee/cultblade/dagger, H) + if(metal) + . += cult_give_item(/obj/item/stack/sheet/runed_metal/ten, H) to_chat(owner, "These will help you start the cult on this station. Use them well, and remember - you are not the only one.
") @@ -110,10 +109,11 @@ current = mob_override current.faction |= "cult" current.grant_language(/datum/language/narsie) - current.verbs += /mob/living/proc/cult_help - if(!cult_team.cult_mastered) + if(!cult_team.cult_master) vote.Grant(current) communion.Grant(current) + if(ishuman(current)) + magic.Grant(current) current.throw_alert("bloodsense", /obj/screen/alert/bloodsense) /datum/antagonist/cult/remove_innate_effects(mob/living/mob_override) @@ -123,9 +123,9 @@ current = mob_override current.faction -= "cult" current.remove_language(/datum/language/narsie) - current.verbs -= /mob/living/proc/cult_help vote.Remove(current) communion.Remove(current) + magic.Remove(current) current.clear_alert("bloodsense") /datum/antagonist/cult/on_removal() @@ -153,16 +153,16 @@ /datum/antagonist/cult/get_admin_commands() . = ..() - .["Tome"] = CALLBACK(src,.proc/admin_give_tome) - .["Amulet"] = CALLBACK(src,.proc/admin_give_amulet) + .["Dagger"] = CALLBACK(src,.proc/admin_give_dagger) + .["Dagger and Metal"] = CALLBACK(src,.proc/admin_give_metal) -/datum/antagonist/cult/proc/admin_give_tome(mob/admin) - if(equip_cultist(owner.current,1)) - to_chat(admin, "Spawning tome failed!") +/datum/antagonist/cult/proc/admin_give_dagger(mob/admin) + if(!equip_cultist(FALSE)) + to_chat(admin, "Spawning dagger failed!") -/datum/antagonist/cult/proc/admin_give_amulet(mob/admin) - if (equip_cultist(owner.current)) - to_chat(admin, "Spawning amulet failed!") +/datum/antagonist/cult/proc/admin_give_metal(mob/admin) + if (!equip_cultist(TRUE)) + to_chat(admin, "Spawning runed metal failed!") /datum/antagonist/cult/master ignore_implant = TRUE @@ -218,7 +218,7 @@ var/blood_target_reset_timer var/cult_vote_called = FALSE - var/cult_mastered = FALSE + var/mob/living/cult_master var/reckoning_complete = FALSE @@ -326,4 +326,4 @@ return "
[parts.Join("
")]
" /datum/team/cult/is_gamemode_hero() - return SSticker.mode.name == "cult" \ No newline at end of file + return SSticker.mode.name == "cult" diff --git a/code/modules/antagonists/cult/cult_comms.dm b/code/modules/antagonists/cult/cult_comms.dm index c73a77c95bb..bedb7dc9bc0 100644 --- a/code/modules/antagonists/cult/cult_comms.dm +++ b/code/modules/antagonists/cult/cult_comms.dm @@ -14,6 +14,7 @@ /datum/action/innate/cult/comm name = "Communion" + desc = "Whispered words that all cultists can hear.
Warning:Nearby non-cultists can still hear you." button_icon_state = "cult_comms" /datum/action/innate/cult/comm/Activate() @@ -23,7 +24,7 @@ cultist_commune(usr, input) -/proc/cultist_commune(mob/living/user, message) +/datum/action/innate/cult/comm/proc/cultist_commune(mob/living/user, message) var/my_message if(!message) return @@ -33,10 +34,7 @@ var/span = "cult italic" if(user.mind && user.mind.has_antag_datum(/datum/antagonist/cult/master)) span = "cultlarge" - if(ishuman(user)) - title = "Master" - else - title = "Lord" + title = "Master" else if(!ishuman(user)) title = "Construct" my_message = "[title] [findtextEx(user.name, user.real_name) ? user.name : "[user.real_name] (as [user.name])"]: [message]" @@ -50,38 +48,26 @@ log_talk(user,"CULT:[key_name(user)] : [message]",LOGSAY) -/mob/living/proc/cult_help() - set category = "Cultist" - set name = "How to Play Cult" - var/text = "" - text += "
Tenets of the Dark One



" +/datum/action/innate/cult/comm/spirit + name = "Spiritual Communion" + desc = "Conveys a message from the spirit realm that all cultists can hear." - text += "I. SECRECY
Your cult is a SECRET organization. Your success DEPENDS on keeping your cult's members and locations SECRET for as long as possible. This means that your tome should be hidden \ - in your bag and never brought out in public. You should never create runes where other crew might find them, and you should avoid using talismans or other cult magic with witnesses around.

" +/datum/action/innate/cult/comm/spirit/IsAvailable() + if(iscultist(owner.mind.current)) + return TRUE - text += "II. TOME
You start with a unique talisman in your bag. This supply talisman can be used 3 times, and creates starter equipment for your cult. The most critical of the talisman's functions is \ - the power to create a tome. This tome is your most important item and summoning one (in secret) is your FIRST PRIORITY. It lets you talk to fellow cultists and create runes, which in turn is essential to growing the cult's power.

" - - text += "III. RUNES
Runes are powerful sources of cult magic. Your tome will allow you to draw runes with your blood. Those runes, when hit with an empty hand, will attempt to \ - trigger the rune's magic. Runes are essential for the cult to convert new members, create powerful minions, or call upon incredibly powerful magic. Some runes require more than one cultist to use.

" - - text += "IV. TALISMANS
Talismans are a mobile source of cult magic that are NECESSARY to achieve success as a cult. Your starting talisman can produce certain talismans, but you will need \ - to use the -create talisman- rune (with ordinary paper on top) to get more talismans. Talismans are EXTREMELY powerful, therefore creating more talismans in a HIDDEN location should be one of your TOP PRIORITIES.

" - - text += "V. GROW THE CULT
There are certain basic strategies that all cultists should master. STUN talismans are the foundation of a successful cult. If you intend to convert the stunned person \ - you should use cuffs or a talisman of shackling on them and remove their headset before they recover (it takes about 10 seconds to recover). If you intend to sacrifice the victim, striking them quickly and repeatedly with your tome \ - will knock them out before they can recover. Sacrificed victims will their soul behind in a shard, these shards can be used on construct shells to make powerful servants for the cult. Remember you need TWO cultists standing near a \ - conversion rune to convert someone. Your construct minions cannot trigger most runes, but they will count as cultists in helping you trigger more powerful runes like conversion or blood boil.

" - - text += "VI. VICTORY
You have two ultimate goals as a cultist, sacrifice your target, and summon Nar-Sie. Sacrificing the target involves killing that individual and then placing \ - their corpse on a sacrifice rune and triggering that rune with THREE cultists. Do NOT lose the target's corpse! Only once the target is sacrificed can Nar-Sie be summoned. Summoning Nar-Sie will take nearly one minute \ - just to draw the massive rune needed. Do not create the rune until your cult is ready, the crew will receive the NAME and LOCATION of anyone who attempts to create the Nar-Sie rune. Once the Nar-Sie rune is drawn \ - you must gathered 9 cultists (or constructs) over the rune and then click it to bring the Dark One into this world!

" - - var/datum/browser/popup = new(usr, "mind", "", 800, 600) - popup.set_content(text) - popup.open() - return 1 +/datum/action/innate/cult/comm/spirit/cultist_commune(mob/living/user, message) + var/my_message + if(!message) + return + my_message = "The [user.name]: [message]" + for(var/i in GLOB.player_list) + var/mob/M = i + if(iscultist(M)) + to_chat(M, my_message) + else if(M in GLOB.dead_mob_list) + var/link = FOLLOW_LINK(M, user) + to_chat(M, "[link] [my_message]") /datum/action/innate/cult/mastervote name = "Assert Leadership" @@ -139,7 +125,7 @@ if(!B.current.incapacitated()) to_chat(B.current, "[Nominee] could not win the cult's support and shall continue to serve as an acolyte.") return FALSE - team.cult_mastered = TRUE + team.cult_master = Nominee SSticker.mode.remove_cultist(Nominee.mind, TRUE) Nominee.mind.add_antag_datum(/datum/antagonist/cult/master) for(var/datum/mind/B in team.members) @@ -171,7 +157,7 @@ if(!is_blocked_turf(T, TRUE)) destinations += T if(!LAZYLEN(destinations)) - to_chat(owner, "You need more space to summon the cult!") + to_chat(owner, "You need more space to summon your cult!") return if(do_after(owner, 30, target = owner)) for(var/datum/mind/B in antag.cult_team.members) @@ -234,8 +220,6 @@ ..() /datum/action/innate/cult/master/cultmark/IsAvailable() - if(!owner.mind || !owner.mind.has_antag_datum(/datum/antagonist/cult/master)) - return FALSE if(cooldown > world.time) if(!CM.active) to_chat(owner, "You need to wait [DisplayTimeText(cooldown - world.time)] before you can mark another target!") @@ -278,6 +262,9 @@ var/datum/antagonist/cult/C = caller.mind.has_antag_datum(/datum/antagonist/cult,TRUE) if(target in view(7, get_turf(ranged_ability_user))) + if(C.cult_team.blood_target) + to_chat(ranged_ability_user, "The cult has already designated a target!") + return FALSE C.cult_team.blood_target = target var/area/A = get_area(target) attached_action.cooldown = world.time + attached_action.base_cooldown @@ -288,7 +275,7 @@ C.cult_team.blood_target_image.pixel_y = -target.pixel_y for(var/datum/mind/B in SSticker.mode.cult) if(B.current && B.current.stat != DEAD && B.current.client) - to_chat(B.current, "Master [ranged_ability_user] has marked [C.cult_team.blood_target] in the [A.name] as the cult's top priority, get there immediately!") + to_chat(B.current, "[ranged_ability_user] has marked [C.cult_team.blood_target] in the [A.name] as the cult's top priority, get there immediately!") SEND_SOUND(B.current, sound(pick('sound/hallucinations/over_here2.ogg','sound/hallucinations/over_here3.ogg'),0,1,75)) B.current.client.images += C.cult_team.blood_target_image attached_action.owner.update_action_buttons_icon() @@ -307,6 +294,82 @@ team.blood_target = null +/datum/action/innate/cult/master/cultmark/ghost + name = "Mark a Blood Target for the Cult" + desc = "Marks a target for the entire cult to track." + +/datum/action/innate/cult/master/cultmark/IsAvailable() + if(istype(owner, /mob/dead/observer) && iscultist(owner.mind.current)) + return TRUE + else + qdel(src) + +/datum/action/innate/cult/ghostmark //Ghost version + name = "Blood Mark your Target" + desc = "Marks whatever you are orbitting - for the entire cult to track." + button_icon_state = "cult_mark" + var/tracking = FALSE + var/cooldown = 0 + var/base_cooldown = 600 + +/datum/action/innate/cult/ghostmark/IsAvailable() + if(istype(owner, /mob/dead/observer) && iscultist(owner.mind.current)) + return TRUE + else + qdel(src) + +/datum/action/innate/cult/ghostmark/proc/reset_button() + if(owner) + name = "Blood Mark your Target" + desc = "Marks whatever you are orbitting - for the entire cult to track." + button_icon_state = "cult_mark" + owner.update_action_buttons_icon() + SEND_SOUND(owner, 'sound/magic/enter_blood.ogg') + to_chat(owner,"Your previous mark is gone - you are now ready to create a new blood mark.") + +/datum/action/innate/cult/ghostmark/Activate() + var/datum/antagonist/cult/C = owner.mind.has_antag_datum(/datum/antagonist/cult,TRUE) + if(C.cult_team.blood_target) + if(cooldown>world.time) + reset_blood_target(C.cult_team) + to_chat(owner, "You have cleared the cult's blood target!") + qdel(C.cult_team.blood_target_reset_timer) + return + else + to_chat(owner, "The cult has already designated a target!") + return + if(cooldown>world.time) + to_chat(owner, "You aren't ready to place another blood mark yet!") + return + if(owner.orbiting && owner.orbiting.orbiting) + target = owner.orbiting.orbiting + else + target = get_turf(owner) + if(!target) + return + C.cult_team.blood_target = target + var/area/A = get_area(target) + cooldown = world.time + base_cooldown + addtimer(CALLBACK(owner, /mob.proc/update_action_buttons_icon), base_cooldown) + C.cult_team.blood_target_image = image('icons/effects/cult_target.dmi', target, "glow", ABOVE_MOB_LAYER) + C.cult_team.blood_target_image.appearance_flags = RESET_COLOR + C.cult_team.blood_target_image.pixel_x = -target.pixel_x + C.cult_team.blood_target_image.pixel_y = -target.pixel_y + SEND_SOUND(owner, sound(pick('sound/hallucinations/over_here2.ogg','sound/hallucinations/over_here3.ogg'),0,1,75)) + owner.client.images += C.cult_team.blood_target_image + for(var/datum/mind/B in SSticker.mode.cult) + if(B.current && B.current.stat != DEAD && B.current.client) + to_chat(B.current, "[owner] has marked [C.cult_team.blood_target] in the [A.name] as the cult's top priority, get there immediately!") + SEND_SOUND(B.current, sound(pick('sound/hallucinations/over_here2.ogg','sound/hallucinations/over_here3.ogg'),0,1,75)) + B.current.client.images += C.cult_team.blood_target_image + to_chat(owner,"You have marked the [target] for the cult! It will last for [base_cooldown/10] seconds.") + name = "Clear the Blood Mark" + desc = "Remove the Blood Mark you previously set." + button_icon_state = "emp" + owner.update_action_buttons_icon() + C.cult_team.blood_target_reset_timer = addtimer(CALLBACK(GLOBAL_PROC, .proc/reset_blood_target,C.cult_team), base_cooldown, TIMER_STOPPABLE) + addtimer(CALLBACK(src, .proc/reset_button), base_cooldown) + //////// ELDRITCH PULSE ///////// @@ -342,6 +405,7 @@ QDEL_NULL(PM) return ..() + /datum/action/innate/cult/master/pulse/Activate() PM.toggle(owner) //the important bit return TRUE @@ -352,9 +416,10 @@ var/datum/action/innate/cult/master/pulse/attached_action /obj/effect/proc_holder/pulse/Destroy() - QDEL_NULL(attached_action) + attached_action = null return ..() + /obj/effect/proc_holder/pulse/proc/toggle(mob/user) if(active) remove_ranged_ability("You cease your preparations...") diff --git a/code/modules/antagonists/cult/cult_items.dm b/code/modules/antagonists/cult/cult_items.dm index 1f4a84afd24..6bf65fa2349 100644 --- a/code/modules/antagonists/cult/cult_items.dm +++ b/code/modules/antagonists/cult/cult_items.dm @@ -1,3 +1,33 @@ +/obj/item/tome + name = "arcane tome" + desc = "An old, dusty tome with frayed edges and a sinister-looking cover." + icon_state ="tome" + throw_speed = 2 + throw_range = 5 + w_class = WEIGHT_CLASS_SMALL + +/obj/item/melee/cultblade/dagger + name = "ritual dagger" + desc = "A strange dagger said to be used by sinister groups for \"preparing\" a corpse before sacrificing it to their dark gods." + icon = 'icons/obj/wizard.dmi' + icon_state = "render" + item_state = "cultdagger" + lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' + righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' + inhand_x_dimension = 32 + inhand_y_dimension = 32 + w_class = WEIGHT_CLASS_SMALL + force = 15 + throwforce = 25 + armour_penetration = 35 + actions_types = list(/datum/action/item_action/cult_dagger) + +/obj/item/melee/cultblade/dagger/Initialize() + ..() + var/image/I = image(icon = 'icons/effects/blood.dmi' , icon_state = null, loc = src) + I.override = TRUE + add_alt_appearance(/datum/atom_hud/alternate_appearance/basic/silicons, "cult_dagger", I) + /obj/item/melee/cultblade name = "eldritch longsword" desc = "A sword humming with unholy energy. It glows with a dim red light." @@ -49,29 +79,6 @@ user.apply_damage(30, BRUTE, pick("l_arm", "r_arm")) user.dropItemToGround(src) -/obj/item/melee/cultblade/dagger - name = "sacrificial dagger" - desc = "A strange dagger said to be used by sinister groups for \"preparing\" a corpse before sacrificing it to their dark gods." - icon = 'icons/obj/wizard.dmi' - icon_state = "render" - item_state = "knife" - lefthand_file = 'icons/mob/inhands/equipment/kitchen_lefthand.dmi' - righthand_file = 'icons/mob/inhands/equipment/kitchen_righthand.dmi' - inhand_x_dimension = 32 - inhand_y_dimension = 32 - w_class = WEIGHT_CLASS_SMALL - force = 15 - throwforce = 25 - embedding = list("embed_chance" = 75) - -/obj/item/melee/cultblade/dagger/attack(mob/living/target, mob/living/carbon/human/user) - ..() - if(iscarbon(target)) - var/mob/living/carbon/C = target - C.bleed(50) - if(is_servant_of_ratvar(C) && C.reagents) - C.reagents.add_reagent("heparin", 1) - /obj/item/twohanded/required/cult_bastard name = "bloody bastard sword" desc = "An enormous sword used by Nar-Sien cultists to rapidly harvest the souls of non-believers." @@ -106,6 +113,12 @@ jaunt = new(src) linked_action = new(src) +/obj/item/twohanded/required/cult_bastard/examine(mob/user) + if(contents.len) + desc+="
There are [contents.len] souls trapped within the sword's core." + else + desc+="
The sword appears to be quite lifeless." + /obj/item/twohanded/required/cult_bastard/can_be_pulled(user) return FALSE @@ -146,7 +159,7 @@ /obj/item/twohanded/required/cult_bastard/IsReflect() if(spinning) - playsound(src, pick('sound/weapons/bulletflyby.ogg', 'sound/weapons/bulletflyby2.ogg', 'sound/weapons/bulletflyby3.ogg'), 75, 1) + playsound(src, pick('sound/weapons/effects/ric1.ogg', 'sound/weapons/effects/ric2.ogg', 'sound/weapons/effects/ric3.ogg', 'sound/weapons/effects/ric4.ogg', 'sound/weapons/effects/ric5.ogg'), 100, 1) return TRUE else ..() @@ -155,7 +168,7 @@ if(prob(final_block_chance)) if(attack_type == PROJECTILE_ATTACK) owner.visible_message("[owner] deflects [attack_text] with [src]!") - playsound(src, pick('sound/weapons/bulletflyby.ogg', 'sound/weapons/bulletflyby2.ogg', 'sound/weapons/bulletflyby3.ogg'), 100, 1) + playsound(src, pick('sound/weapons/effects/ric1.ogg', 'sound/weapons/effects/ric2.ogg', 'sound/weapons/effects/ric3.ogg', 'sound/weapons/effects/ric4.ogg', 'sound/weapons/effects/ric5.ogg'), 100, 1) return TRUE else playsound(src, 'sound/weapons/parry.ogg', 75, 1) @@ -165,23 +178,22 @@ /obj/item/twohanded/required/cult_bastard/afterattack(atom/target, mob/user, proximity, click_parameters) . = ..() - if(dash_toggled) + if(dash_toggled && !proximity) jaunt.Teleport(user, target) return - if(!proximity) - return - if(ishuman(target)) - var/mob/living/carbon/human/H = target - if(H.stat != CONSCIOUS) - var/obj/item/device/soulstone/SS = new /obj/item/device/soulstone(src) - SS.attack(H, user) - if(!LAZYLEN(SS.contents)) + if(proximity) + if(ishuman(target)) + var/mob/living/carbon/human/H = target + if(H.stat != CONSCIOUS) + var/obj/item/device/soulstone/SS = new /obj/item/device/soulstone(src) + SS.attack(H, user) + if(!LAZYLEN(SS.contents)) + qdel(SS) + if(istype(target, /obj/structure/constructshell) && contents.len) + var/obj/item/device/soulstone/SS = contents[1] + if(istype(SS)) + SS.transfer_soul("CONSTRUCT",target,user) qdel(SS) - if(istype(target, /obj/structure/constructshell) && contents.len) - var/obj/item/device/soulstone/SS = contents[1] - if(istype(SS)) - SS.transfer_soul("CONSTRUCT",target,user) - qdel(SS) /datum/action/innate/dash/cult name = "Rend the Veil" @@ -241,10 +253,20 @@ /obj/item/restraints/legcuffs/bola/cult name = "nar'sien bola" - desc = "A strong bola, bound with dark magic. Throw it to trip and slow your victim." + desc = "A strong bola, bound with dark magic that allows it to pass harmlessly through Nar'sien cultists. Throw it to trip and slow your victim." icon_state = "bola_cult" - breakouttime = 45 - knockdown = 10 + breakouttime = 60 + knockdown = 20 + +/obj/item/restraints/legcuffs/bola/cult/pickup(mob/living/user) + if(!iscultist(user)) + to_chat(user, "The bola seems to take on a life of its own!") + throw_impact(user) + +/obj/item/restraints/legcuffs/bola/cult/throw_impact(atom/hit_atom) + if(iscultist(hit_atom)) + return + . = ..() /obj/item/clothing/head/culthood @@ -253,7 +275,7 @@ desc = "A torn, dust-caked hood. Strange letters line the inside." flags_inv = HIDEFACE|HIDEHAIR|HIDEEARS flags_cover = HEADCOVERSEYES - armor = list(melee = 30, bullet = 10, laser = 5,energy = 5, bomb = 0, bio = 0, rad = 0, fire = 10, acid = 10) + armor = list(melee = 40, bullet = 30, laser = 40,energy = 20, bomb = 25, bio = 10, rad = 0, fire = 10, acid = 10) cold_protection = HEAD min_cold_protection_temperature = HELMET_MIN_TEMP_PROTECT heat_protection = HEAD @@ -266,7 +288,7 @@ item_state = "cultrobes" body_parts_covered = CHEST|GROIN|LEGS|ARMS allowed = list(/obj/item/tome, /obj/item/melee/cultblade) - armor = list(melee = 50, bullet = 30, laser = 50,energy = 20, bomb = 25, bio = 10, rad = 0, fire = 10, acid = 10) + armor = list(melee = 40, bullet = 30, laser = 40,energy = 20, bomb = 25, bio = 10, rad = 0, fire = 10, acid = 10) flags_inv = HIDEJUMPSUIT cold_protection = CHEST|GROIN|LEGS|ARMS min_cold_protection_temperature = ARMOR_MIN_TEMP_PROTECT @@ -341,7 +363,10 @@ prefix = "darkened" /obj/item/sharpener/cult/update_icon() + var/old_state = icon_state icon_state = "cult_sharpener[used ? "_used" : ""]" + if(old_state != icon_state) + playsound(get_turf(src), 'sound/items/unsheath.ogg', 25, 1) /obj/item/clothing/suit/hooded/cultrobes/cult_shield name = "empowered cultist armor" @@ -431,12 +456,11 @@ user.adjustBruteLoss(25) user.dropItemToGround(src, TRUE) -/obj/item/clothing/glasses/night/cultblind - desc = "May nar-sie guide you through the darkness and shield you from the light." +/obj/item/clothing/glasses/hud/health/night/cultblind + desc = "may Nar-Sie guide you through the darkness and shield you from the light." name = "zealot's blindfold" icon_state = "blindfold" item_state = "blindfold" - darkness_view = 8 flash_protect = 1 /obj/item/clothing/glasses/night/cultblind/equipped(mob/living/user, slot) @@ -448,12 +472,13 @@ user.Knockdown(100) user.blind_eyes(30) -/obj/item/reagent_containers/food/drinks/bottle/unholywater +/obj/item/reagent_containers/glass/beaker/unholywater name = "flask of unholy water" desc = "Toxic to nonbelievers; reinvigorating to the faithful - this flask may be sipped or thrown." + icon = 'icons/obj/drinks.dmi' icon_state = "holyflask" color = "#333333" - list_reagents = list("unholywater" = 40) + list_reagents = list("unholywater" = 50) /obj/item/device/shuttle_curse name = "cursed orb" @@ -604,3 +629,348 @@ ..() to_chat(user, "\The [src] can only transport items!") + +/obj/item/twohanded/cult_spear + name = "blood halberd" + desc = "A sickening spear composed entirely of crystallized blood." + icon_state = "bloodspear0" + lefthand_file = 'icons/mob/inhands/weapons/polearms_lefthand.dmi' + righthand_file = 'icons/mob/inhands/weapons/polearms_righthand.dmi' + slot_flags = 0 + force = 17 + force_wielded = 24 + throwforce = 40 + throw_speed = 2 + armour_penetration = 30 + block_chance = 30 + attack_verb = list("attacked", "impaled", "stabbed", "torn", "gored") + sharpness = IS_SHARP + hitsound = 'sound/weapons/bladeslice.ogg' + var/datum/action/innate/cult/spear/spear_act + +/obj/item/twohanded/cult_spear/Destroy() + if(spear_act) + qdel(spear_act) + ..() + +/obj/item/twohanded/cult_spear/update_icon() + icon_state = "bloodspear[wielded]" + +/obj/item/twohanded/cult_spear/throw_impact(atom/target) + var/turf/T = get_turf(target) + if(isliving(target)) + var/mob/living/L = target + if(iscultist(L)) + playsound(src, 'sound/weapons/throwtap.ogg', 50) + if(L.put_in_active_hand(src)) + L.visible_message("[L] catches [src] out of the air!") + else + L.visible_message("[src] bounces off of [L], as if repelled by an unseen force!") + else if(!..()) + if(!L.null_rod_check()) + if(is_servant_of_ratvar(L)) + L.Knockdown(100) + else + L.Knockdown(50) + break_spear(T) + else + ..() + +/obj/item/twohanded/cult_spear/proc/break_spear(turf/T) + if(src) + if(!T) + T = get_turf(src) + if(T) + T.visible_message("[src] shatters and melts back into blood!") + new /obj/effect/temp_visual/cult/sparks(T) + new /obj/effect/decal/cleanable/blood/splatter(T) + playsound(T, 'sound/effects/glassbr3.ogg', 100) + qdel(src) + +/obj/item/twohanded/cult_spear/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK) + if(wielded) + final_block_chance *= 2 + if(prob(final_block_chance)) + if(attack_type == PROJECTILE_ATTACK) + owner.visible_message("[owner] deflects [attack_text] with [src]!") + playsound(src, pick('sound/weapons/effects/ric1.ogg', 'sound/weapons/effects/ric2.ogg', 'sound/weapons/effects/ric3.ogg', 'sound/weapons/effects/ric4.ogg', 'sound/weapons/effects/ric5.ogg'), 100, 1) + return TRUE + else + playsound(src, 'sound/weapons/parry.ogg', 100, 1) + owner.visible_message("[owner] parries [attack_text] with [src]!") + return TRUE + return FALSE + +/datum/action/innate/cult/spear + name = "Bloody Bond" + desc = "Call the blood spear back to your hand!" + background_icon_state = "bg_demon" + button_icon_state = "bloodspear" + var/obj/item/twohanded/cult_spear/spear + var/cooldown = 0 + +/datum/action/innate/cult/spear/Grant(mob/user, obj/blood_spear) + . = ..() + spear = blood_spear + button.screen_loc = "6:157,4:-2" + button.moved = "6:157,4:-2" + +/datum/action/innate/cult/spear/Activate() + if(owner == spear.loc || cooldown > world.time) + return + var/ST = get_turf(spear) + var/OT = get_turf(owner) + if(get_dist(OT, ST) > 10) + to_chat(owner,"The spear is too far away!") + else + cooldown = world.time + 20 + if(isliving(spear.loc)) + var/mob/living/L = spear.loc + L.dropItemToGround(spear) + L.visible_message("An unseen force pulls the blood spear from [L]'s hands!") + spear.throw_at(owner, 10, 2, owner) + + +/obj/item/gun/ballistic/shotgun/boltaction/enchanted/arcane_barrage/blood + name = "blood bolt barrage" + desc = "Blood for blood." + color = "#ff0000" + guns_left = 24 + mag_type = /obj/item/ammo_box/magazine/internal/boltaction/enchanted/arcane_barrage/blood + fire_sound = 'sound/magic/wand_teleport.ogg' + flags_1 = NOBLUDGEON_1 | DROPDEL_1 + + +/obj/item/ammo_box/magazine/internal/boltaction/enchanted/arcane_barrage/blood + ammo_type = /obj/item/ammo_casing/magic/arcane_barrage/blood + +/obj/item/ammo_casing/magic/arcane_barrage/blood + projectile_type = /obj/item/projectile/magic/arcane_barrage/blood + +/obj/item/projectile/magic/arcane_barrage/blood + name = "blood bolt" + icon_state = "mini_leaper" + damage_type = BRUTE + impact_effect_type = /obj/effect/temp_visual/dir_setting/bloodsplatter + +/obj/item/projectile/magic/arcane_barrage/blood/Collide(atom/target) + colliding = TRUE + var/turf/T = get_turf(target) + playsound(T, 'sound/effects/splat.ogg', 50, TRUE) + if(iscultist(target)) + if(ishuman(target)) + var/mob/living/carbon/human/H = target + if(H.stat != DEAD) + H.reagents.add_reagent("unholywater", 4) + if(isshade(target) || isconstruct(target)) + var/mob/living/simple_animal/M = target + if(M.health+5 < M.maxHealth) + M.adjustHealth(-5) + new /obj/effect/temp_visual/cult/sparks(T) + qdel(src) + colliding = FALSE + else + ..() + +/obj/item/blood_beam + name = "\improper magical aura" + desc = "Sinister looking aura that distorts the flow of reality around it." + icon = 'icons/obj/items_and_weapons.dmi' + icon_state = "disintegrate" + item_state = null + flags_1 = ABSTRACT_1 | NODROP_1 | DROPDEL_1 + w_class = WEIGHT_CLASS_HUGE + throwforce = 0 + throw_range = 0 + throw_speed = 0 + var/charging = FALSE + var/firing = FALSE + var/angle + + +/obj/item/blood_beam/afterattack(atom/A, mob/living/user, flag, params) + if(firing || charging) + return + var/C = user.client + if(ishuman(user) && C) + angle = mouse_angle_from_client(C) + else + qdel(src) + return + charging = TRUE + INVOKE_ASYNC(src, .proc/charge, user) + if(do_after(user, 90, target = user)) + firing = TRUE + INVOKE_ASYNC(src, .proc/pewpew, user, params) + var/obj/structure/emergency_shield/invoker/N = new(user.loc) + if(do_after(user, 90, target = user)) + user.Knockdown(40) + to_chat(user, "You have exhausted the power of this spell!") + firing = FALSE + if(N) + qdel(N) + qdel(src) + charging = FALSE + +/obj/item/blood_beam/proc/charge(mob/user) + var/obj/O + playsound(src, 'sound/magic/lightning_chargeup.ogg', 100, 1) + for(var/i in 1 to 12) + if(!charging) + break + if(i > 1) + sleep(15) + if(i < 4) + O = new /obj/effect/temp_visual/cult/rune_spawn/rune1/inner(user.loc, 30, "#ff0000") + else + O = new /obj/effect/temp_visual/cult/rune_spawn/rune5(user.loc, 30, "#ff0000") + new /obj/effect/temp_visual/dir_setting/cult/phase/out(user.loc, user.dir) + if(O) + qdel(O) + +/obj/item/blood_beam/proc/pewpew(mob/user, params) + var/turf/targets_from = get_turf(src) + var/spread = 40 + var/second = FALSE + var/set_angle = angle + for(var/i in 1 to 12) + if(second) + set_angle = angle - spread + spread -= 8 + else + sleep(15) + set_angle = angle + spread + second = !second //Handles beam firing in pairs + if(!firing) + break + playsound(src, 'sound/magic/exit_blood.ogg', 75, 1) + new /obj/effect/temp_visual/dir_setting/cult/phase(user.loc, user.dir) + var/turf/temp_target = get_turf_in_angle(set_angle, targets_from, 40) + for(var/turf/T in getline(targets_from,temp_target)) + if (locate(/obj/effect/blessing, T)) + temp_target = T + playsound(T, 'sound/machines/clockcult/ark_damage.ogg', 50, 1) + new /obj/effect/temp_visual/at_shield(T, T) + break + T.narsie_act(TRUE, TRUE) + for(var/mob/living/target in T.contents) + if(iscultist(target)) + new /obj/effect/temp_visual/cult/sparks(T) + if(ishuman(target)) + var/mob/living/carbon/human/H = target + if(H.stat != DEAD) + H.reagents.add_reagent("unholywater", 7) + if(isshade(target) || isconstruct(target)) + var/mob/living/simple_animal/M = target + if(M.health+15 < M.maxHealth) + M.adjustHealth(-15) + else + M.health = M.maxHealth + else + var/mob/living/L = target + if(L.density) + L.Knockdown(20) + L.adjustBruteLoss(45) + playsound(L, 'sound/hallucinations/wail.ogg', 50, 1) + L.emote("scream") + var/datum/beam/current_beam = new(user,temp_target,time=7,beam_icon_state="blood_beam",btype=/obj/effect/ebeam/blood) + INVOKE_ASYNC(current_beam, /datum/beam.proc/Start) + + +/obj/effect/ebeam/blood + name = "blood beam" + +/obj/item/shield/mirror + name = "mirror shield" + desc = "An infamous shield used by Nar'sien sects to confuse and disorient their enemies. Its edges are weighted for use as a throwing weapon - capable of disabling multiple foes with preternatural accuracy." + icon = 'icons/obj/items_and_weapons.dmi' + icon_state = "mirror_shield" // eshield1 for expanded + lefthand_file = 'icons/mob/inhands/equipment/shields_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/shields_righthand.dmi' + force = 5 + throwforce = 15 + throw_speed = 1 + throw_range = 6 + w_class = WEIGHT_CLASS_BULKY + attack_verb = list("bumped", "prodded") + hitsound = 'sound/weapons/smash.ogg' + var/illusions = 3 + +/obj/item/shield/mirror/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK) + if(iscultist(owner)) + if(istype(hitby, /obj/item/projectile)) + var/obj/item/projectile/P = hitby + if(P.damage >= 35) + var/turf/T = get_turf(owner) + T.visible_message("The sheer force from [P] shatters the mirror shield!") + new /obj/effect/temp_visual/cult/sparks(T) + playsound(T, 'sound/effects/glassbr3.ogg', 100) + owner.Knockdown(20) + qdel(src) + return FALSE + if(P.is_reflectable) + return FALSE //To avoid reflection chance double-dipping with block chance + . = ..() + if(.) + playsound(src, 'sound/weapons/parry.ogg', 100, 1) + if(illusions > 0) + illusions-- + addtimer(CALLBACK(src, /obj/item/shield/mirror.proc/readd), 450) + if(prob(60)) + var/mob/living/simple_animal/hostile/illusion/M = new(owner.loc) + M.faction = list("cult") + M.Copy_Parent(owner, 70, 10, 5) + M.move_to_delay = owner.movement_delay() + else + var/mob/living/simple_animal/hostile/illusion/escape/E = new(owner.loc) + E.Copy_Parent(owner, 70, 10) + E.GiveTarget(owner) + E.Goto(owner, owner.movement_delay(), E.minimum_distance) + return TRUE + else + if(prob(50)) + var/mob/living/simple_animal/hostile/illusion/H = new(owner.loc) + H.Copy_Parent(owner, 100, 20, 5) + H.faction = list("cult") + H.GiveTarget(owner) + H.move_to_delay = owner.movement_delay() + to_chat(owner, "[src] betrays you!") + return FALSE + +/obj/item/shield/mirror/proc/readd() + illusions++ + if(illusions == initial(illusions) && isliving(loc)) + var/mob/living/holder = loc + to_chat(holder, "The shield's illusions are back at full strength!") + +/obj/item/shield/mirror/IsReflect() + if(prob(block_chance)) + return TRUE + return FALSE + +/obj/item/shield/mirror/throw_impact(atom/target, throwingdatum) + var/turf/T = get_turf(target) + var/datum/thrownthing/D = throwingdatum + if(isliving(target)) + var/mob/living/L = target + if(iscultist(L)) + playsound(src, 'sound/weapons/throwtap.ogg', 50) + if(L.put_in_active_hand(src)) + L.visible_message("[L] catches [src] out of the air!") + else + L.visible_message("[src] bounces off of [L], as if repelled by an unseen force!") + else if(!..()) + if(!L.null_rod_check()) + if(is_servant_of_ratvar(L)) + L.Knockdown(60) + else + L.Knockdown(30) + if(D.thrower) + for(var/mob/living/Next in orange(2, T)) + if(!Next.density || iscultist(Next)) + continue + throw_at(Next, 3, 1, D.thrower) + return + throw_at(D.thrower, 7, 1, D.thrower) + else + ..() \ No newline at end of file diff --git a/code/modules/antagonists/cult/cult_structures.dm b/code/modules/antagonists/cult/cult_structures.dm index a921868f22b..efe94afb884 100644 --- a/code/modules/antagonists/cult/cult_structures.dm +++ b/code/modules/antagonists/cult/cult_structures.dm @@ -2,10 +2,32 @@ density = TRUE anchored = TRUE icon = 'icons/obj/cult.dmi' + light_power = 2 var/cooldowntime = 0 break_sound = 'sound/hallucinations/veryfar_noise.ogg' debris = list(/obj/item/stack/sheet/runed_metal = 1) +/obj/structure/destructible/cult/proc/conceal() //for spells that hide cult presence + density = FALSE + visible_message("[src] fades away.") + invisibility = INVISIBILITY_OBSERVER + alpha = 100 //To help ghosts distinguish hidden runes + light_range = 0 + light_power = 0 + update_light() + STOP_PROCESSING(SSfastprocess, src) + +/obj/structure/destructible/cult/proc/reveal() //for spells that reveal cult presence + density = initial(density) + invisibility = 0 + visible_message("[src] suddenly appears!") + alpha = initial(alpha) + light_range = initial(light_range) + light_power = initial(light_power) + update_light() + START_PROCESSING(SSfastprocess, src) + + /obj/structure/destructible/cult/examine(mob/user) ..() to_chat(user, "\The [src] is [anchored ? "":"not "]secured to the floor.") @@ -33,7 +55,7 @@ ..() /obj/structure/destructible/cult/attackby(obj/I, mob/user, params) - if(istype(I, /obj/item/tome) && iscultist(user)) + if(istype(I, /obj/item/melee/cultblade/dagger) && iscultist(user)) anchored = !anchored to_chat(user, "You [anchored ? "":"un"]secure \the [src] [anchored ? "to":"from"] the floor.") if(!anchored) @@ -62,31 +84,32 @@ to_chat(user, "You're pretty sure you know exactly what this is used for and you can't seem to touch it.") return if(!anchored) - to_chat(user, "You need to anchor [src] to the floor with a tome first.") + to_chat(user, "You need to anchor [src] to the floor with your dagger first.") return if(cooldowntime > world.time) to_chat(user, "The magic in [src] is weak, it will be ready to use again in [DisplayTimeText(cooldowntime - world.time)].") return - var/choice = alert(user,"You study the schematics etched into the forge...",,"Eldritch Whetstone","Zealot's Blindfold","Flask of Unholy Water") - var/pickedtype + var/choice = alert(user,"You study the schematics etched into the altar...",,"Eldritch Whetstone","Construct Shells","Flask of Unholy Water") + var/list/pickedtype = list() switch(choice) if("Eldritch Whetstone") - pickedtype = /obj/item/sharpener/cult - if("Zealot's Blindfold") - pickedtype = /obj/item/clothing/glasses/night/cultblind + pickedtype += /obj/item/sharpener/cult + if("Construct Shells") + pickedtype += /obj/structure/constructshell + pickedtype += /obj/structure/constructshell if("Flask of Unholy Water") - pickedtype = /obj/item/reagent_containers/food/drinks/bottle/unholywater + pickedtype += /obj/item/reagent_containers/glass/beaker/unholywater if(src && !QDELETED(src) && anchored && pickedtype && Adjacent(user) && !user.incapacitated() && iscultist(user) && cooldowntime <= world.time) cooldowntime = world.time + 2400 - var/obj/item/N = new pickedtype(get_turf(src)) - to_chat(user, "You kneel before the altar and your faith is rewarded with an [N]!") - + for(var/N in pickedtype) + new N(get_turf(src)) + to_chat(user, "You kneel before the altar and your faith is rewarded with the [choice]!") /obj/structure/destructible/cult/forge name = "daemon forge" desc = "A forge used in crafting the unholy weapons used by the armies of Nar-Sie." icon_state = "forge" - light_range = 3 + light_range = 2 light_color = LIGHT_COLOR_LAVA break_message = "The force breaks apart into shards with a howling scream!" @@ -95,30 +118,35 @@ to_chat(user, "The heat radiating from [src] pushes you back.") return if(!anchored) - to_chat(user, "You need to anchor [src] to the floor with a tome first.") + to_chat(user, "You need to anchor [src] to the floor with your dagger first.") return if(cooldowntime > world.time) to_chat(user, "The magic in [src] is weak, it will be ready to use again in [DisplayTimeText(cooldowntime - world.time)].") return - var/choice = alert(user,"You study the schematics etched into the forge...",,"Shielded Robe","Flagellant's Robe","Bastard Sword") - var/pickedtype + var/choice = alert(user,"You study the schematics etched into the forge...",,"Shielded Robe","Flagellant's Robe","Mirror Shield") + if(user.mind.has_antag_datum(/datum/antagonist/cult/master)) + choice = alert(user,"You study the schematics etched into the forge...",,"Shielded Robe","Flagellant's Robe","Bastard Sword") + var/list/pickedtype = list() switch(choice) if("Shielded Robe") - pickedtype = /obj/item/clothing/suit/hooded/cultrobes/cult_shield + pickedtype += /obj/item/clothing/suit/hooded/cultrobes/cult_shield if("Flagellant's Robe") - pickedtype = /obj/item/clothing/suit/hooded/cultrobes/berserker + pickedtype += /obj/item/clothing/suit/hooded/cultrobes/berserker if("Bastard Sword") if((world.time - SSticker.round_start_time) >= 12000) - pickedtype = /obj/item/twohanded/required/cult_bastard + pickedtype += /obj/item/twohanded/required/cult_bastard else cooldowntime = 12000 - (world.time - SSticker.round_start_time) to_chat(user, "The forge fires are not yet hot enough for this weapon, give it another [DisplayTimeText(cooldowntime)].") cooldowntime = 0 return + if("Mirror Shield") + pickedtype += /obj/item/shield/mirror if(src && !QDELETED(src) && anchored && pickedtype && Adjacent(user) && !user.incapacitated() && iscultist(user) && cooldowntime <= world.time) cooldowntime = world.time + 2400 - var/obj/item/N = new pickedtype(get_turf(src)) - to_chat(user, "You work the forge as dark knowledge guides your hands, creating [N]!") + for(var/N in pickedtype) + new N(get_turf(src)) + to_chat(user, "You work the forge as dark knowledge guides your hands, creating the [choice]!") @@ -126,7 +154,7 @@ name = "pylon" desc = "A floating crystal that slowly heals those faithful to Nar'Sie." icon_state = "pylon" - light_range = 5 + light_range = 1.5 light_color = LIGHT_COLOR_RED break_sound = 'sound/effects/glassbr2.ogg' break_message = "The blood-red crystal falls to the floor and shatters!" @@ -159,7 +187,7 @@ if(isshade(L) || isconstruct(L)) var/mob/living/simple_animal/M = L if(M.health < M.maxHealth) - M.adjustHealth(-1) + M.adjustHealth(-3) if(ishuman(L) && L.blood_volume < BLOOD_VOLUME_NORMAL) L.blood_volume += 1.0 CHECK_TICK @@ -199,7 +227,7 @@ name = "archives" desc = "A desk covered in arcane manuscripts and tomes in unknown languages. Looking at the text makes your skin crawl." icon_state = "tomealtar" - light_range = 1.4 + light_range = 1.5 light_color = LIGHT_COLOR_FIRE break_message = "The books and tomes of the archives burn into ash as the desk shatters!" @@ -208,16 +236,16 @@ to_chat(user, "All of these books seem to be gibberish.") return if(!anchored) - to_chat(user, "You need to anchor [src] to the floor with a tome first.") + to_chat(user, "You need to anchor [src] to the floor with your dagger first.") return if(cooldowntime > world.time) to_chat(user, "The magic in [src] is weak, it will be ready to use again in [DisplayTimeText(cooldowntime - world.time)].") return - var/choice = alert(user,"You flip through the black pages of the archives...",,"Supply Talisman","Shuttle Curse","Veil Walker Set") + var/choice = alert(user,"You flip through the black pages of the archives...",,"Zealot's Blindfold","Shuttle Curse","Veil Walker Set") var/list/pickedtype = list() switch(choice) - if("Supply Talisman") - pickedtype += /obj/item/paper/talisman/supply/weak + if("Zealot's Blindfold") + pickedtype += /obj/item/clothing/glasses/hud/health/night/cultblind if("Shuttle Curse") pickedtype += /obj/item/device/shuttle_curse if("Veil Walker Set") @@ -226,8 +254,8 @@ if(src && !QDELETED(src) && anchored && pickedtype.len && Adjacent(user) && !user.incapacitated() && iscultist(user) && cooldowntime <= world.time) cooldowntime = world.time + 2400 for(var/N in pickedtype) - var/obj/item/D = new N(get_turf(src)) - to_chat(user, "You summon [D] from the archives!") + new N(get_turf(src)) + to_chat(user, "You summon the [choice] from the archives!") /obj/effect/gateway name = "gateway" diff --git a/code/modules/antagonists/cult/ritual.dm b/code/modules/antagonists/cult/ritual.dm index 93ed9bfdd11..00ec2917558 100644 --- a/code/modules/antagonists/cult/ritual.dm +++ b/code/modules/antagonists/cult/ritual.dm @@ -1,19 +1,11 @@ /* -This file contains the arcane tome files. +This file contains the cult dagger and rune list code */ -/obj/item/tome - name = "arcane tome" - desc = "An old, dusty tome with frayed edges and a sinister-looking cover." - icon_state ="tome" - throw_speed = 2 - throw_range = 5 - w_class = WEIGHT_CLASS_SMALL - -/obj/item/tome/Initialize() +/obj/item/melee/cultblade/dagger/Initialize() . = ..() if(!LAZYLEN(GLOB.rune_types)) GLOB.rune_types = list() @@ -22,19 +14,15 @@ This file contains the arcane tome files. var/obj/effect/rune/R = i_can_do_loops_now_thanks_remie GLOB.rune_types[initial(R.cultist_name)] = R //Uses the cultist name for displaying purposes -/obj/item/tome/examine(mob/user) +/obj/item/melee/cultblade/dagger/examine(mob/user) ..() if(iscultist(user) || isobserver(user)) to_chat(user, "The scriptures of the Geometer. Allows the scribing of runes and access to the knowledge archives of the cult of Nar-Sie.") to_chat(user, "Striking a cult structure will unanchor or reanchor it.") 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.") + to_chat(user, "Striking a noncultist, however, will tear their flesh.") -/obj/item/tome/attack(mob/living/M, mob/living/user) - if(!istype(M)) - return - if(!iscultist(user)) - return ..() +/obj/item/melee/cultblade/dagger/attack(mob/living/M, mob/living/user) 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]." ) @@ -42,136 +30,16 @@ This file contains the arcane tome files. 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_bodypart_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) + return FALSE + . = ..() -/obj/item/tome/attack_self(mob/user) +/obj/item/melee/cultblade/dagger/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?") + to_chat(user, "[src] is covered in unintelligible shapes and markings.") return - open_tome(user) + scribe_rune(user) -/obj/item/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") - return - -/obj/item/tome/proc/read_tome(mob/user) - var/text = "" - text += "
Archives of the Dark One



" - text += "A rune's name and effects can be revealed by examining the rune.

" - - text += "Create Talisman
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.

" - - 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, provided the selected rune is unblocked.

" - - text += "Offer
This rune is necessary to achieve your goals. Placing a noncultist above it will convert them if it can and sacrifice them otherwise. \ - It requires two invokers to convert a target and three to sacrifice a living target or the sacrifice target.
\ - Successful conversions will produce a tome for the new cultist, in addition to healing them.
\ - Successful sacrifices will please the Geometer, can complete your objective if it sacrificed the sacrifice target, and will attempt to place the target into a soulstone.

" - - text += "Raise Dead
This rune requires the corpse of a cultist placed upon the rune, and one person sacrificed for each revival you wish to do.\ - Provided there are remaining revivals from those sacrificed, invoking the rune will revive the cultist placed upon it.

" - - text += "Electromagnetic 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.

" - - 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 += "Form Barrier
While simple, this rune serves an important purpose in defense and hindering passage. When invoked, the rune will draw a small amount of blood from the user \ - and make the space above the rune completely dense, rendering it impassable for about a minute and a half. This effect will spread to other nearby Barrier Runes. \ - The rune may be invoked again to undo this effect and allow passage again.

" - - text += "Summon Cultist
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 += "Blood Boil
When invoked, this rune will rapidly do a massive amount of damage to all non-cultist viewers, but it will also emit a burst of flame once it finishes. \ - It requires three invokers.

" - - text += "Drain Life
This rune will drain the life of every living creature above the rune, healing the invoker for each creature drained by it.

" - - text += "Manifest Spirit
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 the Geometer. \ - 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 += "Summon Nar-Sie
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 the Geometer, Nar-Sie herself. \ - This will complete your objectives.


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

" - - text += "Talisman of Construction
This talisman is the main way of creating construct shells. To use it, one must strike 25 sheets of metal with the talisman. The sheets will then be twisted into a construct shell, ready to receive a soul to occupy it.

" - - text += "Talisman of Tome Summoning
This talisman will produce a single tome at your feet.

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

" - - text += "Talisman of Disguising
This talisman will permanently disguise all nearby runes as crayon runes.

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

" - - 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 += "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 += "Talisman of Horrors
The Talisman of Horror, unlike other talismans, can be applied at range, without the victim noticing. It will cause the victim to have severe hallucinations after a short while.

" - - 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 += "In addition to these runes, the cult has a small selection of equipment and constructs.

" - - text += "Equipment:

" - - 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 += "Cult Bola
Cult bolas are strong bolas, useful for snaring targets. These bolas are produced by the Talisman of Arming.

" - - text += "Cult Robes
Cult robes are heavily armored robes. These robes are produced by the Talisman of Arming.

" - - 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 += "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 += "Constructs:

" - - 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 += "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 += "Juggernaut
The Juggernaut is a slow, but durable, melee attacker which can produce temporary forcewalls. It will also reflect most lethal energy weapons.

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

" - - 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/tome/proc/scribe_rune(mob/living/user) +/obj/item/melee/cultblade/dagger/proc/scribe_rune(mob/living/user) var/turf/Turf = get_turf(user) var/chosen_keyword var/obj/effect/rune/rune_to_scribe @@ -183,9 +51,6 @@ This file contains the arcane tome files. if(!user_antag) return - var/datum/objective/eldergod/summon_objective = locate() in user_antag.cult_team.objectives - var/datum/objective/sacrifice/sac_objective = locate() in user_antag.cult_team.objectives - if(!check_rune_turf(Turf, user)) return entered_rune_name = input(user, "Choose a rite to scribe.", "Sigils of Power") as null|anything in GLOB.rune_types @@ -203,9 +68,21 @@ This file contains the arcane tome files. A = get_area(src) if(!src || QDELETED(src) || !Adjacent(user) || user.incapacitated() || !check_rune_turf(Turf, user)) return - - //AAAAAAAAAAAAAAAH, i'm rewriting enough for now so TODO: remove this shit + if(ispath(rune_to_scribe, /obj/effect/rune/apocalypse)) + if((world.time - SSticker.round_start_time) <= 6000) + var/wait = 6000 - (world.time - SSticker.round_start_time) + to_chat(user, "The veil is not yet weak enough for this rune - it will be available in [DisplayTimeText(wait)].") + return + var/datum/objective/eldergod/summon_objective = locate() in user_antag.cult_team.objectives + if(!(A in summon_objective.summon_spots)) + to_chat(user, "The Apocalypse rune will remove a ritual site (where Nar-sie can be summoned), it can only be scribed in [english_list(summon_objective.summon_spots)]!") + return + if(summon_objective.summon_spots.len < 2) + to_chat(user, "Only one ritual site remains - it must be reserved for the final summoning!") + return if(ispath(rune_to_scribe, /obj/effect/rune/narsie)) + var/datum/objective/eldergod/summon_objective = locate() in user_antag.cult_team.objectives + var/datum/objective/sacrifice/sac_objective = locate() in user_antag.cult_team.objectives if(!summon_objective) to_chat(user, "Nar-Sie does not wish to be summoned!") return @@ -257,7 +134,7 @@ This file contains the arcane tome files. to_chat(user, "The [lowertext(R.cultist_name)] rune [R.cultist_desc]") SSblackbox.record_feedback("tally", "cult_runes_scribed", 1, R.cultist_name) -/obj/item/tome/proc/check_rune_turf(turf/T, mob/user) +/obj/item/melee/cultblade/dagger/proc/check_rune_turf(turf/T, mob/user) if(isspaceturf(T)) to_chat(user, "You cannot scribe runes in space!") return FALSE @@ -266,14 +143,16 @@ This file contains the arcane tome files. to_chat(user, "There is already a rune here.") return FALSE + if(!is_station_level(T.z) && !is_mining_level(T.z)) to_chat(user, "The veil is not weak enough here.") + return FALSE - + var/area/A = get_area(T) if(A && !A.blob_allowed) to_chat(user, "There's a passage in [src] specifically forbidding oyster consumption, triple-frying, and building outside of designated cult zones.") return FALSE - + return TRUE diff --git a/code/modules/antagonists/cult/rune_spawn_action.dm b/code/modules/antagonists/cult/rune_spawn_action.dm index 119d507a5e1..60a8527860c 100644 --- a/code/modules/antagonists/cult/rune_spawn_action.dm +++ b/code/modules/antagonists/cult/rune_spawn_action.dm @@ -1,10 +1,12 @@ //after a delay, creates a rune below you. for constructs creating runes. /datum/action/innate/cult/create_rune - background_icon_state = "bg_cult" + name = "Summon Rune" + desc = "Summons a rune" + background_icon_state = "bg_demon" var/obj/effect/rune/rune_type var/cooldown = 0 - var/base_cooldown = 900 - var/scribe_time = 100 + var/base_cooldown = 1800 + var/scribe_time = 60 var/damage_interrupt = TRUE var/action_interrupt = TRUE var/obj/effect/temp_visual/cult/rune_spawn/rune_word_type @@ -17,57 +19,100 @@ return FALSE return ..() -/datum/action/innate/cult/create_rune/Activate() - var/chosen_keyword - if(!isturf(owner.loc)) - to_chat(owner, "You cannot scribe runes in space!") + return FALSE + if(locate(/obj/effect/rune) in T) + to_chat(owner, "There is already a rune here.") + return FALSE + if(!is_station_level(T.z) && !is_mining_level(T.z)) + to_chat(owner, "The veil is not weak enough here.") + return FALSE + return TRUE - cooldown = base_cooldown + world.time - owner.update_action_buttons_icon() - addtimer(CALLBACK(owner, /mob.proc/update_action_buttons_icon), base_cooldown) - var/list/health - if(damage_interrupt && isliving(owner)) - var/mob/living/L = owner - health = list("health" = L.health) - var/scribe_mod = scribe_time - if(istype(get_turf(owner), /turf/open/floor/engine/cult)) - scribe_mod *= 0.5 - if(do_after(owner, scribe_mod, target = owner, extra_checks = CALLBACK(owner, /mob.proc/break_do_after_checks, health, action_interrupt))) - var/obj/effect/rune/new_rune = new rune_type(owner.loc) - new_rune.keyword = chosen_keyword - else - qdel(R1) - if(R2) - qdel(R2) - if(R3) - qdel(R3) - if(R4) - qdel(R4) - cooldown = 0 + +/datum/action/innate/cult/create_rune/Activate() + var/turf/T = get_turf(owner) + if(turf_check(T)) + var/chosen_keyword + if(initial(rune_type.req_keyword)) + chosen_keyword = stripped_input(owner, "Enter a keyword for the new rune.", "Words of Power") + if(!chosen_keyword) + return + //the outer ring is always the same across all runes + var/obj/effect/temp_visual/cult/rune_spawn/R1 = new(T, scribe_time, rune_color) + //the rest are not always the same, so we need types for em + var/obj/effect/temp_visual/cult/rune_spawn/R2 + if(rune_word_type) + R2 = new rune_word_type(T, scribe_time, rune_color) + var/obj/effect/temp_visual/cult/rune_spawn/R3 + if(rune_innerring_type) + R3 = new rune_innerring_type(T, scribe_time, rune_color) + var/obj/effect/temp_visual/cult/rune_spawn/R4 + if(rune_center_type) + R4 = new rune_center_type(T, scribe_time, rune_color) + + cooldown = base_cooldown + world.time owner.update_action_buttons_icon() + addtimer(CALLBACK(owner, /mob.proc/update_action_buttons_icon), base_cooldown) + var/list/health + if(damage_interrupt && isliving(owner)) + var/mob/living/L = owner + health = list("health" = L.health) + var/scribe_mod = scribe_time + if(istype(T, /turf/open/floor/engine/cult)) + scribe_mod *= 0.5 + playsound(T, 'sound/magic/enter_blood.ogg', 100, FALSE) + if(do_after(owner, scribe_mod, target = owner, extra_checks = CALLBACK(owner, /mob.proc/break_do_after_checks, health, action_interrupt))) + var/obj/effect/rune/new_rune = new rune_type(owner.loc) + new_rune.keyword = chosen_keyword + else + qdel(R1) + if(R2) + qdel(R2) + if(R3) + qdel(R3) + if(R4) + qdel(R4) + cooldown = 0 + owner.update_action_buttons_icon() //teleport rune /datum/action/innate/cult/create_rune/tele + name = "Summon Teleport Rune" + desc = "Summons a teleport rune to your location, as though it has been there all along..." button_icon_state = "telerune" rune_type = /obj/effect/rune/teleport rune_word_type = /obj/effect/temp_visual/cult/rune_spawn/rune2 rune_innerring_type = /obj/effect/temp_visual/cult/rune_spawn/rune2/inner rune_center_type = /obj/effect/temp_visual/cult/rune_spawn/rune2/center rune_color = RUNE_COLOR_TELEPORT + +/datum/action/innate/cult/create_rune/wall + name = "Summon Barrier Rune" + desc = "Summons an active barrier rune to your location, as though it has been there all along..." + button_icon_state = "barrier" + rune_type = /obj/effect/rune/wall + rune_word_type = /obj/effect/temp_visual/cult/rune_spawn/rune4 + rune_innerring_type = /obj/effect/temp_visual/cult/rune_spawn/rune4/inner + rune_center_type = /obj/effect/temp_visual/cult/rune_spawn/rune4/center + rune_color = RUNE_COLOR_DARKRED + +/datum/action/innate/cult/create_rune/wall/Activate() + . = ..() + var/obj/effect/rune/wall/W = locate(/obj/effect/rune/wall) in owner.loc + if(W) + W.spread_density() + +/datum/action/innate/cult/create_rune/revive + name = "Summon Revive Rune" + desc = "Summons a revive rune to your location, as though it has been there all along..." + button_icon_state = "revive" + rune_type = /obj/effect/rune/raise_dead + rune_word_type = /obj/effect/temp_visual/cult/rune_spawn/rune1 + rune_innerring_type = /obj/effect/temp_visual/cult/rune_spawn/rune1/inner + rune_center_type = /obj/effect/temp_visual/cult/rune_spawn/rune1/center + rune_color = RUNE_COLOR_MEDIUMRED \ No newline at end of file diff --git a/code/modules/antagonists/cult/runes.dm b/code/modules/antagonists/cult/runes.dm index a0de57ea22f..1bcb9ef63ca 100644 --- a/code/modules/antagonists/cult/runes.dm +++ b/code/modules/antagonists/cult/runes.dm @@ -1,16 +1,15 @@ GLOBAL_LIST_EMPTY(sacrificed) //a mixed list of minds and mobs -GLOBAL_LIST(rune_types) //Every rune that can be drawn by tomes +GLOBAL_LIST(rune_types) //Every rune that can be drawn by ritual daggers GLOBAL_LIST_EMPTY(teleport_runes) GLOBAL_LIST_EMPTY(wall_runes) /* 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. +They are drawn with a ritual dagger 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. */ @@ -31,7 +30,7 @@ To draw a rune, use an arcane tome. var/req_cultists_text //if we have a description override for required cultists to invoke var/rune_in_use = FALSE // 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_delay = 40 //how long the rune takes to create var/scribe_damage = 0.1 //how much damage you take doing it var/allow_excess_invokers = FALSE //if we allow excess invokers when being invoked @@ -45,6 +44,9 @@ To draw a rune, use an arcane tome. . = ..() if(set_keyword) keyword = set_keyword + var/image/I = image(icon = 'icons/effects/blood.dmi', icon_state = null, loc = src) + I.override = TRUE + add_alt_appearance(/datum/atom_hud/alternate_appearance/basic/silicons, "cult_runes", I) /obj/effect/rune/examine(mob/user) ..() @@ -56,9 +58,11 @@ To draw a rune, use an arcane tome. to_chat(user, "Keyword: [keyword]") /obj/effect/rune/attackby(obj/I, mob/user, params) - if(istype(I, /obj/item/tome) && iscultist(user)) - to_chat(user, "You carefully erase the [lowertext(cultist_name)] rune.") - qdel(src) + if(istype(I, /obj/item/melee/cultblade/dagger) && iscultist(user)) + SEND_SOUND(user,'sound/items/sheath.ogg') + if(do_after(user, 15, target = src)) + to_chat(user, "You carefully erase the [lowertext(cultist_name)] rune.") + qdel(src) else if(istype(I, /obj/item/nullrod)) user.say("BEGONE FOUL MAGIKS!!") to_chat(user, "You disrupt the magic of [src] with [I].") @@ -72,6 +76,7 @@ To draw a rune, use an arcane tome. if(invokers.len >= req_cultists) invoke(invokers) else + to_chat(user, "You need [req_cultists - invokers.len] more adjacent cultists to use this rune in such a manner.") fail_invoke() /obj/effect/rune/attack_animal(mob/living/simple_animal/M) @@ -81,12 +86,12 @@ To draw a rune, use an arcane tome. else to_chat(M, "You are unable to invoke the rune!") -/obj/effect/rune/proc/talismanhide() //for talisman of revealing/hiding +/obj/effect/rune/proc/conceal() //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 +/obj/effect/rune/proc/reveal() //for talisman of revealing/hiding invisibility = 0 visible_message("[src] suddenly appears!") alpha = initial(alpha) @@ -186,136 +191,6 @@ structure_check() searches for nearby cultist structures required for the invoca return B return 0 -//Rite of Binding: A paper on top of the rune to a talisman. -/obj/effect/rune/imbue - cultist_name = "Create Talisman" - cultist_desc = "transforms paper into powerful magic talismans." - invocation = "H'drak v'loso, mir'kanas verbot!" - icon_state = "3" - color = RUNE_COLOR_TALISMAN - -/obj/effect/rune/imbue/invoke(var/list/invokers) - var/mob/living/user = invokers[1] //the first invoker is always the user - var/list/papers_on_rune = checkpapers() - var/entered_talisman_name - var/obj/item/paper/talisman/talisman_type - var/list/possible_talismans = list() - 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 - - for(var/I in subtypesof(/obj/item/paper/talisman) - /obj/item/paper/talisman/malformed - /obj/item/paper/talisman/supply - /obj/item/paper/talisman/supply/weak - /obj/item/paper/talisman/summon_tome) - var/obj/item/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 - papers_on_rune = checkpapers() - 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 - var/obj/item/paper/paper_to_imbue = papers_on_rune[1] - ..() - visible_message("Dark power begins to channel into the paper!") - rune_in_use = TRUE - if(do_after(user, initial(talisman_type.creation_time), target = paper_to_imbue)) - 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 = FALSE - -/obj/effect/rune/imbue/proc/checkpapers() - . = list() - for(var/obj/item/paper/P in get_turf(src)) - if(!P.info && !istype(P, /obj/item/paper/talisman)) - . |= P - -/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" - color = RUNE_COLOR_TELEPORT - req_keyword = TRUE - var/listkey - -/obj/effect/rune/teleport/Initialize(mapload, set_keyword) - . = ..() - var/area/A = get_area(src) - var/locname = initial(A.name) - listkey = set_keyword ? "[set_keyword] [locname]":"[locname]" - GLOB.teleport_runes += src - -/obj/effect/rune/teleport/Destroy() - GLOB.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() - for(var/R in GLOB.teleport_runes) - var/obj/effect/rune/teleport/T = R - if(T != src && !is_away_level(T.z)) - potential_runes[avoid_assoc_duplicate_keys(T.listkey, teleportnames)] = 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 - - var/turf/T = get_turf(src) - if(is_away_level(T.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/target = get_turf(actual_selected_rune) - if(is_blocked_turf(target, TRUE)) - to_chat(user, "The target rune is blocked. Attempting to teleport to it would be massively unwise.") - fail_invoke() - return - var/movedsomething = FALSE - var/moveuserlater = FALSE - for(var/atom/movable/A in T) - if(A == user) - moveuserlater = TRUE - movedsomething = TRUE - continue - if(!A.anchored) - movedsomething = TRUE - A.forceMove(target) - if(movedsomething) - ..() - visible_message("There is a sharp crack of inrushing air, and everything above the rune disappears!", null, "You hear a sharp crack.") - to_chat(user, "You[moveuserlater ? "r vision blurs, and you suddenly appear somewhere else":" send everything above the rune away"].") - if(moveuserlater) - user.forceMove(target) - target.visible_message("There is a boom of outrushing air as something appears above the rune!", null, "You hear a boom.") - else - fail_invoke() - - //Rite of Offering: Converts or sacrifices a target. /obj/effect/rune/convert cultist_name = "Offer" @@ -392,12 +267,17 @@ structure_check() searches for nearby cultist structures required for the invoca [brutedamage || burndamage ? "even as [convertee.p_their()] wounds heal and close" : "as the markings below [convertee.p_them()] glow a bloody red"]!", \ "AAAAAAAAAAAAAA-") SSticker.mode.add_cultist(convertee.mind, 1) - new /obj/item/tome(get_turf(src)) + new /obj/item/melee/cultblade/dagger(get_turf(src)) convertee.mind.special_role = "Cultist" to_chat(convertee, "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(convertee, "Assist your new compatriots in their dark dealings. Your goal is theirs, and theirs is yours. You serve the Geometer above all else. Bring it back.\ ") + if(ishuman(convertee)) + var/mob/living/carbon/human/H = convertee + H.uncuff() + H.stuttering = 0 + H.cultslurring = 0 return 1 /obj/effect/rune/convert/proc/do_sacrifice(mob/living/sacrificial, list/invokers) @@ -450,9 +330,135 @@ structure_check() searches for nearby cultist structures required for the invoca sacrificial.gib() return TRUE + +/obj/effect/rune/empower + cultist_name = "Empower" + cultist_desc = "allows cultists to prepare greater amounts of blood magic at far less of a cost." + invocation = "H'drak v'loso, mir'kanas verbot!" + icon_state = "3" + color = RUNE_COLOR_TALISMAN + construct_invoke = FALSE + +/obj/effect/rune/empower/invoke(var/list/invokers) + . = ..() + var/mob/living/user = invokers[1] //the first invoker is always the user + for(var/datum/action/innate/cult/blood_magic/BM in user.actions) + BM.Activate() + +/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" + color = RUNE_COLOR_TELEPORT + req_keyword = TRUE + light_power = 4 + var/obj/effect/temp_visual/cult/portal/inner_portal //The portal "hint" for off-station teleportations + var/obj/effect/temp_visual/cult/rune_spawn/rune2/outer_portal + var/listkey + + +/obj/effect/rune/teleport/Initialize(mapload, set_keyword) + . = ..() + var/area/A = get_area(src) + var/locname = initial(A.name) + listkey = set_keyword ? "[set_keyword] [locname]":"[locname]" + GLOB.teleport_runes += src + +/obj/effect/rune/teleport/Destroy() + GLOB.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() + for(var/R in GLOB.teleport_runes) + var/obj/effect/rune/teleport/T = R + if(T != src && !is_away_level(T.z)) + potential_runes[avoid_assoc_duplicate_keys(T.listkey, teleportnames)] = 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 + + var/turf/T = get_turf(src) + if(is_away_level(T.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/target = get_turf(actual_selected_rune) + if(is_blocked_turf(target, TRUE)) + to_chat(user, "The target rune is blocked. Attempting to teleport to it would be massively unwise.") + fail_invoke() + return + var/movedsomething = FALSE + var/moveuserlater = FALSE + for(var/atom/movable/A in T) + if(ishuman(A)) + new /obj/effect/temp_visual/dir_setting/cult/phase/out(T, A.dir) + new /obj/effect/temp_visual/dir_setting/cult/phase(target, A.dir) + if(A == user) + moveuserlater = TRUE + movedsomething = TRUE + continue + if(!A.anchored) + movedsomething = TRUE + A.forceMove(target) + if(movedsomething) + ..() + visible_message("There is a sharp crack of inrushing air, and everything above the rune disappears!", null, "You hear a sharp crack.") + to_chat(user, "You[moveuserlater ? "r vision blurs, and you suddenly appear somewhere else":" send everything above the rune away"].") + if(moveuserlater) + user.forceMove(target) + if(is_mining_level(z) && !is_mining_level(target.z)) //No effect if you stay on lavaland + actual_selected_rune.handle_portal("lava") + else + var/area/A = get_area(T) + if(A.map_name == "Space") + actual_selected_rune.handle_portal("space") + target.visible_message("There is a boom of outrushing air as something appears above the rune!", null, "You hear a boom.") + else + fail_invoke() + +/obj/effect/rune/teleport/proc/handle_portal(portal_type) + var/turf/T = get_turf(src) + if(inner_portal) + qdel(inner_portal) //We need fresh effects/animations + if(outer_portal) + qdel(outer_portal) + playsound(T, pick('sound/effects/sparks1.ogg', 'sound/effects/sparks2.ogg', 'sound/effects/sparks3.ogg', 'sound/effects/sparks4.ogg'), 100, TRUE, 14) + inner_portal = new /obj/effect/temp_visual/cult/portal(T) + if(portal_type == "space") + light_color = RUNE_COLOR_TELEPORT + desc += "
A tear in reality reveals a black void interspersed with dots of light... something recently teleported here from space!" + else + inner_portal.icon_state = "lava" + light_color = LIGHT_COLOR_FIRE + desc += "
A tear in reality reveals a coursing river of lava... something recently teleported here from the Lavaland Mines!" + outer_portal = new(T, 600, color) + light_range = 4 + update_light() + addtimer(CALLBACK(src, .proc/close_portal), 600, TIMER_UNIQUE) + +/obj/effect/rune/teleport/proc/close_portal() + desc = initial(desc) + light_range = 0 + update_light() + //Ritual of Dimensional Rending: Calls forth the avatar of Nar-Sie upon the station. /obj/effect/rune/narsie - cultist_name = "Summon Nar-Sie" + cultist_name = "Nar-Sie" cultist_desc = "tears apart dimensional barriers, calling forth the Geometer. Requires 9 invokers." invocation = "TOK-LYR RQA-NAP G'OLT-ULOFT!!" req_cultists = 9 @@ -473,7 +479,7 @@ structure_check() searches for nearby cultist structures required for the invoca GLOB.poi_list -= src . = ..() -/obj/effect/rune/narsie/talismanhide() //can't hide this, and you wouldn't want to +/obj/effect/rune/narsie/conceal() //can't hide this, and you wouldn't want to return /obj/effect/rune/narsie/invoke(var/list/invokers) @@ -481,12 +487,17 @@ structure_check() searches for nearby cultist structures required for the invoca return if(!is_station_level(z)) return - + var/mob/living/user = invokers[1] + var/datum/antagonist/cult/user_antag = user.mind.has_antag_datum(/datum/antagonist/cult,TRUE) + var/datum/objective/eldergod/summon_objective = locate() in user_antag.cult_team.objectives + var/area/place = get_area(src) + if(!(place in summon_objective.summon_spots)) + to_chat(user, "The Geometer can only be summoned where the veil is weak - in [english_list(summon_objective.summon_spots)]!") + return if(locate(/obj/singularity/narsie) in GLOB.poi_list) for(var/M in invokers) - to_chat(M, "[src] fizzles uselessly, Nar-Sie is already on this plane!") - playsound(src, 'sound/items/welder.ogg', 50, 1) - log_game("Summon Nar-Sie rune at [COORD(src)] failed - already summoned") + to_chat(M, "Nar-Sie is already on this plane!") + log_game("Nar-Sie rune failed - already summoned") return //BEGIN THE SUMMONING used = TRUE @@ -494,20 +505,16 @@ structure_check() searches for nearby cultist structures required for the invoca sound_to_playing_players('sound/effects/dimensional_rend.ogg') var/turf/T = get_turf(src) sleep(40) - if(locate(/obj/singularity/narsie) in GLOB.poi_list) - T.visible_message("A faint fizzle could be heard echoing along with a soft chorus of screams and chanting...") - playsound(T, 'sound/items/welder.ogg', 25, 1) - return if(src) color = RUNE_COLOR_RED new /obj/singularity/narsie/large/cult(T) //Causes Nar-Sie to spawn even if the rune has been removed /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/tome) && iscultist(user))) + if((istype(I, /obj/item/melee/cultblade/dagger) && iscultist(user))) user.visible_message("[user.name] begins erasing [src]...", "You begin erasing [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") + log_game("Summon Narsie rune erased by [user.mind.key] (ckey) with [I.name]") + message_admins("[key_name_admin(user)] erased a Narsie rune with [I.name]") ..() else if(istype(I, /obj/item/nullrod)) //Begone foul magiks. You cannot hinder me. @@ -517,7 +524,7 @@ structure_check() searches for nearby cultist structures required for the invoca //Rite of Resurrection: Requires a dead or inactive cultist. When reviving the dead, you can only perform one revival for every sacrifice your cult has carried out. /obj/effect/rune/raise_dead - cultist_name = "Revive Cultist" + cultist_name = "Revive" cultist_desc = "requires a dead, mindless, or inactive cultist placed upon the rune. Provided there have been sufficient sacrifices, they will be given a new life." invocation = "Pasnar val'keriam usinar. Savrae ines amutan. Yam'toth remium il'tarat!" //Depends on the name of the user - see below icon_state = "1" @@ -545,14 +552,13 @@ structure_check() searches for nearby cultist structures required for the invoca to_chat(user, "There are no dead cultists on the rune!") log_game("Raise Dead rune failed - no cultists to revive") fail_invoke() - rune_in_use = FALSE return if(potential_revive_mobs.len > 1) mob_to_revive = input(user, "Choose a cultist to revive.", "Cultist to Revive") as null|anything in potential_revive_mobs else mob_to_revive = potential_revive_mobs[1] if(QDELETED(src) || !validness_checks(mob_to_revive, user)) - rune_in_use = FALSE + fail_invoke() return if(user.name == "Herbert West") invocation = "To life, to life, I bring them!" @@ -563,12 +569,11 @@ structure_check() searches for nearby cultist structures required for the invoca if(LAZYLEN(GLOB.sacrificed) <= revives_used) to_chat(user, "Your cult must carry out another sacrifice before it can revive a cultist!") fail_invoke() - rune_in_use = FALSE return revives_used++ mob_to_revive.revive(1, 1) //This does remove traits and such, but the rune might actually see some use because of it! mob_to_revive.grab_ghost() - else if(!mob_to_revive.client || mob_to_revive.client.is_afk()) + if(!mob_to_revive.client || mob_to_revive.client.is_afk()) set waitfor = FALSE var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as a [mob_to_revive.name], an inactive blood cultist?", ROLE_CULTIST, null, ROLE_CULTIST, 50, mob_to_revive) var/mob/dead/observer/theghost = null @@ -578,6 +583,10 @@ structure_check() searches for nearby cultist structures required for the invoca message_admins("[key_name_admin(theghost)] has taken control of ([key_name_admin(mob_to_revive)]) to replace an AFK player.") mob_to_revive.ghostize(0) mob_to_revive.key = theghost.key + else + fail_invoke() + return + SEND_SOUND(mob_to_revive, 'sound/ambience/antag/bloodcult.ogg') 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 [mob_to_revive.p_their()] eyes.", \ "You awaken suddenly from the void. You're alive!") @@ -590,140 +599,29 @@ structure_check() searches for nearby cultist structures required for the invoca if(!Adjacent(user) || user.incapacitated()) return FALSE if(QDELETED(target_mob)) - fail_invoke() return FALSE if(!(target_mob in T.contents)) to_chat(user, "The cultist to revive has been moved!") - fail_invoke() log_game("Raise Dead rune failed - revival target moved") return FALSE - var/mob/dead/observer/ghost = target_mob.get_ghost(TRUE) - if(!ghost && (!target_mob.mind || !target_mob.mind.active)) - to_chat(user, "The corpse to revive has no spirit!") - fail_invoke() - log_game("Raise Dead rune failed - revival target has no ghost") - return FALSE - if(!GLOB.sacrificed.len || GLOB.sacrificed.len <= revives_used) - to_chat(user, "You have sacrificed too few people to revive a cultist!") - fail_invoke() - log_game("Raise Dead rune failed - too few sacrificed") - return FALSE return TRUE /obj/effect/rune/raise_dead/fail_invoke() ..() + rune_in_use = FALSE for(var/mob/living/M in range(1,src)) if(iscultist(M) && M.stat == DEAD) M.visible_message("[M] twitches.") - -//Rite of Disruption: Emits an EMP blast. -/obj/effect/rune/emp - cultist_name = "Electromagnetic 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 = TRUE - color = RUNE_COLOR_EMP - -/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/magic/disable_tech.ogg', 50, 1) - for(var/M in invokers) - to_chat(M, "Your hair stands on end as a shockwave emanates from the rune!") - if(7 to INFINITY) - playsound(E, 'sound/magic/disable_tech.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.Knockdown(40) - 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 Spirit Sight: Separates one's spirit from their body. They will take damage while it is active. -/obj/effect/rune/spirit - cultist_name = "Spirit Sight" - 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 = "7" - color = RUNE_COLOR_DARKRED - rune_in_use = FALSE //One at a time, please! - construct_invoke = FALSE - var/mob/living/affecting = null - -/obj/effect/rune/spirit/Destroy() - affecting = null - return ..() - -/obj/effect/rune/spirit/examine(mob/user) - ..() - if(affecting) - to_chat(user, "A translucent field encases [affecting] above the rune!") - -/obj/effect/rune/spirit/can_invoke(mob/living/user) - if(rune_in_use) - to_chat(user, "[src] cannot support more than one body!") - log_game("Spirit Sight rune failed - more than one user") - return list() - var/turf/T = get_turf(src) - if(!(user in T)) - to_chat(user, "You must be standing on top of [src]!") - log_game("Spirit Sight rune failed - user not standing on rune") - return list() - return ..() - -/obj/effect/rune/spirit/invoke(var/list/invokers) - var/mob/living/user = invokers[1] - ..() - var/turf/T = get_turf(src) - rune_in_use = TRUE - affecting = user - affecting.add_atom_colour(RUNE_COLOR_DARKRED, ADMIN_COLOUR_PRIORITY) - affecting.visible_message("[affecting] 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...") - affecting.ghostize(1) - while(!QDELETED(affecting)) - affecting.apply_damage(0.1, BRUTE) - if(!(affecting in T)) - user.visible_message("A spectral tendril wraps around [affecting] and pulls [affecting.p_them()] back to the rune!") - Beam(affecting, icon_state="drainbeam", time=2) - affecting.forceMove(get_turf(src)) //NO ESCAPE :^) - if(affecting.key) - affecting.visible_message("[affecting] slowly relaxes, the glow around [affecting.p_them()] dimming.", \ - "You are re-united with your physical form. [src] releases its hold over you.") - affecting.remove_atom_colour(ADMIN_COLOUR_PRIORITY, RUNE_COLOR_DARKRED) - affecting.Knockdown(60) - break - if(affecting.stat == UNCONSCIOUS) - if(prob(1)) - var/mob/dead/observer/G = affecting.get_ghost() - to_chat(G, "You feel the link between you and your body weakening... you must hurry!") - else if(affecting.stat == DEAD) - affecting.remove_atom_colour(ADMIN_COLOUR_PRIORITY, RUNE_COLOR_DARKRED) - var/mob/dead/observer/G = affecting.get_ghost() - to_chat(G, "You suddenly feel your physical form pass on. [src]'s exertion has killed you!") - break - sleep(1) - affecting = null - rune_in_use = FALSE - //Rite of the Corporeal Shield: When invoked, becomes solid and cannot be passed. Invoke again to undo. /obj/effect/rune/wall - cultist_name = "Form Barrier" + cultist_name = "Barrier" cultist_desc = "when invoked, makes a temporary invisible wall to block passage. Can be invoked again to reverse this." invocation = "Khari'd! Eske'te tannin!" - icon_state = "1" - color = RUNE_COLOR_MEDIUMRED + icon_state = "4" + color = RUNE_COLOR_DARKRED CanAtmosPass = ATMOS_PASS_DENSITY - var/density_timer + var/datum/timedevent/density_timer var/recharging = FALSE /obj/effect/rune/wall/Initialize(mapload, set_keyword) @@ -732,8 +630,10 @@ structure_check() searches for nearby cultist structures required for the invoca /obj/effect/rune/wall/examine(mob/user) ..() - if(density) - to_chat(user, "There is a barely perceptible shimmering of the air above [src].") + if(density && iscultist(user)) + var/datum/timedevent/TMR = active_timers[1] + if(TMR) + to_chat(user, "The air above this rune has hardened into a barrier that will last [DisplayTimeText(TMR.timeToRun - world.time)].") /obj/effect/rune/wall/Destroy() density = FALSE @@ -767,7 +667,7 @@ structure_check() searches for nearby cultist structures required for the invoca W.density = TRUE W.update_state() W.spread_density() - density_timer = addtimer(CALLBACK(src, .proc/lose_density), 900, TIMER_STOPPABLE) + density_timer = addtimer(CALLBACK(src, .proc/lose_density), 3000, TIMER_STOPPABLE) /obj/effect/rune/wall/proc/lose_density() if(density) @@ -804,7 +704,7 @@ structure_check() searches for nearby cultist structures required for the invoca invocation = "N'ath reth sh'yro eth d'rekkathnor!" req_cultists = 2 invoke_damage = 10 - icon_state = "5" + icon_state = "3" color = RUNE_COLOR_SUMMON /obj/effect/rune/summon/invoke(var/list/invokers) @@ -849,7 +749,7 @@ structure_check() searches for nearby cultist structures required for the invoca cultist_desc = "boils the blood of non-believers who can see the rune, rapidly dealing extreme amounts of damage. Requires 3 invokers." invocation = "Dedo ol'btoh!" icon_state = "4" - color = RUNE_COLOR_MEDIUMRED + color = RUNE_COLOR_BURNTORANGE light_color = LIGHT_COLOR_LAVA req_cultists = 3 invoke_damage = 10 @@ -909,19 +809,20 @@ structure_check() searches for nearby cultist structures required for the invoca //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 = "Manifest Spirit" - cultist_desc = "manifests a spirit as a servant of the Geometer. The invoker must not move from atop the rune, and will take damage for each summoned spirit." + cultist_name = "Spirit Realm" + cultist_desc = "manifests a spirit servant of the Geometer and allows you to ascend as a spirit yourself. 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" + icon_state = "7" invoke_damage = 10 construct_invoke = FALSE - color = RUNE_COLOR_MEDIUMRED - var/ghost_limit = 5 + color = RUNE_COLOR_DARKRED + var/mob/living/affecting = null + var/ghost_limit = 4 var/ghosts = 0 /obj/effect/rune/manifest/Initialize() . = ..() - 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))) @@ -934,60 +835,91 @@ structure_check() searches for nearby cultist structures required for the invoca fail_invoke() log_game("Manifest rune failed - user is a ghost") return list() - if(ghosts >= ghost_limit) - to_chat(user, "You are sustaining too many ghosts to summon more!") - fail_invoke() - log_game("Manifest rune failed - too many summoned ghosts") - 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/cult_ghost/new_human = new(get_turf(src)) - new_human.real_name = ghost_to_spawn.real_name - new_human.alpha = 150 //Makes them translucent - new_human.equipOutfit(/datum/outfit/ghost_cultist) //give them armor - new_human.apply_status_effect(STATUS_EFFECT_SUMMONEDGHOST) //ghosts can't summon more ghosts - ..() - ghosts++ - playsound(src, 'sound/magic/exit_blood.ogg', 50, 1) - visible_message("A cloud of red mist forms above [src], and from within steps... a [new_human.gender == FEMALE ? "wo":""]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/turf/T = get_turf(src) - var/obj/structure/emergency_shield/invoker/N = new(T) + var/choice = alert(user,"You tear open a connection to the spirit realm...",,"Summon a Cult Ghost","Ascend as a Dark Spirit","Cancel") + if(choice == "Summon a Cult Ghost") + notify_ghosts("Manifest rune invoked in [get_area(src)].", 'sound/effects/ghost2.ogg', source = src) + 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() + var/mob/dead/observer/ghost_to_spawn = pick(ghosts_on_rune) + var/mob/living/carbon/human/cult_ghost/new_human = new(get_turf(src)) + new_human.real_name = ghost_to_spawn.real_name + new_human.alpha = 150 //Makes them translucent + new_human.equipOutfit(/datum/outfit/ghost_cultist) //give them armor + new_human.apply_status_effect(STATUS_EFFECT_SUMMONEDGHOST) //ghosts can't summon more ghosts + new_human.see_invisible = SEE_INVISIBLE_OBSERVER + ghosts++ + if(ghosts >= ghost_limit) + to_chat(user, "You are sustaining too many ghosts to summon more!") + fail_invoke() + log_game("Manifest rune failed - too many summoned ghosts") + return list() + playsound(src, 'sound/magic/exit_blood.ogg', 50, 1) + visible_message("A cloud of red mist forms above [src], and from within steps... a [new_human.gender == FEMALE ? "wo":""]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/structure/emergency_shield/invoker/N = new(T) + new_human.key = ghost_to_spawn.key + SSticker.mode.add_cultist(new_human.mind, 0) + to_chat(new_human, "You are a servant of the Geometer. You have been made semi-corporeal by the cult of Nar-Sie, and you are to serve them at all costs.") - new_human.key = ghost_to_spawn.key - SSticker.mode.add_cultist(new_human.mind, 0) - to_chat(new_human, "You are a servant of the Geometer. You have been made semi-corporeal by the cult of Nar-Sie, and you are to serve them at all costs.") + while(!QDELETED(src) && !QDELETED(user) && !QDELETED(new_human) && (user in T)) + if(user.stat || new_human.InCritical()) + break + user.apply_damage(0.1, BRUTE) + sleep(1) - while(!QDELETED(src) && !QDELETED(user) && !QDELETED(new_human) && (user in T)) - if(user.stat || new_human.InCritical()) - break - user.apply_damage(0.1, BRUTE) - sleep(1) - - qdel(N) - ghosts-- - 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.dropItemToGround(I, TRUE) - new_human.dust() + qdel(N) + ghosts-- + 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.dropItemToGround(I, TRUE) + new_human.dust() + else if(choice == "Ascend as a Dark Spirit") + affecting = user + affecting.add_atom_colour(RUNE_COLOR_DARKRED, ADMIN_COLOUR_PRIORITY) + affecting.visible_message("[affecting] freezes statue-still, glowing an unearthly red.", \ + "You see what lies beyond. All is revealed. In this form you find that your voice booms louder and you can mark targets for the entire cult") + var/mob/dead/observer/G = affecting.ghostize(1) + var/datum/action/innate/cult/comm/spirit/CM = new + var/datum/action/innate/cult/ghostmark/GM = new + G.name = "Dark Spirit of [G.name]" + G.color = "red" + CM.Grant(G) + GM.Grant(G) + while(!QDELETED(affecting)) + if(!(affecting in T)) + user.visible_message("A spectral tendril wraps around [affecting] and pulls [affecting.p_them()] back to the rune!") + Beam(affecting, icon_state="drainbeam", time=2) + affecting.forceMove(get_turf(src)) //NO ESCAPE :^) + if(affecting.key) + affecting.visible_message("[affecting] slowly relaxes, the glow around [affecting.p_them()] dimming.", \ + "You are re-united with your physical form. [src] releases its hold over you.") + affecting.Knockdown(40) + break + if(affecting.health <= 10) + to_chat(G, "Your body can no longer sustain the connection!") + break + sleep(5) + CM.Remove(G) + GM.Remove(G) + affecting.remove_atom_colour(ADMIN_COLOUR_PRIORITY, RUNE_COLOR_DARKRED) + affecting.grab_ghost() + affecting = null + rune_in_use = FALSE /mob/living/carbon/human/cult_ghost/spill_organs(no_brain, no_organs, no_bodyparts) //cult ghosts never drop a brain no_brain = TRUE @@ -997,3 +929,149 @@ structure_check() searches for nearby cultist structures required for the invoca . = ..() for(var/obj/item/organ/brain/B in .) //they're not that smart, really . -= B + + +/obj/effect/rune/apocalypse + cultist_name = "Apocalypse" + cultist_desc = "a harbinger of the end times. Grows in strength with the cult's desperation - but at the risk of... side effects." + invocation = "Ta'gh fara'qha fel d'amar det!" + icon = 'icons/effects/96x96.dmi' + icon_state = "apoc" + pixel_x = -32 + pixel_y = -32 + allow_excess_invokers = TRUE + color = RUNE_COLOR_DARKRED + req_cultists = 3 + scribe_delay = 100 + +/obj/effect/rune/apocalypse/invoke(var/list/invokers) + if(rune_in_use) + return + . = ..() + var/area/place = get_area(src) + var/mob/living/user = invokers[1] + var/datum/antagonist/cult/user_antag = user.mind.has_antag_datum(/datum/antagonist/cult,TRUE) + var/datum/objective/eldergod/summon_objective = locate() in user_antag.cult_team.objectives + if(summon_objective.summon_spots.len <= 1) + to_chat(user, "Only one ritual site remains - it must be reserved for the final summoning!") + return + if(!(place in summon_objective.summon_spots)) + to_chat(user, "The Apocalypse rune will remove a ritual site, where Nar-sie can be summoned, it can only be scribed in [english_list(summon_objective.summon_spots)]!") + return + summon_objective.summon_spots -= place + rune_in_use = TRUE + var/turf/T = get_turf(src) + new /obj/effect/temp_visual/dir_setting/curse/grasp_portal/fading(T) + var/intensity = 0 + for(var/mob/living/M in GLOB.player_list) + if(iscultist(M)) + intensity++ + intensity = max(60, 360 - (360*(intensity/GLOB.player_list.len + 0.3)**2)) //significantly lower intensity for "winning" cults + var/duration = intensity*10 + playsound(T, 'sound/magic/enter_blood.ogg', 100, 1) + visible_message("A colossal shockwave of energy bursts from the rune, disintegrating it in the process!") + for(var/mob/living/L in range(src, 3)) + L.Knockdown(30) + empulse(T, 0.42*(intensity), 1) + var/list/images = list() + var/zmatch = T.z + var/datum/atom_hud/AH = GLOB.huds[DATA_HUD_SECURITY_ADVANCED] + for(var/mob/living/M in GLOB.alive_mob_list) + if(M.z != zmatch) + continue + if(ishuman(M)) + if(!iscultist(M)) + AH.remove_hud_from(M) + addtimer(CALLBACK(GLOBAL_PROC, .proc/hudFix, M), duration) + var/image/A = image('icons/mob/mob.dmi',M,"cultist", ABOVE_MOB_LAYER) + A.override = 1 + add_alt_appearance(/datum/atom_hud/alternate_appearance/basic/noncult, "human_apoc", A, FALSE) + addtimer(CALLBACK(M,/atom/.proc/remove_alt_appearance,"human_apoc",TRUE), duration) + images += A + SEND_SOUND(M, pick(sound('sound/ambience/antag/bloodcult.ogg'),sound('sound/spookoween/ghost_whisper.ogg'),sound('sound/spookoween/ghosty_wind.ogg'))) + else + var/construct = pick("floater","artificer","behemoth") + var/image/B = image('icons/mob/mob.dmi',M,construct, ABOVE_MOB_LAYER) + B.override = 1 + add_alt_appearance(/datum/atom_hud/alternate_appearance/basic/noncult, "mob_apoc", B, FALSE) + addtimer(CALLBACK(M,/atom/.proc/remove_alt_appearance,"mob_apoc",TRUE), duration) + images += B + if(!iscultist(M)) + if(M.client) + var/image/C = image('icons/effects/cult_effects.dmi',M,"bloodsparkles", ABOVE_MOB_LAYER) + add_alt_appearance(/datum/atom_hud/alternate_appearance/basic/cult, "cult_apoc", C, FALSE) + addtimer(CALLBACK(M,/atom/.proc/remove_alt_appearance,"cult_apoc",TRUE), duration) + images += C + else + to_chat(M, "An Apocalypse Rune was invoked in the [place.name], it is no longer available as a summoning site!") + SEND_SOUND(M, 'sound/effects/pope_entry.ogg') + image_handler(images, duration) + if(intensity>=285) // Based on the prior formula, this means the cult makes up <15% of current players + var/outcome = rand(1,100) + switch(outcome) + if(1 to 10) + var/datum/round_event_control/disease_outbreak/D = new() + var/datum/round_event_control/mice_migration/M = new() + D.runEvent() + M.runEvent() + if(11 to 20) + var/datum/round_event_control/radiation_storm/RS = new() + RS.runEvent() + if(21 to 30) + var/datum/round_event_control/brand_intelligence/BI = new() + BI.runEvent() + if(31 to 40) + var/datum/round_event_control/immovable_rod/R = new() + R.runEvent() + R.runEvent() + R.runEvent() + if(41 to 50) + var/datum/round_event_control/meteor_wave/MW = new() + MW.runEvent() + if(51 to 60) + var/datum/round_event_control/spider_infestation/SI = new() + SI.runEvent() + if(61 to 70) + var/datum/round_event_control/anomaly/anomaly_flux/AF + var/datum/round_event_control/anomaly/anomaly_grav/AG + var/datum/round_event_control/anomaly/anomaly_pyro/AP + var/datum/round_event_control/anomaly/anomaly_vortex/AV + AF.runEvent() + AG.runEvent() + AP.runEvent() + AV.runEvent() + if(71 to 80) + var/datum/round_event_control/spacevine/SV = new() + var/datum/round_event_control/grey_tide/GT = new() + SV.runEvent() + GT.runEvent() + if(81 to 100) + var/datum/round_event_control/portal_storm_narsie/N = new() + N.runEvent() + qdel(src) + +/obj/effect/rune/apocalypse/proc/image_handler(var/list/images, duration) + var/end = world.time + duration + set waitfor = 0 + while(end>world.time) + for(var/image/I in images) + I.override = FALSE + animate(I, alpha = 0, time = 25, flags = ANIMATION_PARALLEL) + sleep(35) + for(var/image/I in images) + animate(I, alpha = 255, time = 25, flags = ANIMATION_PARALLEL) + sleep(25) + for(var/image/I in images) + if(I.icon_state != "bloodsparkles") + I.override = TRUE + sleep(190) + + + +/proc/hudFix(mob/living/carbon/human/target) + if(!target || !target.client) + return + var/obj/O = target.get_item_by_slot(slot_glasses) + if(istype(O, /obj/item/clothing/glasses/hud/security)) + var/datum/atom_hud/AH = GLOB.huds[DATA_HUD_SECURITY_ADVANCED] + AH.add_hud_to(target) \ No newline at end of file diff --git a/code/modules/antagonists/cult/supply.dm b/code/modules/antagonists/cult/supply.dm deleted file mode 100644 index 3720e496ea8..00000000000 --- a/code/modules/antagonists/cult/supply.dm +++ /dev/null @@ -1,123 +0,0 @@ -//Supply Talisman: Has a few unique effects. Granted only to starter cultists. -/obj/item/paper/talisman/supply - cultist_name = "Supply Talisman" - cultist_desc = "A multi-use talisman that can create various objects. Intended to increase the cult's strength early on." - invocation = null - uses = 3 - var/list/possible_summons = list( - /datum/cult_supply/tome, - /datum/cult_supply/metal, - /datum/cult_supply/talisman/teleport, - /datum/cult_supply/talisman/emp, - /datum/cult_supply/talisman/stun, - /datum/cult_supply/talisman/veil, - /datum/cult_supply/soulstone, - /datum/cult_supply/construct_shell - ) - -/obj/item/paper/talisman/supply/invoke(mob/living/user, successfuluse = 1) - var/list/dat = list() - dat += "There are [uses] bloody runes on the parchment.
" - dat += "Please choose the chant to be imbued into the fabric of reality.
" - dat += "
" - for(var/s in possible_summons) - var/datum/cult_supply/S = s - dat += "[initial(S.invocation)] - [initial(S.desc)]
" - var/datum/browser/popup = new(user, "talisman", "", 400, 400) - popup.set_content(dat.Join("")) - popup.open() - return 0 - -/obj/item/paper/talisman/supply/Topic(href, href_list) - if(QDELETED(src) || usr.incapacitated() || !in_range(src, usr)) - return - - var/id = href_list["id"] - var/datum/cult_supply/match - - for(var/s in possible_summons) - var/datum/cult_supply/S = s - if(initial(S.id) == id) - match = S - break - - if(!match) - to_chat(usr, "The fabric of reality quivers in agony.") - return - - var/turf/T = get_turf(src) - var/summon_type = initial(match.summon_type) - - - var/atom/movable/AM = new summon_type(T) - if(istype(AM, /obj/item)) - usr.put_in_hands(AM) - - uses-- - if(uses <= 0) - to_chat(usr, "[src] crumbles to dust.") - burn() - -/obj/item/paper/talisman/supply/weak - cultist_name = "Lesser Supply Talisman" - uses = 2 - -/obj/item/paper/talisman/supply/weak/Initialize(mapload) - . = ..() - // no runed metal from lesser talismans. - possible_summons -= /datum/cult_supply/metal - -/datum/cult_supply - var/id = "used_popcorn" - var/invocation = "Pla'ceho'lder." - var/desc = "Summons a generic supply item, to aid the cult." - var/summon_type = /obj/item/trash/popcorn // wait this isn't useful - -/datum/cult_supply/tome - id = "arcane_tome" - invocation = "N'ath reth sh'yro eth d'raggathnor!" - desc = "Summons an arcane tome, used to scribe runes." - summon_type = /obj/item/tome - -/datum/cult_supply/metal - id = "runed_metal" - invocation = "Bar'tea eas!" - desc = "Provides 5 runed metal, which can build a variety of cult structures." - summon_type = /obj/item/stack/sheet/runed_metal/five - -/datum/cult_supply/talisman/teleport - id = "teleport_talisman" - invocation = "Sas'so c'arta forbici!" - desc = "Allows you to move to a selected teleportation rune." - summon_type = /obj/item/paper/talisman/teleport - -/datum/cult_supply/talisman/emp - id = "emp_talisman" - invocation = "Ta'gh fara'qha fel d'amar det!" - desc = "Allows you to destroy technology in a short range." - summon_type = /obj/item/paper/talisman/emp - -/datum/cult_supply/talisman/stun - id = "stun_talisman" - invocation = "Fuu ma'jin!" - desc = "Allows you to stun a person by attacking them with the talisman. Does not work on people holding a holy weapon!" - summon_type = /obj/item/paper/talisman/stun - -/datum/cult_supply/talisman/veil - id = "veil_talisman" - invocation = "Kla'atu barada nikt'o!" - desc = "Two use talisman, first use makes all nearby runes invisible, secnd use reveals nearby hidden runes." - summon_type = /obj/item/paper/talisman/true_sight - -/datum/cult_supply/soulstone - id = "soulstone" - invocation = "Kal'om neth!" - desc = "Summons a soul stone, used to capture the spirits of dead or dying humans." - summon_type = /obj/item/device/soulstone - -/datum/cult_supply/construct_shell - id = "construct_shell" - invocation = "Daa'ig osk!" - desc = "Summons a construct shell for use with soulstone-captured souls. It is too large to carry on your person." - summon_type = /obj/structure/constructshell - diff --git a/code/modules/antagonists/cult/talisman.dm b/code/modules/antagonists/cult/talisman.dm deleted file mode 100644 index 588b45d5f68..00000000000 --- a/code/modules/antagonists/cult/talisman.dm +++ /dev/null @@ -1,346 +0,0 @@ -/obj/item/paper/talisman - var/cultist_name = "talisman" - var/cultist_desc = "A basic talisman. It serves no purpose." - var/invocation = "Naise meam!" - var/uses = 1 - var/health_cost = 0 //The amount of health taken from the user when invoking the talisman - var/creation_time = 100 //how long it takes an imbue rune to make this type of talisman - -/obj/item/paper/talisman/examine(mob/user) - if(iscultist(user) || user.stat == DEAD) - to_chat(user, "Name: [cultist_name]") - to_chat(user, "Effect: [cultist_desc]") - to_chat(user, "Uses Remaining: [uses]") - else - to_chat(user, "There are indecipherable images scrawled on the paper in what looks to be... blood?") - -/obj/item/paper/talisman/attack_self(mob/living/user) - if(!iscultist(user)) - to_chat(user, "There are indecipherable images scrawled on the paper in what looks to be... blood?") - return - if(invoke(user)) - uses-- - if(uses <= 0) - qdel(src) - -/obj/item/paper/talisman/proc/invoke(mob/living/user, successfuluse = 1) - . = successfuluse - if(successfuluse) //if the calling whatever says we succeed, do the fancy stuff - if(invocation) - user.whisper(invocation, language = /datum/language/common) - if(health_cost && iscarbon(user)) - var/mob/living/carbon/C = user - C.apply_damage(health_cost, BRUTE, pick("l_arm", "r_arm")) - -//Malformed Talisman: If something goes wrong. -/obj/item/paper/talisman/malformed - cultist_name = "malformed talisman" - cultist_desc = "A talisman with gibberish scrawlings. No good can come from invoking this." - invocation = "Ra'sha yoka!" - -/obj/item/paper/talisman/malformed/invoke(mob/living/user, successfuluse = 1) - to_chat(user, "You feel a pain in your head. The Geometer is displeased.") - if(iscarbon(user)) - var/mob/living/carbon/C = user - C.apply_damage(10, BRUTE, "head") - -//Rite of Translocation: Same as rune -/obj/item/paper/talisman/teleport - cultist_name = "Talisman of Teleportation" - cultist_desc = "A single-use talisman that will teleport a user to a random rune of the same keyword." - color = RUNE_COLOR_TELEPORT - invocation = "Sas'so c'arta forbici!" - health_cost = 5 - creation_time = 80 - -/obj/item/paper/talisman/teleport/invoke(mob/living/user, successfuluse = 1) - var/list/potential_runes = list() - var/list/teleportnames = list() - for(var/R in GLOB.teleport_runes) - var/obj/effect/rune/teleport/T = R - potential_runes[avoid_assoc_duplicate_keys(T.listkey, teleportnames)] = T - - if(!potential_runes.len) - to_chat(user, "There are no valid runes to teleport to!") - log_game("Teleport talisman failed - no other teleport runes") - return ..(user, 0) - - if(is_away_level(user.z)) - to_chat(user, "You are not in the right dimension!") - log_game("Teleport talisman failed - user in away mission") - return ..(user, 0) - - 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(!src || QDELETED(src) || !user || !user.is_holding(src) || user.incapacitated() || !actual_selected_rune) - return ..(user, 0) - var/turf/target = get_turf(actual_selected_rune) - if(is_blocked_turf(target, TRUE)) - to_chat(user, "The target rune is blocked. Attempting to teleport to it would be massively unwise.") - return ..(user, 0) - user.visible_message("Dust flows from [user]'s hand, and [user.p_they()] disappear[user.p_s()] with a sharp crack!", \ - "You speak the words of the talisman and find yourself somewhere else!", "You hear a sharp crack.") - user.forceMove(target) - target.visible_message("There is a boom of outrushing air as something appears above the rune!", null, "You hear a boom.") - return ..() - - -/obj/item/paper/talisman/summon_tome - cultist_name = "Talisman of Tome Summoning" - cultist_desc = "A one-use talisman that will call an untranslated tome from the archives of the Geometer." - color = "#512727" // red-black - invocation = "N'ath reth sh'yro eth d'raggathnor!" - health_cost = 1 - creation_time = 30 - -/obj/item/paper/talisman/summon_tome/invoke(mob/living/user, successfuluse = 1) - . = ..() - user.visible_message("[user]'s hand glows red for a moment.", \ - "You speak the words of the talisman!") - new /obj/item/tome(get_turf(user)) - user.visible_message("A tome appears at [user]'s feet!", \ - "An arcane tome materializes at your feet.") - -/obj/item/paper/talisman/true_sight - cultist_name = "Talisman of Veiling" - cultist_desc = "A multi-use talisman that hides nearby runes. On its second use, will reveal nearby runes." - color = "#9c9c9c" // grey - invocation = "Kla'atu barada nikt'o!" - health_cost = 1 - creation_time = 30 - uses = 6 - var/revealing = FALSE //if it reveals or not - -/obj/item/paper/talisman/true_sight/invoke(mob/living/user, successfuluse = 1) - . = ..() - if(!revealing) - user.visible_message("Thin grey dust falls from [user]'s hand!", \ - "You speak the words of the talisman, hiding nearby runes.") - invocation = "Nikt'o barada kla'atu!" - revealing = TRUE - for(var/obj/effect/rune/R in range(4,user)) - R.talismanhide() - else - user.visible_message("A flash of light shines from [user]'s hand!", \ - "You speak the words of the talisman, revealing nearby runes.") - for(var/obj/effect/rune/R in range(3,user)) - R.talismanreveal() - -//Rite of Disruption: Weaker than rune -/obj/item/paper/talisman/emp - cultist_name = "Talisman of Electromagnetic Pulse" - cultist_desc = "A talisman that will cause a moderately-sized electromagnetic pulse." - color = "#4d94ff" // light blue - invocation = "Ta'gh fara'qha fel d'amar det!" - health_cost = 5 - -/obj/item/paper/talisman/emp/invoke(mob/living/user, successfuluse = 1) - . = ..() - user.visible_message("[user]'s hand flashes a bright blue!", \ - "You speak the words of the talisman, emitting an EMP blast.") - empulse(src, 4, 8) - - -//Rite of Disorientation: Stuns and inhibit speech on a single target for quite some time -/obj/item/paper/talisman/stun - cultist_name = "Talisman of Stunning" - cultist_desc = "A talisman that will stun and inhibit speech on a single target. To use, attack target directly." - color = "#ff0000" // red - invocation = "Fuu ma'jin!" - health_cost = 10 - -/obj/item/paper/talisman/stun/invoke(mob/living/user, successfuluse = 0) - if(successfuluse) //if we're forced to be successful(we normally aren't) then do the normal stuff - return ..() - if(iscultist(user)) - to_chat(user, "To use this talisman, attack the target directly.") - else - to_chat(user, "There are indecipherable images scrawled on the paper in what looks to be... blood?") - return 0 - -/obj/item/paper/talisman/stun/attack(mob/living/target, mob/living/user, successfuluse = 1) - if(iscultist(user)) - invoke(user, 1) - user.visible_message("[user] holds up [src], which explodes in a flash of red light!", \ - "You stun [target] with the talisman!") - var/obj/item/nullrod/N = locate() in target - if(N) - target.visible_message("[target]'s holy weapon absorbs the talisman's light!", \ - "Your holy weapon absorbs the blinding light!") - else - target.Knockdown(200) - target.flash_act(1,1) - if(issilicon(target)) - var/mob/living/silicon/S = target - S.emp_act(EMP_HEAVY) - else if(iscarbon(target)) - var/mob/living/carbon/C = target - C.silent += 5 - C.stuttering += 15 - C.cultslurring += 15 - C.Jitter(15) - if(is_servant_of_ratvar(target)) - target.adjustBruteLoss(15) - qdel(src) - return - ..() - - -//Rite of Arming: Equips cultist armor on the user, where available -/obj/item/paper/talisman/armor - cultist_name = "Talisman of Arming" - cultist_desc = "A talisman that will equip the invoker with cultist equipment if there is a slot to equip it to." - color = "#33cc33" // green - invocation = "N'ath reth sh'yro eth draggathnor!" - creation_time = 80 - -/obj/item/paper/talisman/armor/invoke(mob/living/user, successfuluse = 1) - . = ..() - user.visible_message("Otherworldly armor suddenly appears on [user]!", \ - "You speak the words of the talisman, arming yourself!") - user.equip_to_slot_or_del(new /obj/item/clothing/head/culthood/alt(user), slot_head) - user.equip_to_slot_or_del(new /obj/item/clothing/suit/cultrobes/alt(user), slot_wear_suit) - user.equip_to_slot_or_del(new /obj/item/clothing/shoes/cult/alt(user), slot_shoes) - user.equip_to_slot_or_del(new /obj/item/storage/backpack/cultpack(user), slot_back) - user.dropItemToGround(src) - user.put_in_hands(new /obj/item/melee/cultblade(user)) - user.put_in_hands(new /obj/item/restraints/legcuffs/bola/cult(user)) - -/obj/item/paper/talisman/armor/attack(mob/living/target, mob/living/user) - if(iscultist(user) && iscultist(target)) - user.temporarilyRemoveItemFromInventory(src) - invoke(target) - qdel(src) - return - ..() - - -//Talisman of Horrors: Breaks the mind of the victim with nightmarish hallucinations -/obj/item/paper/talisman/horror - cultist_name = "Talisman of Horrors" - cultist_desc = "A talisman that will break the mind of the victim with nightmarish hallucinations." - color = "#ffb366" // light orange - invocation = "Lo'Nab Na'Dm!" - creation_time = 80 - -/obj/item/paper/talisman/horror/afterattack(mob/living/target, mob/living/user) - if(iscultist(user) && (get_dist(user, target) < 7)) - if(iscarbon(target)) - to_chat(user, "You disturb [target] with visions of madness!") - var/mob/living/carbon/H = target - H.reagents.add_reagent("mindbreaker", 12) - if(is_servant_of_ratvar(target)) - to_chat(target, "You see a brief but horrible vision of Ratvar, rusted and scrapped, being torn apart.") - target.emote("scream") - target.confused = max(0, target.confused + 3) - target.flash_act() - qdel(src) - -//Talisman of Fabrication: Creates a construct shell out of 25 metal sheets, or converts plasteel into runed metal up to 25 times -/obj/item/paper/talisman/construction - cultist_name = "Talisman of Construction" - cultist_desc = "Use this talisman on at least twenty-five metal sheets to create an empty construct shell" - invocation = "Ethra p'ni dedol!" - color = "#000000" // black - uses = 25 - creation_time = 80 - -/obj/item/paper/talisman/construction/attack_self(mob/living/user) - if(iscultist(user)) - to_chat(user, "To use this talisman, place it upon a stack of metal sheets.") - else - to_chat(user, "There are indecipherable images scrawled on the paper in what looks to be... blood?") - - -/obj/item/paper/talisman/construction/attack(obj/M,mob/living/user) - if(iscultist(user)) - to_chat(user, "This talisman will only work on a stack of metal or plasteel sheets!") - log_game("Construct talisman failed - not a valid target") - else - ..() - -/obj/item/paper/talisman/construction/afterattack(obj/item/stack/sheet/target, mob/user, proximity_flag, click_parameters) - ..() - if(proximity_flag && iscultist(user)) - var/turf/T = get_turf(target) - if(istype(target, /obj/item/stack/sheet/metal)) - if(target.use(25)) - new /obj/structure/constructshell(T) - to_chat(user, "The talisman clings to the metal and twists it into a construct shell!") - SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25)) - invoke(user, 1) - qdel(src) - else - to_chat(user, "You need more metal to produce a construct shell!") - else if(istype(target, /obj/item/stack/sheet/plasteel)) - var/quantity = min(target.amount, uses) - uses -= quantity - new /obj/item/stack/sheet/runed_metal(T,quantity) - target.use(quantity) - to_chat(user, "The talisman clings to the plasteel, transforming it into runed metal!") - SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25)) - invoke(user, 1) - if(uses <= 0) - qdel(src) - else - to_chat(user, "The talisman must be used on metal or plasteel!") - - -//Talisman of Shackling: Applies special cuffs directly from the talisman -/obj/item/paper/talisman/shackle - cultist_name = "Talisman of Shackling" - cultist_desc = "Use this talisman on a victim to handcuff them with dark bindings." - invocation = "In'totum Lig'abis!" - color = "#B27300" // burnt-orange - uses = 6 - -/obj/item/paper/talisman/shackle/invoke(mob/living/user, successfuluse = 0) - if(successfuluse) //if we're forced to be successful(we normally aren't) then do the normal stuff - return ..() - if(iscultist(user)) - to_chat(user, "To use this talisman, attack the target directly.") - else - to_chat(user, "There are indecipherable images scrawled on the paper in what looks to be... blood?") - return 0 - -/obj/item/paper/talisman/shackle/attack(mob/living/carbon/target, mob/living/user) - if(iscultist(user) && istype(target)) - if(target.stat == DEAD) - user.visible_message("This talisman's magic does not affect the dead!") - return - CuffAttack(target, user) - return - ..() - -/obj/item/paper/talisman/shackle/proc/CuffAttack(mob/living/carbon/C, mob/living/user) - if(!C.handcuffed) - invoke(user, 1) - playsound(loc, 'sound/weapons/cablecuff.ogg', 30, 1, -2) - C.visible_message("[user] begins restraining [C] with dark magic!", \ - "[user] begins shaping a dark magic around your wrists!") - if(do_mob(user, C, 30)) - if(!C.handcuffed) - C.handcuffed = new /obj/item/restraints/handcuffs/energy/cult/used(C) - C.update_handcuffed() - to_chat(user, "You shackle [C].") - add_logs(user, C, "handcuffed") - uses-- - else - to_chat(user, "[C] is already bound.") - else - to_chat(user, "You fail to shackle [C].") - else - to_chat(user, "[C] is already bound.") - if(uses <= 0) - qdel(src) - -/obj/item/restraints/handcuffs/energy/cult //For the talisman of shackling - name = "cult shackles" - desc = "Shackles that bind the wrists with sinister magic." - trashtype = /obj/item/restraints/handcuffs/energy/used - flags_1 = DROPDEL_1 - -/obj/item/restraints/handcuffs/energy/cult/used/dropped(mob/user) - user.visible_message("[user]'s shackles shatter in a discharge of dark magic!", \ - "Your [src] shatters in a discharge of dark magic!") - . = ..() diff --git a/code/modules/cargo/packs.dm b/code/modules/cargo/packs.dm index 0d4471fd43e..0b2deb2425d 100644 --- a/code/modules/cargo/packs.dm +++ b/code/modules/cargo/packs.dm @@ -1,1797 +1,1797 @@ -/datum/supply_pack - var/name = "Crate" - var/group = "" - var/hidden = FALSE - var/contraband = FALSE - var/cost = 700 // Minimum cost, or infinite points are possible. - var/access = FALSE - var/access_any = FALSE - var/list/contains = null - var/crate_name = "crate" - var/crate_type = /obj/structure/closet/crate - var/dangerous = FALSE // Should we message admins? - var/special = FALSE //Event/Station Goals/Admin enabled packs - var/special_enabled = FALSE - var/DropPodOnly = FALSE//only usable by the Bluespace Drop Pod via the express cargo console - -/datum/supply_pack/proc/generate(turf/T) - var/obj/structure/closet/crate/C = new crate_type(T) - C.name = crate_name - if(access) - C.req_access = list(access) - if(access_any) - C.req_one_access = access_any - - fill(C) - - return C - -/datum/supply_pack/proc/fill(obj/structure/closet/crate/C) - for(var/item in contains) - new item(C) - - -////////////////////////////////////////////////////////////////////////////// -//////////////////////////// Emergency /////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - -/datum/supply_pack/emergency - group = "Emergency" - -/datum/supply_pack/emergency/spacesuit - name = "Space Suit Crate" - cost = 3000 - access = ACCESS_EVA - contains = list(/obj/item/clothing/suit/space, - /obj/item/clothing/suit/space, - /obj/item/clothing/head/helmet/space, - /obj/item/clothing/head/helmet/space, - /obj/item/clothing/mask/breath, - /obj/item/clothing/mask/breath) - crate_name = "space suit crate" - crate_type = /obj/structure/closet/crate/secure - -/datum/supply_pack/emergency/vehicle - name = "Biker Gang Kit" //TUNNEL SNAKES OWN THIS TOWN - cost = 2000 - contraband = TRUE - contains = list(/obj/vehicle/ridden/atv, - /obj/item/key, - /obj/item/clothing/suit/jacket/leather/overcoat, - /obj/item/clothing/gloves/color/black, - /obj/item/clothing/head/soft, - /obj/item/clothing/mask/bandana/skull)//so you can properly #cargoniabikergang - crate_name = "Biker Kit" - crate_type = /obj/structure/closet/crate/large - -/datum/supply_pack/emergency/equipment - name = "Emergency Equipment" - cost = 3500 - contains = list(/mob/living/simple_animal/bot/floorbot, - /mob/living/simple_animal/bot/floorbot, - /mob/living/simple_animal/bot/medbot, - /mob/living/simple_animal/bot/medbot, - /obj/item/tank/internals/air, - /obj/item/tank/internals/air, - /obj/item/tank/internals/air, - /obj/item/tank/internals/air, - /obj/item/tank/internals/air, - /obj/item/clothing/mask/gas, - /obj/item/clothing/mask/gas, - /obj/item/clothing/mask/gas, - /obj/item/clothing/mask/gas, - /obj/item/clothing/mask/gas) - crate_name = "emergency crate" - crate_type = /obj/structure/closet/crate/internals - -/datum/supply_pack/emergency/internals - name = "Internals Crate" - cost = 1000 - contains = list(/obj/item/clothing/mask/gas, - /obj/item/clothing/mask/gas, - /obj/item/clothing/mask/gas, - /obj/item/clothing/mask/breath, - /obj/item/clothing/mask/breath, - /obj/item/clothing/mask/breath, - /obj/item/tank/internals/emergency_oxygen, - /obj/item/tank/internals/emergency_oxygen, - /obj/item/tank/internals/emergency_oxygen, - /obj/item/tank/internals/air, - /obj/item/tank/internals/air, - /obj/item/tank/internals/air) - crate_name = "internals crate" - crate_type = /obj/structure/closet/crate/internals - -/datum/supply_pack/emergency/firefighting - name = "Firefighting Crate" - cost = 1000 - contains = list(/obj/item/clothing/suit/fire/firefighter, - /obj/item/clothing/suit/fire/firefighter, - /obj/item/clothing/mask/gas, - /obj/item/clothing/mask/gas, - /obj/item/device/flashlight, - /obj/item/device/flashlight, - /obj/item/tank/internals/oxygen/red, - /obj/item/tank/internals/oxygen/red, - /obj/item/extinguisher, - /obj/item/extinguisher, - /obj/item/clothing/head/hardhat/red, - /obj/item/clothing/head/hardhat/red) - crate_name = "firefighting crate" - -/datum/supply_pack/emergency/atmostank - name = "Firefighting Watertank" - cost = 1000 - access = ACCESS_ATMOSPHERICS - contains = list(/obj/item/watertank/atmos) - crate_name = "firefighting watertank crate" - crate_type = /obj/structure/closet/crate/secure - -/datum/supply_pack/emergency/radiation - name = "Radiation Protection Crate" - cost = 1000 - contains = list(/obj/item/clothing/head/radiation, - /obj/item/clothing/head/radiation, - /obj/item/clothing/suit/radiation, - /obj/item/clothing/suit/radiation, - /obj/item/device/geiger_counter, - /obj/item/device/geiger_counter, - /obj/item/reagent_containers/food/drinks/bottle/vodka, - /obj/item/reagent_containers/food/drinks/drinkingglass/shotglass, - /obj/item/reagent_containers/food/drinks/drinkingglass/shotglass) - crate_name = "radiation protection crate" - crate_type = /obj/structure/closet/crate/radiation - -/datum/supply_pack/emergency/weedcontrol - name = "Weed Control Crate" - cost = 1500 - access = ACCESS_HYDROPONICS - contains = list(/obj/item/scythe, - /obj/item/clothing/mask/gas, - /obj/item/grenade/chem_grenade/antiweed, - /obj/item/grenade/chem_grenade/antiweed) - crate_name = "weed control crate" - crate_type = /obj/structure/closet/crate/secure/hydroponics - -/datum/supply_pack/emergency/metalfoam - name = "Metal Foam Grenade Crate" - cost = 1000 - contains = list(/obj/item/storage/box/metalfoam) - crate_name = "metal foam grenade crate" - -/datum/supply_pack/emergency/droneshells - name = "Drone Shell Crate" - cost = 1000 - contains = list(/obj/item/drone_shell, - /obj/item/drone_shell, - /obj/item/drone_shell) - crate_name = "drone shell crate" - -/datum/supply_pack/emergency/specialops - name = "Special Ops Supplies" - hidden = TRUE - cost = 2000 - contains = list(/obj/item/storage/box/emps, - /obj/item/grenade/smokebomb, - /obj/item/grenade/smokebomb, - /obj/item/grenade/smokebomb, - /obj/item/pen/sleepy, - /obj/item/grenade/chem_grenade/incendiary) - crate_name = "emergency crate" - crate_type = /obj/structure/closet/crate/internals - -/datum/supply_pack/emergency/syndicate - name = "NULL_ENTRY" - hidden = TRUE - cost = 20000 - contains = list() - crate_name = "emergency crate" - crate_type = /obj/structure/closet/crate/internals - dangerous = TRUE - -/datum/supply_pack/emergency/syndicate/fill(obj/structure/closet/crate/C) - var/crate_value = 30 - var/list/uplink_items = get_uplink_items(SSticker.mode) - while(crate_value) - var/category = pick(uplink_items) - var/item = pick(uplink_items[category]) - var/datum/uplink_item/I = uplink_items[category][item] - - if(!I.surplus || prob(100 - I.surplus)) - continue - if(crate_value < I.cost) - continue - crate_value -= I.cost - new I.item(C) - -////////////////////////////////////////////////////////////////////////////// -//////////////////////////// Security //////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - -/datum/supply_pack/security - group = "Security" - access = ACCESS_SECURITY - crate_type = /obj/structure/closet/crate/secure/gear - -/datum/supply_pack/security/supplies - name = "Security Supplies Crate" - cost = 1000 - contains = list(/obj/item/storage/box/flashbangs, - /obj/item/storage/box/teargas, - /obj/item/storage/box/flashes, - /obj/item/storage/box/handcuffs) - crate_name = "security supply crate" - -/datum/supply_pack/security/helmets - name = "Helmets Crate" - cost = 1000 - contains = list(/obj/item/clothing/head/helmet/sec, - /obj/item/clothing/head/helmet/sec, - /obj/item/clothing/head/helmet/sec) - crate_name = "helmet crate" - -/datum/supply_pack/security/armor - name = "Armor Crate" - cost = 1000 - contains = list(/obj/item/clothing/suit/armor/vest, - /obj/item/clothing/suit/armor/vest, - /obj/item/clothing/suit/armor/vest) - crate_name = "armor crate" - -/datum/supply_pack/security/baton - name = "Stun Batons Crate" - cost = 1000 - contains = list(/obj/item/melee/baton/loaded, - /obj/item/melee/baton/loaded, - /obj/item/melee/baton/loaded) - crate_name = "stun baton crate" - -/datum/supply_pack/security/wall_flash - name = "Wall-Mounted Flash Crate" - cost = 1000 - contains = list(/obj/item/storage/box/wall_flash, - /obj/item/storage/box/wall_flash, - /obj/item/storage/box/wall_flash, - /obj/item/storage/box/wall_flash) - crate_name = "wall-mounted flash crate" - -/datum/supply_pack/security/laser - name = "Lasers Crate" - cost = 2000 - contains = list(/obj/item/gun/energy/laser, - /obj/item/gun/energy/laser, - /obj/item/gun/energy/laser) - crate_name = "laser crate" - -/datum/supply_pack/security/taser - name = "Taser Crate" - cost = 3000 - contains = list(/obj/item/gun/energy/e_gun/advtaser, - /obj/item/gun/energy/e_gun/advtaser, - /obj/item/gun/energy/e_gun/advtaser) - crate_name = "taser crate" - -/datum/supply_pack/security/disabler - name = "Disabler Crate" - cost = 1500 - contains = list(/obj/item/gun/energy/disabler, - /obj/item/gun/energy/disabler, - /obj/item/gun/energy/disabler) - crate_name = "disabler crate" - -/datum/supply_pack/security/forensics - name = "Forensics Crate" - cost = 2000 - contains = list(/obj/item/device/detective_scanner, - /obj/item/storage/box/evidence, - /obj/item/device/camera, - /obj/item/device/taperecorder, - /obj/item/toy/crayon/white, - /obj/item/clothing/head/fedora/det_hat) - crate_name = "forensics crate" - -/datum/supply_pack/security/armory - access = ACCESS_ARMORY - crate_type = /obj/structure/closet/crate/secure/weapon - -/datum/supply_pack/security/armory/riothelmets - name = "Riot Helmets Crate" - cost = 1500 - contains = list(/obj/item/clothing/head/helmet/riot, - /obj/item/clothing/head/helmet/riot, - /obj/item/clothing/head/helmet/riot) - crate_name = "riot helmets crate" - -/datum/supply_pack/security/armory/riotarmor - name = "Riot Armor Crate" - cost = 1500 - contains = list(/obj/item/clothing/suit/armor/riot, - /obj/item/clothing/suit/armor/riot, - /obj/item/clothing/suit/armor/riot) - crate_name = "riot armor crate" - -/datum/supply_pack/security/armory/riotshields - name = "Riot Shields Crate" - cost = 2000 - contains = list(/obj/item/shield/riot, - /obj/item/shield/riot, - /obj/item/shield/riot) - crate_name = "riot shields crate" - -/datum/supply_pack/security/armory/bulletarmor - name = "Bulletproof Armor Crate" - cost = 1500 - contains = list(/obj/item/clothing/suit/armor/bulletproof, - /obj/item/clothing/suit/armor/bulletproof, - /obj/item/clothing/suit/armor/bulletproof) - crate_name = "bulletproof armor crate" - -/datum/supply_pack/security/armory/swat - name = "SWAT Crate" - cost = 6000 - contains = list(/obj/item/clothing/head/helmet/swat/nanotrasen, - /obj/item/clothing/head/helmet/swat/nanotrasen, - /obj/item/clothing/suit/space/swat, - /obj/item/clothing/suit/space/swat, - /obj/item/clothing/mask/gas/sechailer/swat, - /obj/item/clothing/mask/gas/sechailer/swat, - /obj/item/storage/belt/military/assault, - /obj/item/storage/belt/military/assault, - /obj/item/clothing/gloves/combat, - /obj/item/clothing/gloves/combat) - crate_name = "swat crate" - -/datum/supply_pack/security/armory/combatknives - name = "Combat Knives Crate" - cost = 3000 - contains = list(/obj/item/kitchen/knife/combat, - /obj/item/kitchen/knife/combat, - /obj/item/kitchen/knife/combat) - crate_name = "combat knife crate" - -/datum/supply_pack/security/armory/laserarmor - name = "Reflector Vest Crate" - cost = 2000 - contains = list(/obj/item/clothing/suit/armor/laserproof, - /obj/item/clothing/suit/armor/laserproof) - crate_name = "reflector vest crate" - crate_type = /obj/structure/closet/crate/secure/plasma - -/datum/supply_pack/security/armory/ballistic - name = "Combat Shotguns Crate" - cost = 8000 - contains = list(/obj/item/gun/ballistic/shotgun/automatic/combat, - /obj/item/gun/ballistic/shotgun/automatic/combat, - /obj/item/gun/ballistic/shotgun/automatic/combat, - /obj/item/storage/belt/bandolier, - /obj/item/storage/belt/bandolier, - /obj/item/storage/belt/bandolier) - crate_name = "combat shotguns crate" - -/datum/supply_pack/security/armory/energy - name = "Energy Guns Crate" - cost = 2500 - contains = list(/obj/item/gun/energy/e_gun, - /obj/item/gun/energy/e_gun) - crate_name = "energy gun crate" - crate_type = /obj/structure/closet/crate/secure/plasma - -/datum/supply_pack/security/armory/fire - name = "Incendiary Weapons Crate" - cost = 1500 - access = ACCESS_HEADS - contains = list(/obj/item/flamethrower/full, - /obj/item/tank/internals/plasma, - /obj/item/tank/internals/plasma, - /obj/item/tank/internals/plasma, - /obj/item/grenade/chem_grenade/incendiary, - /obj/item/grenade/chem_grenade/incendiary, - /obj/item/grenade/chem_grenade/incendiary) - crate_name = "incendiary weapons crate" - crate_type = /obj/structure/closet/crate/secure/plasma - dangerous = TRUE - -/datum/supply_pack/security/armory/wt550 - name = "WT-550 Auto Rifle Crate" - cost = 3500 - contains = list(/obj/item/gun/ballistic/automatic/wt550, - /obj/item/gun/ballistic/automatic/wt550) - crate_name = "auto rifle crate" - -/datum/supply_pack/security/armory/wt550ammo - name = "WT-550 Auto Rifle Ammo Crate" - cost = 3000 - contains = list(/obj/item/ammo_box/magazine/wt550m9, - /obj/item/ammo_box/magazine/wt550m9, - /obj/item/ammo_box/magazine/wt550m9, - /obj/item/ammo_box/magazine/wt550m9) - crate_name = "auto rifle ammo crate" - -/datum/supply_pack/security/armory/mindshield - name = "mindshield implants Crate" - cost = 4000 - contains = list(/obj/item/storage/lockbox/loyalty) - crate_name = "mindshield implant crate" - -/datum/supply_pack/security/armory/trackingimp - name = "Tracking Implants Crate" - cost = 2000 - contains = list(/obj/item/storage/box/trackimp) - crate_name = "tracking implant crate" - -/datum/supply_pack/security/armory/chemimp - name = "Chemical Implants Crate" - cost = 2000 - contains = list(/obj/item/storage/box/chemimp) - crate_name = "chemical implant crate" - -/datum/supply_pack/security/armory/exileimp - name = "Exile Implants Crate" - cost = 3000 - contains = list(/obj/item/storage/box/exileimp) - crate_name = "exile implant crate" - -/datum/supply_pack/security/securitybarriers - name = "Security Barriers Crate" - contains = list(/obj/item/grenade/barrier, - /obj/item/grenade/barrier, - /obj/item/grenade/barrier, - /obj/item/grenade/barrier) - cost = 2000 - crate_name = "security barriers crate" - -/datum/supply_pack/security/firingpins - name = "Standard Firing Pins Crate" - cost = 2000 - contains = list(/obj/item/storage/box/firingpins, - /obj/item/storage/box/firingpins) - crate_name = "firing pins crate" - -/datum/supply_pack/security/securityclothes - name = "Security Clothing Crate" - cost = 3000 - contains = list(/obj/item/clothing/under/rank/security/navyblue, - /obj/item/clothing/under/rank/security/navyblue, - /obj/item/clothing/suit/security/officer, - /obj/item/clothing/suit/security/officer, - /obj/item/clothing/head/beret/sec/navyofficer, - /obj/item/clothing/head/beret/sec/navyofficer, - /obj/item/clothing/under/rank/warden/navyblue, - /obj/item/clothing/suit/security/warden, - /obj/item/clothing/head/beret/sec/navywarden, - /obj/item/clothing/under/rank/head_of_security/navyblue, - /obj/item/clothing/suit/security/hos, - /obj/item/clothing/head/beret/sec/navyhos) - crate_name = "security clothing crate" - -/datum/supply_pack/security/justiceinbound - name = "Standard Justice Enforcer Crate" - cost = 6000 //justice comes at a price. An expensive, noisy price. - contraband = TRUE - contains = list(/obj/item/clothing/head/helmet/justice, - /obj/item/clothing/mask/gas/sechailer) - crate_name = "security clothing crate" - -////////////////////////////////////////////////////////////////////////////// -//////////////////////////// Engineering ///////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - -/datum/supply_pack/engineering - group = "Engineering" - crate_type = /obj/structure/closet/crate/engineering - -/datum/supply_pack/engineering/fueltank - name = "Fuel Tank Crate" - cost = 800 - contains = list(/obj/structure/reagent_dispensers/fueltank) - crate_name = "fuel tank crate" - crate_type = /obj/structure/closet/crate/large - -/datum/supply_pack/engineering/oxygen - name = "Oxygen Canister" - cost = 1500 - contains = list(/obj/machinery/portable_atmospherics/canister/oxygen) - crate_name = "oxygen canister crate" - crate_type = /obj/structure/closet/crate/large - -/datum/supply_pack/engineering/nitrogen - name = "Nitrogen Canister" - cost = 2000 - contains = list(/obj/machinery/portable_atmospherics/canister/nitrogen) - crate_name = "nitrogen canister crate" - crate_type = /obj/structure/closet/crate/large - -/datum/supply_pack/engineering/carbon_dio - name = "Carbon Dioxide Canister" - cost = 3000 - contains = list(/obj/machinery/portable_atmospherics/canister/carbon_dioxide) - crate_name = "carbon dioxide canister crate" - crate_type = /obj/structure/closet/crate/large - -/datum/supply_pack/science/nitrous_oxide_canister - name = "Nitrous Oxide Canister" - cost = 3000 - access = ACCESS_ATMOSPHERICS - contains = list(/obj/machinery/portable_atmospherics/canister/nitrous_oxide) - crate_name = "nitrous oxide canister crate" - crate_type = /obj/structure/closet/crate/secure - -/datum/supply_pack/engineering/tools - name = "Toolbox Crate" - contains = list(/obj/item/storage/toolbox/electrical, - /obj/item/storage/toolbox/electrical, - /obj/item/storage/toolbox/mechanical, - /obj/item/storage/toolbox/electrical, - /obj/item/storage/toolbox/mechanical, - /obj/item/storage/toolbox/mechanical) - cost = 1000 - crate_name = "toolbox crate" - -/datum/supply_pack/engineering/powergamermitts - name = "Insulated Gloves Crate" - cost = 2000 //Made of pure-grade bullshittinium - contains = list(/obj/item/clothing/gloves/color/yellow, - /obj/item/clothing/gloves/color/yellow, - /obj/item/clothing/gloves/color/yellow) - crate_name = "insulated gloves crate" - -/datum/supply_pack/engineering/power - name = "Powercell Crate" - cost = 1000 - contains = list(/obj/item/stock_parts/cell/high, - /obj/item/stock_parts/cell/high, - /obj/item/stock_parts/cell/high) - crate_name = "electrical maintenance crate" - crate_type = /obj/structure/closet/crate/engineering/electrical - -/obj/item/stock_parts/cell/inducer_supply - maxcharge = 5000 - charge = 5000 - -/datum/supply_pack/engineering/inducers - name = "NT-75 Electromagnetic Power Inducers Crate" - cost = 2000 - contains = list(/obj/item/inducer/sci {cell_type = /obj/item/stock_parts/cell/inducer_supply; opened = 0}, /obj/item/inducer/sci {cell_type = /obj/item/stock_parts/cell/inducer_supply; opened = 0}) //FALSE doesn't work in modified type paths apparently. - crate_name = "inducer crate" - crate_type = /obj/structure/closet/crate/engineering/electrical - -/datum/supply_pack/engineering/engiequipment - name = "Engineering Gear Crate" - cost = 1300 - contains = list(/obj/item/storage/belt/utility, - /obj/item/storage/belt/utility, - /obj/item/storage/belt/utility, - /obj/item/clothing/suit/hazardvest, - /obj/item/clothing/suit/hazardvest, - /obj/item/clothing/suit/hazardvest, - /obj/item/clothing/head/welding, - /obj/item/clothing/head/welding, - /obj/item/clothing/head/welding, - /obj/item/clothing/head/hardhat, - /obj/item/clothing/head/hardhat, - /obj/item/clothing/head/hardhat, - /obj/item/clothing/glasses/meson/engine, - /obj/item/clothing/glasses/meson/engine) - crate_name = "engineering gear crate" - - -/datum/supply_pack/engineering/shieldgen - name = "Anti-breach Shield Projector Crate" - cost = 2500 - contains = list(/obj/machinery/shieldgen, - /obj/machinery/shieldgen) - crate_name = "anti-breach shield projector crate" - -/datum/supply_pack/engineering/grounding_rods - name = "Grounding Rod Crate" - cost = 1700 - contains = list(/obj/machinery/power/grounding_rod, - /obj/machinery/power/grounding_rod, - /obj/machinery/power/grounding_rod, - /obj/machinery/power/grounding_rod) - crate_name = "grounding rod crate" - crate_type = /obj/structure/closet/crate/engineering/electrical - -/datum/supply_pack/engineering/pacman - name = "P.A.C.M.A.N Generator Crate" - cost = 2500 - contains = list(/obj/machinery/power/port_gen/pacman) - crate_name = "PACMAN generator crate" - crate_type = /obj/structure/closet/crate/engineering/electrical - -/datum/supply_pack/engineering/solar - name = "Solar Panel Crate" - cost = 2000 - contains = list(/obj/item/solar_assembly, - /obj/item/solar_assembly, - /obj/item/solar_assembly, - /obj/item/solar_assembly, - /obj/item/solar_assembly, - /obj/item/solar_assembly, - /obj/item/solar_assembly, - /obj/item/solar_assembly, - /obj/item/solar_assembly, - /obj/item/solar_assembly, - /obj/item/solar_assembly, - /obj/item/solar_assembly, - /obj/item/solar_assembly, - /obj/item/solar_assembly, - /obj/item/solar_assembly, - /obj/item/solar_assembly, - /obj/item/solar_assembly, - /obj/item/solar_assembly, - /obj/item/solar_assembly, - /obj/item/solar_assembly, - /obj/item/solar_assembly, - /obj/item/circuitboard/computer/solar_control, - /obj/item/electronics/tracker, - /obj/item/paper/guides/jobs/engi/solars) - crate_name = "solar panel crate" - crate_type = /obj/structure/closet/crate/engineering/electrical - -/datum/supply_pack/engineering/engine - name = "Emitter Crate" - cost = 1500 - access = ACCESS_CE - contains = list(/obj/machinery/power/emitter, - /obj/machinery/power/emitter) - crate_name = "emitter crate" - crate_type = /obj/structure/closet/crate/secure/engineering - dangerous = TRUE - -/datum/supply_pack/engineering/engine/field_gen - name = "Field Generator Crate" - cost = 1500 - contains = list(/obj/machinery/field/generator, - /obj/machinery/field/generator) - crate_name = "field generator crate" - -/datum/supply_pack/engineering/engine/sing_gen - name = "Singularity Generator Crate" - cost = 5000 - contains = list(/obj/machinery/the_singularitygen) - crate_name = "singularity generator crate" - -/datum/supply_pack/engineering/engine/tesla_gen - name = "Tesla Generator Crate" - cost = 5000 - contains = list(/obj/machinery/the_singularitygen/tesla) - crate_name = "tesla generator crate" - -/datum/supply_pack/engineering/engine/collector - name = "Collector Crate" - cost = 2500 - contains = list(/obj/machinery/power/rad_collector, - /obj/machinery/power/rad_collector, - /obj/machinery/power/rad_collector) - crate_name = "collector crate" - -/datum/supply_pack/engineering/engine/PA - name = "Particle Accelerator Crate" - cost = 3000 - contains = list(/obj/structure/particle_accelerator/fuel_chamber, - /obj/machinery/particle_accelerator/control_box, - /obj/structure/particle_accelerator/particle_emitter/center, - /obj/structure/particle_accelerator/particle_emitter/left, - /obj/structure/particle_accelerator/particle_emitter/right, - /obj/structure/particle_accelerator/power_box, - /obj/structure/particle_accelerator/end_cap) - crate_name = "particle accelerator crate" - -/datum/supply_pack/engineering/engine/supermatter_shard - name = "Supermatter Shard Crate" - cost = 10000 - access = ACCESS_CE - contains = list(/obj/machinery/power/supermatter_shard) - crate_name = "supermatter shard crate" - crate_type = /obj/structure/closet/crate/secure/engineering - dangerous = TRUE - -/datum/supply_pack/engineering/engine/am_shielding - name = "Antimatter Shielding Crate" - cost = 2000 - contains = list(/obj/item/device/am_shielding_container, - /obj/item/device/am_shielding_container, - /obj/item/device/am_shielding_container, - /obj/item/device/am_shielding_container, - /obj/item/device/am_shielding_container, - /obj/item/device/am_shielding_container, - /obj/item/device/am_shielding_container, - /obj/item/device/am_shielding_container, - /obj/item/device/am_shielding_container, - /obj/item/device/am_shielding_container)//10 shields: 3x3 containment and a core - crate_name = "antimatter shielding crate" - -/datum/supply_pack/engineering/engine/am_core - name = "Antimatter Control Crate" - cost = 5000 - contains = list(/obj/machinery/power/am_control_unit) - crate_name = "antimatter control crate" - -/datum/supply_pack/engineering/engine/am_jar - name = "Antimatter Containment Jar Crate" - cost = 2000 - contains = list(/obj/item/am_containment, - /obj/item/am_containment) - crate_name = "antimatter jar crate" - -/datum/supply_pack/engineering/shuttle_engine - name = "Shuttle Engine Crate" - cost = 5000 - access = ACCESS_CE - contains = list(/obj/structure/shuttle/engine/propulsion/burst/cargo) - crate_name = "shuttle engine crate" - crate_type = /obj/structure/closet/crate/secure/engineering - special = TRUE - -////////////////////////////////////////////////////////////////////////////// -//////////////////////////// Medical ///////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - -/datum/supply_pack/medical - group = "Medical" - crate_type = /obj/structure/closet/crate/medical - -/datum/supply_pack/medical/supplies - name = "Medical Supplies Crate" - cost = 2000 - contains = list(/obj/item/reagent_containers/glass/bottle/charcoal, - /obj/item/reagent_containers/glass/bottle/charcoal, - /obj/item/reagent_containers/glass/bottle/epinephrine, - /obj/item/reagent_containers/glass/bottle/epinephrine, - /obj/item/reagent_containers/glass/bottle/morphine, - /obj/item/reagent_containers/glass/bottle/morphine, - /obj/item/reagent_containers/glass/bottle/morphine, - /obj/item/reagent_containers/glass/bottle/morphine, - /obj/item/reagent_containers/glass/bottle/morphine, - /obj/item/reagent_containers/glass/bottle/morphine, - /obj/item/reagent_containers/glass/bottle/toxin, - /obj/item/reagent_containers/glass/bottle/toxin, - /obj/item/reagent_containers/glass/beaker/large, - /obj/item/reagent_containers/glass/beaker/large, - /obj/item/reagent_containers/pill/insulin, - /obj/item/reagent_containers/pill/insulin, - /obj/item/reagent_containers/pill/insulin, - /obj/item/reagent_containers/pill/insulin, - /obj/item/stack/medical/gauze, - /obj/item/storage/box/beakers, - /obj/item/storage/box/syringes, - /obj/item/storage/box/bodybags) - crate_name = "medical supplies crate" - -/datum/supply_pack/medical/firstaid - name = "First Aid Kit Crate" - cost = 1000 - contains = list(/obj/item/storage/firstaid/regular, - /obj/item/storage/firstaid/regular, - /obj/item/storage/firstaid/regular, - /obj/item/storage/firstaid/regular) - crate_name = "first aid kit crate" - -/datum/supply_pack/medical/firstaidbruises - name = "Bruise Treatment Kit Crate" - cost = 1000 - contains = list(/obj/item/storage/firstaid/brute, - /obj/item/storage/firstaid/brute, - /obj/item/storage/firstaid/brute) - crate_name = "brute treatment kit crate" - -/datum/supply_pack/medical/firstaidburns - name = "Burn Treatment Kit Crate" - cost = 1000 - contains = list(/obj/item/storage/firstaid/fire, - /obj/item/storage/firstaid/fire, - /obj/item/storage/firstaid/fire) - crate_name = "burn treatment kit crate" - -/datum/supply_pack/medical/firstaidtoxins - name = "Toxin Treatment Kit Crate" - cost = 1000 - contains = list(/obj/item/storage/firstaid/toxin, - /obj/item/storage/firstaid/toxin, - /obj/item/storage/firstaid/toxin) - crate_name = "toxin treatment kit crate" - -/datum/supply_pack/medical/firstaidoxygen - name = "Oxygen Deprivation Kit Crate" - cost = 1000 - contains = list(/obj/item/storage/firstaid/o2, - /obj/item/storage/firstaid/o2, - /obj/item/storage/firstaid/o2) - crate_name = "oxygen deprivation kit crate" - -/datum/supply_pack/medical/virus - name = "Virus Crate" - cost = 2500 - access = ACCESS_CMO - contains = list(/obj/item/reagent_containers/glass/bottle/flu_virion, - /obj/item/reagent_containers/glass/bottle/cold, - /obj/item/reagent_containers/glass/bottle/epiglottis_virion, - /obj/item/reagent_containers/glass/bottle/liver_enhance_virion, - /obj/item/reagent_containers/glass/bottle/fake_gbs, - /obj/item/reagent_containers/glass/bottle/magnitis, - /obj/item/reagent_containers/glass/bottle/pierrot_throat, - /obj/item/reagent_containers/glass/bottle/brainrot, - /obj/item/reagent_containers/glass/bottle/hallucigen_virion, - /obj/item/reagent_containers/glass/bottle/anxiety, - /obj/item/reagent_containers/glass/bottle/beesease, - /obj/item/storage/box/syringes, - /obj/item/storage/box/beakers, - /obj/item/reagent_containers/glass/bottle/mutagen) - crate_name = "virus crate" - crate_type = /obj/structure/closet/crate/secure/plasma - dangerous = TRUE - -/datum/supply_pack/medical/bloodpacks - name = "Blood Pack Variety Crate" - cost = 3500 - contains = list(/obj/item/reagent_containers/blood/empty, - /obj/item/reagent_containers/blood/empty, - /obj/item/reagent_containers/blood/APlus, - /obj/item/reagent_containers/blood/AMinus, - /obj/item/reagent_containers/blood/BPlus, - /obj/item/reagent_containers/blood/BMinus, - /obj/item/reagent_containers/blood/OPlus, - /obj/item/reagent_containers/blood/OMinus) - crate_name = "blood freezer" - crate_type = /obj/structure/closet/crate/freezer - -/datum/supply_pack/medical/iv_drip - name = "IV Drip Crate" - cost = 1000 - contains = list(/obj/machinery/iv_drip) - crate_name = "iv drip crate" - -/datum/supply_pack/medical/defibs - name = "Defibrillator Crate" - cost = 2500 - contains = list(/obj/item/defibrillator/loaded, - /obj/item/defibrillator/loaded) - crate_name = "defibrillator crate" - -/datum/supply_pack/medical/vending - name = "Medical Vending Crate" - cost = 2000 - contains = list(/obj/item/vending_refill/medical, - /obj/item/vending_refill/medical, - /obj/item/vending_refill/medical) - crate_name = "medical vending crate" - -////////////////////////////////////////////////////////////////////////////// -//////////////////////////// Science ///////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - -/datum/supply_pack/science - group = "Science" - crate_type = /obj/structure/closet/crate/science - -/datum/supply_pack/science/bz - name = "BZ canister" - cost = 4000 - access = ACCESS_TOX_STORAGE - contains = list(/obj/machinery/portable_atmospherics/canister/bz) - crate_name = "BZ canister crate" - crate_type = /obj/structure/closet/crate/secure/science - -/datum/supply_pack/science/robotics - name = "Robotics Assembly Crate" - cost = 1000 - access = ACCESS_ROBOTICS - contains = list(/obj/item/device/assembly/prox_sensor, - /obj/item/device/assembly/prox_sensor, - /obj/item/device/assembly/prox_sensor, - /obj/item/storage/toolbox/electrical, - /obj/item/storage/box/flashes, - /obj/item/stock_parts/cell/high, - /obj/item/stock_parts/cell/high) - crate_name = "robotics assembly crate" - crate_type = /obj/structure/closet/crate/secure/science - -/datum/supply_pack/science/robotics/mecha_ripley - name = "Circuit Crate (Ripley APLU)" - cost = 3000 - access = ACCESS_ROBOTICS - contains = list(/obj/item/book/manual/ripley_build_and_repair, - /obj/item/circuitboard/mecha/ripley/main, - /obj/item/circuitboard/mecha/ripley/peripherals) - crate_name = "\improper APLU Ripley circuit crate" - crate_type = /obj/structure/closet/crate/secure/science - -/datum/supply_pack/science/robotics/mecha_odysseus - name = "Circuit Crate (Odysseus)" - cost = 2500 - access = ACCESS_ROBOTICS - contains = list(/obj/item/circuitboard/mecha/odysseus/peripherals, - /obj/item/circuitboard/mecha/odysseus/main) - crate_name = "\improper Odysseus circuit crate" - crate_type = /obj/structure/closet/crate/secure/science - -/datum/supply_pack/science/plasma - name = "Plasma Assembly Crate" - cost = 1000 - access = ACCESS_TOX_STORAGE - contains = list(/obj/item/tank/internals/plasma, - /obj/item/tank/internals/plasma, - /obj/item/tank/internals/plasma, - /obj/item/device/assembly/igniter, - /obj/item/device/assembly/igniter, - /obj/item/device/assembly/igniter, - /obj/item/device/assembly/prox_sensor, - /obj/item/device/assembly/prox_sensor, - /obj/item/device/assembly/prox_sensor, - /obj/item/device/assembly/timer, - /obj/item/device/assembly/timer, - /obj/item/device/assembly/timer) - crate_name = "plasma assembly crate" - crate_type = /obj/structure/closet/crate/secure/plasma - -/datum/supply_pack/science/shieldwalls - name = "Shield Generators" - cost = 2000 - access = ACCESS_TELEPORTER - contains = list(/obj/machinery/shieldwallgen, - /obj/machinery/shieldwallgen, - /obj/machinery/shieldwallgen, - /obj/machinery/shieldwallgen) - crate_name = "shield generators crate" - crate_type = /obj/structure/closet/crate/secure/science - -/datum/supply_pack/science/transfer_valves - name = "Tank Transfer Valves Crate" - cost = 6000 - access = ACCESS_RD - contains = list(/obj/item/device/transfer_valve, - /obj/item/device/transfer_valve) - crate_name = "tank transfer valves crate" - crate_type = /obj/structure/closet/crate/secure/science - dangerous = TRUE - -/datum/supply_pack/science/tablets - name = "Tablet Crate" - cost = 5000 - contains = list(/obj/item/device/modular_computer/tablet/preset/cargo, - /obj/item/device/modular_computer/tablet/preset/cargo, - /obj/item/device/modular_computer/tablet/preset/cargo, - /obj/item/device/modular_computer/tablet/preset/cargo, - /obj/item/device/modular_computer/tablet/preset/cargo) - crate_name = "tablet crate" - -////////////////////////////////////////////////////////////////////////////// -//////////////////////////// Organic ///////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - -/datum/supply_pack/organic - group = "Food & Livestock" - crate_type = /obj/structure/closet/crate/freezer - -/datum/supply_pack/organic/food - name = "Food Crate" - cost = 1000 - contains = list(/obj/item/reagent_containers/food/condiment/flour, - /obj/item/reagent_containers/food/condiment/rice, - /obj/item/reagent_containers/food/condiment/milk, - /obj/item/reagent_containers/food/condiment/soymilk, - /obj/item/reagent_containers/food/condiment/saltshaker, - /obj/item/reagent_containers/food/condiment/peppermill, - /obj/item/storage/fancy/egg_box, - /obj/item/reagent_containers/food/condiment/enzyme, - /obj/item/reagent_containers/food/condiment/sugar, - /obj/item/reagent_containers/food/snacks/meat/slab/monkey, - /obj/item/reagent_containers/food/snacks/grown/banana, - /obj/item/reagent_containers/food/snacks/grown/banana, - /obj/item/reagent_containers/food/snacks/grown/banana) - crate_name = "food crate" - -/datum/supply_pack/organic/pizza - name = "Pizza Crate" - cost = 6000 // Best prices this side of the galaxy. - contains = list(/obj/item/pizzabox/margherita, - /obj/item/pizzabox/mushroom, - /obj/item/pizzabox/meat, - /obj/item/pizzabox/vegetable) - crate_name = "pizza crate" - -/datum/supply_pack/organic/cream_piee - name = "High-yield Clown-grade Cream Pie Crate" - cost = 6000 - contains = list(/obj/item/storage/backpack/duffelbag/clown/cream_pie) - crate_name = "party equipment crate" - contraband = TRUE - access = ACCESS_THEATRE - crate_type = /obj/structure/closet/crate/secure - -/datum/supply_pack/organic/monkey - name = "Monkey Crate" - cost = 2000 - contains = list (/obj/item/storage/box/monkeycubes) - crate_name = "monkey crate" - -/datum/supply_pack/organic/party - name = "Party Equipment" - cost = 2000 - contains = list(/obj/item/storage/box/drinkingglasses, - /obj/item/reagent_containers/food/drinks/shaker, - /obj/item/reagent_containers/food/drinks/bottle/patron, - /obj/item/reagent_containers/food/drinks/bottle/goldschlager, - /obj/item/reagent_containers/food/drinks/ale, - /obj/item/reagent_containers/food/drinks/ale, - /obj/item/reagent_containers/food/drinks/beer, - /obj/item/reagent_containers/food/drinks/beer, - /obj/item/reagent_containers/food/drinks/beer, - /obj/item/reagent_containers/food/drinks/beer, - /obj/item/device/flashlight/glowstick, - /obj/item/device/flashlight/glowstick/red, - /obj/item/device/flashlight/glowstick/blue, - /obj/item/device/flashlight/glowstick/cyan, - /obj/item/device/flashlight/glowstick/orange, - /obj/item/device/flashlight/glowstick/yellow, - /obj/item/device/flashlight/glowstick/pink) - crate_name = "party equipment crate" - -/datum/supply_pack/organic/critter - crate_type = /obj/structure/closet/crate/critter - -/datum/supply_pack/organic/critter/cow - name = "Cow Crate" - cost = 3000 - contains = list(/mob/living/simple_animal/cow) - crate_name = "cow crate" - -/datum/supply_pack/organic/critter/goat - name = "Goat Crate" - cost = 2500 - contains = list(/mob/living/simple_animal/hostile/retaliate/goat) - crate_name = "goat crate" - -/datum/supply_pack/organic/critter/snake - name = "Snake Crate" - cost = 3000 - contains = list(/mob/living/simple_animal/hostile/retaliate/poison/snake, - /mob/living/simple_animal/hostile/retaliate/poison/snake, - /mob/living/simple_animal/hostile/retaliate/poison/snake) - crate_name = "snake crate" - -/datum/supply_pack/organic/critter/chick - name = "Chicken Crate" - cost = 2000 - contains = list( /mob/living/simple_animal/chick) - crate_name = "chicken crate" - -/datum/supply_pack/organic/critter/corgi - name = "Corgi Crate" - cost = 5000 - contains = list(/mob/living/simple_animal/pet/dog/corgi, - /obj/item/clothing/neck/petcollar) - crate_name = "corgi crate" - -/datum/supply_pack/organic/critter/corgi/generate() - . = ..() - if(prob(50)) - var/mob/living/simple_animal/pet/dog/corgi/D = locate() in . - qdel(D) - new /mob/living/simple_animal/pet/dog/corgi/Lisa(.) - -/datum/supply_pack/organic/critter/cat - name = "Cat Crate" - cost = 5000 //Cats are worth as much as corgis. - contains = list(/mob/living/simple_animal/pet/cat, - /obj/item/clothing/neck/petcollar, - /obj/item/toy/cattoy) - crate_name = "cat crate" - -/datum/supply_pack/organic/critter/cat/generate() - . = ..() - if(prob(50)) - var/mob/living/simple_animal/pet/cat/C = locate() in . - qdel(C) - new /mob/living/simple_animal/pet/cat/Proc(.) - -/datum/supply_pack/organic/critter/pug - name = "Pug Crate" - cost = 5000 - contains = list(/mob/living/simple_animal/pet/dog/pug, - /obj/item/clothing/neck/petcollar) - crate_name = "pug crate" - -/datum/supply_pack/organic/critter/fox - name = "Fox Crate" - cost = 5000 - contains = list(/mob/living/simple_animal/pet/fox, - /obj/item/clothing/neck/petcollar) - crate_name = "fox crate" - -/datum/supply_pack/organic/critter/butterfly - name = "Butterflies Crate" - contraband = TRUE - cost = 5000 - contains = list(/mob/living/simple_animal/butterfly) - crate_name = "entomology samples crate" - -/datum/supply_pack/organic/critter/butterfly/generate() - . = ..() - for(var/i in 1 to 49) - new /mob/living/simple_animal/butterfly(.) - -/datum/supply_pack/organic/hydroponics - name = "Hydroponics Crate" - cost = 1500 - contains = list(/obj/item/reagent_containers/spray/plantbgone, - /obj/item/reagent_containers/spray/plantbgone, - /obj/item/reagent_containers/glass/bottle/ammonia, - /obj/item/reagent_containers/glass/bottle/ammonia, - /obj/item/hatchet, - /obj/item/cultivator, - /obj/item/device/plant_analyzer, - /obj/item/clothing/gloves/botanic_leather, - /obj/item/clothing/suit/apron) - crate_name = "hydroponics crate" - crate_type = /obj/structure/closet/crate/hydroponics - -/datum/supply_pack/organic/hydroponics/hydrotank - name = "Hydroponics Backpack Crate" - cost = 1000 - access = ACCESS_HYDROPONICS - contains = list(/obj/item/watertank) - crate_name = "hydroponics backpack crate" - crate_type = /obj/structure/closet/crate/secure - -/datum/supply_pack/organic/potted_plants - name = "Potted Plants Crate" - cost = 700 - contains = list(/obj/item/twohanded/required/kirbyplants/random, - /obj/item/twohanded/required/kirbyplants/random, - /obj/item/twohanded/required/kirbyplants/random, - /obj/item/twohanded/required/kirbyplants/random, - /obj/item/twohanded/required/kirbyplants/random) - crate_name = "potted plants crate" - crate_type = /obj/structure/closet/crate/hydroponics - -/datum/supply_pack/organic/hydroponics/seeds - name = "Seeds Crate" - cost = 1000 - contains = list(/obj/item/seeds/chili, - /obj/item/seeds/berry, - /obj/item/seeds/corn, - /obj/item/seeds/eggplant, - /obj/item/seeds/tomato, - /obj/item/seeds/soya, - /obj/item/seeds/wheat, - /obj/item/seeds/wheat/rice, - /obj/item/seeds/carrot, - /obj/item/seeds/sunflower, - /obj/item/seeds/chanter, - /obj/item/seeds/potato, - /obj/item/seeds/sugarcane) - crate_name = "seeds crate" - -/datum/supply_pack/organic/hydroponics/exoticseeds - name = "Exotic Seeds Crate" - cost = 1500 - contains = list(/obj/item/seeds/nettle, - /obj/item/seeds/replicapod, - /obj/item/seeds/replicapod, - /obj/item/seeds/replicapod, - /obj/item/seeds/plump, - /obj/item/seeds/liberty, - /obj/item/seeds/amanita, - /obj/item/seeds/reishi, - /obj/item/seeds/banana, - /obj/item/seeds/eggplant/eggy, - /obj/item/seeds/random, - /obj/item/seeds/random) - crate_name = "exotic seeds crate" - -/datum/supply_pack/organic/hydroponics/beekeeping_fullkit - name = "Beekeeping Starter Crate" - cost = 1500 - contains = list(/obj/structure/beebox, - /obj/item/honey_frame, - /obj/item/honey_frame, - /obj/item/honey_frame, - /obj/item/queen_bee/bought, - /obj/item/clothing/head/beekeeper_head, - /obj/item/clothing/suit/beekeeper_suit, - /obj/item/melee/flyswatter) - crate_name = "beekeeping starter crate" - -/datum/supply_pack/organic/hydroponics/beekeeping_suits - name = "Beekeeper Suit Crate" - cost = 1000 - contains = list(/obj/item/clothing/head/beekeeper_head, - /obj/item/clothing/suit/beekeeper_suit, - /obj/item/clothing/head/beekeeper_head, - /obj/item/clothing/suit/beekeeper_suit) - crate_name = "beekeeper suits" - -/datum/supply_pack/organic/vending - name = "Bartending Supply Crate" - cost = 2000 - contains = list(/obj/item/vending_refill/boozeomat, - /obj/item/vending_refill/boozeomat, - /obj/item/vending_refill/boozeomat, - /obj/item/vending_refill/coffee, - /obj/item/vending_refill/coffee, - /obj/item/vending_refill/coffee) - crate_name = "bartending supply crate" - -/datum/supply_pack/organic/vending/snack - name = "Snack Supply Crate" - cost = 1500 - contains = list(/obj/item/vending_refill/snack, - /obj/item/vending_refill/snack, - /obj/item/vending_refill/snack) - crate_name = "snacks supply crate" - -/datum/supply_pack/organic/vending/cola - name = "Softdrinks Supply Crate" - cost = 1500 - contains = list(/obj/item/vending_refill/cola, - /obj/item/vending_refill/cola, - /obj/item/vending_refill/cola) - crate_name = "soft drinks supply crate" - -/datum/supply_pack/organic/vending/cigarette - name = "Cigarette Supply Crate" - cost = 1500 - contains = list(/obj/item/vending_refill/cigarette, - /obj/item/vending_refill/cigarette, - /obj/item/vending_refill/cigarette) - crate_name = "cigarette supply crate" - -/datum/supply_pack/organic/vending/games - name = "Games Supply Crate" - cost = 1000 - contains = list(/obj/item/vending_refill/games, - /obj/item/vending_refill/games, - /obj/item/vending_refill/games) - crate_name = "games supply crate" - -////////////////////////////////////////////////////////////////////////////// -//////////////////////////// Materials /////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - -/datum/supply_pack/materials - group = "Raw Materials" - -/datum/supply_pack/materials/metal50 - name = "50 Metal Sheets" - cost = 1000 - contains = list(/obj/item/stack/sheet/metal/fifty) - crate_name = "metal sheets crate" - -/datum/supply_pack/materials/plasteel20 - name = "20 Plasteel Sheets" - cost = 7500 - contains = list(/obj/item/stack/sheet/plasteel/twenty) - crate_name = "plasteel sheets crate" - -/datum/supply_pack/materials/plasteel50 - name = "50 Plasteel Sheets" - cost = 16500 - contains = list(/obj/item/stack/sheet/plasteel/fifty) - crate_name = "plasteel sheets crate" - -/datum/supply_pack/materials/glass50 - name = "50 Glass Sheets" - cost = 1000 - contains = list(/obj/item/stack/sheet/glass/fifty) - crate_name = "glass sheets crate" - -/datum/supply_pack/materials/wood50 - name = "50 Wood Planks" - cost = 2000 - contains = list(/obj/item/stack/sheet/mineral/wood/fifty) - crate_name = "wood planks crate" - -/datum/supply_pack/materials/cardboard50 - name = "50 Cardboard Sheets" - cost = 1000 - contains = list(/obj/item/stack/sheet/cardboard/fifty) - crate_name = "cardboard sheets crate" - -/datum/supply_pack/materials/plastic50 - name = "50 Plastic Sheets" - cost = 1000 - contains = list(/obj/item/stack/sheet/plastic/fifty) - crate_name = "plastic sheets crate" - -/datum/supply_pack/materials/sandstone30 - name = "30 Sandstone Blocks" - cost = 1000 - contains = list(/obj/item/stack/sheet/mineral/sandstone/thirty) - crate_name = "sandstone blocks crate" - -////////////////////////////////////////////////////////////////////////////// -//////////////////////////// Miscellaneous /////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - -/datum/supply_pack/misc - group = "Miscellaneous Supplies" - -/datum/supply_pack/misc/minerkit - name = "Shaft Miner Starter Kit" - cost = 2500 - access = ACCESS_QM - contains = list(/obj/item/pickaxe/mini, - /obj/item/clothing/glasses/meson, - /obj/item/device/t_scanner/adv_mining_scanner/lesser, - /obj/item/device/radio/headset/headset_cargo/mining, - /obj/item/storage/bag/ore, - /obj/item/clothing/suit/hooded/explorer, - /obj/item/clothing/mask/gas/explorer) - crate_name = "shaft miner starter kit" - crate_type = /obj/structure/closet/crate/secure - -/datum/supply_pack/misc/mule - name = "MULEbot Crate" - cost = 2000 - contains = list(/mob/living/simple_animal/bot/mulebot) - crate_name = "\improper MULEbot Crate" - crate_type = /obj/structure/closet/crate/large - -/datum/supply_pack/misc/conveyor - name = "Conveyor Assembly Crate" - cost = 1500 - contains = list(/obj/item/conveyor_construct, - /obj/item/conveyor_construct, - /obj/item/conveyor_construct, - /obj/item/conveyor_construct, - /obj/item/conveyor_construct, - /obj/item/conveyor_construct, - /obj/item/conveyor_switch_construct, - /obj/item/paper/guides/conveyor) - crate_name = "conveyor assembly crate" - -/datum/supply_pack/misc/watertank - name = "Water Tank Crate" - cost = 600 - contains = list(/obj/structure/reagent_dispensers/watertank) - crate_name = "water tank crate" - crate_type = /obj/structure/closet/crate/large - -/datum/supply_pack/misc/hightank - name = "High-Capacity Water Tank Crate" - cost = 1200 - contains = list(/obj/structure/reagent_dispensers/watertank/high) - crate_name = "high-capacity water tank crate" - crate_type = /obj/structure/closet/crate/large - -/datum/supply_pack/misc/water_vapor - name = "Water Vapor Canister" - cost = 2500 - contains = list(/obj/machinery/portable_atmospherics/canister/water_vapor) - crate_name = "water vapor canister crate" - crate_type = /obj/structure/closet/crate/large - -/datum/supply_pack/misc/lasertag - name = "Laser Tag Crate" - cost = 1500 - contains = list(/obj/item/gun/energy/laser/redtag, - /obj/item/gun/energy/laser/redtag, - /obj/item/gun/energy/laser/redtag, - /obj/item/gun/energy/laser/bluetag, - /obj/item/gun/energy/laser/bluetag, - /obj/item/gun/energy/laser/bluetag, - /obj/item/clothing/suit/redtag, - /obj/item/clothing/suit/redtag, - /obj/item/clothing/suit/redtag, - /obj/item/clothing/suit/bluetag, - /obj/item/clothing/suit/bluetag, - /obj/item/clothing/suit/bluetag, - /obj/item/clothing/head/helmet/redtaghelm, - /obj/item/clothing/head/helmet/redtaghelm, - /obj/item/clothing/head/helmet/redtaghelm, - /obj/item/clothing/head/helmet/bluetaghelm, - /obj/item/clothing/head/helmet/bluetaghelm, - /obj/item/clothing/head/helmet/bluetaghelm) - crate_name = "laser tag crate" - -/datum/supply_pack/misc/lasertag/pins - name = "Laser Tag Firing Pins Crate" - cost = 3000 - contraband = TRUE - contains = list(/obj/item/storage/box/lasertagpins) - crate_name = "laser tag crate" - -/datum/supply_pack/misc/clownpin - name = "Hilarious Firing Pin Crate" - cost = 5000 - contraband = TRUE - contains = list(/obj/item/device/firing_pin/clown) - // It's /technically/ a toy. For the clown, at least. - crate_name = "toy crate" - -/datum/supply_pack/misc/religious_supplies - name = "Religious Supplies Crate" - cost = 4000 // it costs so much because the Space Church is ran by Space Jews - contains = list(/obj/item/reagent_containers/food/drinks/bottle/holywater, - /obj/item/reagent_containers/food/drinks/bottle/holywater, - /obj/item/storage/book/bible/booze, - /obj/item/storage/book/bible/booze, - /obj/item/clothing/suit/hooded/chaplain_hoodie, - /obj/item/clothing/suit/hooded/chaplain_hoodie, - /obj/item/clothing/under/burial, - /obj/item/clothing/under/burial) - crate_name = "religious supplies crate" - -/datum/supply_pack/misc/book_crate - name = "Book Crate" - cost = 1500 - contains = list(/obj/item/book/codex_gigas, - /obj/item/book/manual/random/, - /obj/item/book/manual/random/, - /obj/item/book/manual/random/, - /obj/item/book/random/triple) - -/datum/supply_pack/misc/paper - name = "Bureaucracy Crate" - cost = 1500 - contains = list(/obj/structure/filingcabinet/chestdrawer/wheeled, - /obj/item/device/camera_film, - /obj/item/hand_labeler, - /obj/item/hand_labeler_refill, - /obj/item/hand_labeler_refill, - /obj/item/paper_bin, - /obj/item/pen/fourcolor, - /obj/item/pen/fourcolor, - /obj/item/pen, - /obj/item/pen/fountain, - /obj/item/pen/blue, - /obj/item/pen/red, - /obj/item/folder/blue, - /obj/item/folder/red, - /obj/item/folder/yellow, - /obj/item/clipboard, - /obj/item/clipboard, - /obj/item/stamp, - /obj/item/stamp/denied) - crate_name = "bureaucracy crate" - -/datum/supply_pack/misc/fountainpens - name = "Calligraphy Crate" - cost = 700 - contains = list(/obj/item/storage/box/fountainpens) - crate_type = /obj/structure/closet/crate/wooden - -/datum/supply_pack/misc/toner - name = "Toner Crate" - cost = 1000 - contains = list(/obj/item/device/toner, - /obj/item/device/toner, - /obj/item/device/toner, - /obj/item/device/toner, - /obj/item/device/toner, - /obj/item/device/toner) - crate_name = "toner crate" - -/datum/supply_pack/misc/janitor - name = "Janitorial Supplies Crate" - cost = 1000 - contains = list(/obj/item/reagent_containers/glass/bucket, - /obj/item/reagent_containers/glass/bucket, - /obj/item/reagent_containers/glass/bucket, - /obj/item/mop, - /obj/item/caution, - /obj/item/caution, - /obj/item/caution, - /obj/item/storage/bag/trash, - /obj/item/reagent_containers/spray/cleaner, - /obj/item/reagent_containers/glass/rag, - /obj/item/grenade/chem_grenade/cleaner, - /obj/item/grenade/chem_grenade/cleaner, - /obj/item/grenade/chem_grenade/cleaner) - crate_name = "janitorial supplies crate" - -/datum/supply_pack/misc/janitor/janicart - name = "Janitorial Cart and Galoshes Crate" - cost = 2000 - contains = list(/obj/structure/janitorialcart, - /obj/item/clothing/shoes/galoshes) - crate_name = "janitorial cart crate" - crate_type = /obj/structure/closet/crate/large - -/datum/supply_pack/misc/janitor/janitank - name = "Janitor Backpack Crate" - cost = 1000 - access = ACCESS_JANITOR - contains = list(/obj/item/watertank/janitor) - crate_name = "janitor backpack crate" - crate_type = /obj/structure/closet/crate/secure - -/datum/supply_pack/misc/janitor/lightbulbs - name = "Replacement Lights" - cost = 1000 - contains = list(/obj/item/storage/box/lights/mixed, - /obj/item/storage/box/lights/mixed, - /obj/item/storage/box/lights/mixed) - crate_name = "replacement lights" - -/datum/supply_pack/misc/noslipfloor - name = "High-traction Floor Tiles" - cost = 2000 - contains = list(/obj/item/stack/tile/noslip/thirty) - crate_name = "high-traction floor tiles crate" - -/datum/supply_pack/misc/plasmaman - name = "Plasmaman Supply Kit" - cost = 2000 - contains = list(/obj/item/clothing/under/plasmaman, - /obj/item/clothing/under/plasmaman, - /obj/item/tank/internals/plasmaman/belt/full, - /obj/item/tank/internals/plasmaman/belt/full, - /obj/item/clothing/head/helmet/space/plasmaman, - /obj/item/clothing/head/helmet/space/plasmaman) - crate_name = "plasmaman supply kit" - -/datum/supply_pack/misc/costume - name = "Standard Costume Crate" - cost = 1000 - access = ACCESS_THEATRE - contains = list(/obj/item/storage/backpack/clown, - /obj/item/clothing/shoes/clown_shoes, - /obj/item/clothing/mask/gas/clown_hat, - /obj/item/clothing/under/rank/clown, - /obj/item/bikehorn, - /obj/item/clothing/under/rank/mime, - /obj/item/clothing/shoes/sneakers/black, - /obj/item/clothing/gloves/color/white, - /obj/item/clothing/mask/gas/mime, - /obj/item/clothing/head/beret, - /obj/item/clothing/suit/suspenders, - /obj/item/reagent_containers/food/drinks/bottle/bottleofnothing, - /obj/item/storage/backpack/mime) - crate_name = "standard costume crate" - crate_type = /obj/structure/closet/crate/secure - -/datum/supply_pack/misc/costume_original - name = "Original Costume Crate" - cost = 1000 - contains = list(/obj/item/clothing/head/snowman, - /obj/item/clothing/suit/snowman, - /obj/item/clothing/head/chicken, - /obj/item/clothing/suit/chickensuit, - /obj/item/clothing/mask/gas/monkeymask, - /obj/item/clothing/suit/monkeysuit, - /obj/item/clothing/head/cardborg, - /obj/item/clothing/suit/cardborg, - /obj/item/clothing/head/xenos, - /obj/item/clothing/suit/xenos, - /obj/item/clothing/suit/hooded/ian_costume, - /obj/item/clothing/suit/hooded/carp_costume, - /obj/item/clothing/suit/hooded/bee_costume) - crate_name = "original costume crate" - -/datum/supply_pack/misc/wizard - name = "Wizard Costume Crate" - cost = 2000 - contains = list(/obj/item/staff, - /obj/item/clothing/suit/wizrobe/fake, - /obj/item/clothing/shoes/sandal, - /obj/item/clothing/head/wizard/fake) - crate_name = "wizard costume crate" - -/datum/supply_pack/misc/randomised - name = "Collectable Hats Crate!" - cost = 20000 - var/num_contained = 3 //number of items picked to be contained in a randomised crate - contains = list(/obj/item/clothing/head/collectable/chef, - /obj/item/clothing/head/collectable/paper, - /obj/item/clothing/head/collectable/tophat, - /obj/item/clothing/head/collectable/captain, - /obj/item/clothing/head/collectable/beret, - /obj/item/clothing/head/collectable/welding, - /obj/item/clothing/head/collectable/flatcap, - /obj/item/clothing/head/collectable/pirate, - /obj/item/clothing/head/collectable/kitty, - /obj/item/clothing/head/collectable/rabbitears, - /obj/item/clothing/head/collectable/wizard, - /obj/item/clothing/head/collectable/hardhat, - /obj/item/clothing/head/collectable/HoS, - /obj/item/clothing/head/collectable/HoP, - /obj/item/clothing/head/collectable/thunderdome, - /obj/item/clothing/head/collectable/swat, - /obj/item/clothing/head/collectable/slime, - /obj/item/clothing/head/collectable/police, - /obj/item/clothing/head/collectable/slime, - /obj/item/clothing/head/collectable/xenom, - /obj/item/clothing/head/collectable/petehat) - crate_name = "collectable hats crate" - -/datum/supply_pack/misc/randomised/fill(obj/structure/closet/crate/C) - var/list/L = contains.Copy() - for(var/i in 1 to num_contained) - var/item = pick_n_take(L) - new item(C) - -/datum/supply_pack/misc/bigband - contains = list(/obj/item/device/instrument/violin, - /obj/item/device/instrument/guitar, - /obj/item/device/instrument/glockenspiel, - /obj/item/device/instrument/accordion, - /obj/item/device/instrument/saxophone, - /obj/item/device/instrument/trombone, - /obj/item/device/instrument/recorder, - /obj/item/device/instrument/harmonica, - /obj/structure/piano/unanchored) - name = "Big band instrument collection" - cost = 5000 - crate_name = "Big band musical instruments collection" - -/datum/supply_pack/misc/randomised/contraband - name = "Contraband Crate" - contraband = TRUE - cost = 3000 - num_contained = 5 - contains = list(/obj/item/poster/random_contraband, - /obj/item/storage/fancy/cigarettes/cigpack_shadyjims, - /obj/item/storage/fancy/cigarettes/cigpack_midori, - /obj/item/seeds/ambrosia/deus, - /obj/item/clothing/neck/necklace/dope) - crate_name = "crate" - -/datum/supply_pack/misc/randomised/toys - name = "Toy Crate" - cost = 5000 // or play the arcade machines ya lazy bum - // TODO make this actually just use the arcade machine loot list - num_contained = 5 - contains = list(/obj/item/toy/spinningtoy, - /obj/item/toy/sword, - /obj/item/toy/foamblade, - /obj/item/toy/talking/AI, - /obj/item/toy/talking/owl, - /obj/item/toy/talking/griffin, - /obj/item/toy/nuke, - /obj/item/toy/minimeteor, - /obj/item/toy/plush/carpplushie, - /obj/item/toy/plush/lizardplushie, - /obj/item/toy/plush/snakeplushie, - /obj/item/toy/plush/nukeplushie, - /obj/item/toy/plush/slimeplushie, - /obj/item/coin/antagtoken, - /obj/item/stack/tile/fakespace/loaded, - /obj/item/gun/ballistic/shotgun/toy/crossbow, - /obj/item/toy/redbutton, - /obj/item/toy/eightball, - /obj/item/vending_refill/donksoft) - crate_name = "toy crate" - -/datum/supply_pack/misc/autodrobe - name = "Autodrobe Supply Crate" - cost = 1500 - contains = list(/obj/item/vending_refill/autodrobe, - /obj/item/vending_refill/autodrobe) - crate_name = "autodrobe supply crate" - -/datum/supply_pack/misc/formalwear - name = "Formalwear Crate" - cost = 3000 //Lots of very expensive items. You gotta pay up to look good! - contains = list(/obj/item/clothing/under/blacktango, - /obj/item/clothing/under/assistantformal, - /obj/item/clothing/under/assistantformal, - /obj/item/clothing/under/lawyer/bluesuit, - /obj/item/clothing/suit/toggle/lawyer, - /obj/item/clothing/under/lawyer/purpsuit, - /obj/item/clothing/suit/toggle/lawyer/purple, - /obj/item/clothing/under/lawyer/blacksuit, - /obj/item/clothing/suit/toggle/lawyer/black, - /obj/item/clothing/accessory/waistcoat, - /obj/item/clothing/neck/tie/blue, - /obj/item/clothing/neck/tie/red, - /obj/item/clothing/neck/tie/black, - /obj/item/clothing/head/bowler, - /obj/item/clothing/head/fedora, - /obj/item/clothing/head/flatcap, - /obj/item/clothing/head/beret, - /obj/item/clothing/head/that, - /obj/item/clothing/shoes/laceup, - /obj/item/clothing/shoes/laceup, - /obj/item/clothing/shoes/laceup, - /obj/item/clothing/under/suit_jacket/charcoal, - /obj/item/clothing/under/suit_jacket/navy, - /obj/item/clothing/under/suit_jacket/burgundy, - /obj/item/clothing/under/suit_jacket/checkered, - /obj/item/clothing/under/suit_jacket/tan, - /obj/item/lipstick/random) - crate_name = "formalwear crate" - -/datum/supply_pack/misc/foamforce - name = "Foam Force Crate" - cost = 1000 - contains = list(/obj/item/gun/ballistic/shotgun/toy, - /obj/item/gun/ballistic/shotgun/toy, - /obj/item/gun/ballistic/shotgun/toy, - /obj/item/gun/ballistic/shotgun/toy, - /obj/item/gun/ballistic/shotgun/toy, - /obj/item/gun/ballistic/shotgun/toy, - /obj/item/gun/ballistic/shotgun/toy, - /obj/item/gun/ballistic/shotgun/toy) - crate_name = "foam force crate" - -/datum/supply_pack/misc/foamforce/bonus - name = "Foam Force Pistols Crate" - contraband = TRUE - cost = 4000 - contains = list(/obj/item/gun/ballistic/automatic/toy/pistol, - /obj/item/gun/ballistic/automatic/toy/pistol, - /obj/item/ammo_box/magazine/toy/pistol, - /obj/item/ammo_box/magazine/toy/pistol) - crate_name = "foam force crate" - -/datum/supply_pack/misc/artsupply - name = "Art Supplies" - cost = 800 - contains = list(/obj/structure/easel, - /obj/structure/easel, - /obj/item/canvas/nineteenXnineteen, - /obj/item/canvas/nineteenXnineteen, - /obj/item/canvas/twentythreeXnineteen, - /obj/item/canvas/twentythreeXnineteen, - /obj/item/canvas/twentythreeXtwentythree, - /obj/item/canvas/twentythreeXtwentythree, - /obj/item/toy/crayon/rainbow, - /obj/item/toy/crayon/rainbow) - crate_name = "art supply crate" - -/datum/supply_pack/misc/bsa - name = "Bluespace Artillery Parts" - cost = 15000 - special = TRUE - contains = list(/obj/item/circuitboard/machine/bsa/front, - /obj/item/circuitboard/machine/bsa/middle, - /obj/item/circuitboard/machine/bsa/back, - /obj/item/circuitboard/computer/bsa_control - ) - crate_name= "bluespace artillery parts crate" - -/datum/supply_pack/misc/dna_vault - name = "DNA Vault Parts" - cost = 12000 - special = TRUE - contains = list( - /obj/item/circuitboard/machine/dna_vault, - /obj/item/device/dna_probe, - /obj/item/device/dna_probe, - /obj/item/device/dna_probe, - /obj/item/device/dna_probe, - /obj/item/device/dna_probe - ) - crate_name= "dna vault parts crate" - -/datum/supply_pack/misc/dna_probes - name = "DNA Vault Samplers" - cost = 3000 - special = TRUE - contains = list(/obj/item/device/dna_probe, - /obj/item/device/dna_probe, - /obj/item/device/dna_probe, - /obj/item/device/dna_probe, - /obj/item/device/dna_probe - ) - crate_name= "dna samplers crate" - - -/datum/supply_pack/misc/shield_sat - name = "Shield Generator Satellite" - cost = 3000 - special = TRUE - contains = list( - /obj/machinery/satellite/meteor_shield, - /obj/machinery/satellite/meteor_shield, - /obj/machinery/satellite/meteor_shield - ) - crate_name= "shield sat crate" - - -/datum/supply_pack/misc/shield_sat_control - name = "Shield System Control Board" - cost = 5000 - special = TRUE - contains = list(/obj/item/circuitboard/computer/sat_control) - crate_name= "shield control board crate" - -/datum/supply_pack/misc/bicycle - name = "Bicycle" - cost = 1000000 - contains = list(/obj/vehicle/bicycle) - crate_name = "Bicycle Crate" - crate_type = /obj/structure/closet/crate/large +/datum/supply_pack + var/name = "Crate" + var/group = "" + var/hidden = FALSE + var/contraband = FALSE + var/cost = 700 // Minimum cost, or infinite points are possible. + var/access = FALSE + var/access_any = FALSE + var/list/contains = null + var/crate_name = "crate" + var/crate_type = /obj/structure/closet/crate + var/dangerous = FALSE // Should we message admins? + var/special = FALSE //Event/Station Goals/Admin enabled packs + var/special_enabled = FALSE + var/DropPodOnly = FALSE//only usable by the Bluespace Drop Pod via the express cargo console + +/datum/supply_pack/proc/generate(turf/T) + var/obj/structure/closet/crate/C = new crate_type(T) + C.name = crate_name + if(access) + C.req_access = list(access) + if(access_any) + C.req_one_access = access_any + + fill(C) + + return C + +/datum/supply_pack/proc/fill(obj/structure/closet/crate/C) + for(var/item in contains) + new item(C) + + +////////////////////////////////////////////////////////////////////////////// +//////////////////////////// Emergency /////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +/datum/supply_pack/emergency + group = "Emergency" + +/datum/supply_pack/emergency/spacesuit + name = "Space Suit Crate" + cost = 3000 + access = ACCESS_EVA + contains = list(/obj/item/clothing/suit/space, + /obj/item/clothing/suit/space, + /obj/item/clothing/head/helmet/space, + /obj/item/clothing/head/helmet/space, + /obj/item/clothing/mask/breath, + /obj/item/clothing/mask/breath) + crate_name = "space suit crate" + crate_type = /obj/structure/closet/crate/secure + +/datum/supply_pack/emergency/vehicle + name = "Biker Gang Kit" //TUNNEL SNAKES OWN THIS TOWN + cost = 2000 + contraband = TRUE + contains = list(/obj/vehicle/ridden/atv, + /obj/item/key, + /obj/item/clothing/suit/jacket/leather/overcoat, + /obj/item/clothing/gloves/color/black, + /obj/item/clothing/head/soft, + /obj/item/clothing/mask/bandana/skull)//so you can properly #cargoniabikergang + crate_name = "Biker Kit" + crate_type = /obj/structure/closet/crate/large + +/datum/supply_pack/emergency/equipment + name = "Emergency Equipment" + cost = 3500 + contains = list(/mob/living/simple_animal/bot/floorbot, + /mob/living/simple_animal/bot/floorbot, + /mob/living/simple_animal/bot/medbot, + /mob/living/simple_animal/bot/medbot, + /obj/item/tank/internals/air, + /obj/item/tank/internals/air, + /obj/item/tank/internals/air, + /obj/item/tank/internals/air, + /obj/item/tank/internals/air, + /obj/item/clothing/mask/gas, + /obj/item/clothing/mask/gas, + /obj/item/clothing/mask/gas, + /obj/item/clothing/mask/gas, + /obj/item/clothing/mask/gas) + crate_name = "emergency crate" + crate_type = /obj/structure/closet/crate/internals + +/datum/supply_pack/emergency/internals + name = "Internals Crate" + cost = 1000 + contains = list(/obj/item/clothing/mask/gas, + /obj/item/clothing/mask/gas, + /obj/item/clothing/mask/gas, + /obj/item/clothing/mask/breath, + /obj/item/clothing/mask/breath, + /obj/item/clothing/mask/breath, + /obj/item/tank/internals/emergency_oxygen, + /obj/item/tank/internals/emergency_oxygen, + /obj/item/tank/internals/emergency_oxygen, + /obj/item/tank/internals/air, + /obj/item/tank/internals/air, + /obj/item/tank/internals/air) + crate_name = "internals crate" + crate_type = /obj/structure/closet/crate/internals + +/datum/supply_pack/emergency/firefighting + name = "Firefighting Crate" + cost = 1000 + contains = list(/obj/item/clothing/suit/fire/firefighter, + /obj/item/clothing/suit/fire/firefighter, + /obj/item/clothing/mask/gas, + /obj/item/clothing/mask/gas, + /obj/item/device/flashlight, + /obj/item/device/flashlight, + /obj/item/tank/internals/oxygen/red, + /obj/item/tank/internals/oxygen/red, + /obj/item/extinguisher, + /obj/item/extinguisher, + /obj/item/clothing/head/hardhat/red, + /obj/item/clothing/head/hardhat/red) + crate_name = "firefighting crate" + +/datum/supply_pack/emergency/atmostank + name = "Firefighting Watertank" + cost = 1000 + access = ACCESS_ATMOSPHERICS + contains = list(/obj/item/watertank/atmos) + crate_name = "firefighting watertank crate" + crate_type = /obj/structure/closet/crate/secure + +/datum/supply_pack/emergency/radiation + name = "Radiation Protection Crate" + cost = 1000 + contains = list(/obj/item/clothing/head/radiation, + /obj/item/clothing/head/radiation, + /obj/item/clothing/suit/radiation, + /obj/item/clothing/suit/radiation, + /obj/item/device/geiger_counter, + /obj/item/device/geiger_counter, + /obj/item/reagent_containers/food/drinks/bottle/vodka, + /obj/item/reagent_containers/food/drinks/drinkingglass/shotglass, + /obj/item/reagent_containers/food/drinks/drinkingglass/shotglass) + crate_name = "radiation protection crate" + crate_type = /obj/structure/closet/crate/radiation + +/datum/supply_pack/emergency/weedcontrol + name = "Weed Control Crate" + cost = 1500 + access = ACCESS_HYDROPONICS + contains = list(/obj/item/scythe, + /obj/item/clothing/mask/gas, + /obj/item/grenade/chem_grenade/antiweed, + /obj/item/grenade/chem_grenade/antiweed) + crate_name = "weed control crate" + crate_type = /obj/structure/closet/crate/secure/hydroponics + +/datum/supply_pack/emergency/metalfoam + name = "Metal Foam Grenade Crate" + cost = 1000 + contains = list(/obj/item/storage/box/metalfoam) + crate_name = "metal foam grenade crate" + +/datum/supply_pack/emergency/droneshells + name = "Drone Shell Crate" + cost = 1000 + contains = list(/obj/item/drone_shell, + /obj/item/drone_shell, + /obj/item/drone_shell) + crate_name = "drone shell crate" + +/datum/supply_pack/emergency/specialops + name = "Special Ops Supplies" + hidden = TRUE + cost = 2000 + contains = list(/obj/item/storage/box/emps, + /obj/item/grenade/smokebomb, + /obj/item/grenade/smokebomb, + /obj/item/grenade/smokebomb, + /obj/item/pen/sleepy, + /obj/item/grenade/chem_grenade/incendiary) + crate_name = "emergency crate" + crate_type = /obj/structure/closet/crate/internals + +/datum/supply_pack/emergency/syndicate + name = "NULL_ENTRY" + hidden = TRUE + cost = 20000 + contains = list() + crate_name = "emergency crate" + crate_type = /obj/structure/closet/crate/internals + dangerous = TRUE + +/datum/supply_pack/emergency/syndicate/fill(obj/structure/closet/crate/C) + var/crate_value = 30 + var/list/uplink_items = get_uplink_items(SSticker.mode) + while(crate_value) + var/category = pick(uplink_items) + var/item = pick(uplink_items[category]) + var/datum/uplink_item/I = uplink_items[category][item] + + if(!I.surplus || prob(100 - I.surplus)) + continue + if(crate_value < I.cost) + continue + crate_value -= I.cost + new I.item(C) + +////////////////////////////////////////////////////////////////////////////// +//////////////////////////// Security //////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +/datum/supply_pack/security + group = "Security" + access = ACCESS_SECURITY + crate_type = /obj/structure/closet/crate/secure/gear + +/datum/supply_pack/security/supplies + name = "Security Supplies Crate" + cost = 1000 + contains = list(/obj/item/storage/box/flashbangs, + /obj/item/storage/box/teargas, + /obj/item/storage/box/flashes, + /obj/item/storage/box/handcuffs) + crate_name = "security supply crate" + +/datum/supply_pack/security/helmets + name = "Helmets Crate" + cost = 1000 + contains = list(/obj/item/clothing/head/helmet/sec, + /obj/item/clothing/head/helmet/sec, + /obj/item/clothing/head/helmet/sec) + crate_name = "helmet crate" + +/datum/supply_pack/security/armor + name = "Armor Crate" + cost = 1000 + contains = list(/obj/item/clothing/suit/armor/vest, + /obj/item/clothing/suit/armor/vest, + /obj/item/clothing/suit/armor/vest) + crate_name = "armor crate" + +/datum/supply_pack/security/baton + name = "Stun Batons Crate" + cost = 1000 + contains = list(/obj/item/melee/baton/loaded, + /obj/item/melee/baton/loaded, + /obj/item/melee/baton/loaded) + crate_name = "stun baton crate" + +/datum/supply_pack/security/wall_flash + name = "Wall-Mounted Flash Crate" + cost = 1000 + contains = list(/obj/item/storage/box/wall_flash, + /obj/item/storage/box/wall_flash, + /obj/item/storage/box/wall_flash, + /obj/item/storage/box/wall_flash) + crate_name = "wall-mounted flash crate" + +/datum/supply_pack/security/laser + name = "Lasers Crate" + cost = 2000 + contains = list(/obj/item/gun/energy/laser, + /obj/item/gun/energy/laser, + /obj/item/gun/energy/laser) + crate_name = "laser crate" + +/datum/supply_pack/security/taser + name = "Taser Crate" + cost = 3000 + contains = list(/obj/item/gun/energy/e_gun/advtaser, + /obj/item/gun/energy/e_gun/advtaser, + /obj/item/gun/energy/e_gun/advtaser) + crate_name = "taser crate" + +/datum/supply_pack/security/disabler + name = "Disabler Crate" + cost = 1500 + contains = list(/obj/item/gun/energy/disabler, + /obj/item/gun/energy/disabler, + /obj/item/gun/energy/disabler) + crate_name = "disabler crate" + +/datum/supply_pack/security/forensics + name = "Forensics Crate" + cost = 2000 + contains = list(/obj/item/device/detective_scanner, + /obj/item/storage/box/evidence, + /obj/item/device/camera, + /obj/item/device/taperecorder, + /obj/item/toy/crayon/white, + /obj/item/clothing/head/fedora/det_hat) + crate_name = "forensics crate" + +/datum/supply_pack/security/armory + access = ACCESS_ARMORY + crate_type = /obj/structure/closet/crate/secure/weapon + +/datum/supply_pack/security/armory/riothelmets + name = "Riot Helmets Crate" + cost = 1500 + contains = list(/obj/item/clothing/head/helmet/riot, + /obj/item/clothing/head/helmet/riot, + /obj/item/clothing/head/helmet/riot) + crate_name = "riot helmets crate" + +/datum/supply_pack/security/armory/riotarmor + name = "Riot Armor Crate" + cost = 1500 + contains = list(/obj/item/clothing/suit/armor/riot, + /obj/item/clothing/suit/armor/riot, + /obj/item/clothing/suit/armor/riot) + crate_name = "riot armor crate" + +/datum/supply_pack/security/armory/riotshields + name = "Riot Shields Crate" + cost = 2000 + contains = list(/obj/item/shield/riot, + /obj/item/shield/riot, + /obj/item/shield/riot) + crate_name = "riot shields crate" + +/datum/supply_pack/security/armory/bulletarmor + name = "Bulletproof Armor Crate" + cost = 1500 + contains = list(/obj/item/clothing/suit/armor/bulletproof, + /obj/item/clothing/suit/armor/bulletproof, + /obj/item/clothing/suit/armor/bulletproof) + crate_name = "bulletproof armor crate" + +/datum/supply_pack/security/armory/swat + name = "SWAT Crate" + cost = 6000 + contains = list(/obj/item/clothing/head/helmet/swat/nanotrasen, + /obj/item/clothing/head/helmet/swat/nanotrasen, + /obj/item/clothing/suit/space/swat, + /obj/item/clothing/suit/space/swat, + /obj/item/clothing/mask/gas/sechailer/swat, + /obj/item/clothing/mask/gas/sechailer/swat, + /obj/item/storage/belt/military/assault, + /obj/item/storage/belt/military/assault, + /obj/item/clothing/gloves/combat, + /obj/item/clothing/gloves/combat) + crate_name = "swat crate" + +/datum/supply_pack/security/armory/combatknives + name = "Combat Knives Crate" + cost = 3000 + contains = list(/obj/item/kitchen/knife/combat, + /obj/item/kitchen/knife/combat, + /obj/item/kitchen/knife/combat) + crate_name = "combat knife crate" + +/datum/supply_pack/security/armory/laserarmor + name = "Reflector Vest Crate" + cost = 2000 + contains = list(/obj/item/clothing/suit/armor/laserproof, + /obj/item/clothing/suit/armor/laserproof) + crate_name = "reflector vest crate" + crate_type = /obj/structure/closet/crate/secure/plasma + +/datum/supply_pack/security/armory/ballistic + name = "Combat Shotguns Crate" + cost = 8000 + contains = list(/obj/item/gun/ballistic/shotgun/automatic/combat, + /obj/item/gun/ballistic/shotgun/automatic/combat, + /obj/item/gun/ballistic/shotgun/automatic/combat, + /obj/item/storage/belt/bandolier, + /obj/item/storage/belt/bandolier, + /obj/item/storage/belt/bandolier) + crate_name = "combat shotguns crate" + +/datum/supply_pack/security/armory/energy + name = "Energy Guns Crate" + cost = 2500 + contains = list(/obj/item/gun/energy/e_gun, + /obj/item/gun/energy/e_gun) + crate_name = "energy gun crate" + crate_type = /obj/structure/closet/crate/secure/plasma + +/datum/supply_pack/security/armory/fire + name = "Incendiary Weapons Crate" + cost = 1500 + access = ACCESS_HEADS + contains = list(/obj/item/flamethrower/full, + /obj/item/tank/internals/plasma, + /obj/item/tank/internals/plasma, + /obj/item/tank/internals/plasma, + /obj/item/grenade/chem_grenade/incendiary, + /obj/item/grenade/chem_grenade/incendiary, + /obj/item/grenade/chem_grenade/incendiary) + crate_name = "incendiary weapons crate" + crate_type = /obj/structure/closet/crate/secure/plasma + dangerous = TRUE + +/datum/supply_pack/security/armory/wt550 + name = "WT-550 Auto Rifle Crate" + cost = 3500 + contains = list(/obj/item/gun/ballistic/automatic/wt550, + /obj/item/gun/ballistic/automatic/wt550) + crate_name = "auto rifle crate" + +/datum/supply_pack/security/armory/wt550ammo + name = "WT-550 Auto Rifle Ammo Crate" + cost = 3000 + contains = list(/obj/item/ammo_box/magazine/wt550m9, + /obj/item/ammo_box/magazine/wt550m9, + /obj/item/ammo_box/magazine/wt550m9, + /obj/item/ammo_box/magazine/wt550m9) + crate_name = "auto rifle ammo crate" + +/datum/supply_pack/security/armory/mindshield + name = "mindshield implants Crate" + cost = 4000 + contains = list(/obj/item/storage/lockbox/loyalty) + crate_name = "mindshield implant crate" + +/datum/supply_pack/security/armory/trackingimp + name = "Tracking Implants Crate" + cost = 2000 + contains = list(/obj/item/storage/box/trackimp) + crate_name = "tracking implant crate" + +/datum/supply_pack/security/armory/chemimp + name = "Chemical Implants Crate" + cost = 2000 + contains = list(/obj/item/storage/box/chemimp) + crate_name = "chemical implant crate" + +/datum/supply_pack/security/armory/exileimp + name = "Exile Implants Crate" + cost = 3000 + contains = list(/obj/item/storage/box/exileimp) + crate_name = "exile implant crate" + +/datum/supply_pack/security/securitybarriers + name = "Security Barriers Crate" + contains = list(/obj/item/grenade/barrier, + /obj/item/grenade/barrier, + /obj/item/grenade/barrier, + /obj/item/grenade/barrier) + cost = 2000 + crate_name = "security barriers crate" + +/datum/supply_pack/security/firingpins + name = "Standard Firing Pins Crate" + cost = 2000 + contains = list(/obj/item/storage/box/firingpins, + /obj/item/storage/box/firingpins) + crate_name = "firing pins crate" + +/datum/supply_pack/security/securityclothes + name = "Security Clothing Crate" + cost = 3000 + contains = list(/obj/item/clothing/under/rank/security/navyblue, + /obj/item/clothing/under/rank/security/navyblue, + /obj/item/clothing/suit/security/officer, + /obj/item/clothing/suit/security/officer, + /obj/item/clothing/head/beret/sec/navyofficer, + /obj/item/clothing/head/beret/sec/navyofficer, + /obj/item/clothing/under/rank/warden/navyblue, + /obj/item/clothing/suit/security/warden, + /obj/item/clothing/head/beret/sec/navywarden, + /obj/item/clothing/under/rank/head_of_security/navyblue, + /obj/item/clothing/suit/security/hos, + /obj/item/clothing/head/beret/sec/navyhos) + crate_name = "security clothing crate" + +/datum/supply_pack/security/justiceinbound + name = "Standard Justice Enforcer Crate" + cost = 6000 //justice comes at a price. An expensive, noisy price. + contraband = TRUE + contains = list(/obj/item/clothing/head/helmet/justice, + /obj/item/clothing/mask/gas/sechailer) + crate_name = "security clothing crate" + +////////////////////////////////////////////////////////////////////////////// +//////////////////////////// Engineering ///////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +/datum/supply_pack/engineering + group = "Engineering" + crate_type = /obj/structure/closet/crate/engineering + +/datum/supply_pack/engineering/fueltank + name = "Fuel Tank Crate" + cost = 800 + contains = list(/obj/structure/reagent_dispensers/fueltank) + crate_name = "fuel tank crate" + crate_type = /obj/structure/closet/crate/large + +/datum/supply_pack/engineering/oxygen + name = "Oxygen Canister" + cost = 1500 + contains = list(/obj/machinery/portable_atmospherics/canister/oxygen) + crate_name = "oxygen canister crate" + crate_type = /obj/structure/closet/crate/large + +/datum/supply_pack/engineering/nitrogen + name = "Nitrogen Canister" + cost = 2000 + contains = list(/obj/machinery/portable_atmospherics/canister/nitrogen) + crate_name = "nitrogen canister crate" + crate_type = /obj/structure/closet/crate/large + +/datum/supply_pack/engineering/carbon_dio + name = "Carbon Dioxide Canister" + cost = 3000 + contains = list(/obj/machinery/portable_atmospherics/canister/carbon_dioxide) + crate_name = "carbon dioxide canister crate" + crate_type = /obj/structure/closet/crate/large + +/datum/supply_pack/science/nitrous_oxide_canister + name = "Nitrous Oxide Canister" + cost = 3000 + access = ACCESS_ATMOSPHERICS + contains = list(/obj/machinery/portable_atmospherics/canister/nitrous_oxide) + crate_name = "nitrous oxide canister crate" + crate_type = /obj/structure/closet/crate/secure + +/datum/supply_pack/engineering/tools + name = "Toolbox Crate" + contains = list(/obj/item/storage/toolbox/electrical, + /obj/item/storage/toolbox/electrical, + /obj/item/storage/toolbox/mechanical, + /obj/item/storage/toolbox/electrical, + /obj/item/storage/toolbox/mechanical, + /obj/item/storage/toolbox/mechanical) + cost = 1000 + crate_name = "toolbox crate" + +/datum/supply_pack/engineering/powergamermitts + name = "Insulated Gloves Crate" + cost = 2000 //Made of pure-grade bullshittinium + contains = list(/obj/item/clothing/gloves/color/yellow, + /obj/item/clothing/gloves/color/yellow, + /obj/item/clothing/gloves/color/yellow) + crate_name = "insulated gloves crate" + +/datum/supply_pack/engineering/power + name = "Powercell Crate" + cost = 1000 + contains = list(/obj/item/stock_parts/cell/high, + /obj/item/stock_parts/cell/high, + /obj/item/stock_parts/cell/high) + crate_name = "electrical maintenance crate" + crate_type = /obj/structure/closet/crate/engineering/electrical + +/obj/item/stock_parts/cell/inducer_supply + maxcharge = 5000 + charge = 5000 + +/datum/supply_pack/engineering/inducers + name = "NT-75 Electromagnetic Power Inducers Crate" + cost = 2000 + contains = list(/obj/item/inducer/sci {cell_type = /obj/item/stock_parts/cell/inducer_supply; opened = 0}, /obj/item/inducer/sci {cell_type = /obj/item/stock_parts/cell/inducer_supply; opened = 0}) //FALSE doesn't work in modified type paths apparently. + crate_name = "inducer crate" + crate_type = /obj/structure/closet/crate/engineering/electrical + +/datum/supply_pack/engineering/engiequipment + name = "Engineering Gear Crate" + cost = 1300 + contains = list(/obj/item/storage/belt/utility, + /obj/item/storage/belt/utility, + /obj/item/storage/belt/utility, + /obj/item/clothing/suit/hazardvest, + /obj/item/clothing/suit/hazardvest, + /obj/item/clothing/suit/hazardvest, + /obj/item/clothing/head/welding, + /obj/item/clothing/head/welding, + /obj/item/clothing/head/welding, + /obj/item/clothing/head/hardhat, + /obj/item/clothing/head/hardhat, + /obj/item/clothing/head/hardhat, + /obj/item/clothing/glasses/meson/engine, + /obj/item/clothing/glasses/meson/engine) + crate_name = "engineering gear crate" + + +/datum/supply_pack/engineering/shieldgen + name = "Anti-breach Shield Projector Crate" + cost = 2500 + contains = list(/obj/machinery/shieldgen, + /obj/machinery/shieldgen) + crate_name = "anti-breach shield projector crate" + +/datum/supply_pack/engineering/grounding_rods + name = "Grounding Rod Crate" + cost = 1700 + contains = list(/obj/machinery/power/grounding_rod, + /obj/machinery/power/grounding_rod, + /obj/machinery/power/grounding_rod, + /obj/machinery/power/grounding_rod) + crate_name = "grounding rod crate" + crate_type = /obj/structure/closet/crate/engineering/electrical + +/datum/supply_pack/engineering/pacman + name = "P.A.C.M.A.N Generator Crate" + cost = 2500 + contains = list(/obj/machinery/power/port_gen/pacman) + crate_name = "PACMAN generator crate" + crate_type = /obj/structure/closet/crate/engineering/electrical + +/datum/supply_pack/engineering/solar + name = "Solar Panel Crate" + cost = 2000 + contains = list(/obj/item/solar_assembly, + /obj/item/solar_assembly, + /obj/item/solar_assembly, + /obj/item/solar_assembly, + /obj/item/solar_assembly, + /obj/item/solar_assembly, + /obj/item/solar_assembly, + /obj/item/solar_assembly, + /obj/item/solar_assembly, + /obj/item/solar_assembly, + /obj/item/solar_assembly, + /obj/item/solar_assembly, + /obj/item/solar_assembly, + /obj/item/solar_assembly, + /obj/item/solar_assembly, + /obj/item/solar_assembly, + /obj/item/solar_assembly, + /obj/item/solar_assembly, + /obj/item/solar_assembly, + /obj/item/solar_assembly, + /obj/item/solar_assembly, + /obj/item/circuitboard/computer/solar_control, + /obj/item/electronics/tracker, + /obj/item/paper/guides/jobs/engi/solars) + crate_name = "solar panel crate" + crate_type = /obj/structure/closet/crate/engineering/electrical + +/datum/supply_pack/engineering/engine + name = "Emitter Crate" + cost = 1500 + access = ACCESS_CE + contains = list(/obj/machinery/power/emitter, + /obj/machinery/power/emitter) + crate_name = "emitter crate" + crate_type = /obj/structure/closet/crate/secure/engineering + dangerous = TRUE + +/datum/supply_pack/engineering/engine/field_gen + name = "Field Generator Crate" + cost = 1500 + contains = list(/obj/machinery/field/generator, + /obj/machinery/field/generator) + crate_name = "field generator crate" + +/datum/supply_pack/engineering/engine/sing_gen + name = "Singularity Generator Crate" + cost = 5000 + contains = list(/obj/machinery/the_singularitygen) + crate_name = "singularity generator crate" + +/datum/supply_pack/engineering/engine/tesla_gen + name = "Tesla Generator Crate" + cost = 5000 + contains = list(/obj/machinery/the_singularitygen/tesla) + crate_name = "tesla generator crate" + +/datum/supply_pack/engineering/engine/collector + name = "Collector Crate" + cost = 2500 + contains = list(/obj/machinery/power/rad_collector, + /obj/machinery/power/rad_collector, + /obj/machinery/power/rad_collector) + crate_name = "collector crate" + +/datum/supply_pack/engineering/engine/PA + name = "Particle Accelerator Crate" + cost = 3000 + contains = list(/obj/structure/particle_accelerator/fuel_chamber, + /obj/machinery/particle_accelerator/control_box, + /obj/structure/particle_accelerator/particle_emitter/center, + /obj/structure/particle_accelerator/particle_emitter/left, + /obj/structure/particle_accelerator/particle_emitter/right, + /obj/structure/particle_accelerator/power_box, + /obj/structure/particle_accelerator/end_cap) + crate_name = "particle accelerator crate" + +/datum/supply_pack/engineering/engine/supermatter_shard + name = "Supermatter Shard Crate" + cost = 10000 + access = ACCESS_CE + contains = list(/obj/machinery/power/supermatter_shard) + crate_name = "supermatter shard crate" + crate_type = /obj/structure/closet/crate/secure/engineering + dangerous = TRUE + +/datum/supply_pack/engineering/engine/am_shielding + name = "Antimatter Shielding Crate" + cost = 2000 + contains = list(/obj/item/device/am_shielding_container, + /obj/item/device/am_shielding_container, + /obj/item/device/am_shielding_container, + /obj/item/device/am_shielding_container, + /obj/item/device/am_shielding_container, + /obj/item/device/am_shielding_container, + /obj/item/device/am_shielding_container, + /obj/item/device/am_shielding_container, + /obj/item/device/am_shielding_container, + /obj/item/device/am_shielding_container)//10 shields: 3x3 containment and a core + crate_name = "antimatter shielding crate" + +/datum/supply_pack/engineering/engine/am_core + name = "Antimatter Control Crate" + cost = 5000 + contains = list(/obj/machinery/power/am_control_unit) + crate_name = "antimatter control crate" + +/datum/supply_pack/engineering/engine/am_jar + name = "Antimatter Containment Jar Crate" + cost = 2000 + contains = list(/obj/item/am_containment, + /obj/item/am_containment) + crate_name = "antimatter jar crate" + +/datum/supply_pack/engineering/shuttle_engine + name = "Shuttle Engine Crate" + cost = 5000 + access = ACCESS_CE + contains = list(/obj/structure/shuttle/engine/propulsion/burst/cargo) + crate_name = "shuttle engine crate" + crate_type = /obj/structure/closet/crate/secure/engineering + special = TRUE + +////////////////////////////////////////////////////////////////////////////// +//////////////////////////// Medical ///////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +/datum/supply_pack/medical + group = "Medical" + crate_type = /obj/structure/closet/crate/medical + +/datum/supply_pack/medical/supplies + name = "Medical Supplies Crate" + cost = 2000 + contains = list(/obj/item/reagent_containers/glass/bottle/charcoal, + /obj/item/reagent_containers/glass/bottle/charcoal, + /obj/item/reagent_containers/glass/bottle/epinephrine, + /obj/item/reagent_containers/glass/bottle/epinephrine, + /obj/item/reagent_containers/glass/bottle/morphine, + /obj/item/reagent_containers/glass/bottle/morphine, + /obj/item/reagent_containers/glass/bottle/morphine, + /obj/item/reagent_containers/glass/bottle/morphine, + /obj/item/reagent_containers/glass/bottle/morphine, + /obj/item/reagent_containers/glass/bottle/morphine, + /obj/item/reagent_containers/glass/bottle/toxin, + /obj/item/reagent_containers/glass/bottle/toxin, + /obj/item/reagent_containers/glass/beaker/large, + /obj/item/reagent_containers/glass/beaker/large, + /obj/item/reagent_containers/pill/insulin, + /obj/item/reagent_containers/pill/insulin, + /obj/item/reagent_containers/pill/insulin, + /obj/item/reagent_containers/pill/insulin, + /obj/item/stack/medical/gauze, + /obj/item/storage/box/beakers, + /obj/item/storage/box/syringes, + /obj/item/storage/box/bodybags) + crate_name = "medical supplies crate" + +/datum/supply_pack/medical/firstaid + name = "First Aid Kit Crate" + cost = 1000 + contains = list(/obj/item/storage/firstaid/regular, + /obj/item/storage/firstaid/regular, + /obj/item/storage/firstaid/regular, + /obj/item/storage/firstaid/regular) + crate_name = "first aid kit crate" + +/datum/supply_pack/medical/firstaidbruises + name = "Bruise Treatment Kit Crate" + cost = 1000 + contains = list(/obj/item/storage/firstaid/brute, + /obj/item/storage/firstaid/brute, + /obj/item/storage/firstaid/brute) + crate_name = "brute treatment kit crate" + +/datum/supply_pack/medical/firstaidburns + name = "Burn Treatment Kit Crate" + cost = 1000 + contains = list(/obj/item/storage/firstaid/fire, + /obj/item/storage/firstaid/fire, + /obj/item/storage/firstaid/fire) + crate_name = "burn treatment kit crate" + +/datum/supply_pack/medical/firstaidtoxins + name = "Toxin Treatment Kit Crate" + cost = 1000 + contains = list(/obj/item/storage/firstaid/toxin, + /obj/item/storage/firstaid/toxin, + /obj/item/storage/firstaid/toxin) + crate_name = "toxin treatment kit crate" + +/datum/supply_pack/medical/firstaidoxygen + name = "Oxygen Deprivation Kit Crate" + cost = 1000 + contains = list(/obj/item/storage/firstaid/o2, + /obj/item/storage/firstaid/o2, + /obj/item/storage/firstaid/o2) + crate_name = "oxygen deprivation kit crate" + +/datum/supply_pack/medical/virus + name = "Virus Crate" + cost = 2500 + access = ACCESS_CMO + contains = list(/obj/item/reagent_containers/glass/bottle/flu_virion, + /obj/item/reagent_containers/glass/bottle/cold, + /obj/item/reagent_containers/glass/bottle/epiglottis_virion, + /obj/item/reagent_containers/glass/bottle/liver_enhance_virion, + /obj/item/reagent_containers/glass/bottle/fake_gbs, + /obj/item/reagent_containers/glass/bottle/magnitis, + /obj/item/reagent_containers/glass/bottle/pierrot_throat, + /obj/item/reagent_containers/glass/bottle/brainrot, + /obj/item/reagent_containers/glass/bottle/hallucigen_virion, + /obj/item/reagent_containers/glass/bottle/anxiety, + /obj/item/reagent_containers/glass/bottle/beesease, + /obj/item/storage/box/syringes, + /obj/item/storage/box/beakers, + /obj/item/reagent_containers/glass/bottle/mutagen) + crate_name = "virus crate" + crate_type = /obj/structure/closet/crate/secure/plasma + dangerous = TRUE + +/datum/supply_pack/medical/bloodpacks + name = "Blood Pack Variety Crate" + cost = 3500 + contains = list(/obj/item/reagent_containers/blood/empty, + /obj/item/reagent_containers/blood/empty, + /obj/item/reagent_containers/blood/APlus, + /obj/item/reagent_containers/blood/AMinus, + /obj/item/reagent_containers/blood/BPlus, + /obj/item/reagent_containers/blood/BMinus, + /obj/item/reagent_containers/blood/OPlus, + /obj/item/reagent_containers/blood/OMinus) + crate_name = "blood freezer" + crate_type = /obj/structure/closet/crate/freezer + +/datum/supply_pack/medical/iv_drip + name = "IV Drip Crate" + cost = 1000 + contains = list(/obj/machinery/iv_drip) + crate_name = "iv drip crate" + +/datum/supply_pack/medical/defibs + name = "Defibrillator Crate" + cost = 2500 + contains = list(/obj/item/defibrillator/loaded, + /obj/item/defibrillator/loaded) + crate_name = "defibrillator crate" + +/datum/supply_pack/medical/vending + name = "Medical Vending Crate" + cost = 2000 + contains = list(/obj/item/vending_refill/medical, + /obj/item/vending_refill/medical, + /obj/item/vending_refill/medical) + crate_name = "medical vending crate" + +////////////////////////////////////////////////////////////////////////////// +//////////////////////////// Science ///////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +/datum/supply_pack/science + group = "Science" + crate_type = /obj/structure/closet/crate/science + +/datum/supply_pack/science/bz + name = "BZ canister" + cost = 4000 + access = ACCESS_TOX_STORAGE + contains = list(/obj/machinery/portable_atmospherics/canister/bz) + crate_name = "BZ canister crate" + crate_type = /obj/structure/closet/crate/secure/science + +/datum/supply_pack/science/robotics + name = "Robotics Assembly Crate" + cost = 1000 + access = ACCESS_ROBOTICS + contains = list(/obj/item/device/assembly/prox_sensor, + /obj/item/device/assembly/prox_sensor, + /obj/item/device/assembly/prox_sensor, + /obj/item/storage/toolbox/electrical, + /obj/item/storage/box/flashes, + /obj/item/stock_parts/cell/high, + /obj/item/stock_parts/cell/high) + crate_name = "robotics assembly crate" + crate_type = /obj/structure/closet/crate/secure/science + +/datum/supply_pack/science/robotics/mecha_ripley + name = "Circuit Crate (Ripley APLU)" + cost = 3000 + access = ACCESS_ROBOTICS + contains = list(/obj/item/book/manual/ripley_build_and_repair, + /obj/item/circuitboard/mecha/ripley/main, + /obj/item/circuitboard/mecha/ripley/peripherals) + crate_name = "\improper APLU Ripley circuit crate" + crate_type = /obj/structure/closet/crate/secure/science + +/datum/supply_pack/science/robotics/mecha_odysseus + name = "Circuit Crate (Odysseus)" + cost = 2500 + access = ACCESS_ROBOTICS + contains = list(/obj/item/circuitboard/mecha/odysseus/peripherals, + /obj/item/circuitboard/mecha/odysseus/main) + crate_name = "\improper Odysseus circuit crate" + crate_type = /obj/structure/closet/crate/secure/science + +/datum/supply_pack/science/plasma + name = "Plasma Assembly Crate" + cost = 1000 + access = ACCESS_TOX_STORAGE + contains = list(/obj/item/tank/internals/plasma, + /obj/item/tank/internals/plasma, + /obj/item/tank/internals/plasma, + /obj/item/device/assembly/igniter, + /obj/item/device/assembly/igniter, + /obj/item/device/assembly/igniter, + /obj/item/device/assembly/prox_sensor, + /obj/item/device/assembly/prox_sensor, + /obj/item/device/assembly/prox_sensor, + /obj/item/device/assembly/timer, + /obj/item/device/assembly/timer, + /obj/item/device/assembly/timer) + crate_name = "plasma assembly crate" + crate_type = /obj/structure/closet/crate/secure/plasma + +/datum/supply_pack/science/shieldwalls + name = "Shield Generators" + cost = 2000 + access = ACCESS_TELEPORTER + contains = list(/obj/machinery/shieldwallgen, + /obj/machinery/shieldwallgen, + /obj/machinery/shieldwallgen, + /obj/machinery/shieldwallgen) + crate_name = "shield generators crate" + crate_type = /obj/structure/closet/crate/secure/science + +/datum/supply_pack/science/transfer_valves + name = "Tank Transfer Valves Crate" + cost = 6000 + access = ACCESS_RD + contains = list(/obj/item/device/transfer_valve, + /obj/item/device/transfer_valve) + crate_name = "tank transfer valves crate" + crate_type = /obj/structure/closet/crate/secure/science + dangerous = TRUE + +/datum/supply_pack/science/tablets + name = "Tablet Crate" + cost = 5000 + contains = list(/obj/item/device/modular_computer/tablet/preset/cargo, + /obj/item/device/modular_computer/tablet/preset/cargo, + /obj/item/device/modular_computer/tablet/preset/cargo, + /obj/item/device/modular_computer/tablet/preset/cargo, + /obj/item/device/modular_computer/tablet/preset/cargo) + crate_name = "tablet crate" + +////////////////////////////////////////////////////////////////////////////// +//////////////////////////// Organic ///////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +/datum/supply_pack/organic + group = "Food & Livestock" + crate_type = /obj/structure/closet/crate/freezer + +/datum/supply_pack/organic/food + name = "Food Crate" + cost = 1000 + contains = list(/obj/item/reagent_containers/food/condiment/flour, + /obj/item/reagent_containers/food/condiment/rice, + /obj/item/reagent_containers/food/condiment/milk, + /obj/item/reagent_containers/food/condiment/soymilk, + /obj/item/reagent_containers/food/condiment/saltshaker, + /obj/item/reagent_containers/food/condiment/peppermill, + /obj/item/storage/fancy/egg_box, + /obj/item/reagent_containers/food/condiment/enzyme, + /obj/item/reagent_containers/food/condiment/sugar, + /obj/item/reagent_containers/food/snacks/meat/slab/monkey, + /obj/item/reagent_containers/food/snacks/grown/banana, + /obj/item/reagent_containers/food/snacks/grown/banana, + /obj/item/reagent_containers/food/snacks/grown/banana) + crate_name = "food crate" + +/datum/supply_pack/organic/pizza + name = "Pizza Crate" + cost = 6000 // Best prices this side of the galaxy. + contains = list(/obj/item/pizzabox/margherita, + /obj/item/pizzabox/mushroom, + /obj/item/pizzabox/meat, + /obj/item/pizzabox/vegetable) + crate_name = "pizza crate" + +/datum/supply_pack/organic/cream_piee + name = "High-yield Clown-grade Cream Pie Crate" + cost = 6000 + contains = list(/obj/item/storage/backpack/duffelbag/clown/cream_pie) + crate_name = "party equipment crate" + contraband = TRUE + access = ACCESS_THEATRE + crate_type = /obj/structure/closet/crate/secure + +/datum/supply_pack/organic/monkey + name = "Monkey Crate" + cost = 2000 + contains = list (/obj/item/storage/box/monkeycubes) + crate_name = "monkey crate" + +/datum/supply_pack/organic/party + name = "Party Equipment" + cost = 2000 + contains = list(/obj/item/storage/box/drinkingglasses, + /obj/item/reagent_containers/food/drinks/shaker, + /obj/item/reagent_containers/food/drinks/bottle/patron, + /obj/item/reagent_containers/food/drinks/bottle/goldschlager, + /obj/item/reagent_containers/food/drinks/ale, + /obj/item/reagent_containers/food/drinks/ale, + /obj/item/reagent_containers/food/drinks/beer, + /obj/item/reagent_containers/food/drinks/beer, + /obj/item/reagent_containers/food/drinks/beer, + /obj/item/reagent_containers/food/drinks/beer, + /obj/item/device/flashlight/glowstick, + /obj/item/device/flashlight/glowstick/red, + /obj/item/device/flashlight/glowstick/blue, + /obj/item/device/flashlight/glowstick/cyan, + /obj/item/device/flashlight/glowstick/orange, + /obj/item/device/flashlight/glowstick/yellow, + /obj/item/device/flashlight/glowstick/pink) + crate_name = "party equipment crate" + +/datum/supply_pack/organic/critter + crate_type = /obj/structure/closet/crate/critter + +/datum/supply_pack/organic/critter/cow + name = "Cow Crate" + cost = 3000 + contains = list(/mob/living/simple_animal/cow) + crate_name = "cow crate" + +/datum/supply_pack/organic/critter/goat + name = "Goat Crate" + cost = 2500 + contains = list(/mob/living/simple_animal/hostile/retaliate/goat) + crate_name = "goat crate" + +/datum/supply_pack/organic/critter/snake + name = "Snake Crate" + cost = 3000 + contains = list(/mob/living/simple_animal/hostile/retaliate/poison/snake, + /mob/living/simple_animal/hostile/retaliate/poison/snake, + /mob/living/simple_animal/hostile/retaliate/poison/snake) + crate_name = "snake crate" + +/datum/supply_pack/organic/critter/chick + name = "Chicken Crate" + cost = 2000 + contains = list( /mob/living/simple_animal/chick) + crate_name = "chicken crate" + +/datum/supply_pack/organic/critter/corgi + name = "Corgi Crate" + cost = 5000 + contains = list(/mob/living/simple_animal/pet/dog/corgi, + /obj/item/clothing/neck/petcollar) + crate_name = "corgi crate" + +/datum/supply_pack/organic/critter/corgi/generate() + . = ..() + if(prob(50)) + var/mob/living/simple_animal/pet/dog/corgi/D = locate() in . + qdel(D) + new /mob/living/simple_animal/pet/dog/corgi/Lisa(.) + +/datum/supply_pack/organic/critter/cat + name = "Cat Crate" + cost = 5000 //Cats are worth as much as corgis. + contains = list(/mob/living/simple_animal/pet/cat, + /obj/item/clothing/neck/petcollar, + /obj/item/toy/cattoy) + crate_name = "cat crate" + +/datum/supply_pack/organic/critter/cat/generate() + . = ..() + if(prob(50)) + var/mob/living/simple_animal/pet/cat/C = locate() in . + qdel(C) + new /mob/living/simple_animal/pet/cat/Proc(.) + +/datum/supply_pack/organic/critter/pug + name = "Pug Crate" + cost = 5000 + contains = list(/mob/living/simple_animal/pet/dog/pug, + /obj/item/clothing/neck/petcollar) + crate_name = "pug crate" + +/datum/supply_pack/organic/critter/fox + name = "Fox Crate" + cost = 5000 + contains = list(/mob/living/simple_animal/pet/fox, + /obj/item/clothing/neck/petcollar) + crate_name = "fox crate" + +/datum/supply_pack/organic/critter/butterfly + name = "Butterflies Crate" + contraband = TRUE + cost = 5000 + contains = list(/mob/living/simple_animal/butterfly) + crate_name = "entomology samples crate" + +/datum/supply_pack/organic/critter/butterfly/generate() + . = ..() + for(var/i in 1 to 49) + new /mob/living/simple_animal/butterfly(.) + +/datum/supply_pack/organic/hydroponics + name = "Hydroponics Crate" + cost = 1500 + contains = list(/obj/item/reagent_containers/spray/plantbgone, + /obj/item/reagent_containers/spray/plantbgone, + /obj/item/reagent_containers/glass/bottle/ammonia, + /obj/item/reagent_containers/glass/bottle/ammonia, + /obj/item/hatchet, + /obj/item/cultivator, + /obj/item/device/plant_analyzer, + /obj/item/clothing/gloves/botanic_leather, + /obj/item/clothing/suit/apron) + crate_name = "hydroponics crate" + crate_type = /obj/structure/closet/crate/hydroponics + +/datum/supply_pack/organic/hydroponics/hydrotank + name = "Hydroponics Backpack Crate" + cost = 1000 + access = ACCESS_HYDROPONICS + contains = list(/obj/item/watertank) + crate_name = "hydroponics backpack crate" + crate_type = /obj/structure/closet/crate/secure + +/datum/supply_pack/organic/potted_plants + name = "Potted Plants Crate" + cost = 700 + contains = list(/obj/item/twohanded/required/kirbyplants/random, + /obj/item/twohanded/required/kirbyplants/random, + /obj/item/twohanded/required/kirbyplants/random, + /obj/item/twohanded/required/kirbyplants/random, + /obj/item/twohanded/required/kirbyplants/random) + crate_name = "potted plants crate" + crate_type = /obj/structure/closet/crate/hydroponics + +/datum/supply_pack/organic/hydroponics/seeds + name = "Seeds Crate" + cost = 1000 + contains = list(/obj/item/seeds/chili, + /obj/item/seeds/berry, + /obj/item/seeds/corn, + /obj/item/seeds/eggplant, + /obj/item/seeds/tomato, + /obj/item/seeds/soya, + /obj/item/seeds/wheat, + /obj/item/seeds/wheat/rice, + /obj/item/seeds/carrot, + /obj/item/seeds/sunflower, + /obj/item/seeds/chanter, + /obj/item/seeds/potato, + /obj/item/seeds/sugarcane) + crate_name = "seeds crate" + +/datum/supply_pack/organic/hydroponics/exoticseeds + name = "Exotic Seeds Crate" + cost = 1500 + contains = list(/obj/item/seeds/nettle, + /obj/item/seeds/replicapod, + /obj/item/seeds/replicapod, + /obj/item/seeds/replicapod, + /obj/item/seeds/plump, + /obj/item/seeds/liberty, + /obj/item/seeds/amanita, + /obj/item/seeds/reishi, + /obj/item/seeds/banana, + /obj/item/seeds/eggplant/eggy, + /obj/item/seeds/random, + /obj/item/seeds/random) + crate_name = "exotic seeds crate" + +/datum/supply_pack/organic/hydroponics/beekeeping_fullkit + name = "Beekeeping Starter Crate" + cost = 1500 + contains = list(/obj/structure/beebox, + /obj/item/honey_frame, + /obj/item/honey_frame, + /obj/item/honey_frame, + /obj/item/queen_bee/bought, + /obj/item/clothing/head/beekeeper_head, + /obj/item/clothing/suit/beekeeper_suit, + /obj/item/melee/flyswatter) + crate_name = "beekeeping starter crate" + +/datum/supply_pack/organic/hydroponics/beekeeping_suits + name = "Beekeeper Suit Crate" + cost = 1000 + contains = list(/obj/item/clothing/head/beekeeper_head, + /obj/item/clothing/suit/beekeeper_suit, + /obj/item/clothing/head/beekeeper_head, + /obj/item/clothing/suit/beekeeper_suit) + crate_name = "beekeeper suits" + +/datum/supply_pack/organic/vending + name = "Bartending Supply Crate" + cost = 2000 + contains = list(/obj/item/vending_refill/boozeomat, + /obj/item/vending_refill/boozeomat, + /obj/item/vending_refill/boozeomat, + /obj/item/vending_refill/coffee, + /obj/item/vending_refill/coffee, + /obj/item/vending_refill/coffee) + crate_name = "bartending supply crate" + +/datum/supply_pack/organic/vending/snack + name = "Snack Supply Crate" + cost = 1500 + contains = list(/obj/item/vending_refill/snack, + /obj/item/vending_refill/snack, + /obj/item/vending_refill/snack) + crate_name = "snacks supply crate" + +/datum/supply_pack/organic/vending/cola + name = "Softdrinks Supply Crate" + cost = 1500 + contains = list(/obj/item/vending_refill/cola, + /obj/item/vending_refill/cola, + /obj/item/vending_refill/cola) + crate_name = "soft drinks supply crate" + +/datum/supply_pack/organic/vending/cigarette + name = "Cigarette Supply Crate" + cost = 1500 + contains = list(/obj/item/vending_refill/cigarette, + /obj/item/vending_refill/cigarette, + /obj/item/vending_refill/cigarette) + crate_name = "cigarette supply crate" + +/datum/supply_pack/organic/vending/games + name = "Games Supply Crate" + cost = 1000 + contains = list(/obj/item/vending_refill/games, + /obj/item/vending_refill/games, + /obj/item/vending_refill/games) + crate_name = "games supply crate" + +////////////////////////////////////////////////////////////////////////////// +//////////////////////////// Materials /////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +/datum/supply_pack/materials + group = "Raw Materials" + +/datum/supply_pack/materials/metal50 + name = "50 Metal Sheets" + cost = 1000 + contains = list(/obj/item/stack/sheet/metal/fifty) + crate_name = "metal sheets crate" + +/datum/supply_pack/materials/plasteel20 + name = "20 Plasteel Sheets" + cost = 7500 + contains = list(/obj/item/stack/sheet/plasteel/twenty) + crate_name = "plasteel sheets crate" + +/datum/supply_pack/materials/plasteel50 + name = "50 Plasteel Sheets" + cost = 16500 + contains = list(/obj/item/stack/sheet/plasteel/fifty) + crate_name = "plasteel sheets crate" + +/datum/supply_pack/materials/glass50 + name = "50 Glass Sheets" + cost = 1000 + contains = list(/obj/item/stack/sheet/glass/fifty) + crate_name = "glass sheets crate" + +/datum/supply_pack/materials/wood50 + name = "50 Wood Planks" + cost = 2000 + contains = list(/obj/item/stack/sheet/mineral/wood/fifty) + crate_name = "wood planks crate" + +/datum/supply_pack/materials/cardboard50 + name = "50 Cardboard Sheets" + cost = 1000 + contains = list(/obj/item/stack/sheet/cardboard/fifty) + crate_name = "cardboard sheets crate" + +/datum/supply_pack/materials/plastic50 + name = "50 Plastic Sheets" + cost = 1000 + contains = list(/obj/item/stack/sheet/plastic/fifty) + crate_name = "plastic sheets crate" + +/datum/supply_pack/materials/sandstone30 + name = "30 Sandstone Blocks" + cost = 1000 + contains = list(/obj/item/stack/sheet/mineral/sandstone/thirty) + crate_name = "sandstone blocks crate" + +////////////////////////////////////////////////////////////////////////////// +//////////////////////////// Miscellaneous /////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +/datum/supply_pack/misc + group = "Miscellaneous Supplies" + +/datum/supply_pack/misc/minerkit + name = "Shaft Miner Starter Kit" + cost = 2500 + access = ACCESS_QM + contains = list(/obj/item/pickaxe/mini, + /obj/item/clothing/glasses/meson, + /obj/item/device/t_scanner/adv_mining_scanner/lesser, + /obj/item/device/radio/headset/headset_cargo/mining, + /obj/item/storage/bag/ore, + /obj/item/clothing/suit/hooded/explorer, + /obj/item/clothing/mask/gas/explorer) + crate_name = "shaft miner starter kit" + crate_type = /obj/structure/closet/crate/secure + +/datum/supply_pack/misc/mule + name = "MULEbot Crate" + cost = 2000 + contains = list(/mob/living/simple_animal/bot/mulebot) + crate_name = "\improper MULEbot Crate" + crate_type = /obj/structure/closet/crate/large + +/datum/supply_pack/misc/conveyor + name = "Conveyor Assembly Crate" + cost = 1500 + contains = list(/obj/item/conveyor_construct, + /obj/item/conveyor_construct, + /obj/item/conveyor_construct, + /obj/item/conveyor_construct, + /obj/item/conveyor_construct, + /obj/item/conveyor_construct, + /obj/item/conveyor_switch_construct, + /obj/item/paper/guides/conveyor) + crate_name = "conveyor assembly crate" + +/datum/supply_pack/misc/watertank + name = "Water Tank Crate" + cost = 600 + contains = list(/obj/structure/reagent_dispensers/watertank) + crate_name = "water tank crate" + crate_type = /obj/structure/closet/crate/large + +/datum/supply_pack/misc/hightank + name = "High-Capacity Water Tank Crate" + cost = 1200 + contains = list(/obj/structure/reagent_dispensers/watertank/high) + crate_name = "high-capacity water tank crate" + crate_type = /obj/structure/closet/crate/large + +/datum/supply_pack/misc/water_vapor + name = "Water Vapor Canister" + cost = 2500 + contains = list(/obj/machinery/portable_atmospherics/canister/water_vapor) + crate_name = "water vapor canister crate" + crate_type = /obj/structure/closet/crate/large + +/datum/supply_pack/misc/lasertag + name = "Laser Tag Crate" + cost = 1500 + contains = list(/obj/item/gun/energy/laser/redtag, + /obj/item/gun/energy/laser/redtag, + /obj/item/gun/energy/laser/redtag, + /obj/item/gun/energy/laser/bluetag, + /obj/item/gun/energy/laser/bluetag, + /obj/item/gun/energy/laser/bluetag, + /obj/item/clothing/suit/redtag, + /obj/item/clothing/suit/redtag, + /obj/item/clothing/suit/redtag, + /obj/item/clothing/suit/bluetag, + /obj/item/clothing/suit/bluetag, + /obj/item/clothing/suit/bluetag, + /obj/item/clothing/head/helmet/redtaghelm, + /obj/item/clothing/head/helmet/redtaghelm, + /obj/item/clothing/head/helmet/redtaghelm, + /obj/item/clothing/head/helmet/bluetaghelm, + /obj/item/clothing/head/helmet/bluetaghelm, + /obj/item/clothing/head/helmet/bluetaghelm) + crate_name = "laser tag crate" + +/datum/supply_pack/misc/lasertag/pins + name = "Laser Tag Firing Pins Crate" + cost = 3000 + contraband = TRUE + contains = list(/obj/item/storage/box/lasertagpins) + crate_name = "laser tag crate" + +/datum/supply_pack/misc/clownpin + name = "Hilarious Firing Pin Crate" + cost = 5000 + contraband = TRUE + contains = list(/obj/item/device/firing_pin/clown) + // It's /technically/ a toy. For the clown, at least. + crate_name = "toy crate" + +/datum/supply_pack/misc/religious_supplies + name = "Religious Supplies Crate" + cost = 4000 // it costs so much because the Space Church is ran by Space Jews + contains = list(/obj/item/reagent_containers/food/drinks/bottle/holywater, + /obj/item/reagent_containers/food/drinks/bottle/holywater, + /obj/item/storage/book/bible/booze, + /obj/item/storage/book/bible/booze, + /obj/item/clothing/suit/hooded/chaplain_hoodie, + /obj/item/clothing/suit/hooded/chaplain_hoodie, + /obj/item/clothing/under/burial, + /obj/item/clothing/under/burial) + crate_name = "religious supplies crate" + +/datum/supply_pack/misc/book_crate + name = "Book Crate" + cost = 1500 + contains = list(/obj/item/book/codex_gigas, + /obj/item/book/manual/random/, + /obj/item/book/manual/random/, + /obj/item/book/manual/random/, + /obj/item/book/random/triple) + +/datum/supply_pack/misc/paper + name = "Bureaucracy Crate" + cost = 1500 + contains = list(/obj/structure/filingcabinet/chestdrawer/wheeled, + /obj/item/device/camera_film, + /obj/item/hand_labeler, + /obj/item/hand_labeler_refill, + /obj/item/hand_labeler_refill, + /obj/item/paper_bin, + /obj/item/pen/fourcolor, + /obj/item/pen/fourcolor, + /obj/item/pen, + /obj/item/pen/fountain, + /obj/item/pen/blue, + /obj/item/pen/red, + /obj/item/folder/blue, + /obj/item/folder/red, + /obj/item/folder/yellow, + /obj/item/clipboard, + /obj/item/clipboard, + /obj/item/stamp, + /obj/item/stamp/denied) + crate_name = "bureaucracy crate" + +/datum/supply_pack/misc/fountainpens + name = "Calligraphy Crate" + cost = 700 + contains = list(/obj/item/storage/box/fountainpens) + crate_type = /obj/structure/closet/crate/wooden + +/datum/supply_pack/misc/toner + name = "Toner Crate" + cost = 1000 + contains = list(/obj/item/device/toner, + /obj/item/device/toner, + /obj/item/device/toner, + /obj/item/device/toner, + /obj/item/device/toner, + /obj/item/device/toner) + crate_name = "toner crate" + +/datum/supply_pack/misc/janitor + name = "Janitorial Supplies Crate" + cost = 1000 + contains = list(/obj/item/reagent_containers/glass/bucket, + /obj/item/reagent_containers/glass/bucket, + /obj/item/reagent_containers/glass/bucket, + /obj/item/mop, + /obj/item/caution, + /obj/item/caution, + /obj/item/caution, + /obj/item/storage/bag/trash, + /obj/item/reagent_containers/spray/cleaner, + /obj/item/reagent_containers/glass/rag, + /obj/item/grenade/chem_grenade/cleaner, + /obj/item/grenade/chem_grenade/cleaner, + /obj/item/grenade/chem_grenade/cleaner) + crate_name = "janitorial supplies crate" + +/datum/supply_pack/misc/janitor/janicart + name = "Janitorial Cart and Galoshes Crate" + cost = 2000 + contains = list(/obj/structure/janitorialcart, + /obj/item/clothing/shoes/galoshes) + crate_name = "janitorial cart crate" + crate_type = /obj/structure/closet/crate/large + +/datum/supply_pack/misc/janitor/janitank + name = "Janitor Backpack Crate" + cost = 1000 + access = ACCESS_JANITOR + contains = list(/obj/item/watertank/janitor) + crate_name = "janitor backpack crate" + crate_type = /obj/structure/closet/crate/secure + +/datum/supply_pack/misc/janitor/lightbulbs + name = "Replacement Lights" + cost = 1000 + contains = list(/obj/item/storage/box/lights/mixed, + /obj/item/storage/box/lights/mixed, + /obj/item/storage/box/lights/mixed) + crate_name = "replacement lights" + +/datum/supply_pack/misc/noslipfloor + name = "High-traction Floor Tiles" + cost = 2000 + contains = list(/obj/item/stack/tile/noslip/thirty) + crate_name = "high-traction floor tiles crate" + +/datum/supply_pack/misc/plasmaman + name = "Plasmaman Supply Kit" + cost = 2000 + contains = list(/obj/item/clothing/under/plasmaman, + /obj/item/clothing/under/plasmaman, + /obj/item/tank/internals/plasmaman/belt/full, + /obj/item/tank/internals/plasmaman/belt/full, + /obj/item/clothing/head/helmet/space/plasmaman, + /obj/item/clothing/head/helmet/space/plasmaman) + crate_name = "plasmaman supply kit" + +/datum/supply_pack/misc/costume + name = "Standard Costume Crate" + cost = 1000 + access = ACCESS_THEATRE + contains = list(/obj/item/storage/backpack/clown, + /obj/item/clothing/shoes/clown_shoes, + /obj/item/clothing/mask/gas/clown_hat, + /obj/item/clothing/under/rank/clown, + /obj/item/bikehorn, + /obj/item/clothing/under/rank/mime, + /obj/item/clothing/shoes/sneakers/black, + /obj/item/clothing/gloves/color/white, + /obj/item/clothing/mask/gas/mime, + /obj/item/clothing/head/beret, + /obj/item/clothing/suit/suspenders, + /obj/item/reagent_containers/food/drinks/bottle/bottleofnothing, + /obj/item/storage/backpack/mime) + crate_name = "standard costume crate" + crate_type = /obj/structure/closet/crate/secure + +/datum/supply_pack/misc/costume_original + name = "Original Costume Crate" + cost = 1000 + contains = list(/obj/item/clothing/head/snowman, + /obj/item/clothing/suit/snowman, + /obj/item/clothing/head/chicken, + /obj/item/clothing/suit/chickensuit, + /obj/item/clothing/mask/gas/monkeymask, + /obj/item/clothing/suit/monkeysuit, + /obj/item/clothing/head/cardborg, + /obj/item/clothing/suit/cardborg, + /obj/item/clothing/head/xenos, + /obj/item/clothing/suit/xenos, + /obj/item/clothing/suit/hooded/ian_costume, + /obj/item/clothing/suit/hooded/carp_costume, + /obj/item/clothing/suit/hooded/bee_costume) + crate_name = "original costume crate" + +/datum/supply_pack/misc/wizard + name = "Wizard Costume Crate" + cost = 2000 + contains = list(/obj/item/staff, + /obj/item/clothing/suit/wizrobe/fake, + /obj/item/clothing/shoes/sandal, + /obj/item/clothing/head/wizard/fake) + crate_name = "wizard costume crate" + +/datum/supply_pack/misc/randomised + name = "Collectable Hats Crate!" + cost = 20000 + var/num_contained = 3 //number of items picked to be contained in a randomised crate + contains = list(/obj/item/clothing/head/collectable/chef, + /obj/item/clothing/head/collectable/paper, + /obj/item/clothing/head/collectable/tophat, + /obj/item/clothing/head/collectable/captain, + /obj/item/clothing/head/collectable/beret, + /obj/item/clothing/head/collectable/welding, + /obj/item/clothing/head/collectable/flatcap, + /obj/item/clothing/head/collectable/pirate, + /obj/item/clothing/head/collectable/kitty, + /obj/item/clothing/head/collectable/rabbitears, + /obj/item/clothing/head/collectable/wizard, + /obj/item/clothing/head/collectable/hardhat, + /obj/item/clothing/head/collectable/HoS, + /obj/item/clothing/head/collectable/HoP, + /obj/item/clothing/head/collectable/thunderdome, + /obj/item/clothing/head/collectable/swat, + /obj/item/clothing/head/collectable/slime, + /obj/item/clothing/head/collectable/police, + /obj/item/clothing/head/collectable/slime, + /obj/item/clothing/head/collectable/xenom, + /obj/item/clothing/head/collectable/petehat) + crate_name = "collectable hats crate" + +/datum/supply_pack/misc/randomised/fill(obj/structure/closet/crate/C) + var/list/L = contains.Copy() + for(var/i in 1 to num_contained) + var/item = pick_n_take(L) + new item(C) + +/datum/supply_pack/misc/bigband + contains = list(/obj/item/device/instrument/violin, + /obj/item/device/instrument/guitar, + /obj/item/device/instrument/glockenspiel, + /obj/item/device/instrument/accordion, + /obj/item/device/instrument/saxophone, + /obj/item/device/instrument/trombone, + /obj/item/device/instrument/recorder, + /obj/item/device/instrument/harmonica, + /obj/structure/piano/unanchored) + name = "Big band instrument collection" + cost = 5000 + crate_name = "Big band musical instruments collection" + +/datum/supply_pack/misc/randomised/contraband + name = "Contraband Crate" + contraband = TRUE + cost = 3000 + num_contained = 5 + contains = list(/obj/item/poster/random_contraband, + /obj/item/storage/fancy/cigarettes/cigpack_shadyjims, + /obj/item/storage/fancy/cigarettes/cigpack_midori, + /obj/item/seeds/ambrosia/deus, + /obj/item/clothing/neck/necklace/dope) + crate_name = "crate" + +/datum/supply_pack/misc/randomised/toys + name = "Toy Crate" + cost = 5000 // or play the arcade machines ya lazy bum + // TODO make this actually just use the arcade machine loot list + num_contained = 5 + contains = list(/obj/item/toy/spinningtoy, + /obj/item/toy/sword, + /obj/item/toy/foamblade, + /obj/item/toy/talking/AI, + /obj/item/toy/talking/owl, + /obj/item/toy/talking/griffin, + /obj/item/toy/nuke, + /obj/item/toy/minimeteor, + /obj/item/toy/plush/carpplushie, + /obj/item/toy/plush/lizardplushie, + /obj/item/toy/plush/snakeplushie, + /obj/item/toy/plush/nukeplushie, + /obj/item/toy/plush/slimeplushie, + /obj/item/coin/antagtoken, + /obj/item/stack/tile/fakespace/loaded, + /obj/item/gun/ballistic/shotgun/toy/crossbow, + /obj/item/toy/redbutton, + /obj/item/toy/eightball, + /obj/item/vending_refill/donksoft) + crate_name = "toy crate" + +/datum/supply_pack/misc/autodrobe + name = "Autodrobe Supply Crate" + cost = 1500 + contains = list(/obj/item/vending_refill/autodrobe, + /obj/item/vending_refill/autodrobe) + crate_name = "autodrobe supply crate" + +/datum/supply_pack/misc/formalwear + name = "Formalwear Crate" + cost = 3000 //Lots of very expensive items. You gotta pay up to look good! + contains = list(/obj/item/clothing/under/blacktango, + /obj/item/clothing/under/assistantformal, + /obj/item/clothing/under/assistantformal, + /obj/item/clothing/under/lawyer/bluesuit, + /obj/item/clothing/suit/toggle/lawyer, + /obj/item/clothing/under/lawyer/purpsuit, + /obj/item/clothing/suit/toggle/lawyer/purple, + /obj/item/clothing/under/lawyer/blacksuit, + /obj/item/clothing/suit/toggle/lawyer/black, + /obj/item/clothing/accessory/waistcoat, + /obj/item/clothing/neck/tie/blue, + /obj/item/clothing/neck/tie/red, + /obj/item/clothing/neck/tie/black, + /obj/item/clothing/head/bowler, + /obj/item/clothing/head/fedora, + /obj/item/clothing/head/flatcap, + /obj/item/clothing/head/beret, + /obj/item/clothing/head/that, + /obj/item/clothing/shoes/laceup, + /obj/item/clothing/shoes/laceup, + /obj/item/clothing/shoes/laceup, + /obj/item/clothing/under/suit_jacket/charcoal, + /obj/item/clothing/under/suit_jacket/navy, + /obj/item/clothing/under/suit_jacket/burgundy, + /obj/item/clothing/under/suit_jacket/checkered, + /obj/item/clothing/under/suit_jacket/tan, + /obj/item/lipstick/random) + crate_name = "formalwear crate" + +/datum/supply_pack/misc/foamforce + name = "Foam Force Crate" + cost = 1000 + contains = list(/obj/item/gun/ballistic/shotgun/toy, + /obj/item/gun/ballistic/shotgun/toy, + /obj/item/gun/ballistic/shotgun/toy, + /obj/item/gun/ballistic/shotgun/toy, + /obj/item/gun/ballistic/shotgun/toy, + /obj/item/gun/ballistic/shotgun/toy, + /obj/item/gun/ballistic/shotgun/toy, + /obj/item/gun/ballistic/shotgun/toy) + crate_name = "foam force crate" + +/datum/supply_pack/misc/foamforce/bonus + name = "Foam Force Pistols Crate" + contraband = TRUE + cost = 4000 + contains = list(/obj/item/gun/ballistic/automatic/toy/pistol, + /obj/item/gun/ballistic/automatic/toy/pistol, + /obj/item/ammo_box/magazine/toy/pistol, + /obj/item/ammo_box/magazine/toy/pistol) + crate_name = "foam force crate" + +/datum/supply_pack/misc/artsupply + name = "Art Supplies" + cost = 800 + contains = list(/obj/structure/easel, + /obj/structure/easel, + /obj/item/canvas/nineteenXnineteen, + /obj/item/canvas/nineteenXnineteen, + /obj/item/canvas/twentythreeXnineteen, + /obj/item/canvas/twentythreeXnineteen, + /obj/item/canvas/twentythreeXtwentythree, + /obj/item/canvas/twentythreeXtwentythree, + /obj/item/toy/crayon/rainbow, + /obj/item/toy/crayon/rainbow) + crate_name = "art supply crate" + +/datum/supply_pack/misc/bsa + name = "Bluespace Artillery Parts" + cost = 15000 + special = TRUE + contains = list(/obj/item/circuitboard/machine/bsa/front, + /obj/item/circuitboard/machine/bsa/middle, + /obj/item/circuitboard/machine/bsa/back, + /obj/item/circuitboard/computer/bsa_control + ) + crate_name= "bluespace artillery parts crate" + +/datum/supply_pack/misc/dna_vault + name = "DNA Vault Parts" + cost = 12000 + special = TRUE + contains = list( + /obj/item/circuitboard/machine/dna_vault, + /obj/item/device/dna_probe, + /obj/item/device/dna_probe, + /obj/item/device/dna_probe, + /obj/item/device/dna_probe, + /obj/item/device/dna_probe + ) + crate_name= "dna vault parts crate" + +/datum/supply_pack/misc/dna_probes + name = "DNA Vault Samplers" + cost = 3000 + special = TRUE + contains = list(/obj/item/device/dna_probe, + /obj/item/device/dna_probe, + /obj/item/device/dna_probe, + /obj/item/device/dna_probe, + /obj/item/device/dna_probe + ) + crate_name= "dna samplers crate" + + +/datum/supply_pack/misc/shield_sat + name = "Shield Generator Satellite" + cost = 3000 + special = TRUE + contains = list( + /obj/machinery/satellite/meteor_shield, + /obj/machinery/satellite/meteor_shield, + /obj/machinery/satellite/meteor_shield + ) + crate_name= "shield sat crate" + + +/datum/supply_pack/misc/shield_sat_control + name = "Shield System Control Board" + cost = 5000 + special = TRUE + contains = list(/obj/item/circuitboard/computer/sat_control) + crate_name= "shield control board crate" + +/datum/supply_pack/misc/bicycle + name = "Bicycle" + cost = 1000000 + contains = list(/obj/vehicle/bicycle) + crate_name = "Bicycle Crate" + crate_type = /obj/structure/closet/crate/large diff --git a/code/modules/goonchat/browserassets/css/browserOutput.css b/code/modules/goonchat/browserassets/css/browserOutput.css index f766491d02c..5e070fdbfe7 100644 --- a/code/modules/goonchat/browserassets/css/browserOutput.css +++ b/code/modules/goonchat/browserassets/css/browserOutput.css @@ -318,6 +318,11 @@ h1.alert, h2.alert {color: #000000;} .green {color: #03ff39;} .shadowling {color: #3b2769;} .cult {color: #960000;} + +.cultitalic {color: #960000; font-style: italic;} +.cultbold {color: #960000; font-style: italic; font-weight: bold;} +.cultboldtalic {color: #960000; font-weight: bold; font-size: 24px;} + .cultlarge {color: #960000; font-weight: bold; font-size: 24px;} .narsie {color: #960000; font-weight: bold; font-size: 120px;} .narsiesmall {color: #960000; font-weight: bold; font-size: 48px;} diff --git a/code/modules/library/lib_machines.dm b/code/modules/library/lib_machines.dm index f0b881c9e22..269c6ad13f9 100644 --- a/code/modules/library/lib_machines.dm +++ b/code/modules/library/lib_machines.dm @@ -304,7 +304,7 @@ GLOBAL_LIST(cachedbooks) // List of our cached book datums dat += "(Return to main menu)
" if(8) dat += "

Accessing Forbidden Lore Vault v 1.3

" - dat += "Are you absolutely sure you want to proceed? EldritchTomes Inc. takes no responsibilities for loss of sanity resulting from this action.

" + dat += "Are you absolutely sure you want to proceed? EldritchRelics Inc. takes no responsibilities for loss of sanity resulting from this action.

" dat += "Yes.
" dat += "No.
" @@ -322,11 +322,11 @@ GLOBAL_LIST(cachedbooks) // List of our cached book datums var/spook = pick("blood", "brass") var/turf/T = get_turf(src) if(spook == "blood") - new /obj/item/tome(T) + new /obj/item/melee/cultblade/dagger(T) else new /obj/item/clockwork/slab(T) - to_chat(user, "Your sanity barely endures the seconds spent in the vault's browsing window. The only thing to remind you of this when you stop browsing is a [spook == "blood" ? "dusty old tome" : "strange metal tablet"] sitting on the desk. You don't really remember printing it.[spook == "brass" ? " And how did it print something made of metal?" : ""]") + to_chat(user, "Your sanity barely endures the seconds spent in the vault's browsing window. The only thing to remind you of this when you stop browsing is a [spook == "blood" ? "sinister dagger" : "strange metal tablet"] sitting on the desk. You don't even remember where it came from...") user.visible_message("[user] stares at the blank screen for a few moments, [user.p_their()] expression frozen in fear. When [user.p_they()] finally awaken[user.p_s()] from it, [user.p_they()] look[user.p_s()] a lot older.", 2) /obj/machinery/computer/libraryconsole/bookmanagement/attackby(obj/item/W, mob/user, params) diff --git a/code/modules/mob/living/simple_animal/constructs.dm b/code/modules/mob/living/simple_animal/constructs.dm index 0a3061cacce..6c6f39ffc13 100644 --- a/code/modules/mob/living/simple_animal/constructs.dm +++ b/code/modules/mob/living/simple_animal/constructs.dm @@ -37,12 +37,28 @@ var/seeking = FALSE var/can_repair_constructs = FALSE var/can_repair_self = FALSE + var/runetype /mob/living/simple_animal/hostile/construct/Initialize() . = ..() update_health_hud() + var/spellnum = 1 for(var/spell in construct_spells) - AddSpell(new spell(null)) + var/the_spell = new spell(null) + AddSpell(the_spell) + var/obj/effect/proc_holder/spell/S = mob_spell_list[spellnum] + var/pos = 2+spellnum*31 + if(construct_spells.len >= 4) + pos -= 31*(construct_spells.len - 4) + S.action.button.screen_loc = "6:[pos],4:-2" + S.action.button.moved = "6:[pos],4:-2" + spellnum++ + if(runetype) + var/datum/action/innate/cult/create_rune/CR = new runetype(src) + CR.Grant(src) + var/pos = 2+spellnum*31 + CR.button.screen_loc = "6:[pos],4:-2" + CR.button.moved = "6:[pos],4:-2" /mob/living/simple_animal/hostile/construct/Login() ..() @@ -104,22 +120,24 @@ desc = "A massive, armored construct built to spearhead attacks and soak up enemy fire." icon_state = "behemoth" icon_living = "behemoth" - maxHealth = 250 - health = 250 + maxHealth = 200 + health = 200 response_harm = "harmlessly punches" harm_intent_damage = 0 obj_damage = 90 melee_damage_lower = 30 melee_damage_upper = 30 attacktext = "smashes their armored gauntlet into" - speed = 3 + speed = 2.5 environment_smash = ENVIRONMENT_SMASH_WALLS attack_sound = 'sound/weapons/punch3.ogg' status_flags = 0 mob_size = MOB_SIZE_LARGE force_threshold = 11 - construct_spells = list(/obj/effect/proc_holder/spell/aoe_turf/conjure/lesserforcewall) - playstyle_string = "You are a Juggernaut. Though slow, your shell can withstand extreme punishment, \ + construct_spells = list(/obj/effect/proc_holder/spell/targeted/forcewall/cult, + /obj/effect/proc_holder/spell/dumbfire/juggernaut) + runetype = /datum/action/innate/cult/create_rune/wall + playstyle_string = "You are a Juggernaut. Though slow, your shell can withstand extreme punishment, \ create shield walls, rip apart enemies and walls alike, and even deflect energy weapons." /mob/living/simple_animal/hostile/construct/armored/hostile //actually hostile, will move around, hit things @@ -164,15 +182,17 @@ desc = "A wicked, clawed shell constructed to assassinate enemies and sow chaos behind enemy lines." icon_state = "floating" icon_living = "floating" - maxHealth = 75 - health = 75 + maxHealth = 65 + health = 65 melee_damage_lower = 25 melee_damage_upper = 25 retreat_distance = 2 //AI wraiths will move in and out of combat attacktext = "slashes" attack_sound = 'sound/weapons/bladeslice.ogg' construct_spells = list(/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/shift) - playstyle_string = "You are a Wraith. Though relatively fragile, you are fast, deadly, can phase through walls, and your attacks will lower the cooldown on phasing." + runetype = /datum/action/innate/cult/create_rune/tele + playstyle_string = "You are a Wraith. Though relatively fragile, you are fast, deadly, can phase through walls, and your attacks will lower the cooldown on phasing." + var/attack_refund = 10 //1 second per attack var/crit_refund = 50 //5 seconds when putting a target into critical var/kill_refund = 250 //full refund on kills @@ -226,7 +246,9 @@ /obj/effect/proc_holder/spell/aoe_turf/conjure/soulstone, /obj/effect/proc_holder/spell/aoe_turf/conjure/construct/lesser, /obj/effect/proc_holder/spell/targeted/projectile/magic_missile/lesser) - playstyle_string = "You are an Artificer. You are incredibly weak and fragile, but you are able to construct fortifications, \ + runetype = /datum/action/innate/cult/create_rune/revive + playstyle_string = "You are an Artificer. You are incredibly weak and fragile, but you are able to construct fortifications, \ + use magic missile, repair allied constructs, shades, and yourself (by clicking on them), \ and, most important of all, create new constructs by producing soulstones to capture souls, \ and shells to place those soulstones into." @@ -299,9 +321,9 @@ attacktext = "butchers" attack_sound = 'sound/weapons/bladeslice.ogg' construct_spells = list(/obj/effect/proc_holder/spell/aoe_turf/area_conversion, - /obj/effect/proc_holder/spell/aoe_turf/conjure/lesserforcewall) - playstyle_string = "You are a Harvester. You are incapable of directly killing humans, but your attacks will remove their limbs: \ - Bring those who still cling to this world of illusion back to the Geometer so they may know Truth. Your form and any you are pulling can pass through runed walls effortlessly." + /obj/effect/proc_holder/spell/targeted/forcewall/cult) + playstyle_string = "You are a Harvester. You are incapable of directly killing humans, but your attacks will remove their limbs: \ + Bring those who still cling to this world of illusion back to the Geometer so they may know Truth. Your form and any you are pulling can pass through runed walls effortlessly." can_repair_constructs = TRUE @@ -376,7 +398,7 @@ if(summon_objective.check_completion()) the_construct.master = C.cult_team.blood_target - + if(!the_construct.master) to_chat(the_construct, "You have no master to seek!") the_construct.seeking = FALSE diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord.dm index d2980bbdaf1..5cb5bbe1654 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord.dm @@ -366,7 +366,7 @@ r_pocket = /obj/item/restraints/legcuffs/bola/cult l_pocket = /obj/item/melee/cultblade/dagger glasses = /obj/item/clothing/glasses/night/cultblind - backpack_contents = list(/obj/item/reagent_containers/food/drinks/bottle/unholywater = 1, /obj/item/device/cult_shift = 1, /obj/item/device/flashlight/flare/culttorch = 1, /obj/item/stack/sheet/runed_metal = 15) + backpack_contents = list(/obj/item/reagent_containers/glass/beaker/unholywater = 1, /obj/item/device/cult_shift = 1, /obj/item/device/flashlight/flare/culttorch = 1, /obj/item/stack/sheet/runed_metal = 15) . = ..() diff --git a/code/modules/paperwork/paper.dm b/code/modules/paperwork/paper.dm index 35ec667027c..312c789f07c 100644 --- a/code/modules/paperwork/paper.dm +++ b/code/modules/paperwork/paper.dm @@ -69,10 +69,6 @@ var/datum/asset/assets = get_asset_datum(/datum/asset/simple/paper) assets.send(user) - if(istype(src, /obj/item/paper/talisman)) //Talismans cannot be read - if(!iscultist(user) && !user.stat) - to_chat(user, "There are indecipherable images scrawled on the paper in what looks to be... blood?") - return if(in_range(user, src) || isobserver(user)) if(user.is_literate()) user << browse("[name][info]


[stamps]", "window=[name]") @@ -297,9 +293,6 @@ else to_chat(user, "You don't know how to read or write.") return - if(istype(src, /obj/item/paper/talisman/)) - to_chat(user, "[P]'s ink fades away shortly after it is written.") - return else if(istype(P, /obj/item/stamp)) diff --git a/code/modules/power/singularity/narsie.dm b/code/modules/power/singularity/narsie.dm index 0fa14397963..2293fb2fb2f 100644 --- a/code/modules/power/singularity/narsie.dm +++ b/code/modules/power/singularity/narsie.dm @@ -77,7 +77,7 @@ set_security_level("delta") SSshuttle.registerHostileEnvironment(src) SSshuttle.lockdown = TRUE - sleep(1150) + sleep(850) if(resolved == FALSE) resolved = TRUE sound_to_playing_players('sound/machines/alarm.ogg') diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm index 91ca8715b11..d80e43b8a4c 100644 --- a/code/modules/reagents/chemistry/reagents/other_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm @@ -200,6 +200,11 @@ data = 1 data++ M.jitteriness = min(M.jitteriness+4,10) + if(iscultist(M)) + for(var/datum/action/innate/cult/blood_magic/BM in M.actions) + to_chat(M, "Your blood rites falter as holy water scours your body!") + for(var/datum/action/innate/cult/blood_spell/BS in BM.spells) + qdel(BS) if(data >= 30) // 12 units, 54 seconds @ metabolism 0.4 units & tick rate 1.8 sec if(!M.stuttering) M.stuttering = 1 @@ -216,7 +221,7 @@ "You can't save him. Nothing can save him now", "It seems that Nar-Sie will triumph after all")].") if("emote") M.visible_message("[M] [pick("whimpers quietly", "shivers as though cold", "glances around in paranoia")].") - if(data >= 75) // 30 units, 135 seconds + if(data >= 60) // 30 units, 135 seconds if(iscultist(M) || is_servant_of_ratvar(M)) if(iscultist(M)) SSticker.mode.remove_cultist(M.mind, FALSE, TRUE) @@ -245,7 +250,7 @@ /datum/reagent/fuel/unholywater/reaction_mob(mob/living/M, method=TOUCH, reac_volume) if(method == TOUCH || method == VAPOR) - M.reagents.add_reagent("unholywater", (reac_volume/4)) + M.reagents.add_reagent(id,reac_volume/4) return return ..() @@ -255,17 +260,20 @@ M.AdjustUnconscious(-20, 0) M.AdjustStun(-40, 0) M.AdjustKnockdown(-40, 0) + M.adjustStaminaLoss(-10, 0) M.adjustToxLoss(-2, 0) M.adjustOxyLoss(-2, 0) M.adjustBruteLoss(-2, 0) M.adjustFireLoss(-2, 0) - else + if(ishuman(M) && M.blood_volume < BLOOD_VOLUME_NORMAL) + M.blood_volume += 3 + else // Will deal about 90 damage when 50 units are thrown M.adjustBrainLoss(3, 150) - M.adjustToxLoss(1, 0) + M.adjustToxLoss(2, 0) M.adjustFireLoss(2, 0) M.adjustOxyLoss(2, 0) M.adjustBruteLoss(2, 0) - holder.remove_reagent(src.id, 1) + holder.remove_reagent(id, 1) . = 1 /datum/reagent/hellwater //if someone has this in their system they've really pissed off an eldrich god diff --git a/code/modules/spells/spell.dm b/code/modules/spells/spell.dm index 2d6d1ed75fe..19162d52599 100644 --- a/code/modules/spells/spell.dm +++ b/code/modules/spells/spell.dm @@ -104,7 +104,6 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th pass_flags = PASSTABLE density = FALSE opacity = 0 - base_action = /datum/action/spell_action/spell var/school = "evocation" //not relevant at now, but may be important later if there are changes to how spells work. the ones I used for now will probably be changed... maybe spell presets? lacking flexibility but with some other benefit? @@ -151,6 +150,7 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th action_icon = 'icons/mob/actions/actions_spells.dmi' action_icon_state = "spell_default" action_background_icon_state = "bg_spell" + base_action = /datum/action/spell_action/spell /obj/effect/proc_holder/spell/proc/cast_check(skipcharge = 0,mob/user = usr) //checks if the spell can be cast based on its settings; skipcharge is used when an additional cast_check is called inside the spell diff --git a/code/modules/spells/spell_types/construct_spells.dm b/code/modules/spells/spell_types/construct_spells.dm index 69a8ab07b77..07e75002bc1 100644 --- a/code/modules/spells/spell_types/construct_spells.dm +++ b/code/modules/spells/spell_types/construct_spells.dm @@ -82,7 +82,7 @@ desc = "This spell reaches into Nar-Sie's realm, summoning one of the legendary fragments across time and space." school = "conjuration" - charge_max = 3000 + charge_max = 2400 clothes_req = 0 invocation = "none" invocation_type = "none" @@ -95,30 +95,26 @@ /obj/effect/proc_holder/spell/aoe_turf/conjure/soulstone/cult cult_req = 1 - charge_max = 4000 + charge_max = 3600 /obj/effect/proc_holder/spell/aoe_turf/conjure/soulstone/noncult summon_type = list(/obj/item/device/soulstone/anybody) - - -/obj/effect/proc_holder/spell/aoe_turf/conjure/lesserforcewall +/obj/effect/proc_holder/spell/targeted/forcewall/cult name = "Shield" desc = "This spell creates a temporary forcefield to shield yourself and allies from incoming fire." - school = "transmutation" - charge_max = 300 - clothes_req = 0 + charge_max = 400 + clothes_req = FALSE invocation = "none" invocation_type = "none" - range = 0 - summon_type = list(/obj/effect/forcefield/cult) - summon_lifespan = 200 + wall_type = /obj/effect/forcefield/cult action_icon = 'icons/mob/actions/actions_cult.dmi' action_icon_state = "cultforcewall" action_background_icon_state = "bg_demon" + /obj/effect/proc_holder/spell/targeted/ethereal_jaunt/shift name = "Phase Shift" desc = "This spell allows you to pass through walls." @@ -279,4 +275,38 @@ /obj/effect/proc_holder/spell/targeted/ethereal_jaunt/shift/golem charge_max = 800 jaunt_in_type = /obj/effect/temp_visual/dir_setting/cult/phase - jaunt_out_type = /obj/effect/temp_visual/dir_setting/cult/phase/out \ No newline at end of file + jaunt_out_type = /obj/effect/temp_visual/dir_setting/cult/phase/out + + +/obj/effect/proc_holder/spell/dumbfire/juggernaut + name = "Gauntlet Echo" + desc = "Channels energy into your gauntlet - firing its essence forward in a slow-moving but devastating blow." + proj_icon_state = "cursehand0" + proj_name = "Shadowfist" + proj_type = "/obj/effect/proc_holder/spell/targeted/inflict_handler/juggernaut" //IMPORTANT use only subtypes of this + proj_lifespan = 15 + proj_step_delay = 7 + charge_max = 350 + clothes_req = FALSE + action_icon = 'icons/mob/actions/actions_cult.dmi' + action_icon_state = "cultfist" + action_background_icon_state = "bg_demon" + sound = 'sound/weapons/resonator_blast.ogg' + proj_trigger_range = 0 + ignore_factions = list("cult") + +/obj/effect/proc_holder/spell/targeted/inflict_handler/juggernaut + name = "Gauntlet Echo" + amt_dam_brute = 30 + amt_knockdown = 50 + sound = 'sound/weapons/punch3.ogg' + +/obj/effect/proc_holder/spell/targeted/inflict_handler/juggernaut/cast(list/targets,mob/user = usr) + var/turf/T = get_turf(src) + playsound(T, 'sound/weapons/resonator_blast.ogg', 100, FALSE) + new /obj/effect/temp_visual/cult/sac(T) + for(var/obj/O in range(src,1)) + if(O.density && !istype(O, /obj/structure/destructible/cult)) + O.take_damage(90, BRUTE, "gauntlet echo", 0) + new /obj/effect/temp_visual/cult/turf/floor + ..() diff --git a/code/modules/spells/spell_types/dumbfire.dm b/code/modules/spells/spell_types/dumbfire.dm index f86c29fdc27..f4a56fc466f 100644 --- a/code/modules/spells/spell_types/dumbfire.dm +++ b/code/modules/spells/spell_types/dumbfire.dm @@ -22,6 +22,7 @@ var/proj_lifespan = 100 //in deciseconds * proj_step_delay var/proj_step_delay = 1 //lower = faster + var/list/ignore_factions = list() //Faction types that will be ignored /obj/effect/proc_holder/spell/dumbfire/choose_targets(mob/user = usr) @@ -74,8 +75,18 @@ var/mob/living/L = locate(/mob/living) in range(projectile, proj_trigger_range) - user if(L && L.stat != DEAD) - projectile.cast(L.loc,user=user) - break + if(!ignore_factions.len) + projectile.cast(L.loc,user=user) + break + else + var/faction_check = FALSE + for(var/faction in L.faction) + if(ignore_factions.Find(faction)) + faction_check = TRUE + break + if(!faction_check) + projectile.cast(L.loc,user=user) + break if(proj_trail && projectile) proj_trail(projectile) diff --git a/code/modules/spells/spell_types/forcewall.dm b/code/modules/spells/spell_types/forcewall.dm index a9d13728a3f..9efbbdf8756 100644 --- a/code/modules/spells/spell_types/forcewall.dm +++ b/code/modules/spells/spell_types/forcewall.dm @@ -29,7 +29,6 @@ /obj/effect/forcefield/wizard/Initialize(mapload, mob/summoner) . = ..() wizard = summoner - QDEL_IN(src, 300) /obj/effect/forcefield/wizard/CanPass(atom/movable/mover, turf/target) if(mover == wizard) diff --git a/icons/effects/128x128.dmi b/icons/effects/128x128.dmi index 5b73044c50c..d916318402a 100644 Binary files a/icons/effects/128x128.dmi and b/icons/effects/128x128.dmi differ diff --git a/icons/effects/96x96.dmi b/icons/effects/96x96.dmi index 644d2a0860b..70e097c9f42 100644 Binary files a/icons/effects/96x96.dmi and b/icons/effects/96x96.dmi differ diff --git a/icons/effects/beam.dmi b/icons/effects/beam.dmi index e7f61d605d1..07315837334 100644 Binary files a/icons/effects/beam.dmi and b/icons/effects/beam.dmi differ diff --git a/icons/effects/cult_effects.dmi b/icons/effects/cult_effects.dmi index 925950b9a39..230eac74c3f 100644 Binary files a/icons/effects/cult_effects.dmi and b/icons/effects/cult_effects.dmi differ diff --git a/icons/mob/actions/actions_cult.dmi b/icons/mob/actions/actions_cult.dmi index f96242ea9ed..07432d2a279 100644 Binary files a/icons/mob/actions/actions_cult.dmi and b/icons/mob/actions/actions_cult.dmi differ diff --git a/icons/mob/inhands/equipment/shields_lefthand.dmi b/icons/mob/inhands/equipment/shields_lefthand.dmi index 9748457dc3e..6b5ca3857d9 100644 Binary files a/icons/mob/inhands/equipment/shields_lefthand.dmi and b/icons/mob/inhands/equipment/shields_lefthand.dmi differ diff --git a/icons/mob/inhands/equipment/shields_righthand.dmi b/icons/mob/inhands/equipment/shields_righthand.dmi index f67cbc6b9ef..e3de91087a8 100644 Binary files a/icons/mob/inhands/equipment/shields_righthand.dmi and b/icons/mob/inhands/equipment/shields_righthand.dmi differ diff --git a/icons/mob/inhands/weapons/polearms_lefthand.dmi b/icons/mob/inhands/weapons/polearms_lefthand.dmi index f07dc02a0b2..5529edfa510 100644 Binary files a/icons/mob/inhands/weapons/polearms_lefthand.dmi and b/icons/mob/inhands/weapons/polearms_lefthand.dmi differ diff --git a/icons/mob/inhands/weapons/polearms_righthand.dmi b/icons/mob/inhands/weapons/polearms_righthand.dmi index 510cb3b4da6..e902dcdc3bd 100644 Binary files a/icons/mob/inhands/weapons/polearms_righthand.dmi and b/icons/mob/inhands/weapons/polearms_righthand.dmi differ diff --git a/icons/mob/inhands/weapons/swords_lefthand.dmi b/icons/mob/inhands/weapons/swords_lefthand.dmi index 231a98f537f..5e7b04a25a3 100644 Binary files a/icons/mob/inhands/weapons/swords_lefthand.dmi and b/icons/mob/inhands/weapons/swords_lefthand.dmi differ diff --git a/icons/mob/inhands/weapons/swords_righthand.dmi b/icons/mob/inhands/weapons/swords_righthand.dmi index 6b491b05eef..b330dc8f956 100644 Binary files a/icons/mob/inhands/weapons/swords_righthand.dmi and b/icons/mob/inhands/weapons/swords_righthand.dmi differ diff --git a/icons/mob/mob.dmi b/icons/mob/mob.dmi index 8dabf5fce48..16497062799 100644 Binary files a/icons/mob/mob.dmi and b/icons/mob/mob.dmi differ diff --git a/icons/obj/items_and_weapons.dmi b/icons/obj/items_and_weapons.dmi index 3d26d561813..a1abe445a7d 100644 Binary files a/icons/obj/items_and_weapons.dmi and b/icons/obj/items_and_weapons.dmi differ diff --git a/icons/obj/projectiles.dmi b/icons/obj/projectiles.dmi index 1880dd5d0d3..b2299a75fe0 100644 Binary files a/icons/obj/projectiles.dmi and b/icons/obj/projectiles.dmi differ diff --git a/tgstation.dme b/tgstation.dme index fdb89bf9409..acbe1d77ece 100755 --- a/tgstation.dme +++ b/tgstation.dme @@ -451,6 +451,7 @@ #include "code\game\gamemodes\changeling\changeling.dm" #include "code\game\gamemodes\changeling\traitor_chan.dm" #include "code\game\gamemodes\clock_cult\clock_cult.dm" +#include "code\game\gamemodes\cult\blood_magic.dm" #include "code\game\gamemodes\cult\cult.dm" #include "code\game\gamemodes\devil\devil_game_mode.dm" #include "code\game\gamemodes\devil\game_mode.dm" @@ -1148,8 +1149,6 @@ #include "code\modules\antagonists\cult\ritual.dm" #include "code\modules\antagonists\cult\rune_spawn_action.dm" #include "code\modules\antagonists\cult\runes.dm" -#include "code\modules\antagonists\cult\supply.dm" -#include "code\modules\antagonists\cult\talisman.dm" #include "code\modules\antagonists\devil\devil.dm" #include "code\modules\antagonists\devil\devil_helpers.dm" #include "code\modules\antagonists\devil\imp\imp.dm"