RegionRandom.ts 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. /// <reference path="../Region.ts" />
  2. /// <reference path="../Shuffler.ts" />
  3. /// <reference path="ShufflerDirection.ts" />
  4. /// <reference path="RoomRandomMap.ts" />
  5. /// <reference path="RoomRandom.ts" />
  6. /// <reference path="RoomRandomFodder.ts" />
  7. interface RandomizingRoomOptions {
  8. region : RegionRandom;
  9. room : RoomRandom;
  10. map : RoomRandomMap;
  11. }
  12. class RegionRandom extends Region {
  13. private randomized = false;
  14. public map : RoomRandomMap;
  15. public fodderRoomClass : typeof RoomRandom = RoomRandomFodder;
  16. public placedRooms : Array<RoomRandom> = [];
  17. public constructor (name : string, map? : RoomRandomMap) {
  18. super(name);
  19. this.map = map == undefined ? new RoomRandomMap() : map;
  20. }
  21. public async randomize () {
  22. if (!this.randomized) {
  23. await RegionRandom.rulebookRandomizeRegion.execute({
  24. noun : this
  25. });
  26. }
  27. }
  28. public placeAt (room : RoomRandom, x : number, y : number) {
  29. this.map.map(room, x, y);
  30. this.place(room);
  31. }
  32. public static rng : () => number = () => { return Math.random(); };
  33. public static rulebookRandomizeRegion = new Rulebook<Region>("Randomizing Random Region something");
  34. public static rulebookPlaceRoom = new Rulebook<RandomizingRoomOptions>("Placing Random Room something");
  35. public static rulebookBeforePlaceRoom = new Rulebook<RandomizingRoomOptions>("Before placing Random Room something");
  36. public static rulebookAfterPlaceRoom = new Rulebook<RandomizingRoomOptions>("After placing Random Room something");
  37. public static ruleFirstRandomizeRegion = RegionRandom.rulebookRandomizeRegion.createAndAddRule({
  38. name : "Empty map cache to start randomizing region",
  39. firstPriority : Rule.PRIORITY_HIGHEST,
  40. code : runner => {
  41. let region = <RegionRandom> runner.noun;
  42. // We don't want to connect a region to another region unintentionally
  43. region.map.emptyCache();
  44. }
  45. });
  46. public static ruleBasicRandomizeRegion = RegionRandom.rulebookRandomizeRegion.createAndAddRule({
  47. name : "Randomize all unplaced, randomizable rooms in region something",
  48. code : async runner => {
  49. let region = <RegionRandom> runner.noun;
  50. let roomShuffler = new Shuffler(
  51. Region.InRelation.getAllRightTypes(region, RoomRandom).filter((room : RoomRandom) => {
  52. return room.randomizable && !room.placed &&
  53. (room == WorldState.player.getRoom() || (RegionRandom.rng() * 100) <= room.appearChance);
  54. }), RegionRandom.rng
  55. );
  56. for (let room = roomShuffler.getOne(); room != undefined; room = roomShuffler.getOne()) {
  57. // Prevent available connections from getting too low
  58. // If we're placing rooms with too few availableConnections, we might end up reaching 0 availableConnections
  59. // Which would mean no more rooms can be placed.
  60. while (region.map.rooms > 0 && region.map.getAvailableConnections() < 4) {
  61. let fodder = new region.fodderRoomClass();
  62. let options = <RandomizingRoomOptions> {
  63. map : region.map,
  64. room : fodder,
  65. region : region
  66. };
  67. region.place(fodder);
  68. await RegionRandom.rulebookBeforePlaceRoom.execute({noun : options});
  69. await RegionRandom.rulebookPlaceRoom.execute({noun : options});
  70. await RegionRandom.rulebookAfterPlaceRoom.execute({noun : options});
  71. }
  72. let options = <RandomizingRoomOptions> {
  73. map : region.map,
  74. room : room,
  75. region : region
  76. };
  77. await RegionRandom.rulebookBeforePlaceRoom.execute({noun : options});
  78. await RegionRandom.rulebookPlaceRoom.execute({noun : options});
  79. await RegionRandom.rulebookAfterPlaceRoom.execute({noun : options});
  80. if (!room.placed) {
  81. Elements.CurrentTurnHandler.printAsError(new Say("Was unable to place room ", room, ". Game might be unplayable."));
  82. }
  83. }
  84. }
  85. });
  86. public static ruleAddExtraConnections = RegionRandom.rulebookRandomizeRegion.createAndAddRule({
  87. firstPriority : Rule.PRIORITY_LOWEST,
  88. name : "Add extra connections to rooms in region",
  89. code : runner => {
  90. let region = <RegionRandom> runner.noun;
  91. let placedRooms = Region.InRelation.getAllRightTypes(region, RoomRandom).filter((room : RoomRandom) => {
  92. return room.placed;
  93. });
  94. placedRooms.forEach((room : RoomRandom) => {
  95. let myCoordinates = region.map.getCoordinates(room);
  96. let directionShuffler = new Shuffler<number>(room.connectableOn.slice(0), RegionRandom.rng);
  97. // use greater connection chance
  98. for (let direction = directionShuffler.getOne(); direction != undefined; direction = directionShuffler.getOne()) {
  99. let chance1 = room.extraConnectionChance;
  100. if (room.connections[direction] == undefined) {
  101. let otherCoordinates = Room.shift(myCoordinates, direction);
  102. let otherRoom = region.map.getRoom(otherCoordinates[0], otherCoordinates[1]);
  103. if (otherRoom != undefined && otherRoom.randomizable
  104. && otherRoom.isConnectableOn(OppositeDirection[Direction[direction]])
  105. ) {
  106. let chance2 = otherRoom.extraConnectionChance;
  107. let chance = (chance1 == 0 || chance2 == 0) ? 0 : Math.max(chance1, chance2);
  108. if ((RegionRandom.rng() * 100) <= chance) {
  109. room.mapRoom(otherRoom, direction);
  110. }
  111. }
  112. }
  113. }
  114. // for (let direction = directionShuffler.getOne(); direction != undefined && (RegionRandom.rng() * 100) <= room.extraConnectionChance; direction = directionShuffler.getOne()) {
  115. // if (room.connections[direction] == undefined) {
  116. // let otherCoordinates = Room.shift(myCoordinates, direction);
  117. // let otherRoom = region.map.getRoom(otherCoordinates[0], otherCoordinates[1]);
  118. // if (otherRoom != undefined && otherRoom.randomizable
  119. // && otherRoom.isConnectableOn(OppositeDirection[Direction[direction]])
  120. // && (RegionRandom.rng() * 100) <= otherRoom.extraConnectionChance) {
  121. // room.mapRoom(otherRoom, direction);
  122. // }
  123. // }
  124. // }
  125. });
  126. }
  127. });
  128. public static rulePlaceFirstRoom = RegionRandom.rulebookPlaceRoom.createAndAddRule({
  129. name : "Placing First room something",
  130. firstPriority : Rule.PRIORITY_HIGHEST,
  131. code : runner => {
  132. let placingOptions = <RandomizingRoomOptions> runner.noun;
  133. if (placingOptions.map.isFree(0, 0)) {
  134. placingOptions.map.map(placingOptions.room, 0, 0);
  135. return true;
  136. }
  137. },
  138. conditions : runner => {
  139. return runner.noun.map.rooms == 0;
  140. }
  141. });
  142. public static rulePlaceNonTrickyRoom = RegionRandom.rulebookPlaceRoom.createAndAddRule({
  143. name : "Placing non-tricky room something",
  144. firstPriority : Rule.PRIORITY_HIGH,
  145. code : runner => {
  146. let placingOptions = <RandomizingRoomOptions> runner.noun;
  147. //let directionShuffler = new Shuffler<number>(placingOptions.room.connectableOn);
  148. let preferredGrowthDirection = placingOptions.map.getPreferredGrowth();
  149. let directionShuffler = new ShufflerDirection(placingOptions.room.connectableOn, preferredGrowthDirection);
  150. //for (let direction = directionShuffler.getOne(); direction != undefined; direction = directionShuffler.getOne()) {
  151. for (let direction = directionShuffler.getDirection(); direction != undefined; direction = directionShuffler.getDirection()) {
  152. let oppositeDirection = OppositeDirection[Direction[direction]];
  153. let connectableRoom = placingOptions.map.getAnyFromCache(oppositeDirection);
  154. if (connectableRoom != undefined) {
  155. let otherCoordinates = placingOptions.map.getCoordinates(connectableRoom);
  156. let myCoordinates = Room.shift(otherCoordinates, oppositeDirection);
  157. placingOptions.room.mapRoom(connectableRoom, direction);
  158. placingOptions.map.map(placingOptions.room, myCoordinates[0], myCoordinates[1]);
  159. return true;
  160. }
  161. }
  162. },
  163. conditions : runner => {
  164. return runner.noun.room.trickyCode == undefined;
  165. }
  166. });
  167. public static rulePlaceTrickyRoom = RegionRandom.rulebookPlaceRoom.createAndAddRule({
  168. name : "Placing tricky room something",
  169. code : runner => {
  170. let placingOptions = <RandomizingRoomOptions> runner.noun;
  171. let placedRooms = <Array<RoomRandom>> placingOptions.region.getRooms().filter((room) => {
  172. return room instanceof RoomRandom && room.placed;
  173. });
  174. if (placedRooms.length == 0) {
  175. Elements.CurrentTurnHandler.printAsError("Unable to place room " + placingOptions.room.getPrintedName() + ": There are no rooms to connect to!");
  176. return false;
  177. }
  178. let roomShuffler = new Shuffler(placedRooms, RegionRandom.rng);
  179. for (let connectableRoom = roomShuffler.getOne(); connectableRoom != undefined; connectableRoom = roomShuffler.getOne()) {
  180. let trickier = <TrickierOptions> {
  181. region : placingOptions.region,
  182. map : placingOptions.map,
  183. otherRoom : connectableRoom
  184. };
  185. let tricky = placingOptions.room.getAnyDirection(trickier);
  186. if (tricky != undefined) {
  187. placingOptions.room.mapRoom(connectableRoom, tricky.trickyRoomDirection);
  188. placingOptions.map.map(placingOptions.room, tricky.x, tricky.y);
  189. return true;
  190. }
  191. }
  192. // THIS WORKS
  193. // I DON'T KNOW WHY
  194. // I DON'T CARE WHY
  195. // LEAVE
  196. let connectableThroughFodder = (fodderStep : number, connectingRoom : RoomRandom) => {
  197. let trickier = <TrickierOptions> {
  198. region : placingOptions.region,
  199. map : placingOptions.map,
  200. otherRoom : connectingRoom
  201. };
  202. if (fodderStep == 0) {
  203. return placingOptions.room.getAnyDirection(trickier);
  204. } else {
  205. let newFodder = new (placingOptions.region.fodderRoomClass)();
  206. //let directionShuffler = new Shuffler<number>(newFodder.connectableOn, RegionRandom.rng);
  207. let preferredGrowthDirection = placingOptions.map.getPreferredGrowth();
  208. let directionShuffler = new ShufflerDirection(placingOptions.room.connectableOn, preferredGrowthDirection);
  209. for (let direction = directionShuffler.getDirection(); direction != undefined; direction = directionShuffler.getDirection()) {
  210. let oppositeDirection = OppositeDirection[Direction[direction]];
  211. let otherCoordinates = placingOptions.map.getCoordinates(connectingRoom);
  212. let wouldbeCoordinates = Room.shift(otherCoordinates, oppositeDirection);
  213. let fodderTricky = {
  214. otherRoom : connectingRoom,
  215. otherRoomDirection : oppositeDirection,
  216. trickyRoomDirection : direction,
  217. map : placingOptions.map,
  218. region : placingOptions.region,
  219. x : wouldbeCoordinates[0],
  220. y : wouldbeCoordinates[1]
  221. };
  222. if (newFodder.isPlaceable(fodderTricky)) {
  223. newFodder.mapRoom(connectingRoom, fodderTricky.trickyRoomDirection);
  224. placingOptions.map.map(newFodder, fodderTricky.x, fodderTricky.y);
  225. let nextTricky = connectableThroughFodder(fodderStep - 1, newFodder);
  226. if (nextTricky != undefined) {
  227. placingOptions.region.place(newFodder);
  228. return nextTricky;
  229. } else {
  230. newFodder.unmapRoom(fodderTricky.trickyRoomDirection);
  231. placingOptions.map.unmap(fodderTricky.x, fodderTricky.y);
  232. }
  233. }
  234. }
  235. }
  236. };
  237. for (let fodderLevel = 1; fodderLevel < 30; fodderLevel++) {
  238. roomShuffler.restart();
  239. for (let connectableRoom = roomShuffler.getOne(); connectableRoom != undefined; connectableRoom = roomShuffler.getOne()) {
  240. let tricky = connectableThroughFodder(fodderLevel, connectableRoom);
  241. if (tricky != undefined) {
  242. placingOptions.room.mapRoom(tricky.otherRoom, tricky.trickyRoomDirection);
  243. placingOptions.map.map(placingOptions.room, tricky.x, tricky.y);
  244. return true;
  245. }
  246. }
  247. }
  248. Elements.CurrentTurnHandler.printAsError("Unable to place room " + placingOptions.room.getPrintedName() + ": All attempts failed");
  249. return false;
  250. }
  251. });
  252. }