isaacscript-common 12.5.2 → 12.6.1

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/dist/index.d.ts CHANGED
@@ -1779,7 +1779,7 @@ export declare function deployJSONRoom(jsonRoom: JSONRoom | Readonly<JSONRoom>,
1779
1779
  * @param verbose Optional. If specified, will write entries to the "log.txt" file that describe
1780
1780
  * what the function is doing. Default is false.
1781
1781
  */
1782
- export declare function deployRandomJSONRoom(jsonRooms: JSONRoom[] | readonly JSONRoom[], seedOrRNG?: Seed | RNG, verbose?: boolean): void;
1782
+ export declare function deployRandomJSONRoom(jsonRooms: JSONRoom[], seedOrRNG?: Seed | RNG, verbose?: boolean): void;
1783
1783
 
1784
1784
  /**
1785
1785
  * Helper function to convert a `SerializedBitSet128` object to a normal `BitSet128` object. (This
@@ -4527,6 +4527,21 @@ export declare function getRandomFromWeightedArray<T>(weightedArray: WeightedArr
4527
4527
  */
4528
4528
  export declare function getRandomInt(min: int, max: int, seedOrRNG?: Seed | RNG, exceptions?: int[] | readonly int[]): int;
4529
4529
 
4530
+ /**
4531
+ * Helper function to get a random JSON entity from an array of JSON entities.
4532
+ *
4533
+ * Note that this function does not simply choose a random element in the provided array; it will
4534
+ * properly account for each room weight using the algorithm from:
4535
+ * https://stackoverflow.com/questions/1761626/weighted-random-numbers
4536
+ *
4537
+ * @param jsonEntities The array of entities to randomly choose between.
4538
+ * @param seedOrRNG Optional. The `Seed` or `RNG` object to use. If an `RNG` object is provided, the
4539
+ * `RNG.Next` method will be called. Default is `getRandomSeed()`.
4540
+ * @param verbose Optional. If specified, will write entries to the "log.txt" file that describe
4541
+ * what the function is doing. Default is false.
4542
+ */
4543
+ export declare function getRandomJSONEntity(jsonEntities: JSONEntity[], seedOrRNG?: Seed | RNG, verbose?: boolean): JSONEntity;
4544
+
4530
4545
  /**
4531
4546
  * Helper function to get a random JSON room from an array of JSON rooms.
4532
4547
  *
@@ -4534,13 +4549,13 @@ export declare function getRandomInt(min: int, max: int, seedOrRNG?: Seed | RNG,
4534
4549
  * properly account for each room weight using the algorithm from:
4535
4550
  * https://stackoverflow.com/questions/1761626/weighted-random-numbers
4536
4551
  *
4537
- * @param jsonRooms The array of rooms to random choose between.
4552
+ * @param jsonRooms The array of rooms to randomly choose between.
4538
4553
  * @param seedOrRNG Optional. The `Seed` or `RNG` object to use. If an `RNG` object is provided, the
4539
4554
  * `RNG.Next` method will be called. Default is `getRandomSeed()`.
4540
4555
  * @param verbose Optional. If specified, will write entries to the "log.txt" file that describe
4541
4556
  * what the function is doing. Default is false.
4542
4557
  */
4543
- export declare function getRandomJSONRoom(jsonRooms: JSONRoom[] | readonly JSONRoom[], seedOrRNG?: Seed | RNG, verbose?: boolean): JSONRoom;
4558
+ export declare function getRandomJSONRoom(jsonRooms: JSONRoom[], seedOrRNG?: Seed | RNG, verbose?: boolean): JSONRoom;
4544
4559
 
4545
4560
  /**
4546
4561
  * Helper function to get a random color.
@@ -1,6 +1,6 @@
1
1
  --[[
2
2
 
3
- isaacscript-common 12.5.2
3
+ isaacscript-common 12.6.1
4
4
 
5
5
  This is the "isaacscript-common" library, which was created with the IsaacScript tool.
6
6
 
@@ -19235,6 +19235,7 @@ local RockVariant = ____isaac_2Dtypescript_2Ddefinitions.RockVariant
19235
19235
  local StatueVariant = ____isaac_2Dtypescript_2Ddefinitions.StatueVariant
19236
19236
  local TrapdoorVariant = ____isaac_2Dtypescript_2Ddefinitions.TrapdoorVariant
19237
19237
  ____exports.GRID_ENTITY_XML_MAP = __TS__New(Map, {
19238
+ {GridEntityXMLType.DECORATION, {GridEntityType.DECORATION, 0}},
19238
19239
  {GridEntityXMLType.ROCK, {GridEntityType.ROCK, RockVariant.NORMAL}},
19239
19240
  {GridEntityXMLType.ROCK_BOMB, {GridEntityType.ROCK_BOMB, 0}},
19240
19241
  {GridEntityXMLType.ROCK_ALT, {GridEntityType.ROCK_ALT, 0}},
@@ -40810,7 +40811,7 @@ local ____lualib = require("lualib_bundle")
40810
40811
  local __TS__ArrayFilter = ____lualib.__TS__ArrayFilter
40811
40812
  local __TS__ArrayMap = ____lualib.__TS__ArrayMap
40812
40813
  local ____exports = {}
40813
- local getTotalWeightOfJSONRooms, getJSONRoomWithChosenWeight
40814
+ local getTotalWeightOfJSONObject, getJSONObjectWithChosenWeight
40814
40815
  local ____isaac_2Dtypescript_2Ddefinitions = require("lua_modules.isaac-typescript-definitions.dist.src.index")
40815
40816
  local DoorSlotFlagZero = ____isaac_2Dtypescript_2Ddefinitions.DoorSlotFlagZero
40816
40817
  local ____array = require("src.functions.array")
@@ -40826,33 +40827,34 @@ local ____random = require("src.functions.random")
40826
40827
  local getRandomFloat = ____random.getRandomFloat
40827
40828
  local ____rng = require("src.functions.rng")
40828
40829
  local getRandomSeed = ____rng.getRandomSeed
40829
- function getTotalWeightOfJSONRooms(self, jsonRooms)
40830
+ function getTotalWeightOfJSONObject(self, jsonOjectArray)
40830
40831
  local weights = __TS__ArrayMap(
40831
- jsonRooms,
40832
- function(____, jsonRoom)
40833
- local roomWeightString = jsonRoom["$"].weight
40834
- local roomWeight = tonumber(roomWeightString)
40835
- if roomWeight == nil then
40836
- error(("Failed to parse the weight of a JSON room: " .. roomWeightString) .. ".")
40832
+ jsonOjectArray,
40833
+ function(____, jsonObject)
40834
+ local weightString = jsonObject["$"].weight
40835
+ local weight = tonumber(weightString)
40836
+ if weight == nil then
40837
+ error(("Failed to parse the weight of a JSON object: " .. tostring(weightString)) .. ".")
40837
40838
  end
40838
- return roomWeight
40839
+ return weight
40839
40840
  end
40840
40841
  )
40841
40842
  return sumArray(nil, weights)
40842
40843
  end
40843
- function getJSONRoomWithChosenWeight(self, jsonRooms, chosenWeight)
40844
- for ____, jsonRoom in ipairs(jsonRooms) do
40845
- local roomWeightString = jsonRoom["$"].weight
40846
- local roomWeight = tonumber(roomWeightString)
40847
- if roomWeight == nil then
40848
- error("Failed to parse the weight of a JSON room: " .. roomWeightString)
40844
+ function getJSONObjectWithChosenWeight(self, jsonOjectArray, chosenWeight)
40845
+ local weightAccumulator = 0
40846
+ for ____, jsonObject in ipairs(jsonOjectArray) do
40847
+ local weightString = jsonObject["$"].weight
40848
+ local weight = tonumber(weightString)
40849
+ if weight == nil then
40850
+ error("Failed to parse the weight of a JSON object: " .. tostring(weightString))
40849
40851
  end
40850
- if chosenWeight < roomWeight then
40851
- return jsonRoom
40852
+ weightAccumulator = weightAccumulator + weight
40853
+ if weightAccumulator >= chosenWeight then
40854
+ return jsonObject
40852
40855
  end
40853
- chosenWeight = chosenWeight - roomWeight
40854
40856
  end
40855
- error("Failed to get a JSON room with chosen weight: " .. tostring(chosenWeight))
40857
+ return nil
40856
40858
  end
40857
40859
  function ____exports.getJSONRoomDoorSlotFlags(self, jsonRoom)
40858
40860
  local roomShapeString = jsonRoom["$"].shape
@@ -40919,6 +40921,33 @@ function ____exports.getJSONRoomsOfSubType(self, jsonRooms, subType)
40919
40921
  end
40920
40922
  )
40921
40923
  end
40924
+ function ____exports.getRandomJSONEntity(self, jsonEntities, seedOrRNG, verbose)
40925
+ if seedOrRNG == nil then
40926
+ seedOrRNG = getRandomSeed(nil)
40927
+ end
40928
+ if verbose == nil then
40929
+ verbose = false
40930
+ end
40931
+ local totalWeight = getTotalWeightOfJSONObject(nil, jsonEntities)
40932
+ if verbose then
40933
+ log(
40934
+ nil,
40935
+ "Total weight of the JSON entities provided: " .. tostring(totalWeight)
40936
+ )
40937
+ end
40938
+ local chosenWeight = getRandomFloat(nil, 0, totalWeight, seedOrRNG)
40939
+ if verbose then
40940
+ log(
40941
+ nil,
40942
+ "Randomly chose weight for JSON entity: " .. tostring(chosenWeight)
40943
+ )
40944
+ end
40945
+ local randomJSONEntity = getJSONObjectWithChosenWeight(nil, jsonEntities, chosenWeight)
40946
+ if randomJSONEntity == nil then
40947
+ error("Failed to get a JSON entity with chosen weight: " .. tostring(chosenWeight))
40948
+ end
40949
+ return randomJSONEntity
40950
+ end
40922
40951
  function ____exports.getRandomJSONRoom(self, jsonRooms, seedOrRNG, verbose)
40923
40952
  if seedOrRNG == nil then
40924
40953
  seedOrRNG = getRandomSeed(nil)
@@ -40926,7 +40955,7 @@ function ____exports.getRandomJSONRoom(self, jsonRooms, seedOrRNG, verbose)
40926
40955
  if verbose == nil then
40927
40956
  verbose = false
40928
40957
  end
40929
- local totalWeight = getTotalWeightOfJSONRooms(nil, jsonRooms)
40958
+ local totalWeight = getTotalWeightOfJSONObject(nil, jsonRooms)
40930
40959
  if verbose then
40931
40960
  log(
40932
40961
  nil,
@@ -40940,7 +40969,11 @@ function ____exports.getRandomJSONRoom(self, jsonRooms, seedOrRNG, verbose)
40940
40969
  "Randomly chose weight for JSON room: " .. tostring(chosenWeight)
40941
40970
  )
40942
40971
  end
40943
- return getJSONRoomWithChosenWeight(nil, jsonRooms, chosenWeight)
40972
+ local randomJSONRoom = getJSONObjectWithChosenWeight(nil, jsonRooms, chosenWeight)
40973
+ if randomJSONRoom == nil then
40974
+ error("Failed to get a JSON room with chosen weight: " .. tostring(chosenWeight))
40975
+ end
40976
+ return randomJSONRoom
40944
40977
  end
40945
40978
  return ____exports
40946
40979
  end,
@@ -41254,10 +41287,9 @@ local __TS__New = ____lualib.__TS__New
41254
41287
  local Map = ____lualib.Map
41255
41288
  local __TS__Iterator = ____lualib.__TS__Iterator
41256
41289
  local ____exports = {}
41257
- local preUseItemWeNeedToGoDeeper, postNewRoomReordered, setDecorationsInvisible, respawnPersistentEntities, removeSpecificNPCs, fillRoomWithDecorations, spawnAllEntities, spawnGridEntityForJSONRoom, spawnNormalEntityForJSONRoom, storePersistentEntity, fixPitGraphics, getPitMap, getPitFrame, FEATURE_NAME, NPC_TYPES_TO_NOT_REMOVE, PERSISTENT_ENTITY_TYPES, GRID_ENTITY_XML_TYPE_SET, v
41290
+ local preUseItemWeNeedToGoDeeper, postNewRoomReordered, setDecorationsInvisible, respawnPersistentEntities, emptyRoomEntities, emptyRoomGridEntities, fillRoomWithDecorations, spawnAllEntities, spawnGridEntityForJSONRoom, spawnNormalEntityForJSONRoom, storePersistentEntity, fixPitGraphics, getPitMap, getPitFrame, FEATURE_NAME, PERSISTENT_ENTITY_TYPES, GRID_ENTITY_XML_TYPE_SET, EMPTY_ROOM_BLACKLIST_ENTITY_SET, EMPTY_ROOM_BLACKLIST_GRID_ENTITY_SET, v
41258
41291
  local ____isaac_2Dtypescript_2Ddefinitions = require("lua_modules.isaac-typescript-definitions.dist.src.index")
41259
41292
  local CollectibleType = ____isaac_2Dtypescript_2Ddefinitions.CollectibleType
41260
- local EffectVariant = ____isaac_2Dtypescript_2Ddefinitions.EffectVariant
41261
41293
  local EntityCollisionClass = ____isaac_2Dtypescript_2Ddefinitions.EntityCollisionClass
41262
41294
  local EntityFlag = ____isaac_2Dtypescript_2Ddefinitions.EntityFlag
41263
41295
  local EntityGridCollisionClass = ____isaac_2Dtypescript_2Ddefinitions.EntityGridCollisionClass
@@ -41279,25 +41311,21 @@ local errorIfFeaturesNotInitialized = ____featuresInitialized.errorIfFeaturesNot
41279
41311
  local ____array = require("src.functions.array")
41280
41312
  local emptyArray = ____array.emptyArray
41281
41313
  local ____entities = require("src.functions.entities")
41314
+ local getEntities = ____entities.getEntities
41282
41315
  local getEntityIDFromConstituents = ____entities.getEntityIDFromConstituents
41283
- local removeAllMatchingEntities = ____entities.removeAllMatchingEntities
41284
41316
  local spawn = ____entities.spawn
41285
41317
  local spawnWithSeed = ____entities.spawnWithSeed
41286
- local ____entitiesSpecific = require("src.functions.entitiesSpecific")
41287
- local getNPCs = ____entitiesSpecific.getNPCs
41288
- local removeAllBombs = ____entitiesSpecific.removeAllBombs
41289
- local removeAllPickups = ____entitiesSpecific.removeAllPickups
41290
41318
  local ____enums = require("src.functions.enums")
41291
41319
  local getEnumValues = ____enums.getEnumValues
41292
41320
  local ____gridEntities = require("src.functions.gridEntities")
41293
41321
  local convertXMLGridEntityType = ____gridEntities.convertXMLGridEntityType
41294
41322
  local getAllGridIndexes = ____gridEntities.getAllGridIndexes
41295
41323
  local getGridEntities = ____gridEntities.getGridEntities
41296
- local removeAllGridEntitiesExcept = ____gridEntities.removeAllGridEntitiesExcept
41297
41324
  local removeGridEntity = ____gridEntities.removeGridEntity
41298
41325
  local setGridEntityInvisible = ____gridEntities.setGridEntityInvisible
41299
41326
  local spawnGridEntityWithVariant = ____gridEntities.spawnGridEntityWithVariant
41300
41327
  local ____jsonRoom = require("src.functions.jsonRoom")
41328
+ local getRandomJSONEntity = ____jsonRoom.getRandomJSONEntity
41301
41329
  local getRandomJSONRoom = ____jsonRoom.getRandomJSONRoom
41302
41330
  local ____log = require("src.functions.log")
41303
41331
  local log = ____log.log
@@ -41310,6 +41338,7 @@ local getRoomListIndex = ____roomData.getRoomListIndex
41310
41338
  local ____roomGrid = require("src.functions.roomGrid")
41311
41339
  local gridCoordinatesToWorldPosition = ____roomGrid.gridCoordinatesToWorldPosition
41312
41340
  local ____rooms = require("src.functions.rooms")
41341
+ local roomUpdateSafe = ____rooms.roomUpdateSafe
41313
41342
  local setRoomCleared = ____rooms.setRoomCleared
41314
41343
  local setRoomUncleared = ____rooms.setRoomUncleared
41315
41344
  local ____spawnCollectible = require("src.functions.spawnCollectible")
@@ -41396,38 +41425,50 @@ function ____exports.emptyRoom(self, fillWithDecorations)
41396
41425
  errorIfFeaturesNotInitialized(nil, FEATURE_NAME)
41397
41426
  local roomListIndex = getRoomListIndex(nil)
41398
41427
  v.level.deployedRoomListIndexes:add(roomListIndex)
41399
- removeAllBombs(nil)
41400
- removeAllPickups(nil)
41401
- removeAllMatchingEntities(nil, EntityType.SLOT)
41402
- removeSpecificNPCs(nil)
41403
- removeAllMatchingEntities(nil, EntityType.EFFECT, EffectVariant.DEVIL)
41404
- removeAllMatchingEntities(nil, EntityType.EFFECT, EffectVariant.ANGEL)
41405
- removeAllGridEntitiesExcept(nil, GridEntityType.WALL, GridEntityType.DOOR)
41428
+ emptyRoomEntities(nil)
41429
+ emptyRoomGridEntities(nil)
41406
41430
  setRoomCleared(nil)
41407
41431
  if fillWithDecorations then
41408
41432
  fillRoomWithDecorations(nil)
41409
41433
  end
41410
41434
  end
41411
- function removeSpecificNPCs(self)
41435
+ function emptyRoomEntities(self)
41412
41436
  local room = game:GetRoom()
41413
- for ____, npc in ipairs(getNPCs(nil)) do
41437
+ for ____, entity in ipairs(getEntities(nil)) do
41414
41438
  do
41415
- if NPC_TYPES_TO_NOT_REMOVE:has(npc.Type) then
41439
+ if EMPTY_ROOM_BLACKLIST_ENTITY_SET:has(entity.Type) then
41416
41440
  goto __continue33
41417
41441
  end
41418
- if npc:HasEntityFlags(EntityFlag.CHARM) or npc:HasEntityFlags(EntityFlag.FRIENDLY) or npc:HasEntityFlags(EntityFlag.PERSISTENT) then
41442
+ if entity:HasEntityFlags(EntityFlag.CHARM) or entity:HasEntityFlags(EntityFlag.FRIENDLY) or entity:HasEntityFlags(EntityFlag.PERSISTENT) then
41419
41443
  goto __continue33
41420
41444
  end
41421
- npc:ClearEntityFlags(EntityFlag.APPEAR)
41422
- npc:Remove()
41423
- if npc.Type == EntityType.FIREPLACE then
41424
- local gridIndex = room:GetGridIndex(npc.Position)
41445
+ entity:ClearEntityFlags(EntityFlag.APPEAR)
41446
+ entity:Remove()
41447
+ if entity.Type == EntityType.FIREPLACE then
41448
+ local gridIndex = room:GetGridIndex(entity.Position)
41425
41449
  room:SetGridPath(gridIndex, 0)
41426
41450
  end
41427
41451
  end
41428
41452
  ::__continue33::
41429
41453
  end
41430
41454
  end
41455
+ function emptyRoomGridEntities(self)
41456
+ local removedOneOrMoreGridEntities = false
41457
+ for ____, gridEntity in ipairs(getGridEntities(nil)) do
41458
+ do
41459
+ local gridEntityType = gridEntity:GetType()
41460
+ if EMPTY_ROOM_BLACKLIST_GRID_ENTITY_SET:has(gridEntityType) then
41461
+ goto __continue39
41462
+ end
41463
+ removeGridEntity(nil, gridEntity, false)
41464
+ removedOneOrMoreGridEntities = true
41465
+ end
41466
+ ::__continue39::
41467
+ end
41468
+ if removedOneOrMoreGridEntities then
41469
+ roomUpdateSafe(nil)
41470
+ end
41471
+ end
41431
41472
  function fillRoomWithDecorations(self)
41432
41473
  local room = game:GetRoom()
41433
41474
  local roomListIndex = getRoomListIndex(nil)
@@ -41436,7 +41477,7 @@ function fillRoomWithDecorations(self)
41436
41477
  do
41437
41478
  local existingGridEntity = room:GetGridEntity(gridIndex)
41438
41479
  if existingGridEntity ~= nil then
41439
- goto __continue39
41480
+ goto __continue44
41440
41481
  end
41441
41482
  local position = room:GetGridPosition(gridIndex)
41442
41483
  local decoration = Isaac.GridSpawn(GridEntityType.DECORATION, 0, position)
@@ -41445,7 +41486,7 @@ function fillRoomWithDecorations(self)
41445
41486
  end
41446
41487
  decorationGridIndexes[#decorationGridIndexes + 1] = gridIndex
41447
41488
  end
41448
- ::__continue39::
41489
+ ::__continue44::
41449
41490
  end
41450
41491
  end
41451
41492
  function spawnAllEntities(self, jsonRoom, rng, verbose)
@@ -41464,24 +41505,18 @@ function spawnAllEntities(self, jsonRoom, rng, verbose)
41464
41505
  if y == nil then
41465
41506
  error("Failed to convert the following y coordinate to a number (for a spawn): " .. yString)
41466
41507
  end
41467
- if #jsonSpawn.entity > 1 then
41468
- error("Stacked entities are not implemented for JSON rooms.")
41469
- end
41470
- local firstXMLEntity = jsonSpawn.entity[1]
41471
- if firstXMLEntity == nil then
41472
- error("Failed to get the first JSON entity from an \"entity\" array.")
41473
- end
41474
- local entityTypeString = firstXMLEntity["$"].type
41508
+ local jsonEntity = getRandomJSONEntity(nil, jsonSpawn.entity)
41509
+ local entityTypeString = jsonEntity["$"].type
41475
41510
  local entityTypeNumber = tonumber(entityTypeString)
41476
41511
  if entityTypeNumber == nil then
41477
41512
  error("Failed to convert the entity type to a number: " .. entityTypeString)
41478
41513
  end
41479
- local variantString = firstXMLEntity["$"].variant
41514
+ local variantString = jsonEntity["$"].variant
41480
41515
  local variant = tonumber(variantString)
41481
41516
  if variant == nil then
41482
41517
  error("Failed to convert the entity variant to a number: " .. tostring(variant))
41483
41518
  end
41484
- local subTypeString = firstXMLEntity["$"].subtype
41519
+ local subTypeString = jsonEntity["$"].subtype
41485
41520
  local subType = tonumber(subTypeString)
41486
41521
  if subType == nil then
41487
41522
  error("Failed to convert the entity sub-type to a number: " .. tostring(subType))
@@ -41709,10 +41744,19 @@ function getPitFrame(self, L, R, U, D, UL, UR, DL, DR)
41709
41744
  return F
41710
41745
  end
41711
41746
  FEATURE_NAME = "deployJSONRoom"
41712
- NPC_TYPES_TO_NOT_REMOVE = __TS__New(Set, {EntityType.DARK_ESAU})
41713
41747
  PERSISTENT_ENTITY_TYPES = __TS__New(Set, {EntityType.WALL_HUGGER})
41714
41748
  local gridEntityXMLTypes = getEnumValues(nil, GridEntityXMLType)
41715
41749
  GRID_ENTITY_XML_TYPE_SET = __TS__New(Set, gridEntityXMLTypes)
41750
+ EMPTY_ROOM_BLACKLIST_ENTITY_SET = __TS__New(Set, {
41751
+ EntityType.PLAYER,
41752
+ EntityType.TEAR,
41753
+ EntityType.FAMILIAR,
41754
+ EntityType.LASER,
41755
+ EntityType.KNIFE,
41756
+ EntityType.PROJECTILE,
41757
+ EntityType.DARK_ESAU
41758
+ })
41759
+ EMPTY_ROOM_BLACKLIST_GRID_ENTITY_SET = __TS__New(Set, {GridEntityType.WALL, GridEntityType.DOOR})
41716
41760
  v = {
41717
41761
  level = {
41718
41762
  deployedRoomListIndexes = __TS__New(Set),
@@ -62,7 +62,7 @@ export declare function deployJSONRoom(jsonRoom: JSONRoom | Readonly<JSONRoom>,
62
62
  * @param verbose Optional. If specified, will write entries to the "log.txt" file that describe
63
63
  * what the function is doing. Default is false.
64
64
  */
65
- export declare function deployRandomJSONRoom(jsonRooms: JSONRoom[] | readonly JSONRoom[], seedOrRNG?: Seed | RNG, verbose?: boolean): void;
65
+ export declare function deployRandomJSONRoom(jsonRooms: JSONRoom[], seedOrRNG?: Seed | RNG, verbose?: boolean): void;
66
66
  /**
67
67
  * Helper function to remove all naturally spawning entities and grid entities from a room. Notably,
68
68
  * this will not remove players (1), tears (2), familiars (3), lasers (7), knives (8), projectiles
@@ -1 +1 @@
1
- {"version":3,"file":"deployJSONRoom.d.ts","sourceRoot":"","sources":["../../../src/features/deployJSONRoom.ts"],"names":[],"mappings":";;AAwDA,OAAO,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AA4KvD;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,QAAQ,GAAG,QAAQ,CAAC,QAAQ,CAAC,EACvC,SAAS,GAAE,IAAI,GAAG,GAAqB,EACvC,OAAO,UAAQ,GACd,IAAI,CAuBN;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,QAAQ,EAAE,GAAG,SAAS,QAAQ,EAAE,EAC3C,SAAS,GAAE,IAAI,GAAG,GAAqB,EACvC,OAAO,UAAQ,GACd,IAAI,CAaN;AAED;;;;;;;;;GASG;AACH,wBAAgB,SAAS,CAAC,mBAAmB,EAAE,OAAO,GAAG,IAAI,CAwB5D"}
1
+ {"version":3,"file":"deployJSONRoom.d.ts","sourceRoot":"","sources":["../../../src/features/deployJSONRoom.ts"],"names":[],"mappings":";;AAqDA,OAAO,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AAwLvD;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,QAAQ,GAAG,QAAQ,CAAC,QAAQ,CAAC,EACvC,SAAS,GAAE,IAAI,GAAG,GAAqB,EACvC,OAAO,UAAQ,GACd,IAAI,CAuBN;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,QAAQ,EAAE,EACrB,SAAS,GAAE,IAAI,GAAG,GAAqB,EACvC,OAAO,UAAQ,GACd,IAAI,CAaN;AAED;;;;;;;;;GASG;AACH,wBAAgB,SAAS,CAAC,mBAAmB,EAAE,OAAO,GAAG,IAAI,CAa5D"}
@@ -4,10 +4,9 @@ local __TS__New = ____lualib.__TS__New
4
4
  local Map = ____lualib.Map
5
5
  local __TS__Iterator = ____lualib.__TS__Iterator
6
6
  local ____exports = {}
7
- local preUseItemWeNeedToGoDeeper, postNewRoomReordered, setDecorationsInvisible, respawnPersistentEntities, removeSpecificNPCs, fillRoomWithDecorations, spawnAllEntities, spawnGridEntityForJSONRoom, spawnNormalEntityForJSONRoom, storePersistentEntity, fixPitGraphics, getPitMap, getPitFrame, FEATURE_NAME, NPC_TYPES_TO_NOT_REMOVE, PERSISTENT_ENTITY_TYPES, GRID_ENTITY_XML_TYPE_SET, v
7
+ local preUseItemWeNeedToGoDeeper, postNewRoomReordered, setDecorationsInvisible, respawnPersistentEntities, emptyRoomEntities, emptyRoomGridEntities, fillRoomWithDecorations, spawnAllEntities, spawnGridEntityForJSONRoom, spawnNormalEntityForJSONRoom, storePersistentEntity, fixPitGraphics, getPitMap, getPitFrame, FEATURE_NAME, PERSISTENT_ENTITY_TYPES, GRID_ENTITY_XML_TYPE_SET, EMPTY_ROOM_BLACKLIST_ENTITY_SET, EMPTY_ROOM_BLACKLIST_GRID_ENTITY_SET, v
8
8
  local ____isaac_2Dtypescript_2Ddefinitions = require("isaac-typescript-definitions")
9
9
  local CollectibleType = ____isaac_2Dtypescript_2Ddefinitions.CollectibleType
10
- local EffectVariant = ____isaac_2Dtypescript_2Ddefinitions.EffectVariant
11
10
  local EntityCollisionClass = ____isaac_2Dtypescript_2Ddefinitions.EntityCollisionClass
12
11
  local EntityFlag = ____isaac_2Dtypescript_2Ddefinitions.EntityFlag
13
12
  local EntityGridCollisionClass = ____isaac_2Dtypescript_2Ddefinitions.EntityGridCollisionClass
@@ -29,25 +28,21 @@ local errorIfFeaturesNotInitialized = ____featuresInitialized.errorIfFeaturesNot
29
28
  local ____array = require("src.functions.array")
30
29
  local emptyArray = ____array.emptyArray
31
30
  local ____entities = require("src.functions.entities")
31
+ local getEntities = ____entities.getEntities
32
32
  local getEntityIDFromConstituents = ____entities.getEntityIDFromConstituents
33
- local removeAllMatchingEntities = ____entities.removeAllMatchingEntities
34
33
  local spawn = ____entities.spawn
35
34
  local spawnWithSeed = ____entities.spawnWithSeed
36
- local ____entitiesSpecific = require("src.functions.entitiesSpecific")
37
- local getNPCs = ____entitiesSpecific.getNPCs
38
- local removeAllBombs = ____entitiesSpecific.removeAllBombs
39
- local removeAllPickups = ____entitiesSpecific.removeAllPickups
40
35
  local ____enums = require("src.functions.enums")
41
36
  local getEnumValues = ____enums.getEnumValues
42
37
  local ____gridEntities = require("src.functions.gridEntities")
43
38
  local convertXMLGridEntityType = ____gridEntities.convertXMLGridEntityType
44
39
  local getAllGridIndexes = ____gridEntities.getAllGridIndexes
45
40
  local getGridEntities = ____gridEntities.getGridEntities
46
- local removeAllGridEntitiesExcept = ____gridEntities.removeAllGridEntitiesExcept
47
41
  local removeGridEntity = ____gridEntities.removeGridEntity
48
42
  local setGridEntityInvisible = ____gridEntities.setGridEntityInvisible
49
43
  local spawnGridEntityWithVariant = ____gridEntities.spawnGridEntityWithVariant
50
44
  local ____jsonRoom = require("src.functions.jsonRoom")
45
+ local getRandomJSONEntity = ____jsonRoom.getRandomJSONEntity
51
46
  local getRandomJSONRoom = ____jsonRoom.getRandomJSONRoom
52
47
  local ____log = require("src.functions.log")
53
48
  local log = ____log.log
@@ -60,6 +55,7 @@ local getRoomListIndex = ____roomData.getRoomListIndex
60
55
  local ____roomGrid = require("src.functions.roomGrid")
61
56
  local gridCoordinatesToWorldPosition = ____roomGrid.gridCoordinatesToWorldPosition
62
57
  local ____rooms = require("src.functions.rooms")
58
+ local roomUpdateSafe = ____rooms.roomUpdateSafe
63
59
  local setRoomCleared = ____rooms.setRoomCleared
64
60
  local setRoomUncleared = ____rooms.setRoomUncleared
65
61
  local ____spawnCollectible = require("src.functions.spawnCollectible")
@@ -154,38 +150,50 @@ function ____exports.emptyRoom(self, fillWithDecorations)
154
150
  errorIfFeaturesNotInitialized(nil, FEATURE_NAME)
155
151
  local roomListIndex = getRoomListIndex(nil)
156
152
  v.level.deployedRoomListIndexes:add(roomListIndex)
157
- removeAllBombs(nil)
158
- removeAllPickups(nil)
159
- removeAllMatchingEntities(nil, EntityType.SLOT)
160
- removeSpecificNPCs(nil)
161
- removeAllMatchingEntities(nil, EntityType.EFFECT, EffectVariant.DEVIL)
162
- removeAllMatchingEntities(nil, EntityType.EFFECT, EffectVariant.ANGEL)
163
- removeAllGridEntitiesExcept(nil, GridEntityType.WALL, GridEntityType.DOOR)
153
+ emptyRoomEntities(nil)
154
+ emptyRoomGridEntities(nil)
164
155
  setRoomCleared(nil)
165
156
  if fillWithDecorations then
166
157
  fillRoomWithDecorations(nil)
167
158
  end
168
159
  end
169
- function removeSpecificNPCs(self)
160
+ function emptyRoomEntities(self)
170
161
  local room = game:GetRoom()
171
- for ____, npc in ipairs(getNPCs(nil)) do
162
+ for ____, entity in ipairs(getEntities(nil)) do
172
163
  do
173
- if NPC_TYPES_TO_NOT_REMOVE:has(npc.Type) then
164
+ if EMPTY_ROOM_BLACKLIST_ENTITY_SET:has(entity.Type) then
174
165
  goto __continue33
175
166
  end
176
- if npc:HasEntityFlags(EntityFlag.CHARM) or npc:HasEntityFlags(EntityFlag.FRIENDLY) or npc:HasEntityFlags(EntityFlag.PERSISTENT) then
167
+ if entity:HasEntityFlags(EntityFlag.CHARM) or entity:HasEntityFlags(EntityFlag.FRIENDLY) or entity:HasEntityFlags(EntityFlag.PERSISTENT) then
177
168
  goto __continue33
178
169
  end
179
- npc:ClearEntityFlags(EntityFlag.APPEAR)
180
- npc:Remove()
181
- if npc.Type == EntityType.FIREPLACE then
182
- local gridIndex = room:GetGridIndex(npc.Position)
170
+ entity:ClearEntityFlags(EntityFlag.APPEAR)
171
+ entity:Remove()
172
+ if entity.Type == EntityType.FIREPLACE then
173
+ local gridIndex = room:GetGridIndex(entity.Position)
183
174
  room:SetGridPath(gridIndex, 0)
184
175
  end
185
176
  end
186
177
  ::__continue33::
187
178
  end
188
179
  end
180
+ function emptyRoomGridEntities(self)
181
+ local removedOneOrMoreGridEntities = false
182
+ for ____, gridEntity in ipairs(getGridEntities(nil)) do
183
+ do
184
+ local gridEntityType = gridEntity:GetType()
185
+ if EMPTY_ROOM_BLACKLIST_GRID_ENTITY_SET:has(gridEntityType) then
186
+ goto __continue39
187
+ end
188
+ removeGridEntity(nil, gridEntity, false)
189
+ removedOneOrMoreGridEntities = true
190
+ end
191
+ ::__continue39::
192
+ end
193
+ if removedOneOrMoreGridEntities then
194
+ roomUpdateSafe(nil)
195
+ end
196
+ end
189
197
  function fillRoomWithDecorations(self)
190
198
  local room = game:GetRoom()
191
199
  local roomListIndex = getRoomListIndex(nil)
@@ -194,7 +202,7 @@ function fillRoomWithDecorations(self)
194
202
  do
195
203
  local existingGridEntity = room:GetGridEntity(gridIndex)
196
204
  if existingGridEntity ~= nil then
197
- goto __continue39
205
+ goto __continue44
198
206
  end
199
207
  local position = room:GetGridPosition(gridIndex)
200
208
  local decoration = Isaac.GridSpawn(GridEntityType.DECORATION, 0, position)
@@ -203,7 +211,7 @@ function fillRoomWithDecorations(self)
203
211
  end
204
212
  decorationGridIndexes[#decorationGridIndexes + 1] = gridIndex
205
213
  end
206
- ::__continue39::
214
+ ::__continue44::
207
215
  end
208
216
  end
209
217
  function spawnAllEntities(self, jsonRoom, rng, verbose)
@@ -222,24 +230,18 @@ function spawnAllEntities(self, jsonRoom, rng, verbose)
222
230
  if y == nil then
223
231
  error("Failed to convert the following y coordinate to a number (for a spawn): " .. yString)
224
232
  end
225
- if #jsonSpawn.entity > 1 then
226
- error("Stacked entities are not implemented for JSON rooms.")
227
- end
228
- local firstXMLEntity = jsonSpawn.entity[1]
229
- if firstXMLEntity == nil then
230
- error("Failed to get the first JSON entity from an \"entity\" array.")
231
- end
232
- local entityTypeString = firstXMLEntity["$"].type
233
+ local jsonEntity = getRandomJSONEntity(nil, jsonSpawn.entity)
234
+ local entityTypeString = jsonEntity["$"].type
233
235
  local entityTypeNumber = tonumber(entityTypeString)
234
236
  if entityTypeNumber == nil then
235
237
  error("Failed to convert the entity type to a number: " .. entityTypeString)
236
238
  end
237
- local variantString = firstXMLEntity["$"].variant
239
+ local variantString = jsonEntity["$"].variant
238
240
  local variant = tonumber(variantString)
239
241
  if variant == nil then
240
242
  error("Failed to convert the entity variant to a number: " .. tostring(variant))
241
243
  end
242
- local subTypeString = firstXMLEntity["$"].subtype
244
+ local subTypeString = jsonEntity["$"].subtype
243
245
  local subType = tonumber(subTypeString)
244
246
  if subType == nil then
245
247
  error("Failed to convert the entity sub-type to a number: " .. tostring(subType))
@@ -467,10 +469,19 @@ function getPitFrame(self, L, R, U, D, UL, UR, DL, DR)
467
469
  return F
468
470
  end
469
471
  FEATURE_NAME = "deployJSONRoom"
470
- NPC_TYPES_TO_NOT_REMOVE = __TS__New(Set, {EntityType.DARK_ESAU})
471
472
  PERSISTENT_ENTITY_TYPES = __TS__New(Set, {EntityType.WALL_HUGGER})
472
473
  local gridEntityXMLTypes = getEnumValues(nil, GridEntityXMLType)
473
474
  GRID_ENTITY_XML_TYPE_SET = __TS__New(Set, gridEntityXMLTypes)
475
+ EMPTY_ROOM_BLACKLIST_ENTITY_SET = __TS__New(Set, {
476
+ EntityType.PLAYER,
477
+ EntityType.TEAR,
478
+ EntityType.FAMILIAR,
479
+ EntityType.LASER,
480
+ EntityType.KNIFE,
481
+ EntityType.PROJECTILE,
482
+ EntityType.DARK_ESAU
483
+ })
484
+ EMPTY_ROOM_BLACKLIST_GRID_ENTITY_SET = __TS__New(Set, {GridEntityType.WALL, GridEntityType.DOOR})
474
485
  v = {
475
486
  level = {
476
487
  deployedRoomListIndexes = __TS__New(Set),
@@ -1,5 +1,5 @@
1
1
  import { DoorSlotFlag } from "isaac-typescript-definitions";
2
- import { JSONRoom } from "../interfaces/JSONRoomsFile";
2
+ import { JSONEntity, JSONRoom } from "../interfaces/JSONRoomsFile";
3
3
  /**
4
4
  * Helper function to calculate what the resulting `BitFlags<DoorSlotFlag>` value would be for a
5
5
  * given JSON room.
@@ -20,6 +20,20 @@ export declare function getJSONRoomOfVariant(jsonRooms: JSONRoom[] | readonly JS
20
20
  * @param subType The sub-type to match.
21
21
  */
22
22
  export declare function getJSONRoomsOfSubType(jsonRooms: JSONRoom[] | readonly JSONRoom[], subType: int): JSONRoom[];
23
+ /**
24
+ * Helper function to get a random JSON entity from an array of JSON entities.
25
+ *
26
+ * Note that this function does not simply choose a random element in the provided array; it will
27
+ * properly account for each room weight using the algorithm from:
28
+ * https://stackoverflow.com/questions/1761626/weighted-random-numbers
29
+ *
30
+ * @param jsonEntities The array of entities to randomly choose between.
31
+ * @param seedOrRNG Optional. The `Seed` or `RNG` object to use. If an `RNG` object is provided, the
32
+ * `RNG.Next` method will be called. Default is `getRandomSeed()`.
33
+ * @param verbose Optional. If specified, will write entries to the "log.txt" file that describe
34
+ * what the function is doing. Default is false.
35
+ */
36
+ export declare function getRandomJSONEntity(jsonEntities: JSONEntity[], seedOrRNG?: Seed | RNG, verbose?: boolean): JSONEntity;
23
37
  /**
24
38
  * Helper function to get a random JSON room from an array of JSON rooms.
25
39
  *
@@ -27,11 +41,11 @@ export declare function getJSONRoomsOfSubType(jsonRooms: JSONRoom[] | readonly J
27
41
  * properly account for each room weight using the algorithm from:
28
42
  * https://stackoverflow.com/questions/1761626/weighted-random-numbers
29
43
  *
30
- * @param jsonRooms The array of rooms to random choose between.
44
+ * @param jsonRooms The array of rooms to randomly choose between.
31
45
  * @param seedOrRNG Optional. The `Seed` or `RNG` object to use. If an `RNG` object is provided, the
32
46
  * `RNG.Next` method will be called. Default is `getRandomSeed()`.
33
47
  * @param verbose Optional. If specified, will write entries to the "log.txt" file that describe
34
48
  * what the function is doing. Default is false.
35
49
  */
36
- export declare function getRandomJSONRoom(jsonRooms: JSONRoom[] | readonly JSONRoom[], seedOrRNG?: Seed | RNG, verbose?: boolean): JSONRoom;
50
+ export declare function getRandomJSONRoom(jsonRooms: JSONRoom[], seedOrRNG?: Seed | RNG, verbose?: boolean): JSONRoom;
37
51
  //# sourceMappingURL=jsonRoom.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"jsonRoom.d.ts","sourceRoot":"","sources":["../../../src/functions/jsonRoom.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EAGb,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AAQvD;;;GAGG;AACH,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,QAAQ,GACjB,QAAQ,CAAC,YAAY,CAAC,CAgDxB;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,QAAQ,EAAE,GAAG,SAAS,QAAQ,EAAE,EAC3C,OAAO,EAAE,GAAG,GACX,QAAQ,GAAG,SAAS,CAoBtB;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,QAAQ,EAAE,GAAG,SAAS,QAAQ,EAAE,EAC3C,OAAO,EAAE,GAAG,GACX,QAAQ,EAAE,CAMZ;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,QAAQ,EAAE,GAAG,SAAS,QAAQ,EAAE,EAC3C,SAAS,GAAE,IAAI,GAAG,GAAqB,EACvC,OAAO,UAAQ,GACd,QAAQ,CAYV"}
1
+ {"version":3,"file":"jsonRoom.d.ts","sourceRoot":"","sources":["../../../src/functions/jsonRoom.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EAGb,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AAanE;;;GAGG;AACH,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,QAAQ,GACjB,QAAQ,CAAC,YAAY,CAAC,CAgDxB;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,QAAQ,EAAE,GAAG,SAAS,QAAQ,EAAE,EAC3C,OAAO,EAAE,GAAG,GACX,QAAQ,GAAG,SAAS,CAoBtB;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,QAAQ,EAAE,GAAG,SAAS,QAAQ,EAAE,EAC3C,OAAO,EAAE,GAAG,GACX,QAAQ,EAAE,CAMZ;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,mBAAmB,CACjC,YAAY,EAAE,UAAU,EAAE,EAC1B,SAAS,GAAE,IAAI,GAAG,GAAqB,EACvC,OAAO,UAAQ,GACd,UAAU,CAoBZ;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,QAAQ,EAAE,EACrB,SAAS,GAAE,IAAI,GAAG,GAAqB,EACvC,OAAO,UAAQ,GACd,QAAQ,CAiBV"}
@@ -2,7 +2,7 @@ local ____lualib = require("lualib_bundle")
2
2
  local __TS__ArrayFilter = ____lualib.__TS__ArrayFilter
3
3
  local __TS__ArrayMap = ____lualib.__TS__ArrayMap
4
4
  local ____exports = {}
5
- local getTotalWeightOfJSONRooms, getJSONRoomWithChosenWeight
5
+ local getTotalWeightOfJSONObject, getJSONObjectWithChosenWeight
6
6
  local ____isaac_2Dtypescript_2Ddefinitions = require("isaac-typescript-definitions")
7
7
  local DoorSlotFlagZero = ____isaac_2Dtypescript_2Ddefinitions.DoorSlotFlagZero
8
8
  local ____array = require("src.functions.array")
@@ -18,33 +18,34 @@ local ____random = require("src.functions.random")
18
18
  local getRandomFloat = ____random.getRandomFloat
19
19
  local ____rng = require("src.functions.rng")
20
20
  local getRandomSeed = ____rng.getRandomSeed
21
- function getTotalWeightOfJSONRooms(self, jsonRooms)
21
+ function getTotalWeightOfJSONObject(self, jsonOjectArray)
22
22
  local weights = __TS__ArrayMap(
23
- jsonRooms,
24
- function(____, jsonRoom)
25
- local roomWeightString = jsonRoom["$"].weight
26
- local roomWeight = tonumber(roomWeightString)
27
- if roomWeight == nil then
28
- error(("Failed to parse the weight of a JSON room: " .. roomWeightString) .. ".")
23
+ jsonOjectArray,
24
+ function(____, jsonObject)
25
+ local weightString = jsonObject["$"].weight
26
+ local weight = tonumber(weightString)
27
+ if weight == nil then
28
+ error(("Failed to parse the weight of a JSON object: " .. tostring(weightString)) .. ".")
29
29
  end
30
- return roomWeight
30
+ return weight
31
31
  end
32
32
  )
33
33
  return sumArray(nil, weights)
34
34
  end
35
- function getJSONRoomWithChosenWeight(self, jsonRooms, chosenWeight)
36
- for ____, jsonRoom in ipairs(jsonRooms) do
37
- local roomWeightString = jsonRoom["$"].weight
38
- local roomWeight = tonumber(roomWeightString)
39
- if roomWeight == nil then
40
- error("Failed to parse the weight of a JSON room: " .. roomWeightString)
35
+ function getJSONObjectWithChosenWeight(self, jsonOjectArray, chosenWeight)
36
+ local weightAccumulator = 0
37
+ for ____, jsonObject in ipairs(jsonOjectArray) do
38
+ local weightString = jsonObject["$"].weight
39
+ local weight = tonumber(weightString)
40
+ if weight == nil then
41
+ error("Failed to parse the weight of a JSON object: " .. tostring(weightString))
41
42
  end
42
- if chosenWeight < roomWeight then
43
- return jsonRoom
43
+ weightAccumulator = weightAccumulator + weight
44
+ if weightAccumulator >= chosenWeight then
45
+ return jsonObject
44
46
  end
45
- chosenWeight = chosenWeight - roomWeight
46
47
  end
47
- error("Failed to get a JSON room with chosen weight: " .. tostring(chosenWeight))
48
+ return nil
48
49
  end
49
50
  --- Helper function to calculate what the resulting `BitFlags<DoorSlotFlag>` value would be for a
50
51
  -- given JSON room.
@@ -122,13 +123,51 @@ function ____exports.getJSONRoomsOfSubType(self, jsonRooms, subType)
122
123
  end
123
124
  )
124
125
  end
126
+ --- Helper function to get a random JSON entity from an array of JSON entities.
127
+ --
128
+ -- Note that this function does not simply choose a random element in the provided array; it will
129
+ -- properly account for each room weight using the algorithm from:
130
+ -- https://stackoverflow.com/questions/1761626/weighted-random-numbers
131
+ --
132
+ -- @param jsonEntities The array of entities to randomly choose between.
133
+ -- @param seedOrRNG Optional. The `Seed` or `RNG` object to use. If an `RNG` object is provided, the
134
+ -- `RNG.Next` method will be called. Default is `getRandomSeed()`.
135
+ -- @param verbose Optional. If specified, will write entries to the "log.txt" file that describe
136
+ -- what the function is doing. Default is false.
137
+ function ____exports.getRandomJSONEntity(self, jsonEntities, seedOrRNG, verbose)
138
+ if seedOrRNG == nil then
139
+ seedOrRNG = getRandomSeed(nil)
140
+ end
141
+ if verbose == nil then
142
+ verbose = false
143
+ end
144
+ local totalWeight = getTotalWeightOfJSONObject(nil, jsonEntities)
145
+ if verbose then
146
+ log(
147
+ nil,
148
+ "Total weight of the JSON entities provided: " .. tostring(totalWeight)
149
+ )
150
+ end
151
+ local chosenWeight = getRandomFloat(nil, 0, totalWeight, seedOrRNG)
152
+ if verbose then
153
+ log(
154
+ nil,
155
+ "Randomly chose weight for JSON entity: " .. tostring(chosenWeight)
156
+ )
157
+ end
158
+ local randomJSONEntity = getJSONObjectWithChosenWeight(nil, jsonEntities, chosenWeight)
159
+ if randomJSONEntity == nil then
160
+ error("Failed to get a JSON entity with chosen weight: " .. tostring(chosenWeight))
161
+ end
162
+ return randomJSONEntity
163
+ end
125
164
  --- Helper function to get a random JSON room from an array of JSON rooms.
126
165
  --
127
166
  -- Note that this function does not simply choose a random element in the provided array; it will
128
167
  -- properly account for each room weight using the algorithm from:
129
168
  -- https://stackoverflow.com/questions/1761626/weighted-random-numbers
130
169
  --
131
- -- @param jsonRooms The array of rooms to random choose between.
170
+ -- @param jsonRooms The array of rooms to randomly choose between.
132
171
  -- @param seedOrRNG Optional. The `Seed` or `RNG` object to use. If an `RNG` object is provided, the
133
172
  -- `RNG.Next` method will be called. Default is `getRandomSeed()`.
134
173
  -- @param verbose Optional. If specified, will write entries to the "log.txt" file that describe
@@ -140,7 +179,7 @@ function ____exports.getRandomJSONRoom(self, jsonRooms, seedOrRNG, verbose)
140
179
  if verbose == nil then
141
180
  verbose = false
142
181
  end
143
- local totalWeight = getTotalWeightOfJSONRooms(nil, jsonRooms)
182
+ local totalWeight = getTotalWeightOfJSONObject(nil, jsonRooms)
144
183
  if verbose then
145
184
  log(
146
185
  nil,
@@ -154,6 +193,10 @@ function ____exports.getRandomJSONRoom(self, jsonRooms, seedOrRNG, verbose)
154
193
  "Randomly chose weight for JSON room: " .. tostring(chosenWeight)
155
194
  )
156
195
  end
157
- return getJSONRoomWithChosenWeight(nil, jsonRooms, chosenWeight)
196
+ local randomJSONRoom = getJSONObjectWithChosenWeight(nil, jsonRooms, chosenWeight)
197
+ if randomJSONRoom == nil then
198
+ error("Failed to get a JSON room with chosen weight: " .. tostring(chosenWeight))
199
+ end
200
+ return randomJSONRoom
158
201
  end
159
202
  return ____exports
@@ -1 +1 @@
1
- {"version":3,"file":"gridEntityXMLMap.d.ts","sourceRoot":"","sources":["../../../src/maps/gridEntityXMLMap.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,cAAc,EACd,iBAAiB,EAOlB,MAAM,8BAA8B,CAAC;AAEtC;;;GAGG;AACH,eAAO,MAAM,mBAAmB,EAAE,WAAW,CAC3C,iBAAiB,EACjB;IAAC,cAAc;IAAE,GAAG;CAAC,CA6JrB,CAAC"}
1
+ {"version":3,"file":"gridEntityXMLMap.d.ts","sourceRoot":"","sources":["../../../src/maps/gridEntityXMLMap.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,cAAc,EACd,iBAAiB,EAOlB,MAAM,8BAA8B,CAAC;AAEtC;;;GAGG;AACH,eAAO,MAAM,mBAAmB,EAAE,WAAW,CAC3C,iBAAiB,EACjB;IAAC,cAAc;IAAE,GAAG;CAAC,CAgKrB,CAAC"}
@@ -15,6 +15,7 @@ local TrapdoorVariant = ____isaac_2Dtypescript_2Ddefinitions.TrapdoorVariant
15
15
  --- This maps the GridEntityXMLType (i.e. the type contained in the room XML/STB file) to the
16
16
  -- GridEntityType and the variant used by the game.
17
17
  ____exports.GRID_ENTITY_XML_MAP = __TS__New(Map, {
18
+ {GridEntityXMLType.DECORATION, {GridEntityType.DECORATION, 0}},
18
19
  {GridEntityXMLType.ROCK, {GridEntityType.ROCK, RockVariant.NORMAL}},
19
20
  {GridEntityXMLType.ROCK_BOMB, {GridEntityType.ROCK_BOMB, 0}},
20
21
  {GridEntityXMLType.ROCK_ALT, {GridEntityType.ROCK_ALT, 0}},
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "isaacscript-common",
3
- "version": "12.5.2",
3
+ "version": "12.6.1",
4
4
  "description": "Helper functions and features for IsaacScript mods.",
5
5
  "keywords": [
6
6
  "isaac",
@@ -6,7 +6,6 @@
6
6
  import {
7
7
  ActiveSlot,
8
8
  CollectibleType,
9
- EffectVariant,
10
9
  EntityCollisionClass,
11
10
  EntityFlag,
12
11
  EntityGridCollisionClass,
@@ -26,32 +25,30 @@ import { ModCallbackCustom } from "../enums/ModCallbackCustom";
26
25
  import { errorIfFeaturesNotInitialized } from "../featuresInitialized";
27
26
  import { emptyArray } from "../functions/array";
28
27
  import {
28
+ getEntities,
29
29
  getEntityIDFromConstituents,
30
- removeAllMatchingEntities,
31
30
  spawn,
32
31
  spawnWithSeed,
33
32
  } from "../functions/entities";
34
- import {
35
- getNPCs,
36
- removeAllBombs,
37
- removeAllPickups,
38
- } from "../functions/entitiesSpecific";
39
33
  import { getEnumValues } from "../functions/enums";
40
34
  import {
41
35
  convertXMLGridEntityType,
42
36
  getAllGridIndexes,
43
37
  getGridEntities,
44
- removeAllGridEntitiesExcept,
45
38
  removeGridEntity,
46
39
  setGridEntityInvisible,
47
40
  spawnGridEntityWithVariant,
48
41
  } from "../functions/gridEntities";
49
- import { getRandomJSONRoom } from "../functions/jsonRoom";
42
+ import { getRandomJSONEntity, getRandomJSONRoom } from "../functions/jsonRoom";
50
43
  import { log } from "../functions/log";
51
44
  import { getRandomSeed, isRNG, newRNG } from "../functions/rng";
52
45
  import { getRoomListIndex } from "../functions/roomData";
53
46
  import { gridCoordinatesToWorldPosition } from "../functions/roomGrid";
54
- import { setRoomCleared, setRoomUncleared } from "../functions/rooms";
47
+ import {
48
+ roomUpdateSafe,
49
+ setRoomCleared,
50
+ setRoomUncleared,
51
+ } from "../functions/rooms";
55
52
  import { spawnCollectible } from "../functions/spawnCollectible";
56
53
  import { asCollectibleType, asNumber } from "../functions/types";
57
54
  import { JSONRoom } from "../interfaces/JSONRoomsFile";
@@ -67,10 +64,6 @@ interface PersistentEntityDescription {
67
64
 
68
65
  const FEATURE_NAME = "deployJSONRoom";
69
66
 
70
- const NPC_TYPES_TO_NOT_REMOVE: ReadonlySet<EntityType> = new Set([
71
- EntityType.DARK_ESAU,
72
- ]);
73
-
74
67
  const PERSISTENT_ENTITY_TYPES: ReadonlySet<EntityType> = new Set([
75
68
  EntityType.WALL_HUGGER,
76
69
  ]);
@@ -80,6 +73,22 @@ const GRID_ENTITY_XML_TYPE_SET: ReadonlySet<number> = new Set(
80
73
  gridEntityXMLTypes,
81
74
  );
82
75
 
76
+ const EMPTY_ROOM_BLACKLIST_ENTITY_SET: ReadonlySet<EntityType> = new Set([
77
+ EntityType.PLAYER, // 1
78
+ EntityType.TEAR, // 2
79
+ EntityType.FAMILIAR, // 3
80
+ EntityType.LASER, // 7
81
+ EntityType.KNIFE, // 8
82
+ EntityType.PROJECTILE, // 9
83
+ EntityType.DARK_ESAU, // 866
84
+ ]);
85
+
86
+ const EMPTY_ROOM_BLACKLIST_GRID_ENTITY_SET: ReadonlySet<GridEntityType> =
87
+ new Set([
88
+ GridEntityType.WALL, // 15
89
+ GridEntityType.DOOR, // 16
90
+ ]);
91
+
83
92
  const v = {
84
93
  level: {
85
94
  deployedRoomListIndexes: new Set<int>(),
@@ -316,7 +325,7 @@ export function deployJSONRoom(
316
325
  * what the function is doing. Default is false.
317
326
  */
318
327
  export function deployRandomJSONRoom(
319
- jsonRooms: JSONRoom[] | readonly JSONRoom[],
328
+ jsonRooms: JSONRoom[],
320
329
  seedOrRNG: Seed | RNG = getRandomSeed(),
321
330
  verbose = false,
322
331
  ): void {
@@ -348,21 +357,10 @@ export function emptyRoom(fillWithDecorations: boolean): void {
348
357
  errorIfFeaturesNotInitialized(FEATURE_NAME);
349
358
 
350
359
  const roomListIndex = getRoomListIndex();
351
-
352
360
  v.level.deployedRoomListIndexes.add(roomListIndex);
353
361
 
354
- removeAllBombs(); // 4
355
- removeAllPickups(); // 5
356
- removeAllMatchingEntities(EntityType.SLOT); // 6
357
- removeSpecificNPCs();
358
- removeAllMatchingEntities(EntityType.EFFECT, EffectVariant.DEVIL);
359
- removeAllMatchingEntities(EntityType.EFFECT, EffectVariant.ANGEL);
360
-
361
- removeAllGridEntitiesExcept(
362
- GridEntityType.WALL, // 15
363
- GridEntityType.DOOR, // 16
364
- );
365
-
362
+ emptyRoomEntities();
363
+ emptyRoomGridEntities();
366
364
  setRoomCleared();
367
365
 
368
366
  if (fillWithDecorations) {
@@ -371,38 +369,54 @@ export function emptyRoom(fillWithDecorations: boolean): void {
371
369
  }
372
370
 
373
371
  /**
374
- * We remove entities in the `POST_NEW_ROOM` callback instead of in the PreRoomEntitySpawn callback
375
- * so that they will not re-appear when we re-enter the room.
372
+ * We remove entities in the `POST_NEW_ROOM` callback instead of in the `PRE_ROOM_ENTITY_SPAWN`
373
+ * callback so that they will not re-appear when we re-enter the room.
376
374
  */
377
- function removeSpecificNPCs() {
375
+ function emptyRoomEntities() {
378
376
  const room = game.GetRoom();
379
377
 
380
- for (const npc of getNPCs()) {
381
- if (NPC_TYPES_TO_NOT_REMOVE.has(npc.Type)) {
378
+ for (const entity of getEntities()) {
379
+ if (EMPTY_ROOM_BLACKLIST_ENTITY_SET.has(entity.Type)) {
382
380
  continue;
383
381
  }
384
382
 
385
383
  if (
386
- npc.HasEntityFlags(EntityFlag.CHARM) ||
387
- npc.HasEntityFlags(EntityFlag.FRIENDLY) ||
388
- npc.HasEntityFlags(EntityFlag.PERSISTENT)
384
+ entity.HasEntityFlags(EntityFlag.CHARM) ||
385
+ entity.HasEntityFlags(EntityFlag.FRIENDLY) ||
386
+ entity.HasEntityFlags(EntityFlag.PERSISTENT)
389
387
  ) {
390
388
  continue;
391
389
  }
392
390
 
393
- npc.ClearEntityFlags(EntityFlag.APPEAR);
394
- npc.Remove();
391
+ entity.ClearEntityFlags(EntityFlag.APPEAR);
392
+ entity.Remove();
395
393
 
396
394
  // When fire places are removed, they will leave behind a "path" that will prevent future grid
397
395
  // entities from being spawned on the same tile. Thus, reset the path for this tile if this is a
398
396
  // fire place.
399
- if (npc.Type === EntityType.FIREPLACE) {
400
- const gridIndex = room.GetGridIndex(npc.Position);
397
+ if (entity.Type === EntityType.FIREPLACE) {
398
+ const gridIndex = room.GetGridIndex(entity.Position);
401
399
  room.SetGridPath(gridIndex, 0);
402
400
  }
403
401
  }
404
402
  }
405
403
 
404
+ function emptyRoomGridEntities() {
405
+ let removedOneOrMoreGridEntities = false;
406
+ for (const gridEntity of getGridEntities()) {
407
+ const gridEntityType = gridEntity.GetType();
408
+ if (EMPTY_ROOM_BLACKLIST_GRID_ENTITY_SET.has(gridEntityType)) {
409
+ continue;
410
+ }
411
+
412
+ removeGridEntity(gridEntity, false);
413
+ removedOneOrMoreGridEntities = true;
414
+ }
415
+ if (removedOneOrMoreGridEntities) {
416
+ roomUpdateSafe();
417
+ }
418
+ }
419
+
406
420
  /**
407
421
  * We removed most normal entities, which should prevent them from respawning when the player
408
422
  * re-enters the room. However, this is not the case for grid entities; even if they are removed,
@@ -469,16 +483,9 @@ function spawnAllEntities(
469
483
  );
470
484
  }
471
485
 
472
- if (jsonSpawn.entity.length > 1) {
473
- error("Stacked entities are not implemented for JSON rooms.");
474
- }
475
-
476
- const firstXMLEntity = jsonSpawn.entity[0];
477
- if (firstXMLEntity === undefined) {
478
- error('Failed to get the first JSON entity from an "entity" array.');
479
- }
486
+ const jsonEntity = getRandomJSONEntity(jsonSpawn.entity);
480
487
 
481
- const entityTypeString = firstXMLEntity.$.type;
488
+ const entityTypeString = jsonEntity.$.type;
482
489
  const entityTypeNumber = tonumber(entityTypeString);
483
490
  if (entityTypeNumber === undefined) {
484
491
  error(
@@ -486,13 +493,13 @@ function spawnAllEntities(
486
493
  );
487
494
  }
488
495
 
489
- const variantString = firstXMLEntity.$.variant;
496
+ const variantString = jsonEntity.$.variant;
490
497
  const variant = tonumber(variantString);
491
498
  if (variant === undefined) {
492
499
  error(`Failed to convert the entity variant to a number: ${variant}`);
493
500
  }
494
501
 
495
- const subTypeString = firstXMLEntity.$.subtype;
502
+ const subTypeString = jsonEntity.$.subtype;
496
503
  const subType = tonumber(subTypeString);
497
504
  if (subType === undefined) {
498
505
  error(`Failed to convert the entity sub-type to a number: ${subType}`);
@@ -3,7 +3,7 @@ import {
3
3
  DoorSlotFlagZero,
4
4
  RoomShape,
5
5
  } from "isaac-typescript-definitions";
6
- import { JSONRoom } from "../interfaces/JSONRoomsFile";
6
+ import { JSONEntity, JSONRoom } from "../interfaces/JSONRoomsFile";
7
7
  import { sumArray } from "./array";
8
8
  import { doorSlotToDoorSlotFlag, getRoomShapeDoorSlot } from "./doors";
9
9
  import { addFlag } from "./flag";
@@ -11,6 +11,11 @@ import { log } from "./log";
11
11
  import { getRandomFloat } from "./random";
12
12
  import { getRandomSeed } from "./rng";
13
13
 
14
+ /** This represents either a `JSONRoom` or a `JSONEntity`. */
15
+ interface JSONObject {
16
+ $: { weight: string | undefined };
17
+ }
18
+
14
19
  /**
15
20
  * Helper function to calculate what the resulting `BitFlags<DoorSlotFlag>` value would be for a
16
21
  * given JSON room.
@@ -116,6 +121,45 @@ export function getJSONRoomsOfSubType(
116
121
  });
117
122
  }
118
123
 
124
+ /**
125
+ * Helper function to get a random JSON entity from an array of JSON entities.
126
+ *
127
+ * Note that this function does not simply choose a random element in the provided array; it will
128
+ * properly account for each room weight using the algorithm from:
129
+ * https://stackoverflow.com/questions/1761626/weighted-random-numbers
130
+ *
131
+ * @param jsonEntities The array of entities to randomly choose between.
132
+ * @param seedOrRNG Optional. The `Seed` or `RNG` object to use. If an `RNG` object is provided, the
133
+ * `RNG.Next` method will be called. Default is `getRandomSeed()`.
134
+ * @param verbose Optional. If specified, will write entries to the "log.txt" file that describe
135
+ * what the function is doing. Default is false.
136
+ */
137
+ export function getRandomJSONEntity(
138
+ jsonEntities: JSONEntity[],
139
+ seedOrRNG: Seed | RNG = getRandomSeed(),
140
+ verbose = false,
141
+ ): JSONEntity {
142
+ const totalWeight = getTotalWeightOfJSONObject(jsonEntities);
143
+ if (verbose) {
144
+ log(`Total weight of the JSON entities provided: ${totalWeight}`);
145
+ }
146
+
147
+ const chosenWeight = getRandomFloat(0, totalWeight, seedOrRNG);
148
+ if (verbose) {
149
+ log(`Randomly chose weight for JSON entity: ${chosenWeight}`);
150
+ }
151
+
152
+ const randomJSONEntity = getJSONObjectWithChosenWeight(
153
+ jsonEntities,
154
+ chosenWeight,
155
+ );
156
+ if (randomJSONEntity === undefined) {
157
+ error(`Failed to get a JSON entity with chosen weight: ${chosenWeight}`);
158
+ }
159
+
160
+ return randomJSONEntity;
161
+ }
162
+
119
163
  /**
120
164
  * Helper function to get a random JSON room from an array of JSON rooms.
121
165
  *
@@ -123,18 +167,18 @@ export function getJSONRoomsOfSubType(
123
167
  * properly account for each room weight using the algorithm from:
124
168
  * https://stackoverflow.com/questions/1761626/weighted-random-numbers
125
169
  *
126
- * @param jsonRooms The array of rooms to random choose between.
170
+ * @param jsonRooms The array of rooms to randomly choose between.
127
171
  * @param seedOrRNG Optional. The `Seed` or `RNG` object to use. If an `RNG` object is provided, the
128
172
  * `RNG.Next` method will be called. Default is `getRandomSeed()`.
129
173
  * @param verbose Optional. If specified, will write entries to the "log.txt" file that describe
130
174
  * what the function is doing. Default is false.
131
175
  */
132
176
  export function getRandomJSONRoom(
133
- jsonRooms: JSONRoom[] | readonly JSONRoom[],
177
+ jsonRooms: JSONRoom[],
134
178
  seedOrRNG: Seed | RNG = getRandomSeed(),
135
179
  verbose = false,
136
180
  ): JSONRoom {
137
- const totalWeight = getTotalWeightOfJSONRooms(jsonRooms);
181
+ const totalWeight = getTotalWeightOfJSONObject(jsonRooms);
138
182
  if (verbose) {
139
183
  log(`Total weight of the JSON rooms provided: ${totalWeight}`);
140
184
  }
@@ -144,41 +188,46 @@ export function getRandomJSONRoom(
144
188
  log(`Randomly chose weight for JSON room: ${chosenWeight}`);
145
189
  }
146
190
 
147
- return getJSONRoomWithChosenWeight(jsonRooms, chosenWeight);
191
+ const randomJSONRoom = getJSONObjectWithChosenWeight(jsonRooms, chosenWeight);
192
+ if (randomJSONRoom === undefined) {
193
+ error(`Failed to get a JSON room with chosen weight: ${chosenWeight}`);
194
+ }
195
+
196
+ return randomJSONRoom;
148
197
  }
149
198
 
150
- function getTotalWeightOfJSONRooms(
151
- jsonRooms: JSONRoom[] | readonly JSONRoom[],
152
- ): float {
153
- const weights = jsonRooms.map((jsonRoom) => {
154
- const roomWeightString = jsonRoom.$.weight;
155
- const roomWeight = tonumber(roomWeightString);
156
- if (roomWeight === undefined) {
157
- error(`Failed to parse the weight of a JSON room: ${roomWeightString}.`);
199
+ function getTotalWeightOfJSONObject(jsonOjectArray: JSONObject[]): float {
200
+ const weights = jsonOjectArray.map((jsonObject) => {
201
+ const weightString = jsonObject.$.weight;
202
+ const weight = tonumber(weightString);
203
+ if (weight === undefined) {
204
+ error(`Failed to parse the weight of a JSON object: ${weightString}.`);
158
205
  }
159
- return roomWeight;
206
+
207
+ return weight;
160
208
  });
161
209
 
162
210
  return sumArray(weights);
163
211
  }
164
212
 
165
- function getJSONRoomWithChosenWeight(
166
- jsonRooms: JSONRoom[] | readonly JSONRoom[],
213
+ function getJSONObjectWithChosenWeight<T extends JSONObject>(
214
+ jsonOjectArray: T[],
167
215
  chosenWeight: float,
168
- ): JSONRoom {
169
- for (const jsonRoom of jsonRooms) {
170
- const roomWeightString = jsonRoom.$.weight;
171
- const roomWeight = tonumber(roomWeightString);
172
- if (roomWeight === undefined) {
173
- error(`Failed to parse the weight of a JSON room: ${roomWeightString}`);
216
+ ): T | undefined {
217
+ let weightAccumulator = 0;
218
+
219
+ for (const jsonObject of jsonOjectArray) {
220
+ const weightString = jsonObject.$.weight;
221
+ const weight = tonumber(weightString);
222
+ if (weight === undefined) {
223
+ error(`Failed to parse the weight of a JSON object: ${weightString}`);
174
224
  }
175
225
 
176
- if (chosenWeight < roomWeight) {
177
- return jsonRoom;
226
+ weightAccumulator += weight;
227
+ if (weightAccumulator >= chosenWeight) {
228
+ return jsonObject;
178
229
  }
179
-
180
- chosenWeight -= roomWeight;
181
230
  }
182
231
 
183
- error(`Failed to get a JSON room with chosen weight: ${chosenWeight}`);
232
+ return undefined;
184
233
  }
@@ -18,6 +18,9 @@ export const GRID_ENTITY_XML_MAP: ReadonlyMap<
18
18
  GridEntityXMLType,
19
19
  [GridEntityType, int]
20
20
  > = new Map([
21
+ // 0
22
+ [GridEntityXMLType.DECORATION, [GridEntityType.DECORATION, 0]],
23
+
21
24
  // 1000
22
25
  [GridEntityXMLType.ROCK, [GridEntityType.ROCK, RockVariant.NORMAL]],
23
26