diff --git a/code/__DEFINES/prefs.dm b/code/__DEFINES/prefs.dm index 6725d511af1..d6497dc1716 100644 --- a/code/__DEFINES/prefs.dm +++ b/code/__DEFINES/prefs.dm @@ -15,6 +15,9 @@ /// Will show job suit if true, will hide if this is false or EQUIP_PREVIEW_JOB is false #define EQUIP_PREVIEW_JOB_SUIT BITFLAG(4) +/// Will show custom items if set, not set by default, to prevent overloading SQL requests +#define EQUIP_PREVIEW_CUSTOM_ITEMS BITFLAG(5) + /// The default EQUIP_PREVIEW bitflag, with this, all character creation items are shown #define EQUIP_PREVIEW_ALL (EQUIP_PREVIEW_LOADOUT|EQUIP_PREVIEW_JOB|EQUIP_PREVIEW_JOB_HAT|EQUIP_PREVIEW_JOB_UNIFORM|EQUIP_PREVIEW_JOB_SUIT) diff --git a/code/modules/client/preference_setup/general/03_body.dm b/code/modules/client/preference_setup/general/03_body.dm index 9792e24319d..3b909ff38a1 100644 --- a/code/modules/client/preference_setup/general/03_body.dm +++ b/code/modules/client/preference_setup/general/03_body.dm @@ -300,6 +300,7 @@ var/global/list/valid_bloodtypes = list( out += "
[pref.equip_preview_mob & EQUIP_PREVIEW_JOB_HAT ? "Hide job hat" : "Show job hat"]" out += "
[pref.equip_preview_mob & EQUIP_PREVIEW_JOB_UNIFORM ? "Hide job uniform" : "Show job uniform"]" out += "
[pref.equip_preview_mob & EQUIP_PREVIEW_JOB_SUIT ? "Hide job suit" : "Show job suit"]" + out += "
[pref.equip_preview_mob & EQUIP_PREVIEW_CUSTOM_ITEMS ? "Hide custom items" : "Show custom items"]" out += "" var/tail_spacing = FALSE diff --git a/code/modules/customitems/item_defines.dm b/code/modules/customitems/item_defines.dm index fab6fd39906..fec77804371 100644 --- a/code/modules/customitems/item_defines.dm +++ b/code/modules/customitems/item_defines.dm @@ -1971,3 +1971,23 @@ All custom items with worn sprites must follow the contained sprite system: http flag_path = "devorask_flag" flag_size = TRUE flag_item = /obj/item/flag/fluff/devorask_flag/l + +/obj/item/organ/external/arm/fluff/gracia_autakh // gracia's aut'akh left arm - Gracia Hiza - cometblaze + robotize_type = PROSTHETIC_AUTAKH + skin_color = FALSE + override_robotize_force_icon = 'icons/mob/human_races/fluff/gracia_arm.dmi' + override_robotize_painted = FALSE + robotize_children = FALSE + +/obj/item/organ/external/arm/fluff/gracia_autakh/Initialize(mapload) + . = ..() + // adding the hand to the child here means only the arm has to be added to the DB + // since the hand will be attached automatically + LAZYADD(children, new /obj/item/organ/external/hand/fluff/gracia_autakh(src)) + +/obj/item/organ/external/hand/fluff/gracia_autakh // gracia's aut'akh left hand - Gracia Hiza - cometblaze + robotize_type = PROSTHETIC_AUTAKH + skin_color = FALSE + override_robotize_force_icon = 'icons/mob/human_races/fluff/gracia_arm.dmi' + override_robotize_painted = FALSE + robotize_children = FALSE diff --git a/code/modules/customitems/item_spawning.dm b/code/modules/customitems/item_spawning.dm index 0488c76a7c4..3ff7978678b 100644 --- a/code/modules/customitems/item_spawning.dm +++ b/code/modules/customitems/item_spawning.dm @@ -213,68 +213,108 @@ return item -//gets the relevant list for the key from the listlist if it exists, check to make sure they are meant to have it and then calls the giving function -/proc/equip_custom_items(var/mob/living/carbon/human/M) +GLOBAL_LIST_EMPTY(character_id_to_custom_items_mapping) + +/// Gets the relevant custom items for the given target_mob, character_id, and player_ckey, and equips the target_mob with those custom items +/proc/equip_custom_items(var/mob/living/carbon/human/target_mob, var/character_id, var/player_ckey) + if(!character_id) + character_id = target_mob.character_id + + if(!player_ckey) + player_ckey = target_mob.ckey + + var/glob_character_id_key = "[player_ckey]-[character_id]" + //Fetch the custom items for the mob if(GLOB.config.sql_enabled) if(!establish_db_connection(GLOB.dbcon)) log_module_customitems("Unable to establish database connection while loading item. - Aborting") return - var/DBQuery/char_item_query = GLOB.dbcon.NewQuery("SELECT ss13_characters_custom_items.id, ss13_characters_custom_items.char_id, ss13_characters.ckey as usr_ckey, ss13_characters.name as usr_charname, item_path, item_data, req_titles, additional_data FROM ss13_characters_custom_items LEFT JOIN ss13_characters ON ss13_characters.id = ss13_characters_custom_items.char_id WHERE char_id = :char_id:") - char_item_query.Execute(list("char_id"=M.character_id)) - while(char_item_query.NextRow()) - CHECK_TICK - var/datum/custom_item/ci = new() - ci.id = text2num(char_item_query.item[1]) - ci.character_id = text2num(char_item_query.item[2]) - ci.usr_ckey = char_item_query.item[3] - ci.usr_charname = char_item_query.item[4] - ci.item_path = text2path(char_item_query.item[5]) - ci.item_data = json_decode(char_item_query.item[6]) //TODO: try/catch - ci.req_titles = json_decode(char_item_query.item[7]) //TODO: try/catch - ci.additional_data = char_item_query.item[8] + if(!GLOB.character_id_to_custom_items_mapping[glob_character_id_key]) + var/list/custom_items_list = list() - equip_custom_item_to_mob(ci,M) + var/DBQuery/char_item_query = GLOB.dbcon.NewQuery("SELECT ss13_characters_custom_items.id, ss13_characters_custom_items.char_id, ss13_characters.ckey as usr_ckey, ss13_characters.name as usr_charname, item_path, item_data, req_titles, additional_data FROM ss13_characters_custom_items LEFT JOIN ss13_characters ON ss13_characters.id = ss13_characters_custom_items.char_id WHERE char_id = :char_id:") + char_item_query.Execute(list("char_id"=character_id)) + while(char_item_query.NextRow()) + CHECK_TICK + var/datum/custom_item/ci = new() + ci.id = text2num(char_item_query.item[1]) + ci.character_id = text2num(char_item_query.item[2]) + ci.usr_ckey = char_item_query.item[3] + ci.usr_charname = char_item_query.item[4] + ci.item_path = text2path(char_item_query.item[5]) + ci.item_data = json_decode(char_item_query.item[6]) //TODO: try/catch + ci.req_titles = json_decode(char_item_query.item[7]) //TODO: try/catch + ci.additional_data = char_item_query.item[8] + + custom_items_list += ci + + GLOB.character_id_to_custom_items_mapping[glob_character_id_key] = custom_items_list else - for(var/item in custom_items) - CHECK_TICK - var/datum/custom_item/ci = item - if(lowertext(ci.usr_ckey) != lowertext(M.ckey)) - continue - if(lowertext(ci.usr_charname) != lowertext(M.real_name)) - continue - equip_custom_item_to_mob(ci,M) + if(!GLOB.character_id_to_custom_items_mapping[glob_character_id_key]) + var/list/custom_items_list = list() + + for(var/item in custom_items) + CHECK_TICK + var/datum/custom_item/ci = item + if(lowertext(ci.usr_ckey) != lowertext(player_ckey)) + continue + if(lowertext(ci.usr_charname) != lowertext(target_mob.real_name)) + continue + custom_items_list += ci + + GLOB.character_id_to_custom_items_mapping[glob_character_id_key] = custom_items_list + + for(var/datum/custom_item/ci as anything in GLOB.character_id_to_custom_items_mapping[glob_character_id_key]) + equip_custom_item_to_mob(ci, target_mob) -/proc/equip_custom_item_to_mob(var/datum/custom_item/citem, var/mob/living/carbon/human/M) +/proc/equip_custom_item_to_mob(var/datum/custom_item/citem, var/mob/living/carbon/human/target_mob) // Check for required job title. if(length(citem.req_titles)) var/has_title - var/current_title = M.mind.role_alt_title ? M.mind.role_alt_title : M.mind.assigned_role + var/current_title = target_mob.mind.role_alt_title ? target_mob.mind.role_alt_title : target_mob.mind.assigned_role for(var/title in citem.req_titles) if(title == current_title) has_title = 1 break if(!has_title) - to_chat(M, "A custom item could not be equipped as you have joined with the wrong role.") + to_chat(target_mob, "A custom item could not be equipped as you have joined with the wrong role.") return FALSE if(ispath(citem.item_path, /obj/item/organ/internal/augment/fluff)) - var/obj/item/organ/internal/augment/fluff/aug = citem.spawn_item(M) - var/obj/item/organ/external/affected = M.get_organ(aug.parent_organ) - aug.replaced(M, affected) - M.update_body() - M.updatehealth() - M.UpdateDamageIcon() + var/obj/item/organ/internal/augment/fluff/aug = citem.spawn_item(target_mob) + var/obj/item/organ/external/affected = target_mob.get_organ(aug.parent_organ) + aug.replaced(target_mob, affected) + target_mob.update_body() + target_mob.updatehealth() + target_mob.UpdateDamageIcon() + return + + if(ispath(citem.item_path, /obj/item/organ/external)) + var/obj/item/organ/external/dummy_limb = citem.item_path + var/obj/item/organ/external/parent_organ = target_mob.get_organ(initial(dummy_limb.parent_organ)) + if(parent_organ) + var/obj/item/organ/external/existing_limb = target_mob.get_organ(initial(dummy_limb.limb_name)) + if(existing_limb) + existing_limb.droplimb(TRUE) + qdel(existing_limb) + + var/obj/item/organ/external/custom_limb = citem.spawn_item(target_mob) + custom_limb.replaced(target_mob, parent_organ) + + target_mob.update_body() + target_mob.updatehealth() + target_mob.UpdateDamageIcon() return // ID cards and MCs are applied directly to the existing object rather than spawned fresh. var/obj/item/existing_item if(citem.item_path == /obj/item/card/id) - existing_item = locate(/obj/item/card/id) in M.get_contents() //TODO: Improve this ? + existing_item = locate(/obj/item/card/id) in target_mob.get_contents() //TODO: Improve this ? else if(citem.item_path == /obj/item/modular_computer) - existing_item = locate(/obj/item/modular_computer) in M.contents + existing_item = locate(/obj/item/modular_computer) in target_mob.contents // Spawn and equip the item. if(existing_item) @@ -283,12 +323,12 @@ else var/obj/item/newitem = citem.spawn_item() - if(M.equip_to_appropriate_slot(newitem)) + if(target_mob.equip_to_appropriate_slot(newitem)) return TRUE - if(M.equip_to_storage(newitem)) + if(target_mob.equip_to_storage(newitem)) return TRUE - newitem.forceMove(get_turf(M.loc)) - to_chat(M, "A custom item has been placed on the floor as there was no space for it on your mob.") + newitem.forceMove(get_turf(target_mob.loc)) + to_chat(target_mob, "A custom item has been placed on the floor as there was no space for it on your mob.") return TRUE diff --git a/code/modules/mob/abstract/new_player/preferences_setup.dm b/code/modules/mob/abstract/new_player/preferences_setup.dm index 5dab3c7d195..94bd19d83cb 100644 --- a/code/modules/mob/abstract/new_player/preferences_setup.dm +++ b/code/modules/mob/abstract/new_player/preferences_setup.dm @@ -217,7 +217,10 @@ var/list/leftovers = list() var/list/used_slots = list() - if((equip_preview_mob & EQUIP_PREVIEW_LOADOUT)) + if(equip_preview_mob & EQUIP_PREVIEW_CUSTOM_ITEMS) + equip_custom_items(mannequin, current_character, client.ckey) + + if(equip_preview_mob & EQUIP_PREVIEW_LOADOUT) SSjobs.EquipCustom(mannequin, previewJob, src, leftovers, null, used_slots) if((equip_preview_mob & EQUIP_PREVIEW_JOB) && previewJob) diff --git a/code/modules/organs/organ_external.dm b/code/modules/organs/organ_external.dm index 761ef90e9fd..b58339be8b6 100644 --- a/code/modules/organs/organ_external.dm +++ b/code/modules/organs/organ_external.dm @@ -68,6 +68,15 @@ var/gendered_icon = 0 var/force_icon + /// If set, will use this as the robotized force icon instead of the robotype + var/override_robotize_force_icon + + /// If set, will use tihs as the painted value instead of the robotype + var/override_robotize_painted + + /// Will robotize the children of this limb if set to true + var/robotize_children = TRUE + var/limb_name var/disfigured = 0 @@ -328,9 +337,12 @@ /obj/item/organ/external/replaced(var/mob/living/carbon/human/target) ..() + if(istype(owner)) owner.organs_by_name[limb_name] = src owner.organs |= src + if(!species) + species = owner.species for(var/obj/item/organ/organ in src) organ.replaced(owner,src) @@ -1217,8 +1229,8 @@ Note that amputating the affected organ does in fact remove the infection from t var/datum/robolimb/R = GLOB.all_robolimbs[company] if(R) - if(!force_skintone) - force_icon = R.icon + if(!force_skintone || override_robotize_force_icon) + force_icon = override_robotize_force_icon ? override_robotize_force_icon : R.icon if(R.lifelike) status |= ORGAN_LIFELIKE if(force_prosthetic_name) @@ -1231,8 +1243,8 @@ Note that amputating the affected organ does in fact remove the infection from t else name = "[R.company] [initial(name)]" desc = "[R.desc]" - if(R.paintable) - painted = 1 + if(R.paintable || !isnull(override_robotize_painted)) + painted = !isnull(override_robotize_painted) ? override_robotize_painted : TRUE brute_mod = R.brute_mod burn_mod = R.burn_mod robotize_type = company @@ -1242,8 +1254,8 @@ Note that amputating the affected organ does in fact remove the infection from t limb_flags &= ~ORGAN_CAN_BREAK get_icon() unmutate() - for (var/obj/item/organ/external/T in children) - if(T) + if(robotize_children) + for (var/obj/item/organ/external/T in children) T.robotize(company) /obj/item/organ/external/mechassist() diff --git a/code/modules/organs/organ_icon.dm b/code/modules/organs/organ_icon.dm index 73d1a909528..7c36614aeb9 100644 --- a/code/modules/organs/organ_icon.dm +++ b/code/modules/organs/organ_icon.dm @@ -18,7 +18,7 @@ var/limb_exception = FALSE if(robotize_type) var/datum/robolimb/R = GLOB.all_robolimbs[robotize_type] - if(R?.paintable) + if(R?.paintable && (isnull(override_robotize_painted) || override_robotize_painted)) limb_exception = TRUE if((status & ORGAN_ROBOT) && !limb_exception) return diff --git a/html/changelogs/geeves-custom_item_limb_framework.yml b/html/changelogs/geeves-custom_item_limb_framework.yml new file mode 100644 index 00000000000..f149b29704d --- /dev/null +++ b/html/changelogs/geeves-custom_item_limb_framework.yml @@ -0,0 +1,6 @@ +author: Geeves + +delete-after: True + +changes: + - rscadd: "You can now view your custom items from within the loadout." diff --git a/icons/mob/human_races/fluff/gracia_arm.dmi b/icons/mob/human_races/fluff/gracia_arm.dmi new file mode 100644 index 00000000000..b7880d36b4a Binary files /dev/null and b/icons/mob/human_races/fluff/gracia_arm.dmi differ