|
|
|
@@ -39,21 +39,29 @@
|
|
|
|
|
name = "canvas"
|
|
|
|
|
desc = "Draw out your soul on this canvas!"
|
|
|
|
|
icon = 'icons/obj/artstuff.dmi'
|
|
|
|
|
icon_state = "square"
|
|
|
|
|
icon_state = "11x11"
|
|
|
|
|
resistance_flags = FLAMMABLE
|
|
|
|
|
var/width = 11
|
|
|
|
|
var/height = 11
|
|
|
|
|
var/list/grid
|
|
|
|
|
var/list/top_colors
|
|
|
|
|
var/canvas_color = "#ffffff" //empty canvas color
|
|
|
|
|
var/ui_x = 400
|
|
|
|
|
var/ui_y = 400
|
|
|
|
|
var/used = FALSE
|
|
|
|
|
var/painting_name //Painting name, this is set after framing.
|
|
|
|
|
var/framed = FALSE //Blocks edits, set on framing
|
|
|
|
|
var/finalized = FALSE //Blocks edits
|
|
|
|
|
var/icon_generated = FALSE
|
|
|
|
|
var/icon/generated_icon
|
|
|
|
|
|
|
|
|
|
// Painting overlay offset when framed
|
|
|
|
|
var/framed_offset_x = 11
|
|
|
|
|
var/framed_offset_y = 10
|
|
|
|
|
|
|
|
|
|
pixel_x = 10
|
|
|
|
|
pixel_y = 9
|
|
|
|
|
|
|
|
|
|
/obj/item/canvas/Initialize()
|
|
|
|
|
. = ..()
|
|
|
|
|
top_colors = list()
|
|
|
|
|
reset_grid()
|
|
|
|
|
|
|
|
|
|
/obj/item/canvas/proc/reset_grid()
|
|
|
|
@@ -85,6 +93,7 @@
|
|
|
|
|
. = ..()
|
|
|
|
|
.["grid"] = grid
|
|
|
|
|
.["name"] = painting_name
|
|
|
|
|
.["finalized"] = finalized
|
|
|
|
|
|
|
|
|
|
/obj/item/canvas/examine(mob/user)
|
|
|
|
|
. = ..()
|
|
|
|
@@ -92,7 +101,7 @@
|
|
|
|
|
|
|
|
|
|
/obj/item/canvas/ui_act(action, params)
|
|
|
|
|
. = ..()
|
|
|
|
|
if(. || framed)
|
|
|
|
|
if(. || finalized)
|
|
|
|
|
return
|
|
|
|
|
var/mob/user = usr
|
|
|
|
|
switch(action)
|
|
|
|
@@ -104,34 +113,50 @@
|
|
|
|
|
var/x = text2num(params["x"])
|
|
|
|
|
var/y = text2num(params["y"])
|
|
|
|
|
grid[x][y] = color
|
|
|
|
|
top_colors = get_most_common_colors(3)
|
|
|
|
|
used = TRUE
|
|
|
|
|
update_icon()
|
|
|
|
|
. = TRUE
|
|
|
|
|
if("finalize")
|
|
|
|
|
. = TRUE
|
|
|
|
|
if(!finalized)
|
|
|
|
|
finalize(user)
|
|
|
|
|
|
|
|
|
|
/obj/item/canvas/proc/finalize(mob/user)
|
|
|
|
|
finalized = TRUE
|
|
|
|
|
generate_proper_overlay()
|
|
|
|
|
try_rename(user)
|
|
|
|
|
|
|
|
|
|
/obj/item/canvas/update_overlays()
|
|
|
|
|
. = ..()
|
|
|
|
|
for(var/i in 2 to top_colors.len) //first is used as base color
|
|
|
|
|
var/mutable_appearance/detail = mutable_appearance(icon, "[icon_state]_detail_[i-1]")
|
|
|
|
|
detail.appearance_flags |= RESET_COLOR
|
|
|
|
|
detail.color = top_colors[i]
|
|
|
|
|
if(!icon_generated)
|
|
|
|
|
if(used)
|
|
|
|
|
var/mutable_appearance/detail = mutable_appearance(icon,"[icon_state]wip")
|
|
|
|
|
detail.pixel_x = 1
|
|
|
|
|
detail.pixel_y = 1
|
|
|
|
|
. += detail
|
|
|
|
|
else
|
|
|
|
|
var/mutable_appearance/detail = mutable_appearance(generated_icon)
|
|
|
|
|
detail.pixel_x = 1
|
|
|
|
|
detail.pixel_y = 1
|
|
|
|
|
. += detail
|
|
|
|
|
|
|
|
|
|
/obj/item/canvas/update_icon_state()
|
|
|
|
|
. = ..()
|
|
|
|
|
if(top_colors.len)
|
|
|
|
|
color = top_colors[1]
|
|
|
|
|
/obj/item/canvas/proc/generate_proper_overlay()
|
|
|
|
|
if(icon_generated)
|
|
|
|
|
return
|
|
|
|
|
var/png_filename = "data/paintings/temp_painting.png"
|
|
|
|
|
var/result = rustg_dmi_create_png(png_filename,"[width]","[height]",get_data_string())
|
|
|
|
|
if(result)
|
|
|
|
|
CRASH("Error generating painting png : [result]")
|
|
|
|
|
generated_icon = new(png_filename)
|
|
|
|
|
icon_generated = TRUE
|
|
|
|
|
update_icon()
|
|
|
|
|
|
|
|
|
|
/obj/item/canvas/proc/get_most_common_colors(count)
|
|
|
|
|
var/list/tally = list()
|
|
|
|
|
for(var/x in 1 to width)
|
|
|
|
|
for(var/y in 1 to height)
|
|
|
|
|
tally[grid[x][y]] += 1
|
|
|
|
|
sortTim(tally,/proc/cmp_numeric_dsc,associative=TRUE)
|
|
|
|
|
. = list()
|
|
|
|
|
for(var/result in tally)
|
|
|
|
|
. += result
|
|
|
|
|
if(length(.) >= count)
|
|
|
|
|
break
|
|
|
|
|
/obj/item/canvas/proc/get_data_string()
|
|
|
|
|
var/list/data = list()
|
|
|
|
|
for(var/y in 1 to height)
|
|
|
|
|
for(var/x in 1 to width)
|
|
|
|
|
data += grid[x][y]
|
|
|
|
|
return data.Join("")
|
|
|
|
|
|
|
|
|
|
//Todo make this element ?
|
|
|
|
|
/obj/item/canvas/proc/get_paint_tool_color(obj/item/I)
|
|
|
|
@@ -153,27 +178,44 @@
|
|
|
|
|
else if(istype(I, /obj/item/soap) || istype(I, /obj/item/reagent_containers/glass/rag))
|
|
|
|
|
return canvas_color
|
|
|
|
|
|
|
|
|
|
/obj/item/canvas/proc/try_rename(mob/user)
|
|
|
|
|
var/new_name = stripped_input(user,"What do you want to name the painting?")
|
|
|
|
|
if(!painting_name && new_name && user.canUseTopic(src,BE_CLOSE))
|
|
|
|
|
painting_name = new_name
|
|
|
|
|
SStgui.update_uis(src)
|
|
|
|
|
|
|
|
|
|
/obj/item/canvas/nineteenXnineteen
|
|
|
|
|
icon_state = "square"
|
|
|
|
|
icon_state = "19x19"
|
|
|
|
|
width = 19
|
|
|
|
|
height = 19
|
|
|
|
|
ui_x = 600
|
|
|
|
|
ui_y = 600
|
|
|
|
|
pixel_x = 6
|
|
|
|
|
pixel_y = 9
|
|
|
|
|
framed_offset_x = 8
|
|
|
|
|
framed_offset_y = 9
|
|
|
|
|
|
|
|
|
|
/obj/item/canvas/twentythreeXnineteen
|
|
|
|
|
icon_state = "wide"
|
|
|
|
|
icon_state = "23x19"
|
|
|
|
|
width = 23
|
|
|
|
|
height = 19
|
|
|
|
|
ui_x = 800
|
|
|
|
|
ui_y = 600
|
|
|
|
|
pixel_x = 4
|
|
|
|
|
pixel_y = 10
|
|
|
|
|
framed_offset_x = 6
|
|
|
|
|
framed_offset_y = 8
|
|
|
|
|
|
|
|
|
|
/obj/item/canvas/twentythreeXtwentythree
|
|
|
|
|
icon_state = "square"
|
|
|
|
|
icon_state = "23x23"
|
|
|
|
|
width = 23
|
|
|
|
|
height = 23
|
|
|
|
|
ui_x = 800
|
|
|
|
|
ui_y = 800
|
|
|
|
|
|
|
|
|
|
pixel_x = 5
|
|
|
|
|
pixel_y = 9
|
|
|
|
|
framed_offset_x = 5
|
|
|
|
|
framed_offset_y = 6
|
|
|
|
|
|
|
|
|
|
/obj/item/wallframe/painting
|
|
|
|
|
name = "painting frame"
|
|
|
|
@@ -191,6 +233,7 @@
|
|
|
|
|
icon_state = "frame-empty"
|
|
|
|
|
buildable_sign = FALSE
|
|
|
|
|
var/obj/item/canvas/C
|
|
|
|
|
var/persistence_id
|
|
|
|
|
|
|
|
|
|
/obj/structure/sign/painting/Initialize(mapload, dir, building)
|
|
|
|
|
. = ..()
|
|
|
|
@@ -217,7 +260,6 @@
|
|
|
|
|
/obj/structure/sign/painting/wirecutter_act(mob/living/user, obj/item/I)
|
|
|
|
|
. = ..()
|
|
|
|
|
if(C)
|
|
|
|
|
C.framed = FALSE
|
|
|
|
|
C.forceMove(drop_location())
|
|
|
|
|
C = null
|
|
|
|
|
to_chat(user, "<span class='notice'>You remove the painting from the frame.</span>")
|
|
|
|
@@ -227,20 +269,98 @@
|
|
|
|
|
/obj/structure/sign/painting/proc/frame_canvas(mob/user,obj/item/canvas/new_canvas)
|
|
|
|
|
if(user.transferItemToLoc(new_canvas,src))
|
|
|
|
|
C = new_canvas
|
|
|
|
|
C.framed = TRUE
|
|
|
|
|
if(!C.finalized)
|
|
|
|
|
C.finalize(user)
|
|
|
|
|
to_chat(user,"<span class='notice'>You frame [C].</span>")
|
|
|
|
|
update_icon()
|
|
|
|
|
|
|
|
|
|
/obj/structure/sign/painting/proc/try_rename(mob/user)
|
|
|
|
|
var/new_name = stripped_input(user,"What do you want to name the painting?")
|
|
|
|
|
if(C && !C.painting_name && new_name && user.canUseTopic(src,BE_CLOSE))
|
|
|
|
|
C.painting_name = new_name
|
|
|
|
|
SStgui.update_uis(C)
|
|
|
|
|
if(!C.painting_name)
|
|
|
|
|
C.try_rename(user)
|
|
|
|
|
|
|
|
|
|
/obj/structure/sign/painting/update_icon_state()
|
|
|
|
|
. = ..()
|
|
|
|
|
if(C && C.generated_icon)
|
|
|
|
|
icon_state = null
|
|
|
|
|
else
|
|
|
|
|
icon_state = "frame-empty"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/obj/structure/sign/painting/update_overlays()
|
|
|
|
|
. = ..()
|
|
|
|
|
if(C && C.top_colors.len)
|
|
|
|
|
var/mutable_appearance/MA = mutable_appearance(icon, "frame-content-overlay")
|
|
|
|
|
MA.appearance_flags |= RESET_COLOR
|
|
|
|
|
MA.color = C.top_colors[1]
|
|
|
|
|
if(C && C.generated_icon)
|
|
|
|
|
var/mutable_appearance/MA = mutable_appearance(C.generated_icon)
|
|
|
|
|
MA.pixel_x = C.framed_offset_x
|
|
|
|
|
MA.pixel_y = C.framed_offset_y
|
|
|
|
|
. += MA
|
|
|
|
|
var/mutable_appearance/frame = mutable_appearance(C.icon,"[C.icon_state]frame")
|
|
|
|
|
frame.pixel_x = C.framed_offset_x - 1
|
|
|
|
|
frame.pixel_y = C.framed_offset_y - 1
|
|
|
|
|
. += frame
|
|
|
|
|
|
|
|
|
|
/obj/structure/sign/painting/proc/load_persistent()
|
|
|
|
|
if(!persistence_id)
|
|
|
|
|
return
|
|
|
|
|
if(!SSpersistence.paintings || !SSpersistence.paintings[persistence_id] || !length(SSpersistence.paintings[persistence_id]))
|
|
|
|
|
return
|
|
|
|
|
var/list/chosen = pick(SSpersistence.paintings[persistence_id])
|
|
|
|
|
var/title = chosen["title"]
|
|
|
|
|
var/png = "data/paintings/[persistence_id]/[chosen["md5"]].png"
|
|
|
|
|
if(!fexists(png))
|
|
|
|
|
stack_trace("Persistent painting [chosen["md5"]].png was not found in [persistence_id] directory.")
|
|
|
|
|
return
|
|
|
|
|
var/icon/I = new(png)
|
|
|
|
|
var/obj/item/canvas/new_canvas
|
|
|
|
|
var/w = I.Width()
|
|
|
|
|
var/h = I.Height()
|
|
|
|
|
for(var/T in typesof(/obj/item/canvas))
|
|
|
|
|
new_canvas = T
|
|
|
|
|
if(initial(new_canvas.width) == w && initial(new_canvas.height) == h)
|
|
|
|
|
new_canvas = new T(src)
|
|
|
|
|
break
|
|
|
|
|
new_canvas.fill_grid_from_icon(I)
|
|
|
|
|
new_canvas.generated_icon = I
|
|
|
|
|
new_canvas.icon_generated = TRUE
|
|
|
|
|
new_canvas.finalized = TRUE
|
|
|
|
|
new_canvas.painting_name = title
|
|
|
|
|
C = new_canvas
|
|
|
|
|
update_icon()
|
|
|
|
|
|
|
|
|
|
/obj/structure/sign/painting/proc/save_persistent()
|
|
|
|
|
if(!persistence_id || !C)
|
|
|
|
|
return
|
|
|
|
|
if(sanitize_filename(persistence_id) != persistence_id)
|
|
|
|
|
stack_trace("Invalid persistence_id - [persistence_id]")
|
|
|
|
|
return
|
|
|
|
|
var/data = C.get_data_string()
|
|
|
|
|
var/md5 = md5(data)
|
|
|
|
|
var/list/current = SSpersistence.paintings[persistence_id]
|
|
|
|
|
if(!current)
|
|
|
|
|
current = list()
|
|
|
|
|
for(var/list/entry in current)
|
|
|
|
|
if(entry["md5"] == md5)
|
|
|
|
|
return
|
|
|
|
|
var/png_directory = "data/paintings/[persistence_id]/"
|
|
|
|
|
var/png_path = png_directory + "[md5].png"
|
|
|
|
|
var/result = rustg_dmi_create_png(png_path,"[C.width]","[C.height]",data)
|
|
|
|
|
if(result)
|
|
|
|
|
CRASH("Error saving persistent painting: [result]")
|
|
|
|
|
current += list(list("title" = C.painting_name , "md5" = md5))
|
|
|
|
|
SSpersistence.paintings[persistence_id] = current
|
|
|
|
|
|
|
|
|
|
/obj/item/canvas/proc/fill_grid_from_icon(icon/I)
|
|
|
|
|
var/w = I.Width() + 1
|
|
|
|
|
var/h = I.Height() + 1
|
|
|
|
|
for(var/x in 1 to width)
|
|
|
|
|
for(var/y in 1 to height)
|
|
|
|
|
grid[x][y] = I.GetPixel(w-x,h-y)
|
|
|
|
|
|
|
|
|
|
//Presets for art gallery mapping, for paintings to be shared across stations
|
|
|
|
|
/obj/structure/sign/painting/library
|
|
|
|
|
persistence_id = "library"
|
|
|
|
|
|
|
|
|
|
/obj/structure/sign/painting/library_secure
|
|
|
|
|
persistence_id = "library_secure"
|
|
|
|
|
|
|
|
|
|
/obj/structure/sign/painting/library_private // keep your smut away from prying eyes, or non-librarians at least
|
|
|
|
|
persistence_id = "library_private"
|
|
|
|
|