diff --git a/code/modules/paperwork/paper.dm b/code/modules/paperwork/paper.dm
index 8dd814c604..87693e01ba 100644
--- a/code/modules/paperwork/paper.dm
+++ b/code/modules/paperwork/paper.dm
@@ -10,13 +10,52 @@
#define MODE_READING 0
#define MODE_WRITING 1
#define MODE_STAMPING 2
+
+
+/**
+ ** This is a custom ui state. All it really does is keep track of pen
+ ** being used and if they are editing it or not. This way we can keep
+ ** the data with the ui rather than on the paper
+ **/
+/datum/ui_state/default/paper_state
+ /// What edit mode we are in and who is
+ /// writing on it right now
+ var/edit_mode = MODE_READING
+ /// Setup for writing to a sheet
+ var/pen_color = "black"
+ var/pen_font = ""
+ var/is_crayon = FALSE
+ /// Setup for stamping a sheet
+ // Why not the stamp obj? I have no idea
+ // what happens to states out of scope so
+ // don't want to put instances in this
+ var/stamp_icon_state = ""
+ var/stamp_name = ""
+ var/stamp_class = ""
+
+
+/datum/ui_state/default/paper_state/proc/copy_from(datum/ui_state/default/paper_state/from)
+ switch(from.edit_mode)
+ if(MODE_READING)
+ edit_mode = MODE_READING
+ if(MODE_WRITING)
+ edit_mode = MODE_WRITING
+ pen_color = from.pen_color
+ pen_font = from.pen_font
+ is_crayon = from.is_crayon
+ if(MODE_STAMPING)
+ edit_mode = MODE_STAMPING
+ stamp_icon_state = from.stamp_icon_state
+ stamp_class = from.stamp_class
+ stamp_name = from.stamp_name
+
+
/**
** 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
- var/static/regex/sign_regex = regex("%s(?:ign)?(?=\\s|$)", "igm")
name = "paper"
gender = NEUTER
icon = 'icons/obj/bureaucracy.dmi'
@@ -35,6 +74,7 @@
color = "white"
/// What's actually written on the paper.
var/info = ""
+ var/show_written_words = TRUE
/// The (text for the) stamps on the paper.
var/list/stamps /// Positioning for the stamp in tgui
@@ -48,23 +88,31 @@
var/contact_poison // Reagent ID to transfer on contact
var/contact_poison_volume = 0
+ // ui stuff
var/ui_x = 600
var/ui_y = 800
+ // Ok, so WHY are we caching the ui's?
+ // Since we are not using autoupdate we
+ // need some way to update the ui's of
+ // other people looking at it and if
+ // its been updated. Yes yes, lame
+ // but canot be helped. However by
+ // doing it this way, we can see
+ // live updates and have multipule
+ // people look at it
+ var/list/viewing_ui = list()
+
+
/// When the sheet can be "filled out"
/// This is an associated list
- var/list/form_fields = null
+ var/list/form_fields = list()
var/field_counter = 1
- /// What edit mode we are in and who is
- /// writing on it right now
- var/edit_mode = MODE_READING
- var/mob/living/edit_usr = null
- /// Setup for writing to a sheet
- var/pen_color = "black"
- var/pen_font = ""
- var/is_crayon = FALSE
- /// Setup for stamping a sheet
- var/obj/item/stamp/current_stamp = null
- var/stamp_class = null
+
+/obj/item/paper/Destroy()
+ close_all_ui()
+ stamps = null
+ stamped = null
+ . = ..()
/**
** This proc copies this sheet of paper to a new
@@ -108,17 +156,12 @@
. = ..()
pixel_y = rand(-8, 8)
pixel_x = rand(-9, 9)
- update_icon_state()
+ update_icon()
/obj/item/paper/update_icon_state()
- if(resistance_flags & ON_FIRE)
- icon_state = "paper_onfire"
- return
- if(info)
- icon_state = "paper_words"
- return
- icon_state = "paper"
+ if(info && show_written_words)
+ icon_state = "[initial(icon_state)]_words"
/obj/item/paper/ui_base_html(html)
/// This might change in a future PR
@@ -157,10 +200,6 @@
/obj/item/paper/attack_self(mob/user)
- if(edit_usr == user)
- // we are shifting out of editing mode
- edit_mode = MODE_READING
- edit_usr = null
if(rigged && (SSevents.holidays && SSevents.holidays[APRIL_FOOLS]))
if(!spam_flag)
spam_flag = TRUE
@@ -177,6 +216,10 @@
update_icon_state()
+/obj/item/paper/examine(mob/user)
+ ui_interact(user)
+
+
/obj/item/paper/can_interact(mob/user)
if(!..())
return FALSE
@@ -187,82 +230,90 @@
return user.can_read(src) // checks if the user can read.
-/obj/item/paper/attackby(obj/item/P, mob/living/carbon/human/user, params)
+/**
+ ** This creates the ui, since we are using a custom state but not much else
+ ** just makes it easyer to make it. Also we make a custom ui_key as I am
+ ** not sure how tgui handles many producers?
+**/
+/obj/item/paper/proc/create_ui(mob/user, datum/ui_state/default/paper_state/state)
+ ui_interact(user, "main", null, FALSE, null, state)
+
+
+/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("[user] accidentally ignites [user.p_them()]self!", \
+ "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/attackby(obj/item/P, mob/living/user, params)
+ if(burn_paper_product_attackby_check(P, user))
+ close_all_ui()
+ return
+
if(istype(P, /obj/item/pen) || istype(P, /obj/item/toy/crayon))
if(length(info) >= MAX_PAPER_LENGTH) // Sheet must have less than 1000 charaters
to_chat(user, "This sheet of paper is full!")
return
- if(edit_mode != MODE_READING)
- to_chat(user, "[edit_usr] is already working on this sheet!")
- return
- edit_mode = MODE_WRITING
- edit_usr = user
+ var/datum/ui_state/default/paper_state/state = new
+ state.edit_mode = MODE_WRITING
// should a crayon be in the same subtype as a pen? How about a brush or charcoal?
// TODO: Convert all writing stuff to one type, /obj/item/art_tool maybe?
- is_crayon = istype(P, /obj/item/toy/crayon);
- if(is_crayon)
+ state.is_crayon = istype(P, /obj/item/toy/crayon);
+ if(state.is_crayon)
var/obj/item/toy/crayon/PEN = P
- pen_font = CRAYON_FONT
- pen_color = PEN.paint_color
+ state.pen_font = CRAYON_FONT
+ state.pen_color = PEN.paint_color
else
var/obj/item/pen/PEN = P
- pen_font = PEN.font
- pen_color = PEN.colour
+ state.pen_font = PEN.font
+ state.pen_color = PEN.colour
- ui_interact(user)
+ create_ui(user, state)
return
else if(istype(P, /obj/item/stamp))
- if(edit_mode != MODE_READING)
- to_chat(user, "[edit_usr] is already working on this sheet!")
- return
-
- edit_mode = MODE_STAMPING // we are read only becausse the sheet is full
- edit_usr = user
- current_stamp = P
+ var/datum/ui_state/default/paper_state/state = new
+ state.edit_mode = MODE_STAMPING // we are read only becausse the sheet is full
+ state.stamp_icon_state = P.icon_state
var/datum/asset/spritesheet/sheet = get_asset_datum(/datum/asset/spritesheet/simple/paper)
- stamp_class = sheet.icon_class_name(P.icon_state)
+ state.stamp_class = sheet.icon_class_name(P.icon_state)
to_chat(user, "You ready your stamp over the paper! ")
- ui_interact(user)
+ create_ui(user, state)
return /// Normaly you just stamp, you don't need to read the thing
- else if(P.get_temperature())
- if(HAS_TRAIT(user, TRAIT_CLUMSY) && prob(10))
- user.visible_message("[user] accidentally ignites [user.p_them()]self!", \
- "You miss the paper and accidentally light yourself on fire!")
- user.dropItemToGround(P)
- user.adjust_fire_stacks(1)
- user.IgniteMob()
- return
-
- user.dropItemToGround(src)
- user.visible_message("[user] lights [src] ablaze with [P]!", "You light [src] on fire!")
- fire_act()
else
- if(edit_mode != MODE_READING)
- to_chat(user, "You look at the sheet while [edit_usr] edits it")
- else
- edit_mode = MODE_READING
- ui_interact(user) // The other ui will be created with just read mode outside of this
+ // cut paper? the sky is the limit!
+ var/datum/ui_state/default/paper_state/state = new
+ state.edit_mode = MODE_READING
+ create_ui(user, state) // The other ui will be created with just read mode outside of this
- . = ..()
+ return ..()
/obj/item/paper/fire_act(exposed_temperature, exposed_volume)
- ..()
- if(!(resistance_flags & FIRE_PROOF))
- add_overlay("paper_onfire_overlay")
+ . = ..()
+ if(.)
info = "[stars(info)]"
-
-/obj/item/paper/extinguish()
- ..()
- cut_overlay("paper_onfire_overlay")
-
-/obj/item/paper/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
+/obj/item/paper/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/default/paper_state/state = new)
+ ui_key = "main-[REF(user)]"
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
var/datum/asset/assets = get_asset_datum(/datum/asset/spritesheet/simple/paper)
@@ -270,34 +321,38 @@
// The x size is because we double the width for the editor
ui = new(user, src, ui_key, "PaperSheet", name, ui_x, ui_y, master_ui, state)
ui.set_autoupdate(FALSE)
+ viewing_ui[user] = ui
ui.open()
+ else
+ var/datum/ui_state/default/paper_state/last_state = ui.state
+ if(last_state)
+ last_state.copy_from(state)
+ else
+ ui.state = state
/obj/item/paper/ui_close(mob/user)
/// close the editing window and change the mode
- if(edit_usr != null && user == edit_usr)
- edit_mode = MODE_READING
- edit_usr = null
- current_stamp = null
- stamp_class = null
-
+ viewing_ui[user] = null
. = ..()
-
-/obj/item/paper/proc/ui_force_close()
- var/datum/tgui/ui = SStgui.try_update_ui(usr, src, "main");
- if(ui)
- ui.close()
-
-
-/obj/item/paper/proc/ui_update()
- var/datum/tgui/ui = SStgui.try_update_ui(usr, src, "main");
- if(ui)
+// Again, we have to do this as autoupdate is off
+/obj/item/paper/proc/update_all_ui()
+ for(var/datum/tgui/ui in viewing_ui)
ui.update()
+// Again, we have to do this as autoupdate is off
+/obj/item/paper/proc/close_all_ui()
+ for(var/datum/tgui/ui in viewing_ui)
+ ui.close()
+ viewing_ui = list()
/obj/item/paper/ui_data(mob/user)
var/list/data = list()
+
+ var/datum/tgui/ui = viewing_ui[user]
+ var/datum/ui_state/default/paper_state/state = ui.state
+
// Should all this go in static data and just do a forced update?
data["text"] = info
data["max_length"] = MAX_PAPER_LENGTH
@@ -305,24 +360,23 @@
data["paper_color"] = !color || color == "white" ? "#FFFFFF" : color // color might not be set
data["stamps"] = stamps
- if(edit_usr == null || user != edit_usr)
- data["edit_mode"] = MODE_READING /// Eveyone else is just an observer
- else
- data["edit_mode"] = edit_mode
+ data["edit_mode"] = state.edit_mode
+ data["edit_usr"] = "[ui.user]";
// pen info for editing
- data["is_crayon"] = is_crayon
- data["pen_font"] = pen_font
- data["pen_color"] = pen_color
-
+ data["is_crayon"] = state.is_crayon
+ data["pen_font"] = state.pen_font
+ data["pen_color"] = state.pen_color
// stamping info for..stamping
- data["stamp_class"] = stamp_class
+ data["stamp_class"] = state.stamp_class
+
data["field_counter"] = field_counter
+ data["form_fields"] = form_fields
return data
-/obj/item/paper/ui_act(action, params)
+/obj/item/paper/ui_act(action, params, datum/tgui/ui, datum/ui_state/default/paper_state/state)
if(..())
return
switch(action)
@@ -335,23 +389,23 @@
stamps = new/list()
if(stamps.len < MAX_PAPER_STAMPS)
// I hate byond when dealing with freaking lists
- stamps += list(list(stamp_class, stamp_x, stamp_y,stamp_r)) /// WHHHHY
+ stamps += list(list(state.stamp_class, stamp_x, stamp_y,stamp_r)) /// WHHHHY
/// This does the overlay stuff
if (isnull(stamped))
stamped = new/list()
if(stamped.len < MAX_PAPER_STAMPS_OVERLAYS)
- var/mutable_appearance/stampoverlay = mutable_appearance('icons/obj/bureaucracy.dmi', "paper_[current_stamp.icon_state]")
+ var/mutable_appearance/stampoverlay = mutable_appearance('icons/obj/bureaucracy.dmi', "paper_[state.stamp_icon_state]")
stampoverlay.pixel_x = rand(-2, 2)
stampoverlay.pixel_y = rand(-3, 2)
add_overlay(stampoverlay)
- LAZYADD(stamped, current_stamp.icon_state)
+ LAZYADD(stamped, state.stamp_icon_state)
- edit_usr.visible_message("[edit_usr] stamps [src] with [current_stamp]!", "You stamp [src] with [current_stamp]!")
+ ui.user.visible_message("[ui.user] stamps [src] with [state.stamp_name]!", "You stamp [src] with [state.stamp_name]!")
else
to_chat(usr, pick("You try to stamp but you miss!", "There is no where else you can stamp!"))
- ui_update()
+ update_all_ui()
. = TRUE
if("save")
@@ -363,31 +417,22 @@
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.
- log_paper("[key_name(edit_usr)] writing to paper [name], and overwrote it by [paper_len-MAX_PAPER_LENGTH], aborting")
- ui_force_close()
- else if(paper_len == 0)
- to_chat(usr, pick("Writing block strikes again!", "You forgot to write anthing!"))
- ui_force_close()
+ // 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
- // Next find the sign marker and replace it with somones sig
- // All other processing should of been done in the js module
- in_paper = sign_regex.Replace(in_paper, "[edit_usr]")
- // Do the same with form fields
- log_paper("[key_name(edit_usr)] writing to paper [name]")
- if(info != in_paper)
- to_chat(usr, "You have added to your paper masterpiece!");
+ 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
- if(!fields) //Possible runtiming
- return
- if(fields && fields.len > 0)
- for(var/key in fields) // In case somone %sign in a field
- form_fields[key] = sign_regex.Replace(fields[key], "[edit_usr]")
- /// Switch ui to reading mode
- edit_mode = MODE_READING
- edit_usr = null
- ui_update()
+ for(var/key in fields)
+ form_fields[key] = fields[key];
+
+
+ update_all_ui()
update_icon()
. = TRUE
@@ -415,6 +460,7 @@
name = "paper scrap"
icon_state = "scrap"
slot_flags = null
+ show_written_words = FALSE
/obj/item/paper/crumpled/update_icon_state()
return
diff --git a/code/modules/paperwork/photocopier.dm b/code/modules/paperwork/photocopier.dm
index cbedb915ec..0b1f3bb01d 100644
--- a/code/modules/paperwork/photocopier.dm
+++ b/code/modules/paperwork/photocopier.dm
@@ -65,16 +65,24 @@
if(C)
copy_as_paper = 0
if(copy_as_paper)
- var/obj/item/paper/c
+ var/obj/item/paper/c = new /obj/item/paper (loc)
if(length(copy.info) > 0) //Only print and add content if the copied doc has words on it
- c = copy.copy(loc)
if(toner > 10) //lots of toner, make it dark
- c.pen_color = "#101010"
+ c.info = ""
else //no toner? shitty copies for you!
- c.pen_color = "#808080"
+ c.info = ""
+ var/copied = copy.info
+ copied = replacetext(copied, ""
+ c.name = copy.name
+ c.update_icon()
+ c.stamps = copy.stamps
+ if(copy.stamped)
+ c.stamped = copy.stamped.Copy()
+ c.copy_overlays(copy, TRUE)
toner--
- else
- c = new(loc) // shoot out blank sheet of paper
busy = TRUE
addtimer(CALLBACK(src, .proc/reset_busy), 1.5 SECONDS)
else