/* Library Machines * * Contains: * Borrowbook datum * Library Public Computer * Cachedbook datum * Library Computer * Library Scanner * Book Binder */ /* * Library Public Computer */ /obj/machinery/computer/libraryconsole name = "library visitor console" icon_state = "oldcomp" icon_screen = "library" icon_keyboard = "no_keyboard" circuit = /obj/item/circuitboard/computer/libraryconsole desc = "Checked out books MUST be returned on time." var/screenstate = 0 var/title var/category = "Any" var/author var/search_page = 0 COOLDOWN_DECLARE(library_visitor_topic_cooldown) /obj/machinery/computer/libraryconsole/ui_interact(mob/user) . = ..() var/list/dat = list() // switch(screenstate) if(0) dat += "

Search Settings


" dat += "Filter by Title: [title]
" dat += "Filter by Category: [category]
" dat += "Filter by Author: [author]
" dat += "\[Start Search\]
" if(1) if (!SSdbcore.Connect()) dat += "ERROR: Unable to contact External Archive. Please contact your system administrator for assistance.
" else if(QDELETED(user)) return else dat += "" dat += "" var/SQLsearch = "isnull(deleted) AND " if(category == "Any") SQLsearch += "author LIKE '%[author]%' AND title LIKE '%[title]%'" else SQLsearch += "author LIKE '%[author]%' AND title LIKE '%[title]%' AND category='[category]'" var/bookcount = 0 var/booksperpage = 20 var/datum/db_query/query_library_count_books = SSdbcore.NewQuery({" SELECT COUNT(id) FROM [format_table_name("library")] WHERE isnull(deleted) AND author LIKE CONCAT('%',:author,'%') AND title LIKE CONCAT('%',:title,'%') AND (:category = 'Any' OR category = :category) "}, list("author" = author, "title" = title, "category" = category)) if(!query_library_count_books.warn_execute()) qdel(query_library_count_books) return if(query_library_count_books.NextRow()) bookcount = text2num(query_library_count_books.item[1]) qdel(query_library_count_books) if(bookcount > booksperpage) dat += "Page: " var/pagecount = 1 var/list/pagelist = list() while(bookcount > 0) pagelist += "[pagecount == search_page + 1 ? "\[[pagecount]\]" : "\[[pagecount]\]"]" bookcount -= booksperpage pagecount++ dat += pagelist.Join(" | ") search_page = text2num(search_page) var/datum/db_query/query_library_list_books = SSdbcore.NewQuery({" SELECT author, title, category, id FROM [format_table_name("library")] WHERE isnull(deleted) AND author LIKE CONCAT('%',:author,'%') AND title LIKE CONCAT('%',:title,'%') AND (:category = 'Any' OR category = :category) LIMIT :skip, :take "}, list("author" = author, "title" = title, "category" = category, "skip" = booksperpage * search_page, "take" = booksperpage)) if(!query_library_list_books.Execute()) dat += "ERROR: Unable to retrieve book listings. Please contact your system administrator for assistance.
" else while(query_library_list_books.NextRow()) var/author = query_library_list_books.item[1] var/title = query_library_list_books.item[2] var/category = query_library_list_books.item[3] var/id = query_library_list_books.item[4] dat += "" qdel(query_library_list_books) if(QDELETED(user)) return dat += "
AUTHORTITLECATEGORYSS13BN
[author][title][category][id]

