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.
 
 
 

1889 lines
50 KiB

  1. /*
  2. function defaultSumDST(thing) {
  3. return function() {
  4. var counts = {};
  5. if (thing.name != "Container") //if a container is detected, sets counts
  6. counts[thing.name] = thing.count;
  7. for (var key in thing.contents) {
  8. if (thing.contents.hasOwnProperty(key)) {
  9. var subcount = thing.contents[key].sum();
  10. for (var subkey in subcount) {
  11. if (!counts.hasOwnProperty(subkey)) {
  12. counts[subkey] = 0;
  13. }
  14. counts[subkey] += subcount[subkey];
  15. }
  16. }
  17. }
  18. return counts;
  19. };
  20. }
  21. function defaultSumProperty(thing) {
  22. return function(prop) {
  23. var total = 0;
  24. total += thing[prop] * thing.count;
  25. for (var key in thing.contents) {
  26. if (thing.contents.hasOwnProperty(key)) {
  27. total += thing.contents[key].sum_property(prop);
  28. }
  29. }
  30. return total;
  31. };
  32. }
  33. function defaultArea(thing) {
  34. return areas[thing.name];
  35. }
  36. function DefaultDestructable() {
  37. this.name = this.defaults.name;
  38. this.area = this.defaults.area;
  39. this.mass = this.defaults.mass;
  40. this.sum = defaultSumDST;
  41. this.sum_property = defaultSumProperty;
  42. this.merge = defaultMerge;
  43. this.multiply = defaultMultiply;
  44. this.describeSimple = defaultDescribeSimple;
  45. return this;
  46. }
  47. function copy_defaultsDST(self,proto) {
  48. for (var key in proto) {
  49. if (proto.hasOwnProperty(key)) {
  50. self[key] = proto[key](self);
  51. }
  52. }
  53. }
  54. personVar = {
  55. name: "Person",
  56. area: 0.33,
  57. mass: 80,
  58. clusters: 5,
  59. cluster_chances: .8,
  60. contents: [],
  61. body: [["skinny", -10,0],["fat", 15,.05],["tall", 7, 0],["short",-7,0],["stocky",5,.02],["spindly",-5,-.02],["muscular",7,0],["fit",0,0],["multi-colored",0,0]],//["bodytype", mass modifier, area modifier]
  62. sex: [["male",2,.02],["female",2,.02]],//["sex", mass modifier, area modifier]
  63. species: [["wolf",80,.35],["cat",70,.3],["dog",75,.31],["squirrel",68,.29],["horse",90,.4],["hyena",78,.32],["fox",72,.3],["jackal",74,.32],["crux",90,.33],["sergal",77,.34]],//["species", mass modifier, area modifier]
  64. singular: "person",
  65. plural: "people"
  66. }
  67. function PersonDST(count = 1) {
  68. this.defaults = personVar;
  69. copy_defaultsDST(this,new DefaultDestructable());
  70. this.count = count;
  71. this.contents = initContents(this.name,this.count);
  72. this.describeOne = function (verbose=true) {
  73. var body = random_desc(this.properties.body, (verbose ? 0.6 : 0));
  74. var sex = random_desc(this.properties.sex, (verbose ? 1 : 0));
  75. var species = random_desc(this.properties.species);
  76. return "a " + merge_desc([body,sex,species]);
  77. };
  78. this.describe = function(verbose=true) {
  79. if (verbose) {
  80. if (count <= 3) {
  81. var list = [];
  82. for (var i = 0; i < count; i++) {
  83. list.push(this.describeOne(this.count <= 2));
  84. }
  85. return merge_things(list);
  86. } else {
  87. return this.count + " people";
  88. }
  89. } else {
  90. return (this.count > 1 ? this.count + " people" : "a person");
  91. }
  92. };
  93. return this;
  94. }
  95. */
  96. 'use strict';
  97. var things =
  98. {
  99. "Container": {
  100. "Container": Container,
  101. mass: 0,
  102. area: 0,
  103. clusters: 0,
  104. cluster_chances: 0,
  105. contents: [],
  106. },
  107. //Creatures
  108. "Person": {
  109. "Person": Person,
  110. mass: 80,
  111. area: .33,
  112. clusters: 5,
  113. cluster_chances: .8,
  114. contents: [],
  115. },
  116. "Human": {
  117. "Human": Human,
  118. mass: 80,
  119. area: .33,
  120. clusters: 5,
  121. cluster_chances: .8,
  122. contents: [],
  123. },
  124. "Cow": {
  125. "Cow": Cow,
  126. mass: 300,
  127. area: 2,
  128. clusters: 15,
  129. cluster_chances: .5,
  130. contents: [],
  131. },
  132. "Micro": {
  133. "Micro": Micro,
  134. mass: .01,
  135. area: .05,
  136. clusters: 50,
  137. cluster_chances: 1,
  138. contents: [[]],
  139. },
  140. "Macro": {
  141. "Macro": Macro,
  142. mass: 8e4,
  143. area: 100,
  144. clusters: 0,
  145. cluster_chances: 0,
  146. contents: [[]],
  147. },
  148. //Vehicles
  149. "Empty Car": {
  150. "Empty Car": EmptyCar,
  151. mass: 1000,
  152. area: 4,
  153. clusters: 2,
  154. cluster_chances: .3,
  155. contents: [[]],
  156. },
  157. "Car": {
  158. "Car": Car,
  159. mass: 1000,
  160. area: 4,
  161. clusters: 4,
  162. cluster_chances: .5,
  163. contents: [["Person",1,4]],
  164. },
  165. "Bus": {
  166. "Bus": Bus,
  167. mass: 5000,
  168. area: 12,
  169. clusters: 1,
  170. cluster_chances: .25,
  171. contents: [["Person",2,30]],
  172. },
  173. "Tram": {
  174. "Tram": Tram,
  175. mass: 1e4,
  176. area: 20,
  177. clusters: 1,
  178. cluster_chances: .2,
  179. contents: [["Person",10,50]],
  180. },
  181. "Train": {
  182. "Train": Train,
  183. mass: 5e4,
  184. area: 40,
  185. clusters: 2,
  186. cluster_chances: .1,
  187. contents: [["Person",1,4,"engine"],["Train Car",2,10]],
  188. },
  189. "Train Car": {
  190. "Train Car": TrainCar,
  191. mass: 7500,
  192. area: 20,
  193. clusters: 1,
  194. cluster_chances: .05,
  195. contents: [["Person",10,40]],
  196. },
  197. //Buildings
  198. "House": {
  199. "House": House,
  200. mass: 1e4,
  201. area: 150,
  202. clusters: 5,
  203. cluster_chances: .5,
  204. contents: [["Person",0,8],["Empty Car",0,2]],
  205. },
  206. "Business": {
  207. "Business": Business,
  208. mass: 5e4,
  209. area: 400,
  210. clusters: 5,
  211. cluster_chances: .25,
  212. contents: [["Person",0,30],["Car",0,5],["Empty Car",0,20]],
  213. },
  214. "Barn": {
  215. "Barn": Barn,
  216. mass: 5e3,
  217. area: 300,
  218. clusters: 1,
  219. cluster_chances: .1,
  220. contents: [["Person",0,2],["Cow",30,70]],
  221. },
  222. "Small Skyscraper": {
  223. "Small Skyscraper": SmallSkyscraper,
  224. mass: 1e7,
  225. area: 1000,
  226. clusters: 2,
  227. cluster_chances: .25,
  228. contents: [["Person",150,750],["Empty Car",10,50]],
  229. },
  230. "Large Skyscraper": {
  231. "Large Skyscraper": LargeSkyscraper,
  232. mass: 8e7,
  233. area: 2000,
  234. clusters: 1,
  235. cluster_chances: .25,
  236. contents: [["Person",500,1500],["Empty Car",20,100]],
  237. },
  238. "Parking Garage": {
  239. "Parking Garage": ParkingGarage,
  240. mass: 1e7,
  241. area: 750,
  242. clusters: 1,
  243. cluster_chances: .1,
  244. contents: [["Person",10,200],["Empty Car",100,300],["Car",5,30]],
  245. },
  246. //Places
  247. "Town": {
  248. "Town": Town,
  249. mass: 1,
  250. area: 1e7,
  251. clusters: 5,
  252. cluster_chances: .1,
  253. contents: [["Person",10000,100000],["House",5000,50000],["Empty Car",200,800],["Car",500,80000],["Bus",5,25],["Train",5,25],["Business",500,5000]],
  254. },
  255. "City": {
  256. "City": City,
  257. mass: 1,
  258. area: 1e9,
  259. clusters: 0,
  260. cluster_chances: .2,
  261. contents: [["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],["Business",2000,10000]],
  262. },
  263. "Continent": {
  264. "Continent": Continent,
  265. mass: 1e21,
  266. area: 1.5e13,
  267. clusters: 5,
  268. cluster_chances: .5,
  269. contents: [["Person",1000000,15000000],["House",2500,10000],["Car",25000,375000],["Train",50,500],["Town",500,1000],["City",50,250],["Business",250,1000]],
  270. },
  271. "Planet": {
  272. "Planet": Planet,
  273. mass: 5.972e24,
  274. area: 2.5e14,
  275. clusters: 0,
  276. cluster_chances: 1,
  277. contents: [["Continent",4,9]],
  278. },
  279. "Star": {
  280. "Star": Star,
  281. mass: 1e40,
  282. area: 3e18,
  283. clusters: 1,
  284. cluster_chances: 1,
  285. contents: [],
  286. },
  287. "Solar System": {
  288. "Solar System": SolarSystem,
  289. mass: 1,
  290. area: 3e21,
  291. clusters: 1,
  292. cluster_chances: 1,
  293. contents: [["Star",1,1],["Planet",5,15]],
  294. },
  295. "Galaxy": {
  296. "Galaxy": Galaxy,
  297. mass: 1,
  298. area: 2e45,
  299. clusters: 1,
  300. cluster_chances: 1,
  301. contents: [["Star",1e9,500e9],["Solar System",1e8,500e8]],
  302. },
  303. "Cluster": {
  304. "Cluster": Cluster,
  305. mass: 1,
  306. area: 2e49,
  307. clusters: 1,
  308. cluster_chances: 1,
  309. contents: [["Galaxy",200,5000]],
  310. },
  311. "Universe": {
  312. "Universe": Universe,
  313. mass: 1,
  314. area: 7e53,
  315. clusters: 1,
  316. cluster_chances: 1,
  317. contents: [["Cluster",1.5e9,2.5e9]],
  318. },
  319. "Multiverse": {
  320. "Multiverse": Multiverse,
  321. mass: 1,
  322. area: 5e56,
  323. clusters: 1,
  324. cluster_chances: 1,
  325. contents: [["Universe",100,1000]],
  326. },
  327. //Military
  328. "Soldier": {
  329. "Soldier": Soldier,
  330. mass: 80,
  331. area: 1,
  332. clusters: 2,
  333. cluster_chances: .2,
  334. contents: [],
  335. },
  336. "Tank": {
  337. "Tank": Tank,
  338. mass: 5000,
  339. area: 20,
  340. clusters: 2,
  341. cluster_chances: .25,
  342. contents: [["Soldier",3,5]],
  343. },
  344. "Artillery": {
  345. "Artillery": Artillery,
  346. mass: 7000,
  347. area: 25,
  348. clusters: 3,
  349. cluster_chances: .5,
  350. contents: [["Soldier",4,6]],
  351. },
  352. "Helicopter": {
  353. "Helicopter": Helicopter,
  354. mass: 1500,
  355. area: 12,
  356. clusters: 0,
  357. cluster_chances: 0,
  358. contents: [["Soldier",4,16]],
  359. },
  360. "Squad": {
  361. "Squad": Squad,
  362. mass: 1,
  363. area: 30,
  364. clusters: 20,
  365. cluster_chances: .05,
  366. contents: [["Soldier",6,9]],
  367. },
  368. "Platoon": {
  369. "Platoon": Platoon,
  370. mass: 100,
  371. area: 150,
  372. clusters: 2,
  373. cluster_chances: .1,
  374. contents: [["Soldier",16,44]],
  375. },
  376. "Company": {
  377. "Company": Company,
  378. mass: 500,
  379. area: 600,
  380. clusters: 2,
  381. cluster_chances: .1,
  382. contents: [["Soldier",60,200]],
  383. },
  384. "Battalion": {
  385. "Battalion": Battalion,
  386. mass: 1000,
  387. area: 3500,
  388. clusters: 2,
  389. cluster_chances: .1,
  390. contents: [["Soldier",300,1000]],
  391. },
  392. "Brigade": {
  393. "Brigade": Brigade,
  394. mass: 1500,
  395. area: 2e4,
  396. clusters: 2,
  397. cluster_chances: .1,
  398. contents: [["Soldier",1500,3200]],
  399. },
  400. "Division": {
  401. "Division": Division,
  402. mass: 2000,
  403. area: 8e4,
  404. clusters: 3,
  405. cluster_chances: .1,
  406. contents: [["Soldier",10000,16000]],
  407. },
  408. "Tank Division": {
  409. "Tank Division": TankDivision,
  410. mass: 3000,
  411. area: 1e5,
  412. clusters: 1,
  413. cluster_chances: .15,
  414. contents: [["Soldier",8000,1200],["Tank",250,500]],
  415. },
  416. "Army": {
  417. "Army": Army,
  418. mass: 5000,
  419. area: 1e6,
  420. clusters: 2,
  421. cluster_chances: .1,
  422. contents: [["Soldier",40000,75000]],
  423. },
  424. };
  425. //Alterante Army Structuring, may be used later
  426. //"Squad": [["Soldier",6,9]],
  427. // "Platoon": [["Squad",3,4]],
  428. //"Company": [["Platoon",3,5],["Squad",0,2]],
  429. //"Battalion": [["Company",4,6]],
  430. //"Brigade": [["Battalion",2,5],["Company",0,3]],
  431. //"Division": [["Brigade",2,4]],
  432. //"Tank Division": [["Brigade",2,4],["Tank",250,500]],
  433. //"Army": [["Division",3,8],["Tank Division",1,5]],
  434. var clusters =
  435. {
  436. "Container": 0,
  437. //Creatures
  438. "Person": 5,
  439. "Human": 5,
  440. "Cow": 15,
  441. "Micro": 50,
  442. "Macro": 0,
  443. //Vehicles
  444. "Car": 3,
  445. "Bus": 1,
  446. "Tram": 1,
  447. "Train": 2,
  448. "Train Car": 1,
  449. //Buildings
  450. "House": 5,
  451. "Business": 5,
  452. "Barn": 1,
  453. "Small Skyscraper": 2,
  454. "Large Skyscraper": 1,
  455. "Parking Garage": 1,
  456. //Places
  457. "Town": 5,
  458. "City": 1,
  459. "Continent": 5,
  460. "Planet": 9,
  461. "Star": 1,
  462. "Solar System": 1,
  463. "Galaxy": 1,
  464. "Cluster": 1,
  465. "Universe": 1,
  466. "Multiverse": 1,
  467. //Military
  468. "Soldier": 0,
  469. "Tank": 0,
  470. "Artillery": 0,
  471. "Helicopter": 0,
  472. "Squad": 20,
  473. "Platoon": 2,
  474. "Company": 2,
  475. "Battalion": 2,
  476. "Brigade": 2,
  477. "Division": 3,
  478. "Tank Division": 1,
  479. "Army": 2,
  480. };
  481. var cluster_chances =
  482. {
  483. "Container": 0,
  484. //Creatures
  485. "Person": 0.8,
  486. "Human": 0.8,
  487. "Cow": 0.5,
  488. "Micro": 1,
  489. "Macro": 0,
  490. //Vehicles
  491. "Car": 0.5,
  492. "Bus": 0.25,
  493. "Tram": 0.2,
  494. "Train": 0.1,
  495. "Train Car": 0.05,
  496. //Buildings
  497. "House": 0.5,
  498. "Business": .05,
  499. "Barn": 0.1,
  500. "Small Skyscraper": 0.25,
  501. "Large Skyscraper": 0.25,
  502. "Parking Garage": 0.1,
  503. //Places
  504. "Town": 0.1,
  505. "City": 0.2,
  506. "Continent": 0.5,
  507. "Planet": 1,
  508. "Star": 1,
  509. "Solar System": 1,
  510. "Galaxy": 1,
  511. "Cluster": 1,
  512. "Universe": 1,
  513. "Multiverse": 1,
  514. //Military
  515. "Soldier": 0,
  516. "Tank": 0,
  517. "Artillery": 0,
  518. "Helicopter": 0,
  519. "Squad": .05,
  520. "Platoon": .05,
  521. "Company": .1,
  522. "Battalion": .1,
  523. "Brigade": .1,
  524. "Division": .1,
  525. "Tank Division": 0.15,
  526. "Army": .1,
  527. };
  528. var contents =
  529. {
  530. "Container": [],
  531. //Creatures
  532. "Person": [],
  533. "Human": [],
  534. "Cow": [],
  535. "Micro": [[]],
  536. "Macro": [[]],
  537. //Vehicles
  538. "Car": [["Person",1,4]],
  539. "Bus": [["Person",2,30]],
  540. "Tram": [["Person",10,50]],
  541. "Train": [["Person",1,4,"engine"],["Train Car",2,10]],
  542. "Train Car": [["Person",10,40]],
  543. //Buildings
  544. "House": [["Person",0,8],["Empty Car",0,2]],
  545. "Business": [["Person",0,30],["Car",0,20]],
  546. "Barn": [["Person",0,2],["Cow",30,70]],
  547. "Small Skyscraper": [["Person",150,750],["Empty Car",10,50]],
  548. "Large Skyscraper": [["Person",500,1500],["Empty Car",20,100]],
  549. "Parking Garage": [["Person",10,200],["Empty Car",100,300],["Car",5,30]],
  550. //Places
  551. "Town": [["Person",10000,100000],["House",5000,50000],["Empty Car",200,800],["Car",500,80000],["Bus",5,25],["Train",5,25],["Business",500,5000]],
  552. "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],["Business",2000,10000]],
  553. "Continent": [["Person",1000000,15000000],["House",2500,10000],["Car",25000,375000],["Train",50,500],["Town",500,1000],["City",50,250],["Business",250,1000]],
  554. "Planet": [["Continent",4,9]],
  555. "Star": [],
  556. "Solar System": [["Star",1,1],["Planet",5,15]],
  557. "Galaxy": [["Star",1e9,500e9],["Solar System",1e8,500e8]],
  558. "Cluster": [["Galaxy",200,5000]],
  559. "Universe": [["Cluster",1.5e9,2.5e9]],
  560. "Multiverse": [["Universe",100,1000]],
  561. //Military
  562. "Soldier": [],
  563. "Tank": [["Soldier",3,5]],
  564. "Artillery": [["Soldier",4,6]],
  565. "Helicopter": [["Soldier",4,16]],
  566. //Alterante Army Structuring, may be used later
  567. //"Squad": [["Soldier",6,9]],
  568. // "Platoon": [["Squad",3,4]],
  569. //"Company": [["Platoon",3,5],["Squad",0,2]],
  570. //"Battalion": [["Company",4,6]],
  571. //"Brigade": [["Battalion",2,5],["Company",0,3]],
  572. //"Division": [["Brigade",2,4]],
  573. //"Tank Division": [["Brigade",2,4],["Tank",250,500]],
  574. //"Army": [["Division",3,8],["Tank Division",1,5]],
  575. "Squad": [["Soldier",6,9]],
  576. "Platoon": [["Soldier",16,44]],
  577. "Company": [["Soldier",60,200]],
  578. "Battalion": [["Soldier",300,1000]],
  579. "Brigade": [["Soldier",1500,3200]],
  580. "Division": [["Soldier",10000,16000]],
  581. "Tank Division": [["Soldier",8000,1200],["Tank",250,500]],
  582. "Army": [["Soldier",40000,75000]],
  583. };
  584. // replace all instances of from with to
  585. function contents_substitute(from,to) {
  586. for (let key in contents) {
  587. if (contents.hasOwnProperty(key)) {
  588. let type = contents[key];
  589. for (let i=0; i<type.length; i++) {
  590. if (type[i][0] == from) {
  591. type[i][0] = to;
  592. }
  593. }
  594. }
  595. }
  596. }
  597. // remove all instances of thing
  598. function contents_remove(thing) {
  599. for (let key in contents) {
  600. if (contents.hasOwnProperty(key)) {
  601. let type = contents[key];
  602. for (let i=0; i<type.length; i++) {
  603. if (type[i][0] == thing) {
  604. type.splice(i,1);
  605. --i;
  606. }
  607. }
  608. }
  609. }
  610. }
  611. // adds thing to parent
  612. function contents_insert(parent,thing,min,max,label) {
  613. let owner = contents[parent];
  614. if (label == undefined)
  615. owner.push([thing,min,max]);
  616. else
  617. owner.push([thing,min,max,label]);
  618. }
  619. function initContents(name,count) { //builds the contents for each destrucable(thing) when called
  620. let result = {};
  621. let type = things[name].contents;
  622. for (let i=0; i<type.length; i++) {
  623. let amount = distribution(type[i][1],type[i][2],count); //arrays of contents look like ["thing name",min,max,"optional name"] so those values have to pulled out
  624. if (amount > 0) {
  625. // if a custom label is supplied, use it!
  626. if (type[i].length == 4) //if has optional name
  627. result[type[i][3]] = new things[type[i][0]][type[i][0]](amount); //creates a "thing name" under the key of "optional name"
  628. else
  629. result[type[i][0]] = new things[type[i][0]][type[i][0]](amount);
  630. }
  631. }
  632. return result;
  633. }
  634. function get_living_prey(sum) {
  635. let total = 0;
  636. for (let key in sum) {
  637. if (sum.hasOwnProperty(key)) {
  638. if (key == "Micro" || key == "Macro" || key == "Person" || key == "Cow" || key == 'Soldier')
  639. total += sum[key];
  640. }
  641. }
  642. return total;
  643. }
  644. // general logic: each step fills in a fraction of the remaining space
  645. function fill_area(area, weights, variance=0.15)
  646. {
  647. area = area + Math.random() * variance * 2 * area - variance * area;
  648. var result = [];
  649. var candidates = [];
  650. for (var key in weights) {
  651. if (weights.hasOwnProperty(key)) {
  652. candidates.push({"name": key, "area": things[key].area, "weight": weights[key]});
  653. }
  654. }
  655. candidates = candidates.sort(function (x,y) {
  656. return x.area - y.area;
  657. });
  658. while(candidates.length > 0) {
  659. var candidate = candidates.pop();
  660. if (candidate.area > area)
  661. continue;
  662. var max = Math.floor(area / candidate.area);
  663. var limit = Math.min(max, 1000);
  664. var count = 0;
  665. var loopvar = 0;
  666. // for small amounts, actually do the randomness
  667. // the first few ones get a much better shot
  668. // if we have nothing at all, it's even better!
  669. while (loopvar < limit) {
  670. if (loopvar == 0 && result.length == 0) {
  671. ++count;
  672. }
  673. else if (loopvar <= clusters[candidate.name]) {
  674. if (Math.random() < candidate.weight ? 1 : Math.random() < cluster_chances[candidate.name]) {
  675. ++count;
  676. }
  677. }
  678. else {
  679. count += Math.random() < candidate.weight ? 1 : 0;
  680. }
  681. ++loopvar;
  682. }
  683. // if we're doing more than the limit, then we just add on the rest, with some variance
  684. if (limit < max) {
  685. const base = (max-limit) * candidate.weight;
  686. count += Math.round(base - base / 10 + base * Math.random() / 5);
  687. }
  688. area -= count * candidate.area;
  689. if (count > 0)
  690. result.push(new things[candidate.name][candidate.name](count));
  691. }
  692. return new Container(result);
  693. }
  694. // describes everything in the container
  695. function describe_all(contents,verbose=true,except=[]) {
  696. var things = [];
  697. for (var key in contents) {
  698. if (contents.hasOwnProperty(key) && !except.includes(key)) {
  699. things.push(contents[key].describe(verbose));
  700. }
  701. }
  702. return merge_things(things);
  703. }
  704. function random_desc(list, odds=1) {
  705. if (Math.random() < odds)
  706. return list[Math.floor(Math.random() * list.length)];
  707. else
  708. return "";
  709. }
  710. // combine strings into a list with proper grammar
  711. function merge_things(list,semicolons=false) {
  712. if (list.length == 0) {
  713. return "";
  714. } else if (list.length == 1) {
  715. return list[0];
  716. } else if (list.length == 2) {
  717. return list[0] + " and " + list[1];
  718. } else {
  719. var result = "";
  720. list.slice(0,list.length-1).forEach(function(term) {
  721. result += term + ", ";
  722. });
  723. result += "and " + list[list.length-1];
  724. return result;
  725. }
  726. }
  727. // combine the adjectives for something into a single string
  728. function merge_desc(list) {
  729. var result = "";
  730. list.forEach(function(term) {
  731. if (term != "")
  732. result += term + " ";
  733. });
  734. // knock off the last space
  735. if (result.length > 0) {
  736. result = result.substring(0, result.length - 1);
  737. }
  738. return result;
  739. }
  740. // maybe make this something that approximates a
  741. // normal distribution; doing this 15,000,000 times is bad...
  742. // solution: only a few are random lul
  743. // improvement: take up to 100 samples, then use that to scale the final result
  744. function distribution(min, max, samples) {
  745. var result = 0;
  746. var limit = Math.min(100,samples);
  747. if (limit < samples) {
  748. let dist = 0;
  749. for (let i = 0; i < limit; i++) {
  750. dist += Math.random();
  751. }
  752. dist /= 100;
  753. return Math.floor(dist * samples * (max - min + 1) + samples * min);
  754. } else {
  755. for (let i = 0; i < limit; i++) {
  756. result += Math.floor(Math.random() * (max - min + 1) + min);
  757. }
  758. }
  759. return result;
  760. }
  761. function defaultMultiply(thing) {
  762. return function(amount) {
  763. thing.count *= amount;
  764. for (var key in thing.contents) {
  765. if (thing.contents.hasOwnProperty(key)) {
  766. thing.contents[key].multiply(amount);
  767. }
  768. }
  769. };
  770. }
  771. function defaultArea(thing) {
  772. return things[thing.name].area;
  773. }
  774. function defaultMass(thing) {
  775. return things[thing.name].mass;
  776. }
  777. function defaultMerge(thing) { //this merges all objects into one containers
  778. return function(container) {
  779. var newCount = this.count + container.count;
  780. var newThing = new things[thing.name][thing.name](newCount);
  781. newThing.contents = {};
  782. for (var key in this.contents) {
  783. if (this.contents.hasOwnProperty(key)) {
  784. newThing.contents[key] = this.contents[key];
  785. }
  786. }
  787. for (key in container.contents) {
  788. if (container.contents.hasOwnProperty(key)) {
  789. if (this.contents.hasOwnProperty(key)) {
  790. newThing.contents[key] = this.contents[key].merge(container.contents[key]);
  791. } else {
  792. newThing.contents[key] = container.contents[key];
  793. }
  794. }
  795. }
  796. return newThing;
  797. };
  798. }
  799. function listSum(sum) {
  800. let result = [];
  801. for (let key in sum) {
  802. if (sum.hasOwnProperty(key)) {
  803. result.push(new things[key][key](sum[key]).describe(false));
  804. }
  805. }
  806. return merge_things(result);
  807. }
  808. // turn a nested object into a container with everything on one level
  809. function flatten(thing) {
  810. let dict = defaultSum(thing)();
  811. let list = [];
  812. Object.entries(dict).forEach(function([key, val]) {
  813. let obj = new things[key][key](val);
  814. obj.contents = [];
  815. list.push(obj);
  816. });
  817. list.sort(function(x,y) {
  818. if (y.area != x.area){
  819. return y.area - x.area;
  820. } else {
  821. return x.name.localeCompare(y.name);
  822. }
  823. });
  824. return new Container(list);
  825. }
  826. function defaultSum(thing) {
  827. return function() {
  828. var counts = {};
  829. if (thing.name != "Container")
  830. counts[thing.name] = thing.count;
  831. for (var key in thing.contents) {
  832. if (thing.contents.hasOwnProperty(key)) {
  833. var subcount = thing.contents[key].sum();
  834. for (var subkey in subcount) {
  835. if (!counts.hasOwnProperty(subkey)) {
  836. counts[subkey] = 0;
  837. }
  838. counts[subkey] += subcount[subkey];
  839. }
  840. }
  841. }
  842. return counts;
  843. };
  844. }
  845. function defaultSumProperty(thing) {
  846. return function(prop) {
  847. var total = 0;
  848. total += thing[prop] * thing.count;
  849. for (var key in thing.contents) {
  850. if (thing.contents.hasOwnProperty(key)) {
  851. total += thing.contents[key].sum_property(prop);
  852. }
  853. }
  854. return total;
  855. };
  856. }
  857. function defaultAddContent(thing) {
  858. return function(name, min, max, count) {
  859. if (min == max) {
  860. let object = new things[name](min*count);
  861. thing.contents[object.name] = object;
  862. } else {
  863. let object = new things[name](distribution(min, max, count));
  864. thing.contents[object.name] = object;
  865. }
  866. };
  867. }
  868. function defaultDescribeSimple(thing) {
  869. return function(flat) {
  870. if (flat) {
  871. return flatten(thing).describe(false)
  872. } else {
  873. return thing.describe(false);
  874. }
  875. }
  876. }
  877. function DefaultEntity() {
  878. this.sum = defaultSum;
  879. this.area = defaultArea;
  880. this.mass = defaultMass;
  881. this.sum_property = defaultSumProperty;
  882. this.merge = defaultMerge;
  883. this.multiply = defaultMultiply;
  884. this.describeSimple = defaultDescribeSimple;
  885. return this;
  886. }
  887. // god I love reinventing the wheel
  888. function copy_defaults(self,proto) { //loads the values defined in things into the fuction that calls it
  889. for (var key in proto) { //proto will always be a new DefaultEntity, self is the parent function
  890. if (proto.hasOwnProperty(key)) {
  891. self[key] = proto[key](self);
  892. }
  893. }
  894. }
  895. function Container(contents = []) {
  896. this.name = "Container";
  897. copy_defaults(this,new DefaultEntity());
  898. if (Number.isInteger(contents))
  899. this.count = contents;
  900. else
  901. this.count = 0;
  902. this.contents = {};
  903. for (var i=0; i < contents.length; i++) {
  904. this.contents[contents[i].name] = contents[i];
  905. }
  906. for (var key in this.contents) {
  907. if (this.contents.hasOwnProperty(key)) {
  908. this.count += this.contents[key].count;
  909. }
  910. }
  911. this.describe = function(verbose = true) {
  912. return describe_all(this.contents,verbose);
  913. };
  914. return this;
  915. }
  916. function Person(count = 1) {
  917. this.name = "Person";
  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 body = random_desc(["skinny","fat","tall","short","stocky","spindly","muscular","fit","multi-colored"], (verbose ? 0.6 : 0));
  923. var sex = random_desc(["male", "female"], (verbose ? 0.75 : 0));
  924. var species = "";
  925. species = random_desc(["wolf","cat","dog","squirrel","horse","hyena","fox","jackal","crux","sergal","coyote","rabbit","lizard","avian"]);
  926. return "a " + merge_desc([body,sex,species]);
  927. };
  928. this.describe = function(verbose=true) {
  929. if (verbose) {
  930. if (count <= 3) {
  931. var list = [];
  932. for (var i = 0; i < count; i++) {
  933. list.push(this.describeOne(this.count <= 2));
  934. }
  935. return merge_things(list);
  936. } else {
  937. return this.count + " people";
  938. }
  939. } else {
  940. return (this.count > 1 ? this.count + " people" : "a person");
  941. }
  942. };
  943. return this;
  944. }
  945. function Human(count = 1) {
  946. this.name = "Person";
  947. copy_defaults(this,new DefaultEntity());
  948. this.count = count;
  949. this.contents = initContents(this.name,this.count);
  950. this.describeOne = function (verbose=true) {
  951. var body = random_desc(["skinny","fat","tall","short","stocky","spindly","muscular","fit","tanned"], (verbose ? 0.6 : 0));
  952. var sex = random_desc(["man", "woman"], 1);
  953. return "a " + merge_desc([body,sex]);
  954. };
  955. this.describe = function(verbose=true) {
  956. if (verbose) {
  957. if (count <= 3) {
  958. var list = [];
  959. for (var i = 0; i < count; i++) {
  960. list.push(this.describeOne(this.count <= 2));
  961. }
  962. return merge_things(list);
  963. } else {
  964. return this.count + " people";
  965. }
  966. } else {
  967. return (this.count > 1 ? this.count + " people" : "a person");
  968. }
  969. };
  970. return this;
  971. }
  972. function Cow(count = 1) {
  973. this.name = "Cow";
  974. copy_defaults(this,new DefaultEntity());
  975. this.count = count;
  976. this.contents = initContents(this.name,this.count);
  977. this.describeOne = function (verbose=true) {
  978. var body = random_desc(["skinny","fat","tall","short","stocky","spindly"], (verbose ? 0.6 : 0));
  979. var sex = random_desc(["male", "female"], (verbose ? 1 : 0));
  980. return "a " + merge_desc([body,sex,"cow"]);
  981. };
  982. this.describe = function(verbose=true) {
  983. if (verbose) {
  984. if (count <= 3) {
  985. var list = [];
  986. for (var i = 0; i < count; i++) {
  987. list.push(this.describeOne(this.count <= 2));
  988. }
  989. return merge_things(list);
  990. } else {
  991. return this.count + " cattle";
  992. }
  993. } else {
  994. return (this.count > 1 ? this.count + " cattle" : "a cow");
  995. }
  996. };
  997. return this;
  998. }
  999. function EmptyCar(count = 1) {
  1000. this.name = "Car";
  1001. copy_defaults(this,new DefaultEntity());
  1002. this.count = count;
  1003. this.contents = initContents(this.name,this.count);
  1004. this.describeOne = function(verbose=true) {
  1005. var color = random_desc(["black","black","gray","gray","blue","red","tan","white","white"]);
  1006. var adjective = random_desc(["rusty","brand-new","luxury","beat-up","dented","restored","classic"],0.3);
  1007. var type = random_desc(["SUV","coupe","sedan","truck","van","convertible"]);
  1008. return "a parked " + merge_desc([adjective,color,type]);
  1009. };
  1010. this.describe = function(verbose = true) {
  1011. if (verbose) {
  1012. if (this.count <= 3) {
  1013. var list = [];
  1014. for (var i = 0; i < this.count; i++) {
  1015. list.push(this.describeOne());
  1016. }
  1017. return merge_things(list);
  1018. } else {
  1019. return this.count + " parked cars";
  1020. }
  1021. } else {
  1022. return (this.count > 1 ? this.count + " parked cars" : "a parked car");
  1023. }
  1024. };
  1025. }
  1026. function Car(count = 1) {
  1027. this.name = "Car";
  1028. copy_defaults(this,new DefaultEntity());
  1029. this.count = count;
  1030. this.contents = initContents(this.name,this.count);
  1031. this.describeOne = function(verbose=true) {
  1032. var color = random_desc(["black","black","gray","gray","blue","red","tan","white","white"], (verbose ? 1 : 0));
  1033. var adjective = random_desc(["rusty","brand-new","luxury","beat-up","dented","restored","classic"], (verbose ? 0.3 : 0));
  1034. var type = random_desc(["SUV","coupe","sedan","truck","van","convertible"]);
  1035. return "a " + merge_desc([adjective,color,type]);
  1036. };
  1037. this.describe = function(verbose = true) {
  1038. if (verbose) {
  1039. if (this.count <= 3) {
  1040. var list = [];
  1041. for (var i = 0; i < this.count; i++) {
  1042. list.push(this.describeOne(this.count < 2));
  1043. }
  1044. return merge_things(list) + " with " + describe_all(this.contents,verbose) + " inside";
  1045. } else {
  1046. return this.count + " cars with " + describe_all(this.contents,verbose) + " inside";
  1047. }
  1048. } else {
  1049. return (this.count > 1 ? this.count + " cars" : "a car");
  1050. }
  1051. };
  1052. }
  1053. function Bus(count = 1) {
  1054. this.name = "Bus";
  1055. copy_defaults(this,new DefaultEntity());
  1056. this.count = count;
  1057. this.contents = initContents(this.name,this.count);
  1058. this.describeOne = function(verbose=true) {
  1059. var adjective = random_desc(["rusty","brand-new","aging","modern"], (verbose ? 0.3 : 0));
  1060. var color = random_desc(["black","tan","gray"], (verbose ? 1 : 0));
  1061. var type = random_desc(["bus","double-decker bus","articulating bus","open-top bus","sleeper bus","intercity bus"]);
  1062. return "a " + merge_desc([adjective,color,type]);
  1063. };
  1064. this.describe = function(verbose = true) {
  1065. if (verbose) {
  1066. if (this.count <= 3) {
  1067. var list = [];
  1068. for (var i = 0; i < this.count; i++) {
  1069. list.push(this.describeOne(this.count < 2));
  1070. }
  1071. return merge_things(list) + " with " + describe_all(this.contents,verbose) + " inside";
  1072. } else {
  1073. return this.count + " buses with " + describe_all(this.contents,verbose) + " inside";
  1074. }
  1075. } else {
  1076. return (this.count > 1 ? this.count + " buses" : "a bus");
  1077. }
  1078. };
  1079. }
  1080. function Tram(count = 1) {
  1081. this.name = "Tram";
  1082. copy_defaults(this,new DefaultEntity());
  1083. this.count = count;
  1084. this.contents = initContents(this.name,this.count);
  1085. this.describeOne = function(verbose=true) {
  1086. var adjective = random_desc(["rusty","weathered","well-maintained",], (verbose ? 0.3 : 0));
  1087. var color = random_desc(["blue","brown","gray"], (verbose ? 1 : 0));
  1088. var type = random_desc(["tram"]);
  1089. return "a " + merge_desc([adjective,color,type]);
  1090. };
  1091. this.describe = function(verbose = true) {
  1092. if (verbose) {
  1093. if (this.count == 1) {
  1094. var list = [];
  1095. for (var i = 0; i < this.count; i++) {
  1096. list.push(this.describeOne(verbose));
  1097. }
  1098. return merge_things(list) + " with " + describe_all(this.contents,verbose) + " inside";
  1099. } else {
  1100. return this.count + " trams with " + describe_all(this.contents,verbose) + " inside";
  1101. }
  1102. } else {
  1103. return (this.count > 1 ? this.count + " trams" : "a tram");
  1104. }
  1105. };
  1106. this.anal_vore = function() {
  1107. return "You slide " + this.describe() + " up your tight ass";
  1108. };
  1109. }
  1110. function Train(count = 1) {
  1111. this.name = "Train";
  1112. copy_defaults(this,new DefaultEntity());
  1113. this.count = count;
  1114. this.contents = initContents(this.name,this.count);
  1115. this.describeOne = function(verbose=true) {
  1116. var adjective = random_desc(["rusty","brand-new","steam","freshly-painted"], (verbose ? 0.3 : 0));
  1117. var color = random_desc(["black","tan","gray"], (verbose ? 1 : 0));
  1118. var type = random_desc(["train","passenger train","freight train"]);
  1119. return "a " + merge_desc([adjective,color,type]);
  1120. };
  1121. this.describe = function(verbose = true) {
  1122. if (verbose) {
  1123. if (this.count == 1) {
  1124. var list = [];
  1125. for (var i = 0; i < this.count; i++) {
  1126. list.push(this.describeOne(verbose));
  1127. }
  1128. return merge_things(list) + " with " + this.contents["engine"].describe(false) + " in the engine and " + this.contents["Train Car"].describe() + " attached";
  1129. } else {
  1130. return this.count + " trains with " + this.contents["engine"].describe(false) + " in the engine and " + this.contents["Train Car"].describe() + " attached";
  1131. }
  1132. } else {
  1133. return (this.count > 1 ? this.count + " trains" : "a train");
  1134. }
  1135. };
  1136. this.anal_vore = function() {
  1137. 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");
  1138. return "You snatch up " + this.describeOne() + " and stuff it into your pucker, moaning as " + cars;
  1139. };
  1140. }
  1141. function TrainCar(count = 1) {
  1142. this.name = "Train Car";
  1143. copy_defaults(this,new DefaultEntity());
  1144. this.count = count;
  1145. this.contents = initContents(this.name,this.count);
  1146. this.describeOne = function(verbose=true) {
  1147. var adjective = random_desc(["rusty","brand-new","vintage","graffitied","well-maintained"], (verbose ? 0.3 : 0));
  1148. var color = random_desc(["black","tan","gray","yellow","steel","wooden"], (verbose ? 1 : 0));
  1149. var type = random_desc(["train car","passenger train car","freight train car"]);
  1150. return "a " + merge_desc([adjective,color,type]);
  1151. };
  1152. this.describe = function(verbose = true) {
  1153. if (verbose) {
  1154. return (this.count > 1 ? this.count + " train cars" : "a train car") + " with " + describe_all(this.contents) + " inside";
  1155. } else {
  1156. return (this.count > 1 ? this.count + " train cars" : "a train car");
  1157. }
  1158. };
  1159. }
  1160. function House(count = 1) {
  1161. this.name = "House";
  1162. copy_defaults(this,new DefaultEntity());
  1163. this.count = count;
  1164. this.contents = initContents(this.name,this.count);
  1165. this.describeOne = function(verbose=true) {
  1166. var size = random_desc(["little","two-story","large","well-built","run-down","cheap",], (verbose ? 0.5 : 0));
  1167. var color = random_desc(["blue","white","gray","tan","green","wooden","brick"], (verbose ? 0.5 : 0));
  1168. var name = random_desc(["house","home","house","house","house","trailer"], 1);
  1169. return "a " + merge_desc([size,color,name]);
  1170. };
  1171. this.describe = function(verbose = true) {
  1172. if (verbose) {
  1173. if (this.count <= 3) {
  1174. var list = [];
  1175. for (var i = 0; i < this.count; i++) {
  1176. list.push(this.describeOne(this.count < 2));
  1177. }
  1178. return merge_things(list) + " with " + describe_all(this.contents,verbose) + " inside";
  1179. } else {
  1180. return this.count + " homes with " + describe_all(this.contents,verbose) + " inside";
  1181. }
  1182. } else {
  1183. return (this.count > 1 ? this.count + " houses" : "a house");
  1184. }
  1185. };
  1186. }
  1187. //might split this into a general business and resutrant categories
  1188. function Business(count = 1) {
  1189. this.name = "Business";
  1190. copy_defaults(this,new DefaultEntity());
  1191. this.count = count;
  1192. this.contents = initContents(this.name,this.count);
  1193. this.describeOne = function(verbose=true) {
  1194. var size = random_desc(["little","two-story","large","well-built","run-down","cheap","aging","corner"], (verbose ? 0.5 : 0));
  1195. var color = random_desc(["blue","white","gray","tan","green","brick","concrete"], (verbose ? 0.5 : 0));
  1196. var name = random_desc(["mall","resturant","bank","clinic","shop","post office","tire shop","chain resturant","grocery store","barber shop","pizza resturant","hardware store","movie theather","gas station"], 1);
  1197. return "a " + merge_desc([size,color,name]);
  1198. };
  1199. this.describe = function(verbose = true) {
  1200. if (verbose) {
  1201. if (this.count <= 3) {
  1202. var list = [];
  1203. for (var i = 0; i < this.count; i++) {
  1204. list.push(this.describeOne(this.count < 2));
  1205. }
  1206. return merge_things(list) + " with " + describe_all(this.contents,verbose);
  1207. } else {
  1208. return this.count + " local business containing " + describe_all(this.contents,verbose);
  1209. }
  1210. } else {
  1211. return (this.count > 1 ? this.count + " buildings" : "a local business");
  1212. }
  1213. };
  1214. }
  1215. function Barn(count = 1) {
  1216. this.name = "Barn";
  1217. copy_defaults(this,new DefaultEntity());
  1218. this.count = count;
  1219. this.contents = initContents(this.name,this.count);
  1220. this.describeOne = function(verbose=true) {
  1221. var size = random_desc(["little","big","large","weathered","rotted","new"], (verbose ? 0.5 : 0));
  1222. var color = random_desc(["blue","white","gray","tan","green","red"], (verbose ? 0.5 : 0));
  1223. var name = random_desc(["barn","barn","barn","barn","barn","farmhouse"], 1);
  1224. return "a " + merge_desc([size,color,name]);
  1225. };
  1226. this.describe = function(verbose = true) {
  1227. if (verbose) {
  1228. if (this.count <= 3) {
  1229. var list = [];
  1230. for (var i = 0; i < this.count; i++) {
  1231. list.push(this.describeOne(this.count < 2));
  1232. }
  1233. return merge_things(list) + " with " + describe_all(this.contents,verbose) + " inside";
  1234. } else {
  1235. return this.count + " barns with " + describe_all(this.contents,verbose) + " inside";
  1236. }
  1237. } else {
  1238. return (this.count > 1 ? this.count + " barns" : "a barn");
  1239. }
  1240. };
  1241. }
  1242. function SmallSkyscraper(count = 1) {
  1243. this.name = "Small Skyscraper";
  1244. copy_defaults(this,new DefaultEntity());
  1245. this.count = count;
  1246. this.contents = initContents(this.name,this.count);
  1247. this.describeOne = function(verbose=true) {
  1248. var color = random_desc(["blue","white","gray","tan","green"], (verbose ? 0.5 : 0));
  1249. var name = random_desc(["skyscraper","office tower","office building","high rise"], 1);
  1250. return "a " + merge_desc([color,name]);
  1251. };
  1252. this.describe = function(verbose = true) {
  1253. if (verbose) {
  1254. if (this.count <= 3) {
  1255. var list = [];
  1256. for (var i = 0; i < this.count; i++) {
  1257. list.push(this.describeOne(this.count < 2));
  1258. }
  1259. return merge_things(list) + " with " + describe_all(this.contents,verbose) + " inside";
  1260. } else {
  1261. return this.count + " small skyscrapers with " + describe_all(this.contents,verbose) + " inside";
  1262. }
  1263. } else {
  1264. return (this.count > 1 ? this.count + " small skyscrapers" : "a small skyscraper");
  1265. }
  1266. };
  1267. }
  1268. function LargeSkyscraper(count = 1) {
  1269. this.name = "Large Skyscraper";
  1270. copy_defaults(this,new DefaultEntity());
  1271. this.count = count;
  1272. this.contents = initContents(this.name,this.count);
  1273. this.describeOne = function(verbose=true) {
  1274. var color = random_desc(["blue","white","gray","tan","green","glass"], (verbose ? 0.5 : 0));
  1275. var name = random_desc(["skyscraper","office tower","office building"], 1);
  1276. return "a " + merge_desc(["towering",color,name]);
  1277. };
  1278. this.describe = function(verbose = true) {
  1279. if (verbose) {
  1280. if (this.count <= 3) {
  1281. var list = [];
  1282. for (var i = 0; i < this.count; i++) {
  1283. list.push(this.describeOne(this.count < 2));
  1284. }
  1285. return merge_things(list) + " with " + describe_all(this.contents,verbose) + " inside";
  1286. } else {
  1287. return this.count + " large skyscrapers with " + describe_all(this.contents,verbose) + " inside";
  1288. }
  1289. } else {
  1290. return (this.count > 1 ? this.count + " large skyscrapers" : "a large skyscraper");
  1291. }
  1292. };
  1293. }
  1294. function ParkingGarage(count = 1) {
  1295. this.name = "Parking Garage";
  1296. copy_defaults(this,new DefaultEntity());
  1297. this.count = count;
  1298. this.contents = initContents(this.name,this.count);
  1299. this.describeOne = function(verbose=true) {
  1300. return "a parking garage";
  1301. };
  1302. this.describe = function(verbose = true) {
  1303. if (verbose) {
  1304. return (this.count == 1 ? "a parking garage" : this.count + " parking garages") + " with " + describe_all(this.contents, verbose);
  1305. } else {
  1306. return (this.count == 1 ? "a parking garage" : this.count + " parking garages");
  1307. }
  1308. };
  1309. }
  1310. function Town(count = 1) {
  1311. this.name = "Town";
  1312. copy_defaults(this,new DefaultEntity());
  1313. this.count = count;
  1314. this.contents = initContents(this.name,this.count);
  1315. this.describe = function(verbose = true) {
  1316. if (verbose) {
  1317. return (this.count == 1 ? "a town" : this.count + " towns") + " with " + describe_all(this.contents, verbose) + " in " + (this.count == 1 ? "it" : "them");
  1318. } else {
  1319. return (this.count == 1 ? "a town" : this.count + " towns");
  1320. }
  1321. };
  1322. }
  1323. function City(count = 1) {
  1324. this.name = "City";
  1325. copy_defaults(this,new DefaultEntity());
  1326. this.count = count;
  1327. this.contents = initContents(this.name,this.count);
  1328. this.describe = function(verbose = true) {
  1329. if (verbose) {
  1330. return (this.count == 1 ? "a city" : this.count + " cities") + " with " + describe_all(this.contents, verbose) + " in " + (this.count == 1 ? "it" : "them");
  1331. } else {
  1332. return (this.count == 1 ? "a city" : this.count + " cities");
  1333. }
  1334. };
  1335. }
  1336. function Continent(count = 1) {
  1337. this.name = "Continent";
  1338. copy_defaults(this,new DefaultEntity());
  1339. this.count = count;
  1340. this.contents = initContents(this.name,this.count);
  1341. this.describe = function(verbose = true) {
  1342. if (verbose) {
  1343. return (this.count == 1 ? "a continent" : this.count + " continents") + " with " + describe_all(this.contents, verbose) + " on " + (this.count == 1 ? "it" : "them");
  1344. } else {
  1345. return (this.count == 1 ? "a continent" : this.count + " continents");
  1346. }
  1347. };
  1348. }
  1349. function Planet(count = 1) {
  1350. this.name = "Planet";
  1351. copy_defaults(this,new DefaultEntity());
  1352. this.count = count;
  1353. this.contents = initContents(this.name,this.count);
  1354. this.describe = function(verbose = true) {
  1355. if (verbose) {
  1356. return (this.count == 1 ? "a planet" : this.count + " planets") + " with " + describe_all(this.contents, verbose) + " on " + (this.count == 1 ? "it" : "them");
  1357. } else {
  1358. return (this.count == 1 ? "a planet" : this.count + " planets");
  1359. }
  1360. };
  1361. }
  1362. function Star(count = 1) {
  1363. this.name = "Star";
  1364. copy_defaults(this,new DefaultEntity());
  1365. this.count = count;
  1366. this.contents = initContents(this.name,this.count);
  1367. this.describe = function(verbose = true) {
  1368. return (this.count == 1 ? "a star" : this.count + " stars");
  1369. };
  1370. }
  1371. function SolarSystem(count = 1) {
  1372. this.name = "Solar System";
  1373. copy_defaults(this,new DefaultEntity());
  1374. this.count = count;
  1375. this.contents = initContents(this.name,this.count);
  1376. this.describe = function(verbose = true) {
  1377. if (verbose) {
  1378. return (this.count == 1 ? "a solar system" : this.count + " solar systems") + " made up of " + describe_all(this.contents, verbose);
  1379. } else {
  1380. return (this.count == 1 ? "a solar system" : this.count + " solar systems");
  1381. }
  1382. };
  1383. }
  1384. function Galaxy(count = 1) {
  1385. this.name = "Galaxy";
  1386. copy_defaults(this,new DefaultEntity());
  1387. this.count = count;
  1388. this.contents = initContents(this.name,this.count);
  1389. this.describe = function(verbose = true) {
  1390. if (verbose) {
  1391. return (this.count == 1 ? "a galaxy" : this.count + " galaxies") + " made up of " + describe_all(this.contents, verbose);
  1392. } else {
  1393. return (this.count == 1 ? "a galaxy" : this.count + " galaxies");
  1394. }
  1395. };
  1396. }
  1397. function Cluster(count = 1) {
  1398. this.name = "Cluster";
  1399. copy_defaults(this,new DefaultEntity());
  1400. this.count = count;
  1401. this.contents = initContents(this.name,this.count);
  1402. this.describe = function(verbose = true) {
  1403. if (verbose) {
  1404. return (this.count == 1 ? "a cluster" : this.count + " clusters") + " made up of " + describe_all(this.contents, verbose);
  1405. } else {
  1406. return (this.count == 1 ? "a cluster" : this.count + " clusters");
  1407. }
  1408. };
  1409. }
  1410. function Universe(count = 1) {
  1411. this.name = "Universe";
  1412. copy_defaults(this,new DefaultEntity());
  1413. this.count = count;
  1414. this.contents = initContents(this.name,this.count);
  1415. this.describe = function(verbose = true) {
  1416. if (verbose) {
  1417. return (this.count == 1 ? "a universe" : this.count + " universes") + " made up of " + describe_all(this.contents, verbose);
  1418. } else {
  1419. return (this.count == 1 ? "a universe" : this.count + " universes");
  1420. }
  1421. };
  1422. }
  1423. function Multiverse(count = 1) {
  1424. this.name = "Multiverse";
  1425. copy_defaults(this,new DefaultEntity());
  1426. this.count = count;
  1427. this.contents = initContents(this.name,this.count);
  1428. this.describe = function(verbose = true) {
  1429. if (verbose) {
  1430. return (this.count == 1 ? "a multiverse" : this.count + " multiverses") + " made up of " + describe_all(this.contents, verbose);
  1431. } else {
  1432. return (this.count == 1 ? "a multiverse" : this.count + " multiverses");
  1433. }
  1434. };
  1435. }
  1436. function Soldier(count = 1) {
  1437. this.name = "Soldier";
  1438. copy_defaults(this,new DefaultEntity());
  1439. this.count = count;
  1440. this.contents = initContents(this.name,this.count);
  1441. this.describe = function(verbose = true) {
  1442. return (this.count == 1 ? "a soldier" : this.count + " soldiers");
  1443. };
  1444. }
  1445. function Tank(count = 1) {
  1446. this.name = "Tank";
  1447. copy_defaults(this,new DefaultEntity());
  1448. this.count = count;
  1449. this.contents = initContents(this.name,this.count);
  1450. this.describe = function(verbose = true) {
  1451. if (verbose) {
  1452. return (this.count == 1 ? "a tank" : this.count + " tanks") + " with " + describe_all(this.contents, verbose) + " trapped inside";
  1453. } else {
  1454. return (this.count == 1 ? "a tank" : this.count + " tanks");
  1455. }
  1456. };
  1457. }
  1458. function Artillery(count = 1) {
  1459. this.name = "Artillery";
  1460. copy_defaults(this,new DefaultEntity());
  1461. this.count = count;
  1462. this.contents = initContents(this.name,this.count);
  1463. this.describe = function(verbose = true) {
  1464. if (verbose) {
  1465. return (this.count == 1 ? "an artillery unit" : this.count + " artillery units") + " with " + describe_all(this.contents, verbose) + " trapped inside";
  1466. } else {
  1467. return (this.count == 1 ? "an artillery unit" : this.count + " artillery units");
  1468. }
  1469. };
  1470. }
  1471. function Helicopter(count = 1) {
  1472. this.name = "Helicopter";
  1473. copy_defaults(this,new DefaultEntity());
  1474. this.count = count;
  1475. this.contents = initContents(this.name,this.count);
  1476. this.describe = function(verbose = true) {
  1477. if (verbose) {
  1478. return (this.count == 1 ? "a helicopter" : this.count + " helicopters") + " with " + describe_all(this.contents, verbose) + " riding inside";
  1479. } else {
  1480. return (this.count == 1 ? "a helicopter" : this.count + " helicopters");
  1481. }
  1482. };
  1483. }
  1484. function Micro(count = 1) {
  1485. this.name = "Micro";
  1486. copy_defaults(this,new DefaultEntity());
  1487. this.count = count;
  1488. this.contents = initContents(this.name,this.count);
  1489. this.describe = function(verbose = true) {
  1490. return (this.count == 1 ? "a micro" : this.count + " micros");
  1491. };
  1492. }
  1493. function Macro(count = 1) {
  1494. this.name = "Macro";
  1495. copy_defaults(this,new DefaultEntity());
  1496. this.count = count;
  1497. this.contents = initContents(this.name,this.count);
  1498. this.describe = function(verbose = true) {
  1499. return (this.count == 1 ? "a smaller macro" : this.count + " smaller macros");
  1500. };
  1501. }
  1502. function Squad(count = 1) {
  1503. this.name = "Squad";
  1504. copy_defaults(this,new DefaultEntity());
  1505. this.count = count;
  1506. this.contents = initContents(this.name,this.count);
  1507. this.describeOne = function(verbose=true) {
  1508. return "a squad";
  1509. };
  1510. this.describe = function(verbose = true) {
  1511. if (verbose) {
  1512. return (this.count == 1 ? "a squad" : this.count + " squads") + " made up of " + describe_all(this.contents, verbose);
  1513. } else {
  1514. return (this.count == 1 ? "a squad" : this.count + " squads");
  1515. }
  1516. };
  1517. }
  1518. function Platoon(count = 1) {
  1519. this.name = "Platoon";
  1520. copy_defaults(this,new DefaultEntity());
  1521. this.count = count;
  1522. this.contents = initContents(this.name,this.count);
  1523. this.describeOne = function(verbose=true) {
  1524. return "a military platoon";
  1525. };
  1526. this.describe = function(verbose = true) {
  1527. if (verbose) {
  1528. return (this.count == 1 ? "a platoon" : this.count + " platoons") + " consisting of " + describe_all(this.contents, verbose);
  1529. } else {
  1530. return (this.count == 1 ? "a platoon" : this.count + " platoons");
  1531. }
  1532. };
  1533. }
  1534. function Company(count = 1) {
  1535. this.name = "Company";
  1536. copy_defaults(this,new DefaultEntity());
  1537. this.count = count;
  1538. this.contents = initContents(this.name,this.count);
  1539. this.describeOne = function(verbose=true) {
  1540. return "a company of soldiers";
  1541. };
  1542. this.describe = function(verbose = true) {
  1543. if (verbose) {
  1544. return (this.count == 1 ? "a company" : this.count + " companies") + " of " + describe_all(this.contents, verbose);
  1545. } else {
  1546. return (this.count == 1 ? "a company" : this.count + " companies");
  1547. }
  1548. };
  1549. }
  1550. function Battalion(count = 1) {
  1551. this.name = "Battalion";
  1552. copy_defaults(this,new DefaultEntity());
  1553. this.count = count;
  1554. this.contents = initContents(this.name,this.count);
  1555. this.describeOne = function(verbose=true) {
  1556. return "a battalion";
  1557. };
  1558. this.describe = function(verbose = true) {
  1559. if (verbose) {
  1560. return (this.count == 1 ? "a battalion" : this.count + " battalions") + " containing " + describe_all(this.contents, verbose);
  1561. } else {
  1562. return (this.count == 1 ? "a battalion" : this.count + " battalions");
  1563. }
  1564. };
  1565. }
  1566. function Brigade(count = 1) {
  1567. this.name = "Brigade";
  1568. copy_defaults(this,new DefaultEntity());
  1569. this.count = count;
  1570. this.contents = initContents(this.name,this.count);
  1571. this.describeOne = function(verbose=true) {
  1572. return "a brigade";
  1573. };
  1574. this.describe = function(verbose = true) {
  1575. if (verbose) {
  1576. return (this.count == 1 ? "a brigade" : this.count + " brigades") + " made up of " + describe_all(this.contents, verbose);
  1577. } else {
  1578. return (this.count == 1 ? "a brigade" : this.count + " brigades");
  1579. }
  1580. };
  1581. }
  1582. function Division(count = 1) {
  1583. this.name = "Division";
  1584. copy_defaults(this,new DefaultEntity());
  1585. this.count = count;
  1586. this.contents = initContents(this.name,this.count);
  1587. this.describeOne = function(verbose=true) {
  1588. return "a division";
  1589. };
  1590. this.describe = function(verbose = true) {
  1591. if (verbose) {
  1592. return (this.count == 1 ? "a division" : this.count + " divisions") + " of " + describe_all(this.contents, verbose);
  1593. } else {
  1594. return (this.count == 1 ? "a division" : this.count + " divisions");
  1595. }
  1596. };
  1597. }
  1598. function TankDivision(count = 1) {
  1599. this.name = "Tank Division";
  1600. copy_defaults(this,new DefaultEntity());
  1601. this.count = count;
  1602. this.contents = initContents(this.name,this.count);
  1603. this.describeOne = function(verbose=true) {
  1604. return "a tank division";
  1605. };
  1606. this.describe = function(verbose = true) {
  1607. if (verbose) {
  1608. return (this.count == 1 ? "a tank division" : this.count + " tank divisions") + " of " + describe_all(this.contents, verbose);
  1609. } else {
  1610. return (this.count == 1 ? "a tank division" : this.count + " tank divisions");
  1611. }
  1612. };
  1613. }
  1614. function Army(count = 1) {
  1615. this.name = "Army";
  1616. copy_defaults(this,new DefaultEntity());
  1617. this.count = count;
  1618. this.contents = initContents(this.name,this.count);
  1619. this.describeOne = function(verbose=true) {
  1620. return "an army";
  1621. };
  1622. this.describe = function(verbose = true) {
  1623. if (verbose) {
  1624. return (this.count == 1 ? "an army" : this.count + " armies") + " made up of " + describe_all(this.contents, verbose);
  1625. } else {
  1626. return (this.count == 1 ? "an army" : this.count + " armies");
  1627. }
  1628. };
  1629. }
  1630. //todo
  1631. //redo everything
  1632. //airports
  1633. //farms
  1634. //racetracks
  1635. //more building types
  1636. //nebula
  1637. //grand army
  1638. //armada