diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm index 4c72c599bdb..6aace0e8942 100644 --- a/_maps/map_files/Deltastation/DeltaStation2.dmm +++ b/_maps/map_files/Deltastation/DeltaStation2.dmm @@ -49899,6 +49899,17 @@ name = "library camera" }, /obj/structure/extinguisher_cabinet/directional/north, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/structure/window/reinforced, +/obj/effect/spawner/random/decoration/statue{ + spawn_loot_chance = 35 + }, +/obj/structure/table/wood/fancy, +/obj/structure/sign/painting/large/library{ + dir = 1 + }, /turf/open/floor/wood, /area/service/library) "mic" = ( @@ -66198,16 +66209,10 @@ /turf/open/floor/iron, /area/engineering/atmos/project) "rhJ" = ( -/obj/structure/window/reinforced{ - dir = 8 - }, -/obj/structure/window/reinforced, /obj/structure/table/wood/fancy, -/obj/structure/sign/painting/library_secure{ - pixel_y = 32 - }, -/obj/effect/spawner/random/decoration/statue{ - spawn_loot_chance = 35 +/obj/machinery/door/window{ + name = "Secure Art Exhibition"; + req_access_txt = "37" }, /turf/open/floor/carpet, /area/service/library) @@ -71859,6 +71864,10 @@ /obj/structure/destructible/cult/item_dispenser/archives/library, /obj/item/book/codex_gigas, /obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/structure/sign/painting/large/library_private{ + dir = 8; + pixel_x = -29 + }, /turf/open/floor/iron/dark, /area/service/library) "sNL" = ( diff --git a/_maps/map_files/IceBoxStation/IceBoxStation.dmm b/_maps/map_files/IceBoxStation/IceBoxStation.dmm index 1c74360e520..c67e0673dcf 100644 --- a/_maps/map_files/IceBoxStation/IceBoxStation.dmm +++ b/_maps/map_files/IceBoxStation/IceBoxStation.dmm @@ -328,6 +328,15 @@ /obj/effect/turf_decal/stripes/line{ dir = 9 }, +/obj{ + name = "---Merge conflict marker---" + }, +/obj/structure/bed/dogbed/lia, +/obj/machinery/camera/directional/west{ + c_tag = "Security - HoS Office" + }, +/obj/machinery/newscaster/directional/west, +/mob/living/simple_animal/hostile/carp/lia, /turf/open/floor/iron, /area/ai_monitored/security/armory) "acm" = ( @@ -9264,6 +9273,9 @@ /obj/structure/bookcase{ name = "Forbidden Knowledge" }, +/obj/structure/sign/painting/large/library_private{ + dir = 1 + }, /turf/open/floor/engine/cult, /area/service/library) "cnR" = ( @@ -16351,6 +16363,7 @@ dir = 8 }, /obj/machinery/firealarm/directional/west, +/obj/item/radio/intercom/directional/north, /turf/open/floor/wood, /area/service/library) "fBN" = ( @@ -25145,10 +25158,10 @@ dir = 4 }, /obj/structure/cable, +/obj/machinery/duct, /mob/living/simple_animal/hostile/retaliate/goat{ name = "Pete" }, -/obj/machinery/duct, /turf/open/floor/iron/freezer, /area/service/kitchen/coldroom) "jJP" = ( @@ -29260,6 +29273,13 @@ /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj{ + name = "---Merge conflict marker---" + }, +/obj/structure/bed/dogbed/mcgriff, +/obj/item/food/beef_wellington_slice, +/obj/structure/cable, +/mob/living/simple_animal/pet/dog/pug/mcgriff, /turf/open/floor/iron, /area/security/brig) "lWs" = ( @@ -38059,6 +38079,9 @@ /obj/item/camera, /obj/item/taperecorder, /obj/item/radio/intercom/directional/east, +/obj/structure/sign/painting/library_private{ + pixel_y = 32 + }, /turf/open/floor/engine/cult, /area/service/library) "qqA" = ( @@ -45106,9 +45129,6 @@ /obj/structure/sign/painting/library_secure{ pixel_x = 32 }, -/obj/structure/window/reinforced{ - dir = 1 - }, /obj/machinery/door/window{ dir = 8; name = "Secure Art Exhibition"; @@ -47269,11 +47289,17 @@ /turf/open/floor/iron, /area/science/misc_lab) "uOl" = ( -/obj/item/radio/intercom/directional/east, -/obj/machinery/light/directional/east, /obj/machinery/camera/directional/east{ c_tag = "Library Art Gallery" }, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/effect/spawner/random/structure/table_fancy, +/obj/machinery/light/blacklight/directional/north, +/obj/structure/sign/painting/large/library{ + dir = 4 + }, /turf/open/floor/wood, /area/service/library) "uOC" = ( @@ -47447,9 +47473,9 @@ /area/medical/medbay/aft) "uTm" = ( /obj/structure/bed/dogbed/runtime, -/mob/living/simple_animal/pet/cat/runtime, /obj/item/toy/cattoy, /obj/machinery/newscaster/directional/north, +/mob/living/simple_animal/pet/cat/runtime, /turf/open/floor/iron/dark, /area/command/heads_quarters/cmo) "uTA" = ( @@ -51995,9 +52021,6 @@ /turf/open/floor/iron, /area/hallway/secondary/exit/departure_lounge) "xkb" = ( -/obj/structure/sign/painting/library_private{ - pixel_y = 32 - }, /obj/structure/table/wood, /obj/item/clothing/under/suit/red, /obj/item/candle{ diff --git a/_maps/map_files/KiloStation/KiloStation.dmm b/_maps/map_files/KiloStation/KiloStation.dmm index 5100ca04a6f..7a9ba9784e6 100644 --- a/_maps/map_files/KiloStation/KiloStation.dmm +++ b/_maps/map_files/KiloStation/KiloStation.dmm @@ -23291,6 +23291,15 @@ /obj/structure/table/wood/fancy/red, /obj/structure/window/reinforced, /obj/machinery/door/window/eastright, +/obj{ + name = "---Merge conflict marker---" + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral, +/obj/structure/table/wood/fancy/red, +/obj/machinery/door/window/right/directional/east, /turf/open/floor/iron/dark, /area/service/library) "dmX" = ( @@ -55601,8 +55610,15 @@ }, /obj/effect/turf_decal/tile/neutral, /obj/machinery/light/small/directional/west, -/obj/structure/bookcase/random, /obj/machinery/newscaster/directional/south, +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/structure/table/wood/fancy/red, +/obj/structure/sign/painting/large/library{ + dir = 8; + pixel_x = -29 + }, /turf/open/floor/iron/dark, /area/service/library) "ocN" = ( @@ -83552,6 +83568,10 @@ c_tag = "Library Backroom"; name = "library camera" }, +/obj/structure/sign/painting/large/library_private{ + dir = 8; + pixel_x = -29 + }, /turf/open/floor/iron/dark, /area/service/library) "xcO" = ( diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm index dc60022183c..093a3b1dea0 100644 --- a/_maps/map_files/MetaStation/MetaStation.dmm +++ b/_maps/map_files/MetaStation/MetaStation.dmm @@ -9368,6 +9368,17 @@ /area/hallway/primary/aft) "cyx" = ( /obj/machinery/light/directional/north, +/obj/machinery/door/window{ + name = "Secure Art Exhibition"; + req_access_txt = "37" + }, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/structure/table/wood/fancy/royalblue, +/obj/structure/sign/painting/large/library{ + dir = 1 + }, /turf/open/floor/wood, /area/service/library) "cyK" = ( @@ -36498,11 +36509,6 @@ /area/hallway/primary/port) "mhh" = ( /obj/structure/table/wood/fancy/royalblue, -/obj/machinery/door/window{ - dir = 8; - name = "Secure Art Exhibition"; - req_access_txt = "37" - }, /obj/structure/sign/painting/library_secure{ pixel_x = 32 }, @@ -42373,6 +42379,10 @@ "ofl" = ( /obj/structure/table/wood, /obj/item/storage/photo_album/library, +/obj/structure/sign/painting/large/library_private{ + dir = 8; + pixel_x = -29 + }, /turf/open/floor/engine/cult, /area/service/library) "ofp" = ( diff --git a/_maps/map_files/tramstation/tramstation.dmm b/_maps/map_files/tramstation/tramstation.dmm index 13f56a21815..1257d4abef2 100644 --- a/_maps/map_files/tramstation/tramstation.dmm +++ b/_maps/map_files/tramstation/tramstation.dmm @@ -542,11 +542,6 @@ /obj/structure/sign/painting/library_secure{ pixel_x = 32 }, -/obj/machinery/door/window{ - dir = 8; - name = "Secure Art Exhibition"; - req_access_txt = "37" - }, /obj/structure/window/reinforced/spawner, /obj/effect/spawner/random/decoration/statue{ spawn_loot_chance = 50 @@ -554,6 +549,7 @@ /obj/effect/turf_decal/siding/wood{ dir = 8 }, +/obj/structure/window/reinforced/spawner/west, /turf/open/floor/wood/large, /area/service/library) "aeC" = ( @@ -2995,6 +2991,9 @@ "avv" = ( /obj/machinery/disposal/bin, /obj/structure/disposalpipe/trunk, +/obj/structure/sign/painting/large/library_private{ + dir = 1 + }, /turf/open/floor/engine/cult, /area/service/library) "avx" = ( @@ -3181,10 +3180,14 @@ /obj/effect/spawner/random/decoration/statue{ spawn_loot_chance = 50 }, -/obj/structure/window/reinforced/spawner/west, /obj/effect/turf_decal/siding/wood{ dir = 8 }, +/obj/machinery/door/window{ + dir = 8; + name = "Secure Art Exhibition"; + req_access_txt = "37" + }, /turf/open/floor/wood/large, /area/service/library) "awr" = ( @@ -11504,14 +11507,15 @@ /turf/open/floor/iron, /area/security/brig) "cQt" = ( -/obj/structure/chair/comfy/black{ - dir = 1 - }, /obj/effect/turf_decal/siding/wood{ dir = 8 }, -/obj/effect/landmark/start/assistant, -/obj/item/radio/intercom/directional/east, +/obj/structure/window/reinforced/spawner/north, +/obj/structure/window/reinforced/spawner/west, +/obj/effect/spawner/random/decoration/statue{ + spawn_loot_chance = 50 + }, +/obj/structure/table/wood/fancy/royalblue, /turf/open/floor/wood/large, /area/service/library) "cQG" = ( @@ -29937,6 +29941,12 @@ /obj/structure/cable, /turf/open/floor/catwalk_floor, /area/hallway/primary/tram/left) +"jtl" = ( +/obj/structure/chair/comfy/black{ + dir = 4 + }, +/turf/open/floor/carpet, +/area/service/library) "jto" = ( /obj/effect/turf_decal/trimline/neutral/filled/corner{ dir = 8 @@ -30552,21 +30562,17 @@ /area/science/xenobiology) "jES" = ( /obj/structure/table/wood/fancy/royalblue, -/obj/structure/sign/painting/library_secure{ - pixel_x = 32 - }, /obj/machinery/door/window{ dir = 8; name = "Secure Art Exhibition"; req_access_txt = "37" }, -/obj/structure/window/reinforced/spawner/north, -/obj/effect/spawner/random/decoration/statue{ - spawn_loot_chance = 50 - }, /obj/effect/turf_decal/siding/wood{ dir = 8 }, +/obj/structure/sign/painting/large/library{ + dir = 4 + }, /turf/open/floor/wood/large, /area/service/library) "jEU" = ( @@ -40683,6 +40689,7 @@ "nma" = ( /obj/structure/table/wood, /obj/item/paicard, +/obj/item/radio/intercom/directional/west, /turf/open/floor/wood/large, /area/service/library) "nml" = ( @@ -61434,6 +61441,7 @@ /obj/effect/turf_decal/siding/wood{ dir = 8 }, +/obj/effect/landmark/start/assistant, /turf/open/floor/wood/large, /area/service/library) "uTw" = ( @@ -67248,6 +67256,12 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron, /area/hallway/secondary/exit/departure_lounge) +"xfW" = ( +/obj/structure/sign/painting/library_private{ + pixel_y = -32 + }, +/turf/open/floor/engine/cult, +/area/service/library) "xfZ" = ( /obj/effect/turf_decal/trimline/blue/filled/line{ dir = 4 @@ -150170,7 +150184,7 @@ wDZ aKl avv deW -cKD +xfW aKl aKl aKl @@ -152743,7 +152757,7 @@ mCH xWM aFN aFN -aFN +jtl aFN aFN aFN diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm index fe8df67778c..49db100c841 100644 --- a/code/__DEFINES/traits.dm +++ b/code/__DEFINES/traits.dm @@ -781,6 +781,8 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define EXPIRED_LIFE_TRAIT "expired_life" /// Trait given to an atom/movable when they orbit something. #define ORBITING_TRAIT "orbiting" +/// From the item_scaling element +#define ITEM_SCALING_TRAIT "item_scaling" /** * Trait granted by [/mob/living/carbon/Initialize] and diff --git a/code/controllers/subsystem/persistent_paintings.dm b/code/controllers/subsystem/persistent_paintings.dm index 3e213d1575b..b00a41c6f6b 100644 --- a/code/controllers/subsystem/persistent_paintings.dm +++ b/code/controllers/subsystem/persistent_paintings.dm @@ -170,7 +170,13 @@ SUBSYSTEM_DEF(persistent_paintings) pdata["ref"] = REF(painting) . += list(pdata) else - . += list(list("title" = painting.title, "creator" = painting.creator_name, "md5" = painting.md5,"ref" = REF(painting))) + . += list(list( + "title" = painting.title, + "creator" = painting.creator_name, + "md5" = painting.md5, + "ref" = REF(painting), + "ratio" = painting.width/painting.height, + )) /// Returns paintings with given tag. /datum/controller/subsystem/persistent_paintings/proc/get_paintings_with_tag(tag_name) diff --git a/code/datums/elements/item_scaling.dm b/code/datums/elements/item_scaling.dm index 4c9fc21e32e..1f804beee16 100644 --- a/code/datums/elements/item_scaling.dm +++ b/code/datums/elements/item_scaling.dm @@ -28,16 +28,20 @@ * * overworld_scaling - Integer or float to scale the item in the overworld. * * storage_scaling - Integer or float to scale the item in storage/inventory. */ -/datum/element/item_scaling/Attach(datum/target, overworld_scaling, storage_scaling) +/datum/element/item_scaling/Attach(atom/target, overworld_scaling, storage_scaling) . = ..() if(!isatom(target)) return ELEMENT_INCOMPATIBLE + // Initial scaling set to overworld_scaling when item is spawned. scale(target, overworld_scaling) src.overworld_scaling = overworld_scaling src.storage_scaling = storage_scaling + // Make sure overlays also inherit the scaling. + ADD_KEEP_TOGETHER(target, ITEM_SCALING_TRAIT) + // Object scaled when dropped/thrown OR when exiting a storage component. RegisterSignal(target, list(COMSIG_ITEM_DROPPED, COMSIG_STORAGE_EXITED), .proc/scale_overworld) // Object scaled when placed in an inventory slot OR when entering a storage component. @@ -50,13 +54,16 @@ * Arguments: * * target - Datum which the element is attached to. */ -/datum/element/item_scaling/Detach(datum/target) +/datum/element/item_scaling/Detach(atom/target) UnregisterSignal(target, list( COMSIG_ITEM_PICKUP, COMSIG_ITEM_DROPPED, COMSIG_STORAGE_ENTERED, COMSIG_STORAGE_EXITED, )) + + REMOVE_KEEP_TOGETHER(target, ITEM_SCALING_TRAIT) + return ..() /** diff --git a/code/modules/admin/painting_manager.dm b/code/modules/admin/painting_manager.dm index b3d76de0c19..bd7d28fb73f 100644 --- a/code/modules/admin/painting_manager.dm +++ b/code/modules/admin/painting_manager.dm @@ -79,6 +79,7 @@ chosen_painting.patron_name = "" chosen_painting.patron_ckey = "" chosen_painting.credit_value = 0 + chosen_painting.frame_type = initial(chosen_painting.frame_type) log_admin("[key_name(user)] has reset patronage data on a persistent painting made by [chosen_painting.creator_ckey] with id [chosen_painting.md5].") return TRUE if("remove_tag") diff --git a/code/modules/art/paintings.dm b/code/modules/art/paintings.dm index 2e98850ee2e..7760276b688 100644 --- a/code/modules/art/paintings.dm +++ b/code/modules/art/paintings.dm @@ -64,8 +64,18 @@ var/framed_offset_x = 11 var/framed_offset_y = 10 - pixel_x = 10 - pixel_y = 9 + /** + * How big the grid cells that compose the painting are in the UI. + * This impacts the size of the UI, so smaller values are generally better for bigger canvases and viceversa + */ + var/pixels_per_unit = 24 + + pixel_x = 11 + pixel_y = 10 + base_pixel_x = 11 + base_pixel_y = 10 + + custom_premium_price = PAYCHECK_MEDIUM /obj/item/canvas/Initialize(mapload) . = ..() @@ -105,6 +115,10 @@ else return ..() +/obj/item/canvas/ui_static_data(mob/user) + . = ..() + .["px_per_unit"] = pixels_per_unit + /obj/item/canvas/ui_data(mob/user) . = ..() .["grid"] = grid @@ -333,8 +347,10 @@ icon_state = "19x19" width = 19 height = 19 - pixel_x = 6 - pixel_y = 9 + pixel_x = 7 + pixel_y = 7 + base_pixel_x = 7 + base_pixel_y = 7 framed_offset_x = 7 framed_offset_y = 7 @@ -343,8 +359,10 @@ icon_state = "23x19" width = 23 height = 19 - pixel_x = 4 - pixel_y = 10 + pixel_x = 5 + pixel_y = 7 + base_pixel_x = 5 + base_pixel_y = 7 framed_offset_x = 5 framed_offset_y = 7 @@ -354,21 +372,71 @@ width = 23 height = 23 pixel_x = 5 - pixel_y = 9 + pixel_y = 5 + base_pixel_x = 5 + base_pixel_y = 5 framed_offset_x = 5 framed_offset_y = 5 /obj/item/canvas/twentyfour_twentyfour name = "canvas (AI Universal Standard)" - desc = "Besides being very large, the AI can accept these as a display from their internal database after you've hung it up." + desc = "Besides being almost too large for a standard frame, the AI can accept these as a display from their internal database after you've hung it up." icon_state = "24x24" width = 24 height = 24 - pixel_x = 2 - pixel_y = 1 + pixel_x = 4 + pixel_y = 4 + base_pixel_x = 4 + base_pixel_y = 4 framed_offset_x = 4 framed_offset_y = 4 +/obj/item/canvas/thirtysix_twentyfour + name = "canvas (36x24)" + desc = "A very large canvas to draw out your soul on. You'll need a larger frame to put it on a wall." + icon_state = "24x24" //The vending spritesheet needs the icons to be 32x32. We'll set the actual icon on Initialize. + width = 36 + height = 24 + pixel_x = -4 + pixel_y = 4 + base_pixel_x = -4 + base_pixel_y = 4 + framed_offset_x = 14 + framed_offset_y = 4 + pixels_per_unit = 20 + w_class = WEIGHT_CLASS_BULKY + + custom_premium_price = PAYCHECK_HARD * 1.25 + +/obj/item/canvas/thirtysix_twentyfour/Initialize() + . = ..() + AddElement(/datum/element/item_scaling, 1, 0.8) + icon = 'icons/obj/artstuff_64x64.dmi' + icon_state = "36x24" + +/obj/item/canvas/fortyfive_twentyseven + name = "canvas (45x27)" + desc = "The largest canvas available on the space market. You'll need a larger frame to put it on a wall." + icon_state = "24x24" //Ditto + width = 45 + height = 27 + pixel_x = -8 + pixel_y = 2 + base_pixel_x = -8 + base_pixel_y = 2 + framed_offset_x = 9 + framed_offset_y = 4 + pixels_per_unit = 18 + w_class = WEIGHT_CLASS_BULKY + + custom_premium_price = PAYCHECK_HARD * 1.75 + +/obj/item/canvas/fortyfive_twentyseven/Initialize() + . = ..() + AddElement(/datum/element/item_scaling, 1, 0.7) + icon = 'icons/obj/artstuff_64x64.dmi' + icon_state = "45x27" + /obj/item/wallframe/painting name = "painting frame" desc = "The perfect showcase for your favorite deathtrap memories." @@ -392,6 +460,14 @@ ///Description set when canvas is added. var/desc_with_canvas var/persistence_id + /// The list of canvas types accepted by this frame + var/list/accepted_canvas_types = list( + /obj/item/canvas, + /obj/item/canvas/nineteen_nineteen, + /obj/item/canvas/twentythree_nineteen, + /obj/item/canvas/twentythree_twentythree, + /obj/item/canvas/twentyfour_twentyfour, + ) /obj/structure/sign/painting/Initialize(mapload, dir, building) . = ..() @@ -425,28 +501,42 @@ . = ..() if(current_canvas) current_canvas.forceMove(drop_location()) - current_canvas = null to_chat(user, span_notice("You remove the painting from the frame.")) - update_appearance() return TRUE +/obj/structure/sign/painting/Exited(atom/movable/movable, atom/newloc) + . = ..() + if(movable == current_canvas) + current_canvas = null + update_appearance() + /obj/structure/sign/painting/AltClick(mob/user) . = ..() if(current_canvas?.can_select_frame(user)) INVOKE_ASYNC(current_canvas, /obj/item/canvas.proc/select_new_frame, user) -/obj/structure/sign/painting/proc/frame_canvas(mob/user,obj/item/canvas/new_canvas) +/obj/structure/sign/painting/proc/frame_canvas(mob/user, obj/item/canvas/new_canvas) + if(!(new_canvas.type in accepted_canvas_types)) + to_chat(user, span_warning("[new_canvas] won't fit in this frame.")) + return FALSE if(user.transferItemToLoc(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() + update_appearance() + return TRUE + return FALSE /obj/structure/sign/painting/proc/try_rename(mob/user) if(current_canvas.painting_metadata.title == initial(current_canvas.painting_metadata.title)) current_canvas.try_rename(user) +/obj/structure/sign/painting/update_icon_state(updates=ALL) + . = ..() + // Stops the frame icon_state from poking out behind the paintings. we have proper frame overlays in artstuff.dmi. + icon = current_canvas?.generated_icon ? null : initial(icon) + /obj/structure/sign/painting/update_name(updates) name = current_canvas ? "painting - [current_canvas.painting_metadata.title]" : initial(name) return ..() @@ -455,10 +545,6 @@ desc = current_canvas ? desc_with_canvas : initial(desc) return ..() -/obj/structure/sign/painting/update_icon_state() - icon_state = "[base_icon_state]-[current_canvas?.generated_icon ? "overlay" : "empty"]" - return ..() - /obj/structure/sign/painting/update_overlays() . = ..() if(!current_canvas?.generated_icon) @@ -491,6 +577,8 @@ for(var/T in typesof(/obj/item/canvas)) new_canvas = T if(initial(new_canvas.width) == w && initial(new_canvas.height) == h) + if(!(new_canvas in accepted_canvas_types)) + CRASH("Found painting with canvas size not compatible with this frame. Canvas type: [new_canvas]") new_canvas = new T(src) break if(!istype(new_canvas)) @@ -537,6 +625,96 @@ for(var/y in 1 to height) grid[x][y] = I.GetPixel(x,h-y) +/obj/item/wallframe/painting/large + name = "large painting frame" + desc = "The perfect showcase for your favorite deathtrap memories. Make sure you have enough space to mount this one to the wall." + custom_materials = list(/datum/material/wood = 4000) + icon_state = "frame-large-empty" + result_path = /obj/structure/sign/painting/large + pixel_shift = 0 //See [/obj/structure/sign/painting/large/proc/finalize_size] + +/obj/item/wallframe/painting/large/try_build(turf/on_wall, mob/user) + . = ..() + if(!.) + return + var/our_dir = get_dir(user, on_wall) + var/check_dir = our_dir & (EAST|WEST) ? NORTH : EAST + var/turf/closed/wall/second_wall = get_step(on_wall, check_dir) + if(!istype(second_wall) || !user.CanReach(second_wall)) + to_chat(user, span_warning("You need a reachable wall to the [check_dir == EAST ? "right" : "left"] of this one to mount this frame!")) + return FALSE + if(check_wall_item(second_wall, our_dir, wall_external)) + to_chat(user, span_warning("There's already an item on the wall to the [check_dir == EAST ? "right" : "left"] of this one!")) + return FALSE + +/obj/item/wallframe/painting/large/after_attach(obj/object) + . = ..() + var/obj/structure/sign/painting/large/our_frame = object + our_frame.finalize_size() + +/obj/structure/sign/painting/large + icon = 'icons/obj/artstuff_64x64.dmi' + custom_materials = list(/datum/material/wood = 4000) + accepted_canvas_types = list( + /obj/item/canvas/thirtysix_twentyfour, + /obj/item/canvas/fortyfive_twentyseven, + ) + +/obj/structure/sign/painting/large/Initialize(mapload) + . = ..() + // Necessary so that the painting is framed correctly by the frame overlay when flipped. + ADD_KEEP_TOGETHER(src, INNATE_TRAIT) + if(mapload) + finalize_size() + +/** + * This frame is visually put between two wall turfs and it has an icon that's bigger than 32px, and because + * of the way it's designed, the pixel_shift variable from the wallframe item won't do. + * Also we want higher bounds so it actually covers an extra wall turf, so that it can count toward check_wall_item calls for + * that wall turf. + */ +/obj/structure/sign/painting/large/proc/finalize_size() + switch(dir) + if(SOUTH) + pixel_y = -32 + bound_width = 64 + if(NORTH) + bound_width = 64 + if(WEST) + // Totally intended so that the frame sprite doesn't spill behind the wall and get partly covered by the darkness plane. + // Ditto for the ones below. + pixel_x = -29 + bound_height = 64 + if(EAST) + bound_height = 64 + +/obj/structure/sign/painting/large/frame_canvas(mob/user, obj/item/canvas/new_canvas) + . = ..() + if(!.) + return + switch(dir) + if(EAST) + transform = transform.Turn(90) + pixel_x += 29 + pixel_y += 29 + if(WEST) + transform = transform.Turn(-90) + if(NORTH) + pixel_y += 29 + +/obj/structure/sign/painting/large/Exited(atom/movable/movable, atom/newloc) + if(movable == current_canvas) + switch(dir) + if(EAST) + transform = transform.Turn(-90) + pixel_x -= 29 + pixel_y -= 29 + if(WEST) + transform = transform.Turn(90) + if(NORTH) + pixel_y -= 29 + return ..() + //Presets for art gallery mapping, for paintings to be shared across stations /obj/structure/sign/painting/library name = "\improper Public Painting Exhibit mounting" @@ -556,6 +734,19 @@ desc_with_canvas = "A painting hung away from lesser minds." persistence_id = "library_private" +/obj/structure/sign/painting/large/library + name = "\improper Large Painting Exhibit mounting" + desc = "For the bulkier art pieces, hand-picked by the curator." + desc_with_canvas = "A curated, large piece of art (or \"art\"). Hopefully the price of the canvas was worth it." + persistence_id = "library_large" + +/obj/structure/sign/painting/large/library_private + name = "\improper Private Painting Exhibit mounting" + desc = "For the privier and less tasteful compositions that oughtn't to be shown in a parlor nor to the masses." + desc_with_canvas = "A painting that oughn't to be shown to the less open-minded commoners." + persistence_id = "library_large_private" + + #define AVAILABLE_PALETTE_SPACE 14 // Enough to fill two radial menu pages /// Simple painting utility. diff --git a/code/modules/unit_tests/paintings.dm b/code/modules/unit_tests/paintings.dm index fa999f0ab8e..136adea534d 100644 --- a/code/modules/unit_tests/paintings.dm +++ b/code/modules/unit_tests/paintings.dm @@ -2,13 +2,13 @@ /datum/unit_test/paintings /datum/unit_test/paintings/Run() - for(var/obj/item/canvas/canvas_prototype as anything in typesof(/obj/item/canvas)) + for(var/obj/item/canvas/canvas as anything in typesof(/obj/item/canvas)) //SKYRAT EDIT START - if(canvas_prototype == /obj/item/canvas/drawingtablet) //This doesn't need frames. + if(canvas == /obj/item/canvas/drawingtablet) //This doesn't need frames. continue //SKYRAT EDIT END - var/canvas_icons = icon_states(initial(canvas_prototype.icon)) - var/canvas_icon_state = initial(canvas_prototype.icon_state) + canvas = new canvas + var/canvas_icons = icon_states(canvas.icon) for(var/frame_type in SSpersistent_paintings.frame_types_by_patronage_tier) - if(!("[canvas_icon_state]frame_[frame_type]" in canvas_icons)) - Fail("Canvas [canvas_icon_state] doesn't have an icon state for frame: [frame_type].") + if(!("[canvas.icon_state]frame_[frame_type]" in canvas_icons)) + Fail("Canvas [canvas.icon_state] doesn't have an icon state for frame: [frame_type].") diff --git a/code/modules/vending/games.dm b/code/modules/vending/games.dm index 18f754eaa65..3ded87a6d97 100644 --- a/code/modules/vending/games.dm +++ b/code/modules/vending/games.dm @@ -32,7 +32,8 @@ /obj/item/canvas/nineteen_nineteen = 5, /obj/item/canvas/twentythree_nineteen = 5, /obj/item/canvas/twentythree_twentythree = 5, - /obj/item/paint_palette = 3 + /obj/item/paint_palette = 3, + /obj/item/wallframe/painting/large = 5, ) //SKYRAT EDIT: Adds Ceramic, Glassblowing, and Fishing Skillchips contraband = list( @@ -44,6 +45,8 @@ /obj/item/disk/holodisk = 5, /obj/item/toy/crayon/spraycan = 3, /obj/item/canvas/twentyfour_twentyfour = 5, + /obj/item/canvas/thirtysix_twentyfour = 3, + /obj/item/canvas/fortyfive_twentyseven = 3, /obj/item/rcl = 2, /obj/item/airlock_painter = 1, /obj/item/melee/skateboard/pro = 3, diff --git a/icons/obj/artstuff.dmi b/icons/obj/artstuff.dmi index c6ee25e3f61..a3dd1a84d9d 100644 Binary files a/icons/obj/artstuff.dmi and b/icons/obj/artstuff.dmi differ diff --git a/icons/obj/artstuff_64x64.dmi b/icons/obj/artstuff_64x64.dmi new file mode 100644 index 00000000000..5f840e558b5 Binary files /dev/null and b/icons/obj/artstuff_64x64.dmi differ diff --git a/icons/obj/decals.dmi b/icons/obj/decals.dmi index 523756de9ab..4da4913ac91 100644 Binary files a/icons/obj/decals.dmi and b/icons/obj/decals.dmi differ diff --git a/tgui/packages/tgui/interfaces/Canvas.tsx b/tgui/packages/tgui/interfaces/Canvas.tsx index 4d44d99e570..13b84c5ae8e 100644 --- a/tgui/packages/tgui/interfaces/Canvas.tsx +++ b/tgui/packages/tgui/interfaces/Canvas.tsx @@ -5,8 +5,6 @@ import { useBackend } from '../backend'; import { Box, Button, Flex } from '../components'; import { Window } from '../layouts'; -const PX_PER_UNIT = 24; - type PaintCanvasProps = Partial<{ onCanvasModifiedHandler: (data : PointData[]) => void, value: string[][], @@ -189,6 +187,7 @@ type PaletteColor = { type CanvasData = { grid: string[][], + px_per_unit: number, finalized: boolean, name: string, editable: boolean, @@ -204,8 +203,8 @@ type CanvasData = { export const Canvas = (props, context) => { const { act, data } = useBackend(context); const [width, height] = getImageSize(data.grid); - const scaled_width = width * PX_PER_UNIT; - const scaled_height = height * PX_PER_UNIT; + const scaled_width = width * data.px_per_unit; + const scaled_height = height * data.px_per_unit; const average_plaque_height = 90; const palette_height = 36; return ( diff --git a/tgui/packages/tgui/interfaces/NtosPortraitPrinter.js b/tgui/packages/tgui/interfaces/NtosPortraitPrinter.js index 16d7e308c08..a33c4ac18a9 100644 --- a/tgui/packages/tgui/interfaces/NtosPortraitPrinter.js +++ b/tgui/packages/tgui/interfaces/NtosPortraitPrinter.js @@ -18,6 +18,8 @@ export const NtosPortraitPrinter = (props, context) => { && "By " + paintings[listIndex]["creator"]; const current_portrait_asset_name = got_paintings && "paintings" + "_" + paintings[listIndex]["md5"]; + const current_portrait_ratio = got_paintings + && paintings[listIndex]["ratio"]; return ( {