@amxts/core 0.2.4 → 0.3.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/README.md +5 -5
- package/README.ru.md +5 -5
- package/as/amxts.d.ts +13 -3
- package/as/entities.ts +571 -501
- package/as/events.ts +3323 -557
- package/as/facade.ts +3079 -718
- package/as/fetch.ts +2 -2
- package/as/fs.ts +352 -59
- package/as/hlds.ts +121 -120
- package/as/hooks.ts +10585 -5177
- package/as/lib/check.ts +3 -2
- package/as/natives.ts +856 -1272
- package/as/promise.ts +37 -27
- package/as/vector.ts +94 -14
- package/includes/order.txt +17 -19
- package/node_modules/assemblyscript/std/assembly/index.d.ts +1 -1
- package/package.json +9 -6
- package/runtime/deps/assemblyscript/dist/asc.js +136 -42
- package/runtime/deps/assemblyscript/dist/assemblyscript.js +141 -141
- package/runtime/licenses/README.md +9 -7
- package/runtime/licenses/ReGameDLL-LICENSE +21 -0
- package/runtime/licenses/ReHLDS-LICENSE +21 -0
- package/runtime/licenses/zlib-LICENSE +22 -0
- package/runtime/natives.txt +618 -523
- package/runtime/patches/README.md +87 -1
- package/runtime/patches/assemblyscript-0.28.20-amxts.patch +4838 -416
- package/runtime/patches/wamr-2.4.5-amxts.patch +417 -5
- package/scripts/auto-imports.ts +1 -1
- package/scripts/build-identity.ts +102 -65
- package/scripts/build-wasm.ts +12 -12
- package/scripts/check.ts +4 -1
- package/scripts/client-messages.ts +73 -1
- package/scripts/compile-cache.ts +11 -8
- package/scripts/compile-pool.ts +6 -3
- package/scripts/compile-worker.ts +23 -23
- package/scripts/compile.ts +142 -19
- package/scripts/docs/as/amxts.ts +10 -4
- package/scripts/docs/as/facade.ts +1779 -275
- package/scripts/docs/as/fetch.ts +2 -2
- package/scripts/docs/as/fs.ts +190 -6
- package/scripts/docs/as/vector.ts +81 -0
- package/scripts/docs/entities.ts +12 -0
- package/scripts/docs/events.ts +49 -13
- package/scripts/docs/game.ts +6 -0
- package/scripts/docs/messages.ts +10 -1
- package/scripts/hlds-events.ts +11 -11
- package/scripts/includes.ts +3 -4
- package/scripts/leaf-natives.ts +84 -0
- package/scripts/player-fields.ts +1 -1
- package/scripts/plugin-natives.ts +1 -1
- package/scripts/prebuilt.ts +41 -10
- package/scripts/project.ts +2 -3
- package/scripts/reapi-events.ts +9 -9
- package/scripts/server-env.ts +145 -0
- package/scripts/shared-modules.ts +23 -7
- package/scripts/system.ts +1 -1
- package/scripts/tracked-fs.ts +11 -2
- package/scripts/typed-commands.ts +153 -15
- package/scripts/upgrade-calls.ts +225 -0
- package/scripts/upgrade-names.ts +1 -4
- package/scripts/upgrade.ts +26 -11
- package/src/cli-api.mjs +3 -2
- package/src/system.mjs +21 -11
- package/src/testing/compile.ts +31 -8
- package/src/testing/coroutines.ts +0 -10
- package/src/testing/memory.ts +89 -2
- package/src/testing/natives.ts +67 -30
- package/src/testing/server.ts +1094 -155
- package/src/testing/tables.ts +23 -6
- package/src/typecheck.mjs +110 -0
- package/runtime/licenses/Bun-LICENSE.md +0 -84
package/as/hlds.ts
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
// The game events and game rules fields of ReGameDLL's and ReHLDS's own,
|
|
2
|
-
// which
|
|
3
|
-
// the stock
|
|
4
|
-
//
|
|
5
|
-
//
|
|
2
|
+
// which their hookchains alone deliver, on a server without them - plain
|
|
3
|
+
// HLDS - through the stock hooks, each the module's own: the game's log and
|
|
4
|
+
// messages, Ham Sandwich's functions (in a vtable), the engine's and the
|
|
5
|
+
// game's functions fakemeta hooks, cstrike's buying, a client's commands.
|
|
6
|
+
// scripts/hlds-events.ts says, for each, what plain HLDS gives and what it
|
|
7
|
+
// does not.
|
|
6
8
|
//
|
|
7
9
|
// `<event>Hlds(fire, hook)` is registered once, on the event's first listener,
|
|
8
|
-
// when the server has
|
|
10
|
+
// when the server has not the chain's API (as/hooks.ts), and everything it registers is
|
|
9
11
|
// switched by `hook`: off while the event has no listener, so that what it
|
|
10
12
|
// hears does not reach the plugin for nothing. It makes the event with the fields
|
|
11
13
|
// the stock hook knows - by the argument's place in reapi's hookchain, as the
|
|
@@ -15,8 +17,9 @@
|
|
|
15
17
|
// answer, a field written - reaches it where the stock hook can take it, and
|
|
16
18
|
// is one line in the console where it cannot (`settle`).
|
|
17
19
|
import {
|
|
18
|
-
Call, CellBuffer, Player, TouchEvent, game, server, handled, arg, argText, cellFloat, floatCell,
|
|
19
|
-
__Switch, __ham,
|
|
20
|
+
Call, CellBuffer, MessageArgs, Player, TouchEvent, game, server, handled, arg, argText, cellFloat, floatCell,
|
|
21
|
+
__Listeners, __Switch, __chainSet, __chainSetText, __ham, __logHook, __messageHook, __playerOf, __off, __onCell, __outcome,
|
|
22
|
+
__sayOnce, __stockHook, __whenUp
|
|
20
23
|
} from "./facade";
|
|
21
24
|
import { Entity } from "./entities";
|
|
22
25
|
import {
|
|
@@ -31,18 +34,15 @@ import {
|
|
|
31
34
|
ThrowFlashbangEvent, ThrowGrenadeEvent, ThrowHeGrenadeEvent, ThrowSmokeGrenadeEvent
|
|
32
35
|
} from "./hooks";
|
|
33
36
|
import {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
get_user_userid, is_user_alive, is_user_connected, pev_valid, read_argv, read_logargv, read_logdata, register_clcmd, register_forward,
|
|
37
|
+
NATIVE_dllfunc, NATIVE_engfunc, cs_get_user_money, find_ent_by_model, get_cvar_float, get_ent_data,
|
|
38
|
+
get_gametime, get_maxplayers, get_timeleft, get_user_info, get_user_msgid, get_user_name,
|
|
39
|
+
get_user_userid, is_user_alive, is_user_connected, pev_valid, read_argv, read_logargv,
|
|
38
40
|
set_cvar_float,
|
|
39
41
|
} from "./natives";
|
|
40
42
|
import {
|
|
41
43
|
CSI_DEFUSER, CSI_FLASHBANG, CSI_HEGRENADE, CSI_LAST_WEAPON, CSI_NVGS, CSI_PRIAMMO, CSI_SECAMMO, CSI_SHIELD,
|
|
42
44
|
CSI_SHIELDGUN, CSI_SMOKEGRENADE, CSI_VEST, CSI_VESTHELM, DLLFunc_GetGameDescription, EngFunc_PrecacheEvent,
|
|
43
|
-
|
|
44
|
-
FM_GetGameDescription, FM_PrecacheGeneric, FM_PrecacheModel, FM_PrecacheSound, FM_SetModel,
|
|
45
|
-
FM_Voice_SetClientListening, Ham_AddPlayerItem, Ham_CS_Player_Blind, Ham_Killed, Ham_Spawn,
|
|
45
|
+
Ham_AddPlayerItem, Ham_CS_Player_Blind, Ham_Killed, Ham_Spawn, MSG_ONE, MSG_ONE_UNRELIABLE, SVC_INTERMISSION,
|
|
46
46
|
ITEM_ASSAULT, ITEM_DEFUSEKIT, ITEM_KEVLAR, ITEM_NVG, ITEM_SHIELDGUN, ITEM_TYPE_BUYING,
|
|
47
47
|
ROUND_ALL_HOSTAGES_RESCUED, ROUND_BOMB_DEFUSED, ROUND_CTS_PREVENT_ESCAPE, ROUND_CTS_WIN, ROUND_END_DRAW,
|
|
48
48
|
ROUND_ESCAPING_TERRORISTS_NEUTRALIZED, ROUND_GAME_COMMENCE, ROUND_HOSTAGE_NOT_RESCUED, ROUND_NONE,
|
|
@@ -52,7 +52,7 @@ import {
|
|
|
52
52
|
} from "./constants";
|
|
53
53
|
import {
|
|
54
54
|
TextMsgMessage, SendAudioMessage, MoneyMessage, DeathMsgMessage, VGUIMenuMessage, CS_OnBuyEvent, CS_OnBuyAttemptEvent,
|
|
55
|
-
ClientConnectEvent, ClientDisconnectedEvent, ClientInfochangedEvent, ClientPutinserverEvent, ServerChangelevelEvent,
|
|
55
|
+
ClientCommandEvent, ClientConnectEvent, ClientDisconnectedEvent, ClientInfochangedEvent, ClientPutinserverEvent, ServerChangelevelEvent,
|
|
56
56
|
ServerFrameEvent, ServerMessageMap, addServerListener, removeServerListener
|
|
57
57
|
} from "./events";
|
|
58
58
|
|
|
@@ -109,7 +109,7 @@ function onMessage<K extends keyof ServerMessageMap>(name: K, listener: (event:
|
|
|
109
109
|
* for, and the hook is switched off while none is.
|
|
110
110
|
*/
|
|
111
111
|
class Hearers<H> {
|
|
112
|
-
list: H
|
|
112
|
+
list: __Listeners<H> = new __Listeners<H>();
|
|
113
113
|
private hook: __Switch = new __Switch();
|
|
114
114
|
private hooked: bool = false;
|
|
115
115
|
|
|
@@ -122,8 +122,8 @@ class Hearers<H> {
|
|
|
122
122
|
this.list.push(hearer);
|
|
123
123
|
listened.add((on: bool): void => {
|
|
124
124
|
if (on) this.list.push(hearer);
|
|
125
|
-
else this.list.
|
|
126
|
-
this.hook.set(this.list.
|
|
125
|
+
else this.list.remove(hearer);
|
|
126
|
+
this.hook.set(this.list.count > 0);
|
|
127
127
|
});
|
|
128
128
|
}
|
|
129
129
|
}
|
|
@@ -134,27 +134,8 @@ class Hearers<H> {
|
|
|
134
134
|
* Calls `handler` on a line of the game's log that AMX Mod X's logevent
|
|
135
135
|
* filter takes: `argc` arguments, `filter` such as "1=Round_End".
|
|
136
136
|
*/
|
|
137
|
-
function onLog(
|
|
138
|
-
|
|
139
|
-
const pub = __switchedPublic((a: number, b: number, c: number, d: number): void => {
|
|
140
|
-
if (heardTwice(key)) return;
|
|
141
|
-
handler();
|
|
142
|
-
}, `hlds:log:${key}`, hook);
|
|
143
|
-
if (pub.length > 0) new Call(NATIVE_register_logevent).str(pub).num(argc).str(filter).run();
|
|
144
|
-
});
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
// AMX Mod X walks its logevents with the line it parsed last. A line logged
|
|
148
|
-
// while a logevent runs - the "Round_End" of the kills a listener of
|
|
149
|
-
// "Round_Start" makes - is heard, and then again by every logevent after
|
|
150
|
-
// the outer one as its walk goes on. Each logevent hears a line once a frame.
|
|
151
|
-
const lastLines = new Map<string, string>();
|
|
152
|
-
|
|
153
|
-
function heardTwice(key: string): bool {
|
|
154
|
-
const line = `${get_gametime()} ${read_logdata()}`;
|
|
155
|
-
if (lastLines.has(key) && lastLines.get(key) == line) return true;
|
|
156
|
-
lastLines.set(key, line);
|
|
157
|
-
return false;
|
|
137
|
+
function onLog(argc: i32, filter: string, handler: () => void, hook: __Switch): void {
|
|
138
|
+
__logHook(argc, filter, handler, hook);
|
|
158
139
|
}
|
|
159
140
|
|
|
160
141
|
/** The player a log line names first - `"Name<userid><authid><team>"` - or 0. */
|
|
@@ -174,8 +155,8 @@ function loggedPlayer(): i32 {
|
|
|
174
155
|
}
|
|
175
156
|
|
|
176
157
|
/** A player's line of the log - `"..." triggered "<what>"`: the player, 0 when he is gone. */
|
|
177
|
-
function onPlayerLog(
|
|
178
|
-
onLog(
|
|
158
|
+
function onPlayerLog(what: string, handler: (id: i32) => void, hook: __Switch): void {
|
|
159
|
+
onLog(3, `2=${what}`, (): void => handler(loggedPlayer()), hook);
|
|
179
160
|
}
|
|
180
161
|
|
|
181
162
|
/** The planted bomb: the grenade with the C4's model, or 0. */
|
|
@@ -183,16 +164,20 @@ function plantedBomb(): i32 {
|
|
|
183
164
|
return max(<i32>find_ent_by_model(-1, "grenade", "models/w_c4.mdl"), 0);
|
|
184
165
|
}
|
|
185
166
|
|
|
186
|
-
// ---------------------------------------------------------------- fakemeta
|
|
167
|
+
// ---------------------------------------------------------------- the functions fakemeta hooks
|
|
187
168
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
169
|
+
// The functions by stock_hook's number: must match StockFunction in runtime/src/enginehooks.h.
|
|
170
|
+
const STOCK_SET_MODEL: i32 = 0;
|
|
171
|
+
const STOCK_EMIT_SOUND: i32 = 1;
|
|
172
|
+
const STOCK_CLIENT_LISTENING: i32 = 2;
|
|
173
|
+
const STOCK_PRECACHE_MODEL: i32 = 3;
|
|
174
|
+
const STOCK_PRECACHE_SOUND: i32 = 4;
|
|
175
|
+
const STOCK_PRECACHE_GENERIC: i32 = 5;
|
|
176
|
+
const STOCK_GAME_DESCRIPTION: i32 = 6;
|
|
177
|
+
|
|
178
|
+
/** Hooks one of the engine's or the game's functions (STOCK_*): `handler` reads its arguments with arg() and argText(). */
|
|
179
|
+
function onStock(fn: i32, post: bool, handler: () => void, hook: __Switch | null): void {
|
|
180
|
+
__stockHook(fn, (a: number, b: number, c: number, d: number): void => handler(), post, hook);
|
|
196
181
|
}
|
|
197
182
|
|
|
198
183
|
// One SetModel hook for every event that hears an entity get its model: each
|
|
@@ -200,48 +185,64 @@ function onFakemeta(fn: i32, post: bool, key: string, handler: () => void, hook:
|
|
|
200
185
|
const modelHearers = new Hearers<(entity: i32, model: string) => void>();
|
|
201
186
|
|
|
202
187
|
function onSetModel(hearer: (entity: i32, model: string) => void, hook: __Switch): void {
|
|
203
|
-
modelHearers.add(hearer, hook, (shared: __Switch): void =>
|
|
188
|
+
modelHearers.add(hearer, hook, (shared: __Switch): void => onStock(STOCK_SET_MODEL, false, heardModel, shared));
|
|
204
189
|
}
|
|
205
190
|
|
|
206
191
|
function heardModel(): void {
|
|
207
192
|
const entity = <i32>arg(0);
|
|
208
193
|
const model = argText(1);
|
|
209
|
-
const hearers = modelHearers.list
|
|
210
|
-
|
|
194
|
+
const hearers = modelHearers.list;
|
|
195
|
+
const n = hearers.begin();
|
|
196
|
+
for (let i = 0; i < n; i++) {
|
|
197
|
+
const hearer = hearers.at(i);
|
|
198
|
+
if (hearer) hearer(entity, model);
|
|
199
|
+
}
|
|
200
|
+
hearers.end();
|
|
211
201
|
}
|
|
212
202
|
|
|
213
203
|
// One EmitSound hook for every event that hears a sound.
|
|
214
204
|
const soundHearers = new Hearers<(entity: i32, sample: string) => void>();
|
|
215
205
|
|
|
216
206
|
function onSound(hearer: (entity: i32, sample: string) => void, hook: __Switch): void {
|
|
217
|
-
soundHearers.add(hearer, hook, (shared: __Switch): void =>
|
|
207
|
+
soundHearers.add(hearer, hook, (shared: __Switch): void => onStock(STOCK_EMIT_SOUND, false, heardSound, shared));
|
|
218
208
|
}
|
|
219
209
|
|
|
220
210
|
function heardSound(): void {
|
|
221
211
|
const entity = <i32>arg(0);
|
|
222
212
|
const sample = argText(2);
|
|
223
|
-
const hearers = soundHearers.list
|
|
224
|
-
|
|
213
|
+
const hearers = soundHearers.list;
|
|
214
|
+
const n = hearers.begin();
|
|
215
|
+
for (let i = 0; i < n; i++) {
|
|
216
|
+
const hearer = hearers.at(i);
|
|
217
|
+
if (hearer) hearer(entity, sample);
|
|
218
|
+
}
|
|
219
|
+
hearers.end();
|
|
225
220
|
}
|
|
226
221
|
|
|
227
222
|
// ---------------------------------------------------------------- client commands
|
|
228
223
|
|
|
229
224
|
/** Hears a client command before the game: `handler` may block it with handled(). */
|
|
230
|
-
function onCommand(
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
});
|
|
225
|
+
function onCommand(command: string, handler: (id: i32) => void, hook: __Switch): void {
|
|
226
|
+
onServer<ClientCommandEvent>((heard: ClientCommandEvent): void => {
|
|
227
|
+
if (read_argv(0) == command) handler(<i32>heard.player.id);
|
|
228
|
+
}, hook);
|
|
235
229
|
}
|
|
236
230
|
|
|
237
|
-
|
|
238
|
-
|
|
231
|
+
const heardArgs = new MessageArgs();
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Hears one of the game's messages to everyone - not to one player - as
|
|
235
|
+
* AMX Mod X's register_event with "a" does: by its name, or an engine
|
|
236
|
+
* message by its number (`svc`); `wanted` picks those of the arguments it is
|
|
237
|
+
* after. The game numbers its messages as the map loads.
|
|
238
|
+
*/
|
|
239
|
+
function onGlobalMessage(name: string, svc: i32, handler: () => void, hook: __Switch, wanted: ((args: MessageArgs) => bool) | null = null): void {
|
|
239
240
|
__whenUp((): void => {
|
|
240
|
-
const
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
241
|
+
const id = svc > 0 ? svc : <i32>get_user_msgid(name);
|
|
242
|
+
__messageHook(id, (receiver: number, message: number, dest: number, d: number): void => {
|
|
243
|
+
if (dest == MSG_ONE || dest == MSG_ONE_UNRELIABLE) return;
|
|
244
|
+
if (wanted == null || wanted(heardArgs)) handler();
|
|
245
|
+
}, hook);
|
|
245
246
|
});
|
|
246
247
|
}
|
|
247
248
|
|
|
@@ -263,7 +264,7 @@ let newRoundAt: f64 = -1;
|
|
|
263
264
|
* game commences once both sides have players.
|
|
264
265
|
*/
|
|
265
266
|
export function newRoundHlds(fire: Fire<NewRoundEvent>, hook: __Switch): void {
|
|
266
|
-
|
|
267
|
+
onGlobalMessage("HLTV", 0, (): void => announceRound(fire), hook, (args: MessageArgs): bool => args.number(0) == 0 && args.number(1) == 0);
|
|
267
268
|
}
|
|
268
269
|
|
|
269
270
|
function announceRound(fire: Fire<NewRoundEvent>): void {
|
|
@@ -293,8 +294,13 @@ function onDecalsReset(hearer: () => void, hook: __Switch): void {
|
|
|
293
294
|
}
|
|
294
295
|
|
|
295
296
|
function decalsReset(a: i32): void {
|
|
296
|
-
const hearers = decalHearers.list
|
|
297
|
-
|
|
297
|
+
const hearers = decalHearers.list;
|
|
298
|
+
const n = hearers.begin();
|
|
299
|
+
for (let i = 0; i < n; i++) {
|
|
300
|
+
const hearer = hearers.at(i);
|
|
301
|
+
if (hearer) hearer();
|
|
302
|
+
}
|
|
303
|
+
hearers.end();
|
|
298
304
|
}
|
|
299
305
|
|
|
300
306
|
/** The round once its players have respawned: the decals' reset at its HLTV message's time. */
|
|
@@ -314,7 +320,7 @@ export function mapResetHlds(fire: Fire<MapResetEvent>, hook: __Switch): void {
|
|
|
314
320
|
|
|
315
321
|
/** The freeze time is over: the game logs "Round_Start". */
|
|
316
322
|
export function roundStartHlds(fire: Fire<RoundStartEvent>, hook: __Switch): void {
|
|
317
|
-
onLog(
|
|
323
|
+
onLog(2, "1=Round_Start", (): void => hear(fire, new RoundStartEvent(), "roundStart"), hook);
|
|
318
324
|
}
|
|
319
325
|
|
|
320
326
|
// The round's end, told before its log line, by the time each came: the
|
|
@@ -377,15 +383,15 @@ export function roundEndHlds(fire: Fire<RoundEndEvent>, hook: __Switch): void {
|
|
|
377
383
|
endSound = message.sound;
|
|
378
384
|
endSoundAt = get_gametime();
|
|
379
385
|
}, hook);
|
|
380
|
-
onLog(
|
|
386
|
+
onLog(6, "0=Team", (): void => {
|
|
381
387
|
endTrigger = `#${read_logargv(3)}`;
|
|
382
388
|
endTriggerAt = get_gametime();
|
|
383
389
|
}, hook);
|
|
384
|
-
onLog(
|
|
390
|
+
onLog(4, "0=World triggered", (): void => {
|
|
385
391
|
endTrigger = `#${read_logargv(1)}`;
|
|
386
392
|
endTriggerAt = get_gametime();
|
|
387
393
|
}, hook);
|
|
388
|
-
onLog(
|
|
394
|
+
onLog(2, "1=Round_End", (): void => {
|
|
389
395
|
const now = get_gametime();
|
|
390
396
|
let ending = endTextAt == now ? endingOf(endText) : null;
|
|
391
397
|
if (ending == null && endTriggerAt == now) ending = endingOf(endTrigger);
|
|
@@ -416,7 +422,7 @@ export function gameThinkHlds(fire: Fire<GameThinkEvent>, hook: __Switch): void
|
|
|
416
422
|
|
|
417
423
|
/** The map is over: the game sends SVC_INTERMISSION, which AMX Mod X's events hear as "30". */
|
|
418
424
|
export function intermissionHlds(fire: Fire<IntermissionEvent>, hook: __Switch): void {
|
|
419
|
-
|
|
425
|
+
onGlobalMessage("", SVC_INTERMISSION, (): void => hear(fire, new IntermissionEvent(), "intermission"), hook);
|
|
420
426
|
}
|
|
421
427
|
|
|
422
428
|
/** The game changes the map: AMX Mod X's server_changelevel. */
|
|
@@ -494,7 +500,7 @@ export function painHlds(fire: Fire<PainEvent>, hook: __Switch): void {
|
|
|
494
500
|
event.__give(0, entity);
|
|
495
501
|
event.__give(1, hitGroup);
|
|
496
502
|
event.__give(2, armour ? 1 : 0);
|
|
497
|
-
hear(fire, event, "pain",
|
|
503
|
+
hear(fire, event, "pain", PLUGIN_HANDLED);
|
|
498
504
|
}, hook);
|
|
499
505
|
}
|
|
500
506
|
|
|
@@ -504,7 +510,7 @@ export function deathSoundHlds(fire: Fire<DeathSoundEvent>, hook: __Switch): voi
|
|
|
504
510
|
if (playerOr0(entity) == 0 || !DEATH_SOUNDS.includes(sample)) return;
|
|
505
511
|
const event = new DeathSoundEvent();
|
|
506
512
|
event.__give(0, entity);
|
|
507
|
-
hear(fire, event, "deathSound",
|
|
513
|
+
hear(fire, event, "deathSound", PLUGIN_HANDLED);
|
|
508
514
|
}, hook);
|
|
509
515
|
}
|
|
510
516
|
|
|
@@ -519,7 +525,7 @@ export function startSoundHlds(fire: Fire<StartSoundEvent>, hook: __Switch): voi
|
|
|
519
525
|
event.__give(5, <i32>arg(4));
|
|
520
526
|
event.__give(6, <i32>arg(5));
|
|
521
527
|
event.__give(7, <i32>arg(6));
|
|
522
|
-
hear(fire, event, "startSound",
|
|
528
|
+
hear(fire, event, "startSound", PLUGIN_HANDLED);
|
|
523
529
|
}, hook);
|
|
524
530
|
}
|
|
525
531
|
|
|
@@ -527,7 +533,7 @@ export function startSoundHlds(fire: Fire<StartSoundEvent>, hook: __Switch): voi
|
|
|
527
533
|
|
|
528
534
|
/** The terrorist who gets the bomb at the round's start: the game logs "Spawned_With_The_Bomb". */
|
|
529
535
|
export function giveBombHlds(fire: Fire<GiveBombEvent>, hook: __Switch): void {
|
|
530
|
-
onPlayerLog("
|
|
536
|
+
onPlayerLog("Spawned_With_The_Bomb", (id: i32): void => {
|
|
531
537
|
const event = new GiveBombEvent();
|
|
532
538
|
event.__give(-1, id);
|
|
533
539
|
hear(fire, event, "giveBomb");
|
|
@@ -535,7 +541,7 @@ export function giveBombHlds(fire: Fire<GiveBombEvent>, hook: __Switch): void {
|
|
|
535
541
|
}
|
|
536
542
|
|
|
537
543
|
export function becomeBomberHlds(fire: Fire<BecomeBomberEvent>, hook: __Switch): void {
|
|
538
|
-
onPlayerLog("
|
|
544
|
+
onPlayerLog("Spawned_With_The_Bomb", (id: i32): void => {
|
|
539
545
|
const event = new BecomeBomberEvent();
|
|
540
546
|
event.__give(0, id);
|
|
541
547
|
event.__give(-1, 1);
|
|
@@ -544,7 +550,7 @@ export function becomeBomberHlds(fire: Fire<BecomeBomberEvent>, hook: __Switch):
|
|
|
544
550
|
}
|
|
545
551
|
|
|
546
552
|
export function becomeVipHlds(fire: Fire<BecomeVipEvent>, hook: __Switch): void {
|
|
547
|
-
onPlayerLog("
|
|
553
|
+
onPlayerLog("Became_VIP", (id: i32): void => {
|
|
548
554
|
const event = new BecomeVipEvent();
|
|
549
555
|
event.__give(0, id);
|
|
550
556
|
hear(fire, event, "becomeVip");
|
|
@@ -568,7 +574,7 @@ export function plantBombHlds(fire: Fire<PlantBombEvent>, hook: __Switch): void
|
|
|
568
574
|
|
|
569
575
|
/** A defuse begins: the game logs "Begin_Bomb_Defuse_With_Kit", or "_Without_Kit". */
|
|
570
576
|
export function defuseBombStartHlds(fire: Fire<DefuseBombStartEvent>, hook: __Switch): void {
|
|
571
|
-
onLog(
|
|
577
|
+
onLog(3, "2&Begin_Bomb_Defuse_", (): void => {
|
|
572
578
|
const event = new DefuseBombStartEvent();
|
|
573
579
|
event.__give(0, plantedBomb());
|
|
574
580
|
event.__give(1, loggedPlayer());
|
|
@@ -578,7 +584,7 @@ export function defuseBombStartHlds(fire: Fire<DefuseBombStartEvent>, hook: __Sw
|
|
|
578
584
|
|
|
579
585
|
/** The bomb defused: the game logs "Defused_The_Bomb". */
|
|
580
586
|
export function defuseBombEndHlds(fire: Fire<DefuseBombEndEvent>, hook: __Switch): void {
|
|
581
|
-
onPlayerLog("
|
|
587
|
+
onPlayerLog("Defused_The_Bomb", (id: i32): void => {
|
|
582
588
|
const event = new DefuseBombEndEvent();
|
|
583
589
|
event.__give(0, plantedBomb());
|
|
584
590
|
event.__give(1, id);
|
|
@@ -589,7 +595,7 @@ export function defuseBombEndHlds(fire: Fire<DefuseBombEndEvent>, hook: __Switch
|
|
|
589
595
|
|
|
590
596
|
/** The bomb blew up: the terrorists trigger "Target_Bombed". */
|
|
591
597
|
export function explodeBombHlds(fire: Fire<ExplodeBombEvent>, hook: __Switch): void {
|
|
592
|
-
onLog(
|
|
598
|
+
onLog(6, "3=Target_Bombed", (): void => {
|
|
593
599
|
const event = new ExplodeBombEvent();
|
|
594
600
|
event.__give(0, plantedBomb());
|
|
595
601
|
hear(fire, event, "explodeBomb");
|
|
@@ -718,9 +724,9 @@ export function chooseTeamHlds(fire: Fire<ChooseTeamEvent>, hook: __Switch): voi
|
|
|
718
724
|
event.__give(1, commandNumber());
|
|
719
725
|
hear(fire, event, "chooseTeam", PLUGIN_HANDLED);
|
|
720
726
|
};
|
|
721
|
-
onCommand("
|
|
722
|
-
onCommand("
|
|
723
|
-
const menu =
|
|
727
|
+
onCommand("jointeam", chosen, hook);
|
|
728
|
+
onCommand("menuselect", (id: i32): void => {
|
|
729
|
+
const menu = __playerOf(id).openMenu;
|
|
724
730
|
if (menu == "team" || menu == "teamInGame") chosen(id);
|
|
725
731
|
}, hook);
|
|
726
732
|
}
|
|
@@ -733,15 +739,15 @@ export function chooseAppearanceHlds(fire: Fire<ChooseAppearanceEvent>, hook: __
|
|
|
733
739
|
event.__give(1, commandNumber());
|
|
734
740
|
hear(fire, event, "chooseAppearance", PLUGIN_HANDLED);
|
|
735
741
|
};
|
|
736
|
-
onCommand("
|
|
737
|
-
onCommand("
|
|
738
|
-
if (
|
|
742
|
+
onCommand("joinclass", chosen, hook);
|
|
743
|
+
onCommand("menuselect", (id: i32): void => {
|
|
744
|
+
if (__playerOf(id).openMenu == "appearance") chosen(id);
|
|
739
745
|
}, hook);
|
|
740
746
|
}
|
|
741
747
|
|
|
742
748
|
/** A weapon dropped: the player's `drop` command, with the weapon he names. */
|
|
743
749
|
export function dropPlayerItemHlds(fire: Fire<DropPlayerItemEvent>, hook: __Switch): void {
|
|
744
|
-
onCommand("
|
|
750
|
+
onCommand("drop", (id: i32): void => {
|
|
745
751
|
const event = new DropPlayerItemEvent();
|
|
746
752
|
event.__give(0, id);
|
|
747
753
|
event.__giveText(1, read_argv(1));
|
|
@@ -821,14 +827,10 @@ export function playerBlindHlds(fire: Fire<PlayerBlindEvent>, hook: __Switch): v
|
|
|
821
827
|
}, true, hook);
|
|
822
828
|
}
|
|
823
829
|
|
|
824
|
-
|
|
825
|
-
const hamAnswer = new StaticArray<i32>(1);
|
|
826
|
-
|
|
827
|
-
/** A player got a weapon: Ham Sandwich's AddPlayerItem after the game, when it took the item. */
|
|
830
|
+
/** A player got a weapon: Ham Sandwich's AddPlayerItem after the game, when it took the item - its answer, arg(-1). */
|
|
828
831
|
export function playerGotWeaponHlds(fire: Fire<PlayerGotWeaponEvent>, hook: __Switch): void {
|
|
829
832
|
__ham(Ham_AddPlayerItem, "player", (id: number, item: number, c: number, d: number): void => {
|
|
830
|
-
|
|
831
|
-
if (hamAnswer[0] == 0) return;
|
|
833
|
+
if (arg(-1) == 0) return;
|
|
832
834
|
const event = new PlayerGotWeaponEvent();
|
|
833
835
|
event.__give(0, <i32>id);
|
|
834
836
|
event.__give(1, <i32>item);
|
|
@@ -841,7 +843,7 @@ export function playerGotWeaponHlds(fire: Fire<PlayerGotWeaponEvent>, hook: __Sw
|
|
|
841
843
|
* answer is told instead - preventDefault() answers `false`.
|
|
842
844
|
*/
|
|
843
845
|
export function canPlayerHearPlayerHlds(fire: Fire<CanPlayerHearPlayerEvent>, hook: __Switch): void {
|
|
844
|
-
|
|
846
|
+
onStock(STOCK_CLIENT_LISTENING, false, (): void => {
|
|
845
847
|
const listener = playerOr0(<i32>arg(0));
|
|
846
848
|
const sender = playerOr0(<i32>arg(1));
|
|
847
849
|
if (listener == 0 || sender == 0) return;
|
|
@@ -853,9 +855,7 @@ export function canPlayerHearPlayerHlds(fire: Fire<CanPlayerHearPlayerEvent>, ho
|
|
|
853
855
|
fire(event, true);
|
|
854
856
|
if (event.__answered || event.__prevented) {
|
|
855
857
|
const hears = event.__prevented ? 0 : event.__answerCell;
|
|
856
|
-
|
|
857
|
-
new Call(NATIVE_forward_return).num(FMV_CELL).ref(hears).run();
|
|
858
|
-
__outcome(FMRES_SUPERCEDE);
|
|
858
|
+
__chainSet(2, hears);
|
|
859
859
|
}
|
|
860
860
|
event.__prevented = false;
|
|
861
861
|
settle(event, "canPlayerHearPlayer", -1, true);
|
|
@@ -919,7 +919,7 @@ const THROWN: string[] = ["models/w_hegrenade.mdl", "models/w_flashbang.mdl", "m
|
|
|
919
919
|
export function throwGrenadeHlds(fire: Fire<ThrowGrenadeEvent>, hook: __Switch): void {
|
|
920
920
|
for (let i = 0; i < THROWN.length; i++) {
|
|
921
921
|
onThrown(THROWN[i], (grenade: Entity, thrower: i32, fuse: f64): void => {
|
|
922
|
-
const weapon = thrower > 0 ?
|
|
922
|
+
const weapon = thrower > 0 ? __playerOf(thrower).activeItem : null;
|
|
923
923
|
const event = new ThrowGrenadeEvent();
|
|
924
924
|
event.__give(0, thrower);
|
|
925
925
|
event.__give(1, weapon != null ? <i32>weapon.id : 0);
|
|
@@ -939,7 +939,7 @@ export function setModelHlds(fire: Fire<SetModelEvent>, hook: __Switch): void {
|
|
|
939
939
|
const event = new SetModelEvent();
|
|
940
940
|
event.__give(0, entity);
|
|
941
941
|
event.__giveText(1, model);
|
|
942
|
-
hear(fire, event, "setModel",
|
|
942
|
+
hear(fire, event, "setModel", PLUGIN_HANDLED);
|
|
943
943
|
}, hook);
|
|
944
944
|
}
|
|
945
945
|
|
|
@@ -970,38 +970,39 @@ export function bounceGibTouchHlds(fire: Fire<BounceGibTouchEvent>, hook: __Swit
|
|
|
970
970
|
}
|
|
971
971
|
|
|
972
972
|
/**
|
|
973
|
-
* The game precaches a file:
|
|
974
|
-
* before the game's own. The listeners before the game hear
|
|
975
|
-
* asked, preventDefault() skips it; the ones after hear the
|
|
973
|
+
* The game precaches a file: the engine's function, hooked as the plugin
|
|
974
|
+
* loads, before the game's own precaches. The listeners before the game hear
|
|
975
|
+
* it as it is asked, preventDefault() skips it; the ones after hear the
|
|
976
|
+
* engine's answer.
|
|
976
977
|
*/
|
|
977
|
-
function onPrecache<E>(fn: i32,
|
|
978
|
-
|
|
978
|
+
function onPrecache<E>(fn: i32, make: () => E, fire: Fire<E>, name: string, hook: __Switch): void {
|
|
979
|
+
onStock(fn, false, (): void => {
|
|
979
980
|
const event = make();
|
|
980
981
|
const fields = changetype<HookEvent>(event);
|
|
981
982
|
fields.__giveText(0, argText(0));
|
|
982
983
|
fire(event, false);
|
|
983
|
-
settle(changetype<HookEvent>(event), name,
|
|
984
|
-
}, hook
|
|
985
|
-
|
|
984
|
+
settle(changetype<HookEvent>(event), name, PLUGIN_HANDLED);
|
|
985
|
+
}, hook);
|
|
986
|
+
onStock(fn, true, (): void => {
|
|
986
987
|
const event = make();
|
|
987
988
|
const fields = changetype<HookEvent>(event);
|
|
988
989
|
fields.__giveText(0, argText(0));
|
|
989
|
-
fields.__give(-1, <i32>
|
|
990
|
+
fields.__give(-1, <i32>arg(-1));
|
|
990
991
|
fire(event, true);
|
|
991
992
|
settle(changetype<HookEvent>(event), name);
|
|
992
|
-
}, hook
|
|
993
|
+
}, hook);
|
|
993
994
|
}
|
|
994
995
|
|
|
995
996
|
export function precacheModelHlds(fire: Fire<PrecacheModelEvent>, hook: __Switch): void {
|
|
996
|
-
onPrecache<PrecacheModelEvent>(
|
|
997
|
+
onPrecache<PrecacheModelEvent>(STOCK_PRECACHE_MODEL, (): PrecacheModelEvent => new PrecacheModelEvent(), fire, "precacheModel", hook);
|
|
997
998
|
}
|
|
998
999
|
|
|
999
1000
|
export function precacheSoundHlds(fire: Fire<PrecacheSoundEvent>, hook: __Switch): void {
|
|
1000
|
-
onPrecache<PrecacheSoundEvent>(
|
|
1001
|
+
onPrecache<PrecacheSoundEvent>(STOCK_PRECACHE_SOUND, (): PrecacheSoundEvent => new PrecacheSoundEvent(), fire, "precacheSound", hook);
|
|
1001
1002
|
}
|
|
1002
1003
|
|
|
1003
1004
|
export function precacheFileHlds(fire: Fire<PrecacheFileEvent>, hook: __Switch): void {
|
|
1004
|
-
onPrecache<PrecacheFileEvent>(
|
|
1005
|
+
onPrecache<PrecacheFileEvent>(STOCK_PRECACHE_GENERIC, (): PrecacheFileEvent => new PrecacheFileEvent(), fire, "precacheFile", hook);
|
|
1005
1006
|
}
|
|
1006
1007
|
|
|
1007
1008
|
// ---------------------------------------------------------------- the game rules' fields
|
|
@@ -1020,9 +1021,9 @@ export function gameNameHlds(): string {
|
|
|
1020
1021
|
/** Writes the game's name: the game's GetGameDescription is answered with it from now on. */
|
|
1021
1022
|
export function setGameNameHlds(value: string): void {
|
|
1022
1023
|
if (gameNameWritten.length == 0) {
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1024
|
+
onStock(STOCK_GAME_DESCRIPTION, false, (): void => {
|
|
1025
|
+
__chainSetText(-1, gameNameWritten);
|
|
1026
|
+
handled();
|
|
1026
1027
|
}, null);
|
|
1027
1028
|
}
|
|
1028
1029
|
gameNameWritten = value;
|