Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions frontend/app/components/wiki/recipeIconAlignment.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { describe, expect, it } from "vitest";
import { iconTranslation, recipeIconTransform } from "./recipeIconAlignment";
import RecipeItemIcon from "./RecipeItemIcon";
import CraftingGrid from "./CraftingGrid";
import { materialRecipes } from "../../wiki/data/materials";
import { magicPartRecipes } from "../../wiki/data/magic-parts";

describe("visible recipe sprite alignment", () => {
it("corrects the measured Steel Magical Core padding without changing its size", () => {
Expand Down Expand Up @@ -37,7 +37,7 @@ describe("visible recipe sprite alignment", () => {
});

it("applies visible-pixel centering to the actual Steel Magical Core recipe output", () => {
const recipe = materialRecipes.find((candidate) => candidate.output.name === "Steel Magical Core")!;
const recipe = magicPartRecipes.find((candidate) => candidate.output.name === "Steel Magical Core")!;
const html = renderToStaticMarkup(CraftingGrid({ recipe }));
expect(html).toMatch(/<img[^>]*alt="Steel Magical Core"[^>]*style="transform:translate\(-3\.125%, 3\.125%\)"/);
expect(html).toContain("grid grid-cols-3 gap-1");
Expand Down
96 changes: 69 additions & 27 deletions frontend/app/wiki/commands/page.tsx
Original file line number Diff line number Diff line change
@@ -1,39 +1,81 @@
import Link from "next/link";
import { DataTable, SeeAlso, WikiPage, WikiSectionHeading } from "@/app/components/wiki";
import { allCommandRows, getNavItemByHref } from "../data";
import { allCommandRows, getNavItemByHref, wikiCategories, type RegisteredCommand } from "../data";

export default function CommandIndexPage() {
const code = "font-mono text-[var(--tfmc-accent)]";
const body = "mt-3 text-sm text-[var(--tfmc-mist)]";

/** Player commands only, grouped under the guide category of the page that explains them. */
function commandGroups() {
const commands = allCommandRows.filter((entry) => (entry.row.access ?? "player") === "player");
return wikiCategories
.map((category) => ({
category,
commands: commands.filter((entry) => getNavItemByHref(entry.href)?.category === category.key),
}))
.filter((group) => group.commands.length > 0);
}

function CommandCell({ entry }: { entry: RegisteredCommand }) {
return (
<>
<code className={code}>{entry.row.command}</code>
{entry.row.aliases?.length ? (
<span className="mt-1 block text-xs text-[var(--tfmc-stone)]">Also: {entry.row.aliases.join(", ")}</span>
) : null}
</>
);
}

export default function CommandIndexPage() {
const groups = commandGroups();
return (
<WikiPage
lastModified="2026-09-12"
lastModified="2026-10-23"
title="Command Index"
width="lg"
intro="Player commands covered in this guide, A–Z."
intro="Every command a player can type, grouped by topic. Each one links to the guide page that explains it."
>
<WikiSectionHeading id="commands">Player commands</WikiSectionHeading>
<DataTable
className="mt-4"
minWidth="48rem"
rowKey={(_row, index) => `${commands[index].href}:${commands[index].row.command}`}
columns={[
{ header: "Command", width: "18rem" },
{ header: "Aliases", width: "10rem" },
{ header: "What it does" },
{ header: "Guide", width: "12rem" },
]}
rows={commands.map((entry) => [
<code key="command" className="font-mono text-[var(--tfmc-accent)]">
{entry.row.command}
</code>,
entry.row.aliases?.length ? entry.row.aliases.join(", ") : "None",
entry.row.description,
<Link key="guide" href={entry.href} className="underline decoration-dotted hover:text-[var(--tfmc-accent)]">
{getNavItemByHref(entry.href)?.label ?? entry.system}
</Link>,
])}
/>
<SeeAlso hrefs={["/wiki/getting-started", "/wiki/materials", "/wiki/stations"]} />
<WikiSectionHeading id="reading">Reading a command</WikiSectionHeading>
<p className={body}>
Type commands in chat, starting with <code className={code}>/</code>. A word in angle brackets, like{" "}
<code className={code}>&lt;player&gt;</code>, is something you fill in. A word in square brackets, like{" "}
<code className={code}>[page]</code>, is optional. A bar, as in <code className={code}>keep | discard</code>,
means you pick one. Press Tab while typing to see what the server accepts.
</p>
<p className={body}>
Many systems have no command at all: you use them by right-clicking a block or an item. Their guide pages
explain how.
</p>

{groups.map(({ category, commands }) => (
<section key={category.key}>
<WikiSectionHeading id={category.key}>{category.label}</WikiSectionHeading>
<DataTable
className="mt-4"
minWidth="40rem"
rowKey={(_row, index) => `${commands[index].href}:${commands[index].row.command}`}
columns={[
{ header: "Command", width: "40%" },
{ header: "What it does" },
{ header: "Guide", width: "11rem" },
]}
rows={commands.map((entry) => [
<CommandCell key="command" entry={entry} />,
entry.row.description,
<Link
key="guide"
href={entry.href}
className="underline decoration-dotted hover:text-[var(--tfmc-accent)]"
>
{getNavItemByHref(entry.href)?.label ?? entry.system}
</Link>,
])}
/>
</section>
))}

<SeeAlso hrefs={["/wiki/getting-started", "/wiki/stations", "/wiki/materials"]} />
</WikiPage>
);
}
2 changes: 1 addition & 1 deletion frontend/app/wiki/data/advanced-crafting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export const weaponStationRecipe: Recipe = {
{ name: "Oak Planks", qty: 1, texture: V("oak_planks.png") },
{ name: "Oak Planks", qty: 1, texture: V("oak_planks.png") },
],
output: { name: "Forging Station", qty: 1, sourceId: "itemsadder:weapon_station", model: weaponStationModel },
output: { name: "Forging Station", qty: 1, sourceId: "itemsadder:forging_station", model: weaponStationModel },
};

export const ingredientConverterRecipe: Recipe = {
Expand Down
18 changes: 5 additions & 13 deletions frontend/app/wiki/data/catalog.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { slugify } from "./helpers";
import { dropOnlyMaterials, materialRecipes, serverCraftedMaterials } from "./materials";
import { dropOnlyMaterials, serverCraftedMaterials } from "./materials";
import { allRecipes } from "./registry";
import { customItemIdentity } from "./item-identity";
import type { MaterialCatalogEntry, Recipe } from "./types";
Expand All @@ -13,24 +13,16 @@ export function getRecipesForStation(name: string): Recipe[] {
function buildMaterialCatalog(): Map<string, MaterialCatalogEntry> {
const map = new Map<string, MaterialCatalogEntry>();

for (const r of materialRecipes) {
map.set(r.output.name, {
slug: slugify(r.output.name),
name: r.output.name,
texture: r.output.texture,
recipe: r,
recipes: [],
unpackingRecipes: [],
usedIn: [],
});
}
for (const m of [...serverCraftedMaterials, ...dropOnlyMaterials]) {
// Gathered materials first, so each group reads from raw material to what is made from it.
for (const m of [...dropOnlyMaterials, ...serverCraftedMaterials]) {
if (!map.has(m.name)) {
map.set(m.name, {
slug: slugify(m.name),
name: m.name,
group: m.group,
texture: m.texture,
lore: m.lore,
usedFor: m.usedFor,
recipes: [],
acquisition: m.acquisition,
unpackingRecipes: allRecipes.filter((r) => m.unpackingRecipeKeys?.includes(r.key)),
Expand Down
2 changes: 1 addition & 1 deletion frontend/app/wiki/data/command-index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@ export const commandIndexSection: WikiSection = {
href: "/wiki/commands",
label: "Command Index",
category: "reference",
blurb: "Every command a player can type, A–Z, with the page that documents it.",
blurb: "Every command a player can type, grouped by topic, with the page that explains it.",
},
};
14 changes: 14 additions & 0 deletions frontend/app/wiki/data/generated/itemDescriptions.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,11 @@
"mmoitem:LOOT:GREATER_ARMOR_RUNESTONE": ["Research this Rune to unlock its Spell!"],
"mmoitem:LOOT:ASCENDANT_ARMOR_RUNESTONE": ["Research this Rune to unlock its Spell!"],
"mmoitem:LOOT:COMMON_ITEM_SKIN_SCROLL": ["Used to Reskin an item.", "Type /armourshop to use."],
"mmoitem:LOOT:SEALED_ARTIFACT": ["Contains a random Artifact.", "Right Click to break the seal!"],
"mmoitem:LOOT:SEALED_OSENI_ARTIFACT": ["Contains a random Oseni Artifact.", "Right Click to break the seal!"],
"mmoitem:LOOT:SEALED_SEITHR_ARTIFACT": ["Contains a random Seithr Artifact.", "Right Click to break the seal!"],
"mmoitem:LOOT:SEALED_CERRITH_ARTIFACT": ["Contains a random Cerrith Artifact.", "Right Click to break the seal!"],
"mmoitem:LOOT:SEALED_MITLAN_ARTIFACT": ["Contains a random Mitlan Artifact.", "Right Click to break the seal!"],
"mmoitem:MATERIALS:IGNITIUM": ["An uncommon crystal used as", "the catalyst in Coke production."],
"mmoitem:MATERIALS:COKE": ["A highly carbonic fuel primarily", "used in the production of Steel."],
"mmoitem:MATERIALS:RAW_TIN": ["A rare, malleable metal often used", "to produce alloys such as Bronze."],
Expand Down Expand Up @@ -130,6 +135,8 @@
"mmoitem:MUSIC:DISC11": ["Right Click to play without a Jukebox!"],
"mmoitem:MUSIC:DISC12": ["Right Click to play without a Jukebox!", "The TFMC: Season 5 Combat Theme"],
"mmoitem:MUSIC:DISC13": ["Right Click to play without a Jukebox!", "The TFMC: Season 5 Main Theme"],
"mmoitem:MUSIC:DISC14": ["Right Click to play without a Jukebox!"],
"mmoitem:MUSIC:DISC15": ["Right Click to play without a Jukebox!"],
"mmoitem:PETS:TAMING_ITEM": ["Used to tame an animal.", "Right Click an animal to tame it."],
"mmoitem:PETS:COOWNERSHIP_ITEM": [
"Shares the ownership of an animal.",
Expand Down Expand Up @@ -186,6 +193,13 @@
"mmoitem:PETS:PET_LAGOTTOROMAGNOLO_EGG": ["Right-click to hatch your companion.", "Choose its name in chat."],
"mmoitem:PETS:PET_YORKSHIRE_EGG": ["Right-click to hatch your companion.", "Choose its name in chat."],
"mmoitem:PETS:PET_BORDERCOLLIEGRAY_EGG": ["Right-click to hatch your companion.", "Choose its name in chat."],
"mmoitem:PETS:PET_CAVALIER_KING_CHARLES_SPANIEL_EGG": [
"Right-click to hatch your companion.",
"Choose its name in chat."
],
"mmoitem:PETS:PET_SPHYNX_EGG": ["Right-click to hatch your companion.", "Choose its name in chat."],
"mmoitem:PROPS:FOREARM_CRUTCH": ["Made for wide arms"],
"mmoitem:PROPS:FOREARM_CRUTCH_SLIM": ["Made for slim arms"],
"mmoitem:RESEARCH:SCRIBE_PAPER": [
"Used to create various Research",
"Papers in a Cartography Table.",
Expand Down
4 changes: 4 additions & 0 deletions frontend/app/wiki/data/generated/itemsadderItems.json
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,10 @@
"name": "Mixing Bowl",
"material": "PAPER"
},
"music_station": {
"name": "Music Station",
"material": "PAPER"
},
"mythril_block1": {
"name": "Block of Mythril",
"material": "PAPER",
Expand Down
67 changes: 67 additions & 0 deletions frontend/app/wiki/data/generated/mmoitemsItems.json
Original file line number Diff line number Diff line change
Expand Up @@ -578,6 +578,22 @@
"sourceModel": "tfmc_pack/resourcepack/assets/minecraft/models/item/music/disc_dearly_beloved.json",
"sourceTexture": "tfmc_pack/resourcepack/assets/minecraft/textures/item/music/disc_dearly_beloved.png"
},
"DISC14": {
"name": "Music Disc",
"material": "RECOVERY_COMPASS",
"customModelData": 8,
"texture": "mmoitems/disc14.png",
"sourceModel": "tfmc_pack/resourcepack/assets/minecraft/models/item/music/disc_kjope_hele_sverige.json",
"sourceTexture": "tfmc_pack/resourcepack/assets/minecraft/textures/item/music/disc_kjope_hele_sverige.png"
},
"DISC15": {
"name": "Music Disc",
"material": "RECOVERY_COMPASS",
"customModelData": 16,
"texture": "mmoitems/disc15.png",
"sourceModel": "tfmc_pack/resourcepack/assets/minecraft/models/item/music/disc_o_strings_my_strings.json",
"sourceTexture": "tfmc_pack/resourcepack/assets/minecraft/textures/item/music/disc_o_strings_my_strings.png"
},
"DISC2": {
"name": "Music Disc",
"material": "RECOVERY_COMPASS",
Expand Down Expand Up @@ -830,6 +846,22 @@
"sourceModel": "tfmc_pack/resourcepack/assets/minecraft/models/item/instruments/flute.json",
"sourceTexture": "tfmc_pack/resourcepack/assets/minecraft/textures/item/instruments/flute.png"
},
"FOREARM_CRUTCH": {
"name": "Forearm Crutch",
"material": "STICK",
"customModelData": 77,
"texture": "mmoitems/forearm_crutch.png",
"sourceModel": "tfmc_pack/resourcepack/assets/minecraft/models/item/props/forearm_crutch.json",
"sourceTexture": "tfmc_pack/resourcepack/assets/minecraft/textures/item/props/forearm_crutch.png"
},
"FOREARM_CRUTCH_SLIM": {
"name": "Slim Forearm Crutch",
"material": "STICK",
"customModelData": 78,
"texture": "mmoitems/forearm_crutch_slim.png",
"sourceModel": "tfmc_pack/resourcepack/assets/minecraft/models/item/props/forearm_crutch_slim.json",
"sourceTexture": "tfmc_pack/resourcepack/assets/minecraft/textures/item/props/forearm_crutch.png"
},
"FORGING_BRANDING_TOOL": {
"name": "Forging Branding Tool",
"material": "BREEZE_ROD",
Expand Down Expand Up @@ -1562,6 +1594,11 @@
"material": "CAT_SPAWN_EGG",
"customModelData": 12015
},
"PET_CAVALIER_KING_CHARLES_SPANIEL_EGG": {
"name": "Cavalier King Charles Spaniel Companion Egg",
"material": "WOLF_SPAWN_EGG",
"customModelData": 12019
},
"PET_CHEW_BONE": {
"name": "Bone Plush",
"material": "RABBIT_FOOT",
Expand Down Expand Up @@ -1626,6 +1663,11 @@
"sourceModel": "tfmc_pack/resourcepack/assets/tfmc/models/item/pets/pet_mouse_plush.json",
"sourceTexture": "tfmc_pack/resourcepack/assets/tfmc/textures/item/pets/pet_mouse_plush.png"
},
"PET_SPHYNX_EGG": {
"name": "Sphynx Cat Companion Egg",
"material": "CAT_SPAWN_EGG",
"customModelData": 12020
},
"PET_TEDDY_PLUSH": {
"name": "Teddy Bear Plush",
"material": "RABBIT_FOOT",
Expand Down Expand Up @@ -1903,6 +1945,31 @@
"sourceModel": "tfmc_pack/resourcepack/assets/minecraft/models/item/miscellaneous/parchment_paper.json",
"sourceTexture": "tfmc_pack/resourcepack/assets/minecraft/textures/item/miscellaneous/parchment_paper.png"
},
"SEALED_ARTIFACT": {
"name": "Sealed Artifact",
"material": "PAPER",
"customModelData": 10859
},
"SEALED_CERRITH_ARTIFACT": {
"name": "Sealed Cerrith Artifact",
"material": "PAPER",
"customModelData": 10790
},
"SEALED_MITLAN_ARTIFACT": {
"name": "Sealed Mitlan Artifact",
"material": "PAPER",
"customModelData": 10810
},
"SEALED_OSENI_ARTIFACT": {
"name": "Sealed Oseni Artifact",
"material": "PAPER",
"customModelData": 10817
},
"SEALED_SEITHR_ARTIFACT": {
"name": "Sealed Seithr Artifact",
"material": "PAPER",
"customModelData": 10838
},
"SEWING_NEEDLE": {
"name": "Sewing Needle",
"material": "BREEZE_ROD",
Expand Down
Loading
Loading