Files
Bubberstation/code/modules/paperwork/paper.dm
Tad Hardesty cf6f064e21 Use spritesheets to reduce time spent sending PNG assets by 90+% (#37399)
The total number of assets to be sent has been reduced from 1532 to 76, with time between first asset and last going from about 112s to about 7s (a 93% reduction) by my measure. The following assets have been coalesced:

    705 pipe images (used by RPD) -> 1 spritesheet + css
    595 research design icons (used by R&D console) -> 3 spritesheets + css
    116 OOC emoji + 15 language icons -> 1 spritesheet + css
    27 PDA icons -> 1 spritesheet + css
    11 paperwork stamps -> 1 spritesheet + css
2018-05-10 14:34:57 +12:00

374 lines
11 KiB
Plaintext

/*
* Paper
* also scraps of paper
*
* lipstick wiping is in code/game/objects/items/weapons/cosmetics.dm!
*/
/obj/item/paper
name = "paper"
gender = NEUTER
icon = 'icons/obj/bureaucracy.dmi'
icon_state = "paper"
item_state = "paper"
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
var/info //What's actually written on the paper.
var/info_links //A different version of the paper which includes html links at fields and EOF
var/stamps //The (text for the) stamps on the paper.
var/fields = 0 //Amount of user created fields
var/list/stamped
var/rigged = 0
var/spam_flag = 0
var/contact_poison // Reagent ID to transfer on contact
var/contact_poison_volume = 0
/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()
. = ..()
pixel_y = rand(-8, 8)
pixel_x = rand(-9, 9)
update_icon()
updateinfolinks()
/obj/item/paper/update_icon()
if(resistance_flags & ON_FIRE)
icon_state = "paper_onfire"
return
if(info)
icon_state = "paper_words"
return
icon_state = "paper"
/obj/item/paper/examine(mob/user)
..()
to_chat(user, "<span class='notice'>Alt-click to fold it.</span>")
var/datum/asset/assets = get_asset_datum(/datum/asset/spritesheet/simple/paper)
assets.send(user)
if(in_range(user, src) || isobserver(user))
if(user.is_literate())
user << browse("<HTML><HEAD><TITLE>[name]</TITLE></HEAD><BODY>[info]<HR>[stamps]</BODY></HTML>", "window=[name]")
onclose(user, "[name]")
else
user << browse("<HTML><HEAD><TITLE>[name]</TITLE></HEAD><BODY>[stars(info)]<HR>[stamps]</BODY></HTML>", "window=[name]")
onclose(user, "[name]")
else
to_chat(user, "<span class='warning'>You're too far away to read it!</span>")
/obj/item/paper/verb/rename()
set name = "Rename paper"
set category = "Object"
set src in usr
if(usr.incapacitated() || !usr.is_literate())
return
if(ishuman(usr))
var/mob/living/carbon/human/H = usr
if(H.has_trait(TRAIT_CLUMSY) && prob(25))
to_chat(H, "<span class='warning'>You cut yourself on the paper! Ahhhh! Ahhhhh!</span>")
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 && 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 class='suicide'>[user] scratches a grid on [user.p_their()] wrist with the paper! It looks like [user.p_theyre()] trying to commit sudoku...</span>")
return (BRUTELOSS)
/obj/item/paper/proc/reset_spamflag()
spam_flag = FALSE
/obj/item/paper/attack_self(mob/user)
user.examinate(src)
if(rigged && (SSevents.holidays && SSevents.holidays[APRIL_FOOLS]))
if(!spam_flag)
spam_flag = TRUE
playsound(loc, 'sound/items/bikehorn.ogg', 50, 1)
addtimer(CALLBACK(src, .proc/reset_spamflag), 20)
/obj/item/paper/attack_ai(mob/living/silicon/ai/user)
var/dist
if(istype(user) && user.current) //is AI
dist = get_dist(src, user.current)
else //cyborg or AI not seeing through a camera
dist = get_dist(src, user)
if(dist < 2)
usr << browse("<HTML><HEAD><TITLE>[name]</TITLE></HEAD><BODY>[info]<HR>[stamps]</BODY></HTML>", "window=[name]")
onclose(usr, "[name]")
else
usr << browse("<HTML><HEAD><TITLE>[name]</TITLE></HEAD><BODY>[stars(info)]<HR>[stamps]</BODY></HTML>", "window=[name]")
onclose(usr, "[name]")
/obj/item/paper/proc/addtofield(id, text, links = 0)
var/locid = 0
var/laststart = 1
var/textindex = 1
while(1) //I know this can cause infinite loops and fuck up the whole server, but the if(istart==0) should be safe as fuck
var/istart = 0
if(links)
istart = findtext(info_links, "<span class=\"paper_field\">", laststart)
else
istart = findtext(info, "<span class=\"paper_field\">", laststart)
if(istart == 0)
return //No field found with matching id
laststart = istart+1
locid++
if(locid == id)
var/iend = 1
if(links)
iend = findtext(info_links, "</span>", istart)
else
iend = findtext(info, "</span>", istart)
//textindex = istart+26
textindex = iend
break
if(links)
var/before = copytext(info_links, 1, textindex)
var/after = copytext(info_links, textindex)
info_links = before + text + after
else
var/before = copytext(info, 1, textindex)
var/after = copytext(info, textindex)
info = before + text + after
updateinfolinks()
/obj/item/paper/proc/updateinfolinks()
info_links = info
for(var/i in 1 to min(fields, 15))
addtofield(i, "<font face=\"[PEN_FONT]\"><A href='?src=[REF(src)];write=[i]'>write</A></font>", 1)
info_links = info_links + "<font face=\"[PEN_FONT]\"><A href='?src=[REF(src)];write=end'>write</A></font>"
/obj/item/paper/proc/clearpaper()
info = null
stamps = null
LAZYCLEARLIST(stamped)
cut_overlays()
updateinfolinks()
update_icon()
/obj/item/paper/proc/parsepencode(t, obj/item/pen/P, mob/user, iscrayon = 0)
if(length(t) < 1) //No input means nothing needs to be parsed
return
t = parsemarkdown(t, user, iscrayon)
if(!iscrayon)
t = "<font face=\"[P.font]\" color=[P.colour]>[t]</font>"
else
var/obj/item/toy/crayon/C = P
t = "<font face=\"[CRAYON_FONT]\" color=[C.paint_color]><b>[t]</b></font>"
// Count the fields
var/laststart = 1
while(1)
var/i = findtext(t, "<span class=\"paper_field\">", laststart)
if(i == 0)
break
laststart = i+1
fields++
return t
/obj/item/paper/proc/reload_fields() // Useful if you made the paper programicly and want to include fields. Also runs updateinfolinks() for you.
fields = 0
var/laststart = 1
while(1)
var/i = findtext(info, "<span class=\"paper_field\">", laststart)
if(i == 0)
break
laststart = i+1
fields++
updateinfolinks()
/obj/item/paper/proc/openhelp(mob/user)
user << browse({"<HTML><HEAD><TITLE>Paper Help</TITLE></HEAD>
<BODY>
You can use backslash (\\) to escape special characters.<br>
<br>
<b><center>Crayon&Pen commands</center></b><br>
<br>
# text : Defines a header.<br>
|text| : Centers the text.<br>
**text** : Makes the text <b>bold</b>.<br>
*text* : Makes the text <i>italic</i>.<br>
^text^ : Increases the <font size = \"4\">size</font> of the text.<br>
%s : Inserts a signature of your name in a foolproof way.<br>
%f : Inserts an invisible field which lets you start type from there. Useful for forms.<br>
<br>
<b><center>Pen exclusive commands</center></b><br>
((text)) : Decreases the <font size = \"1\">size</font> of the text.<br>
* item : An unordered list item.<br>
&nbsp;&nbsp;* item: An unordered list child item.<br>
--- : Adds a horizontal rule.
</BODY></HTML>"}, "window=paper_help")
/obj/item/paper/Topic(href, href_list)
..()
var/literate = usr.is_literate()
if(!usr.canUseTopic(src, BE_CLOSE, literate))
return
if(href_list["help"])
openhelp(usr)
return
if(href_list["write"])
var/id = href_list["write"]
var/t = stripped_multiline_input("Enter what you want to write:", "Write", no_trim=TRUE)
if(!t || !usr.canUseTopic(src, BE_CLOSE, literate))
return
var/obj/item/i = usr.get_active_held_item() //Check to see if he still got that darn pen, also check if he's using a crayon or pen.
var/iscrayon = 0
if(!istype(i, /obj/item/pen))
if(!istype(i, /obj/item/toy/crayon))
return
iscrayon = 1
if(!in_range(src, usr) && loc != usr && !istype(loc, /obj/item/clipboard) && loc.loc != usr && usr.get_active_held_item() != i) //Some check to see if he's allowed to write
return
t = parsepencode(t, i, usr, iscrayon) // Encode everything from pencode to html
if(t != null) //No input from the user means nothing needs to be added
if(id!="end")
addtofield(text2num(id), t) // He wants to edit a field, let him.
else
info += t // Oh, he wants to edit to the end of the file, let him.
updateinfolinks()
usr << browse("<HTML><HEAD><TITLE>[name]</TITLE></HEAD><BODY>[info_links]<HR>[stamps]</BODY><div align='right'style='position:fixed;bottom:0;font-style:bold;'><A href='?src=[REF(src)];help=1'>\[?\]</A></div></HTML>", "window=[name]") // Update the window
update_icon()
/obj/item/paper/attackby(obj/item/P, mob/living/carbon/human/user, params)
..()
if(resistance_flags & ON_FIRE)
return
if(is_blind(user))
return
if(istype(P, /obj/item/pen) || istype(P, /obj/item/toy/crayon))
if(user.is_literate())
user << browse("<HTML><HEAD><TITLE>[name]</TITLE></HEAD><BODY>[info_links]<HR>[stamps]</BODY><div align='right'style='position:fixed;bottom:0;font-style:bold;'><A href='?src=[REF(src)];help=1'>\[?\]</A></div></HTML>", "window=[name]")
return
else
to_chat(user, "<span class='notice'>You don't know how to read or write.</span>")
return
else if(istype(P, /obj/item/stamp))
if(!in_range(src, user))
return
var/datum/asset/spritesheet/sheet = get_asset_datum(/datum/asset/spritesheet/simple/paper)
if (isnull(stamps))
stamps = sheet.css_tag()
stamps += sheet.icon_tag(P.icon_state)
var/mutable_appearance/stampoverlay = mutable_appearance('icons/obj/bureaucracy.dmi', "paper_[P.icon_state]")
stampoverlay.pixel_x = rand(-2, 2)
stampoverlay.pixel_y = rand(-3, 2)
LAZYADD(stamped, P.icon_state)
add_overlay(stampoverlay)
to_chat(user, "<span class='notice'>You stamp the paper with your rubber stamp.</span>")
if(P.is_hot())
if(user.has_trait(TRAIT_CLUMSY) && prob(10))
user.visible_message("<span class='warning'>[user] accidentally ignites [user.p_them()]self!</span>", \
"<span class='userdanger'>You miss the paper and accidentally light yourself on fire!</span>")
user.dropItemToGround(P)
user.adjust_fire_stacks(1)
user.IgniteMob()
return
if(!(in_range(user, src))) //to prevent issues as a result of telepathically lighting a paper
return
user.dropItemToGround(src)
user.visible_message("<span class='danger'>[user] lights [src] ablaze with [P]!</span>", "<span class='danger'>You light [src] on fire!</span>")
fire_act()
add_fingerprint(user)
/obj/item/paper/fire_act(exposed_temperature, exposed_volume)
..()
if(!(resistance_flags & FIRE_PROOF))
icon_state = "paper_onfire"
info = "[stars(info)]"
/obj/item/paper/extinguish()
..()
update_icon()
/*
* Construction paper
*/
/obj/item/paper/construction
/obj/item/paper/construction/Initialize()
. = ..()
color = pick("FF0000", "#33cc33", "#ffb366", "#551A8B", "#ff80d5", "#4d94ff")
/*
* Natural paper
*/
/obj/item/paper/natural/Initialize()
. = ..()
color = "#FFF5ED"
/obj/item/paper/crumpled
name = "paper scrap"
icon_state = "scrap"
slot_flags = null
/obj/item/paper/crumpled/update_icon()
return
/obj/item/paper/crumpled/bloody
icon_state = "scrap_bloodied"