h1z1-server 0.23.1 → 0.23.2

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.
Files changed (28) hide show
  1. package/package.json +1 -1
  2. package/src/packets/ClientProtocol/ClientProtocol_1080/command.ts +9 -1
  3. package/src/servers/ZoneServer2016/classes/baseItem.ts +16 -1
  4. package/src/servers/ZoneServer2016/classes/collectingentity.ts +6 -1
  5. package/src/servers/ZoneServer2016/classes/gridcell.ts +1 -3
  6. package/src/servers/ZoneServer2016/classes/loadoutcontainer.ts +1 -1
  7. package/src/servers/ZoneServer2016/classes/smeltingentity.ts +9 -4
  8. package/src/servers/ZoneServer2016/commands/commands.ts +32 -0
  9. package/src/servers/ZoneServer2016/data/Recipes.ts +10 -0
  10. package/src/servers/ZoneServer2016/data/lootspawns.ts +49 -25
  11. package/src/servers/ZoneServer2016/entities/baseentity.ts +7 -2
  12. package/src/servers/ZoneServer2016/entities/basefullcharacter.ts +17 -6
  13. package/src/servers/ZoneServer2016/entities/baselootableentity.ts +7 -2
  14. package/src/servers/ZoneServer2016/entities/constructionchildentity.ts +13 -2
  15. package/src/servers/ZoneServer2016/entities/constructiondoor.ts +109 -66
  16. package/src/servers/ZoneServer2016/entities/constructionparententity.ts +8 -2
  17. package/src/servers/ZoneServer2016/entities/doorentity.ts +7 -2
  18. package/src/servers/ZoneServer2016/entities/itemobject.ts +7 -2
  19. package/src/servers/ZoneServer2016/entities/lootableconstructionentity.ts +7 -2
  20. package/src/servers/ZoneServer2016/entities/lootableprop.ts +7 -1
  21. package/src/servers/ZoneServer2016/entities/plant.ts +7 -2
  22. package/src/servers/ZoneServer2016/entities/vehicle.ts +7 -2
  23. package/src/servers/ZoneServer2016/managers/craftmanager.ts +4 -1
  24. package/src/servers/ZoneServer2016/managers/worlddatamanager.ts +15 -6
  25. package/src/servers/ZoneServer2016/managers/worldobjectmanager.ts +9 -8
  26. package/src/servers/ZoneServer2016/zonepackethandlers.ts +41 -47
  27. package/src/servers/ZoneServer2016/zoneserver.ts +130 -122
  28. package/src/types/zone2016packets.ts +3 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "h1z1-server",
3
- "version": "0.23.1",
3
+ "version": "0.23.2",
4
4
  "description": "Library for emulating h1z1 servers",
5
5
  "author": "Quentin Gruber <quentingruber@gmail.com> (http://github.com/quentingruber)",
6
6
  "license": "GPL-3.0-only",
@@ -35,7 +35,15 @@ export const commandPackets: any = [
35
35
  "Command.InteractRequest",
36
36
  0x090700,
37
37
  {
38
- fields: [{ name: "guid", type: "uint64string", defaultValue: "0" }],
38
+ fields: [
39
+ { name: "characterId", type: "uint64string", defaultValue: "0" },
40
+ {
41
+ name: "entityPosition",
42
+ type: "floatvector4",
43
+ defaultValue: [0, 0, 0, 0],
44
+ },
45
+ { name: "isInstant", type: "boolean", defaultValue: true },
46
+ ],
39
47
  },
40
48
  ],
