feat: add GFF type schema definitions for visual editors
This commit is contained in:
@@ -0,0 +1,106 @@
|
|||||||
|
import { GffFieldType, type GffTypeSchema } from "./schema.js";
|
||||||
|
|
||||||
|
export const schema: GffTypeSchema = {
|
||||||
|
fileType: "are",
|
||||||
|
displayName: "Area",
|
||||||
|
categories: ["Identity", "Dimensions", "Lighting"],
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
label: "Tag",
|
||||||
|
displayName: "Tag",
|
||||||
|
type: GffFieldType.CExoString,
|
||||||
|
category: "Identity",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "ResRef",
|
||||||
|
displayName: "ResRef",
|
||||||
|
type: GffFieldType.ResRef,
|
||||||
|
category: "Identity",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Name",
|
||||||
|
displayName: "Name",
|
||||||
|
type: GffFieldType.CExoLocString,
|
||||||
|
category: "Identity",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Flags",
|
||||||
|
displayName: "Area Flags",
|
||||||
|
type: GffFieldType.Dword,
|
||||||
|
category: "Identity",
|
||||||
|
description: "Bitmask: bit 0 = Interior, bit 1 = Underground, bit 2 = Natural",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Width",
|
||||||
|
displayName: "Width",
|
||||||
|
type: GffFieldType.Int,
|
||||||
|
category: "Dimensions",
|
||||||
|
description: "Area width in tiles",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Height",
|
||||||
|
displayName: "Height",
|
||||||
|
type: GffFieldType.Int,
|
||||||
|
category: "Dimensions",
|
||||||
|
description: "Area height in tiles",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Tileset",
|
||||||
|
displayName: "Tileset",
|
||||||
|
type: GffFieldType.ResRef,
|
||||||
|
category: "Dimensions",
|
||||||
|
description: "Tileset resref from tilesets.2da",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "SunAmbientColor",
|
||||||
|
displayName: "Sun Ambient Color",
|
||||||
|
type: GffFieldType.Dword,
|
||||||
|
category: "Lighting",
|
||||||
|
description: "Ambient light color during daytime (BGR integer)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "SunDiffuseColor",
|
||||||
|
displayName: "Sun Diffuse Color",
|
||||||
|
type: GffFieldType.Dword,
|
||||||
|
category: "Lighting",
|
||||||
|
description: "Directional light color during daytime (BGR integer)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "SunFogColor",
|
||||||
|
displayName: "Sun Fog Color",
|
||||||
|
type: GffFieldType.Dword,
|
||||||
|
category: "Lighting",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "MoonAmbientColor",
|
||||||
|
displayName: "Moon Ambient Color",
|
||||||
|
type: GffFieldType.Dword,
|
||||||
|
category: "Lighting",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "MoonDiffuseColor",
|
||||||
|
displayName: "Moon Diffuse Color",
|
||||||
|
type: GffFieldType.Dword,
|
||||||
|
category: "Lighting",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "MoonFogColor",
|
||||||
|
displayName: "Moon Fog Color",
|
||||||
|
type: GffFieldType.Dword,
|
||||||
|
category: "Lighting",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "IsNight",
|
||||||
|
displayName: "Is Night",
|
||||||
|
type: GffFieldType.Byte,
|
||||||
|
category: "Lighting",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "SkyBox",
|
||||||
|
displayName: "Sky Box",
|
||||||
|
type: GffFieldType.Byte,
|
||||||
|
category: "Lighting",
|
||||||
|
description: "Skybox index from skyboxes.2da",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
@@ -0,0 +1,138 @@
|
|||||||
|
import { GffFieldType, type GffTypeSchema } from "./schema.js";
|
||||||
|
|
||||||
|
export const schema: GffTypeSchema = {
|
||||||
|
fileType: "dlg",
|
||||||
|
displayName: "Dialog",
|
||||||
|
categories: ["Properties", "Entries", "Replies"],
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
label: "DelayEntry",
|
||||||
|
displayName: "Entry Delay",
|
||||||
|
type: GffFieldType.Dword,
|
||||||
|
category: "Properties",
|
||||||
|
description: "Delay in milliseconds before NPC lines appear",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "DelayReply",
|
||||||
|
displayName: "Reply Delay",
|
||||||
|
type: GffFieldType.Dword,
|
||||||
|
category: "Properties",
|
||||||
|
description: "Delay in milliseconds before PC reply options appear",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "PreventZoomIn",
|
||||||
|
displayName: "Prevent Zoom In",
|
||||||
|
type: GffFieldType.Byte,
|
||||||
|
category: "Properties",
|
||||||
|
description: "Disables camera zoom during conversation",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "NumWords",
|
||||||
|
displayName: "Word Count",
|
||||||
|
type: GffFieldType.Dword,
|
||||||
|
category: "Properties",
|
||||||
|
editable: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "EndConverAbort",
|
||||||
|
displayName: "On Abort Script",
|
||||||
|
type: GffFieldType.ResRef,
|
||||||
|
category: "Properties",
|
||||||
|
description: "Script fired when the player aborts the conversation",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "EndConversation",
|
||||||
|
displayName: "On End Script",
|
||||||
|
type: GffFieldType.ResRef,
|
||||||
|
category: "Properties",
|
||||||
|
description: "Script fired when the conversation ends normally",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "EntryList",
|
||||||
|
displayName: "NPC Entries",
|
||||||
|
type: GffFieldType.List,
|
||||||
|
category: "Entries",
|
||||||
|
description: "Lines spoken by NPCs",
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
label: "Text",
|
||||||
|
displayName: "Text",
|
||||||
|
type: GffFieldType.CExoLocString,
|
||||||
|
description: "The dialog text displayed to the player",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Speaker",
|
||||||
|
displayName: "Speaker",
|
||||||
|
type: GffFieldType.CExoString,
|
||||||
|
description: "Tag of the speaking creature (empty = conversation owner)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Animation",
|
||||||
|
displayName: "Animation",
|
||||||
|
type: GffFieldType.Dword,
|
||||||
|
description: "Animation to play while speaking",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Sound",
|
||||||
|
displayName: "Sound",
|
||||||
|
type: GffFieldType.ResRef,
|
||||||
|
description: "Sound file to play with this line",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Script",
|
||||||
|
displayName: "Action Script",
|
||||||
|
type: GffFieldType.ResRef,
|
||||||
|
description: "Script fired when this entry is displayed",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Active",
|
||||||
|
displayName: "Condition Script",
|
||||||
|
type: GffFieldType.ResRef,
|
||||||
|
description: "Script that must return TRUE for this entry to appear",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "ReplyList",
|
||||||
|
displayName: "PC Replies",
|
||||||
|
type: GffFieldType.List,
|
||||||
|
category: "Replies",
|
||||||
|
description: "Response options available to the player",
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
label: "Text",
|
||||||
|
displayName: "Text",
|
||||||
|
type: GffFieldType.CExoLocString,
|
||||||
|
description: "The reply text shown as a dialog option",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Speaker",
|
||||||
|
displayName: "Speaker",
|
||||||
|
type: GffFieldType.CExoString,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Animation",
|
||||||
|
displayName: "Animation",
|
||||||
|
type: GffFieldType.Dword,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Sound",
|
||||||
|
displayName: "Sound",
|
||||||
|
type: GffFieldType.ResRef,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Script",
|
||||||
|
displayName: "Action Script",
|
||||||
|
type: GffFieldType.ResRef,
|
||||||
|
description: "Script fired when this reply is selected",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Active",
|
||||||
|
displayName: "Condition Script",
|
||||||
|
type: GffFieldType.ResRef,
|
||||||
|
description: "Script that must return TRUE for this reply to appear",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
export enum GffFieldType {
|
||||||
|
Byte = 0,
|
||||||
|
Char = 1,
|
||||||
|
Word = 2,
|
||||||
|
Short = 3,
|
||||||
|
Dword = 4,
|
||||||
|
Int = 5,
|
||||||
|
Dword64 = 6,
|
||||||
|
Int64 = 7,
|
||||||
|
Float = 8,
|
||||||
|
Double = 9,
|
||||||
|
CExoString = 10,
|
||||||
|
ResRef = 11,
|
||||||
|
CExoLocString = 12,
|
||||||
|
Void = 13,
|
||||||
|
Struct = 14,
|
||||||
|
List = 15,
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GffFieldSchema {
|
||||||
|
label: string;
|
||||||
|
displayName: string;
|
||||||
|
type: GffFieldType;
|
||||||
|
description?: string;
|
||||||
|
category?: string;
|
||||||
|
editable?: boolean;
|
||||||
|
hidden?: boolean;
|
||||||
|
fields?: GffFieldSchema[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GffTypeSchema {
|
||||||
|
fileType: string;
|
||||||
|
displayName: string;
|
||||||
|
categories: string[];
|
||||||
|
fields: GffFieldSchema[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const schemaRegistry = new Map<string, () => Promise<GffTypeSchema>>();
|
||||||
|
|
||||||
|
schemaRegistry.set("uti", () => import("./uti.schema.js").then((m) => m.schema));
|
||||||
|
schemaRegistry.set("utc", () => import("./utc.schema.js").then((m) => m.schema));
|
||||||
|
schemaRegistry.set("are", () => import("./are.schema.js").then((m) => m.schema));
|
||||||
|
schemaRegistry.set("dlg", () => import("./dlg.schema.js").then((m) => m.schema));
|
||||||
|
schemaRegistry.set("utp", () => import("./utp.schema.js").then((m) => m.schema));
|
||||||
|
schemaRegistry.set("utm", () => import("./utm.schema.js").then((m) => m.schema));
|
||||||
|
|
||||||
|
export async function getSchema(
|
||||||
|
type: string,
|
||||||
|
): Promise<GffTypeSchema | undefined> {
|
||||||
|
const loader = schemaRegistry.get(type);
|
||||||
|
if (!loader) return undefined;
|
||||||
|
return loader();
|
||||||
|
}
|
||||||
@@ -0,0 +1,144 @@
|
|||||||
|
import { GffFieldType, type GffTypeSchema } from "./schema.js";
|
||||||
|
|
||||||
|
export const schema: GffTypeSchema = {
|
||||||
|
fileType: "utc",
|
||||||
|
displayName: "Creature",
|
||||||
|
categories: ["Identity", "Attributes", "Scripts", "Equipment", "AI"],
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
label: "Tag",
|
||||||
|
displayName: "Tag",
|
||||||
|
type: GffFieldType.CExoString,
|
||||||
|
category: "Identity",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "TemplateResRef",
|
||||||
|
displayName: "Template ResRef",
|
||||||
|
type: GffFieldType.ResRef,
|
||||||
|
category: "Identity",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Appearance_Type",
|
||||||
|
displayName: "Appearance Type",
|
||||||
|
type: GffFieldType.Word,
|
||||||
|
category: "Identity",
|
||||||
|
description: "Row index into appearance.2da",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Race",
|
||||||
|
displayName: "Race",
|
||||||
|
type: GffFieldType.Byte,
|
||||||
|
category: "Attributes",
|
||||||
|
description: "Row index into racialtypes.2da",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Gender",
|
||||||
|
displayName: "Gender",
|
||||||
|
type: GffFieldType.Byte,
|
||||||
|
category: "Attributes",
|
||||||
|
description: "0 = Male, 1 = Female",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Str",
|
||||||
|
displayName: "Strength",
|
||||||
|
type: GffFieldType.Byte,
|
||||||
|
category: "Attributes",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Dex",
|
||||||
|
displayName: "Dexterity",
|
||||||
|
type: GffFieldType.Byte,
|
||||||
|
category: "Attributes",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Con",
|
||||||
|
displayName: "Constitution",
|
||||||
|
type: GffFieldType.Byte,
|
||||||
|
category: "Attributes",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Int",
|
||||||
|
displayName: "Intelligence",
|
||||||
|
type: GffFieldType.Byte,
|
||||||
|
category: "Attributes",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Wis",
|
||||||
|
displayName: "Wisdom",
|
||||||
|
type: GffFieldType.Byte,
|
||||||
|
category: "Attributes",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Cha",
|
||||||
|
displayName: "Charisma",
|
||||||
|
type: GffFieldType.Byte,
|
||||||
|
category: "Attributes",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "FactionID",
|
||||||
|
displayName: "Faction ID",
|
||||||
|
type: GffFieldType.Word,
|
||||||
|
category: "AI",
|
||||||
|
description: "Determines NPC hostility and alliance behavior",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "WalkRate",
|
||||||
|
displayName: "Walk Rate",
|
||||||
|
type: GffFieldType.Int,
|
||||||
|
category: "AI",
|
||||||
|
description: "Movement speed index (7 = default from appearance.2da)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "ChallengeRating",
|
||||||
|
displayName: "Challenge Rating",
|
||||||
|
type: GffFieldType.Float,
|
||||||
|
category: "AI",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "ScriptHeartbeat",
|
||||||
|
displayName: "Heartbeat Script",
|
||||||
|
type: GffFieldType.ResRef,
|
||||||
|
category: "Scripts",
|
||||||
|
description: "Runs every 6 seconds",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "ScriptOnDamaged",
|
||||||
|
displayName: "On Damaged Script",
|
||||||
|
type: GffFieldType.ResRef,
|
||||||
|
category: "Scripts",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "ScriptDeath",
|
||||||
|
displayName: "On Death Script",
|
||||||
|
type: GffFieldType.ResRef,
|
||||||
|
category: "Scripts",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "ScriptSpawn",
|
||||||
|
displayName: "On Spawn Script",
|
||||||
|
type: GffFieldType.ResRef,
|
||||||
|
category: "Scripts",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "ClassList",
|
||||||
|
displayName: "Classes",
|
||||||
|
type: GffFieldType.List,
|
||||||
|
category: "Attributes",
|
||||||
|
description: "Character class levels",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Equip_ItemList",
|
||||||
|
displayName: "Equipped Items",
|
||||||
|
type: GffFieldType.List,
|
||||||
|
category: "Equipment",
|
||||||
|
description: "Items in equipment slots",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "ItemList",
|
||||||
|
displayName: "Inventory",
|
||||||
|
type: GffFieldType.List,
|
||||||
|
category: "Equipment",
|
||||||
|
description: "Items carried in inventory",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
import { GffFieldType, type GffTypeSchema } from "./schema.js";
|
||||||
|
|
||||||
|
export const schema: GffTypeSchema = {
|
||||||
|
fileType: "uti",
|
||||||
|
displayName: "Item",
|
||||||
|
categories: ["Identity", "Properties", "Appearance"],
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
label: "LocalizedName",
|
||||||
|
displayName: "Name",
|
||||||
|
type: GffFieldType.CExoLocString,
|
||||||
|
category: "Identity",
|
||||||
|
description: "Localized display name of the item",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Tag",
|
||||||
|
displayName: "Tag",
|
||||||
|
type: GffFieldType.CExoString,
|
||||||
|
category: "Identity",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "TemplateResRef",
|
||||||
|
displayName: "Template ResRef",
|
||||||
|
type: GffFieldType.ResRef,
|
||||||
|
category: "Identity",
|
||||||
|
description: "Blueprint resource reference (max 16 chars)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "BaseItem",
|
||||||
|
displayName: "Base Item Type",
|
||||||
|
type: GffFieldType.Int,
|
||||||
|
category: "Identity",
|
||||||
|
description: "Row index into baseitems.2da",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "StackSize",
|
||||||
|
displayName: "Stack Size",
|
||||||
|
type: GffFieldType.Word,
|
||||||
|
category: "Properties",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Cost",
|
||||||
|
displayName: "Cost",
|
||||||
|
type: GffFieldType.Dword,
|
||||||
|
category: "Properties",
|
||||||
|
description: "Gold piece value override (0 = use 2da calculation)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Charges",
|
||||||
|
displayName: "Charges",
|
||||||
|
type: GffFieldType.Byte,
|
||||||
|
category: "Properties",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Identified",
|
||||||
|
displayName: "Identified",
|
||||||
|
type: GffFieldType.Byte,
|
||||||
|
category: "Properties",
|
||||||
|
description: "Whether the item starts identified",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Plot",
|
||||||
|
displayName: "Plot Item",
|
||||||
|
type: GffFieldType.Byte,
|
||||||
|
category: "Properties",
|
||||||
|
description: "Cannot be dropped or sold if set",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Stolen",
|
||||||
|
displayName: "Stolen",
|
||||||
|
type: GffFieldType.Byte,
|
||||||
|
category: "Properties",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Cursed",
|
||||||
|
displayName: "Cursed",
|
||||||
|
type: GffFieldType.Byte,
|
||||||
|
category: "Properties",
|
||||||
|
description: "Cannot be unequipped if set",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "PropertiesList",
|
||||||
|
displayName: "Item Properties",
|
||||||
|
type: GffFieldType.List,
|
||||||
|
category: "Properties",
|
||||||
|
description: "Magical and special properties on this item",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
import { GffFieldType, type GffTypeSchema } from "./schema.js";
|
||||||
|
|
||||||
|
export const schema: GffTypeSchema = {
|
||||||
|
fileType: "utm",
|
||||||
|
displayName: "Store",
|
||||||
|
categories: ["Identity", "Economy", "Inventory"],
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
label: "Tag",
|
||||||
|
displayName: "Tag",
|
||||||
|
type: GffFieldType.CExoString,
|
||||||
|
category: "Identity",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "TemplateResRef",
|
||||||
|
displayName: "Template ResRef",
|
||||||
|
type: GffFieldType.ResRef,
|
||||||
|
category: "Identity",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "MarkDown",
|
||||||
|
displayName: "Buy Price Adjustment",
|
||||||
|
type: GffFieldType.Int,
|
||||||
|
category: "Economy",
|
||||||
|
description: "Percentage adjustment when store buys from player (negative = pays less)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "MarkUp",
|
||||||
|
displayName: "Sell Price Adjustment",
|
||||||
|
type: GffFieldType.Int,
|
||||||
|
category: "Economy",
|
||||||
|
description: "Percentage adjustment when store sells to player (positive = charges more)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "BM_MarkDown",
|
||||||
|
displayName: "Black Market Buy Adjustment",
|
||||||
|
type: GffFieldType.Int,
|
||||||
|
category: "Economy",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "StoreGold",
|
||||||
|
displayName: "Store Gold",
|
||||||
|
type: GffFieldType.Int,
|
||||||
|
category: "Economy",
|
||||||
|
description: "Gold available for buying from players (-1 = unlimited)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "BlackMarket",
|
||||||
|
displayName: "Black Market",
|
||||||
|
type: GffFieldType.Byte,
|
||||||
|
category: "Economy",
|
||||||
|
description: "Whether the store buys stolen goods",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "StoreList",
|
||||||
|
displayName: "Store Inventory",
|
||||||
|
type: GffFieldType.List,
|
||||||
|
category: "Inventory",
|
||||||
|
description: "Categories and items available for sale",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
@@ -0,0 +1,116 @@
|
|||||||
|
import { GffFieldType, type GffTypeSchema } from "./schema.js";
|
||||||
|
|
||||||
|
export const schema: GffTypeSchema = {
|
||||||
|
fileType: "utp",
|
||||||
|
displayName: "Placeable",
|
||||||
|
categories: ["Identity", "Lock", "Trap", "Scripts"],
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
label: "Appearance",
|
||||||
|
displayName: "Appearance",
|
||||||
|
type: GffFieldType.Dword,
|
||||||
|
category: "Identity",
|
||||||
|
description: "Row index into placeables.2da",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Tag",
|
||||||
|
displayName: "Tag",
|
||||||
|
type: GffFieldType.CExoString,
|
||||||
|
category: "Identity",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "TemplateResRef",
|
||||||
|
displayName: "Template ResRef",
|
||||||
|
type: GffFieldType.ResRef,
|
||||||
|
category: "Identity",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Faction",
|
||||||
|
displayName: "Faction",
|
||||||
|
type: GffFieldType.Dword,
|
||||||
|
category: "Identity",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Plot",
|
||||||
|
displayName: "Plot",
|
||||||
|
type: GffFieldType.Byte,
|
||||||
|
category: "Identity",
|
||||||
|
description: "Indestructible if set",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Useable",
|
||||||
|
displayName: "Useable",
|
||||||
|
type: GffFieldType.Byte,
|
||||||
|
category: "Identity",
|
||||||
|
description: "Whether the player can interact with this placeable",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "HasInventory",
|
||||||
|
displayName: "Has Inventory",
|
||||||
|
type: GffFieldType.Byte,
|
||||||
|
category: "Identity",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Locked",
|
||||||
|
displayName: "Locked",
|
||||||
|
type: GffFieldType.Byte,
|
||||||
|
category: "Lock",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "LockDC",
|
||||||
|
displayName: "Lock DC",
|
||||||
|
type: GffFieldType.Byte,
|
||||||
|
category: "Lock",
|
||||||
|
description: "Difficulty class to pick the lock",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "OpenLockDC",
|
||||||
|
displayName: "Open Lock DC",
|
||||||
|
type: GffFieldType.Byte,
|
||||||
|
category: "Lock",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "KeyName",
|
||||||
|
displayName: "Key Tag",
|
||||||
|
type: GffFieldType.CExoString,
|
||||||
|
category: "Lock",
|
||||||
|
description: "Tag of the key item that unlocks this",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "KeyRequired",
|
||||||
|
displayName: "Key Required",
|
||||||
|
type: GffFieldType.Byte,
|
||||||
|
category: "Lock",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "TrapDetectable",
|
||||||
|
displayName: "Trap Detectable",
|
||||||
|
type: GffFieldType.Byte,
|
||||||
|
category: "Trap",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "TrapDisarmable",
|
||||||
|
displayName: "Trap Disarmable",
|
||||||
|
type: GffFieldType.Byte,
|
||||||
|
category: "Trap",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "ScriptOnOpen",
|
||||||
|
displayName: "On Open Script",
|
||||||
|
type: GffFieldType.ResRef,
|
||||||
|
category: "Scripts",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "ScriptOnClosed",
|
||||||
|
displayName: "On Closed Script",
|
||||||
|
type: GffFieldType.ResRef,
|
||||||
|
category: "Scripts",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "ScriptOnUsed",
|
||||||
|
displayName: "On Used Script",
|
||||||
|
type: GffFieldType.ResRef,
|
||||||
|
category: "Scripts",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
@@ -9,6 +9,7 @@ import {
|
|||||||
import { lookupResref, getResrefCount } from "../nwscript/resref-index.js";
|
import { lookupResref, getResrefCount } from "../nwscript/resref-index.js";
|
||||||
import { lookupTlk, getTlkCount } from "../nwscript/tlk-index.js";
|
import { lookupTlk, getTlkCount } from "../nwscript/tlk-index.js";
|
||||||
import { get2DAFile, list2DAFiles, get2DARow } from "../nwscript/twoda-index.js";
|
import { get2DAFile, list2DAFiles, get2DARow } from "../nwscript/twoda-index.js";
|
||||||
|
import { getSchema } from "../gff/schema.js";
|
||||||
|
|
||||||
const router = Router();
|
const router = Router();
|
||||||
|
|
||||||
@@ -110,4 +111,15 @@ router.get("/2da/:name/:row", (req, res) => {
|
|||||||
res.json(data);
|
res.json(data);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
router.get("/gff-schema/:type", async (req, res) => {
|
||||||
|
try {
|
||||||
|
const schema = await getSchema(req.params.type);
|
||||||
|
if (!schema) return res.status(404).json({ error: "unknown GFF type" });
|
||||||
|
res.json(schema);
|
||||||
|
} catch (err: unknown) {
|
||||||
|
const message = err instanceof Error ? err.message : "Unknown error";
|
||||||
|
res.status(500).json({ error: message });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
export default router;
|
export default router;
|
||||||
|
|||||||
Reference in New Issue
Block a user