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.
 
 
 

625 lines
16 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. "Train": Train,
  12. "Train Car": TrainCar,
  13. "Parking Garage": ParkingGarage,
  14. "Overpass": Overpass,
  15. };
  16. var areas =
  17. {
  18. "Container": 0,
  19. "Person": 3,
  20. "Car": 4,
  21. "Bus": 12,
  22. "Tram": 20,
  23. "Motorcycle": 2,
  24. "House": 1000,
  25. "Train": 500,
  26. "TrainCar": 500,
  27. "Parking Garage": 20000,
  28. "Overpass": 10000,
  29. };
  30. function fill_area(area, weights = {"Person": 0.1})
  31. {
  32. var testRadius = Math.sqrt(area / Math.PI);
  33. result = []
  34. for (var key in weights) {
  35. if (weights.hasOwnProperty(key)) {
  36. var objArea = areas[key];
  37. var objRadius = Math.sqrt(objArea / Math.PI);
  38. var newRadius = testRadius - objRadius;
  39. if (newRadius > 0) {
  40. var newArea = newRadius * newRadius * Math.PI;
  41. var numObjs = weights[key] * newArea;
  42. if (numObjs < 1) {
  43. numObjs = Math.random() > numObjs ? 0 : 1;
  44. }
  45. else {
  46. numObjs = Math.round(numObjs);
  47. }
  48. if (numObjs > 0)
  49. result.push(new things[key](numObjs));
  50. else {
  51. // try again with a better chance for just one
  52. }
  53. }
  54. }
  55. }
  56. if (result.length > 1)
  57. return new Container(result);
  58. else if (result.length == 1)
  59. return result[0];
  60. else
  61. return new Person();
  62. }
  63. var masses =
  64. {
  65. "Container": 0,
  66. "Person": 80,
  67. "Car": 1000,
  68. "Bus": 5000,
  69. "Tram": 10000,
  70. "Motorcycle": 200,
  71. "House": 10000,
  72. "Train": 5000,
  73. "Train Car": 5000,
  74. "Parking Garage": 100000,
  75. "Overpass": 100000,
  76. };
  77. // describes everything in the container
  78. function describe_all(contents) {
  79. var things = [];
  80. for (var key in contents) {
  81. if (contents.hasOwnProperty(key)) {
  82. things.push(contents[key].describe());
  83. }
  84. }
  85. return merge_things(things);
  86. }
  87. function random_desc(list, odds=1) {
  88. if (Math.random() < odds)
  89. return list[Math.floor(Math.random() * list.length)];
  90. else
  91. return "";
  92. }
  93. // combine strings into a list with proper grammar
  94. function merge_things(list,semicolons=false) {
  95. if (list.length == 0) {
  96. return "";
  97. } else if (list.length == 1) {
  98. return list[0];
  99. } else if (list.length == 2) {
  100. return list[0] + " and " + list[1];
  101. } else {
  102. result = "";
  103. list.slice(0,list.length-1).forEach(function(term) {
  104. result += term + ", ";
  105. })
  106. result += "and " + list[list.length-1]
  107. return result;
  108. }
  109. }
  110. // combine the adjectives for something into a single string
  111. function merge_desc(list) {
  112. result = ""
  113. list.forEach(function(term) {
  114. if (term != "")
  115. result += term + " ";
  116. });
  117. // knock off the last space
  118. if (result.length > 0) {
  119. result = result.substring(0, result.length - 1);
  120. }
  121. return result;
  122. }
  123. // maybe make this something that approximates a
  124. // normal distribution; doing this 15,000,000 times is bad...
  125. // solution: only a few are random lul
  126. function distribution(min, max, samples) {
  127. var result = 0;
  128. var limit = Math.min(100,samples)
  129. for (var i = 0; i < limit; i++) {
  130. result += Math.floor(Math.random() * (max - min + 1) + min);
  131. }
  132. if (limit < samples) {
  133. result += Math.round((max - min) * (samples - limit));
  134. }
  135. return result;
  136. }
  137. /* default actions */
  138. function defaultStomp(thing) {
  139. return function () { return "You crush " + thing.describe() + " underfoot."};
  140. }
  141. function defaultKick(thing) {
  142. return function() { return "You punt " + thing.describe() + ", destroying " + (thing.count > 1 ? "them" : "it") + "."; }
  143. }
  144. function defaultEat(thing) {
  145. return function() { return "You scoop up " + thing.describe() + " and swallow " + (thing.count > 1 ? "them" : "it") + " whole."; }
  146. }
  147. function defaultAnalVore(thing) {
  148. return function() { return "Your ass slams down on " + thing.describe() + ". " + (thing.count > 1 ? "They slide" : "It slides") + " inside with ease."; }
  149. }
  150. function defaultArea(thing) {
  151. return areas[thing.name];
  152. }
  153. function defaultMass(thing) {
  154. return masses[thing.name];
  155. }
  156. function defaultMerge(thing) {
  157. return function(container) {
  158. var newCount = this.count + container.count;
  159. var newThing = new things[thing.name](newCount);
  160. newThing.contents = {};
  161. for (var key in this.contents) {
  162. if (this.contents.hasOwnProperty(key)) {
  163. newThing.contents[key] = this.contents[key];
  164. }
  165. }
  166. for (var key in container.contents) {
  167. if (container.contents.hasOwnProperty(key)) {
  168. if (this.contents.hasOwnProperty(key)) {
  169. newThing.contents[key] = this.contents[key].merge(container.contents[key]);
  170. } else {;
  171. newThing.contents[key] = container.contents[key];
  172. }
  173. }
  174. }
  175. return newThing;
  176. }
  177. }
  178. function defaultSum(thing) {
  179. return function() {
  180. var counts = {}
  181. if (thing.name != "Container")
  182. counts[thing.name] = thing.count;
  183. for (var key in thing.contents) {
  184. if (thing.contents.hasOwnProperty(key)) {
  185. subcount = thing.contents[key].sum();
  186. for (var subkey in subcount) {
  187. if (!counts.hasOwnProperty(subkey)) {
  188. counts[subkey] = 0;
  189. }
  190. counts[subkey] += subcount[subkey];
  191. }
  192. }
  193. }
  194. return counts;
  195. }
  196. }
  197. function defaultSumProperty(thing) {
  198. return function(prop) {
  199. var total = 0;
  200. total += thing[prop] * thing.count;
  201. for (var key in thing.contents) {
  202. if (thing.contents.hasOwnProperty(key)) {
  203. total += thing.contents[key].sum_property(prop);
  204. }
  205. }
  206. return total;
  207. }
  208. }
  209. function DefaultEntity() {
  210. this.stomp = defaultStomp;
  211. this.eat = defaultEat;
  212. this.kick = defaultKick;
  213. this.anal_vore = defaultAnalVore;
  214. this.sum = defaultSum;
  215. this.area = defaultArea;
  216. this.mass = defaultMass;
  217. this.sum_property = defaultSumProperty;
  218. this.merge = defaultMerge;
  219. return this;
  220. }
  221. // god I love reinventing the wheel
  222. function copy_defaults(self,proto) {
  223. for (var key in proto) {
  224. if (proto.hasOwnProperty(key)) {
  225. self[key] = proto[key](self)
  226. }
  227. }
  228. }
  229. function Container(contents = []) {
  230. this.name = "Container";
  231. copy_defaults(this,new DefaultEntity());
  232. this.count = 0;
  233. this.contents = {}
  234. for (var i=0; i < contents.length; i++) {
  235. this.contents[contents[i].name] = contents[i];
  236. }
  237. for (var key in this.contents) {
  238. if (this.contents.hasOwnProperty(key)) {
  239. this.count += this.contents[key].count;
  240. }
  241. }
  242. this.describe = function() {
  243. return describe_all(this.contents)
  244. }
  245. return this;
  246. }
  247. function Person(count = 1) {
  248. this.name = "Person";
  249. copy_defaults(this,new DefaultEntity());
  250. this.count = count;
  251. this.contents = {};
  252. this.describeOne = function (verbose=true) {
  253. sex = random_desc(["male", "female"], (verbose ? 1 : 0));
  254. body = random_desc(["skinny","fat","tall","short","stocky","spindly"], (verbose ? 0.6 : 0));
  255. species = random_desc(["wolf","cat","dog","squirrel","horse","hyena","fox","jackal","crux","sergal"]);
  256. return "a " + merge_desc([sex,body,species]);
  257. }
  258. this.describe = function() {
  259. if (count <= 3) {
  260. list = [];
  261. for (var i = 0; i < count; i++) {
  262. list.push(this.describeOne(this.count <= 2));
  263. }
  264. return merge_things(list);
  265. } else {
  266. return this.count + " people"
  267. }
  268. }
  269. return this;
  270. }
  271. function EmptyCar(count = 1) {
  272. this.name = "Car";
  273. copy_defaults(this,new DefaultEntity());
  274. this.count = count;
  275. this.contents = {};
  276. this.describeOne = function() {
  277. color = random_desc(["black","black","gray","gray","blue","red","tan","white","white"]);
  278. adjective = random_desc(["rusty","brand-new"],0.3);
  279. type = random_desc(["SUV","coupe","sedan","truck","van","convertible"]);
  280. return "a parked " + merge_desc([adjective,color,type]);
  281. }
  282. this.describe = function() {
  283. if (this.count <= 3) {
  284. list = [];
  285. for (var i = 0; i < this.count; i++) {
  286. list.push(this.describeOne());
  287. }
  288. return merge_things(list);
  289. } else {
  290. return this.count + " parked cars";
  291. }
  292. }
  293. }
  294. function Car(count = 1) {
  295. this.name = "Car";
  296. copy_defaults(this,new DefaultEntity());
  297. this.count = count;
  298. this.contents = {};
  299. var amount = distribution(2,5,count);
  300. this.contents.person = new Person(amount);
  301. this.describeOne = function(verbose=true) {
  302. color = random_desc(["black","black","gray","gray","blue","red","tan","white","white"], (verbose ? 1 : 0));
  303. adjective = random_desc(["rusty","brand-new"], (verbose ? 0.3 : 0));
  304. type = random_desc(["SUV","coupe","sedan","truck","van","convertible"]);
  305. return "a " + merge_desc([adjective,color,type]);
  306. }
  307. this.describe = function() {
  308. if (this.count <= 3) {
  309. list = [];
  310. for (var i = 0; i < this.count; i++) {
  311. list.push(this.describeOne(this.count < 2));
  312. }
  313. return merge_things(list) + " with " + this.contents.person.describe() + " inside";
  314. } else {
  315. return this.count + " cars with " + this.contents.person.describe() + " inside";
  316. }
  317. }
  318. }
  319. function Bus(count = 1) {
  320. this.name = "Bus";
  321. copy_defaults(this,new DefaultEntity());
  322. this.count = count;
  323. this.contents = {};
  324. var amount = distribution(10,35,count);
  325. this.contents.person = new Person(amount);
  326. this.describeOne = function(verbose=true) {
  327. adjective = random_desc(["rusty","brand-new"], (verbose ? 0.3 : 0));
  328. color = random_desc(["black","tan","gray"], (verbose ? 1 : 0));
  329. type = random_desc(["bus","double-decker bus","articulating bus"]);
  330. return "a " + merge_desc([adjective,color,type]);
  331. }
  332. this.describe = function() {
  333. if (this.count <= 3) {
  334. list = [];
  335. for (var i = 0; i < this.count; i++) {
  336. list.push(this.describeOne(this.count < 2));
  337. }
  338. return merge_things(list) + " with " + this.contents.person.describe() + " inside";
  339. } else {
  340. return this.count + " buses with " + this.contents.person.describe() + " inside";
  341. }
  342. }
  343. }
  344. function Tram(count = 1) {
  345. this.name = "Tram";
  346. copy_defaults(this,new DefaultEntity());
  347. this.count = count;
  348. this.contents = {};
  349. var amount = distribution(40,60,count);
  350. this.contents.person = new Person(amount);
  351. this.describeOne = function(verbose=true) {
  352. adjective = random_desc(["rusty","weathered"], (verbose ? 0.3 : 0));
  353. color = random_desc(["blue","brown","gray"], (verbose ? 1 : 0));
  354. type = random_desc(["tram"]);
  355. return "a " + merge_desc([adjective,color,type]);
  356. }
  357. this.describe = function() {
  358. if (this.count <= 3) {
  359. list = [];
  360. for (var i = 0; i < this.count; i++) {
  361. list.push(this.describeOne(this.count < 2));
  362. }
  363. return merge_things(list) + " with " + this.contents.person.describe() + " inside";
  364. } else {
  365. return this.count + " trams with " + this.contents.person.describe() + " inside";
  366. }
  367. }
  368. this.anal_vore = function() {
  369. return "You slide " + this.describe() + " up your tight ass";
  370. }
  371. }
  372. function Motorcycle(count = 1) {
  373. this.name = "Motorcycle";
  374. copy_defaults(this,new DefaultEntity());
  375. this.count = count;
  376. this.contents = {};
  377. var amount = distribution(1,2,count);
  378. this.contents.person = new Person(amount);
  379. }
  380. function Train(count = 1) {
  381. this.name = "Train";
  382. copy_defaults(this,new DefaultEntity());
  383. this.count = count;
  384. this.contents = {};
  385. var amount = distribution(1,4,count);
  386. this.contents.person = new Person(amount);
  387. amount = distribution(1,10,count);
  388. this.contents.traincar = new TrainCar(amount);
  389. this.describeOne = function(verbose=true) {
  390. adjective = random_desc(["rusty","brand-new"], (verbose ? 0.3 : 0));
  391. color = random_desc(["black","tan","gray"], (verbose ? 1 : 0));
  392. type = random_desc(["train","passenger train","freight train"]);
  393. return "a " + merge_desc([adjective,color,type]);
  394. }
  395. this.describe = function() {
  396. if (this.count <= 3) {
  397. list = [];
  398. for (var i = 0; i < this.count; i++) {
  399. list.push(this.describeOne(this.count < 2));
  400. }
  401. return merge_things(list) + " with " + this.contents.person.describe() + " in the engine and " + this.contents.traincar.describe() + " attached";
  402. } else {
  403. return this.count + " trains with " + this.contents.person.describe() + " in the engine and " + this.contents.traincar.describe() + " attached";
  404. }
  405. }
  406. this.anal_vore = function() {
  407. var cars = (this.contents.traincar.count == 1 ? this.contents.traincar.describe() + " follows it inside" : this.contents.traincar.describe() + " are pulled slowly inside");
  408. return "You snatch up " + this.describeOne() + " and stuff it into your pucker, moaning as " + cars;
  409. }
  410. }
  411. function TrainCar(count = 1) {
  412. this.name = "Train Car";
  413. copy_defaults(this,new DefaultEntity());
  414. this.count = count;
  415. this.contents = {};
  416. var amount = distribution(10,40,count);
  417. this.contents.person = new Person(amount);
  418. this.describeOne = function(verbose=true) {
  419. adjective = random_desc(["rusty","brand-new"], (verbose ? 0.3 : 0));
  420. color = random_desc(["black","tan","gray"], (verbose ? 1 : 0));
  421. type = random_desc(["train car","passenger train car","freight train car"]);
  422. return "a " + merge_desc([adjective,color,type]);
  423. }
  424. this.describe = function() {
  425. if (this.count <= 3) {
  426. list = [];
  427. for (var i = 0; i < this.count; i++) {
  428. list.push(this.describeOne(this.count < 2));
  429. }
  430. return merge_things(list) + " with " + describe_all(this.contents) + " inside";
  431. } else {
  432. return this.count + " train cars with " + describe_all(this.contents) + " inside";
  433. }
  434. }
  435. }
  436. function House(count = 1) {
  437. this.name = "House";
  438. copy_defaults(this,new DefaultEntity());
  439. this.count = count;
  440. this.contents = {};
  441. var amount = distribution(0,8,count);
  442. this.contents.person = new Person(amount);
  443. amount = distribution(0,2,count);
  444. this.contents.emptycar = new EmptyCar(amount);
  445. this.describeOne = function(verbose=true) {
  446. size = random_desc(["little","two-story","large"], (verbose ? 0.5 : 0));
  447. color = random_desc(["blue","white","gray","tan","green"], (verbose ? 0.5 : 0));
  448. name = random_desc(["house","house","house","house","house","trailer"], 1);
  449. return "a " + merge_desc([size,color,name]);
  450. }
  451. this.describe = function() {
  452. if (this.count <= 3) {
  453. list = [];
  454. for (var i = 0; i < this.count; i++) {
  455. list.push(this.describeOne(this.count < 2));
  456. }
  457. return merge_things(list) + " with " + this.contents.person.describe() + " inside";
  458. } else {
  459. return this.count + " homes with " + this.contents.person.describe() + " inside";
  460. }
  461. }
  462. }
  463. function ParkingGarage(count = 1) {
  464. this.name = "Parking Garage";
  465. copy_defaults(this,new DefaultEntity());
  466. this.count = count;
  467. this.contents = {};
  468. var amount = distribution(10,200,count);
  469. this.contents.person = new Person(amount);
  470. amount = distribution(30,100,count);
  471. this.contents.emptycar = new EmptyCar(amount);
  472. amount = distribution(5,20,count);
  473. this.contents.car = new Car(amount);
  474. this.describeOne = function(verbose=true) {
  475. return "a parking garage";
  476. }
  477. this.describe = function() {
  478. if (this.count <= 3) {
  479. list = [];
  480. for (var i = 0; i < this.count; i++) {
  481. list.push(this.describeOne(this.count < 2));
  482. }
  483. return merge_things(list) + " with " + describe_all(this.contents) + " inside";
  484. } else {
  485. return this.count + " parking garages with " + describe_all(this.contents) + " inside";
  486. }
  487. }
  488. }
  489. function Overpass(count = 1) {
  490. this.name = "Overpass";
  491. copy_defaults(this,new DefaultEntity());
  492. this.count = count;
  493. this.contents = {};
  494. var amount = distribution(0,20,count);
  495. this.contents.person = new Person(amount);
  496. amount = distribution(25,100,count);
  497. this.contents.car = new Car(amount);
  498. }