Adding in discovery zone modifications
This commit is contained in:
parent
8746c23518
commit
2c1ff2473d
21 changed files with 423 additions and 58 deletions
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
[submodule "src/assets/server-grid-editor"]
|
||||||
|
path = src/assets/server-grid-editor
|
||||||
|
url = https://github.com/GrapeshotGames/ServerGridEditor.git
|
||||||
3
.idea/dictionaries/Tom.xml
generated
3
.idea/dictionaries/Tom.xml
generated
|
|
@ -4,6 +4,9 @@
|
||||||
<w>deparse</w>
|
<w>deparse</w>
|
||||||
<w>gameplay</w>
|
<w>gameplay</w>
|
||||||
<w>pegjs</w>
|
<w>pegjs</w>
|
||||||
|
<w>powerstones</w>
|
||||||
|
<w>sublevel</w>
|
||||||
|
<w>sublevels</w>
|
||||||
</words>
|
</words>
|
||||||
</dictionary>
|
</dictionary>
|
||||||
</component>
|
</component>
|
||||||
1
.idea/vcs.xml
generated
1
.idea/vcs.xml
generated
|
|
@ -2,5 +2,6 @@
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="VcsDirectoryMappings">
|
<component name="VcsDirectoryMappings">
|
||||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||||
|
<mapping directory="$PROJECT_DIR$/src/assets/server-grid-editor" vcs="Git" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
20
package-lock.json
generated
20
package-lock.json
generated
|
|
@ -1886,8 +1886,7 @@
|
||||||
"@types/geojson": {
|
"@types/geojson": {
|
||||||
"version": "7946.0.7",
|
"version": "7946.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.7.tgz",
|
||||||
"integrity": "sha512-wE2v81i4C4Ol09RtsWFAqg3BUitWbHSpSlIo+bNdsCJijO9sjme+zm+73ZMCa/qMC8UEERxzGbvmr1cffo2SiQ==",
|
"integrity": "sha512-wE2v81i4C4Ol09RtsWFAqg3BUitWbHSpSlIo+bNdsCJijO9sjme+zm+73ZMCa/qMC8UEERxzGbvmr1cffo2SiQ=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"@types/glob": {
|
"@types/glob": {
|
||||||
"version": "7.1.1",
|
"version": "7.1.1",
|
||||||
|
|
@ -1919,11 +1918,18 @@
|
||||||
"version": "1.5.7",
|
"version": "1.5.7",
|
||||||
"resolved": "https://registry.npmjs.org/@types/leaflet/-/leaflet-1.5.7.tgz",
|
"resolved": "https://registry.npmjs.org/@types/leaflet/-/leaflet-1.5.7.tgz",
|
||||||
"integrity": "sha512-FiPU4NQwH+jQ2wc3IjD7+9hgNZ95m4ry8qILO+eS6L4eUUVSXr+472+k4SRVEW+8j18QwqY7PFqudDQzfpRXTQ==",
|
"integrity": "sha512-FiPU4NQwH+jQ2wc3IjD7+9hgNZ95m4ry8qILO+eS6L4eUUVSXr+472+k4SRVEW+8j18QwqY7PFqudDQzfpRXTQ==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"@types/geojson": "*"
|
"@types/geojson": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@types/leaflet-imageoverlay-rotated": {
|
||||||
|
"version": "0.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/leaflet-imageoverlay-rotated/-/leaflet-imageoverlay-rotated-0.1.4.tgz",
|
||||||
|
"integrity": "sha512-b5Q2h1D4APy/hsYfqU1D1WGzsg7/jcxaezZk52R6V0VicqS9Lno72+ok0VNYTkdWmAWHhRFuwJOU1TldznYBqQ==",
|
||||||
|
"requires": {
|
||||||
|
"@types/leaflet": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@types/minimatch": {
|
"@types/minimatch": {
|
||||||
"version": "3.0.3",
|
"version": "3.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz",
|
||||||
|
|
@ -7340,6 +7346,14 @@
|
||||||
"resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.6.0.tgz",
|
||||||
"integrity": "sha512-CPkhyqWUKZKFJ6K8umN5/D2wrJ2+/8UIpXppY7QDnUZW5bZL5+SEI2J7GBpwh4LIupOKqbNSQXgqmrEJopHVNQ=="
|
"integrity": "sha512-CPkhyqWUKZKFJ6K8umN5/D2wrJ2+/8UIpXppY7QDnUZW5bZL5+SEI2J7GBpwh4LIupOKqbNSQXgqmrEJopHVNQ=="
|
||||||
},
|
},
|
||||||
|
"leaflet-imageoverlay-rotated": {
|
||||||
|
"version": "0.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/leaflet-imageoverlay-rotated/-/leaflet-imageoverlay-rotated-0.2.1.tgz",
|
||||||
|
"integrity": "sha512-8MsrIuW/aXI0EjDXgJSJJ67nqVNQJsP/glmND9g6yc6t+zQgdPUbTRHC65jSs/IBwzwyhggnDgDuydalcEX+ew==",
|
||||||
|
"requires": {
|
||||||
|
"leaflet": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"less": {
|
"less": {
|
||||||
"version": "3.9.0",
|
"version": "3.9.0",
|
||||||
"resolved": "https://registry.npmjs.org/less/-/less-3.9.0.tgz",
|
"resolved": "https://registry.npmjs.org/less/-/less-3.9.0.tgz",
|
||||||
|
|
|
||||||
|
|
@ -21,10 +21,12 @@
|
||||||
"@angular/router": "~8.2.11",
|
"@angular/router": "~8.2.11",
|
||||||
"@asymmetrik/ngx-leaflet": "^6.0.1",
|
"@asymmetrik/ngx-leaflet": "^6.0.1",
|
||||||
"@ng-bootstrap/ng-bootstrap": "^5.1.1",
|
"@ng-bootstrap/ng-bootstrap": "^5.1.1",
|
||||||
|
"@types/leaflet-imageoverlay-rotated": "^0.1.4",
|
||||||
"@types/pegjs": "^0.10.1",
|
"@types/pegjs": "^0.10.1",
|
||||||
"ace-builds": "^1.4.7",
|
"ace-builds": "^1.4.7",
|
||||||
"bootstrap": "^4.3.1",
|
"bootstrap": "^4.3.1",
|
||||||
"leaflet": "^1.6.0",
|
"leaflet": "^1.6.0",
|
||||||
|
"leaflet-imageoverlay-rotated": "^0.2.1",
|
||||||
"rxjs": "~6.4.0",
|
"rxjs": "~6.4.0",
|
||||||
"ts-pegjs": "^0.2.6",
|
"ts-pegjs": "^0.2.6",
|
||||||
"tslib": "^1.10.0",
|
"tslib": "^1.10.0",
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import { ServersComponent } from "./pages/config/servers/servers.component";
|
||||||
import { ServerComponent } from "./pages/config/servers/server/server.component";
|
import { ServerComponent } from "./pages/config/servers/server/server.component";
|
||||||
import { IslandInstanceComponent } from "./pages/config/servers/island-instance/island-instance.component";
|
import { IslandInstanceComponent } from "./pages/config/servers/island-instance/island-instance.component";
|
||||||
import { MapComponent } from "./pages/config/map/map.component";
|
import { MapComponent } from "./pages/config/map/map.component";
|
||||||
|
import { DiscoveryZoneComponent } from "./pages/config/servers/discovery-zone/discovery-zone.component";
|
||||||
|
|
||||||
|
|
||||||
const routes: Routes = [
|
const routes: Routes = [
|
||||||
|
|
@ -22,6 +23,7 @@ const routes: Routes = [
|
||||||
{path: 'servers', component: ServersComponent},
|
{path: 'servers', component: ServersComponent},
|
||||||
{path: 'server/:index', component: ServerComponent},
|
{path: 'server/:index', component: ServerComponent},
|
||||||
{path: 'server/:index/island/:islandIndex', component: IslandInstanceComponent},
|
{path: 'server/:index/island/:islandIndex', component: IslandInstanceComponent},
|
||||||
|
{path: 'server/:index/discovery/:discoIndex', component: DiscoveryZoneComponent},
|
||||||
{path: 'map', component: MapComponent}
|
{path: 'map', component: MapComponent}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ import { SelectObjectComponent } from './components/form/select-object/select-ob
|
||||||
import { IslandInstanceComponent } from './pages/config/servers/island-instance/island-instance.component';
|
import { IslandInstanceComponent } from './pages/config/servers/island-instance/island-instance.component';
|
||||||
import { LeafletModule } from "@asymmetrik/ngx-leaflet";
|
import { LeafletModule } from "@asymmetrik/ngx-leaflet";
|
||||||
import { MapComponent } from './pages/config/map/map.component';
|
import { MapComponent } from './pages/config/map/map.component';
|
||||||
|
import { DiscoveryZoneComponent } from './pages/config/servers/discovery-zone/discovery-zone.component';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
|
|
@ -45,7 +46,8 @@ import { MapComponent } from './pages/config/map/map.component';
|
||||||
SelectListComponent,
|
SelectListComponent,
|
||||||
SelectObjectComponent,
|
SelectObjectComponent,
|
||||||
IslandInstanceComponent,
|
IslandInstanceComponent,
|
||||||
MapComponent
|
MapComponent,
|
||||||
|
DiscoveryZoneComponent
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
BrowserModule,
|
BrowserModule,
|
||||||
|
|
|
||||||
34
src/app/models/atlasData/discovery-zone.model.ts
Normal file
34
src/app/models/atlasData/discovery-zone.model.ts
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
import { Deserialize } from "../util/deserialize.model";
|
||||||
|
|
||||||
|
export class DiscoveryZoneModel implements Deserialize {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
sizeX: number = 0;
|
||||||
|
sizeY: number = 0;
|
||||||
|
sizeZ: number = 0;
|
||||||
|
|
||||||
|
worldX: number = 0;
|
||||||
|
worldY: number = 0;
|
||||||
|
rotation: number = 0;
|
||||||
|
|
||||||
|
xp: number = 0;
|
||||||
|
|
||||||
|
allowSea: boolean = false;
|
||||||
|
explorerNoteIndex: number = 0;
|
||||||
|
|
||||||
|
bIsManuallyPlaced: boolean = false;
|
||||||
|
ManualVolumeName: string;
|
||||||
|
|
||||||
|
deserialize(input: any): this {
|
||||||
|
Object.assign(this, input);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
toJSON(): object {
|
||||||
|
let json = Object.assign({}, this);
|
||||||
|
// Key not shown at all if manually placed.
|
||||||
|
if (!json.bIsManuallyPlaced) delete json.ManualVolumeName;
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import { Deserialize } from "../util/deserialize.model";
|
import { Deserialize } from "../util/deserialize.model";
|
||||||
import { ServerSublevelModel } from "./serverSublevel.model";
|
import { ServerSublevelModel } from "./serverSublevel.model";
|
||||||
import { IslandInstanceModel } from "./island-instance.model";
|
import { IslandInstanceModel } from "./island-instance.model";
|
||||||
|
import { DiscoveryZoneModel } from "./discovery-zone.model";
|
||||||
|
|
||||||
export class ServerModel implements Deserialize {
|
export class ServerModel implements Deserialize {
|
||||||
// General Settings
|
// General Settings
|
||||||
|
|
@ -46,7 +47,7 @@ export class ServerModel implements Deserialize {
|
||||||
extraSublevels: string[];
|
extraSublevels: string[];
|
||||||
totalExtraSublevels: string[];
|
totalExtraSublevels: string[];
|
||||||
islandInstances: IslandInstanceModel[];
|
islandInstances: IslandInstanceModel[];
|
||||||
discoZones;
|
discoZones: DiscoveryZoneModel[];
|
||||||
spawnRegions;
|
spawnRegions;
|
||||||
|
|
||||||
// Dont render if default/empty
|
// Dont render if default/empty
|
||||||
|
|
@ -72,6 +73,7 @@ export class ServerModel implements Deserialize {
|
||||||
Object.assign(this, input);
|
Object.assign(this, input);
|
||||||
this.sublevels = this.sublevels.map(i => new ServerSublevelModel().deserialize(i));
|
this.sublevels = this.sublevels.map(i => new ServerSublevelModel().deserialize(i));
|
||||||
this.islandInstances = this.islandInstances.map(i => new IslandInstanceModel().deserialize(i));
|
this.islandInstances = this.islandInstances.map(i => new IslandInstanceModel().deserialize(i));
|
||||||
|
this.discoZones = this.discoZones.map(i => new DiscoveryZoneModel().deserialize(i));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
<button class="btn btn-primary btn-block" [routerLink]="['dbs']">DB Settings</button>
|
<button class="btn btn-primary btn-block" [routerLink]="['dbs']">DB Settings</button>
|
||||||
<button class="btn btn-primary btn-block" [routerLink]="['quests']">Quest Settings</button>
|
<button class="btn btn-primary btn-block" [routerLink]="['quests']">Quest Settings</button>
|
||||||
<button class="btn btn-primary btn-block" [routerLink]="['servers']">Server Settings</button>
|
<button class="btn btn-primary btn-block" [routerLink]="['servers']">Server Settings</button>
|
||||||
|
<button class="btn btn-primary btn-block" [routerLink]="['map']">Map</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-10"><router-outlet></router-outlet></div>
|
<div class="col-10"><router-outlet></router-outlet></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -1,9 +1,7 @@
|
||||||
<div style="height: 400px;"
|
<div style="height: 600px;"
|
||||||
leaflet
|
leaflet
|
||||||
[leafletOptions]="options"
|
[leafletOptions]="options">
|
||||||
[(leafletCenter)]="center"
|
<div *ngFor="let s of serverLayers" [leafletLayer]="s"></div>
|
||||||
[(leafletZoom)]="zoom">
|
<div *ngFor="let i of islandLayers" [leafletLayer]="i"></div>
|
||||||
<div *ngFor="let l of layers" [leafletLayer]="l"></div>
|
<div *ngFor="let d of discoveryLayers" [leafletLayer]="d"></div>
|
||||||
</div>
|
</div>
|
||||||
<p>Zoom: {{ zoom }}</p>
|
|
||||||
<p>Center lat: {{ center.lat }} Center long: {{ center.lng }}</p>
|
|
||||||
|
|
@ -1,8 +1,11 @@
|
||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { CRS, LatLng, latLng, LatLngBounds, latLngBounds, Rectangle, tileLayer } from "leaflet";
|
import { Circle, CRS, ImageOverlay, LatLng, LatLngBounds, Rectangle } from "leaflet";
|
||||||
import { Server } from "../../../server";
|
import { Server } from "../../../server";
|
||||||
|
import { IslandInstanceModel } from "../../../models/atlasData/island-instance.model";
|
||||||
|
import * as L from 'leaflet';
|
||||||
|
import 'leaflet-imageoverlay-rotated';
|
||||||
|
|
||||||
const SIZE_SCALE = 100_000;
|
const RADIAN_RATIO = Math.PI / 180;
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-map',
|
selector: 'app-map',
|
||||||
|
|
@ -13,16 +16,20 @@ export class MapComponent implements OnInit {
|
||||||
|
|
||||||
options = {
|
options = {
|
||||||
crs: CRS.Simple,
|
crs: CRS.Simple,
|
||||||
zoom: 0,
|
zoom: -16,
|
||||||
maxBounds: undefined,
|
maxBounds: undefined,
|
||||||
maxBoundsViscosity: 0.5,
|
maxBoundsViscosity: 0.5,
|
||||||
center: undefined,
|
center: undefined,
|
||||||
layers: []
|
layers: [],
|
||||||
|
minZoom: -16,
|
||||||
};
|
};
|
||||||
|
|
||||||
center: LatLng;
|
serverLayers = [];
|
||||||
zoom: number;
|
islandLayers = [];
|
||||||
layers = [];
|
discoveryLayers = [];
|
||||||
|
|
||||||
|
maxX: number;
|
||||||
|
maxY: number;
|
||||||
|
|
||||||
constructor(private server: Server) {
|
constructor(private server: Server) {
|
||||||
}
|
}
|
||||||
|
|
@ -30,28 +37,83 @@ export class MapComponent implements OnInit {
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
// all in Y X format. Also, upside down! (0,0 is bottom left instead of top left)
|
// all in Y X format. Also, upside down! (0,0 is bottom left instead of top left)
|
||||||
// Also, due to insanely large sizes, divide by 100_000
|
// Also, due to insanely large sizes, divide by 100_000
|
||||||
const maxX = (this.server.serverGrid.gridSize * this.server.serverGrid.totalGridsX) / SIZE_SCALE;
|
this.maxX = this.server.serverGrid.gridSize * this.server.serverGrid.totalGridsX;
|
||||||
const maxY = (this.server.serverGrid.gridSize * this.server.serverGrid.totalGridsY) / SIZE_SCALE;
|
this.maxY = this.server.serverGrid.gridSize * this.server.serverGrid.totalGridsY;
|
||||||
const northEast = new LatLng(0, maxX);
|
const northEast = new LatLng(0, this.maxX);
|
||||||
const southWest = new LatLng(maxY, 0);
|
const southWest = new LatLng(this.maxY, 0);
|
||||||
this.options.maxBounds = new LatLngBounds(southWest, northEast);
|
this.options.maxBounds = new LatLngBounds(southWest, northEast);
|
||||||
this.options.center = new LatLng(0, 0);
|
this.options.center = new LatLng(0, 0);
|
||||||
this.options.layers[0] = new Rectangle(this.options.maxBounds, {
|
this.options.layers.push(new ImageOverlay('./assets/server-grid-editor/WaterTiles/instinctworld-autoscaling.png', this.options.maxBounds));
|
||||||
color: '#3c3c00',
|
|
||||||
weight: 5,
|
|
||||||
fillColor: 'lightblue',
|
|
||||||
fill: true
|
|
||||||
});
|
|
||||||
|
|
||||||
this.server.serverGrid.servers.forEach(i => {
|
this.server.serverGrid.servers.forEach(s => {
|
||||||
const servMinX = (this.server.serverGrid.gridSize * i.gridX) / SIZE_SCALE;
|
// Server Layer
|
||||||
const servMaxX = servMinX + (this.server.serverGrid.gridSize / SIZE_SCALE);
|
const servMinX = this.server.serverGrid.gridSize * s.gridX;
|
||||||
const servMinY = (this.server.serverGrid.gridSize * i.gridY) / SIZE_SCALE;
|
const servMaxX = servMinX + this.server.serverGrid.gridSize;
|
||||||
const servMaxY = servMinY + (this.server.serverGrid.gridSize / SIZE_SCALE);
|
const servMinY = this.server.serverGrid.gridSize * s.gridY;
|
||||||
|
const servMaxY = servMinY + this.server.serverGrid.gridSize;
|
||||||
const servNE = new LatLng(servMinY, servMaxX);
|
const servNE = new LatLng(servMinY, servMaxX);
|
||||||
const servSW = new LatLng(servMaxY, servMinX);
|
const servSW = new LatLng(servMaxY, servMinX);
|
||||||
const servBounds = new LatLngBounds(servSW, servNE);
|
const servBounds = new LatLngBounds(servSW, servNE);
|
||||||
this.layers.push(new Rectangle(servBounds,{color: 'pink', weight: 5}));
|
this.serverLayers.push(new Rectangle(servBounds,{color: 'black', weight: 1}));
|
||||||
|
|
||||||
|
s.islandInstances.forEach(i => {
|
||||||
|
const imgUrl = './assets/server-grid-editor/' + this.server.islands[i.name].imagePath.substring(2);
|
||||||
|
const islandLocation = this.islandToImageRotation(i);
|
||||||
|
this.islandLayers.push(L.imageOverlay.rotated(imgUrl, islandLocation[0], islandLocation[1], islandLocation[2]));
|
||||||
|
});
|
||||||
|
|
||||||
|
s.discoZones.forEach(d => {
|
||||||
|
if (d.ManualVolumeName !== undefined) return;
|
||||||
|
const imgUrl = './assets/server-grid-editor/Resources/discoZoneBox.png';
|
||||||
|
const discoLocation = this.discoveryZoneToImageRotation(d);
|
||||||
|
this.discoveryLayers.push(L.imageOverlay.rotated(imgUrl, discoLocation[0], discoLocation[1], discoLocation[2]));
|
||||||
|
});
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gridCoordinateToMapLatLng(gridX: number, gridY: number): LatLng {
|
||||||
|
// Need to invert gridY for the Latitude.
|
||||||
|
const newY = this.maxY - gridY;
|
||||||
|
return new LatLng(newY, gridX);
|
||||||
|
}
|
||||||
|
|
||||||
|
islandToImageRotation(island: IslandInstanceModel): LatLng[] {
|
||||||
|
return this.gridCoordinateToImageRotation(island.worldX, island.worldY, island.rotation, island.islandWidth, island.islandHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
discoveryZoneToImageRotation(disco): LatLng[] {
|
||||||
|
return this.gridCoordinateToImageRotation(disco.worldX, disco.worldY, disco.rotation, disco.sizeX, disco.sizeY);
|
||||||
|
}
|
||||||
|
|
||||||
|
gridCoordinateToImageRotation(worldX, worldY, rotation, width, height): LatLng[] {
|
||||||
|
const halfWidth = width / 2;
|
||||||
|
const halfHeight = height / 2;
|
||||||
|
|
||||||
|
const radians = (rotation + 90) * RADIAN_RATIO;
|
||||||
|
|
||||||
|
const cosR = Math.cos(radians);
|
||||||
|
const sinR = Math.sin(radians);
|
||||||
|
|
||||||
|
// https://gamedev.stackexchange.com/questions/86755/how-to-calculate-corner-positions-marks-of-a-rotated-tilted-rectangle
|
||||||
|
// Rotate any point around
|
||||||
|
// Nx = x * cos(a) - y * sin(a)
|
||||||
|
// Ny = x * sin(a) + y * cos(a)
|
||||||
|
|
||||||
|
// REMEMBER everything is upside down
|
||||||
|
// Top Left -1, 1
|
||||||
|
const topLeftX = worldX + (-halfWidth * cosR) - (halfHeight * sinR);
|
||||||
|
const topLeftY = worldY + (-halfWidth * sinR) + (halfHeight * cosR);
|
||||||
|
// Bottom Left -1, -1 BUT mirrored for some reason so 1, 1
|
||||||
|
const botLeftX = worldX + (halfWidth * cosR) - (halfHeight * sinR);
|
||||||
|
const botLeftY = worldY + (halfWidth * sinR) + (halfHeight * cosR);
|
||||||
|
// Top Right 1, 1 BUT mirrored for some reason so -1, -1
|
||||||
|
const topRightX = worldX + (-halfWidth * cosR) - (-halfHeight * sinR);
|
||||||
|
const topRightY = worldY + (-halfWidth * sinR) + (-halfHeight * cosR);
|
||||||
|
|
||||||
|
return [
|
||||||
|
this.gridCoordinateToMapLatLng(topLeftX, topLeftY),
|
||||||
|
this.gridCoordinateToMapLatLng(topRightX, topRightY),
|
||||||
|
this.gridCoordinateToMapLatLng(botLeftX, botLeftY)
|
||||||
|
];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,55 @@
|
||||||
|
<div class="mt-3">
|
||||||
|
<h2>{{ discovery.name }}
|
||||||
|
<button class="btn btn-primary btn-sm" [routerLink]="['/config', 'server', cellIndex]">Back to Cell</button>
|
||||||
|
</h2>
|
||||||
|
<p>{{ discovery.sizeX }} by {{ discovery.sizeY }} by {{ discovery.sizeZ }}</p>
|
||||||
|
<ngb-accordion>
|
||||||
|
<ngb-panel title="General Settings">
|
||||||
|
<ng-template ngbPanelContent>
|
||||||
|
<app-text id="name" label="Name" [(text)]="discovery.name"></app-text>
|
||||||
|
<app-number id="worldX" label="World X" [(number)]="discovery.worldX"></app-number>
|
||||||
|
<app-number id="worldY" label="World Y" [(number)]="discovery.worldY"></app-number>
|
||||||
|
<app-number id="rotation" label="Rotation" [(number)]="discovery.rotation" step="0.000001"
|
||||||
|
min="{{ minRot }}" max="{{ maxRot }}"></app-number>
|
||||||
|
<h4>Zone Size</h4>
|
||||||
|
<app-number id="sizeX" label="Size X" [(number)]="discovery.sizeX"></app-number>
|
||||||
|
<app-number id="sizeY" label="Size Y" [(number)]="discovery.sizeY"></app-number>
|
||||||
|
<app-number id="sizeZ" label="Size Z" [(number)]="discovery.sizeZ"
|
||||||
|
help="If the discovery zone has any size, this is normally 40,000"></app-number>
|
||||||
|
</ng-template>
|
||||||
|
</ngb-panel>
|
||||||
|
<ngb-panel title="Discovery Settings">
|
||||||
|
<ng-template ngbPanelContent>
|
||||||
|
<app-number id="xp" label="XP" [(number)]="discovery.xp"
|
||||||
|
help="XP Gained for discovering this zone. Note this also alters the max XP you can gain by levelling"></app-number>
|
||||||
|
<app-checkbox id="allowSea" label="Allow Sea Discovery" [(checkbox)]="discovery.allowSea"
|
||||||
|
help="May not do what you think - Always false on Official Server"></app-checkbox>
|
||||||
|
<app-select-object id="explorerNoteIndex" label="Explorer Note" [optionObject]="explorerNotes"
|
||||||
|
[option]="discovery.explorerNoteIndex" (optionChange)="setExplorerNote($event)"
|
||||||
|
help="Opens a page in the players Discoveries menu on unlocking"></app-select-object>
|
||||||
|
</ng-template>
|
||||||
|
</ngb-panel>
|
||||||
|
<ngb-panel title="Manual Volumes">
|
||||||
|
<ng-template ngbPanelContent>
|
||||||
|
<p>Manual Volumes are either specific points on a map, or a particular 'discovery' available in a
|
||||||
|
cell. For example, certain Forests and Pools on an island are discovery zones in the official
|
||||||
|
server. Also the Powerstone locations are a discovery point, however the names for these aren't tied
|
||||||
|
to a specific island.</p>
|
||||||
|
<p>When a player enters the area of the 'Volume' or otherwise triggers it (in the case of Powerstones),
|
||||||
|
the discovery zone will be unlocked. This happens whether the player is on land, gliding, or
|
||||||
|
swimming. This only happens with these Manual Volume Discoveries - Normal discovery zones require
|
||||||
|
you to set foot on the area.</p>
|
||||||
|
<p>If the Zone size (under general settings) is set to 0 for XYZ, then no shimmer will show around the
|
||||||
|
discovery. Any other size will show a shimmer of that set size, and location, in game.</p>
|
||||||
|
<p>Note as well, the location of a Manual Volume discovery doesnt really matter, however it defaults to
|
||||||
|
the center of the cell.</p>
|
||||||
|
<app-checkbox id="bIsManuallyPlaced" label="Enable Manual Volume"
|
||||||
|
[(checkbox)]="discovery.bIsManuallyPlaced"></app-checkbox>
|
||||||
|
<app-select-list id="ManualVolumeName" label="Manual Volume Name" *ngIf="discovery.bIsManuallyPlaced"
|
||||||
|
[optionList]="discoveryVolumeNameOptions"
|
||||||
|
[(option)]="discovery.ManualVolumeName"></app-select-list>
|
||||||
|
<button class="btn btn-warning" (click)="setLocationCenterOfCell()">Set Center to Cell Center</button>
|
||||||
|
</ng-template>
|
||||||
|
</ngb-panel>
|
||||||
|
</ngb-accordion>
|
||||||
|
</div>
|
||||||
|
|
@ -0,0 +1,78 @@
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { ActivatedRoute } from "@angular/router";
|
||||||
|
import { Server } from "../../../../server";
|
||||||
|
import { ServerModel } from "../../../../models/atlasData/server.model";
|
||||||
|
import { DiscoveryZoneModel } from "../../../../models/atlasData/discovery-zone.model";
|
||||||
|
import * as ExplorerNotes from '../../../../../data/explorer-notes.json';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-discovery-zone',
|
||||||
|
templateUrl: './discovery-zone.component.html'
|
||||||
|
})
|
||||||
|
export class DiscoveryZoneComponent implements OnInit {
|
||||||
|
private cell: ServerModel;
|
||||||
|
private cellIndex;
|
||||||
|
private discovery: DiscoveryZoneModel;
|
||||||
|
private discoIndex;
|
||||||
|
|
||||||
|
private minX: number;
|
||||||
|
private maxX: number;
|
||||||
|
private minY: number;
|
||||||
|
private maxY: number;
|
||||||
|
private minRot: number = 0;
|
||||||
|
private maxRot: number = 360;
|
||||||
|
|
||||||
|
private explorerNotes;
|
||||||
|
|
||||||
|
private discoveryVolumeNameOptions: string[] = [
|
||||||
|
"PowerStone1",
|
||||||
|
"PowerStone2",
|
||||||
|
"PowerStone3",
|
||||||
|
"PowerStone4",
|
||||||
|
"PowerStone5",
|
||||||
|
"PowerStone6",
|
||||||
|
"PowerStone7",
|
||||||
|
"PowerStone8",
|
||||||
|
"PowerStone9",
|
||||||
|
"SecondaryStone1",
|
||||||
|
"SecondaryStone2",
|
||||||
|
"SecondaryStone3",
|
||||||
|
"SecondaryStone4",
|
||||||
|
"SecondaryStone5",
|
||||||
|
"SecondaryStone6",
|
||||||
|
"SecondaryStone7",
|
||||||
|
"SecondaryStone8",
|
||||||
|
"SecondaryStone9",
|
||||||
|
];
|
||||||
|
|
||||||
|
constructor(private server: Server, private route: ActivatedRoute) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.cellIndex = this.route.snapshot.paramMap.get('index');
|
||||||
|
this.discoIndex = this.route.snapshot.paramMap.get('discoIndex');
|
||||||
|
this.cell = this.server.serverGrid.servers[this.cellIndex];
|
||||||
|
this.discovery = this.cell.discoZones[this.discoIndex];
|
||||||
|
this.minX = this.cell.gridX * this.server.serverGrid.gridSize;
|
||||||
|
this.maxX = this.minX + this.server.serverGrid.gridSize;
|
||||||
|
this.minY = this.cell.gridY * this.server.serverGrid.gridSize;
|
||||||
|
this.maxY = this.minY + this.server.serverGrid.gridSize;
|
||||||
|
this.explorerNotes = (ExplorerNotes as any).default;
|
||||||
|
|
||||||
|
this.cell.islandInstances.forEach(i => {
|
||||||
|
const islandData = this.server.islands[i.name];
|
||||||
|
if (islandData.discoveryVolumeNames === undefined ) return;
|
||||||
|
this.discoveryVolumeNameOptions = this.discoveryVolumeNameOptions.concat(islandData.discoveryVolumeNames);
|
||||||
|
});
|
||||||
|
console.log(this.discoveryVolumeNameOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
private setExplorerNote(option: string) {
|
||||||
|
this.discovery.explorerNoteIndex = parseInt(option);
|
||||||
|
}
|
||||||
|
|
||||||
|
private setLocationCenterOfCell() {
|
||||||
|
this.discovery.worldX = this.minX + ( this.server.serverGrid.gridSize / 2 );
|
||||||
|
this.discovery.worldY = this.minY + ( this.server.serverGrid.gridSize / 2 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -34,6 +34,7 @@ export class IslandInstanceComponent implements OnInit {
|
||||||
this.minY = this.cell.gridY * this.server.serverGrid.gridSize;
|
this.minY = this.cell.gridY * this.server.serverGrid.gridSize;
|
||||||
this.maxY = this.minY + this.server.serverGrid.gridSize;
|
this.maxY = this.minY + this.server.serverGrid.gridSize;
|
||||||
}
|
}
|
||||||
|
// TODO Need to update subLevels in parent Cell when updating X and Y...
|
||||||
|
|
||||||
// Issue with text arrays and editing jumps on each change.
|
// Issue with text arrays and editing jumps on each change.
|
||||||
trackByFn(index: any, item: any) {
|
trackByFn(index: any, item: any) {
|
||||||
|
|
|
||||||
|
|
@ -50,11 +50,55 @@
|
||||||
<ngb-panel title="Island Settings">
|
<ngb-panel title="Island Settings">
|
||||||
<ng-template ngbPanelContent>
|
<ng-template ngbPanelContent>
|
||||||
<p><em>Note that Sublevel settings are sorted in the background</em></p>
|
<p><em>Note that Sublevel settings are sorted in the background</em></p>
|
||||||
<div *ngFor="let island of cell.islandInstances; let i = index">
|
|
||||||
<h4>Island Instance {{ i }} - ID {{ island.id }} <button class="btn btn-sm btn-primary" [routerLink]="['island', i]">Edit</button></h4>
|
<table class="table table-hover">
|
||||||
<app-select-object id="{{ i }}-island-name" label="Island Model" [optionObject]="islandOptions"
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Name & Model</th>
|
||||||
|
<th></th>
|
||||||
|
<th></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<app-select-object id="new-island" label="New Island" [optionObject]="islandOptions" [withEmptyOption]="true"
|
||||||
|
[(option)]="newIslandName"></app-select-object>
|
||||||
|
</td>
|
||||||
|
<td><button class="btn btn-warning" (click)="addNewIsland()" [disabled]="!newIslandName">Add</button></td>
|
||||||
|
</tr>
|
||||||
|
<tr *ngFor="let island of cell.islandInstances; let i = index">
|
||||||
|
<td>
|
||||||
|
<app-select-object id="{{ i }}-island-name" label="{{ island.name }}" [optionObject]="islandOptions"
|
||||||
[option]="island.name" (optionChange)="changeIslandModel(i, $event)"></app-select-object>
|
[option]="island.name" (optionChange)="changeIslandModel(i, $event)"></app-select-object>
|
||||||
</div>
|
</td>
|
||||||
|
<td><button class="btn btn-primary" [routerLink]="['island', i]">Edit</button></td>
|
||||||
|
<td><button class="btn btn-danger" (click)="deleteIsland(i)">Delete</button></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</ng-template>
|
||||||
|
</ngb-panel>
|
||||||
|
<ngb-panel title="Discovery Zone Settings">
|
||||||
|
<ng-template ngbPanelContent>
|
||||||
|
<table class="table table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Discovery Type</th>
|
||||||
|
<th><button class="btn btn-sm btn-warning" (click)="addNewDiscovery()">Add</button></th>
|
||||||
|
<th></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr *ngFor="let disco of cell.discoZones; let i = index">
|
||||||
|
<th>{{ disco.name }}</th>
|
||||||
|
<td>{{ disco.bIsManuallyPlaced ? "Location" : "Island" }}</td>
|
||||||
|
<td><button class="btn btn-sm btn-primary" [routerLink]="['discovery', i]">Edit</button></td>
|
||||||
|
<td><button class="btn btn-sm btn-danger" (click)="deleteDiscovery(i)">Delete</button></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</ngb-panel>
|
</ngb-panel>
|
||||||
</ngb-accordion>
|
</ngb-accordion>
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import { ServerModel } from "../../../../models/atlasData/server.model";
|
||||||
import { IslandDataModel } from "../../../../../data/models/island-data.model";
|
import { IslandDataModel } from "../../../../../data/models/island-data.model";
|
||||||
import { IslandInstanceModel } from "../../../../models/atlasData/island-instance.model";
|
import { IslandInstanceModel } from "../../../../models/atlasData/island-instance.model";
|
||||||
import { ServerSublevelModel } from "../../../../models/atlasData/serverSublevel.model";
|
import { ServerSublevelModel } from "../../../../models/atlasData/serverSublevel.model";
|
||||||
|
import { DiscoveryZoneModel } from "../../../../models/atlasData/discovery-zone.model";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-server',
|
selector: 'app-server',
|
||||||
|
|
@ -14,6 +15,7 @@ export class ServerComponent implements OnInit {
|
||||||
private cell: ServerModel;
|
private cell: ServerModel;
|
||||||
private templateOptions: string[];
|
private templateOptions: string[];
|
||||||
private islandOptions: object = {};
|
private islandOptions: object = {};
|
||||||
|
private newIslandName: string;
|
||||||
|
|
||||||
constructor(private server: Server, private route: ActivatedRoute) {
|
constructor(private server: Server, private route: ActivatedRoute) {
|
||||||
}
|
}
|
||||||
|
|
@ -27,38 +29,38 @@ export class ServerComponent implements OnInit {
|
||||||
|
|
||||||
private changeIslandModel(index: number, name: string) {
|
private changeIslandModel(index: number, name: string) {
|
||||||
let oldIsland = this.cell.islandInstances[index];
|
let oldIsland = this.cell.islandInstances[index];
|
||||||
const newIslandData = this.server.islands[name];
|
let newIsland = IslandInstanceModel.fromIslandData(this.server.islands[name]);
|
||||||
const oldIslandData = this.server.islands[oldIsland.name];
|
newIsland.id = this.server.serverGrid.getNextId();
|
||||||
|
|
||||||
let newIsland = IslandInstanceModel.fromIslandData(newIslandData);
|
|
||||||
|
|
||||||
// keep X, Y and Rotation the same
|
// keep X, Y and Rotation the same
|
||||||
newIsland.worldX = oldIsland.worldX;
|
newIsland.worldX = oldIsland.worldX;
|
||||||
newIsland.worldY = oldIsland.worldY;
|
newIsland.worldY = oldIsland.worldY;
|
||||||
newIsland.rotation = oldIsland.rotation;
|
newIsland.rotation = oldIsland.rotation;
|
||||||
|
|
||||||
// Remove old Sublevels
|
this.removeSublevelsForIsland(oldIsland);
|
||||||
oldIslandData.sublevelNames.forEach(i => {
|
this.addSublevelsForIsland(newIsland);
|
||||||
|
this.cell.islandInstances[index] = newIsland;
|
||||||
|
this.updateExtraSublevels();
|
||||||
|
}
|
||||||
|
|
||||||
|
private removeSublevelsForIsland(island: IslandInstanceModel) {
|
||||||
|
const islandData = this.server.islands[island.name];
|
||||||
|
islandData.sublevelNames.forEach(i => {
|
||||||
const j = this.cell.sublevels.findIndex(sublevel => sublevel.name === i);
|
const j = this.cell.sublevels.findIndex(sublevel => sublevel.name === i);
|
||||||
if (j > -1) {
|
if (j > -1) {
|
||||||
this.cell.sublevels.splice(j, 1);
|
this.cell.sublevels.splice(j, 1);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Get new unique ID
|
private addSublevelsForIsland(island: IslandInstanceModel) {
|
||||||
newIsland.id = this.server.serverGrid.getNextId();
|
const islandData = this.server.islands[island.name];
|
||||||
|
islandData.sublevelNames.forEach(i => {
|
||||||
// Add new Sublevels
|
|
||||||
newIslandData.sublevelNames.forEach(i => {
|
|
||||||
let newSublevel = new ServerSublevelModel();
|
let newSublevel = new ServerSublevelModel();
|
||||||
newSublevel.name = i;
|
newSublevel.name = i;
|
||||||
newSublevel.setupFromIsland(newIsland, newIslandData, this.cell, this.server.serverGrid);
|
newSublevel.setupFromIsland(island, islandData, this.cell, this.server.serverGrid);
|
||||||
this.cell.sublevels.push(newSublevel);
|
this.cell.sublevels.push(newSublevel);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.cell.islandInstances[index] = newIsland;
|
|
||||||
|
|
||||||
this.updateExtraSublevels();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private updateExtraSublevels() {
|
private updateExtraSublevels() {
|
||||||
|
|
@ -75,4 +77,30 @@ export class ServerComponent implements OnInit {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addNewIsland() {
|
||||||
|
const newIslandData = this.server.islands[this.newIslandName];
|
||||||
|
let newIsland = IslandInstanceModel.fromIslandData(newIslandData);
|
||||||
|
newIsland.id = this.server.serverGrid.getNextId();
|
||||||
|
this.addSublevelsForIsland(newIsland);
|
||||||
|
this.cell.islandInstances.push(newIsland);
|
||||||
|
this.updateExtraSublevels();
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteIsland(index: number) {
|
||||||
|
let oldIsland = this.cell.islandInstances[index];
|
||||||
|
this.removeSublevelsForIsland(oldIsland);
|
||||||
|
this.cell.islandInstances.splice(index, 1);
|
||||||
|
this.updateExtraSublevels();
|
||||||
|
}
|
||||||
|
|
||||||
|
addNewDiscovery() {
|
||||||
|
let newDisco = new DiscoveryZoneModel();
|
||||||
|
newDisco.id = this.server.serverGrid.getNextId();
|
||||||
|
this.cell.discoZones.push(newDisco);
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteDiscovery(index: number) {
|
||||||
|
this.cell.discoZones.splice(index, 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
1
src/assets/server-grid-editor
Submodule
1
src/assets/server-grid-editor
Submodule
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit cffac3d0dff6391908bde5d2180efb6bbc76a101
|
||||||
30
src/data/explorer-notes.json
Normal file
30
src/data/explorer-notes.json
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
{
|
||||||
|
"0": "None Set",
|
||||||
|
"1": "The Ladle of Life",
|
||||||
|
"2": "Gorgon's Perch",
|
||||||
|
"3": "The Fish's Mouth",
|
||||||
|
"4": "The Slender Gate",
|
||||||
|
"5": "Widowmaker's Claw",
|
||||||
|
"6": "Faceplant!",
|
||||||
|
"8": "Horseshoe of Eternity",
|
||||||
|
"9": "The Rainless Reef",
|
||||||
|
"11": "Hawthorn's Trap",
|
||||||
|
"12": "Giant's Crown",
|
||||||
|
"13": "Eagle's Eye",
|
||||||
|
"14": "Twin Tales",
|
||||||
|
"15": "Unknown Temple",
|
||||||
|
"16": "The Prancing Lady",
|
||||||
|
"17": "The Great and Angry Warrior",
|
||||||
|
"18": "Shattered Castle",
|
||||||
|
"19": "Eye of the Wolf",
|
||||||
|
"20": "The Demon of the Deep",
|
||||||
|
"21": "PowerStone 1",
|
||||||
|
"22": "PowerStone 2",
|
||||||
|
"23": "PowerStone 3",
|
||||||
|
"24": "PowerStone 4",
|
||||||
|
"25": "PowerStone 5",
|
||||||
|
"26": "PowerStone 6",
|
||||||
|
"27": "PowerStone 7",
|
||||||
|
"28": "PowerStone 8",
|
||||||
|
"29": "PowerStone 9"
|
||||||
|
}
|
||||||
|
|
@ -127,7 +127,7 @@
|
||||||
"name": "Mnt_B_WF",
|
"name": "Mnt_B_WF",
|
||||||
"x": 306000.0,
|
"x": 306000.0,
|
||||||
"y": 306000.0,
|
"y": 306000.0,
|
||||||
"imagePath": "./IslandImages/Mnt_B_WF_img.png",
|
"imagePath": "./IslandImages/MNT_B_WF_img.png",
|
||||||
"landscapeMaterialOverride": 5,
|
"landscapeMaterialOverride": 5,
|
||||||
"sublevelNames": [
|
"sublevelNames": [
|
||||||
"Mnt_B",
|
"Mnt_B",
|
||||||
|
|
@ -12472,6 +12472,9 @@
|
||||||
"Mnt_H_Marine_Cold_Near",
|
"Mnt_H_Marine_Cold_Near",
|
||||||
"Mnt_H_PO"
|
"Mnt_H_PO"
|
||||||
],
|
],
|
||||||
|
"discoveryVolumeNames": [
|
||||||
|
"Mnt_H_Near_08B-BarricadeofIce"
|
||||||
|
],
|
||||||
"spawnerOverrides": {},
|
"spawnerOverrides": {},
|
||||||
"extraSublevels": [
|
"extraSublevels": [
|
||||||
"MasterIBL_CaveEntrance_Polar",
|
"MasterIBL_CaveEntrance_Polar",
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ export class IslandDataModel implements Deserialize {
|
||||||
imagePath: string;
|
imagePath: string;
|
||||||
landscapeMaterialOverride: number;
|
landscapeMaterialOverride: number;
|
||||||
sublevelNames: string[];
|
sublevelNames: string[];
|
||||||
|
discoveryVolumeNames: string[];
|
||||||
spawnerOverrides: object;
|
spawnerOverrides: object;
|
||||||
extraSublevels: string[];
|
extraSublevels: string[];
|
||||||
treasureMapSpawnPoints: string[];
|
treasureMapSpawnPoints: string[];
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue