main.ts 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. var rooma = new RoomRandom("Room A");
  2. rooma.description = new Say(
  3. "You are inside a box of metal painted blue. Your head almost touches the ceiling, making the room look smaller than it really is.",
  4. Say.LINE_BREAK,
  5. new SayIf(
  6. () => {
  7. return Thing.InsideRoomRelation.getLeft(vase) == rooma || Thing.InsideRoomRelation.getLeft(urn) == rooma;
  8. },
  9. " Still, there are some things thrown about."
  10. )
  11. );
  12. PlayBegins.setStartingRoom(rooma);
  13. let paddedBra = new Clothing({name : "Padded Bra", unique : true});
  14. paddedBra.breastPadding = 3;
  15. paddedBra.slots = [Humanoid.SLOT_BREASTS];
  16. let paddedUnderwear = new Clothing({name : "Padded Underwear", unique : true});
  17. paddedUnderwear.crotchPadding = 15;
  18. paddedUnderwear.slots = [Humanoid.SLOT_CROTCH_BACK, Humanoid.SLOT_CROTCH_FRONT];
  19. // Thing.WearRelation.setRelation(WorldState.player, paddedBra);
  20. // Thing.WearRelation.setRelation(WorldState.player, paddedUnderwear);
  21. let player = WorldState.player;
  22. WorldState.player = player;
  23. var vase = new Thing({name : "Vase"});
  24. vase.description = new Say("This is an ornamental vase that'd look very nice on your lap. Why? Who knows.");
  25. rooma.place(vase);
  26. let mapOfTest = new MapNote({name: "Map of this Region",
  27. description : "This is a simple map showing all the rooms here.", unique : true});
  28. rooma.place(mapOfTest);
  29. let urn = new Thing({unique: true, name : "Urn of Dreams", image : "image001"});
  30. urn.description = new Say("This appears to be a simple, black urn containing the ashes of your dreams.");
  31. rooma.place(urn);
  32. var roomb = new RoomRandom("Room B");
  33. roomb.place(vase);
  34. let frillyPouch = new CoinPouch({
  35. name : "Frilly Pouch",
  36. //image : new SayImage("image001"),
  37. description : new Say("This is a very gay little pink pouch full of little hearts.")
  38. });
  39. frillyPouch.addCoins(502);
  40. rooma.place(frillyPouch);
  41. // ActionTake.check.addRule(new Rule(<RuleOptions<any>> {
  42. // code : function () {
  43. // let promise = new Promise(() => {});
  44. // return promise;
  45. // }
  46. // }));
  47. let bigSack = new CoinPouch({name : "Big Sack"});
  48. bigSack.addCoins(100);
  49. rooma.place(bigSack);
  50. let region = new RegionRandom("Test Region");
  51. region.place(rooma, roomb);
  52. for (let i = 1; i < 6; i++) {
  53. let room = new RoomRandom("Room " + i.toString());
  54. // let randomDirection = new Shuffler([Room.NORTH, Room.SOUTH, Room.EAST, Room.WEST])
  55. // room.connectableOn = [randomDirection.getOne()];
  56. //room.connectableOn = [Room.NORTH, Room.SOUTH, Room.EAST, Room.WEST];
  57. region.place(room);
  58. if (Math.random() > 0.5) {
  59. //mapOfTest.addRoom(room);
  60. }
  61. }
  62. mapOfTest.addRegion(region);
  63. let southestRoom = new RoomRandom("Southest Room");
  64. //southestRoom.appearChance = 0;
  65. region.place(southestRoom);
  66. //southestRoom.connectableOn = [Room.NORTH];
  67. southestRoom.appearChance = 100;
  68. southestRoom.backgroundImage = "bloo";
  69. southestRoom.trickyCode = (options : TrickyOptions) => {
  70. let myCoordinates = [options.x, options.y];
  71. for (let i = 0; i < Room.DIRECTIONS.length; i++) {
  72. let direction = Room.DIRECTIONS[i];
  73. if (direction != Direction.NORTH) {
  74. let coordinates = Room.shift(myCoordinates, direction);
  75. if (!options.map.isFree(coordinates[0], coordinates[1])) {
  76. return false; // This room can only have rooms on north of it
  77. }
  78. coordinates = Room.shift(coordinates, direction);
  79. if (!options.map.isFree(coordinates[0], coordinates[1])) {
  80. return false; // This room can only have rooms on north of it
  81. }
  82. }
  83. }
  84. return true;
  85. };
  86. RegionRandom.rulebookAfterPlaceRoom.addRule(new Rule({
  87. name : "After placing the southest room",
  88. code : runner => {
  89. let options = <RandomizingRoomOptions> runner.noun;
  90. let myCoordinates = options.map.getCoordinates(options.room);
  91. if (myCoordinates != undefined) {
  92. for (let i = 0; i < Room.DIRECTIONS.length; i++) {
  93. let direction = Room.DIRECTIONS[i];
  94. if (direction != Direction.NORTH) {
  95. let coordinates = Room.shift(myCoordinates, direction);
  96. options.map.block(coordinates[0], coordinates[1]);
  97. coordinates = Room.shift(coordinates, direction);
  98. options.map.block(coordinates[0], coordinates[1]);
  99. }
  100. }
  101. }
  102. },
  103. conditions : runner => {
  104. return runner.noun.room == southestRoom;
  105. }
  106. }))
  107. Thing.CarryRelation.setRelation(WorldState.player, mapOfTest);
  108. // Settings.setDebug(false);
  109. PlayBegins.rulebook.addRule(new Rule({
  110. name : "randomize region",
  111. firstPriority : Rule.PRIORITY_HIGHEST,
  112. code : async runner => {
  113. //let t0 = performance.now();
  114. await region.randomize();
  115. //let t1 = performance.now();
  116. }
  117. }));
  118. RegionRandom.rulebookRandomizeRegion.addRule(new Rule({
  119. name : "Add room A and B to region",
  120. firstPriority : Rule.PRIORITY_HIGHEST,
  121. code : async runner => {
  122. await RegionRandom.rulebookPlaceRoom.execute({
  123. noun : <RandomizingRoomOptions> {
  124. map : region.map,
  125. room : rooma,
  126. region : region
  127. }
  128. }).then();
  129. await RegionRandom.rulebookPlaceRoom.execute({
  130. noun : <RandomizingRoomOptions> {
  131. map : region.map,
  132. room : roomb,
  133. region : region
  134. }
  135. }).then();
  136. },
  137. conditions : runner => {
  138. return runner.noun == region;
  139. }
  140. }));
  141. function getPath (rooma : Room, roomb : Room) {
  142. console.debug("The best path from " + rooma.getPrintedName() + " to " + roomb.getPrintedName() + " is:");
  143. let t0, dir, t1;
  144. t0 = performance.now();
  145. dir = rooma.bestDirectionTo(roomb);
  146. t1 = performance.now();
  147. if (dir != undefined) {
  148. console.debug(DirectionNames[Direction[dir]]);
  149. } else {
  150. console.debug("There is no path.");
  151. }
  152. console.debug("Call to doSomething took " + (t1 - t0) + " milliseconds.");
  153. }
  154. // let t0 = performance.now();
  155. // for (var i = 0; i < 1; i++) {
  156. // getPath(rooma, roomj);
  157. // }
  158. // window['roome'] = roome;
  159. // let t1 = performance.now();
  160. // console.debug("Total: " + (t1 - t0) + " milliseconds.");
  161. let wanderRegion = new RegionRandom("OrcableRegion");
  162. wanderRegion.place(rooma, roomb);
  163. region.place(wanderRegion);
  164. // Test done with a thousand orcs searching paths and reading rooms. Total time taken: 200ms.
  165. // 1000 orcs, no wanderers: 130ms
  166. // 100 orcs, no wanderer: 13ms (so the same amount of time as not having any orcs)
  167. // 100 orcs, wanderer: 30ms
  168. // 100 orcs, no shiny picker, wanderer: 30ms
  169. // 100 orcs, no wanderer, no shiny picker: 13ms
  170. // 1000 orcs, no wanderer, no shiny picker: 51ms
  171. /**
  172. * Conclusion:
  173. * The test had all orcs placed in the same room, so every time ShinyPicker AI runs, all the orcs were looking at all the other orcs.
  174. * Game feels "instant" up to 100ms turns, which was reached at 250 orcs with JUST one PIcks Shiny and Wanderer rules.
  175. * With 100 EMPTY shiny rules, 250 orcs already take up 500ms per turn!
  176. * If the orcs fail the conditions for wanderer and shiny rules, then there is just a small overhead to having these rules there.
  177. * 100 Rules failing the conditions allows for 800 orcs below 100ms.
  178. * 50 orcs with 150 Shiny Rules which go through all the other orcs while they wander towards a region results in a 250ms wait.
  179. * That's not good since those numbers are similar to what end game should have, however real rules might not be as expensive as Pick Shinies with a room full of orcs..
  180. * Wait is bearable for 100 orcs with 800 disabled rules, so it should be "fine" to have all rules in the same rulebook.
  181. * First possible optimization: make AI rules have a static "check" and bake them into each NPC's rulebook so that they don't have to be checked every turn.
  182. * Second possible optimization: use maximum distance from player to decide which NPCs have their AIs executed (even better: only run AI for the current region).
  183. * Third optimization: reduce number of rules. Last resort.
  184. */
  185. let rooms = region.getRooms();
  186. let shuffler = new Shuffler(rooms);
  187. for (let i = 0; i < 0; i++) {
  188. AI.rules.createAndAddRule({
  189. name : "Pick Shinies",
  190. firstPriority : AIRules.PRIORITY_ACTING_ON_PLACE,
  191. conditions : (runner : RulebookRunner<Person>) => {
  192. let person = runner.noun;
  193. return person.AI.picksShinies;
  194. },
  195. code : (runner : RulebookRunner<Person>) => {
  196. let person = runner.noun;
  197. let room = person.getRoom();
  198. let visibleThings = room.getContainedAndVisibleTo(person);
  199. if (visibleThings.length > 0) {
  200. for (let i = 0; i < visibleThings.length; i++) {
  201. if (!visibleThings[i].fixedInPlace && visibleThings[i].getShiny()) {
  202. return new ActionTake(person, visibleThings[i]);
  203. }
  204. }
  205. }
  206. }
  207. });
  208. }
  209. let randomOrc;
  210. let randomOrc2;
  211. for (let i = 0; i < 8; i++) {
  212. let orc = new OrcDebugger();
  213. randomOrc = orc;
  214. if (randomOrc2 == undefined) {
  215. randomOrc2 = orc;
  216. }
  217. orc.AI.wanderer = true;
  218. orc.AI.picksShinies = true;
  219. orc.AI.wandersOn = wanderRegion;
  220. let room = new Shuffler(region.getRooms()).getOne();
  221. room.place(orc);
  222. }
  223. var fTarget = new ContentGroup();
  224. fTarget.addUnit(
  225. new FuckingUnit()
  226. .setFucked(WorldState.player)
  227. .setFucker(randomOrc)
  228. .setHole(WorldState.player.getPart(HumanoidVagina))
  229. .setStick(randomOrc.getPart(HumanoidPenis))
  230. );
  231. fTarget.addUnit(
  232. new FuckingUnit()
  233. .setFucked(WorldState.player)
  234. .setFucker(randomOrc2)
  235. .setHole(WorldState.player.getPart(HumanoidHead))
  236. .setStick(randomOrc2.getPart(HumanoidPenis))
  237. );
  238. let spitroast = (new FuckingDescription("Orc spitroast!"));
  239. spitroast.setDescription(new Say("Orc Spitroast!"))
  240. .addUnit()
  241. .setFucker(OrcDebugger)
  242. .setHole(HumanoidVagina)
  243. .setStick(HumanoidPenis);
  244. spitroast.addUnit()
  245. .setFucker(OrcDebugger)
  246. .setHole(HumanoidHead)
  247. .setStick(HumanoidPenis);
  248. (new FuckingDescription("Specific Orc in Vagina"))
  249. .setDescription(new Say("Specific Orc in Vagina."))
  250. .addUnit()
  251. .setFucker(randomOrc)
  252. .setHole(WorldState.player.getPart(HumanoidVagina))
  253. .setStick(randomOrc.getPart(HumanoidPenis));
  254. (new FuckingDescription("Specific Orc Starts Cumming in Vagina"))
  255. .setDescription(new Say("Specific Orc Starts Cumming in Vagina"))
  256. .addUnit()
  257. .setFucker(randomOrc)
  258. .setHole(WorldState.player.getPart(HumanoidVagina))
  259. .addMarker(FuckingState.CUM_START)
  260. .setStick(randomOrc.getPart(HumanoidPenis));
  261. (new FuckingDescription("Orc in mouth"))
  262. .setDescription(new Say("Orc in mouth."))
  263. .addUnit()
  264. .setFucker(OrcDebugger)
  265. .setHole(HumanoidHead)
  266. .setStick(HumanoidPenis);
  267. // (new CombatDescription("Poking 2")
  268. // .setDescription("Oy cheeky kunt stahp that"))
  269. // .addPokeUnit()
  270. // .setTarget(Person)
  271. // .addMarker(CombatPokeResult.ANNOYED);
  272. //
  273. // (new CombatDescription("Poking 1")
  274. // .setDescription("Heh whatever"))
  275. // .addPokeUnit()
  276. // .setTarget(Person)
  277. // .addMarker(CombatPokeResult.NOHEAT);
  278. //
  279. // (new CombatDescription("Poking 3")
  280. // .setDescription("A'IGHT YOU GET FUCKED NOW MATE SWAER ON ME MUM"))
  281. // .addPokeUnit()
  282. // .setTarget(Person)
  283. // .addMarker(CombatPokeResult.AGGROED);
  284. (new CombatDescription("Allranging Fists"))
  285. .setDescriptionFunction((actor, target, weapons, markers) => {
  286. let say = new Say(...Say.Mention(actor), " attack", target != WorldState.player ? "s " : " ", ...Say.Mention(target), " with ", ...Say.YourTheir(target) ," fists");
  287. if (markers.indexOf(CombatHit.MISS) != -1) {
  288. say.add(", but ", ...Say.Mention(actor), " miss");
  289. } else if (markers.indexOf(CombatHit.CRITICAL) != -1) {
  290. say.add(", it is a strong hit");
  291. }
  292. if (markers.indexOf(CombatResult.KNOCKED) != -1) {
  293. say.add(", the strength of ", ...Say.YourTheir(target) ," attack knocks ", ...Say.Mention(target) , " on the floor.");
  294. } else if (markers.indexOf(CombatResult.KNOCKED_OFF) != -1) {
  295. say.add(", the strength of ", ...Say.YourTheir(target) ," attack knocks ", ...Say.Mention(target), " unconscious.");
  296. } else if (markers.indexOf(CombatResult.KILLED) != -1) {
  297. say.add(", ", new SayHeSheIt(target), " dies.");
  298. } else {
  299. say.add(".");
  300. }
  301. return say;
  302. })
  303. .addUnit()
  304. .setActor(Person)
  305. .setTarget(Person)
  306. .addMarker(AdaptiveDifferential.FULLYADAPTIVE(CombatHit.HIT, CombatHit.CRITICAL, CombatHit.MISS))
  307. .addMarker(AdaptiveDifferential.FULLYADAPTIVE(CombatResult.KILLED, CombatResult.KNOCKED, CombatResult.KNOCKED_OFF));
  308. (new CombatPokeDescription("Hitting Orc"))
  309. .setDescriptionFunction((aggressor, target, markers) => {
  310. let say = new Say(new SayBold(target), ": ");
  311. let action = new SayAction();
  312. action.add("looks at ");
  313. if (aggressor != WorldState.player) {
  314. action.add(new SayThe(), aggressor)
  315. } else {
  316. action.add("you");
  317. }
  318. say.add(action);
  319. if (markers.includes(AIRules.resultHostile)) {
  320. say.add("Fucking seriously!? I'm going to rip your head off!");
  321. return say;
  322. } else if (AIRules.resultRetaliate) {
  323. say.add("Fucking STOP that!");
  324. return say;
  325. }
  326. if (markers.includes(AIRules.actionMin)) {
  327. say.add(
  328. new OneOf(OneOf.PURELY_AT_RANDOM,
  329. "Stop that.",
  330. "You better stop that.",
  331. "Look, I'm not very patient. Stop that."
  332. )
  333. );
  334. } else if (markers.includes(AIRules.actionMed)) {
  335. say.add(
  336. new OneOf(OneOf.PURELY_AT_RANDOM,
  337. "Fucking do that again, see what happens.",
  338. "Watch it!",
  339. "I'm THIS close to ripping your head off!"
  340. )
  341. );
  342. } else if (markers.includes(AIRules.actionMax)) {
  343. say.add(
  344. new OneOf(OneOf.PURELY_AT_RANDOM,
  345. "Goddamn it.",
  346. "Watch it!",
  347. "I'm THIS close to ripping your head off!"
  348. )
  349. );
  350. }
  351. return say;
  352. })
  353. .addUnit()
  354. .setAggressor(Person)
  355. .setTarget(OrcDebugger)
  356. .addMarker(AdaptiveDifferential.FULLYADAPTIVE(AIRules.resultRetaliate, AIRules.resultHostile, AIRules.resultNotHostile))
  357. .addMarker(AdaptiveDifferential.FULLYADAPTIVE(AIRules.actionMin, AIRules.actionMed, AIRules.actionMax));