quake2ts 0.0.207 → 0.0.209

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.
@@ -3502,59 +3502,12 @@ var __export3 = (target, all) => {
3502
3502
  };
3503
3503
  var ZERO_VEC3 = { x: 0, y: 0, z: 0 };
3504
3504
  var DEG_TO_RAD2 = Math.PI / 180;
3505
- function dotVec3(a, b) {
3506
- return a.x * b.x + a.y * b.y + a.z * b.z;
3507
- }
3508
- var PITCH = 0;
3509
- var YAW = 1;
3510
- var ROLL = 2;
3511
3505
  var DEG2RAD_FACTOR2 = Math.PI / 180;
3512
3506
  var RAD2DEG_FACTOR2 = 180 / Math.PI;
3513
- function axisComponent(vec, axis) {
3514
- switch (axis) {
3515
- case PITCH:
3516
- return vec.x;
3517
- case YAW:
3518
- return vec.y;
3519
- case ROLL:
3520
- default:
3521
- return vec.z;
3522
- }
3523
- }
3524
- function degToRad(degrees) {
3525
- return degrees * DEG2RAD_FACTOR2;
3526
- }
3527
3507
  function angleMod(angle2) {
3528
3508
  const value = angle2 % 360;
3529
3509
  return value < 0 ? 360 + value : value;
3530
3510
  }
3531
- function angleVectors(angles) {
3532
- const yaw = degToRad(axisComponent(angles, YAW));
3533
- const pitch = degToRad(axisComponent(angles, PITCH));
3534
- const roll = degToRad(axisComponent(angles, ROLL));
3535
- const sy = Math.sin(yaw);
3536
- const cy = Math.cos(yaw);
3537
- const sp = Math.sin(pitch);
3538
- const cp = Math.cos(pitch);
3539
- const sr = Math.sin(roll);
3540
- const cr = Math.cos(roll);
3541
- const forward = {
3542
- x: cp * cy,
3543
- y: cp * sy,
3544
- z: -sp
3545
- };
3546
- const right = {
3547
- x: -sr * sp * cy - cr * -sy,
3548
- y: -sr * sp * sy - cr * cy,
3549
- z: -sr * cp
3550
- };
3551
- const up = {
3552
- x: cr * sp * cy - sr * -sy,
3553
- y: cr * sp * sy - sr * cy,
3554
- z: cr * cp
3555
- };
3556
- return { forward, right, up };
3557
- }
3558
3511
  var CONTENTS_SOLID2 = 1 << 0;
3559
3512
  var CONTENTS_WINDOW2 = 1 << 1;
3560
3513
  var CONTENTS_AUX2 = 1 << 2;
@@ -3754,6 +3707,56 @@ function mouseDeltaToViewDelta(delta, options) {
3754
3707
  z: 0
3755
3708
  };
3756
3709
  }
