big steppy
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

777 lines
20 KiB

  1. var things =
  2. {
  3. "Container": Container,
  4. "Person": Person,
  5. "Empty Car": EmptyCar,
  6. "Car": Car,
  7. "Bus": Bus,
  8. "Tram": Tram,
  9. "Motorcycle": Motorcycle,
  10. "House": House,
  11. "Small Skyscraper": SmallSkyscraper,
  12. "Train": Train,
  13. "Train Car": TrainCar,
  14. "Parking Garage": ParkingGarage,
  15. "Overpass": Overpass,
  16. };
  17. var areas =
  18. {
  19. "Container": 0,
  20. "Person": 1,
  21. "Car": 4,
  22. "Bus": 12,
  23. "Tram": 20,
  24. "Motorcycle": 2,
  25. "House": 1000,
  26. "Small Skyscraper": 10000,
  27. "Train": 500,
  28. "TrainCar": 500,
  29. "Parking Garage": 5000,
  30. "Overpass": 10000,
  31. };
  32. var masses =
  33. {
  34. "Container": 0,
  35. "Person": 80,
  36. "Car": 1000,
  37. "Bus": 5000,
  38. "Tram": 10000,
  39. "Motorcycle": 200,
  40. "House": 10000,
  41. "Small Skyscraper": 100000,
  42. "Train": 5000,
  43. "Train Car": 5000,
  44. "Parking Garage": 100000,
  45. "Overpass": 100000,
  46. };
  47. // general logic: each step fills in a fraction of the remaining space
  48. function fill_area2(area, weights = {"Person": 0.1, "Car": 0.05, "House": 0.1})
  49. {
  50. result = [];
  51. candidates = [];
  52. for (var key in weights) {
  53. if (weights.hasOwnProperty(key)) {
  54. candidates.push({"name": key, "area": areas[key], "weight": weights[key]});
  55. }
  56. }
  57. candidates = candidates.sort(function (x,y) {
  58. return x.area > y.area
  59. });
  60. while(candidates.length > 0) {
  61. var candidate = candidates.pop();
  62. if (candidate.area > area)
  63. continue;
  64. var max = Math.floor(area / candidate.area);
  65. var limit = Math.min(max, 100);
  66. var count = 0;
  67. // for small amounts, actually do the randomness
  68. // the first few ones get a better shot
  69. while (limit > 0) {
  70. if (limit <= 3)
  71. count += Math.random() < (1 - Math.pow((1 - candidate.weight),2)) ? 1 : 0;
  72. else
  73. count += Math.random() < candidate.weight ? 1 : 0;
  74. --limit;
  75. }
  76. if (limit < max) {
  77. count += Math.round((max-limit) * candidate.weight);
  78. }
  79. area -= count * candidate.area;
  80. if (count > 0)
  81. result.push(new things[candidate.name](count));
  82. }
  83. if (result.length > 1) {
  84. return new Container(result);
  85. } else if (result.length == 1) {
  86. return result[0];
  87. } else {
  88. return new Person(1);
  89. }
  90. }
  91. function fill_area(area, weights = {"Person": 0.1})
  92. {
  93. var testRadius = Math.sqrt(area / Math.PI);
  94. result = []
  95. for (var key in weights) {
  96. if (weights.hasOwnProperty(key)) {
  97. var objArea = areas[key];
  98. var objRadius = Math.sqrt(objArea / Math.PI);
  99. var newRadius = testRadius - objRadius;
  100. if (newRadius > 0) {
  101. var newArea = newRadius * newRadius * Math.PI;
  102. var numObjs = weights[key] * newArea;
  103. if (numObjs < 1) {
  104. numObjs = Math.random() > numObjs ? 0 : 1;
  105. }
  106. else {
  107. numObjs = Math.round(numObjs);
  108. }
  109. if (numObjs > 0)
  110. result.push(new things[key](numObjs));
  111. else {
  112. // try again with a better chance for just one
  113. }
  114. }
  115. }
  116. }
  117. if (result.length > 1)
  118. return new Container(result);
  119. else if (result.length == 1)
  120. return result[0];
  121. else
  122. return new Person();
  123. }
  124. // describes everything in the container
  125. function describe_all(contents,verbose=true) {
  126. var things = [];
  127. for (var key in contents) {
  128. if (contents.hasOwnProperty(key)) {
  129. things.push(contents[key].describe(verbose));
  130. }
  131. }
  132. return merge_things(things);
  133. }
  134. function random_desc(list, odds=1) {
  135. if (Math.random() < odds)
  136. return list[Math.floor(Math.random() * list.length)];
  137. else
  138. return "";
  139. }
  140. // combine strings into a list with proper grammar
  141. function merge_things(list,semicolons=false) {
  142. if (list.length == 0) {
  143. return "";
  144. } else if (list.length == 1) {
  145. return list[0];
  146. } else if (list.length == 2) {
  147. return list[0] + " and " + list[1];
  148. } else {
  149. result = "";
  150. list.slice(0,list.length-1).forEach(function(term) {
  151. result += term + ", ";
  152. })
  153. result += "and " + list[list.length-1]
  154. return result;
  155. }
  156. }
  157. // combine the adjectives for something into a single string
  158. function merge_desc(list) {
  159. result = ""
  160. list.forEach(function(term) {
  161. if (term != "")
  162. result += term + " ";
  163. });
  164. // knock off the last space
  165. if (result.length > 0) {
  166. result = result.substring(0, result.length - 1);
  167. }
  168. return result;
  169. }
  170. // maybe make this something that approximates a
  171. // normal distribution; doing this 15,000,000 times is bad...
  172. // solution: only a few are random lul
  173. function distribution(min, max, samples) {
  174. var result = 0;
  175. var limit = Math.min(100,samples)
  176. for (var i = 0; i < limit; i++) {
  177. result += Math.floor(Math.random() * (max - min + 1) + min);
  178. }
  179. if (limit < samples) {
  180. result += Math.round((max - min) * (samples - limit));
  181. }
  182. return result;
  183. }
  184. /* default actions */
  185. function defaultStomp(thing) {
  186. return function (verbose=true,height=10) { return "You crush " + thing.describe(verbose) + " underfoot."};
  187. }
  188. function defaultKick(thing) {
  189. return function(verbose=true,height=10) { return "You punt " + thing.describe(verbose) + ", destroying " + (thing.count > 1 ? "them" : "it") + "."; }
  190. }
  191. function defaultEat(thing) {
  192. return function(verbose=true,height=10) { return "You scoop up " + thing.describe(verbose) + " and swallow " + (thing.count > 1 ? "them" : "it") + " whole."; }
  193. }
  194. function defaultAnalVore(thing) {
  195. return function(verbose=true,height=10) { return "You sit yourself down on " + thing.describe(verbose) + ". " + (thing.count > 1 ? "They slide" : "It slides") + " inside with ease."; }
  196. }
  197. function defaultButtcrush(thing) {
  198. return function(verbose=true,height=10) { return "Your heavy ass obliterates " + thing.describe(verbose) + ". "; }
  199. }
  200. function defaultArea(thing) {
  201. return areas[thing.name];
  202. }
  203. function defaultMass(thing) {
  204. return masses[thing.name];
  205. }
  206. function defaultMerge(thing) {
  207. return function(container) {
  208. var newCount = this.count + container.count;
  209. var newThing = new things[thing.name](newCount);
  210. newThing.contents = {};
  211. for (var key in this.contents) {
  212. if (this.contents.hasOwnProperty(key)) {
  213. newThing.contents[key] = this.contents[key];
  214. }
  215. }
  216. for (var key in container.contents) {
  217. if (container.contents.hasOwnProperty(key)) {
  218. if (this.contents.hasOwnProperty(key)) {
  219. newThing.contents[key] = this.contents[key].merge(container.contents[key]);
  220. } else {;
  221. newThing.contents[key] = container.contents[key];
  222. }
  223. }
  224. }
  225. return newThing;
  226. }
  227. }
  228. function defaultSum(thing) {
  229. return function() {
  230. var counts = {}
  231. if (thing.name != "Container")
  232. counts[thing.name] = thing.count;
  233. for (var key in thing.contents) {
  234. if (thing.contents.hasOwnProperty(key)) {
  235. subcount = thing.contents[key].sum();
  236. for (var subkey in subcount) {
  237. if (!counts.hasOwnProperty(subkey)) {
  238. counts[subkey] = 0;
  239. }
  240. counts[subkey] += subcount[subkey];
  241. }
  242. }
  243. }
  244. return counts;
  245. }
  246. }
  247. function defaultSumProperty(thing) {
  248. return function(prop) {
  249. var total = 0;
  250. total += thing[prop] * thing.count;
  251. for (var key in thing.contents) {
  252. if (thing.contents.hasOwnProperty(key)) {
  253. total += thing.contents[key].sum_property(prop);
  254. }
  255. }
  256. return total;
  257. }
  258. }
  259. function DefaultEntity() {
  260. this.stomp = defaultStomp;
  261. this.eat = defaultEat;
  262. this.kick = defaultKick;
  263. this.anal_vore = defaultAnalVore;
  264. this.buttcrush = defaultButtcrush;
  265. this.sum = defaultSum;
  266. this.area = defaultArea;
  267. this.mass = defaultMass;
  268. this.sum_property = defaultSumProperty;
  269. this.merge = defaultMerge;
  270. return this;
  271. }
  272. // god I love reinventing the wheel
  273. function copy_defaults(self,proto) {
  274. for (var key in proto) {
  275. if (proto.hasOwnProperty(key)) {
  276. self[key] = proto[key](self)
  277. }
  278. }
  279. }
  280. function Container(contents = []) {
  281. this.name = "Container";
  282. copy_defaults(this,new DefaultEntity());
  283. this.count = 0;
  284. this.contents = {}
  285. for (var i=0; i < contents.length; i++) {
  286. this.contents[contents[i].name] = contents[i];
  287. }
  288. for (var key in this.contents) {
  289. if (this.contents.hasOwnProperty(key)) {
  290. this.count += this.contents[key].count;
  291. }
  292. }
  293. this.describe = function(verbose = true) {
  294. return describe_all(this.contents,verbose)
  295. }
  296. this.eat = function() {
  297. var line = containerEat(this);
  298. if (line == "")
  299. return defaultEat(this)();
  300. else
  301. return line;
  302. };
  303. return this;
  304. }
  305. function Person(count = 1) {
  306. this.name = "Person";
  307. copy_defaults(this,new DefaultEntity());
  308. this.count = count;
  309. this.contents = {};
  310. this.describeOne = function (verbose=true) {
  311. body = random_desc(["skinny","fat","tall","short","stocky","spindly"], (verbose ? 0.6 : 0));
  312. sex = random_desc(["male", "female"], (verbose ? 1 : 0));
  313. species = random_desc(["wolf","cat","dog","squirrel","horse","hyena","fox","jackal","crux","sergal"]);
  314. return "a " + merge_desc([body,sex,species]);
  315. }
  316. this.describe = function(verbose=true) {
  317. if (verbose) {
  318. if (count <= 3) {
  319. list = [];
  320. for (var i = 0; i < count; i++) {
  321. list.push(this.describeOne(this.count <= 2));
  322. }
  323. return merge_things(list);
  324. } else {
  325. return this.count + " people"
  326. }
  327. } else {
  328. return (this.count > 1 ? this.count + " people" : "a person");
  329. }
  330. }
  331. this.stomp = function() {
  332. var line = personStomp(this);
  333. if (line == "")
  334. return defaultStomp(this)();
  335. else
  336. return line;
  337. };
  338. this.eat = function() {
  339. var line = personEat(this);
  340. if (line == "")
  341. return defaultEat(this)();
  342. else
  343. return line;
  344. };
  345. return this;
  346. }
  347. function EmptyCar(count = 1) {
  348. this.name = "Car";
  349. copy_defaults(this,new DefaultEntity());
  350. this.count = count;
  351. this.contents = {};
  352. this.describeOne = function(verbose=true) {
  353. color = random_desc(["black","black","gray","gray","blue","red","tan","white","white"]);
  354. adjective = random_desc(["rusty","brand-new"],0.3);
  355. type = random_desc(["SUV","coupe","sedan","truck","van","convertible"]);
  356. return "a parked " + merge_desc([adjective,color,type]);
  357. }
  358. this.describe = function(verbose = true) {
  359. if (verbose) {
  360. if (this.count <= 3) {
  361. list = [];
  362. for (var i = 0; i < this.count; i++) {
  363. list.push(this.describeOne());
  364. }
  365. return merge_things(list);
  366. } else {
  367. return this.count + " parked cars";
  368. }
  369. } else {
  370. return (this.count > 1 ? this.count + " parked cars" : "a parked car");
  371. }
  372. }
  373. }
  374. function Car(count = 1) {
  375. this.name = "Car";
  376. copy_defaults(this,new DefaultEntity());
  377. this.count = count;
  378. this.contents = {};
  379. var amount = distribution(2,5,count);
  380. this.contents.person = new Person(amount);
  381. this.describeOne = function(verbose=true) {
  382. color = random_desc(["black","black","gray","gray","blue","red","tan","white","white"], (verbose ? 1 : 0));
  383. adjective = random_desc(["rusty","brand-new"], (verbose ? 0.3 : 0));
  384. type = random_desc(["SUV","coupe","sedan","truck","van","convertible"]);
  385. return "a " + merge_desc([adjective,color,type]);
  386. }
  387. this.describe = function(verbose = true) {
  388. if (verbose) {
  389. if (this.count <= 3) {
  390. list = [];
  391. for (var i = 0; i < this.count; i++) {
  392. list.push(this.describeOne(this.count < 2));
  393. }
  394. return merge_things(list) + " with " + this.contents.person.describe(false) + " inside";
  395. } else {
  396. return this.count + " cars with " + this.contents.person.describe(false) + " inside";
  397. }
  398. } else {
  399. return (this.count > 1 ? this.count + " cars" : "a car");
  400. }
  401. }
  402. }
  403. function Bus(count = 1) {
  404. this.name = "Bus";
  405. copy_defaults(this,new DefaultEntity());
  406. this.count = count;
  407. this.contents = {};
  408. var amount = distribution(10,35,count);
  409. this.contents.person = new Person(amount);
  410. this.describeOne = function(verbose=true) {
  411. adjective = random_desc(["rusty","brand-new"], (verbose ? 0.3 : 0));
  412. color = random_desc(["black","tan","gray"], (verbose ? 1 : 0));
  413. type = random_desc(["bus","double-decker bus","articulating bus"]);
  414. return "a " + merge_desc([adjective,color,type]);
  415. }
  416. this.describe = function(verbose = true) {
  417. if (verbose) {
  418. if (this.count <= 3) {
  419. list = [];
  420. for (var i = 0; i < this.count; i++) {
  421. list.push(this.describeOne(this.count < 2));
  422. }
  423. return merge_things(list) + " with " + this.contents.person.describe() + " inside";
  424. } else {
  425. return this.count + " buses with " + this.contents.person.describe() + " inside";
  426. }
  427. } else {
  428. return (this.count > 1 ? this.count + " buses" : "a bus");
  429. }
  430. }
  431. }
  432. function Tram(count = 1) {
  433. this.name = "Tram";
  434. copy_defaults(this,new DefaultEntity());
  435. this.count = count;
  436. this.contents = {};
  437. var amount = distribution(40,60,count);
  438. this.contents.person = new Person(amount);
  439. this.describeOne = function(verbose=true) {
  440. adjective = random_desc(["rusty","weathered"], (verbose ? 0.3 : 0));
  441. color = random_desc(["blue","brown","gray"], (verbose ? 1 : 0));
  442. type = random_desc(["tram"]);
  443. return "a " + merge_desc([adjective,color,type]);
  444. }
  445. this.describe = function(verbose = true) {
  446. if (verbose) {
  447. if (this.count <= 3) {
  448. list = [];
  449. for (var i = 0; i < this.count; i++) {
  450. list.push(this.describeOne(this.count < 2));
  451. }
  452. return merge_things(list) + " with " + this.contents.person.describe() + " inside";
  453. } else {
  454. return this.count + " trams with " + this.contents.person.describe() + " inside";
  455. }
  456. } else {
  457. return (this.count > 1 ? this.count + " trams" : "a tram");
  458. }
  459. }
  460. this.anal_vore = function() {
  461. return "You slide " + this.describe() + " up your tight ass";
  462. }
  463. }
  464. function Motorcycle(count = 1) {
  465. this.name = "Motorcycle";
  466. copy_defaults(this,new DefaultEntity());
  467. this.count = count;
  468. this.contents = {};
  469. var amount = distribution(1,2,count);
  470. this.contents.person = new Person(amount);
  471. }
  472. function Train(count = 1) {
  473. this.name = "Train";
  474. copy_defaults(this,new DefaultEntity());
  475. this.count = count;
  476. this.contents = {};
  477. var amount = distribution(1,4,count);
  478. this.contents.person = new Person(amount);
  479. amount = distribution(1,10,count);
  480. this.contents.traincar = new TrainCar(amount);
  481. this.describeOne = function(verbose=true) {
  482. adjective = random_desc(["rusty","brand-new"], (verbose ? 0.3 : 0));
  483. color = random_desc(["black","tan","gray"], (verbose ? 1 : 0));
  484. type = random_desc(["train","passenger train","freight train"]);
  485. return "a " + merge_desc([adjective,color,type]);
  486. }
  487. this.describe = function(verbose = true) {
  488. if (verbose) {
  489. if (this.count <= 3) {
  490. list = [];
  491. for (var i = 0; i < this.count; i++) {
  492. list.push(this.describeOne(this.count < 2));
  493. }
  494. return merge_things(list) + " with " + this.contents.person.describe() + " in the engine and " + this.contents.traincar.describe() + " attached";
  495. } else {
  496. return this.count + " trains with " + this.contents.person.describe() + " in the engine and " + this.contents.traincar.describe() + " attached";
  497. }
  498. } else {
  499. return (this.count > 1 ? this.count + " trains" : "a train");
  500. }
  501. }
  502. this.anal_vore = function() {
  503. var cars = (this.contents.traincar.count == 1 ? this.contents.traincar.describe() + " follows it inside" : this.contents.traincar.describe() + " are pulled slowly inside");
  504. return "You snatch up " + this.describeOne() + " and stuff it into your pucker, moaning as " + cars;
  505. }
  506. }
  507. function TrainCar(count = 1) {
  508. this.name = "Train Car";
  509. copy_defaults(this,new DefaultEntity());
  510. this.count = count;
  511. this.contents = {};
  512. var amount = distribution(10,40,count);
  513. this.contents.person = new Person(amount);
  514. this.describeOne = function(verbose=true) {
  515. adjective = random_desc(["rusty","brand-new"], (verbose ? 0.3 : 0));
  516. color = random_desc(["black","tan","gray"], (verbose ? 1 : 0));
  517. type = random_desc(["train car","passenger train car","freight train car"]);
  518. return "a " + merge_desc([adjective,color,type]);
  519. }
  520. this.describe = function(verbose = true) {
  521. if (verbose) {
  522. if (this.count <= 3) {
  523. list = [];
  524. for (var i = 0; i < this.count; i++) {
  525. list.push(this.describeOne(this.count < 2));
  526. }
  527. return merge_things(list) + " with " + describe_all(this.contents) + " inside";
  528. } else {
  529. return this.count + " train cars with " + describe_all(this.contents) + " inside";
  530. }
  531. } else {
  532. return (this.count > 1 ? this.count + " train cars" : "a train car");
  533. }
  534. }
  535. }
  536. function House(count = 1) {
  537. this.name = "House";
  538. copy_defaults(this,new DefaultEntity());
  539. this.count = count;
  540. this.contents = {};
  541. var amount = distribution(0,8,count);
  542. this.contents.person = new Person(amount);
  543. amount = distribution(0,2,count);
  544. this.contents.emptycar = new EmptyCar(amount);
  545. this.describeOne = function(verbose=true) {
  546. size = random_desc(["little","two-story","large"], (verbose ? 0.5 : 0));
  547. color = random_desc(["blue","white","gray","tan","green"], (verbose ? 0.5 : 0));
  548. name = random_desc(["house","house","house","house","house","trailer"], 1);
  549. return "a " + merge_desc([size,color,name]);
  550. }
  551. this.describe = function(verbose = true) {
  552. if (verbose) {
  553. if (this.count <= 3) {
  554. list = [];
  555. for (var i = 0; i < this.count; i++) {
  556. list.push(this.describeOne(this.count < 2));
  557. }
  558. return merge_things(list) + " with " + this.contents.person.describe(verbose) + " inside";
  559. } else {
  560. return this.count + " homes with " + this.contents.person.describe(verbose) + " inside";
  561. }
  562. } else {
  563. return (this.count > 1 ? this.count + " houses" : "a house");
  564. }
  565. }
  566. }
  567. function SmallSkyscraper(count = 1) {
  568. this.name = "Small Skyscraper";
  569. copy_defaults(this,new DefaultEntity());
  570. this.count = count;
  571. this.contents = {};
  572. var amount = distribution(50,500,count);
  573. this.contents.person = new Person(amount);
  574. amount = distribution(10,50,count);
  575. this.contents.emptycar = new EmptyCar(amount);
  576. this.describeOne = function(verbose=true) {
  577. color = random_desc(["blue","white","gray","tan","green"], (verbose ? 0.5 : 0));
  578. name = random_desc(["skyscraper","office tower","office building"], 1);
  579. return "a " + merge_desc([color,name]);
  580. }
  581. this.describe = function(verbose = true) {
  582. if (verbose) {
  583. if (this.count <= 3) {
  584. list = [];
  585. for (var i = 0; i < this.count; i++) {
  586. list.push(this.describeOne(this.count < 2));
  587. }
  588. return merge_things(list) + " with " + describe_all(this.contents,verbose) + " inside";
  589. } else {
  590. return this.count + " small skyscrapers with " + describe_all(this.contents,verbose) + " inside";
  591. }
  592. } else {
  593. return (this.count > 1 ? this.count + " skyscrapers" : "a skyscraper");
  594. }
  595. }
  596. this.anal_vore = function(height=10) {
  597. var line = skyscraperAnalVore(this,height);
  598. if (line == "")
  599. return defaultAnalVore(this)();
  600. else
  601. return line;
  602. };
  603. }
  604. function ParkingGarage(count = 1) {
  605. this.name = "Parking Garage";
  606. copy_defaults(this,new DefaultEntity());
  607. this.count = count;
  608. this.contents = {};
  609. var amount = distribution(10,200,count);
  610. this.contents.person = new Person(amount);
  611. amount = distribution(30,100,count);
  612. this.contents.emptycar = new EmptyCar(amount);
  613. amount = distribution(5,20,count);
  614. this.contents.car = new Car(amount);
  615. this.describeOne = function(verbose=true) {
  616. return "a parking garage";
  617. }
  618. this.describe = function(verbose = true) {
  619. if (verbose) {
  620. return (this.count == 1 ? "a parking garage" : this.count + " parking garages") + " with " + describe_all(this.contents, verbose) + " inside";
  621. } else {
  622. return (this.count == 1 ? "a parking garage" : this.count + " parking garages");
  623. }
  624. }
  625. }
  626. function Overpass(count = 1) {
  627. this.name = "Overpass";
  628. copy_defaults(this,new DefaultEntity());
  629. this.count = count;
  630. this.contents = {};
  631. var amount = distribution(0,20,count);
  632. this.contents.person = new Person(amount);
  633. amount = distribution(25,100,count);
  634. this.contents.car = new Car(amount);
  635. }