mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-28 23:58:07 +01:00
[MIRROR] Paintings improvements. [MDB IGNORE] (#9977)
* Paintings improvements. (#63170) About The Pull Request Paintings can now do stroke painting. Added painting management panel for admins. Paintings now display author's character name, year of painting, medium and patron when hung on wall. You can become new patron by paying more than the previous one. Added painter's palettes to library vendor. (Sprites by @ Mickyan ) Backend changes: Images are now stored in /data/paintings/images/*.png instead of /data/paintings/[category]/*.png Old categories are now just tags Screens & Video Changelog cl add: You can now become patron of your favorite painting by buying sponsorship from Nanotrasen Trust Foundation. add: Painter's palettes are now available at library vendor. qol: Can use strokes in paintings now /cl * Paintings improvements. Co-authored-by: AnturK <AnturK@users.noreply.github.com>
This commit is contained in:
+153
-82
@@ -45,16 +45,18 @@
|
||||
var/width = 11
|
||||
var/height = 11
|
||||
var/list/grid
|
||||
var/canvas_color = "#ffffff" //empty canvas color
|
||||
/// empty canvas color
|
||||
var/canvas_color = "#ffffff"
|
||||
/// Is it clean canvas or was there something painted on it at some point, used to decide when to show wip splotch overlay
|
||||
var/used = FALSE
|
||||
var/painting_name = "Untitled Artwork" //Painting name, this is set after framing.
|
||||
var/finalized = FALSE //Blocks edits
|
||||
var/author_ckey
|
||||
var/icon_generated = FALSE
|
||||
var/icon/generated_icon
|
||||
///boolean that blocks persistence from saving it. enabled from printing copies, because we do not want to save copies.
|
||||
var/no_save = FALSE
|
||||
|
||||
var/datum/painting/painting_metadata
|
||||
|
||||
// Painting overlay offset when framed
|
||||
var/framed_offset_x = 11
|
||||
var/framed_offset_y = 10
|
||||
@@ -66,6 +68,12 @@
|
||||
. = ..()
|
||||
reset_grid()
|
||||
|
||||
painting_metadata = new
|
||||
painting_metadata.title = "Untitled Artwork"
|
||||
painting_metadata.creation_round_id = GLOB.round_id
|
||||
painting_metadata.width = width
|
||||
painting_metadata.height = height
|
||||
|
||||
/obj/item/canvas/proc/reset_grid()
|
||||
grid = new/list(width,height)
|
||||
for(var/x in 1 to width)
|
||||
@@ -86,7 +94,6 @@
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "Canvas", name)
|
||||
ui.set_autoupdate(FALSE)
|
||||
ui.open()
|
||||
|
||||
/obj/item/canvas/attackby(obj/item/I, mob/living/user, params)
|
||||
@@ -98,8 +105,15 @@
|
||||
/obj/item/canvas/ui_data(mob/user)
|
||||
. = ..()
|
||||
.["grid"] = grid
|
||||
.["name"] = painting_name
|
||||
.["name"] = painting_metadata.title
|
||||
.["author"] = painting_metadata.creator_name
|
||||
.["patron"] = painting_metadata.patron_name
|
||||
.["medium"] = painting_metadata.medium
|
||||
.["date"] = painting_metadata.creation_date
|
||||
.["finalized"] = finalized
|
||||
.["editable"] = !finalized //Ideally you should be able to draw moustaches on existing paintings in the gallery but that's not implemented yet
|
||||
.["show_plaque"] = istype(loc,/obj/structure/sign/painting)
|
||||
.["paint_tool_color"] = get_paint_tool_color(user.get_active_held_item())
|
||||
|
||||
/obj/item/canvas/examine(mob/user)
|
||||
. = ..()
|
||||
@@ -107,32 +121,79 @@
|
||||
|
||||
/obj/item/canvas/ui_act(action, params)
|
||||
. = ..()
|
||||
if(. || finalized)
|
||||
if(.)
|
||||
return
|
||||
var/mob/user = usr
|
||||
switch(action)
|
||||
if("paint")
|
||||
if(finalized)
|
||||
return TRUE
|
||||
var/obj/item/I = user.get_active_held_item()
|
||||
var/color = get_paint_tool_color(I)
|
||||
if(!color)
|
||||
var/tool_color = get_paint_tool_color(I)
|
||||
if(!tool_color)
|
||||
return FALSE
|
||||
var/x = text2num(params["x"])
|
||||
var/y = text2num(params["y"])
|
||||
grid[x][y] = color
|
||||
var/list/data = params["data"]
|
||||
//could maybe validate continuity but eh
|
||||
for(var/point in data)
|
||||
var/x = text2num(point["x"])
|
||||
var/y = text2num(point["y"])
|
||||
grid[x][y] = tool_color
|
||||
var/medium = get_paint_tool_medium(I)
|
||||
if(medium && painting_metadata.medium && painting_metadata.medium != medium)
|
||||
painting_metadata.medium = "Mixed medium"
|
||||
else
|
||||
painting_metadata.medium = medium
|
||||
used = TRUE
|
||||
update_appearance()
|
||||
. = TRUE
|
||||
if("finalize")
|
||||
. = TRUE
|
||||
if(!finalized)
|
||||
finalize(user)
|
||||
finalize(user)
|
||||
if("patronage")
|
||||
. = TRUE
|
||||
patron(user)
|
||||
|
||||
/obj/item/canvas/proc/finalize(mob/user)
|
||||
if(painting_metadata.loaded_from_json || finalized)
|
||||
return
|
||||
finalized = TRUE
|
||||
author_ckey = user.ckey
|
||||
painting_metadata.creator_ckey = user.ckey
|
||||
painting_metadata.creator_name = user.real_name
|
||||
painting_metadata.creation_date = time2text(world.realtime)
|
||||
painting_metadata.creation_round_id = GLOB.round_id
|
||||
generate_proper_overlay()
|
||||
try_rename(user)
|
||||
|
||||
/obj/item/canvas/proc/patron(mob/user)
|
||||
if(!finalized || !painting_metadata.loaded_from_json || !isliving(user))
|
||||
return
|
||||
var/mob/living/living_user = user
|
||||
var/obj/item/card/id/id_card = living_user.get_idcard(TRUE)
|
||||
if(!id_card)
|
||||
to_chat(user,span_notice("You don't even have a id and you want to be an art patron?"))
|
||||
return
|
||||
if(!id_card.registered_account || !id_card.registered_account.account_job)
|
||||
to_chat(user,span_notice("No valid non-departamental account found."))
|
||||
return
|
||||
var/datum/bank_account/account = id_card.registered_account
|
||||
if(account.account_balance < painting_metadata.credit_value)
|
||||
to_chat(user,span_notice("You can't afford this."))
|
||||
return
|
||||
var/sniped_amount = painting_metadata.credit_value
|
||||
var/offer_amount = input(user,"How much do you want to offer ? Minimum : [painting_metadata.credit_value]","Patronage Amount", painting_metadata.credit_value + 1) as num|null
|
||||
if(account.account_balance < offer_amount)
|
||||
to_chat(user,span_notice("You can't afford this."))
|
||||
return
|
||||
if(!offer_amount || sniped_amount != painting_metadata.credit_value || offer_amount < painting_metadata.credit_value+1 || !user.canUseTopic(src))
|
||||
return
|
||||
if(!account.adjust_money(-offer_amount))
|
||||
to_chat(user,span_warning("Transaction failure. Please try again."))
|
||||
return
|
||||
painting_metadata.patron_ckey = user.ckey
|
||||
painting_metadata.patron_name = user.real_name
|
||||
painting_metadata.credit_value = offer_amount
|
||||
to_chat(user,span_notice("Nanotrasen Trust Foundation thanks you for your contribution. You're now offical patron of this painting."))
|
||||
|
||||
/obj/item/canvas/update_overlays()
|
||||
. = ..()
|
||||
if(icon_generated)
|
||||
@@ -153,9 +214,11 @@
|
||||
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())
|
||||
var/image_data = get_data_string()
|
||||
var/result = rustg_dmi_create_png(png_filename, "[width]", "[height]", image_data)
|
||||
if(result)
|
||||
CRASH("Error generating painting png : [result]")
|
||||
painting_metadata.md5 = md5(lowertext(image_data))
|
||||
generated_icon = new(png_filename)
|
||||
icon_generated = TRUE
|
||||
update_appearance()
|
||||
@@ -168,14 +231,17 @@
|
||||
return data.Join("")
|
||||
|
||||
//Todo make this element ?
|
||||
/obj/item/canvas/proc/get_paint_tool_color(obj/item/I)
|
||||
if(!I)
|
||||
/obj/item/canvas/proc/get_paint_tool_color(obj/item/painting_implement)
|
||||
if(!painting_implement)
|
||||
return
|
||||
if(istype(I, /obj/item/toy/crayon))
|
||||
var/obj/item/toy/crayon/crayon = I
|
||||
if(istype(painting_implement, /obj/item/paint_palette))
|
||||
var/obj/item/paint_palette/palette = painting_implement
|
||||
return palette.current_color
|
||||
if(istype(painting_implement, /obj/item/toy/crayon))
|
||||
var/obj/item/toy/crayon/crayon = painting_implement
|
||||
return crayon.paint_color
|
||||
else if(istype(I, /obj/item/pen))
|
||||
var/obj/item/pen/P = I
|
||||
else if(istype(painting_implement, /obj/item/pen))
|
||||
var/obj/item/pen/P = painting_implement
|
||||
switch(P.colour)
|
||||
if("black")
|
||||
return "#000000"
|
||||
@@ -184,14 +250,37 @@
|
||||
if("red")
|
||||
return "#ff0000"
|
||||
return P.colour
|
||||
else if(istype(I, /obj/item/soap) || istype(I, /obj/item/reagent_containers/glass/rag))
|
||||
else if(istype(painting_implement, /obj/item/soap) || istype(painting_implement, /obj/item/reagent_containers/glass/rag))
|
||||
return canvas_color
|
||||
|
||||
/// Generates medium description
|
||||
/obj/item/canvas/proc/get_paint_tool_medium(obj/item/painting_implement)
|
||||
if(!painting_implement)
|
||||
return
|
||||
if(istype(painting_implement, /obj/item/paint_palette))
|
||||
return "Oil on canvas"
|
||||
else if(istype(painting_implement, /obj/item/toy/crayon/spraycan))
|
||||
return "Spraycan on canvas"
|
||||
else if(istype(painting_implement, /obj/item/toy/crayon))
|
||||
return "Crayon on canvas"
|
||||
else if(istype(painting_implement, /obj/item/pen))
|
||||
return "Ink on canvas"
|
||||
else if(istype(painting_implement, /obj/item/soap) || istype(painting_implement, /obj/item/reagent_containers/glass/rag))
|
||||
return //These are just for cleaning, ignore them
|
||||
else
|
||||
return "Unknown medium"
|
||||
|
||||
/obj/item/canvas/proc/try_rename(mob/user)
|
||||
if(painting_metadata.loaded_from_json) // No renaming old paintings
|
||||
return
|
||||
var/new_name = stripped_input(user,"What do you want to name the painting?")
|
||||
if(new_name != painting_name && new_name && user.canUseTopic(src,BE_CLOSE))
|
||||
painting_name = new_name
|
||||
SStgui.update_uis(src)
|
||||
if(new_name != painting_metadata.title && new_name && user.canUseTopic(src, BE_CLOSE))
|
||||
painting_metadata.title = new_name
|
||||
var/sign_choice = tgui_alert(user, "Do you want to sign it or remain anonymous?", "Sign painting?", list("Yes", "No"))
|
||||
if(sign_choice != "Yes")
|
||||
painting_metadata.creator_name = "Anonymous"
|
||||
SStgui.update_uis(src)
|
||||
|
||||
|
||||
/obj/item/canvas/nineteen_nineteen
|
||||
name = "canvas (19x19)"
|
||||
@@ -271,7 +360,7 @@
|
||||
/obj/structure/sign/painting/attackby(obj/item/I, mob/user, params)
|
||||
if(!current_canvas && istype(I, /obj/item/canvas))
|
||||
frame_canvas(user,I)
|
||||
else if(current_canvas && current_canvas.painting_name == initial(current_canvas.painting_name) && istype(I,/obj/item/pen))
|
||||
else if(current_canvas && current_canvas.painting_metadata.title == initial(current_canvas.painting_metadata.title) && istype(I,/obj/item/pen))
|
||||
try_rename(user)
|
||||
else
|
||||
return ..()
|
||||
@@ -302,11 +391,11 @@
|
||||
update_appearance()
|
||||
|
||||
/obj/structure/sign/painting/proc/try_rename(mob/user)
|
||||
if(current_canvas.painting_name == initial(current_canvas.painting_name))
|
||||
if(current_canvas.painting_metadata.title == initial(current_canvas.painting_metadata.title))
|
||||
current_canvas.try_rename(user)
|
||||
|
||||
/obj/structure/sign/painting/update_name(updates)
|
||||
name = current_canvas ? "painting - [current_canvas.painting_name]" : initial(name)
|
||||
name = current_canvas ? "painting - [current_canvas.painting_metadata.title]" : initial(name)
|
||||
return ..()
|
||||
|
||||
/obj/structure/sign/painting/update_desc(updates)
|
||||
@@ -337,24 +426,13 @@
|
||||
* Deleting paintings leaves their json, so this proc will remove the json and try again if it finds one of those.
|
||||
*/
|
||||
/obj/structure/sign/painting/proc/load_persistent()
|
||||
if(!persistence_id || !SSpersistent_paintings.paintings[persistence_id])
|
||||
if(!persistence_id)
|
||||
return
|
||||
var/list/painting_category = SSpersistent_paintings.paintings[persistence_id]
|
||||
var/list/painting
|
||||
while(!painting)
|
||||
if(!length(SSpersistent_paintings.paintings[persistence_id]))
|
||||
return //aborts loading anything this category has no usable paintings
|
||||
var/list/chosen = pick(painting_category)
|
||||
if(!fexists("data/paintings/[persistence_id]/[chosen["md5"]].png")) //shitmin deleted this art, lets remove json entry to avoid errors
|
||||
painting_category -= list(chosen)
|
||||
continue //and try again
|
||||
painting = chosen
|
||||
var/title = painting["title"]
|
||||
var/author = painting["ckey"]
|
||||
var/png = "data/paintings/[persistence_id]/[painting["md5"]].png"
|
||||
if(!title)
|
||||
title = "Untitled Artwork" //legacy artwork allowed null names which was bad for the json, lets fix that
|
||||
painting["title"] = title
|
||||
var/list/valid_paintings = SSpersistent_paintings.get_paintings_with_tag(persistence_id)
|
||||
if(!length(valid_paintings))
|
||||
return //aborts loading anything this category has no usable paintings
|
||||
var/datum/painting/painting = pick(valid_paintings)
|
||||
var/png = "data/paintings/images/[painting.md5].png"
|
||||
var/icon/I = new(png)
|
||||
var/obj/item/canvas/new_canvas
|
||||
var/w = I.Width()
|
||||
@@ -364,39 +442,43 @@
|
||||
if(initial(new_canvas.width) == w && initial(new_canvas.height) == h)
|
||||
new_canvas = new T(src)
|
||||
break
|
||||
if(!istype(new_canvas))
|
||||
CRASH("Found painting size with no matching canvas type")
|
||||
new_canvas.painting_metadata = painting
|
||||
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
|
||||
new_canvas.author_ckey = author
|
||||
new_canvas.name = "painting - [title]"
|
||||
new_canvas.name = "painting - [painting.title]"
|
||||
current_canvas = new_canvas
|
||||
current_canvas.update_appearance()
|
||||
update_appearance()
|
||||
|
||||
/obj/structure/sign/painting/proc/save_persistent()
|
||||
if(!persistence_id || !current_canvas || current_canvas.no_save)
|
||||
if(!persistence_id || !current_canvas || current_canvas.no_save || current_canvas.painting_metadata.loaded_from_json)
|
||||
return
|
||||
if(SANITIZE_FILENAME(persistence_id) != persistence_id)
|
||||
stack_trace("Invalid persistence_id - [persistence_id]")
|
||||
return
|
||||
if(!current_canvas.painting_name)
|
||||
current_canvas.painting_name = "Untitled Artwork"
|
||||
var/data = current_canvas.get_data_string()
|
||||
var/md5 = md5(lowertext(data))
|
||||
var/list/current = SSpersistent_paintings.paintings[persistence_id]
|
||||
if(!current)
|
||||
current = list()
|
||||
for(var/list/entry in current)
|
||||
if(entry["md5"] == md5)
|
||||
for(var/datum/painting/entry in SSpersistent_paintings.paintings)
|
||||
if(entry.md5 == md5) // No duplicates
|
||||
return
|
||||
var/png_directory = "data/paintings/[persistence_id]/"
|
||||
current_canvas.painting_metadata.md5 = md5
|
||||
if(!current_canvas.painting_metadata.tags)
|
||||
current_canvas.painting_metadata.tags = list(persistence_id)
|
||||
else
|
||||
current_canvas.painting_metadata.tags |= persistence_id
|
||||
var/png_directory = "data/paintings/images/"
|
||||
var/png_path = png_directory + "[md5].png"
|
||||
var/result = rustg_dmi_create_png(png_path,"[current_canvas.width]","[current_canvas.height]",data)
|
||||
if(result)
|
||||
CRASH("Error saving persistent painting: [result]")
|
||||
current += list(list("title" = current_canvas.painting_name , "md5" = md5, "ckey" = current_canvas.author_ckey))
|
||||
SSpersistent_paintings.paintings[persistence_id] = current
|
||||
SSpersistent_paintings.paintings += current_canvas.painting_metadata
|
||||
|
||||
/obj/item/canvas/proc/fill_grid_from_icon(icon/I)
|
||||
var/h = I.Height() + 1
|
||||
@@ -423,31 +505,20 @@
|
||||
desc_with_canvas = "A painting hung away from lesser minds."
|
||||
persistence_id = "library_private"
|
||||
|
||||
/obj/structure/sign/painting/vv_get_dropdown()
|
||||
. = ..()
|
||||
VV_DROPDOWN_OPTION(VV_HK_REMOVE_PAINTING, "Remove Persistent Painting")
|
||||
/// Simple painting utility.
|
||||
/obj/item/paint_palette
|
||||
name = "paint palette"
|
||||
desc = "paintbrush included"
|
||||
icon = 'icons/obj/artstuff.dmi'
|
||||
icon_state = "palette"
|
||||
lefthand_file = 'icons/mob/inhands/equipment/palette_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/equipment/palette_righthand.dmi'
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
///Chosen paint color
|
||||
var/current_color
|
||||
|
||||
/obj/structure/sign/painting/vv_do_topic(list/href_list)
|
||||
/obj/item/paint_palette/attack_self(mob/user, modifiers)
|
||||
. = ..()
|
||||
if(href_list[VV_HK_REMOVE_PAINTING])
|
||||
if(!check_rights(NONE))
|
||||
return
|
||||
var/mob/user = usr
|
||||
if(!persistence_id || !current_canvas)
|
||||
to_chat(user,span_warning("This is not a persistent painting."))
|
||||
return
|
||||
var/md5 = md5(lowertext(current_canvas.get_data_string()))
|
||||
var/author = current_canvas.author_ckey
|
||||
var/list/current = SSpersistent_paintings.paintings[persistence_id]
|
||||
if(current)
|
||||
for(var/list/entry in current)
|
||||
if(entry["md5"] == md5)
|
||||
current -= entry
|
||||
var/png = "data/paintings/[persistence_id]/[md5].png"
|
||||
fdel(png)
|
||||
for(var/obj/structure/sign/painting/painting as anything in SSpersistent_paintings.painting_frames)
|
||||
if(painting.current_canvas && md5(painting.current_canvas.get_data_string()) == md5)
|
||||
QDEL_NULL(painting.current_canvas)
|
||||
painting.update_appearance()
|
||||
log_admin("[key_name(user)] has deleted a persistent painting made by [author].")
|
||||
message_admins(span_notice("[key_name_admin(user)] has deleted persistent painting made by [author]."))
|
||||
var/chosen_color = input(user,"Pick new color","Palette") as color|null
|
||||
if(chosen_color)
|
||||
current_color = chosen_color
|
||||
|
||||
Reference in New Issue
Block a user