3710
+ var PlayerStat = /* @__PURE__ */ ((PlayerStat2) => {
3711
+ PlayerStat2[PlayerStat2["STAT_HEALTH_ICON"] = 0] = "STAT_HEALTH_ICON";
3712
+ PlayerStat2[PlayerStat2["STAT_HEALTH"] = 1] = "STAT_HEALTH";
3713
+ PlayerStat2[PlayerStat2["STAT_AMMO_ICON"] = 2] = "STAT_AMMO_ICON";
3714
+ PlayerStat2[PlayerStat2["STAT_AMMO"] = 3] = "STAT_AMMO";
3715
+ PlayerStat2[PlayerStat2["STAT_ARMOR_ICON"] = 4] = "STAT_ARMOR_ICON";
3716
+ PlayerStat2[PlayerStat2["STAT_ARMOR"] = 5] = "STAT_ARMOR";
3717
+ PlayerStat2[PlayerStat2["STAT_SELECTED_ICON"] = 6] = "STAT_SELECTED_ICON";
3718
+ PlayerStat2[PlayerStat2["STAT_PICKUP_ICON"] = 7] = "STAT_PICKUP_ICON";
3719
+ PlayerStat2[PlayerStat2["STAT_PICKUP_STRING"] = 8] = "STAT_PICKUP_STRING";
3720
+ PlayerStat2[PlayerStat2["STAT_TIMER_ICON"] = 9] = "STAT_TIMER_ICON";
3721
+ PlayerStat2[PlayerStat2["STAT_TIMER"] = 10] = "STAT_TIMER";
3722
+ PlayerStat2[PlayerStat2["STAT_HELPICON"] = 11] = "STAT_HELPICON";
3723
+ PlayerStat2[PlayerStat2["STAT_SELECTED_ITEM"] = 12] = "STAT_SELECTED_ITEM";
3724
+ PlayerStat2[PlayerStat2["STAT_LAYOUTS"] = 13] = "STAT_LAYOUTS";
3725
+ PlayerStat2[PlayerStat2["STAT_FRAGS"] = 14] = "STAT_FRAGS";
3726
+ PlayerStat2[PlayerStat2["STAT_FLASHES"] = 15] = "STAT_FLASHES";
3727
+ PlayerStat2[PlayerStat2["STAT_CHASE"] = 16] = "STAT_CHASE";
3728
+ PlayerStat2[PlayerStat2["STAT_SPECTATOR"] = 17] = "STAT_SPECTATOR";
3729
+ PlayerStat2[PlayerStat2["STAT_CTF_TEAM1_PIC"] = 18] = "STAT_CTF_TEAM1_PIC";
3730
+ PlayerStat2[PlayerStat2["STAT_CTF_TEAM1_CAPS"] = 19] = "STAT_CTF_TEAM1_CAPS";
3731
+ PlayerStat2[PlayerStat2["STAT_CTF_TEAM2_PIC"] = 20] = "STAT_CTF_TEAM2_PIC";
3732
+ PlayerStat2[PlayerStat2["STAT_CTF_TEAM2_CAPS"] = 21] = "STAT_CTF_TEAM2_CAPS";
3733
+ PlayerStat2[PlayerStat2["STAT_CTF_FLAG_PIC"] = 22] = "STAT_CTF_FLAG_PIC";
3734
+ PlayerStat2[PlayerStat2["STAT_CTF_JOINED_TEAM1_PIC"] = 23] = "STAT_CTF_JOINED_TEAM1_PIC";
3735
+ PlayerStat2[PlayerStat2["STAT_CTF_JOINED_TEAM2_PIC"] = 24] = "STAT_CTF_JOINED_TEAM2_PIC";
3736
+ PlayerStat2[PlayerStat2["STAT_CTF_TEAM1_HEADER"] = 25] = "STAT_CTF_TEAM1_HEADER";
3737
+ PlayerStat2[PlayerStat2["STAT_CTF_TEAM2_HEADER"] = 26] = "STAT_CTF_TEAM2_HEADER";
3738
+ PlayerStat2[PlayerStat2["STAT_CTF_TECH"] = 27] = "STAT_CTF_TECH";
3739
+ PlayerStat2[PlayerStat2["STAT_CTF_ID_VIEW"] = 28] = "STAT_CTF_ID_VIEW";
3740
+ PlayerStat2[PlayerStat2["STAT_CTF_MATCH"] = 29] = "STAT_CTF_MATCH";
3741
+ PlayerStat2[PlayerStat2["STAT_CTF_ID_VIEW_COLOR"] = 30] = "STAT_CTF_ID_VIEW_COLOR";
3742
+ PlayerStat2[PlayerStat2["STAT_CTF_TEAMINFO"] = 31] = "STAT_CTF_TEAMINFO";
3743
+ PlayerStat2[PlayerStat2["STAT_WEAPONS_OWNED_1"] = 32] = "STAT_WEAPONS_OWNED_1";
3744
+ PlayerStat2[PlayerStat2["STAT_WEAPONS_OWNED_2"] = 33] = "STAT_WEAPONS_OWNED_2";
3745
+ PlayerStat2[PlayerStat2["STAT_AMMO_INFO_START"] = 34] = "STAT_AMMO_INFO_START";
3746
+ PlayerStat2[PlayerStat2["STAT_POWERUP_INFO_START"] = 41] = "STAT_POWERUP_INFO_START";
3747
+ PlayerStat2[PlayerStat2["STAT_KEY_A"] = 44] = "STAT_KEY_A";
3748
+ PlayerStat2[PlayerStat2["STAT_KEY_B"] = 45] = "STAT_KEY_B";
3749
+ PlayerStat2[PlayerStat2["STAT_KEY_C"] = 46] = "STAT_KEY_C";
3750
+ PlayerStat2[PlayerStat2["STAT_ACTIVE_WHEEL_WEAPON"] = 47] = "STAT_ACTIVE_WHEEL_WEAPON";
3751
+ PlayerStat2[PlayerStat2["STAT_COOP_RESPAWN"] = 48] = "STAT_COOP_RESPAWN";
3752
+ PlayerStat2[PlayerStat2["STAT_LIVES"] = 49] = "STAT_LIVES";
3753
+ PlayerStat2[PlayerStat2["STAT_HIT_MARKER"] = 50] = "STAT_HIT_MARKER";
3754
+ PlayerStat2[PlayerStat2["STAT_SELECTED_ITEM_NAME"] = 51] = "STAT_SELECTED_ITEM_NAME";
3755
+ PlayerStat2[PlayerStat2["STAT_HEALTH_BARS"] = 52] = "STAT_HEALTH_BARS";
3756
+ PlayerStat2[PlayerStat2["STAT_ACTIVE_WEAPON"] = 53] = "STAT_ACTIVE_WEAPON";
3757
+ PlayerStat2[PlayerStat2["STAT_LAST"] = 54] = "STAT_LAST";
3758
+ return PlayerStat2;
3759
+ })(PlayerStat || {});
3757
3760
  var AMMO_MAX2 = 12;