" dat += "\[Go Back\]
" var/datum/browser/popup = new(user, "publiclibrary", name, 600, 400) popup.set_content(jointext(dat, "")) popup.open() /obj/machinery/computer/libraryconsole/Topic(href, href_list) if(!COOLDOWN_FINISHED(src, library_visitor_topic_cooldown)) return COOLDOWN_START(src, library_visitor_topic_cooldown, 1 SECONDS) . = ..() if(.) usr << browse(null, "window=publiclibrary") onclose(usr, "publiclibrary") return if(href_list["settitle"]) var/newtitle = input("Enter a title to search for:") as text|null if(newtitle) title = sanitize(newtitle) else title = null if(href_list["setcategory"]) var/newcategory = input("Choose a category to search for:") in list("Any", "Fiction", "Non-Fiction", "Adult", "Reference", "Religion") if(newcategory) category = sanitize(newcategory) else category = "Any" if(href_list["setauthor"]) var/newauthor = input("Enter an author to search for:") as text|null if(newauthor) author = sanitize(newauthor) else author = null if(href_list["search"]) screenstate = 1 if(href_list["bookpagecount"]) search_page = text2num(href_list["bookpagecount"]) if(href_list["back"]) screenstate = 0 src.add_fingerprint(usr) src.updateUsrDialog() return /* * Borrowbook datum */ /datum/borrowbook // Datum used to keep track of who has borrowed what when and for how long. var/bookname var/mobname var/getdate var/duedate #define PRINTER_COOLDOWN 60 /* * Library Computer * After 860 days, it's finally a buildable computer. */ // TODO: Make this an actual /obj/machinery/computer that can be crafted from circuit boards and such // It is August 22nd, 2012... This TODO has already been here for months.. I wonder how long it'll last before someone does something about it. // It's December 25th, 2014, and this is STILL here, and it's STILL relevant. Kill me /obj/machinery/computer/bookmanagement name = "book inventory management console" desc = "Librarian's command station." verb_say = "beeps" verb_ask = "beeps" verb_exclaim = "beeps" pass_flags = PASSTABLE icon_state = "oldcomp" icon_screen = "library" icon_keyboard = "no_keyboard" circuit = /obj/item/circuitboard/computer/libraryconsole var/screenstate = 0 // 0 - Main Menu, 1 - Inventory, 2 - Checked Out, 3 - Check Out a Book var/arcanecheckout = 0 var/buffer_book var/buffer_mob var/upload_category = "Fiction" var/list/checkouts = list() var/list/inventory = list() var/checkoutperiod = 5 // In minutes var/obj/machinery/libraryscanner/scanner // Book scanner that will be used when uploading books to the Archive var/page = 1 //current page of the external archives var/printer_cooldown = 0 COOLDOWN_DECLARE(library_console_topic_cooldown) /obj/machinery/computer/bookmanagement/Initialize() . = ..() if(circuit) circuit.name = "Book Inventory Management Console (Machine Board)" circuit.build_path = /obj/machinery/computer/bookmanagement /obj/machinery/computer/bookmanagement/ui_interact(mob/user) . = ..() var/dat = "" // switch(screenstate) if(0) // Main Menu dat += "1. View General Inventory
" dat += "2. View Checked Out Inventory
" dat += "3. Check out a Book
" dat += "4. Connect to External Archive
" dat += "5. Upload New Title to Archive
" dat += "6. Upload Scanned Title to Newscaster
" dat += "7. Print Corporate Materials
" if(obj_flags & EMAGGED) dat += "8. Access the Forbidden Lore Vault
" if(src.arcanecheckout) print_forbidden_lore(user) src.arcanecheckout = 0 if(1) // Inventory dat += "

Inventory


" for(var/obj/item/book/b in inventory) dat += "[b.name] (Delete)
" dat += "(Return to main menu)
" if(2) // Checked Out dat += "

Checked Out Books


" for(var/datum/borrowbook/b in checkouts) var/timetaken = world.time - b.getdate timetaken /= 600 timetaken = round(timetaken) var/timedue = b.duedate - world.time timedue /= 600 if(timedue <= 0) timedue = "(OVERDUE) [timedue]" else timedue = round(timedue) dat += "\"[b.bookname]\", Checked out to: [b.mobname]
--- Taken: [timetaken] minutes ago, Due: in [timedue] minutes
" dat += "(Check In)

" dat += "(Return to main menu)
" if(3) // Check Out a Book dat += "

Check Out a Book


" dat += "Book: [src.buffer_book] " dat += "\[Edit\]
" dat += "Recipient: [src.buffer_mob] " dat += "\[Edit\]
" dat += "Checkout Date : [world.time/600]
" dat += "Due Date: [(world.time + checkoutperiod)/600]
" dat += "(Checkout Period: [checkoutperiod] minutes) (+/-)" dat += "(Commit Entry)
" dat += "(Return to main menu)
" if(4) dat += "

External Archive

