mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-31 20:11:56 +00:00
I'm adding a circuit component that can print text string on a paper object in a variety of colors and font typefaces (currently only web-safe ones are available, maybe i'll add some fancy ones in the future but they'd need to be imported either through @import of @font-face in a separate CSS not imported by every tgui UI). It's important to note that because the UI sanitizes new text inputed by users and not what's already written on the paper (so the pen_color and pen_font don't be purged in the process), we can't safely have these strings "printed" into the info variable directly, because of that these values will be stored in two new list variables, one for the text and one for font color, face and the signature. When the paper sheet UI is opened, these will be sanitized and then parsed into the text, so the next time the paper is edited we can clear these two lists. Obviously better than a hacky byond proc - parsemarkdown() is outdated af -, albeit a bit messy... like the rest of paper code. Requires #62033.
457 lines
15 KiB
Plaintext
457 lines
15 KiB
Plaintext
/**
|
|
* Paper
|
|
* also scraps of paper
|
|
*
|
|
* lipstick wiping is in code/game/objects/items/weapons/cosmetics.dm!
|
|
*/
|
|
#define MAX_PAPER_LENGTH 5000
|
|
#define MAX_PAPER_STAMPS 30 // Too low?
|
|
#define MAX_PAPER_STAMPS_OVERLAYS 4
|
|
#define MODE_READING 0
|
|
#define MODE_WRITING 1
|
|
#define MODE_STAMPING 2
|
|
|
|
#define DEFAULT_ADD_INFO_COLOR "black"
|
|
#define DEFAULT_ADD_INFO_FONT "Verdana"
|
|
#define DEFAULT_ADD_INFO_SIGN "signature"
|
|
|
|
/**
|
|
* Paper is now using markdown (like in github pull notes) for ALL rendering
|
|
* so we do loose a bit of functionality but we gain in easy of use of
|
|
* paper and getting rid of that crashing bug
|
|
*/
|
|
/obj/item/paper
|
|
name = "paper"
|
|
gender = NEUTER
|
|
icon = 'icons/obj/bureaucracy.dmi'
|
|
icon_state = "paper"
|
|
inhand_icon_state = "paper"
|
|
worn_icon_state = "paper"
|
|
custom_fire_overlay = "paper_onfire_overlay"
|
|
throwforce = 0
|
|
w_class = WEIGHT_CLASS_TINY
|
|
throw_range = 1
|
|
throw_speed = 1
|
|
pressure_resistance = 0
|
|
slot_flags = ITEM_SLOT_HEAD
|
|
body_parts_covered = HEAD
|
|
resistance_flags = FLAMMABLE
|
|
max_integrity = 50
|
|
dog_fashion = /datum/dog_fashion/head
|
|
drop_sound = 'sound/items/handling/paper_drop.ogg'
|
|
pickup_sound = 'sound/items/handling/paper_pickup.ogg'
|
|
grind_results = list(/datum/reagent/cellulose = 3)
|
|
color = "white"
|
|
/// What's actually written on the paper.
|
|
var/info = ""
|
|
/**
|
|
* What's been written on the paper by things other than players.
|
|
* Will be sanitized by the UI, and finally
|
|
* added to info when the user edits the paper text.
|
|
*/
|
|
var/list/add_info
|
|
/// The font color, face and the signature of the above.
|
|
var/list/add_info_style
|
|
|
|
var/show_written_words = TRUE
|
|
|
|
/// The (text for the) stamps on the paper.
|
|
var/list/stamps /// Positioning for the stamp in tgui
|
|
var/list/stamped /// Overlay info
|
|
|
|
var/contact_poison // Reagent ID to transfer on contact
|
|
var/contact_poison_volume = 0
|
|
|
|
/// When the sheet can be "filled out"
|
|
/// This is an associated list
|
|
var/list/form_fields = list()
|
|
var/field_counter = 1
|
|
|
|
/obj/item/paper/Destroy()
|
|
stamps = null
|
|
stamped = null
|
|
form_fields = null
|
|
stamped = null
|
|
. = ..()
|
|
|
|
/**
|
|
* This proc copies this sheet of paper to a new
|
|
* sheet. Used by carbon papers and the photocopier machine.
|
|
*/
|
|
/obj/item/paper/proc/copy(paper_type = /obj/item/paper, atom/location = loc, colored = TRUE)
|
|
var/obj/item/paper/new_paper = new paper_type (location)
|
|
if(colored)
|
|
new_paper.color = color
|
|
new_paper.info = info
|
|
new_paper.add_info_style = add_info_style.Copy()
|
|
else //This basically just breaks the existing color tag, which we need to do because the innermost tag takes priority.
|
|
var/static/greyscale_info = regex("(?<=<font style=\")color=(.*)?>", "i")
|
|
new_paper.info = replacetext(info, greyscale_info, "nocolor=$1>")
|
|
for(var/list/style as anything in add_info_style)
|
|
LAZYADD(new_paper.add_info_style, list(list(DEFAULT_ADD_INFO_COLOR, style[ADD_INFO_FONT], style[ADD_INFO_SIGN])))
|
|
new_paper.add_info = add_info?.Copy()
|
|
new_paper.stamps = stamps?.Copy()
|
|
new_paper.stamped = stamped?.Copy()
|
|
new_paper.form_fields = form_fields.Copy()
|
|
new_paper.field_counter = field_counter
|
|
new_paper.update_icon_state()
|
|
copy_overlays(new_paper, TRUE)
|
|
return new_paper
|
|
|
|
/**
|
|
* This proc sets the text of the paper and updates the
|
|
* icons. You can modify the pen_color after if need
|
|
* be.
|
|
*/
|
|
/obj/item/paper/proc/setText(text, update_icon = TRUE)
|
|
info = text
|
|
add_info = null
|
|
add_info_style = null
|
|
form_fields = null
|
|
field_counter = 0
|
|
if(update_icon)
|
|
update_appearance()
|
|
|
|
/obj/item/paper/pickup(user)
|
|
if(contact_poison && ishuman(user))
|
|
var/mob/living/carbon/human/H = user
|
|
var/obj/item/clothing/gloves/G = H.gloves
|
|
if(!istype(G) || G.transfer_prints)
|
|
H.reagents.add_reagent(contact_poison,contact_poison_volume)
|
|
contact_poison = null
|
|
. = ..()
|
|
|
|
/obj/item/paper/Initialize(mapload)
|
|
. = ..()
|
|
pixel_x = base_pixel_x + rand(-9, 9)
|
|
pixel_y = base_pixel_y + rand(-8, 8)
|
|
update_appearance()
|
|
|
|
/obj/item/paper/update_icon_state()
|
|
if((info || add_info) && show_written_words)
|
|
icon_state = "[initial(icon_state)]_words"
|
|
return ..()
|
|
|
|
/obj/item/paper/verb/rename()
|
|
set name = "Rename paper"
|
|
set category = "Object"
|
|
set src in usr
|
|
|
|
if(!usr.can_read(src) || usr.incapacitated(TRUE, TRUE) || (isobserver(usr) && !isAdminGhostAI(usr)))
|
|
return
|
|
if(ishuman(usr))
|
|
var/mob/living/carbon/human/H = usr
|
|
if(HAS_TRAIT(H, TRAIT_CLUMSY) && prob(25))
|
|
to_chat(H, span_warning("You cut yourself on the paper! Ahhhh! Ahhhhh!"))
|
|
H.damageoverlaytemp = 9001
|
|
H.update_damage_hud()
|
|
return
|
|
var/n_name = stripped_input(usr, "What would you like to label the paper?", "Paper Labelling", null, MAX_NAME_LEN)
|
|
if(((loc == usr || istype(loc, /obj/item/clipboard)) && usr.stat == CONSCIOUS))
|
|
name = "paper[(n_name ? text("- '[n_name]'") : null)]"
|
|
add_fingerprint(usr)
|
|
|
|
/obj/item/paper/suicide_act(mob/user)
|
|
user.visible_message(span_suicide("[user] scratches a grid on [user.p_their()] wrist with the paper! It looks like [user.p_theyre()] trying to commit sudoku..."))
|
|
return (BRUTELOSS)
|
|
|
|
/obj/item/paper/proc/clearpaper()
|
|
setText("", update_icon = FALSE)
|
|
stamps = null
|
|
LAZYCLEARLIST(stamped)
|
|
cut_overlays()
|
|
update_icon_state()
|
|
|
|
/obj/item/paper/examine(mob/user)
|
|
. = ..()
|
|
if(!in_range(user, src) && !isobserver(user))
|
|
. += span_warning("You're too far away to read it!")
|
|
return
|
|
if(user.can_read(src))
|
|
ui_interact(user)
|
|
return
|
|
. += span_warning("You cannot read it!")
|
|
|
|
/obj/item/paper/ui_status(mob/user,/datum/ui_state/state)
|
|
// Are we on fire? Hard ot read if so
|
|
if(resistance_flags & ON_FIRE)
|
|
return UI_CLOSE
|
|
if(!in_range(user, src) && !isobserver(user))
|
|
return UI_CLOSE
|
|
if(user.incapacitated(TRUE, TRUE) || (isobserver(user) && !isAdminGhostAI(user)))
|
|
return UI_UPDATE
|
|
// Even harder to read if your blind...braile? humm
|
|
// .. or if you cannot read
|
|
if(!user.can_read(src))
|
|
return UI_CLOSE
|
|
if(in_contents_of(/obj/machinery/door/airlock) || in_contents_of(/obj/item/clipboard))
|
|
return UI_INTERACTIVE
|
|
return ..()
|
|
|
|
|
|
|
|
/obj/item/paper/can_interact(mob/user)
|
|
if(in_contents_of(/obj/machinery/door/airlock))
|
|
return TRUE
|
|
return ..()
|
|
|
|
|
|
/obj/item/proc/burn_paper_product_attackby_check(obj/item/I, mob/living/user, bypass_clumsy)
|
|
var/ignition_message = I.ignition_effect(src, user)
|
|
if(!ignition_message)
|
|
return
|
|
. = TRUE
|
|
if(!bypass_clumsy && HAS_TRAIT(user, TRAIT_CLUMSY) && prob(10) && Adjacent(user))
|
|
user.visible_message(span_warning("[user] accidentally ignites [user.p_them()]self!"), \
|
|
span_userdanger("You miss [src] and accidentally light yourself on fire!"))
|
|
if(user.is_holding(I)) //checking if they're holding it in case TK is involved
|
|
user.dropItemToGround(I)
|
|
user.adjust_fire_stacks(1)
|
|
user.IgniteMob()
|
|
return
|
|
|
|
if(user.is_holding(src)) //no TK shit here.
|
|
user.dropItemToGround(src)
|
|
user.visible_message(ignition_message)
|
|
add_fingerprint(user)
|
|
fire_act(I.get_temperature())
|
|
|
|
/obj/item/paper/proc/add_info(text, color = DEFAULT_ADD_INFO_COLOR, font = DEFAULT_ADD_INFO_FONT, signature = DEFAULT_ADD_INFO_SIGN)
|
|
LAZYADD(add_info, text)
|
|
LAZYADD(add_info_style, list(list(color, font, signature)))
|
|
|
|
/obj/item/paper/proc/get_info_length()
|
|
. = length_char(info)
|
|
for(var/index in 1 to length(add_info))
|
|
var/style = LAZYACCESS(add_info_style, index)
|
|
if(style)
|
|
var/static/regex/sign_regex = regex("%s(?:ign)?(?=\\s|$)?", "igm")
|
|
var/signed_text = sign_regex.Replace(add_info[index], style[ADD_INFO_SIGN])
|
|
. += length_char(PAPER_MARK_TEXT(signed_text, style[ADD_INFO_COLOR], style[ADD_INFO_FONT]))
|
|
else
|
|
. += length_char(add_info[index])
|
|
|
|
/obj/item/paper/attackby(obj/item/P, mob/living/user, params)
|
|
if(burn_paper_product_attackby_check(P, user))
|
|
SStgui.close_uis(src)
|
|
return
|
|
|
|
// Enable picking paper up by clicking on it with the clipboard or folder
|
|
if(istype(P, /obj/item/clipboard) || istype(P, /obj/item/folder) || istype(P, /obj/item/paper_bin))
|
|
P.attackby(src, user)
|
|
return
|
|
else if(istype(P, /obj/item/pen) || istype(P, /obj/item/toy/crayon))
|
|
if(get_info_length() >= MAX_PAPER_LENGTH) // Sheet must have less than 5000 charaters
|
|
to_chat(user, span_warning("This sheet of paper is full!"))
|
|
return
|
|
ui_interact(user)
|
|
return
|
|
else if(istype(P, /obj/item/stamp))
|
|
to_chat(user, span_notice("You ready your stamp over the paper! "))
|
|
ui_interact(user)
|
|
return /// Normaly you just stamp, you don't need to read the thing
|
|
else
|
|
// cut paper? the sky is the limit!
|
|
ui_interact(user) // The other ui will be created with just read mode outside of this
|
|
|
|
return ..()
|
|
|
|
|
|
/obj/item/paper/fire_act(exposed_temperature, exposed_volume)
|
|
. = ..()
|
|
if(.)
|
|
info = "[stars(info)]"
|
|
for(var/index in 1 to add_info)
|
|
add_info[index] = "[stars(add_info[index])]"
|
|
|
|
/obj/item/paper/ui_assets(mob/user)
|
|
return list(
|
|
get_asset_datum(/datum/asset/spritesheet/simple/paper),
|
|
)
|
|
|
|
/obj/item/paper/ui_interact(mob/user, datum/tgui/ui)
|
|
// Update the UI
|
|
ui = SStgui.try_update_ui(user, src, ui)
|
|
if(!ui)
|
|
ui = new(user, src, "PaperSheet", name)
|
|
ui.open()
|
|
|
|
/obj/item/paper/ui_static_data(mob/user)
|
|
. = list()
|
|
.["text"] = info
|
|
if(length(add_info))
|
|
.["add_text"] = add_info
|
|
.["add_color"] = list()
|
|
.["add_font"] = list()
|
|
.["add_sign"] = list()
|
|
for(var/index in 1 to length(add_info))
|
|
var/list/style = LAZYACCESS(add_info_style, index)
|
|
if(!islist(index) || length(style) < ADD_INFO_SIGN) // failsafe for malformed add_info_style.
|
|
var/list/corrected_style = list(DEFAULT_ADD_INFO_COLOR, DEFAULT_ADD_INFO_FONT, DEFAULT_ADD_INFO_SIGN)
|
|
LAZYADD(add_info_style, corrected_style)
|
|
style = corrected_style
|
|
.["add_color"] += style[ADD_INFO_COLOR]
|
|
.["add_font"] += style[ADD_INFO_FONT]
|
|
.["add_sign"] += style[ADD_INFO_SIGN]
|
|
|
|
.["max_length"] = MAX_PAPER_LENGTH
|
|
.["paper_color"] = !color || color == "white" ? "#FFFFFF" : color // color might not be set
|
|
.["paper_state"] = icon_state /// TODO: show the sheet will bloodied or crinkling?
|
|
.["stamps"] = stamps
|
|
|
|
|
|
/obj/item/paper/ui_data(mob/user)
|
|
var/list/data = list()
|
|
data["edit_usr"] = "[user.real_name]"
|
|
|
|
var/obj/holding = user.get_active_held_item()
|
|
// Use a clipboard's pen, if applicable
|
|
if(istype(loc, /obj/item/clipboard))
|
|
var/obj/item/clipboard/clipboard = loc
|
|
// This is just so you can still use a stamp if you're holding one. Otherwise, it'll
|
|
// use the clipboard's pen, if applicable.
|
|
if(!istype(holding, /obj/item/stamp) && clipboard.pen)
|
|
holding = clipboard.pen
|
|
if(istype(holding, /obj/item/toy/crayon))
|
|
var/obj/item/toy/crayon/PEN = holding
|
|
data["pen_font"] = CRAYON_FONT
|
|
data["pen_color"] = PEN.paint_color
|
|
data["edit_mode"] = MODE_WRITING
|
|
data["is_crayon"] = TRUE
|
|
data["stamp_class"] = "FAKE"
|
|
data["stamp_icon_state"] = "FAKE"
|
|
else if(istype(holding, /obj/item/pen))
|
|
var/obj/item/pen/PEN = holding
|
|
data["pen_font"] = PEN.font
|
|
data["pen_color"] = PEN.colour
|
|
data["edit_mode"] = MODE_WRITING
|
|
data["is_crayon"] = FALSE
|
|
data["stamp_class"] = "FAKE"
|
|
data["stamp_icon_state"] = "FAKE"
|
|
else if(istype(holding, /obj/item/stamp))
|
|
var/datum/asset/spritesheet/sheet = get_asset_datum(/datum/asset/spritesheet/simple/paper)
|
|
data["stamp_icon_state"] = holding.icon_state
|
|
data["stamp_class"] = sheet.icon_class_name(holding.icon_state)
|
|
data["edit_mode"] = MODE_STAMPING
|
|
data["pen_font"] = "FAKE"
|
|
data["pen_color"] = "FAKE"
|
|
data["is_crayon"] = FALSE
|
|
else
|
|
data["edit_mode"] = MODE_READING
|
|
data["pen_font"] = "FAKE"
|
|
data["pen_color"] = "FAKE"
|
|
data["is_crayon"] = FALSE
|
|
data["stamp_icon_state"] = "FAKE"
|
|
data["stamp_class"] = "FAKE"
|
|
if(istype(loc, /obj/structure/noticeboard))
|
|
var/obj/structure/noticeboard/noticeboard = loc
|
|
if(!noticeboard.allowed(user))
|
|
data["edit_mode"] = MODE_READING
|
|
data["field_counter"] = field_counter
|
|
data["form_fields"] = form_fields
|
|
|
|
return data
|
|
|
|
/obj/item/paper/ui_act(action, params,datum/tgui/ui)
|
|
. = ..()
|
|
if(.)
|
|
return
|
|
switch(action)
|
|
if("stamp")
|
|
var/stamp_x = text2num(params["x"])
|
|
var/stamp_y = text2num(params["y"])
|
|
var/stamp_r = text2num(params["r"]) // rotation in degrees
|
|
var/stamp_icon_state = params["stamp_icon_state"]
|
|
var/stamp_class = params["stamp_class"]
|
|
if (isnull(stamps))
|
|
stamps = list()
|
|
if(stamps.len < MAX_PAPER_STAMPS)
|
|
// I hate byond when dealing with freaking lists
|
|
stamps[++stamps.len] = list(stamp_class, stamp_x, stamp_y, stamp_r) /// WHHHHY
|
|
|
|
/// This does the overlay stuff
|
|
if (isnull(stamped))
|
|
stamped = list()
|
|
if(stamped.len < MAX_PAPER_STAMPS_OVERLAYS)
|
|
var/mutable_appearance/stampoverlay = mutable_appearance('icons/obj/bureaucracy.dmi', "paper_[stamp_icon_state]")
|
|
stampoverlay.pixel_x = rand(-2, 2)
|
|
stampoverlay.pixel_y = rand(-3, 2)
|
|
add_overlay(stampoverlay)
|
|
LAZYADD(stamped, stamp_icon_state)
|
|
update_icon()
|
|
|
|
update_static_data(usr,ui)
|
|
var/obj/O = ui.user.get_active_held_item()
|
|
ui.user.visible_message(span_notice("[ui.user] stamps [src] with \the [O.name]!"), span_notice("You stamp [src] with \the [O.name]!"))
|
|
else
|
|
to_chat(usr, pick("You try to stamp but you miss!", "There is no where else you can stamp!"))
|
|
. = TRUE
|
|
|
|
if("save")
|
|
var/in_paper = params["text"]
|
|
var/paper_len = length(in_paper)
|
|
field_counter = params["field_counter"] ? text2num(params["field_counter"]) : field_counter
|
|
|
|
if(paper_len > MAX_PAPER_LENGTH)
|
|
// Side note, the only way we should get here is if
|
|
// the javascript was modified, somehow, outside of
|
|
// byond. but right now we are logging it as
|
|
// the generated html might get beyond this limit
|
|
log_paper("[key_name(ui.user)] writing to paper [name], and overwrote it by [paper_len-MAX_PAPER_LENGTH]")
|
|
if(paper_len == 0)
|
|
to_chat(ui.user, pick("Writing block strikes again!", "You forgot to write anthing!"))
|
|
else
|
|
log_paper("[key_name(ui.user)] writing to paper [name]")
|
|
if(info != in_paper)
|
|
to_chat(ui.user, "You have added to your paper masterpiece!");
|
|
info = in_paper
|
|
add_info = null
|
|
add_info_style = null
|
|
update_static_data(usr,ui)
|
|
|
|
update_appearance()
|
|
. = TRUE
|
|
|
|
/obj/item/paper/ui_host(mob/user)
|
|
if(istype(loc, /obj/structure/noticeboard))
|
|
return loc
|
|
return ..()
|
|
|
|
/**
|
|
* Construction paper
|
|
*/
|
|
/obj/item/paper/construction
|
|
|
|
/obj/item/paper/construction/Initialize(mapload)
|
|
. = ..()
|
|
color = pick("FF0000", "#33cc33", "#ffb366", "#551A8B", "#ff80d5", "#4d94ff")
|
|
|
|
/**
|
|
* Natural paper
|
|
*/
|
|
/obj/item/paper/natural/Initialize(mapload)
|
|
. = ..()
|
|
color = "#FFF5ED"
|
|
|
|
/obj/item/paper/crumpled
|
|
name = "paper scrap"
|
|
icon_state = "scrap"
|
|
slot_flags = null
|
|
show_written_words = FALSE
|
|
|
|
/obj/item/paper/crumpled/bloody
|
|
icon_state = "scrap_bloodied"
|
|
|
|
/obj/item/paper/crumpled/muddy
|
|
icon_state = "scrap_mud"
|
|
|
|
#undef MAX_PAPER_LENGTH
|
|
#undef MAX_PAPER_STAMPS
|
|
#undef MAX_PAPER_STAMPS_OVERLAYS
|
|
#undef MODE_READING
|
|
#undef MODE_WRITING
|
|
#undef MODE_STAMPING
|
|
#undef DEFAULT_ADD_INFO_COLOR
|
|
#undef DEFAULT_ADD_INFO_FONT
|
|
#undef DEFAULT_ADD_INFO_SIGN
|