3758
3761
  var NUM_BITS_FOR_AMMO2 = 9;
3759
3762
  var NUM_AMMO_STATS2 = Math.ceil(AMMO_MAX2 * NUM_BITS_FOR_AMMO2 / 16);
@@ -3990,7 +3993,6 @@ function createCGameImport(imports, state) {
3990
3993
  // src/hud/crosshair.ts
3991
3994
  var crosshairPic = null;
3992
3995
  var crosshairIndex = 0;
3993
- var crosshairColor = [1, 1, 1, 1];
3994
3996
  var crosshairEnabled = true;
3995
3997
  var CROSSHAIR_NAMES = ["ch1", "ch2", "ch3"];
3996
3998
  var crosshairPics = [null, null, null];
@@ -4044,59 +4046,9 @@ var Cycle_Crosshair = () => {
4044
4046
  }
4045
4047
  return crosshairEnabled ? crosshairIndex : -1;
4046
4048
  };
4047
- var Draw_Crosshair = (renderer, width, height) => {
4048
- if (crosshairEnabled && crosshairPic) {
4049
- const x = (width - crosshairPic.width) / 2;
4050
- const y = (height - crosshairPic.height) / 2;
4051
- renderer.drawPic(x, y, crosshairPic, crosshairColor);
4052
- }
4053
- };
4054
4049
 
4055
4050
  // src/hud/icons.ts
4056
4051
  import { WEAPON_ITEMS } from "@quake2ts/game";
