/* 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 = null 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/SQLquery clockwork = TRUE //it'd look weird /obj/machinery/computer/libraryconsole/ui_interact(mob/user) . = ..() var/dat = "" // 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(!SQLquery) dat += "ERROR: Malformed search request. Please contact your system administrator for assistance.
" else dat += "" dat += "" var/datum/DBQuery/query_library_list_books = SSdbcore.NewQuery(SQLquery) if(!query_library_list_books.Execute()) dat += "ERROR: Unable to retrieve book listings. Please contact your system administrator for assistance.
" 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 += "" dat += "
AUTHORTITLECATEGORYSS13BN
[author][title][category][id]

" dat += "\[Go Back\]
" var/datum/browser/popup = new(user, "publiclibrary", name, 600, 400) popup.set_content(dat) popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state)) popup.open() /obj/machinery/computer/libraryconsole/Topic(href, href_list) . = ..() 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 title = sanitizeSQL(title) 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" category = sanitizeSQL(category) if(href_list["setauthor"]) var/newauthor = input("Enter an author to search for:") as text|null if(newauthor) author = sanitize(newauthor) else author = null author = sanitizeSQL(author) if(href_list["search"]) SQLquery = "SELECT author, title, category, id FROM [format_table_name("library")] WHERE isnull(deleted) AND " if(category == "Any") SQLquery += "author LIKE '%[author]%' AND title LIKE '%[title]%'" else SQLquery += "author LIKE '%[author]%' AND title LIKE '%[title]%' AND category='[category]'" screenstate = 1 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 /* * Cachedbook datum */ /datum/cachedbook // Datum used to cache the SQL DB books locally in order to achieve a performance gain. var/id var/title var/author var/category GLOBAL_LIST(cachedbooks) // List of our cached book datums /proc/load_library_db_to_cache() if(GLOB.cachedbooks) return if(!SSdbcore.Connect()) return GLOB.cachedbooks = list() var/datum/DBQuery/query_library_cache = SSdbcore.NewQuery("SELECT id, author, title, category FROM [format_table_name("library")] WHERE isnull(deleted)") if(!query_library_cache.Execute()) return while(query_library_cache.NextRow()) var/datum/cachedbook/newbook = new() newbook.id = query_library_cache.item[1] newbook.author = query_library_cache.item[2] newbook.title = query_library_cache.item[3] newbook.category = query_library_cache.item[4] GLOB.cachedbooks += newbook #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/libraryconsole/bookmanagement name = "book inventory management console" desc = "Librarian's command station." var/arcanecheckout = 0 screenstate = 0 // 0 - Main Menu, 1 - Inventory, 2 - Checked Out, 3 - Check Out a Book verb_say = "beeps" verb_ask = "beeps" verb_exclaim = "beeps" 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/list/libcomp_menu var/page = 1 //current page of the external archives var/cooldown = 0 /obj/machinery/computer/libraryconsole/bookmanagement/proc/build_library_menu() if(libcomp_menu) return load_library_db_to_cache() if(!GLOB.cachedbooks) return libcomp_menu = list("") for(var/i in 1 to GLOB.cachedbooks.len) var/datum/cachedbook/C = GLOB.cachedbooks[i] var/page = round(i/250)+1 if (libcomp_menu.len < page) libcomp_menu.len = page libcomp_menu[page] = "" libcomp_menu[page] += "[C.author][C.title][C.category]\[Order\]\n" /obj/machinery/computer/libraryconsole/bookmanagement/Initialize() . = ..() if(circuit) circuit.name = "Book Inventory Management Console (Machine Board)" circuit.build_path = /obj/machinery/computer/libraryconsole/bookmanagement /obj/machinery/computer/libraryconsole/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

" build_library_menu() if(!GLOB.cachedbooks) dat += "ERROR: Unable to contact External Archive. Please contact your system administrator for assistance." else dat += "(Order book by SS13BN)

" dat += "" dat += "" dat += libcomp_menu[CLAMP(page,1,libcomp_menu.len)] dat += "" dat += "
AUTHORTITLECATEGORY
<<<< >>>>
" 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.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state)) popup.open() /obj/machinery/computer/libraryconsole/bookmanagement/proc/findscanner(viewrange) for(var/obj/machinery/libraryscanner/S in range(viewrange, get_turf(src))) return S return null /obj/machinery/computer/libraryconsole/bookmanagement/proc/print_forbidden_lore(mob/user) var/spook = pick("blood", "brass") var/turf/T = get_turf(src) if(spook == "blood") new /obj/item/melee/cultblade/dagger(T) else new /obj/item/clockwork/slab(T) 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 [spook == "blood" ? "sinister dagger" : "strange metal tablet"] 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/libraryconsole/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/libraryconsole/bookmanagement/emag_act(mob/user) if(density && !(obj_flags & EMAGGED)) obj_flags |= EMAGGED /obj/machinery/computer/libraryconsole/bookmanagement/Topic(href, href_list) 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 = copytext(sanitize(input("Enter the book's title:") as text|null),1,MAX_MESSAGE_LEN) if(href_list["editmob"]) buffer_mob = copytext(sanitize(input("Enter the recipient's name:") as text|null),1,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 = copytext(sanitize(input("Enter the author's name: ") as text|null),1,MAX_MESSAGE_LEN) 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/sqltitle = sanitizeSQL(scanner.cache.name) var/sqlauthor = sanitizeSQL(scanner.cache.author) var/sqlcontent = sanitizeSQL(scanner.cache.dat) var/sqlcategory = sanitizeSQL(upload_category) var/datum/DBQuery/query_library_upload = SSdbcore.NewQuery("INSERT INTO [format_table_name("library")] (author, title, content, category, ckey, datetime, round_id_created) VALUES ('[sqlauthor]', '[sqltitle]', '[sqlcontent]', '[sqlcategory]', '[usr.ckey]', Now(), '[GLOB.round_id]')") if(!query_library_upload.Execute()) alert("Database error encountered uploading to Archive") return else log_game("[usr.name]/[usr.key] has uploaded the book titled [scanner.cache.name], [length(scanner.cache.dat)] signs") 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(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/sqlid = sanitizeSQL(href_list["targetid"]) if (!SSdbcore.Connect()) alert("Connection to Archive has been severed. Aborting.") if(cooldown > world.time) say("Printer unavailable. Please allow a short time before attempting to print.") else cooldown = world.time + PRINTER_COOLDOWN var/datum/DBQuery/query_library_print = SSdbcore.NewQuery("SELECT * FROM [format_table_name("library")] WHERE id=[sqlid] AND isnull(deleted)") if(!query_library_print.Execute()) say("PRINTER ERROR! Failed to print document (0x0000000F)") return 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] 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 if(href_list["printbible"]) if(cooldown < world.time) var/obj/item/storage/book/bible/B = new /obj/item/storage/book/bible(src.loc) if(SSreligion.bible_icon_state && SSreligion.bible_item_state) B.icon_state = SSreligion.bible_icon_state B.item_state = SSreligion.bible_item_state B.name = SSreligion.bible_name B.deity_name = SSreligion.deity cooldown = world.time + PRINTER_COOLDOWN else say("Printer currently unavailable, please wait a moment.") if(href_list["printposter"]) if(cooldown < world.time) new /obj/item/poster/random_official(src.loc) 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) . = ..() 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.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state)) 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(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(!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())