" if(!SSdbcore.Connect()) dat += "ERROR: Unable to contact External Archive. Please contact your system administrator for assistance." else var/booksperpage = 50 var/pagecount var/datum/db_query/query_library_count_books = SSdbcore.NewQuery("SELECT COUNT(id) FROM [format_table_name("library")] WHERE isnull(deleted)") if(!query_library_count_books.Execute()) qdel(query_library_count_books) return if(query_library_count_books.NextRow()) pagecount = CEILING(text2num(query_library_count_books.item[1]) / booksperpage, 1) qdel(query_library_count_books) var/list/booklist = list() var/datum/db_query/query_library_get_books = SSdbcore.NewQuery({" SELECT id, author, title, category FROM [format_table_name("library")] WHERE isnull(deleted) LIMIT :skip, :take "}, list("skip" = booksperpage * (page - 1), "take" = booksperpage)) if(!query_library_get_books.Execute()) qdel(query_library_get_books) return while(query_library_get_books.NextRow()) booklist += "[query_library_get_books.item[2]][query_library_get_books.item[3]][query_library_get_books.item[4]]\[Order\]\n" dat += "(Order book by SS13BN)

" dat += "" dat += "" dat += jointext(booklist, "") dat += "" dat += "
AUTHORTITLECATEGORY
<<<< >>>>
" qdel(query_library_get_books) dat += "
(Return to main menu)
" if(5) dat += "

Upload a New Title

" if(!scanner) scanner = findscanner(9) if(!scanner) dat += "No scanner found within wireless network range.
" else if(!scanner.cache) dat += "No data found in scanner memory.
" else dat += "Data marked for upload...
" dat += "Title: [scanner.cache.name]
" if(!scanner.cache.author) scanner.cache.author = "Anonymous" dat += "Author: [scanner.cache.author]
" dat += "Category: [upload_category]
" dat += "\[Upload\]
" dat += "(Return to main menu)
" if(6) dat += "

Post Title to Newscaster

" if(!scanner) scanner = findscanner(9) if(!scanner) dat += "No scanner found within wireless network range.
" else if(!scanner.cache) dat += "No data found in scanner memory.
" else dat += "Post [scanner.cache.name] to station newscasters?" dat += "\[Post\]
" dat += "(Return to main menu)
" if(7) dat += "

NTGanda(tm) Universal Printing Module

" dat += "What would you like to print?
" dat += "\[Bible\]
" dat += "\[Poster\]
" dat += "(Return to main menu)
" if(8) dat += "

Accessing Forbidden Lore Vault v 1.3

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