4057
-
4058
- // src/hud/layout.ts
4059
- var REFERENCE_WIDTH = 640;
4060
- var REFERENCE_HEIGHT = 480;
4061
- var getHudLayout = (width, height) => {
4062
- const scaleX = width / REFERENCE_WIDTH;
4063
- const scaleY = height / REFERENCE_HEIGHT;
4064
- const scale3 = Math.min(scaleX, scaleY);
4065
- return {
4066
- // Status bar numbers - Anchored Bottom-Left / Center / Right
4067
- HEALTH_X: 100 * scale3,
4068
- HEALTH_Y: height - (REFERENCE_HEIGHT - 450) * scale3,
4069
- ARMOR_X: 200 * scale3,
4070
- ARMOR_Y: height - (REFERENCE_HEIGHT - 450) * scale3,
4071
- AMMO_X: width - (REFERENCE_WIDTH - 540) * scale3,
4072
- // Anchor right? 540 is near right (640)
4073
- AMMO_Y: height - (REFERENCE_HEIGHT - 450) * scale3,
4074
- // Center print messages - Center
4075
- CENTER_PRINT_X: width / 2,
4076
- CENTER_PRINT_Y: 100 * scale3,
4077
- // Top anchor
4078
- // Weapon and powerup icons
4079
- WEAPON_ICON_X: 10 * scale3,
4080
- WEAPON_ICON_Y: height - (REFERENCE_HEIGHT - 450) * scale3,
4081
- POWERUP_X: width - (REFERENCE_WIDTH - 610) * scale3,
4082
- POWERUP_Y: height - (REFERENCE_HEIGHT - 450) * scale3,
4083
- scale: scale3
4084
- };
4085
- };
4086
-
4087
- // src/hud/numbers.ts
4088
- var Draw_Number = (renderer, x, y, value, pics, width, color) => {
4089
- const s = Math.abs(value).toString();
4090
- for (let i = 0; i < s.length; i++) {
4091
- const digit = parseInt(s[i]);
4092
- const pic = pics[digit];
4093
- if (pic) {
4094
- renderer.drawPic(x + i * width, y, pic, color);
4095
- }
4096
- }
4097
- };
4098
-
4099
- // src/hud/icons.ts
4100
4052
  var iconPics = /* @__PURE__ */ new Map();
4101
4053
  var ICON_NAMES = [
4102
4054
  // Weapons
@@ -4172,163 +4124,6 @@ var Init_Damage = async (renderer, assets) => {
4172
4124
  }
4173
4125
  }
4174
4126
  };
