+
+
+
+
+
+
{
+ MutationEncyclopediaSearchQuery =
+ SearchInput.value;
+
+ RenderMutationEncyclopedia();
+ }
+ );
+ }
+
+
+ if (SortSelect !== null) {
+ SortSelect.value =
+ MutationEncyclopediaSortMode;
+
+ SortSelect.addEventListener(
+ "change",
+ () => {
+ MutationEncyclopediaSortMode =
+ SortSelect.value;
+
+ RenderMutationEncyclopedia();
+ }
+ );
+ }
+}
+
+
function RenderMutationEncyclopedia() {
const List =
document.getElementById(
@@ -69,10 +117,37 @@ function RenderMutationEncyclopedia() {
)
: [];
+ const SearchQuery =
+ MutationEncyclopediaSearchQuery
+ .trim()
+ .toLocaleLowerCase();
+
+ const VisibleHints =
+ AvailableHints.filter(
+ Mutation =>
+ DoesMutationHintMatchSearch(
+ Mutation,
+ SearchQuery
+ )
+ );
+
+ const VisibleMutations =
+ DiscoveredMutations
+ .filter(
+ Mutation =>
+ DoesMutationEncyclopediaMatchSearch(
+ Mutation,
+ SearchQuery
+ )
+ )
+ .sort(
+ CompareMutationEncyclopediaMutations
+ );
+
for (
const Mutation
- of AvailableHints
+ of VisibleHints
) {
List.appendChild(
CreateMutationHintCard(
@@ -84,7 +159,7 @@ function RenderMutationEncyclopedia() {
for (
const Mutation
- of DiscoveredMutations
+ of VisibleMutations
) {
List.appendChild(
CreateMutationEncyclopediaCard(
@@ -106,24 +181,60 @@ function RenderMutationEncyclopedia() {
}
+ if (
+ VisibleMutations.length === 0 &&
+ VisibleHints.length === 0
+ ) {
+ SetMutationEncyclopediaMessage(
+ "No mutations or hints match your search."
+ );
+
+ return;
+ }
+
+
const MessageParts = [];
- MessageParts.push(
- DiscoveredMutations.length === 1
- ? "1 mutation discovered."
- : DiscoveredMutations.length
- .toLocaleString() +
- " mutations discovered."
- );
-
- if (AvailableHints.length > 0) {
+ if (SearchQuery.length > 0) {
MessageParts.push(
- AvailableHints.length === 1
- ? "1 hint available."
- : AvailableHints.length
- .toLocaleString() +
- " hints available."
+ "Showing " +
+ VisibleMutations.length
+ .toLocaleString() +
+ " of " +
+ DiscoveredMutations.length
+ .toLocaleString() +
+ " discovered mutations."
);
+
+ if (AvailableHints.length > 0) {
+ MessageParts.push(
+ "Showing " +
+ VisibleHints.length
+ .toLocaleString() +
+ " of " +
+ AvailableHints.length
+ .toLocaleString() +
+ " available hints."
+ );
+ }
+ } else {
+ MessageParts.push(
+ DiscoveredMutations.length === 1
+ ? "1 mutation discovered."
+ : DiscoveredMutations.length
+ .toLocaleString() +
+ " mutations discovered."
+ );
+
+ if (AvailableHints.length > 0) {
+ MessageParts.push(
+ AvailableHints.length === 1
+ ? "1 hint available."
+ : AvailableHints.length
+ .toLocaleString() +
+ " hints available."
+ );
+ }
}
SetMutationEncyclopediaMessage(
@@ -134,6 +245,183 @@ function RenderMutationEncyclopedia() {
}
+function DoesMutationHintMatchSearch(
+ Mutation,
+ SearchQuery
+) {
+ if (SearchQuery.length === 0) {
+ return true;
+ }
+
+ return String(
+ Mutation.Hint ?? ""
+ )
+ .toLocaleLowerCase()
+ .includes(
+ SearchQuery
+ );
+}
+
+
+function DoesMutationEncyclopediaMatchSearch(
+ Mutation,
+ SearchQuery
+) {
+ if (SearchQuery.length === 0) {
+ return true;
+ }
+
+ const SearchParts = [
+ Mutation.Id,
+ Mutation.Name,
+ Mutation.Description,
+ Mutation.Hint,
+ FormatMutationChance(
+ Mutation.Chance
+ ),
+ FormatMutationEncyclopediaTime(
+ Mutation.Cooldown
+ ),
+ Mutation.Rotation
+ ];
+
+ const RelationPlantIds = [
+ ...(Mutation.Relations
+ ?.PlantsUsed ?? []),
+ ...(Mutation.Relations
+ ?.PlantsCreated ?? [])
+ ];
+
+ for (
+ const PlantId
+ of RelationPlantIds
+ ) {
+ if (
+ !HasDiscoveredPlant(
+ MutationEncyclopediaSave,
+ PlantId
+ )
+ ) {
+ continue;
+ }
+
+ const Plant =
+ GetPlantById(
+ PlantId
+ );
+
+ if (Plant !== null) {
+ SearchParts.push(
+ Plant.Name
+ );
+ }
+ }
+
+ return SearchParts
+ .filter(
+ Value =>
+ Value !== null &&
+ Value !== undefined
+ )
+ .join(" ")
+ .toLocaleLowerCase()
+ .includes(
+ SearchQuery
+ );
+}
+
+
+function CompareMutationEncyclopediaMutations(
+ A,
+ B
+) {
+ switch (MutationEncyclopediaSortMode) {
+ case "NameAsc":
+ return String(A.Name ?? "")
+ .localeCompare(
+ String(B.Name ?? ""),
+ undefined,
+ {sensitivity: "base"}
+ ) || A.Id - B.Id;
+
+ case "ChanceAsc":
+ return CompareMutationEncyclopediaNumbers(
+ A.Chance,
+ B.Chance,
+ 1
+ ) || A.Id - B.Id;
+
+ case "ChanceDesc":
+ return CompareMutationEncyclopediaNumbers(
+ A.Chance,
+ B.Chance,
+ -1
+ ) || A.Id - B.Id;
+
+ case "CooldownAsc":
+ return CompareMutationEncyclopediaNumbers(
+ A.Cooldown,
+ B.Cooldown,
+ 1
+ ) || A.Id - B.Id;
+
+ case "CooldownDesc":
+ return CompareMutationEncyclopediaNumbers(
+ A.Cooldown,
+ B.Cooldown,
+ -1
+ ) || A.Id - B.Id;
+
+ case "IdAsc":
+ default:
+ return A.Id - B.Id;
+ }
+}
+
+
+function CompareMutationEncyclopediaNumbers(
+ A,
+ B,
+ Direction
+) {
+ const MissingA =
+ A === null ||
+ A === undefined ||
+ A === "";
+
+ const MissingB =
+ B === null ||
+ B === undefined ||
+ B === "";
+
+ const NumberA = Number(A);
+ const NumberB = Number(B);
+
+ const ValidA =
+ !MissingA &&
+ Number.isFinite(NumberA);
+
+ const ValidB =
+ !MissingB &&
+ Number.isFinite(NumberB);
+
+ if (!ValidA && !ValidB) {
+ return 0;
+ }
+
+ if (!ValidA) {
+ return 1;
+ }
+
+ if (!ValidB) {
+ return -1;
+ }
+
+ return (NumberA - NumberB) *
+ Direction;
+}
+
+
function HasUsableMutationHint(
Mutation
) {
diff --git a/Scripts/Garden/PlantEncyclopedia.js b/Scripts/Garden/PlantEncyclopedia.js
index abdb87f..0b2297b 100644
--- a/Scripts/Garden/PlantEncyclopedia.js
+++ b/Scripts/Garden/PlantEncyclopedia.js
@@ -1,4 +1,6 @@
let PlantEncyclopediaSave;
+let PlantEncyclopediaSearchQuery = "";
+let PlantEncyclopediaSortMode = "IdAsc";
async function StartPlantEncyclopedia() {
@@ -7,6 +9,7 @@ async function StartPlantEncyclopedia() {
PlantEncyclopediaSave =
await LoadGame();
+ BindPlantEncyclopediaControls();
RenderPlantEncyclopedia();
} catch (Error) {
console.error(
@@ -21,6 +24,51 @@ async function StartPlantEncyclopedia() {
}
+function BindPlantEncyclopediaControls() {
+ const SearchInput =
+ document.getElementById(
+ "PlantEncyclopediaSearchInput"
+ );
+
+ const SortSelect =
+ document.getElementById(
+ "PlantEncyclopediaSortSelect"
+ );
+
+
+ if (SearchInput !== null) {
+ SearchInput.value =
+ PlantEncyclopediaSearchQuery;
+
+ SearchInput.addEventListener(
+ "input",
+ () => {
+ PlantEncyclopediaSearchQuery =
+ SearchInput.value;
+
+ RenderPlantEncyclopedia();
+ }
+ );
+ }
+
+
+ if (SortSelect !== null) {
+ SortSelect.value =
+ PlantEncyclopediaSortMode;
+
+ SortSelect.addEventListener(
+ "change",
+ () => {
+ PlantEncyclopediaSortMode =
+ SortSelect.value;
+
+ RenderPlantEncyclopedia();
+ }
+ );
+ }
+}
+
+
function RenderPlantEncyclopedia() {
const List =
document.getElementById(
@@ -38,16 +86,28 @@ function RenderPlantEncyclopedia() {
PlantEncyclopediaSave,
Plant.Id
)
+ );
+
+ const SearchQuery =
+ PlantEncyclopediaSearchQuery
+ .trim()
+ .toLocaleLowerCase();
+
+ const VisiblePlants =
+ DiscoveredPlants
+ .filter(
+ Plant =>
+ DoesPlantEncyclopediaMatchSearch(
+ Plant,
+ SearchQuery
+ )
)
.sort(
- (A, B) =>
- A.Id - B.Id
+ ComparePlantEncyclopediaPlants
);
- if (
- DiscoveredPlants.length === 0
- ) {
+ if (DiscoveredPlants.length === 0) {
SetPlantEncyclopediaMessage(
"No plants discovered yet."
);
@@ -56,9 +116,18 @@ function RenderPlantEncyclopedia() {
}
+ if (VisiblePlants.length === 0) {
+ SetPlantEncyclopediaMessage(
+ "No discovered plants match your search."
+ );
+
+ return;
+ }
+
+
for (
const Plant
- of DiscoveredPlants
+ of VisiblePlants
) {
List.appendChild(
CreatePlantEncyclopediaCard(
@@ -68,6 +137,21 @@ function RenderPlantEncyclopedia() {
}
+ if (SearchQuery.length > 0) {
+ SetPlantEncyclopediaMessage(
+ "Showing " +
+ VisiblePlants.length
+ .toLocaleString() +
+ " of " +
+ DiscoveredPlants.length
+ .toLocaleString() +
+ " discovered plants."
+ );
+
+ return;
+ }
+
+
SetPlantEncyclopediaMessage(
DiscoveredPlants.length === 1
? "1 plant discovered."
@@ -78,6 +162,190 @@ function RenderPlantEncyclopedia() {
}
+function DoesPlantEncyclopediaMatchSearch(
+ Plant,
+ SearchQuery
+) {
+ if (SearchQuery.length === 0) {
+ return true;
+ }
+
+ const SearchParts = [
+ Plant.Id,
+ Plant.Name,
+ Plant.Description,
+ ...(Array.isArray(Plant.Tags)
+ ? Plant.Tags
+ : [])
+ ];
+
+ for (
+ const Mutation
+ of GetPlantRelatedMutations(
+ Plant.Id,
+ "PlantsCreated"
+ ).concat(
+ GetPlantRelatedMutations(
+ Plant.Id,
+ "PlantsUsed"
+ )
+ )
+ ) {
+ if (
+ HasDiscoveredMutation(
+ PlantEncyclopediaSave,
+ Mutation.Id
+ )
+ ) {
+ SearchParts.push(
+ Mutation.Name
+ );
+ }
+ }
+
+ return SearchParts
+ .filter(
+ Value =>
+ Value !== null &&
+ Value !== undefined
+ )
+ .join(" ")
+ .toLocaleLowerCase()
+ .includes(
+ SearchQuery
+ );
+}
+
+
+function ComparePlantEncyclopediaPlants(
+ A,
+ B
+) {
+ switch (PlantEncyclopediaSortMode) {
+ case "NameAsc":
+ return String(A.Name ?? "")
+ .localeCompare(
+ String(B.Name ?? ""),
+ undefined,
+ {sensitivity: "base"}
+ ) || A.Id - B.Id;
+
+ case "GrowthAsc":
+ return ComparePlantEncyclopediaNumbers(
+ A.GrowthTime,
+ B.GrowthTime,
+ 1
+ ) || A.Id - B.Id;
+
+ case "GrowthDesc":
+ return ComparePlantEncyclopediaNumbers(
+ A.GrowthTime,
+ B.GrowthTime,
+ -1
+ ) || A.Id - B.Id;
+
+ case "RewardAsc":
+ return ComparePlantEncyclopediaNumbers(
+ GetPlantHarvestReward(
+ PlantEncyclopediaSave,
+ A.Id
+ ),
+ GetPlantHarvestReward(
+ PlantEncyclopediaSave,
+ B.Id
+ ),
+ 1
+ ) || A.Id - B.Id;
+
+ case "RewardDesc":
+ return ComparePlantEncyclopediaNumbers(
+ GetPlantHarvestReward(
+ PlantEncyclopediaSave,
+ A.Id
+ ),
+ GetPlantHarvestReward(
+ PlantEncyclopediaSave,
+ B.Id
+ ),
+ -1
+ ) || A.Id - B.Id;
+
+ case "DphAsc":
+ return ComparePlantEncyclopediaNumbers(
+ GetPlantDewPerHour(
+ PlantEncyclopediaSave,
+ A.Id
+ ),
+ GetPlantDewPerHour(
+ PlantEncyclopediaSave,
+ B.Id
+ ),
+ 1
+ ) || A.Id - B.Id;
+
+ case "DphDesc":
+ return ComparePlantEncyclopediaNumbers(
+ GetPlantDewPerHour(
+ PlantEncyclopediaSave,
+ A.Id
+ ),
+ GetPlantDewPerHour(
+ PlantEncyclopediaSave,
+ B.Id
+ ),
+ -1
+ ) || A.Id - B.Id;
+
+ case "IdAsc":
+ default:
+ return A.Id - B.Id;
+ }
+}
+
+
+function ComparePlantEncyclopediaNumbers(
+ A,
+ B,
+ Direction
+) {
+ const MissingA =
+ A === null ||
+ A === undefined ||
+ A === "";
+
+ const MissingB =
+ B === null ||
+ B === undefined ||
+ B === "";
+
+ const NumberA = Number(A);
+ const NumberB = Number(B);
+
+ const ValidA =
+ !MissingA &&
+ Number.isFinite(NumberA);
+
+ const ValidB =
+ !MissingB &&
+ Number.isFinite(NumberB);
+
+ if (!ValidA && !ValidB) {
+ return 0;
+ }
+
+ if (!ValidA) {
+ return 1;
+ }
+
+ if (!ValidB) {
+ return -1;
+ }
+
+ return (NumberA - NumberB) *
+ Direction;
+}
+
+
function CreatePlantEncyclopediaCard(
Plant
) {
diff --git a/Scripts/Garden/Shop.js b/Scripts/Garden/Shop.js
index af7e673..eaa2baa 100644
--- a/Scripts/Garden/Shop.js
+++ b/Scripts/Garden/Shop.js
@@ -1,5 +1,7 @@
let ShopSave;
let ShopPurchasePending = false;
+let ShopSeedSearchQuery = "";
+let ShopSeedSortMode = "IdAsc";
async function StartShop() {
@@ -22,6 +24,7 @@ async function StartShop() {
ShopSave = await LoadGame();
BindShopSectionToggles();
+ BindShopSeedControls();
RenderShop();
}
@@ -84,6 +87,51 @@ function BindShopSectionToggle(
}
+function BindShopSeedControls() {
+ const SearchInput =
+ document.getElementById(
+ "ShopSeedSearchInput"
+ );
+
+ const SortSelect =
+ document.getElementById(
+ "ShopSeedSortSelect"
+ );
+
+
+ if (SearchInput !== null) {
+ SearchInput.value =
+ ShopSeedSearchQuery;
+
+ SearchInput.addEventListener(
+ "input",
+ () => {
+ ShopSeedSearchQuery =
+ SearchInput.value;
+
+ RenderShopSeeds();
+ }
+ );
+ }
+
+
+ if (SortSelect !== null) {
+ SortSelect.value =
+ ShopSeedSortMode;
+
+ SortSelect.addEventListener(
+ "change",
+ () => {
+ ShopSeedSortMode =
+ SortSelect.value;
+
+ RenderShopSeeds();
+ }
+ );
+ }
+}
+
+
function RenderShop() {
RenderShopCurrency();
RenderShopSeeds();
@@ -124,29 +172,41 @@ function RenderShopSeeds() {
ShopSave,
Plant
)
+ );
+
+ const SearchQuery =
+ ShopSeedSearchQuery
+ .trim()
+ .toLocaleLowerCase();
+
+ const VisiblePlants =
+ AvailablePlants
+ .filter(
+ Plant =>
+ DoesShopPlantMatchSearch(
+ Plant,
+ SearchQuery
+ )
)
.sort(
- (A, B) =>
- A.Id - B.Id
+ CompareShopPlants
);
- if (
- AvailablePlants.length === 0
- ) {
- const EmptyMessage =
- document.createElement(
- "p"
- );
+ if (AvailablePlants.length === 0) {
+ AppendShopSeedEmptyMessage(
+ SeedList,
+ "No seeds are available yet."
+ );
- EmptyMessage.className =
- "ShopEmpty";
+ return;
+ }
- EmptyMessage.textContent =
- "No seeds are available yet.";
- SeedList.appendChild(
- EmptyMessage
+ if (VisiblePlants.length === 0) {
+ AppendShopSeedEmptyMessage(
+ SeedList,
+ "No seeds match your search."
);
return;
@@ -155,7 +215,7 @@ function RenderShopSeeds() {
for (
const Plant
- of AvailablePlants
+ of VisiblePlants
) {
SeedList.appendChild(
CreateShopSeedCard(
@@ -166,6 +226,202 @@ function RenderShopSeeds() {
}
+function AppendShopSeedEmptyMessage(
+ SeedList,
+ Message
+) {
+ const EmptyMessage =
+ document.createElement(
+ "p"
+ );
+
+ EmptyMessage.className =
+ "ShopEmpty";
+
+ EmptyMessage.textContent =
+ Message;
+
+ SeedList.appendChild(
+ EmptyMessage
+ );
+}
+
+
+function DoesShopPlantMatchSearch(
+ Plant,
+ SearchQuery
+) {
+ if (SearchQuery.length === 0) {
+ return true;
+ }
+
+ const SearchParts = [
+ Plant.Id,
+ Plant.Name,
+ Plant.Description,
+ ...(Array.isArray(Plant.Tags)
+ ? Plant.Tags
+ : [])
+ ];
+
+ return SearchParts
+ .filter(
+ Value =>
+ Value !== null &&
+ Value !== undefined
+ )
+ .join(" ")
+ .toLocaleLowerCase()
+ .includes(
+ SearchQuery
+ );
+}
+
+
+function CompareShopPlants(
+ A,
+ B
+) {
+ switch (ShopSeedSortMode) {
+ case "NameAsc":
+ return CompareShopText(
+ A.Name,
+ B.Name
+ ) || A.Id - B.Id;
+
+ case "PriceAsc":
+ return CompareShopNumbers(
+ GetPlantShopCost(ShopSave, A.Id),
+ GetPlantShopCost(ShopSave, B.Id),
+ 1
+ ) || A.Id - B.Id;
+
+ case "PriceDesc":
+ return CompareShopNumbers(
+ GetPlantShopCost(ShopSave, A.Id),
+ GetPlantShopCost(ShopSave, B.Id),
+ -1
+ ) || A.Id - B.Id;
+
+ case "GrowthAsc":
+ return CompareShopNumbers(
+ A.GrowthTime,
+ B.GrowthTime,
+ 1
+ ) || A.Id - B.Id;
+
+ case "GrowthDesc":
+ return CompareShopNumbers(
+ A.GrowthTime,
+ B.GrowthTime,
+ -1
+ ) || A.Id - B.Id;
+
+ case "RewardAsc":
+ return CompareShopNumbers(
+ GetPlantHarvestReward(ShopSave, A.Id),
+ GetPlantHarvestReward(ShopSave, B.Id),
+ 1
+ ) || A.Id - B.Id;
+
+ case "RewardDesc":
+ return CompareShopNumbers(
+ GetPlantHarvestReward(ShopSave, A.Id),
+ GetPlantHarvestReward(ShopSave, B.Id),
+ -1
+ ) || A.Id - B.Id;
+
+ case "DphAsc":
+ return CompareShopNumbers(
+ GetPlantDewPerHour(ShopSave, A.Id),
+ GetPlantDewPerHour(ShopSave, B.Id),
+ 1
+ ) || A.Id - B.Id;
+
+ case "DphDesc":
+ return CompareShopNumbers(
+ GetPlantDewPerHour(ShopSave, A.Id),
+ GetPlantDewPerHour(ShopSave, B.Id),
+ -1
+ ) || A.Id - B.Id;
+
+ case "InventoryAsc":
+ return CompareShopNumbers(
+ GetSeedCount(ShopSave, A.Id),
+ GetSeedCount(ShopSave, B.Id),
+ 1
+ ) || A.Id - B.Id;
+
+ case "InventoryDesc":
+ return CompareShopNumbers(
+ GetSeedCount(ShopSave, A.Id),
+ GetSeedCount(ShopSave, B.Id),
+ -1
+ ) || A.Id - B.Id;
+
+ case "IdAsc":
+ default:
+ return A.Id - B.Id;
+ }
+}
+
+
+function CompareShopText(
+ A,
+ B
+) {
+ return String(A ?? "")
+ .localeCompare(
+ String(B ?? ""),
+ undefined,
+ {sensitivity: "base"}
+ );
+}
+
+
+function CompareShopNumbers(
+ A,
+ B,
+ Direction
+) {
+ const MissingA =
+ A === null ||
+ A === undefined ||
+ A === "";
+
+ const MissingB =
+ B === null ||
+ B === undefined ||
+ B === "";
+
+ const NumberA = Number(A);
+ const NumberB = Number(B);
+
+ const ValidA =
+ !MissingA &&
+ Number.isFinite(NumberA);
+
+ const ValidB =
+ !MissingB &&
+ Number.isFinite(NumberB);
+
+ if (!ValidA && !ValidB) {
+ return 0;
+ }
+
+ if (!ValidA) {
+ return 1;
+ }
+
+ if (!ValidB) {
+ return -1;
+ }
+
+ return (NumberA - NumberB) *
+ Direction;
+}
+
+
function RenderGardenUpgrades() {
const UpgradeList =
document.getElementById(
diff --git a/Styles/Style.css b/Styles/Style.css
index 4ed2f03..eff0b72 100644
--- a/Styles/Style.css
+++ b/Styles/Style.css
@@ -1210,6 +1210,50 @@ input, button, textarea, select {
display: none;
}
+
+.CatalogueControls {
+ display: grid;
+ grid-template-columns: minmax(0, 1fr) minmax(0, 14rem);
+ gap: 0.75rem;
+ margin: 0 0 1rem;
+ align-items: center;
+}
+
+.CatalogueControls input, .CatalogueControls select {
+ width: 100%;
+ min-width: 0;
+ padding: 0.65rem 0.75rem;
+ color: var(--Text);
+ background-color: var(--Mantle);
+ border: 3px solid var(--Surface2);
+ border-radius: 0;
+ font-size: 1rem;
+ box-shadow: 3px 3px 0 var(--Crust);
+}
+
+.CatalogueControls input::placeholder {
+ color: var(--Overlay1);
+}
+
+.CatalogueControls input:hover, .CatalogueControls select:hover {
+ border-color: var(--Sky);
+}
+
+.CatalogueControls input:focus, .CatalogueControls select:focus {
+ outline: 3px solid var(--Yellow);
+ outline-offset: 3px;
+}
+
+.CatalogueControls select {
+ cursor: pointer;
+}
+
+@media (max-width: 500px) {
+ .CatalogueControls {
+ grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
+ }
+}
+
.ShopSeedList {
display: grid;
grid-template-columns: repeat( auto-fit, minmax(15rem, 1fr) );
@@ -1450,7 +1494,7 @@ input, button, textarea, select {
display: flex;
flex-direction: column;
gap: 1rem;
- margin-top: 1.5rem;
+ margin-top: 0;
}
.PlantEncyclopediaCard {
@@ -1594,7 +1638,7 @@ input, button, textarea, select {
display: flex;
flex-direction: column;
gap: 1rem;
- margin-top: 1.5rem;
+ margin-top: 0;
}
.MutationEncyclopediaCard {