diff --git a/code/datums/outfits/outfit.dm b/code/datums/outfits/outfit.dm index 1c5aba0f171..283b6951b9f 100644 --- a/code/datums/outfits/outfit.dm +++ b/code/datums/outfits/outfit.dm @@ -111,6 +111,8 @@ for(var/path in backpack_contents) var/number = backpack_contents[path] + if(!number) + number = 1 for(var/i in 1 to number) H.equip_or_collect(new path(H), slot_in_backpack) diff --git a/code/datums/spells/construct_spells.dm b/code/datums/spells/construct_spells.dm index afc91f922ab..57dd43ad38c 100644 --- a/code/datums/spells/construct_spells.dm +++ b/code/datums/spells/construct_spells.dm @@ -49,7 +49,7 @@ /obj/effect/proc_holder/spell/aoe_turf/conjure/soulstone name = "Summon Soulstone" - desc = "This spell reaches into Nar'Sie's realm, summoning one of the legendary fragments across time and space" + desc = "This spell reaches into Redspace, summoning one of the legendary fragments across time and space" action_icon_state = "summonsoulstone" action_background_icon_state = "bg_cult" school = "conjuration" @@ -68,7 +68,7 @@ /obj/effect/proc_holder/spell/aoe_turf/conjure/pylon name = "Cult Pylon" - desc = "This spell conjures a fragile crystal from Nar'Sie's realm. Makes for a convenient light source." + desc = "This spell conjures a fragile crystal from Redspace. Makes for a convenient light source." action_icon_state = "pylon" action_background_icon_state = "bg_cult" school = "conjuration" @@ -118,7 +118,12 @@ /obj/effect/proc_holder/spell/targeted/ethereal_jaunt/shift/do_jaunt(mob/living/target) target.set_light(0) ..() - target.set_light(2, 3, l_color = SSticker.cultdat ? SSticker.cultdat.construct_glow : LIGHT_COLOR_BLOOD_MAGIC) + if(isconstruct(target)) + var/mob/living/simple_animal/hostile/construct/C = target + if(C.holy) + C.set_light(3, 5, LIGHT_COLOR_DARK_BLUE) + else + C.set_light(2, 3, l_color = SSticker.cultdat ? SSticker.cultdat.construct_glow : LIGHT_COLOR_BLOOD_MAGIC) /obj/effect/proc_holder/spell/targeted/ethereal_jaunt/shift/jaunt_steam(mobloc) return diff --git a/code/game/area/ss13_areas.dm b/code/game/area/ss13_areas.dm index 736a6d84447..36b3461bd6f 100644 --- a/code/game/area/ss13_areas.dm +++ b/code/game/area/ss13_areas.dm @@ -1108,7 +1108,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station sound_environment = SOUND_AREA_SMALL_ENCLOSED /area/engine/equipmentstorage - name = "\improper Engineering Equipment Storage" + name = "Engineering Equipment Storage" icon_state = "storage" sound_environment = SOUND_AREA_SMALL_ENCLOSED @@ -1260,7 +1260,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station /area/medical/biostorage - name = "\improper Medical Storage" + name = "Medical Storage" icon_state = "medbaysecstorage" /area/medical/reception @@ -1285,19 +1285,19 @@ NOTE: there are two lists of areas in the end of this file: centcom and station icon_state = "patientsward" /area/medical/patient_a - name = "\improper Isolation A" + name = "Isolation A" icon_state = "medbayisoa" /area/medical/patient_b - name = "\improper Isolation B" + name = "Isolation B" icon_state = "medbayisob" /area/medical/patient_c - name = "\improper Isolation C" + name = "Isolation C" icon_state = "medbayisoc" /area/medical/iso_access - name = "\improper Isolation Access" + name = "Isolation Access" icon_state = "medbayisoaccess" /area/medical/cmo @@ -1305,15 +1305,15 @@ NOTE: there are two lists of areas in the end of this file: centcom and station icon_state = "CMO" /area/medical/cmostore - name = "\improper Medical Secondary Storage" + name = "Medical Secondary Storage" icon_state = "medbaysecstorage" /area/medical/robotics - name = "\improper Robotics" + name = "Robotics" icon_state = "medresearch" /area/medical/research - name = "\improper Medical Research" + name = "Medical Research" icon_state = "medresearch" /area/medical/research_shuttle_dock @@ -1321,7 +1321,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station icon_state = "medresearch" /area/medical/virology - name = "\improper Virology" + name = "Virology" icon_state = "virology" /area/medical/virology/lab @@ -1336,7 +1336,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station sound_environment = SOUND_AREA_SMALL_ENCLOSED /area/medical/chemistry - name = "\improper Chemistry" + name = "Chemistry" icon_state = "chem" /area/medical/surgery @@ -1344,19 +1344,19 @@ NOTE: there are two lists of areas in the end of this file: centcom and station icon_state = "surgery" /area/medical/surgery1 - name = "\improper Surgery 1" + name = "Surgery 1" icon_state = "surgery1" /area/medical/surgery2 - name = "\improper Surgery 2" + name = "Surgery 2" icon_state = "surgery2" /area/medical/surgeryobs - name = "\improper Surgery Observation" + name = "Surgery Observation" icon_state = "surgery" /area/medical/cryo - name = "\improper Cryogenics" + name = "Cryogenics" icon_state = "cryo" /area/medical/exam_room @@ -1376,7 +1376,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station icon_state = "exam_room" /area/medical/paramedic - name = "\improper Paramedic" + name = "Paramedic" icon_state = "medbay" //Security @@ -1441,22 +1441,22 @@ NOTE: there are two lists of areas in the end of this file: centcom and station icon_state = "brig" /area/security/execution - name = "\improper Execution" + name = "Execution" icon_state = "execution" can_get_auto_cryod = FALSE /area/security/processing - name = "\improper Prisoner Processing" + name = "Prisoner Processing" icon_state = "prisonerprocessing" can_get_auto_cryod = FALSE /area/security/interrogation - name = "\improper Interrogation" + name = "Interrogation" icon_state = "interrogation" can_get_auto_cryod = FALSE /area/security/seceqstorage - name = "\improper Security Equipment Storage" + name = "Security Equipment Storage" icon_state = "securityequipmentstorage" /area/security/interrogationhallway @@ -1469,7 +1469,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station sound_environment = SOUND_AREA_LARGE_ENCLOSED /area/security/interrogationobs - name = "\improper Interrogation Observation" + name = "Interrogation Observation" icon_state = "security" can_get_auto_cryod = FALSE @@ -1530,11 +1530,11 @@ NOTE: there are two lists of areas in the end of this file: centcom and station icon_state = "nuke_storage" /area/security/customs - name = "\improper Customs" + name = "Customs" icon_state = "checkpoint1" /area/security/customs2 - name = "\improper Customs" + name = "Customs" icon_state = "security" /area/security/checkpoint @@ -1601,7 +1601,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station icon_state = "mining" /area/quartermaster/miningstorage - name = "\improper Mining Storage" + name = "Mining Storage" icon_state = "green" /area/quartermaster/mechbay @@ -1614,7 +1614,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station sound_environment = SOUND_AREA_SMALL_ENCLOSED /area/hydroponics - name = "\improper Hydroponics" + name = "Hydroponics" icon_state = "hydro" sound_environment = SOUND_AREA_STANDARD_STATION @@ -1629,7 +1629,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station sound_environment = SOUND_AREA_STANDARD_STATION /area/toxins/lab - name = "\improper Research and Development" + name = "Research and Development" icon_state = "toxlab" /area/toxins/hallway @@ -1650,7 +1650,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station xenobiology_compatible = TRUE /area/toxins/xenobiology/xenoflora_storage - name = "\improper Xenoflora Storage" + name = "Xenoflora Storage" icon_state = "toxlab" /area/toxins/xenobiology/xenoflora @@ -1658,7 +1658,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station icon_state = "toxlab" /area/toxins/storage - name = "\improper Toxins Storage" + name = "Toxins Storage" icon_state = "toxstorage" /area/toxins/test_area @@ -1671,7 +1671,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station icon_state = "toxmix" /area/toxins/launch - name = "Toxins Launch Room" + name = "\improper Toxins Launch Room" icon_state = "toxlaunch" /area/toxins/misc_lab @@ -1739,7 +1739,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station icon_state = "auxstorage" /area/storage/office - name = "\improper Office Supplies" + name = "Office Supplies" icon_state = "office_supplies" // ENGIE OUTPOST diff --git a/code/game/gamemodes/cult/blood_magic.dm b/code/game/gamemodes/cult/blood_magic.dm index 2583fd693d3..c1b4f6a98d5 100644 --- a/code/game/gamemodes/cult/blood_magic.dm +++ b/code/game/gamemodes/cult/blood_magic.dm @@ -249,7 +249,7 @@ /datum/action/innate/cult/blood_spell/horror/Destroy() var/obj/effect/proc_holder/horror/destroy = PH . = ..() - if(destroy && !QDELETED(destroy)) + if(!QDELETED(destroy)) QDEL_NULL(destroy) /datum/action/innate/cult/blood_spell/horror/Activate() @@ -264,7 +264,7 @@ /obj/effect/proc_holder/horror/Destroy() var/datum/action/innate/cult/blood_spell/AA = attached_action . = ..() - if(AA && !QDELETED(AA)) + if(!QDELETED(AA)) QDEL_NULL(AA) /obj/effect/proc_holder/horror/proc/toggle(mob/user) @@ -464,9 +464,15 @@ var/list/potential_runes = list() var/list/teleportnames = list() var/list/duplicaterunecount = list() + var/atom/movable/teleportee if(!iscultist(target) || !proximity) to_chat(user, "You can only teleport adjacent cultists with this spell!") return + if(user != target) // So that the teleport effect shows on the correct mob + teleportee = target + else + teleportee = user + for(var/R in GLOB.teleport_runes) var/obj/effect/rune/teleport/T = R var/resultkey = T.listkey @@ -487,16 +493,15 @@ log_game("Teleport spell failed - user in away mission") return - var/mob/living/L = target 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.l_hand != src && user.r_hand != src || user.incapacitated() || !actual_selected_rune) + if(QDELETED(src) || !user || user.l_hand != src && user.r_hand != src || user.incapacitated() || !actual_selected_rune) return uses-- - var/turf/origin = get_turf(user) + var/turf/origin = get_turf(teleportee) var/turf/destination = get_turf(actual_selected_rune) - INVOKE_ASYNC(actual_selected_rune, /obj/effect/rune/.proc/teleport_effect, user, origin, destination) + INVOKE_ASYNC(actual_selected_rune, /obj/effect/rune/.proc/teleport_effect, teleportee, origin, destination) if(is_mining_level(user.z) && !is_mining_level(destination.z)) //No effect if you stay on lavaland actual_selected_rune.handle_portal("lava") @@ -510,7 +515,7 @@ target.visible_message("Dust flows from [user]'s hand, and [target] disappears in a flash of red light!", \ "You suddenly find yourself somewhere else!") destination.visible_message("There is a boom of outrushing air as something appears above the rune!", null, "You hear a boom.") - L.forceMove(destination) + teleportee.forceMove(destination) return ..() //Shackles @@ -658,7 +663,7 @@ /obj/item/melee/blood_magic/empower/afterattack(atom/target, mob/user, proximity_flag, click_parameters) if(proximity_flag) - //Shielded suit + // Shielded suit if(istype(target, /obj/item/clothing/suit/hooded/cultrobes/cult_shield)) var/obj/item/clothing/suit/hooded/cultrobes/cult_shield/C = target if(C.current_charges < 3) @@ -672,7 +677,7 @@ to_chat(user, "[target] is already at full charge!") return - //Plasteel to runed metal + // Veil Shifter else if(istype(target, /obj/item/cult_shift)) var/obj/item/cult_shift/S = target if(S.uses < 4) @@ -846,39 +851,6 @@ var/list/options = list("Blood Orb (50)", "Blood Recharge (75)", "Blood Spear (150)", "Blood Bolt Barrage (300)") var/choice = input(user, "Choose a greater blood rite...", "Greater Blood Rites") as null|anything in options switch(choice) - if("Blood Spear (150)") - if(uses < BLOOD_SPEAR_COST) - to_chat(user, "You need [BLOOD_SPEAR_COST] charges to perform this rite.") - else - uses -= BLOOD_SPEAR_COST - 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 (300)") - if(uses < BLOOD_BARRAGE_COST) - to_chat(user, "You need [BLOOD_BARRAGE_COST] charges to perform this rite.") - else - var/obj/rite = new /obj/item/gun/projectile/shotgun/boltaction/enchanted/arcane_barrage/blood() - uses -= BLOOD_BARRAGE_COST - qdel(src) - user.swap_hand() - user.drop_item() - if(user.put_in_hands(rite)) - to_chat(user, "Both of your hands glow with power!") - else - to_chat(user, "You need a free hand for this rite!") - uses += BLOOD_BARRAGE_COST // Refund the charges - qdel(rite) - if("Blood Orb (50)") if(uses < BLOOD_ORB_COST) to_chat(user, "You need [BLOOD_ORB_COST] charges to perform this rite.") @@ -898,7 +870,7 @@ 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!", \ + user.visible_message("A [rite.name] appears at [user]'s feet!", "A [rite.name] materializes at your feet.") if("Blood Recharge (75)") @@ -914,3 +886,36 @@ to_chat(user, "You need a free hand for this rite!") uses += BLOOD_RECHARGE_COST // Refund the charges qdel(rite) + + if("Blood Spear (150)") + if(uses < BLOOD_SPEAR_COST) + to_chat(user, "You need [BLOOD_SPEAR_COST] charges to perform this rite.") + else + uses -= BLOOD_SPEAR_COST + 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 (300)") + if(uses < BLOOD_BARRAGE_COST) + to_chat(user, "You need [BLOOD_BARRAGE_COST] charges to perform this rite.") + else + var/obj/rite = new /obj/item/gun/projectile/shotgun/boltaction/enchanted/arcane_barrage/blood() + uses -= BLOOD_BARRAGE_COST + qdel(src) + user.swap_hand() + user.drop_item() + if(user.put_in_hands(rite)) + to_chat(user, "Both of your hands glow with power!") + else + to_chat(user, "You need a free hand for this rite!") + uses += BLOOD_BARRAGE_COST // Refund the charges + qdel(rite) diff --git a/code/game/gamemodes/cult/cult.dm b/code/game/gamemodes/cult/cult.dm index 04c9e13b605..ba9062af831 100644 --- a/code/game/gamemodes/cult/cult.dm +++ b/code/game/gamemodes/cult/cult.dm @@ -85,6 +85,9 @@ GLOBAL_LIST_EMPTY(all_cults) to_chat(cult_mind.current, CULT_GREETING) equip_cultist(cult_mind.current) cult_mind.current.faction |= "cult" + var/datum/objective/servecult/obj = new + obj.owner = cult_mind + cult_mind.objectives += obj if(cult_mind.assigned_role == "Clown") to_chat(cult_mind.current, "A dark power has allowed you to overcome your clownish nature, letting you wield weapons without harming yourself.") @@ -100,50 +103,6 @@ GLOBAL_LIST_EMPTY(all_cults) addtimer(CALLBACK(src, .proc/cult_threshold_check), 2 MINUTES) // Check again in 2 minutes for latejoiners ..() -/** - * Decides at the start of the round how many conversions are needed to rise/ascend. - * - * The number is decided by (Percentage * (Players - Cultists)), so for example at 110 players it would be 11 conversions for rise. (0.1 * (110 - 4)) - * These values change based on population because 20 cultists are MUCH more powerful if there's only 50 players, compared to 120. - * - * Below 100 players, [CULT_RISEN_LOW] and [CULT_ASCENDANT_LOW] are used. - * Above 100 players, [CULT_RISEN_HIGH] and [CULT_ASCENDANT_HIGH] are used. - */ -/datum/game_mode/proc/cult_threshold_check() - var/players = length(GLOB.player_list) - var/cultists = get_cultists() // Don't count the starting cultists towards the number of needed conversions - if(players >= CULT_POPULATION_THRESHOLD) - // Highpop - ascend_percent = CULT_ASCENDANT_HIGH - rise_number = round(CULT_RISEN_HIGH * (players - cultists)) - ascend_number = round(CULT_ASCENDANT_HIGH * (players - cultists)) - else - // Lowpop - ascend_percent = CULT_ASCENDANT_LOW - rise_number = round(CULT_RISEN_LOW * (players - cultists)) - ascend_number = round(CULT_ASCENDANT_LOW * (players - cultists)) - -/** - * Returns the current number of cultists and constructs. - * - * Returns the number of cultists and constructs in a list ([1] = Cultists, [2] = Constructs), or as one combined number. - * - * * separate - Should the number be returned in two separate values (Humans and Constructs) or as one? - */ -/datum/game_mode/proc/get_cultists(separate = FALSE) - var/cultists = 0 - var/constructs = 0 - for(var/I in cult) - var/datum/mind/M = I - if(ishuman(M.current) && !M.current.has_status_effect(STATUS_EFFECT_SUMMONEDGHOST)) - cultists++ - else if(isconstruct(M.current)) - constructs++ - if(separate) - return list(cultists, constructs) - else - return cultists + constructs - /datum/game_mode/proc/equip_cultist(mob/living/carbon/human/H, metal = TRUE) if(!istype(H)) return @@ -209,6 +168,81 @@ GLOBAL_LIST_EMPTY(all_cults) cult_objs.study(cult_mind.current) return TRUE +/datum/game_mode/proc/remove_cultist(datum/mind/cult_mind, show_message = TRUE, remove_gear = FALSE) + if(!(cult_mind in cult)) // Not actually a cultist in the first place + return + + var/mob/cultist = cult_mind.current + cult -= cult_mind + cultist.faction -= "cult" + cult_mind.special_role = null + for(var/datum/objective/servecult/S in cult_mind.objectives) + cult_mind.objectives -= S + qdel(S) + for(var/datum/action/innate/cult/C in cultist.actions) + qdel(C) + update_cult_icons_removed(cult_mind) + + if(ishuman(cultist)) + var/mob/living/carbon/human/H = cultist + REMOVE_TRAIT(H, CULT_EYES, null) + H.change_eye_color(H.original_eye_color, FALSE) + H.update_eyes() + H.remove_overlay(HALO_LAYER) + H.update_body() + if(remove_gear) // No flagellants robe for non-cultists + for(var/I in H.contents) + if(is_type_in_list(I, CULT_CLOTHING)) + H.unEquip(I) + check_cult_size() + if(show_message) + cultist.visible_message("[cultist] looks like [cultist.p_they()] just reverted to [cultist.p_their()] old faith!", + "An unfamiliar white light flashes through your mind, cleansing the taint of [SSticker.cultdat ? SSticker.cultdat.entity_title1 : "Nar'Sie"] and the memories of your time as their servant with it.") + + +/** + * Decides at the start of the round how many conversions are needed to rise/ascend. + * + * The number is decided by (Percentage * (Players - Cultists)), so for example at 110 players it would be 11 conversions for rise. (0.1 * (110 - 4)) + * These values change based on population because 20 cultists are MUCH more powerful if there's only 50 players, compared to 120. + * + * Below 100 players, [CULT_RISEN_LOW] and [CULT_ASCENDANT_LOW] are used. + * Above 100 players, [CULT_RISEN_HIGH] and [CULT_ASCENDANT_HIGH] are used. + */ +/datum/game_mode/proc/cult_threshold_check() + var/players = length(GLOB.player_list) + var/cultists = get_cultists() // Don't count the starting cultists towards the number of needed conversions + if(players >= CULT_POPULATION_THRESHOLD) + // Highpop + ascend_percent = CULT_ASCENDANT_HIGH + rise_number = round(CULT_RISEN_HIGH * (players - cultists)) + ascend_number = round(CULT_ASCENDANT_HIGH * (players - cultists)) + else + // Lowpop + ascend_percent = CULT_ASCENDANT_LOW + rise_number = round(CULT_RISEN_LOW * (players - cultists)) + ascend_number = round(CULT_ASCENDANT_LOW * (players - cultists)) + +/** + * Returns the current number of cultists and constructs. + * + * Returns the number of cultists and constructs in a list ([1] = Cultists, [2] = Constructs), or as one combined number. + * + * * separate - Should the number be returned as a list with two separate values (Humans and Constructs) or as one number. + */ +/datum/game_mode/proc/get_cultists(separate = FALSE) + var/cultists = 0 + var/constructs = 0 + for(var/I in cult) + var/datum/mind/M = I + if(ishuman(M.current) && !M.current.has_status_effect(STATUS_EFFECT_SUMMONEDGHOST)) + cultists++ + else if(isconstruct(M.current)) + constructs++ + if(separate) + return list(cultists, constructs) + else + return cultists + constructs /datum/game_mode/proc/check_cult_size() if(cult_ascendant) @@ -238,6 +272,8 @@ GLOBAL_LIST_EMPTY(all_cults) /datum/game_mode/proc/rise(cultist) if(ishuman(cultist) && iscultist(cultist)) var/mob/living/carbon/human/H = cultist + if(!H.original_eye_color) + H.original_eye_color = H.get_eye_color() H.change_eye_color(BLOODCULT_EYE, FALSE) H.update_eyes() ADD_TRAIT(H, CULT_EYES, CULT_TRAIT) @@ -249,29 +285,6 @@ GLOBAL_LIST_EMPTY(all_cults) new /obj/effect/temp_visual/cult/sparks(get_turf(H), H.dir) H.update_halo_layer() - -/datum/game_mode/proc/remove_cultist(datum/mind/cult_mind, show_message = TRUE) - if(cult_mind in cult) - var/mob/cultist = cult_mind.current - cult -= cult_mind - cultist.faction -= "cult" - cult_mind.special_role = null - for(var/datum/action/innate/cult/C in cultist.actions) - qdel(C) - update_cult_icons_removed(cult_mind) - - if(ishuman(cultist)) - var/mob/living/carbon/human/H = cultist - REMOVE_TRAIT(H, CULT_EYES, null) - H.change_eye_color(H.original_eye_color, FALSE) - H.update_eyes() - H.remove_overlay(HALO_LAYER) - H.update_body() - check_cult_size() - if(show_message) - cultist.visible_message("[cultist] looks like [cultist.p_they()] just reverted to [cultist.p_their()] old faith!", - "An unfamiliar white light flashes through your mind, cleansing the taint of [SSticker.cultdat ? SSticker.cultdat.entity_title1 : "Nar'Sie"] and the memories of your time as their servant with it.") - /datum/game_mode/proc/update_cult_icons_added(datum/mind/cult_mind) var/datum/atom_hud/antag/culthud = GLOB.huds[ANTAG_HUD_CULT] if(cult_mind.current) diff --git a/code/game/gamemodes/cult/cult_items.dm b/code/game/gamemodes/cult/cult_items.dm index ca1938a76ea..24ffbb96ce3 100644 --- a/code/game/gamemodes/cult/cult_items.dm +++ b/code/game/gamemodes/cult/cult_items.dm @@ -316,7 +316,8 @@ var/mob/living/carbon/C = user if(C.pulling) var/atom/movable/pulled = C.pulling - pulled.forceMove(T) + var/turf/turf_behind = get_turf(get_step(T, turn(C.dir, 180))) + pulled.forceMove(turf_behind) . = pulled /obj/item/cult_shift/attack_self(mob/user) @@ -324,7 +325,7 @@ to_chat(user, "[src] is dull and unmoving in your hands.") return if(!iscultist(user)) - user.unEquip(src, 1) + user.unEquip(src, TRUE) step(src, pick(GLOB.alldirs)) to_chat(user, "[src] flickers out of your hands, too eager to move!") return @@ -332,36 +333,31 @@ var/outer_tele_radius = 9 var/mob/living/carbon/C = user - var/turf/mobloc = get_turf(C) - var/list/turfs = new/list() - for(var/turf/T in range(user, outer_tele_radius)) + var/list/turfs = list() + for(var/turf/T in orange(user, outer_tele_radius)) if(!is_teleport_allowed(T.z)) break - if(get_dir(C, T) != C.dir) + if(get_dir(C, T) != C.dir) // This seems like a very bad way to do this continue - if(T == mobloc) - continue - if(istype(T, /turf/space)) + if(isspaceturf(T)) continue if(T.x > world.maxx-outer_tele_radius || T.x < outer_tele_radius) continue //putting them at the edge is dumb if(T.y > world.maxy-outer_tele_radius || T.y < outer_tele_radius) continue - turfs += T - if(turfs) + if(length(turfs)) uses-- + var/turf/mobloc = get_turf(C) var/turf/destination = pick(turfs) if(uses <= 0) - icon_state ="shifter_drained" - playsound(mobloc, "sparks", 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) + icon_state = "shifter_drained" + playsound(src, "sparks", 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) new /obj/effect/temp_visual/dir_setting/cult/phase/out(mobloc, C.dir) - var/atom/movable/pulled = handle_teleport_grab(destination, C) + handle_teleport_grab(destination, C) C.forceMove(destination) - if(pulled) - C.start_pulling(pulled) //forcemove resets pulls, so we need to re-pull new /obj/effect/temp_visual/dir_setting/cult/phase(destination, C.dir) playsound(destination, 'sound/effects/phasein.ogg', 25, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) diff --git a/code/game/gamemodes/cult/cult_objectives.dm b/code/game/gamemodes/cult/cult_objectives.dm index 4565e66ff29..ca8921b7534 100644 --- a/code/game/gamemodes/cult/cult_objectives.dm +++ b/code/game/gamemodes/cult/cult_objectives.dm @@ -133,13 +133,13 @@ for(var/mob/living/carbon/human/H in GLOB.player_list) if(is_admin_level(H.z)) //We can't sacrifice people that are on the centcom z-level continue - if(H.mind && !is_convertable_to_cult(H.mind) && (H.stat != DEAD) && (H.mind.offstation_role != TRUE)) + if(H.mind && !iscultist(H) && !is_convertable_to_cult(H.mind) && (H.stat != DEAD) && !H.mind.offstation_role) target_candidates += H.mind if(!length(target_candidates)) //There are no living unconvertables on the station. Looking for a Sacrifice Target among the ordinary crewmembers for(var/mob/living/carbon/human/H in GLOB.player_list) if(is_admin_level(H.z)) //We can't sacrifice people that are on the centcom z-level continue - if(H.mind && !iscultist(H) && (H.stat != DEAD) && (H.mind.offstation_role != TRUE)) + if(H.mind && !iscultist(H) && (H.stat != DEAD) && !H.mind.offstation_role) // Same checks, but add them even if they could be converted target_candidates += H.mind if(length(target_candidates)) target = pick(target_candidates) diff --git a/code/game/gamemodes/cult/ritual.dm b/code/game/gamemodes/cult/ritual.dm index 5211b82ea44..47a53ef89c6 100644 --- a/code/game/gamemodes/cult/ritual.dm +++ b/code/game/gamemodes/cult/ritual.dm @@ -84,6 +84,10 @@ /obj/item/melee/cultblade/dagger/proc/can_scribe(mob/living/user) if(!src || !user || loc != user || user.incapacitated()) return FALSE + if(drawing_rune) + to_chat(user, "You're already drawing a rune!") + return FALSE + var/turf/T = get_turf(user) if(isspaceturf(T)) return FALSE @@ -135,12 +139,12 @@ to_chat(user, "The veil is not weak enough here to summon a cultist, you must be on station!") return - var/old_color = user.color // we'll temporarily redden the user for better feedback to fellow cultists. Store this to revert them back. + var/old_color = user.color // we'll temporarily redden the user for better feedback to fellow cultists. Store this to revert them back. if(narsie_rune) if(!narsie_rune_check(user, A)) return // don't do shit var/list/summon_areas = gamemode.cult_objs.obj_summon.summon_spots - if(!(A in summon_areas)) // Check again to make sure they didn't move + if(!(A in summon_areas)) // Check again to make sure they didn't move to_chat(user, "The ritual can only begin where the veil is weak - in [english_list(summon_areas)]!") return GLOB.command_announcement.Announce("Figments from an eldritch god are being summoned into the [A.map_name] from an unknown dimension. Disrupt the ritual at all costs, before the station is destroyed! Space law and SOP are suspended. The entire crew must kill cultists on sight.", "Central Command Higher Dimensional Affairs", 'sound/AI/spanomalies.ogg') @@ -148,7 +152,7 @@ var/turf/T = I var/obj/machinery/shield/cult/narsie/N = new(T) shields |= N - user.color = "red" + user.color = COLOR_RED // Draw the rune var/mob/living/carbon/human/H = user @@ -161,12 +165,14 @@ user.visible_message(others_message, "You slice open your body and begin drawing a sigil of [SSticker.cultdat.entity_title3].") + drawing_rune = TRUE // Only one at a time var/scribe_successful = do_after(user, initial(rune.scribe_delay) * scribe_multiplier, target = runeturf) for(var/V in shields) // Only used for the 'Tear Veil' rune var/obj/machinery/shield/S = V if(S && !QDELETED(S)) qdel(S) user.color = old_color + drawing_rune = FALSE if(!scribe_successful) return diff --git a/code/game/gamemodes/cult/runes.dm b/code/game/gamemodes/cult/runes.dm index 4c98a3c59d3..272076e1f67 100644 --- a/code/game/gamemodes/cult/runes.dm +++ b/code/game/gamemodes/cult/runes.dm @@ -263,6 +263,8 @@ structure_check() searches for nearby cultist structures required for the invoca var/turf/T = get_turf(src) for(var/mob/living/M in T) if(!iscultist(M) || (M.mind && is_sacrifice_target(M.mind))) + if(isconstruct(M)) // No offering constructs please + continue offer_targets += M // Offering a head/brain @@ -418,6 +420,8 @@ structure_check() searches for nearby cultist structures required for the invoca /obj/effect/rune/teleport/Destroy() GLOB.teleport_runes -= src + QDEL_NULL(inner_portal) + QDEL_NULL(outer_portal) return ..() /obj/effect/rune/teleport/invoke(list/invokers) @@ -452,7 +456,7 @@ structure_check() searches for nearby cultist structures required for the invoca 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 || !Adjacent(user) || QDELETED(src) || user.incapacitated() || !actual_selected_rune) + if(QDELETED(src) || QDELETED(actual_selected_rune) ||!Adjacent(user) || user.incapacitated()) fail_invoke() return @@ -685,7 +689,7 @@ structure_check() searches for nearby cultist structures required for the invoca cultists[M.current.real_name] = M.current var/input = input(user, "Who do you wish to call to [src]?", "Acolytes") as null|anything in cultists var/mob/living/cultist_to_summon = cultists[input] - if(!src || QDELETED(src) || !Adjacent(user) || user.incapacitated()) + if(QDELETED(src) || !Adjacent(user) || user.incapacitated()) return if(!cultist_to_summon) log_game("Summon Cultist rune failed - no target") @@ -882,6 +886,7 @@ structure_check() searches for nearby cultist structures required for the invoca var/mob/living/carbon/human/new_human = new(T) new_human.real_name = ghost_to_spawn.real_name new_human.key = ghost_to_spawn.key + new_human.gender = ghost_to_spawn.gender 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, also lets you see actual ghosts @@ -999,7 +1004,7 @@ structure_check() searches for nearby cultist structures required for the invoca //BEGIN THE SUMMONING gamemode.cult_objs.succesful_summon() used = TRUE - color = rgb(255, 0, 0) + color = COLOR_RED ..() SEND_SOUND(world, sound('sound/effects/dimensional_rend.ogg')) to_chat(world, "The veil... is... TORN!!!--") diff --git a/code/game/gamemodes/wizard/soulstone.dm b/code/game/gamemodes/wizard/soulstone.dm index cd7c5d21546..3e1f1aa32bd 100644 --- a/code/game/gamemodes/wizard/soulstone.dm +++ b/code/game/gamemodes/wizard/soulstone.dm @@ -339,13 +339,11 @@ if(shade.mind) shade.mind.transfer_to(src) if(SS.purified) - set_light(3, 5, LIGHT_COLOR_DARK_BLUE) - name = "Holy [name]" - real_name = "Holy [real_name]" - + make_holy() // Replace regular soulstone summoning with purified soulstones - RemoveSpell(/obj/effect/proc_holder/spell/aoe_turf/conjure/soulstone) - AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/conjure/soulstone/holy) + if(is_type_in_list(/obj/effect/proc_holder/spell/aoe_turf/conjure/soulstone, mob_spell_list)) + RemoveSpell(/obj/effect/proc_holder/spell/aoe_turf/conjure/soulstone) + AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/conjure/soulstone/holy) else if(iscultist(src)) // Re-grant cult actions, lost in the transfer var/datum/action/innate/cult/comm/CC = new diff --git a/code/game/machinery/doors/airlock_types.dm b/code/game/machinery/doors/airlock_types.dm index 9b913dbf148..e23aa154d6d 100644 --- a/code/game/machinery/doors/airlock_types.dm +++ b/code/game/machinery/doors/airlock_types.dm @@ -532,6 +532,9 @@ L.throw_at(throwtarget, 5, 1,src) return FALSE +/obj/machinery/door/airlock/cult/screwdriver_act(mob/user, obj/item/I) + return + /obj/machinery/door/airlock/cult/cult_conceal() icon = stealth_icon overlays_file = stealth_overlays diff --git a/code/game/objects/effects/temporary_visuals/miscellaneous.dm b/code/game/objects/effects/temporary_visuals/miscellaneous.dm index 27d5eafb677..298c6686df2 100644 --- a/code/game/objects/effects/temporary_visuals/miscellaneous.dm +++ b/code/game/objects/effects/temporary_visuals/miscellaneous.dm @@ -83,7 +83,7 @@ /obj/effect/temp_visual/dir_setting/wraith name = "blood" - icon = 'icons/mob/mob.dmi' + icon = 'icons/mob/cult.dmi' icon_state = "phase_shift2" duration = 12 diff --git a/code/game/objects/items/weapons/holy_weapons.dm b/code/game/objects/items/weapons/holy_weapons.dm index a9cfbbbe36b..0b9aeee47dd 100644 --- a/code/game/objects/items/weapons/holy_weapons.dm +++ b/code/game/objects/items/weapons/holy_weapons.dm @@ -471,7 +471,7 @@ if(target.mind) if(iscultist(target)) - SSticker.mode.remove_cultist(target.mind) // This proc will handle message generation. + SSticker.mode.remove_cultist(target.mind, TRUE, TRUE) // This proc will handle message generation. praying = FALSE return diff --git a/code/modules/mob/living/carbon/human/appearance.dm b/code/modules/mob/living/carbon/human/appearance.dm index 00d0f8be2a8..c6d224975e8 100644 --- a/code/modules/mob/living/carbon/human/appearance.dm +++ b/code/modules/mob/living/carbon/human/appearance.dm @@ -202,7 +202,7 @@ H.ha_style = "None" update_head_accessory() -/mob/living/carbon/human/proc/change_eye_color(colour = "#000000", update_dna = 1) +/mob/living/carbon/human/proc/change_eye_color(colour = "#000000", update_dna = TRUE) // Update the main DNA datum, then sync the change across the organs var/obj/item/organ/internal/eyes/eyes_organ = get_int_organ(/obj/item/organ/internal/eyes) if(eyes_organ) @@ -215,10 +215,16 @@ if(update_dna) update_dna() - sync_organ_dna(assimilate=0) + sync_organ_dna(assimilate = FALSE) update_eyes() update_body() - return 1 + return TRUE + +/mob/living/carbon/human/proc/get_eye_color() + var/obj/item/organ/internal/eyes/E = get_int_organ(/obj/item/organ/internal/eyes) + if(E) + return E.eye_color + return FALSE /mob/living/carbon/human/proc/change_hair_color(colour = "#000000", secondary) var/obj/item/organ/external/head/H = get_organ("head") diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index ec931e5af9a..23f4d829d43 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -973,7 +973,7 @@ M.LAssailant = usr /mob/living/proc/check_pull() - if(pulling && !(pulling in orange(1))) + if(pulling && !pulling.Adjacent(src)) stop_pulling() /mob/living/proc/update_z(new_z) // 1+ to register, null to unregister diff --git a/code/modules/mob/living/simple_animal/constructs.dm b/code/modules/mob/living/simple_animal/constructs.dm index e45f8e311fd..b888836c5d7 100644 --- a/code/modules/mob/living/simple_animal/constructs.dm +++ b/code/modules/mob/living/simple_animal/constructs.dm @@ -4,9 +4,10 @@ mob_biotypes = NONE speak_emote = list("hisses") emote_hear = list("wails","screeches") - response_help = "thinks better of touching" + response_help = "thinks better of touching" response_disarm = "flails at" - response_harm = "punches" + response_harm = "punches" + icon = 'icons/mob/cult.dmi' icon_dead = "shade_dead" speed = 0 a_intent = INTENT_HARM @@ -26,6 +27,9 @@ deathmessage = "collapses in a shattered heap." var/construct_type = "shade" var/list/construct_spells = list() + /// Is this a holy/purified construct? + var/holy = FALSE + /// Message to send to the construct when they are created, containing information about their role. var/playstyle_string = "You are a generic construct! Your job is to not exist, and you should probably adminhelp this." /mob/living/simple_animal/hostile/construct/New() @@ -98,7 +102,6 @@ name = "Juggernaut" real_name = "Juggernaut" desc = "A possessed suit of armour driven by the will of the restless dead" - icon = 'icons/mob/mob.dmi' icon_state = "behemoth" icon_living = "behemoth" maxHealth = 250 @@ -149,7 +152,6 @@ name = "Wraith" real_name = "Wraith" desc = "A wicked bladed shell contraption piloted by a bound spirit" - icon = 'icons/mob/mob.dmi' icon_state = "floating" icon_living = "floating" maxHealth = 75 @@ -174,7 +176,6 @@ name = "Artificer" real_name = "Artificer" desc = "A bulbous construct dedicated to building and maintaining Cult armies." - icon = 'icons/mob/mob.dmi' icon_state = "artificer" icon_living = "artificer" maxHealth = 50 @@ -254,7 +255,6 @@ name = "Behemoth" real_name = "Behemoth" desc = "The pinnacle of occult technology, Behemoths are the ultimate weapon in the Cult's arsenal." - icon = 'icons/mob/mob.dmi' icon_state = "behemoth" icon_living = "behemoth" maxHealth = 750 @@ -288,7 +288,6 @@ name = "Harvester" real_name = "Harvester" desc = "A harbinger of enlightenment. It'll be all over soon." - icon = 'icons/mob/mob.dmi' icon_state = "harvester" icon_living = "harvester" maxHealth = 60 @@ -316,6 +315,17 @@ AIStatus = AI_ON environment_smash = 1 //only token destruction, don't smash the cult wall NO STOP + +/mob/living/simple_animal/hostile/construct/proc/make_holy() + if(holy) // Already holy-fied + return + holy = TRUE + set_light(3, 5, LIGHT_COLOR_DARK_BLUE) + name = "Holy [name]" + real_name = "Holy [real_name]" + faction.Remove("cult") + + ///ui stuff /mob/living/simple_animal/hostile/construct/armoured/update_health_hud() diff --git a/code/modules/mob/living/simple_animal/hostile/mining/hivelord.dm b/code/modules/mob/living/simple_animal/hostile/mining/hivelord.dm index a2972b7d14f..819612d0f34 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining/hivelord.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining/hivelord.dm @@ -419,11 +419,13 @@ back = /obj/item/tank/internals/oxygen mask = /obj/item/clothing/mask/breath if("Cultist") - uniform = /obj/item/clothing/under/roman - suit = /obj/item/clothing/suit/hooded/cultrobes - suit_store = /obj/item/tome - r_pocket = /obj/item/restraints/legcuffs/bola/cult + uniform = /obj/item/clothing/under/color/black + back = /obj/item/storage/backpack/cultpack + suit = /obj/item/clothing/suit/hooded/cultrobes/alt + if(prob(40)) + suit_store = /obj/item/melee/cultblade l_pocket = /obj/item/melee/cultblade/dagger - glasses = /obj/item/clothing/glasses/hud/health/night - backpack_contents = list(/obj/item/reagent_containers/food/drinks/bottle/unholywater = 1, /obj/item/cult_shift = 1, /obj/item/flashlight/flare = 1, /obj/item/stack/sheet/runed_metal = 15) + if(prob(60)) + r_pocket = /obj/item/reagent_containers/food/drinks/bottle/unholywater + backpack_contents = list(/obj/item/tome = 1, /obj/item/restraints/legcuffs/bola/cult = 1, /obj/item/stack/sheet/runed_metal = 15) . = ..() diff --git a/code/modules/mob/living/simple_animal/shade.dm b/code/modules/mob/living/simple_animal/shade.dm index eaf5c6e0625..3e4686e146d 100644 --- a/code/modules/mob/living/simple_animal/shade.dm +++ b/code/modules/mob/living/simple_animal/shade.dm @@ -2,7 +2,7 @@ name = "Shade" real_name = "Shade" desc = "A bound spirit" - icon = 'icons/mob/mob.dmi' + icon = 'icons/mob/cult.dmi' icon_state = "shade" icon_living = "shade" icon_dead = "shade_dead" @@ -34,6 +34,10 @@ deathmessage = "lets out a contented sigh as their form unwinds." var/holy = FALSE +/mob/living/simple_animal/shade/cult/Initialize(mapload) + . = ..() + icon_state = SSticker.cultdat?.shade_icon_state + /mob/living/simple_animal/shade/death(gibbed) . = ..() SSticker.mode.remove_cultist(mind, FALSE) @@ -48,11 +52,6 @@ /mob/living/simple_animal/shade/Process_Spacemove() return TRUE - -/mob/living/simple_animal/shade/cult/Initialize(mapload) - . = ..() - icon_state = SSticker.cultdat?.shade_icon_state - /mob/living/simple_animal/shade/holy holy = TRUE icon_state = "shade_angelic" diff --git a/code/modules/mob/mob_grab.dm b/code/modules/mob/mob_grab.dm index 14901a8384d..61118a32cdb 100644 --- a/code/modules/mob/mob_grab.dm +++ b/code/modules/mob/mob_grab.dm @@ -193,6 +193,8 @@ /obj/item/grab/proc/adjust_position() if(affecting.buckled) return + if(!assailant.Adjacent(affecting)) // To prevent teleportation via grab + return if(affecting.lying && state != GRAB_KILL) animate(affecting, pixel_x = 0, pixel_y = 0, 5, 1, LINEAR_EASING) return //KJK diff --git a/code/modules/reagents/chemistry/reagents/water.dm b/code/modules/reagents/chemistry/reagents/water.dm index c51972b99c6..6be18db54a5 100644 --- a/code/modules/reagents/chemistry/reagents/water.dm +++ b/code/modules/reagents/chemistry/reagents/water.dm @@ -265,16 +265,11 @@ M.SetConfused(0) return if(iscultist(M)) - SSticker.mode.remove_cultist(M.mind) + SSticker.mode.remove_cultist(M.mind, TRUE, TRUE) holder.remove_reagent(id, volume) // maybe this is a little too perfect and a max() cap on the statuses would be better?? M.SetJitter(0) M.SetStuttering(0) M.SetConfused(0) - if(ishuman(M)) // Unequip all cult clothing - var/mob/living/carbon/human/H = M - for(var/I in H.contents) - if(is_type_in_list(I, CULT_CLOTHING)) - H.unEquip(I) return if(ishuman(M) && M.mind && M.mind.vampire && !M.mind.vampire.get_ability(/datum/vampire_passive/full) && prob(80)) var/mob/living/carbon/V = M diff --git a/icons/mob/cult.dmi b/icons/mob/cult.dmi new file mode 100644 index 00000000000..b13bfa1b51b Binary files /dev/null and b/icons/mob/cult.dmi differ diff --git a/icons/mob/mob.dmi b/icons/mob/mob.dmi index 79a05bd3b88..86151e74123 100644 Binary files a/icons/mob/mob.dmi and b/icons/mob/mob.dmi differ