4175
- var Draw_Damage = (renderer, ps) => {
4176
- if (!ps.damageIndicators) {
4177
- return;
4178
- }
4179
- const screenWidth = renderer.width;
4180
- const screenHeight = renderer.height;
4181
- const { forward, right, up } = angleVectors(ps.viewAngles);
4182
- for (const indicator of ps.damageIndicators) {
4183
- const { direction, strength } = indicator;
4184
- const normalizedDirection = { ...direction };
4185
- const len2 = Math.sqrt(normalizedDirection.x * normalizedDirection.x + normalizedDirection.y * normalizedDirection.y + normalizedDirection.z * normalizedDirection.z);
4186
- if (len2 > 0) {
4187
- normalizedDirection.x /= len2;
4188
- normalizedDirection.y /= len2;
4189
- normalizedDirection.z /= len2;
4190
- }
4191
- const rightDot = dotVec3(normalizedDirection, right);
4192
- const forwardDot = dotVec3(normalizedDirection, forward);
4193
- const angle2 = Math.atan2(forwardDot, rightDot) * 180 / Math.PI;
4194
- let pic;
4195
- let x = 0;
4196
- let y = 0;
4197
- if (angle2 > -45 && angle2 <= 45) {
4198
- pic = damagePics.get("d_right");
4199
- x = screenWidth - (pic?.width || 0);
4200
- y = (screenHeight - (pic?.height || 0)) / 2;
4201
- } else if (angle2 > 45 && angle2 <= 135) {
4202
- pic = damagePics.get("d_up");
4203
- x = (screenWidth - (pic?.width || 0)) / 2;
4204
- y = 0;
4205
- } else if (angle2 > 135 || angle2 <= -135) {
4206
- pic = damagePics.get("d_left");
4207
- x = 0;
4208
- y = (screenHeight - (pic?.height || 0)) / 2;
4209
- } else {
4210
- pic = damagePics.get("d_down");
4211
- x = (screenWidth - (pic?.width || 0)) / 2;
4212
- y = screenHeight - (pic?.height || 0);
4213
- }
4214
- if (pic) {
4215
- renderer.drawPic(x, y, pic);
4216
- }
4217
- }
4218
- };
4219
-
4220
- // src/hud/diagnostics.ts
4221
- var Draw_Diagnostics = (renderer, stats) => {
4222
- const lines = [
4223
- `FPS: ${stats.fps}`,
4224
- `Draw Calls: ${stats.drawCalls}`,
4225
- `Batches: ${stats.batches}`,
4226
- `Faces Drawn: ${stats.facesDrawn}`,
4227
- `Vertices: ${stats.vertexCount}`
4228
- ];
4229
- let y = 10;
4230
- for (const line of lines) {
4231
- renderer.drawString(10, y, line);
4232
- y += 10;
4233
- }
4234
- };
4235
-
4236
- // src/hud/blends.ts
4237
- var Draw_Blends = (renderer, ps) => {
4238
- if (!ps.blend) return;
4239
- const [r, g, b, a] = ps.blend;
4240
- if (a > 0) {
4241
- renderer.drawfillRect(0, 0, renderer.width, renderer.height, [r, g, b, a]);
4242
- }
4243
- };
4244
-
4245
- // src/hud/pickup.ts
4246
- var Draw_Pickup = (renderer, ps) => {
4247
- if (!ps.pickupIcon) return;
4248
- const icon = iconPics.get(ps.pickupIcon);
4249
- if (icon) {
4250
- const x = renderer.width - icon.width - 10;
4251
- const y = renderer.height - icon.height - 10;
4252
- renderer.drawPic(x, y, icon);
4253
- }
4254
- };
4255
-
4256
- // src/hud/statusbar.ts
4257
- import { WEAPON_ITEMS as WEAPON_ITEMS2 } from "@quake2ts/game";
4258
- var colorblindMode = false;
4259
- var Draw_StatusBar = (renderer, client, health, armor, ammo, hudNumberPics2, numberWidth2, timeMs, layout) => {
4260
- let healthColor = void 0;
4261
- if (health <= 25) {
4262
- if (colorblindMode) {
4263
- healthColor = [0.2, 0.6, 1, 1];
4264
- } else {
4265
- healthColor = [1, 0, 0, 1];
4266
- }
4267
- }
4268
- if (hudNumberPics2.length > 0) {
4269
- Draw_Number(renderer, layout.HEALTH_X, layout.HEALTH_Y, health, hudNumberPics2, numberWidth2, healthColor);
4270
- Draw_Number(renderer, layout.ARMOR_X, layout.ARMOR_Y, armor, hudNumberPics2, numberWidth2);
4271
- Draw_Number(renderer, layout.AMMO_X, layout.AMMO_Y, ammo, hudNumberPics2, numberWidth2);
4272
- }
4273
- const armorItem = client.inventory.armor;
4274
- if (armorItem && armorItem.armorCount > 0) {
4275
- const iconName = `i_${armorItem.armorType}armor`;
4276
- const icon = iconPics.get(iconName);
4277
- if (icon) {
4278
- renderer.drawPic(layout.ARMOR_X - 24, layout.ARMOR_Y - 2, icon);
4279
- }
4280
- }
4281
- const currentWeapon = client.inventory.currentWeapon;
4282
- if (currentWeapon) {
4283
- const weaponDef = Object.values(WEAPON_ITEMS2).find((w) => w.weaponId === currentWeapon);
4284
- if (weaponDef) {
4285
- const iconName = `w_${weaponDef.id.substring(7)}`;
4286
- const icon = iconPics.get(iconName);
4287
- if (icon) {
4288
- renderer.drawPic(layout.WEAPON_ICON_X, layout.WEAPON_ICON_Y, icon);
4289
- }
4290
- }
4291
- }
4292
- const keys = Array.from(client.inventory.keys).sort();
4293
- let keyY = layout.WEAPON_ICON_Y - 150 * layout.scale;
4294
- for (const key of keys) {
4295
- let iconName = "";
4296
- switch (key) {
4297
- case "blue":
4298
- iconName = "k_bluekey";
4299
- break;
4300
- case "red":
4301
- iconName = "k_redkey";
4302
- break;
4303
- case "green":
4304
- iconName = "k_security";
4305
- break;
4306
- case "yellow":
4307
- iconName = "k_pyramid";
4308
- break;
4309
- }
4310
- if (iconName) {
4311
- const icon = iconPics.get(iconName);
4312
- if (icon) {
4313
- renderer.drawPic(layout.WEAPON_ICON_X, keyY, icon);
4314
- keyY += icon.height + 2;
4315
- }
4316
- }
4317
- }
4318
- let powerupX = layout.POWERUP_X;
4319
- for (const [powerup, expiresAt] of client.inventory.powerups.entries()) {
4320
- if (expiresAt && expiresAt > timeMs) {
4321
- const iconName = `p_${powerup}`;
4322
- const icon = iconPics.get(iconName);
4323
- if (icon) {
4324
- renderer.drawPic(powerupX, layout.POWERUP_Y, icon);
4325
- const remainingSeconds = Math.ceil((expiresAt - timeMs) / 1e3);
4326
- Draw_Number(renderer, powerupX + icon.width + 2, layout.POWERUP_Y, remainingSeconds, hudNumberPics2, numberWidth2);
4327
- powerupX -= icon.width + numberWidth2 * remainingSeconds.toString().length + 8;
4328
- }
4329
- }
4330
- }
4331
- };
4332
4127
 
