diff --git a/app/js/app.js b/app/js/app.js index 96d218ee..1a691aa5 100755 --- a/app/js/app.js +++ b/app/js/app.js @@ -1,6 +1,6 @@ angular.module('app', ['ui.router', 'ct.ui.router.extras.sticky', 'ui.sortable', 'shipyard', 'ngLodash', 'app.templates']) -.run(['$rootScope', '$location', '$window', '$document', '$state', 'commonArray', 'shipPurpose', 'shipSize', 'hardPointClass', 'GroupMap', 'Persist', -function($rootScope, $location, $window, $doc, $state, CArr, shipPurpose, sz, hpc, GroupMap, Persist) { +.run(['$rootScope', '$location', '$window', '$document', '$state', 'commonArray', 'shipPurpose', 'shipSize', 'hardPointClass', 'GroupMap', 'Persist', 'Discounts', +function($rootScope, $location, $window, $doc, $state, CArr, shipPurpose, sz, hpc, GroupMap, Persist, Discounts) { // App is running as a standalone web app on tablet/mobile var isStandAlone; // This was causing issues on Windows phones ($window.external was causing Angular js to throw an exception). Backup is to try this and set isStandAlone to false if this fails. @@ -40,7 +40,7 @@ function($rootScope, $location, $window, $doc, $state, CArr, shipPurpose, sz, hp $rootScope.HPC = hpc; $rootScope.GMAP = GroupMap; $rootScope.insurance = { opts: [{ name: 'Standard', pct: 0.05 }, { name: 'Alpha', pct: 0.025 }, { name: 'Beta', pct: 0.035 }] }; - $rootScope.discounts = { opts: [{ name: 'None', pct: 1 }, { name: 'Founders World - 10%', pct: 0.90 }] }; + $rootScope. discounts = { opts: Discounts }; $rootScope.STATUS = ['', 'DISABLED', 'OFF', 'ON']; $rootScope.STATUS_CLASS = ['', 'disabled', 'warning', 'secondary-disabled']; $rootScope.title = 'Coriolis'; diff --git a/app/js/controllers/controller-outfit.js b/app/js/controllers/controller-outfit.js index 91445217..da571241 100755 --- a/app/js/controllers/controller-outfit.js +++ b/app/js/controllers/controller-outfit.js @@ -11,6 +11,8 @@ angular.module('app').controller('OutfitController', ['$window', '$rootScope', ' ship.buildWith(data.defaults); // Populate with default components } + ship.applyDiscounts($rootScope.discounts.ship, $rootScope.discounts.components); + $scope.buildName = $p.bn; $rootScope.title = ship.name + ($scope.buildName ? ' - ' + $scope.buildName : ''); $scope.ship = ship; @@ -280,4 +282,9 @@ angular.module('app').controller('OutfitController', ['$window', '$rootScope', ' $scope.selectedSlot = null; }); + // Hide any open menu/slot/etc if the background is clicked + $scope.$on('discountChange', function() { + ship.applyDiscounts($rootScope.discounts.ship, $rootScope.discounts.components); + }); + }]); diff --git a/app/js/directives/directive-header.js b/app/js/directives/directive-header.js index 0925089a..d8f5f039 100755 --- a/app/js/directives/directive-header.js +++ b/app/js/directives/directive-header.js @@ -13,8 +13,10 @@ angular.module('app').directive('shipyardHeader', ['lodash', '$rootScope', 'Pers scope.bs = Persist.state; var insIndex = _.findIndex($rootScope.insurance.opts, 'name', Persist.getInsurance()); + var savedDiscounts = Persist.getDiscount() || [1, 1]; $rootScope.insurance.current = $rootScope.insurance.opts[insIndex != -1 ? insIndex : 0]; - $rootScope.discounts.current = $rootScope.discounts.opts[Persist.getDiscount() || 0]; + $rootScope.discounts.ship = savedDiscounts[0]; + $rootScope.discounts.components = savedDiscounts[1]; // Close menus if a navigation change event occurs $rootScope.$on('$stateChangeStart', function() { @@ -38,7 +40,8 @@ angular.module('app').directive('shipyardHeader', ['lodash', '$rootScope', 'Pers * Save selected discount option */ scope.updateDiscount = function() { - Persist.setDiscount($rootScope.discounts.opts.indexOf($rootScope.discounts.current)); + Persist.setDiscount([$rootScope.discounts.ship, $rootScope.discounts.components]); + $rootScope.$broadcast('discountChange'); }; scope.openMenu = function(e, menu) { diff --git a/app/js/service-persist.js b/app/js/service-persist.js index 6e065377..0158b7d2 100755 --- a/app/js/service-persist.js +++ b/app/js/service-persist.js @@ -189,7 +189,7 @@ angular.module('app').service('Persist', ['$window', 'lodash', function($window, */ this.setDiscount = function(val) { if (this.lsEnabled) { - return localStorage.setItem('discount', val); + return localStorage.setItem('discounts', angular.toJson(val)); } }; @@ -199,7 +199,7 @@ angular.module('app').service('Persist', ['$window', 'lodash', function($window, */ this.getDiscount = function() { if (this.lsEnabled) { - return localStorage.getItem('discount'); + return angular.fromJson(localStorage.getItem('discounts')); } return null; }; diff --git a/app/js/shipyard/factory-ship.js b/app/js/shipyard/factory-ship.js index c75f004e..871816fa 100755 --- a/app/js/shipyard/factory-ship.js +++ b/app/js/shipyard/factory-ship.js @@ -28,7 +28,7 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', function Ship(id, properties, slots) { this.id = id; this.cargoScoop = { c: Components.cargoScoop(), type: 'SYS' }; - this.bulkheads = { incCost: true, maxClass: 8, discount: 1 }; + this.bulkheads = { incCost: true, maxClass: 8 }; for (var p in properties) { this[p] = properties[p]; } // Copy all base properties from shipData @@ -36,10 +36,11 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', var slotGroup = slots[slotType]; var group = this[slotType] = []; // Initialize Slot group (Common, Hardpoints, Internal) for (var i = 0; i < slotGroup.length; i++) { - group.push({ id: null, c: null, incCost: true, maxClass: slotGroup[i], discount: 1 }); + group.push({ id: null, c: null, incCost: true, maxClass: slotGroup[i] }); } } - this.c = { incCost: true, discount: 1, c: { name: this.name, cost: this.cost } }; // Make a 'Ship' component similar to other components + // Make a Ship 'slot'/item similar to other slots + this.c = { incCost: true, type: 'SHIP', discountedCost: this.cost, c: { name: this.name, cost: this.cost } }; this.costList = _.union(this.internal, this.common, this.hardpoints); this.costList.push(this.bulkheads); // Add The bulkheads @@ -54,6 +55,9 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', this.powerList.unshift(this.common[2]); // Add FSD this.powerList.unshift(this.common[0]); // Add Power Plant + this.shipDiscount = 1; + this.componentDiscount = 1; + this.priorityBands = [ { deployed: 0, retracted: 0, retOnly: 0 }, { deployed: 0, retracted: 0, retOnly: 0 }, @@ -81,7 +85,7 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', this.ladenMass = 0; this.armourAdded = 0; this.shieldMultiplier = 1; - this.totalCost = this.cost; + this.totalCost = this.c.incCost ? this.c.discountedCost : 0; this.unladenMass = this.mass; this.armourTotal = this.armour; @@ -106,6 +110,7 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', common[i].priority = priorities ? priorities[i + 1] * 1 : 0; common[i].type = 'SYS'; common[i].c = common[i].id = null; // Resetting 'old' component if there was one + common[i].discountedCost = 0; this.use(common[i], comps.common[i], Components.common(i, comps.common[i]), true); } @@ -119,6 +124,7 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', hps[i].priority = priorities ? priorities[cl + i] * 1 : 0; hps[i].type = hps[i].maxClass ? 'WEP' : 'SYS'; hps[i].c = hps[i].id = null; // Resetting 'old' component if there was one + hps[i].discountedCost = 0; if (comps.hardpoints[i] !== 0) { this.use(hps[i], comps.hardpoints[i], Components.hardpoints(comps.hardpoints[i]), true); @@ -133,6 +139,7 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', internal[i].priority = priorities ? priorities[cl + i] * 1 : 0; internal[i].type = 'SYS'; internal[i].id = internal[i].c = null; // Resetting 'old' component if there was one + internal[i].discountedCost = 0; if (comps.internal[i] !== 0) { this.use(internal[i], comps.internal[i], Components.internal(comps.internal[i]), true); @@ -149,6 +156,7 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', var oldBulkhead = this.bulkheads.c; this.bulkheads.id = index; this.bulkheads.c = Components.bulkheads(this.id, index); + this.bulkheads.discountedCost = this.bulkheads.c.cost * this.componentDiscount; this.updateStats(this.bulkheads, this.bulkheads.c, oldBulkhead, preventUpdate); }; @@ -171,11 +179,13 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', if (!preventUpdate && similarSlot && similarSlot !== slot) { this.updateStats(similarSlot, null, similarSlot.c, true); // Update stats but don't trigger a global update similarSlot.id = similarSlot.c = null; // Empty the slot + similarSlot.discountedCost = 0; } } var oldComponent = slot.c; slot.id = id; slot.c = component; + slot.discountedCost = (component && component.cost) ? component.cost * this.componentDiscount : 0; this.updateStats(slot, component, oldComponent, preventUpdate); } }; @@ -232,7 +242,7 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', Ship.prototype.setCostIncluded = function(item, included) { if (item.incCost != included && item.c) { - this.totalCost += included ? item.c.cost : -item.c.cost; + this.totalCost += included ? item.discountedCost : -item.discountedCost; } item.incCost = included; }; @@ -292,7 +302,7 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', } if (slot.incCost && old.cost) { - this.totalCost -= old.cost; + this.totalCost -= old.cost * this.componentDiscount; } if (old.power && slot.enabled) { @@ -322,7 +332,7 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', } if (slot.incCost && n.cost) { - this.totalCost += n.cost; + this.totalCost += n.cost * this.componentDiscount; } if (n.power && slot.enabled) { @@ -377,5 +387,28 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', this.maxJumpCount = Math.ceil(this.fuelCapacity / fsd.maxfuel); }; + /** + * Recalculate all item costs and total based on discounts. + * @param {number} shipDiscount Ship cost multiplier discount (e.g. 0.9 === 10% discount) + * @param {number} componentDiscount Component cost multiplier discount (e.g. 0.75 === 25% discount) + */ + Ship.prototype.applyDiscounts = function(shipDiscount, componentDiscount) { + var total = 0; + var costList = this.costList; + + for (var i = 0, l = costList.length; i < l; i++) { + var item = costList[i]; + if (item.c && item.c.cost) { + item.discountedCost = item.c.cost * (item.type == 'SHIP' ? shipDiscount : componentDiscount); + if (item.incCost) { + total += item.discountedCost; + } + } + } + this.shipDiscount = shipDiscount; + this.componentDiscount = componentDiscount; + this.totalCost = total; + }; + return Ship; }]); diff --git a/app/js/shipyard/module-shipyard.js b/app/js/shipyard/module-shipyard.js index 8c98dad4..d648be5d 100755 --- a/app/js/shipyard/module-shipyard.js +++ b/app/js/shipyard/module-shipyard.js @@ -165,6 +165,19 @@ angular.module('shipyard', ['ngLodash']) fmt: 'fRound' } ]) + /** + * Set of all available / theoretical discounts + * + * @type {Object} + */ + .value('Discounts', { + 'None': 1, + '5%': 0.95, + '10%': 0.90, + '15%': 0.85, + '20%': 0.80, + '25%': 0.75 + }) /** * Calculate the maximum single jump range based on mass and a specific FSD * diff --git a/app/less/outfit.less b/app/less/outfit.less index c3577177..86066253 100755 --- a/app/less/outfit.less +++ b/app/less/outfit.less @@ -139,11 +139,6 @@ table.total { font-weight: normal; } - tbody tr:hover { - background-color: @warning-bg; - } - - .smallTablet({ width: 50%; }); diff --git a/app/less/table.less b/app/less/table.less index d9ddc0c4..bb0af584 100755 --- a/app/less/table.less +++ b/app/less/table.less @@ -43,7 +43,6 @@ thead { } } - tbody tr { &.tr { @@ -55,6 +54,12 @@ tbody tr { } } + &.highlight { + &:hover { + background-color: @warning-bg; + } + } + td { line-height: 1.4em; padding: 0 0.3em; diff --git a/app/views/_header.html b/app/views/_header.html index ce8d926f..8d0d9eb1 100755 --- a/app/views/_header.html +++ b/app/views/_header.html @@ -53,8 +53,12 @@
| Component | -Credits | +
+ Component
+
+ [Ship {{fRPct(1 - discounts.ship)}} off]
+ [Components {{fRPct(1 - discounts.components)}} off]
+
+ |
+ Credits | ||
|---|---|---|---|---|---|
| {{c.c.class}}{{c.c.rating}} | -- | {{fCrd(discounts.current.pct * c.c.cost)}} CR | +|||
| {{item.c.class}}{{item.c.rating}} | +{{cName(item)}} | +{{fCrd(item.discountedCost)}} CR | |||
| Total | -{{fCrd(ship.totalCost * discounts.current.pct)}} CR | +{{fCrd(ship.totalCost)}} CR |
| Insurance | -{{fCrd(ship.totalCost * discounts.current.pct * insurance.current.pct)}} CR | +{{fCrd(ship.totalCost * insurance.current.pct)}} CR |