mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-19 06:03:14 +00:00
* You can do more things while floored (#81641) ## About The Pull Request While on the floor, you can: - Use the UIs of Atmos machinery (except thermomachine and bluespace gas vendor), Holopads, Crayons (spray cans too), radios, and Disposal bins - Close extinguisher cabinets with Right-Click - Click and drag yourself onto a photocopier to climb onto it. I also changed all instances of ``ui_status`` to have all the args it's being passed, I was messing with it a bit but it's gonna be for a later PR. ## Why It's Good For The Game It's an extra layer of harmless realism, also nice QoL for people who do not have functional legs and do not have a wheelchair. ## Changelog 🆑 qol: You can use atmos machines, holopads, crayons, spray cans, and disposal bins while floored. fix: You can close extinguisher cabinets while floored. fix: You can climb onto a photocopier from the floor. /🆑 * You can do more things while floored --------- Co-authored-by: John Willard <53777086+JohnFulpWillard@users.noreply.github.com>
368 lines
13 KiB
Plaintext
368 lines
13 KiB
Plaintext
#define BOOK_ADMIN_DELETE "deleted"
|
|
#define BOOK_ADMIN_RESTORE "undeleted"
|
|
#define BOOK_ADMIN_REPORT "reported"
|
|
|
|
/obj/machinery/computer/libraryconsole/admin_only_do_not_map_in_you_fucker
|
|
interface_type = "LibraryAdmin"
|
|
/// When a user clicks view, do we display the raw text, or process it with markdown
|
|
var/view_raw = FALSE
|
|
/// If we should show deleted entries or not
|
|
var/show_deleted = TRUE
|
|
/// The current ckey we're looking for
|
|
var/ckey = ""
|
|
/// List mapping requested book ids to a list of their edit logs
|
|
var/list/book_history = list()
|
|
|
|
|
|
/obj/machinery/computer/libraryconsole/admin_only_do_not_map_in_you_fucker/can_db_request()
|
|
if(sending_request)
|
|
return FALSE
|
|
return TRUE
|
|
|
|
/obj/machinery/computer/libraryconsole/admin_only_do_not_map_in_you_fucker/hash_search_info()
|
|
. = ..()
|
|
return "[.]-[ckey]-[show_deleted]"
|
|
|
|
/obj/machinery/computer/libraryconsole/admin_only_do_not_map_in_you_fucker/update_page_contents()
|
|
if(sending_request) //Final defense against nerds spamming db requests
|
|
return
|
|
sending_request = TRUE
|
|
search_page = clamp(search_page, 0, page_count)
|
|
var/datum/db_query/query_library_list_books = SSdbcore.NewQuery({"
|
|
SELECT id, author, title, category, ckey, deleted
|
|
FROM [format_table_name("library")]
|
|
[show_deleted ? "" : "WHERE deleted IS NULL"]
|
|
[show_deleted ? "WHERE" : "AND"] author LIKE CONCAT('%',:author,'%')
|
|
AND title LIKE CONCAT('%',:title,'%')
|
|
AND (:category = 'Any' OR category = :category)
|
|
[book_id ? "AND id LIKE CONCAT('%', :book_id, '%')" : ""]
|
|
AND ckey LIKE CONCAT('%',:ckey,'%')
|
|
ORDER BY id DESC
|
|
LIMIT :skip, :take
|
|
"}, list("author" = author, "title" = title, "book_id" = book_id, "category" = category, "ckey" = ckey, "skip" = BOOKS_PER_PAGE * search_page, "take" = BOOKS_PER_PAGE))
|
|
|
|
var/query_succeeded = query_library_list_books.Execute()
|
|
sending_request = FALSE
|
|
page_content.Cut()
|
|
if(!query_succeeded)
|
|
qdel(query_library_list_books)
|
|
return
|
|
while(query_library_list_books.NextRow())
|
|
page_content += list(list(
|
|
"id" = query_library_list_books.item[1],
|
|
"author" = html_decode(query_library_list_books.item[2]),
|
|
"title" = html_decode(query_library_list_books.item[3]),
|
|
"category" = query_library_list_books.item[4],
|
|
"author_ckey" = query_library_list_books.item[5],
|
|
"deleted" = query_library_list_books.item[6],
|
|
))
|
|
qdel(query_library_list_books)
|
|
|
|
/obj/machinery/computer/libraryconsole/admin_only_do_not_map_in_you_fucker/update_page_count()
|
|
var/bookcount = 0
|
|
var/datum/db_query/query_library_count_books = SSdbcore.NewQuery({"
|
|
SELECT COUNT(id) FROM [format_table_name("library")]
|
|
[show_deleted ? "" : "WHERE deleted IS NULL"]
|
|
[show_deleted ? "WHERE" : "AND"] author LIKE CONCAT('%',:author,'%')
|
|
AND title LIKE CONCAT('%',:title,'%')
|
|
AND (:category = 'Any' OR category = :category)
|
|
[book_id ? "AND id LIKE CONCAT('%', :book_id, '%')" : ""]
|
|
AND ckey LIKE CONCAT('%',:ckey,'%')
|
|
"}, list("author" = author, "title" = title, "book_id" = book_id, "category" = category, "ckey" = ckey))
|
|
|
|
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)
|
|
|
|
page_count = round(max(bookcount - 1, 0) / BOOKS_PER_PAGE) //This is just floor()
|
|
search_page = clamp(search_page, 0, page_count)
|
|
|
|
/obj/machinery/computer/libraryconsole/admin_only_do_not_map_in_you_fucker/ui_status(mob/user, datum/ui_state/state)
|
|
if(!check_rights_for(user.client, R_BAN))
|
|
return UI_CLOSE
|
|
if(!SSdbcore.Connect())
|
|
can_connect = FALSE
|
|
return UI_CLOSE
|
|
return UI_INTERACTIVE
|
|
|
|
/obj/machinery/computer/libraryconsole/admin_only_do_not_map_in_you_fucker/ui_act(action, params, datum/tgui/ui)
|
|
. = ..()
|
|
if(.)
|
|
// We'll always trigger a search attempt if the parent does something, this ensures the ui is v fast to update
|
|
INVOKE_ASYNC(src, PROC_REF(update_db_info))
|
|
return
|
|
switch(action)
|
|
if("set_search_ckey")
|
|
ckey = params["ckey"]
|
|
INVOKE_ASYNC(src, PROC_REF(update_db_info))
|
|
return TRUE
|
|
if("refresh")
|
|
last_search_hash = ""
|
|
INVOKE_ASYNC(src, PROC_REF(update_db_info))
|
|
return TRUE
|
|
if("hide_book")
|
|
var/reason = params["delete_reason"]
|
|
var/id = params["book_id"]
|
|
var/client/actor = ui.user?.client
|
|
if(!actor)
|
|
return
|
|
INVOKE_ASYNC(src, PROC_REF(hide_book), id, reason, actor)
|
|
return TRUE
|
|
if("unhide_book")
|
|
var/reason = params["free_reason"]
|
|
var/id = params["book_id"]
|
|
var/client/actor = ui.user?.client
|
|
if(!actor)
|
|
return
|
|
INVOKE_ASYNC(src, PROC_REF(unhide_book), id, reason, actor)
|
|
return TRUE
|
|
if("get_history")
|
|
var/id = params["book_id"]
|
|
book_history["[id]"] = get_book_history(id)
|
|
return TRUE
|
|
if("view_book")
|
|
var/id = params["book_id"]
|
|
view_book(id, ui.user)
|
|
return TRUE
|
|
if("toggle_raw")
|
|
view_raw = !view_raw
|
|
return TRUE
|
|
if("toggle_deleted")
|
|
show_deleted = !show_deleted
|
|
INVOKE_ASYNC(src, PROC_REF(update_db_info))
|
|
return TRUE
|
|
|
|
/obj/machinery/computer/libraryconsole/admin_only_do_not_map_in_you_fucker/ui_data(mob/user)
|
|
. = ..()
|
|
.["view_raw"] = view_raw
|
|
.["show_deleted"] = show_deleted
|
|
var/list/histories = list()
|
|
for(var/id as anything in book_history)
|
|
var/list/insert = list()
|
|
for(var/datum/book_history_entry/entry in book_history[id])
|
|
insert += list(entry.serialize())
|
|
histories[id] = insert
|
|
.["history"] = histories
|
|
|
|
/obj/machinery/computer/libraryconsole/admin_only_do_not_map_in_you_fucker/proc/view_book(id, mob/show_to)
|
|
if (!SSdbcore.Connect())
|
|
can_connect = FALSE
|
|
message_admins("Failed to establish database connection.")
|
|
return
|
|
|
|
var/datum/db_query/query_library_view = SSdbcore.NewQuery(
|
|
"SELECT * FROM [format_table_name("library")] WHERE id=:id",
|
|
list("id" = id)
|
|
)
|
|
if(!query_library_view.Execute())
|
|
qdel(query_library_view)
|
|
return
|
|
|
|
while(query_library_view.NextRow())
|
|
var/datum/admin_book_viewer/viewer = new()
|
|
viewer.set_owner(src)
|
|
viewer.id = query_library_view.item[1]
|
|
viewer.author = query_library_view.item[2]
|
|
viewer.title = query_library_view.item[3]
|
|
viewer.content = query_library_view.item[4]
|
|
viewer.category = query_library_view.item[5]
|
|
viewer.author_ckey = query_library_view.item[6]
|
|
viewer.creation_time = query_library_view.item[7]
|
|
viewer.deleted = query_library_view.item[8]
|
|
viewer.creation_round = query_library_view.item[9]
|
|
viewer.history = get_book_history(id)
|
|
viewer.ui_interact(show_to)
|
|
break
|
|
qdel(query_library_view)
|
|
|
|
/obj/machinery/computer/libraryconsole/admin_only_do_not_map_in_you_fucker/proc/get_book_history(id)
|
|
var/datum/db_query/query_book_history = SSdbcore.NewQuery({"
|
|
SELECT id, book, reason, ckey, datetime, action, INET_NTOA(ip_addr)
|
|
FROM [format_table_name("library_action")] WHERE book=:id
|
|
"},
|
|
list("id" = id)
|
|
)
|
|
if(!query_book_history.Execute())
|
|
qdel(query_book_history)
|
|
return list()
|
|
|
|
var/list/full_history = list()
|
|
while(query_book_history.NextRow())
|
|
var/datum/book_history_entry/history = new()
|
|
history.id = query_book_history.item[1]
|
|
history.book = query_book_history.item[2]
|
|
history.reason = query_book_history.item[3]
|
|
history.ckey = query_book_history.item[4]
|
|
history.datetime = query_book_history.item[5]
|
|
history.action = query_book_history.item[6]
|
|
history.ip_addr = query_book_history.item[7]
|
|
full_history += history
|
|
qdel(query_book_history)
|
|
return full_history
|
|
|
|
/obj/machinery/computer/libraryconsole/admin_only_do_not_map_in_you_fucker/proc/hide_book(id, reason, client/admin)
|
|
if(!SSdbcore.Connect())
|
|
can_connect = FALSE
|
|
to_chat(admin, span_danger("Failed to establish database connection."))
|
|
return
|
|
if(!check_rights_for(admin, R_BAN))
|
|
log_admin_private("[admin.ckey] tried to hide a book without the required perms")
|
|
message_admins("[admin.ckey] tried to hide a book without the required perms")
|
|
return
|
|
|
|
var/datum/db_query/query_hide_book = SSdbcore.NewQuery({"
|
|
UPDATE [format_table_name("library")]
|
|
SET deleted = 1
|
|
WHERE id = :id
|
|
"}, list("id" = id))
|
|
if(!query_hide_book.warn_execute())
|
|
qdel(query_hide_book)
|
|
return
|
|
qdel(query_hide_book)
|
|
|
|
|
|
var/datum/db_query/query_update_log = SSdbcore.NewQuery({"
|
|
INSERT INTO [format_table_name("library_action")] (book, reason, ckey, datetime, action, ip_addr)
|
|
VALUES (:book, :reason, :ckey, Now(), :action, INET_ATON(:ip_addr))
|
|
"}, list("book" = id, "reason" = reason, "ckey" = admin.ckey, "action" = BOOK_ADMIN_DELETE, "ip_addr" = admin.address))
|
|
if(!query_update_log.warn_execute())
|
|
qdel(query_update_log)
|
|
return
|
|
qdel(query_update_log)
|
|
|
|
var/log_reason = "([admin.ckey]) hid book #[id][reason ? ": \"[reason]\"" : ""]"
|
|
log_admin_private(log_reason)
|
|
library_updated()
|
|
update_db_info()
|
|
|
|
/obj/machinery/computer/libraryconsole/admin_only_do_not_map_in_you_fucker/proc/unhide_book(id, reason, client/admin)
|
|
if(!SSdbcore.Connect())
|
|
can_connect = FALSE
|
|
to_chat(admin, span_danger("Failed to establish database connection."))
|
|
return
|
|
if(!check_rights_for(admin, R_BAN))
|
|
log_admin_private("[admin.ckey] tried to unhide a book without the required perms")
|
|
message_admins("[admin.ckey] tried to unhide a book without the required perms")
|
|
return
|
|
|
|
var/datum/db_query/query_unhide_book = SSdbcore.NewQuery({"
|
|
UPDATE [format_table_name("library")]
|
|
SET deleted = NULL
|
|
WHERE id = :id
|
|
"}, list("id" = id))
|
|
|
|
if(!query_unhide_book.warn_execute())
|
|
qdel(query_unhide_book)
|
|
return
|
|
qdel(query_unhide_book)
|
|
|
|
var/datum/db_query/query_update_log = SSdbcore.NewQuery({"
|
|
INSERT INTO [format_table_name("library_action")] (book, reason, ckey, datetime, action, ip_addr)
|
|
VALUES (:book, :reason, :ckey, Now(), :action, INET_ATON(:ip_addr))
|
|
"}, list("book" = id, "reason" = reason, "ckey" = admin.ckey, "action" = BOOK_ADMIN_RESTORE, "ip_addr" = admin.address))
|
|
if(!query_update_log.warn_execute())
|
|
qdel(query_update_log)
|
|
return
|
|
qdel(query_update_log)
|
|
|
|
log_admin_private("([admin.ckey]) unhid book #[id]")
|
|
library_updated()
|
|
update_db_info()
|
|
|
|
/// This mostly exists to document the form of the library_action table, since it doesn't do that good a job on its own
|
|
/datum/book_history_entry
|
|
/// The id of this logged action
|
|
var/id
|
|
/// The book id this log applies to
|
|
var/book
|
|
/// The reason this action was enacted
|
|
var/reason
|
|
/// The admin who performed the action
|
|
var/ckey
|
|
/// The time of the action being performed
|
|
var/datetime
|
|
/// The action that occured (BOOK_ADMIN_DELETE, BOOK_ADMIN_RESTORE, and legacy BOOK_ADMIN_REPORT)
|
|
var/action
|
|
/// The ip address of the admin who performed the action
|
|
var/ip_addr
|
|
|
|
/datum/book_history_entry/proc/serialize()
|
|
var/list/data = list()
|
|
data["id"] = id
|
|
data["book"] = book
|
|
data["reason"] = reason
|
|
data["ckey"] = ckey
|
|
data["datetime"] = datetime
|
|
data["action"] = action
|
|
data["address"] = ip_addr
|
|
return data
|
|
|
|
/// Weaps around a book's sql data, feeds it into a ui that allows us to at base view the contents of the book
|
|
/datum/admin_book_viewer
|
|
/// Weakref to the /obj/machinery/computer/libraryconsole/admin_only_do_not_map_in_you_fucker that spawned us
|
|
var/datum/weakref/owner_ref
|
|
/// If we're displaying raw data or rendered markdown
|
|
var/view_raw = FALSE
|
|
/// The book id. Incremental, goes up over time
|
|
var/id
|
|
/// The display name for the book, taken from the player's character
|
|
var/author
|
|
/// Title of the book
|
|
var/title
|
|
/// The full text of the book, stored raw
|
|
var/content
|
|
/// Category the book falls into, see SSlibrary.search_categories
|
|
var/category
|
|
/// The ckey of the user who triggered the upload request
|
|
var/author_ckey
|
|
/// The time of day at which the book was uploaded
|
|
var/creation_time
|
|
/// Boolean, flips to true to "hide" a book from public viewing. Defaults to null
|
|
var/deleted
|
|
/// The round id the book was uploaded in
|
|
var/creation_round
|
|
/// Represents the full admin record of this book, as of the view request. Datumized to make it easier to deal with.
|
|
var/list/datum/book_history_entry/history
|
|
|
|
/datum/admin_book_viewer/proc/set_owner(obj/machinery/computer/libraryconsole/admin_only_do_not_map_in_you_fucker/owner)
|
|
owner_ref = WEAKREF(owner)
|
|
view_raw = owner.view_raw
|
|
|
|
/datum/admin_book_viewer/ui_interact(mob/user, datum/tgui/ui)
|
|
. = ..()
|
|
ui = SStgui.try_update_ui(user, src, ui)
|
|
if(!ui)
|
|
ui = new(user, src, "AdminBookViewer")
|
|
ui.set_autoupdate(FALSE) // Nothing is changing here brother
|
|
ui.open()
|
|
|
|
/datum/admin_book_viewer/ui_status(mob/user, datum/ui_state/state)
|
|
if(!check_rights_for(user.client, R_BAN))
|
|
return UI_CLOSE
|
|
return UI_INTERACTIVE
|
|
|
|
/datum/admin_book_viewer/ui_data(mob/user)
|
|
var/list/data = list()
|
|
data["view_raw"] = view_raw
|
|
data["id"] = id
|
|
data["author"] = author
|
|
data["title"] = title
|
|
data["content"] = content
|
|
data["category"] = category
|
|
data["author_ckey"] = author_ckey
|
|
data["creation_time"] = creation_time
|
|
data["deleted"] = deleted
|
|
data["creation_round"] = creation_round
|
|
data["history"] = list()
|
|
for(var/datum/book_history_entry/entry as anything in history)
|
|
data["history"] += list(entry.serialize())
|
|
|
|
return data
|
|
|
|
#undef BOOK_ADMIN_DELETE
|
|
#undef BOOK_ADMIN_RESTORE
|
|
#undef BOOK_ADMIN_REPORT
|