Files
Bubberstation/code/modules/library/lib_items.dm
Watermelon914 375a20e49b Refactors most spans into span procs (#59645)
Converts most spans into span procs. Mostly used regex for this and sorted out any compile time errors afterwards so there could be some bugs.
Was initially going to do defines, but ninja said to make it into a proc, and if there's any overhead, they can easily be changed to defines.

Makes it easier to control the formatting and prevents typos when creating spans as it'll runtime if you misspell instead of silently failing.
Reduces the code you need to write when writing spans, as you don't need to close the span as that's automatically handled by the proc.

(Note from Lemon: This should be converted to defines once we update the minimum version to 514. Didn't do it now because byond pain and such)
2021-06-14 13:03:53 -07:00

385 lines
13 KiB
Plaintext

#define BOOKCASE_UNANCHORED 0
#define BOOKCASE_ANCHORED 1
#define BOOKCASE_FINISHED 2
/* Library Items
*
* Contains:
* Bookcase
* Book
* Barcode Scanner
*/
/*
* Bookcase
*/
/obj/structure/bookcase
name = "bookcase"
icon = 'icons/obj/library.dmi'
icon_state = "bookempty"
desc = "A great place for storing knowledge."
anchored = FALSE
density = TRUE
opacity = FALSE
resistance_flags = FLAMMABLE
max_integrity = 200
armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 0)
var/state = BOOKCASE_UNANCHORED
/// When enabled, books_to_load number of random books will be generated for this bookcase when first interacted with.
var/load_random_books = FALSE
/// The category of books to pick from when populating random books.
var/random_category = null
/// How many random books to generate.
var/books_to_load = 0
/obj/structure/bookcase/examine(mob/user)
. = ..()
if(!anchored)
. += span_notice("The <i>bolts</i> on the bottom are unsecured.")
else
. += span_notice("It's secured in place with <b>bolts</b>.")
switch(state)
if(BOOKCASE_UNANCHORED)
. += span_notice("There's a <b>small crack</b> visible on the back panel.")
if(BOOKCASE_ANCHORED)
. += span_notice("There's space inside for a <i>wooden</i> shelf.")
if(BOOKCASE_FINISHED)
. += span_notice("There's a <b>small crack</b> visible on the shelf.")
/obj/structure/bookcase/Initialize(mapload)
. = ..()
if(!mapload)
return
set_anchored(TRUE)
state = BOOKCASE_FINISHED
for(var/obj/item/I in loc)
if(!isbook(I))
continue
I.forceMove(src)
update_appearance()
/obj/structure/bookcase/set_anchored(anchorvalue)
. = ..()
if(isnull(.))
return
state = anchorvalue
if(!anchorvalue) //in case we were vareditted or uprooted by a hostile mob, ensure we drop all our books instead of having them disappear till we're rebuild.
var/atom/Tsec = drop_location()
for(var/obj/I in contents)
if(!isbook(I))
continue
I.forceMove(Tsec)
update_appearance()
/obj/structure/bookcase/attackby(obj/item/I, mob/user, params)
switch(state)
if(BOOKCASE_UNANCHORED)
if(I.tool_behaviour == TOOL_WRENCH)
if(I.use_tool(src, user, 20, volume=50))
to_chat(user, span_notice("You wrench the frame into place."))
set_anchored(TRUE)
else if(I.tool_behaviour == TOOL_CROWBAR)
if(I.use_tool(src, user, 20, volume=50))
to_chat(user, span_notice("You pry the frame apart."))
deconstruct(TRUE)
if(BOOKCASE_ANCHORED)
if(istype(I, /obj/item/stack/sheet/mineral/wood))
var/obj/item/stack/sheet/mineral/wood/W = I
if(W.get_amount() >= 2)
W.use(2)
to_chat(user, span_notice("You add a shelf."))
state = BOOKCASE_FINISHED
update_appearance()
else if(I.tool_behaviour == TOOL_WRENCH)
I.play_tool_sound(src, 100)
to_chat(user, span_notice("You unwrench the frame."))
set_anchored(FALSE)
if(BOOKCASE_FINISHED)
var/datum/component/storage/STR = I.GetComponent(/datum/component/storage)
if(isbook(I))
if(!user.transferItemToLoc(I, src))
return
update_appearance()
else if(STR)
for(var/obj/item/T in I.contents)
if(istype(T, /obj/item/book) || istype(T, /obj/item/spellbook))
STR.remove_from_storage(T, src)
to_chat(user, span_notice("You empty \the [I] into \the [src]."))
update_appearance()
else if(istype(I, /obj/item/pen))
if(!user.is_literate())
to_chat(user, span_notice("You scribble illegibly on the side of [src]!"))
return
var/newname = stripped_input(user, "What would you like to title this bookshelf?")
if(!user.canUseTopic(src, BE_CLOSE))
return
if(!newname)
return
else
name = "bookcase ([sanitize(newname)])"
else if(I.tool_behaviour == TOOL_CROWBAR)
if(contents.len)
to_chat(user, span_warning("You need to remove the books first!"))
else
I.play_tool_sound(src, 100)
to_chat(user, span_notice("You pry the shelf out."))
new /obj/item/stack/sheet/mineral/wood(drop_location(), 2)
state = BOOKCASE_ANCHORED
update_appearance()
else
return ..()
/obj/structure/bookcase/attack_hand(mob/living/user, list/modifiers)
. = ..()
if(.)
return
if(!istype(user))
return
if(load_random_books)
create_random_books(books_to_load, src, FALSE, random_category)
load_random_books = FALSE
if(contents.len)
var/obj/item/book/choice = input(user, "Which book would you like to remove from the shelf?") as null|obj in sortNames(contents.Copy())
if(choice)
if(!(user.mobility_flags & MOBILITY_USE) || user.stat != CONSCIOUS || HAS_TRAIT(user, TRAIT_HANDS_BLOCKED) || !in_range(loc, user))
return
if(ishuman(user))
if(!user.get_active_held_item())
user.put_in_hands(choice)
else
choice.forceMove(drop_location())
update_appearance()
/obj/structure/bookcase/deconstruct(disassembled = TRUE)
var/atom/Tsec = drop_location()
new /obj/item/stack/sheet/mineral/wood(Tsec, 4)
for(var/obj/item/I in contents)
if(!isbook(I))
continue
I.forceMove(Tsec)
return ..()
/obj/structure/bookcase/update_icon_state()
if(state == BOOKCASE_UNANCHORED || state == BOOKCASE_ANCHORED)
icon_state = "bookempty"
return ..()
var/amount = contents.len
if(load_random_books)
amount += books_to_load
icon_state = "book-[clamp(amount, 0, 5)]"
return ..()
/obj/structure/bookcase/manuals/engineering
name = "engineering manuals bookcase"
/obj/structure/bookcase/manuals/engineering/Initialize()
. = ..()
new /obj/item/book/manual/wiki/engineering_construction(src)
new /obj/item/book/manual/wiki/engineering_hacking(src)
new /obj/item/book/manual/wiki/engineering_guide(src)
new /obj/item/book/manual/wiki/engineering_singulo_tesla(src)
new /obj/item/book/manual/wiki/robotics_cyborgs(src)
update_appearance()
/obj/structure/bookcase/manuals/research_and_development
name = "\improper R&D manuals bookcase"
/obj/structure/bookcase/manuals/research_and_development/Initialize()
. = ..()
new /obj/item/book/manual/wiki/research_and_development(src)
update_appearance()
/*
* Book
*/
/obj/item/book
name = "book"
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)
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'
var/dat //Actual page content
var/due_date = 0 //Game time in 1/10th seconds
var/author //Who wrote the thing, can be changed by pen or PC. It is not automatically assigned
var/unique = FALSE //false - Normal book, true - Should not be treated as normal book, unable to be copied, unable to be modified
var/title //The real name of the book.
var/window_size = null // Specific window size for the book, i.e: "1920x1080", Size x Width
/obj/item/book/attack_self(mob/user)
if(!user.can_read(src))
return
user.visible_message(span_notice("[user] opens a book titled \"[title]\" and begins reading intently."))
SEND_SIGNAL(user, COMSIG_ADD_MOOD_EVENT, "book_nerd", /datum/mood_event/book_nerd)
on_read(user)
/obj/item/book/proc/on_read(mob/user)
if(dat)
user << browse("<meta charset=UTF-8><TT><I>Penned by [author].</I></TT> <BR>" + "[dat]", "window=book[window_size != null ? ";size=[window_size]" : ""]")
onclose(user, "book")
else
to_chat(user, span_notice("This book is completely blank!"))
/obj/item/book/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/pen))
if(user.is_blind())
to_chat(user, span_warning("As you are trying to write on the book, you suddenly feel very stupid!"))
return
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
var/literate = user.is_literate()
if(!literate)
to_chat(user, span_notice("You scribble illegibly on the cover of [src]!"))
return
var/choice = tgui_input_list(usr, "What would you like to change?",,list("Title", "Contents", "Author", "Cancel"))
if(!user.canUseTopic(src, BE_CLOSE, literate))
return
switch(choice)
if("Title")
var/newtitle = reject_bad_text(stripped_input(user, "Write a new title:"))
if(!user.canUseTopic(src, BE_CLOSE, literate))
return
if (length_char(newtitle) > 30)
to_chat(user, span_warning("That title won't fit on the cover!"))
return
if(!newtitle)
to_chat(user, span_warning("That title is invalid."))
return
else
name = newtitle
title = newtitle
if("Contents")
var/content = stripped_input(user, "Write your book's contents (HTML NOT allowed):","","",8192)
if(!user.canUseTopic(src, BE_CLOSE, literate))
return
if(!content)
to_chat(user, span_warning("The content is invalid."))
return
else
dat += content
if("Author")
var/newauthor = stripped_input(user, "Write the author's name:")
if(!user.canUseTopic(src, BE_CLOSE, literate))
return
if(!newauthor)
to_chat(user, span_warning("The name is invalid."))
return
else
author = newauthor
else
return
else if(istype(I, /obj/item/barcodescanner))
var/obj/item/barcodescanner/scanner = I
if(!scanner.computer)
to_chat(user, span_alert("[I]'s screen flashes: 'No associated computer found!'"))
else
switch(scanner.mode)
if(0)
scanner.book = src
to_chat(user, span_notice("[I]'s screen flashes: 'Book stored in buffer.'"))
if(1)
scanner.book = src
scanner.computer.buffer_book = name
to_chat(user, span_notice("[I]'s screen flashes: 'Book stored in buffer. Book title stored in associated computer buffer.'"))
if(2)
scanner.book = src
for(var/datum/borrowbook/b in scanner.computer.checkouts)
if(b.bookname == name)
scanner.computer.checkouts.Remove(b)
to_chat(user, span_notice("[I]'s screen flashes: 'Book stored in buffer. Book has been checked in.'"))
return
to_chat(user, span_notice("[I]'s screen flashes: 'Book stored in buffer. No active check-out record found for current title.'"))
if(3)
scanner.book = src
for(var/obj/item/book in scanner.computer.inventory)
if(book == src)
to_chat(user, span_alert("[I]'s screen flashes: 'Book stored in buffer. Title already present in inventory, aborting to avoid duplicate entry.'"))
return
scanner.computer.inventory.Add(src)
to_chat(user, span_notice("[I]'s screen flashes: 'Book stored in buffer. Title added to general inventory.'"))
else if((istype(I, /obj/item/kitchen/knife) || I.tool_behaviour == TOOL_WIRECUTTER) && !(flags_1 & HOLOGRAM_1))
to_chat(user, span_notice("You begin to carve out [title]..."))
if(do_after(user, 30, target = src))
to_chat(user, span_notice("You carve out the pages from [title]! You didn't want to read it anyway."))
var/obj/item/storage/book/B = new
B.name = src.name
B.title = src.title
B.icon_state = src.icon_state
if(user.is_holding(src))
qdel(src)
user.put_in_hands(B)
return
else
B.forceMove(drop_location())
qdel(src)
return
return
else
..()
/*
* Barcode Scanner
*/
/obj/item/barcodescanner
name = "barcode scanner"
icon = 'icons/obj/library.dmi'
icon_state ="scanner"
desc = "A fabulous tool if you need to scan a barcode."
throw_speed = 3
throw_range = 5
w_class = WEIGHT_CLASS_TINY
var/obj/machinery/computer/bookmanagement/computer //Associated computer - Modes 1 to 3 use this
var/obj/item/book/book //Currently scanned book
var/mode = 0 //0 - Scan only, 1 - Scan and Set Buffer, 2 - Scan and Attempt to Check In, 3 - Scan and Attempt to Add to Inventory
/obj/item/barcodescanner/attack_self(mob/user)
mode += 1
if(mode > 3)
mode = 0
to_chat(user, "[src] Status Display:")
var/modedesc
switch(mode)
if(0)
modedesc = "Scan book to local buffer."
if(1)
modedesc = "Scan book to local buffer and set associated computer buffer to match."
if(2)
modedesc = "Scan book to local buffer, attempt to check in scanned book."
if(3)
modedesc = "Scan book to local buffer, attempt to add book to general inventory."
else
modedesc = "ERROR"
to_chat(user, " - Mode [mode] : [modedesc]")
if(computer)
to_chat(user, "<font color=green>Computer has been associated with this unit.</font>")
else
to_chat(user, "<font color=red>No associated computer found. Only local scans will function properly.</font>")
to_chat(user, "\n")
#undef BOOKCASE_UNANCHORED
#undef BOOKCASE_ANCHORED
#undef BOOKCASE_FINISHED