// ==UserScript==
// @name Planets.nu - Ship List Plugin
// @namespace vgap.plugins.shipList
// @version 1.0.4
// @date 2020-06-22
// @author Space Pirate Harlock
// @description Planets.NU add-on to automatically keep track of other players' fleets.
// @homepage https://planets.nu/
// @license GPL
// @include https://planets.nu/*
// @include https://play.planets.nu/*
// @include https://test.planets.nu/*
// @include https://mobile.planets.nu/*
// @include https://planets.nu/*
// @resource userscript https://greasyfork.org/en/scripts/405323-planets-nu-enemy-ship-list-plugin
// ==/UserScript==
/*
Changelog:
1.0.4 Feature: Notes saved from ship list
Feature: Ship history saved to ship notes
Bug fix: Ghost ships made showShips crash
Bug fix: Not visible ships from allies weren't deleted
1.0.3 Feature: Added toggle for compact tables
Feature: Added hull name to ship scan
Feature: Added turns ago to ship scan
Feature: Added min-max mass to ship scan
1.0.2 Bug fix: Loading stale notes after finishing time machine loop
1.0.1 Feature: UI improvements for Firefox and mobile
Bug fix: Notes weren't read in correctly (vgap.nowTurn)
1.0.0 Initial release
*/
/*
Known Issues:
-
Roadmap:
- Overview table showing fleet strength of opposing player
- Add info about towing ships and ships being towed
- Adding info about ships intercepted the previous turn
- Adding minimum/maximum mass seen
- Make it possible to add ships without knowing their exact ID
- Tooltip over ship showing notes
- Parse reports for mine hit damage > 100% (150 for Lizzies) and delete ship
*/
function script(vgap) { // script for injection
if (vgap.version < 4.0) {
console.log("Ship List: [3000] NU version < 4.0. Plugin Disabled.");
return;
}
const version = '1.0.4';
console.log('Ship List v' + version);
/** @namespace vgap.plugin.shipList */
const shipList =
{
/** Hooks called by VGAP */
/** Called when redrawing the map */
draw: function () {
const plugin = vgap.plugins.shipList;
try {
plugin.drawShips();
plugin.shipsDrawn = [];
} catch (e) {
console.log('[5003] (draw)');
if (plugin.settings.debugMode) {
console.log(e.name + ' ' + e.message);
console.trace();
}
}
},
/** Called when building the dashboard */
loaddashboard: function () {
const plugin = vgap.plugins.shipList;
try {
let menu = document.getElementById("DashboardMenu").childNodes[2]; //insert after starships
$("<li>Ship List »</li>").tclick(function () {
plugin.showShips();
}).appendTo(menu);
} catch (e) {
console.log('[5004] (loaddashboard)');
if (plugin.settings.debugMode) {
console.log(e.name + ' ' + e.message);
console.trace();
}
}
},
/**
* Called after loading the first turn to create the map
* @namespace plugin.playerToggles
* @namespace vgap.accountsettings.myshipto
*/
loadmap: function () {
const plugin = vgap.plugins.shipList;
try {
const numButtons = plugin.playerToggles.length + 1;
vgap.map.addMapTool('Ship List', 'shipListTool', plugin.toggleMapTool);
// load colors from diplomacy and configuration settings
for (let i = vgap.players.length - 1; i >= 0; i--) {
let color = plugin.playerColors[i + 1];
let id = vgap.players[i].id;
if (id == vgap.player.id) {
if (vgap.accountsettings.myshipto) color = vgap.accountsettings.myshipto;
} else {
let relation = vgap.getRelation(id);
if (relation != null && relation.color && relation.color != "") color = '#' + relation.color;
}
plugin.playerColors[i + 1] = color;
}
let css = [
'<style type="text/css">',
'#MessageInbox, #ShipPane {margin:0px 0px 50px 0px}',
'#playerToggles {position:absolute;right:40px;top:0px;}',
'#playerToggles.hori {display:flex;}',
'#playerToggles .mapbutton {relative;margin:0px 0px 10px 10px;}',
'#playerToggles .mapbutton::before {font-family:"Arial" !important;font-weight:600}',
'#playerToggles .hideToggles::before {font-family:"Font Awesome 5 Free" !important;font-weight:900;content:"\\f105"}',
'#playerToggles .player0::before{content:"All";color:#fff}#playerToggles .player0.active::before{content:"All";color:#ff0}',
'.shipListTool::before {content:"\\f135"}',
'#ShipTable, #FreighterTable, #PlayerSelectionTable, #ConfigTable {width:100%;border-spacing:0;margin-bottom:20px}',
'#ShipTable th, #FreighterTable th {white-space:nowrap;padding:10px 5px}',
'#ShipTable td, #FreighterTable td {white-space:nowrap;padding:10px 5px}',
'#ShipTable.compact td, #FreighterTable.compact td {padding:3px 3px}',
'#ShipTable th, #FreighterTable th, .BasicFlatButton:hover {background-color:#666}',
'#ShipTable tr:hover, #FreighterTable tr:hover, #ConfigTable tr:hover {background-color:#333;cursor:pointer}',
'#SettingsTable{border-spacing:0}#SettingsTable tr:hover{background-color:#111}',
'#WarningPane .BasicFlatButton, #ConfigTable .BasicFlatButton, #newShipForm .BasicFlatButton {float:left;margin:0px 20px 0px 0px;display:inline-block;width:80px;text-align:center}',
'#newShipForm{padding:0px}#newShipForm td,#newShipForm th{text-align:center}',
'#newShipForm label, .ConfigForm label {display:inline-block; cursor:pointer}',
'#newShipForm input, #newShipForm select, .ConfigForm input, .ConfigForm select {-webkit-appearance:auto;font-size:13px;height:16px;border-radius:8px;padding:8px 15px;width:-webkit-fill-available;text-align:center;border:none;background-color:#111 !important;color:#fff !important}',
'#newShipForm input[type=checkbox], .ConfigForm input[type=checkbox] {height:16px;width:16px;cursor:pointer}',
'#hullImg {width:90px;height:90px;margin:0px 5px;background-color:#000}',
'#ShipEditPane, #PlayerSelectionPane, #WarningPane {display:table;background-image:url(https://mobile.planets.nu/img/game/dashboardbg.png);border-radius:10px;width:calc(100% - 32px);margin-bottom:10px;padding:10px}',
'#WarningTable {display:inline-block;width:calc(100% - 20px)}',
'#ShipRows .BasicFlatButton {border-radius:6px;padding:2px 15px;margin:3px}',
'#ShipRows form, #FreighterRows form {padding:0px 20px}',
'.EnemyItem .lval, .AllyItem .lval, .MyItem .lval {font-size:11px !important;color:#ccc !important;line-height:15px !important}',
'.ItemSelection.ShipSeen img {top:60px}',
'.warning{color:#f90}.center{text-align:center}.capitalize {text-transform:capitalize}',
'.noteIcon::before {content:"\\f15c";font-family:"Font Awesome 5 Free";display:inline-block;width:20px;font-weight:900;color:#00ffff;-webkit-font-smoothing:antialiased;text-align:center;}',
'.noteIcon.down::before{content:"\\f0d8"}.noteRow{display:none}',
'.heading::before {color: #339999;content: "\\f14e";}',
'.mass::before {color: #333399;content: "\\f5cd";}',
'textarea.note {margin:0 0 0 5px;width:75%;height:120px;background-color:#333;border:solid 2px #000;color:#fff}',
'.closeIcon {float:right;}',
'.closeIcon::before {content:"\\f00d";font-family:"Font Awesome 5 Free";display:inline-block;width:16px;font-weight:900;color:#00ffff;-webkit-font-smoothing:antialiased;text-align:center;}',
'section.popup: {max-width:max-content}',
'form.modal {padding:0px}',
'form.modal .table {margin:0px}',
'form.modal .td {border:0;padding:10px 15px 10px 0px}',
'form.modal label {white-space:nowrap;margin:0}'
];
for (let i = plugin.playerToggles.length - 1; i > 0; i--) {
css.push(
'.player' + i + '::before {content:"' + i + '";color:#fff}',
'.player' + i + '.active::before {content:"' + i + '";color:' + plugin.playerColors[i] + '}',
'.shipRow' + i + ' {background-color:' + colorToRGBA(plugin.playerColors[i], 0.5) + '}',
'.shipRow' + i + '.alt {color:' + plugin.playerColors[i] + ';background-color:transparent}'
);
}
if (plugin.settings.addShipHistory) {
css.push('.GoodTextNote {font: .9em "Roboto Mono", "Lucida Console", monospace;white-space:pre}');
}
// SimpTip CSS - (c) Arash Manteghi under MIT licence
css.push("[data-tooltip]{position:relative;display:inline-block;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}[data-tooltip]:before,[data-tooltip]:after{position:absolute;visibility:hidden;opacity:0;z-index:999999;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-transform:translate3d(0, 0, 0);-moz-transform:translate3d(0, 0, 0);transform:translate3d(0, 0, 0)}[data-tooltip]:before{content:'';border:6px solid transparent}[data-tooltip]:after{height:22px;padding:11px 11px 0 11px;font-size:13px;line-height:11px;content:attr(data-tooltip);white-space:nowrap}[data-tooltip].simptip-position-top:before{border-top-color:#323232}[data-tooltip].simptip-position-top:after{background-color:#323232;color:#ecf0f1}[data-tooltip].simptip-position-bottom:before{border-bottom-color:#323232}[data-tooltip].simptip-position-bottom:after{background-color:#323232;color:#ecf0f1}[data-tooltip].simptip-position-left:before{border-left-color:#323232}[data-tooltip].simptip-position-left:after{background-color:#323232;color:#ecf0f1}[data-tooltip].simptip-position-right:before{border-right-color:#323232}[data-tooltip].simptip-position-right:after{background-color:#323232;color:#ecf0f1}[data-tooltip].simptip-position-top.half-arrow:before{border-right:7px solid #323232}[data-tooltip].simptip-position-bottom.half-arrow:before{border-right:7px solid #323232}[data-tooltip]:hover,[data-tooltip]:focus{background-color:transparent}[data-tooltip]:hover:before,[data-tooltip]:hover:after,[data-tooltip]:focus:before,[data-tooltip]:focus:after{opacity:1;visibility:visible}.simptip-position-right:before,.simptip-position-left:before,.simptip-position-right:after,.simptip-position-left:after{bottom:50%}.simptip-position-right:before,.simptip-position-left:before{margin-bottom:-5px}.simptip-position-right:after,.simptip-position-left:after{margin-bottom:-14.66667px}.half-arrow.simptip-position-right:before,.half-arrow.simptip-position-left:before{bottom:16px;border-style:none;border-top:7px solid transparent}.simptip-multiline.simptip-position-right:before,.simptip-multiline.simptip-position-left:before,.simptip-multiline.simptip-position-right:after,.simptip-multiline.simptip-position-left:after{-webkit-transform:translateY(50%);-moz-transform:translateY(50%);-ms-transform:translateY(50%);-o-transform:translateY(50%);transform:translateY(50%);-webkit-filter:blur(0px);filter:blur(0px);margin-bottom:0}.simptip-multiline.simptip-position-right:before,.simptip-multiline.simptip-position-left:before{margin-bottom:0}.simptip-multiline.half-arrow.simptip-position-right:before,.simptip-multiline.half-arrow.simptip-position-left:before{margin-bottom:-2px}.simptip-position-right:before,.simptip-position-right:after{left:100%}.simptip-position-right:before{margin-left:-2px}.simptip-position-right:after{margin-left:10px}.simptip-position-right.simptip-movable:before{margin-left:-10px}.simptip-position-right.simptip-movable:after{margin-left:2px}.simptip-position-right.simptip-movable:hover:before,.simptip-position-right.simptip-movable:hover:after{-webkit-transform:translateX(10px);-moz-transform:translateX(10px);-ms-transform:translateX(10px);-o-transform:translateX(10px);transform:translateX(10px)}.simptip-position-right.simptip-movable.half-arrow:before{margin-left:-5px}.simptip-position-right.simptip-movable.simptip-multiline:hover:before,.simptip-position-right.simptip-movable.simptip-multiline:hover:after{-webkit-transform:translate(10px, 50%);-moz-transform:translate(10px, 50%);-ms-transform:translate(10px, 50%);-o-transform:translate(10px, 50%);transform:translate(10px, 50%)}.simptip-position-right.half-arrow:before{margin-left:3px;border-right:7px solid #323232}.simptip-position-left:before,.simptip-position-left:after{right:100%}.simptip-position-left:before{margin-right:-2px}.simptip-position-left:after{margin-right:10px}.simptip-position-left.simptip-movable:before{margin-right:-10px}.simptip-position-left.simptip-movable:after{margin-right:2px}.simptip-position-left.simptip-movable:hover:before,.simptip-position-left.simptip-movable:hover:after{-webkit-transform:translateX(-10px);-moz-transform:translateX(-10px);-ms-transform:translateX(-10px);-o-transform:translateX(-10px);transform:translateX(-10px)}.simptip-position-left.simptip-movable.half-arrow:before{margin-right:-5px}.simptip-position-left.simptip-movable.simptip-multiline:hover:before,.simptip-position-left.simptip-movable.simptip-multiline:hover:after{-webkit-transform:translate(-10px, 50%);-moz-transform:translate(-10px, 50%);-ms-transform:translate(-10px, 50%);-o-transform:translate(-10px, 50%);transform:translate(-10px, 50%)}.simptip-position-left.half-arrow:before{margin-right:3px;border-left:7px solid #323232}.simptip-position-bottom:before,.simptip-position-top:before,.simptip-position-bottom:after,.simptip-position-top:after{left:50%;-webkit-transform:translateX(-50%);-moz-transform:translateX(-50%);-ms-transform:translateX(-50%);-o-transform:translateX(-50%);transform:translateX(-50%)}.simptip-position-bottom:after,.simptip-position-top:after{width:auto}.half-arrow.simptip-position-bottom:before,.half-arrow.simptip-position-top:before{border-style:none;border-right:7px solid #323232}.simptip-position-bottom:before,.simptip-position-bottom:after{top:100%}.simptip-position-bottom:before{margin-top:-5px}.simptip-position-bottom:after{margin-top:7px}.simptip-position-bottom:hover:before,.simptip-position-bottom:hover:after{-webkit-transform:translate(-50%, 0);-moz-transform:translate(-50%, 0);-ms-transform:translate(-50%, 0);-o-transform:translate(-50%, 0);transform:translate(-50%, 0)}.simptip-position-bottom.simptip-movable:before{margin-top:-15px}.simptip-position-bottom.simptip-movable:after{margin-top:-3px}.simptip-position-bottom.simptip-movable:hover:before,.simptip-position-bottom.simptip-movable:hover:after{-webkit-transform:translate(-50%, 10px);-moz-transform:translate(-50%, 10px);-ms-transform:translate(-50%, 10px);-o-transform:translate(-50%, 10px);transform:translate(-50%, 10px)}.simptip-position-bottom.simptip-movable.half-arrow:before{margin-top:-10px}.simptip-position-bottom.half-arrow:before{margin-top:0;border-top:7px solid transparent}.simptip-position-top:before,.simptip-position-top:after{bottom:100%}.simptip-position-top:before{margin-bottom:-5px}.simptip-position-top:after{margin-bottom:7px}.simptip-position-top:hover:before,.simptip-position-top:hover:after{-webkit-transform:translate(-50%, 0px);-moz-transform:translate(-50%, 0px);-ms-transform:translate(-50%, 0px);-o-transform:translate(-50%, 0px);transform:translate(-50%, 0px)}.simptip-position-top.simptip-movable:before{margin-bottom:-15px}.simptip-position-top.simptip-movable:after{margin-bottom:-3px}.simptip-position-top.simptip-movable:hover:before,.simptip-position-top.simptip-movable:hover:after{-webkit-transform:translate(-50%, -10px);-moz-transform:translate(-50%, -10px);-ms-transform:translate(-50%, -10px);-o-transform:translate(-50%, -10px);transform:translate(-50%, -10px)}.simptip-position-top.simptip-movable.half-arrow:before{margin-bottom:-10px}.simptip-position-top.half-arrow:before{margin-bottom:0;border-bottom:7px solid transparent}.simptip-movable:before,.simptip-movable:after{-webkit-transition:all 0.1s linear;-moz-transition:all 0.1s linear;-o-transition:all 0.1s linear;-ms-transition:all 0.1s linear;transition:all 0.1s linear}.simptip-smooth:after{-webkit-border-radius:4px;border-radius:4px}.simptip-fade:before,.simptip-fade:after{-webkit-transition:opacity 0.2s linear,visibility 0.2s linear;-moz-transition:opacity 0.2s linear,visibility 0.2s linear;-o-transition:opacity 0.2s linear,visibility 0.2s linear;-ms-transition:opacity 0.2s linear,visibility 0.2s linear;transition:opacity 0.2s linear,visibility 0.2s linear}.simptip-multiline:after{height:auto;width:150px;padding:11px;line-height:19px;white-space:normal;text-align:left}.simptip-success.simptip-position-top:before{border-top-color:#62c462}.simptip-success.simptip-position-top:after{background-color:#62c462;color:#ecf0f1}.simptip-success.simptip-position-bottom:before{border-bottom-color:#62c462}.simptip-success.simptip-position-bottom:after{background-color:#62c462;color:#ecf0f1}.simptip-success.simptip-position-left:before{border-left-color:#62c462}.simptip-success.simptip-position-left:after{background-color:#62c462;color:#ecf0f1}.simptip-success.simptip-position-right:before{border-right-color:#62c462}.simptip-success.simptip-position-right:after{background-color:#62c462;color:#ecf0f1}.simptip-success.simptip-position-top.half-arrow:before{border-right:7px solid #62c462}.simptip-success.simptip-position-bottom.half-arrow:before{border-right:7px solid #62c462}.simptip-info.simptip-position-top:before{border-top-color:#5bc0de}.simptip-info.simptip-position-top:after{background-color:#5bc0de;color:#ecf0f1}.simptip-info.simptip-position-bottom:before{border-bottom-color:#5bc0de}.simptip-info.simptip-position-bottom:after{background-color:#5bc0de;color:#ecf0f1}.simptip-info.simptip-position-left:before{border-left-color:#5bc0de}.simptip-info.simptip-position-left:after{background-color:#5bc0de;color:#ecf0f1}.simptip-info.simptip-position-right:before{border-right-color:#5bc0de}.simptip-info.simptip-position-right:after{background-color:#5bc0de;color:#ecf0f1}.simptip-info.simptip-position-top.half-arrow:before{border-right:7px solid #5bc0de}.simptip-info.simptip-position-bottom.half-arrow:before{border-right:7px solid #5bc0de}.simptip-danger.simptip-position-top:before{border-top-color:#e74c3c}.simptip-danger.simptip-position-top:after{background-color:#e74c3c;color:#ecf0f1}.simptip-danger.simptip-position-bottom:before{border-bottom-color:#e74c3c}.simptip-danger.simptip-position-bottom:after{background-color:#e74c3c;color:#ecf0f1}.simptip-danger.simptip-position-left:before{border-left-color:#e74c3c}.simptip-danger.simptip-position-left:after{background-color:#e74c3c;color:#ecf0f1}.simptip-danger.simptip-position-right:before{border-right-color:#e74c3c}.simptip-danger.simptip-position-right:after{background-color:#e74c3c;color:#ecf0f1}.simptip-danger.simptip-position-top.half-arrow:before{border-right:7px solid #e74c3c}.simptip-danger.simptip-position-bottom.half-arrow:before{border-right:7px solid #e74c3c}.simptip-warning.simptip-position-top:before{border-top-color:#e67e22}.simptip-warning.simptip-position-top:after{background-color:#e67e22;color:#ecf0f1}.simptip-warning.simptip-position-bottom:before{border-bottom-color:#e67e22}.simptip-warning.simptip-position-bottom:after{background-color:#e67e22;color:#ecf0f1}.simptip-warning.simptip-position-left:before{border-left-color:#e67e22}.simptip-warning.simptip-position-left:after{background-color:#e67e22;color:#ecf0f1}.simptip-warning.simptip-position-right:before{border-right-color:#e67e22}.simptip-warning.simptip-position-right:after{background-color:#e67e22;color:#ecf0f1}.simptip-warning.simptip-position-top.half-arrow:before{border-right:7px solid #e67e22}.simptip-warning.simptip-position-bottom.half-arrow:before{border-right:7px solid #e67e22}");
css.push('</style>');
$(css.join('')).appendTo($('head:first'));
console.log('Ship List: [1001] (loadmap) T' + vgap.game.turn + '.');
} catch (e) {
console.log('Ship List: [5001] (loadmap)');
if (plugin.settings.debugMode) {
console.log(e.name + ' ' + e.message);
console.trace();
}
}
},
/** Called when loading a turn (current turn or time machine) */
processload: function () {
const plugin = vgap.plugins.shipList;
try {
// https://greasyfork.org/en/scripts/6685-planets-nu-plugin-toolkit/code
plugin.noteType = -parseInt(plugin.pluginName.replace(/[_\W]/g, ''), 36) % 2147483648,
plugin.storagePath = plugin.storagePrefix + vgap.gameId + '.' + vgap.player.id + '.';
plugin.playerName = vgap.player.username;
plugin.gameName = vgap.game.name;
plugin.raceName = (vgap.getRace(vgap.player.raceid)).shortname;
for (let i = 0; i <= vgap.players.length; i++) {
plugin.playerToggles[i] = false;
}
console.log('Ship List: [1000] (processload) T' + vgap.game.turn + '.');
//console.log('vgap.game.turn '+vgap.game.turn);
//console.log('vgap.settings.turn '+vgap.settings.turn);
//console.log('this.doLoop '+plugin.doLoop);
if (plugin.doReset) {
plugin.doReset = false;
plugin.ships = [];
plugin.firstTurn = vgap.game.turn;
plugin.lastTurn = vgap.game.turn - 1;
} else {
plugin.load();
// disable looping here instead of in processLoadHistory - doesn't get called on current turn
// don't use vgap.nowTurn - hasn't been set at this point
if (plugin.doLoop && !vgap.inHistory && vgap.game.turn == vgap.settings.turn) {
plugin.doLoop = false;
}
}
plugin.updateShips();
} catch (e) {
console.log('Ship List: [5000] (processload)');
if (plugin.settings.debugMode) {
console.log(e.name + ' ' + e.message);
console.trace();
}
}
},
/** Called when viewing the home screen of the dashboard */
showsummary: function () {
const plugin = vgap.plugins.shipList;
try {
let ships = plugin.ships;
let shipCount = 0;
plugin.maxShipId = vgap.settings.shiplimit;
for (let i = plugin.ships.length - 1; i >= 0; i--) {
if (ships[i].id > plugin.maxShipId) plugin.maxShipId = ships[i].id;
if (ships[i].ownerid == vgap.player.id) continue;
shipCount++;
}
$([
'<span><div class="iconholder">',
'<img src="https://planets.nu/_library/2013/7/enemy_ships.png"/>',
'</div>', shipCount, ' Enemy Ships</span>',
].join(''))
.click(function () {
plugin.showShips(1);
})
.insertBefore($('#TurnSummary').find(':nth-child(5)'))
;
console.log('Ship List: [1002] (showsummary)');
} catch (e) {
console.log('Ship List: [5002] (showsummary)');
if (plugin.settings.debugMode) {
console.log(e.name + ' ' + e.message);
console.trace();
}
}
},
/** loadplanet: Called when selecting a planet */
/** loadstarbase: Called when selecting a planet */
/** loadship: Called when selecting a ship */
/** showdashboard: Called when switching to dashboard */
/** showmap: Called when switching to starmap */
/**
* VARIABLES
*/
// views
playerId: 1,
playerToggles: [],
togglesShown: false,
drawRadius: 10,
view: 1,
// internal
doImport: false,
doLoop: false,
doReset: false,
editMode: false,
enabled: false,
importPrefix: 'EnemyShipListPlugin.',
maxShipId: 0,
playerColors: ["#ffff00", "#0000ff", "#00ff00", "#ff0000", "#ffff00", "#ff00ff", "#0000ff", "#ff9900", "#00ff99", "#9900ff", "#cccc00", "#00cccc", "#cc00cc", "#ff9999", "#99ff99", "#9999ff", "#cc0044", "#44cc00", "#0044cc", "#999900", "#009999", "#990099", "#ee3300", "#00ee33", "#3300ee", "#ee0033", "#33ee00", "#0033ee", "#bb4444", "#44bb44", "#4444bb"],
pluginName: "Ship List",
noteType: -1,
shipsDrawn: [],
shortEngineNames: ['?', 'SD1', 'SD2', 'SD3', 'SSD4', 'ND5', 'HND6', 'QD7', 'HD8', 'TW'],
shortBeamNames: ['?', 'Las', 'X-Ray', 'Pla', 'Bla', 'Posi', 'Dis', 'HB', 'PH', 'HD', 'HP'],
shortTorpNames: ['?', 'Mk1', 'Prot', 'Mk2', 'GaB', 'Mk3', 'Mk4', 'Mk5', 'Mk6', 'Mk7', 'Mk8', 'QT'],
storagePath: '',
storagePrefix: 'ShipList.',
// serialized
firstTurn: 0,
gameName: "",
lastTurn: 0,
playerName: "",
raceName: "",
ships: [],
version: version,
// view preferences
settings: {
addShipHistory: false,
debugMode: true,
deleteAfterImport: false,
showFullAllies: true,
showSafePassage: true,
showShareIntel: true,
showOwnShips: false,
showUnknown: false,
showColoredText: false,
showCompactTable: false,
showLocationHistory: true,
showVerticalButtons: true
},
hideWarningPane: false,
/** MEAT AND BONES: SHIP LIST UPDATE FUNCTIONS */
/**
* Update the ship list with data from current turn if appropriate
* @returns {shipList}
*/
updateShips: function () {
if (!this.enabled) return this;
if (vgap.game.turn <= this.lastTurn) {
console.log('Ship List: [2012] (updateShips) Turn ' + vgap.game.turn + ' already processed, skipping.');
return this;
}
if (vgap.game.turn != (this.lastTurn + 1)) {
console.log('Ship List: [2013] (updateShips) Turn ' + vgap.game.turn + '. Turn for update required: ' + (this.lastTurn + 1) + ', skipping.');
return this;
}
console.log('Ship List: [2014] (updateShips) Updating Ships for Turn ' + vgap.game.turn + '.');
// make vcrPlayer
const vcr = new vcrPlayer();
//first process all VCRs
for (let i = 0; i < vgap.vcrs.length; i++) {
let ship;
let shipIdx;
let shipIds = this.ships.map(function (ship) {
return ship.id;
});
this.initVcrPlayer(vcr, vgap.vcrs[i]);
/** @namespace x.objectid */
shipIdx = shipIds.indexOf(vgap.vcrs[i].left.objectid);
if (vcr.results[0] == 'Left Destroyed') {
// delete ship
if (shipIdx != -1) this.ships.splice(shipIdx, 1);
} else {
// build ship
ship = this.buildShipFromVcr(vcr, vgap.vcrs[i], 0, shipIdx);
/*
if (shipIdx == -1) {
// add missing properties
$.extend(ship, {
engineid: 0,
heading: -1,
history: [],
warp: -1
});
this.updateShipHistory(ship, ship);
this.ships.push(ship);
} else { // existing ship
let oldShip = this.ships[shipIdx];
this.updateShipHistory(oldShip, ship);
$.extend(true, oldShip, ship);
}
*/
}
// ignore planets
if (/** @type int */ vgap.vcrs[i].battletype == 1) continue;
// refresh ship ids
shipIds = this.ships.map(function (ship) {
return ship.id;
});
shipIdx = shipIds.indexOf(vgap.vcrs[i].right.objectid);
for (let j = 0; j < vcr.results.length; j++) {
if (vcr.results[j] == 'Right Destroyed') {
if (shipIdx != -1) this.ships.splice(shipIdx, 1);
break;
} else {
ship = this.buildShipFromVcr(vcr, vgap.vcrs[i], 1, shipIdx);
/*
// new ship
if (shipIdx == -1) {
// add missing properties
$.extend(ship, {
engineid: 0,
heading: -1,
history: [],
warp: -1
});
this.updateShipHistory(ship, ship);
this.ships.push(ship);
} else { // existing ship
let oldShip = this.ships[shipIdx];
this.updateShipHistory(oldShip, ship);
$.extend(true, oldShip, ship);
}
*/
}
}
}
this.buildShipsFromVgap();
this.ships.sort(function (a, b) {
return (a.id - b.id);
});
this.lastTurn = vgap.game.turn;
this.save();
return this;
},
/** Prime the VCR player with combat data */
initVcrPlayer: function (vcr, report) {
let left = new combatObject();
let right = new combatObject();
left.setObject(report.left);
right.setObject(report.right);
/** @namespace x.battletype */
vcr.init(left, right, report.battletype, report.seed);
vcr.finished = function () {
};
vcr.run(-1);
},
/**
* Update ship list from VGAP ship list
* @returns {vgap.plugin.shipList}
*/
buildShipsFromVgap: function () {
// mark all ships in list invisible
for (let i = this.ships.length - 1; i >= 0; i--) {
this.ships[i].visible = false;
}
// get ids of ships in enemy vgapShip list
const shipIds = this.ships.map(function (ship) {return ship.id;});
// get ids of vgap ships
const vgapShipIds = vgap.ships.map(function (ship) {return ship.id;});
// loop through vgap ship list
for (let i = vgap.ships.length - 1; i >= 0; i--) {
const vgapShip = vgap.ships[i];
//support for sphere addon
if (vgapShip.id < 0) continue;
let ship = {
id: vgapShip.id,
name: vgapShip.name,
heading: vgapShip.heading,
hullid: vgapShip.hullid,
infoturn: vgapShip.infoturn,
mass: vgapShip.mass,
ownerid: vgapShip.ownerid,
targetx: vgapShip.targetx,
targety: vgapShip.targety,
visible: true,
warp: vgapShip.warp,
x: vgapShip.x,
y: vgapShip.y
};
let shipIdx = shipIds.indexOf(vgapShip.id);
if (shipIdx == -1) {
// add missing properties
$.extend(ship, {
ammo: vgapShip.ammo,
beamid: vgapShip.beamid,
beams: vgapShip.beams,
crew: vgapShip.crew,
damage: vgapShip.damage,
engineid: vgapShip.engineid,
heading: -1,
history: [],
torpedoid: vgapShip.torpedoid,
torps: vgapShip.torps
});
this.updateShipHistory(ship, ship);
this.ships.push(ship);
if (this.settings.addShipHistory) this.addShipHistoryToNote(ship);
if (this.settings.debugMode) {
console.log('Ship List: [1007] (buildShipsFromVgap) Adding New Ship.');
console.log(ship);
}
} else {
if (vgapShip.ammo) ship.ammo = vgapShip.ammo;
if (vgapShip.beamid) ship.beamid = vgapShip.beamid;
if (vgapShip.beams) ship.beams = vgapShip.beams;
if (vgapShip.crew != -1) ship.crew = vgapShip.crew;
if (vgapShip.damage != -1) ship.damage = vgapShip.damage;
if (vgapShip.engineid) ship.engineid = vgapShip.engineid;
if (vgapShip.torpedoid) ship.torpedoid = vgapShip.torpedoid;
if (vgapShip.torps) ship.torps = vgapShip.torps;
let oldShip = this.ships[shipIdx];
this.updateShipHistory(oldShip, ship);
$.extend(true, oldShip, ship);
if (this.settings.addShipHistory) this.addShipHistoryToNote(oldShip);
if (this.settings.debugMode) {
console.log('Ship List: [1008] (buildShipsFromVgap) Updating Ship.');
console.log(oldShip);
}
}
}
// delete own ships / from share intel / full allies that aren't visible
for (let i = this.ships.length - 1; i >= 0; i--) {
if (vgapShipIds.indexOf(this.ships[i].id) == -1
&& vgap.getRelation(this.ships[i].ownerid).relationfrom >= 3
) this.ships.splice(i, 1);
}
return this;
},
/**
* Builds a ship object from VCR player and VCR report
* @param vcr vcrPlayer
* @param report vcr Report object
* @param ix [0-1]
* @returns {*}
*/
buildShipFromVcr: function (vcr, report, ix, shipIdx) {
const combatInfo = vcr.Objects[ix];
const side = ix == 0 ? 'left' : 'right';
const shipInfo = report[side];
let ownerId = report[side + 'ownerid'];
for (let j = 0; j < vcr.results.length; j++) {
if (vcr.results[j].toLowerCase() == side + ' captured') {
ownerId = ix == 0 ? /** @type int */ report.rightownerid : /** @type int */ report.leftownerid;
}
}
let ship = {
id: shipInfo.objectid,
name: shipInfo.name,
ammo: combatInfo.BayCount ? combatInfo.Fighters : combatInfo.Torpedos,
beams: combatInfo.BeamCount,
beamid: combatInfo.BeamId,
crew: combatInfo.Crew,
damage: combatInfo.Damage,
// engineid - unavailable from vcr
// heading - unavailable from vcr
hullid: shipInfo.hullid,
infoturn: vgap.game.turn,
mass: combatInfo.Mass,
ownerid: ownerId,
torpedoid: combatInfo.TorpedoId,
torps: combatInfo.LauncherCount,
//warp - unavailable from vcr
x: report.x,
y: report.y,
};
if (shipIdx == -1) {
// add missing properties
$.extend(ship, {
engineid: 0,
heading: -1,
history: [],
warp: -1
});
this.updateShipHistory(ship, ship);
this.ships.push(ship);
} else {
let oldShip = this.ships[shipIdx];
this.updateShipHistory(oldShip, ship);
$.extend(true, oldShip, ship);
}
if (this.settings.addShipHistory) this.addShipHistoryToNote(ship);
if (this.settings.debugMode) {
console.log('Ship List: [1009] (buildShipFromVcr) Adding Ship.');
console.log(ship);
}
return ship;
},
/**
* Add ship history to ship note
* @param ship {*}
*/
addShipHistoryToNote: function (ship) {
const start = '\n\n---SHIP HISTORY---';
const note = vgap.getNote(ship.id, 2);
const body = note.body.split(start);
const rows = [];
rows.push(body[0]);
rows.push(start);
rows.push('\nT', ship.infoturn.toString().padEnd(3, ' '), '', ship.x, ',', ship.y, ' W', (ship.warp == -1 ? '?' : ship.warp),
' H', ship.heading.toString().padStart(3, ' '), ship.mass.toString().padStart(5, ' '), 'kt');
if (body.length != 1) {
const turns = body[1].split('\n');
// remove empty string
turns.shift();
// remove first row is same as current turn
const match = turns[0].match(/^T(\d+)/);
if (match && match[1] == vgap.game.turn) turns.shift();
// remove last row if more than 5
if (turns.length > 5) turns.pop();
// add newline before first row
turns.unshift('\n');
rows.push(rows, turns.join('\n'));
}
note.body = rows.join('');
note.changed = 1;
},
/**
* Update ship history
* @param oldShip {*} ship info to be updated
* @param newShip {*} ship info to update with
* @returns {*} oldShip
*/
updateShipHistory: function (oldShip, newShip) {
if (oldShip.history.length == 0 || oldShip.history[0].turn < newShip.infoturn) {
oldShip.history.unshift({
turn: newShip.infoturn,
x: newShip.x,
y: newShip.y,
mass: newShip.mass
});
}
if (oldShip.history.length > 5) oldShip.history.pop();
oldShip.history.sort(function (a, b) {
return (b.turn - a.turn);
});
return oldShip;
},
/** HTML */
/**
* HTML for Ship List tabs
* @param view
* @param playerId
*/
showShips: function (view, playerId) {
if (!playerId) playerId = 1;
vgap.playSound("button");
vgap.closeSecond();
vgap.dash.content.empty();
// disable hotkeys in edit mode
if (this.editMode) vgap.hotkeysOn = false;
$([
'<ul class="FilterMenu">',
'<li onclick="vgap.plugins.shipList.showShips(1);" ' + (view == 1 ? 'class="SelectedFilter"' : '') + '>Summary</li>',
'<li onclick="vgap.plugins.shipList.showShips(2);" ' + (view == 2 ? 'class="SelectedFilter"' : '') + '>All Ships</li>',
'<li onclick="vgap.plugins.shipList.showShips(3);" ' + (view == 3 ? 'class="SelectedFilter"' : '') + '>Other Players</li>',
'<li onclick="vgap.plugins.shipList.showShips(4);" ' + (view == 4 ? 'class="SelectedFilter"' : '') + '>Allies</li>',
'<li onclick="vgap.plugins.shipList.showShips(5);" ' + (view == 5 ? 'class="SelectedFilter"' : '') + '>Enemies</li>',
'<li onclick="vgap.plugins.shipList.showShips(6);" ' + (view == 6 ? 'class="SelectedFilter"' : '') + '>Single Player</li>',
'<li onclick="vgap.plugins.shipList.showShips(7);" ' + (view == 7 ? 'class="SelectedFilter"' : '') + '>Settings</li>',
'<li onclick="vgap.plugins.shipList.showShips(8);" ' + (view == 8 ? 'class="SelectedFilter"' : '') + '>Storage Stats</li>',
'</ul>'
].join('')).appendTo(vgap.dash.content);
let pane = $('<div id="dashPane" class="DashPane" style="height:' + ($('#DashboardContent').height() - 30) + 'px;"></div>').appendTo(vgap.dash.content);
if (view == 8) return this.showStorage(pane, view);
this.showWarningPane(pane, view);
if (view == 7) return this.showSettings(pane);
if (view == 1) return this.showOverview(pane);
console.time('showShips');
if (view == 2) this.showSelectionPaneComplete(pane, view, playerId);
if (view == 4) this.showSelectionPaneAllied(pane, view, playerId);
if (view == 6) {
this.showSelectionPaneSingle(pane, view, playerId);
this.showShipForm($('#newShipForm'), view, playerId);
}
if (this.ships.length) this.showShipTableHeader(pane, view, playerId);
const shipIds = this.ships.map(function (ship) {return ship.id;});
const shipRows = $('#ShipRows');
const freighterRows = $('#FreighterRows');
// loop through all ship ids
for (let id = 1; id <= this.maxShipId; id++) {
const shipIdx = shipIds.indexOf(id);
if (shipIdx == -1) {
// no unknown ships or not complete view - continue
if (!this.settings.showUnknown || view != 2) continue;
shipRows.append('<tr><td>' + id + '</td><td>-</td><td>-</td><td>-</td><td>-</td><td></td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td></tr>');
continue;
}
let ship = this.ships[shipIdx];
// thanks to Jellyfishspam for this one
// ghost ship - continue loop
if (!ship.ownerid) continue;
/** @namespace x.relationfrom */
let relation = vgap.getRelation(ship.ownerid).relationfrom;
if (
//ships of other players
(view == 3 && ship.ownerid == vgap.player.id) ||
//allies (>= safe passage)
(view == 4 && (
relation == 1 ||
(relation == 2 && !this.settings.showSafePassage) ||
(relation == 3 && !this.settings.showShareIntel) ||
(relation == 4 && !this.settings.showFullAllies) ||
(ship.ownerid == vgap.player.id && !this.showOwnShips)
)) ||
//non-allies
(view == 5 &&
(ship.ownerid == vgap.player.id || vgap.alliedTo(ship.ownerid))
) ||
//single player
(view == 6 && ship.ownerid != playerId)
) continue;
const hull = vgap.getHull(ship.hullid);
const player = vgap.getPlayer(ship.ownerid);
let beam_weapons = '?';
if (hull.beams == 0) {
beam_weapons = "---";
} else if (ship.beams != 0 && ship.beamid != 0) {
beam_weapons = (ship.beams ? ship.beams + ' ' : '') + this.shortBeamNames[ship.beamid];
}
let secondary_weapons = '?';
if (hull.fighterbays > 0) {
secondary_weapons = hull.fighterbays + (hull.fighterbays == 1 ? ' Bay' : ' Bays');
} else if (hull.launchers > 0) {
if (ship.torps == -1 || ship.torpedoid == -1) secondary_weapons = "?";
else if (ship.torps == 0 || ship.torpedoid == 0) secondary_weapons = "---";
else secondary_weapons = ( ship.torps ? ship.torps + ' ' : '') + this.shortTorpNames[ship.torpedoid];
} else secondary_weapons = "---";
let row = [
'<tr class="shipRow' + player.id + (this.settings.showColoredText ? ' alt' : '') + '">',
!this.editMode ? '' : '<td><div class="BasicFlatButton" onclick="vgap.plugins.shipList.deleteShip(' + ship.id + ').showShips(' + view + ',' + playerId + ');">Delete</div></td>',
'<td>' + ship.id + '</td>',
'<td>' + player.username + '</td>',
'<td>' + vgap.getRace(player.raceid).shortname.substr(3) + '</td>',
'<td title="' + hull.name + '"><img class="TinyIcon" src="' + hullImg(ship.hullid) + '"/><div style="display: none;">' + hull.id + '</div></td>',
'<td>' + ship.name + '</td>',
'<td class="noteIcon"></td>',
'<td>(' + ship.x + "," + ship.y + ')</td>',
'<td>' + ship.infoturn + '</td>',
'<td>' + (ship.heading > -1 ? ship.heading : '?') + '</td>',
'<td>' + ship.warp + '</td>',
'<td>' + (ship.engineid > 0 ? this.shortEngineNames[ship.engineid] : '?') + '</td>',
'<td>' + beam_weapons + '</td>',
'<td>' + secondary_weapons + '</td>',
'<td>' + ((ship.ammo == -1) ? '?' : ship.ammo) + '</td>',
'<td>' + ship.mass + '</td>',
'<td>' + ((ship.crew == -1) ? '?' : ship.crew) + '</td>',
'<td>' + ((ship.damage == -1) ? '?' : ship.damage) + '</td>',
'</tr>'
].join('');
const note = vgap.getNote(ship.id, 2).body;
const noteRow = [
'<tr class="shipRow' + player.id + (this.settings.showColoredText ? ' alt' : '') + ' noteRow tablesorter-childRow">',
'<td colspan="' + (this.editMode ? '18' : '17') + '">',
'<form>',
'<label for="note' + ship.id + '">Ship Notes</label>',
'<textarea class="note" id="note' + ship.id + '" name="body">' + note + '</textarea>',
'</form>',
'</td>',
'</tr>'
].join('');
if (view == 6 && hull.beams == 0 && hull.launchers == 0 && hull.fighterbays == 0) {
row = $(row).appendTo(freighterRows);
freighterRows.append(noteRow);
} else {
row = $(row).appendTo(shipRows);
shipRows.append(noteRow);
}
if (view == 6 && this.editMode) {
row.on('fill-form', this.fillShipForm.bind(this));
row.click(function () {
$(this).trigger('fill-form', [ship.id, playerId]);
pane.data('jsp').scrollToElement($('#ShipEditTable'));
});
} else {
row.children().eq(6).hover((function (ship) {
this.showScan(ship);
}).bind(this, ship), this.hideScan.bind(this));
row.click((function (x, y, id) {
vgap.showMap();
vgap.map.centerMap(x, y);
/** @namespace this.drawShips */
this.selectPlayer(id)
.drawShips();
}).bind(this, ship.x, ship.y, ship.ownerid));
}
// add slide toggle for notes row
row.children('.noteIcon').click(function (e) {
$(this)
.toggleClass('down')
.parent().next().slideToggle();
e.stopPropagation();
});
// save note on blur
row.next().find('textarea').blur(function () {
const note = vgap.getNote(ship.id, 2);
note.body = $(this).val();
note.changed = 1;
});
}
//add freighters and warships to end of list
this.showUnknownShipsSingle(view, playerId, shipRows, freighterRows);
$('#ShipTable').tablesorter({cssChildRow: 'tablesorter-childRow'});
shipRows.find('td:nth-child(2)').addClass('capitalize');
if (view == 6) {
$("#FreighterTable").tablesorter();
freighterRows.find('td:nth-child(2)').addClass('capitalize');
}
pane.jScrollPane({animateScroll: true});
// fix annoying scroll up behavior
$('#newShipForm *').off('focus');
// remove focus handler on textareas
shipRows.find('textarea').off('focus');
freighterRows.find('textarea').off('focus');
// vgap.action added for the assistant
vgap.showShipsViewed = 1;
vgap.action();
console.timeEnd('showShips');
return this;
},
/** Unknown Ships for "Single Player" view */
showUnknownShipsSingle: function (view, playerId, shipRows, freighterRows) {
if (view == 6 && this.settings.showUnknown) {
const player = vgap.getPlayer(playerId);
const race = vgap.getRace(player.raceid).shortname.substr(3);
const warshipTotal = this.playerInfo(player.id, "capitalships");
const freighterTotal = this.playerInfo(player.id, "freighters");
let warshipCount = 0;
let freighterCount = 0;
let row = '<tr class="shipRow"' + playerId + '>' + (this.editMode ? '<td></td>' : '') + '<td>-</td><td>' + player.username + '</td><td>' + race + '</td><td>-</td><td>-</td><td></td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td></tr>';
let rows = [];
for (let i = this.ships.length - 1; i >= 0; i--) {
let ship = this.ships[i];
if (ship.ownerid != player.id) continue;
let hull = vgap.getHull(ship.hullid);
if (hull.beams == 0 && hull.launchers == 0 && hull.fighterbays == 0) {
freighterCount++;
} else {
warshipCount++;
}
}
for (let i = warshipCount; i < warshipTotal; i++) {
rows.push(row);
}
shipRows.append(rows.join(''));
for (let i = freighterCount; i < freighterTotal; i++) {
rows.push(row);
}
freighterRows.append(rows.join(''));
}
return this;
},
/** Selection pane for "Allies" view */
showSelectionPaneAllied: function (target, view, playerId) {
target.append([
'<form id="newShipForm"><div id="PlayerSelectionPane">',
'<table id="PlayerSelectionTable">',
'<tr><th><label for="showFullAllies">Show Full Allies</label></th><th><label for="showShareIntel">Show Share Intel</label></th><th><label for="showSafePassage">Show Safe Passage</label></th><th><label for="showOwnShips">Show Own Ships</label></th></tr>',
'<tr><td><input type="checkbox" ' + (this.settings.showFullAllies ? 'checked="yes" ' : '') + 'id="showFullAllies"/></td>',
'<td><input type="checkbox" ' + (this.settings.showShareIntel ? 'checked="yes" ' : '') + 'id="showShareIntel"/></td>',
'<td><input type="checkbox" ' + (this.settings.showSafePassage ? 'checked="yes" ' : '') + 'id="showSafePassage"/></td>',
'<td><input type="checkbox" ' + (this.settings.showOwnShips ? 'checked="yes" ' : '') + 'id="showOwnShips"/></td>',
'</tr></table>',
'</div></form>'
].join(''));
$('#showFullAllies').click((function (view, playerid) {
this.toggleFullAllies().showShips(view, playerid);
}).bind(this, view, playerId));
$('#showShareIntel').click((function (view, playerid) {
this.toggleShareIntel().showShips(view, playerid);
}).bind(this, view, playerId));
$('#showSafePassage').click((function (view, playerid) {
this.toggleSafePassage().showShips(view, playerid);
}).bind(this, view, playerId));
$('#showOwnShips').click((function (view, playerid) {
this.toggleOwnShips().showShips(view, playerid);
}).bind(this, view, playerId));
return this;
},
/** Selection pane for "Complete" view */
showSelectionPaneComplete: function (target, view, playerId) {
target.append([
'<form id="newShipForm">',
'<div id="PlayerSelectionPane">',
'<table id="PlayerSelectionTable">',
'<tr><th><label for="showUnknown">Show Unknown</label></th></tr>',
'<tr><td><input type="checkbox" ' + (this.settings.showUnknown ? 'checked="yes" ' : '') + 'id="showUnknown"/></td></tr>',
'</table>',
'</div>',
'</form>'
].join(''));
$('#showUnknown').click((function (view, playerid) {
this.toggleUnknown().showShips(view, playerid);
}).bind(this, view, playerId));
return this;
},
/** Selection pane for "Single Player" view */
showSelectionPaneSingle: function (target, view, playerId) {
target.append([
'<script>var newShip = { overwrite: false, ship: {} };</script>',
'<form id="newShipForm">',
'<div id="PlayerSelectionPane">',
'<table id="PlayerSelectionTable">',
'<tr><th><label for="shipListPlayer">Select Player</label></th><th><label for="showUnknown">Show Unknown</label></th><th><label for="enableEdit">Enable Edit</label></th></tr>',
'<tr><td><select id="shipListPlayer" class="capitalize" onchange="vgap.plugins.shipList.showShips(6,$(this).val());"></select></td>',
'<td><input type="checkbox" ' + (this.settings.showUnknown ? 'checked="yes" ' : '') + 'id="showUnknown"/></td>',
'<td><input type="checkbox" ' + (this.editMode ? 'checked="yes" ' : '') + 'id="enableEdit"/></td></tr>',
'</table>',
'</div>',
'</form>'
].join(''));
$.each(vgap.players, function (k, v) {
$('#shipListPlayer').append('<option value="' + v.id + '">' + v.id + ' - ' + v.fullname + '</option>');
});
$('#shipListPlayer').val(playerId);
$('#showUnknown').click((function (view, playerId) {
this.toggleUnknown().showShips(view, playerId);
}).bind(this, view, playerId));
$('#enableEdit').click((function (view, playerId) {
this.toggleEdit().showShips(view, playerId);
$('#dashPane').data('jsp').reinitialise();
}).bind(this, view, playerId));
return this;
},
/** Overview tab */
showOverview: function (target) {
let table = target
.append('<div id="MessageInbox"></div>').children(':last-child')
.append('<table></table>').children(':last-child')
.append('<tr><td><strong>Overview</strong></td></tr>')
;
$('#MessageInbox').append([
'<table id="ShipTable"><thead>',
'<th>ID</th><th>Player</th><th>Race</th>',
'<th>Warships</th>',
'<th>Freighters</th>',
'<th>Total</th>',
'</thead><tbody id="ShipRows">',
'</tbody></table>'
].join(''));
for (let i = 0; i < vgap.players.length; i++) {
let warshipsKnown = 0;
let freightersKnown = 0;
let player = vgap.players[i];
let warshipsTotal = this.playerInfo(player.id, "capitalships");
let freightersTotal = this.playerInfo(player.id, "freighters");
for (let i = this.ships.length - 1; i >= 0; i--) {
let ship = this.ships[i];
if (ship.ownerid != player.id) continue;
//support for sphere addon: don't count ships with negative id
if (ship.id < 0) continue;
let hull = vgap.getHull(ship.hullid);
if ((hull.beams == 0 || (ship.beamid == 0 && ship.ownerid == vgap.player.id)) && (hull.launchers == 0 || (ship.torpedoid == 0 && ship.ownerid == vgap.player.id)) && hull.fighterbays == 0) {
freightersKnown++;
} else {
warshipsKnown++;
}
}
$(['<tr class="shipRow' + player.id + '">',
'<td>' + player.id + '</td>',
'<td>' + player.username + '</td>',
'<td>' + vgap.getRace(player.raceid).shortname + '</td>',
'<td>' + warshipsKnown + ' / ' + warshipsTotal + '</td>',
'<td>' + freightersKnown + ' / ' + freightersTotal + '</td>',
'<td>' + (freightersTotal + warshipsTotal) + '</td>',
'</tr>'
].join('')).appendTo("#ShipRows")
.click((function (playerId) {
this.showShips(6, playerId);
}).bind(this, player.id))
;
$('#ShipRows').find('td:nth-child(2)').addClass('capitalize');
}
$("#ShipTable").tablesorter();
target.jScrollPane();
vgap.action();
return this;
},
showSettings: function (target) {
let rows = [
'<tr><td><p><strong>Plugin Preferences</strong></p></td></tr>',
'<tr><td><form class="ConfigForm"><table id="SettingsTable">',
'<tr><td><input type="checkbox" ' + (this.settings.showLocationHistory ? 'checked="yes" ' : '') + 'id="showLocationHistory"/></td><td><label for="showLocationHistory"><span>Show ship location history.</span></label></td></tr>',
'<tr><td><input type="checkbox" ' + (this.settings.showVerticalButtons ? 'checked="yes" ' : '') + 'id="showVerticalButtons"/></td><td><label for="showVerticalButtons"><span>Vertical player buttons.</span></label></td></tr>',
'<tr><td><input type="checkbox" ' + (this.settings.showColoredText ? 'checked="yes" ' : '') + 'id="showColoredText"/></td><td><label for="showColoredText"><span>Colored text instead of colored rows.</span></label></td></tr>',
'<tr><td><input type="checkbox" ' + (this.settings.showCompactTable ? 'checked="yes" ' : '') + 'id="showCompactTable"/></td><td><label for="showCompactTable"><span>Compact ship tables.</span></label></td></tr>',
'<tr><td><input type="checkbox" ' + (this.settings.addShipHistory ? 'checked="yes" ' : '') + 'id="addShipHistory"/></td><td><label for="addShipHistory"><span>Add ship history to notes.</span></label></td></tr>',
'<tr><td><input type="checkbox" ' + (this.settings.deleteAfterImport ? 'checked="yes" ' : '') + 'id="deleteAfterImport"/></td><td><label for="deleteAfterImport"><span>Delete EnemyShipList plugin data after import.</span></label></td></tr>',
'<tr><td><input type="checkbox" ' + (this.settings.debugMode ? 'checked="yes" ' : '') + 'id="toggleDebugMode"/></td><td><label for="toggleDebugMode"><span>Debug Mode (verbose logging).</span></label></td></tr>',
'</table></form></td></tr>',
/*
'<tr><td><p><strong>Tools</strong></p></td></tr>',
'<tr><td><form class="ConfigForm"><table id="SettingsTable">',
'<tr><td><input type="checkbox" id="sendShipData" style="visibility:hidden"/></td><td><label for="sendShipData"><span class="simptip-position-top simptip-smooth simptip-multiline simptip-info" data-tooltip="Send your ship data you have on a specific player to another player. Data will be integrated in their Ship List if they accept."></span></label></td></tr>',
*/
'<tr><td><p><strong>Update Options</strong></p></td></tr>',
'<tr><td><form class="ConfigForm"><table id="SettingsTable">',
'<tr><td><input type="checkbox" ' + (this.lastTurn == vgap.nowTurn ? 'disabled ' : '') + 'id="updateMissingTurns"/></td><td><label for="updateMissingTurns"><span class="simptip-position-top simptip-smooth simptip-multiline simptip-info" data-tooltip="Add all data from missing turns to the ship list. ' +
'(Your list contains data up to turn ' + this.lastTurn + '.) ' +
'More recent turns will be automatically processed.">Update all missing turns.</span></label></td></tr>',
'<tr><td><input type="checkbox" id="rebuildFromCurrent"/></td><td><label id="ttReset" for="rebuildFromCurrent"><span class="simptip-position-top simptip-smooth simptip-multiline simptip-warning" data-tooltip="Empty the ship list and rebuild it starting from the ' +
'first turn. More recent turns will be automatically processed. All custom entries will be deleted.">Rebuild ship list from current turn.</span></label></td></tr>',
'<tr><td><input type="checkbox" id="rebuildFromScratch"/></td><td><label id="ttRebuild" for="rebuildFromScratch"><span class="simptip-position-top simptip-smooth simptip-multiline simptip-warning" data-tooltip="Empty the ship list and rebuild it with information from this turn. ' +
'More recent turns will not be processed. All custom entries will be deleted.">Rebuild ship list from the first turn.</span></label></td></tr>',
'</table></form></td></tr>',
'<tr><td><p><strong>Usage Notes</strong></p></td></tr>',
'<tr><td><p>The plugin records all ships seen throughout the game. A starmap tool allows you to draw circles on the map where ships were last seen. The plugin needs to be activated for each game/player combination, and on each computer on which you use it.</p>',
'<p>Plugin data is saved both to local storage and to the server, meaning it is shared between computers.</p></td></tr>',
'<tr><td><p><strong>Limitations</strong></p></td></tr><tr><td><p>Ships destroyed by mine hits or just listed in "Explosion" reports are not removed since ship id cannot be determined.</p>' +
'<p>Warships without beam weapons, technically freighters, will be shown as warships, since NU internally stores unknown beams as 0. </p>' +
'<p>To make a backup of your data, use the "Export" function found under "Storage".</p></td></tr>',
'<tr><td><p><strong>Credits</strong></p></td></tr>',
'<tr><td>',
'<p><a href="http://planets.nu/#/account/kedalion" target="_blank" style="color:#00F7FF">Kedalion</a> - the writer of the original Enemy Ship List plugin.</p>' +
'<p><a href="http://planets.nu/#/account/mcnimble" target="_blank" style="color:#00F7FF">McNimble</a> - for the help in saving ship info to the server.</p>' +
'</td></tr>',
'<tr><td><p><strong>Bugs / Feature Requests:</strong></p></td></tr>',
'<tr><td><p>Drop me a line anytime on NU: <a href="http://planets.nu/#/account/space+pirate+harlock" target="_blank" style="color:#00F7FF">http://planets.nu/#/account/space+pirate+harlock</a>.</p></td></tr>'
];
/*
rows.push('<tr><td><strong>Turn:</strong><select id="rebuildStartTurn" style="width:80px"></select></td></tr>');
rows.push('<tr><td><div class="BasicFlatButton" onclick="' +
'vgap.plugins.shipList.enable().rebuildShips($(\'#rebuildStartTurn\').val());">' +
'Rebuild</div></td></tr>');
const firstTurn = (vgap.settings.acceleratedturns > 0 ? vgap.settings.acceleratedturns : 1);
const nowTurn = vgap.nowTurn;
for (let i = firstTurn; i <= nowTurn; i++) {
$('#rebuildStartTurn').append('<option value="' + i + '">' + i + '</option>')
}
*/
target.append(
'<div id="MessageInbox"><table id="ConfigTable">' +
rows.join('') +
'</table></div>'
);
const accel = vgap.settings.acceleratedturns;
$('#showLocationHistory').click((function () {
this.toggleLocationHistory();
}).bind(this));
$('#showVerticalButtons').click((function () {
this.toggleVerticalButtons();
}).bind(this));
$('#showColoredText').click((function () {
this.toggleColoredText();
}).bind(this));
$('#showCompactTable').click((function () {
this.toggleCompactTable();
}).bind(this));
$('#addShipHistory').click((function () {
this.toggleAddShipHistory();
}).bind(this));
$('#deleteAfterImport').click((function () {
this.toggleDeleteAfterImport();
}).bind(this));
$('#toggleDebugMode').click((function () {
this.toggleDebugMode();
}).bind(this));
$('#sendShipData').click((function () {
}).bind(this));
$("#esendmessage").tclick(function () {
//var scr = templater.get("PrivateMessage", { fromid: nu.data.account.id, username: account.username, showinvitetogroup: false });
nu.modal($([
'<form><table>',
'<tr>',
'<td><label>Send Data on:</label></td>',
'<td><div class="select"><select></select></div></td>',
'</tr><tr>',
'<td><label>To Recipient:</label></td>',
'<td><div class="select"><select></select></div></td>',
'</table></form>' +
'<div class="center">',
'<span id="eyes" class="button eadd">Yes</span>',
'<span id="ecancel" class="button enav">Cancel</span>',
'</div>'
].join('')), 'Send Ship Data', 700);
var pm = $("#epm");
pm.val("");
pm.focus();
pm.removeClass("eunfocused");
//pm.css("user-select", "text");
/*
scr.find(".eunfocused").focus(function () {
var ta = $(this);
ta.val("");
ta.removeClass("eunfocused");
ta.unbind();
});
*/
scr.find("#esendbutton").tclick(function () {
$(this).hide();
nu.api.privateMessage(scr.pm.innerText(), account.id, function () {
nu.closemodal();
});
});
return false;
});
$('#updateMissingTurns').click((function () {
this.initLoop();
}).bind(this));
$('#rebuildFromCurrent').click((function () {
this.enable().resetShips().showShips(7);
}).bind(this));
$('#rebuildFromScratch').click((function () {
this.enable().rebuildShips(accel > 0 ? accel : 1);
}).bind(this));
if (vgap.game.turn < accel) {
$('#rebuildFromCurrent').prop('disabled', true);
$('#rebuildFromScratch').prop('disabled', true);
const txt = 'This game has "Accelerated Start" enabled. The plugin can only be enabled once you reach turn ' + accel + '.'
$('#ttReset').prop('data-tooltip', txt);
$('#ttRebuild').prop('data-tooltip', txt);
}
target.jScrollPane();
// fix annoying scroll up behavior
// $('#rebuildStartTurn').off('focus');
$('.ConfigForm *').off('focus');
vgap.action();
return this;
},
showShipForm: function (target, view, playerId) {
if (!(view == 6) || !this.editMode) return this;
target.append([
'<div id="ShipEditPane">',
'<table id="ShipEditTable">',
'<tr><th>Id</th><th>Hull</th><th>Name</th></tr>',
'<tr><td><select id="shipId"><optgroup id="optGroupOwn" label="Owned Ships"/><optgroup id="optGroupNew" label="Unknown Ships"/></select></td><td><select id="shipHullId"/></td><td><input id="shipName" size="30"></td></tr>',
'<tr><th></th><th>Engine(s)</th></tr>',
'<tr><td rowspan="3"><input id="shipVisible" type="hidden" value="false"><input id="shipHistory" type="hidden" value="[]"><input id="shipOwnerId" type="hidden" value="' + playerId + '"><img id="hullImg"/></td><td><select id="shipEngineId"/></td></tr>',
'<tr><th>Beam Type</th><th>Beam #</th></tr>',
'<tr><td><select id="shipBeamId"/></td><td><input id="shipBeams" size="4"></td></tr>',
'<tr><th></th><th>Torp Type</th><th>Tube #</th></tr>',
'<tr><td></td><td><select id="shipTorpedoId"/></td><td><input id="shipTorps" size="4"></td></tr>',
'<tr><th rowspan="2"></th><td colspan="2"><table id="ShipMiscTable">',
'<tr><th>Turn</th><th>X</th><th>Y</th><th>Heading</th><th>Warp</th><th>Ammo</th><th>Mass</th><th>Crew</th><th>Dmg</th></tr>',
'<tr><td><input id="shipInfoTurn" size="4" value="' + vgap.game.turn + '"></td><td><input id="shipX" size="4" value="2000"></td><td><input id="shipY" size="4" value="2000"></td>',
'<td><input id="shipHeading" size="4" value="0"></td><td><input id="shipWarp" size="4" value="0"></td><td><input id="shipAmmo" size="4" value="0"></td>',
'<td><input id="shipMass" size="4" value="0"></td><td><input id="shipCrew" size="4" value="0"></td><td><input id="shipDamage" size="4" value="0"></td></tr>',
'</table></td></tr>',
'<tr><td colspan="3"><div id="shipSaveButton" class="BasicFlatButton">Save</div>',
'<div id="shipResetButton" class="BasicFlatButton">Reset</div></td></tr>',
'</table></div>'
].join(''));
/*
* Select Box Fillers
*/
let player = vgap.getPlayer(playerId);
let race = vgap.getRace(player.raceid);
let shipForm = $('#newShipForm');
let shipIdSelect = $('#shipId');
let shipHullSelect = $('#shipHullId');
let shipEngineSelect = $('#shipEngineId');
let shipBeamSelect = $('#shipBeamId');
let shipTorpSelect = $('#shipTorpedoId');
let optGroupNew = $('#optGroupNew');
let optGroupOwn = $('#optGroupOwn');
let options;
let id = 1;
for (let i = 0; i < this.ships.length; i++) {
while (id < this.ships[i].id) {
optGroupNew.append('<option value="' + id + '">' + id + '</option>');
id++;
}
if (this.ships[i].ownerid == playerId) {
optGroupOwn.append('<option value="' + id + '">' + id + '</option>');
}
id++;
}
while (id <= this.maxShipId) {
optGroupNew.append('<option value="' + id + '">' + id + '</option>');
id++;
}
shipIdSelect.val((optGroupNew).find(':first').val());
options = [];
let hulls = race.hulls.split(',');
for (let i = 0; i < hulls.length; i++) {
options.push('<option value="' + hulls[i] + '">' + vgap.getHull(hulls[i]).name + '</option>');
}
options.push('<option value="0">-------</option>');
hulls = vgap.hulls;
for (let i = 0; i < hulls.length; i++) {
options.push('<option value="' + hulls[i].id + '">' + hulls[i].name + '</option>');
}
shipHullSelect.append(options.join(''));
options = [];
options.push('<option value="0">Unknown</option>');
for (let i = 0; i < vgap.engines.length; i++) {
options.push('<option value="' + vgap.engines[i].id + '">' + vgap.engines[i].name + '</option>');
}
shipEngineSelect.append(options.join(''));
options = [];
options.push('<option value="0">Unknown</option>');
for (let i = 0; i < vgap.beams.length; i++) {
options.push('<option value="' + vgap.beams[i].id + '">' + vgap.beams[i].name + '</option>');
}
shipBeamSelect.append(options.join(''));
options = [];
options.push('<option value="0">Unknown</option>');
for (let i = 0; i < vgap.torpedos.length; i++) {
options.push('<option value="' + vgap.torpedos[i].id + '">' + vgap.torpedos[i].name + '</option>');
}
shipTorpSelect.append(options.join(''));
/*
* Event Handlers
*/
shipForm.change(this.changeShipForm);
shipIdSelect.on('fill-form', this.fillShipForm.bind(this));
shipIdSelect.change(function () {
$(this).trigger('fill-form', [$(this).val(), playerId]);
});
shipHullSelect.change(function () {
const val = $(this).val();
// new ships - add name of hull
if (val != 0 && !newShip.overwrite) {
const hull = vgap.getHull(val);
$('#shipName').val(hull.name);
$('#shipBeams').val(hull.beams);
$('#shipTorps').val(hull.launchers);
$('#shipCrew').val(hull.crew);
$('#hullImg')[0].src = hullImg(hull.id);
}
});
// fill form when loading the page
shipHullSelect.trigger('change');
$('#shipSaveButton').click((function (view, playerId) {
shipForm.trigger('change');
console.log('Ship List: [2017] (newShipForm) Saving Ship ' + newShip.ship.id + '.');
console.log(newShip);
this.saveShip(newShip.ship, newShip.overwrite).showShips(view, playerId);
}).bind(this, view, playerId));
$('#shipResetButton').click(function () {
shipForm.trigger('reset');
// DUPLICATE CODE - REFACTOR
$('#shipListPlayer').val(playerId);
shipIdSelect.val(optGroupNew.find(':first').val());
// hidden fields don't reset
$('#shipHistory').val('[]');
newShip = {overwrite: false, ship: {}};
// update hull and name
shipHullSelect.trigger('change');
});
return this;
},
fillShipForm: function (e, shipId, playerId) {
shipId = parseInt(shipId);
let shipIds = this.ships.map(function (ship) {
return ship.id;
});
let shipIdx = shipIds.indexOf(shipId);
if (shipIdx != -1) {
let ship = this.ships[shipIdx];
newShip.overwrite = true;
$('#shipId').val(ship.id);
$('#shipHullId').val(ship.hullid);
$('#hullImg')[0].src = hullImg(ship.hullid);
$('#shipName').val(ship.name);
$('#shipHistory').val(JSON.stringify(ship.history));
$('#shipEngineId').val(ship.engineid);
$('#shipBeamId').val(ship.beamid);
$('#shipBeams').val(ship.beams);
$('#shipTorpedoId').val(ship.torpedoid);
$('#shipTorps').val(ship.torps);
$('#shipInfoTurn').val(ship.infoturn);
$('#shipX').val(ship.x);
$('#shipY').val(ship.y);
$('#shipHeading').val(ship.heading > -1 ? ship.heading : '');
$('#shipWarp').val(ship.warp > -1 ? ship.warp : '');
$('#shipAmmo').val(ship.ammo);
$('#shipMass').val(ship.mass);
$('#shipCrew').val(ship.crew > -1 ? ship.crew : '');
$('#shipDamage').val(ship.damage > -1 ? ship.damage : '');
$('#shipVisible').val(ship.visible);
} else {
newShip.overwrite = false;
$('#newShipForm').trigger('reset');
$('#shipListPlayer').val(playerId);
$('#shipId').val(shipId);
// hidden fields don't reset
$('#shipHistory').val('[]');
$('#shipVisible').val('false');
$('#shipHullId').trigger('change');
}
return this;
},
/**
* Event handler for ship form change
* @returns {shipList}
*/
changeShipForm: function () {
let ship = newShip.ship;
ship.id = parseInt($('#shipId').val());
ship.ownerid = parseInt($('#shipOwnerId').val());
ship.hullid = parseInt($('#shipHullId').val());
ship.engineid = parseInt($('#shipEngineId').val());
ship.beamid = parseInt($('#shipBeamId').val());
ship.beams = parseInt($('#shipBeams').val());
ship.torpedoid = parseInt($('#shipTorpedoId').val());
ship.torps = parseInt($('#shipTorps').val());
ship.infoturn = parseInt($('#shipInfoTurn').val());
ship.x = parseInt($('#shipX').val());
ship.y = parseInt($('#shipY').val());
ship.heading = parseInt($('#shipHeading').val());
ship.warp = parseInt($('#shipWarp').val());
ship.ammo = parseInt($('#shipAmmo').val());
ship.mass = parseInt($('#shipMass').val());
ship.crew = parseInt($('#shipCrew').val());
ship.damage = parseInt($('#shipDamage').val());
ship.visible = ($('#shipVisible').val() == 'true');
for (let key in ship) {
if (isNaN(ship[key])) ship[key] = -1;
}
ship.name = $('#shipName').val();
ship.history = JSON.parse($('#shipHistory').val());
console.log(newShip);
return this;
},
showShipTableHeader: function (target, view, playerId) {
let warshipsTotal = this.playerInfo(playerId, "capitalships");
let freightersTotal = this.playerInfo(playerId, "freighters");
let warshipsKnown = 0;
let freightersKnown = 0;
let rows = ['<div id="ShipPane">'];
if (view == 6) {
for (let i = this.ships.length - 1; i >= 0; i--) {
let ship = this.ships[i];
if (ship.ownerid != playerId) continue;
let hull = vgap.getHull(ship.hullid);
if (hull.beams == 0 && hull.launchers == 0 && hull.fighterbays == 0) {
freightersKnown++;
} else {
warshipsKnown++;
}
}
}
// warship table header
if (view == 6) {
rows.push('<table><tr><td><p><strong>Warships (' + warshipsKnown + ' / ' + warshipsTotal + ')</strong></p></td></tr></table>');
}
rows.push(
'<table id="ShipTable"' + (this.settings.showCompactTable ? ' class="compact"' : '') + '>',
'<thead><tr>' + (this.editMode ? '<th></th>' : '') + '<th>ID</th><th>Player</th><th>Race</th><th>Hull</th><th>Name</th>',
'<th></th><th>Location</th><th>Turn</th><th>Heading</th><th>Warp</th><th>Engine</th><th>Beams</th><th>Torps/Bays</th><th>Ammo</th>',
'<th>Mass</th><th>Crew</th><th>Dmg</th></tr></thead>',
'<tbody id="ShipRows"></tbody>',
'</table>'
);
// freighter table header
if (view == 6) {
rows.push(
'<table><tr><td><p><strong>Freighters (' + freightersKnown + ' / ' + freightersTotal + ')</strong></p></td></tr></table>',
'<table id="FreighterTable"' + (this.settings.showCompactTable ? ' class="compact"' : '') + '>',
'<thead><tr>' + (this.editMode ? '<th></th>' : '') + '<th>Id</th><th>Player</th><th>Race</th><th>Hull</th><th>Name</th><th></th>',
'<th>Location</th><th>Turn</th><th>Heading</th><th>Warp</th><th>Engine</th><th>Beams</th><th>Torps/Bays</th><th>Ammo</th><th>Mass</th>',
'<th>Crew</th><th>Dmg</th></tr></thead>',
'<tbody id="FreighterRows"></tbody>',
'</table>'
);
}
rows.push('</div>');
target.append(rows.join(''));
return this;
},
showStorage: function (target, view) {
target.append([
'<div id="MessageInbox">',
'<table id="ConfigTable"><tr><td><p><strong>Storage</strong></p></td></tr>',
'<tr><td><p>The ', this.pluginName, ' plugin stores ship data locally on your machine. Since the amount of available storage varies, you may need to delete some stale game data to free up space.</p></td></tr>',
'<tr><td><p><strong>Games</strong></p></td></tr><tr><td><table id="ShipTable"><tr>' +
'<th>Game Id</th><th>Name</th><th>Slot</th><th>Player</th><th>Race</th><th>#1 Turn</th><th>Last Turn</th><th>Memory</th><th>Version</th><th></th>' +
'</tr><tbody id="ShipRows"></tbody></table></td></tr><tr><td><p><strong>Import / Export</strong></p></td></tr>',
'<tr><td><p>This allows you to export all game data on this computer, and to import it to another. Note that importing will delete all prior game data on the target machine. It is highly recommended to make regular backups, especially if using the bleeding edge versions of the plugin, which I highly encourage.</p></td></tr>',
'<tr><td><div class="center"><div class="BasicFlatButton" onclick="vgap.plugins.shipList.exportGameData();">Export</div>',
'<label for="fileInput"><div class="BasicFlatButton">Import</div></label><input id="fileInput" type="file" onchange="',
'vgap.plugins.shipList.importGameData();" style="display:none"/></div></td></tr>',
'</table>',
'</div>'
].join(''));
let rows = [];
let totalSize = 0;
for (let key in localStorage) {
let prefix = this.storagePrefix;
let re = new RegExp(prefix + '(\\d+)\\.(\\d+)\\.data');
let match = re.exec(key);
if (match) {
let gameId = match[1];
let playerId = match[2];
let gameData = localStorage.getItem(prefix + match[1] + '.' + match[2] + '.data');
let gameSize = gameData.length * 2;
gameData = JSON.parse(gameData);
totalSize += gameSize;
rows.push('<tr>',
'<td>' + gameId + '</td>',
'<td>' + gameData.gameName + '</td>',
'<td>' + playerId + '</td>',
'<td>' + gameData.playerName + '</td>',
'<td>' + gameData.raceName + '</td>',
'<td>' + gameData.firstTurn + '</td>',
'<td>' + gameData.lastTurn + '</td>',
'<td>' + (gameSize / 1024).toFixed(2) + ' kB</td>',
'<td>' + gameData.version + "</td>",
'<td><div class="BasicFlatButton" onclick="vgap.plugins.shipList.deleteGame(' + gameId + ',' + playerId + ').showShips(' + view + ');">Delete</div></td>',
'</tr>'
);
}
}
rows.push('<tr><td>All games</td><td></td><td>All players</td><td></td><td></td><td></td><td></td>',
'<td>' + (totalSize / 1024).toFixed(2) + ' kB</td><td></td>',
'<td><div class="BasicFlatButton" onclick="vgap.plugins.shipList.deleteAllGames().showShips(' + view + ');">Delete All</div></td>',
'</tr>'
);
const shipRows = $('#ShipRows').append(rows.join(''));
shipRows.find('td:nth-child(4)').addClass('capitalize');
$("#ShipTable").tablesorter();
target.jScrollPane();
vgap.action();
return this;
},
/** Warning pane */
showWarningPane: function (target, view) {
if (this.hideWarningPane) return this;
let table = target
.append('<div id="WarningPane"></div>').children(':last-child')
.append('<table id="WarningTable"></table>').children(':last-child')
;
$('#WarningPane').append('<div id="closeWarningPane" class="closeIcon"></div>');
$('#closeWarningPane').click((function () {
$('#WarningPane').hide();
this.hideWarningPane = true;
}).bind(this));
if (this.enabled) {
table.append('<tr><th><p>The ship list contains data from turn ' + this.firstTurn + ' to turn ' + this.lastTurn + '</p></th></tr>');
if (this.lastTurn > vgap.game.turn) {
table.append('<tr><th><p class="warning">Total ships from turn (' + vgap.game.turn + '), known ships from turn (' + this.lastTurn + ')! More ships can be shown than the player had this turn.</p></th></tr>');
}
if (this.lastTurn != vgap.nowTurn) {
table.append('<tr><th><p class="warning">This list does not include the most recent turns yet. ' +
'You will need to either manually go through all turns starting at turn ' + ((this.lastTurn) + 1) + ' or use "Auto Update". ' +
'More options are available under "Settings".</p><div class="center"><div class="BasicFlatButton" onclick="vgap.plugins.shipList.initLoop();"> Auto Update</div></div></th></tr>'
);
}
if (this.lastTurn > vgap.game.turn) {
table.append('<tr><th><p class="warning">Information in this list is more recent than the turn you\'re viewing. Most recent turn: ' + this.lastTurn + '.</p></th></tr>');
}
} else {
table.append('<tr><th><p class="warning">Plugin is not enabled for this game/player combination on this machine.</p></th></tr>');
if (view != 7) {
if (vgap.nowTurn < vgap.settings.acceleratedturns) {
table.append('<tr><th>This game has "Accelerated Start" enabled. The plugin can only be enabled once you reach turn ' + vgap.settings.acceleratedturns + '.</tr></th>');
} else {
table.append('<tr><td><p>To enable the plugin, select one of the options below.</p></td></tr>');
if (!vgap.settings.acceleratedturns || vgap.game.turn >= vgap.settings.acceleratedturns) {
table.append('<tr><th><div class="BasicFlatButton" onclick="' +
/** @namespace shipList.resetShips */
'vgap.plugins.shipList.enable().resetShips().showShips(' + view + ');">' +
'Initialize</div><span>Initialize list from the current turn only.</span></th></tr>');
}
table.append('<tr><th><div class="BasicFlatButton" onclick="' +
/** @namespace plugin.rebuildShips */
'vgap.plugins.shipList.enable().rebuildShips(' +
(vgap.settings.acceleratedturns > 0 ? vgap.settings.acceleratedturns : 1) + ');"> ' +
'Build</div><span>Build list starting from turn ' + (vgap.settings.acceleratedturns > 0 ? vgap.settings.acceleratedturns : 1) +
'</span></th></tr>');
}
}
}
return this;
},
/**
* MAP DRAWING
*/
/**
* Draw last location of ships
*/
drawShips: function () {
let drawShips = false;
for (let i = 0; i <= vgap.players.length; i++) {
if (this.playerToggles[i]) {
drawShips = true;
break;
}
}
if (!drawShips) return;
for (let i = this.ships.length - 1; i >= 0; i--) {
const ship = this.ships[i];
if (vgap.game.turn < ship.infoturn) continue;
if (this.playerToggles[0] || this.playerToggles[ship.ownerid]) {
this.drawShipCircle(ship.x, ship.y, this.drawRadius, {stroke: this.playerColors[ship.ownerid]}, null);
}
}
// mark visible ships in time machine
if (vgap.game.turn < vgap.nowTurn) {
for (let i = vgap.ships.length - 1; i >= 0; i--) {
const ship = vgap.ships[i];
if (this.playerToggles[0] || this.playerToggles[ship.ownerid]) {
this.drawShipCircle(ship.x, ship.y, this.drawRadius, {stroke: this.playerColors[ship.ownerid]}, null);
}
}
}
},
/**
* Draw ship circle on map
* @param x int
* @param y int
* @param radius int
* @param attr {*}
* @param ctx context
*/
drawShipCircle: function (x, y, radius, attr, ctx) {
if (!vgap.map.isVisible(x, y, radius)) return;
radius *= vgap.map.zoom;
if (radius <= 1) radius = 1;
if (ctx == null) ctx = vgap.map.ctx;
ctx.strokeStyle = attr.stroke;
ctx.lineWidth = 3;
ctx.beginPath();
ctx.arc(vgap.map.screenX(x), vgap.map.screenY(y), radius, 0, Math.PI * 2, false);
ctx.stroke();
},
/**
* Select player ships on map
* @param id
* @returns {shipList}
*/
selectPlayer: function (id) {
for (let i = this.playerToggles.length - 1; i >= 0; i--) {
if (!this.playerToggles[i]) {
this.playerToggles[0] = false;
}
}
this.playerToggles[id] = true;
return this;
},
/**
* Show player toggles
* @returns {shipList}
*/
showMapTool: function () {
const map = vgap.map;
$("#playerToggles").remove();
let playerToggles = $('<div id="playerToggles"' + (this.settings.showVerticalButtons ? '' : ' class="hori"') + '></div>').appendTo('#MapControls');
map.addMapTool("Close Ship Tool", "hideToggles", function () {
vgap.plugins["shipList"].toggleMapTool();
}, "#playerToggles");
map.addMapTool('All Ships', 'player0' + (this.playerToggles[0] ? ' active' : ''), function () {
vgap.plugins.shipList.togglePlayer(0)
}, "#playerToggles");
for (let i = 1; i < this.playerToggles.length; i++) {
let name = '';
for (let j = 0; j < vgap.players.length; j++) {
if (vgap.players[j].id == i) {
name = vgap.players[j].fullname;
break;
}
}
map.addMapTool(name, 'player' + i + (this.playerToggles[i] ? ' active' : ''), function () {
vgap.plugins.shipList.togglePlayer(i)
}, "#playerToggles");
}
return this;
},
/**
* Get ships in radius
* @param x int
* @param y int
* @param includeVisible boolean include visible ships from the list
* @return Array of ships
*/
shipsAt: function (x, y, includeVisible) {
let ships = [];
for (let i = 0; i < this.ships.length; i++) {
let ship = this.ships[i];
if ((this.playerToggles[0] || this.playerToggles[ship.ownerid]) && (!ship.visible || includeVisible) && (Math.dist(x, y, ship.x, ship.y) <= this.drawRadius)) {
ships.push(ship);
}
}
return ships;
},
/**
* Show planet pane when hovering over ship location
* @param ship
*/
showScan: function (ship) {
vgap.list.empty();
vgap.list.show();
const pane = $('<div class="childpane"></div>').appendTo(vgap.list);
let planet = vgap.planetAt(ship.x, ship.y);
const titleBar = $("<div id='ScanTitle'></div>").appendTo(pane);
if (planet) {
titleBar.html('<div>' + Math.abs(planet.id) + ': ' + planet.name + '</div>');
} else {
let dist = 1000;
let planetB;
let distB = 1000;
for (let i = 0; i < vgap.planets.length; i++) {
planetB = vgap.planets[i];
distB = Math.dist(planetB.x, planetB.y, ship.x, ship.y);
if (distB <= dist) {
dist = distB;
planet = planetB;
}
}
if (dist <= 3) {
titleBar.html('<div>' + Math.abs(planet.id) + ': ' + planet.name + '<span>(Warp Well)</span></div>');
} else {
titleBar.html('<div>' + Math.abs(planet.id) + ': ' + planet.name + '<span>(' + dist.toFixed(1) + ' ly away)</span></div>');
}
}
pane.append(shtml.planetScan(planet, true));
const starBase = vgap.getStarbase(planet.id);
if (starBase != null) pane.append(shtml.starbaseScan(starBase));
},
hideScan: function () {
vgap.list.hide();
},
/** Show ships from previous turns in pane (hover) */
shipScan: function (ship, showdamage) {
/** @todo Clean up nu.js code */
const hull = vgap.getHull(ship.hullid);
const player = vgap.getPlayer(ship.ownerid);
const race = vgap.getRace(player.raceid);
const note = vgap.getNote(ship.id, 2);
let cls = "";
if (ship.ownerid == vgap.player.id) cls = "MyItem";
else if (vgap.allied(ship.ownerid)) cls = "AllyItem";
else if (ship.ownerid != vgap.player.id) cls = "EnemyItem";
let html = "<div class='ItemSelection ShipSeen " + cls + "' data-id='" + ship.id + "'>";
html += "<img " + (ship.iscloaked ? "class='imgcloaked'" : "") + " src='" + hullImg(ship.hullid) + "'/>";
let cloaked = "";
if (ship.iscloaked) cloaked = "<div class='sval cloak' style='margin-right:3px;'></div>";
html += "<div class='ItemTitle'><div class='sval warp'>" + ( ship.warp == -1 ? '?' : ship.warp ) + "</div>" + cloaked + Math.abs(ship.id) + ": " + ship.name + "</div>";
html += "<div class='ItemTitle'>" + hull.name + "</div>";
//if (ship.iscloaked)
// html += "<div class='sval cloak' style='margin-right: 50px;'></div>"
//html += "<span class='" + cls + "'>" + hull.name + "</span>";
// var tower = vgap.isTowTarget(ship.id);
if (ship.ownerid != vgap.player.id && !vgap.fullallied(ship.ownerid) && !vgap.editmode) {
const ago = vgap.game.turn - ship.infoturn;
html += "<div><strong>Seen: Turn " + ship.infoturn + " (" + ago + " turn" + (ago > 1 ? "s" : "") + " ago)</strong></div>";
html += "<hr/><div>" + race.shortname + "<br/>(" + player.username + ")</div>";
if (ship.heading > 0)
html += "<div class='lval heading'>" + ship.heading + "</div>";
html += "<div class='lval crew'>" + ( ship.crew == -1 ? '?' : ship.crew ) + "/" + hull.crew + "</div>";
if (ship.damage > 0)
html += "<div class='lval damage'>" + ship.damage + "%</div>";
if (hull.launchers > 0)
html += "<div class='lval torpedo'>" + ship.ammo + "</div>";
if (hull.fighterbays > 0)
html += "<div class='lval fighters'>" + ship.ammo + "</div>";
let minMass = ship.mass;
let maxMass = minMass;
for (let i = ship.history.length - 1; i >= 0; i--) {
if (ship.history[i].mass < minMass) minMass = ship.history[i].mass;
if (ship.history[i].mass > maxMass) maxMass = ship.history[i].mass;
}
html += "<div class='lval mass'>" + ship.mass + " kt" +
(minMass != ship.mass || maxMass != ship.mass ? ' (' + minMass + '-' + maxMass + ')' : '') + "</div>";
}
else if (race.id == 12) {
let cargoType = vgap.podCargoType(ship.hullid);
let cargoName = cargoType;
if (cargoType == "nativeclans")
cargoName = "native clans";
html += "<div class='lval " + cargoType + "'><b>" + cargoName + "</b>" + ship.clans + "</div>";
if (hull.fighterbays > 0) {
let fighters = Math.floor((ship.clans / hull.cargo) * 10 * hull.fighterbays) + 10;
html += "<div class='lval fighters'>" + fighters + "</div>";
}
}
/*
html += "<div class='lval crew'>" + ship.crew + "/" + hull.crew + "</div>";
if (ship.damage > 0)
html += "<div class='lval damage'>" + ship.damage + "%</div>";
}
if (vgap.gameUsesFuel())
html += "<div class='lval neu'>" + ship.neutronium + "</div>";
if (vgap.gameUsesSupplies())
html += "<div class='lval supplies' " + (ship.supplies == 0 ? "style='display:none;'" : "") + ">" + ship.supplies + "</div>";
html += "<div class='lval mc' " + (ship.megacredits == 0 ? "style='display:none;'" : "") + ">" + ship.megacredits + "</div>";
html += "<div class='lval dur' " + (ship.duranium == 0 ? "style='display:none;'" : "") + ">" + ship.duranium + "</div>";
html += "<div class='lval tri' " + (ship.tritanium == 0 ? "style='display:none;'" : "") + ">" + ship.tritanium + "</div>";
html += "<div class='lval mol' " + (ship.molybdenum == 0 ? "style='display:none;'" : "") + ">" + ship.molybdenum + "</div>";
html += "<div class='lval clans' " + (ship.clans == 0 ? "style='display:none;'" : "") + ">" + ship.clans + "</div>";
*/
/*
if (vgap.gameUsesAmmo()) {
if (hull.launchers > 0)
html += "<div class='lval torpedo'>" + ship.ammo + "</div>";
if (hull.fighterbays > 0)
html += "<div class='lval fighters'>" + ship.ammo + "</div>";
}
*/
// if (tower != null)
// html += "<div style='color:#990099;margin-top:10px;'>" + nu.t.towedbyship + " s" + tower.id + "</div>";
if (note != null) html += "<hr/><div class='GoodTextNote'>" + note.body.replace(/\n/g, "<br/>") + "</div>";
html += "</div>";
return html;
},
/** PERSISTENCE */
/**
* Load plugin data from storage or initialize empty list
* @returns {shipList}
*/
load: function () {
/**
* get from VGAP note
* will not work when looping - notes in time machine don't get written
* so disabled in earlier turns
*/
if (vgap.game.turn == vgap.settings.turn && !this.doLoop) {
let data = this.fromNote('data');
if (data) {
this.ships = data.ships;
this.settings = data.settings;
this.firstTurn = data.firstTurn;
this.lastTurn = data.lastTurn;
this.enabled = true;
return this;
}
} else {
console.log('Ship List: [2022] (load) Time Machine: Notes Disabled.')
}
// get from Local Storage
let str = this.fromStorage('data');
if (str) {
try {
if (this.settings.debugMode) console.log(str);
let data = JSON.parse(str);
this.ships = data.ships;
this.settings = data.settings;
this.firstTurn = data.firstTurn;
this.lastTurn = data.lastTurn;
this.enabled = true;
console.log('Ship List: [2001] (load) Loaded Game Data from Local Storage.')
this.save(); // toNote
} catch (e) {
console.log('Ship List: [4001] (load) Corrupt Local Storage Game Data.');
console.log(str);
}
if (this.settings.debugMode) console.log(this);
return this;
}
// compatibility mode
console.log('Ship List: [2002] (load) Compatibility Mode.')
this.storagePath = this.importPrefix + vgap.gameId + '.' + vgap.player.id + '.';
const stored_version = this.fromStorage('version');
const stored_list = this.fromStorage('shiplist');
const stored_turn = this.fromStorage('turn');
const first_turn = this.fromStorage('firstturn');
if (stored_version) {
this.enabled = true;
this.ships = JSON.parse(stored_list);
this.lastTurn = parseInt(stored_turn);
this.firstTurn = parseInt(first_turn);
if (stored_version < 1.40) {
for (let i = this.ships.length - 1; i >= 0; i--) {
this.ships[i].history = [];
}
}
this.doImport = true;
console.log('Ship List: [2003] (load) Converting Game Data.');
if (this.settings.deleteAfterImport) this.deleteGame(vgap.gameId, vgap.player.id);
this.storagePath = this.storagePrefix + vgap.gameId + '.' + vgap.player.id + '.';
this.save();
this.doImport = false;
} else {
this.storagePath = this.storagePrefix + vgap.gameId + '.' + vgap.player.id + '.';
console.log('Ship List: [2004] (load) No Game Data Found.');
this.reInitialize();
}
if (this.settings.debugMode) console.log(this);
return this;
},
/**
* Save plugin data to local storage
* @returns {shipList}
*/
save: function () {
if (!this.enabled) return this;
console.log('Ship List: [2018] (save) Saving Game Data.')
const data = {
version: this.version,
ships: this.ships,
firstTurn: this.firstTurn,
lastTurn: this.lastTurn,
gameName: this.gameName,
playerName: this.playerName,
raceName: this.raceName,
settings: this.settings
};
if (this.settings.debugMode) console.log(data);
// saving notes in time machine does f*all
if (vgap.game.turn == vgap.nowTurn) {
this.toNote('data', data);
} else {
console.log('Ship List: [2021] (save) Time Machine: Notes Disabled.')
}
const old = this.fromStorage('data');
try {
this.toStorage('data', JSON.stringify(data));
} catch (e) {
this.toStorage(old);
// abort loop
if (this.doLoop) {
this.doLoop = false;
}
nu.info([
'Your browser has run out of Local Storage space. ',
'Please go to the "Storage" tab to delete data, ',
'then try re-enabling the plugin.'
].join(''), this.pluginName + ' Error 4002: No Storage Available.', 400);
}
return this;
},
/**
* Get from local storage
* @param key
* @returns {*}
*/
fromStorage: function (key) {
if ($.isPlainObject(key)) {
const self = this;
$.each(key, function (k, v) {
v = localStorage.getItem(self.storagePath + k);
});
return key;
}
return localStorage.getItem(this.storagePath + key);
},
/**
* Save to local storage
* @param key
* @param data
* @returns {*}
*/
toStorage: function (key, data) {
// hash
if ($.isPlainObject(key)) {
const self = this;
$.each(key, function (k, v) {
localStorage.setItem(self.storagePath + k, v);
});
return key;
}
// 2 arguments
localStorage.setItem(this.storagePath + key, data);
return data;
},
/** Thanks to McNimble for the pointers to using notes. */
/** Get data from VGAP notes */
fromNote: function (key) {
console.log('Ship List: [1005] (fromNote) Loading VGAP Note.');
try {
let noteId = 0;
let arr = [];
let chunks = JSON.parse(vgap.getNote(noteId--, this.noteType).body).chunks;
for (let i = 0; i < chunks; i++) {
arr.push(vgap.getNote(noteId--, this.noteType).body);
}
let obj = JSON.parse(arr.join(''));
console.log('Ship List: [2005] (fromNote) VGAP Note Read Success.');
return obj[key];
} catch (e) {
console.log('Ship List: [5005] (fromNote) VGAP Note Read Error.');
console.log(e.name + ' ' + e.message);
console.trace();
}
},
/** Save data to VGAP notes */
toNote: function (key, value) {
console.log('Ship List: [1006] (toNote) Saving VGAP Note.');
try {
let noteId = 0;
let obj = {};
obj[key] = value;
let match = JSON.stringify(obj).match(/.{1,16384}/g);
let chunks = match.length;
let note = vgap.getNote(noteId--, this.noteType);
note.body = JSON.stringify({chunks: chunks});
note.changed = 1;
for (let i = 0; i < chunks; i++) {
note = vgap.getNote(noteId--, this.noteType);
note.body = match[i];
note.changed = 1;
}
vgap.save();
console.log('Ship List: [2006] (toNote) VGAP Note Save Success.');
} catch (e) {
console.log('Ship List: [5006] (toNote) VGAP Note Save Error.');
console.log(e.name + ' ' + e.message);
console.trace();
}
},
/** UI HANDLERS / UTILITIES */
/**
* Delete data for a given game and player
* @param gameId int
* @param playerId int
* @returns {shipList}
*/
deleteGame: function (gameId, playerId) {
console.log('Ship List: [2019] (deleteGame) Deleting Game Data.');
const path = this.storagePrefix + '.' + gameId + '.' + playerId + '.';
if (this.doImport) {
let keys = ['version', 'shiplist', 'turn', 'firstturn', 'player', 'race', 'game_name'];
for (let i = keys.length - 1; i >= 0; i--) {
localStorage.removeItem(path + keys[i]);
}
} else {
localStorage.removeItem(path + data);
}
if (gameId == vgap.gameId && playerId == vgap.player.id) {
this.reInitialize();
this.enabled = false;
}
return this;
},
/**
* Delete all game data from local storage
* @returns {shipList}
*/
deleteAllGames: function () {
console.log('Ship List: [2020] (deleteAllGames) Deleting Game Data.');
let prefix = this.storagePrefix;
let re = new RegExp(prefix + '\\d+\\.\\d+\\.data');
for (let key in localStorage) {
if (re.test(key)) localStorage.removeItem(key);
}
return this;
},
/**
* Delete a ship (ship form)
* @param id id of ship to remove
* @returns {vgap.plugin.shipList}
*/
deleteShip: function (id) {
for (let i = this.ships.length - 1; i >= 0; i--) {
if (this.ships[i].id == id) {
this.ships.splice(i, 1);
break;
}
}
this.save();
return this;
},
/**
* Enable plugin
* @returns {shipList}
*/
enable: function () {
/** @todo Remove Local Storage check once we switch entirely to notes */
try {
localStorage.setItem(this.storagePrefix, this.version);
} catch (err) {
nu.info([
'Your browser has run out of Local Storage space. ',
'Please go to the "Storage" tab to delete data, ',
'then try re-enabling the plugin.'
].join(''), this.pluginName + ' Error 4001: No Storage Available.', 400);
} finally {
localStorage.removeItem(this.storagePrefix);
}
this.enabled = true;
return this;
},
/** Exports all game data to JSON */
exportGameData: function () {
const pluginData = {};
for (let key in localStorage) {
if (key.indexOf(this.storagePrefix) != -1) {
pluginData[key] = localStorage.getItem(key);
}
}
let blob = new Blob([JSON.stringify(pluginData)], {type: 'text/json;charset=utf-8'});
/** @namespace window.URL.createObjectURL */
let url = window.URL.createObjectURL(blob);
let a = $('<a style="display:none" href="' + url + '" download="ShipList.json"></a>')
.appendTo($('#MessageInbox'))
;
// jQuery click doesn't work for default event
a[0].click();
a.remove();
/** @namespace window.URL.revokeObjectURL */
window.URL.revokeObjectURL(url);
},
/** Import JSON game data */
importGameData: function () {
console.log('Ship List: [2007] (importGameData) Starting Import.');
let fileInput = $('#fileInput');
if (fileInput[0].files.length == 0) return;
const file = fileInput[0].files[0];
const read = new FileReader();
const self = this;
// reset fileInput
fileInput.val('');
read.onload = function () {
let obj;
try {
obj = JSON.parse(read.result.toString())
}
catch (err) {
nu.info([
file.name + ' does not contain valid JSON data. ',
'Please try again with a correct game export file.'
].join(''), this.pluginName + ' Error 4002: Invalid JSON.', 400);
return;
}
console.log(obj);
// load saved plugin data
const pluginData = {};
for (let key in localStorage) {
if (key.indexOf(self.storagePrefix) != -1) {
pluginData[key] = localStorage.getItem(key);
}
}
// remove all plugin data
self.deleteAllGames();
// save uploaded data
let err;
$.each(obj, function (key, val) {
if (key.indexOf(self.storagePrefix) != 0) {
err = true;
return false;
}
localStorage.setItem(key, val);
return true;
});
// revert if an error occurred
if (err) {
self.deleteAllGames();
self.enabled = true;
$.each(pluginData, function (key, val) {
localStorage.setItem(key, val);
});
nu.info([
file.name + ' does not contain valid ' + this.pluginName + ' data. ',
'Please try again with a correct game export file.'
].join(''), this.pluginName + ' Error 4003: Invalid Game Data.', 400);
return;
}
self.enabled = true;
self.showShips(8);
};
read.readAsText(file);
},
/**
* Start looping through turns
* @param turn
* @returns {shipList}
*/
initLoop: function (turn) {
if (!turn) turn = this.lastTurn + 1;
if (turn < 1 || turn > vgap.nowTurn) return this;
if (turn == vgap.nowTurn) {
vgap.loadNow();
} else {
this.doLoop = true;
console.log('Ship List: [2015] (initLoop) Looping from turn ' + turn + ' to ' + vgap.nowTurn + '.');
vgap.loadHistory(turn);
}
return this;
},
/**
* get scoreboard info for player
* @param id
* @param type
* @returns {*}
*/
playerInfo: function (id, type) {
for (let i = vgap.scores.length - 1; i >= 0; i--) {
if (vgap.scores[i].ownerid == id) {
return vgap.scores[i][type];
}
}
return 0;
},
/**
* Empty ship list and update from given turn
* @param turn int
* @returns {shipList}
*/
rebuildShips: function (turn) {
console.log('Ship List: [2009] (rebuildShips) Updating from turn ' + turn + '.');
if (!turn) turn = vgap.game.turn;
if (turn > vgap.nowTurn || turn < 1) return this;
this.doReset = true;
this.initLoop(turn);
return this;
},
/**
* Reset game defaults
* @returns {shipList}
*/
reInitialize: function () {
console.log('Ship List: [2016] (reInitialize) Reinitializing.');
this.ships = [];
this.firstTurn = vgap.game.turn;
this.lastTurn = vgap.game.turn - 1;
this.maxShipId = vgap.settings.shiplimit;
if (this.settings.debugMode) console.log(this);
return this;
},
/**
* Empty ship list and update from current turn
* @returns {shipList}
*/
resetShips: function () {
console.log('Ship List: [2008] (resetShips) Updating from current turn.');
this.ships = [];
this.firstTurn = vgap.game.turn;
this.lastTurn = vgap.game.turn - 1;
this.updateShips();
vgap.showDashboard();
return this;
},
/**
* Save a ship (ship form)
* @param ship {*} ship
* @param update boolean
* @returns {vgap.plugin.shipList}
*/
saveShip: function (ship, update) {
for (let i = this.ships.length - 1; i >= 0; i--) {
if (this.ships[i].id == ship.id) {
if (update) {
this.ships.splice(i, 1);
break;
} else {
return this;
}
}
}
this.ships.push(ship);
this.ships.sort(function (a, b) {
return (a.id - b.id);
});
this.save();
return this;
},
/** TOGGLES */
/** Toggles adding ship history to notes */
toggleAddShipHistory: function () {
this.settings.addShipHistory = !this.settings.addShipHistory;
return this.save();
},
/** Toggles between colored text and background */
toggleColoredText: function () {
this.settings.showColoredText = !this.settings.showColoredText;
return this.save();
},
/** Toggles compact tables */
toggleCompactTable: function () {
this.settings.showCompactTable = !this.settings.showCompactTable;
return this.save();
},
/** Toggles debug mode */
toggleDebugMode: function () {
this.settings.debugMode = !this.settings.debugMode;
return this.save();
},
/** Toggles removal of older data */
toggleDeleteAfterImport: function () {
this.settings.deleteAfterImport = !this.settings.deleteAfterImport;
return this.save();
},
/** Toggles edit in single player view */
toggleEdit: function () {
this.editMode = !this.editMode;
return this.save();
},
/** Toggles full allies */
toggleFullAllies: function () {
this.settings.showFullAllies = !this.settings.showFullAllies;
return this.save();
},
/** Toggles between colored text and background */
toggleLocationHistory: function () {
this.settings.showLocationHistory = !this.settings.showLocationHistory;
return this.save();
},
/** Toggles player buttons */
toggleMapTool: function () {
const plugin = vgap.plugins.shipList;
if (plugin.togglesShown) $("#playerToggles").remove();
else plugin.showMapTool();
plugin.togglesShown = !plugin.togglesShown;
},
/** Toggles own ships */
toggleOwnShips: function () {
this.settings.showOwnShips = !this.settings.showOwnShips;
return this.save();
},
/**
* Toggle player ships on starmap
* @param id int player id
*/
togglePlayer: function (id) {
if (id < 0 || id > vgap.players.length) return;
this.playerToggles[id] = !this.playerToggles[id];
if (id == 0) { // all
for (let i = this.playerToggles.length - 1; i >= 1; i--) {
this.playerToggles[i] = this.playerToggles[id];
}
} else { // set state of "all" toggle
this.playerToggles[0] = true;
for (let i = this.playerToggles.length - 1; i >= 1; i--) {
if (!this.playerToggles[i]) {
this.playerToggles[0] = false;
}
}
}
this.showMapTool();
vgap.map.draw();
},
/** Toggles safe passage */
toggleSafePassage: function () {
this.settings.showSafePassage = !this.settings.showSafePassage;
return this.save();
},
/** Toggles share intel */
toggleShareIntel: function () {
this.settings.showShareIntel = !this.settings.showShareIntel;
return this.save();
},
/** Toggles unknown ships */
toggleUnknown: function () {
this.settings.showUnknown = !this.settings.showUnknown;
return this.save();
},
/** Toggles between horizontal and vertical buttons */
toggleVerticalButtons: function () {
this.settings.showVerticalButtons = !this.settings.showVerticalButtons;
return this.save();
},
}; // end shipList
/** register the plugin */
vgap.registerPlugin(shipList, "shipList");
/** OVERLOADED nu.js FUNCTIONS */
/**
* Overload to clear player toggles
* @@namespace vgap.plugins.shipList
*/
let fn1 = vgapMap.prototype.clearTools;
vgapMap.prototype.clearTools = function (result) {
const plugin = vgap.plugins.shipList;
for (let i = 0; i < plugin.playerToggles.length; i++) {
plugin.playerToggles[i] = false;
}
plugin.togglesShown = false;
$("#playerToggles").remove();
// call nu.js clearTools
/** @type Function */
fn1.apply(this, arguments);
};
/**
* Overload to loop through turns
* @@namespace vgap.plugins.shipList
*/
let fn2 = vgaPlanets.prototype.processLoadHistory;
vgaPlanets.prototype.processLoadHistory = function (result) {
const plugin = vgap.plugins.shipList;
//call nu.js processLoadHistory
/** @type Function */
fn2.apply(this, arguments);
if (plugin.doLoop) {
if (!result.success) {
console.log('Ship List: [5010] (processLoadHistory) Error loading turn. Aborting rebuild.');
console.trace();
plugin.doReset = false;
plugin.doLoop = false;
return;
}
console.log('Ship List: [2010] (processLoadHistory) Next Turn: ' + (this.settings.turn + 1) + '/' + this.nowTurn + '.');
if (this.settings.turn + 1 == this.nowTurn) {
this.loadNow();
} else {
this.loadHistory(this.settings.turn + 1);
}
}
};
/**
* Overload showScan function to show ships seen in previous turns
* @@namespace vgap.plugins.shipList
*/
let fn3 = sharedContent.prototype.showScan;
sharedContent.prototype.showScan = function (x, y, target, lock) {
const plugin = vgap.plugins.shipList;
const pane = vgap.list.first();
let ships = plugin.shipsAt(x, y, false);
/** @type Function */
fn3.apply(this, arguments);
for (let i = ships.length - 1; i >= 0; i--) {
$(plugin.shipScan(ships[i], true)).appendTo(pane);
}
ships = plugin.shipsAt(x, y, true);
for (let i = ships.length - 1; i >= 0; i--) {
const ship = ships[i];
if (!ship.history || !plugin.settings.showLocationHistory ||
plugin.shipsDrawn.indexOf(ship.id) != -1
) continue;
let x1 = ship.x;
let y1 = ship.y;
let opacity = 1;
const ctx = vgap.map.ctx;
for (let i = 0; i < ship.history.length; i++) {
let loc = ship.history[i];
let x2 = loc.x;
let y2 = loc.y;
opacity *= 0.75;
if (opacity < 0.25) opacity = 0.25;
ctx.strokeStyle = colorToRGBA("#ADD8E6", opacity);
ctx.lineWidth = 1;
ctx.beginPath();
ctx.dashedLine(vgap.map.screenX(x1), vgap.map.screenY(y1), vgap.map.screenX(x2), vgap.map.screenY(y2), [5, 3]);
ctx.closePath();
ctx.stroke();
if (loc.turn != vgap.game.turn && loc.turn != ship.infoturn) vgap.map.drawOffsetText(x2, y2, 'T' + loc.turn, 0, -10);
x1 = x2;
y1 = y2;
}
plugin.shipsDrawn.push(ship.id);
}
}
} //script for injection
let el = document.createElement("script");
el.type = "application/javascript";
el.textContent = "(" + script + ")(vgap,$);";
document.body.appendChild(el);
document.body.removeChild(el);