Adding in discovery zone modifications

This commit is contained in:
Tom Bloor 2020-01-13 21:43:36 +00:00
parent 8746c23518
commit 2c1ff2473d
Signed by: TBSliver
GPG key ID: 4657C7EBE42CC5CC
21 changed files with 423 additions and 58 deletions

3
.gitmodules vendored Normal file
View file

@ -0,0 +1,3 @@
[submodule "src/assets/server-grid-editor"]
path = src/assets/server-grid-editor
url = https://github.com/GrapeshotGames/ServerGridEditor.git

View file

@ -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
View file

@ -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
View file

@ -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",

View file

@ -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",

View file

@ -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}
] ]
} }

View file

@ -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,

View 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;
}
}

View file

@ -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;
} }
} }

View file

@ -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>

View file

@ -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>

View file

@ -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)
];
}
} }

View file

@ -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>

View file

@ -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 );
}
}

View file

@ -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) {

View file

@ -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>
[option]="island.name" (optionChange)="changeIslandModel(i, $event)"></app-select-object> <tr>
</div> <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>
</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>

View file

@ -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);
}
} }

@ -0,0 +1 @@
Subproject commit cffac3d0dff6391908bde5d2180efb6bbc76a101

View 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"
}

View file

@ -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",

View file

@ -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[];