big steppy
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 

1507 行
40 KiB

  1. 'use strict';
  2. var things =
  3. {
  4. "Container": Container,
  5. "Person": Person,
  6. "Human": Human,
  7. "Cow": Cow,
  8. "Empty Car": EmptyCar,
  9. "Car": Car,
  10. "Bus": Bus,
  11. "Tram": Tram,
  12. "House": House,
  13. "Barn": Barn,
  14. "Small Skyscraper": SmallSkyscraper,
  15. "Large Skyscraper": LargeSkyscraper,
  16. "Train": Train,
  17. "Train Car": TrainCar,
  18. "Parking Garage": ParkingGarage,
  19. "Town": Town,
  20. "City": City,
  21. "Continent": Continent,
  22. "Planet": Planet,
  23. "Star": Star,
  24. "Solar System": SolarSystem,
  25. "Galaxy": Galaxy,
  26. "Cluster": Cluster,
  27. "Universe": Universe,
  28. "Multiverse": Multiverse,
  29. "Soldier": Soldier,
  30. "Tank": Tank,
  31. "Artillery": Artillery,
  32. "Helicopter": Helicopter,
  33. "Micro": Micro,
  34. "Macro": Macro,
  35. "Squad": Squad,
  36. "Platoon": Platoon,
  37. "Company": Company,
  38. "Battalion": Battalion,
  39. "Brigade": Brigade,
  40. "Division": Division,
  41. "Tank Division": TankDivision,
  42. "Army": Army,
  43. };
  44. var areas =
  45. {
  46. "Container": 0,
  47. "Person": 0.33,
  48. "Human": 0.33,
  49. "Cow": 2,
  50. "Car": 4,
  51. "Bus": 12,
  52. "Tram": 20,
  53. "House": 150,
  54. "Barn": 300,
  55. "Small Skyscraper": 1000,
  56. "Large Skyscraper": 2000,
  57. "Train": 40,
  58. "Train Car": 20,
  59. "Parking Garage": 750,
  60. "Town": 1e7,
  61. "City": 1e9,
  62. "Continent": 1.5e13,
  63. "Planet": 2.5e14,
  64. "Star": 3e18,
  65. "Solar System": 3e21,
  66. "Galaxy": 2e45,
  67. "Cluster": 2e49,
  68. "Universe": 7e53,
  69. "Multiverse": 5e56,
  70. "Soldier": 1,
  71. "Tank": 10,
  72. "Artillery": 12,
  73. "Helicopter": 8,
  74. "Micro": 0.05,
  75. "Macro": 100,
  76. "Squad": 20,
  77. "Platoon": 100,
  78. "Company": 500,
  79. "Battalion": 3000,
  80. "Brigade": 20000,
  81. "Division": 80000,
  82. "Tank Division": 100000,
  83. "Army": 750000,
  84. };
  85. var masses =
  86. {
  87. "Container": 0,
  88. "Person": 80,
  89. "Human": 80,
  90. "Cow": 300,
  91. "Car": 1000,
  92. "Bus": 5000,
  93. "Tram": 10000,
  94. "House": 10000,
  95. "Barn": 5000,
  96. "Small Skyscraper": 10000000,
  97. "Large Skyscraper": 80000000,
  98. "Train": 50000,
  99. "Train Car": 7500,
  100. "Parking Garage": 10000000,
  101. "Town": 1,
  102. "City": 1,
  103. "Continent": 1e21,
  104. "Planet": 5.972e24,
  105. "Star": 1e40,
  106. "Solar System": 1,
  107. "Galaxy": 1,
  108. "Cluster": 1,
  109. "Universe": 1,
  110. "Multiverse": 1,
  111. "Soldier": 80,
  112. "Tank": 5000,
  113. "Artillery": 7000,
  114. "Helicopter": 1500,
  115. "Micro": 0.01,
  116. "Macro": 80000,
  117. "Squad": 1,
  118. "Platoon": 100,
  119. "Company": 500,
  120. "Battalion": 1000,
  121. "Brigade": 1500,
  122. "Division": 2000,
  123. "Tank Division": 3000,
  124. "Army": 5000,
  125. };
  126. var clusters =
  127. {
  128. "Container": 0,
  129. "Person": 5,
  130. "Human": 5,
  131. "Cow": 15,
  132. "Car": 3,
  133. "Bus": 1,
  134. "Tram": 1,
  135. "House": 5,
  136. "Barn": 1,
  137. "Small Skyscraper": 2,
  138. "Large Skyscraper": 1,
  139. "Train": 2,
  140. "Train Car": 1,
  141. "Parking Garage": 1,
  142. "Town": 5,
  143. "City": 1,
  144. "Continent": 5,
  145. "Planet": 1,
  146. "Star": 1,
  147. "Solar System": 1,
  148. "Galaxy": 1,
  149. "Cluster": 1,
  150. "Universe": 1,
  151. "Multiverse": 1,
  152. "Soldier": 0,
  153. "Tank": 0,
  154. "Artillery": 0,
  155. "Helicopter": 0,
  156. "Micro": 10,
  157. "Macro": 0,
  158. "Squad": 20,
  159. "Platoon": 2,
  160. "Company": 2,
  161. "Battalion": 2,
  162. "Brigade": 2,
  163. "Division": 3,
  164. "Tank Division": 1,
  165. "Army": 2,
  166. };
  167. var cluster_chances =
  168. {
  169. "Container": 0,
  170. "Person": 0.8,
  171. "Human": 0.8,
  172. "Cow": 0.5,
  173. "Car": 0.5,
  174. "Bus": 0.25,
  175. "Tram": 0.2,
  176. "House": 0.5,
  177. "Barn": 0.1,
  178. "Small Skyscraper": 0.25,
  179. "Large Skyscraper": 0.25,
  180. "Train": 0.1,
  181. "Train Car": 0.05,
  182. "Parking Garage": 0.1,
  183. "Town": 0.1,
  184. "City": 0.2,
  185. "Continent": 0.5,
  186. "Planet": 1,
  187. "Star": 1,
  188. "Solar System": 1,
  189. "Galaxy": 1,
  190. "Cluster": 1,
  191. "Universe": 1,
  192. "Multiverse": 1,
  193. "Soldier": 0,
  194. "Tank": 0,
  195. "Artillery": 0,
  196. "Helicopter": 0,
  197. "Micro": 10,
  198. "Macro": 0,
  199. "Squad": .1,
  200. "Platoon": .1,
  201. "Company": .1,
  202. "Battalion": .1,
  203. "Brigade": .1,
  204. "Division": .1,
  205. "Tank Division": 0.15,
  206. "Army": .1,
  207. };
  208. var contents =
  209. {
  210. "Container": [],
  211. "Person": [],
  212. "Human": [],
  213. "Cow": [],
  214. "Car": [["Person",1,4]],
  215. "Bus": [["Person",2,30]],
  216. "Tram": [["Person",10,50]],
  217. "Train": [["Person",1,4,"engine"],["Train Car",2,10]],
  218. "Train Car": [["Person",10,40]],
  219. "House": [["Person",0,8],["Empty Car",0,2]],
  220. "Barn": [["Person",0,2],["Cow",30,70]],
  221. "Small Skyscraper": [["Person",150,750],["Empty Car",10,50]],
  222. "Large Skyscraper": [["Person",500,1500],["Empty Car",20,100]],
  223. "Parking Garage": [["Person",10,200],["Empty Car",100,300],["Car",5,30]],
  224. "Town": [["Person",10000,100000],["House",5000,50000],["Empty Car",200,800],["Car",500,80000],["Bus",5,25],["Train",5,25]],
  225. "City": [["Person",100000,1500000],["House",20000,200000],["Empty Car",10000,100000],["Car",7500,125000],["Bus",200,400],["Train",10,50],["Tram",25,100],["Small Skyscraper",50,300],["Large Skyscraper",10,75],["Parking Garage",5,10]],
  226. "Continent": [["Person",1000000,15000000],["House",2500,10000],["Car",25000,375000],["Train",50,500],["Town",500,1000],["City",50,250]],
  227. "Planet": [["Continent",4,9]],
  228. "Star": [],
  229. "Solar System": [["Star",1,1],["Planet",5,15]],
  230. "Galaxy": [["Star",1e9,500e9],["Solar System",1e8,500e8]],
  231. "Cluster": [["Galaxy",200,5000]],
  232. "Universe": [["Cluster",1.5e9,2.5e9]],
  233. "Multiverse": [["Universe",100,1000]],
  234. "Soldier": [],
  235. "Tank": [["Soldier",3,5]],
  236. "Artillery": [["Soldier",4,6]],
  237. "Helicopter": [["Soldier",4,16]],
  238. "Micro": [[]],
  239. "Macro": [[]],
  240. //Alterante Army Structuring, may be used later
  241. //"Squad": [["Soldier",6,9]],
  242. // "Platoon": [["Squad",3,4]],
  243. //"Company": [["Platoon",3,5],["Squad",0,2]],
  244. //"Battalion": [["Company",4,6]],
  245. //"Brigade": [["Battalion",2,5],["Company",0,3]],
  246. //"Division": [["Brigade",2,4]],
  247. //"Tank Division": [["Brigade",2,4],["Tank",250,500]],
  248. //"Army": [["Division",3,8],["Tank Division",1,5]],
  249. "Squad": [["Soldier",6,9]],
  250. "Platoon": [["Soldier",16,44]],
  251. "Company": [["Soldier",60,200]],
  252. "Battalion": [["Soldier",300,1000]],
  253. "Brigade": [["Soldier",1500,3200]],
  254. "Division": [["Soldier",10000,16000]],
  255. "Tank Division": [["Soldier",8000,1200],["Tank",250,500]],
  256. "Army": [["Soldier",40000,75000]],
  257. };
  258. // replace all instances of from with to
  259. function contents_substitute(from,to) {
  260. for (let key in contents) {
  261. if (contents.hasOwnProperty(key)) {
  262. let type = contents[key];
  263. for (let i=0; i<type.length; i++) {
  264. if (type[i][0] == from) {
  265. type[i][0] = to;
  266. }
  267. }
  268. }
  269. }
  270. }
  271. // remove all instances of thing
  272. function contents_remove(thing) {
  273. for (let key in contents) {
  274. if (contents.hasOwnProperty(key)) {
  275. let type = contents[key];
  276. for (let i=0; i<type.length; i++) {
  277. if (type[i][0] == thing) {
  278. type.splice(i,1);
  279. --i;
  280. }
  281. }
  282. }
  283. }
  284. }
  285. // adds thing to parent
  286. function contents_insert(parent,thing,min,max,label) {
  287. let owner = contents[parent];
  288. if (label == undefined)
  289. owner.push([thing,min,max]);
  290. else
  291. owner.push([thing,min,max,label]);
  292. }
  293. function initContents(name,count) {
  294. let result = {};
  295. let type = contents[name];
  296. for (let i=0; i<type.length; i++) {
  297. let amount = distribution(type[i][1],type[i][2],count);
  298. if (amount > 0) {
  299. // if a custom label is supplied, use it!
  300. if (type[i].length == 4)
  301. result[type[i][3]] = new things[type[i][0]](amount);
  302. else
  303. result[type[i][0]] = new things[type[i][0]](amount);
  304. }
  305. }
  306. return result;
  307. }
  308. function get_living_prey(sum) {
  309. let total = 0;
  310. for (let key in sum) {
  311. if (sum.hasOwnProperty(key)) {
  312. if (key == "Micro" || key == "Macro" || key == "Person" || key == "Cow" || key == 'Soldier')
  313. total += sum[key];
  314. }
  315. }
  316. return total;
  317. }
  318. // general logic: each step fills in a fraction of the remaining space
  319. function fill_area(area, weights, variance=0.15)
  320. {
  321. area = area + Math.random() * variance * 2 * area - variance * area;
  322. var result = [];
  323. var candidates = [];
  324. for (var key in weights) {
  325. if (weights.hasOwnProperty(key)) {
  326. candidates.push({"name": key, "area": areas[key], "weight": weights[key]});
  327. }
  328. }
  329. candidates = candidates.sort(function (x,y) {
  330. return x.area - y.area;
  331. });
  332. while(candidates.length > 0) {
  333. var candidate = candidates.pop();
  334. if (candidate.area > area)
  335. continue;
  336. var max = Math.floor(area / candidate.area);
  337. var limit = Math.min(max, 100);
  338. var count = 0;
  339. var loopvar = limit;
  340. // for small amounts, actually do the randomness
  341. // the first few ones get a much better shot
  342. // if we have nothing at all, it's even better!
  343. if (limit > 0 && result.length == 0) {
  344. ++count;
  345. ++loopvar;
  346. }
  347. while (loopvar < limit) {
  348. if (loopvar <= clusters[candidate.name] && loopvar == 0 && Math.random() < cluster_chances[candidate.name]) {
  349. ++count;
  350. }
  351. else if (loopvar <= clusters[candidate.name]) {
  352. if (Math.random() < candidate.weight ? 1 : 0 || Math.random() < 0.75 * cluster_chances[candidate.name]) {
  353. ++count;
  354. }
  355. }
  356. else {
  357. count += Math.random() < candidate.weight ? 1 : 0;
  358. }
  359. ++loopvar;
  360. }
  361. if (limit < max) {
  362. count += Math.round((max-limit) * candidate.weight);
  363. }
  364. area -= count * candidate.area;
  365. if (count > 0)
  366. result.push(new things[candidate.name](count));
  367. }
  368. return new Container(result);
  369. }
  370. // describes everything in the container
  371. function describe_all(contents,verbose=true,except=[]) {
  372. var things = [];
  373. for (var key in contents) {
  374. if (contents.hasOwnProperty(key) && !except.includes(key)) {
  375. things.push(contents[key].describe(verbose));
  376. }
  377. }
  378. return merge_things(things);
  379. }
  380. function random_desc(list, odds=1) {
  381. if (Math.random() < odds)
  382. return list[Math.floor(Math.random() * list.length)];
  383. else
  384. return "";
  385. }
  386. // combine strings into a list with proper grammar
  387. function merge_things(list,semicolons=false) {
  388. if (list.length == 0) {
  389. return "";
  390. } else if (list.length == 1) {
  391. return list[0];
  392. } else if (list.length == 2) {
  393. return list[0] + " and " + list[1];
  394. } else {
  395. var result = "";
  396. list.slice(0,list.length-1).forEach(function(term) {
  397. result += term + ", ";
  398. });
  399. result += "and " + list[list.length-1];
  400. return result;
  401. }
  402. }
  403. // combine the adjectives for something into a single string
  404. function merge_desc(list) {
  405. var result = "";
  406. list.forEach(function(term) {
  407. if (term != "")
  408. result += term + " ";
  409. });
  410. // knock off the last space
  411. if (result.length > 0) {
  412. result = result.substring(0, result.length - 1);
  413. }
  414. return result;
  415. }
  416. // maybe make this something that approximates a
  417. // normal distribution; doing this 15,000,000 times is bad...
  418. // solution: only a few are random lul
  419. // improvement: take up to 100 samples, then use that to scale the final result
  420. function distribution(min, max, samples) {
  421. var result = 0;
  422. var limit = Math.min(100,samples);
  423. if (limit < samples) {
  424. let dist = 0;
  425. for (let i = 0; i < limit; i++) {
  426. dist += Math.random();
  427. }
  428. dist /= 100;
  429. return Math.floor(dist * samples * (max - min + 1) + samples * min);
  430. } else {
  431. for (let i = 0; i < limit; i++) {
  432. result += Math.floor(Math.random() * (max - min + 1) + min);
  433. }
  434. }
  435. return result;
  436. }
  437. function defaultMultiply(thing) {
  438. return function(amount) {
  439. thing.count *= amount;
  440. for (var key in thing.contents) {
  441. if (thing.contents.hasOwnProperty(key)) {
  442. thing.contents[key].multiply(amount);
  443. }
  444. }
  445. };
  446. }
  447. function defaultArea(thing) {
  448. return areas[thing.name];
  449. }
  450. function defaultMass(thing) {
  451. return masses[thing.name];
  452. }
  453. function defaultMerge(thing) {
  454. return function(container) {
  455. var newCount = this.count + container.count;
  456. var newThing = new things[thing.name](newCount);
  457. newThing.contents = {};
  458. for (var key in this.contents) {
  459. if (this.contents.hasOwnProperty(key)) {
  460. newThing.contents[key] = this.contents[key];
  461. }
  462. }
  463. for (key in container.contents) {
  464. if (container.contents.hasOwnProperty(key)) {
  465. if (this.contents.hasOwnProperty(key)) {
  466. newThing.contents[key] = this.contents[key].merge(container.contents[key]);
  467. } else {
  468. newThing.contents[key] = container.contents[key];
  469. }
  470. }
  471. }
  472. return newThing;
  473. };
  474. }
  475. function listSum(sum) {
  476. let result = [];
  477. for (let key in sum) {
  478. if (sum.hasOwnProperty(key)) {
  479. result.push(new things[key](sum[key]).describe(false));
  480. }
  481. }
  482. return merge_things(result);
  483. }
  484. // turn a nested object into a container with everything on one level
  485. function flatten(thing) {
  486. let dict = defaultSum(thing)();
  487. let list = [];
  488. Object.entries(dict).forEach(function([key, val]) {
  489. let obj = new things[key](val);
  490. obj.contents = [];
  491. list.push(obj);
  492. });
  493. list.sort(function(x,y) {
  494. if (y.area != x.area){
  495. return y.area - x.area;
  496. } else {
  497. return x.name.localeCompare(y.name);
  498. }
  499. });
  500. return new Container(list);
  501. }
  502. function defaultSum(thing) {
  503. return function() {
  504. var counts = {};
  505. if (thing.name != "Container")
  506. counts[thing.name] = thing.count;
  507. for (var key in thing.contents) {
  508. if (thing.contents.hasOwnProperty(key)) {
  509. var subcount = thing.contents[key].sum();
  510. for (var subkey in subcount) {
  511. if (!counts.hasOwnProperty(subkey)) {
  512. counts[subkey] = 0;
  513. }
  514. counts[subkey] += subcount[subkey];
  515. }
  516. }
  517. }
  518. return counts;
  519. };
  520. }
  521. function defaultSumProperty(thing) {
  522. return function(prop) {
  523. var total = 0;
  524. total += thing[prop] * thing.count;
  525. for (var key in thing.contents) {
  526. if (thing.contents.hasOwnProperty(key)) {
  527. total += thing.contents[key].sum_property(prop);
  528. }
  529. }
  530. return total;
  531. };
  532. }
  533. function defaultAddContent(thing) {
  534. return function(name, min, max, count) {
  535. if (min == max) {
  536. let object = new things[name](min*count);
  537. thing.contents[object.name] = object;
  538. } else {
  539. let object = new things[name](distribution(min, max, count));
  540. thing.contents[object.name] = object;
  541. }
  542. };
  543. }
  544. function defaultDescribeSimple(thing) {
  545. return function(flat) {
  546. if (flat) {
  547. return flatten(thing).describe(false)
  548. } else {
  549. return thing.describe(false);
  550. }
  551. }
  552. }
  553. function DefaultEntity() {
  554. this.sum = defaultSum;
  555. this.area = defaultArea;
  556. this.mass = defaultMass;
  557. this.sum_property = defaultSumProperty;
  558. this.merge = defaultMerge;
  559. this.multiply = defaultMultiply;
  560. this.describeSimple = defaultDescribeSimple;
  561. return this;
  562. }
  563. // god I love reinventing the wheel
  564. function copy_defaults(self,proto) {
  565. for (var key in proto) {
  566. if (proto.hasOwnProperty(key)) {
  567. self[key] = proto[key](self);
  568. }
  569. }
  570. }
  571. function Container(contents = []) {
  572. this.name = "Container";
  573. copy_defaults(this,new DefaultEntity());
  574. if (Number.isInteger(contents))
  575. this.count = contents;
  576. else
  577. this.count = 0;
  578. this.contents = {};
  579. for (var i=0; i < contents.length; i++) {
  580. this.contents[contents[i].name] = contents[i];
  581. }
  582. for (var key in this.contents) {
  583. if (this.contents.hasOwnProperty(key)) {
  584. this.count += this.contents[key].count;
  585. }
  586. }
  587. this.describe = function(verbose = true) {
  588. return describe_all(this.contents,verbose);
  589. };
  590. return this;
  591. }
  592. function Person(count = 1) {
  593. this.name = "Person";
  594. copy_defaults(this,new DefaultEntity());
  595. this.count = count;
  596. this.contents = initContents(this.name,this.count);
  597. this.describeOne = function (verbose=true) {
  598. var body = random_desc(["skinny","fat","tall","short","stocky","spindly"], (verbose ? 0.6 : 0));
  599. var sex = random_desc(["male", "female"], (verbose ? 1 : 0));
  600. var species = "";
  601. species = random_desc(["wolf","cat","dog","squirrel","horse","hyena","fox","jackal","crux","sergal"]);
  602. return "a " + merge_desc([body,sex,species]);
  603. };
  604. this.describe = function(verbose=true) {
  605. if (verbose) {
  606. if (count <= 3) {
  607. var list = [];
  608. for (var i = 0; i < count; i++) {
  609. list.push(this.describeOne(this.count <= 2));
  610. }
  611. return merge_things(list);
  612. } else {
  613. return this.count + " people";
  614. }
  615. } else {
  616. return (this.count > 1 ? this.count + " people" : "a person");
  617. }
  618. };
  619. return this;
  620. }
  621. function Human(count = 1) {
  622. this.name = "Person";
  623. copy_defaults(this,new DefaultEntity());
  624. this.count = count;
  625. this.contents = initContents(this.name,this.count);
  626. this.describeOne = function (verbose=true) {
  627. var body = random_desc(["skinny","fat","tall","short","stocky","spindly"], (verbose ? 0.6 : 0));
  628. var sex = random_desc(["man", "woman"], 1);
  629. return "a " + merge_desc([body,sex]);
  630. };
  631. this.describe = function(verbose=true) {
  632. if (verbose) {
  633. if (count <= 3) {
  634. var list = [];
  635. for (var i = 0; i < count; i++) {
  636. list.push(this.describeOne(this.count <= 2));
  637. }
  638. return merge_things(list);
  639. } else {
  640. return this.count + " people";
  641. }
  642. } else {
  643. return (this.count > 1 ? this.count + " people" : "a person");
  644. }
  645. };
  646. return this;
  647. }
  648. function Cow(count = 1) {
  649. this.name = "Cow";
  650. copy_defaults(this,new DefaultEntity());
  651. this.count = count;
  652. this.contents = initContents(this.name,this.count);
  653. this.describeOne = function (verbose=true) {
  654. var body = random_desc(["skinny","fat","tall","short","stocky","spindly"], (verbose ? 0.6 : 0));
  655. var sex = random_desc(["male", "female"], (verbose ? 1 : 0));
  656. return "a " + merge_desc([body,sex,"cow"]);
  657. };
  658. this.describe = function(verbose=true) {
  659. if (verbose) {
  660. if (count <= 3) {
  661. var list = [];
  662. for (var i = 0; i < count; i++) {
  663. list.push(this.describeOne(this.count <= 2));
  664. }
  665. return merge_things(list);
  666. } else {
  667. return this.count + " cattle";
  668. }
  669. } else {
  670. return (this.count > 1 ? this.count + " cattle" : "a cow");
  671. }
  672. };
  673. return this;
  674. }
  675. function EmptyCar(count = 1) {
  676. this.name = "Car";
  677. copy_defaults(this,new DefaultEntity());
  678. this.count = count;
  679. this.contents = initContents(this.name,this.count);
  680. this.describeOne = function(verbose=true) {
  681. var color = random_desc(["black","black","gray","gray","blue","red","tan","white","white"]);
  682. var adjective = random_desc(["rusty","brand-new"],0.3);
  683. var type = random_desc(["SUV","coupe","sedan","truck","van","convertible"]);
  684. return "a parked " + merge_desc([adjective,color,type]);
  685. };
  686. this.describe = function(verbose = true) {
  687. if (verbose) {
  688. if (this.count <= 3) {
  689. var list = [];
  690. for (var i = 0; i < this.count; i++) {
  691. list.push(this.describeOne());
  692. }
  693. return merge_things(list);
  694. } else {
  695. return this.count + " parked cars";
  696. }
  697. } else {
  698. return (this.count > 1 ? this.count + " parked cars" : "a parked car");
  699. }
  700. };
  701. }
  702. function Car(count = 1) {
  703. this.name = "Car";
  704. copy_defaults(this,new DefaultEntity());
  705. this.count = count;
  706. this.contents = initContents(this.name,this.count);
  707. this.describeOne = function(verbose=true) {
  708. var color = random_desc(["black","black","gray","gray","blue","red","tan","white","white"], (verbose ? 1 : 0));
  709. var adjective = random_desc(["rusty","brand-new"], (verbose ? 0.3 : 0));
  710. var type = random_desc(["SUV","coupe","sedan","truck","van","convertible"]);
  711. return "a " + merge_desc([adjective,color,type]);
  712. };
  713. this.describe = function(verbose = true) {
  714. if (verbose) {
  715. if (this.count <= 3) {
  716. var list = [];
  717. for (var i = 0; i < this.count; i++) {
  718. list.push(this.describeOne(this.count < 2));
  719. }
  720. return merge_things(list) + " with " + describe_all(this.contents,verbose) + " inside";
  721. } else {
  722. return this.count + " cars with " + describe_all(this.contents,verbose) + " inside";
  723. }
  724. } else {
  725. return (this.count > 1 ? this.count + " cars" : "a car");
  726. }
  727. };
  728. }
  729. function Bus(count = 1) {
  730. this.name = "Bus";
  731. copy_defaults(this,new DefaultEntity());
  732. this.count = count;
  733. this.contents = initContents(this.name,this.count);
  734. this.describeOne = function(verbose=true) {
  735. var adjective = random_desc(["rusty","brand-new"], (verbose ? 0.3 : 0));
  736. var color = random_desc(["black","tan","gray"], (verbose ? 1 : 0));
  737. var type = random_desc(["bus","school bus","double-decker bus","articulating bus"]);
  738. return "a " + merge_desc([adjective,color,type]);
  739. };
  740. this.describe = function(verbose = true) {
  741. if (verbose) {
  742. if (this.count <= 3) {
  743. var list = [];
  744. for (var i = 0; i < this.count; i++) {
  745. list.push(this.describeOne(this.count < 2));
  746. }
  747. return merge_things(list) + " with " + describe_all(this.contents,verbose) + " inside";
  748. } else {
  749. return this.count + " buses with " + describe_all(this.contents,verbose) + " inside";
  750. }
  751. } else {
  752. return (this.count > 1 ? this.count + " buses" : "a bus");
  753. }
  754. };
  755. }
  756. function Tram(count = 1) {
  757. this.name = "Tram";
  758. copy_defaults(this,new DefaultEntity());
  759. this.count = count;
  760. this.contents = initContents(this.name,this.count);
  761. this.describeOne = function(verbose=true) {
  762. var adjective = random_desc(["rusty","weathered"], (verbose ? 0.3 : 0));
  763. var color = random_desc(["blue","brown","gray"], (verbose ? 1 : 0));
  764. var type = random_desc(["tram"]);
  765. return "a " + merge_desc([adjective,color,type]);
  766. };
  767. this.describe = function(verbose = true) {
  768. if (verbose) {
  769. if (this.count == 1) {
  770. var list = [];
  771. for (var i = 0; i < this.count; i++) {
  772. list.push(this.describeOne(verbose));
  773. }
  774. return merge_things(list) + " with " + describe_all(this.contents,verbose) + " inside";
  775. } else {
  776. return this.count + " trams with " + describe_all(this.contents,verbose) + " inside";
  777. }
  778. } else {
  779. return (this.count > 1 ? this.count + " trams" : "a tram");
  780. }
  781. };
  782. this.anal_vore = function() {
  783. return "You slide " + this.describe() + " up your tight ass";
  784. };
  785. }
  786. function Train(count = 1) {
  787. this.name = "Train";
  788. copy_defaults(this,new DefaultEntity());
  789. this.count = count;
  790. this.contents = initContents(this.name,this.count);
  791. this.describeOne = function(verbose=true) {
  792. var adjective = random_desc(["rusty","brand-new"], (verbose ? 0.3 : 0));
  793. var color = random_desc(["black","tan","gray"], (verbose ? 1 : 0));
  794. var type = random_desc(["train","passenger train","freight train"]);
  795. return "a " + merge_desc([adjective,color,type]);
  796. };
  797. this.describe = function(verbose = true) {
  798. if (verbose) {
  799. if (this.count == 1) {
  800. var list = [];
  801. for (var i = 0; i < this.count; i++) {
  802. list.push(this.describeOne(verbose));
  803. }
  804. return merge_things(list) + " with " + this.contents["engine"].describe(false) + " in the engine and " + this.contents["Train Car"].describe() + " attached";
  805. } else {
  806. return this.count + " trains with " + this.contents["engine"].describe(false) + " in the engine and " + this.contents["Train Car"].describe() + " attached";
  807. }
  808. } else {
  809. return (this.count > 1 ? this.count + " trains" : "a train");
  810. }
  811. };
  812. this.anal_vore = function() {
  813. var cars = (this.contents["Train Car"].count == 1 ? this.contents["Train Car"].describe() + " follows it inside" : this.contents["Train Car"].describe() + " are pulled slowly inside");
  814. return "You snatch up " + this.describeOne() + " and stuff it into your pucker, moaning as " + cars;
  815. };
  816. }
  817. function TrainCar(count = 1) {
  818. this.name = "Train Car";
  819. copy_defaults(this,new DefaultEntity());
  820. this.count = count;
  821. this.contents = initContents(this.name,this.count);
  822. this.describeOne = function(verbose=true) {
  823. var adjective = random_desc(["rusty","brand-new"], (verbose ? 0.3 : 0));
  824. var color = random_desc(["black","tan","gray"], (verbose ? 1 : 0));
  825. var type = random_desc(["train car","passenger train car","freight train car"]);
  826. return "a " + merge_desc([adjective,color,type]);
  827. };
  828. this.describe = function(verbose = true) {
  829. if (verbose) {
  830. return (this.count > 1 ? this.count + " train cars" : "a train car") + " with " + describe_all(this.contents) + " inside";
  831. } else {
  832. return (this.count > 1 ? this.count + " train cars" : "a train car");
  833. }
  834. };
  835. }
  836. function House(count = 1) {
  837. this.name = "House";
  838. copy_defaults(this,new DefaultEntity());
  839. this.count = count;
  840. this.contents = initContents(this.name,this.count);
  841. this.describeOne = function(verbose=true) {
  842. var size = random_desc(["little","two-story","large"], (verbose ? 0.5 : 0));
  843. var color = random_desc(["blue","white","gray","tan","green"], (verbose ? 0.5 : 0));
  844. var name = random_desc(["house","home","house","house","house","trailer"], 1);
  845. return "a " + merge_desc([size,color,name]);
  846. };
  847. this.describe = function(verbose = true) {
  848. if (verbose) {
  849. if (this.count <= 3) {
  850. var list = [];
  851. for (var i = 0; i < this.count; i++) {
  852. list.push(this.describeOne(this.count < 2));
  853. }
  854. return merge_things(list) + " with " + describe_all(this.contents,verbose) + " inside";
  855. } else {
  856. return this.count + " homes with " + describe_all(this.contents,verbose) + " inside";
  857. }
  858. } else {
  859. return (this.count > 1 ? this.count + " houses" : "a house");
  860. }
  861. };
  862. }
  863. function Barn(count = 1) {
  864. this.name = "Barn";
  865. copy_defaults(this,new DefaultEntity());
  866. this.count = count;
  867. this.contents = initContents(this.name,this.count);
  868. this.describeOne = function(verbose=true) {
  869. var size = random_desc(["little","big","large"], (verbose ? 0.5 : 0));
  870. var color = random_desc(["blue","white","gray","tan","green","red"], (verbose ? 0.5 : 0));
  871. var name = random_desc(["barn","barn","barn","barn","barn","farmhouse"], 1);
  872. return "a " + merge_desc([size,color,name]);
  873. };
  874. this.describe = function(verbose = true) {
  875. if (verbose) {
  876. if (this.count <= 3) {
  877. var list = [];
  878. for (var i = 0; i < this.count; i++) {
  879. list.push(this.describeOne(this.count < 2));
  880. }
  881. return merge_things(list) + " with " + describe_all(this.contents,verbose) + " inside";
  882. } else {
  883. return this.count + " barns with " + describe_all(this.contents,verbose) + " inside";
  884. }
  885. } else {
  886. return (this.count > 1 ? this.count + " barns" : "a barn");
  887. }
  888. };
  889. }
  890. function SmallSkyscraper(count = 1) {
  891. this.name = "Small Skyscraper";
  892. copy_defaults(this,new DefaultEntity());
  893. this.count = count;
  894. this.contents = initContents(this.name,this.count);
  895. this.describeOne = function(verbose=true) {
  896. var color = random_desc(["blue","white","gray","tan","green"], (verbose ? 0.5 : 0));
  897. var name = random_desc(["skyscraper","office tower","office building"], 1);
  898. return "a " + merge_desc([color,name]);
  899. };
  900. this.describe = function(verbose = true) {
  901. if (verbose) {
  902. if (this.count <= 3) {
  903. var list = [];
  904. for (var i = 0; i < this.count; i++) {
  905. list.push(this.describeOne(this.count < 2));
  906. }
  907. return merge_things(list) + " with " + describe_all(this.contents,verbose) + " inside";
  908. } else {
  909. return this.count + " small skyscrapers with " + describe_all(this.contents,verbose) + " inside";
  910. }
  911. } else {
  912. return (this.count > 1 ? this.count + " small skyscrapers" : "a small skyscraper");
  913. }
  914. };
  915. }
  916. function LargeSkyscraper(count = 1) {
  917. this.name = "Large Skyscraper";
  918. copy_defaults(this,new DefaultEntity());
  919. this.count = count;
  920. this.contents = initContents(this.name,this.count);
  921. this.describeOne = function(verbose=true) {
  922. var color = random_desc(["blue","white","gray","tan","green","glass"], (verbose ? 0.5 : 0));
  923. var name = random_desc(["skyscraper","office tower","office building"], 1);
  924. return "a " + merge_desc(["towering",color,name]);
  925. };
  926. this.describe = function(verbose = true) {
  927. if (verbose) {
  928. if (this.count <= 3) {
  929. var list = [];
  930. for (var i = 0; i < this.count; i++) {
  931. list.push(this.describeOne(this.count < 2));
  932. }
  933. return merge_things(list) + " with " + describe_all(this.contents,verbose) + " inside";
  934. } else {
  935. return this.count + " large skyscrapers with " + describe_all(this.contents,verbose) + " inside";
  936. }
  937. } else {
  938. return (this.count > 1 ? this.count + " large skyscrapers" : "a large skyscraper");
  939. }
  940. };
  941. }
  942. function ParkingGarage(count = 1) {
  943. this.name = "Parking Garage";
  944. copy_defaults(this,new DefaultEntity());
  945. this.count = count;
  946. this.contents = initContents(this.name,this.count);
  947. this.describeOne = function(verbose=true) {
  948. return "a parking garage";
  949. };
  950. this.describe = function(verbose = true) {
  951. if (verbose) {
  952. return (this.count == 1 ? "a parking garage" : this.count + " parking garages") + " with " + describe_all(this.contents, verbose) + " inside";
  953. } else {
  954. return (this.count == 1 ? "a parking garage" : this.count + " parking garages");
  955. }
  956. };
  957. }
  958. function Town(count = 1) {
  959. this.name = "Town";
  960. copy_defaults(this,new DefaultEntity());
  961. this.count = count;
  962. this.contents = initContents(this.name,this.count);
  963. this.describe = function(verbose = true) {
  964. if (verbose) {
  965. return (this.count == 1 ? "a town" : this.count + " towns") + " with " + describe_all(this.contents, verbose) + " in " + (this.count == 1 ? "it" : "them");
  966. } else {
  967. return (this.count == 1 ? "a town" : this.count + " towns");
  968. }
  969. };
  970. }
  971. function City(count = 1) {
  972. this.name = "City";
  973. copy_defaults(this,new DefaultEntity());
  974. this.count = count;
  975. this.contents = initContents(this.name,this.count);
  976. this.describe = function(verbose = true) {
  977. if (verbose) {
  978. return (this.count == 1 ? "a city" : this.count + " cities") + " with " + describe_all(this.contents, verbose) + " in " + (this.count == 1 ? "it" : "them");
  979. } else {
  980. return (this.count == 1 ? "a city" : this.count + " cities");
  981. }
  982. };
  983. }
  984. function Continent(count = 1) {
  985. this.name = "Continent";
  986. copy_defaults(this,new DefaultEntity());
  987. this.count = count;
  988. this.contents = initContents(this.name,this.count);
  989. this.describe = function(verbose = true) {
  990. if (verbose) {
  991. return (this.count == 1 ? "a continent" : this.count + " continents") + " with " + describe_all(this.contents, verbose) + " on " + (this.count == 1 ? "it" : "them");
  992. } else {
  993. return (this.count == 1 ? "a continent" : this.count + " continents");
  994. }
  995. };
  996. }
  997. function Planet(count = 1) {
  998. this.name = "Planet";
  999. copy_defaults(this,new DefaultEntity());
  1000. this.count = count;
  1001. this.contents = initContents(this.name,this.count);
  1002. this.describe = function(verbose = true) {
  1003. if (verbose) {
  1004. return (this.count == 1 ? "a planet" : this.count + " planets") + " with " + describe_all(this.contents, verbose) + " on " + (this.count == 1 ? "it" : "them");
  1005. } else {
  1006. return (this.count == 1 ? "a planet" : this.count + " planets");
  1007. }
  1008. };
  1009. }
  1010. function Star(count = 1) {
  1011. this.name = "Star";
  1012. copy_defaults(this,new DefaultEntity());
  1013. this.count = count;
  1014. this.contents = initContents(this.name,this.count);
  1015. this.describe = function(verbose = true) {
  1016. return (this.count == 1 ? "a star" : this.count + " stars");
  1017. };
  1018. }
  1019. function SolarSystem(count = 1) {
  1020. this.name = "Solar System";
  1021. copy_defaults(this,new DefaultEntity());
  1022. this.count = count;
  1023. this.contents = initContents(this.name,this.count);
  1024. this.describe = function(verbose = true) {
  1025. if (verbose) {
  1026. return (this.count == 1 ? "a solar system" : this.count + " solar systems") + " made up of " + describe_all(this.contents, verbose);
  1027. } else {
  1028. return (this.count == 1 ? "a solar system" : this.count + " solar systems");
  1029. }
  1030. };
  1031. }
  1032. function Galaxy(count = 1) {
  1033. this.name = "Galaxy";
  1034. copy_defaults(this,new DefaultEntity());
  1035. this.count = count;
  1036. this.contents = initContents(this.name,this.count);
  1037. this.describe = function(verbose = true) {
  1038. if (verbose) {
  1039. return (this.count == 1 ? "a galaxy" : this.count + " galaxies") + " made up of " + describe_all(this.contents, verbose);
  1040. } else {
  1041. return (this.count == 1 ? "a galaxy" : this.count + " galaxies");
  1042. }
  1043. };
  1044. }
  1045. function Cluster(count = 1) {
  1046. this.name = "Cluster";
  1047. copy_defaults(this,new DefaultEntity());
  1048. this.count = count;
  1049. this.contents = initContents(this.name,this.count);
  1050. this.describe = function(verbose = true) {
  1051. if (verbose) {
  1052. return (this.count == 1 ? "a cluster" : this.count + " clusters") + " made up of " + describe_all(this.contents, verbose);
  1053. } else {
  1054. return (this.count == 1 ? "a cluster" : this.count + " clusters");
  1055. }
  1056. };
  1057. }
  1058. function Universe(count = 1) {
  1059. this.name = "Universe";
  1060. copy_defaults(this,new DefaultEntity());
  1061. this.count = count;
  1062. this.contents = initContents(this.name,this.count);
  1063. this.describe = function(verbose = true) {
  1064. if (verbose) {
  1065. return (this.count == 1 ? "a universe" : this.count + " universes") + " made up of " + describe_all(this.contents, verbose);
  1066. } else {
  1067. return (this.count == 1 ? "a universe" : this.count + " universes");
  1068. }
  1069. };
  1070. }
  1071. function Multiverse(count = 1) {
  1072. this.name = "Multiverse";
  1073. copy_defaults(this,new DefaultEntity());
  1074. this.count = count;
  1075. this.contents = initContents(this.name,this.count);
  1076. this.describe = function(verbose = true) {
  1077. if (verbose) {
  1078. return (this.count == 1 ? "a multiverse" : this.count + " multiverses") + " made up of " + describe_all(this.contents, verbose);
  1079. } else {
  1080. return (this.count == 1 ? "a multiverse" : this.count + " multiverses");
  1081. }
  1082. };
  1083. }
  1084. function Soldier(count = 1) {
  1085. this.name = "Soldier";
  1086. copy_defaults(this,new DefaultEntity());
  1087. this.count = count;
  1088. this.contents = initContents(this.name,this.count);
  1089. this.describe = function(verbose = true) {
  1090. return (this.count == 1 ? "a soldier" : this.count + " soldiers");
  1091. };
  1092. }
  1093. function Tank(count = 1) {
  1094. this.name = "Tank";
  1095. copy_defaults(this,new DefaultEntity());
  1096. this.count = count;
  1097. this.contents = initContents(this.name,this.count);
  1098. this.describe = function(verbose = true) {
  1099. if (verbose) {
  1100. return (this.count == 1 ? "a tank" : this.count + " tanks") + " with " + describe_all(this.contents, verbose) + " trapped inside.";
  1101. } else {
  1102. return (this.count == 1 ? "a tank" : this.count + " tanks");
  1103. }
  1104. };
  1105. }
  1106. function Artillery(count = 1) {
  1107. this.name = "Artillery";
  1108. copy_defaults(this,new DefaultEntity());
  1109. this.count = count;
  1110. this.contents = initContents(this.name,this.count);
  1111. this.describe = function(verbose = true) {
  1112. if (verbose) {
  1113. return (this.count == 1 ? "an artillery unit" : this.count + " artillery units") + " with " + describe_all(this.contents, verbose) + " trapped inside.";
  1114. } else {
  1115. return (this.count == 1 ? "an artillery unit" : this.count + " artillery units");
  1116. }
  1117. };
  1118. }
  1119. function Helicopter(count = 1) {
  1120. this.name = "Helicopter";
  1121. copy_defaults(this,new DefaultEntity());
  1122. this.count = count;
  1123. this.contents = initContents(this.name,this.count);
  1124. this.describe = function(verbose = true) {
  1125. if (verbose) {
  1126. return (this.count == 1 ? "a helicopter" : this.count + " helicopters") + " with " + describe_all(this.contents, verbose) + " riding inside.";
  1127. } else {
  1128. return (this.count == 1 ? "a helicopter" : this.count + " helicopters");
  1129. }
  1130. };
  1131. }
  1132. function Micro(count = 1) {
  1133. this.name = "Micro";
  1134. copy_defaults(this,new DefaultEntity());
  1135. this.count = count;
  1136. this.contents = initContents(this.name,this.count);
  1137. this.describe = function(verbose = true) {
  1138. return (this.count == 1 ? "a micro" : this.count + " micros");
  1139. };
  1140. }
  1141. function Macro(count = 1) {
  1142. this.name = "Macro";
  1143. copy_defaults(this,new DefaultEntity());
  1144. this.count = count;
  1145. this.contents = initContents(this.name,this.count);
  1146. this.describe = function(verbose = true) {
  1147. return (this.count == 1 ? "a smaller macro" : this.count + " smaller macros");
  1148. };
  1149. }
  1150. function Squad(count = 1) {
  1151. this.name = "Squad";
  1152. copy_defaults(this,new DefaultEntity());
  1153. this.count = count;
  1154. this.contents = initContents(this.name,this.count);
  1155. this.describeOne = function(verbose=true) {
  1156. return "a squad";
  1157. };
  1158. this.describe = function(verbose = true) {
  1159. if (verbose) {
  1160. return (this.count == 1 ? "a squad" : this.count + " squads") + " made up of " + describe_all(this.contents, verbose);
  1161. } else {
  1162. return (this.count == 1 ? "a squad" : this.count + " squads");
  1163. }
  1164. };
  1165. }
  1166. function Platoon(count = 1) {
  1167. this.name = "Platoon";
  1168. copy_defaults(this,new DefaultEntity());
  1169. this.count = count;
  1170. this.contents = initContents(this.name,this.count);
  1171. this.describeOne = function(verbose=true) {
  1172. return "a military platoon";
  1173. };
  1174. this.describe = function(verbose = true) {
  1175. if (verbose) {
  1176. return (this.count == 1 ? "a platoon" : this.count + " platoons") + " consisting of " + describe_all(this.contents, verbose);
  1177. } else {
  1178. return (this.count == 1 ? "a platoon" : this.count + " platoons");
  1179. }
  1180. };
  1181. }
  1182. function Company(count = 1) {
  1183. this.name = "Company";
  1184. copy_defaults(this,new DefaultEntity());
  1185. this.count = count;
  1186. this.contents = initContents(this.name,this.count);
  1187. this.describeOne = function(verbose=true) {
  1188. return "a company of soldiers";
  1189. };
  1190. this.describe = function(verbose = true) {
  1191. if (verbose) {
  1192. return (this.count == 1 ? "a company" : this.count + " companies") + " of " + describe_all(this.contents, verbose);
  1193. } else {
  1194. return (this.count == 1 ? "a company" : this.count + " companies");
  1195. }
  1196. };
  1197. }
  1198. function Battalion(count = 1) {
  1199. this.name = "Battalion";
  1200. copy_defaults(this,new DefaultEntity());
  1201. this.count = count;
  1202. this.contents = initContents(this.name,this.count);
  1203. this.describeOne = function(verbose=true) {
  1204. return "a battalion";
  1205. };
  1206. this.describe = function(verbose = true) {
  1207. if (verbose) {
  1208. return (this.count == 1 ? "a battalion" : this.count + " battalions") + " containing " + describe_all(this.contents, verbose);
  1209. } else {
  1210. return (this.count == 1 ? "a battalion" : this.count + " battalions");
  1211. }
  1212. };
  1213. }
  1214. function Brigade(count = 1) {
  1215. this.name = "Brigade";
  1216. copy_defaults(this,new DefaultEntity());
  1217. this.count = count;
  1218. this.contents = initContents(this.name,this.count);
  1219. this.describeOne = function(verbose=true) {
  1220. return "a brigade";
  1221. };
  1222. this.describe = function(verbose = true) {
  1223. if (verbose) {
  1224. return (this.count == 1 ? "a brigade" : this.count + " brigades") + " made up of " + describe_all(this.contents, verbose);
  1225. } else {
  1226. return (this.count == 1 ? "a brigade" : this.count + " brigades");
  1227. }
  1228. };
  1229. }
  1230. function Division(count = 1) {
  1231. this.name = "Division";
  1232. copy_defaults(this,new DefaultEntity());
  1233. this.count = count;
  1234. this.contents = initContents(this.name,this.count);
  1235. this.describeOne = function(verbose=true) {
  1236. return "a division";
  1237. };
  1238. this.describe = function(verbose = true) {
  1239. if (verbose) {
  1240. return (this.count == 1 ? "a division" : this.count + " divisions") + " of " + describe_all(this.contents, verbose);
  1241. } else {
  1242. return (this.count == 1 ? "a division" : this.count + " divisions");
  1243. }
  1244. };
  1245. }
  1246. function TankDivision(count = 1) {
  1247. this.name = "Tank Division";
  1248. copy_defaults(this,new DefaultEntity());
  1249. this.count = count;
  1250. this.contents = initContents(this.name,this.count);
  1251. this.describeOne = function(verbose=true) {
  1252. return "a tank division";
  1253. };
  1254. this.describe = function(verbose = true) {
  1255. if (verbose) {
  1256. return (this.count == 1 ? "a tank division" : this.count + " tank divisions") + " of " + describe_all(this.contents, verbose);
  1257. } else {
  1258. return (this.count == 1 ? "a tank division" : this.count + " tank divisions");
  1259. }
  1260. };
  1261. }
  1262. function Army(count = 1) {
  1263. this.name = "Army";
  1264. copy_defaults(this,new DefaultEntity());
  1265. this.count = count;
  1266. this.contents = initContents(this.name,this.count);
  1267. this.describeOne = function(verbose=true) {
  1268. return "an army";
  1269. };
  1270. this.describe = function(verbose = true) {
  1271. if (verbose) {
  1272. return (this.count == 1 ? "an army" : this.count + " armies") + " made up of " + describe_all(this.contents, verbose);
  1273. } else {
  1274. return (this.count == 1 ? "an army" : this.count + " armies");
  1275. }
  1276. };
  1277. }
  1278. //"Brigade": 20000,
  1279. //"Division": 80000,
  1280. //"Tank Division": 100000,
  1281. //"Army": 750000,