diff --git a/code/datums/greyscale/README.md b/code/datums/greyscale/README.md index 2e39af452a2..d0bbd846587 100644 --- a/code/datums/greyscale/README.md +++ b/code/datums/greyscale/README.md @@ -29,7 +29,7 @@ The json is made up of some metadata and a list of layers used while creating th ```json { - "layers": [ + "icon_state_name": [ { "type": "reference", "reference_type": "/datum/greyscale_config/some_other_config", @@ -61,6 +61,8 @@ The last layer is another reference type. Note that you don't need to give color "blend_mode" and "color_ids" are special, all layer types have them. The blend mode is what controls how that layer's finished product gets merged together with the rest of the sprite. The color ids control what colors are passed in to the layer. +Once it is done generating it will be placed in an icon file with the icon state of "icon_state_name". You can use any name you like here. + ## Dmi File There are no special requirements from the dmi file to work with this system. You just need to specify the icon file in code and the icon_state in the json configuration. @@ -88,4 +90,4 @@ More configurations can be found in [code/datums/greyscale/greyscale_configs.dm] ## Debugging -If you're making a new greyscale sprite you sometimes want to be able to see how layers got generated or maybe you're just tweaking some colors. Rather than rebooting the server with every change there is a greyscale modification menu that can be found in the vv dropdown menu for the greyscale object. Here you can change colors and preview the results. +If you're making a new greyscale sprite you sometimes want to be able to see how layers got generated or maybe you're just tweaking some colors. Rather than rebooting the server with every change there is a greyscale modification menu that can be found in the vv dropdown menu for the greyscale object. Here you can change colors, preview the results, and reload everything from their files. diff --git a/code/datums/greyscale/_greyscale_config.dm b/code/datums/greyscale/_greyscale_config.dm index 78bc4baf644..c220e3c2410 100644 --- a/code/datums/greyscale/_greyscale_config.dm +++ b/code/datums/greyscale/_greyscale_config.dm @@ -14,8 +14,8 @@ /// String path to the icon file, used for reloading var/string_icon_file - /// Layer objects that the sprite is made up of - var/list/layers + /// A list of icon states and their layers + var/list/icon_states /// How many colors are expected to be given when building the sprite var/expected_colors = 0 @@ -40,10 +40,13 @@ json_config = file(string_json_config) icon_file = file(string_icon_file) + icon_states = list() + var/list/raw = json_decode(file2text(json_config)) - layers = ReadLayersFromJson(raw["layers"]) - if(!length(layers)) - CRASH("The json configuration [DebugName()] is missing any layers.") + ReadIconStateConfiguration(raw) + + if(!length(icon_states)) + CRASH("The json configuration [DebugName()] is missing any icon_states.") icon_cache = list() @@ -53,6 +56,17 @@ /datum/greyscale_config/proc/DebugName() return "([icon_file]|[json_config])" +/// Takes the json icon state configuration and puts it into a more processed format +/datum/greyscale_config/proc/ReadIconStateConfiguration(list/data) + for(var/state in data) + var/list/raw_layers = data[state] + if(!length(raw_layers)) + stack_trace("The json configuration [DebugName()] for icon state '[state]' is missing any layers.") + continue + if(icon_states[state]) + stack_trace("The json configuration [DebugName()] has a duplicate icon state '[state]' and is being overriden.") + icon_states[state] = ReadLayersFromJson(raw_layers) + /// Takes the json layers configuration and puts it into a more processed format /datum/greyscale_config/proc/ReadLayersFromJson(list/data) var/list/output = ReadLayerGroup(data) @@ -74,7 +88,9 @@ /// Reads layer configurations to take out some useful overall information /datum/greyscale_config/proc/ReadMetadata() var/list/datum/greyscale_layer/all_layers = list() - var/list/to_process = list(layers) + var/list/to_process = list() + for(var/state in icon_states) + to_process += icon_states[state] while(length(to_process)) var/current = to_process[length(to_process)] to_process.len-- @@ -91,21 +107,24 @@ expected_colors = length(color_groups) /// Actually create the icon and color it in, handles caching -/datum/greyscale_config/proc/Generate(color_string) +/datum/greyscale_config/proc/Generate(color_string, list/render_steps) var/key = color_string var/icon/new_icon = icon_cache[key] - if(new_icon) + if(new_icon && !render_steps) return icon(new_icon) var/list/colors = ParseColorString(color_string) if(length(colors) != expected_colors) CRASH("[DebugName()] expected [expected_colors] color arguments but only received [length(colors)]") - new_icon = GenerateLayerGroup(colors, layers) - // We read a pixel to force the icon to be fully generated before we let it loose into the world - // I hate this - new_icon.GetPixel(1, 1) - new_icon = fcopy_rsc(new_icon) - icon_cache[key] = new_icon - return icon(new_icon) + var/icon/icon_bundle = new + for(var/icon_state in icon_states) + var/icon/generated_icon = GenerateLayerGroup(colors, icon_states[icon_state], render_steps) + // We read a pixel to force the icon to be fully generated before we let it loose into the world + // I hate this + generated_icon.GetPixel(1, 1) + icon_bundle.Insert(generated_icon, icon_state) + icon_bundle = fcopy_rsc(icon_bundle) + icon_cache[key] = icon_bundle + return icon(icon_bundle) /// Internal recursive proc to handle nested layer groups /datum/greyscale_config/proc/GenerateLayerGroup(list/colors, list/group, list/render_steps) @@ -125,20 +144,15 @@ // These are so we can see the result of every step of the process in the preview ui if(render_steps) - var/icon/new_icon_copy = new(new_icon) - var/icon/layer_icon_copy = new(layer_icon) - render_steps[layer_icon_copy] = icon(new_icon_copy) + render_steps[image(new_icon)] = image(layer_icon) return new_icon -/datum/greyscale_config/proc/GenerateDebug(list/colors) - if(length(colors) != expected_colors) - CRASH("[DebugName()] expected [expected_colors] color arguments but only received [length(colors)]") - +/datum/greyscale_config/proc/GenerateDebug(colors) var/list/output = list() var/list/debug_steps = list() output["steps"] = debug_steps - output["icon"] = GenerateLayerGroup(colors, layers, debug_steps) + output["icon"] = Generate(colors, debug_steps) return output /datum/greyscale_config/proc/ParseColorString(color_string) diff --git a/code/datums/greyscale/json_configs/canister_base.json b/code/datums/greyscale/json_configs/canister_base.json index c9318e8a26c..4528c6225c6 100644 --- a/code/datums/greyscale/json_configs/canister_base.json +++ b/code/datums/greyscale/json_configs/canister_base.json @@ -1,5 +1,5 @@ { - "layers": [ + "": [ { "type": "icon_state", "icon_state": "base", diff --git a/code/datums/greyscale/json_configs/canister_default.json b/code/datums/greyscale/json_configs/canister_default.json index a37d83fc322..7ce97efcc57 100644 --- a/code/datums/greyscale/json_configs/canister_default.json +++ b/code/datums/greyscale/json_configs/canister_default.json @@ -1,5 +1,5 @@ { - "layers": [ + "": [ { "type": "reference", "reference_type": "/datum/greyscale_config/canister/base", diff --git a/code/datums/greyscale/json_configs/canister_double_stripe.json b/code/datums/greyscale/json_configs/canister_double_stripe.json index f1dd6410041..914f7102719 100644 --- a/code/datums/greyscale/json_configs/canister_double_stripe.json +++ b/code/datums/greyscale/json_configs/canister_double_stripe.json @@ -1,5 +1,5 @@ { - "layers": [ + "": [ { "type": "reference", "reference_type": "/datum/greyscale_config/canister/base", diff --git a/code/datums/greyscale/json_configs/canister_hazard.json b/code/datums/greyscale/json_configs/canister_hazard.json index d900035650f..5bd07b49d4c 100644 --- a/code/datums/greyscale/json_configs/canister_hazard.json +++ b/code/datums/greyscale/json_configs/canister_hazard.json @@ -1,5 +1,5 @@ { - "layers": [ + "": [ { "type": "reference", "reference_type": "/datum/greyscale_config/canister/base", diff --git a/code/datums/greyscale/json_configs/canister_post_effects.json b/code/datums/greyscale/json_configs/canister_post_effects.json index ee2b550638c..6756c3221f9 100644 --- a/code/datums/greyscale/json_configs/canister_post_effects.json +++ b/code/datums/greyscale/json_configs/canister_post_effects.json @@ -1,5 +1,5 @@ { - "layers": [ + "": [ { "type": "icon_state", "icon_state": "outline", diff --git a/code/datums/greyscale/json_configs/canister_proto.json b/code/datums/greyscale/json_configs/canister_proto.json index f77e9a5ada9..09f19b80e9b 100644 --- a/code/datums/greyscale/json_configs/canister_proto.json +++ b/code/datums/greyscale/json_configs/canister_proto.json @@ -1,5 +1,5 @@ { - "layers": [ + "": [ { "type": "icon_state", "icon_state": "can_base", diff --git a/code/datums/greyscale/json_configs/canister_stripe.json b/code/datums/greyscale/json_configs/canister_stripe.json index 91444eb566d..0fe05bf9112 100644 --- a/code/datums/greyscale/json_configs/canister_stripe.json +++ b/code/datums/greyscale/json_configs/canister_stripe.json @@ -1,5 +1,5 @@ { - "layers": [ + "": [ { "type": "reference", "reference_type": "/datum/greyscale_config/canister/base", diff --git a/code/datums/greyscale/json_configs/wirecutters.json b/code/datums/greyscale/json_configs/wirecutters.json index b27a2367aec..3e08c430b9f 100644 --- a/code/datums/greyscale/json_configs/wirecutters.json +++ b/code/datums/greyscale/json_configs/wirecutters.json @@ -1,5 +1,5 @@ { - "layers": [ + "": [ { "type": "icon_state", "icon_state": "cutters", diff --git a/code/datums/greyscale/layer.dm b/code/datums/greyscale/layer.dm index e0c2a1eac86..c1aa41f7550 100644 --- a/code/datums/greyscale/layer.dm +++ b/code/datums/greyscale/layer.dm @@ -14,6 +14,9 @@ /datum/greyscale_layer/New(icon_file, list/json_data) color_ids = json_data["color_ids"] + for(var/i in color_ids) + if(!isnum(i)) + CRASH("Color ids must be a positive integer starting from 1, '[i]' is not valid. Make sure it is not quoted in the json configuration.") blend_mode = blend_modes[lowertext(json_data["blend_mode"])] if(isnull(blend_mode)) CRASH("Greyscale config for [icon_file] is missing a blend mode on a layer.") @@ -26,7 +29,7 @@ processed_colors += colors[i] return InternalGenerate(processed_colors, render_steps) -/datum/greyscale_layer/proc/InternalGenerate(list/colors) +/datum/greyscale_layer/proc/InternalGenerate(list/colors, list/render_steps) //////////////////////////////////////////////////////// // Subtypes @@ -66,9 +69,4 @@ CRASH("An unknown greyscale configuration was given to a reference layer: [json_data["reference_type"]]") /datum/greyscale_layer/reference/InternalGenerate(list/colors, list/render_steps) - if(render_steps) - // We're debugging - var/list/debug_data = reference_config.GenerateDebug(colors) - render_steps += debug_data["steps"] - return debug_data["icon"] - return reference_config.Generate(colors.Join()) + return reference_config.Generate(colors.Join(), render_steps) diff --git a/code/modules/admin/greyscale_modify_menu.dm b/code/modules/admin/greyscale_modify_menu.dm index e2a3cc4393d..d35b7a0f832 100644 --- a/code/modules/admin/greyscale_modify_menu.dm +++ b/code/modules/admin/greyscale_modify_menu.dm @@ -83,10 +83,11 @@ split_colors += "#[raw_colors[i]]" /datum/greyscale_modify_menu/proc/refresh_preview() - var/list/data = SSgreyscale.configurations["[target.greyscale_config]"].GenerateDebug(split_colors) + var/list/data = SSgreyscale.configurations["[target.greyscale_config]"].GenerateDebug(split_colors.Join()) sprite_data = list() var/list/steps = list() sprite_data["steps"] = steps for(var/step in data["steps"]) + CHECK_TICK steps += list(list("layer"=icon2html(data["steps"][step], user, sourceonly=TRUE), "result"=icon2html(step, user, sourceonly=TRUE)))