mirror of
https://github.com/VOREStation/VOREStation.git
synced 2026-03-30 08:33:15 +01:00
* Begin clickcode attack_self fix Begins the work to make everything call back to parent for attack_self so that signals are sacred. * Makes MORE things call the attack_self() parent Yes, I could make special_handling a var on obj/item HOWEVER i want it to be specific so it can be tracked down later and ONLY the objects that use it can be refactored instead of sitting there literally forever and it just becoming 'a thing'. * Finishes making the rest of attack_self call parent. As mentioned, things such as 'specialty_goggles' 'special_handling' and the such are only there to help with attack_self until the attack_self is recoded for those items. * begone foul demon * some more cleanup * These * GOD this was annoying * yeh * Fix this * fLARES * Thesee too * toys! * Even more! * More fixes * Even more * rest of em * these too * Update syndie.dm * hardref clear * Update code/game/gamemodes/nuclear/pinpointer.dm * Update code/game/objects/effects/mines.dm * Update code/game/objects/items/blueprints_vr.dm * Update code/game/objects/items/blueprints_vr.dm * Update code/game/objects/items/contraband_vr.dm * Update code/game/objects/items/crayons.dm * Update code/game/objects/items/crayons.dm * Update code/game/objects/items/gunbox.dm * Update code/game/objects/items/gunbox.dm * Update code/game/objects/items/gunbox_vr.dm * Update code/game/objects/items/gunbox_vr.dm * Update code/game/objects/items/weapons/gift_wrappaper.dm * Update code/game/objects/items/crayons.dm * Update code/game/objects/items/crayons.dm * Update code/game/objects/items/gunbox.dm * these too * Update maintpanel_stack.dm * angry warning * Fixes packaged snacks. Fixes improper var default. * Special handling for these * proper poly types * Fixes magclaws Makes the 'features' it had just part of base magboots that can be adjusted via varswap. * Fixes jackets Fixes https://github.com/VOREStation/VOREStation/issues/18941 * Small bugfix Makes p_Theyre properly capitialize Makes examine show proper wording * Update gift_wrappaper.dm
701 lines
23 KiB
Plaintext
701 lines
23 KiB
Plaintext
|
|
///////////
|
|
// EASEL //
|
|
///////////
|
|
|
|
/obj/structure/easel
|
|
name = "easel"
|
|
desc = "Only for the finest of art!"
|
|
icon = 'icons/obj/artstuff.dmi'
|
|
icon_state = "easel"
|
|
density = TRUE
|
|
//resistance_flags = FLAMMABLE
|
|
//max_integrity = 60
|
|
var/obj/item/canvas/painting = null
|
|
|
|
/obj/structure/easel/Initialize(mapload)
|
|
. = ..()
|
|
AddElement(/datum/element/climbable)
|
|
|
|
//Adding canvases
|
|
/obj/structure/easel/attackby(obj/item/I, mob/user, params)
|
|
if(istype(I, /obj/item/canvas))
|
|
var/obj/item/canvas/canvas = I
|
|
user.drop_from_inventory(canvas)
|
|
painting = canvas
|
|
canvas.forceMove(get_turf(src))
|
|
canvas.layer = layer+0.1
|
|
user.visible_message(span_notice("[user] puts \the [canvas] on \the [src]."),span_notice("You place \the [canvas] on \the [src]."))
|
|
else
|
|
return ..()
|
|
|
|
|
|
//Stick to the easel like glue
|
|
/obj/structure/easel/Move()
|
|
var/turf/T = get_turf(src)
|
|
. = ..()
|
|
if(painting && painting.loc == T) //Only move if it's near us.
|
|
painting.forceMove(get_turf(src))
|
|
else
|
|
painting = null
|
|
|
|
/obj/item/canvas
|
|
name = "canvas"
|
|
desc = "Draw out your soul on this canvas!"
|
|
icon = 'icons/obj/artstuff.dmi'
|
|
icon_state = "11x11"
|
|
//flags_1 = UNPAINTABLE_1
|
|
//resistance_flags = FLAMMABLE
|
|
var/width = 11
|
|
var/height = 11
|
|
var/list/grid
|
|
var/canvas_color = "#ffffff" //empty canvas color
|
|
var/used = FALSE
|
|
var/painting_name = "Untitled Artwork" //Painting name, this is set after framing.
|
|
var/finalized = FALSE //Blocks edits
|
|
var/author_name
|
|
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
|
|
|
|
/// From the origin of the turf we're on, where should the left of the canvas pixel be
|
|
var/framed_offset_x = 11
|
|
/// From the origin of the turf we're on, where should the bottom of the canvas be
|
|
var/framed_offset_y = 10
|
|
/// The frame takes the painting's offset, then moves this X offset
|
|
var/frame_offset_x = -1
|
|
/// The frame takes the painting's offset, then moves this Y offset
|
|
var/frame_offset_y = -1
|
|
|
|
pixel_x = 10
|
|
pixel_y = 9
|
|
|
|
/obj/item/canvas/Initialize(mapload)
|
|
. = ..()
|
|
reset_grid()
|
|
desc += " (Canvas size is [width]x[height].)"
|
|
|
|
/obj/item/canvas/proc/reset_grid()
|
|
grid = new/list(width,height)
|
|
for(var/x in 1 to width)
|
|
for(var/y in 1 to height)
|
|
grid[x][y] = canvas_color
|
|
|
|
/obj/item/canvas/attack_self(mob/user)
|
|
. = ..(user)
|
|
if(.)
|
|
return TRUE
|
|
tgui_interact(user)
|
|
|
|
/obj/item/canvas/dropped(mob/user)
|
|
pixel_x = initial(pixel_x)
|
|
pixel_y = initial(pixel_y)
|
|
return ..()
|
|
|
|
/obj/item/canvas/tgui_state(mob/user)
|
|
if(finalized)
|
|
return GLOB.tgui_physical_obscured_state
|
|
else
|
|
return GLOB.tgui_default_state
|
|
|
|
/obj/item/canvas/tgui_interact(mob/user, datum/tgui/ui)
|
|
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)
|
|
if(istype(I, /obj/item/paint_palette))
|
|
var/choice = tgui_alert(user, "Adjusting the base color of this canvas will replace ALL pixels with the selected color. Are you sure?", "Confirm Color Fill", list("Yes", "No"))
|
|
if(choice != "Yes")
|
|
return
|
|
var/basecolor = tgui_color_picker(user, "Select a base color for the canvas:", "Base Color", canvas_color)
|
|
if(basecolor && Adjacent(user) && user.get_active_hand() == I)
|
|
canvas_color = basecolor
|
|
reset_grid()
|
|
user.visible_message("[user] smears paint on [src], covering the entire thing in paint.", "You smear paint on [src], changing the color of the entire thing.", runemessage = "smears paint")
|
|
update_appearance()
|
|
return
|
|
|
|
if(user.a_intent == I_HELP)
|
|
tgui_interact(user)
|
|
else
|
|
return ..()
|
|
|
|
/obj/item/canvas/tgui_data(mob/user)
|
|
. = ..()
|
|
.["grid"] = grid
|
|
.["name"] = painting_name
|
|
.["finalized"] = finalized
|
|
|
|
/obj/item/canvas/examine(mob/user)
|
|
. = ..()
|
|
tgui_interact(user)
|
|
|
|
/obj/item/canvas/tgui_act(action, params, datum/tgui/ui)
|
|
. = ..()
|
|
if(. || finalized)
|
|
return
|
|
switch(action)
|
|
if("paint")
|
|
var/obj/item/I = ui.user.get_active_hand()
|
|
var/color = get_paint_tool_color(I)
|
|
if(!color)
|
|
return FALSE
|
|
var/x = text2num(params["x"])
|
|
var/y = text2num(params["y"])
|
|
grid[x][y] = color
|
|
used = TRUE
|
|
update_appearance()
|
|
. = TRUE
|
|
if("finalize")
|
|
. = TRUE
|
|
if(!finalized)
|
|
finalize(ui.user)
|
|
|
|
/obj/item/canvas/proc/finalize(mob/user)
|
|
finalized = TRUE
|
|
author_name = user.real_name
|
|
author_ckey = user.ckey
|
|
generate_proper_overlay()
|
|
try_rename(user)
|
|
|
|
/obj/item/canvas/proc/update_appearance()
|
|
cut_overlays()
|
|
if(icon_generated)
|
|
var/mutable_appearance/detail = mutable_appearance(generated_icon)
|
|
detail.pixel_x = 1
|
|
detail.pixel_y = 1
|
|
add_overlay(detail)
|
|
return
|
|
if(!used)
|
|
return
|
|
|
|
var/mutable_appearance/detail = mutable_appearance(icon, "[icon_state]wip")
|
|
detail.pixel_x = 1
|
|
detail.pixel_y = 1
|
|
add_overlay(detail)
|
|
|
|
/obj/item/canvas/proc/generate_proper_overlay()
|
|
if(icon_generated)
|
|
return
|
|
var/png_filename = "data/persistent/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_appearance()
|
|
|
|
/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)
|
|
if(!I)
|
|
return
|
|
if(istype(I, /obj/item/paint_brush))
|
|
var/obj/item/paint_brush/P = I
|
|
return P.selected_color
|
|
else if(istype(I, /obj/item/pen/crayon))
|
|
var/obj/item/pen/crayon/crayon = I
|
|
return crayon.colour
|
|
else if(istype(I, /obj/item/pen))
|
|
var/obj/item/pen/P = I
|
|
switch(P.colour)
|
|
if("black")
|
|
return "#000000"
|
|
if("blue")
|
|
return "#0000ff"
|
|
if("red")
|
|
return "#ff0000"
|
|
return P.colour
|
|
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 = tgui_input_text(user,"What do you want to name the painting?", max_length = 250, encode=TRUE)
|
|
if(new_name != painting_name && new_name && CanUseTopic(user, GLOB.tgui_physical_state))
|
|
painting_name = new_name
|
|
SStgui.update_uis(src)
|
|
|
|
/obj/item/canvas/nineteen_nineteen
|
|
icon_state = "19x19"
|
|
width = 19
|
|
height = 19
|
|
pixel_x = 5
|
|
pixel_y = 10
|
|
framed_offset_x = 8
|
|
framed_offset_y = 9
|
|
|
|
/obj/item/canvas/twentythree_nineteen
|
|
icon_state = "23x19"
|
|
width = 23
|
|
height = 19
|
|
pixel_x = 4
|
|
pixel_y = 10
|
|
framed_offset_x = 6
|
|
framed_offset_y = 8
|
|
|
|
/obj/item/canvas/twentythree_twentythree
|
|
icon_state = "23x23"
|
|
width = 23
|
|
height = 23
|
|
pixel_x = 5
|
|
pixel_y = 9
|
|
framed_offset_x = 5
|
|
framed_offset_y = 6
|
|
|
|
/obj/item/canvas/twentyfour_twentyfour
|
|
//name = "ai universal standard canvas" // Uncomment this when AI can actually
|
|
//desc = "Besides being very large, the AI can accept these as a display from their internal database after you've hung it up." // Not yet
|
|
icon_state = "24x24"
|
|
width = 24
|
|
height = 24
|
|
pixel_x = 2
|
|
pixel_y = 2
|
|
framed_offset_x = 4
|
|
framed_offset_y = 4
|
|
frame_offset_x = -2
|
|
frame_offset_y = -2
|
|
|
|
/obj/item/paint_brush
|
|
name = "artist's paintbrush"
|
|
desc = "When you really want to put together a masterpiece!"
|
|
description_info = "Hit this on a palette to set the color, and use it on a canvas to paint with that color."
|
|
icon = 'icons/obj/artstuff.dmi'
|
|
icon_state = "brush"
|
|
var/selected_color = "#000000"
|
|
var/image/color_drop
|
|
var/hud_level = FALSE
|
|
|
|
/obj/item/paint_brush/Initialize(mapload)
|
|
. = ..()
|
|
color_drop = image(icon, null, "brush_color")
|
|
color_drop.color = selected_color
|
|
|
|
// When picked up
|
|
/obj/item/paint_brush/hud_layerise()
|
|
. = ..()
|
|
hud_level = TRUE
|
|
update_paint()
|
|
|
|
// When put down
|
|
/obj/item/paint_brush/reset_plane_and_layer()
|
|
. = ..()
|
|
hud_level = FALSE
|
|
update_paint()
|
|
|
|
/obj/item/paint_brush/proc/update_paint(var/new_color)
|
|
if(new_color)
|
|
selected_color = new_color
|
|
color_drop.color = new_color
|
|
|
|
cut_overlays()
|
|
if(hud_level)
|
|
add_overlay(color_drop)
|
|
|
|
/obj/item/paint_palette
|
|
name = "artist's palette"
|
|
desc = "Helps to have a paintbrush, too."
|
|
description_info = "You can hit this on a canvas to set the entire canvas color (but note that it will wipe out any works in progress). You can hit a paintbrush on this to set the color."
|
|
icon = 'icons/obj/artstuff.dmi'
|
|
icon_state = "palette"
|
|
|
|
/obj/item/paint_palette/attackby(obj/item/W, mob/user)
|
|
if(istype(W, /obj/item/paint_brush))
|
|
var/obj/item/paint_brush/P = W
|
|
var/newcolor = tgui_color_picker(user, "Select a new paint color:", "Paint Palette", P.selected_color)
|
|
if(newcolor && Adjacent(user, P) && Adjacent(user, src))
|
|
P.update_paint(newcolor)
|
|
else
|
|
return ..()
|
|
|
|
/obj/item/frame/painting
|
|
name = "painting frame"
|
|
desc = "The perfect showcase for your favorite deathtrap memories."
|
|
icon = 'icons/obj/decals.dmi'
|
|
refund_amt = 5
|
|
refund_type = /obj/item/stack/material/wood
|
|
icon_state = "frame-empty"
|
|
build_machine_type = /obj/structure/sign/painting
|
|
|
|
/obj/structure/sign/painting
|
|
name = "Painting"
|
|
desc = "Art or \"Art\"? You decide."
|
|
icon = 'icons/obj/decals.dmi'
|
|
icon_state = "frame-empty"
|
|
var/base_icon_state = "frame"
|
|
//custom_materials = list(/datum/material/wood = 2000)
|
|
//buildable_sign = FALSE
|
|
///Canvas we're currently displaying.
|
|
var/obj/item/canvas/current_canvas
|
|
///Description set when canvas is added.
|
|
var/desc_with_canvas
|
|
var/persistence_id
|
|
var/loaded = FALSE
|
|
var/curator = "nobody! Report bug if you see this."
|
|
var/static/list/art_appreciators = list()
|
|
|
|
//Presets for art gallery mapping, for paintings to be shared across stations
|
|
/obj/structure/sign/painting/public
|
|
name = "\improper Public Painting Exhibit mounting"
|
|
desc = "For art pieces hung by the public."
|
|
desc_with_canvas = "A piece of art (or \"art\"). Anyone could've hung it."
|
|
persistence_id = "public"
|
|
|
|
/obj/structure/sign/painting/public/north
|
|
pixel_y = 30
|
|
|
|
/obj/structure/sign/painting/public/south
|
|
pixel_y = -30
|
|
|
|
/obj/structure/sign/painting/public/east
|
|
pixel_x = 30
|
|
|
|
/obj/structure/sign/painting/public/west
|
|
pixel_x = -30
|
|
|
|
/obj/structure/sign/painting/library_secure
|
|
name = "\improper Curated Painting Exhibit mounting"
|
|
desc = "For masterpieces hand-picked by the librarian."
|
|
desc_with_canvas = "A masterpiece hand-picked by the librarian, supposedly."
|
|
persistence_id = "library"
|
|
req_one_access = list(ACCESS_LIBRARY)
|
|
curator = JOB_LIBRARIAN
|
|
|
|
/obj/structure/sign/painting/chapel_secure
|
|
name = "\improper Religious Painting Exhibit mounting"
|
|
desc = "For masterpieces hand-picked by the chaplain."
|
|
desc_with_canvas = "A masterpiece hand-picked by the chaplain, supposedly."
|
|
persistence_id = "chapel"
|
|
req_one_access = list(ACCESS_CHAPEL_OFFICE)
|
|
curator = JOB_CHAPLAIN
|
|
|
|
/obj/structure/sign/painting/library_private // keep your smut away from prying eyes, or non-librarians at least
|
|
name = "\improper Private Painting Exhibit mounting"
|
|
desc = "For art pieces deemed too subversive or too illegal to be shared outside of librarians."
|
|
desc_with_canvas = "A painting hung away from lesser minds."
|
|
persistence_id = "library_private"
|
|
req_one_access = list(ACCESS_LIBRARY)
|
|
curator = JOB_LIBRARIAN
|
|
|
|
/obj/structure/sign/painting/away_areas // for very hard-to-get-to areas
|
|
name = "\improper Remote Painting Exhibit mounting"
|
|
desc = "For art pieces made in the depths of space."
|
|
desc_with_canvas = "A painting hung where only the determined can reach it."
|
|
persistence_id = "away_area"
|
|
|
|
/obj/structure/sign/painting/Initialize(mapload, dir, building)
|
|
. = ..()
|
|
if(persistence_id)
|
|
SSpersistence.painting_frames += src
|
|
if(dir)
|
|
set_dir(dir)
|
|
if(building)
|
|
pixel_x = (dir & 3)? 0 : (dir == 4 ? -30 : 30)
|
|
pixel_y = (dir & 3)? (dir ==1 ? -30 : 30) : 0
|
|
|
|
/obj/structure/sign/painting/Destroy()
|
|
. = ..()
|
|
SSpersistence.painting_frames -= src
|
|
|
|
/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))
|
|
try_rename(user)
|
|
else if(current_canvas && I.has_tool_quality(TOOL_WIRECUTTER))
|
|
unframe_canvas(user)
|
|
else
|
|
return ..()
|
|
|
|
/obj/structure/sign/painting/examine(mob/user)
|
|
. = ..()
|
|
if(persistence_id)
|
|
. += span_notice("Any painting placed here will be archived at the end of the shift.")
|
|
|
|
if(current_canvas)
|
|
current_canvas.tgui_interact(user)
|
|
. += span_notice("Use wirecutters to remove the painting.")
|
|
. += span_notice("Paintings hung here are curated based on interest. The more often someone EXAMINEs the painting, the longer it will stay in rotation.")
|
|
// Painting loaded and persistent frame, give a hint about removal safety
|
|
if(persistence_id)
|
|
if(loaded)
|
|
. += span_warning("Don't worry, the currently framed painting has already been entered into the archives and can be safely removed. It will still be used on future shifts.")
|
|
back_of_the_line(user)
|
|
else
|
|
. += span_warning("This painting has not been entered into the archives yet. Removing it will prevent that from happening.")
|
|
|
|
/obj/structure/sign/painting/proc/frame_canvas(mob/user,obj/item/canvas/new_canvas)
|
|
if(!allowed(user))
|
|
to_chat(user, span_notice("Access lock prevents you from putting a painting into this frame. Ask [curator] for help!"))
|
|
return
|
|
if(user.drop_from_inventory(new_canvas, src))
|
|
current_canvas = new_canvas
|
|
if(!current_canvas.finalized)
|
|
current_canvas.finalize(user)
|
|
to_chat(user,span_notice("You frame [current_canvas]."))
|
|
update_appearance()
|
|
|
|
/obj/structure/sign/painting/proc/unframe_canvas(mob/living/user)
|
|
if(!allowed(user))
|
|
to_chat(user, span_notice("Access lock prevents you from removing paintings from this frame. Ask [curator] ((or admins)) for help!"))
|
|
return
|
|
if(current_canvas)
|
|
current_canvas.forceMove(drop_location())
|
|
current_canvas = null
|
|
loaded = FALSE
|
|
to_chat(user, span_notice("You remove the painting from the frame."))
|
|
update_appearance()
|
|
|
|
/obj/structure/sign/painting/proc/try_rename(mob/user)
|
|
if(current_canvas.painting_name == initial(current_canvas.painting_name))
|
|
current_canvas.try_rename(user)
|
|
|
|
/obj/structure/sign/painting/proc/update_appearance()
|
|
name = current_canvas ? "painting - [current_canvas.painting_name]" : initial(name)
|
|
desc = current_canvas ? desc_with_canvas : initial(desc)
|
|
icon_state = "[base_icon_state]-[current_canvas?.generated_icon ? "hidden" : "empty"]"
|
|
|
|
cut_overlays()
|
|
|
|
if(!current_canvas?.generated_icon)
|
|
return
|
|
|
|
. = list()
|
|
var/mutable_appearance/MA = mutable_appearance(current_canvas.generated_icon)
|
|
MA.pixel_x = current_canvas.framed_offset_x
|
|
MA.pixel_y = current_canvas.framed_offset_y
|
|
. += MA
|
|
var/mutable_appearance/frame = mutable_appearance(current_canvas.icon,"[current_canvas.icon_state]frame")
|
|
frame.pixel_x = current_canvas.framed_offset_x + current_canvas.frame_offset_x
|
|
frame.pixel_y = current_canvas.framed_offset_y + current_canvas.frame_offset_y
|
|
. += frame
|
|
|
|
add_overlay(.)
|
|
|
|
/obj/item/canvas/proc/fill_grid_from_icon(icon/I)
|
|
var/h = I.Height() + 1
|
|
for(var/x in 1 to width)
|
|
for(var/y in 1 to height)
|
|
grid[x][y] = I.GetPixel(x,h-y)
|
|
|
|
/**
|
|
* Loads a painting from SSpersistence. Called globally by said subsystem when it inits
|
|
*
|
|
* 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 || !LAZYLEN(SSpersistence.unpicked_paintings))
|
|
return
|
|
|
|
var/list/painting_category = list()
|
|
for (var/list/P in SSpersistence.unpicked_paintings)
|
|
if(P["persistence_id"] == persistence_id)
|
|
painting_category[++painting_category.len] = P
|
|
|
|
var/list/painting
|
|
while(!painting)
|
|
if(!length(painting_category))
|
|
return //aborts loading anything this category has no usable paintings
|
|
var/list/chosen = pick(painting_category)
|
|
if(!fexists("data/persistent/paintings/[persistence_id]/[chosen["md5"]].png")) //shitmin deleted this art, lets remove json entry to avoid errors
|
|
painting_category -= list(chosen)
|
|
SSpersistence.unpicked_paintings -= list(chosen)
|
|
continue //and try again
|
|
painting = chosen
|
|
SSpersistence.unpicked_paintings -= list(chosen)
|
|
|
|
var/title = painting["title"]
|
|
var/author_name = painting["author"]
|
|
var/author_ckey = painting["ckey"]
|
|
var/png = "data/persistent/paintings/[persistence_id]/[painting["md5"]].png"
|
|
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
|
|
|
|
if(!new_canvas)
|
|
WARNING("Couldn't find a canvas to match [w]x[h] of painting")
|
|
return
|
|
|
|
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_name = author_name
|
|
new_canvas.author_ckey = author_ckey
|
|
new_canvas.name = "painting - [title]"
|
|
current_canvas = new_canvas
|
|
loaded = TRUE
|
|
update_appearance()
|
|
|
|
/*
|
|
* Recursive Proc. If given no arguments, requests user to input arguments with warning that generating the list may be res intensive
|
|
* Upon generating arguments, calls itself and spawns the painting
|
|
* Ideally called using the vvar dropdown admin verb and used using debugging the SSpersistence list to minimize lag
|
|
* usr must have an admin holder (ergo: only staff may use this)
|
|
* TODO: create a machine in the library for curators to spawn canvases and refactor this to use the proc used there.
|
|
* For now, we do it this way because calling this on a canvas itself might cause issues due to the whole dimension thing.
|
|
*/
|
|
/obj/structure/sign/painting/proc/admin_lateload_painting(var/spawn_specific = 0, var/which_painting = 0)
|
|
if(!check_rights_for(usr.client, R_HOLDER))
|
|
return 0
|
|
if(spawn_specific && isnum(which_painting))
|
|
var/list/painting = SSpersistence.all_paintings[which_painting]
|
|
var/title = painting["title"]
|
|
var/author_name = painting["author"]
|
|
var/author_ckey = painting["ckey"]
|
|
var/persistence_id = painting["persistence_id"]
|
|
var/png = "data/persistent/paintings/[persistence_id]/[painting["md5"]].png"
|
|
to_chat(usr, span_notice("The chosen painting is the following \n\n \
|
|
Title: [title] \n \
|
|
Author's Name: [author_name]. \n \
|
|
Author's CKey: [author_ckey]"))
|
|
if(tgui_alert(usr, "Check your chat log (if filtering for notices, check where you don't) for painting details.",
|
|
"Is this the painting you want?", list("Yes", "No")) != "Yes")
|
|
return 0
|
|
if(!fexists("data/persistent/paintings/[persistence_id]/[painting["md5"]].png"))
|
|
to_chat(usr, span_warning("Chosen painting could not be loaded! Incident was logged, but no action taken at this time"))
|
|
log_runtime("[usr] tried to spawn painting of list id [which_painting] in all_paintings list and associated file could not be found. \n \
|
|
Painting was titled [title] by [author_ckey] of [persistence_id]")
|
|
return 0
|
|
|
|
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
|
|
|
|
if(!new_canvas)
|
|
WARNING("Couldn't find a canvas to match [w]x[h] of painting")
|
|
return 0
|
|
|
|
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_name = author_name
|
|
new_canvas.author_ckey = author_ckey
|
|
new_canvas.name = "painting - [title]"
|
|
current_canvas = new_canvas
|
|
loaded = TRUE
|
|
update_appearance()
|
|
log_and_message_admins("spawned painting from [author_ckey] with title [title]", usr)
|
|
|
|
else
|
|
|
|
if(tgui_alert(usr, "No painting list ID was given. You may obtain such by debugging SSPersistence and checking the all_paintings entry. \
|
|
If you do not wish to do that, you may request a list to be generated of painting titles. This might be resource intensive. \
|
|
Proceed? It will likely have over 500 entries", "Generate list?", list("Proceed!", "Cancel")) != "Proceed!")
|
|
return
|
|
|
|
// to_chat(world, "[usr] generated list of paintings from SSPersistence")
|
|
var/list/paintings = list()
|
|
var/current = 1
|
|
for(var/entry in SSpersistence.all_paintings)
|
|
var/key = "[entry["title"]] by [entry["author"]]"
|
|
paintings[key] = current
|
|
current += 1
|
|
|
|
var/choice = tgui_input_list(usr, "Choose which painting to spawn!", "Spawn painting", paintings, null)
|
|
if(!choice)
|
|
return 0
|
|
admin_lateload_painting(1, paintings[choice])
|
|
|
|
|
|
|
|
|
|
/obj/structure/sign/painting/proc/save_persistent()
|
|
if(!persistence_id || !current_canvas || current_canvas.no_save)
|
|
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))
|
|
for(var/list/entry in SSpersistence.all_paintings)
|
|
if(entry["md5"] == md5 && entry["persistence_id"] == persistence_id)
|
|
return
|
|
var/png_directory = "data/persistent/paintings/[persistence_id]/"
|
|
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]")
|
|
|
|
SSpersistence.all_paintings += list(list(
|
|
"persistence_id" = persistence_id,
|
|
"title" = current_canvas.painting_name,
|
|
"md5" = md5,
|
|
"author" = current_canvas.author_name,
|
|
"ckey" = current_canvas.author_ckey
|
|
))
|
|
|
|
/obj/structure/sign/painting/proc/back_of_the_line(mob/user)
|
|
if(user.ckey in art_appreciators)
|
|
return
|
|
if(!persistence_id || !current_canvas || current_canvas.no_save)
|
|
return
|
|
var/data = current_canvas.get_data_string()
|
|
var/md5 = md5(lowertext(data))
|
|
for(var/list/entry in SSpersistence.all_paintings)
|
|
if(entry["md5"] == md5 && entry["persistence_id"] == persistence_id)
|
|
SSpersistence.all_paintings.Remove(list(entry))
|
|
SSpersistence.all_paintings.Add(list(entry))
|
|
art_appreciators += user.ckey
|
|
to_chat(user, span_notice("Showing interest in this painting renews its position in the curator database."))
|
|
|
|
/obj/structure/sign/painting/vv_get_dropdown()
|
|
. = ..()
|
|
VV_DROPDOWN_OPTION("removepainting", "Remove Persistent Painting")
|
|
|
|
/obj/structure/sign/painting/vv_do_topic(list/href_list)
|
|
. = ..()
|
|
if(href_list["removepainting"])
|
|
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/filenames_found = list()
|
|
for(var/list/entry in SSpersistence.all_paintings)
|
|
if(entry["md5"] == md5)
|
|
filenames_found += "data/persistent/paintings/[entry["persistence_id"]]/[entry["md5"]].png"
|
|
SSpersistence.all_paintings -= list(entry)
|
|
for(var/png in filenames_found)
|
|
if(fexists(png))
|
|
fdel(png)
|
|
for(var/obj/structure/sign/painting/P in SSpersistence.painting_frames)
|
|
if(P.current_canvas && md5(P.current_canvas.get_data_string()) == md5)
|
|
QDEL_NULL(P.current_canvas)
|
|
P.update_appearance()
|
|
loaded = FALSE
|
|
log_and_message_admins(span_notice("[key_name_admin(user)] has deleted persistent painting made by [author]."))
|