" dat += "Yes.
" dat += "No.
" var/datum/browser/popup = new(user, "library", name, 600, 400) popup.set_content(dat) popup.open() /obj/machinery/computer/bookmanagement/proc/findscanner(viewrange) for(var/obj/machinery/libraryscanner/S in range(viewrange, get_turf(src))) return S return null /obj/machinery/computer/bookmanagement/proc/print_forbidden_lore(mob/user) new /obj/item/melee/cultblade/dagger(get_turf(src)) to_chat(user, "Your sanity barely endures the seconds spent in the vault's browsing window. The only thing to remind you of this when you stop browsing is a sinister dagger sitting on the desk. You don't even remember where it came from...") user.visible_message("[user] stares at the blank screen for a few moments, [user.p_their()] expression frozen in fear. When [user.p_they()] finally awaken[user.p_s()] from it, [user.p_they()] look[user.p_s()] a lot older.", 2) /obj/machinery/computer/bookmanagement/attackby(obj/item/W, mob/user, params) if(istype(W, /obj/item/barcodescanner)) var/obj/item/barcodescanner/scanner = W scanner.computer = src to_chat(user, "[scanner]'s associated machine has been set to [src].") audible_message("[src] lets out a low, short blip.") else return ..() /obj/machinery/computer/bookmanagement/emag_act(mob/user) if(density && !(obj_flags & EMAGGED)) obj_flags |= EMAGGED /obj/machinery/computer/bookmanagement/Topic(href, href_list) if(!COOLDOWN_FINISHED(src, library_console_topic_cooldown)) return COOLDOWN_START(src, library_console_topic_cooldown, 1 SECONDS) if(..()) usr << browse(null, "window=library") onclose(usr, "library") return if(href_list["page"] && screenstate == 4) page = text2num(href_list["page"]) if(href_list["switchscreen"]) switch(href_list["switchscreen"]) if("0") screenstate = 0 if("1") screenstate = 1 if("2") screenstate = 2 if("3") screenstate = 3 if("4") screenstate = 4 if("5") screenstate = 5 if("6") screenstate = 6 if("7") screenstate = 7 if("8") screenstate = 8 if(href_list["arccheckout"]) if(obj_flags & EMAGGED) src.arcanecheckout = 1 src.screenstate = 0 if(href_list["increasetime"]) checkoutperiod += 1 if(href_list["decreasetime"]) checkoutperiod -= 1 if(checkoutperiod < 1) checkoutperiod = 1 if(href_list["editbook"]) buffer_book = stripped_input(usr, "Enter the book's title:", max_length = 45) if(href_list["editmob"]) buffer_mob = stripped_input(usr, "Enter the recipient's name:", max_length = MAX_NAME_LEN) if(href_list["checkout"]) var/datum/borrowbook/b = new /datum/borrowbook b.bookname = sanitize(buffer_book) b.mobname = sanitize(buffer_mob) b.getdate = world.time b.duedate = world.time + (checkoutperiod * 600) checkouts.Add(b) if(href_list["checkin"]) var/datum/borrowbook/b = locate(href_list["checkin"]) in checkouts if(b && istype(b)) checkouts.Remove(b) if(href_list["delbook"]) var/obj/item/book/b = locate(href_list["delbook"]) in inventory if(b && istype(b)) inventory.Remove(b) if(href_list["setauthor"]) var/newauthor = stripped_input(usr, "Enter the author's name: ", max_length = 45) if(newauthor) scanner.cache.author = newauthor if(href_list["setcategory"]) var/newcategory = input("Choose a category: ") in list("Fiction", "Non-Fiction", "Adult", "Reference", "Religion","Technical") if(newcategory) upload_category = newcategory if(href_list["upload"]) if(scanner) if(scanner.cache) var/choice = input("Are you certain you wish to upload this title to the Archive?") in list("Confirm", "Abort") if(choice == "Confirm") if (!SSdbcore.Connect()) alert("Connection to Archive has been severed. Aborting.") else var/msg = "[key_name(usr)] has uploaded the book titled [scanner.cache.name], [length(scanner.cache.dat)] signs" var/datum/db_query/query_library_upload = SSdbcore.NewQuery({" INSERT INTO [format_table_name("library")] (author, title, content, category, ckey, datetime, round_id_created) VALUES (:author, :title, :content, :category, :ckey, Now(), :round_id) "}, list("title" = scanner.cache.name, "author" = scanner.cache.author, "content" = scanner.cache.dat, "category" = upload_category, "ckey" = usr.ckey, "round_id" = GLOB.round_id)) if(!query_library_upload.Execute()) qdel(query_library_upload) alert("Database error encountered uploading to Archive") return else log_game(msg) qdel(query_library_upload) alert("Upload Complete. Uploaded title will be unavailable for printing for a short period") if(href_list["newspost"]) if(!GLOB.news_network) alert("No news network found on station. Aborting.") var/channelexists = 0 for(var/datum/newscaster/feed_channel/FC in GLOB.news_network.network_channels) if(FC.channel_name == "Nanotrasen Book Club") channelexists = 1 break if(!channelexists) GLOB.news_network.CreateFeedChannel("Nanotrasen Book Club", "Library", null) GLOB.news_network.SubmitArticle(scanner.cache.dat, "[scanner.cache.name]", "Nanotrasen Book Club", null) alert("Upload complete. Your uploaded title is now available on station newscasters.") if(href_list["orderbyid"]) if(printer_cooldown > world.time) say("Printer unavailable. Please allow a short time before attempting to print.") else var/orderid = input("Enter your order:") as num|null if(orderid) if(isnum(orderid) && ISINTEGER(orderid)) href_list["targetid"] = num2text(orderid) if(href_list["targetid"]) var/id = href_list["targetid"] if (!SSdbcore.Connect()) alert("Connection to Archive has been severed. Aborting.") if(printer_cooldown > world.time) say("Printer unavailable. Please allow a short time before attempting to print.") else var/datum/db_query/query_library_print = SSdbcore.NewQuery( "SELECT * FROM [format_table_name("library")] WHERE id=:id AND isnull(deleted)", list("id" = id) ) if(!query_library_print.Execute()) qdel(query_library_print) say("PRINTER ERROR! Failed to print document (0x0000000F)") return printer_cooldown = world.time + PRINTER_COOLDOWN while(query_library_print.NextRow()) var/author = query_library_print.item[2] var/title = query_library_print.item[3] var/content = query_library_print.item[4] if(!QDELETED(src)) var/obj/item/book/B = new(get_turf(src)) B.name = "Book: [title]" B.title = title B.author = author B.dat = content B.icon_state = "book[rand(1,8)]" visible_message("[src]'s printer hums as it produces a completely bound book. How did it do that?") break qdel(query_library_print) if(href_list["printbible"]) if(printer_cooldown < world.time) var/obj/item/storage/book/bible/B = new /obj/item/storage/book/bible(src.loc) if(GLOB.bible_icon_state && GLOB.bible_inhand_icon_state) B.icon_state = GLOB.bible_icon_state B.inhand_icon_state = GLOB.bible_inhand_icon_state B.name = GLOB.bible_name B.deity_name = GLOB.deity printer_cooldown = world.time + PRINTER_COOLDOWN else say("Printer currently unavailable, please wait a moment.") if(href_list["printposter"]) if(printer_cooldown < world.time) new /obj/item/poster/random_official(src.loc) printer_cooldown = world.time + PRINTER_COOLDOWN else say("Printer currently unavailable, please wait a moment.") add_fingerprint(usr) updateUsrDialog() /* * Library Scanner */ /obj/machinery/libraryscanner name = "scanner control interface" icon = 'icons/obj/library.dmi' icon_state = "bigscanner" desc = "It servers the purpose of scanning stuff." density = TRUE var/obj/item/book/cache // Last scanned book /obj/machinery/libraryscanner/attackby(obj/O, mob/user, params) if(istype(O, /obj/item/book)) if(!user.transferItemToLoc(O, src)) return else return ..() /obj/machinery/libraryscanner/attack_hand(mob/user, list/modifiers) . = ..() if(.) return usr.set_machine(src) var/dat = "" // if(cache) dat += "Data stored in memory.
" else dat += "No data stored in memory.
" dat += "\[Scan\]" if(cache) dat += " \[Clear Memory\]