41
49
  [
@@ -19,7 +19,22 @@ export class BaseItem {
19
19
  itemGuid: string;
20
20
  containerGuid = "0x0";
21
21
  currentDurability: number;
22
- stackCount: number;
22
+ debugFlag: string = "unset";
23
+ set stackCount(stackCount: number) {
24
+ if (stackCount <= 0) {
25
+ console.error(
26
+ `negative stackcount (${stackCount}) detected for item ${this.itemDefinitionId} debugflag ${this.debugFlag}`
27
+ );
28
+ this._stackCount = 1;
29
+ return;
30
+ }
31
+ this._stackCount = stackCount;
32
+ }
33
+ private _stackCount?: number = 0;
34
+ /* eslint-disable @typescript-eslint/adjacent-overload-signatures */
35
+ get stackCount() {
36
+ return this._stackCount || 1;
37
+ }
23
38
  weapon?: Weapon;
24
39
  constructor(
25
40
  itemDefinitionId: number,
@@ -124,7 +124,12 @@ export class CollectingEntity {
124
124
  passed = true;
125
125
  if (this.currentTicks >= this.requiredTicks) {
126
126
  this.currentTicks = 0;
127
- server.removeContainerItemNoClient(item, parentObject, 1);
127
+ server.removeContainerItem(
128
+ this.parentObject,
129
+ item,
130
+ parentObject.getContainer(),
131
+ 1
132
+ );
128
133
  server.addContainerItemExternal(
129
134
  parentObject.mountedCharacter
130
135
  ? parentObject.mountedCharacter
@@ -1,8 +1,6 @@
1
- import { BaseEntity } from "../entities/baseentity";
2
-
3
1
  export class GridCell {
4
2
  position: Float32Array;
5
- objects: Array<BaseEntity> = [];
3
+ objects: Array<any> = [];
6
4
  width: number;
7
5
  height: number;
8
6
  constructor(x: number, y: number, width: number, height: number) {
@@ -199,7 +199,7 @@ export class LoadoutContainer extends LoadoutItem {
199
199
  // allows items in the same container but different stacks to be stacked
200
200
  return;
201
201
  }
202
- if (!server.removeContainerItem(client, item, this, count)) {
202
+ if (!server.removeContainerItem(client.character, item, this, count)) {
203
203
  server.containerError(client, ContainerErrors.NO_ITEM_IN_SLOT);
204
204
  return;
205
205
  }
@@ -148,7 +148,12 @@ export class SmeltingEntity {
148
148
  Object.values(container.items).forEach((item: BaseItem) => {
149
149
  if (allowBurn) return;
150
150
  if (this.allowedFuel.includes(item.itemDefinitionId)) {
151
- server.removeContainerItemNoClient(item, parentObject, 1);
151
+ server.removeContainerItem(
152
+ this.parentObject,
153
+ item,
154
+ this.parentObject.getContainer(),
155
+ 1
156
+ );
152
157
  if (item.itemDefinitionId == Items.WOOD_LOG) {
153
158
  // give charcoal if wood log was burned
154
159
  server.addContainerItemExternal(
@@ -231,9 +236,10 @@ export class SmeltingEntity {
231
236
  if (fulfilledComponents.length == recipe.components.length) {
232
237
  itemsToRemove.forEach(
233
238
  (item: { item: BaseItem; count: number }) => {
234
- server.removeContainerItemNoClient(
239
+ server.removeContainerItem(
240
+ this.parentObject,
235
241
  item.item,
236
- parentObject,
242
+ this.parentObject.getContainer(),
237
243
  item.count
238
244
  );
239
245
  }
@@ -255,7 +261,6 @@ export class SmeltingEntity {
255
261
  });
256
262
  }
257
263
  });
258
- this.isSmelting = false;
259
264
  setTimeout(() => {
260
265
  this.startSmelting(server, parentObject);
261
266
  }, this.smeltingTime);
@@ -1559,6 +1559,38 @@ export const commands: Array<Command> = [
1559
1559
  }
1560
1560
  }
1561
1561
 
1562
+ for (const a in server._temporaryObjects) {
1563
+ const construction = server._temporaryObjects[a];
1564
+ if (
1565
+ isPosInRadius(
1566
+ Number(args[0]),
1567
+ client.character.state.position,
1568
+ construction.state.position
1569
+ )
1570
+ ) {
1571
+ entitiesToDelete.push({
1572
+ characterId: construction.characterId,
1573
+ dictionary: server._temporaryObjects,
1574
+ });
1575
+ }
1576
+ }
1577
+
1578
+ for (const a in server._plants) {
1579
+ const construction = server._plants[a];
1580
+ if (
1581
+ isPosInRadius(
1582
+ Number(args[0]),
1583
+ client.character.state.position,
1584
+ construction.state.position
1585
+ )
1586
+ ) {
1587
+ entitiesToDelete.push({
1588
+ characterId: construction.characterId,
1589
+ dictionary: server._plants,
1590
+ });
1591
+ }
1592
+ }
1593
+
1562
1594
  entitiesToDelete.forEach(
1563
1595
  (entity: { characterId: string; dictionary: any }) => {
1564
1596
  server.deleteEntity(entity.characterId, entity.dictionary, 1875, 500);
@@ -462,6 +462,16 @@ export const smeltingData: { [recipeId: number]: smeltRecipe } = {
462
462
  },
463
463
  ],
464
464
  },
465
+ 41: {
466
+ filterId: FilterIds.FURNACE,
467
+ rewardId: Items.METAL_BAR,
468
+ components: [
469
+ {
470
+ itemDefinitionId: Items.METAL_PIPE,
471
+ requiredAmount: 1,
472
+ },
473
+ ],
474
+ },
465
475
  };
466
476
 
467
477
  export const recipes: { [recipeId: number]: Recipe } = {
@@ -535,6 +535,38 @@ export const lootTables: { [lootSpawner: string]: LootSpawner } = {
535
535
  "ItemSpawnerResidential_Tier00.adr": {
536
536
  spawnChance: 20,
537
537
  items: [
538
+ {
539
+ item: Items.WEAPON_308,
540
+ weight: 7,
541
+ spawnCount: {
542
+ min: 1,
543
+ max: 1,
544
+ },
545
+ },
546
+ {
547
+ item: Items.WEAPON_SHOTGUN,
548
+ weight: 5,
549
+ spawnCount: {
550
+ min: 1,
551
+ max: 1,
552
+ },
553
+ },
554
+ {
555
+ item: Items.WEAPON_1911,
556
+ weight: 10,
557
+ spawnCount: {
558
+ min: 1,
559
+ max: 1,
560
+ },
561
+ },
562
+ {
563
+ item: Items.WEAPON_M9,
564
+ weight: 10,
565
+ spawnCount: {
566
+ min: 1,
567
+ max: 1,
568
+ },
569
+ },
538
570
  {
539
571
  item: Items.DUCT_TAPE,
540
572
  weight: 20,
@@ -553,7 +585,7 @@ export const lootTables: { [lootSpawner: string]: LootSpawner } = {
553
585
  },
554
586
  {
555
587
  item: Items.SHIRT_DEFAULT,
556
- weight: 100,
588
+ weight: 40,
557
589
  spawnCount: {
558
590
  min: 1,
559
591
  max: 1,
@@ -561,7 +593,7 @@ export const lootTables: { [lootSpawner: string]: LootSpawner } = {
561
593
  },
562
594
  {
563
595
  item: Items.PANTS_DEFAULT,
564
- weight: 100,
596
+ weight: 40,
565
597
  spawnCount: {
566
598
  min: 1,
567
599
  max: 1,
@@ -569,7 +601,7 @@ export const lootTables: { [lootSpawner: string]: LootSpawner } = {
569
601
  },
570
602
  {
571
603
  item: Items.CONVEYS_BLUE,
572
- weight: 50,
604
+ weight: 30,
573
605
  spawnCount: {
574
606
  min: 1,
575
607
  max: 1,
@@ -593,7 +625,7 @@ export const lootTables: { [lootSpawner: string]: LootSpawner } = {
593
625
  },
594
626
  {
595
627
  item: Items.HAT_CAP,
596
- weight: 100,
628
+ weight: 15,
597
629
  spawnCount: {
598
630
  min: 1,
599
631
  max: 1,
@@ -601,7 +633,7 @@ export const lootTables: { [lootSpawner: string]: LootSpawner } = {
601
633
  },
602
634
  {
603
635
  item: Items.HAT_BEANIE,
604
- weight: 100,
636
+ weight: 15,
605
637
  spawnCount: {
606
638
  min: 1,
607
639
  max: 1,
@@ -609,7 +641,7 @@ export const lootTables: { [lootSpawner: string]: LootSpawner } = {
609
641
  },
610
642
  {
611
643
  item: Items.HELMET_MOTORCYCLE,
612
- weight: 10,
644
+ weight: 15,
613
645
  spawnCount: {
614
646
  min: 1,
615
647
  max: 1,
@@ -697,7 +729,7 @@ export const lootTables: { [lootSpawner: string]: LootSpawner } = {
697
729
  },
698
730
  {
699
731
  item: Items.AMMO_308,
700
- weight: 20,
732
+ weight: 18,
701
733
  spawnCount: {
702
734
  min: 1,
703
735
  max: 3,
@@ -705,7 +737,7 @@ export const lootTables: { [lootSpawner: string]: LootSpawner } = {
705
737
  },
706
738
  {
707
739
  item: Items.AMMO_12GA,
708
- weight: 20,
740
+ weight: 18,
709
741
  spawnCount: {
710
742
  min: 1,
711
743
  max: 3,
@@ -721,7 +753,7 @@ export const lootTables: { [lootSpawner: string]: LootSpawner } = {
721
753
  },
722
754
  {
723
755
  item: Items.FIRST_AID,
724
- weight: 20,
756
+ weight: 15,
725
757
  spawnCount: {
726
758
  min: 1,
727
759
  max: 1,
@@ -1142,11 +1174,11 @@ export const lootTables: { [lootSpawner: string]: LootSpawner } = {
1142
1174
 
1143
1175
  // #region FARM
1144
1176
  "ItemSpawnerFarm.adr": {
1145
- spawnChance: 30,
1177
+ spawnChance: 50,
1146
1178
  items: [
1147
1179
  {
1148
1180
  item: Items.FERTILIZER,
1149
- weight: 60,
1181
+ weight: 65,
1150
1182
  spawnCount: {
1151
1183
  min: 1,
1152
1184
  max: 1,
@@ -1186,7 +1218,7 @@ export const lootTables: { [lootSpawner: string]: LootSpawner } = {
1186
1218
  },
1187
1219
  {
1188
1220
  item: Items.WATER_EMPTY,
1189
- weight: 40,
1221
+ weight: 35,
1190
1222
  spawnCount: {
1191
1223
  min: 1,
1192
1224
  max: 1,
@@ -1194,7 +1226,7 @@ export const lootTables: { [lootSpawner: string]: LootSpawner } = {
1194
1226
  },
1195
1227
  {
1196
1228
  item: Items.GROUND_TILLER,
1197
- weight: 40,
1229
+ weight: 20,
1198
1230
  spawnCount: {
1199
1231
  min: 1,
1200
1232
  max: 1,
@@ -1862,20 +1894,20 @@ export const containerLootSpawners: {
1862
1894
  ],
1863
1895
  },
1864
1896
  "Weapons Locker": {
1865
- spawnChance: 100,
1897
+ spawnChance: 60,
1866
1898
  maxItems: 1,
1867
1899
  items: [
1868
1900
  {
1869
1901
  item: Items.WEAPON_AR15,
1870
- weight: 30,
1902
+ weight: 20,
1871
1903
  spawnCount: {
1872
1904
  min: 1,
1873
1905
  max: 1,
1874
1906
  },
1875
1907
  },
1876
1908
  {
1877
- item: Items.WEAPON_308,
1878
- weight: 5,
1909
+ item: Items.KEVLAR_DEFAULT,
1910
+ weight: 35,
1879
1911
  spawnCount: {
1880
1912
  min: 1,
1881
1913
  max: 1,
@@ -1889,14 +1921,6 @@ export const containerLootSpawners: {
1889
1921
  max: 11,
1890
1922
  },
1891
1923
  },
1892
- {
1893
- item: Items.AMMO_308,
1894
- weight: 10,
1895
- spawnCount: {
1896
- min: 2,
1897
- max: 8,
1898
- },
1899
- },
1900
1924
  ],
1901
1925
  },
1902
1926
  Locker: {
@@ -84,10 +84,15 @@ export class BaseEntity {
84
84
  // default: do nothing
85
85
  }
86
86
 
87
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
88
- OnPlayerSelect(server: ZoneServer2016, client: ZoneClient2016) {
87
+ /* eslint-disable @typescript-eslint/no-unused-vars */
88
+ OnPlayerSelect(
89
+ server: ZoneServer2016,
90
+ client: ZoneClient2016,
91
+ isInstant?: boolean
92
+ ) {
89
93
  // default: do nothing
90
94
  }
95
+ /* eslint-enable @typescript-eslint/no-unused-vars */
91
96
 
92
97
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
93
98
  OnInteractionString(server: ZoneServer2016, client: ZoneClient2016) {
@@ -28,6 +28,7 @@ import { BaseLightweightCharacter } from "./baselightweightcharacter";
28
28
  import { LoadoutContainer } from "../classes/loadoutcontainer";
29
29
  import { LoadoutItem } from "../classes/loadoutItem";
30
30
  import { ZoneClient2016 } from "../classes/zoneclient";
31
+ import { Weapon } from "../classes/weapon";
31
32
 
32
33
  const debugName = "ZoneServer",
33
34
  debug = require("debug")(debugName);
@@ -482,14 +483,24 @@ export class BaseFullCharacter extends BaseLightweightCharacter {
482
483
 
483
484
  getDeathItems(server: ZoneServer2016) {
484
485
  const items: { [itemGuid: string]: BaseItem } = {};
485
- Object.values(this._loadout).forEach((item) => {
486
+ Object.values(this._loadout).forEach((itemData) => {
486
487
  if (
487
- item.itemGuid != "0x0" &&
488
- !this.isDefaultItem(item.itemDefinitionId) &&
489
- !server.isAdminItem(item.itemDefinitionId)
488
+ itemData.itemGuid != "0x0" &&
489
+ !this.isDefaultItem(itemData.itemDefinitionId) &&
490
+ !server.isAdminItem(itemData.itemDefinitionId)
490
491
  ) {
491
- items[item.itemGuid] = _.cloneDeep(item);
492
- items[item.itemGuid].slotId = Object.keys(items).length + 1;
492
+ const item = new BaseItem(
493
+ itemData.itemDefinitionId,
494
+ itemData.itemGuid,
495
+ itemData.currentDurability,
496
+ itemData.stackCount
497
+ );
498
+
499
+ item.debugFlag = "getDeathItems";
500
+ if (itemData.weapon)
501
+ item.weapon = new Weapon(item, itemData.weapon.ammoCount);
502
+ item.slotId = Object.keys(items).length + 1;
503
+ items[item.itemGuid] = item;
493
504
  }
494
505
  });
495
506
 
@@ -43,8 +43,13 @@ export class BaseLootableEntity extends BaseFullCharacter {
43
43
  stringId: StringIds.OPEN,
44
44
  });
45
45
  }
46
-
47
- OnPlayerSelect(server: ZoneServer2016, client: ZoneClient2016): void {
46
+ /* eslint-disable @typescript-eslint/no-unused-vars */
47
+ OnPlayerSelect(
48
+ server: ZoneServer2016,
49
+ client: ZoneClient2016,
50
+ isInstant?: boolean
51
+ /* eslint-enable @typescript-eslint/no-unused-vars */
52
+ ): void {
48
53
  if (client.character.characterId == this.mountedCharacter) {
49
54
  client.character.dismountContainer(server);
50
55
  delete this.mountedCharacter; // the check below wont fix container if characterId is the same
@@ -345,6 +345,12 @@ export class ConstructionChildEntity extends BaseLightweightCharacter {
345
345
 
346
346
  isInside(position: Float32Array) {
347
347
  if (!this.bounds) {
348
+ switch (this.itemDefinitionId) {
349
+ case Items.STRUCTURE_STAIRS:
350
+ case Items.STRUCTURE_STAIRS_UPPER:
351
+ case Items.LOOKOUT_TOWER:
352
+ return false;
353
+ }
348
354
  console.error(
349
355
  `ERROR: CONSTRUCTION BOUNDS IS NOT DEFINED FOR ${this.itemDefinitionId} ${this.characterId}`
350
356
  );
@@ -485,8 +491,13 @@ export class ConstructionChildEntity extends BaseLightweightCharacter {
485
491
  if (!this.slot) return 0;
486
492
  return getConstructionSlotId(this.slot);
487
493
  }
488
-
489
- OnPlayerSelect(server: ZoneServer2016, client: ZoneClient2016) {
494
+ /* eslint-disable @typescript-eslint/no-unused-vars */
495
+ OnPlayerSelect(
496
+ server: ZoneServer2016,
497
+ client: ZoneClient2016,
498
+ isInstant?: boolean
499
+ /* eslint-enable @typescript-eslint/no-unused-vars */
500
+ ) {
490
501
  if (this.canUndoPlacement(server, client)) {
491
502
  this.destroy(server);
492
503
  client.character.lootItem(
@@ -82,6 +82,7 @@ export class ConstructionDoor extends DoorEntity {
82
82
  );
83
83
  const itemDefinition = server.getItemDefinition(this.itemDefinitionId);
84
84
  if (itemDefinition) this.nameId = itemDefinition.NAME_ID;
85
+ this.grantedAccess.push(ownerCharacterId);
85
86
  }
86
87
 
87
88
  pGetConstructionHealth() {
@@ -176,7 +177,11 @@ export class ConstructionDoor extends DoorEntity {
176
177
  return getConstructionSlotId(this.slot);
177
178
  }
178
179
 
179
- OnPlayerSelect(server: ZoneServer2016, client: ZoneClient2016) {
180
+ OnPlayerSelect(
181
+ server: ZoneServer2016,
182
+ client: ZoneClient2016,
183
+ isInstant?: boolean
184
+ ) {
180
185
  if (this.canUndoPlacement(server, client)) {
181
186
  this.destroy(server);
182
187
  client.character.lootItem(
@@ -186,69 +191,97 @@ export class ConstructionDoor extends DoorEntity {
186
191
  return;
187
192
  }
188
193
 
189
- if (
190
- this.passwordHash != 0 &&
191
- this.ownerCharacterId != client.character.characterId &&
192
- !this.grantedAccess.includes(client.character.characterId)
193
- ) {
194
- server.sendData(client, "Locks.ShowMenu", {
195
- characterId: client.character.characterId,
196
- unknownDword1: 2,
197
- lockType: 2,
198
- objectCharacterId: this.characterId,
199
- });
200
- return;
201
- }
202
- if (
203
- this.passwordHash == 0 &&
204
- this.ownerCharacterId === client.character.characterId
205
- ) {
206
- server.sendData(client, "Locks.ShowMenu", {
207
- characterId: client.character.characterId,
208
- unknownDword1: 2,
209
- lockType: 1,
210
- objectCharacterId: this.characterId,
211
- });
212
- return;
213
- }
214
- if (this.moving) {
215
- return;
216
- }
217
- this.moving = true;
218
- // eslint-disable-next-line
219
- const door = this; // for setTimeout callback
220
- setTimeout(function () {
221
- door.moving = false;
222
- }, 1000);
223
- server.sendDataToAllWithSpawnedEntity(
224
- server._constructionDoors,
225
- this.characterId,
226
- "PlayerUpdatePosition",
227
- {
228
- transientId: this.transientId,
229
- positionUpdate: {
230
- sequenceTime: 0,
231
- unknown3_int8: 0,
232
- position: this.state.position,
233
- orientation: this.isOpen ? this.closedAngle : this.openAngle,
234
- },
194
+ if (isInstant) {
195
+ if (
196
+ this.passwordHash == 0 ||
197
+ this.grantedAccess.includes(client.character.characterId) ||
198
+ client.character.characterId === this.ownerCharacterId
199
+ ) {
200
+ if (this.moving) {
201
+ return;
202
+ }
203
+ this.moving = true;
204
+ // eslint-disable-next-line
205
+ const door = this; // for setTimeout callback
206
+ setTimeout(function () {
207
+ door.moving = false;
208
+ }, 1000);
209
+ server.sendDataToAllWithSpawnedEntity(
210
+ server._constructionDoors,
211
+ this.characterId,
212
+ "PlayerUpdatePosition",
213
+ {
214
+ transientId: this.transientId,
215
+ positionUpdate: {
216
+ sequenceTime: 0,
217
+ unknown3_int8: 0,
218
+ position: this.state.position,
219
+ orientation: this.isOpen ? this.closedAngle : this.openAngle,
220
+ },
221
+ }
222
+ );
223
+ server.sendDataToAllWithSpawnedEntity(
224
+ server._constructionDoors,
225
+ this.characterId,
226
+ "Command.PlayDialogEffect",
227
+ {
228
+ characterId: this.characterId,
229
+ effectId: this.isOpen ? this.closeSound : this.openSound,
230
+ }
231
+ );
232
+ this.isOpen = !this.isOpen;
233
+ this.isSecured = !this.isOpen;
234
+ const parent = this.getParent(server);
235
+ if (parent) {
236
+ parent.updateSecuredState(server);
237
+ // spawn hidden characters emmediately after door opens
238
+ const allowedConstruction = [
239
+ Items.SHELTER,
240
+ Items.SHELTER_LARGE,
241
+ Items.SHELTER_UPPER,
242
+ Items.SHELTER_UPPER_LARGE,
243
+ Items.SHACK,
244
+ Items.SHACK_BASIC,
245
+ Items.SHACK_SMALL,
246
+ ];
247
+ if (
248
+ this.isOpen &&
249
+ allowedConstruction.includes(parent.itemDefinitionId)
250
+ ) {
251
+ for (const a in server._clients) {
252
+ const client = server._clients[a];
253
+ if (client.character.isHidden == parent.characterId)
254
+ server.constructionManager(client);
255
+ }
256
+ }
257
+ }
258
+ return;
259
+ } else {
260
+ server.sendData(client, "Locks.ShowMenu", {
261
+ characterId: client.character.characterId,
262
+ unknownDword1: 2,
263
+ lockType: 2,
264
+ objectCharacterId: this.characterId,
265
+ });
266
+ return;
235
267
  }
236
- );
237
- server.sendDataToAllWithSpawnedEntity(
238
- server._constructionDoors,
239
- this.characterId,
240
- "Command.PlayDialogEffect",
241
- {
242
- characterId: this.characterId,
243
- effectId: this.isOpen ? this.closeSound : this.openSound,
268
+ } else if (!isInstant) {
269
+ if (client.character.characterId === this.ownerCharacterId) {
270
+ server.sendData(client, "Locks.ShowMenu", {
271
+ characterId: client.character.characterId,
272
+ unknownDword1: 2,
273
+ lockType: 1,
274
+ objectCharacterId: this.characterId,
275
+ });
276
+ return;
277
+ } else if (!this.grantedAccess.includes(client.character.characterId)) {
278
+ server.sendData(client, "Locks.ShowMenu", {
279
+ characterId: client.character.characterId,
280
+ unknownDword1: 2,
281
+ lockType: 2,
282
+ objectCharacterId: this.characterId,
283
+ });
244
284
  }
245
- );
246
- this.isOpen = !this.isOpen;
247
- this.isSecured = !this.isOpen;
248
-
249
- const parent = this.getParent(server);
250
- if (parent) {
251
- parent.updateSecuredState(server);
252
285
  }
253
286
  }
254
287
 
@@ -257,9 +290,19 @@ export class ConstructionDoor extends DoorEntity {
257
290
  server.undoPlacementInteractionString(this, client);
258
291
  return;
259
292
  }
260
- server.sendData(client, "Command.InteractionString", {
261
- guid: this.characterId,
262
- stringId: StringIds.OPEN_AND_LOCK,
263
- });
293
+ if (
294
+ client.character.characterId === this.ownerCharacterId ||
295
+ !this.grantedAccess.includes(client.character.characterId)
296
+ ) {
297
+ server.sendData(client, "Command.InteractionString", {
298
+ guid: this.characterId,
299
+ stringId: StringIds.OPEN_AND_LOCK,
300
+ });
301
+ } else {
302
+ server.sendData(client, "Command.InteractionString", {
303
+ guid: this.characterId,
304
+ stringId: StringIds.OPEN,
305
+ });
306
+ }
264
307
  }
265
308
  }