mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-01-27 01:21:30 +00:00
## About The Pull Request This mostly just refactors the book `attackby(...)` proc into `item_interaction(...)`, with some side-effects and screentips. Notable ones follow here: We move carving away from combat mode, and instead based it on whether our tool is a pure writing utensil, a pure carving tool, or both at once like the captain's fountain pen. If it's a pure tool, both left click and right click are its respective primary action. If it's both, however, left click is vandalizing and right click is carving. This tries to ensure the expected primary interaction is always left-click, without blocking anything if it could do both. We move the barcode scanner interaction to the barcode scanner instead. There's no good reason for this to stay on the book itself. We add `can_vandalize(...)` as a proc and move all checks in there, so we can call it after every tgui input. We don't replace the `to_chat(...)` calls here with balloon alerts because the additional clarifying info is needed, and it keeps the 'soulful' blind message. We add `get_attack_self_context(...)` as a proc for getting screentips on hovering over it in your active hand, because both the bible subtype and the syndicate bible _bible subtype_ want different screentips there in different situations, and so while it's clunky it's much less clunky than the alternatives I considered. Making it use actual storage datums avoids subtypes needing to make manual changes to it in the `carve_out(...)` proc, and is just good for organization. This doesn't add screentips to most bible-specific interactions, as I deemed them outside of the scope of this pr. Those are better off done atomized into another pr. ## Why It's Good For The Game less attackby, more item interaction screentips good I think having the carving interaction on combat mode is unintuitive, especially when that's the only interaction it can do. This ensures the expected primary interaction is always left-click. ## Changelog 🆑 refactor: Refactored the book interaction chain. Please report any issues. fix: You can no longer vandalize carved out books if you carve it after opening the input menu but before entering anything. qol: Added screentips to book interactions. qol: Added screentips to barcode scanner interactions. qol: Carving out books no longer uses combat mode, instead using left-click by default and right-click if your tool can also write. Screentips account for this. /🆑 --------- Co-authored-by: Ben10Omintrix <138636438+Ben10Omintrix@users.noreply.github.com>
258 lines
9.2 KiB
Plaintext
258 lines
9.2 KiB
Plaintext
/obj/item/book
|
|
name = "book"
|
|
desc = "Crack it open, inhale the musk of its pages, and learn something new."
|
|
icon = 'icons/obj/service/library.dmi'
|
|
icon_state ="book"
|
|
worn_icon_state = "book"
|
|
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)
|
|
attack_verb_continuous = list("bashes", "whacks", "educates")
|
|
attack_verb_simple = list("bash", "whack", "educate")
|
|
resistance_flags = FLAMMABLE
|
|
drop_sound = 'sound/items/handling/book_drop.ogg'
|
|
pickup_sound = 'sound/items/handling/book_pickup.ogg'
|
|
/// 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
|
|
var/unique = FALSE
|
|
/// Whether or not we have been carved out.
|
|
var/carved = FALSE
|
|
/// The typepath for the storage datum we use when carved out.
|
|
var/carved_storage_type = /datum/storage/carved_book
|
|
|
|
/// The initial title, for use in var editing and such
|
|
var/starting_title
|
|
/// 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
|
|
var/starting_content
|
|
/// The packet of information that describes this book
|
|
var/datum/book_info/book_data
|
|
|
|
/obj/item/book/Initialize(mapload)
|
|
. = ..()
|
|
book_data = new(starting_title, starting_author, starting_content)
|
|
|
|
AddElement(/datum/element/falling_hazard, damage = 5, wound_bonus = 0, hardhat_safety = TRUE, crushes = FALSE, impact_sound = drop_sound)
|
|
AddElement(/datum/element/burn_on_item_ignition)
|
|
register_context()
|
|
|
|
/obj/item/book/examine(mob/user)
|
|
. = ..()
|
|
if(carved)
|
|
. += span_notice("[src] has been hollowed out.")
|
|
|
|
/obj/item/book/add_context(atom/source, list/context, obj/item/held_item, mob/living/user)
|
|
if(isnull(held_item))
|
|
return NONE
|
|
|
|
if(held_item == src)
|
|
var/attack_self_context = get_attack_self_context(user)
|
|
if(!attack_self_context)
|
|
return NONE
|
|
context[SCREENTIP_CONTEXT_LMB] = attack_self_context
|
|
return CONTEXTUAL_SCREENTIP_SET
|
|
|
|
if(IS_WRITING_UTENSIL(held_item))
|
|
context[SCREENTIP_CONTEXT_LMB] = "Vandalize"
|
|
if(is_carving_tool(held_item))
|
|
context[SCREENTIP_CONTEXT_RMB] = "Carve out"
|
|
return CONTEXTUAL_SCREENTIP_SET
|
|
|
|
if(is_carving_tool(held_item))
|
|
context[SCREENTIP_CONTEXT_LMB] = "Carve out"
|
|
return CONTEXTUAL_SCREENTIP_SET
|
|
return NONE
|
|
|
|
/// Gets the context to add for clicking the book inhand. Returns null if none.
|
|
/obj/item/book/proc/get_attack_self_context(mob/living/user)
|
|
return "Read"
|
|
|
|
/obj/item/book/ui_static_data(mob/user)
|
|
var/list/data = list()
|
|
data["author"] = book_data.get_author()
|
|
data["title"] = book_data.get_title()
|
|
data["content"] = book_data.get_content()
|
|
return data
|
|
|
|
/obj/item/book/ui_interact(mob/living/user, datum/tgui/ui)
|
|
ui = SStgui.try_update_ui(user, src, ui)
|
|
if(!ui)
|
|
ui = new(user, src, "MarkdownViewer", name)
|
|
ui.open()
|
|
|
|
/// Proc that handles sending the book information to the user, as well as some housekeeping stuff.
|
|
/obj/item/book/proc/display_content(mob/living/user)
|
|
credit_book_to_reader(user)
|
|
ui_interact(user)
|
|
|
|
/// Proc that checks if the user is capable of reading the book, for UI interactions and otherwise. Returns TRUE if they can, FALSE if they can't.
|
|
/obj/item/book/proc/can_read_book(mob/living/user)
|
|
if(user.is_blind())
|
|
to_chat(user, span_warning("You are blind and can't read anything!"))
|
|
return FALSE
|
|
|
|
if(!user.can_read(src))
|
|
return FALSE
|
|
|
|
if(carved)
|
|
balloon_alert(user, "book is carved out!")
|
|
return FALSE
|
|
|
|
if(!length(book_data.get_content()))
|
|
balloon_alert(user, "book is blank!")
|
|
return FALSE
|
|
|
|
return TRUE
|
|
|
|
/// Proc that adds the book to a list on the user's mind so we know what works of art they've been catching up on.
|
|
/obj/item/book/proc/credit_book_to_reader(mob/living/user)
|
|
if(!isliving(user) || isnull(user.mind))
|
|
return
|
|
|
|
LAZYINITLIST(user.mind.book_titles_read)
|
|
if(starting_title in user.mind.book_titles_read)
|
|
return
|
|
|
|
user.add_mood_event("book_nerd", /datum/mood_event/book_nerd)
|
|
user.mind.book_titles_read[starting_title] = TRUE
|
|
|
|
/obj/item/book/attack_self(mob/user)
|
|
if(!can_read_book(user))
|
|
return
|
|
|
|
user.visible_message(span_notice("[user] opens a book titled \"[book_data.title]\" and begins reading intently."))
|
|
display_content(user)
|
|
|
|
/obj/item/book/proc/is_carving_tool(obj/item/tool)
|
|
PRIVATE_PROC(TRUE)
|
|
if(tool.get_sharpness() & SHARP_EDGED)
|
|
return TRUE
|
|
if(tool.tool_behaviour == TOOL_WIRECUTTER)
|
|
return TRUE
|
|
return FALSE
|
|
|
|
/// Checks for whether we can vandalize this book, to ensure we still can after each input.
|
|
/// Uses to_chat over balloon alerts to give more detailed information as to why.
|
|
/obj/item/book/proc/can_vandalize(mob/living/user, obj/item/tool)
|
|
if(!user.can_perform_action(src) || !user.can_write(tool))
|
|
return FALSE
|
|
if(user.is_blind())
|
|
to_chat(user, span_warning("As you are trying to write on the book, you suddenly feel very stupid!"))
|
|
return FALSE
|
|
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 FALSE
|
|
if(carved)
|
|
to_chat(user, span_warning("The book has been carved out! There is nothing to be vandalized."))
|
|
return FALSE
|
|
return TRUE
|
|
|
|
/obj/item/book/item_interaction(mob/living/user, obj/item/tool, list/modifiers)
|
|
// Items can both be carving tools and writing utensils.
|
|
// Because of this, we flip interaction priority on secondary.
|
|
// This means pure writing utensils have writing as their primary action,
|
|
// pure carving tools have carving as their primary action,
|
|
// but items with both have primary write secondary carve.
|
|
if(IS_WRITING_UTENSIL(tool))
|
|
return writing_utensil_act(user, tool)
|
|
if(is_carving_tool(tool))
|
|
return carving_act(user, tool)
|
|
return NONE
|
|
|
|
/obj/item/book/item_interaction_secondary(mob/living/user, obj/item/tool, list/modifiers)
|
|
if(is_carving_tool(tool))
|
|
return carving_act(user, tool)
|
|
if(IS_WRITING_UTENSIL(tool))
|
|
return writing_utensil_act(user, tool)
|
|
return NONE
|
|
|
|
/// Called when user clicks on the book with a writing utensil. Attempts to vandalize the book.
|
|
/obj/item/book/proc/writing_utensil_act(mob/living/user, obj/item/tool)
|
|
if(!can_vandalize(user, tool))
|
|
return ITEM_INTERACT_BLOCKING
|
|
|
|
var/choice = tgui_input_list(usr, "What would you like to change?", "Book Alteration", list("Title", "Contents", "Author", "Cancel"))
|
|
if(isnull(choice))
|
|
return ITEM_INTERACT_BLOCKING
|
|
if(!can_vandalize(user, tool))
|
|
return ITEM_INTERACT_BLOCKING
|
|
|
|
switch(choice)
|
|
if("Title")
|
|
return vandalize_title(user, tool)
|
|
if("Contents")
|
|
return vandalize_contents(user, tool)
|
|
if("Author")
|
|
return vandalize_author(user, tool)
|
|
|
|
return NONE
|
|
|
|
/obj/item/book/proc/vandalize_title(mob/living/user, obj/item/tool)
|
|
var/newtitle = reject_bad_text(tgui_input_text(user, "Write a new title", "Book Title", max_length = 30))
|
|
if(!newtitle)
|
|
balloon_alert(user, "invalid input!")
|
|
return ITEM_INTERACT_BLOCKING
|
|
if(length_char(newtitle) > 30)
|
|
balloon_alert(user, "too long!")
|
|
return ITEM_INTERACT_BLOCKING
|
|
if(!can_vandalize(user, tool))
|
|
return ITEM_INTERACT_BLOCKING
|
|
|
|
name = newtitle
|
|
book_data.set_title(html_decode(newtitle)) //Don't want to double encode here
|
|
playsound(src, SFX_WRITING_PEN, 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE, SOUND_FALLOFF_EXPONENT + 3, ignore_walls = FALSE)
|
|
return ITEM_INTERACT_SUCCESS
|
|
|
|
/obj/item/book/proc/vandalize_contents(mob/living/user, obj/item/tool)
|
|
var/content = tgui_input_text(user, "Write your book's contents (HTML NOT allowed)", "Book Contents", max_length = MAX_PAPER_LENGTH, multiline = TRUE)
|
|
if(!content)
|
|
balloon_alert(user, "invalid input!")
|
|
return ITEM_INTERACT_BLOCKING
|
|
if(!can_vandalize(user, tool))
|
|
return ITEM_INTERACT_BLOCKING
|
|
|
|
book_data.set_content(html_decode(content))
|
|
playsound(src, SFX_WRITING_PEN, 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE, SOUND_FALLOFF_EXPONENT + 3, ignore_walls = FALSE)
|
|
return ITEM_INTERACT_SUCCESS
|
|
|
|
/obj/item/book/proc/vandalize_author(mob/living/user, obj/item/tool)
|
|
var/author = tgui_input_text(user, "Write the author's name", "Author Name", max_length = MAX_NAME_LEN)
|
|
if(!author)
|
|
balloon_alert(user, "invalid input!")
|
|
return ITEM_INTERACT_BLOCKING
|
|
if(!can_vandalize(user, tool))
|
|
return ITEM_INTERACT_BLOCKING
|
|
|
|
book_data.set_author(html_decode(author)) //Setting this encodes, don't want to double up
|
|
playsound(src, SFX_WRITING_PEN, 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE, SOUND_FALLOFF_EXPONENT + 3, ignore_walls = FALSE)
|
|
return ITEM_INTERACT_SUCCESS
|
|
|
|
/// Called when user clicks on the book with a carving utensil. Attempts to carve the book.
|
|
/obj/item/book/proc/carving_act(mob/living/user, obj/item/tool)
|
|
if(carved)
|
|
balloon_alert(user, "already carved!")
|
|
return ITEM_INTERACT_BLOCKING
|
|
|
|
balloon_alert(user, "carving out...")
|
|
if(!do_after(user, 3 SECONDS, target = src))
|
|
balloon_alert(user, "interrupted!")
|
|
return ITEM_INTERACT_BLOCKING
|
|
|
|
balloon_alert(user, "carved out")
|
|
playsound(src, 'sound/effects/cloth_rip.ogg', vol = 75, vary = TRUE)
|
|
carve_out()
|
|
return ITEM_INTERACT_SUCCESS
|
|
|
|
/// Handles setting everything a carved book needs.
|
|
/obj/item/book/proc/carve_out()
|
|
carved = TRUE
|
|
create_storage(storage_type = carved_storage_type)
|
|
|
|
/// Generates a random icon state for the book
|
|
/obj/item/book/proc/gen_random_icon_state()
|
|
icon_state = "book[rand(1, maximum_book_state)]"
|