Ports vg's library machinery, also flagging books

This commit is contained in:
Tastyfish
2016-04-10 20:38:10 -04:00
parent 1b8711171a
commit 65432404fa
14 changed files with 945 additions and 471 deletions
+2
View File
@@ -62,6 +62,7 @@ var/list/admin_verbs_admin = list(
/client/proc/man_up,
/client/proc/global_man_up,
/client/proc/delbook,
/client/proc/view_flagged_books,
/client/proc/empty_ai_core_toggle_latejoin,
/client/proc/aooc,
/client/proc/freeze,
@@ -125,6 +126,7 @@ var/list/admin_verbs_server = list(
/client/proc/cmd_debug_del_all,
/datum/admins/proc/toggle_aliens,
/client/proc/delbook,
/client/proc/view_flagged_books,
/client/proc/toggle_antagHUD_use,
/client/proc/toggle_antagHUD_restrictions,
/client/proc/set_ooc,
+41
View File
@@ -0,0 +1,41 @@
/client/proc/delbook()
set name = "Delete Book"
set desc = "Permamently deletes a book from the database."
set category = "Admin"
if(!holder)
to_chat(src, "Only administrators may use this command.")
return
var/isbn = input("ISBN number?", "Delete Book") as num | null
if(!isbn)
return
var/DBQuery/query_delbook = dbcon.NewQuery("DELETE FROM [format_table_name("library")] WHERE id=[isbn]")
if(!query_delbook.Execute())
var/err = query_delbook.ErrorMsg()
log_game("SQL ERROR deleting book. Error : \[[err]\]\n")
return
log_admin("[key_name(usr)] has deleted the book [isbn].")
message_admins("[key_name_admin(usr)] has deleted the book [isbn].")
/client/proc/view_flagged_books()
set name = "View Flagged Books"
set desc = "View books flagged for content."
set category = "Admin"
if(!holder)
to_chat(src, "Only administrators may use this command.")
return
var/DBQuery/query = dbcon.NewQuery("SELECT id, title, flagged FROM [format_table_name("library")] WHERE flagged > 0 ORDER BY flagged DESC")
if(!query.Execute())
var/err = query.ErrorMsg()
log_game("SQL ERROR getting flagged books. Error : \[[err]\]\n")
return
var/i
for(i = 0, query.NextRow(), i++)
to_chat(usr, "[add_zero(query.item[1], 4)] ([query.item[2]]) - flagged [query.item[3]] times.")
to_chat(usr, "[i] flagged books total.")
+93
View File
@@ -0,0 +1,93 @@
#define MAX_BOOK_FLAGS 3 // maximum number of times a book can be flagged before being removed from results
/obj/machinery/computer/library
name = "visitor computer"
anchored = 1
density = 1
icon_keyboard = ""
icon_screen = "computer_on"
var/screenstate = 0
var/page_num = 1
var/num_pages = 0
var/num_results = 0
var/datum/library_query/query = new()
icon = 'icons/obj/library.dmi'
icon_state = "computer"
/obj/machinery/computer/library/proc/interact_check(var/mob/user)
if(stat & (BROKEN | NOPOWER))
return 1
if (!Adjacent(user))
if (!issilicon(user) && !isobserver(user))
user.unset_machine()
user << browse(null, "window=library")
return 1
user.set_machine(src)
return 0
/obj/machinery/computer/library/proc/get_page(var/page_num)
var/searchquery = ""
var/where = 0
if(query)
if(query.title && query.title != "")
searchquery += " WHERE title LIKE '%[query.title]%'"
where = 1
if(query.author && query.author != "")
searchquery += " [!where ? "WHERE" : "AND"] author LIKE '%[query.author]%'"
where = 1
if(query.category && query.category != "")
searchquery += " [!where ? "WHERE" : "AND"] category LIKE '%[query.category]%'"
if(query.category == "Fiction")
searchquery += " AND category NOT LIKE '%Non-Fiction%'"
where = 1
searchquery += " [!where ? "WHERE" : "AND"] flagged < [MAX_BOOK_FLAGS]"
var/sql = "SELECT id, author, title, category, ckey, flagged FROM [format_table_name("library")] [searchquery] LIMIT [(page_num - 1) * LIBRARY_BOOKS_PER_PAGE], [LIBRARY_BOOKS_PER_PAGE]"
// Pagination
var/DBQuery/_query = dbcon.NewQuery(sql)
_query.Execute()
if(_query.ErrorMsg())
log_to_dd(_query.ErrorMsg())
var/list/results = list()
while(_query.NextRow())
var/datum/cachedbook/CB = new()
CB.LoadFromRow(list(
"id" =_query.item[1],
"author" =_query.item[2],
"title" =_query.item[3],
"category"=_query.item[4],
"ckey" =_query.item[5],
"flagged" =text2num(_query.item[6])
))
results += CB
return results
/obj/machinery/computer/library/proc/get_num_results()
var/sql = "SELECT COUNT(*) FROM [format_table_name("library")]"
var/DBQuery/_query = dbcon.NewQuery(sql)
_query.Execute()
while(_query.NextRow())
return text2num(_query.item[1])
return 0
/obj/machinery/computer/library/proc/get_pagelist()
var/pagelist = "<div class='pages'>"
var/start = max(1, page_num - 3)
var/end = min(num_pages, page_num + 3)
for(var/i = start to end)
var/dat = "<a href='?src=\ref[src];page=[i]'>[i]</a>"
if(i == page_num)
dat = "<font size=3><b>[dat]</b></font>"
if(i != end)
dat += " "
pagelist += dat
pagelist += "</div>"
return pagelist
/obj/machinery/computer/library/proc/getBookByID(var/id as text)
return library_catalog.getBookByID(id)
+465
View File
@@ -0,0 +1,465 @@
/*
* Library Computer
*/
/obj/machinery/computer/library/checkout
name = "Check-In/Out Computer"
icon = 'icons/obj/library.dmi'
icon_state = "computer"
anchored = 1
density = 1
var/arcanecheckout = 0
//var/screenstate = 0 // 0 - Main Menu, 1 - Inventory, 2 - Checked Out, 3 - Check Out a Book
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/bibledelay = 0 // LOL NO SPAM (1 minute delay) -- Doohl
var/booklist
/obj/machinery/computer/library/checkout/attack_hand(var/mob/user as mob)
if(..())
return
interact(user)
/obj/machinery/computer/library/checkout/interact(var/mob/user)
if(interact_check(user))
return
var/dat = ""
switch(screenstate)
if(0)
// Main Menu
dat += {"<ol>
<li><A href='?src=\ref[src];switchscreen=1'>View General Inventory</A></li>
<li><A href='?src=\ref[src];switchscreen=2'>View Checked Out Inventory</A></li>
<li><A href='?src=\ref[src];switchscreen=3'>Check out a Book</A></li>
<li><A href='?src=\ref[src];switchscreen=4'>Connect to External Archive</A></li>
<li><A href='?src=\ref[src];switchscreen=5'>Upload New Title to Archive</A></li>
<li><A href='?src=\ref[src];switchscreen=6'>Print a Bible</A></li>
<li><A href='?src=\ref[src];switchscreen=7'>Print a Manual</A></li>"}
if(src.emagged)
dat += "<li><A href='?src=\ref[src];switchscreen=8'>Access the Forbidden Lore Vault</A></li>"
dat += "</ol>"
if(src.arcanecheckout)
new /obj/item/weapon/tome(src.loc)
to_chat(user, "<span class='warning'>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 dusty old tome sitting on the desk. You don't really remember printing it.</span>")
user.visible_message("[user] stares at the blank screen for a few moments, his expression frozen in fear. When he finally awakens from it, he looks a lot older.", 2)
src.arcanecheckout = 0
if(1)
// Inventory
dat += "<h3>Inventory</h3>"
for(var/obj/item/weapon/book/b in inventory)
dat += "[b.name] <A href='?src=\ref[src];delbook=\ref[b]'>(Delete)</A><BR>"
dat += "<A href='?src=\ref[src];switchscreen=0'>(Return to main menu)</A><BR>"
if(2)
// Checked Out
dat += "<h3>Checked Out Books</h3><BR>"
for(var/datum/borrowbook/b in checkouts)
var/timetaken = world.time - b.getdate
//timetaken *= 10
timetaken /= 600
timetaken = round(timetaken)
var/timedue = b.duedate - world.time
//timedue *= 10
timedue /= 600
if(timedue <= 0)
timedue = "<font color=red><b>(OVERDUE)</b> [timedue]</font>"
else
timedue = round(timedue)
dat += {"\"[b.bookname]\", Checked out to: [b.mobname]<BR>--- Taken: [timetaken] minutes ago, Due: in [timedue] minutes<BR>
<A href='?src=\ref[src];checkin=\ref[b]'>(Check In)</A><BR><BR>"}
dat += "<A href='?src=\ref[src];switchscreen=0'>(Return to main menu)</A><BR>"
if(3)
// Check Out a Book
dat += {"<h3>Check Out a Book</h3><BR>
Book: [src.buffer_book]
<A href='?src=\ref[src];editbook=1'>\[Edit\]</A><BR>
Recipient: [src.buffer_mob]
<A href='?src=\ref[src];editmob=1'>\[Edit\]</A><BR>
Checkout Date : [world.time/600]<BR>
Due Date: [(world.time + checkoutperiod)/600]<BR>
(Checkout Period: [checkoutperiod] minutes) (<A href='?src=\ref[src];increasetime=1'>+</A>/<A href='?src=\ref[src];decreasetime=1'>-</A>)
<A href='?src=\ref[src];checkout=1'>(Commit Entry)</A><BR>
<A href='?src=\ref[src];switchscreen=0'>(Return to main menu)</A><BR>"}
if(4)
dat += "<h3>External Archive</h3>"
if(!dbcon.IsConnected())
dat += "<font color=red><b>ERROR</b>: Unable to contact External Archive. Please contact your system administrator for assistance.</font>"
else
num_results = src.get_num_results()
num_pages = Ceiling(num_results/LIBRARY_BOOKS_PER_PAGE)
dat += {"<ul>
<li><A href='?src=\ref[src];id=-1'>(Order book by SS<sup>13</sup>BN)</A></li>
</ul>"}
var/pagelist = get_pagelist()
dat += {"<h2>Search Settings</h2><br />
<A href='?src=\ref[src];settitle=1'>Filter by Title: [query.title]</A><br />
<A href='?src=\ref[src];setcategory=1'>Filter by Category: [query.category]</A><br />
<A href='?src=\ref[src];setauthor=1'>Filter by Author: [query.author]</A><br />
<A href='?src=\ref[src];search=1'>\[Start Search\]</A><br />"}
dat += pagelist
dat += {"<form name='pagenum' action='?src=\ref[src]' method='get'>
<input type='hidden' name='src' value='\ref[src]'>
<input type='text' name='pagenum' value='[page_num]' maxlength="5" size="5">
<input type='submit' value='Jump To Page'>
</form>"}
dat += {"<table border=\"0\">
<tr>
<td>Author</td>
<td>Title</td>
<td>Category</td>
<td>Controls</td>
</tr>"}
for(var/datum/cachedbook/CB in get_page(page_num))
var/author = CB.author
var/controls = "<A href='?src=\ref[src];id=[CB.id]'>\[Order\]</A>"
controls += {" <A href="?src=\ref[src];flag=[CB.id]">\[Flag[CB.flagged ? "ged" : ""]\]</A>"}
if(check_rights(R_ADMIN, user = user))
controls += " <A style='color:red' href='?src=\ref[src];del=[CB.id]'>\[Delete\]</A>"
author += " (<A style='color:red' href='?src=\ref[src];delbyckey=[ckey(CB.ckey)]'>[ckey(CB.ckey)])</A>)"
dat += {"<tr>
<td>[author]</td>
<td>[CB.title]</td>
<td>[CB.category]</td>
<td>[controls]</td>
</tr>"}
dat += "</table><br />[pagelist]"
dat += "<br /><A href='?src=\ref[src];switchscreen=0'>(Return to main menu)</A><BR>"
if(5)
dat += "<h3>Upload a New Title</h3>"
if(!scanner)
for(var/obj/machinery/libraryscanner/S in range(9))
scanner = S
break
if(!scanner)
dat += "<FONT color=red>No scanner found within wireless network range.</FONT><BR>"
else if(!scanner.cache)
dat += "<FONT color=red>No data found in scanner memory.</FONT><BR>"
else
dat += {"<TT>Data marked for upload...</TT><BR>
<TT>Title: </TT>[scanner.cache.name]<BR>"}
if(!scanner.cache.author)
scanner.cache.author = "Anonymous"
dat += {"<TT>Author: </TT><A href='?src=\ref[src];uploadauthor=1'>[scanner.cache.author]</A><BR>
<TT>Category: </TT><A href='?src=\ref[src];uploadcategory=1'>[upload_category]</A><BR>
<A href='?src=\ref[src];upload=1'>\[Upload\]</A><BR>"}
dat += "<A href='?src=\ref[src];switchscreen=0'>(Return to main menu)</A><BR>"
if(7)
dat += "<H3>Print a Manual</H3>"
dat += "<table>"
var/list/forbidden = list(
/obj/item/weapon/book/manual
)
if(!emagged)
forbidden |= /obj/item/weapon/book/manual/nuclear
var/manualcount = 1
var/obj/item/weapon/book/manual/M = null
for(var/manual_type in (typesof(/obj/item/weapon/book/manual) - forbidden))
M = new manual_type()
dat += "<tr><td><A href='?src=\ref[src];manual=[manualcount]'>[M.title]</A></td></tr>"
manualcount++
qdel(M)
M = null
dat += "</table>"
dat += "<BR><A href='?src=\ref[src];switchscreen=0'>(Return to main menu)</A><BR>"
if(8)
dat += {"<h3>Accessing Forbidden Lore Vault v 1.3</h3>
Are you absolutely sure you want to proceed? EldritchTomes Inc. takes no responsibilities for loss of sanity resulting from this action.<p>
<A href='?src=\ref[src];arccheckout=1'>Yes.</A><BR>
<A href='?src=\ref[src];switchscreen=0'>No.</A><BR>"}
var/datum/browser/B = new /datum/browser(user, "library", "Book Inventory Management")
B.set_content(dat)
B.open()
/obj/machinery/computer/library/checkout/emag_act(mob/user)
if(density && !emagged)
emagged = 1
to_chat(user, "<span class='notice'>You override the library computer's printing restrictions.</span>")
/obj/machinery/computer/library/checkout/attackby(obj/item/weapon/W as obj, mob/user as mob)
if(istype(W, /obj/item/weapon/barcodescanner))
var/obj/item/weapon/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.", 2)
return 1
else
return ..()
/obj/machinery/computer/library/checkout/Topic(href, href_list)
if(..())
usr << browse(null, "window=library")
onclose(usr, "library")
return 1
if(href_list["pagenum"])
if(!num_pages)
page_num = 1
else
var/pn = text2num(href_list["pagenum"])
if(!isnull(pn))
page_num = Clamp(pn, 1, num_pages)
if(href_list["page"])
if(num_pages == 0)
page_num = 1
else
page_num = Clamp(text2num(href_list["page"]), 1, num_pages)
if(href_list["settitle"])
var/newtitle = input("Enter a title to search for:") as text|null
if(newtitle)
query.title = sanitize(newtitle)
else
query.title = null
if(href_list["setcategory"])
var/newcategory = input("Choose a category to search for:") in (list("Any") + library_section_names)
if(newcategory == "Any")
query.category = null
else if(newcategory)
query.category = sanitize(newcategory)
if(href_list["setauthor"])
var/newauthor = input("Enter an author to search for:") as text|null
if(newauthor)
query.author = sanitize(newauthor)
else
query.author = null
if(href_list["search"])
num_results = src.get_num_results()
num_pages = Ceiling(num_results/LIBRARY_BOOKS_PER_PAGE)
page_num = 1
screenstate = 4
if(href_list["del"])
if(!check_rights(R_ADMIN))
to_chat(usr, "You aren't an admin, piss off.")
return
var/datum/cachedbook/target = getBookByID(href_list["del"]) // Sanitized in getBookByID
var/ans = alert(usr, "Are you sure you wish to delete \"[target.title]\", by [target.author]? This cannot be undone.", "Library System", "Yes", "No")
if(ans=="Yes")
var/DBQuery/query = dbcon.NewQuery("DELETE FROM [format_table_name("library")] WHERE id=[target.id]")
var/response = query.Execute()
if(!response)
to_chat(usr, query.ErrorMsg())
return
log_admin("LIBRARY: [usr.name]/[usr.key] has deleted \"[target.title]\", by [target.author] ([target.ckey])!")
message_admins("[key_name_admin(usr)] has deleted \"[target.title]\", by [target.author] ([target.ckey])!")
src.updateUsrDialog()
return
if(href_list["delbyckey"])
if(!check_rights(R_ADMIN))
to_chat(usr, "You aren't an admin, piss off.")
return
var/tckey = ckey(href_list["delbyckey"])
var/ans = alert(usr,"Are you sure you wish to delete all books by [tckey]? This cannot be undone.", "Library System", "Yes", "No")
if(ans=="Yes")
var/DBQuery/query = dbcon.NewQuery("DELETE FROM [format_table_name("library")] WHERE ckey='[sanitizeSQL(tckey)]'")
var/response = query.Execute()
if(!response)
to_chat(usr, query.ErrorMsg())
return
var/affected=query.RowsAffected()
if(affected==0)
to_chat(usr, "<span class='danger'>Unable to find any matching rows.</span>")
return
log_admin("LIBRARY: [usr.name]/[usr.key] has deleted [affected] books written by [tckey]!")
message_admins("[key_name_admin(usr)] has deleted [affected] books written by [tckey]!")
src.updateUsrDialog()
return
if(href_list["flag"])
if(!dbcon.IsConnected())
alert("Connection to Archive has been severed. Aborting.")
return
var/id = href_list["flag"]
if(id)
var/datum/cachedbook/B = getBookByID(id)
if(B)
if((input(usr, "Are you sure you want to flag [B.title] as having inappropriate content?", "Flag Book #[B.id]") in list("Yes", "No")) == "Yes")
library_catalog.flag_book_by_id(usr, id)
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")
if(!bibledelay)
var/obj/item/weapon/storage/bible/B = new /obj/item/weapon/storage/bible(src.loc)
if(ticker && ( ticker.Bible_icon_state && ticker.Bible_item_state) )
B.icon_state = ticker.Bible_icon_state
B.item_state = ticker.Bible_item_state
B.name = ticker.Bible_name
B.deity_name = ticker.Bible_deity_name
bibledelay = 1
spawn(60)
bibledelay = 0
else
visible_message("<b>[src]</b>'s monitor flashes, \"Bible printer currently unavailable, please wait a moment.\"")
if("7")
screenstate = 7
if("8")
screenstate = 8
if(href_list["arccheckout"])
if(src.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"])
checkouts.Remove(b)
if(href_list["delbook"])
var/obj/item/weapon/book/b = locate(href_list["delbook"])
inventory.Remove(b)
if(href_list["uploadauthor"])
var/newauthor = copytext(sanitize(input("Enter the author's name: ") as text|null),1,MAX_MESSAGE_LEN)
if(newauthor && scanner)
scanner.cache.author = newauthor
if(href_list["uploadcategory"])
var/newcategory = input("Choose a category: ") in list("Fiction", "Non-Fiction", "Adult", "Reference", "Religion")
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")
establish_db_connection()
if(!dbcon.IsConnected())
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/DBQuery/query = dbcon.NewQuery("INSERT INTO [format_table_name("library")] (author, title, content, category, ckey, flagged) VALUES ('[sqlauthor]', '[sqltitle]', '[sqlcontent]', '[sqlcategory]', '[ckey(usr.key)]', 0)")
var/response = query.Execute()
if(!response)
to_chat(usr, query.ErrorMsg())
else
log_admin("[usr.name]/[usr.key] has uploaded the book titled [scanner.cache.name], [length(scanner.cache.dat)] characters in length")
message_admins("[key_name_admin(usr)] has uploaded the book titled [scanner.cache.name], [length(scanner.cache.dat)] characters in length")
if(href_list["id"])
if(href_list["id"]=="-1")
href_list["id"] = input("Enter your order:") as null|num
if(!href_list["id"])
return
if(!dbcon.IsConnected())
alert("Connection to Archive has been severed. Aborting.")
return
var/datum/cachedbook/newbook = getBookByID(href_list["id"]) // Sanitized in getBookByID
if(!newbook)
alert("No book found")
return
if((newbook.forbidden == 2 && !emagged) || newbook.forbidden == 1)
alert("This book is forbidden and cannot be printed.")
return
if(bibledelay)
audible_message("<b>[src]</b>'s monitor flashes, \"Printer unavailable. Please allow a short time before attempting to print.\"")
else
bibledelay = 1
spawn(60)
bibledelay = 0
make_external_book(newbook)
if(href_list["manual"])
if(!href_list["manual"]) return
var/bookid = href_list["manual"]
if(!dbcon.IsConnected())
alert("Connection to Archive has been severed. Aborting.")
return
var/datum/cachedbook/newbook = getBookByID("M[bookid]")
if(!newbook)
alert("No book found")
return
if((newbook.forbidden == 2 && !emagged) || newbook.forbidden == 1)
alert("This book is forbidden and cannot be printed.")
return
if(bibledelay)
for (var/mob/V in hearers(src))
V.show_message("<b>[src]</b>'s monitor flashes, \"Printer unavailable. Please allow a short time before attempting to print.\"")
else
bibledelay = 1
spawn(60)
bibledelay = 0
make_external_book(newbook)
src.add_fingerprint(usr)
src.updateUsrDialog()
return
/*
* Library Scanner
*/
/obj/machinery/computer/library/checkout/proc/make_external_book(var/datum/cachedbook/newbook)
if(!newbook || !newbook.id)
return
var/obj/item/weapon/book/B = new newbook.path(loc)
if (!newbook.programmatic)
B.name = "Book: [newbook.title]"
B.title = newbook.title
B.author = newbook.author
B.dat = newbook.content
B.icon_state = "book[rand(1,9)]"
visible_message("[src]'s printer hums as it produces a completely bound book. How did it do that?")
+122
View File
@@ -0,0 +1,122 @@
/obj/machinery/computer/library/public
name = "visitor computer"
/obj/machinery/computer/library/public/attack_hand(var/mob/user as mob)
if(..())
return
interact(user)
/obj/machinery/computer/library/public/interact(var/mob/user)
if(interact_check(user))
return
var/dat = ""
switch(screenstate)
if(0)
dat += {"<h2>Search Settings</h2><br />
<A href='?src=\ref[src];settitle=1'>Filter by Title: [query.title]</A><br />
<A href='?src=\ref[src];setcategory=1'>Filter by Category: [query.category]</A><br />
<A href='?src=\ref[src];setauthor=1'>Filter by Author: [query.author]</A><br />
<A href='?src=\ref[src];search=1'>\[Start Search\]</A><br />"}
if(1)
establish_db_connection()
if(!dbcon.IsConnected())
dat += "<font color=red><b>ERROR</b>: Unable to contact External Archive. Please contact your system administrator for assistance.</font><br />"
else if(num_results == 0)
dat += "<em>No results found.</em>"
else
var/pagelist = get_pagelist()
dat += pagelist
dat += {"<form name='pagenum' action='?src=\ref[src]' method='get'>
<input type='hidden' name='src' value='\ref[src]'>
<input type='text' name='pagenum' value='[page_num]' maxlength="5" size="5">
<input type='submit' value='Jump To Page'>
</form>"}
dat += {"<table border=\"0\">
<tr>
<td>Author</td>
<td>Title</td>
<td>Category</td>
<td>SS<sup>13</sup>BN</td>
<td>Controls</td>
</tr>"}
for(var/datum/cachedbook/CB in get_page(page_num))
dat += {"<tr>
<td>[CB.author]</td>
<td>[CB.title]</td>
<td>[CB.category]</td>
<td>[CB.id]</td>
<td><A href="?src=\ref[src];flag=[CB.id]">\[Flag[CB.flagged ? "ged" : ""]\]</A></td>
</tr>"}
dat += "</table><br />[pagelist]"
dat += "<A href='?src=\ref[src];back=1'>\[Go Back\]</A><br />"
var/datum/browser/B = new /datum/browser(user, "library", "Library Visitor")
B.set_content(dat)
B.open()
/obj/machinery/computer/library/public/Topic(href, href_list)
if(..())
usr << browse(null, "window=publiclibrary")
onclose(usr, "publiclibrary")
return
if(href_list["pagenum"])
if(!num_pages)
page_num = 1
else
var/pn = text2num(href_list["pagenum"])
if(!isnull(pn))
page_num = Clamp(pn, 1, num_pages)
if(href_list["settitle"])
var/newtitle = input("Enter a title to search for:") as text|null
if(newtitle)
query.title = sanitize(newtitle)
else
query.title = null
if(href_list["setcategory"])
var/newcategory = input("Choose a category to search for:") in (list("Any") + library_section_names)
if(newcategory == "Any")
query.category = null
else if(newcategory)
query.category = sanitize(newcategory)
if(href_list["setauthor"])
var/newauthor = input("Enter an author to search for:") as text|null
if(newauthor)
query.author = sanitize(newauthor)
else
query.author = null
if(href_list["page"])
if(num_pages == 0)
page_num = 1
else
page_num = Clamp(text2num(href_list["page"]), 1, num_pages)
if(href_list["search"])
num_results = src.get_num_results()
num_pages = Ceiling(num_results/LIBRARY_BOOKS_PER_PAGE)
page_num = 1
screenstate = 1
if(href_list["back"])
screenstate = 0
if(href_list["flag"])
if(!dbcon.IsConnected())
alert("Connection to Archive has been severed. Aborting.")
return
var/id = href_list["flag"]
if(id)
var/datum/cachedbook/B = getBookByID(id)
if(B)
if((input(usr, "Are you sure you want to flag [B.title] as having inappropriate content?", "Flag Book #[B.id]") in list("Yes", "No")) == "Yes")
library_catalog.flag_book_by_id(usr, id)
add_fingerprint(usr)
updateUsrDialog()
return
+75 -55
View File
@@ -19,86 +19,103 @@
density = 1
opacity = 1
var/health = 50
var/tmp/busy = 0
var/list/valid_types = list(/obj/item/weapon/book, \
/obj/item/weapon/tome, \
/obj/item/weapon/spellbook, \
/obj/item/weapon/storage/bible)
/obj/structure/bookcase/initialize()
for(var/obj/item/I in loc)
if(istype(I, /obj/item/weapon/book))
I.loc = src
if(is_type_in_list(I, valid_types))
I.forceMove(src)
update_icon()
/obj/structure/bookcase/attackby(obj/O as obj, mob/user as mob, params)
if(istype(O, /obj/item/weapon/book) || istype(O, /obj/item/weapon/spellbook))
if(busy) //So that you can't mess with it while deconstructing
return 1
if(is_type_in_list(O, valid_types))
user.drop_item()
O.loc = src
O.forceMove(src)
update_icon()
return 1
else if(istype(O, /obj/item/weapon/wrench))
to_chat(user, "\blue Now disassembling bookcase")
user.visible_message("<span class='warning'>[user] starts disassembling \the [src].</span>", \
"<span class='notice'>You start disassembling \the [src].</span>")
playsound(get_turf(src), 'sound/items/Ratchet.ogg', 50, 1)
busy = 1
if(do_after(user,50, target = src))
new /obj/item/stack/sheet/wood(get_turf(src))
new /obj/item/stack/sheet/wood(get_turf(src))
new /obj/item/stack/sheet/wood(get_turf(src))
new /obj/item/stack/sheet/wood(get_turf(src))
new /obj/item/stack/sheet/wood(get_turf(src))
playsound(get_turf(src), 'sound/items/Deconstruct.ogg', 75, 1)
user.visible_message("<span class='warning'>[user] disassembles \the [src].</span>", \
"<span class='notice'>You disassemble \the [src].</span>")
busy = 0
for(var/i = 1 to 5)
new /obj/item/stack/sheet/wood(get_turf(src))
density = 0
qdel(src)
return
else if(istype(O, /obj/item/weapon/pen))
var/newname = stripped_input(usr, "What would you like to title this bookshelf?")
if(!newname)
return
else
busy = 0
return 1
else if(istype(O, /obj/item/weapon/pen))
var/newname = stripped_input(user, "What would you like to title this [name]?")
if(newname)
name = ("bookcase ([sanitize(newname)])")
return 1
else
switch(O.damtype)
if("fire")
src.health -= O.force * 1
health -= O.force * 1
if("brute")
src.health -= O.force * 0.75
health -= O.force * 0.75
else
if (src.health <= 0)
if (health <= 0)
visible_message("<span class=warning>The bookcase is smashed apart!</span>")
new /obj/item/stack/sheet/wood(get_turf(src))
new /obj/item/stack/sheet/wood(get_turf(src))
new /obj/item/stack/sheet/wood(get_turf(src))
qdel(src)
..()
return ..()
/obj/structure/bookcase/attack_hand(var/mob/user as mob)
if(contents.len)
var/obj/item/weapon/book/choice = input("Which book would you like to remove from the shelf?") in contents as obj|null
var/obj/item/weapon/book/choice = input("Which book would you like to remove from \the [src]?") in contents as obj|null
if(choice)
if(!usr.canmove || usr.stat || usr.restrained() || !in_range(loc, usr))
if(user.incapacitated() || user.lying || !Adjacent(user))
return
if(ishuman(user))
if(!user.get_active_hand())
user.put_in_hands(choice)
if(!user.get_active_hand())
user.put_in_hands(choice)
else
choice.loc = get_turf(src)
choice.forceMove(get_turf(src))
update_icon()
/obj/structure/bookcase/ex_act(severity)
switch(severity)
if(1.0)
for(var/obj/item/weapon/book/b in contents)
qdel(b)
for(var/obj/item/I in contents)
qdel(I)
qdel(src)
return
if(2.0)
for(var/obj/item/weapon/book/b in contents)
if (prob(50)) b.loc = (get_turf(src))
else qdel(b)
for(var/obj/item/I in contents)
if(prob(50))
qdel(I)
qdel(src)
return
if(3.0)
if (prob(50))
for(var/obj/item/weapon/book/b in contents)
b.loc = (get_turf(src))
if(prob(50))
qdel(src)
return
else
return
/obj/structure/bookcase/Destroy()
for(var/i = 1 to 3)
new /obj/item/stack/sheet/wood(get_turf(src))
for(var/obj/item/I in contents)
if(is_type_in_list(I, valid_types))
I.forceMove(get_turf(src))
return ..()
/obj/structure/bookcase/update_icon()
if(contents.len < 5)
icon_state = "book-[contents.len]"
@@ -155,13 +172,14 @@
var/unique = 0 // 0 - Normal book, 1 - Should not be treated as normal book, unable to be copied, unable to be modified
var/title // The real name of the book.
var/carved = 0 // Has the book been hollowed out for use as a secret storage item?
var/obj/item/store //What's in the book?
var/forbidden = 0 // Prevent ordering of this book. (0=no, 1=yes, 2=emag only)
var/obj/item/store // What's in the book?
/obj/item/weapon/book/attack_self(var/mob/user as mob)
if(carved)
if(store)
to_chat(user, "<span class='notice'>[store] falls out of [title]!</span>")
store.loc = get_turf(src.loc)
store.forceMove(get_turf(loc))
store = null
return
else
@@ -169,7 +187,8 @@
return
if(src.dat)
user << browse("<TT><I>Penned by [author].</I></TT> <BR>" + "[dat]", "window=book")
user.visible_message("[user] opens a book titled \"[src.title]\" and begins reading intently.")
if(!isobserver(user))
user.visible_message("[user] opens a book titled \"[title]\" and begins reading intently.")
onclose(user, "book")
else
to_chat(user, "This book is completely blank!")
@@ -179,46 +198,45 @@
if(!store)
if(W.w_class < 3)
user.drop_item()
W.loc = src
W.forceMove(src)
store = W
to_chat(user, "<span class='notice'>You put [W] in [title].</span>")
return
return 1
else
to_chat(user, "<span class='notice'>[W] won't fit in [title].</span>")
return
return 1
else
to_chat(user, "<span class='notice'>There's already something in [title]!</span>")
return
return 1
if(istype(W, /obj/item/weapon/pen))
if(unique)
to_chat(user, "These pages don't seem to take the ink well. Looks like you can't modify it.")
return
return 1
var/choice = input("What would you like to change?") in list("Title", "Contents", "Author", "Cancel")
switch(choice)
if("Title")
var/newtitle = reject_bad_text(stripped_input(usr, "Write a new title:"))
if(!newtitle)
to_chat(usr, "The title is invalid.")
return
return 1
else
src.name = newtitle
src.title = newtitle
if("Contents")
var/content = strip_html(input(usr, "Write your book's contents (HTML NOT allowed):"),8192) as message|null
var/content = strip_html(input(usr, "Write your book's contents (HTML NOT allowed):"), MAX_BOOK_MESSAGE_LEN) as message|null
if(!content)
to_chat(usr, "The content is invalid.")
return
return 1
else
src.dat += content
if("Author")
var/newauthor = stripped_input(usr, "Write the author's name:")
if(!newauthor)
to_chat(usr, "The name is invalid.")
return
return 1
else
src.author = newauthor
else
return
return 1
else if(istype(W, /obj/item/weapon/barcodescanner))
var/obj/item/weapon/barcodescanner/scanner = W
if(!scanner.computer)
@@ -238,25 +256,27 @@
if(b.bookname == src.name)
scanner.computer.checkouts.Remove(b)
to_chat(user, "[W]'s screen flashes: 'Book stored in buffer. Book has been checked in.'")
return
return 1
to_chat(user, "[W]'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/weapon/book in scanner.computer.inventory)
if(book == src)
to_chat(user, "[W]'s screen flashes: 'Book stored in buffer. Title already present in inventory, aborting to avoid duplicate entry.'")
return
return 1
scanner.computer.inventory.Add(src)
to_chat(user, "[W]'s screen flashes: 'Book stored in buffer. Title added to general inventory.'")
else if(istype(W, /obj/item/weapon/kitchen/knife) || istype(W, /obj/item/weapon/wirecutters))
if(carved) return
return 1
else if(istype(W, /obj/item/weapon/kitchen/knife) || iswirecutter(W))
if(carved)
return 1
to_chat(user, "<span class='notice'>You begin to carve out [title].</span>")
if(do_after(user, 30, target = src))
to_chat(user, "<span class='notice'>You carve out the pages from [title]! You didn't want to read it anyway.</span>")
carved = 1
return
return 1
else
..()
return ..()
/*
@@ -269,7 +289,7 @@
throw_speed = 1
throw_range = 5
w_class = 1.0
var/obj/machinery/librarycomp/computer // Associated computer - Modes 1 to 3 use this
var/obj/machinery/computer/library/checkout/computer // Associated computer - Modes 1 to 3 use this
var/obj/item/weapon/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
+135 -410
View File
@@ -1,407 +1,146 @@
/* Library Machines
*
* Contains:
* Borrowbook datum
* Library Public Computer
* Library Computer
* Library Scanner
* Book Binder
*/
#define LIBRARY_BOOKS_PER_PAGE 25
var/global/datum/library_catalog/library_catalog = new()
var/global/list/library_section_names = list("Any", "Fiction", "Non-Fiction", "Adult", "Reference", "Religion")
/hook/startup/proc/load_manuals()
library_catalog.initialize()
return 1
/*
* Borrowbook datum
*/
datum/borrowbook // Datum used to keep track of who has borrowed what when and for how long.
/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
/*
* Library Public Computer
* Cachedbook datum
*/
/obj/machinery/librarypubliccomp
name = "visitor computer"
icon = 'icons/obj/library.dmi'
icon_state = "computer"
anchored = 1
density = 1
var/screenstate = 0
/datum/cachedbook // Datum used to cache the SQL DB books locally in order to achieve a performance gain.
var/id
var/title
var/category = "Any"
var/author
var/SQLquery
var/ckey // ADDED 24/2/2015 - N3X
var/category
var/content
var/programmatic=0 // Is the book programmatically added to the catalog?
var/forbidden=0
var/path = /obj/item/weapon/book // Type path of the book to generate
var/flagged = 0
/obj/machinery/librarypubliccomp/attack_hand(var/mob/user as mob)
usr.set_machine(src)
var/dat = "<HEAD><TITLE>Library Visitor</TITLE></HEAD><BODY>\n" // <META HTTP-EQUIV='Refresh' CONTENT='10'>
switch(screenstate)
if(0)
dat += {"<h2>Search Settings</h2><br>
<A href='?src=\ref[src];settitle=1'>Filter by Title: [title]</A><BR>
<A href='?src=\ref[src];setcategory=1'>Filter by Category: [category]</A><BR>"
<A href='?src=\ref[src];setauthor=1'>Filter by Author: [author]</A><BR>
<A href='?src=\ref[src];search=1'>\[Start Search\]</A><BR>"}
if(1)
if(!dbcon.IsConnected())
dat += "<font color=red><b>ERROR</b>: Unable to contact External Archive. Please contact your system administrator for assistance.</font><BR>"
else if(!SQLquery)
dat += "<font color=red><b>ERROR</b>: Malformed search request. Please contact your system administrator for assistance.</font><BR>"
else
dat += "<table>"
dat += "<tr><td>AUTHOR</td><td>TITLE</td><td>CATEGORY</td><td>SS<sup>13</sup>BN</td></tr>"
/datum/cachedbook/proc/LoadFromRow(var/list/row)
id = row["id"]
author = row["author"]
title = row["title"]
category = row["category"]
ckey = row["ckey"]
flagged = row["flagged"]
if("content" in row)
content = row["content"]
programmatic=0
var/DBQuery/query = dbcon.NewQuery(SQLquery)
query.Execute()
// Builds a SQL statement
/datum/library_query
var/author
var/category
var/title
while(query.NextRow())
var/author = query.item[1]
var/title = query.item[2]
var/category = query.item[3]
var/id = query.item[4]
dat += "<tr><td>[author]</td><td>[title]</td><td>[category]</td><td>[id]</td></tr>"
dat += "</table><BR>"
dat += "<A href='?src=\ref[src];back=1'>\[Go Back\]</A><BR>"
user << browse(dat, "window=publiclibrary")
onclose(user, "publiclibrary")
/datum/library_query/proc/toSQL()
var/list/where = list()
if(author || title || category)
if(author)
where.Add("author LIKE '%[sanitizeSQL(author)]%'")
if(category)
where.Add("category = '[sanitizeSQL(category)]'")
if(title)
where.Add("title LIKE '%[sanitizeSQL(title)]%'")
return " WHERE " + jointext(where, " AND ")
return ""
/obj/machinery/librarypubliccomp/Topic(href, href_list)
if(..())
usr << browse(null, "window=publiclibrary")
onclose(usr, "publiclibrary")
// So we can have catalogs of books that are programmatic, and ones that aren't.
/datum/library_catalog
var/list/cached_books = list()
/datum/library_catalog/proc/initialize()
var/newid=1
for(var/typepath in subtypesof(/obj/item/weapon/book/manual))
var/obj/item/weapon/book/B = new typepath(null)
var/datum/cachedbook/CB = new()
CB.forbidden = B.forbidden
CB.title = B.name
CB.author = B.author
CB.programmatic=1
CB.path=typepath
CB.id = "M[newid]"
newid++
cached_books["[CB.id]"]=CB
/datum/library_catalog/proc/flag_book_by_id(mob/user, id)
var/global/books_flagged_this_round[0]
if("[id]" in cached_books)
var/datum/cachedbook/CB = cached_books["[id]"]
if(CB.programmatic)
to_chat(user, "<span class='danger'>That book cannot be flagged in the system, as it does not actually exist in the database.</span>")
return
if("[id]" in books_flagged_this_round)
to_chat(user, "<span class='danger'>This book has already been flagged this shift.</span>")
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 "
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
books_flagged_this_round["[id]"] = 1
message_admins("[key_name_admin(user)] has flagged book #[id] as inappropriate.")
if(href_list["back"])
screenstate = 0
src.add_fingerprint(usr)
src.updateUsrDialog()
return
/*
* Library 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.
/obj/machinery/librarycomp
name = "check-in/out computer"
icon = 'icons/obj/library.dmi'
icon_state = "computer"
anchored = 1
density = 1
var/arcanecheckout = 0
var/screenstate = 0 // 0 - Main Menu, 1 - Inventory, 2 - Checked Out, 3 - Check Out a Book
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/bibledelay = 0 // LOL NO SPAM (1 minute delay) -- Doohl
/obj/machinery/librarycomp/attack_hand(var/mob/user as mob)
usr.set_machine(src)
var/dat = "<HEAD><TITLE>Book Inventory Management</TITLE></HEAD><BODY>\n" // <META HTTP-EQUIV='Refresh' CONTENT='10'>
switch(screenstate)
if(0)
// Main Menu
dat += {"<A href='?src=\ref[src];switchscreen=1'>1. View General Inventory</A><BR>
<A href='?src=\ref[src];switchscreen=2'>2. View Checked Out Inventory</A><BR>
<A href='?src=\ref[src];switchscreen=3'>3. Check out a Book</A><BR>
<A href='?src=\ref[src];switchscreen=4'>4. Connect to External Archive</A><BR>
<A href='?src=\ref[src];switchscreen=5'>5. Upload New Title to Archive</A><BR>
<A href='?src=\ref[src];switchscreen=6'>6. Print a Bible</A><BR>"}
if(src.emagged)
dat += "<A href='?src=\ref[src];switchscreen=7'>7. Access the Forbidden Lore Vault</A><BR>"
if(src.arcanecheckout)
new /obj/item/weapon/tome(src.loc)
to_chat(user, "<span class='warning'>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 dusty old tome sitting on the desk. You don't really remember printing it.</span>")
user.visible_message("[user] stares at the blank screen for a few moments, his expression frozen in fear. When he finally awakens from it, he looks a lot older.", 2)
src.arcanecheckout = 0
if(1)
// Inventory
dat += "<H3>Inventory</H3><BR>"
for(var/obj/item/weapon/book/b in inventory)
dat += "[b.name] <A href='?src=\ref[src];delbook=\ref[b]'>(Delete)</A><BR>"
dat += "<A href='?src=\ref[src];switchscreen=0'>(Return to main menu)</A><BR>"
if(2)
// Checked Out
dat += "<h3>Checked Out Books</h3><BR>"
for(var/datum/borrowbook/b in checkouts)
var/timetaken = world.time - b.getdate
//timetaken *= 10
timetaken /= 600
timetaken = round(timetaken)
var/timedue = b.duedate - world.time
//timedue *= 10
timedue /= 600
if(timedue <= 0)
timedue = "<font color=red><b>(OVERDUE)</b> [timedue]</font>"
else
timedue = round(timedue)
dat += "\"[b.bookname]\", Checked out to: [b.mobname]<BR>--- Taken: [timetaken] minutes ago, Due: in [timedue] minutes<BR>"
dat += "<A href='?src=\ref[src];checkin=\ref[b]'>(Check In)</A><BR><BR>"
dat += "<A href='?src=\ref[src];switchscreen=0'>(Return to main menu)</A><BR>"
if(3)
// Check Out a Book
dat += {"<h3>Check Out a Book</h3><BR>
Book: [src.buffer_book]
<A href='?src=\ref[src];editbook=1'>\[Edit\]</A><BR>
Recipient: [src.buffer_mob]
<A href='?src=\ref[src];editmob=1'>\[Edit\]</A><BR>
Checkout Date : [world.time/600]<BR>
Due Date: [(world.time + checkoutperiod)/600]<BR>
(Checkout Period: [checkoutperiod] minutes) (<A href='?src=\ref[src];increasetime=1'>+</A>/<A href='?src=\ref[src];decreasetime=1'>-</A>)
<A href='?src=\ref[src];checkout=1'>(Commit Entry)</A><BR>
<A href='?src=\ref[src];switchscreen=0'>(Return to main menu)</A><BR>"}
if(4)
dat += "<h3>External Archive</h3>"
if(!dbcon.IsConnected())
dat += "<font color=red><b>ERROR</b>: Unable to contact External Archive. Please contact your system administrator for assistance.</font>"
else
dat += "<A href='?src=\ref[src];orderbyid=1'>(Order book by SS<sup>13</sup>BN)</A><BR><BR>"
dat += "<table>"
dat += "<tr><td>AUTHOR</td><td>TITLE</td><td>CATEGORY</td><td>ID</td><td></td></tr>"
var/DBQuery/query = dbcon.NewQuery("SELECT id, author, title, category FROM [format_table_name("library")]")
if(!query.Execute())
var/err = query.ErrorMsg()
log_game("SQL ERROR accessing book. Error : \[[err]\]\n")
return
while(query.NextRow())
var/id = query.item[1]
var/author = query.item[2]
var/title = query.item[3]
var/category = query.item[4]
dat += "<tr><td>[author]</td><td>[title]</td><td>[category]</td><td>[id]</td><td><A href='?src=\ref[src];targetid=[id]'>\[Order\]</A></td></tr>"
dat += "</table>"
dat += "<BR><A href='?src=\ref[src];switchscreen=0'>(Return to main menu)</A><BR>"
if(5)
dat += "<H3>Upload a New Title</H3>"
if(!scanner)
for(var/obj/machinery/libraryscanner/S in range(9))
scanner = S
break
if(!scanner)
dat += "<FONT color=red>No scanner found within wireless network range.</FONT><BR>"
else if(!scanner.cache)
dat += "<FONT color=red>No data found in scanner memory.</FONT><BR>"
else
dat += "<TT>Data marked for upload...</TT><BR>"
dat += "<TT>Title: </TT>[scanner.cache.name]<BR>"
if(!scanner.cache.author)
scanner.cache.author = "Anonymous"
dat += "<TT>Author: </TT><A href='?src=\ref[src];setauthor=1'>[scanner.cache.author]</A><BR>"
dat += "<TT>Category: </TT><A href='?src=\ref[src];setcategory=1'>[upload_category]</A><BR>"
dat += "<A href='?src=\ref[src];upload=1'>\[Upload\]</A><BR>"
dat += "OOC Upload Rules: No erotica, No real world literature. Only IC guides, stories and accounts."
dat += "Failure to follow these simple rules will lead to bans."
dat += "<A href='?src=\ref[src];switchscreen=0'>(Return to main menu)</A><BR>"
if(7)
dat += "<h3>Accessing Forbidden Lore Vault v 1.3</h3>"
dat += "Are you absolutely sure you want to proceed? EldritchTomes Inc. takes no responsibilities for loss of sanity resulting from this action.<p>"
dat += "<A href='?src=\ref[src];arccheckout=1'>Yes.</A><BR>"
dat += "<A href='?src=\ref[src];switchscreen=0'>No.</A><BR>"
//dat += "<A HREF='?src=\ref[user];mach_close=library'>Close</A><br><br>"
user << browse(dat, "window=library")
onclose(user, "library")
/obj/machinery/librarycomp/attackby(obj/item/weapon/W as obj, mob/user as mob, params)
if(istype(W, /obj/item/weapon/barcodescanner))
var/obj/item/weapon/barcodescanner/scanner = W
scanner.computer = src
to_chat(user, "[scanner]'s associated machine has been set to [src].")
for (var/mob/V in hearers(src))
V.show_message("[src] lets out a low, short blip.", 2)
else
..()
/obj/machinery/librarycomp/emag_act(user as mob)
if (src.density)
src.emagged = 1
/obj/machinery/librarycomp/Topic(href, href_list)
if(..())
usr << browse(null, "window=library")
onclose(usr, "library")
var/sqlid = text2num(id)
if(!sqlid)
return
var/DBQuery/query = dbcon.NewQuery("UPDATE [format_table_name("library")] SET flagged = flagged + 1 WHERE id=[sqlid]")
query.Execute()
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")
if(!bibledelay)
/datum/library_catalog/proc/rmBookByID(mob/user, id)
if("[id]" in cached_books)
var/datum/cachedbook/CB = cached_books["[id]"]
if(CB.programmatic)
to_chat(user, "<span class='danger'>That book cannot be removed from the system, as it does not actually exist in the database.</span>")
return
playsound(loc, "sound/goonstation/machines/printer_dotmatrix.ogg", 50, 1)
var/obj/item/weapon/storage/bible/B = new /obj/item/weapon/storage/bible(src.loc)
if(ticker && ( ticker.Bible_icon_state && ticker.Bible_item_state) )
B.icon_state = ticker.Bible_icon_state
B.item_state = ticker.Bible_item_state
B.name = ticker.Bible_name
B.deity_name = ticker.Bible_deity_name
var/sqlid = text2num(id)
if(!sqlid)
return
var/DBQuery/query = dbcon.NewQuery("DELETE FROM [format_table_name("library")] WHERE id=[sqlid]")
query.Execute()
bibledelay = 1
spawn(60)
bibledelay = 0
/datum/library_catalog/proc/getBookByID(id)
if("[id]" in cached_books)
return cached_books["[id]"]
else
for (var/mob/V in hearers(src))
V.show_message("<b>[src]</b>'s monitor flashes, \"Bible printer currently unavailable, please wait a moment.\"")
var/sqlid = text2num(id)
if(!sqlid)
return
var/DBQuery/query = dbcon.NewQuery("SELECT id, author, title, category, ckey, flagged FROM [format_table_name("library")] WHERE id=[sqlid]")
query.Execute()
if("7")
screenstate = 7
if(href_list["arccheckout"])
if(src.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 = sanitize(copytext(input("Enter the book's title:") as text|null,1,MAX_MESSAGE_LEN))
if(href_list["editmob"])
buffer_mob = sanitize(copytext(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"])
checkouts.Remove(b)
if(href_list["delbook"])
var/obj/item/weapon/book/b = locate(href_list["delbook"])
inventory.Remove(b)
if(href_list["setauthor"])
var/newauthor = sanitize(copytext(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")
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(!dbcon.IsConnected())
alert("Connection to Archive has been severed. Aborting.")
else
/*
var/sqltitle = dbcon.Quote(scanner.cache.name)
var/sqlauthor = dbcon.Quote(scanner.cache.author)
var/sqlcontent = dbcon.Quote(scanner.cache.dat)
var/sqlcategory = dbcon.Quote(upload_category)
*/
var/sqltitle = sanitizeSQL(scanner.cache.name)
var/sqlauthor = sanitizeSQL(scanner.cache.author)
var/sqlcontent = sanitizeSQL(scanner.cache.dat)
var/sqlcategory = sanitizeSQL(upload_category)
var/DBQuery/query = dbcon.NewQuery("INSERT INTO [format_table_name("library")] (author, title, content, category, ckey) VALUES ('[sqlauthor]', '[sqltitle]', '[sqlcontent]', '[sqlcategory]', '[usr.key]')")
if(!query.Execute())
var/err = query.ErrorMsg()
log_game("SQL ERROR adding new book. Error : \[[err]\]\n")
return
else
log_game("[usr.name]/[usr.key] has uploaded the book titled [scanner.cache.name], [length(scanner.cache.dat)] signs")
message_admins("[key_name_admin(usr)] has uploaded the book titled [scanner.cache.name], [length(scanner.cache.dat)] signs")
alert("Upload Complete.")
var/list/results=list()
while(query.NextRow())
var/datum/cachedbook/CB = new()
CB.LoadFromRow(list(
"id" =query.item[1],
"author" =query.item[2],
"title" =query.item[3],
"category"=query.item[4],
"ckey" =query.item[5],
"flagged" =query.item[6]
))
results += CB
cached_books["[id]"]=CB
return CB
return results
if(href_list["targetid"])
var/sqlid = sanitizeSQL(href_list["targetid"])
if(!dbcon.IsConnected())
alert("Connection to Archive has been severed. Aborting.")
// reused working printing call from bible code.. needs testing ((Lazureus))
if(!bibledelay)
bibledelay = 1
spawn(60)
bibledelay = 0
var/DBQuery/query = dbcon.NewQuery("SELECT * FROM [format_table_name("library")] WHERE id=[sqlid]")
query.Execute()
while(query.NextRow())
var/author = query.item[2]
var/title = query.item[3]
var/content = query.item[4]
playsound(loc, "sound/goonstation/machines/printer_dotmatrix.ogg", 50, 1)
var/obj/item/weapon/book/B = new(src.loc)
B.name = "Book: [title]"
B.title = title
B.author = author
B.dat = content
B.icon_state = "book[rand(1,7)]"
src.visible_message("[src]'s printer hums as it produces a completely bound book. How did it do that?")
break
else
for (var/mob/V in hearers(src))
V.show_message("<b>[src]</b>'s monitor flashes, \"Printer unavailable. Please allow a short time before attempting to print.\"")
if(href_list["orderbyid"])
var/orderid = input("Enter your order:") as num|null
if(orderid)
if(isnum(orderid))
var/nhref = "src=\ref[src];targetid=[orderid]"
spawn() src.Topic(nhref, params2list(nhref), src)
src.add_fingerprint(usr)
src.updateUsrDialog()
return
/*
* Library Scanner
*/
/** Scanner **/
/obj/machinery/libraryscanner
name = "scanner"
icon = 'icons/obj/library.dmi'
@@ -410,12 +149,18 @@ datum/borrowbook // Datum used to keep track of who has borrowed what when and f
density = 1
var/obj/item/weapon/book/cache // Last scanned book
/obj/machinery/libraryscanner/attackby(var/obj/O as obj, var/mob/user as mob, params)
if(istype(O, /obj/item/weapon/book))
/obj/machinery/libraryscanner/attackby(obj/item/I, mob/user)
if(istype(I, /obj/item/weapon/book))
user.drop_item()
O.loc = src
I.forceMove(src)
return 1
else
return ..()
/obj/machinery/libraryscanner/attack_hand(var/mob/user as mob)
/obj/machinery/libraryscanner/attack_hand(mob/user)
if(istype(user,/mob/dead))
to_chat(user, "<span class='danger'>Nope.</span>")
return
usr.set_machine(src)
var/dat = "<HEAD><TITLE>Scanner Control Interface</TITLE></HEAD><BODY>\n" // <META HTTP-EQUIV='Refresh' CONTENT='10'>
if(cache)
@@ -460,39 +205,19 @@ datum/borrowbook // Datum used to keep track of who has borrowed what when and f
anchored = 1
density = 1
/obj/machinery/bookbinder/attackby(var/obj/O as obj, var/mob/user as mob, params)
if(istype(O, /obj/item/weapon/paper))
/obj/machinery/bookbinder/attackby(obj/item/I, mob/user)
var/obj/item/weapon/paper/P = I
if(istype(P))
user.drop_item()
O.loc = src
user.visible_message("[user] loads some paper into [src].", "You load some paper into [src].")
src.visible_message("[src] begins to hum as it warms up its printing drums.")
sleep(rand(200,400))
src.visible_message("[src] whirs as it prints and binds a new book.")
var/obj/item/weapon/book/b = new(src.loc)
b.dat = O:info
b.name = "Print Job #" + "[rand(100, 999)]"
var/obj/item/weapon/book/b = new(loc)
b.dat = P.info
b.name = "Print Job #[rand(100, 999)]"
b.icon_state = "book[rand(1,7)]"
qdel(O)
qdel(P)
return 1
else
..()
/client/proc/delbook()
set name = "Delete Book"
set desc = "Permamently deletes a book from the database."
set category = "Admin"
if(!src.holder)
to_chat(src, "Only administrators may use this command.")
return
var/isbn = input("ISBN number?", "Delete Book") as num | null
if(!isbn)
return
var/DBQuery/query_delbook = dbcon.NewQuery("DELETE FROM [format_table_name("library")] WHERE id=[isbn]")
if(!query_delbook.Execute())
var/err = query_delbook.ErrorMsg()
log_game("SQL ERROR deleting book. Error : \[[err]\]\n")
return
log_admin("[key_name(usr)] has deleted the book [isbn].")
message_admins("[key_name_admin(usr)] has deleted the book [isbn].")
return ..()