Some painting fixes (#31632)

* Fix supply packs

* Fix painting descriptions so you can tell what kind of canvas an item is

* Have palette (item) colors show up on painting UI palette

* Fixes templates sometimes being broken due to opacity, and a few minor things here and there.

* Fixes remote painting. Also fixes a bunch of inconsistencies between paintings in item vs structure form, conversion between the two, glass pane behavior, descriptions, etc.
This commit is contained in:
jellyveggie2
2021-12-14 17:05:47 +01:00
committed by GitHub
parent 6055659cb9
commit f668a164d4
9 changed files with 182 additions and 45 deletions

View File

@@ -371,11 +371,11 @@ var/list/all_supply_groups = list("Supplies","Clothing","Security","Hospitality"
/obj/item/weapon/reagent_containers/glass/paint/white,
/obj/item/weapon/reagent_containers/glass/paint/remover,
/obj/item/weapon/painting_brush,
/obj/structure/painting/custom,
/obj/structure/painting/custom,
/obj/structure/painting/custom/landscape,
/obj/structure/painting/custom/portrait,
/obj/structure/painting/custom/large,
/obj/item/mounted/frame/painting/custom,
/obj/item/mounted/frame/painting/custom,
/obj/item/mounted/frame/painting/custom/landscape,
/obj/item/mounted/frame/painting/custom/portrait,
/obj/item/mounted/frame/painting/custom/large,
/obj/item/mounted/poster,
/obj/item/stack/package_wrap/gift,
/obj/item/stack/package_wrap/gift,

View File

@@ -309,7 +309,7 @@ var/global/list/available_paintings = list(
else
name = "painting"
desc = "a blank painting."
desc = "so perfectly blank you dare not paint on it."
/obj/structure/painting/attack_hand(mob/user)
to_chat(user, "<span class='notice'>You pick up \the [src]...</span>")

View File

@@ -86,13 +86,25 @@
border: 1px solid #000000;
}
.palette div {
.palette div.paletteColor {
width: 28px;
height: 28px;
display: inline-block;
border: 1px solid #000000;
}
.palette div.paletteButton {
background: #40628a;
}
.palette div.paletteButton:hover {
background: #507aac;
}
.paletteButton .uiIcon16 {
margin: 6px;
}
.toolPanel input[type="text"] {
width: 5ch;
text-align:center

View File

@@ -3,7 +3,9 @@
* Scripts meant to handle canvas.html
*/
//--------------------------------
// Tab selector
//--------------------------------
var panelIdList = ["infoPanel", "templatePanel", "exportPanel"];
function panelSelect(panelId) {
var panelClass;
@@ -36,7 +38,9 @@ function toggleHelp(helpButton, helpPanel) {
toggleClass(helpPanel, "hidden");
}
//--------------------------------
// Template control
//--------------------------------
var currentTemplate = {};
/* A test template for 14x14 sized paintings
{
@@ -198,17 +202,21 @@ function templatePaint(id) {
if (currentTemplate.bmp[i] == id) {
var x = i % width;
var y = (i - x)/width;
pixelDraw(x, y, paint_color, paint_strength);
pixelDraw(x, y, getPaintColor(), getOpacity());
}
}
display_bitmap();
document.getElementById("bitmap").value = bitmap;
}
//--------------------------------
// INIT
//--------------------------------
var src;
function initCanvas(paintInitData, canvasInitData) {
initPaint(paintInitData);
document.getElementById("paintColumn").style.maxWidth = (document.getElementById("canvas").width + 40) + "px";
document.getElementById("paint_strength").value = getOpacity()
canvasInitData = JSON.parse(canvasInitData);
@@ -229,11 +237,14 @@ function initCanvas(paintInitData, canvasInitData) {
for (color in palette) {
paletteButtonPanel.innerHTML +=
'<div onclick="setColor(\'' + palette[color] + '\');" style="background-image:' + generateColorPaletteBackgroundStyle(palette[color]) + '; background-image:' + generateColorPaletteBackgroundStyle(palette[color], true) + '"></div>\n';
'<div class="paletteColor" onclick="setColor(\'' + palette[color] + '\');" style="background-image:' + generateColorPaletteBackgroundStyle(palette[color]) + '; background-image:' + generateColorPaletteBackgroundStyle(palette[color], true) + '"></div>\n';
}
setColor(palette[0]);
}
//--------------------------------
// COLORS & PALETTE
//--------------------------------
function generateColorPaletteBackgroundStyle (color, ieMode) {
let colorOpaque = hexToRgba(color);
colorOpaque.a = 255;
@@ -277,6 +288,9 @@ function setStrength() {
updateSelectedColorDisplay(getPaintColor(), strengthInput.value);
}
//--------------------------------
// SUBMIT
//--------------------------------
function sanitizeLength (inputId, meterId) {
var input = document.getElementById(inputId);

View File

@@ -125,6 +125,7 @@
<!-- Paint Tool Controls -->
<div class="paintPanel">
<div class="item">
<span class="toolPanel">
<label class="itemLabelNarrow">Opacity: </label>
<a id="paint_strength_lower" class="button" onclick="changeStrength(-0.05);"><div class="uiIcon16 icon-minus"></div></a>
@@ -136,9 +137,9 @@
&nbsp;</span>
<a id="paint_strength_lower" class="button" onclick="changeStrength(0.05);"><div class="uiIcon16 icon-plus"></div></a>
</span>
<br/>
</div>
<!-- Selected Color -->
<div class="colorPanel">
<div class="item colorPanel">
<label class="selectedColor">
<div style="background: #000000" id="current_color"></div>
</label>

View File

@@ -3,8 +3,6 @@
#define BRUSH_STRENGTH_MAX 1
#define BRUSH_STRENGTH_MIN 0
/*
* PAINTING UTENSIL DATUM
*
@@ -14,7 +12,7 @@
/datum/painting_utensil
var/min_strength = 0
var/max_strength = 1
var/list/palette = list()
var/list/palette = list() // List of colors that will be made available while painting
var/base_color
/datum/painting_utensil/New(mob/user, obj/item/held_item)
@@ -22,6 +20,8 @@
return
if (!held_item)
held_item = user.get_active_hand()
// Painting with a pen
if (istype(held_item, /obj/item/weapon/pen))
var/obj/item/weapon/pen/p = held_item
max_strength = PENCIL_STRENGTH_MAX
@@ -29,6 +29,7 @@
palette += p.colour_rgb
base_color = p.colour_rgb
// Painting with a crayon
if (istype(held_item, /obj/item/toy/crayon))
var/obj/item/toy/crayon/c = held_item
max_strength = PENCIL_STRENGTH_MAX
@@ -37,6 +38,7 @@
palette += c.shadeColour
base_color = c.color
// Painting with hair dye sprays
if (istype(held_item, /obj/item/weapon/hair_dye))
var/obj/item/weapon/hair_dye/h = held_item
max_strength = PENCIL_STRENGTH_MAX
@@ -44,14 +46,24 @@
palette += rgb(h.color_r, h.color_g, h.color_b)
base_color = rgb(h.color_r, h.color_g, h.color_b)
// Painting with a brush
if (istype(held_item, /obj/item/weapon/painting_brush))
// If holding a palette (item) add it's colors to the brush's list
for (var/obj/item/weapon/palette/pal in user.held_items)
for (var/datum/painting_utensil/pu in pal.stored_colours)
palette += pu.base_color
var/obj/item/weapon/painting_brush/b = held_item
if (b.paint_color)
max_strength = BRUSH_STRENGTH_MAX
min_strength = BRUSH_STRENGTH_MIN
palette += b.paint_color
// Players are likely to have one of the palette's colors on their brush from mixing colors earlier,
// so make sure we're not adding it again to the list
if (!(b.paint_color in palette))
palette += b.paint_color
base_color = b.paint_color
/datum/painting_utensil/proc/duplicate()
var/datum/painting_utensil/dupe = new(null, null)
dupe.max_strength = src.max_strength
@@ -127,12 +139,21 @@
src.parent = parent
mp_handler.set_parent(parent)
/datum/custom_painting/proc/blank_contents()
bitmap = list()
for (var/i = 0, i < bitmap_height * bitmap_width, i++)
bitmap += base_color
/datum/custom_painting/proc/is_blank()
if (author || title || description)
return FALSE
for (var/b in bitmap)
if (b != base_color)
return FALSE
return TRUE
/datum/custom_painting/proc/setup_UI()
// Setup head
var/head = {"
@@ -180,20 +201,22 @@
/datum/custom_painting/Topic(href, href_list)
world.log << "painting topic"
// Handle multipart href
if (href_list["multipart"])
world.log << "painting topic: href"
mp_handler.Topic(href, href_list)
return
// Save changes
else
world.log << "painting topic: onwards"
// Make sure the player can actually paint
if(!usr || usr.incapacitated())
return
var /datum/painting_utensil/pu = new /datum/painting_utensil(usr)
if(!pu.palette.len)
//TODO other tools (crayons, brushes)
to_chat(usr, "<span class='warning'>You need to be holding a painting utensil in your active hand.</span>")
return

View File

@@ -116,7 +116,7 @@ function initPaint(initData) {
minPaintStrength = initData.minPaintStrength;
maxPaintStrength = initData.maxPaintStrength;
setStrength();
setOpacity(maxPaintStrength);
//No data? start with a blank canvas
if (bitmap.length != width * height) {

View File

@@ -3,7 +3,7 @@
* here are applied there too.
*/
/obj/structure/painting/custom
name = "small canvas"
desc = "What to draw?"
var/blank = TRUE
@@ -21,9 +21,11 @@
var/base_icon = 'icons/obj/paintings.dmi'
var/base_icon_state = "blank"
starting_materials = list(MAT_WOOD = 2 * CC_PER_SHEET_WOOD)
/obj/structure/painting/custom/New()
..()
src.painting_data = new(src, painting_width, painting_height, painting_offset_x, painting_offset_y, base_color)
..()
/obj/structure/painting/custom/Destroy()
qdel(painting_data)
@@ -41,23 +43,28 @@
// Cleaning
if (istype(W, /obj/item/weapon/soap) && !protectedByGlass)
to_chat(usr, "<span class='warning'>You start cleaning \the [name].</span>")
if (do_after(user, src, 20))
painting_data.blank_contents()
icon = icon(base_icon, base_icon_state)
update_painting()
if (protectedByGlass)
to_chat(usr, "<span class='warning'>\the [name]'s glass cover stops you from cleaning it off.</span>")
else
to_chat(usr, "<span class='warning'>You start cleaning \the [name].</span>")
if (do_after(user, src, 20))
painting_data.blank_contents()
icon = icon(base_icon, base_icon_state)
update_painting()
// Protecting with glass
if (istype(W, /obj/item/stack/sheet/glass/glass) && !protectedByGlass)
var/obj/item/stack/sheet/glass/glass/GS = W
GS.use(1)
materials.addAmount(GS.mat_type, GS.perunit)
protectedByGlass = TRUE
update_painting()
to_chat(usr, "<span class='warning'>You cover \the [name] with a glass sheet.</span>")
if (W.is_screwdriver(user) && protectedByGlass)
var/obj/item/stack/sheet/glass/glass/G = new(user.loc, 1)
G.forceMove(user.loc)
var/obj/item/stack/sheet/glass/glass/GS = new(user.loc, 1)
GS.forceMove(user.loc)
materials.removeAmount(GS.mat_type, GS.perunit)
protectedByGlass = FALSE
update_painting()
to_chat(usr, "<span class='warning'>You screw off \the [name]'s glass cover .</span>")
@@ -65,16 +72,29 @@
return ..()
/obj/structure/painting/custom/Topic(href, href_list)
// Sanity checks
if(..())
return
if(usr.incapacitated())
return
if (!usr.dexterity_check())
to_chat(usr, "<span class='warning'>You don't have the dexterity to do this!</span>")
return
if (!in_range(src, usr))
return
add_fingerprint(usr)
add_hiddenprint(usr)
// Let /datum/custom_painting handle Topic(). If succesful, update appearance
if (painting_data.Topic(href, href_list))
blank = FALSE
update_painting(TRUE)
return ..()
/obj/structure/painting/custom/update_painting(render)
blank = painting_data.is_blank()
if (!blank)
name = (painting_data.title ? ("\proper[painting_data.title]") : "untitled artwork") + (painting_data.author ? ", by [painting_data.author]" : "")
desc = painting_data.description ? "A small plaque reads: \"<span class='info'>[painting_data.description]\"</span>" : "A painting. But what does it mean?"
desc = painting_data.description ? "A small plaque reads: \"<span class='info'>[painting_data.description]\"</span>" : "A painting... But what could it mean?"
if (render)
icon = painting_data.render_on(icon(base_icon, base_icon_state))
else
@@ -88,12 +108,25 @@
/obj/structure/painting/custom/to_item(mob/user)
var/obj/item/mounted/frame/painting/custom/P = new(user.loc)
P.set_painting_data(painting_data.Copy())
// Painting info
P.painting_data = painting_data.Copy()
P.rendered_icon = icon
P.base_icon = base_icon
P.base_icon_state = base_icon_state
P.blank = blank
// Glass panel info
P.protectedByGlass = protectedByGlass
P.materials = new /datum/materials(P)
P.materials.addFrom(materials)
// Fingerprint info
P.fingerprints = fingerprints
P.fingerprintshidden = fingerprintshidden
P.fingerprintslast = fingerprintslast
P.fingerprintslastTS = fingerprintslastTS
P.update_painting()
return P
@@ -104,6 +137,8 @@
* this separate icon is applied as the structure's icon
*/
/obj/item/mounted/frame/painting/custom
name = "small canvas"
desc = "What to draw?"
var/blank = TRUE
var/datum/custom_painting/painting_data
@@ -121,9 +156,11 @@
var/painting_offset_y = 9
var/base_color = "#ffffff"
starting_materials = list(MAT_WOOD = 2 * CC_PER_SHEET_WOOD)
/obj/item/mounted/frame/painting/custom/New()
..()
src.painting_data = new(src, painting_width, painting_height, painting_offset_x, painting_offset_y, base_color)
..()
/obj/item/mounted/frame/painting/custom/Destroy()
qdel(painting_data)
@@ -131,27 +168,54 @@
..()
/obj/item/mounted/frame/painting/custom/attackby(obj/item/W, mob/user)
// Painting
var/datum/painting_utensil/p = new(user, W)
if (p.palette.len)
painting_data.interact(user, p)
if (protectedByGlass)
to_chat(usr, "<span class='warning'>\the [name]'s glass cover stops you from painting on it.</span>")
else
painting_data.interact(user, p)
if (istype(W, /obj/item/weapon/soap))
to_chat(usr, "<span class='warning'>You start cleaning \the [name].</span>")
if (do_after(user, src, 20))
painting_data.blank_contents()
rendered_icon = icon(base_icon, base_icon_state)
update_painting()
// Cleaning
if (istype(W, /obj/item/weapon/soap) && !protectedByGlass)
if (protectedByGlass)
to_chat(usr, "<span class='warning'>\the [name]'s glass cover stops you from cleaning it off.</span>")
else
to_chat(usr, "<span class='warning'>You start cleaning \the [name].</span>")
if (do_after(user, src, 20))
painting_data.blank_contents()
rendered_icon = icon(base_icon, base_icon_state)
update_painting()
// Protecting with glass
if (istype(W, /obj/item/stack/sheet/glass/glass) && !protectedByGlass)
var/obj/item/stack/sheet/glass/glass/GS = W
GS.use(1)
materials.addAmount(GS.mat_type, GS.perunit)
protectedByGlass = TRUE
update_painting()
to_chat(usr, "<span class='warning'>You cover \the [name] with a glass sheet.</span>")
if (W.is_screwdriver(user) && protectedByGlass)
var/obj/item/stack/sheet/glass/glass/GS = new(user.loc, 1)
GS.forceMove(user.loc)
materials.removeAmount(GS.mat_type, GS.perunit)
protectedByGlass = FALSE
update_painting()
to_chat(usr, "<span class='warning'>You screw off \the [name]'s glass cover .</span>")
return ..()
/obj/item/mounted/frame/painting/custom/Topic(href, href_list)
if(..())
return
// Let /datum/custom_painting handle Topic(). If succesful, update appearance
if (painting_data.Topic(href, href_list))
blank = FALSE
update_painting(TRUE)
return ..()
/obj/item/mounted/frame/painting/custom/update_painting(render)
blank = painting_data.is_blank()
if (!blank)
name = (painting_data.title ? ("\proper[painting_data.title]") : "untitled artwork") + (painting_data.author ? ", by [painting_data.author]" : "")
desc = painting_data.description ? "A small plaque reads: \"<span class='info'>[painting_data.description]\"</span>" : "A painting... But what could it mean?"
@@ -160,6 +224,7 @@
else
name = initial(name)
desc = initial(desc)
desc += protectedByGlass ? "\n A glass sheet protects it from would-be-vandals" : ""
/obj/item/mounted/frame/painting/custom/proc/set_painting_data(datum/custom_painting/painting_data)
src.painting_data = painting_data
@@ -167,13 +232,26 @@
/obj/item/mounted/frame/painting/custom/to_structure(turf/on_wall, mob/user)
var/obj/structure/painting/custom/P = new(user.loc)
P.set_painting_data(painting_data.Copy())
// Painting info
P.painting_data = painting_data.Copy()
P.icon = rendered_icon ? rendered_icon : icon(base_icon, base_icon_state)
P.icon_state = base_icon_state
P.base_icon = base_icon
P.base_icon_state = base_icon_state
P.blank = blank
// Glass panel info
P.protectedByGlass = protectedByGlass
P.materials = new /datum/materials(P)
P.materials.addFrom(materials)
// Fingerprint info
P.fingerprints = fingerprints
P.fingerprintshidden = fingerprintshidden
P.fingerprintslast = fingerprintslast
P.fingerprintslastTS = fingerprintslastTS
P.update_painting()
return P
@@ -185,6 +263,7 @@
// Blank landscape canvas
/obj/item/mounted/frame/painting/custom/landscape
name = "landscape canvas"
base_icon_state = "blank_landscape"
painting_height = 14
painting_width = 24
@@ -194,6 +273,7 @@
starting_materials = list(MAT_WOOD = CC_PER_SHEET_WOOD * 3)
/obj/structure/painting/custom/landscape
name = "landscape canvas"
icon_state = "blank_landscape"
base_icon_state = "blank_landscape"
painting_height = 14
@@ -205,6 +285,7 @@
// Blank portrait canvas
/obj/item/mounted/frame/painting/custom/portrait
name = "portrait canvas"
base_icon_state = "blank_portrait"
painting_height = 24
painting_width = 14
@@ -214,6 +295,7 @@
starting_materials = list(MAT_WOOD = CC_PER_SHEET_WOOD * 3)
/obj/structure/painting/custom/portrait
name = "portrait canvas"
icon_state = "blank_portrait"
base_icon_state = "blank_portrait"
painting_height = 24
@@ -225,6 +307,8 @@
// Large blank canvas
/obj/item/mounted/frame/painting/custom/large
name = "large canvas"
desc = "The larger the canvas, the more overwhelming it is to put pen to paper and get started."
base_icon_state = "blank_large"
painting_height = 24
painting_width = 24
@@ -234,6 +318,8 @@
starting_materials = list(MAT_WOOD = CC_PER_SHEET_WOOD * 5)
/obj/structure/painting/custom/large
name = "large canvas"
desc = "The larger the canvas, the more overwhelming it is to put pen to paper and get started."
icon_state = "blank_large"
base_icon_state = "blank_large"
painting_height = 24

View File

@@ -223,7 +223,8 @@ interactions:
rgb[1] = tmpRyb["r"] + tmpRyb["y"] - min(tmpRyb["y"], tmpRyb["b"]);
rgb[2] = tmpRyb["y"] + min(tmpRyb["y"], tmpRyb["b"]);
rgb[3] = 2*(tmpRyb["b"] - min(tmpRyb["y"], tmpRyb["b"]));
/* According to the RYB papers linked, the formula for green should be
/* According to the RYB papers linked in code\modules\html_interface\paintTool\paintTool.js,
* the formula for green should be:
* "g = y + 2*min(y, b)"
* But for whatever godforsaken reason that returns wrong values for colors where y < b
* (eg: cyan). Got rid of the '2*' on a hunch and sure it WORKS without breaking anything