4333
4128
  // src/hud.ts
4334
4129
  var hudNumberPics = [];
@@ -4350,77 +4145,6 @@ var Init_Hud = async (renderer, assets) => {
4350
4145
  await Init_Icons(renderer, assets);
4351
4146
  await Init_Damage(renderer, assets);
4352
4147
  };
4353
- var Draw_Hud = (renderer, ps, client, health, armor, ammo, stats, messageSystem, subtitleSystem, timeMs) => {
4354
- renderer.begin2D();
4355
- Draw_Blends(renderer, ps);
4356
- if (ps.damageAlpha > 0) {
4357
- renderer.drawfillRect(0, 0, renderer.width, renderer.height, [1, 0, 0, ps.damageAlpha]);
4358
- }
4359
- const layout = getHudLayout(renderer.width, renderer.height);
4360
- Draw_StatusBar(renderer, client, health, armor, ammo, hudNumberPics, numberWidth, timeMs, layout);
4361
- Draw_Pickup(renderer, ps);
4362
- Draw_Damage(renderer, ps);
4363
- Draw_Diagnostics(renderer, stats);
4364
- messageSystem.drawCenterPrint(renderer, timeMs, layout);
4365
- messageSystem.drawNotifications(renderer, timeMs);
4366
- subtitleSystem.drawSubtitles(renderer, timeMs);
4367
- if (ps.centerPrint) {
4368
- renderer.drawCenterString(renderer.height / 2 - 20, ps.centerPrint);
4369
- }
4370
- if (ps.notify) {
4371
- renderer.drawString(8, 8, ps.notify);
4372
- }
4373
- Draw_Crosshair(renderer, renderer.width, renderer.height);
4374
- renderer.end2D();
4375
- };
4376
-
4377
- // src/hud/messages.ts
4378
- var CENTER_PRINT_DURATION = 3e3;
4379
- var NOTIFY_DURATION = 5e3;
4380
- var MAX_NOTIFY_MESSAGES = 4;
4381
- var MessageSystem = class {
4382
- constructor() {
4383
- this.centerPrintMsg = null;
4384
- this.notifyMessages = [];
4385
- }
4386
- addCenterPrint(text, now) {
4387
- this.centerPrintMsg = {
4388
- text,
4389
- startTime: now,
4390
- duration: CENTER_PRINT_DURATION
4391
- };
4392
- }
4393
- addNotify(text, now) {
4394
- this.notifyMessages.push({
4395
- text,
4396
- startTime: now,
4397
- duration: NOTIFY_DURATION
4398
- });
4399
- if (this.notifyMessages.length > MAX_NOTIFY_MESSAGES) {
4400
- this.notifyMessages.shift();
4401
- }
4402
- }
4403
- drawCenterPrint(renderer, now, layout) {
4404
- if (!this.centerPrintMsg) return;
4405
- if (now > this.centerPrintMsg.startTime + this.centerPrintMsg.duration) {
4406
- this.centerPrintMsg = null;
4407
- return;
4408
- }
4409
- const width = this.centerPrintMsg.text.length * 8;
4410
- const y = layout.CENTER_PRINT_Y;
4411
- renderer.drawCenterString(y, this.centerPrintMsg.text);
4412
- }
4413
- drawNotifications(renderer, now) {
4414
- while (this.notifyMessages.length > 0 && now > this.notifyMessages[0].startTime + this.notifyMessages[0].duration) {
4415
- this.notifyMessages.shift();
4416
- }
4417
- let y = 10;
4418
- for (const msg of this.notifyMessages) {
4419
- renderer.drawString(10, y, msg.text);
4420
- y += 10;
4421
- }
4422
- }
4423
- };
4424
4148
 
