diff --git a/aurorastation.dme b/aurorastation.dme index ce705c103e8..1c7c783bfab 100644 --- a/aurorastation.dme +++ b/aurorastation.dme @@ -873,9 +873,11 @@ #include "code\game\objects\items\bees_items.dm" #include "code\game\objects\items\blueprints.dm" #include "code\game\objects\items\bodybag.dm" +#include "code\game\objects\items\canvas.dm" #include "code\game\objects\items\contraband.dm" #include "code\game\objects\items\crayons.dm" #include "code\game\objects\items\draftingchalk.dm" +#include "code\game\objects\items\easel.dm" #include "code\game\objects\items\eightball.dm" #include "code\game\objects\items\glassjar.dm" #include "code\game\objects\items\holomenu.dm" diff --git a/code/game/objects/items/canvas.dm b/code/game/objects/items/canvas.dm new file mode 100644 index 00000000000..45f52a1fc1d --- /dev/null +++ b/code/game/objects/items/canvas.dm @@ -0,0 +1,139 @@ +/** + * Interface for using DrawBox() to draw 1 pixel on a coordinate. + * Returns the same icon specifed in the argument, but with the pixel drawn. + */ +/proc/DrawPixel(icon/I, color, drawX, drawY) + if(!I) + return FALSE + + var/Iwidth = I.Width() + var/Iheight = I.Height() + + if(drawX > Iwidth || drawX <= 0) + return FALSE + if(drawY > Iheight || drawY <= 0) + return FALSE + + I.DrawBox(color, drawX, drawY) + return I + +/** + * Interface for easy drawing of one pixel on an atom. + */ +/atom/proc/DrawPixelOn(color, drawX, drawY) + var/icon/I = new(icon) + var/icon/J = DrawPixel(I, color, drawX, drawY) + if(J) // Only set the icon if it succeeded, the icon without the pixel is 1000x better than a black square. + icon = J + return J + return FALSE + +/obj/item/canvas + name = "11px by 11px canvas" + desc = "Draw out your soul on this canvas! Only crayons can draw on it." + icon = 'icons/obj/canvas.dmi' + icon_state = "11x11" + +/obj/item/canvas/nineteen_nineteen + name = "19px by 19px canvas" + icon_state = "19x19" + +/obj/item/canvas/twentythree_nineteen + name = "23px by 19px canvas" + icon_state = "23x19" + +/obj/item/canvas/twentythree_twentythree + name = "23px by 23px canvas" + icon_state = "23x23" + +/** + * One pixel increments. + */ +/obj/item/canvas/attackby(obj/item/I, mob/user, params) + if(I.iswrench()) + playsound(src.loc, I.usesound, 100, 1) + to_chat(user, SPAN_NOTICE("You begin to [anchored ? "loosen" : "tighten"] \the [src]...")) + if(do_after(user, 40 / I.toolspeed)) + user.visible_message("[user] [anchored ? "loosens" : "tightens"] \the [src].", SPAN_NOTICE("You [anchored ? "loosen" : "tighten"] \the [src]."), SPAN_NOTICE("You hear a ratchet.")) + anchored = !anchored + return + + // Click info. + var/list/click_params = params2list(params) + var/pixX = text2num(click_params["icon-x"]) + var/pixY = text2num(click_params["icon-y"]) + + // Should always be true, otherwise you didn't click the object, but let's check because SS13~ + if(!click_params || !click_params["icon-x"] || !click_params["icon-y"]) + return + + // Cleaning one pixel with a soap or rag. + if(istype(I, /obj/item/soap) || istype(I, /obj/item/reagent_containers/glass/rag)) + // Pixel info created only when needed. + var/icon/masterpiece = icon(icon,icon_state) + var/thePix = masterpiece.GetPixel(pixX,pixY) + var/icon/Ico = clean_canvas() + if(!Ico) + qdel(masterpiece) + return + + var/theOriginalPix = Ico.GetPixel(pixX,pixY) + if(thePix != theOriginalPix) // Clour changed. + DrawPixelOn(theOriginalPix,pixX,pixY) + qdel(masterpiece) + + // Drawing one pixel with a crayon. + else if(istype(I, /obj/item/pen/crayon)) + var/obj/item/pen/crayon/C = I + DrawPixelOn(C.shadeColour, pixX, pixY) + else + return ..() + +/** + * Clean the whole canvas. + */ +/obj/item/canvas/attack_self(mob/user) + if(!user) + return + var/icon/blank = clean_canvas() + if(blank) + // It's basically a giant etch-a-sketch. + icon = blank + user.visible_message("[user] cleans the canvas.", SPAN_NOTICE("You clean the canvas.")) + +/obj/item/canvas/afterattack(turf/A, mob/user, flag, params) + if(!istype(A)) + return + + if(!iswall(A)) + return + + var/turf/target_turf = A + var/turf/source_turf = get_turf(user) + + var/dir_offset = 0 + if(target_turf != source_turf) + dir_offset = get_dir(source_turf, target_turf) + if(!(dir_offset in global.cardinal)) + to_chat(user, SPAN_WARNING("You cannot reach that from here.")) + return + + if(user.unEquip(src, source_turf)) + if(params) + var/list/mouse_control = params2list(params) + if(mouse_control["icon-x"]) + pixel_x = text2num(mouse_control["icon-x"]) - 16 + if(dir_offset & EAST) + pixel_x += 32 + else if(dir_offset & WEST) + pixel_x -= 32 + if(mouse_control["icon-y"]) + pixel_y = text2num(mouse_control["icon-y"]) - 16 + if(dir_offset & NORTH) + pixel_y += 32 + else if(dir_offset & SOUTH) + pixel_y -= 32 + +/obj/item/canvas/proc/clean_canvas() + var/icon/I = icon(initial(icon), initial(icon_state)) + . = I \ No newline at end of file diff --git a/code/game/objects/items/easel.dm b/code/game/objects/items/easel.dm new file mode 100644 index 00000000000..925de487ec7 --- /dev/null +++ b/code/game/objects/items/easel.dm @@ -0,0 +1,47 @@ +/obj/structure/easel + name = "easel" + desc = "Only for the finest of art!" + icon = 'icons/obj/canvas.dmi' + icon_state = "easel" + density = TRUE + build_amt = 5 + var/obj/item/canvas/painting = null + +/obj/structure/easel/Initialize(ml, _mat, _reinf_mat) + . = ..() + moved_event.register(src, src, /obj/structure/easel/proc/move_painting) + +/obj/structure/easel/Destroy() + painting = null + moved_event.unregister(src, src, /obj/structure/easel/proc/move_painting) + return ..() + +/* + * Adding canvases. + */ +/obj/structure/easel/attackby(obj/item/I, mob/user, params) + if(istype(I, /obj/item/canvas)) + var/obj/item/canvas/C = I + if(user.unEquip(C)) + painting = C + C.forceMove(get_turf(src)) + C.layer = layer + 0.1 + C.pixel_x = 0 + C.pixel_y = 0 + C.pixel_z = 0 + user.visible_message("[user] puts \the [C] on \the [src].", SPAN_NOTICE("You place \the [C] on \the [src].")) + return + if(I.iswrench()) + to_chat(user, SPAN_NOTICE("You dismantle \the [src].")) + dismantle() + return + return ..() + +/* + * Stick to the easel like glue. + */ +/obj/structure/easel/proc/move_painting() + if(painting && Adjacent(painting)) // Only move if it's near us. + painting.forceMove(get_turf(src)) + else + painting = null \ No newline at end of file diff --git a/code/modules/library/lib_items.dm b/code/modules/library/lib_items.dm index 0e62b0def28..d6d02ebda2b 100644 --- a/code/modules/library/lib_items.dm +++ b/code/modules/library/lib_items.dm @@ -46,11 +46,9 @@ to_chat(user, "You begin dismantling \the [src].") if(do_after(user,25)) to_chat(user, "You dismantle \the [src].") - new /obj/item/stack/material/wood(get_turf(src), 3) for(var/obj/item/book/b in contents) b.forceMove((get_turf(src))) - qdel(src) - + dismantle() else ..() diff --git a/code/modules/materials/material_recipes.dm b/code/modules/materials/material_recipes.dm index 8542e65af86..39663e46848 100644 --- a/code/modules/materials/material_recipes.dm +++ b/code/modules/materials/material_recipes.dm @@ -165,7 +165,8 @@ new /datum/stack_recipe("wooden bucket", /obj/item/reagent_containers/glass/bucket/wood, 2, time = 4, one_per_turf = 0, on_floor = 0), new /datum/stack_recipe("shaft", /obj/item/material/shaft, 10, time = 25, one_per_turf = 0, on_floor = 0), new /datum/stack_recipe("buckler donut", /obj/item/material/woodenshield, 20, time = 25, one_per_turf = 0, on_floor = 0), - new /datum/stack_recipe("torch handle", /obj/item/torch, 3, time = 5, one_per_turf = 0, on_floor = 0) + new /datum/stack_recipe("torch handle", /obj/item/torch, 3, time = 5, one_per_turf = 0, on_floor = 0), + new /datum/stack_recipe("easel", /obj/structure/easel, BUILD_AMT, time = 15, one_per_turf = 1, on_floor = 1) )) /material/stone/generate_recipes() @@ -209,6 +210,13 @@ new /datum/stack_recipe("red shower curtain", /obj/structure/curtain/open/shower/security, BUILD_AMT, time = 10), new /datum/stack_recipe("privacy curtain", /obj/structure/curtain/open/privacy, BUILD_AMT, time = 10) )) + recipes += new /datum/stack_recipe_list("[display_name] canvases", + list( + new /datum/stack_recipe("canvas 11x11", /obj/item/canvas, 3), + new /datum/stack_recipe("canvas 19x19", /obj/item/canvas/nineteen_nineteen, 5), + new /datum/stack_recipe("canvas 23x19", /obj/item/canvas/twentythree_nineteen, 6), + new /datum/stack_recipe("canvas 23x23", /obj/item/canvas/twentythree_twentythree, 8) + )) /material/hide/xeno/generate_recipes() ..() diff --git a/html/changelogs/geeves-painting_time.yml b/html/changelogs/geeves-painting_time.yml new file mode 100644 index 00000000000..ef10a8ac37c --- /dev/null +++ b/html/changelogs/geeves-painting_time.yml @@ -0,0 +1,7 @@ +author: Geeves + +delete-after: True + +changes: + - rscadd: "You can now make an easel out of 5 wood, and a canvas of various sizes out of cloth. To draw on the canvas, use a crayon on it, to clean, use soap or a rag. Using the canvas in-hand will completely clean it." + - tweak: "Bookcases now drop all the materials used to make them when dismantled." \ No newline at end of file diff --git a/icons/obj/canvas.dmi b/icons/obj/canvas.dmi new file mode 100644 index 00000000000..ea24341f5e0 Binary files /dev/null and b/icons/obj/canvas.dmi differ