diff --git a/_maps/RandomRuins/IceRuins/icemoon_underground_abandoned_homestead.dmm b/_maps/RandomRuins/IceRuins/icemoon_underground_abandoned_homestead.dmm index f8fd8f41c92..86db7b55fe7 100644 --- a/_maps/RandomRuins/IceRuins/icemoon_underground_abandoned_homestead.dmm +++ b/_maps/RandomRuins/IceRuins/icemoon_underground_abandoned_homestead.dmm @@ -185,7 +185,7 @@ pixel_x = -3; pixel_y = 3 }, -/obj/item/storage/book/bible{ +/obj/item/book/bible{ pixel_y = 5 }, /obj/item/flashlight/flare/candle{ diff --git a/_maps/RandomRuins/SpaceRuins/clericden.dmm b/_maps/RandomRuins/SpaceRuins/clericden.dmm index 0bf5a3a0579..ed9b63c7947 100644 --- a/_maps/RandomRuins/SpaceRuins/clericden.dmm +++ b/_maps/RandomRuins/SpaceRuins/clericden.dmm @@ -180,7 +180,7 @@ /turf/open/floor/plating/airless, /area/ruin/space) "Q" = ( -/obj/item/storage/book/bible, +/obj/item/book/bible, /obj/effect/decal/cleanable/blood, /turf/open/misc/asteroid/airless, /area/ruin/space) diff --git a/_maps/RandomRuins/SpaceRuins/dangerous_research.dmm b/_maps/RandomRuins/SpaceRuins/dangerous_research.dmm index 1900de44f14..b5ff8df5e29 100644 --- a/_maps/RandomRuins/SpaceRuins/dangerous_research.dmm +++ b/_maps/RandomRuins/SpaceRuins/dangerous_research.dmm @@ -9,7 +9,7 @@ "ae" = ( /obj/structure/table, /obj/machinery/light/small/directional/west, -/obj/item/storage/book/bible{ +/obj/item/book/bible{ pixel_x = 3 }, /obj/item/book/manual/wiki/cytology{ diff --git a/_maps/RandomRuins/SpaceRuins/russian_derelict.dmm b/_maps/RandomRuins/SpaceRuins/russian_derelict.dmm index f94a92e06b0..a80bb186c12 100644 --- a/_maps/RandomRuins/SpaceRuins/russian_derelict.dmm +++ b/_maps/RandomRuins/SpaceRuins/russian_derelict.dmm @@ -1011,7 +1011,7 @@ /area/ruin/space/ks13/hallway/aft) "oC" = ( /obj/structure/table/wood, -/obj/item/storage/book/bible, +/obj/item/book/bible, /obj/effect/decal/cleanable/dirt, /obj/machinery/light/small/directional/east, /obj/structure/cable, diff --git a/_maps/map_files/Birdshot/birdshot.dmm b/_maps/map_files/Birdshot/birdshot.dmm index c522d0e265e..1bfccc91922 100644 --- a/_maps/map_files/Birdshot/birdshot.dmm +++ b/_maps/map_files/Birdshot/birdshot.dmm @@ -9562,7 +9562,7 @@ /area/station/engineering/atmos) "dSQ" = ( /obj/structure/table/wood, -/obj/item/storage/book/bible, +/obj/item/book/bible, /obj/machinery/light/small/directional/east, /obj/effect/decal/cleanable/dirt/dust, /turf/open/floor/iron/dark/smooth_edge{ @@ -15505,7 +15505,7 @@ /area/station/ai_monitored/turret_protected/aisat/maint) "fZC" = ( /obj/structure/table/wood, -/obj/item/storage/book/bible, +/obj/item/book/bible, /obj/effect/decal/cleanable/dirt/dust, /turf/open/floor/iron/dark/smooth_edge, /area/station/maintenance/starboard/greater) @@ -64949,7 +64949,7 @@ /area/station/cargo/office) "wzx" = ( /obj/structure/altar_of_gods, -/obj/item/storage/book/bible, +/obj/item/book/bible, /turf/open/floor/carpet/lone, /area/station/service/chapel/office) "wzK" = ( diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm index c850f6f24f5..8858a325985 100644 --- a/_maps/map_files/Deltastation/DeltaStation2.dmm +++ b/_maps/map_files/Deltastation/DeltaStation2.dmm @@ -11355,7 +11355,7 @@ /area/station/maintenance/port/fore) "cKr" = ( /obj/structure/table/wood/fancy, -/obj/item/storage/book/bible, +/obj/item/book/bible, /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/service/chapel/funeral) @@ -84913,7 +84913,7 @@ /turf/open/floor/iron, /area/station/engineering/atmos/mix) "vkr" = ( -/obj/item/storage/book/bible, +/obj/item/book/bible, /obj/structure/altar_of_gods, /turf/open/floor/iron/grimy, /area/station/service/chapel) diff --git a/_maps/map_files/IceBoxStation/IceBoxStation.dmm b/_maps/map_files/IceBoxStation/IceBoxStation.dmm index 7b8bbeafbb3..2c12463158a 100644 --- a/_maps/map_files/IceBoxStation/IceBoxStation.dmm +++ b/_maps/map_files/IceBoxStation/IceBoxStation.dmm @@ -7798,7 +7798,7 @@ "cvv" = ( /obj/structure/table/wood, /obj/machinery/airalarm/directional/north, -/obj/item/storage/book/bible, +/obj/item/book/bible, /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/service/chapel) @@ -19362,7 +19362,7 @@ /turf/open/floor/eighties/red, /area/station/security/prison/safe) "gcP" = ( -/obj/item/storage/book/bible, +/obj/item/book/bible, /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -30671,7 +30671,7 @@ pixel_x = -7; pixel_y = 3 }, -/obj/item/storage/book{ +/obj/item/book{ name = "Tales from the First"; pixel_x = 5; pixel_y = 5 @@ -47616,7 +47616,7 @@ /area/station/security/prison) "peA" = ( /obj/structure/table/wood, -/obj/item/storage/book/bible, +/obj/item/book/bible, /turf/open/floor/iron/dark, /area/station/service/chapel/office) "peV" = ( @@ -54534,7 +54534,7 @@ /area/station/cargo/lobby) "rqR" = ( /obj/structure/table/glass, -/obj/item/storage/book/bible, +/obj/item/book/bible, /turf/open/floor/iron/chapel, /area/station/service/chapel) "rqT" = ( @@ -75984,7 +75984,7 @@ "ygp" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/item/storage/book/bible, +/obj/item/book/bible, /obj/structure/altar_of_gods, /turf/open/floor/iron/dark, /area/station/service/chapel) diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm index 67630a5fe5f..e2d5cdf04d3 100644 --- a/_maps/map_files/MetaStation/MetaStation.dmm +++ b/_maps/map_files/MetaStation/MetaStation.dmm @@ -3729,7 +3729,7 @@ desc = "A memorial wall for pinning mementos upon."; name = "memorial board" }, -/obj/item/storage/book/bible, +/obj/item/book/bible, /obj/structure/table/wood, /turf/open/floor/carpet, /area/station/service/chapel/funeral) @@ -42991,7 +42991,7 @@ /turf/open/floor/circuit/telecomms/mainframe, /area/station/tcommsat/server) "pwq" = ( -/obj/item/storage/book/bible, +/obj/item/book/bible, /obj/structure/altar_of_gods, /turf/open/floor/iron/dark, /area/station/service/chapel) @@ -51281,7 +51281,7 @@ /turf/open/floor/iron, /area/station/security/execution/transfer) "ssi" = ( -/obj/item/storage/book/bible, +/obj/item/book/bible, /obj/machinery/light/small/directional/north, /obj/machinery/newscaster/directional/north, /obj/machinery/camera/directional/north{ diff --git a/_maps/map_files/NorthStar/north_star.dmm b/_maps/map_files/NorthStar/north_star.dmm index 074559112ab..bad1e16ef64 100644 --- a/_maps/map_files/NorthStar/north_star.dmm +++ b/_maps/map_files/NorthStar/north_star.dmm @@ -33588,7 +33588,7 @@ "iUE" = ( /obj/structure/altar_of_gods, /obj/effect/turf_decal/siding/white, -/obj/item/storage/book/bible, +/obj/item/book/bible, /turf/open/floor/mineral/silver, /area/station/service/chapel) "iUP" = ( @@ -65637,7 +65637,7 @@ /area/station/service/library) "rdu" = ( /obj/structure/table/bronze, -/obj/item/storage/book/bible, +/obj/item/book/bible, /turf/open/floor/iron, /area/station/service/chapel) "rdx" = ( diff --git a/_maps/map_files/tramstation/maintenance_modules/dormmedupper_attachment_a_3.dmm b/_maps/map_files/tramstation/maintenance_modules/dormmedupper_attachment_a_3.dmm index 0c6ee1868b3..e05c8702d05 100644 --- a/_maps/map_files/tramstation/maintenance_modules/dormmedupper_attachment_a_3.dmm +++ b/_maps/map_files/tramstation/maintenance_modules/dormmedupper_attachment_a_3.dmm @@ -6,12 +6,12 @@ "h" = ( /obj/structure/rack, /obj/structure/window/spawner/directional/east, -/obj/item/storage/book/bible{ +/obj/item/book/bible{ pixel_x = -4; pixel_y = -4 }, -/obj/item/storage/book/bible, -/obj/item/storage/book/bible{ +/obj/item/book/bible, +/obj/item/book/bible{ pixel_x = 4; pixel_y = 4 }, diff --git a/_maps/map_files/tramstation/tramstation.dmm b/_maps/map_files/tramstation/tramstation.dmm index 4b0575a6c9b..fd57d03ad59 100644 --- a/_maps/map_files/tramstation/tramstation.dmm +++ b/_maps/map_files/tramstation/tramstation.dmm @@ -6777,7 +6777,7 @@ /turf/open/floor/plating, /area/station/ai_monitored/turret_protected/aisat/foyer) "aQc" = ( -/obj/item/storage/book/bible, +/obj/item/book/bible, /obj/structure/altar_of_gods, /turf/open/floor/iron/dark, /area/station/service/chapel) @@ -42948,7 +42948,7 @@ "ohW" = ( /obj/structure/table/wood, /obj/machinery/light/dim/directional/north, -/obj/item/storage/book/bible, +/obj/item/book/bible, /turf/open/floor/carpet, /area/station/service/chapel/monastery) "ohY" = ( @@ -63100,7 +63100,7 @@ "vrd" = ( /obj/structure/table/wood, /obj/machinery/firealarm/directional/north, -/obj/item/storage/book/bible, +/obj/item/book/bible, /turf/open/floor/iron/chapel{ dir = 9 }, diff --git a/_maps/shuttles/emergency_cruise.dmm b/_maps/shuttles/emergency_cruise.dmm index 98d380a12bc..d488bf896c7 100644 --- a/_maps/shuttles/emergency_cruise.dmm +++ b/_maps/shuttles/emergency_cruise.dmm @@ -694,7 +694,7 @@ /area/shuttle/escape) "LM" = ( /obj/structure/table/reinforced, -/obj/item/storage/book/bible/booze{ +/obj/item/book/bible/booze{ pixel_x = -3; pixel_y = 4 }, diff --git a/_maps/shuttles/emergency_monastery.dmm b/_maps/shuttles/emergency_monastery.dmm index d4f75fa0a0d..ad47329ff48 100644 --- a/_maps/shuttles/emergency_monastery.dmm +++ b/_maps/shuttles/emergency_monastery.dmm @@ -1612,9 +1612,9 @@ "yr" = ( /obj/structure/closet, /obj/machinery/light/small/directional/south, -/obj/item/storage/book/bible, -/obj/item/storage/book/bible, -/obj/item/storage/book/bible, +/obj/item/book/bible, +/obj/item/book/bible, +/obj/item/book/bible, /turf/open/floor/carpet, /area/shuttle/escape) "yu" = ( @@ -2037,7 +2037,7 @@ /turf/open/misc/asteroid, /area/shuttle/escape) "Dv" = ( -/obj/item/storage/book/bible, +/obj/item/book/bible, /obj/structure/cable, /obj/structure/altar_of_gods, /turf/open/floor/carpet, @@ -3211,7 +3211,7 @@ /area/shuttle/escape) "Si" = ( /obj/structure/table/wood/fancy, -/obj/item/storage/book/bible, +/obj/item/book/bible, /turf/open/floor/carpet, /area/shuttle/escape) "Sj" = ( diff --git a/_maps/templates/holodeck_chapelcourt.dmm b/_maps/templates/holodeck_chapelcourt.dmm index 96c39503c3e..6f87e03bc16 100644 --- a/_maps/templates/holodeck_chapelcourt.dmm +++ b/_maps/templates/holodeck_chapelcourt.dmm @@ -190,7 +190,7 @@ /area/template_noop) "au" = ( /obj/structure/table/wood/fancy, -/obj/item/storage/book/bible, +/obj/item/book/bible, /obj/effect/turf_decal/tile/neutral, /obj/effect/turf_decal/tile/neutral{ dir = 1 @@ -495,7 +495,7 @@ /area/template_noop) "kv" = ( /obj/structure/table/wood/fancy, -/obj/item/storage/book/bible, +/obj/item/book/bible, /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/holofloor/dark, /area/template_noop) diff --git a/_maps/templates/lazy_templates/ninja_den.dmm b/_maps/templates/lazy_templates/ninja_den.dmm index d7eafeb4cc3..14a479d5c49 100644 --- a/_maps/templates/lazy_templates/ninja_den.dmm +++ b/_maps/templates/lazy_templates/ninja_den.dmm @@ -122,7 +122,7 @@ /area/centcom/central_command_areas/holding) "dj" = ( /obj/structure/table/wood/fancy/royalblack, -/obj/item/storage/book/bible, +/obj/item/book/bible, /turf/open/floor/wood/large, /area/centcom/central_command_areas/holding) "dy" = ( diff --git a/code/__DEFINES/achievements.dm b/code/__DEFINES/achievements.dm index 96f0a7e023f..10121577466 100644 --- a/code/__DEFINES/achievements.dm +++ b/code/__DEFINES/achievements.dm @@ -45,6 +45,7 @@ #define MEDAL_NARSUPREME "Narsupreme" #define MEDAL_SPRINGLOCK "The Man Inside the Modsuit" #define MEDAL_HEALTHY "Heart Healthy" +#define MEDAL_GODS_WRATH "God's Wrath" //Skill medal hub IDs #define MEDAL_LEGENDARY_MINER "Legendary Miner" diff --git a/code/__DEFINES/dcs/signals/signals_object.dm b/code/__DEFINES/dcs/signals/signals_object.dm index b278dfb6e0e..7a336ec1d4e 100644 --- a/code/__DEFINES/dcs/signals/signals_object.dm +++ b/code/__DEFINES/dcs/signals/signals_object.dm @@ -171,7 +171,7 @@ ///from [/obj/structure/closet/supplypod/proc/preOpen]: #define COMSIG_SUPPLYPOD_LANDED "supplypodgoboom" -///from /obj/item/storage/book/bible/afterattack(): (mob/user, proximity) +///from /obj/item/book/bible/afterattack(): (mob/user, proximity) #define COMSIG_BIBLE_SMACKED "bible_smacked" ///stops the bible chain from continuing. When all of the effects of the bible smacking have been moved to a signal we can kill this #define COMSIG_END_BIBLE_CHAIN (1<<0) diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm index 258aa884b2e..3d08f8d7099 100644 --- a/code/__DEFINES/is_helpers.dm +++ b/code/__DEFINES/is_helpers.dm @@ -267,7 +267,7 @@ GLOBAL_LIST_INIT(glass_sheet_types, typecacheof(list( GLOBAL_LIST_INIT(book_types, typecacheof(list( /obj/item/book, /obj/item/spellbook, - /obj/item/storage/book))) +))) // Jobs #define is_job(job_type) (istype(job_type, /datum/job)) diff --git a/code/datums/achievements/misc_achievements.dm b/code/datums/achievements/misc_achievements.dm index 8d9e5e2db3d..55b5d70cdf9 100644 --- a/code/datums/achievements/misc_achievements.dm +++ b/code/datums/achievements/misc_achievements.dm @@ -217,3 +217,9 @@ desc = "Don't be such a baby, it's just a heart attack. You've bounced back from worse!" database_id = MEDAL_HEALTHY icon = "picofhealth" + +/datum/award/achievement/misc/gods_wrath + name = "God's Wrath" + desc = "Did you think you could get away with defiling the word of God?" + database_id = MEDAL_GODS_WRATH + icon = "godswrath" diff --git a/code/datums/components/crafting/tailoring.dm b/code/datums/components/crafting/tailoring.dm index 7adc8e99dfa..77b056e8235 100644 --- a/code/datums/components/crafting/tailoring.dm +++ b/code/datums/components/crafting/tailoring.dm @@ -268,7 +268,7 @@ time = 1 SECONDS tool_paths = list( /obj/item/clothing/suit/hooded/chaplain_hoodie, - /obj/item/storage/book/bible, + /obj/item/book/bible, ) reqs = list(/obj/item/stack/sheet/cloth = 4) category = CAT_CLOTHING diff --git a/code/datums/components/omen.dm b/code/datums/components/omen.dm index 0f30f7e2a34..46ff3990c2c 100644 --- a/code/datums/components/omen.dm +++ b/code/datums/components/omen.dm @@ -17,11 +17,18 @@ /// Base damage from negative events. Cursed take 25% less damage. var/damage_mod = 1 -/datum/component/omen/Initialize(vessel) +/datum/component/omen/Initialize(obj/vessel, permanent, luck_mod, damage_mod) if(!isliving(parent)) return COMPONENT_INCOMPATIBLE - src.vessel = vessel + if(istype(vessel)) + src.vessel = vessel + RegisterSignal(vessel, COMSIG_PARENT_QDELETING, PROC_REF(vessel_qdeleting)) + src.permanent = permanent + if(!isnull(luck_mod)) + src.luck_mod = luck_mod + if(!isnull(damage_mod)) + src.damage_mod = damage_mod /datum/component/omen/Destroy(force) var/mob/living/person = parent @@ -29,6 +36,8 @@ if(vessel) vessel.visible_message(span_warning("[vessel] burns up in a sinister flash, taking an evil energy with it...")) + UnregisterSignal(vessel, COMSIG_PARENT_QDELETING) + vessel.burn() vessel = null return ..() @@ -53,8 +62,8 @@ if(!isliving(our_guy)) return - var/mob/living/living_guy = our_guy + var/mob/living/living_guy = our_guy if(!prob(15 * luck_mod)) return @@ -124,7 +133,10 @@ /datum/component/omen/proc/check_bless(mob/living/our_guy, category) SIGNAL_HANDLER - if (!("blessing" in our_guy.mob_mood.mood_events)) + if(permanent) + return + + if(!("blessing" in our_guy.mob_mood.mood_events)) return qdel(src) @@ -133,6 +145,9 @@ /datum/component/omen/proc/check_death(mob/living/our_guy) SIGNAL_HANDLER + if(permanent) + return + qdel(src) /// Creates a localized explosion that shakes the camera @@ -142,21 +157,18 @@ for(var/mob/witness in view(2, our_guy)) shake_camera(witness, 1 SECONDS, 2) +/// Vessel got deleted, set it to null +/datum/component/omen/proc/vessel_qdeleting(atom/source) + SIGNAL_HANDLER + + UnregisterSignal(vessel, COMSIG_PARENT_QDELETING) + vessel = null + /** * The smite omen. Permanent. */ /datum/component/omen/smite -/datum/component/omen/smite/Initialize(vessel, permanent) - . = ..() - src.permanent = permanent - -/datum/component/omen/smite/check_bless(mob/living/our_guy, category) - if(!permanent) - return ..() - - return - /datum/component/omen/smite/check_death(mob/living/our_guy) if(!permanent) return ..() @@ -198,3 +210,22 @@ player.spawn_gibs() return + +/** + * The bible omen. + * While it lasts, parent gets a cursed aura filter. + */ +/datum/component/omen/bible + +/datum/component/omen/bible/RegisterWithParent() + . = ..() + var/mob/living/living_parent = parent + living_parent.add_filter("omen", 2, list("type" = "drop_shadow", "color" = COLOR_DARK_RED, "alpha" = 0, "size" = 2)) + var/filter = living_parent.get_filter("omen") + animate(filter, alpha = 255, time = 2 SECONDS, loop = -1) + animate(alpha = 0, time = 2 SECONDS) + +/datum/component/omen/bible/UnregisterFromParent() + . = ..() + var/mob/living/living_parent = parent + living_parent.remove_filter("omen") diff --git a/code/datums/components/religious_tool.dm b/code/datums/components/religious_tool.dm index 0aedee328ea..f28578c5ce9 100644 --- a/code/datums/components/religious_tool.dm +++ b/code/datums/components/religious_tool.dm @@ -14,7 +14,7 @@ /// The rite currently being invoked var/datum/religion_rites/performing_rite ///Sets the type for catalyst - var/catalyst_type = /obj/item/storage/book/bible + var/catalyst_type = /obj/item/book/bible ///Enables overide of COMPONENT_NO_AFTERATTACK, not recommended as it means you can potentially cause damage to the item using the catalyst. var/force_catalyst_afterattack = FALSE var/datum/callback/after_sect_select_cb diff --git a/code/datums/memory/general_memories.dm b/code/datums/memory/general_memories.dm index 1326b72fe16..e3a4a88cd76 100644 --- a/code/datums/memory/general_memories.dm +++ b/code/datums/memory/general_memories.dm @@ -914,3 +914,49 @@ "[protagonist_name]'s mind sets itself on a singular, violent purpose as they're flashed by [antagonist_name]: Kill the heads.", "[antagonist_name] lifts an odd device to [protagonist_name]'s eyes and flashes him, imprinting murderous instructions.", ) + +/// Saw someone play Russian Roulette. +/datum/memory/witnessed_gods_wrath + memory_flags = MEMORY_CHECK_BLINDNESS|MEMORY_SKIP_UNCONSCIOUS + story_value = STORY_VALUE_AMAZING + +/datum/memory/witnessed_gods_wrath/New( + datum/mind/memorizer_mind, + atom/protagonist, + atom/deuteragonist, + atom/antagonist, +) + +/datum/memory/witnessed_gods_wrath/get_names() + return list("[protagonist_name] suffering the wrath of [antagonist_name].") + +/datum/memory/witnessed_gods_wrath/get_starts() + return list( + "[protagonist_name] burns [deuteragonist_name], and [antagonist_name] turns [protagonist_name] into a fine red mist.", + "[antagonist_name] explodes [protagonist_name] into a million pieces for defiling [deuteragonist_name].", + "[protagonist_name] angers [antagonist_name] by defiling [deuteragonist_name], and gets obliterated.", + ) + +/datum/memory/witnessed_gods_wrath/get_moods() + return list("[protagonist_name] [mood_verb] as they get annihilated by [antagonist_name].") + +/datum/memory/witnessed_gods_wrath/get_happy_moods() + return list( + "cackles hysterically", + "laughs maniacally", + "grins widely", + ) + +/datum/memory/witnessed_gods_wrath/get_neutral_moods() + return list( + "appears concerned", + "reconsiders their life decisions", + "has a blank expression", + ) + +/datum/memory/witnessed_gods_wrath/get_sad_moods() + return list( + "appears dejected", + "is filled with regret", + "winces in despair" + ) diff --git a/code/datums/quirks/positive_quirks.dm b/code/datums/quirks/positive_quirks.dm index 70628be0478..45168f725ff 100644 --- a/code/datums/quirks/positive_quirks.dm +++ b/code/datums/quirks/positive_quirks.dm @@ -267,7 +267,7 @@ lose_text = span_danger("You lose faith!") medical_record_text = "Patient reports a belief in a higher power." mail_goodies = list( - /obj/item/storage/book/bible/booze, + /obj/item/book/bible/booze, /obj/item/reagent_containers/cup/glass/bottle/holywater, /obj/item/bedsheet/chaplain, /obj/item/toy/cards/deck/tarot, diff --git a/code/game/objects/items/granters/_granters.dm b/code/game/objects/items/granters/_granters.dm index 8cb63925f24..ad9b9a453f0 100644 --- a/code/game/objects/items/granters/_granters.dm +++ b/code/game/objects/items/granters/_granters.dm @@ -5,7 +5,7 @@ */ /obj/item/book/granter due_date = 0 - unique = 1 + unique = TRUE /// Flavor messages displayed to mobs reading the granter var/list/remarks = list() /// Controls how long a mob must keep the book in his hand to actually successfully learn diff --git a/code/game/objects/items/storage/bags.dm b/code/game/objects/items/storage/bags.dm index ec272c32874..88570986e72 100644 --- a/code/game/objects/items/storage/bags.dm +++ b/code/game/objects/items/storage/bags.dm @@ -325,11 +325,7 @@ atom_storage.max_specific_storage = WEIGHT_CLASS_NORMAL atom_storage.max_total_storage = 21 atom_storage.max_slots = 7 - atom_storage.set_holdable(list( - /obj/item/book, - /obj/item/spellbook, - /obj/item/storage/book, - )) + atom_storage.set_holdable(list(/obj/item/book, /obj/item/spellbook)) /* * Trays - Agouri diff --git a/code/game/objects/items/storage/book.dm b/code/game/objects/items/storage/book.dm deleted file mode 100644 index f558d9552d2..00000000000 --- a/code/game/objects/items/storage/book.dm +++ /dev/null @@ -1,293 +0,0 @@ -/obj/item/storage/book - name = "hollowed book" - desc = "I guess someone didn't like it." - icon = 'icons/obj/library.dmi' - icon_state ="book" - worn_icon_state = "book" - throw_speed = 2 - throw_range = 5 - w_class = WEIGHT_CLASS_NORMAL - resistance_flags = FLAMMABLE - var/title = "book" - -/obj/item/storage/book/Initialize(mapload) - . = ..() - atom_storage.max_slots = 1 - -/obj/item/storage/book/attack_self(mob/user) - balloon_alert(user, "pages cut out!") - -GLOBAL_LIST_INIT(biblenames, list("Bible", "Quran", "Scrapbook", "Burning Bible", "Clown Bible", "Banana Bible", "Creeper Bible", "White Bible", "Holy Light", "The God Delusion", "Tome", "The King in Yellow", "Ithaqua", "Scientology", "Melted Bible", "Necronomicon", "Insulationism", "Guru Granth Sahib", "Kojiki")) -//If you get these two lists not matching in size, there will be runtimes and I will hurt you in ways you couldn't even begin to imagine -// if your bible has no custom itemstate, use one of the existing ones -GLOBAL_LIST_INIT(biblestates, list("bible", "koran", "scrapbook", "burning", "honk1", "honk2", "creeper", "white", "holylight", "atheist", "tome", "kingyellow", "ithaqua", "scientology", "melted", "necronomicon", "insuls", "gurugranthsahib", "kojiki")) -GLOBAL_LIST_INIT(bibleitemstates, list("bible", "koran", "scrapbook", "burning", "honk1", "honk2", "creeper", "white", "holylight", "atheist", "tome", "kingyellow", "ithaqua", "scientology", "melted", "necronomicon", "kingyellow", "gurugranthsahib", "kojiki")) - -/obj/item/storage/book/bible - name = "bible" - desc = "Apply to head repeatedly." - icon = 'icons/obj/storage/book.dmi' - icon_state = "bible" - inhand_icon_state = "bible" - worn_icon_state = "bible" - lefthand_file = 'icons/mob/inhands/items/books_lefthand.dmi' - righthand_file = 'icons/mob/inhands/items/books_righthand.dmi' - var/mob/affecting = null - var/deity_name = "Christ" - force_string = "holy" - -/obj/item/storage/book/bible/examine(mob/user) - . = ..() - if(user?.mind?.holy_role) - if(GLOB.chaplain_altars.len) - . += span_notice("[src] has an expansion pack to replace any broken Altar.") - else - . += span_notice("[src] can be unpacked by hitting the floor of a holy area with it.") - -/obj/item/storage/book/bible/Initialize(mapload) - . = ..() - atom_storage.max_specific_storage = WEIGHT_CLASS_SMALL - AddComponent(/datum/component/anti_magic, MAGIC_RESISTANCE_HOLY) - -/obj/item/storage/book/bible/suicide_act(mob/living/user) - user.visible_message(span_suicide("[user] is offering [user.p_them()]self to [deity_name]! It looks like [user.p_theyre()] trying to commit suicide!")) - return BRUTELOSS - -/obj/item/storage/book/bible/attack_self(mob/living/carbon/human/user) - if(GLOB.bible_icon_state) - return FALSE - if(user?.mind?.holy_role != HOLY_ROLE_HIGHPRIEST) - return FALSE - - var/list/skins = list() - for(var/i in 1 to GLOB.biblestates.len) - var/image/bible_image = image(icon = 'icons/obj/storage/book.dmi', icon_state = GLOB.biblestates[i]) - skins += list("[GLOB.biblenames[i]]" = bible_image) - - var/choice = show_radial_menu(user, src, skins, custom_check = CALLBACK(src, PROC_REF(check_menu), user), radius = 40, require_near = TRUE) - if(!choice) - return FALSE - var/bible_index = GLOB.biblenames.Find(choice) - if(!bible_index) - return FALSE - icon_state = GLOB.biblestates[bible_index] - inhand_icon_state = GLOB.bibleitemstates[bible_index] - - switch(icon_state) - if("honk1") - user.dna.add_mutation(/datum/mutation/human/clumsy) - user.equip_to_slot_or_del(new /obj/item/clothing/mask/gas/clown_hat(user), ITEM_SLOT_MASK) - if("honk2") - user.dna.add_mutation(/datum/mutation/human/clumsy) - user.equip_to_slot_or_del(new /obj/item/clothing/mask/gas/clown_hat(user), ITEM_SLOT_MASK) - if("insuls") - var/obj/item/clothing/gloves/color/fyellow/insuls = new - insuls.name = "insuls" - insuls.desc = "A mere copy of the true insuls." - insuls.siemens_coefficient = 0.99999 - user.equip_to_slot(insuls, ITEM_SLOT_GLOVES) - GLOB.bible_icon_state = icon_state - GLOB.bible_inhand_icon_state = inhand_icon_state - SSblackbox.record_feedback("text", "religion_book", 1, "[choice]") - -/** - * Checks if we are allowed to interact with a radial menu - * - * Arguments: - * * user The mob interacting with the menu - */ -/obj/item/storage/book/bible/proc/check_menu(mob/living/carbon/human/user) - if(GLOB.bible_icon_state) - return FALSE - if(!istype(user) || !user.is_holding(src)) - return FALSE - if(user.incapacitated()) - return FALSE - if(user.mind?.holy_role != HOLY_ROLE_HIGHPRIEST) - return FALSE - return TRUE - -/obj/item/storage/book/bible/proc/make_new_altar(atom/bible_smacked, mob/user) - var/new_altar_area = get_turf(bible_smacked) - - balloon_alert(user, "unpacking bible...") - if(!do_after(user, 15 SECONDS, new_altar_area)) - return - new /obj/structure/altar_of_gods(new_altar_area) - qdel(src) - -/obj/item/storage/book/bible/proc/bless(mob/living/L, mob/living/user) - if(GLOB.religious_sect) - return GLOB.religious_sect.sect_bless(L,user) - if(!ishuman(L)) - return - var/mob/living/carbon/human/H = L - for(var/obj/item/bodypart/bodypart as anything in H.bodyparts) - if(!IS_ORGANIC_LIMB(bodypart)) - balloon_alert(user, "can't heal metal!") - return 0 - - var/heal_amt = 10 - var/list/hurt_limbs = H.get_damaged_bodyparts(1, 1, BODYTYPE_ORGANIC) - - if(hurt_limbs.len) - for(var/X in hurt_limbs) - var/obj/item/bodypart/affecting = X - if(affecting.heal_damage(heal_amt, heal_amt, BODYTYPE_ORGANIC)) - H.update_damage_overlays() - H.visible_message(span_notice("[user] heals [H] with the power of [deity_name]!")) - to_chat(H, span_boldnotice("May the power of [deity_name] compel you to be healed!")) - playsound(src.loc, SFX_PUNCH, 25, TRUE, -1) - H.add_mood_event("blessing", /datum/mood_event/blessing) - return TRUE - -/obj/item/storage/book/bible/attack(mob/living/M, mob/living/carbon/human/user, heal_mode = TRUE) - - if (!ISADVANCEDTOOLUSER(user)) - balloon_alert(user, "not dextrous enough!") - return - - if (HAS_TRAIT(user, TRAIT_CLUMSY) && prob(50)) - to_chat(user, span_danger("[src] slips out of your hand and hits your head.")) - user.take_bodypart_damage(10) - user.Unconscious(40 SECONDS) - return - - if (!user.mind || !user.mind.holy_role) - to_chat(user, span_danger("The book sizzles in your hands.")) - user.take_bodypart_damage(0, 10) - return - - if (!heal_mode) - return ..() - - if (M.stat == DEAD) - M.visible_message(span_danger("[user] smacks [M]'s lifeless corpse with [src].")) - playsound(src.loc, SFX_PUNCH, 25, TRUE, -1) - return - - if(user == M) - balloon_alert(user, "can't heal yourself!") - return - - var/smack = TRUE - - if(prob(60) && bless(M, user)) - smack = FALSE - else if(iscarbon(M)) - var/mob/living/carbon/C = M - if(!istype(C.head, /obj/item/clothing/head/helmet)) - C.adjustOrganLoss(ORGAN_SLOT_BRAIN, 5, 60) - C.balloon_alert(C, "you feel dumber") - - if(smack) - M.visible_message(span_danger("[user] beats [M] over the head with [src]!"), \ - span_userdanger("[user] beats [M] over the head with [src]!")) - playsound(src.loc, SFX_PUNCH, 25, TRUE, -1) - log_combat(user, M, "attacked", src) - -/obj/item/storage/book/bible/attackby_storage_insert(datum/storage, atom/storage_holder, mob/user) - return !istype(storage_holder, /obj/item/storage/book/bible) - -/obj/item/storage/book/bible/afterattack(atom/bible_smacked, mob/user, proximity) - . = ..() - if(!proximity) - return - if(SEND_SIGNAL(bible_smacked, COMSIG_BIBLE_SMACKED, user, proximity) & COMSIG_END_BIBLE_CHAIN) - return . | AFTERATTACK_PROCESSED_ITEM - if(isfloorturf(bible_smacked)) - if(user.mind && (user.mind.holy_role)) - var/area/current_area = get_area(bible_smacked) - if(!GLOB.chaplain_altars.len && istype(current_area, /area/station/service/chapel)) - make_new_altar(bible_smacked, user) - return - for(var/obj/effect/rune/nearby_runes in orange(2,user)) - nearby_runes.invisibility = 0 - bible_smacked.balloon_alert(user, "floor smacked") - - if(user?.mind?.holy_role) - if(bible_smacked.reagents && bible_smacked.reagents.has_reagent(/datum/reagent/water)) // blesses all the water in the holder - . |= AFTERATTACK_PROCESSED_ITEM - bible_smacked.balloon_alert(user, "blessed") - var/water2holy = bible_smacked.reagents.get_reagent_amount(/datum/reagent/water) - bible_smacked.reagents.del_reagent(/datum/reagent/water) - bible_smacked.reagents.add_reagent(/datum/reagent/water/holywater,water2holy) - if(bible_smacked.reagents && bible_smacked.reagents.has_reagent(/datum/reagent/fuel/unholywater)) // yeah yeah, copy pasted code - sue me - . |= AFTERATTACK_PROCESSED_ITEM - bible_smacked.balloon_alert(user, "purified") - var/unholy2clean = bible_smacked.reagents.get_reagent_amount(/datum/reagent/fuel/unholywater) - bible_smacked.reagents.del_reagent(/datum/reagent/fuel/unholywater) - bible_smacked.reagents.add_reagent(/datum/reagent/water/holywater,unholy2clean) - if(istype(bible_smacked, /obj/item/storage/book/bible) && !istype(bible_smacked, /obj/item/storage/book/bible/syndicate)) - . |= AFTERATTACK_PROCESSED_ITEM - bible_smacked.balloon_alert(user, "converted") - var/obj/item/storage/book/bible/B = bible_smacked - B.name = name - B.icon_state = icon_state - B.inhand_icon_state = inhand_icon_state - - if(istype(bible_smacked, /obj/item/cult_bastard) && !IS_CULTIST(user)) - . |= AFTERATTACK_PROCESSED_ITEM - var/obj/item/cult_bastard/sword = bible_smacked - bible_smacked.balloon_alert(user, "exorcising...") - playsound(src,'sound/hallucinations/veryfar_noise.ogg',40,TRUE) - if(do_after(user, 40, target = sword)) - playsound(src,'sound/effects/pray_chaplain.ogg',60,TRUE) - for(var/obj/item/soulstone/SS in sword.contents) - SS.required_role = null - for(var/mob/living/simple_animal/shade/EX in SS) - var/datum/antagonist/cult/cultist = EX.mind.has_antag_datum(/datum/antagonist/cult) - if (cultist) - cultist.silent = TRUE - cultist.on_removal() - - EX.icon_state = "shade_holy" - EX.name = "Purified [EX.name]" - SS.release_shades(user) - qdel(SS) - new /obj/item/nullrod/claymore(get_turf(sword)) - user.visible_message(span_notice("[user] purifies [sword]!")) - qdel(sword) - -/obj/item/storage/book/bible/booze - desc = "To be applied to the head repeatedly." - -/obj/item/storage/book/bible/booze/PopulateContents() - new /obj/item/reagent_containers/cup/glass/bottle/whiskey(src) - -/obj/item/storage/book/bible/syndicate - icon_state ="ebook" - deity_name = "The Syndicate" - throw_speed = 2 - throwforce = 18 - throw_range = 7 - force = 18 - hitsound = 'sound/weapons/sear.ogg' - damtype = BURN - name = "Syndicate Tome" - attack_verb_continuous = list("attacks", "burns", "blesses", "damns", "scorches") - attack_verb_simple = list("attack", "burn", "bless", "damn", "scorch") - item_flags = NO_BLOOD_ON_ITEM - var/uses = 1 - var/ownername - -/obj/item/storage/book/bible/syndicate/attack_self(mob/living/carbon/human/H) - if (uses) - H.mind.holy_role = HOLY_ROLE_PRIEST - uses -= 1 - to_chat(H, span_userdanger("You try to open the book AND IT BITES YOU!")) - playsound(src.loc, 'sound/effects/snap.ogg', 50, TRUE) - H.apply_damage(5, BRUTE, pick(BODY_ZONE_L_ARM, BODY_ZONE_R_ARM), attacking_item = src) - to_chat(H, span_notice("Your name appears on the inside cover, in blood.")) - ownername = H.real_name - -/obj/item/storage/book/bible/syndicate/examine(mob/user) - . = ..() - if(ownername) - . += span_warning("The name [ownername] is written in blood inside the cover.") - -/obj/item/storage/book/bible/syndicate/attack(mob/living/M, mob/living/carbon/human/user, heal_mode = TRUE) - if (!user.combat_mode) - return ..() - else - return ..(M,user,heal_mode = FALSE) diff --git a/code/modules/admin/smites/bad_luck.dm b/code/modules/admin/smites/bad_luck.dm index a5c00aea43d..c9f6a94b93a 100644 --- a/code/modules/admin/smites/bad_luck.dm +++ b/code/modules/admin/smites/bad_luck.dm @@ -14,8 +14,11 @@ /datum/smite/bad_luck/effect(client/user, mob/living/target) . = ..() + //if permanent, replace any existing omen + if(permanent) + var/existing_component = target.GetComponent(/datum/component/omen) + qdel(existing_component) target.AddComponent(/datum/component/omen/smite, permanent = permanent) - if(silent) return to_chat(target, span_warning("You get a bad feeling...")) diff --git a/code/modules/antagonists/heretic/knowledge/general_side.dm b/code/modules/antagonists/heretic/knowledge/general_side.dm index b771108e272..9c3fbe9d447 100644 --- a/code/modules/antagonists/heretic/knowledge/general_side.dm +++ b/code/modules/antagonists/heretic/knowledge/general_side.dm @@ -48,7 +48,7 @@ gain_text = "The occult leaves fragments of knowledge and power anywhere and everywhere. The Codex Cicatrix is one such example. \ Within the leather-bound faces and age old pages, a path into the Mansus is revealed." required_atoms = list( - /obj/item/storage/book/bible = 1, + /obj/item/book/bible = 1, /obj/item/pen/fountain = 1, /obj/item/stack/sheet/animalhide = 1, ) diff --git a/code/modules/antagonists/revenant/haunted_item.dm b/code/modules/antagonists/revenant/haunted_item.dm index a4772912a61..7692d8d29f5 100644 --- a/code/modules/antagonists/revenant/haunted_item.dm +++ b/code/modules/antagonists/revenant/haunted_item.dm @@ -61,7 +61,7 @@ pre_haunt_throwforce = haunted_item.throwforce haunted_item.throwforce = min(haunted_item.throwforce + throw_force_bonus, throw_force_max) - var/static/list/default_dispell_types = list(/obj/item/nullrod, /obj/item/storage/book/bible) + var/static/list/default_dispell_types = list(/obj/item/nullrod, /obj/item/book/bible) src.types_which_dispell_us = types_which_dispell_us || default_dispell_types src.despawn_message = despawn_message diff --git a/code/modules/asset_cache/assets/bibles.dm b/code/modules/asset_cache/assets/bibles.dm index d99a6e26feb..948af216063 100644 --- a/code/modules/asset_cache/assets/bibles.dm +++ b/code/modules/asset_cache/assets/bibles.dm @@ -2,7 +2,7 @@ name = "bibles" /datum/asset/spritesheet/bibles/create_spritesheets() - var/obj/item/storage/book/bible/holy_template = /obj/item/storage/book/bible + var/obj/item/book/bible/holy_template = /obj/item/book/bible InsertAll("display", initial(holy_template.icon)) /datum/asset/spritesheet/bibles/ModifyInserted(icon/pre_asset) diff --git a/code/modules/awaymissions/mission_code/stationCollision.dm b/code/modules/awaymissions/mission_code/stationCollision.dm index 414484c6dcf..b0f31eaa669 100644 --- a/code/modules/awaymissions/mission_code/stationCollision.dm +++ b/code/modules/awaymissions/mission_code/stationCollision.dm @@ -23,16 +23,16 @@ name = "Safecode hint spawner" /obj/effect/landmark/sc_bible_spawner/Initialize(mapload) - ..() - var/obj/item/storage/book/bible/B = new /obj/item/storage/book/bible/booze(loc) - B.name = "The Holy book of the Geometer" - B.deity_name = "Narsie" - B.icon_state = "melted" - B.inhand_icon_state = "melted" - B.lefthand_file = 'icons/mob/inhands/items/books_lefthand.dmi' - B.righthand_file = 'icons/mob/inhands/items/books_righthand.dmi' - new /obj/item/paper/fluff/awaymissions/stationcollision/safehint_paper_bible(B) - new /obj/item/pen(B) + . = ..() + var/obj/item/book/bible/holy_bible = new /obj/item/book/bible/booze(loc) + holy_bible.name = "The Holy book of the Geometer" + holy_bible.deity_name = "Narsie" + holy_bible.icon_state = "melted" + holy_bible.inhand_icon_state = "melted" + holy_bible.lefthand_file = 'icons/mob/inhands/items/books_lefthand.dmi' + holy_bible.righthand_file = 'icons/mob/inhands/items/books_righthand.dmi' + new /obj/item/paper/fluff/awaymissions/stationcollision/safehint_paper_bible(holy_bible) + new /obj/item/pen(holy_bible) return INITIALIZE_HINT_QDEL /* diff --git a/code/modules/cargo/packs/general.dm b/code/modules/cargo/packs/general.dm index a35d9a920a7..96bb9e42a21 100644 --- a/code/modules/cargo/packs/general.dm +++ b/code/modules/cargo/packs/general.dm @@ -209,7 +209,7 @@ cost = CARGO_CRATE_VALUE * 6 // it costs so much because the Space Church needs funding to build a cathedral access_view = ACCESS_CHAPEL_OFFICE contains = list(/obj/item/reagent_containers/cup/glass/bottle/holywater = 2, - /obj/item/storage/book/bible/booze = 2, + /obj/item/book/bible/booze = 2, /obj/item/clothing/suit/hooded/chaplain_hoodie = 2, /obj/item/clothing/under/misc/burial = 2, ) diff --git a/code/modules/clothing/suits/bio.dm b/code/modules/clothing/suits/bio.dm index e4b9fe07950..ffbef12d1ef 100644 --- a/code/modules/clothing/suits/bio.dm +++ b/code/modules/clothing/suits/bio.dm @@ -132,4 +132,4 @@ /obj/item/clothing/suit/bio_suit/plaguedoctorsuit/Initialize(mapload) . = ..() - allowed += list(/obj/item/storage/book/bible, /obj/item/nullrod, /obj/item/cane) + allowed += list(/obj/item/book/bible, /obj/item/nullrod, /obj/item/cane) diff --git a/code/modules/clothing/suits/costume.dm b/code/modules/clothing/suits/costume.dm index 951ca94cca4..c8faa7e86ad 100644 --- a/code/modules/clothing/suits/costume.dm +++ b/code/modules/clothing/suits/costume.dm @@ -127,7 +127,7 @@ inhand_icon_state = "imperium_monk" body_parts_covered = CHEST|GROIN|LEGS|ARMS flags_inv = HIDESHOES|HIDEJUMPSUIT - allowed = list(/obj/item/storage/book/bible, /obj/item/nullrod, /obj/item/reagent_containers/cup/glass/bottle/holywater, /obj/item/storage/fancy/candle_box, /obj/item/flashlight/flare/candle, /obj/item/tank/internals/emergency_oxygen) + allowed = list(/obj/item/book/bible, /obj/item/nullrod, /obj/item/reagent_containers/cup/glass/bottle/holywater, /obj/item/storage/fancy/candle_box, /obj/item/flashlight/flare/candle, /obj/item/tank/internals/emergency_oxygen) /obj/item/clothing/suit/costume/chickensuit name = "chicken suit" @@ -484,7 +484,7 @@ worn_icon = 'icons/mob/clothing/suits/costume.dmi' inhand_icon_state = "mysticrobe" body_parts_covered = CHEST|GROIN|LEGS|ARMS - allowed = list(/obj/item/spellbook, /obj/item/storage/book/bible) + allowed = list(/obj/item/spellbook, /obj/item/book/bible) flags_inv = HIDEJUMPSUIT hoodtype = /obj/item/clothing/head/hooded/mysticrobe diff --git a/code/modules/jobs/job_types/chaplain/chaplain.dm b/code/modules/jobs/job_types/chaplain/chaplain.dm index 78befe1b7bd..4714bf589d4 100644 --- a/code/modules/jobs/job_types/chaplain/chaplain.dm +++ b/code/modules/jobs/job_types/chaplain/chaplain.dm @@ -42,71 +42,69 @@ . = ..() if(!ishuman(spawned)) return - var/mob/living/carbon/human/H = spawned - var/obj/item/storage/book/bible/booze/B = new - + var/mob/living/carbon/human/human_spawned = spawned + var/obj/item/book/bible/booze/holy_bible = new if(GLOB.religion) - if(H.mind) - H.mind.holy_role = HOLY_ROLE_PRIEST - B.deity_name = GLOB.deity - B.name = GLOB.bible_name + if(human_spawned.mind) + human_spawned.mind.holy_role = HOLY_ROLE_PRIEST + holy_bible.deity_name = GLOB.deity + holy_bible.name = GLOB.bible_name // These checks are important as there's no guarantee the "HOLY_ROLE_HIGHPRIEST" chaplain has selected a bible skin. if(GLOB.bible_icon_state) - B.icon_state = GLOB.bible_icon_state + holy_bible.icon_state = GLOB.bible_icon_state if(GLOB.bible_inhand_icon_state) - B.inhand_icon_state = GLOB.bible_inhand_icon_state - to_chat(H, span_boldnotice("There is already an established religion onboard the station. You are an acolyte of [GLOB.deity]. Defer to the Chaplain.")) - H.equip_to_slot_or_del(B, ITEM_SLOT_BACKPACK) + holy_bible.inhand_icon_state = GLOB.bible_inhand_icon_state + to_chat(human_spawned, span_boldnotice("There is already an established religion onboard the station. You are an acolyte of [GLOB.deity]. Defer to the Chaplain.")) + human_spawned.equip_to_slot_or_del(holy_bible, ITEM_SLOT_BACKPACK) var/nrt = GLOB.holy_weapon_type || /obj/item/nullrod - var/obj/item/nullrod/N = new nrt(H) - H.put_in_hands(N) + var/obj/item/nullrod/nullrod = new nrt(human_spawned) + human_spawned.put_in_hands(nullrod) if(GLOB.religious_sect) - GLOB.religious_sect.on_conversion(H) + GLOB.religious_sect.on_conversion(human_spawned) return - if(H.mind) - H.mind.holy_role = HOLY_ROLE_HIGHPRIEST + if(human_spawned.mind) + human_spawned.mind.holy_role = HOLY_ROLE_HIGHPRIEST var/new_religion = player_client?.prefs?.read_preference(/datum/preference/name/religion) || DEFAULT_RELIGION var/new_deity = player_client?.prefs?.read_preference(/datum/preference/name/deity) || DEFAULT_DEITY var/new_bible = player_client?.prefs?.read_preference(/datum/preference/name/bible) || DEFAULT_BIBLE - B.deity_name = new_deity - + holy_bible.deity_name = new_deity switch(lowertext(new_religion)) if("homosexuality", "gay", "penis", "ass", "cock", "cocks") new_bible = pick("Guys Gone Wild","Coming Out of The Closet","War of Cocks") switch(new_bible) if("War of Cocks") - B.deity_name = pick("Dick Powers", "King Cock") + holy_bible.deity_name = pick("Dick Powers", "King Cock") else - B.deity_name = pick("Gay Space Jesus", "Gandalf", "Dumbledore") - H.adjustOrganLoss(ORGAN_SLOT_BRAIN, 100) // starts off brain damaged as fuck + holy_bible.deity_name = pick("Gay Space Jesus", "Gandalf", "Dumbledore") + human_spawned.adjustOrganLoss(ORGAN_SLOT_BRAIN, 100) // starts off brain damaged as fuck if("lol", "wtf", "poo", "badmin", "shitmin", "deadmin", "meme", "memes") new_bible = pick("Woody's Got Wood: The Aftermath", "Sweet Bro and Hella Jeff: Expanded Edition","F.A.T.A.L. Rulebook") switch(new_bible) if("Woody's Got Wood: The Aftermath") - B.deity_name = pick("Woody", "Andy", "Cherry Flavored Lube") + holy_bible.deity_name = pick("Woody", "Andy", "Cherry Flavored Lube") if("Sweet Bro and Hella Jeff: Expanded Edition") - B.deity_name = pick("Sweet Bro", "Hella Jeff", "Stairs", "AH") + holy_bible.deity_name = pick("Sweet Bro", "Hella Jeff", "Stairs", "AH") if("F.A.T.A.L. Rulebook") - B.deity_name = "Twenty Ten-Sided Dice" - H.adjustOrganLoss(ORGAN_SLOT_BRAIN, 100) // also starts off brain damaged as fuck + holy_bible.deity_name = "Twenty Ten-Sided Dice" + human_spawned.adjustOrganLoss(ORGAN_SLOT_BRAIN, 100) // also starts off brain damaged as fuck if("servicianism", "partying") - B.desc = "Happy, Full, Clean. Live it and give it." + holy_bible.desc = "Happy, Full, Clean. Live it and give it." if("weeaboo","kawaii") new_bible = pick("Fanfiction Compendium","Japanese for Dummies","The Manganomicon","Establishing Your O.T.P") - B.deity_name = "Anime" + holy_bible.deity_name = "Anime" else if(new_bible == DEFAULT_BIBLE) new_bible = DEFAULT_BIBLE_REPLACE(new_bible) - B.name = new_bible + holy_bible.name = new_bible GLOB.religion = new_religion GLOB.bible_name = new_bible - GLOB.deity = B.deity_name + GLOB.deity = holy_bible.deity_name - H.equip_to_slot_or_del(B, ITEM_SLOT_BACKPACK) + human_spawned.equip_to_slot_or_del(holy_bible, ITEM_SLOT_BACKPACK) SSblackbox.record_feedback("text", "religion_name", 1, "[new_religion]", 1) SSblackbox.record_feedback("text", "religion_deity", 1, "[new_deity]", 1) diff --git a/code/modules/jobs/job_types/chaplain/chaplain_costumes.dm b/code/modules/jobs/job_types/chaplain/chaplain_costumes.dm index fe49a435607..9dc8b7ade42 100644 --- a/code/modules/jobs/job_types/chaplain/chaplain_costumes.dm +++ b/code/modules/jobs/job_types/chaplain/chaplain_costumes.dm @@ -1,7 +1,7 @@ //Chaplain Suit Subtypes //If any new staple chaplain items get added, put them in these lists /obj/item/clothing/suit/chaplainsuit - allowed = list(/obj/item/storage/book/bible, /obj/item/nullrod, /obj/item/reagent_containers/cup/glass/bottle/holywater, /obj/item/storage/fancy/candle_box, /obj/item/flashlight/flare/candle, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman) + allowed = list(/obj/item/book/bible, /obj/item/nullrod, /obj/item/reagent_containers/cup/glass/bottle/holywater, /obj/item/storage/fancy/candle_box, /obj/item/flashlight/flare/candle, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman) icon = 'icons/obj/clothing/suits/chaplain.dmi' worn_icon = 'icons/mob/clothing/suits/chaplain.dmi' @@ -24,7 +24,7 @@ wound = 20 /obj/item/clothing/suit/hooded/chaplainsuit - allowed = list(/obj/item/storage/book/bible, /obj/item/nullrod, /obj/item/reagent_containers/cup/glass/bottle/holywater, /obj/item/storage/fancy/candle_box, /obj/item/flashlight/flare/candle, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman) + allowed = list(/obj/item/book/bible, /obj/item/nullrod, /obj/item/reagent_containers/cup/glass/bottle/holywater, /obj/item/storage/fancy/candle_box, /obj/item/flashlight/flare/candle, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman) //Suits /obj/item/clothing/suit/chaplainsuit/holidaypriest @@ -134,7 +134,7 @@ desc = "It sounds like hissing steam, ticking cogs, gone silent, It looks like a dead machine, trying to tick with life." icon_state = "clockwork_cuirass" inhand_icon_state = null - allowed = list(/obj/item/storage/book/bible, /obj/item/nullrod, /obj/item/reagent_containers/cup/glass/bottle/holywater, /obj/item/storage/fancy/candle_box, /obj/item/flashlight/flare/candle, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman) + allowed = list(/obj/item/book/bible, /obj/item/nullrod, /obj/item/reagent_containers/cup/glass/bottle/holywater, /obj/item/storage/fancy/candle_box, /obj/item/flashlight/flare/candle, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman) slowdown = 0 clothing_flags = NONE @@ -164,7 +164,7 @@ desc = "God wills it!" icon_state = "knight_templar" inhand_icon_state = null - allowed = list(/obj/item/storage/book/bible, /obj/item/nullrod, /obj/item/reagent_containers/cup/glass/bottle/holywater, /obj/item/storage/fancy/candle_box, /obj/item/flashlight/flare/candle, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman) + allowed = list(/obj/item/book/bible, /obj/item/nullrod, /obj/item/reagent_containers/cup/glass/bottle/holywater, /obj/item/storage/fancy/candle_box, /obj/item/flashlight/flare/candle, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman) slowdown = 0 clothing_flags = NONE @@ -242,7 +242,7 @@ worn_icon = 'icons/mob/clothing/suits/chaplain.dmi' inhand_icon_state = null body_parts_covered = CHEST|GROIN|LEGS|ARMS - allowed = list(/obj/item/storage/book/bible, /obj/item/nullrod, /obj/item/reagent_containers/cup/glass/bottle/holywater, /obj/item/storage/fancy/candle_box, /obj/item/flashlight/flare/candle, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman) + allowed = list(/obj/item/book/bible, /obj/item/nullrod, /obj/item/reagent_containers/cup/glass/bottle/holywater, /obj/item/storage/fancy/candle_box, /obj/item/flashlight/flare/candle, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman) hoodtype = /obj/item/clothing/head/hooded/chaplain_hood /obj/item/clothing/head/hooded/chaplain_hood diff --git a/code/modules/library/bibles.dm b/code/modules/library/bibles.dm new file mode 100644 index 00000000000..830d5c65f19 --- /dev/null +++ b/code/modules/library/bibles.dm @@ -0,0 +1,353 @@ +GLOBAL_LIST_INIT(biblenames, list( + "Bible", + "Quran", + "Scrapbook", + "Burning Bible", + "Clown Bible", + "Banana Bible", + "Creeper Bible", + "White Bible", + "Holy Light", + "The God Delusion", + "Tome", + "The King in Yellow", + "Ithaqua", + "Scientology", + "Melted Bible", + "Necronomicon", + "Insulationism", + "Guru Granth Sahib", + "Kojiki", +)) +//If you get these two lists not matching in size, there will be runtimes and I will hurt you in ways you couldn't even begin to imagine +// if your bible has no custom itemstate, use one of the existing ones +GLOBAL_LIST_INIT(biblestates, list( + "bible", + "koran", + "scrapbook", + "burning", + "honk1", + "honk2", + "creeper", + "white", + "holylight", + "atheist", + "tome", + "kingyellow", + "ithaqua", + "scientology", + "melted", + "necronomicon", + "insuls", + "gurugranthsahib", + "kojiki", +)) +GLOBAL_LIST_INIT(bibleitemstates, list( + "bible", + "koran", + "scrapbook", + "burning", + "honk1", + "honk2", + "creeper", + "white", + "holylight", + "atheist", + "tome", + "kingyellow", + "ithaqua", + "scientology", + "melted", + "necronomicon", + "kingyellow", + "gurugranthsahib", + "kojiki", +)) + +/obj/item/book/bible + name = "bible" + desc = "Apply to head repeatedly." + icon = 'icons/obj/storage/book.dmi' + icon_state = "bible" + worn_icon_state = "bible" + inhand_icon_state = "bible" + lefthand_file = 'icons/mob/inhands/items/books_lefthand.dmi' + righthand_file = 'icons/mob/inhands/items/books_righthand.dmi' + force_string = "holy" + unique = TRUE + /// Deity this bible is related to + var/deity_name = "Space Jesus" + +/obj/item/book/bible/Initialize(mapload) + . = ..() + AddComponent(/datum/component/anti_magic, MAGIC_RESISTANCE_HOLY) + carve_out() + +/obj/item/book/bible/examine(mob/user) + . = ..() + if(deity_name) + . += span_notice("This bible has been approved by [deity_name].") + if(user.mind?.holy_role) + if(GLOB.chaplain_altars.len) + . += span_notice("[src] has an expansion pack to replace any broken Altar.") + else + . += span_notice("[src] can be unpacked by hitting the floor of a holy area with it.") + +/obj/item/book/bible/burn_paper_product_attackby_check(obj/item/attacking_item, mob/living/user, bypass_clumsy) + . = ..() + // no deity to cast a curse upon thee + if(!deity_name) + return + if(. && (resistance_flags & ON_FIRE)) + var/datum/component/omen/existing_omen = user.GetComponent(/datum/component/omen) + //DOUBLE CURSED?! Just straight up gib the guy. + if(existing_omen) + to_chat(user, span_userdanger("[deity_name] SMITE thee!")) + add_memory_in_range(user, 7, /datum/memory/witnessed_gods_wrath, protagonist = user, deuteragonist = src, antagonist = deity_name) + user.client?.give_award(/datum/award/achievement/misc/gods_wrath, user) + user.gib() + else + to_chat(user, span_userdanger("[deity_name] cast a curse upon thee!")) + user.AddComponent(/datum/component/omen/bible) + +/obj/item/book/bible/carve_out(obj/item/carving_item, mob/living/user) + . = ..() + atom_storage.max_specific_storage = WEIGHT_CLASS_SMALL + +/obj/item/book/bible/suicide_act(mob/living/user) + user.visible_message(span_suicide("[user] is offering [user.p_them()]self to [deity_name]! It looks like [user.p_theyre()] trying to commit suicide!")) + return BRUTELOSS + +/obj/item/book/bible/attack_self(mob/living/carbon/human/user) + if(GLOB.bible_icon_state) + return FALSE + if(user?.mind?.holy_role != HOLY_ROLE_HIGHPRIEST) + return FALSE + + var/list/skins = list() + for(var/i in 1 to GLOB.biblestates.len) + var/image/bible_image = image(icon = 'icons/obj/storage/book.dmi', icon_state = GLOB.biblestates[i]) + skins += list("[GLOB.biblenames[i]]" = bible_image) + + var/choice = show_radial_menu(user, src, skins, custom_check = CALLBACK(src, PROC_REF(check_menu), user), radius = 40, require_near = TRUE) + if(!choice) + return FALSE + var/bible_index = GLOB.biblenames.Find(choice) + if(!bible_index) + return FALSE + icon_state = GLOB.biblestates[bible_index] + inhand_icon_state = GLOB.bibleitemstates[bible_index] + + switch(icon_state) + if("honk1") + user.dna.add_mutation(/datum/mutation/human/clumsy) + user.equip_to_slot_or_del(new /obj/item/clothing/mask/gas/clown_hat(user), ITEM_SLOT_MASK) + if("honk2") + user.dna.add_mutation(/datum/mutation/human/clumsy) + user.equip_to_slot_or_del(new /obj/item/clothing/mask/gas/clown_hat(user), ITEM_SLOT_MASK) + if("insuls") + var/obj/item/clothing/gloves/color/fyellow/insuls = new + insuls.name = "insuls" + insuls.desc = "A mere copy of the true insuls." + insuls.siemens_coefficient = 0.99999 + user.equip_to_slot(insuls, ITEM_SLOT_GLOVES) + GLOB.bible_icon_state = icon_state + GLOB.bible_inhand_icon_state = inhand_icon_state + SSblackbox.record_feedback("text", "religion_book", 1, "[choice]") + +/** + * Checks if we are allowed to interact with a radial menu + * + * Arguments: + * * user The mob interacting with the menu + */ +/obj/item/book/bible/proc/check_menu(mob/living/carbon/human/user) + if(GLOB.bible_icon_state) + return FALSE + if(!istype(user) || !user.is_holding(src)) + return FALSE + if(user.incapacitated()) + return FALSE + if(user.mind?.holy_role != HOLY_ROLE_HIGHPRIEST) + return FALSE + return TRUE + +/obj/item/book/bible/proc/make_new_altar(atom/bible_smacked, mob/user) + var/new_altar_area = get_turf(bible_smacked) + + balloon_alert(user, "unpacking bible...") + if(!do_after(user, 15 SECONDS, new_altar_area)) + return + new /obj/structure/altar_of_gods(new_altar_area) + qdel(src) + +/obj/item/book/bible/proc/bless(mob/living/blessed, mob/living/user) + if(GLOB.religious_sect) + return GLOB.religious_sect.sect_bless(blessed,user) + if(!ishuman(blessed)) + return + var/mob/living/carbon/human/built_in_his_image = blessed + for(var/obj/item/bodypart/bodypart as anything in built_in_his_image.bodyparts) + if(!IS_ORGANIC_LIMB(bodypart)) + balloon_alert(user, "can't heal metal!") + return FALSE + + var/heal_amt = 10 + var/list/hurt_limbs = built_in_his_image.get_damaged_bodyparts(1, 1, BODYTYPE_ORGANIC) + if(length(hurt_limbs)) + for(var/obj/item/bodypart/affecting as anything in hurt_limbs) + if(affecting.heal_damage(heal_amt, heal_amt, BODYTYPE_ORGANIC)) + built_in_his_image.update_damage_overlays() + built_in_his_image.visible_message(span_notice("[user] heals [built_in_his_image] with the power of [deity_name]!")) + to_chat(built_in_his_image, span_boldnotice("May the power of [deity_name] compel you to be healed!")) + playsound(built_in_his_image, SFX_PUNCH, 25, TRUE, -1) + built_in_his_image.add_mood_event("blessing", /datum/mood_event/blessing) + return TRUE + +/obj/item/book/bible/attack(mob/living/target_mob, mob/living/carbon/human/user, params, heal_mode = TRUE) + if(!ISADVANCEDTOOLUSER(user)) + balloon_alert(user, "not dextrous enough!") + return + + if(HAS_TRAIT(user, TRAIT_CLUMSY) && prob(50)) + to_chat(user, span_danger("[src] slips out of your hand and hits your head.")) + user.take_bodypart_damage(10) + user.Unconscious(40 SECONDS) + return + + if(!user.mind?.holy_role) + to_chat(user, span_danger("The book sizzles in your hands.")) + user.take_bodypart_damage(burn = 10) + return + + if(!heal_mode) + return ..() + + if(target_mob.stat == DEAD) + target_mob.visible_message(span_danger("[user] smacks [target_mob]'s lifeless corpse with [src].")) + playsound(target_mob, SFX_PUNCH, 25, TRUE, -1) + return + + if(user == target_mob) + balloon_alert(user, "can't heal yourself!") + return + + var/smack = TRUE + if(prob(60) && bless(target_mob, user)) + smack = FALSE + else if(iscarbon(target_mob)) + var/mob/living/carbon/carbon_target = target_mob + if(!istype(carbon_target.head, /obj/item/clothing/head/helmet)) + carbon_target.adjustOrganLoss(ORGAN_SLOT_BRAIN, 5, 60) + carbon_target.balloon_alert(carbon_target, "you feel dumber!") + if(smack) + target_mob.visible_message(span_danger("[user] beats [target_mob] over the head with [src]!"), \ + span_userdanger("[user] beats [target_mob] over the head with [src]!")) + playsound(target_mob, SFX_PUNCH, 25, TRUE, -1) + log_combat(user, target_mob, "attacked", src) + +/obj/item/book/bible/afterattack(atom/bible_smacked, mob/user, proximity_flag, click_parameters) + . = ..() + if(!proximity_flag) + return + if(SEND_SIGNAL(bible_smacked, COMSIG_BIBLE_SMACKED, user, proximity_flag, click_parameters) & COMSIG_END_BIBLE_CHAIN) + return . | AFTERATTACK_PROCESSED_ITEM + if(isfloorturf(bible_smacked)) + if(user.mind?.holy_role) + var/area/current_area = get_area(bible_smacked) + if(!GLOB.chaplain_altars.len && istype(current_area, /area/station/service/chapel)) + make_new_altar(bible_smacked, user) + return + for(var/obj/effect/rune/nearby_runes in range(2, user)) + nearby_runes.invisibility = 0 + bible_smacked.balloon_alert(user, "floor smacked!") + + if(user.mind?.holy_role) + if(bible_smacked.reagents && bible_smacked.reagents.has_reagent(/datum/reagent/water)) // blesses all the water in the holder + . |= AFTERATTACK_PROCESSED_ITEM + bible_smacked.balloon_alert(user, "blessed") + var/water2holy = bible_smacked.reagents.get_reagent_amount(/datum/reagent/water) + bible_smacked.reagents.del_reagent(/datum/reagent/water) + bible_smacked.reagents.add_reagent(/datum/reagent/water/holywater,water2holy) + if(bible_smacked.reagents && bible_smacked.reagents.has_reagent(/datum/reagent/fuel/unholywater)) // yeah yeah, copy pasted code - sue me + . |= AFTERATTACK_PROCESSED_ITEM + bible_smacked.balloon_alert(user, "purified") + var/unholy2holy = bible_smacked.reagents.get_reagent_amount(/datum/reagent/fuel/unholywater) + bible_smacked.reagents.del_reagent(/datum/reagent/fuel/unholywater) + bible_smacked.reagents.add_reagent(/datum/reagent/water/holywater,unholy2holy) + if(istype(bible_smacked, /obj/item/book/bible) && !istype(bible_smacked, /obj/item/book/bible/syndicate)) + . |= AFTERATTACK_PROCESSED_ITEM + bible_smacked.balloon_alert(user, "converted") + var/obj/item/book/bible/other_bible = bible_smacked + other_bible.name = name + other_bible.icon_state = icon_state + other_bible.inhand_icon_state = inhand_icon_state + other_bible.deity_name = deity_name + + if(istype(bible_smacked, /obj/item/cult_bastard) && !IS_CULTIST(user)) + . |= AFTERATTACK_PROCESSED_ITEM + var/obj/item/cult_bastard/sword = bible_smacked + bible_smacked.balloon_alert(user, "exorcising...") + playsound(src,'sound/hallucinations/veryfar_noise.ogg',40,TRUE) + if(do_after(user, 4 SECONDS, target = sword)) + playsound(src,'sound/effects/pray_chaplain.ogg',60,TRUE) + for(var/obj/item/soulstone/stone in sword.contents) + stone.required_role = null + for(var/mob/living/simple_animal/shade/shade in stone) + var/datum/antagonist/cult/cultist = shade.mind.has_antag_datum(/datum/antagonist/cult) + if(cultist) + cultist.silent = TRUE + cultist.on_removal() + shade.icon_state = "shade_holy" + shade.name = "Purified [shade.name]" + stone.release_shades(user) + qdel(stone) + new /obj/item/nullrod/claymore(get_turf(sword)) + user.visible_message(span_notice("[user] exorcises [sword]!")) + qdel(sword) + +/obj/item/book/bible/booze + desc = "To be applied to the head repeatedly." + +/obj/item/book/bible/booze/Initialize(mapload) + . = ..() + new /obj/item/reagent_containers/cup/glass/bottle/whiskey(src) + +/obj/item/book/bible/syndicate + name = "Syndicate Tome" + desc = "A very ominous tome resembling a bible." + icon_state ="ebook" + item_flags = NO_BLOOD_ON_ITEM + throw_speed = 2 + throw_range = 7 + throwforce = 18 + force = 18 + hitsound = 'sound/weapons/sear.ogg' + damtype = BURN + attack_verb_continuous = list("attacks", "burns", "blesses", "damns", "scorches", "curses", "smites") + attack_verb_simple = list("attack", "burn", "bless", "damn", "scorch", "curses", "smites") + deity_name = "The Syndicate" + var/uses = 1 + var/owner_name + +/obj/item/book/bible/syndicate/attack_self(mob/living/carbon/human/user, modifiers) + if(!uses || !istype(user)) + return + user.mind.holy_role = HOLY_ROLE_PRIEST + uses -= 1 + to_chat(user, span_userdanger("You try to open the book AND IT BITES YOU!")) + playsound(src.loc, 'sound/effects/snap.ogg', 50, TRUE) + var/active_hand_zone = (!(user.active_hand_index % RIGHT_HANDS) ? BODY_ZONE_R_ARM : BODY_ZONE_L_ARM) + user.apply_damage(5, BRUTE, active_hand_zone, attacking_item = src) + to_chat(user, span_notice("Your name appears on the inside cover, in blood.")) + owner_name = user.real_name + +/obj/item/book/bible/syndicate/examine(mob/user) + . = ..() + if(owner_name) + . += span_warning("The name [owner_name] is written in blood inside the cover.") + +/obj/item/book/bible/syndicate/attack(mob/living/target_mob, mob/living/carbon/human/user, params, heal_mode = TRUE) + if(!user.combat_mode) + return ..() + return ..(target_mob, user, heal_mode = FALSE) diff --git a/code/modules/library/book.dm b/code/modules/library/book.dm index 42578728554..268a2cfb10f 100644 --- a/code/modules/library/book.dm +++ b/code/modules/library/book.dm @@ -1,84 +1,9 @@ -//Some information about how html sanitization is handled -//All book info datums should store sanitized data. This cannot be worked around -//All inputs and outputs from the round (DB calls) need to use sanitized data -//All tgui menus should get unsanitized data, since jsx handles that on its own -//Everything else should use sanitized data. Yes including names, it's an xss vuln because of how chat works -///A datum which contains all the metadata of a book -/datum/book_info - ///The title of the book - var/title - ///The "author" of the book - var/author - ///The info inside the book - var/content - -/datum/book_info/New(_title, _author, _content) - title = _title - author = _author - content = _content - -/datum/book_info/proc/set_title(_title, trusted = FALSE) //Trusted should only be used for books read from the db, or in cases that we can be sure the info has already been sanitized - if(trusted) - title = _title - return - title = reject_bad_text(trim(html_encode(_title), 30)) - -/datum/book_info/proc/get_title(default="N/A") //Loads in an html decoded version of the title. Only use this for tgui menus, absolutely nothing else. - return html_decode(title) || "N/A" - -/datum/book_info/proc/set_author(_author, trusted = FALSE) - if(trusted) - author = _author - return - author = trim(html_encode(_author), MAX_NAME_LEN) - -/datum/book_info/proc/get_author(default="N/A") - return html_decode(author) || "N/A" - -/datum/book_info/proc/set_content(_content, trusted = FALSE) - if(trusted) - content = _content - return - content = trim(html_encode(_content), MAX_PAPER_LENGTH) - -/datum/book_info/proc/set_content_using_paper(obj/item/paper/paper) - // Just the paper's raw data. - var/raw_content = "" - for(var/datum/paper_input/text_input as anything in paper.raw_text_inputs) - raw_content += text_input.to_raw_html() - - content = trim(html_encode(raw_content), MAX_PAPER_LENGTH) - -/datum/book_info/proc/get_content(default="N/A") - return html_decode(content) || "N/A" - -///Returns a copy of the book_info datum -/datum/book_info/proc/return_copy() - var/datum/book_info/copycat = new(title, author, content) - return copycat - -///Modify an existing book_info datum to match your data -/datum/book_info/proc/copy_into(datum/book_info/copycat) - copycat.set_title(title, trusted = TRUE) - copycat.set_author(author, trusted = TRUE) - copycat.set_content(content, trusted = TRUE) - return copycat - -/datum/book_info/proc/compare(datum/book_info/cmp_with) - if(author != cmp_with.author) - return FALSE - if(title != cmp_with.title) - return FALSE - if(content != cmp_with.content) - return FALSE - return TRUE - /obj/item/book name = "book" + desc = "Crack it open, inhale the musk of its pages, and learn something new." icon = 'icons/obj/library.dmi' icon_state ="book" worn_icon_state = "book" - desc = "Crack it open, inhale the musk of its pages, and learn something new." throw_speed = 1 throw_range = 5 w_class = WEIGHT_CLASS_NORMAL //upped to three because books are, y'know, pretty big. (and you could hide them inside eachother recursively forever) @@ -87,22 +12,25 @@ resistance_flags = FLAMMABLE drop_sound = 'sound/items/handling/book_drop.ogg' pickup_sound = 'sound/items/handling/book_pickup.ogg' - ///Game time in 1/10th seconds + /// Maximum icon state number + var/maximum_book_state = 8 + /// Game time in 1/10th seconds var/due_date = 0 - ///false - Normal book, true - Should not be treated as normal book, unable to be copied, unable to be modified + /// false - Normal book, true - Should not be treated as normal book, unable to be copied, unable to be modified var/unique = FALSE + /// whether or not we have been carved out + var/carved = FALSE + /// Specific window size for the book, i.e: "1920x1080", Size x Width var/window_size = null - ///The initial title, for use in var editing and such + /// The initial title, for use in var editing and such var/starting_title - ///The initial author, for use in var editing and such + /// The initial author, for use in var editing and such var/starting_author - ///The initial bit of content, for use in var editing and such + /// The initial bit of content, for use in var editing and such var/starting_content - ///The packet of information that describes this book + /// The packet of information that describes this book var/datum/book_info/book_data - ///Maximum icon state number - var/maximum_book_state = 8 /obj/item/book/Initialize(mapload) . = ..() @@ -110,6 +38,11 @@ AddElement(/datum/element/falling_hazard, damage = 5, wound_bonus = 0, hardhat_safety = TRUE, crushes = FALSE, impact_sound = drop_sound) +/obj/item/book/examine(mob/user) + . = ..() + if(carved) + . += span_notice("[src] has been hollowed out.") + /obj/item/book/ui_static_data(mob/user) var/list/data = list() data["author"] = book_data.get_author() @@ -118,8 +51,11 @@ return data /obj/item/book/ui_interact(mob/living/user, datum/tgui/ui) + if(carved) + balloon_alert(user, "book is carved out!") + return if(!length(book_data.get_content())) - balloon_alert(user, "this book is blank!") + balloon_alert(user, "book is blank!") return if(istype(user) && !isnull(user.mind)) @@ -134,10 +70,6 @@ ui = new(user, src, "MarkdownViewer", name) ui.open() -/// Generates a random icon state for the book -/obj/item/book/proc/gen_random_icon_state() - icon_state = "book[rand(1, maximum_book_state)]" - /obj/item/book/attack_self(mob/user) if(user.is_blind()) to_chat(user, span_warning("You are blind and can't read anything!")) @@ -149,7 +81,7 @@ user.visible_message(span_notice("[user] opens a book titled \"[book_data.title]\" and begins reading intently.")) ui_interact(user) -/obj/item/book/attackby(obj/item/attacking_item, mob/user, params) +/obj/item/book/attackby(obj/item/attacking_item, mob/living/user, params) if(burn_paper_product_attackby_check(attacking_item, user)) return @@ -162,6 +94,9 @@ if(unique) to_chat(user, span_warning("These pages don't seem to take the ink well! Looks like you can't modify it.")) return + if(carved) + to_chat(user, span_warning("The book has been carved out! There is nothing to be vandalized.")) + return var/choice = tgui_input_list(usr, "What would you like to change?", "Book Alteration", list("Title", "Contents", "Author", "Cancel")) if(isnull(choice)) @@ -197,15 +132,12 @@ to_chat(user, span_warning("The name is invalid.")) return book_data.set_author(html_decode(author)) //Setting this encodes, don't want to double up - else - return - else if(istype(attacking_item, /obj/item/barcodescanner)) var/obj/item/barcodescanner/scanner = attacking_item var/obj/machinery/computer/libraryconsole/bookmanagement/computer = scanner.computer_ref?.resolve() if(!computer) to_chat(user, span_alert("[scanner]'s screen flashes: 'No associated computer found!'")) - return ..() + return scanner.book_data = book_data.return_copy() switch(scanner.mode) @@ -231,23 +163,35 @@ computer.inventory[ref(our_copy)] = our_copy computer.inventory_update() to_chat(user, span_notice("[scanner]'s screen flashes: 'Book stored in buffer. Title added to general inventory.'")) - - else if(((attacking_item.sharpness & SHARP_EDGED) || (attacking_item.tool_behaviour == TOOL_KNIFE) || (attacking_item.tool_behaviour == TOOL_WIRECUTTER)) && !(flags_1 & HOLOGRAM_1)) - to_chat(user, span_notice("You begin to carve out [book_data.title]...")) - if(do_after(user, 30, target = src)) - to_chat(user, span_notice("You carve out the pages from [book_data.title]! You didn't want to read it anyway.")) - var/obj/item/storage/book/carved_out = new - carved_out.name = src.name - carved_out.title = book_data.title - carved_out.icon_state = src.icon_state - if(user.is_holding(src)) - qdel(src) - user.put_in_hands(carved_out) - return - else - carved_out.forceMove(drop_location()) - qdel(src) - return + else if(try_carve(attacking_item, user, params)) return - else - return ..() + return ..() + +/// Generates a random icon state for the book +/obj/item/book/proc/gen_random_icon_state() + icon_state = "book[rand(1, maximum_book_state)]" + +/// Called when user attempts to carve the book with an item +/obj/item/book/proc/try_carve(obj/item/carving_item, mob/living/user, params) + if(carved) + return FALSE + if(!user.combat_mode) + return FALSE + if(!((carving_item.sharpness & SHARP_EDGED) && (carving_item.tool_behaviour != TOOL_KNIFE) && (carving_item.tool_behaviour != TOOL_WIRECUTTER))) + return FALSE + //i hate balloon alerts i hate them so god damn much + balloon_alert(user, "carving out...") + if(!do_after(user, 3 SECONDS, target = src)) + balloon_alert(user, "interrupted!") + return FALSE + carve_out(carving_item, user) + return TRUE + +/// Called when the book gets carved successfully +/obj/item/book/proc/carve_out(obj/item/carving_item, mob/living/user) + if(user) + balloon_alert(user, "carved out") + playsound(src, 'sound/effects/cloth_rip.ogg', vol = 75, vary = TRUE) + carved = TRUE + create_storage(max_slots = 1) + return TRUE diff --git a/code/modules/library/book_info.dm b/code/modules/library/book_info.dm new file mode 100644 index 00000000000..8663069644d --- /dev/null +++ b/code/modules/library/book_info.dm @@ -0,0 +1,74 @@ +//Some information about how html sanitization is handled +//All book info datums should store sanitized data. This cannot be worked around +//All inputs and outputs from the round (DB calls) need to use sanitized data +//All tgui menus should get unsanitized data, since jsx handles that on its own +//Everything else should use sanitized data. Yes including names, it's an xss vuln because of how chat works +///A datum which contains all the metadata of a book +/datum/book_info + ///The title of the book + var/title + ///The "author" of the book + var/author + ///The info inside the book + var/content + +/datum/book_info/New(_title, _author, _content) + title = _title + author = _author + content = _content + +/datum/book_info/proc/set_title(_title, trusted = FALSE) //Trusted should only be used for books read from the db, or in cases that we can be sure the info has already been sanitized + if(trusted) + title = _title + return + title = reject_bad_text(trim(html_encode(_title), 30)) + +/datum/book_info/proc/get_title(default="N/A") //Loads in an html decoded version of the title. Only use this for tgui menus, absolutely nothing else. + return html_decode(title) || "N/A" + +/datum/book_info/proc/set_author(_author, trusted = FALSE) + if(trusted) + author = _author + return + author = trim(html_encode(_author), MAX_NAME_LEN) + +/datum/book_info/proc/get_author(default="N/A") + return html_decode(author) || "N/A" + +/datum/book_info/proc/set_content(_content, trusted = FALSE) + if(trusted) + content = _content + return + content = trim(html_encode(_content), MAX_PAPER_LENGTH) + +/datum/book_info/proc/set_content_using_paper(obj/item/paper/paper) + // Just the paper's raw data. + var/raw_content = "" + for(var/datum/paper_input/text_input as anything in paper.raw_text_inputs) + raw_content += text_input.to_raw_html() + + content = trim(html_encode(raw_content), MAX_PAPER_LENGTH) + +/datum/book_info/proc/get_content(default="N/A") + return html_decode(content) || "N/A" + +///Returns a copy of the book_info datum +/datum/book_info/proc/return_copy() + var/datum/book_info/copycat = new(title, author, content) + return copycat + +///Modify an existing book_info datum to match your data +/datum/book_info/proc/copy_into(datum/book_info/copycat) + copycat.set_title(title, trusted = TRUE) + copycat.set_author(author, trusted = TRUE) + copycat.set_content(content, trusted = TRUE) + return copycat + +/datum/book_info/proc/compare(datum/book_info/cmp_with) + if(author != cmp_with.author) + return FALSE + if(title != cmp_with.title) + return FALSE + if(content != cmp_with.content) + return FALSE + return TRUE diff --git a/code/modules/library/lib_machines.dm b/code/modules/library/lib_machines.dm index c24fba1709c..337b72a4c9d 100644 --- a/code/modules/library/lib_machines.dm +++ b/code/modules/library/lib_machines.dm @@ -648,7 +648,7 @@ return TRUE /obj/machinery/computer/libraryconsole/bookmanagement/proc/print_bible() - var/obj/item/storage/book/bible/holy_book = new(loc) + var/obj/item/book/bible/holy_book = new(loc) if(!GLOB.bible_icon_state || !GLOB.bible_inhand_icon_state) return holy_book.icon_state = GLOB.bible_icon_state diff --git a/code/modules/mapfluff/ruins/lavalandruin_code/elephantgraveyard.dm b/code/modules/mapfluff/ruins/lavalandruin_code/elephantgraveyard.dm index fc52a488b87..3591a33dead 100644 --- a/code/modules/mapfluff/ruins/lavalandruin_code/elephantgraveyard.dm +++ b/code/modules/mapfluff/ruins/lavalandruin_code/elephantgraveyard.dm @@ -178,7 +178,7 @@ new /obj/item/coin/silver(src) new /obj/item/shovel/spade(src) if(4) - new /obj/item/storage/book/bible/booze(src) + new /obj/item/book/bible/booze(src) if(5) new /obj/item/clothing/neck/stethoscope(src) new /obj/item/scalpel(src) diff --git a/code/modules/mob/living/carbon/death.dm b/code/modules/mob/living/carbon/death.dm index 2ba3cf01e98..c3282967e64 100644 --- a/code/modules/mob/living/carbon/death.dm +++ b/code/modules/mob/living/carbon/death.dm @@ -41,9 +41,9 @@ var/atom/Tsec = drop_location() if(!no_bodyparts) if(no_organs)//so the organs don't get transfered inside the bodyparts we'll drop. - for(var/X in organs) - if(no_brain || !istype(X, /obj/item/organ/internal/brain)) - qdel(X) + for(var/organ in organs) + if(no_brain || !istype(organ, /obj/item/organ/internal/brain)) + qdel(organ) else //we're going to drop all bodyparts except chest, so the only organs that needs spilling are those inside it. for(var/obj/item/organ/organ as anything in organs) if(no_brain && istype(organ, /obj/item/organ/internal/brain)) @@ -71,6 +71,8 @@ for(var/obj/item/bodypart/part as anything in bodyparts) if(skip_head && part.body_zone == BODY_ZONE_HEAD) continue + else if(part.body_zone == BODY_ZONE_CHEST) + continue part.drop_limb() part.throw_at(get_edge_target_turf(src, pick(GLOB.alldirs)), rand(1,3), 5) diff --git a/code/modules/paperwork/paper.dm b/code/modules/paperwork/paper.dm index d5503c422f1..4916dc37c8c 100644 --- a/code/modules/paperwork/paper.dm +++ b/code/modules/paperwork/paper.dm @@ -355,6 +355,9 @@ //can't be put on fire! if((resistance_flags & FIRE_PROOF) || !(resistance_flags & FLAMMABLE)) return FALSE + //already on fire! + if(resistance_flags & ON_FIRE) + return FALSE var/ignition_message = attacking_item.ignition_effect(src, user) if(!ignition_message) return FALSE diff --git a/code/modules/uplink/uplink_items/device_tools.dm b/code/modules/uplink/uplink_items/device_tools.dm index b5012ab4f88..8e993aec4ee 100644 --- a/code/modules/uplink/uplink_items/device_tools.dm +++ b/code/modules/uplink/uplink_items/device_tools.dm @@ -37,7 +37,7 @@ the seemingly magical books of a certain cult. Though lacking the esoteric abilities \ of the originals, these inferior copies are still quite useful, being able to provide \ both weal and woe on the battlefield, even if they do occasionally bite off a finger." - item = /obj/item/storage/book/bible/syndicate + item = /obj/item/book/bible/syndicate cost = 5 /datum/uplink_item/device_tools/tram_remote diff --git a/icons/ui_icons/achievements/achievements.dmi b/icons/ui_icons/achievements/achievements.dmi index 29a85c0b3d2..a20e0fbecff 100644 Binary files a/icons/ui_icons/achievements/achievements.dmi and b/icons/ui_icons/achievements/achievements.dmi differ diff --git a/tgstation.dme b/tgstation.dme index 4ba8e682d64..d384779c539 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -2086,7 +2086,6 @@ #include "code\game\objects\items\storage\bags.dm" #include "code\game\objects\items\storage\basket.dm" #include "code\game\objects\items\storage\belt.dm" -#include "code\game\objects\items\storage\book.dm" #include "code\game\objects\items\storage\briefcase.dm" #include "code\game\objects\items\storage\fancy.dm" #include "code\game\objects\items\storage\garment.dm" @@ -3706,7 +3705,9 @@ #include "code\modules\language\voltaic.dm" #include "code\modules\language\xenocommon.dm" #include "code\modules\library\barcode_scanner.dm" +#include "code\modules\library\bibles.dm" #include "code\modules\library\book.dm" +#include "code\modules\library\book_info.dm" #include "code\modules\library\bookcase.dm" #include "code\modules\library\lib_codex_gigas.dm" #include "code\modules\library\lib_machines.dm" diff --git a/tools/UpdatePaths/Scripts/75350_book_storage_repath.txt b/tools/UpdatePaths/Scripts/75350_book_storage_repath.txt new file mode 100644 index 00000000000..2e614084ef1 --- /dev/null +++ b/tools/UpdatePaths/Scripts/75350_book_storage_repath.txt @@ -0,0 +1 @@ +/obj/item/storage/book/@SUBTYPES : /obj/item/book/@SUBTYPES{@OLD}