rpgmaker-mz-mcp 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +425 -0
- package/dist/events/commandBuilders.d.ts +405 -0
- package/dist/events/commandBuilders.d.ts.map +1 -0
- package/dist/events/commandBuilders.js +554 -0
- package/dist/events/commandBuilders.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +105 -0
- package/dist/index.js.map +1 -0
- package/dist/registry.d.ts +81 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +49 -0
- package/dist/registry.js.map +1 -0
- package/dist/tiles/autotile.d.ts +65 -0
- package/dist/tiles/autotile.d.ts.map +1 -0
- package/dist/tiles/autotile.js +201 -0
- package/dist/tiles/autotile.js.map +1 -0
- package/dist/tiles/catalog/dungeon.d.ts +16 -0
- package/dist/tiles/catalog/dungeon.d.ts.map +1 -0
- package/dist/tiles/catalog/dungeon.js +765 -0
- package/dist/tiles/catalog/dungeon.js.map +1 -0
- package/dist/tiles/catalog/index.d.ts +78 -0
- package/dist/tiles/catalog/index.d.ts.map +1 -0
- package/dist/tiles/catalog/index.js +115 -0
- package/dist/tiles/catalog/index.js.map +1 -0
- package/dist/tiles/catalog/inside.d.ts +16 -0
- package/dist/tiles/catalog/inside.d.ts.map +1 -0
- package/dist/tiles/catalog/inside.js +765 -0
- package/dist/tiles/catalog/inside.js.map +1 -0
- package/dist/tiles/catalog/outside.d.ts +16 -0
- package/dist/tiles/catalog/outside.d.ts.map +1 -0
- package/dist/tiles/catalog/outside.js +799 -0
- package/dist/tiles/catalog/outside.js.map +1 -0
- package/dist/tiles/catalog/overworld.d.ts +16 -0
- package/dist/tiles/catalog/overworld.d.ts.map +1 -0
- package/dist/tiles/catalog/overworld.js +585 -0
- package/dist/tiles/catalog/overworld.js.map +1 -0
- package/dist/tiles/catalog/sf.d.ts +16 -0
- package/dist/tiles/catalog/sf.d.ts.map +1 -0
- package/dist/tiles/catalog/sf.js +1313 -0
- package/dist/tiles/catalog/sf.js.map +1 -0
- package/dist/tiles/paint.d.ts +20 -0
- package/dist/tiles/paint.d.ts.map +1 -0
- package/dist/tiles/paint.js +65 -0
- package/dist/tiles/paint.js.map +1 -0
- package/dist/tiles/png.d.ts +11 -0
- package/dist/tiles/png.d.ts.map +1 -0
- package/dist/tiles/png.js +180 -0
- package/dist/tiles/png.js.map +1 -0
- package/dist/tiles/tileCodec.d.ts +95 -0
- package/dist/tiles/tileCodec.d.ts.map +1 -0
- package/dist/tiles/tileCodec.js +186 -0
- package/dist/tiles/tileCodec.js.map +1 -0
- package/dist/tiles/tileFlags.d.ts +98 -0
- package/dist/tiles/tileFlags.d.ts.map +1 -0
- package/dist/tiles/tileFlags.js +129 -0
- package/dist/tiles/tileFlags.js.map +1 -0
- package/dist/tiles/tilegeom.d.ts +29 -0
- package/dist/tiles/tilegeom.d.ts.map +1 -0
- package/dist/tiles/tilegeom.js +111 -0
- package/dist/tiles/tilegeom.js.map +1 -0
- package/dist/tiles/transparency.d.ts +22 -0
- package/dist/tiles/transparency.d.ts.map +1 -0
- package/dist/tiles/transparency.js +59 -0
- package/dist/tiles/transparency.js.map +1 -0
- package/dist/tools/actorTools.d.ts +48 -0
- package/dist/tools/actorTools.d.ts.map +1 -0
- package/dist/tools/actorTools.js +154 -0
- package/dist/tools/actorTools.js.map +1 -0
- package/dist/tools/allTools.d.ts +8 -0
- package/dist/tools/allTools.d.ts.map +1 -0
- package/dist/tools/allTools.js +56 -0
- package/dist/tools/allTools.js.map +1 -0
- package/dist/tools/assetTools.d.ts +113 -0
- package/dist/tools/assetTools.d.ts.map +1 -0
- package/dist/tools/assetTools.js +97 -0
- package/dist/tools/assetTools.js.map +1 -0
- package/dist/tools/batchTools.d.ts +3 -0
- package/dist/tools/batchTools.d.ts.map +1 -0
- package/dist/tools/batchTools.js +138 -0
- package/dist/tools/batchTools.js.map +1 -0
- package/dist/tools/battleTools.d.ts +72 -0
- package/dist/tools/battleTools.d.ts.map +1 -0
- package/dist/tools/battleTools.js +322 -0
- package/dist/tools/battleTools.js.map +1 -0
- package/dist/tools/catalogTools.d.ts +3 -0
- package/dist/tools/catalogTools.d.ts.map +1 -0
- package/dist/tools/catalogTools.js +134 -0
- package/dist/tools/catalogTools.js.map +1 -0
- package/dist/tools/classTools.d.ts +85 -0
- package/dist/tools/classTools.d.ts.map +1 -0
- package/dist/tools/classTools.js +279 -0
- package/dist/tools/classTools.js.map +1 -0
- package/dist/tools/commonEventTools.d.ts +32 -0
- package/dist/tools/commonEventTools.d.ts.map +1 -0
- package/dist/tools/commonEventTools.js +150 -0
- package/dist/tools/commonEventTools.js.map +1 -0
- package/dist/tools/eventCommandTools.d.ts +37 -0
- package/dist/tools/eventCommandTools.d.ts.map +1 -0
- package/dist/tools/eventCommandTools.js +893 -0
- package/dist/tools/eventCommandTools.js.map +1 -0
- package/dist/tools/eventPageTools.d.ts +112 -0
- package/dist/tools/eventPageTools.d.ts.map +1 -0
- package/dist/tools/eventPageTools.js +597 -0
- package/dist/tools/eventPageTools.js.map +1 -0
- package/dist/tools/itemTools.d.ts +82 -0
- package/dist/tools/itemTools.d.ts.map +1 -0
- package/dist/tools/itemTools.js +380 -0
- package/dist/tools/itemTools.js.map +1 -0
- package/dist/tools/listTools.d.ts +58 -0
- package/dist/tools/listTools.d.ts.map +1 -0
- package/dist/tools/listTools.js +99 -0
- package/dist/tools/listTools.js.map +1 -0
- package/dist/tools/mapTools.d.ts +270 -0
- package/dist/tools/mapTools.d.ts.map +1 -0
- package/dist/tools/mapTools.js +1066 -0
- package/dist/tools/mapTools.js.map +1 -0
- package/dist/tools/moveTools.d.ts +43 -0
- package/dist/tools/moveTools.d.ts.map +1 -0
- package/dist/tools/moveTools.js +240 -0
- package/dist/tools/moveTools.js.map +1 -0
- package/dist/tools/objectTools.d.ts +12 -0
- package/dist/tools/objectTools.d.ts.map +1 -0
- package/dist/tools/objectTools.js +221 -0
- package/dist/tools/objectTools.js.map +1 -0
- package/dist/tools/paintTools.d.ts +3 -0
- package/dist/tools/paintTools.d.ts.map +1 -0
- package/dist/tools/paintTools.js +134 -0
- package/dist/tools/paintTools.js.map +1 -0
- package/dist/tools/pluginScanTools.d.ts +22 -0
- package/dist/tools/pluginScanTools.d.ts.map +1 -0
- package/dist/tools/pluginScanTools.js +119 -0
- package/dist/tools/pluginScanTools.js.map +1 -0
- package/dist/tools/pluginTools.d.ts +11 -0
- package/dist/tools/pluginTools.d.ts.map +1 -0
- package/dist/tools/pluginTools.js +63 -0
- package/dist/tools/pluginTools.js.map +1 -0
- package/dist/tools/projectTools.d.ts +11 -0
- package/dist/tools/projectTools.d.ts.map +1 -0
- package/dist/tools/projectTools.js +74 -0
- package/dist/tools/projectTools.js.map +1 -0
- package/dist/tools/skillTools.d.ts +83 -0
- package/dist/tools/skillTools.d.ts.map +1 -0
- package/dist/tools/skillTools.js +369 -0
- package/dist/tools/skillTools.js.map +1 -0
- package/dist/tools/stateTools.d.ts +28 -0
- package/dist/tools/stateTools.d.ts.map +1 -0
- package/dist/tools/stateTools.js +161 -0
- package/dist/tools/stateTools.js.map +1 -0
- package/dist/tools/systemTools.d.ts +86 -0
- package/dist/tools/systemTools.d.ts.map +1 -0
- package/dist/tools/systemTools.js +342 -0
- package/dist/tools/systemTools.js.map +1 -0
- package/dist/tools/tileTools.d.ts +9 -0
- package/dist/tools/tileTools.d.ts.map +1 -0
- package/dist/tools/tileTools.js +34 -0
- package/dist/tools/tileTools.js.map +1 -0
- package/dist/tools/tileTransparency.d.ts +40 -0
- package/dist/tools/tileTransparency.d.ts.map +1 -0
- package/dist/tools/tileTransparency.js +156 -0
- package/dist/tools/tileTransparency.js.map +1 -0
- package/dist/tools/tilesetTools.d.ts +23 -0
- package/dist/tools/tilesetTools.d.ts.map +1 -0
- package/dist/tools/tilesetTools.js +209 -0
- package/dist/tools/tilesetTools.js.map +1 -0
- package/dist/tools/validationTools.d.ts +50 -0
- package/dist/tools/validationTools.d.ts.map +1 -0
- package/dist/tools/validationTools.js +229 -0
- package/dist/tools/validationTools.js.map +1 -0
- package/dist/utils/commit.d.ts +62 -0
- package/dist/utils/commit.d.ts.map +1 -0
- package/dist/utils/commit.js +119 -0
- package/dist/utils/commit.js.map +1 -0
- package/dist/utils/fileHandler.d.ts +49 -0
- package/dist/utils/fileHandler.d.ts.map +1 -0
- package/dist/utils/fileHandler.js +137 -0
- package/dist/utils/fileHandler.js.map +1 -0
- package/dist/utils/records.d.ts +8 -0
- package/dist/utils/records.d.ts.map +1 -0
- package/dist/utils/records.js +10 -0
- package/dist/utils/records.js.map +1 -0
- package/dist/utils/types.d.ts +465 -0
- package/dist/utils/types.d.ts.map +1 -0
- package/dist/utils/types.js +5 -0
- package/dist/utils/types.js.map +1 -0
- package/dist/validation/assets.d.ts +53 -0
- package/dist/validation/assets.d.ts.map +1 -0
- package/dist/validation/assets.js +198 -0
- package/dist/validation/assets.js.map +1 -0
- package/dist/validation/createRefs.d.ts +37 -0
- package/dist/validation/createRefs.d.ts.map +1 -0
- package/dist/validation/createRefs.js +89 -0
- package/dist/validation/createRefs.js.map +1 -0
- package/dist/validation/eventCommands.d.ts +70 -0
- package/dist/validation/eventCommands.d.ts.map +1 -0
- package/dist/validation/eventCommands.js +273 -0
- package/dist/validation/eventCommands.js.map +1 -0
- package/dist/validation/gate.d.ts +56 -0
- package/dist/validation/gate.d.ts.map +1 -0
- package/dist/validation/gate.js +50 -0
- package/dist/validation/gate.js.map +1 -0
- package/dist/validation/moveCommands.d.ts +31 -0
- package/dist/validation/moveCommands.d.ts.map +1 -0
- package/dist/validation/moveCommands.js +123 -0
- package/dist/validation/moveCommands.js.map +1 -0
- package/dist/validation/pluginCommands.d.ts +83 -0
- package/dist/validation/pluginCommands.d.ts.map +1 -0
- package/dist/validation/pluginCommands.js +134 -0
- package/dist/validation/pluginCommands.js.map +1 -0
- package/dist/validation/pluginManifest.d.ts +67 -0
- package/dist/validation/pluginManifest.d.ts.map +1 -0
- package/dist/validation/pluginManifest.js +199 -0
- package/dist/validation/pluginManifest.js.map +1 -0
- package/dist/validation/references.d.ts +57 -0
- package/dist/validation/references.d.ts.map +1 -0
- package/dist/validation/references.js +314 -0
- package/dist/validation/references.js.map +1 -0
- package/package.json +67 -0
|
@@ -0,0 +1,893 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { getMapPath, getDataPath } from '../utils/fileHandler.js';
|
|
3
|
+
import { commitChange } from '../utils/commit.js';
|
|
4
|
+
import { validateCommandList, textLineWidthWarnings, } from '../validation/eventCommands.js';
|
|
5
|
+
import { writeGate } from '../validation/gate.js';
|
|
6
|
+
import { eventWriteGate, getMap } from './mapTools.js';
|
|
7
|
+
import { getCommonEvents } from './commonEventTools.js';
|
|
8
|
+
import { getTroops } from './battleTools.js';
|
|
9
|
+
import { spliceIntoList, showText, showChoices, conditionalBranch, wait, exitEvent, label, jumpToLabel, controlSwitches, controlSelfSwitch, controlVariables, changeGold, changeItems, changeWeapons, changeArmors, changePartyMember, transferPlayer, playAudio, fadeScreen, tintScreen, flashScreen, shakeScreen, showPicture, erasePicture, showAnimation, showBalloon, battleProcessing, shopProcessing, nameInput, changeHp, changeMp, changeState, recoverAll, changeExp, changeLevel, } from '../events/commandBuilders.js';
|
|
10
|
+
import { assetNameWarning } from './assetTools.js';
|
|
11
|
+
/** Zod shape for a raw event command (used where callers pass builder output back). */
|
|
12
|
+
const eventCommandShape = z.object({
|
|
13
|
+
code: z.number().int().describe('Event command code'),
|
|
14
|
+
indent: z.number().int().optional().describe('Indentation level (default 0)'),
|
|
15
|
+
parameters: z.array(z.unknown()).optional().describe('Command parameters (default [])'),
|
|
16
|
+
});
|
|
17
|
+
/** Coerce a loosely-typed command array into well-formed EventCommands. */
|
|
18
|
+
function asCommands(raw) {
|
|
19
|
+
if (!Array.isArray(raw))
|
|
20
|
+
return [];
|
|
21
|
+
return raw.map((c) => {
|
|
22
|
+
const cmd = c;
|
|
23
|
+
return {
|
|
24
|
+
code: cmd.code,
|
|
25
|
+
indent: cmd.indent ?? 0,
|
|
26
|
+
parameters: Array.isArray(cmd.parameters) ? cmd.parameters : [],
|
|
27
|
+
};
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
/** Coerce a nested array-of-command-arrays (per-choice branches). */
|
|
31
|
+
function asCommandGroups(raw) {
|
|
32
|
+
if (!Array.isArray(raw))
|
|
33
|
+
return undefined;
|
|
34
|
+
return raw.map((group) => asCommands(group));
|
|
35
|
+
}
|
|
36
|
+
function requiredArg(value, name, target) {
|
|
37
|
+
if (value === undefined) {
|
|
38
|
+
throw new Error(`${name} is required for target "${target}"`);
|
|
39
|
+
}
|
|
40
|
+
return value;
|
|
41
|
+
}
|
|
42
|
+
/** Locate the command list a target names, without touching it yet. */
|
|
43
|
+
async function resolveCommandList(projectPath, target, opts) {
|
|
44
|
+
if (target === 'map_event') {
|
|
45
|
+
const mapId = requiredArg(opts.mapId, 'mapId', target);
|
|
46
|
+
const eventId = requiredArg(opts.eventId, 'eventId', target);
|
|
47
|
+
const pageIndex = requiredArg(opts.pageIndex, 'pageIndex', target);
|
|
48
|
+
const map = await getMap(projectPath, mapId);
|
|
49
|
+
const event = map.events[eventId];
|
|
50
|
+
if (!event) {
|
|
51
|
+
throw new Error(`Event ${eventId} not found on map ${mapId}`);
|
|
52
|
+
}
|
|
53
|
+
const page = event.pages[pageIndex];
|
|
54
|
+
if (!page) {
|
|
55
|
+
throw new Error(`Page ${pageIndex} not found on event ${eventId}`);
|
|
56
|
+
}
|
|
57
|
+
const gate = eventWriteGate(projectPath, mapId, opts.force);
|
|
58
|
+
return {
|
|
59
|
+
id: eventId,
|
|
60
|
+
list: page.list,
|
|
61
|
+
file: getMapPath(projectPath, mapId),
|
|
62
|
+
root: map,
|
|
63
|
+
precommit: () => gate.precommit(event),
|
|
64
|
+
respond: gate.respond,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
if (target === 'common_event') {
|
|
68
|
+
const commonEventId = requiredArg(opts.commonEventId, 'commonEventId', target);
|
|
69
|
+
const commonEvents = await getCommonEvents(projectPath);
|
|
70
|
+
const ce = commonEvents.find((c) => c && c.id === commonEventId);
|
|
71
|
+
if (!ce) {
|
|
72
|
+
throw new Error(`Common event ${commonEventId} does not exist`);
|
|
73
|
+
}
|
|
74
|
+
const subject = `common event ${ce.id}`;
|
|
75
|
+
const gate = writeGate(opts.force, subject, (list) => validateCommandList(list, subject));
|
|
76
|
+
return {
|
|
77
|
+
id: ce.id,
|
|
78
|
+
list: ce.list,
|
|
79
|
+
file: getDataPath(projectPath, 'CommonEvents.json'),
|
|
80
|
+
root: commonEvents,
|
|
81
|
+
precommit: () => gate.precommit(ce.list),
|
|
82
|
+
respond: gate.respond,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
const troopId = requiredArg(opts.troopId, 'troopId', target);
|
|
86
|
+
const pageIndex = requiredArg(opts.pageIndex, 'pageIndex', target);
|
|
87
|
+
const troops = await getTroops(projectPath);
|
|
88
|
+
const troop = troops.find((t) => t && t.id === troopId);
|
|
89
|
+
if (!troop) {
|
|
90
|
+
throw new Error(`Troop ${troopId} does not exist`);
|
|
91
|
+
}
|
|
92
|
+
const page = troop.pages[pageIndex];
|
|
93
|
+
if (!page) {
|
|
94
|
+
throw new Error(`Page ${pageIndex} not found on troop ${troopId}`);
|
|
95
|
+
}
|
|
96
|
+
const subject = `troop ${troop.id} / page ${pageIndex}`;
|
|
97
|
+
const gate = writeGate(opts.force, subject, (list) => validateCommandList(list, subject));
|
|
98
|
+
return {
|
|
99
|
+
id: troop.id,
|
|
100
|
+
list: page.list,
|
|
101
|
+
file: getDataPath(projectPath, 'Troops.json'),
|
|
102
|
+
root: troops,
|
|
103
|
+
precommit: () => gate.precommit(page.list),
|
|
104
|
+
respond: gate.respond,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Insert a pre-built command sequence into any of the three command lists an MZ
|
|
109
|
+
* project has — a map event page, a common event body, or a troop battle-event
|
|
110
|
+
* page — the mutating companion to the read-only builders below. This is how a
|
|
111
|
+
* Show Text / Show Choices / Conditional Branch block built by the builders
|
|
112
|
+
* actually lands in the game.
|
|
113
|
+
*
|
|
114
|
+
* All three lists share the EventCommand format, so there is one splice path:
|
|
115
|
+
* resolve the list, splice before its code-0 end marker (or at `position`),
|
|
116
|
+
* gate, commit. The resulting list is validated **before** the commit — a
|
|
117
|
+
* structurally invalid result is refused and nothing is written (unless
|
|
118
|
+
* `opts.force`).
|
|
119
|
+
*/
|
|
120
|
+
export async function insertEventCommands(projectPath, target, opts) {
|
|
121
|
+
const site = await resolveCommandList(projectPath, target, opts);
|
|
122
|
+
spliceIntoList(site.list, opts.commands, opts.position);
|
|
123
|
+
await site.precommit();
|
|
124
|
+
await commitChange(site.file, site.root);
|
|
125
|
+
return site.respond({ target, id: site.id, list: site.list });
|
|
126
|
+
}
|
|
127
|
+
/** Zod shape for a Conditional Branch condition (validated further in the builder). */
|
|
128
|
+
const conditionShape = z
|
|
129
|
+
.object({
|
|
130
|
+
type: z
|
|
131
|
+
.enum(['switch', 'self_switch', 'variable', 'actor_in_party', 'gold', 'item'])
|
|
132
|
+
.describe('Condition type'),
|
|
133
|
+
switchId: z.number().int().optional().describe('switch: the switch id to test'),
|
|
134
|
+
name: z.enum(['A', 'B', 'C', 'D']).optional().describe('self_switch: which self switch'),
|
|
135
|
+
value: z
|
|
136
|
+
.enum(['on', 'off'])
|
|
137
|
+
.optional()
|
|
138
|
+
.describe('switch/self_switch: test for on (default) or off'),
|
|
139
|
+
variableId: z.number().int().optional().describe('variable: the variable id (left side)'),
|
|
140
|
+
comparison: z
|
|
141
|
+
.enum(['==', '>=', '<=', '>', '<', '!='])
|
|
142
|
+
.optional()
|
|
143
|
+
.describe('variable: comparison operator'),
|
|
144
|
+
constant: z.number().optional().describe('variable: compare against this constant (default 0)'),
|
|
145
|
+
variableOperand: z
|
|
146
|
+
.number()
|
|
147
|
+
.int()
|
|
148
|
+
.optional()
|
|
149
|
+
.describe('variable: compare against this variable id (overrides constant)'),
|
|
150
|
+
actorId: z.number().int().optional().describe('actor_in_party: the actor id'),
|
|
151
|
+
itemId: z.number().int().optional().describe('item: the item id (tests "party has item")'),
|
|
152
|
+
gold: z.number().optional().describe('gold: the amount to compare against'),
|
|
153
|
+
compare: z.enum(['>=', '<=', '<']).optional().describe('gold: comparison operator'),
|
|
154
|
+
})
|
|
155
|
+
.describe('Conditional branch condition');
|
|
156
|
+
/** Map the flat condition input object to the discriminated {@link BranchCondition}. */
|
|
157
|
+
function toBranchCondition(c) {
|
|
158
|
+
switch (c.type) {
|
|
159
|
+
case 'switch':
|
|
160
|
+
return { type: 'switch', switchId: c.switchId, value: c.value };
|
|
161
|
+
case 'self_switch':
|
|
162
|
+
return {
|
|
163
|
+
type: 'self_switch',
|
|
164
|
+
name: c.name,
|
|
165
|
+
value: c.value,
|
|
166
|
+
};
|
|
167
|
+
case 'variable':
|
|
168
|
+
return {
|
|
169
|
+
type: 'variable',
|
|
170
|
+
variableId: c.variableId,
|
|
171
|
+
comparison: c.comparison,
|
|
172
|
+
constant: c.constant,
|
|
173
|
+
variableOperand: c.variableOperand,
|
|
174
|
+
};
|
|
175
|
+
case 'actor_in_party':
|
|
176
|
+
return { type: 'actor_in_party', actorId: c.actorId };
|
|
177
|
+
case 'gold':
|
|
178
|
+
return { type: 'gold', value: c.gold, compare: c.compare };
|
|
179
|
+
case 'item':
|
|
180
|
+
return { type: 'item', itemId: c.itemId };
|
|
181
|
+
default:
|
|
182
|
+
throw new Error(`Unknown condition type: ${String(c.type)}`);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
/** Zod shape for a Change Gold/Items/Weapons/Armors operand (constant or variable amount). */
|
|
186
|
+
const gainOperandShape = z
|
|
187
|
+
.object({
|
|
188
|
+
type: z.enum(['constant', 'variable']).describe('constant amount or a variable value'),
|
|
189
|
+
value: z.number().optional().describe('constant: the amount'),
|
|
190
|
+
variableId: z.number().int().optional().describe('variable: the variable id to read'),
|
|
191
|
+
})
|
|
192
|
+
.describe('The amount to gain/lose (constant or variable)');
|
|
193
|
+
/** Map the flat gain-operand input to the discriminated {@link GainOperand}. */
|
|
194
|
+
function toGainOperand(o) {
|
|
195
|
+
return o.type === 'variable'
|
|
196
|
+
? { type: 'variable', variableId: o.variableId }
|
|
197
|
+
: { type: 'constant', value: o.value ?? 0 };
|
|
198
|
+
}
|
|
199
|
+
/** Zod shape for a Control Variables operand (constant / variable / random / game_data). */
|
|
200
|
+
const variableOperandShape = z
|
|
201
|
+
.object({
|
|
202
|
+
type: z
|
|
203
|
+
.enum(['constant', 'variable', 'random', 'game_data'])
|
|
204
|
+
.describe('Operand source for the variable value'),
|
|
205
|
+
value: z.number().optional().describe('constant: the value'),
|
|
206
|
+
variableId: z.number().int().optional().describe('variable: the source variable id'),
|
|
207
|
+
min: z.number().optional().describe('random: inclusive minimum'),
|
|
208
|
+
max: z.number().optional().describe('random: inclusive maximum'),
|
|
209
|
+
dataType: z
|
|
210
|
+
.number()
|
|
211
|
+
.int()
|
|
212
|
+
.optional()
|
|
213
|
+
.describe('game_data: 0 item/1 weapon/2 armor count, 3 actor, 4 enemy, 5 char, 6 party, 7 other, 8 last'),
|
|
214
|
+
param1: z.number().int().optional().describe('game_data: first sub-parameter (see corescript)'),
|
|
215
|
+
param2: z
|
|
216
|
+
.number()
|
|
217
|
+
.int()
|
|
218
|
+
.optional()
|
|
219
|
+
.describe('game_data: second sub-parameter (see corescript)'),
|
|
220
|
+
})
|
|
221
|
+
.describe('The right-hand operand of the Control Variables command');
|
|
222
|
+
/** Map the flat variable-operand input to the discriminated {@link VariableOperand}. */
|
|
223
|
+
function toVariableOperand(o) {
|
|
224
|
+
switch (o.type) {
|
|
225
|
+
case 'variable':
|
|
226
|
+
return { type: 'variable', variableId: o.variableId };
|
|
227
|
+
case 'random':
|
|
228
|
+
return { type: 'random', min: o.min ?? 0, max: o.max ?? 0 };
|
|
229
|
+
case 'game_data':
|
|
230
|
+
return {
|
|
231
|
+
type: 'game_data',
|
|
232
|
+
dataType: o.dataType ?? 0,
|
|
233
|
+
param1: o.param1,
|
|
234
|
+
param2: o.param2,
|
|
235
|
+
};
|
|
236
|
+
default:
|
|
237
|
+
return { type: 'constant', value: o.value ?? 0 };
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
/** Coerce a loosely-typed color/tone input into the 4-number tuple (defaults to 0s). */
|
|
241
|
+
function toColorTone(raw) {
|
|
242
|
+
const a = Array.isArray(raw) ? raw : [];
|
|
243
|
+
return [Number(a[0]) || 0, Number(a[1]) || 0, Number(a[2]) || 0, Number(a[3]) || 0];
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Warn (never throw) when an audio `name` isn't among the project's assets for that
|
|
247
|
+
* channel. Thin wrapper over the shared {@link assetNameWarning}.
|
|
248
|
+
*/
|
|
249
|
+
async function audioNameWarnings(projectPath, kind, name) {
|
|
250
|
+
return assetNameWarning(projectPath, kind, name, {
|
|
251
|
+
path: `play_audio ${kind}`,
|
|
252
|
+
label: 'audio',
|
|
253
|
+
consequence: 'a wrong filename fails silently at runtime',
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
/** Zod shape for an actor target (fixed actor id / 0 = whole party, or a variable). */
|
|
257
|
+
const actorTargetShape = z
|
|
258
|
+
.object({
|
|
259
|
+
type: z.enum(['fixed', 'variable']).describe('fixed actor id (0 = whole party) or a variable'),
|
|
260
|
+
actorId: z.number().int().optional().describe('fixed: the actor id (0 = entire party)'),
|
|
261
|
+
variableId: z
|
|
262
|
+
.number()
|
|
263
|
+
.int()
|
|
264
|
+
.optional()
|
|
265
|
+
.describe('variable: the variable id holding the actor id'),
|
|
266
|
+
})
|
|
267
|
+
.describe('Which actor(s) the change applies to');
|
|
268
|
+
/** Map the flat actor-target input to the discriminated {@link ActorTarget}. */
|
|
269
|
+
function toActorTarget(t) {
|
|
270
|
+
return t.type === 'variable'
|
|
271
|
+
? { type: 'variable', variableId: t.variableId ?? 0 }
|
|
272
|
+
: { type: 'fixed', actorId: t.actorId ?? 0 };
|
|
273
|
+
}
|
|
274
|
+
export const eventCommandToolDefinitions = [
|
|
275
|
+
{
|
|
276
|
+
name: 'build_show_text',
|
|
277
|
+
description: 'Build a Show Text event-command sequence (101 setup + one 401 line per text line) for insertion via insert_event_commands. Supports face image (from list_assets("faces")), window background/position, and the MZ name-box speaker. MZ does NOT word-wrap: keep each line under ~55 chars (~38 with a face) or it is cut off at the window edge (warned, never blocked). Read-only: returns { commands, warnings? }, writes nothing.',
|
|
278
|
+
inputSchema: {
|
|
279
|
+
lines: z.array(z.string()).describe('Message lines (one entry per visual line)'),
|
|
280
|
+
faceName: z.string().optional().describe('Face image basename ("" = none, default)'),
|
|
281
|
+
faceIndex: z.number().int().optional().describe('Face index 0–7 in the sheet (default 0)'),
|
|
282
|
+
background: z
|
|
283
|
+
.enum(['window', 'dim', 'transparent'])
|
|
284
|
+
.optional()
|
|
285
|
+
.describe('Window background (default window)'),
|
|
286
|
+
position: z
|
|
287
|
+
.enum(['top', 'middle', 'bottom'])
|
|
288
|
+
.optional()
|
|
289
|
+
.describe('Window position (default bottom)'),
|
|
290
|
+
speakerName: z.string().optional().describe('MZ name-box speaker name (default "")'),
|
|
291
|
+
indent: z.number().int().optional().describe('Indentation level (default 0)'),
|
|
292
|
+
},
|
|
293
|
+
handler: async (_ctx, args) => {
|
|
294
|
+
const options = {
|
|
295
|
+
faceName: args.faceName,
|
|
296
|
+
faceIndex: args.faceIndex,
|
|
297
|
+
background: args.background,
|
|
298
|
+
position: args.position,
|
|
299
|
+
speakerName: args.speakerName,
|
|
300
|
+
indent: args.indent,
|
|
301
|
+
};
|
|
302
|
+
const commands = showText(args.lines, options);
|
|
303
|
+
const warnings = textLineWidthWarnings(commands, 'show_text');
|
|
304
|
+
return warnings.length > 0 ? { commands, warnings } : { commands };
|
|
305
|
+
},
|
|
306
|
+
},
|
|
307
|
+
{
|
|
308
|
+
name: 'build_show_choices',
|
|
309
|
+
description: 'Build a Show Choices block (102 opener + a 402 branch per choice + optional 403 When-Cancel branch + 404 closer, each branch terminated like the editor) for insertion via insert_event_commands. Pass per-choice `branches` (each an EventCommand[] — e.g. from build_show_text) to fill the branch bodies. Read-only: returns { commands }.',
|
|
310
|
+
inputSchema: {
|
|
311
|
+
choices: z.array(z.string()).describe('The choice labels shown to the player'),
|
|
312
|
+
branches: z
|
|
313
|
+
.array(z.array(eventCommandShape))
|
|
314
|
+
.optional()
|
|
315
|
+
.describe('Commands per choice (same order as choices); omitted/short = empty branches'),
|
|
316
|
+
cancelBranch: z
|
|
317
|
+
.array(eventCommandShape)
|
|
318
|
+
.optional()
|
|
319
|
+
.describe('Commands for a "When Cancel" branch (adds a 403 block; cancel routes here)'),
|
|
320
|
+
cancelType: z
|
|
321
|
+
.number()
|
|
322
|
+
.int()
|
|
323
|
+
.optional()
|
|
324
|
+
.describe('Without a cancelBranch: 0-based choice index the Cancel button maps to, or -1 Disallow (default -1)'),
|
|
325
|
+
defaultType: z
|
|
326
|
+
.number()
|
|
327
|
+
.int()
|
|
328
|
+
.optional()
|
|
329
|
+
.describe('0-based default (highlighted) choice, or -1 none (default 0)'),
|
|
330
|
+
position: z
|
|
331
|
+
.enum(['left', 'middle', 'right'])
|
|
332
|
+
.optional()
|
|
333
|
+
.describe('Choice window position (default right)'),
|
|
334
|
+
background: z
|
|
335
|
+
.enum(['window', 'dim', 'transparent'])
|
|
336
|
+
.optional()
|
|
337
|
+
.describe('Choice window background (default window)'),
|
|
338
|
+
indent: z.number().int().optional().describe('Indentation level of the block (default 0)'),
|
|
339
|
+
},
|
|
340
|
+
handler: async (_ctx, args) => {
|
|
341
|
+
const options = {
|
|
342
|
+
branches: asCommandGroups(args.branches),
|
|
343
|
+
cancelBranch: args.cancelBranch !== undefined ? asCommands(args.cancelBranch) : undefined,
|
|
344
|
+
cancelType: args.cancelType,
|
|
345
|
+
defaultType: args.defaultType,
|
|
346
|
+
position: args.position,
|
|
347
|
+
background: args.background,
|
|
348
|
+
indent: args.indent,
|
|
349
|
+
};
|
|
350
|
+
return { commands: showChoices(args.choices, options) };
|
|
351
|
+
},
|
|
352
|
+
},
|
|
353
|
+
{
|
|
354
|
+
name: 'build_conditional_branch',
|
|
355
|
+
description: 'Build a Conditional Branch block (111 condition + then-branch + optional 411 Else + 412 closer, each branch terminated like the editor) for insertion via insert_event_commands. Condition types: switch, self_switch, variable, actor_in_party, gold, item. Provide thenBranch/elseBranch as EventCommand[] (e.g. from other builders). Read-only: returns { commands }.',
|
|
356
|
+
inputSchema: {
|
|
357
|
+
condition: conditionShape,
|
|
358
|
+
thenBranch: z
|
|
359
|
+
.array(eventCommandShape)
|
|
360
|
+
.optional()
|
|
361
|
+
.describe('Commands to run when the condition is true (default empty)'),
|
|
362
|
+
elseBranch: z
|
|
363
|
+
.array(eventCommandShape)
|
|
364
|
+
.optional()
|
|
365
|
+
.describe('Commands for the Else branch; presence (even empty) adds the 411 Else block'),
|
|
366
|
+
indent: z.number().int().optional().describe('Indentation level of the block (default 0)'),
|
|
367
|
+
},
|
|
368
|
+
handler: async (_ctx, args) => {
|
|
369
|
+
const condition = toBranchCondition(args.condition);
|
|
370
|
+
const options = {
|
|
371
|
+
thenBranch: args.thenBranch !== undefined ? asCommands(args.thenBranch) : undefined,
|
|
372
|
+
elseBranch: args.elseBranch !== undefined ? asCommands(args.elseBranch) : undefined,
|
|
373
|
+
indent: args.indent,
|
|
374
|
+
};
|
|
375
|
+
return { commands: conditionalBranch(condition, options) };
|
|
376
|
+
},
|
|
377
|
+
},
|
|
378
|
+
{
|
|
379
|
+
name: 'build_flow_command',
|
|
380
|
+
description: 'Build a single flow-control event command for insertion via insert_event_commands: wait (230, N frames), exit_event (115), label (118, a named jump target), or jump_to_label (119). Read-only: returns { command }.',
|
|
381
|
+
inputSchema: {
|
|
382
|
+
kind: z
|
|
383
|
+
.enum(['wait', 'exit_event', 'label', 'jump_to_label'])
|
|
384
|
+
.describe('Which flow command to build'),
|
|
385
|
+
frames: z.number().int().optional().describe('wait: number of frames (60 = 1 second)'),
|
|
386
|
+
name: z.string().optional().describe('label/jump_to_label: the label name'),
|
|
387
|
+
indent: z.number().int().optional().describe('Indentation level (default 0)'),
|
|
388
|
+
},
|
|
389
|
+
handler: async (_ctx, args) => {
|
|
390
|
+
const indent = args.indent ?? 0;
|
|
391
|
+
switch (args.kind) {
|
|
392
|
+
case 'wait':
|
|
393
|
+
if (typeof args.frames !== 'number')
|
|
394
|
+
throw new Error('wait requires `frames`');
|
|
395
|
+
return { command: wait(args.frames, indent) };
|
|
396
|
+
case 'exit_event':
|
|
397
|
+
return { command: exitEvent(indent) };
|
|
398
|
+
case 'label':
|
|
399
|
+
if (typeof args.name !== 'string')
|
|
400
|
+
throw new Error('label requires `name`');
|
|
401
|
+
return { command: label(args.name, indent) };
|
|
402
|
+
case 'jump_to_label':
|
|
403
|
+
if (typeof args.name !== 'string')
|
|
404
|
+
throw new Error('jump_to_label requires `name`');
|
|
405
|
+
return { command: jumpToLabel(args.name, indent) };
|
|
406
|
+
default:
|
|
407
|
+
throw new Error(`Unknown flow command kind: ${args.kind}`);
|
|
408
|
+
}
|
|
409
|
+
},
|
|
410
|
+
},
|
|
411
|
+
{
|
|
412
|
+
name: 'build_control_switch',
|
|
413
|
+
description: 'Build a Control Switches (121) or Control Self Switch (123) event command for insertion via insert_event_commands. scope "switch": set a switch (or the inclusive switchId..endId range) on/off. scope "self_switch": set the current event\'s self switch A–D. Read-only: returns { command }.',
|
|
414
|
+
inputSchema: {
|
|
415
|
+
scope: z
|
|
416
|
+
.enum(['switch', 'self_switch'])
|
|
417
|
+
.describe('"switch" (global, by id/range) or "self_switch" (this event, A–D)'),
|
|
418
|
+
switchId: z.number().int().optional().describe('switch: the switch id (range start)'),
|
|
419
|
+
endId: z
|
|
420
|
+
.number()
|
|
421
|
+
.int()
|
|
422
|
+
.optional()
|
|
423
|
+
.describe('switch: inclusive range end (default = switchId, a single switch)'),
|
|
424
|
+
name: z.enum(['A', 'B', 'C', 'D']).optional().describe('self_switch: which self switch'),
|
|
425
|
+
value: z.enum(['on', 'off']).optional().describe('Set on (default) or off'),
|
|
426
|
+
indent: z.number().int().optional().describe('Indentation level (default 0)'),
|
|
427
|
+
},
|
|
428
|
+
handler: async (_ctx, args) => {
|
|
429
|
+
const indent = args.indent ?? 0;
|
|
430
|
+
const value = args.value;
|
|
431
|
+
if (args.scope === 'self_switch') {
|
|
432
|
+
if (typeof args.name !== 'string')
|
|
433
|
+
throw new Error('self_switch requires `name` (A–D)');
|
|
434
|
+
return { command: controlSelfSwitch(args.name, value, indent) };
|
|
435
|
+
}
|
|
436
|
+
if (typeof args.switchId !== 'number')
|
|
437
|
+
throw new Error('switch scope requires `switchId`');
|
|
438
|
+
return {
|
|
439
|
+
command: controlSwitches(args.switchId, args.endId ?? args.switchId, value, indent),
|
|
440
|
+
};
|
|
441
|
+
},
|
|
442
|
+
},
|
|
443
|
+
{
|
|
444
|
+
name: 'build_control_variable',
|
|
445
|
+
description: 'Build a Control Variables (122) event command for insertion via insert_event_commands. Applies operation (set/add/sub/mul/div/mod) to a variable (or the inclusive variableId..endId range) using an operand: constant, another variable, a random range, or game_data (item/actor/party/… readouts). Read-only: returns { command }.',
|
|
446
|
+
inputSchema: {
|
|
447
|
+
variableId: z.number().int().describe('The target variable id (range start)'),
|
|
448
|
+
endId: z
|
|
449
|
+
.number()
|
|
450
|
+
.int()
|
|
451
|
+
.optional()
|
|
452
|
+
.describe('Inclusive range end (default = variableId, a single variable)'),
|
|
453
|
+
operation: z
|
|
454
|
+
.enum(['set', 'add', 'sub', 'mul', 'div', 'mod'])
|
|
455
|
+
.optional()
|
|
456
|
+
.describe('Arithmetic applied to the target (default set)'),
|
|
457
|
+
operand: variableOperandShape,
|
|
458
|
+
indent: z.number().int().optional().describe('Indentation level (default 0)'),
|
|
459
|
+
},
|
|
460
|
+
handler: async (_ctx, args) => {
|
|
461
|
+
const operand = toVariableOperand(args.operand);
|
|
462
|
+
return {
|
|
463
|
+
command: controlVariables(args.variableId, (args.operation ?? 'set'), operand, { endId: args.endId, indent: args.indent }),
|
|
464
|
+
};
|
|
465
|
+
},
|
|
466
|
+
},
|
|
467
|
+
{
|
|
468
|
+
name: 'build_change_gold',
|
|
469
|
+
description: 'Build a Change Gold (125) event command for insertion via insert_event_commands — increase or decrease party gold by a constant or variable amount. Read-only: returns { command }.',
|
|
470
|
+
inputSchema: {
|
|
471
|
+
operation: z.enum(['increase', 'decrease']).describe('Gain or lose gold'),
|
|
472
|
+
operand: gainOperandShape,
|
|
473
|
+
indent: z.number().int().optional().describe('Indentation level (default 0)'),
|
|
474
|
+
},
|
|
475
|
+
handler: async (_ctx, args) => {
|
|
476
|
+
const operand = toGainOperand(args.operand);
|
|
477
|
+
return { command: changeGold(args.operation, operand, args.indent ?? 0) };
|
|
478
|
+
},
|
|
479
|
+
},
|
|
480
|
+
{
|
|
481
|
+
name: 'build_change_items',
|
|
482
|
+
description: 'Build a Change Items (126), Change Weapons (127), or Change Armors (128) event command for insertion via insert_event_commands — gain/lose an item/weapon/armor by a constant or variable amount. includeEquip (weapon/armor only) also counts equipped copies when removing. Read-only: returns { command }.',
|
|
483
|
+
inputSchema: {
|
|
484
|
+
kind: z.enum(['item', 'weapon', 'armor']).describe('Which inventory to change'),
|
|
485
|
+
id: z.number().int().describe('The item/weapon/armor id'),
|
|
486
|
+
operation: z.enum(['increase', 'decrease']).describe('Gain or lose'),
|
|
487
|
+
operand: gainOperandShape,
|
|
488
|
+
includeEquip: z
|
|
489
|
+
.boolean()
|
|
490
|
+
.optional()
|
|
491
|
+
.describe('weapon/armor: also count equipped copies (default false)'),
|
|
492
|
+
indent: z.number().int().optional().describe('Indentation level (default 0)'),
|
|
493
|
+
},
|
|
494
|
+
handler: async (_ctx, args) => {
|
|
495
|
+
const operand = toGainOperand(args.operand);
|
|
496
|
+
const operation = args.operation;
|
|
497
|
+
const id = args.id;
|
|
498
|
+
const indent = args.indent ?? 0;
|
|
499
|
+
const includeEquip = args.includeEquip ?? false;
|
|
500
|
+
switch (args.kind) {
|
|
501
|
+
case 'weapon':
|
|
502
|
+
return { command: changeWeapons(id, operation, operand, includeEquip, indent) };
|
|
503
|
+
case 'armor':
|
|
504
|
+
return { command: changeArmors(id, operation, operand, includeEquip, indent) };
|
|
505
|
+
default:
|
|
506
|
+
return { command: changeItems(id, operation, operand, indent) };
|
|
507
|
+
}
|
|
508
|
+
},
|
|
509
|
+
},
|
|
510
|
+
{
|
|
511
|
+
name: 'build_change_party_member',
|
|
512
|
+
description: 'Build a Change Party Member (129) event command for insertion via insert_event_commands — add or remove an actor from the party. initialize (add only) resets the actor to their initial state. Read-only: returns { command }.',
|
|
513
|
+
inputSchema: {
|
|
514
|
+
actorId: z.number().int().describe('The actor id'),
|
|
515
|
+
operation: z.enum(['add', 'remove']).describe('Add to or remove from the party'),
|
|
516
|
+
initialize: z
|
|
517
|
+
.boolean()
|
|
518
|
+
.optional()
|
|
519
|
+
.describe('add only: reset the actor to their initial state (default false)'),
|
|
520
|
+
indent: z.number().int().optional().describe('Indentation level (default 0)'),
|
|
521
|
+
},
|
|
522
|
+
handler: async (_ctx, args) => {
|
|
523
|
+
return {
|
|
524
|
+
command: changePartyMember(args.actorId, args.operation, args.initialize ?? false, args.indent ?? 0),
|
|
525
|
+
};
|
|
526
|
+
},
|
|
527
|
+
},
|
|
528
|
+
{
|
|
529
|
+
name: 'build_transfer_player',
|
|
530
|
+
description: 'Build a Transfer Player (201) event command for insertion via insert_event_commands — move the party to (x, y) on a map. With designation "variable", mapId/x/y are variable ids resolved at runtime. Read-only: returns { command }.',
|
|
531
|
+
inputSchema: {
|
|
532
|
+
mapId: z
|
|
533
|
+
.number()
|
|
534
|
+
.int()
|
|
535
|
+
.describe('Destination map id (or a variable id if designation=variable)'),
|
|
536
|
+
x: z.number().int().describe('Destination tile x (or a variable id)'),
|
|
537
|
+
y: z.number().int().describe('Destination tile y (or a variable id)'),
|
|
538
|
+
direction: z
|
|
539
|
+
.enum(['retain', 'down', 'left', 'right', 'up'])
|
|
540
|
+
.optional()
|
|
541
|
+
.describe('Facing after transfer (default retain)'),
|
|
542
|
+
fade: z.enum(['black', 'white', 'none']).optional().describe('Fade style (default black)'),
|
|
543
|
+
designation: z
|
|
544
|
+
.enum(['direct', 'variable'])
|
|
545
|
+
.optional()
|
|
546
|
+
.describe('direct: mapId/x/y are literal; variable: they are variable ids (default direct)'),
|
|
547
|
+
indent: z.number().int().optional().describe('Indentation level (default 0)'),
|
|
548
|
+
},
|
|
549
|
+
handler: async (_ctx, args) => {
|
|
550
|
+
const options = {
|
|
551
|
+
direction: args.direction,
|
|
552
|
+
fade: args.fade,
|
|
553
|
+
designation: args.designation,
|
|
554
|
+
indent: args.indent,
|
|
555
|
+
};
|
|
556
|
+
return {
|
|
557
|
+
command: transferPlayer(args.mapId, args.x, args.y, options),
|
|
558
|
+
};
|
|
559
|
+
},
|
|
560
|
+
},
|
|
561
|
+
{
|
|
562
|
+
name: 'build_play_audio',
|
|
563
|
+
description: 'Build a Play BGM/BGS/ME/SE (241/245/249/250) event command for insertion via insert_event_commands. Warns (never blocks) when `name` is not a known audio asset for that channel (checked against list_assets). Returns { command, warnings? }.',
|
|
564
|
+
inputSchema: {
|
|
565
|
+
kind: z.enum(['bgm', 'bgs', 'me', 'se']).describe('Which audio channel to play on'),
|
|
566
|
+
name: z.string().describe('Audio basename (from list_assets, extension stripped)'),
|
|
567
|
+
volume: z.number().optional().describe('Volume 0–100 (default 90)'),
|
|
568
|
+
pitch: z.number().optional().describe('Pitch 50–150 (default 100)'),
|
|
569
|
+
pan: z.number().optional().describe('Pan -100–100 (default 0)'),
|
|
570
|
+
indent: z.number().int().optional().describe('Indentation level (default 0)'),
|
|
571
|
+
},
|
|
572
|
+
handler: async (ctx, args) => {
|
|
573
|
+
const kind = args.kind;
|
|
574
|
+
const track = {
|
|
575
|
+
name: args.name,
|
|
576
|
+
volume: args.volume,
|
|
577
|
+
pitch: args.pitch,
|
|
578
|
+
pan: args.pan,
|
|
579
|
+
};
|
|
580
|
+
const command = playAudio(kind, track, args.indent ?? 0);
|
|
581
|
+
const warnings = await audioNameWarnings(ctx.projectPath, kind, track.name);
|
|
582
|
+
return warnings.length > 0 ? { command, warnings } : { command };
|
|
583
|
+
},
|
|
584
|
+
},
|
|
585
|
+
{
|
|
586
|
+
name: 'build_screen_effect',
|
|
587
|
+
description: 'Build a screen transition/effect event command for insertion via insert_event_commands: fadeout (221) / fadein (222) — no params; tint (223) & flash (224) — an [r,g,b,a] color over `duration` frames; shake (225) — power/speed over `duration`. `wait` holds the event until it finishes. Read-only: returns { command }.',
|
|
588
|
+
inputSchema: {
|
|
589
|
+
kind: z
|
|
590
|
+
.enum(['fadeout', 'fadein', 'tint', 'flash', 'shake'])
|
|
591
|
+
.describe('Which screen effect to build'),
|
|
592
|
+
color: z
|
|
593
|
+
.array(z.number())
|
|
594
|
+
.length(4)
|
|
595
|
+
.optional()
|
|
596
|
+
.describe('tint: [red,green,blue,gray] (−255…255); flash: [red,green,blue,intensity] (0…255)'),
|
|
597
|
+
power: z.number().optional().describe('shake: strength 1–9 (default 5)'),
|
|
598
|
+
speed: z.number().optional().describe('shake: speed 1–9 (default 5)'),
|
|
599
|
+
duration: z.number().optional().describe('tint/flash/shake: frames (default 60)'),
|
|
600
|
+
wait: z
|
|
601
|
+
.boolean()
|
|
602
|
+
.optional()
|
|
603
|
+
.describe('tint/flash/shake: hold the event until it finishes (default true)'),
|
|
604
|
+
indent: z.number().int().optional().describe('Indentation level (default 0)'),
|
|
605
|
+
},
|
|
606
|
+
handler: async (_ctx, args) => {
|
|
607
|
+
const indent = args.indent ?? 0;
|
|
608
|
+
const duration = args.duration ?? 60;
|
|
609
|
+
const wait = args.wait ?? true;
|
|
610
|
+
switch (args.kind) {
|
|
611
|
+
case 'fadeout':
|
|
612
|
+
return { command: fadeScreen('out', indent) };
|
|
613
|
+
case 'fadein':
|
|
614
|
+
return { command: fadeScreen('in', indent) };
|
|
615
|
+
case 'tint':
|
|
616
|
+
return { command: tintScreen(toColorTone(args.color), duration, wait, indent) };
|
|
617
|
+
case 'flash':
|
|
618
|
+
return { command: flashScreen(toColorTone(args.color), duration, wait, indent) };
|
|
619
|
+
case 'shake':
|
|
620
|
+
return {
|
|
621
|
+
command: shakeScreen(args.power ?? 5, args.speed ?? 5, duration, wait, indent),
|
|
622
|
+
};
|
|
623
|
+
default:
|
|
624
|
+
throw new Error(`Unknown screen effect kind: ${args.kind}`);
|
|
625
|
+
}
|
|
626
|
+
},
|
|
627
|
+
},
|
|
628
|
+
{
|
|
629
|
+
name: 'build_picture',
|
|
630
|
+
description: 'Build a Show Picture (231) or Erase Picture (235) event command for insertion via insert_event_commands. show: display `name` in slot `pictureId` with origin/position/scale/opacity/blend; erase: clear the slot. Read-only: returns { command }.',
|
|
631
|
+
inputSchema: {
|
|
632
|
+
kind: z.enum(['show', 'erase']).describe('Show a picture or erase a slot'),
|
|
633
|
+
pictureId: z.number().int().describe('Picture slot 1–100'),
|
|
634
|
+
name: z.string().optional().describe('show: picture basename (from list_assets("pictures"))'),
|
|
635
|
+
origin: z
|
|
636
|
+
.enum(['upper_left', 'center'])
|
|
637
|
+
.optional()
|
|
638
|
+
.describe('show: anchor point (default upper_left)'),
|
|
639
|
+
x: z.number().optional().describe('show: screen x in pixels (default 0)'),
|
|
640
|
+
y: z.number().optional().describe('show: screen y in pixels (default 0)'),
|
|
641
|
+
scaleX: z.number().optional().describe('show: horizontal scale % (default 100)'),
|
|
642
|
+
scaleY: z.number().optional().describe('show: vertical scale % (default 100)'),
|
|
643
|
+
opacity: z.number().optional().describe('show: opacity 0–255 (default 255)'),
|
|
644
|
+
blend: z
|
|
645
|
+
.enum(['normal', 'additive', 'multiply', 'screen'])
|
|
646
|
+
.optional()
|
|
647
|
+
.describe('show: blend mode (default normal)'),
|
|
648
|
+
indent: z.number().int().optional().describe('Indentation level (default 0)'),
|
|
649
|
+
},
|
|
650
|
+
handler: async (_ctx, args) => {
|
|
651
|
+
const indent = args.indent ?? 0;
|
|
652
|
+
const pictureId = args.pictureId;
|
|
653
|
+
if (args.kind === 'erase') {
|
|
654
|
+
return { command: erasePicture(pictureId, indent) };
|
|
655
|
+
}
|
|
656
|
+
if (typeof args.name !== 'string')
|
|
657
|
+
throw new Error('show requires `name`');
|
|
658
|
+
const options = {
|
|
659
|
+
origin: args.origin,
|
|
660
|
+
x: args.x,
|
|
661
|
+
y: args.y,
|
|
662
|
+
scaleX: args.scaleX,
|
|
663
|
+
scaleY: args.scaleY,
|
|
664
|
+
opacity: args.opacity,
|
|
665
|
+
blend: args.blend,
|
|
666
|
+
indent,
|
|
667
|
+
};
|
|
668
|
+
return { command: showPicture(pictureId, args.name, options) };
|
|
669
|
+
},
|
|
670
|
+
},
|
|
671
|
+
{
|
|
672
|
+
name: 'build_character_effect',
|
|
673
|
+
description: 'Build a Show Animation (212) or Show Balloon Icon (213) event command for insertion via insert_event_commands, played over a character (characterId: -1 player, 0 this event, N event id). Read-only: returns { command }.',
|
|
674
|
+
inputSchema: {
|
|
675
|
+
kind: z.enum(['animation', 'balloon']).describe('Play an animation or a balloon icon'),
|
|
676
|
+
characterId: z
|
|
677
|
+
.number()
|
|
678
|
+
.int()
|
|
679
|
+
.describe('Target character: -1 player, 0 this event, N event id on the current map'),
|
|
680
|
+
id: z
|
|
681
|
+
.number()
|
|
682
|
+
.int()
|
|
683
|
+
.describe('animation: the animation id; balloon: the balloon id (1 exclamation, 2 question, …)'),
|
|
684
|
+
wait: z.boolean().optional().describe('Hold the event until it finishes (default false)'),
|
|
685
|
+
indent: z.number().int().optional().describe('Indentation level (default 0)'),
|
|
686
|
+
},
|
|
687
|
+
handler: async (_ctx, args) => {
|
|
688
|
+
const characterId = args.characterId;
|
|
689
|
+
const id = args.id;
|
|
690
|
+
const wait = args.wait ?? false;
|
|
691
|
+
const indent = args.indent ?? 0;
|
|
692
|
+
return {
|
|
693
|
+
command: args.kind === 'balloon'
|
|
694
|
+
? showBalloon(characterId, id, wait, indent)
|
|
695
|
+
: showAnimation(characterId, id, wait, indent),
|
|
696
|
+
};
|
|
697
|
+
},
|
|
698
|
+
},
|
|
699
|
+
{
|
|
700
|
+
name: 'build_battle_processing',
|
|
701
|
+
description: 'Build a Battle Processing (301) event command for insertion via insert_event_commands — start a battle against a troop (direct id, a variable holding the id, or "random" like the map encounters). canEscape/canLose gate the battle result branches. Read-only: returns { command }.',
|
|
702
|
+
inputSchema: {
|
|
703
|
+
troop: z
|
|
704
|
+
.enum(['direct', 'variable', 'random'])
|
|
705
|
+
.describe('How the troop is chosen (default direct)')
|
|
706
|
+
.optional(),
|
|
707
|
+
troopId: z
|
|
708
|
+
.number()
|
|
709
|
+
.int()
|
|
710
|
+
.optional()
|
|
711
|
+
.describe('direct: the troop id; variable: the variable id holding it'),
|
|
712
|
+
canEscape: z.boolean().optional().describe('Allow the party to escape (default false)'),
|
|
713
|
+
canLose: z
|
|
714
|
+
.boolean()
|
|
715
|
+
.optional()
|
|
716
|
+
.describe('Continue the event if the party loses (default false)'),
|
|
717
|
+
indent: z.number().int().optional().describe('Indentation level (default 0)'),
|
|
718
|
+
},
|
|
719
|
+
handler: async (_ctx, args) => {
|
|
720
|
+
const mode = args.troop ?? 'direct';
|
|
721
|
+
let troop;
|
|
722
|
+
if (mode === 'random') {
|
|
723
|
+
troop = { type: 'random' };
|
|
724
|
+
}
|
|
725
|
+
else if (mode === 'variable') {
|
|
726
|
+
if (typeof args.troopId !== 'number')
|
|
727
|
+
throw new Error('variable troop requires `troopId` (a variable id)');
|
|
728
|
+
troop = { type: 'variable', variableId: args.troopId };
|
|
729
|
+
}
|
|
730
|
+
else {
|
|
731
|
+
if (typeof args.troopId !== 'number')
|
|
732
|
+
throw new Error('direct troop requires `troopId`');
|
|
733
|
+
troop = { type: 'direct', troopId: args.troopId };
|
|
734
|
+
}
|
|
735
|
+
return {
|
|
736
|
+
command: battleProcessing(troop, args.canEscape ?? false, args.canLose ?? false, args.indent ?? 0),
|
|
737
|
+
};
|
|
738
|
+
},
|
|
739
|
+
},
|
|
740
|
+
{
|
|
741
|
+
name: 'build_shop_processing',
|
|
742
|
+
description: 'Build a Shop Processing (302 + one 605 row per extra good) event-command sequence for insertion via insert_event_commands. Each good sells an item/weapon/armor at its database price, or a specified `price`. purchaseOnly hides the sell tab. Read-only: returns { commands }.',
|
|
743
|
+
inputSchema: {
|
|
744
|
+
goods: z
|
|
745
|
+
.array(z.object({
|
|
746
|
+
kind: z.enum(['item', 'weapon', 'armor']).describe('What is for sale'),
|
|
747
|
+
id: z.number().int().describe('The item/weapon/armor id'),
|
|
748
|
+
price: z
|
|
749
|
+
.number()
|
|
750
|
+
.int()
|
|
751
|
+
.optional()
|
|
752
|
+
.describe('Override price (omitted = the database standard price)'),
|
|
753
|
+
}))
|
|
754
|
+
.describe('The goods offered (at least one)'),
|
|
755
|
+
purchaseOnly: z.boolean().optional().describe('Hide the sell tab (default false)'),
|
|
756
|
+
indent: z.number().int().optional().describe('Indentation level (default 0)'),
|
|
757
|
+
},
|
|
758
|
+
handler: async (_ctx, args) => {
|
|
759
|
+
const goods = args.goods.map((g) => ({
|
|
760
|
+
kind: g.kind,
|
|
761
|
+
id: g.id,
|
|
762
|
+
price: g.price,
|
|
763
|
+
}));
|
|
764
|
+
return {
|
|
765
|
+
commands: shopProcessing(goods, args.purchaseOnly ?? false, args.indent ?? 0),
|
|
766
|
+
};
|
|
767
|
+
},
|
|
768
|
+
},
|
|
769
|
+
{
|
|
770
|
+
name: 'build_name_input',
|
|
771
|
+
description: 'Build a Name Input Processing (303) event command for insertion via insert_event_commands — open the name-entry screen for an actor. Read-only: returns { command }.',
|
|
772
|
+
inputSchema: {
|
|
773
|
+
actorId: z.number().int().describe('The actor whose name is entered'),
|
|
774
|
+
maxLength: z.number().int().optional().describe('Max name length (default 8)'),
|
|
775
|
+
indent: z.number().int().optional().describe('Indentation level (default 0)'),
|
|
776
|
+
},
|
|
777
|
+
handler: async (_ctx, args) => {
|
|
778
|
+
return {
|
|
779
|
+
command: nameInput(args.actorId, args.maxLength ?? 8, args.indent ?? 0),
|
|
780
|
+
};
|
|
781
|
+
},
|
|
782
|
+
},
|
|
783
|
+
{
|
|
784
|
+
name: 'build_change_actor',
|
|
785
|
+
description: 'Build an actor stat-change scene command for insertion via insert_event_commands: hp (311), mp (312), state (313), recover_all (314), exp (315), or level (316). Targets a fixed actor (0 = whole party) or a variable. hp/mp/exp/level take an increase/decrease `operand` (constant or variable); state takes add/remove + `stateId`; recover_all takes nothing extra. Read-only: returns { command }.',
|
|
786
|
+
inputSchema: {
|
|
787
|
+
kind: z
|
|
788
|
+
.enum(['hp', 'mp', 'state', 'recover_all', 'exp', 'level'])
|
|
789
|
+
.describe('Which actor change to build'),
|
|
790
|
+
target: actorTargetShape,
|
|
791
|
+
operation: z
|
|
792
|
+
.enum(['increase', 'decrease'])
|
|
793
|
+
.optional()
|
|
794
|
+
.describe('hp/mp/exp/level: gain or lose (default increase)'),
|
|
795
|
+
operand: gainOperandShape
|
|
796
|
+
.optional()
|
|
797
|
+
.describe('hp/mp/exp/level: the amount (constant/variable)'),
|
|
798
|
+
allowKnockout: z
|
|
799
|
+
.boolean()
|
|
800
|
+
.optional()
|
|
801
|
+
.describe('hp: allow the change to reduce HP to 0/death (default false)'),
|
|
802
|
+
showLevelUp: z
|
|
803
|
+
.boolean()
|
|
804
|
+
.optional()
|
|
805
|
+
.describe('exp/level: show the level-up message (default false)'),
|
|
806
|
+
stateOperation: z
|
|
807
|
+
.enum(['add', 'remove'])
|
|
808
|
+
.optional()
|
|
809
|
+
.describe('state: add or remove the state'),
|
|
810
|
+
stateId: z.number().int().optional().describe('state: the state id'),
|
|
811
|
+
indent: z.number().int().optional().describe('Indentation level (default 0)'),
|
|
812
|
+
},
|
|
813
|
+
handler: async (_ctx, args) => {
|
|
814
|
+
const target = toActorTarget(args.target);
|
|
815
|
+
const indent = args.indent ?? 0;
|
|
816
|
+
if (args.kind === 'recover_all') {
|
|
817
|
+
return { command: recoverAll(target, indent) };
|
|
818
|
+
}
|
|
819
|
+
if (args.kind === 'state') {
|
|
820
|
+
if (typeof args.stateId !== 'number')
|
|
821
|
+
throw new Error('state change requires `stateId`');
|
|
822
|
+
return {
|
|
823
|
+
command: changeState(target, args.stateOperation ?? 'add', args.stateId, indent),
|
|
824
|
+
};
|
|
825
|
+
}
|
|
826
|
+
const operation = args.operation ?? 'increase';
|
|
827
|
+
const operand = toGainOperand(args.operand ?? {});
|
|
828
|
+
switch (args.kind) {
|
|
829
|
+
case 'mp':
|
|
830
|
+
return { command: changeMp(target, operation, operand, indent) };
|
|
831
|
+
case 'exp':
|
|
832
|
+
return {
|
|
833
|
+
command: changeExp(target, operation, operand, args.showLevelUp ?? false, indent),
|
|
834
|
+
};
|
|
835
|
+
case 'level':
|
|
836
|
+
return {
|
|
837
|
+
command: changeLevel(target, operation, operand, args.showLevelUp ?? false, indent),
|
|
838
|
+
};
|
|
839
|
+
default:
|
|
840
|
+
return {
|
|
841
|
+
command: changeHp(target, operation, operand, args.allowKnockout ?? false, indent),
|
|
842
|
+
};
|
|
843
|
+
}
|
|
844
|
+
},
|
|
845
|
+
},
|
|
846
|
+
{
|
|
847
|
+
name: 'insert_event_commands',
|
|
848
|
+
mutates: true,
|
|
849
|
+
forceable: true,
|
|
850
|
+
description: 'Insert a pre-built sequence of event commands (from the build_* builders) into any of the three command lists an MZ project has — the mutating companion to the read-only builders. Splices before the list’s end marker (or at `position`). target "map_event" (the default) needs mapId + eventId + pageIndex; "common_event" needs commonEventId; "troop_page" needs troopId + pageIndex. The resulting list is validated before writing: a structural problem (wrong parameter count for a command code, a list left unterminated) refuses the write and saves nothing — pass force: true to override. Advisory findings (unrecognized code, over-long text line) are returned as `warnings` and never block. Returns { target, id, list, warnings? }.',
|
|
851
|
+
inputSchema: {
|
|
852
|
+
target: z
|
|
853
|
+
.enum(['map_event', 'common_event', 'troop_page'])
|
|
854
|
+
.optional()
|
|
855
|
+
.describe('Which command list to insert into (default map_event)'),
|
|
856
|
+
mapId: z.number().int().positive().optional().describe('target "map_event": the map id'),
|
|
857
|
+
eventId: z.number().int().positive().optional().describe('target "map_event": the event id'),
|
|
858
|
+
commonEventId: z
|
|
859
|
+
.number()
|
|
860
|
+
.int()
|
|
861
|
+
.positive()
|
|
862
|
+
.optional()
|
|
863
|
+
.describe('target "common_event": the common event id'),
|
|
864
|
+
troopId: z.number().int().positive().optional().describe('target "troop_page": the troop id'),
|
|
865
|
+
pageIndex: z
|
|
866
|
+
.number()
|
|
867
|
+
.int()
|
|
868
|
+
.min(0)
|
|
869
|
+
.optional()
|
|
870
|
+
.describe('target "map_event"/"troop_page": zero-based page index'),
|
|
871
|
+
commands: z
|
|
872
|
+
.array(eventCommandShape)
|
|
873
|
+
.describe('The event commands to insert (e.g. the `commands` from a build_* tool)'),
|
|
874
|
+
position: z
|
|
875
|
+
.number()
|
|
876
|
+
.int()
|
|
877
|
+
.min(0)
|
|
878
|
+
.optional()
|
|
879
|
+
.describe('Insertion index; defaults to the end of the list'),
|
|
880
|
+
},
|
|
881
|
+
handler: (ctx, args) => insertEventCommands(ctx.projectPath, (args.target ?? 'map_event'), {
|
|
882
|
+
mapId: args.mapId,
|
|
883
|
+
eventId: args.eventId,
|
|
884
|
+
commonEventId: args.commonEventId,
|
|
885
|
+
troopId: args.troopId,
|
|
886
|
+
pageIndex: args.pageIndex,
|
|
887
|
+
commands: asCommands(args.commands),
|
|
888
|
+
position: args.position,
|
|
889
|
+
force: args.force,
|
|
890
|
+
}),
|
|
891
|
+
},
|
|
892
|
+
];
|
|
893
|
+
//# sourceMappingURL=eventCommandTools.js.map
|