1
0
Fork 0
spacetac/src/ui/map/UniverseMapView.ts

356 lines
13 KiB
TypeScript
Raw Normal View History

/// <reference path="../BaseView.ts"/>
2017-09-24 22:23:22 +00:00
module TK.SpaceTac.UI {
/**
* Interactive map of the universe
*/
export class UniverseMapView extends BaseView {
// Displayed universe
2017-06-05 17:53:27 +00:00
universe = new Universe()
// Interacting player
2017-06-05 17:53:27 +00:00
player = new Player()
// Interaction enabled or not
interactive = true
2017-03-15 21:40:19 +00:00
// Layers
2018-05-15 14:57:45 +00:00
layer_universe!: UIContainer
layer_overlay!: UIContainer
2017-03-15 21:40:19 +00:00
2017-01-26 00:01:31 +00:00
// Star systems
2017-06-05 17:53:27 +00:00
starsystems: StarSystemDisplay[] = []
// Links between stars
2018-05-15 14:57:45 +00:00
starlinks_group!: UIContainer
starlinks: UIGraphics[] = []
2015-03-24 00:00:00 +00:00
2017-01-30 00:40:33 +00:00
// Fleets
2018-01-31 18:19:50 +00:00
player_fleet!: FleetDisplay
2017-01-30 00:40:33 +00:00
2017-07-11 22:28:45 +00:00
// Markers
2018-01-31 18:19:50 +00:00
current_location!: CurrentLocationMarker
mission_markers!: MissionLocationMarker
2017-03-15 23:45:52 +00:00
2017-06-05 22:05:34 +00:00
// Actions for selected location
2018-01-31 18:19:50 +00:00
actions!: MapLocationMenu
// Active missions
2018-01-31 18:19:50 +00:00
missions!: ActiveMissionsDisplay
conversation!: MissionConversationDisplay
2017-02-28 00:07:37 +00:00
// Character sheet
2018-01-31 18:19:50 +00:00
character_sheet!: CharacterSheet
2017-02-28 00:07:37 +00:00
2017-01-26 00:01:31 +00:00
// Zoom level
2017-06-05 17:53:27 +00:00
zoom = 0
2018-05-15 14:57:45 +00:00
zoom_in!: UIButton
zoom_out!: UIButton
// Options button
2018-05-15 14:57:45 +00:00
button_options!: UIButton
/**
* Init the view, binding it to a universe
*/
2018-05-15 14:57:45 +00:00
init(data: { universe: Universe, player: Player }) {
super.init(data);
2018-05-15 14:57:45 +00:00
this.universe = data.universe;
this.player = data.player;
}
/**
* Create view graphics
*/
create() {
super.create();
2017-10-15 17:54:37 +00:00
let builder = new UIBuilder(this);
2017-10-11 20:58:08 +00:00
this.layer_universe = this.getLayer("universe");
this.layer_overlay = this.getLayer("overlay");
2018-05-15 14:57:45 +00:00
this.starlinks_group = builder.in(this.layer_universe).container("starlinks");
this.starlinks = [];
2017-01-26 23:01:04 +00:00
this.starlinks = this.universe.starlinks.map(starlink => {
let loc1 = starlink.first.getWarpLocationTo(starlink.second);
let loc2 = starlink.second.getWarpLocationTo(starlink.first);
2018-05-15 14:57:45 +00:00
let result = builder.in(this.starlinks_group).graphics("starlink");
2017-03-09 17:11:00 +00:00
if (loc1 && loc2) {
2018-06-07 09:53:37 +00:00
result.addLine({
start: { x: starlink.first.x + loc1.x, y: starlink.first.y + loc1.y },
end: { x: starlink.second.x + loc2.x, y: starlink.second.y + loc2.y },
color: 0x6cc7ce,
width: 0.01,
});
2017-03-09 17:11:00 +00:00
}
2018-05-15 14:57:45 +00:00
result.setDataEnabled();
result.data.set("link", starlink);
2017-01-26 23:01:04 +00:00
return result;
});
2017-01-30 00:40:33 +00:00
2017-01-26 00:01:31 +00:00
this.starsystems = this.universe.stars.map(star => new StarSystemDisplay(this, star));
2017-03-15 21:40:19 +00:00
this.starsystems.forEach(starsystem => this.layer_universe.add(starsystem));
this.player_fleet = new FleetDisplay(this, this.player.fleet, this.universe, this.current_location);
2017-03-15 21:40:19 +00:00
this.layer_universe.add(this.player_fleet);
2017-01-30 00:40:33 +00:00
2017-03-15 23:45:52 +00:00
this.current_location = new CurrentLocationMarker(this, this.player_fleet);
this.layer_universe.add(this.current_location);
2017-07-11 22:28:45 +00:00
this.mission_markers = new MissionLocationMarker(this, this.layer_universe);
2018-05-15 14:57:45 +00:00
this.actions = new MapLocationMenu(this, this.layer_overlay, 30, 30);
2017-06-05 22:05:34 +00:00
2017-07-11 22:28:45 +00:00
this.missions = new ActiveMissionsDisplay(this, this.player.missions, this.mission_markers);
2018-06-06 20:36:38 +00:00
this.missions.moveTo(this.layer_overlay, 20, 720);
builder.in(this.layer_overlay, builder => {
this.zoom_in = builder.button("map-zoom-in", 1787, 54, () => this.setZoom(this.zoom + 1), "Zoom in");
this.zoom_out = builder.button("map-zoom-out", 1787, 840, () => this.setZoom(this.zoom - 1), "Zoom out");
this.button_options = builder.button("map-options", 1628, 0, () => this.showOptions(), "Game options");
});
this.character_sheet = new CharacterSheet(this, CharacterSheetMode.EDITION);
2018-05-15 14:57:45 +00:00
this.character_sheet.moveToLayer(this.layer_overlay);
2015-03-25 00:00:00 +00:00
2018-06-06 17:09:31 +00:00
this.conversation = new MissionConversationDisplay(builder.in(this.layer_overlay));
2017-06-29 17:25:38 +00:00
2018-05-15 14:57:45 +00:00
this.audio.startMusic("spring-thaw");
// Inputs
this.inputs.bind(" ", "Conversation step", () => this.conversation.forward());
2017-06-29 17:25:38 +00:00
this.inputs.bind("Escape", "Skip conversation", () => this.conversation.skipConversation());
this.inputs.bindCheat("r", "Reveal whole map", () => this.revealAll());
2018-04-16 18:12:26 +00:00
this.inputs.bindCheat("u", "Level up", () => {
this.player.fleet.ships.forEach(ship => ship.level.forceLevelUp());
this.refresh();
});
2017-06-29 17:25:38 +00:00
this.inputs.bindCheat("n", "Next story step", () => {
if (this.player.missions.main) {
this.player.missions.main.current_part.forceComplete();
this.backToRouter();
}
});
2017-03-15 21:40:19 +00:00
2017-10-15 17:54:37 +00:00
this.setZoom(2, 0);
2018-05-15 14:57:45 +00:00
// Add a background
//builder.image("map-background");
// Trigger an auto-save any time we go back to the map
this.autoSave();
}
/**
* Leaving the view, unbind and destroy
*/
shutdown() {
2017-03-09 17:11:00 +00:00
this.universe = new Universe();
this.player = new Player();
super.shutdown();
}
/**
* Refresh the view
*/
refresh() {
2017-09-11 23:29:15 +00:00
if (this.player.getBattle()) {
this.backToRouter();
} else {
this.setZoom(this.zoom);
this.character_sheet.refresh();
2017-09-11 23:29:15 +00:00
this.player_fleet.updateShipSprites();
}
}
/**
* Check active missions.
*
* When any mission status changes, a refresh is triggered.
*/
checkMissionsUpdate() {
if (this.missions.checkUpdate()) {
this.refresh();
}
}
/**
* Update info on all star systems (fog of war, available data...)
*/
2017-06-05 22:05:34 +00:00
updateInfo(current_star: Star | null, interactive = true) {
2017-03-15 23:45:52 +00:00
this.current_location.setZoom(this.zoom);
2017-07-11 22:28:45 +00:00
if (current_star) {
this.mission_markers.setZoom(this.zoom, current_star);
}
2017-03-15 23:45:52 +00:00
this.starlinks.forEach(linkgraphics => {
2018-05-15 14:57:45 +00:00
let link = linkgraphics.data.get("link");
if (link instanceof StarLink) {
2018-06-06 18:21:27 +00:00
linkgraphics.setVisible(this.player.hasVisitedSystem(link.first) || this.player.hasVisitedSystem(link.second));
2018-05-15 14:57:45 +00:00
}
})
2017-03-09 23:21:34 +00:00
this.starsystems.forEach(system => system.updateInfo(this.zoom, system.starsystem == current_star));
this.actions.setFromLocation(this.session.getLocation(), this);
2017-06-05 22:05:34 +00:00
this.missions.checkUpdate();
this.conversation.updateFromMissions(this.player.missions, () => this.checkMissionsUpdate());
2017-06-05 22:05:34 +00:00
if (interactive) {
this.setInteractionEnabled(true);
}
2017-01-30 00:40:33 +00:00
}
/**
* Reveal the whole map (this is a cheat)
*/
revealAll(): void {
2017-01-29 18:34:38 +00:00
this.universe.stars.forEach(star => {
star.locations.forEach(location => {
this.player.fleet.setVisited(location);
2017-01-29 18:34:38 +00:00
});
});
this.refresh();
2017-01-26 00:01:31 +00:00
}
/**
* Set the camera to center on a target, and to display a given span in height
*/
2018-05-15 14:57:45 +00:00
setCamera(x: number, y: number, span: number, duration = 500, easing = "Cubic.easeInOut") {
2017-01-26 00:01:31 +00:00
let scale = 1000 / span;
2017-10-15 17:54:37 +00:00
let dest_x = 920 - x * scale;
let dest_y = 540 - y * scale;
if (duration) {
2018-05-15 14:57:45 +00:00
this.animations.addAnimation(this.layer_universe, { x: dest_x, y: dest_y, scaleX: scale, scaleY: scale }, duration, easing);
2017-10-15 17:54:37 +00:00
} else {
2018-05-15 14:57:45 +00:00
this.layer_universe.setPosition(dest_x, dest_y);
this.layer_universe.setScale(scale);
2017-10-15 17:54:37 +00:00
}
2017-01-26 00:01:31 +00:00
}
/**
* Set the camera to include all direct-jump accessible stars
*/
2017-10-15 17:54:37 +00:00
setCameraOnAccessible(star: Star, duration: number) {
2017-07-19 23:22:18 +00:00
let accessible = star.getNeighbors().concat([star]);
let xmin = min(accessible.map(star => star.x));
let xmax = max(accessible.map(star => star.x));
let ymin = min(accessible.map(star => star.y));
let ymax = max(accessible.map(star => star.y));
let dmax = Math.max(xmax - xmin, ymax - ymin);
2017-10-15 17:54:37 +00:00
this.setCamera(xmin + (xmax - xmin) * 0.5, ymin + (ymax - ymin) * 0.5, dmax * 1.2, duration);
}
2017-06-05 17:53:27 +00:00
/**
* Set the alpha value for all links
*/
2017-10-15 17:54:37 +00:00
setLinksAlpha(alpha: number, duration = 500) {
if (duration) {
2018-06-06 18:21:27 +00:00
this.animations.addAnimation(this.starlinks_group, { alpha: alpha }, duration, "Cubic.easeInOut");
2017-10-15 17:54:37 +00:00
} else {
2018-06-06 18:21:27 +00:00
this.starlinks_group.setAlpha(alpha);
2017-10-15 17:54:37 +00:00
}
2017-06-05 17:53:27 +00:00
}
/**
* Set the current zoom level (0, 1 or 2)
*/
2017-10-15 17:54:37 +00:00
setZoom(level: number, duration = 500) {
let current_star = this.session.getLocation().star;
2017-03-09 17:11:00 +00:00
if (!current_star || level <= 0) {
2017-10-15 17:54:37 +00:00
this.setCamera(0, 0, this.universe.radius * 2, duration);
this.setLinksAlpha(1, duration);
2017-01-26 00:01:31 +00:00
this.zoom = 0;
} else if (level == 1) {
2017-10-15 17:54:37 +00:00
this.setCameraOnAccessible(current_star, duration);
this.setLinksAlpha(0.6, duration);
2017-01-26 00:01:31 +00:00
this.zoom = 1;
} else {
this.setCamera(current_star.x - current_star.radius * 0.3, current_star.y, current_star.radius * 2, duration);
2017-10-15 17:54:37 +00:00
this.setLinksAlpha(0.2, duration);
2017-01-26 00:01:31 +00:00
this.zoom = 2;
}
2017-03-09 23:21:34 +00:00
this.updateInfo(current_star);
}
/**
* Do the jump animation to another system
2017-06-05 22:05:34 +00:00
*
* This will only work if current location is a warp
*/
2017-06-05 22:05:34 +00:00
doJump(): void {
let location = this.session.getLocation();
if (this.interactive && location && location.type == StarLocationType.WARP && location.jump_dest) {
2017-06-05 22:05:34 +00:00
let dest_location = location.jump_dest;
let dest_star = dest_location.star;
this.player_fleet.moveToLocation(dest_location, 3, duration => {
this.player_fleet.showJumpEffect(location.getDistanceTo(dest_location), duration);
this.timer.schedule(duration * 0.3, () => this.updateInfo(dest_star, false));
this.timer.schedule(duration * 0.7, () => this.player_fleet.showJumpEffect());
2018-06-06 18:21:27 +00:00
this.setCamera(dest_star.x, dest_star.y, dest_star.radius * 2, duration, "Cubic.easeOut");
2017-06-05 22:05:34 +00:00
}, () => {
this.setInteractionEnabled(true);
2017-07-10 22:50:38 +00:00
this.refresh();
});
2017-06-05 22:05:34 +00:00
this.setInteractionEnabled(false);
}
}
2017-06-05 22:05:34 +00:00
/**
* Open the dockyard interface
*
* This will only work if current location has a dockyard
*/
openShop(): void {
let location = this.session.getLocation();
if (this.interactive && location && location.shop) {
this.character_sheet.show(this.player.fleet.ships[0]);
2017-06-05 22:05:34 +00:00
}
}
/**
* Open the missions dialog (job posting)
*
* This will only work if current location has a dockyard
*/
openMissions(): void {
let location = this.session.getLocation();
if (this.interactive && location && location.shop) {
new MissionsDialog(this, location.shop, this.player, () => this.checkMissionsUpdate());
}
}
2017-06-05 22:05:34 +00:00
/**
* Move the fleet to another location
*/
moveToLocation(dest: StarLocation): void {
if (this.interactive && !dest.is(this.player.fleet.location)) {
2017-06-05 22:05:34 +00:00
this.setInteractionEnabled(false);
this.player_fleet.moveToLocation(dest, 1, null, () => {
this.setInteractionEnabled(true);
this.refresh();
});
2017-06-05 22:05:34 +00:00
}
}
/**
* Set the interactive state
*/
setInteractionEnabled(enabled: boolean) {
this.interactive = enabled && !this.session.spectator;
2018-05-15 14:57:45 +00:00
this.animations.setVisible(this.actions.container, enabled && this.zoom == 2, 300);
this.missions.setVisible(enabled && this.zoom == 2, 300);
2017-06-05 22:05:34 +00:00
this.animations.setVisible(this.zoom_in, enabled && this.zoom < 2, 300);
this.animations.setVisible(this.zoom_out, enabled && this.zoom > 0, 300);
this.animations.setVisible(this.button_options, enabled, 300);
2018-05-15 14:57:45 +00:00
//this.animations.setVisible(this.character_sheet, enabled, 300);
2017-06-05 22:05:34 +00:00
}
}
}