4425
4149
  // src/hud/subtitles.ts
4426
4150
  var SUBTITLE_DURATION = 3e3;
@@ -6288,7 +6012,6 @@ function buildRenderableEntities(latestEntities, previousEntities, alpha, config
6288
6012
  function createClient(imports) {
6289
6013
  const prediction = new ClientPrediction(imports.engine.trace);
6290
6014
  const view = new ViewEffects();
6291
- const messageSystem = new MessageSystem();
6292
6015
  const subtitleSystem = new SubtitleSystem();
6293
6016
  const demoPlayback = new DemoPlaybackController();
6294
6017
  const demoHandler = new ClientNetworkHandler(imports);
@@ -6300,19 +6023,7 @@ function createClient(imports) {
6300
6023
  let pauseMenuFactory;
6301
6024
  let optionsFactory;
6302
6025
  const configStrings = new ClientConfigStrings();
6303
- demoHandler.setCallbacks({
6304
- onCenterPrint: (msg) => messageSystem.addCenterPrint(msg, demoHandler.latestFrame?.serverFrame ?? 0),
6305
- onPrint: (level, msg) => messageSystem.addNotify(msg, demoHandler.latestFrame?.serverFrame ?? 0),
6306
- onConfigString: (index, str3) => {
6307
- configStrings.set(index, str3);
6308
- cg.ParseConfigString(index, str3);
6309
- }
6310
- });
6311
- demoPlayback.setHandler(demoHandler);
6312
6026
  let latestFrame;
6313
- let lastRendered;
6314
- let lastView;
6315
- let camera;
6316
6027
  let clientInAutoDemo = false;
6317
6028
  const stateProvider = {
6318
6029
  get tickRate() {
@@ -6325,7 +6036,6 @@ function createClient(imports) {
6325
6036
  get serverFrame() {
6326
6037
  return demoHandler.latestServerFrame;
6327
6038
  },
6328
- // Corrected access
6329
6039
  get serverProtocol() {
6330
6040
  return 34;
6331
6041
  },
@@ -6340,6 +6050,18 @@ function createClient(imports) {
6340
6050
  };
6341
6051
  const cgameImport = createCGameImport(imports, stateProvider);
6342
6052
  const cg = GetCGameAPI(cgameImport);
6053
+ demoHandler.setCallbacks({
6054
+ onCenterPrint: (msg) => cg.ParseCenterPrint(msg, 0, false),
6055
+ onPrint: (level, msg) => cg.NotifyMessage(0, msg, false),
6056
+ onConfigString: (index, str3) => {
6057
+ configStrings.set(index, str3);
6058
+ cg.ParseConfigString(index, str3);
6059
+ }
6060
+ });
6061
+ demoPlayback.setHandler(demoHandler);
6062
+ let lastRendered;
6063
+ let lastView;
6064
+ let camera;
6343
6065
  let fovValue = 90;
6344
6066
  let isZooming = false;
6345
6067
  if (imports.host) {
@@ -6595,6 +6317,9 @@ function createClient(imports) {
6595
6317
  },
6596
6318
  DrawHUD(stats, timeMs) {
6597
6319
  if (!imports.engine.renderer) return;
6320
+ const renderer = imports.engine.renderer;
6321
+ const width = renderer.width;
6322
+ const height = renderer.height;
6598
6323
  if (lastRendered && lastRendered.client) {
6599
6324
  const playerState = {
6600
6325
  origin: lastRendered.origin,
@@ -6608,30 +6333,38 @@ function createClient(imports) {
6608
6333
  damageIndicators: lastRendered.damageIndicators ?? [],
6609
6334
  blend: lastRendered.blend ?? [0, 0, 0, 0],
6610
6335
  pickupIcon: lastRendered.pickupIcon,
6611
- centerPrint: messageSystem["centerPrintMsg"]?.text,
6612
- // Hack to get text for legacy state? No, Draw_Hud uses messageSystem directly now.
6336
+ centerPrint: void 0,
6337
+ // Handled by CGame MessageSystem now
6613
6338
  notify: void 0,
6614
6339
  // Stubs for new fields
6615
- stats: [],
6340
+ // Ensure stats are safely initialized
6341
+ stats: lastRendered.stats ? [...lastRendered.stats] : new Array(32).fill(0),
6616
6342
  kick_angles: ZERO_VEC32,
6617
6343
  gunoffset: ZERO_VEC32,
6618
6344
  gunangles: ZERO_VEC32,
6619
6345
  gunindex: 0
6620
6346
  };
6621
- const playbackState = demoPlayback.getState();
6622
- const hudTimeMs = playbackState === PlaybackState.Playing || playbackState === PlaybackState.Paused ? (demoHandler.latestFrame?.serverFrame || 0) * 100 : timeMs;
6623
- Draw_Hud(
6624
- imports.engine.renderer,
6625
- playerState,
6626
- lastRendered.client,
6627
- lastRendered.health ?? 0,
6628
- lastRendered.armor ?? 0,
6629
- lastRendered.ammo ?? 0,
6630
- stats,
6631
- messageSystem,
6632
- subtitleSystem,
6633
- hudTimeMs
6347
+ playerState.stats[PlayerStat.STAT_HEALTH] = lastRendered.health ?? 0;
6348
+ playerState.stats[PlayerStat.STAT_AMMO] = lastRendered.ammo ?? 0;
6349
+ playerState.stats[PlayerStat.STAT_ARMOR] = lastRendered.armor ?? 0;
6350
+ renderer.begin2D();
6351
+ cg.DrawHUD(
6352
+ 0,
6353
+ // isplit
6354
+ null,
6355
+ // data
6356
+ { x: 0, y: 0, width, height },
6357
+ // hud_vrect
6358
+ { x: 0, y: 0, width, height },
6359
+ // hud_safe
6360
+ 1,
6361
+ // scale
6362
+ 0,
6363
+ // playernum
6364
+ playerState
6634
6365
  );
6366
+ subtitleSystem.drawSubtitles(renderer, timeMs);
6367
+ renderer.end2D();
6635
6368
  }
6636
6369
  if (menuSystem.isActive()) {
6637
6370
  Draw_Menu(imports.engine.renderer, menuSystem.getState(), imports.engine.renderer.width, imports.engine.renderer.height);
@@ -6675,12 +6408,10 @@ function createClient(imports) {
6675
6408
  },
6676
6409
  demoPlayback,
6677
6410
  ParseCenterPrint(msg) {
6678
- const timeMs = latestFrame?.timeMs ?? 0;
6679
- messageSystem.addCenterPrint(msg, timeMs);
6411
+ cg.ParseCenterPrint(msg, 0, false);
6680
6412
  },
6681
6413
  ParseNotify(msg) {
6682
- const timeMs = latestFrame?.timeMs ?? 0;
6683
- messageSystem.addNotify(msg, timeMs);
6414
+ cg.NotifyMessage(0, msg, false);
6684
6415
  },
6685
6416
  showSubtitle(text, soundName) {
6686
6417
  const timeMs = latestFrame?.timeMs ?? 0;