@amxts/menu-core 0.1.0 → 0.2.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/PAWN.md +4 -2
- package/PAWN.ru.md +4 -2
- package/README.md +69 -27
- package/README.ru.md +70 -28
- package/package.json +3 -3
- package/prebuilt/linux/menu-core.aot +0 -0
- package/prebuilt/manifest.json +19 -11
- package/prebuilt/windows/menu-core.aot +0 -0
- package/scripts/docs/src/{index.ts → menus.ts} +35 -21
- package/scripts/docs/src/types.ts +102 -52
- package/src/index.ts +3 -1598
- package/src/internal.ts +350 -328
- package/src/menus.ts +1744 -0
- package/src/natives.ts +11 -11
- package/src/types.ts +69 -39
package/src/natives.ts
CHANGED
|
@@ -19,7 +19,7 @@ import * as menus from "./index";
|
|
|
19
19
|
import { addNamedFilter, iniItem, insertItem, stateOf } from "./internal";
|
|
20
20
|
import { MenuShowOptions } from "./types";
|
|
21
21
|
|
|
22
|
-
plugin({ name: "Menu Core", version: "0.
|
|
22
|
+
plugin({ name: "Menu Core", version: "0.2.0", author: "kukson777", description: "Menus from ini files: the mc_* natives" });
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
25
|
* Menu properties: mc_set_menu_property takes MP_LOCKED .. MP_HIDE_EXIT,
|
|
@@ -102,12 +102,11 @@ export function mc_register_action(name: string, callback: string, _isCritical =
|
|
|
102
102
|
const fn = publicOf(callback);
|
|
103
103
|
|
|
104
104
|
if (fn != null) {
|
|
105
|
-
menus.addAction(name, (player,
|
|
106
|
-
const menu = menus.activeMenu(player);
|
|
105
|
+
menus.addAction(name, ({ player, row, menu }) => {
|
|
107
106
|
const call = fn.call().int(player.id);
|
|
108
107
|
// An items menu's action gets the action's name, a list menu's the row's target.
|
|
109
|
-
if (menu
|
|
110
|
-
else call.int(
|
|
108
|
+
if (menu.kind == "items") call.text(name);
|
|
109
|
+
else call.int(row);
|
|
111
110
|
call.run();
|
|
112
111
|
});
|
|
113
112
|
}
|
|
@@ -122,9 +121,9 @@ export function mc_register_action(name: string, callback: string, _isCritical =
|
|
|
122
121
|
*/
|
|
123
122
|
export function mc_register_placeholder(name: string, callback: string) {
|
|
124
123
|
const fn = publicOf(callback);
|
|
125
|
-
return menus.addPlaceholder(name, (player,
|
|
124
|
+
return menus.addPlaceholder(name, ({ player, row }) => {
|
|
126
125
|
if (fn == null) return "";
|
|
127
|
-
const call = fn.call().int(player.id).int(
|
|
126
|
+
const call = fn.call().int(player.id).int(row).buffer(PLACEHOLDER_CELLS).int(PLACEHOLDER_CELLS - 1);
|
|
128
127
|
call.run();
|
|
129
128
|
return colorTags(call.bufferText);
|
|
130
129
|
});
|
|
@@ -147,9 +146,10 @@ export function mc_register_menu(section: string) {
|
|
|
147
146
|
* such menu, a show filter or ACTIVE_ON stopped it.
|
|
148
147
|
*/
|
|
149
148
|
export function mc_show_menu(player: Player, section: string, time = -1, targetId = 0, resetHistory = false, forceOpen = false, ignoreHistory = false) {
|
|
150
|
-
const options: MenuShowOptions = {
|
|
149
|
+
const options: MenuShowOptions = { resetHistory, force: forceOpen, skipHistory: ignoreHistory };
|
|
151
150
|
// -1, Pawn's "not given": the option left out.
|
|
152
151
|
if (time >= 0) options.time = time;
|
|
152
|
+
if (targetId > 0) options.target = new Player(targetId);
|
|
153
153
|
return answer(menus.show(player, section, options));
|
|
154
154
|
}
|
|
155
155
|
|
|
@@ -182,7 +182,7 @@ export function mc_refresh_menu(sections: string) {
|
|
|
182
182
|
*/
|
|
183
183
|
export function mc_register_restriction(name: string, callback: string, message?: string) {
|
|
184
184
|
const fn = publicOf(callback);
|
|
185
|
-
if (fn != null) menus.addRestriction(name, (player, used,
|
|
185
|
+
if (fn != null) menus.addRestriction(name, ({ player, name: used, row }) => fn.call().int(player.id).text(used).int(row).run() != 0, colorTags(message ?? ""));
|
|
186
186
|
return restrictionCount++;
|
|
187
187
|
}
|
|
188
188
|
|
|
@@ -193,7 +193,7 @@ export function mc_register_restriction(name: string, callback: string, message?
|
|
|
193
193
|
*/
|
|
194
194
|
export function mc_register_action_condition(menuSection: string, actionName: string, callback: string) {
|
|
195
195
|
const fn = publicOf(callback);
|
|
196
|
-
if (fn != null) menus.addActionCheck(menuSection, actionName, (player, menu, action) => fn.call().int(player.id).text(menu).text(action).run() != 0);
|
|
196
|
+
if (fn != null) menus.addActionCheck(menuSection, actionName, ({ player, menu, name: action }) => fn.call().int(player.id).text(menu.name).text(action).run() != 0);
|
|
197
197
|
return 1;
|
|
198
198
|
}
|
|
199
199
|
|
|
@@ -220,7 +220,7 @@ export function mc_register_condition_filter(condition: string, callback: string
|
|
|
220
220
|
*/
|
|
221
221
|
export function mc_register_list_data_source(menuName: string, callback: string) {
|
|
222
222
|
const fn = publicOf(callback);
|
|
223
|
-
return menus.setListSource(menuName,
|
|
223
|
+
return menus.setListSource(menuName, ({ player }) => (fn != null ? rowsFrom(fn, player) : null));
|
|
224
224
|
}
|
|
225
225
|
|
|
226
226
|
/** Called when a menu opens. Callback: public callback(id, const section[]). Returns its id. */
|
package/src/types.ts
CHANGED
|
@@ -3,26 +3,50 @@
|
|
|
3
3
|
* register.
|
|
4
4
|
*/
|
|
5
5
|
import { Player } from "@amxts/core";
|
|
6
|
+
import { Menu } from "./menus";
|
|
6
7
|
|
|
7
8
|
/** A menu's kind, one of `"items"` (a list of items) or `"list"` (a row per player, or per row of a list source). */
|
|
8
9
|
export type MenuKind = "items" | "list";
|
|
9
10
|
|
|
11
|
+
/**
|
|
12
|
+
* A menu's context, which its functions get: the player who looks, who or
|
|
13
|
+
* what the menu is about, and the menu.
|
|
14
|
+
*
|
|
15
|
+
* shop.addItem({ title: ({ player }) => `Heal (${player.health} HP)`, onSelect: ({ player }) => heal(player) });
|
|
16
|
+
*/
|
|
17
|
+
export interface MenuContext {
|
|
18
|
+
/** The player the menu is shown to: who looks at it, and who chooses. */
|
|
19
|
+
player: Player;
|
|
20
|
+
/** The player the menu is about: the row's in a list menu, the one `show()` was given as `target` in an items menu; `player` himself when there is none. */
|
|
21
|
+
target: Player;
|
|
22
|
+
/** The row's number in a list menu, as `listRow()` gave it - e.g. an entity or an index of the source's own; a player's `id` in a list of players. In an items menu, the `id` of the menu's target, `0` without one. */
|
|
23
|
+
row: number;
|
|
24
|
+
/** The menu the function is asked for. */
|
|
25
|
+
menu: Menu;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** The context of a function registered by name - an action, a placeholder, a restriction, an action check: the menu's context, and the name it is asked by. */
|
|
29
|
+
export interface NamedContext extends MenuContext {
|
|
30
|
+
/** The name it is asked by: an action's or a placeholder's, a restriction's whole token - `"NAME:param"` included; for an action check, the item's action. */
|
|
31
|
+
name: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
10
34
|
/**
|
|
11
35
|
* Text of a menu - a title, an item, a message: the text itself, or a
|
|
12
|
-
* function that gives it for the
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
36
|
+
* function that gives it for the menu's context. A lang key is translated
|
|
37
|
+
* either way. Colour tags are chat's letters: `!y` yellow, `!r` red, `!d`
|
|
38
|
+
* grey, `!w` white, `!R` to the right edge; chat's own `!g`, `!b` and `!t`
|
|
39
|
+
* are dropped.
|
|
16
40
|
*
|
|
17
|
-
* menus.create("SHOP", { title: (player) => `Shop for ${player.name}` });
|
|
41
|
+
* menus.create("SHOP", { title: ({ player }) => `Shop for ${player.name}` });
|
|
18
42
|
*/
|
|
19
|
-
export type MenuText = string | ((
|
|
43
|
+
export type MenuText = string | ((context: MenuContext) => string);
|
|
20
44
|
|
|
21
45
|
/** A row of a list menu, as a list source gives it - made with `listRow()` or `textRow()`. */
|
|
22
46
|
export interface ListRow {
|
|
23
47
|
/** The row's kind, one of `"item"` (a row to choose) or `"text"` (a line of text, not a choice). */
|
|
24
48
|
kind: "item" | "text";
|
|
25
|
-
/** The row's
|
|
49
|
+
/** The row's number, `row` of the context its item's functions get: e.g. a player's `id`, an entity or an index of the source's own; `0` for a line of text. */
|
|
26
50
|
target: number;
|
|
27
51
|
/** The row's text, put for `%name%` in the menu's row template. */
|
|
28
52
|
text: string;
|
|
@@ -37,10 +61,10 @@ export interface ListRow {
|
|
|
37
61
|
/**
|
|
38
62
|
* The options of a menu made with `create()`. Every field may be left out:
|
|
39
63
|
*
|
|
40
|
-
* menus.create("SHOP", { title: "Shop", time: 30, activeWhen: player => player.isAlive });
|
|
64
|
+
* menus.create("SHOP", { title: "Shop", time: 30, activeWhen: ({ player }) => player.isAlive });
|
|
41
65
|
*/
|
|
42
66
|
export interface MenuOptions {
|
|
43
|
-
/** The menu's title: the text - a lang key too - or a function that gives it for the
|
|
67
|
+
/** The menu's title: the text - a lang key too - or a function that gives it for the menu's context; left out, the menu's name. */
|
|
44
68
|
title?: MenuText;
|
|
45
69
|
/** Seconds on the countdown when the menu opens, e.g. `10`; left out, none. */
|
|
46
70
|
time?: number;
|
|
@@ -50,8 +74,8 @@ export interface MenuOptions {
|
|
|
50
74
|
hideExit?: boolean;
|
|
51
75
|
/** A lock on the menu: while `true`, items cannot be chosen and no other menu replaces this one. */
|
|
52
76
|
locked?: boolean;
|
|
53
|
-
/** A test the menu opens under: while it says no
|
|
54
|
-
activeWhen?: (
|
|
77
|
+
/** A test the menu opens under: while it says no, the menu does not open for the player. */
|
|
78
|
+
activeWhen?: (context: MenuContext) => boolean;
|
|
55
79
|
}
|
|
56
80
|
|
|
57
81
|
/**
|
|
@@ -62,8 +86,8 @@ export interface MenuOptions {
|
|
|
62
86
|
export interface MenuShowOptions {
|
|
63
87
|
/** Seconds on the countdown; left out, the countdown running goes on, or the menu's own starts. */
|
|
64
88
|
time?: number;
|
|
65
|
-
/** The player the menu is about
|
|
66
|
-
target?:
|
|
89
|
+
/** The player the menu is about: `target` of the context its functions get, and `%target%`. */
|
|
90
|
+
target?: Player;
|
|
67
91
|
/** A new way back: `true` forgets the menus this one was opened from. */
|
|
68
92
|
resetHistory?: boolean;
|
|
69
93
|
/** Opening over a menu that holds on - a countdown, a lock: `true` opens anyway. */
|
|
@@ -73,32 +97,38 @@ export interface MenuShowOptions {
|
|
|
73
97
|
}
|
|
74
98
|
|
|
75
99
|
/**
|
|
76
|
-
*
|
|
100
|
+
* An item: its title, when it is shown and can be chosen, and what choosing
|
|
101
|
+
* it does. Every field but `title` may be left out:
|
|
77
102
|
*
|
|
78
|
-
* shop.addItem(
|
|
79
|
-
*
|
|
80
|
-
*
|
|
103
|
+
* shop.addItem({
|
|
104
|
+
* title: ({ player }) => `Heal (${player.health} HP)`,
|
|
105
|
+
* visible: ({ player }) => player.health < 100,
|
|
106
|
+
* onSelect: ({ player }) => {
|
|
107
|
+
* player.health = 100;
|
|
108
|
+
* },
|
|
81
109
|
* });
|
|
82
110
|
*/
|
|
83
111
|
export interface MenuItemOptions {
|
|
84
|
-
/** The
|
|
85
|
-
|
|
112
|
+
/** The item's text - a lang key too - or a function that gives it for the menu's context. */
|
|
113
|
+
title: MenuText;
|
|
114
|
+
/** The function run when the item is chosen; the menu is drawn again after it, while it stays open. */
|
|
115
|
+
onSelect?: (context: MenuContext) => void;
|
|
86
116
|
/** A test the item is shown under: while it says no, the item is left out and takes no slot. */
|
|
87
|
-
visible?: (
|
|
117
|
+
visible?: (context: MenuContext) => boolean;
|
|
88
118
|
/**
|
|
89
119
|
* A test the item can be chosen under - while it says no, the item is
|
|
90
120
|
* greyed out with `message` beside it; or a list of requirements, each with
|
|
91
121
|
* a message of its own - the first that fails gives its message.
|
|
92
122
|
*
|
|
93
123
|
* enabled: [
|
|
94
|
-
* { when: (player) => player.frags >= 5, message: "5 frags needed" },
|
|
95
|
-
* { when: (player) => player.armor < 100, message: (player) => `(${player.armor} already)` },
|
|
124
|
+
* { when: ({ player }) => player.frags >= 5, message: "5 frags needed" },
|
|
125
|
+
* { when: ({ player }) => player.armor < 100, message: ({ player }) => `(${player.armor} already)` },
|
|
96
126
|
* ],
|
|
97
127
|
*/
|
|
98
|
-
enabled?: ((
|
|
99
|
-
/** The text beside the item while `enabled` greys it out, for a requirement without a message of its own: the text, e.g. `"(full)"`, or a function that gives it for the
|
|
128
|
+
enabled?: ((context: MenuContext) => boolean) | Requirement[];
|
|
129
|
+
/** The text beside the item while `enabled` greys it out, for a requirement without a message of its own: the text, e.g. `"(full)"`, or a function that gives it for the menu's context. */
|
|
100
130
|
message?: MenuText;
|
|
101
|
-
/** The text after the item's
|
|
131
|
+
/** The text after the item's title, for items of menu files and Pawn plugins, placeholders and all, e.g. `"%hp%"`; in code the title is a function instead. */
|
|
102
132
|
placeholder?: string;
|
|
103
133
|
/** Action names from `addAction()` run when the item is chosen, or a built-in one: `"SHOW_<MENU>"`, `"CLOSE_MENU"`. */
|
|
104
134
|
action?: string;
|
|
@@ -114,31 +144,31 @@ export interface MenuItemOptions {
|
|
|
114
144
|
* A requirement of an item, in the list `enabled` takes: while `when` says
|
|
115
145
|
* no, the item is greyed out with `message` beside it.
|
|
116
146
|
*
|
|
117
|
-
* { when: (player) => player.frags >= 5, message: "5 frags needed" }
|
|
147
|
+
* { when: ({ player }) => player.frags >= 5, message: "5 frags needed" }
|
|
118
148
|
*/
|
|
119
149
|
export interface Requirement {
|
|
120
|
-
/** A test the requirement holds under
|
|
121
|
-
when: (
|
|
122
|
-
/** The text beside the item while `when` says no: the text, a lang key, or a function that gives it for the
|
|
150
|
+
/** A test the requirement holds under, given the menu's context. */
|
|
151
|
+
when: (context: MenuContext) => boolean;
|
|
152
|
+
/** The text beside the item while `when` says no: the text, a lang key, or a function that gives it for the menu's context; left out, the item's `message`. */
|
|
123
153
|
message?: MenuText;
|
|
124
154
|
}
|
|
125
155
|
|
|
126
156
|
/** A condition's test, as `addCondition()` registers it. In a list menu `player` is the row's player and `viewer` whoever looks. */
|
|
127
157
|
export type ConditionTest = (player: Player, viewer: Player, name: string) => boolean;
|
|
128
|
-
/** An action, as `addAction()` registers it:
|
|
129
|
-
export type ActionHandler = (
|
|
130
|
-
/** A placeholder's value: the text `%name%` stands for. */
|
|
131
|
-
export type PlaceholderValue = (
|
|
158
|
+
/** An action, as `addAction()` registers it: run with the context of the item chosen, and the action's name. */
|
|
159
|
+
export type ActionHandler = (context: NamedContext) => void;
|
|
160
|
+
/** A placeholder's value: the text `%name%` stands for, given the context of the text it is in. */
|
|
161
|
+
export type PlaceholderValue = (context: NamedContext) => string;
|
|
132
162
|
/** A restriction's test, as `addRestriction()` registers it; `name` is the whole token, `"NAME:param"` included. */
|
|
133
|
-
export type RestrictionTest = (
|
|
134
|
-
/** A test of an item's action, as `addActionCheck()` registers it: `false` greys the item out. */
|
|
135
|
-
export type ActionTest = (
|
|
163
|
+
export type RestrictionTest = (context: NamedContext) => boolean;
|
|
164
|
+
/** A test of an item's action, as `addActionCheck()` registers it: `name` is the action, and `false` greys the item out. */
|
|
165
|
+
export type ActionTest = (context: NamedContext) => boolean;
|
|
136
166
|
/** A filter over a condition someone else registered: gets its value and returns the one to use. */
|
|
137
167
|
export type ConditionFilter = (player: Player, viewer: Player, name: string, value: boolean) => boolean;
|
|
138
|
-
/** A test of a row of a list menu, as `addFilter()` takes it: `
|
|
139
|
-
export type RowTest = (
|
|
168
|
+
/** A test of a row of a list menu, as `addFilter()` takes it: `target` is the row's player, `player` whoever looks. */
|
|
169
|
+
export type RowTest = (context: MenuContext) => boolean;
|
|
140
170
|
/** A list source: the rows of a list menu for the player who looks; `null` lists the players instead. */
|
|
141
|
-
export type ListSource = (
|
|
171
|
+
export type ListSource = (context: MenuContext) => ListRow[] | null;
|
|
142
172
|
|
|
143
173
|
/** A menu event's type, one of `"open"` and `"close"` as they happen, or `"show"` before a menu opens, to stop it. */
|
|
144
174
|
export type MenuEventType = "open" | "close" | "show";
|