diff --git a/src/handbook/data/README.md b/src/handbook/data/README.md index cb7adf9eb..c39e19b8d 100644 --- a/src/handbook/data/README.md +++ b/src/handbook/data/README.md @@ -2,10 +2,12 @@ Use Grasscutter's dumpers to generate the data to put here. ## Files Required +- `mainquests.csv' - `commands.json` - `entities.csv` - `avatars.csv` - `scenes.csv` +- `quests.csv` - `items.csv` # Item Icon Notes diff --git a/src/handbook/src/backend/data.ts b/src/handbook/src/backend/data.ts index 678646440..f8a1fc699 100644 --- a/src/handbook/src/backend/data.ts +++ b/src/handbook/src/backend/data.ts @@ -1,17 +1,21 @@ +import mainQuests from "@data/mainquests.csv"; import commands from "@data/commands.json"; import entities from "@data/entities.csv"; import avatars from "@data/avatars.csv"; import scenes from "@data/scenes.csv"; +import quests from "@data/quests.csv"; import items from "@data/items.csv"; import { Quality, ItemType, ItemCategory, SceneType } from "@backend/types"; -import type { Command, Avatar, Item, Scene, Entity } from "@backend/types"; +import type { MainQuest, Command, Avatar, Item, Scene, Entity, Quest } from "@backend/types"; import { inRange } from "@app/utils"; type AvatarDump = { [key: number]: Avatar }; type CommandDump = { [key: string]: Command }; type TaggedItems = { [key: number]: Item[] }; +type QuestDump = { [key: number]: Quest }; +type MainQuestDump = { [key: number]: MainQuest }; /** * @see {@file src/handbook/data/README.md} @@ -27,6 +31,8 @@ export const sortedItems: TaggedItems = { [ItemCategory.Miscellaneous]: [] }; +export let allMainQuests: MainQuestDump = {}; + /** * Setup function for this file. * Sorts all items into their respective categories. @@ -57,6 +63,8 @@ export function setup(): void { sortedItems[ItemCategory.Avatar].push(item); } }); + + allMainQuests = getMainQuests(); } /** @@ -148,3 +156,56 @@ export function getItems(): Item[] { }; }); } + +/** + * Fetches and casts all quests in the file. + */ +export function getQuests(): QuestDump { + const map: QuestDump = {}; + quests.forEach((quest: Quest) => { + quest.description = quest.description + .replaceAll("\\", ","); + map[quest.id] = quest; + }); + + return map; +} + +/** + * Fetches and lists all the quests in the file. + */ +export function listQuests(): Quest[] { + return Object.values(getQuests()) + .sort((a, b) => a.id - b.id); +} + +/** + * Fetches and casts all quests in the file. + */ +export function getMainQuests(): MainQuestDump { + const map: MainQuestDump = {}; + mainQuests.forEach((quest: MainQuest) => { + quest.title = quest.title + .replaceAll("\\", ","); + map[quest.id] = quest; + }); + + return map; +} + +/** + * Fetches and lists all the quests in the file. + */ +export function listMainQuests(): MainQuestDump[] { + return Object.values(allMainQuests) + .sort((a, b) => a.id - b.id); +} + +/** + * Fetches a quest by its ID. + * + * @param quest The quest ID. + */ +export function getMainQuestFor(quest: Quest): MainQuest { + return allMainQuests[quest.mainId]; +} diff --git a/src/handbook/src/backend/types.ts b/src/handbook/src/backend/types.ts index 0fc6f8e6b..7214b2805 100644 --- a/src/handbook/src/backend/types.ts +++ b/src/handbook/src/backend/types.ts @@ -2,6 +2,11 @@ export type Page = "Home" | "Commands" | "Avatars" | "Items" | "Entities" | "Sce export type Overlays = "None" | "ServerSettings"; export type Days = "Sunday" | "Monday" | "Tuesday" | "Wednesday" | "Thursday" | "Friday" | "Saturday"; +export type MainQuest = { + id: number; + title: string; +}; + export type Command = { name: string[]; description: string; @@ -36,6 +41,12 @@ export type Entity = { internal: string; }; +export type Quest = { + id: number; + description: string; + mainId: number; +}; + // Exported from Project Amber. export type ItemInfo = { response: number | 200 | 404; diff --git a/src/handbook/src/css/views/PlainText.scss b/src/handbook/src/css/views/PlainText.scss index bb0fef0bf..29b4336a1 100644 --- a/src/handbook/src/css/views/PlainText.scss +++ b/src/handbook/src/css/views/PlainText.scss @@ -4,6 +4,6 @@ overflow-x: scroll; p { - color: black; + color: white; } } diff --git a/src/handbook/src/ui/views/PlainText.tsx b/src/handbook/src/ui/views/PlainText.tsx index b5a1d3a9e..1e34b05c8 100644 --- a/src/handbook/src/ui/views/PlainText.tsx +++ b/src/handbook/src/ui/views/PlainText.tsx @@ -1,6 +1,14 @@ import React from "react"; -import { listCommands, listAvatars, getItems, getEntities, getScenes } from "@backend/data"; +import { + listCommands, + listAvatars, + getItems, + getEntities, + getScenes, + listQuests, + getMainQuestFor +} from "@backend/data"; import "@css/views/PlainText.scss"; @@ -13,7 +21,7 @@ class PlainText extends React.PureComponent { return ( <> {listCommands().map((command) => ( -
{`${command.name[0]} : ${command.description}`}
+{`${command.name[0]} : ${command.description}`}
))} > ); @@ -29,7 +37,7 @@ class PlainText extends React.PureComponent { {listAvatars() .sort((a, b) => a.id - b.id) .map((avatar) => ( -{`${avatar.id} : ${avatar.name}`}
+{`${avatar.id} : ${avatar.name}`}
))} > ); @@ -45,7 +53,7 @@ class PlainText extends React.PureComponent { {getItems() .sort((a, b) => a.id - b.id) .map((item) => ( -{`${item.id} : ${item.name}`}
+{`${item.id} : ${item.name}`}
))} > ); @@ -61,7 +69,7 @@ class PlainText extends React.PureComponent { {getEntities() .sort((a, b) => a.id - b.id) .map((entity) => ( -{`${entity.id} : ${entity.name}`}
+{`${entity.id} : ${entity.name}`}
))} > ); @@ -77,7 +85,23 @@ class PlainText extends React.PureComponent { {getScenes() .sort((a, b) => a.id - b.id) .map((scene) => ( -{`${scene.id} : ${scene.identifier} [${scene.type}]`}
+{`${scene.id} : ${scene.identifier} [${scene.type}]`}
+ ))} + > + ); + } + + /** + * Creates a paragraph of quests. + * @private + */ + private getQuests(): React.ReactNode { + return ( + <> + {listQuests() + .sort((a, b) => a.id - b.id) + .map((quest) => ( +{`${quest.id} : ${getMainQuestFor(quest)?.title ?? "Unknown"} - ${quest.description}`}
))} > ); @@ -129,6 +153,14 @@ class PlainText extends React.PureComponent { {this.getScenes()} + +
+
+
+ // Quests
+