/* function defaultSumDST(thing) { return function() { var counts = {}; if (thing.name != "Container") //if a container is detected, sets counts counts[thing.name] = thing.count; for (var key in thing.contents) { if (thing.contents.hasOwnProperty(key)) { var subcount = thing.contents[key].sum(); for (var subkey in subcount) { if (!counts.hasOwnProperty(subkey)) { counts[subkey] = 0; } counts[subkey] += subcount[subkey]; } } } return counts; }; } function defaultSumProperty(thing) { return function(prop) { var total = 0; total += thing[prop] * thing.count; for (var key in thing.contents) { if (thing.contents.hasOwnProperty(key)) { total += thing.contents[key].sum_property(prop); } } return total; }; } function defaultArea(thing) { return areas[thing.name]; } function DefaultDestructable() { this.name = this.defaults.name; this.area = this.defaults.area; this.mass = this.defaults.mass; this.sum = defaultSumDST; this.sum_property = defaultSumProperty; this.merge = defaultMerge; this.multiply = defaultMultiply; this.describeSimple = defaultDescribeSimple; return this; } function copy_defaultsDST(self,proto) { for (var key in proto) { if (proto.hasOwnProperty(key)) { self[key] = proto[key](self); } } } personVar = { name: "Person", area: 0.33, mass: 80, clusters: 5, cluster_chances: .8, contents: [], 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] sex: [["male",2,.02],["female",2,.02]],//["sex", mass modifier, area modifier] 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] singular: "person", plural: "people" } function PersonDST(count = 1) { this.defaults = personVar; copy_defaultsDST(this,new DefaultDestructable()); this.count = count; this.contents = initContents(this.name,this.count); this.describeOne = function (verbose=true) { var body = random_desc(this.properties.body, (verbose ? 0.6 : 0)); var sex = random_desc(this.properties.sex, (verbose ? 1 : 0)); var species = random_desc(this.properties.species); return "a " + merge_desc([body,sex,species]); }; this.describe = function(verbose=true) { if (verbose) { if (count <= 3) { var list = []; for (var i = 0; i < count; i++) { list.push(this.describeOne(this.count <= 2)); } return merge_things(list); } else { return this.count + " people"; } } else { return (this.count > 1 ? this.count + " people" : "a person"); } }; return this; } */ 'use strict'; var things = { "Container": { "Container": Container, mass: 0, area: 0, clusters: 0, cluster_chances: 0, contents: [], }, //Creatures "Person": { "Person": Person, mass: 80, area: .33, clusters: 5, cluster_chances: .8, contents: [], }, "Human": { "Human": Human, mass: 80, area: .33, clusters: 5, cluster_chances: .8, contents: [], }, "Cow": { "Cow": Cow, mass: 300, area: 2, clusters: 15, cluster_chances: .5, contents: [], }, "Micro": { "Micro": Micro, mass: .01, area: .05, clusters: 50, cluster_chances: 1, contents: [[]], }, "Macro": { "Macro": Macro, mass: 8e4, area: 100, clusters: 0, cluster_chances: 0, contents: [[]], }, //Vehicles "Empty Car": { "Empty Car": EmptyCar, mass: 1000, area: 4, clusters: 2, cluster_chances: .3, contents: [[]], }, "Car": { "Car": Car, mass: 1000, area: 4, clusters: 4, cluster_chances: .5, contents: [["Person",1,4]], }, "Bus": { "Bus": Bus, mass: 5000, area: 12, clusters: 1, cluster_chances: .25, contents: [["Person",2,30]], }, "Tram": { "Tram": Tram, mass: 1e4, area: 20, clusters: 1, cluster_chances: .2, contents: [["Person",10,50]], }, "Train": { "Train": Train, mass: 5e4, area: 40, clusters: 2, cluster_chances: .1, contents: [["Person",1,4,"engine"],["Train Car",2,10]], }, "Train Car": { "Train Car": TrainCar, mass: 7500, area: 20, clusters: 1, cluster_chances: .05, contents: [["Person",10,40]], }, //Buildings "House": { "House": House, mass: 1e4, area: 150, clusters: 5, cluster_chances: .5, contents: [["Person",0,8],["Empty Car",0,2]], }, "Business": { "Business": Business, mass: 5e4, area: 400, clusters: 5, cluster_chances: .25, contents: [["Person",0,30],["Car",0,5],["Empty Car",0,20]], }, "Barn": { "Barn": Barn, mass: 5e3, area: 300, clusters: 1, cluster_chances: .1, contents: [["Person",0,2],["Cow",30,70]], }, "Small Skyscraper": { "Small Skyscraper": SmallSkyscraper, mass: 1e7, area: 1000, clusters: 2, cluster_chances: .25, contents: [["Person",150,750],["Empty Car",10,50]], }, "Large Skyscraper": { "Large Skyscraper": LargeSkyscraper, mass: 8e7, area: 2000, clusters: 1, cluster_chances: .25, contents: [["Person",500,1500],["Empty Car",20,100]], }, "Parking Garage": { "Parking Garage": ParkingGarage, mass: 1e7, area: 750, clusters: 1, cluster_chances: .1, contents: [["Person",10,200],["Empty Car",100,300],["Car",5,30]], }, //Places "Town": { "Town": Town, mass: 1, area: 1e7, clusters: 5, cluster_chances: .1, contents: [["Person",10000,100000],["House",5000,50000],["Empty Car",200,800],["Car",500,80000],["Bus",5,25],["Train",5,25],["Business",500,5000]], }, "City": { "City": City, mass: 1, area: 1e9, clusters: 0, cluster_chances: .2, 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]], }, "Continent": { "Continent": Continent, mass: 1e21, area: 1.5e13, clusters: 5, cluster_chances: .5, contents: [["Person",1000000,15000000],["House",2500,10000],["Car",25000,375000],["Train",50,500],["Town",500,1000],["City",50,250],["Business",250,1000]], }, "Planet": { "Planet": Planet, mass: 5.972e24, area: 2.5e14, clusters: 0, cluster_chances: 1, contents: [["Continent",4,9]], }, "Star": { "Star": Star, mass: 1e40, area: 3e18, clusters: 1, cluster_chances: 1, contents: [], }, "Solar System": { "Solar System": SolarSystem, mass: 1, area: 3e21, clusters: 1, cluster_chances: 1, contents: [["Star",1,1],["Planet",5,15]], }, "Galaxy": { "Galaxy": Galaxy, mass: 1, area: 2e45, clusters: 1, cluster_chances: 1, contents: [["Star",1e9,500e9],["Solar System",1e8,500e8]], }, "Cluster": { "Cluster": Cluster, mass: 1, area: 2e49, clusters: 1, cluster_chances: 1, contents: [["Galaxy",200,5000]], }, "Universe": { "Universe": Universe, mass: 1, area: 7e53, clusters: 1, cluster_chances: 1, contents: [["Cluster",1.5e9,2.5e9]], }, "Multiverse": { "Multiverse": Multiverse, mass: 1, area: 5e56, clusters: 1, cluster_chances: 1, contents: [["Universe",100,1000]], }, //Military "Soldier": { "Soldier": Soldier, mass: 80, area: 1, clusters: 2, cluster_chances: .2, contents: [], }, "Tank": { "Tank": Tank, mass: 5000, area: 20, clusters: 2, cluster_chances: .25, contents: [["Soldier",3,5]], }, "Artillery": { "Artillery": Artillery, mass: 7000, area: 25, clusters: 3, cluster_chances: .5, contents: [["Soldier",4,6]], }, "Helicopter": { "Helicopter": Helicopter, mass: 1500, area: 12, clusters: 0, cluster_chances: 0, contents: [["Soldier",4,16]], }, "Squad": { "Squad": Squad, mass: 1, area: 30, clusters: 20, cluster_chances: .05, contents: [["Soldier",6,9]], }, "Platoon": { "Platoon": Platoon, mass: 100, area: 150, clusters: 2, cluster_chances: .1, contents: [["Soldier",16,44]], }, "Company": { "Company": Company, mass: 500, area: 600, clusters: 2, cluster_chances: .1, contents: [["Soldier",60,200]], }, "Battalion": { "Battalion": Battalion, mass: 1000, area: 3500, clusters: 2, cluster_chances: .1, contents: [["Soldier",300,1000]], }, "Brigade": { "Brigade": Brigade, mass: 1500, area: 2e4, clusters: 2, cluster_chances: .1, contents: [["Soldier",1500,3200]], }, "Division": { "Division": Division, mass: 2000, area: 8e4, clusters: 3, cluster_chances: .1, contents: [["Soldier",10000,16000]], }, "Tank Division": { "Tank Division": TankDivision, mass: 3000, area: 1e5, clusters: 1, cluster_chances: .15, contents: [["Soldier",8000,1200],["Tank",250,500]], }, "Army": { "Army": Army, mass: 5000, area: 1e6, clusters: 2, cluster_chances: .1, contents: [["Soldier",40000,75000]], }, }; //Alterante Army Structuring, may be used later //"Squad": [["Soldier",6,9]], // "Platoon": [["Squad",3,4]], //"Company": [["Platoon",3,5],["Squad",0,2]], //"Battalion": [["Company",4,6]], //"Brigade": [["Battalion",2,5],["Company",0,3]], //"Division": [["Brigade",2,4]], //"Tank Division": [["Brigade",2,4],["Tank",250,500]], //"Army": [["Division",3,8],["Tank Division",1,5]], var clusters = { "Container": 0, //Creatures "Person": 5, "Human": 5, "Cow": 15, "Micro": 10, "Macro": 0, //Vehicles "Car": 3, "Bus": 1, "Tram": 1, "Train": 2, "Train Car": 1, //Buildings "House": 5, "Business": 5, "Barn": 1, "Small Skyscraper": 2, "Large Skyscraper": 1, "Parking Garage": 1, //Places "Town": 5, "City": 1, "Continent": 5, "Planet": 1, "Star": 1, "Solar System": 1, "Galaxy": 1, "Cluster": 1, "Universe": 1, "Multiverse": 1, //Military "Soldier": 0, "Tank": 0, "Artillery": 0, "Helicopter": 0, "Squad": 20, "Platoon": 2, "Company": 2, "Battalion": 2, "Brigade": 2, "Division": 3, "Tank Division": 1, "Army": 2, }; var cluster_chances = { "Container": 0, //Creatures "Person": 0.8, "Human": 0.8, "Cow": 0.5, "Micro": 10, "Macro": 0, //Vehicles "Car": 0.5, "Bus": 0.25, "Tram": 0.2, "Train": 0.1, "Train Car": 0.05, //Buildings "House": 0.5, "Business": .05, "Barn": 0.1, "Small Skyscraper": 0.25, "Large Skyscraper": 0.25, "Parking Garage": 0.1, //Places "Town": 0.1, "City": 0.2, "Continent": 0.5, "Planet": 1, "Star": 1, "Solar System": 1, "Galaxy": 1, "Cluster": 1, "Universe": 1, "Multiverse": 1, //Military "Soldier": 0, "Tank": 0, "Artillery": 0, "Helicopter": 0, "Squad": .05, "Platoon": .05, "Company": .1, "Battalion": .1, "Brigade": .1, "Division": .1, "Tank Division": 0.15, "Army": .1, }; var contents = { "Container": [], //Creatures "Person": [], "Human": [], "Cow": [], "Micro": [[]], "Macro": [[]], //Vehicles "Car": [["Person",1,4]], "Bus": [["Person",2,30]], "Tram": [["Person",10,50]], "Train": [["Person",1,4,"engine"],["Train Car",2,10]], "Train Car": [["Person",10,40]], //Buildings "House": [["Person",0,8],["Empty Car",0,2]], "Business": [["Person",0,30],["Car",0,20]], "Barn": [["Person",0,2],["Cow",30,70]], "Small Skyscraper": [["Person",150,750],["Empty Car",10,50]], "Large Skyscraper": [["Person",500,1500],["Empty Car",20,100]], "Parking Garage": [["Person",10,200],["Empty Car",100,300],["Car",5,30]], //Places "Town": [["Person",10000,100000],["House",5000,50000],["Empty Car",200,800],["Car",500,80000],["Bus",5,25],["Train",5,25],["Business",500,5000]], "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]], "Continent": [["Person",1000000,15000000],["House",2500,10000],["Car",25000,375000],["Train",50,500],["Town",500,1000],["City",50,250],["Business",250,1000]], "Planet": [["Continent",4,9]], "Star": [], "Solar System": [["Star",1,1],["Planet",5,15]], "Galaxy": [["Star",1e9,500e9],["Solar System",1e8,500e8]], "Cluster": [["Galaxy",200,5000]], "Universe": [["Cluster",1.5e9,2.5e9]], "Multiverse": [["Universe",100,1000]], //Military "Soldier": [], "Tank": [["Soldier",3,5]], "Artillery": [["Soldier",4,6]], "Helicopter": [["Soldier",4,16]], //Alterante Army Structuring, may be used later //"Squad": [["Soldier",6,9]], // "Platoon": [["Squad",3,4]], //"Company": [["Platoon",3,5],["Squad",0,2]], //"Battalion": [["Company",4,6]], //"Brigade": [["Battalion",2,5],["Company",0,3]], //"Division": [["Brigade",2,4]], //"Tank Division": [["Brigade",2,4],["Tank",250,500]], //"Army": [["Division",3,8],["Tank Division",1,5]], "Squad": [["Soldier",6,9]], "Platoon": [["Soldier",16,44]], "Company": [["Soldier",60,200]], "Battalion": [["Soldier",300,1000]], "Brigade": [["Soldier",1500,3200]], "Division": [["Soldier",10000,16000]], "Tank Division": [["Soldier",8000,1200],["Tank",250,500]], "Army": [["Soldier",40000,75000]], }; // replace all instances of from with to function contents_substitute(from,to) { for (let key in contents) { if (contents.hasOwnProperty(key)) { let type = contents[key]; for (let i=0; i 0) { // if a custom label is supplied, use it! if (type[i].length == 4) //if has optional name result[type[i][3]] = new things[type[i][0]][type[i][0]](amount); //creates a "thing name" under the key of "optional name" else result[type[i][0]] = new things[type[i][0]][type[i][0]](amount); } } return result; } function get_living_prey(sum) { let total = 0; for (let key in sum) { if (sum.hasOwnProperty(key)) { if (key == "Micro" || key == "Macro" || key == "Person" || key == "Cow" || key == 'Soldier') total += sum[key]; } } return total; } // general logic: each step fills in a fraction of the remaining space function fill_area(area, weights, variance=0.15) { area = area + Math.random() * variance * 2 * area - variance * area; var result = []; var candidates = []; for (var key in weights) { if (weights.hasOwnProperty(key)) { candidates.push({"name": key, "area": things[key].area, "weight": weights[key]}); } } candidates = candidates.sort(function (x,y) { return x.area - y.area; }); while(candidates.length > 0) { var candidate = candidates.pop(); if (candidate.area > area) continue; var max = Math.floor(area / candidate.area); var limit = Math.min(max, 100); var count = 0; var loopvar = limit; // for small amounts, actually do the randomness // the first few ones get a much better shot // if we have nothing at all, it's even better! if (limit > 0 && result.length == 0) { ++count; ++loopvar; } while (loopvar < limit) { if (loopvar <= clusters[candidate.name] && loopvar == 0 && Math.random() < cluster_chances[candidate.name]) { ++count; } else if (loopvar <= clusters[candidate.name]) { if (Math.random() < candidate.weight ? 1 : 0 || Math.random() < 0.75 * cluster_chances[candidate.name]) { ++count; } } else { count += Math.random() < candidate.weight ? 1 : 0; } ++loopvar; } if (limit < max) { count += Math.round((max-limit) * candidate.weight); } area -= count * candidate.area; if (count > 0) result.push(new things[candidate.name][candidate.name](count)); } return new Container(result); } // describes everything in the container function describe_all(contents,verbose=true,except=[]) { var things = []; for (var key in contents) { if (contents.hasOwnProperty(key) && !except.includes(key)) { things.push(contents[key].describe(verbose)); } } return merge_things(things); } function random_desc(list, odds=1) { if (Math.random() < odds) return list[Math.floor(Math.random() * list.length)]; else return ""; } // combine strings into a list with proper grammar function merge_things(list,semicolons=false) { if (list.length == 0) { return ""; } else if (list.length == 1) { return list[0]; } else if (list.length == 2) { return list[0] + " and " + list[1]; } else { var result = ""; list.slice(0,list.length-1).forEach(function(term) { result += term + ", "; }); result += "and " + list[list.length-1]; return result; } } // combine the adjectives for something into a single string function merge_desc(list) { var result = ""; list.forEach(function(term) { if (term != "") result += term + " "; }); // knock off the last space if (result.length > 0) { result = result.substring(0, result.length - 1); } return result; } // maybe make this something that approximates a // normal distribution; doing this 15,000,000 times is bad... // solution: only a few are random lul // improvement: take up to 100 samples, then use that to scale the final result function distribution(min, max, samples) { var result = 0; var limit = Math.min(100,samples); if (limit < samples) { let dist = 0; for (let i = 0; i < limit; i++) { dist += Math.random(); } dist /= 100; return Math.floor(dist * samples * (max - min + 1) + samples * min); } else { for (let i = 0; i < limit; i++) { result += Math.floor(Math.random() * (max - min + 1) + min); } } return result; } function defaultMultiply(thing) { return function(amount) { thing.count *= amount; for (var key in thing.contents) { if (thing.contents.hasOwnProperty(key)) { thing.contents[key].multiply(amount); } } }; } function defaultArea(thing) { return things[thing.name].area; } function defaultMass(thing) { return things[thing.name].mass; } function defaultMerge(thing) { //this merges all objects into one containers return function(container) { var newCount = this.count + container.count; var newThing = new things[thing.name][thing.name](newCount); newThing.contents = {}; for (var key in this.contents) { if (this.contents.hasOwnProperty(key)) { newThing.contents[key] = this.contents[key]; } } for (key in container.contents) { if (container.contents.hasOwnProperty(key)) { if (this.contents.hasOwnProperty(key)) { newThing.contents[key] = this.contents[key].merge(container.contents[key]); } else { newThing.contents[key] = container.contents[key]; } } } return newThing; }; } function listSum(sum) { let result = []; for (let key in sum) { if (sum.hasOwnProperty(key)) { result.push(new things[key][key](sum[key]).describe(false)); } } return merge_things(result); } // turn a nested object into a container with everything on one level function flatten(thing) { let dict = defaultSum(thing)(); let list = []; Object.entries(dict).forEach(function([key, val]) { let obj = new things[key][key](val); obj.contents = []; list.push(obj); }); list.sort(function(x,y) { if (y.area != x.area){ return y.area - x.area; } else { return x.name.localeCompare(y.name); } }); return new Container(list); } function defaultSum(thing) { return function() { var counts = {}; if (thing.name != "Container") counts[thing.name] = thing.count; for (var key in thing.contents) { if (thing.contents.hasOwnProperty(key)) { var subcount = thing.contents[key].sum(); for (var subkey in subcount) { if (!counts.hasOwnProperty(subkey)) { counts[subkey] = 0; } counts[subkey] += subcount[subkey]; } } } return counts; }; } function defaultSumProperty(thing) { return function(prop) { var total = 0; total += thing[prop] * thing.count; for (var key in thing.contents) { if (thing.contents.hasOwnProperty(key)) { total += thing.contents[key].sum_property(prop); } } return total; }; } function defaultAddContent(thing) { return function(name, min, max, count) { if (min == max) { let object = new things[name](min*count); thing.contents[object.name] = object; } else { let object = new things[name](distribution(min, max, count)); thing.contents[object.name] = object; } }; } function defaultDescribeSimple(thing) { return function(flat) { if (flat) { return flatten(thing).describe(false) } else { return thing.describe(false); } } } function DefaultEntity() { this.sum = defaultSum; this.area = defaultArea; this.mass = defaultMass; this.sum_property = defaultSumProperty; this.merge = defaultMerge; this.multiply = defaultMultiply; this.describeSimple = defaultDescribeSimple; return this; } // god I love reinventing the wheel function copy_defaults(self,proto) { //loads the values defined in things into the fuction that calls it for (var key in proto) { //proto will always be a new DefaultEntity, self is the parent function if (proto.hasOwnProperty(key)) { self[key] = proto[key](self); } } } function Container(contents = []) { this.name = "Container"; copy_defaults(this,new DefaultEntity()); if (Number.isInteger(contents)) this.count = contents; else this.count = 0; this.contents = {}; for (var i=0; i < contents.length; i++) { this.contents[contents[i].name] = contents[i]; } for (var key in this.contents) { if (this.contents.hasOwnProperty(key)) { this.count += this.contents[key].count; } } this.describe = function(verbose = true) { return describe_all(this.contents,verbose); }; return this; } function Person(count = 1) { this.name = "Person"; copy_defaults(this,new DefaultEntity()); this.count = count; this.contents = initContents(this.name,this.count); this.describeOne = function (verbose=true) { var body = random_desc(["skinny","fat","tall","short","stocky","spindly","muscular","fit","multi-colored"], (verbose ? 0.6 : 0)); var sex = random_desc(["male", "female"], (verbose ? 0.75 : 0)); var species = ""; species = random_desc(["wolf","cat","dog","squirrel","horse","hyena","fox","jackal","crux","sergal","coyote","rabbit","lizard","avian"]); return "a " + merge_desc([body,sex,species]); }; this.describe = function(verbose=true) { if (verbose) { if (count <= 3) { var list = []; for (var i = 0; i < count; i++) { list.push(this.describeOne(this.count <= 2)); } return merge_things(list); } else { return this.count + " people"; } } else { return (this.count > 1 ? this.count + " people" : "a person"); } }; return this; } function Human(count = 1) { this.name = "Person"; copy_defaults(this,new DefaultEntity()); this.count = count; this.contents = initContents(this.name,this.count); this.describeOne = function (verbose=true) { var body = random_desc(["skinny","fat","tall","short","stocky","spindly","muscular","fit","tanned"], (verbose ? 0.6 : 0)); var sex = random_desc(["man", "woman"], 1); return "a " + merge_desc([body,sex]); }; this.describe = function(verbose=true) { if (verbose) { if (count <= 3) { var list = []; for (var i = 0; i < count; i++) { list.push(this.describeOne(this.count <= 2)); } return merge_things(list); } else { return this.count + " people"; } } else { return (this.count > 1 ? this.count + " people" : "a person"); } }; return this; } function Cow(count = 1) { this.name = "Cow"; copy_defaults(this,new DefaultEntity()); this.count = count; this.contents = initContents(this.name,this.count); this.describeOne = function (verbose=true) { var body = random_desc(["skinny","fat","tall","short","stocky","spindly"], (verbose ? 0.6 : 0)); var sex = random_desc(["male", "female"], (verbose ? 1 : 0)); return "a " + merge_desc([body,sex,"cow"]); }; this.describe = function(verbose=true) { if (verbose) { if (count <= 3) { var list = []; for (var i = 0; i < count; i++) { list.push(this.describeOne(this.count <= 2)); } return merge_things(list); } else { return this.count + " cattle"; } } else { return (this.count > 1 ? this.count + " cattle" : "a cow"); } }; return this; } function EmptyCar(count = 1) { this.name = "Car"; copy_defaults(this,new DefaultEntity()); this.count = count; this.contents = initContents(this.name,this.count); this.describeOne = function(verbose=true) { var color = random_desc(["black","black","gray","gray","blue","red","tan","white","white"]); var adjective = random_desc(["rusty","brand-new","luxury","beat-up","dented","restored","classic"],0.3); var type = random_desc(["SUV","coupe","sedan","truck","van","convertible"]); return "a parked " + merge_desc([adjective,color,type]); }; this.describe = function(verbose = true) { if (verbose) { if (this.count <= 3) { var list = []; for (var i = 0; i < this.count; i++) { list.push(this.describeOne()); } return merge_things(list); } else { return this.count + " parked cars"; } } else { return (this.count > 1 ? this.count + " parked cars" : "a parked car"); } }; } function Car(count = 1) { this.name = "Car"; copy_defaults(this,new DefaultEntity()); this.count = count; this.contents = initContents(this.name,this.count); this.describeOne = function(verbose=true) { var color = random_desc(["black","black","gray","gray","blue","red","tan","white","white"], (verbose ? 1 : 0)); var adjective = random_desc(["rusty","brand-new","luxury","beat-up","dented","restored","classic"], (verbose ? 0.3 : 0)); var type = random_desc(["SUV","coupe","sedan","truck","van","convertible"]); return "a " + merge_desc([adjective,color,type]); }; this.describe = function(verbose = true) { if (verbose) { if (this.count <= 3) { var list = []; for (var i = 0; i < this.count; i++) { list.push(this.describeOne(this.count < 2)); } return merge_things(list) + " with " + describe_all(this.contents,verbose) + " inside"; } else { return this.count + " cars with " + describe_all(this.contents,verbose) + " inside"; } } else { return (this.count > 1 ? this.count + " cars" : "a car"); } }; } function Bus(count = 1) { this.name = "Bus"; copy_defaults(this,new DefaultEntity()); this.count = count; this.contents = initContents(this.name,this.count); this.describeOne = function(verbose=true) { var adjective = random_desc(["rusty","brand-new","aging","modern"], (verbose ? 0.3 : 0)); var color = random_desc(["black","tan","gray"], (verbose ? 1 : 0)); var type = random_desc(["bus","double-decker bus","articulating bus","open-top bus","sleeper bus","intercity bus"]); return "a " + merge_desc([adjective,color,type]); }; this.describe = function(verbose = true) { if (verbose) { if (this.count <= 3) { var list = []; for (var i = 0; i < this.count; i++) { list.push(this.describeOne(this.count < 2)); } return merge_things(list) + " with " + describe_all(this.contents,verbose) + " inside"; } else { return this.count + " buses with " + describe_all(this.contents,verbose) + " inside"; } } else { return (this.count > 1 ? this.count + " buses" : "a bus"); } }; } function Tram(count = 1) { this.name = "Tram"; copy_defaults(this,new DefaultEntity()); this.count = count; this.contents = initContents(this.name,this.count); this.describeOne = function(verbose=true) { var adjective = random_desc(["rusty","weathered","well-maintained",], (verbose ? 0.3 : 0)); var color = random_desc(["blue","brown","gray"], (verbose ? 1 : 0)); var type = random_desc(["tram"]); return "a " + merge_desc([adjective,color,type]); }; this.describe = function(verbose = true) { if (verbose) { if (this.count == 1) { var list = []; for (var i = 0; i < this.count; i++) { list.push(this.describeOne(verbose)); } return merge_things(list) + " with " + describe_all(this.contents,verbose) + " inside"; } else { return this.count + " trams with " + describe_all(this.contents,verbose) + " inside"; } } else { return (this.count > 1 ? this.count + " trams" : "a tram"); } }; this.anal_vore = function() { return "You slide " + this.describe() + " up your tight ass"; }; } function Train(count = 1) { this.name = "Train"; copy_defaults(this,new DefaultEntity()); this.count = count; this.contents = initContents(this.name,this.count); this.describeOne = function(verbose=true) { var adjective = random_desc(["rusty","brand-new","steam","freshly-painted"], (verbose ? 0.3 : 0)); var color = random_desc(["black","tan","gray"], (verbose ? 1 : 0)); var type = random_desc(["train","passenger train","freight train"]); return "a " + merge_desc([adjective,color,type]); }; this.describe = function(verbose = true) { if (verbose) { if (this.count == 1) { var list = []; for (var i = 0; i < this.count; i++) { list.push(this.describeOne(verbose)); } return merge_things(list) + " with " + this.contents["engine"].describe(false) + " in the engine and " + this.contents["Train Car"].describe() + " attached"; } else { return this.count + " trains with " + this.contents["engine"].describe(false) + " in the engine and " + this.contents["Train Car"].describe() + " attached"; } } else { return (this.count > 1 ? this.count + " trains" : "a train"); } }; this.anal_vore = function() { 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"); return "You snatch up " + this.describeOne() + " and stuff it into your pucker, moaning as " + cars; }; } function TrainCar(count = 1) { this.name = "Train Car"; copy_defaults(this,new DefaultEntity()); this.count = count; this.contents = initContents(this.name,this.count); this.describeOne = function(verbose=true) { var adjective = random_desc(["rusty","brand-new","vintage","graffitied","well-maintained"], (verbose ? 0.3 : 0)); var color = random_desc(["black","tan","gray","yellow","steel","wooden"], (verbose ? 1 : 0)); var type = random_desc(["train car","passenger train car","freight train car"]); return "a " + merge_desc([adjective,color,type]); }; this.describe = function(verbose = true) { if (verbose) { return (this.count > 1 ? this.count + " train cars" : "a train car") + " with " + describe_all(this.contents) + " inside"; } else { return (this.count > 1 ? this.count + " train cars" : "a train car"); } }; } function House(count = 1) { this.name = "House"; copy_defaults(this,new DefaultEntity()); this.count = count; this.contents = initContents(this.name,this.count); this.describeOne = function(verbose=true) { var size = random_desc(["little","two-story","large","well-built","run-down","cheap",], (verbose ? 0.5 : 0)); var color = random_desc(["blue","white","gray","tan","green","wooden","brick"], (verbose ? 0.5 : 0)); var name = random_desc(["house","home","house","house","house","trailer"], 1); return "a " + merge_desc([size,color,name]); }; this.describe = function(verbose = true) { if (verbose) { if (this.count <= 3) { var list = []; for (var i = 0; i < this.count; i++) { list.push(this.describeOne(this.count < 2)); } return merge_things(list) + " with " + describe_all(this.contents,verbose) + " inside"; } else { return this.count + " homes with " + describe_all(this.contents,verbose) + " inside"; } } else { return (this.count > 1 ? this.count + " houses" : "a house"); } }; } //might split this into a general business and resutrant categories function Business(count = 1) { this.name = "Business"; copy_defaults(this,new DefaultEntity()); this.count = count; this.contents = initContents(this.name,this.count); this.describeOne = function(verbose=true) { var size = random_desc(["little","two-story","large","well-built","run-down","cheap","aging","corner"], (verbose ? 0.5 : 0)); var color = random_desc(["blue","white","gray","tan","green","brick","concrete"], (verbose ? 0.5 : 0)); 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); return "a " + merge_desc([size,color,name]); }; this.describe = function(verbose = true) { if (verbose) { if (this.count <= 3) { var list = []; for (var i = 0; i < this.count; i++) { list.push(this.describeOne(this.count < 2)); } return merge_things(list) + " with " + describe_all(this.contents,verbose); } else { return this.count + " local business containing " + describe_all(this.contents,verbose); } } else { return (this.count > 1 ? this.count + " buildings" : "a local business"); } }; } function Barn(count = 1) { this.name = "Barn"; copy_defaults(this,new DefaultEntity()); this.count = count; this.contents = initContents(this.name,this.count); this.describeOne = function(verbose=true) { var size = random_desc(["little","big","large","weathered","rotted","new"], (verbose ? 0.5 : 0)); var color = random_desc(["blue","white","gray","tan","green","red"], (verbose ? 0.5 : 0)); var name = random_desc(["barn","barn","barn","barn","barn","farmhouse"], 1); return "a " + merge_desc([size,color,name]); }; this.describe = function(verbose = true) { if (verbose) { if (this.count <= 3) { var list = []; for (var i = 0; i < this.count; i++) { list.push(this.describeOne(this.count < 2)); } return merge_things(list) + " with " + describe_all(this.contents,verbose) + " inside"; } else { return this.count + " barns with " + describe_all(this.contents,verbose) + " inside"; } } else { return (this.count > 1 ? this.count + " barns" : "a barn"); } }; } function SmallSkyscraper(count = 1) { this.name = "Small Skyscraper"; copy_defaults(this,new DefaultEntity()); this.count = count; this.contents = initContents(this.name,this.count); this.describeOne = function(verbose=true) { var color = random_desc(["blue","white","gray","tan","green"], (verbose ? 0.5 : 0)); var name = random_desc(["skyscraper","office tower","office building","high rise"], 1); return "a " + merge_desc([color,name]); }; this.describe = function(verbose = true) { if (verbose) { if (this.count <= 3) { var list = []; for (var i = 0; i < this.count; i++) { list.push(this.describeOne(this.count < 2)); } return merge_things(list) + " with " + describe_all(this.contents,verbose) + " inside"; } else { return this.count + " small skyscrapers with " + describe_all(this.contents,verbose) + " inside"; } } else { return (this.count > 1 ? this.count + " small skyscrapers" : "a small skyscraper"); } }; } function LargeSkyscraper(count = 1) { this.name = "Large Skyscraper"; copy_defaults(this,new DefaultEntity()); this.count = count; this.contents = initContents(this.name,this.count); this.describeOne = function(verbose=true) { var color = random_desc(["blue","white","gray","tan","green","glass"], (verbose ? 0.5 : 0)); var name = random_desc(["skyscraper","office tower","office building"], 1); return "a " + merge_desc(["towering",color,name]); }; this.describe = function(verbose = true) { if (verbose) { if (this.count <= 3) { var list = []; for (var i = 0; i < this.count; i++) { list.push(this.describeOne(this.count < 2)); } return merge_things(list) + " with " + describe_all(this.contents,verbose) + " inside"; } else { return this.count + " large skyscrapers with " + describe_all(this.contents,verbose) + " inside"; } } else { return (this.count > 1 ? this.count + " large skyscrapers" : "a large skyscraper"); } }; } function ParkingGarage(count = 1) { this.name = "Parking Garage"; copy_defaults(this,new DefaultEntity()); this.count = count; this.contents = initContents(this.name,this.count); this.describeOne = function(verbose=true) { return "a parking garage"; }; this.describe = function(verbose = true) { if (verbose) { return (this.count == 1 ? "a parking garage" : this.count + " parking garages") + " with " + describe_all(this.contents, verbose); } else { return (this.count == 1 ? "a parking garage" : this.count + " parking garages"); } }; } function Town(count = 1) { this.name = "Town"; copy_defaults(this,new DefaultEntity()); this.count = count; this.contents = initContents(this.name,this.count); this.describe = function(verbose = true) { if (verbose) { return (this.count == 1 ? "a town" : this.count + " towns") + " with " + describe_all(this.contents, verbose) + " in " + (this.count == 1 ? "it" : "them"); } else { return (this.count == 1 ? "a town" : this.count + " towns"); } }; } function City(count = 1) { this.name = "City"; copy_defaults(this,new DefaultEntity()); this.count = count; this.contents = initContents(this.name,this.count); this.describe = function(verbose = true) { if (verbose) { return (this.count == 1 ? "a city" : this.count + " cities") + " with " + describe_all(this.contents, verbose) + " in " + (this.count == 1 ? "it" : "them"); } else { return (this.count == 1 ? "a city" : this.count + " cities"); } }; } function Continent(count = 1) { this.name = "Continent"; copy_defaults(this,new DefaultEntity()); this.count = count; this.contents = initContents(this.name,this.count); this.describe = function(verbose = true) { if (verbose) { return (this.count == 1 ? "a continent" : this.count + " continents") + " with " + describe_all(this.contents, verbose) + " on " + (this.count == 1 ? "it" : "them"); } else { return (this.count == 1 ? "a continent" : this.count + " continents"); } }; } function Planet(count = 1) { this.name = "Planet"; copy_defaults(this,new DefaultEntity()); this.count = count; this.contents = initContents(this.name,this.count); this.describe = function(verbose = true) { if (verbose) { return (this.count == 1 ? "a planet" : this.count + " planets") + " with " + describe_all(this.contents, verbose) + " on " + (this.count == 1 ? "it" : "them"); } else { return (this.count == 1 ? "a planet" : this.count + " planets"); } }; } function Star(count = 1) { this.name = "Star"; copy_defaults(this,new DefaultEntity()); this.count = count; this.contents = initContents(this.name,this.count); this.describe = function(verbose = true) { return (this.count == 1 ? "a star" : this.count + " stars"); }; } function SolarSystem(count = 1) { this.name = "Solar System"; copy_defaults(this,new DefaultEntity()); this.count = count; this.contents = initContents(this.name,this.count); this.describe = function(verbose = true) { if (verbose) { return (this.count == 1 ? "a solar system" : this.count + " solar systems") + " made up of " + describe_all(this.contents, verbose); } else { return (this.count == 1 ? "a solar system" : this.count + " solar systems"); } }; } function Galaxy(count = 1) { this.name = "Galaxy"; copy_defaults(this,new DefaultEntity()); this.count = count; this.contents = initContents(this.name,this.count); this.describe = function(verbose = true) { if (verbose) { return (this.count == 1 ? "a galaxy" : this.count + " galaxies") + " made up of " + describe_all(this.contents, verbose); } else { return (this.count == 1 ? "a galaxy" : this.count + " galaxies"); } }; } function Cluster(count = 1) { this.name = "Cluster"; copy_defaults(this,new DefaultEntity()); this.count = count; this.contents = initContents(this.name,this.count); this.describe = function(verbose = true) { if (verbose) { return (this.count == 1 ? "a cluster" : this.count + " clusters") + " made up of " + describe_all(this.contents, verbose); } else { return (this.count == 1 ? "a cluster" : this.count + " clusters"); } }; } function Universe(count = 1) { this.name = "Universe"; copy_defaults(this,new DefaultEntity()); this.count = count; this.contents = initContents(this.name,this.count); this.describe = function(verbose = true) { if (verbose) { return (this.count == 1 ? "a universe" : this.count + " universes") + " made up of " + describe_all(this.contents, verbose); } else { return (this.count == 1 ? "a universe" : this.count + " universes"); } }; } function Multiverse(count = 1) { this.name = "Multiverse"; copy_defaults(this,new DefaultEntity()); this.count = count; this.contents = initContents(this.name,this.count); this.describe = function(verbose = true) { if (verbose) { return (this.count == 1 ? "a multiverse" : this.count + " multiverses") + " made up of " + describe_all(this.contents, verbose); } else { return (this.count == 1 ? "a multiverse" : this.count + " multiverses"); } }; } function Soldier(count = 1) { this.name = "Soldier"; copy_defaults(this,new DefaultEntity()); this.count = count; this.contents = initContents(this.name,this.count); this.describe = function(verbose = true) { return (this.count == 1 ? "a soldier" : this.count + " soldiers"); }; } function Tank(count = 1) { this.name = "Tank"; copy_defaults(this,new DefaultEntity()); this.count = count; this.contents = initContents(this.name,this.count); this.describe = function(verbose = true) { if (verbose) { return (this.count == 1 ? "a tank" : this.count + " tanks") + " with " + describe_all(this.contents, verbose) + " trapped inside"; } else { return (this.count == 1 ? "a tank" : this.count + " tanks"); } }; } function Artillery(count = 1) { this.name = "Artillery"; copy_defaults(this,new DefaultEntity()); this.count = count; this.contents = initContents(this.name,this.count); this.describe = function(verbose = true) { if (verbose) { return (this.count == 1 ? "an artillery unit" : this.count + " artillery units") + " with " + describe_all(this.contents, verbose) + " trapped inside"; } else { return (this.count == 1 ? "an artillery unit" : this.count + " artillery units"); } }; } function Helicopter(count = 1) { this.name = "Helicopter"; copy_defaults(this,new DefaultEntity()); this.count = count; this.contents = initContents(this.name,this.count); this.describe = function(verbose = true) { if (verbose) { return (this.count == 1 ? "a helicopter" : this.count + " helicopters") + " with " + describe_all(this.contents, verbose) + " riding inside"; } else { return (this.count == 1 ? "a helicopter" : this.count + " helicopters"); } }; } function Micro(count = 1) { this.name = "Micro"; copy_defaults(this,new DefaultEntity()); this.count = count; this.contents = initContents(this.name,this.count); this.describe = function(verbose = true) { return (this.count == 1 ? "a micro" : this.count + " micros"); }; } function Macro(count = 1) { this.name = "Macro"; copy_defaults(this,new DefaultEntity()); this.count = count; this.contents = initContents(this.name,this.count); this.describe = function(verbose = true) { return (this.count == 1 ? "a smaller macro" : this.count + " smaller macros"); }; } function Squad(count = 1) { this.name = "Squad"; copy_defaults(this,new DefaultEntity()); this.count = count; this.contents = initContents(this.name,this.count); this.describeOne = function(verbose=true) { return "a squad"; }; this.describe = function(verbose = true) { if (verbose) { return (this.count == 1 ? "a squad" : this.count + " squads") + " made up of " + describe_all(this.contents, verbose); } else { return (this.count == 1 ? "a squad" : this.count + " squads"); } }; } function Platoon(count = 1) { this.name = "Platoon"; copy_defaults(this,new DefaultEntity()); this.count = count; this.contents = initContents(this.name,this.count); this.describeOne = function(verbose=true) { return "a military platoon"; }; this.describe = function(verbose = true) { if (verbose) { return (this.count == 1 ? "a platoon" : this.count + " platoons") + " consisting of " + describe_all(this.contents, verbose); } else { return (this.count == 1 ? "a platoon" : this.count + " platoons"); } }; } function Company(count = 1) { this.name = "Company"; copy_defaults(this,new DefaultEntity()); this.count = count; this.contents = initContents(this.name,this.count); this.describeOne = function(verbose=true) { return "a company of soldiers"; }; this.describe = function(verbose = true) { if (verbose) { return (this.count == 1 ? "a company" : this.count + " companies") + " of " + describe_all(this.contents, verbose); } else { return (this.count == 1 ? "a company" : this.count + " companies"); } }; } function Battalion(count = 1) { this.name = "Battalion"; copy_defaults(this,new DefaultEntity()); this.count = count; this.contents = initContents(this.name,this.count); this.describeOne = function(verbose=true) { return "a battalion"; }; this.describe = function(verbose = true) { if (verbose) { return (this.count == 1 ? "a battalion" : this.count + " battalions") + " containing " + describe_all(this.contents, verbose); } else { return (this.count == 1 ? "a battalion" : this.count + " battalions"); } }; } function Brigade(count = 1) { this.name = "Brigade"; copy_defaults(this,new DefaultEntity()); this.count = count; this.contents = initContents(this.name,this.count); this.describeOne = function(verbose=true) { return "a brigade"; }; this.describe = function(verbose = true) { if (verbose) { return (this.count == 1 ? "a brigade" : this.count + " brigades") + " made up of " + describe_all(this.contents, verbose); } else { return (this.count == 1 ? "a brigade" : this.count + " brigades"); } }; } function Division(count = 1) { this.name = "Division"; copy_defaults(this,new DefaultEntity()); this.count = count; this.contents = initContents(this.name,this.count); this.describeOne = function(verbose=true) { return "a division"; }; this.describe = function(verbose = true) { if (verbose) { return (this.count == 1 ? "a division" : this.count + " divisions") + " of " + describe_all(this.contents, verbose); } else { return (this.count == 1 ? "a division" : this.count + " divisions"); } }; } function TankDivision(count = 1) { this.name = "Tank Division"; copy_defaults(this,new DefaultEntity()); this.count = count; this.contents = initContents(this.name,this.count); this.describeOne = function(verbose=true) { return "a tank division"; }; this.describe = function(verbose = true) { if (verbose) { return (this.count == 1 ? "a tank division" : this.count + " tank divisions") + " of " + describe_all(this.contents, verbose); } else { return (this.count == 1 ? "a tank division" : this.count + " tank divisions"); } }; } function Army(count = 1) { this.name = "Army"; copy_defaults(this,new DefaultEntity()); this.count = count; this.contents = initContents(this.name,this.count); this.describeOne = function(verbose=true) { return "an army"; }; this.describe = function(verbose = true) { if (verbose) { return (this.count == 1 ? "an army" : this.count + " armies") + " made up of " + describe_all(this.contents, verbose); } else { return (this.count == 1 ? "an army" : this.count + " armies"); } }; } //todo //redo everything //airports //farms //racetracks //more building types //nebula //grand army //armada