import {reactive, ref} from 'vue'; import NoiseMap from 'noise-map'; import MersenneTwister from 'mersenne-twister'; const seedGenerator = new MersenneTwister(); const state = reactive({ maxX: 0, minX: 0, maxY: 0, minY: 0, mapSizeX: 50, mapSizeY: 30, centerX: 0, centerY: 0, radiusY: 5, radiusX: 5, mapID: 'e1-m.lttmm', mapName: '', lttMap: null, seed: ref(seedGenerator.random_int31()) }); const reticulating = ["Adding","Hidden","Agendas","Adjusting","Bell","Curves","Aesthesizing","Industrial","Areas","Aligning","Covariance","Matrices", "Applying","Feng","Shui","Shaders","Applying","Theatre","Soda","Layer","Asserting","Packed","Exemplars","Attempting","to","Lock","Back-Buffer", "Binding","Sapling","Root","System","Breeding","Fauna","Building","Data","Trees","Bureacritizing","Bureaucracies","Calculating","Inverse","Probability","Matrices", "Calculating","Llama","Expectoration","Trajectory","Calibrating","Blue","Skies","Charging","Ozone","Layer","Coalescing","Cloud","Formations", "Cohorting","Exemplars","Collecting","Meteor","Particles","Compounding","Inert","Tessellations","Compressing","Fish","Files", "Computing","Optimal","Bin","Packing","Concatenating","Sub-Contractors","Containing","Existential","Buffer","Debarking","Ark","Ramp", "Debunching","Unionized","Commercial","Services","Deciding","What","Message","to","Display","Next","Decomposing","Singular","Values", "Decrementing","Tectonic","Plates","Deleting","Ferry","Routes","Depixelating","Inner","Mountain","Surface","Back","Faces","Depositing","Slush","Funds", "Destabilizing","Economic","Indicators","Determining","Width","of","Blast","Fronts","Deunionizing","Bulldozers","Dicing","Models", "Diluting","Livestock","Nutrition","Variables","Downloading","Satellite","Terrain","Data","Exposing","Flash","Variables","to","Streak","System", "Extracting","Resources","Factoring","Pay","Scale","Fixing","Election","Outcome","Matrix","Flood-Filling","Ground","Water","Flushing","Pipe","Network", "Gathering","Particle","Sources","Generating","Jobs","Gesticulating","Mimes","Graphing","Whale","Migration","Hiding","Willio","Webnet","Mask", "Implementing","Impeachment","Routine","Increasing","Accuracy","of","RCI","Simulators","Increasing","Magmafacation","Initializing","My","Sim","Tracking","Mechanism", "Initializing","Rhinoceros","Breeding","Timetable","Initializing","Robotic","Click-Path","AI","Inserting","Sublimated","Messages", "Integrating","Curves","Integrating","Illumination","Form","Factors","Integrating","Population","Graphs","Iterating","Cellular","Automata", "Lecturing","Errant","Subsystems","Mixing","Genetic","Pool","Modeling","Object","Components","Mopping","Occupant","Leaks","Normalizing","Power", "Obfuscating","Quigley","Matrix","Overconstraining","Dirty","Industry","Calculations","Partitioning","City","Grid","Singularities", "Perturbing","Matrices","Pixalating","Nude","Patch","Polishing","Water","Highlights","Populating","Lot","Templates","Preparing","Sprites","for","Random","Walks", "Prioritizing","Landmarks","Projecting","Law","Enforcement","Pastry","Intake","Realigning","Alternate","Time","Frames","Reconfiguring","User","Mental","Processes", "Relaxing","Splines","Removing","Road","Network","Speed","Bumps","Removing","Texture","Gradients","Removing","Vehicle","Avoidance","Behavior", "Resolving","GUID","Conflict","Retracting","Phong","Shader","Retrieving","from","Back","Store","Reverse","Engineering","Image","Consultant", "Routing","Neural","Network","Infanstructure","Scattering","Rhino","Food","Sources","Scrubbing","Terrain","Searching","for","Llamas", "Seeding","Architecture","Simulation","Parameters","Sequencing","Particles","Setting","Advisor","Moods","Setting","Inner","Deity","Indicators", "Setting","Universal","Physical","Constants","Sonically","Enhancing","Occupant-Free","Timber","Speculating","Stock","Market","Indices", "Splatting","Transforms","Stratifying","Ground","Layers","Sub-Sampling","Water","Data","Synthesizing","Gravity","Synthesizing","Wavelets", "Time-Compressing","Simulator","Clock","Unable","to","Reveal","Current","Activity","Weathering","Buildings","Zeroing","Crime","Network", "Reticulating","Splines"]; const methods = { /** * Set values back to default for the generation of a new map. * @author Trungel */ reset() { state.mapSizeX = 50; state.mapSizeY = 30; state.centerX = 0; state.centerY = 0; state.radiusY = 5; state.radiusX = 5; state.mapID = 'e1-m.lttmm'; state.mapName = ''; state.lttMap = null; state.seed = ref(seedGenerator.random_int31()); }, /** * Get all information for the map and export it as JSON. * @author Trungel * @returns {{initialViewRadiusX: (number|*), tileSet, initialVieCenterX: (number|*), initialViewRadiusY: (number|*), mapID: (string|*), mapName: (string|*), initialViewCenterY: (number|*)}} The JSON containing the map. */ exportMap() { return{ mapID: state.mapID, mapName: state.mapName, initialViewRadiusX: state.centerX, initialViewRadiusY: state.centerY, initialVieCenterX: state.radiusX, initialViewCenterY: state.radiusY, tileSet: state.lttMap.flat()} }, /** * Load an existing map from JSON entered by a user. * @author Trungel * @param mapData The JSON containing the map to load. */ loadMap(mapData) { let tileSetData = this.getMultDimArrayFromFlattendArray(mapData.tileSet); state.mapID = mapData.mapID; state.mapName = mapData.mapName; state.mapSizeX = tileSetData.mapSizeX; state.mapSizeY = tileSetData.mapSizeY; state.lttMap = tileSetData.map; state.maxX = tileSetData.maxX; state.minX = tileSetData.minX; state.maxY = tileSetData.maxY; state.minY = tileSetData.minY; state.radiusX = mapData.initialViewRadiusX; state.radiusY = mapData.initialViewRadiusY; state.centerX = mapData.initialViewCenterX; state.centerY = mapData.initialViewCenterY; }, /** * Parse the tileSet of the passed map and retrieve information about said map. * @author Trungel * @param arr The tileSet of the map to load. * @returns {{mapSizeY: number, minY, mapSizeX: number, minX, maxY, maxX, map: *[]}} JSON containing information about our map. */ getMultDimArrayFromFlattendArray(arr){ let maxX,minX,maxY,minY, mapSizeX, mapSizeY; let sortArr = arr.sort((a,b)=>{ if(a.y == b.y){ return a.x - b.x; } else { return b.y-a.y } }) let arrSize = sortArr.length; minX = sortArr[0].x; maxY = sortArr[0].y; minY = sortArr[arrSize-1].y; maxX = sortArr[arrSize-1].x; mapSizeX = Math.abs(minX)+Math.abs(maxX)+1; mapSizeY = Math.abs(minY)+Math.abs(maxY)+1; let map = []; for(let m = 0; m < mapSizeY; m++){ let xArr = []; for(let i = 0; i < mapSizeX; i++){ xArr.push(sortArr[(m*mapSizeX)+i]); } map.push(xArr); } return {mapSizeX, mapSizeY,maxX, minX,maxY, minY, map}; }, /** * Generate a random name for the new map. * @author Griefed * @returns {string} Returns a combination of three random words from {@link reticulating}. */ getMapName() { return reticulating[ Math.floor( Math.random() * reticulating.length) - 1] + " " + reticulating[Math.floor(Math.random() * reticulating.length) - 1] + " " + reticulating[Math.floor(Math.random() * reticulating.length) - 1]; }, /** * Return the mapID for the new map. * @author Griefed * @returns {string} */ getMapId() { return 'e1-m.lttmm'; }, /** * Generate a new map with a given size, mapID and mapName. * @author Trungel * @author Griefed */ generateMap() { let defaultTile = "grass"; let map = []; state.minX = -Math.floor(state.mapSizeX/2); if(state.mapSizeX%2){ state.maxX = Math.floor(state.mapSizeX/2); }else{ state.maxX = Math.floor(state.mapSizeX/2)+1; } state.minY = -Math.floor(state.mapSizeY/2); if(state.mapSizeY%2){ state.maxY = Math.floor(state.mapSizeY/2); }else{ state.maxY = Math.floor(state.mapSizeY/2)+1; } for(let m = state.maxY; m >= state.minY; m--){ let xArr = []; for(let i = state.minX; i <= state.maxX; i++){ xArr.push({ x: i, y: m, z: 0, typeId: defaultTile }); } map.push(xArr); } state.lttMap = map; state.mapName = this.getMapName(); }, /** * Generate a random map with the given size, mapID and mapName based on a seed. * @author Griefed */ generateRandomMap() { let defaultTile = "grass"; let map = []; const mapGenerator = new NoiseMap.MapGenerator(state.seed); state.minX = -Math.floor(state.mapSizeX/2); if(state.mapSizeX%2){ state.maxX = Math.floor(state.mapSizeX/2); }else{ state.maxX = Math.floor(state.mapSizeX/2)+1; } state.minY = -Math.floor(state.mapSizeY/2); if(state.mapSizeY%2){ state.maxY = Math.floor(state.mapSizeY/2); }else{ state.maxY = Math.floor(state.mapSizeY/2)+1; } const heightmap = mapGenerator.createMap(state.mapSizeX+2, state.mapSizeY+2, {type: 'perlit'}); heightmap.stepValues(5); for(let m = state.maxY; m >= state.minY; m--){ let xArr = []; for(let i = state.minX; i <= state.maxX; i++){ xArr.push({ x: i, y: m, z: 0, typeId: this.getTileTypeFromHeightmap(heightmap, i+(state.mapSizeX/2), m+(state.mapSizeY/2)) }); } map.push(xArr); } state.lttMap = map; state.mapName = this.getMapName(); }, /** * Get a file from a given heightmap and x/y coordinates. * @author Griefed * @param heightmap A heightmap object generated by {@link NoiseMap} * @param x The x coordinate of which to get the value * @param y The y coordinate of which to get the value * @returns {string} The value at position x and y. */ getTileTypeFromHeightmap(heightmap, x, y) { let value = Math.floor(heightmap.get(x, y)*100); switch(value) { case 100: return "mountain"; case 80: return "ice"; case 60: return "barren"; case 40: return "desert"; case 20: return "grass"; case 0: return "water"; default: return "grass"; } } }; export default { state, methods, seedGenerator };