diff --git a/SQL/migrate/V040__CustomSynths.sql b/SQL/migrate/V040__CustomSynths.sql new file mode 100644 index 00000000000..9891ccaff6f --- /dev/null +++ b/SQL/migrate/V040__CustomSynths.sql @@ -0,0 +1,16 @@ +-- +-- Create the Custom Synths database. +-- + +CREATE TABLE `ss13_customsynths` ( + `synthname` VARCHAR(128) NOT NULL, + `synthckey` varchar(32) NOT NULL, + `synthicon` VARCHAR(26) NOT NULL, + `aichassisicon` VARCHAR(100) NOT NULL, + `aiholoicon` VARCHAR(100) NOT NULL, + `paiicon` VARCHAR(100) NOT NULL, + PRIMARY KEY (`synthname`), + CONSTRAINT `fk_ss13_custom_synths_ss13_players` FOREIGN KEY (`synthckey`) REFERENCES `ss13_player` (`ckey`) ON DELETE CASCADE ON UPDATE CASCADE +) +ENGINE=InnoDB +; \ No newline at end of file diff --git a/aurorastation.dme b/aurorastation.dme index faacde8d034..6051bce61e3 100644 --- a/aurorastation.dme +++ b/aurorastation.dme @@ -299,6 +299,7 @@ #include "code\datums\helper_datums\events.dm" #include "code\datums\helper_datums\getrev.dm" #include "code\datums\helper_datums\space_ruin.dm" +#include "code\datums\helper_datums\synthsprites.dm" #include "code\datums\helper_datums\teleport.dm" #include "code\datums\helper_datums\topic_input.dm" #include "code\datums\looping_sounds\_looping_sound.dm" diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm index 43c3a3214ac..475dc62379a 100644 --- a/code/controllers/configuration.dm +++ b/code/controllers/configuration.dm @@ -286,6 +286,7 @@ var/list/gamemode_cache = list() var/rounds_until_hard_restart = -1 // Changes how often a hard restart will be executed. var/docs_load_docs_from + var/load_customsynths_from var/docs_image_host var/ert_base_chance = 10 @@ -899,6 +900,8 @@ var/list/gamemode_cache = list() if ("docs_load_docs_from") docs_load_docs_from = value + if ("load_customsynths_from") + load_customsynths_from = value if ("docs_image_host") docs_image_host = value diff --git a/code/datums/helper_datums/synthsprites.dm b/code/datums/helper_datums/synthsprites.dm new file mode 100644 index 00000000000..af02979e1b7 --- /dev/null +++ b/code/datums/helper_datums/synthsprites.dm @@ -0,0 +1,65 @@ + +/* + +Just some quick documentation about how this works + +Synthckey is the players ckey which is represented under the synths name in the json, this is required to have +synthicon is just the sprites name in the dmi +aichassisicon is the ai chassis icon sprite name +aiholoicon is the ai hologram icon sprite name +paiicon is the pai icon sprite name + +*/ + + + +/datum/custom_synth + var/synthname = "" + var/synthckey = "" + var/synthicon = "robot" + var/aichassisicon = "" + var/aiholoicon = "" + var/paiicon = "" + + + +/proc/loadsynths_from_json() + var/list/customsynthsprites = list() + try + customsynthsprites = json_decode(return_file_text("config/customsynths.json")) + catch(var/exception/ej) + log_debug("Error: Warning: Could not load custom synth config, as customsynths.json is missing - [ej]") + return + + robot_custom_icons = list() + customsynthsprites = customsynthsprites["synths"] + for (var/synthsprite in customsynthsprites) + var/datum/custom_synth/synth = new() + synth.synthname = synthsprite + synth.synthckey = customsynthsprites[synthsprite]["ckey"] + synth.synthicon = customsynthsprites[synthsprite]["synthicon"] + synth.aichassisicon = customsynthsprites[synthsprite]["aichassisicon"] + synth.aiholoicon = customsynthsprites[synthsprite]["aiholoicon"] + synth.paiicon = customsynthsprites[synthsprite]["paiicon"] + robot_custom_icons[synthsprite] = synth + +/proc/loadsynths_from_sql() + if(!establish_db_connection(dbcon)) + log_debug("SQL ERROR - Failed to connect. - Falling back to JSON") + loadsynths_from_json() + return + else + + var/DBQuery/customsynthsprites = dbcon.NewQuery("SELECT synthname, synthckey, synthicon, aichassisicon, aiholoicon, paiicon FROM ss13_customsynths WHERE deleted_at IS NULL ORDER BY synthckey ASC") + customsynthsprites.Execute() + while(customsynthsprites.NextRow()) + CHECK_TICK + + var/datum/custom_synth/synth = new() + synth.synthname = customsynthsprites.item[1] + synth.synthckey = customsynthsprites.item[2] + synth.synthicon = customsynthsprites.item[3] + synth.aichassisicon = customsynthsprites.item[4] + synth.aiholoicon = customsynthsprites.item[5] + synth.paiicon = customsynthsprites.item[6] + robot_custom_icons[synth.synthname] = synth diff --git a/code/modules/mob/holder.dm b/code/modules/mob/holder.dm index 685d1276b74..5361409773e 100644 --- a/code/modules/mob/holder.dm +++ b/code/modules/mob/holder.dm @@ -592,6 +592,19 @@ var/list/holder_mob_icon_cache = list() /obj/item/weapon/holder/pai/rabbit icon_state = "rabbit_rest" item_state = "rabbit" +/obj/item/weapon/holder/pai/custom + var/customsprite = 1 + +/obj/item/weapon/holder/pai/custom/sync(mob/living/M) + ..() + set_paiholder() + +/obj/item/weapon/holder/pai/custom/proc/set_paiholder() + + if(contained && customsprite == 1) + icon = CUSTOM_ITEM_SYNTH + icon_state = "[contained.icon_state]-holder" + item_state = "[contained.icon_state]" //corgi diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index 12c8a8e27fc..1870a287ae7 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -87,7 +87,7 @@ var/list/ai_verbs_default = list( var/list/cameraRecords = list() //For storing what is shown to the cameras var/datum/ai_icon/selected_sprite // The selected icon set - var/custom_sprite = 0 // Whether the selected icon is custom + var/custom_sprite = FALSE // Whether the selected icon is custom var/carded var/multitool_mode = 0 @@ -245,24 +245,13 @@ var/list/ai_verbs_default = list( return ..() /mob/living/silicon/ai/proc/setup_icon() - var/file = file2text("config/custom_sprites.txt") - var/lines = text2list(file, "\n") - - for(var/line in lines) - // split & clean up - var/list/Entry = text2list(line, ":") - for(var/i = 1 to Entry.len) - Entry[i] = trim(Entry[i]) - - if(Entry.len < 2) - continue; - - if(Entry[1] == src.ckey && Entry[2] == src.real_name) - icon = CUSTOM_ITEM_SYNTH - custom_sprite = 1 - selected_sprite = new/datum/ai_icon("Custom", "[src.ckey]-ai", "4", "[ckey]-ai-crash", "#FFFFFF", "#FFFFFF", "#FFFFFF") - else - selected_sprite = default_ai_icon + var/datum/custom_synth/sprite = robot_custom_icons[name] + if(istype(sprite) && sprite.synthckey == ckey) + custom_sprite = TRUE + icon = CUSTOM_ITEM_SYNTH + selected_sprite = new/datum/ai_icon("Custom", "[sprite.aichassisicon]", "4", "[sprite.aichassisicon]-crash", "#FFFFFF", "#FFFFFF", "#FFFFFF") + else + selected_sprite = default_ai_icon updateicon() /mob/living/silicon/ai/pointed(atom/A as mob|obj|turf in view()) @@ -634,7 +623,8 @@ var/list/ai_verbs_default = list( var/icon_list[] = list( "default", "floating face", - "carp" + "carp", + "custom" ) input = input("Please select a hologram:") as null|anything in icon_list if(input) @@ -646,6 +636,14 @@ var/list/ai_verbs_default = list( holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holo2")) if("carp") holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holo4")) + if("custom") + if(custom_sprite) + var/datum/custom_synth/sprite = robot_custom_icons[name] + if(istype(sprite) && sprite.synthckey == ckey && sprite.aiholoicon) + holo_icon = getHologramIcon(icon("icons/mob/custom_synths/customhologram.dmi","[sprite.aiholoicon]")) + else + to_chat(src, "You do not have a custom sprite!") + return return //Toggles the luminosity and applies it by re-entereing the camera. diff --git a/code/modules/mob/living/silicon/pai/pai.dm b/code/modules/mob/living/silicon/pai/pai.dm index 73685dfd2c7..f3952fa57d0 100644 --- a/code/modules/mob/living/silicon/pai/pai.dm +++ b/code/modules/mob/living/silicon/pai/pai.dm @@ -18,6 +18,7 @@ var/obj/item/device/paicard/card // The card we inhabit var/obj/item/device/radio/radio // Our primary radio + var/chassis = "repairbot" // A record of your chosen chassis. var/global/list/possible_chassis = list( "Drone" = "repairbot", @@ -25,6 +26,7 @@ "Rat" = "rat", "Monkey" = "monkey", "Rabbit" = "rabbit" + ) var/global/list/pai_holder_types = list( @@ -131,6 +133,7 @@ add_language(LANGUAGE_TRADEBAND, 1) add_language(LANGUAGE_GUTTER, 1) add_language(LANGUAGE_EAL, 1) + set_custom_sprite() verbs += /mob/living/silicon/pai/proc/choose_chassis verbs += /mob/living/silicon/pai/proc/choose_verbs @@ -146,6 +149,15 @@ pda.name = "[pda.owner] ([pda.ownjob])" pda.toff = TRUE + +/mob/living/silicon/pai/proc/set_custom_sprite() + var/datum/custom_synth/sprite = robot_custom_icons[name] + if(istype(sprite) && sprite.synthckey == ckey) + possible_chassis["Custom"] = "[sprite.paiicon]" + pai_holder_types["Custom"] = /obj/item/weapon/holder/pai/custom + icon = CUSTOM_ITEM_SYNTH + else + return /mob/living/silicon/pai/init_id() . = ..() idcard.registered_name = "" @@ -361,7 +373,7 @@ var/choice var/finalized = "No" while(finalized == "No" && src.client) - + set_custom_sprite() choice = input(usr,"What would you like to use for your mobile chassis icon? This decision can only be made once.") as null|anything in possible_chassis if(!choice) return diff --git a/code/modules/mob/living/silicon/robot/custom_sprites.dm b/code/modules/mob/living/silicon/robot/custom_sprites.dm index 737b01ef318..ba1fe2a4a3e 100644 --- a/code/modules/mob/living/silicon/robot/custom_sprites.dm +++ b/code/modules/mob/living/silicon/robot/custom_sprites.dm @@ -3,33 +3,21 @@ //Since the ckey is used as the icon_state, the current system will only permit a single custom robot sprite per ckey. //While it might be possible for a ckey to use that custom sprite for several real_names, it seems rather pointless to support it. var/list/robot_custom_icons - /hook/startup/proc/load_robot_custom_sprites() - var/config_file = file2text("config/custom_sprites.txt") - var/list/lines = text2list(config_file, "\n") - - robot_custom_icons = list() - for(var/line in lines) - //split entry into ckey and real_name - var/split_idx = findtext(line, "-") //this works if ckey cannot contain dashes, and findtext starts from the beginning - if(!split_idx || split_idx == length(line)) - continue //bad entry - - var/ckey = copytext(line, 1, split_idx) - var/real_name = copytext(line, split_idx+1) - - robot_custom_icons[ckey] = real_name + if(config.load_customsynths_from == "sql") + loadsynths_from_sql() + else if(config.load_customsynths_from == "json") + loadsynths_from_json() return 1 - /mob/living/silicon/robot/proc/set_custom_sprite() - var/rname = robot_custom_icons[ckey] - if(rname && rname == real_name) + var/datum/custom_synth/sprite = robot_custom_icons[name] + if(istype(sprite) && sprite.synthckey == ckey) custom_sprite = 1 icon = CUSTOM_ITEM_SYNTH var/list/valid_states = icon_states(icon) if(icon_state == "robot") - if("[ckey]-Standard" in valid_states) - icon_state = "[ckey]-Standard" + if("[sprite.synthicon]-Standard" in valid_states) + icon_state = "[sprite.synthicon]-Standard" else - to_chat(src, "Could not locate [ckey]-Standard sprite.") - icon = 'icons/mob/robots.dmi' + to_chat(src, "Could not locate [sprite.synthicon]-Standard sprite.") + icon = 'icons/mob/robots.dmi' \ No newline at end of file diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index b3bd95cba24..80b8bfa9fe9 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -267,15 +267,16 @@ //Custom_sprite check and entry if (custom_sprite == 1) + var/datum/custom_synth/sprite = robot_custom_icons[name] var/list/valid_states = icon_states(CUSTOM_ITEM_SYNTH) - if("[ckey]-[modtype]" in valid_states) - module_sprites["Custom"] = "[src.ckey]-[modtype]" + if("[sprite.synthicon]-[modtype]" in valid_states) + module_sprites["Custom"] = "[sprite.synthicon]-[modtype]" icon = CUSTOM_ITEM_SYNTH icontype = "Custom" else icontype = module_sprites[1] icon = 'icons/mob/robots.dmi' - to_chat(src, "Custom Sprite Sheet does not contain a valid icon_state for [ckey]-[modtype]") + to_chat(src, "Custom Sprite Sheet does not contain a valid icon_state for [sprite.synthicon]-[modtype]") else icontype = module_sprites[1] icon_state = module_sprites[icontype] diff --git a/config/example/customsynths.json b/config/example/customsynths.json new file mode 100644 index 00000000000..74869bf7715 --- /dev/null +++ b/config/example/customsynths.json @@ -0,0 +1,12 @@ +{ + "synths": { + "Synth name here": { + "ckey": "ckey", + "synthicon": "synth icon name", + "aiholoicon": "ai holo icon name", + "aichassisicon": "ai chassis icon name", + "paiicon": "pai icon name" + + } + } +} \ No newline at end of file diff --git a/html/changelogs/customsynths.yml b/html/changelogs/customsynths.yml new file mode 100644 index 00000000000..3c4b75fc414 --- /dev/null +++ b/html/changelogs/customsynths.yml @@ -0,0 +1,41 @@ +################################ +# Example Changelog File +# +# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb. +# +# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.) +# When it is, any changes listed below will disappear. +# +# Valid Prefixes: +# bugfix +# wip (For works in progress) +# tweak +# soundadd +# sounddel +# rscadd (general adding of nice things) +# rscdel (general deleting of nice things) +# imageadd +# imagedel +# maptweak +# spellcheck (typo fixes) +# experiment +# balance +# admin +# backend +# security +# refactor +################################# + +# Your name. +author: Lady Fowl + +# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again. +delete-after: True + +# Any changes you've made. See valid prefix list above. +# INDENT WITH TWO SPACES. NOT TABS. SPACES. +# SCREW THIS UP AND IT WON'T WORK. +# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries. +# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog. +changes: + - refactor: "Added support for multiple synthetic sprites, aswell as custom pai's and holograms." diff --git a/icons/mob/custom_synthetic.dmi b/icons/mob/custom_synthetic.dmi index fe4109e8081..38e9d020ac4 100644 Binary files a/icons/mob/custom_synthetic.dmi and b/icons/mob/custom_synthetic.dmi differ diff --git a/icons/mob/custom_synths/customhologram.dmi b/icons/mob/custom_synths/customhologram.dmi new file mode 100644 index 00000000000..c644196bb23 Binary files /dev/null and b/icons/mob/custom_synths/customhologram.dmi differ