From edbebf3256fa203bbd76acd4647178f2ead22814 Mon Sep 17 00:00:00 2001 From: Maximal08 <73069825+Maximal08@users.noreply.github.com> Date: Sun, 11 Jan 2026 23:17:56 +0500 Subject: [PATCH] New Changeling UI (#94697) ## About The Pull Request Updates the UI for Changeling, adding a categorization of abilities, changes the old Pheromone Receptors ability sprite, adds a sprite for Defibrillator Grasp. --- .../changeling/cellular_emporium.dm | 21 +- .../changeling/changeling_power.dm | 2 + .../changeling/powers/adrenaline.dm | 1 + .../changeling/powers/augmented_eyesight.dm | 1 + .../changeling/powers/biodegrade.dm | 1 + .../changeling/powers/chameleon_skin.dm | 1 + .../changeling/powers/darkness_adaptation.dm | 1 + .../changeling/powers/defib_grasp.dm | 2 + .../changeling/powers/digitalcamo.dm | 3 +- .../changeling/powers/fleshmend.dm | 1 + .../antagonists/changeling/powers/headcrab.dm | 1 + .../changeling/powers/lesserform.dm | 1 + .../changeling/powers/mimic_voice.dm | 1 + .../antagonists/changeling/powers/mmi_talk.dm | 1 + .../changeling/powers/mutations.dm | 7 +- .../antagonists/changeling/powers/panacea.dm | 3 +- .../changeling/powers/pheromone_receptors.dm | 4 +- .../antagonists/changeling/powers/shriek.dm | 4 +- .../antagonists/changeling/powers/spiders.dm | 1 + .../changeling/powers/strained_muscles.dm | 1 + .../changeling/powers/tiny_prick.dm | 13 +- .../changeling/powers/void_adaption.dm | 2 + icons/mob/actions/actions_changeling.dmi | Bin 22581 -> 10647 bytes .../tgui/interfaces/CellularEmporium.tsx | 431 +++++++++++++----- 24 files changed, 367 insertions(+), 137 deletions(-) diff --git a/code/modules/antagonists/changeling/cellular_emporium.dm b/code/modules/antagonists/changeling/cellular_emporium.dm index 4641f859bee..1a661c86cae 100644 --- a/code/modules/antagonists/changeling/cellular_emporium.dm +++ b/code/modules/antagonists/changeling/cellular_emporium.dm @@ -35,24 +35,23 @@ if(isnull(abilities)) abilities = list() for(var/datum/action/changeling/ability_path as anything in changeling.all_powers) - var/dna_cost = initial(ability_path.dna_cost) - if(dna_cost < 0) // 0 = free, but negatives are invalid continue - var/list/ability_data = list() - ability_data["name"] = initial(ability_path.name) - ability_data["desc"] = initial(ability_path.desc) - ability_data["path"] = ability_path - ability_data["helptext"] = initial(ability_path.helptext) - ability_data["genetic_point_required"] = dna_cost - ability_data["absorbs_required"] = initial(ability_path.req_absorbs) // compares against changeling true_absorbs - ability_data["dna_required"] = initial(ability_path.req_dna) // compares against changeling absorbed_count + var/list/ability_data = list( + "name" = initial(ability_path.name), + "desc" = initial(ability_path.desc), + "helptext" = initial(ability_path.helptext), + "path" = ability_path, + "genetic_point_required" = dna_cost, + "absorbs_required" = initial(ability_path.req_absorbs), + "dna_required" = initial(ability_path.req_dna), + "category" = initial(ability_path.category), + ) abilities += list(ability_data) - // Sorts abilities alphabetically by default sortTim(abilities, /proc/cmp_assoc_list_name) data["abilities"] = abilities diff --git a/code/modules/antagonists/changeling/changeling_power.dm b/code/modules/antagonists/changeling/changeling_power.dm index 82b0120a7b6..d14d87b0f40 100644 --- a/code/modules/antagonists/changeling/changeling_power.dm +++ b/code/modules/antagonists/changeling/changeling_power.dm @@ -35,6 +35,8 @@ var/active = FALSE /// Does this ability stop working if you are burning? var/disabled_by_fire = TRUE + ///Defines the ability category: 'stings', 'combat', 'stealth', 'utility' + var/category = "utility" /* changeling code now relies on on_purchase to grant powers. diff --git a/code/modules/antagonists/changeling/powers/adrenaline.dm b/code/modules/antagonists/changeling/powers/adrenaline.dm index 04f59962c01..a88195849d9 100644 --- a/code/modules/antagonists/changeling/powers/adrenaline.dm +++ b/code/modules/antagonists/changeling/powers/adrenaline.dm @@ -3,6 +3,7 @@ desc = "We concentrate our chemicals into a potent stimulant, rendering our form stupendously robust against being incapacitated. Costs 25 chemicals." helptext = "Disregard any condition that has stunned us and suffuse our form with FOUR units of Changeling Adrenaline; our form recovers massive stamina and simply disregards any pain or fatigue during its effects." button_icon_state = "adrenaline" + category = "combat" chemical_cost = 25 // similar cost to biodegrade, as they serve similar purposes dna_cost = 2 req_human = FALSE diff --git a/code/modules/antagonists/changeling/powers/augmented_eyesight.dm b/code/modules/antagonists/changeling/powers/augmented_eyesight.dm index 52a5d371cf0..35895bc5507 100644 --- a/code/modules/antagonists/changeling/powers/augmented_eyesight.dm +++ b/code/modules/antagonists/changeling/powers/augmented_eyesight.dm @@ -8,6 +8,7 @@ helptext = "Grants us x-ray vision or flash protection. \ We will become a lot more vulnerable to flash-based devices while x-ray vision is active." button_icon_state = "augmented_eyesight" + category = "utility" chemical_cost = 0 dna_cost = 2 // Active = Flash weakness and x-ray diff --git a/code/modules/antagonists/changeling/powers/biodegrade.dm b/code/modules/antagonists/changeling/powers/biodegrade.dm index 101bd935844..4b78356d9bc 100644 --- a/code/modules/antagonists/changeling/powers/biodegrade.dm +++ b/code/modules/antagonists/changeling/powers/biodegrade.dm @@ -3,6 +3,7 @@ desc = "Dissolves restraints or other objects preventing free movement. Costs 30 chemicals." helptext = "This is obvious to nearby people, and can destroy standard restraints and closets. Works against grabs." button_icon_state = "biodegrade" + category = "utility" chemical_cost = 30 dna_cost = 2 req_human = TRUE diff --git a/code/modules/antagonists/changeling/powers/chameleon_skin.dm b/code/modules/antagonists/changeling/powers/chameleon_skin.dm index e02437926a8..44d5f7e1e74 100644 --- a/code/modules/antagonists/changeling/powers/chameleon_skin.dm +++ b/code/modules/antagonists/changeling/powers/chameleon_skin.dm @@ -3,6 +3,7 @@ desc = "Our skin pigmentation rapidly changes to suit our current environment. Costs 10 chemicals." helptext = "Allows us to become invisible after a few seconds of standing still. Can be toggled on and off." button_icon_state = "chameleon_skin" + category = "stealth" dna_cost = 1 chemical_cost = 10 req_human = TRUE diff --git a/code/modules/antagonists/changeling/powers/darkness_adaptation.dm b/code/modules/antagonists/changeling/powers/darkness_adaptation.dm index 4d8e8a7e474..7f7126ff30a 100644 --- a/code/modules/antagonists/changeling/powers/darkness_adaptation.dm +++ b/code/modules/antagonists/changeling/powers/darkness_adaptation.dm @@ -5,6 +5,7 @@ helptext = "Allows us to darken and change the translucency of our pigmentation, and adapt our eyes to see in dark conditions, \ The translucent effect works best in dark enviroments and garments. Can be toggled on and off." button_icon_state = "darkness_adaptation" + category = "stealth" dna_cost = 2 chemical_cost = 15 /// How much we slow chemical regeneration while active, in chems per second diff --git a/code/modules/antagonists/changeling/powers/defib_grasp.dm b/code/modules/antagonists/changeling/powers/defib_grasp.dm index 227b11c3a38..38c14efdfe7 100644 --- a/code/modules/antagonists/changeling/powers/defib_grasp.dm +++ b/code/modules/antagonists/changeling/powers/defib_grasp.dm @@ -4,6 +4,8 @@ we will snatch their arms off and instantly finalize our stasis." helptext = "This ability is passive, and will trigger when a defibrillator paddle is applied to our chest \ while we are dead or in stasis. Will also stun cyborgs momentarily." + button_icon_state = "defibrillator_grasp" + category = "utility" owner_has_control = FALSE dna_cost = 0 disabled_by_fire = FALSE diff --git a/code/modules/antagonists/changeling/powers/digitalcamo.dm b/code/modules/antagonists/changeling/powers/digitalcamo.dm index 44c91d0b0e8..1becc9fedc9 100644 --- a/code/modules/antagonists/changeling/powers/digitalcamo.dm +++ b/code/modules/antagonists/changeling/powers/digitalcamo.dm @@ -2,7 +2,8 @@ name = "Digital Camouflage" desc = "By evolving the ability to distort our form and proportions, we defeat common algorithms used to detect lifeforms on cameras." helptext = "We cannot be tracked by camera or seen by AI units while using this skill. However, humans looking at us will find us... uncanny." - button_icon_state = "digital_camo" + button_icon_state = "digital_camouflage" + category = "stealth" dna_cost = 1 active = FALSE diff --git a/code/modules/antagonists/changeling/powers/fleshmend.dm b/code/modules/antagonists/changeling/powers/fleshmend.dm index 0f1b5d8f2f1..13e88b782e9 100644 --- a/code/modules/antagonists/changeling/powers/fleshmend.dm +++ b/code/modules/antagonists/changeling/powers/fleshmend.dm @@ -3,6 +3,7 @@ desc = "Our flesh rapidly regenerates, healing our burns, bruises, and shortness of breath, as well as hiding all of our scars. Costs 20 chemicals." helptext = "If we are on fire, the healing effect will not function. Does not regrow limbs or restore lost blood. Functions while unconscious." button_icon_state = "fleshmend" + category = "combat" chemical_cost = 20 dna_cost = 2 req_stat = HARD_CRIT diff --git a/code/modules/antagonists/changeling/powers/headcrab.dm b/code/modules/antagonists/changeling/powers/headcrab.dm index 0988b9c6b15..a0f9040ea1c 100644 --- a/code/modules/antagonists/changeling/powers/headcrab.dm +++ b/code/modules/antagonists/changeling/powers/headcrab.dm @@ -6,6 +6,7 @@ desc = "We sacrifice our current body in a moment of need, violently expanding to break through obstacles and reforming as a headslug. Costs 20 chemicals." helptext = "We will violently expand, destroying obstacles around us, then be placed in control of a small, fragile creature. We may attack a corpse like this to plant an egg which will slowly mature into a new form for us." button_icon_state = "last_resort" + category = "utility" chemical_cost = 20 dna_cost = 1 req_stat = DEAD diff --git a/code/modules/antagonists/changeling/powers/lesserform.dm b/code/modules/antagonists/changeling/powers/lesserform.dm index 55238ce762d..0667317c1e7 100644 --- a/code/modules/antagonists/changeling/powers/lesserform.dm +++ b/code/modules/antagonists/changeling/powers/lesserform.dm @@ -3,6 +3,7 @@ desc = "We debase ourselves and become lesser. We become a monkey. Costs 5 chemicals." helptext = "The transformation greatly reduces our size, allowing us to slip out of cuffs and climb through vents." button_icon_state = "lesser_form" + category = "stealth" chemical_cost = 5 dna_cost = 1 /// Whether to allow the transformation animation to play diff --git a/code/modules/antagonists/changeling/powers/mimic_voice.dm b/code/modules/antagonists/changeling/powers/mimic_voice.dm index e1d895d2b14..de2ac649991 100644 --- a/code/modules/antagonists/changeling/powers/mimic_voice.dm +++ b/code/modules/antagonists/changeling/powers/mimic_voice.dm @@ -3,6 +3,7 @@ desc = "We shape our vocal glands to sound like a desired voice. Maintaining this power slows chemical production." button_icon_state = "mimic_voice" helptext = "Will turn our voice into the name that we enter. We must constantly expend chemicals to maintain our form like this." + category = "stealth" chemical_cost = 0//constant chemical drain hardcoded dna_cost = 1 req_human = TRUE diff --git a/code/modules/antagonists/changeling/powers/mmi_talk.dm b/code/modules/antagonists/changeling/powers/mmi_talk.dm index 47c748f6f18..c70896c9797 100644 --- a/code/modules/antagonists/changeling/powers/mmi_talk.dm +++ b/code/modules/antagonists/changeling/powers/mmi_talk.dm @@ -4,6 +4,7 @@ In order to maintain our secrecy, we can speak through the decoy as if a normal brain. \ The decoy brain will relay speech it hears to us in purple." button_icon = 'icons/obj/devices/assemblies.dmi' + category = "stealth" button_icon_state = "mmi_off" dna_cost = CHANGELING_POWER_UNOBTAINABLE ignores_fakedeath = TRUE // Can be used while fake dead diff --git a/code/modules/antagonists/changeling/powers/mutations.dm b/code/modules/antagonists/changeling/powers/mutations.dm index 762b6b4c90d..5747a2b6fa0 100644 --- a/code/modules/antagonists/changeling/powers/mutations.dm +++ b/code/modules/antagonists/changeling/powers/mutations.dm @@ -177,7 +177,8 @@ name = "Arm Blade" desc = "We reform one of our arms into a deadly blade. Costs 20 chemicals." helptext = "We may retract our armblade in the same manner as we form it. Cannot be used while in lesser form." - button_icon_state = "armblade" + button_icon_state = "arm_blade" + category = "combat" chemical_cost = 20 dna_cost = 2 req_human = TRUE @@ -273,6 +274,7 @@ In our combat stance, we will put the victim in our hold after catching them, and we will pull them in and impale them if we're also holding a sharp weapon, or have an armblade. This pierces armor. \ Cannot be used while in lesser form." button_icon_state = "tentacle" + category = "combat" chemical_cost = 10 dna_cost = 2 req_human = TRUE @@ -489,6 +491,7 @@ desc = "We reform one of our arms into a hard shield. Costs 20 chemicals." helptext = "Organic tissue cannot resist damage forever; the shield will break after it is hit too much. The more genomes we absorb, the stronger it is. Cannot be used while in lesser form." button_icon_state = "organic_shield" + category = "combat" chemical_cost = 20 dna_cost = 1 req_human = TRUE @@ -546,6 +549,7 @@ desc = "We turn our skin into tough chitin to protect us from damage. Costs 20 chemicals." helptext = "Upkeep of the armor requires a low expenditure of chemicals. The armor provides decent protection against brute force and energy weapons. Cannot be used in lesser form." button_icon_state = "chitinous_armor" + category = "combat" chemical_cost = 20 dna_cost = 1 req_human = TRUE @@ -612,6 +616,7 @@ desc = "We coat our head in a waxy outing coating similar to a bee hive which can be used to manufacture bees to attack our enemies. Costs 15 chemicals." helptext = "While the hive head does not provide much in the ways of armor, it does allow the user to send bees out to attack targets. Reagents can poured inside the hive to cause all bees released to inject said reagents." button_icon_state = "hive_head" + category = "combat" chemical_cost = 15 dna_cost = 2 req_human = FALSE diff --git a/code/modules/antagonists/changeling/powers/panacea.dm b/code/modules/antagonists/changeling/powers/panacea.dm index 079b859faf9..420773e1e27 100644 --- a/code/modules/antagonists/changeling/powers/panacea.dm +++ b/code/modules/antagonists/changeling/powers/panacea.dm @@ -2,7 +2,8 @@ name = "Anatomic Panacea" desc = "Expels impurities from our form: curing diseases, removing parasites, sobering us, purging toxins and radiation, curing traumas and brain damage, and resetting our genetic code completely. Costs 20 chemicals." helptext = "Can be used while unconscious." - button_icon_state = "panacea" + button_icon_state = "anatomic_panacea" + category = "utility" chemical_cost = 20 dna_cost = 1 req_stat = HARD_CRIT diff --git a/code/modules/antagonists/changeling/powers/pheromone_receptors.dm b/code/modules/antagonists/changeling/powers/pheromone_receptors.dm index 7b9eee1bfe9..3bd624972de 100644 --- a/code/modules/antagonists/changeling/powers/pheromone_receptors.dm +++ b/code/modules/antagonists/changeling/powers/pheromone_receptors.dm @@ -7,8 +7,8 @@ name = "Pheromone Receptors" desc = "We attune our senses to track other changelings by scent. The closer they are, the easier we can find them." helptext = "We will know the general direction of nearby changelings, with closer scents being stronger. Our chemical generation is slowed while this is active." - button_icon = 'icons/mob/actions/actions_spells.dmi' - button_icon_state = "nose" + button_icon_state = "pheromone_receptors" + category = "utility" chemical_cost = 0 //Reduces regain rate while active. dna_cost = 2 var/receptors_active = FALSE diff --git a/code/modules/antagonists/changeling/powers/shriek.dm b/code/modules/antagonists/changeling/powers/shriek.dm index 6956a7d9dcf..6b726fe7e42 100644 --- a/code/modules/antagonists/changeling/powers/shriek.dm +++ b/code/modules/antagonists/changeling/powers/shriek.dm @@ -4,6 +4,7 @@ Best used to stop prey from escaping. Doesn't work well in a vacuum. Costs 20 chemicals." helptext = "Emits a high-frequency sound that confuses and deafens humans to hamper their movement, blows out nearby lights and overloads cyborg sensors." button_icon_state = "resonant_shriek" + category = "combat" chemical_cost = 20 dna_cost = 1 req_human = TRUE @@ -34,7 +35,8 @@ /datum/action/changeling/dissonant_shriek name = "Technophagic Shriek" desc = "We shift our vocal cords to release a high-frequency sound that overloads nearby electronics. Breaks headsets and cameras, and can sometimes break laser weaponry, doors, and modsuits. Costs 20 chemicals." - button_icon_state = "dissonant_shriek" + button_icon_state = "technophagic_shriek" + category = "combat" chemical_cost = 20 dna_cost = 1 disabled_by_fire = FALSE diff --git a/code/modules/antagonists/changeling/powers/spiders.dm b/code/modules/antagonists/changeling/powers/spiders.dm index e184815945b..9b368187f6c 100644 --- a/code/modules/antagonists/changeling/powers/spiders.dm +++ b/code/modules/antagonists/changeling/powers/spiders.dm @@ -3,6 +3,7 @@ desc = "Our form divides, creating a cluster of eggs which will grow into a deadly arachnid. Costs 45 chemicals." helptext = "The spiders are ruthless creatures, and may attack their creators when fully grown. Requires at least 3 DNA absorptions." button_icon_state = "spread_infestation" + category = "utility" chemical_cost = 45 dna_cost = 1 req_absorbs = 3 diff --git a/code/modules/antagonists/changeling/powers/strained_muscles.dm b/code/modules/antagonists/changeling/powers/strained_muscles.dm index 2c3686f3fe6..7972c2473b7 100644 --- a/code/modules/antagonists/changeling/powers/strained_muscles.dm +++ b/code/modules/antagonists/changeling/powers/strained_muscles.dm @@ -6,6 +6,7 @@ desc = "We evolve the ability to reduce the acid buildup in our muscles, allowing us to move much faster." helptext = "The strain will make us tired, and we will rapidly become fatigued. Standard weight restrictions, like space suits, still apply. Cannot be used in lesser form." button_icon_state = "strained_muscles" + category = "utility" chemical_cost = 0 dna_cost = 1 req_human = TRUE diff --git a/code/modules/antagonists/changeling/powers/tiny_prick.dm b/code/modules/antagonists/changeling/powers/tiny_prick.dm index f6bc841e11c..91d7f8ba059 100644 --- a/code/modules/antagonists/changeling/powers/tiny_prick.dm +++ b/code/modules/antagonists/changeling/powers/tiny_prick.dm @@ -1,6 +1,7 @@ /datum/action/changeling/sting//parent path, not meant for users afaik name = "Tiny Prick" desc = "Stabby stabby" + category = "stings" /datum/action/changeling/sting/Trigger(mob/clicker, trigger_flags) var/mob/user = owner @@ -143,7 +144,7 @@ name = "False Armblade Sting" desc = "We silently sting a human, injecting a retrovirus that mutates their arm to temporarily appear as an armblade. Costs 20 chemicals." helptext = "The victim will form an armblade much like a changeling would, except the armblade is dull and useless." - button_icon_state = "sting_armblade" + button_icon_state = "false_armblade_sting" chemical_cost = 20 dna_cost = 1 @@ -194,7 +195,7 @@ name = "Extract DNA Sting" desc = "We stealthily sting a target and extract their DNA. Costs 25 chemicals." helptext = "Will give us the DNA of our target, allowing us to transform into them. This will render us unable to absorb their body fully later." - button_icon_state = "sting_extract" + button_icon_state = "extract_dna_sting" chemical_cost = 25 dna_cost = 0 @@ -215,7 +216,7 @@ name = "Mute Sting" desc = "We silently sting a human, completely silencing them for a short time. Costs 20 chemicals." helptext = "Does not provide a warning to the victim that they have been stung, until they try to speak and cannot." - button_icon_state = "sting_mute" + button_icon_state = "mute_sting" chemical_cost = 20 dna_cost = 2 @@ -229,7 +230,7 @@ name = "Blind Sting" desc = "We temporarily blind our victim. Costs 25 chemicals." helptext = "This sting completely blinds a target for a short time, and leaves them with blurred vision for a long time. Does not work if target has robotic or missing eyes." - button_icon_state = "sting_blind" + button_icon_state = "blind_sting" chemical_cost = 25 dna_cost = 1 @@ -256,7 +257,7 @@ desc = "We cause mass terror to our victim. Costs 10 chemicals." helptext = "We evolve the ability to sting a target with a powerful hallucinogenic chemical. \ The target does not notice they have been stung, and the effect occurs after 30 to 60 seconds." - button_icon_state = "sting_lsd" + button_icon_state = "hallucination_sting" chemical_cost = 10 dna_cost = 1 @@ -275,7 +276,7 @@ name = "Cryogenic Sting" desc = "We silently sting our victim with a cocktail of chemicals that freezes them from the inside. Costs 15 chemicals." helptext = "Does not provide a warning to the victim, though they will likely realize they are suddenly freezing." - button_icon_state = "sting_cryo" + button_icon_state = "cryogenic_sting" chemical_cost = 15 dna_cost = 2 diff --git a/code/modules/antagonists/changeling/powers/void_adaption.dm b/code/modules/antagonists/changeling/powers/void_adaption.dm index f066b24b5da..c1be125ebb4 100644 --- a/code/modules/antagonists/changeling/powers/void_adaption.dm +++ b/code/modules/antagonists/changeling/powers/void_adaption.dm @@ -4,6 +4,8 @@ helptext = "This ability is passive, and will automatically protect us in situations of extreme cold or vacuum, \ as well as removing our need to breathe oxygen, although we will still be affected by hazardous gases. \ While it is actively protecting us from temperature or pressure it reduces our chemical regeneration rate." + category = "utility" + button_icon_state = "void_adaption" owner_has_control = FALSE dna_cost = 2 diff --git a/icons/mob/actions/actions_changeling.dmi b/icons/mob/actions/actions_changeling.dmi index 73aac72deb57db5bede18850402271416b1112ee..506f91fc5ccc9b4fbee7295fbaea76712bca9ba5 100644 GIT binary patch literal 10647 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

n#zU}}Y!cD~0nY&^+7_HJr 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 literal 22581 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 a=q!ECi(WG6#s{Ln5JNpP-BN8A(tiMS6{v*( diff --git a/tgui/packages/tgui/interfaces/CellularEmporium.tsx b/tgui/packages/tgui/interfaces/CellularEmporium.tsx index afd453c1bd0..03bef8b4f48 100644 --- a/tgui/packages/tgui/interfaces/CellularEmporium.tsx +++ b/tgui/packages/tgui/interfaces/CellularEmporium.tsx @@ -2,59 +2,116 @@ import { useState } from 'react'; import { Box, Button, + DmIcon, Icon, Input, - LabeledList, NoticeBox, Section, Stack, + Tabs, + Tooltip, } from 'tgui-core/components'; +import type { BooleanLike } from 'tgui-core/react'; import { useBackend } from '../backend'; import { Window } from '../layouts'; -type typePath = string; - -type CellularEmporiumContext = { - abilities: Ability[]; - can_readapt: number; - genetic_points_count: number; - owned_abilities: typePath[]; - absorb_count: number; - dna_count: number; -}; +// ========== +// Types +// ========== +type TypePath = string; type Ability = { name: string; desc: string; helptext: string; - path: typePath; - genetic_point_required: number; // Checks against genetic_points_count - absorbs_required: number; // Checks against absorb_count - dna_required: number; // Checks against dna_count + path: TypePath; + genetic_point_required: number; + absorbs_required: number; + dna_required: number; + category: string; }; +type CellularEmporiumContext = { + abilities: Ability[]; + can_readapt: number; + genetic_points_count: number; + owned_abilities: TypePath[]; + absorb_count: number; + dna_count: number; +}; + +// ========== +// Helper: convert ability name to icon_state +// Example: "Augmented Eyesight" → "augmented_eyesight" +// ========== +const nameToIconState = (name: string): string => { + return name.toLowerCase().replace(/\s+/g, '_'); +}; + +// ========== +// Main Component +// ========== export const CellularEmporium = (props) => { const { act, data } = useBackend(); - const [searchAbilities, setSearchAbilities] = useState(''); + const { + abilities, + can_readapt, + genetic_points_count, + owned_abilities, + absorb_count, + dna_count, + } = data; - const { can_readapt, genetic_points_count } = data; - const readaptTracker = (can_readapt: number): string => { - const firstPart = 'Readapt('; - return firstPart.concat(can_readapt.toString(), ')'); + const [searchText, setSearchText] = useState(''); + const [compactMode, setCompactMode] = useState(false); + + const CATEGORY_ORDER = ['combat', 'stealth', 'utility', 'stings']; + const allCategories = Array.from(new Set(abilities.map((a) => a.category))); + const sortedCategories = [ + ...CATEGORY_ORDER.filter((cat) => allCategories.includes(cat)), + ...allCategories.filter((cat) => !CATEGORY_ORDER.includes(cat)), + ]; + const [selectedCategory, setSelectedCategory] = useState( + sortedCategories[0] || 'utility', + ); + + const filteredItems = ( + searchText + ? abilities.filter((item) => + [item.name, item.desc, item.helptext] + .join(' ') + .toLowerCase() + .includes(searchText.toLowerCase()), + ) + : abilities.filter((item) => item.category === selectedCategory) + ).sort((a, b) => a.name.localeCompare(b.name)); + + const handleBuy = (ability: Ability) => { + act('evolve', { path: ability.path }); }; + return ( - - + +

    - - {genetic_points_count} + scrollable={false} + title={ + + + {genetic_points_count} DNA + - - - } > - + + + + + + + +
    ); }; -const AbilityList = (props: { searchAbilities: string }) => { - const { act, data } = useBackend(); - const { searchAbilities } = props; +// ========== +// ItemList Component +// ========== +type ItemListProps = { + compactMode: BooleanLike; + items: Ability[]; + owned_abilities: TypePath[]; + genetic_points_count: number; + absorb_count: number; + dna_count: number; + handleBuy: (item: Ability) => void; +}; + +const ItemList = (props: ItemListProps) => { const { - abilities, + compactMode, + items, owned_abilities, genetic_points_count, absorb_count, dna_count, - } = data; + handleBuy, + } = props; - const filteredAbilities = - searchAbilities.length <= 1 - ? abilities - : abilities.filter((ability) => { - return ( - ability.name - .toLowerCase() - .includes(searchAbilities.toLowerCase()) || - ability.desc - .toLowerCase() - .includes(searchAbilities.toLowerCase()) || - ability.helptext - .toLowerCase() - .includes(searchAbilities.toLowerCase()) - ); - }); - - if (filteredAbilities.length === 0) { - return ( - - {abilities.length === 0 - ? 'No abilities available to purchase. \ - This is in error, contact your local hivemind today.' - : 'No abilities found.'} - - ); - } + const iconSize = compactMode ? '32px' : '64px'; return ( - - {filteredAbilities.map((ability) => ( - - {ability.genetic_point_required} - - - - - + + + + ) : ( +
    + {ability.name} + {owned && ( + + (Owned) + + )} + + } + buttons={ + + + + + + } + > + {ability.desc} + {ability.helptext && ( + + {ability.helptext} + + )} +
    + )} + + + + + ); + })} + + ); };