\[Remove Book\]" else dat += "
" var/datum/browser/popup = new(user, "scanner", name, 600, 400) popup.set_content(dat) popup.open() /obj/machinery/libraryscanner/Topic(href, href_list) if(..()) usr << browse(null, "window=scanner") onclose(usr, "scanner") return if(href_list["scan"]) for(var/obj/item/book/B in contents) cache = B break if(href_list["clear"]) cache = null if(href_list["eject"]) for(var/obj/item/book/B in contents) B.forceMove(drop_location()) src.add_fingerprint(usr) src.updateUsrDialog() return /* * Book binder */ /obj/machinery/bookbinder name = "book binder" icon = 'icons/obj/library.dmi' icon_state = "binder" desc = "Only intended for binding paper products." density = TRUE var/busy = FALSE /obj/machinery/bookbinder/attackby(obj/O, mob/user, params) if(istype(O, /obj/item/paper)) bind_book(user, O) else if(default_unfasten_wrench(user, O)) return 1 else return ..() /obj/machinery/bookbinder/proc/bind_book(mob/user, obj/item/paper/P) if(machine_stat) return if(busy) to_chat(user, "The book binder is busy. Please wait for completion of previous operation.") return if(!user.transferItemToLoc(P, src)) return user.visible_message("[user] loads some paper into [src].", "You load some paper into [src].") audible_message("[src] begins to hum as it warms up its printing drums.") busy = TRUE sleep(rand(200,400)) busy = FALSE if(P) if(!machine_stat) visible_message("[src] whirs as it prints and binds a new book.") var/obj/item/book/B = new(src.loc) B.dat = P.info B.name = "Print Job #" + "[rand(100, 999)]" B.icon_state = "book[rand(1,7)]" qdel(P) else P.forceMove(drop_location())