diff --git a/devTools/types/FC/financial.d.ts b/devTools/types/FC/financial.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..ab8535a32cdf82d91c841bf41cf21add10b29827 --- /dev/null +++ b/devTools/types/FC/financial.d.ts @@ -0,0 +1,18 @@ +declare namespace FC { + interface Loan { + /** The lender's name. */ + name: 'bank' | 'shark'; + /** The amount they've lent. */ + principal: number; + /** The week on which repayment is due. */ + deadline: number; + /** The number of installments remaining until the full amount is paid. */ + installments: number; + /** The Annual Percentage Rate. */ + apr: number; + /** The amount of interest the loan will accumulate. */ + interest: number; + /** The full amount that will be paid. */ + full: number; + } +} diff --git a/js/003-data/gameVariableData.js b/js/003-data/gameVariableData.js index c8878213d5cda0ed6b2a71d4f4033d5aed4d570d..0d40cceddf39936e8731119659aee42932288d2f 100644 --- a/js/003-data/gameVariableData.js +++ b/js/003-data/gameVariableData.js @@ -1342,5 +1342,10 @@ App.Data.resetOnNGPlus = { * @type {Object.<number, string>} */ choosesOwnAssignmentText: {}, - favorites: [] + favorites: [], + /** + * Any loans the player has taken out. + * @type {FC.Loan[]} + */ + loans: [], }; diff --git a/src/002-config/fc-version.js b/src/002-config/fc-version.js index 4d7974bc7d2dabc239491d820f86bfd1519c85c7..664f0ebf356a7e6433de4995da8fc9d0f2a3cb42 100644 --- a/src/002-config/fc-version.js +++ b/src/002-config/fc-version.js @@ -2,5 +2,5 @@ App.Version = { base: "0.10.7.1", // The vanilla version the mod is based off of, this should never be changed. pmod: "4.0.0-alpha.13", commitHash: null, - release: 1162, // When getting close to 2000, please remove the check located within the onLoad() function defined at line five of src/js/eventHandlers.js. + release: 1163, // When getting close to 2000, please remove the check located within the onLoad() function defined at line five of src/js/eventHandlers.js. }; diff --git a/src/budget/costsBudget.js b/src/budget/costsBudget.js index 0a7f9e508bfa9eea70ad19145d448ca6dc21c63f..03bb29fb5c79d997c79a694dc99c317ee74fc144 100644 --- a/src/budget/costsBudget.js +++ b/src/budget/costsBudget.js @@ -3,62 +3,84 @@ * @returns {DocumentFragment} */ App.Budget.costs = function() { - const f = new DocumentFragment(); + const frag = new DocumentFragment(); - f.append( + App.UI.DOM.appendNewElement("h1", frag, `Budget`); + + frag.append( intro(), + loans(), netWorth(), ); if (V.difficultySwitch === 1) { - f.append(economy()); + frag.append(economy()); } - f.append(settings()); + frag.append(settings()); // Table of Totals if (!V.lastWeeksCashIncome) { - App.UI.DOM.appendNewElement("p", f, "Financial data currently unavailable."); + App.UI.DOM.appendNewElement("p", frag, "Financial data currently unavailable."); } else { - App.UI.DOM.appendNewElement("p", f, App.Budget.table("cash")); + App.UI.DOM.appendNewElement("p", frag, App.Budget.table("cash")); } - errors(f); - return f; + errors(frag); + return frag; + + /** + * @returns {DocumentFragment} + */ + function loans() { + const frag = new DocumentFragment(); + + frag.append(App.Budget.loans()); + + return frag; + } /** * @returns {HTMLParagraphElement} */ function intro() { - return App.UI.DOM.makeElement("p", `Here you can view many of the financial details of your arcology, ${properTitle()}. Proper cash flow is critical to the success of your long term goals. Find expensive waste here and you can change the right policies or sell off slackers. Find your next profit center and invest in new equipment, advertising, or flesh to maximize your assets.`, "scene-intro"); + return App.UI.DOM.makeElement("p", `Here you can view many of the financial details of your arcology, ${properTitle()}. Proper cash flow is critical to the success of your long term goals. Find expensive waste here and you can change the right policies or sell off slackers. Find your next profit center and invest in new equipment, advertising, or flesh to maximize your assets.`, ["scene-intro"]); } /** - * @returns {HTMLParagraphElement} + * @returns {DocumentFragment} */ function netWorth() { - const p = document.createElement("p"); + const frag = new DocumentFragment(); - p.append(`You have a total net worth of ${cashFormat(Math.trunc(App.Utils.totalNetWorth()))}.`); + frag.append( + App.UI.DOM.makeElement("h2", `Net worth`), + `You have a total net worth of ${cashFormat(Math.trunc(App.Utils.totalNetWorth()))}.` + ); if (V.debugMode) { - App.UI.DOM.appendNewElement("div", p, App.UI.DOM.link(`Recalculate net worth`, () => { + App.UI.DOM.appendNewElement("div", frag, App.UI.DOM.link(`Recalculate net worth`, () => { App.UI.reload(); }), ['indent']); } - return p; + return frag; } /** - * @returns {HTMLParagraphElement} + * @returns {DocumentFragment} */ function economy() { + const frag = new DocumentFragment(); + + App.UI.DOM.appendNewElement("h2", frag, `Economy`); + const p = document.createElement("p"); - App.UI.DOM.appendNewElement("div", p, `The Local Economy score effects some prices in your ecology. The lower the score, the higher the prices. The base score is 100.`, "scene-intro"); + + App.UI.DOM.appendNewElement("div", p, `The Local Economy score effects some prices in your ecology. The lower the score, the higher the prices. The base score is 100.`, ["scene-intro"]); const grid = document.createElement("div"); grid.className = "grid-2columns-auto"; - App.UI.DOM.appendNewElement("div", grid, "Global Economy", "cash"); + App.UI.DOM.appendNewElement("div", grid, "Global Economy", ["cash"]); if (V.cheatMode && V.cheatModeM) { const div = document.createElement("div"); div.append(App.UI.DOM.makeTextBox(V.economy, v => { @@ -70,7 +92,7 @@ App.Budget.costs = function() { App.UI.DOM.appendNewElement("div", grid, String(V.economy)); } - App.UI.DOM.appendNewElement("div", grid, "Local Economy", "cash"); + App.UI.DOM.appendNewElement("div", grid, "Local Economy", ["cash"]); if (V.cheatMode && V.cheatModeM) { const div = document.createElement("div"); div.append(App.UI.DOM.makeTextBox(V.localEcon, v => { @@ -97,7 +119,9 @@ App.Budget.costs = function() { } $(p).append(...App.Events.spaceSentences(r)); - return p; + frag.append(p); + + return frag; } /** @@ -105,7 +129,7 @@ App.Budget.costs = function() { */ function settings() { const p = document.createElement("p"); - App.UI.DOM.appendNewElement("div", p, "Your weekly costs are as follows:", "detail"); + App.UI.DOM.appendNewElement("div", p, "Your weekly costs are as follows:", ["detail"]); let options = new App.UI.OptionsGroup(); options.addOption("", "costsBudget", V.showAllEntries) @@ -123,9 +147,9 @@ App.Budget.costs = function() { const p = document.createElement("p"); p.append(App.UI.DOM.passageLink("Reset", "Costs Budget", () => { V.lastWeeksCashErrors = []; })); - App.UI.DOM.appendNewElement("div", p, "Errors:", "error"); + App.UI.DOM.appendNewElement("div", p, "Errors:", ["error"]); for (const error of V.lastWeeksCashErrors) { - App.UI.DOM.appendNewElement("div", p, error, "error"); + App.UI.DOM.appendNewElement("div", p, error, ["error"]); } container.append(p); } diff --git a/src/budget/loans.js b/src/budget/loans.js new file mode 100644 index 0000000000000000000000000000000000000000..346476dd9129ec8c8a4ec6971272900e66144bb1 --- /dev/null +++ b/src/budget/loans.js @@ -0,0 +1,170 @@ +App.Budget.loans = function() { + /** @typedef {('bank'|'shark')} Lender */ + + const frag = new DocumentFragment(); + + const loan = (/** @type {Lender} */ name) => V.loans.find(loan => loan.name === name); + + App.UI.DOM.appendNewElement("h2", frag, `Loans`); + + if (V.loans.length) { + frag.append(pay()); + } + + frag.append( + bank(), + loanshark(), + ); + + return frag; + + function pay() { + const div = document.createElement("div"); + const links = []; + const text = []; + + text.push(`You can pay off a loan here.`); + + if (loan('bank')) { + const bank = loan('bank'); + links.push(App.UI.DOM.link(`Pay off your bank loan`, () => { + cashX(forceNeg(bank.full), "loan"); + V.loans.delete(bank); + + App.UI.reload(); + }, [], '', `You have a remaining balance of ${cashFormat(Math.trunc(bank.full))}.`)); + } + if (loan('shark')) { + const shark = loan('shark'); + links.push(App.UI.DOM.link(`Pay off the loanshark`, () => { + cashX(forceNeg(shark.full), "loan"); + V.loans.delete(shark); + + App.UI.reload(); + }, [], '', `You have a remaining balance of ${cashFormat(Math.trunc(shark.full))}.`)); + } + + div.append(text.join(' ')); + App.UI.DOM.appendNewElement("div", div, App.UI.DOM.generateLinksStrip(links), ['indent']); + + return div; + } + + function bank() { + const div = document.createElement("div"); + const values = [10000, 100000, 1000000]; + const disabledReasons = []; + const links = []; + const text = []; + + let allowed = true; + + text.push(`You can take out a loan from the Free Cities Credit Union, if you have enough reputation.`); + + if (V.rep < 10000) { + disabledReasons.push(`You need at least ${num(10000)} reputation to take a loan from this lender.`); + allowed = false; + } + if (loan('bank')) { + disabledReasons.push(`You have already taken out a loan from this lender.`); + allowed = false; + } + + if (allowed) { + values.map(val => links.push(App.UI.DOM.link(cashFormat(val), () => { + const term = Math.max(val / 50000, 4); + const apr = Math.max(Math.abs((V.rep - 20000) / 500), 5); + const interest = val * (term / 52) * (apr / 100); + const full = val + interest; + V.loans.push({ + name: 'bank', + principal: val, + deadline: V.week + term, + installments: term, + apr, + interest, + full, + }); + cashX(val, "loan"); + + App.UI.reload(); + }, [], '', terms('bank', val)))); + } else { + values.map(val => links.push(App.UI.DOM.disabledLink(cashFormat(val), disabledReasons))); + } + + div.append(text.join(' ')); + App.UI.DOM.appendNewElement("div", div, App.UI.DOM.generateLinksStrip(links), ['indent']); + + return div; + } + + function loanshark() { + const div = document.createElement("div"); + const values = [10000, 100000, 1000000]; + const disabledReasons = []; + const links = []; + const text = []; + + let allowed = true; + + text.push(`If you're not quite reputable enough, you can also borrow money from one of the local loansharks in the area.`); + + if (V.rep < 2000) { + disabledReasons.push(`You need at least ${num(2000)} reputation to take a loan from this lender.`); + allowed = false; + } + if (loan('shark')) { + disabledReasons.push(`You have already taken out a loan from this lender.`); + allowed = false; + } + + if (allowed) { + values.map(val => links.push(App.UI.DOM.link(cashFormat(val), () => { + const term = Math.max(val / 50000, 4); + const apr = Math.max(Math.abs((V.rep - 20000) / 500), 5); + const interest = (val * (term / 52) * (apr / 100)) * 3; + const full = val + interest; + V.loans.push({ + name: 'shark', + principal: val, + deadline: V.week + (Math.max(val / 50000, 4)), + installments: 1, + apr, + interest, + full, + }); + cashX(val, "loan"); + + App.UI.reload(); + }, [], '', terms('shark', val)))); + } else { + values.map(val => links.push(App.UI.DOM.disabledLink(cashFormat(val), disabledReasons))); + } + + div.append(text.join(' ')); + App.UI.DOM.appendNewElement("div", div, App.UI.DOM.generateLinksStrip(links), ['indent']); + + return div; + } + + /** + * @param {Lender} lender + * @param {number} amount + */ + function terms(lender, amount) { + const term = Math.max(amount / 50000, 4); + const apr = Math.max(Math.abs((V.rep - 20000) / 500), 5); + const interest = amount * (term / 52) * (apr / 100); + const full = amount + interest; + const text = []; + + if (lender === 'bank') { + text.push(`You will pay about ${cashFormat(Math.trunc(full / term))} per week for ${num(term)} weeks until you have paid off the entire balance. If for any reason you cannot afford a payment, sectors of ${V.arcologies[0].name} will begin to be repossessed by the bank. You will end up paying back about ${cashFormat(Math.trunc(full))} after interest.`); + } else { + text.push(`You will have ${num(term)} weeks to pay off the full amount, after which the lender will send his men to collect – forcibly, if necessary. You will end up paying back about ${cashFormat(Math.trunc(amount + (interest * 3)))} after interest.`); + } + + return text.join(' '); + } +}; diff --git a/src/endWeek/economics/persBusiness.js b/src/endWeek/economics/persBusiness.js index 392d24e02aef95464dbff1a43ac68c67b4cdfc18..880cea925b65c11ac9308ca30ef7a66d1c780347 100644 --- a/src/endWeek/economics/persBusiness.js +++ b/src/endWeek/economics/persBusiness.js @@ -979,6 +979,59 @@ App.EndWeek.personalBusiness = function() { } r = []; r.push(`Routine upkeep of your demesne costs <span class="yellow">${cashFormat(V.costs)}.</span>`); + if (V.loans.length) { + const loan = (/** @type {'bank'|'shark'} */ name) => V.loans.find(loan => loan.name === name); + + if (V.loans.some(loan => loan.name === 'bank')) { + const bank = loan('bank'); + const full = bank.full; + const installment = full / bank.installments; + const sellable = V.building.findCells(cell => cell.canBeSold()); + + if (V.cash > installment) { + r.push(`You paid the Free Cities Credit Union your weekly payment of <span class="yellow">${cashFormat(Math.trunc(installment))}</span> this week.`); + } else { + if (sellable) { + r.push(`You were unable to afford your weekly payment of ${cashFormat(Math.trunc(installment))} this week. As a result, the Free Cities Credit Union has repossessed one sector of your arcology per your signed contract.`); + + sellable.pluck().owner = 0; + } else { + // not technically possible, but just in case + r.push(`You were unable to afford your weekly payment of ${cashFormat(Math.trunc(installment))} this week. Because you did not own any sectors the Free Cities Credit Union could repossess, your debt was instead put on auction and summarily purchased by another slaveholder.`); + + V.gameover = "debt"; + V.nextLink = "Gameover"; + } + } + + cashX(forceNeg(installment), "loan"); + loan('bank').full -= installment; + loan('bank').installments--; + + if (loan('bank').full > 0) { + r.push(`You now have ${years(loan('bank').installments)} to pay off your remaining balance of ${cashFormat(Math.trunc(loan('bank').full))}.`); + } else { + r.push(`Congratulations! You have paid off your full balance.`); + } + + if (loan('bank').full <= 0) { + V.loans.delete(loan('bank')); + } + } + if (V.loans.some(loan => loan.name === 'shark')) { + const bank = V.loans.some(loan => loan.name === 'bank'); + const term = loan('shark').deadline - V.week; + const full = loan('shark').full; + + r.push(`You ${bank ? `also ` : ``}still owe the local loanshark <span class="yellow">${cashFormat(Math.trunc(full))}.</span> You have ${years(term)} to pay the full amount.`); + + if (term === 1) { + r.push(`The shark will send his men next week to collect on your loan if you don't pay during the week. <span class="red">Make sure you have his money ready.</span>`); + } else if (term === 0) { + r.push(`The shark will be sending his men this week to collect his money. <span class="red">Make sure you have it ready.</span>`); + } + } + } if (V.plot === 1) { if (V.week > 10) { if (V.weatherToday.severity - V.weatherCladding > 2) { diff --git a/src/events/gameover.js b/src/events/gameover.js index d06aa105de5d446c8d12046919dea1c6d55d7228..e28d1328db9ee67eed77f9961a573e1eee447232 100644 --- a/src/events/gameover.js +++ b/src/events/gameover.js @@ -84,6 +84,10 @@ App.Events.Gameover = function() { case "starving citizens": r.push(`You made a promise to your citizens that you would be able to keep them fed, and you had been able to keep that promise – until now, that is. Your food storages have been depleted and you don't have enough money to buy enough to feed the rest of the hungry arcology. Desperate and facing starvation, your once-loyal subjects have taken to the streets, eventually finding their way to your penthouse.${V.arcologyUpgrade.drones ? ` Your drones are only able to keep them at bay for a little while before the sheer number of them overwhelms your defenses.` : ``} Your attempts to calm the crowd fail, and you find yourself wishing you had run when you had the chance as you are grabbed by the crowd and thrown through the nearest window.`); break; + case "loanshark": + r.push(`You signed a contract with the loanshark, and since you weren't able to pay with ¤ or slaves, you will spend the rest of your days working the debt off – or whatever it is the man wants to do with a former arcology owner.`); + V.slavePC = convertPlayerToSlave(V.PC); + break; default: r.push(`Since you are without slaves, Free Cities society no longer considers you a citizen of the first rank. Your personal story may continue, but that part of it worthy of retelling has now ended.`); } diff --git a/src/events/nonRandom/pLoanshark.js b/src/events/nonRandom/pLoanshark.js new file mode 100644 index 0000000000000000000000000000000000000000..0988eac8ec1955f4c9bb2050617fdb6fa7edbce5 --- /dev/null +++ b/src/events/nonRandom/pLoanshark.js @@ -0,0 +1,99 @@ +App.Events.pLoanshark = class pLoanshark extends App.Events.BaseEvent { + eventPrerequisites() { + return [ + () => V.debugMode === 1 || + V.loans.some(loan => loan.name === 'shark' && loan.deadline === V.week) + ]; + } + + execute(node) { + V.nextButton = " "; + + const loan = V.loans.find(loan => loan.name === 'shark'); + + App.Events.addParagraph(node, [`You took out a loan from one of the local loansharks in the area, and the time has come to collect. You receive a notification from ${V.assistant.name} that an envoy and a detachment of mercenaries is here to see you, and after the group has been escorted in, the shark's representative clears his throat and begins.`]); + App.Events.addParagraph(node, [`"It states here in my records that you recently borrowed ${cashFormat(Math.trunc(loan.principal))} from my boss. It's time to fulfill your end of the deal."`]); + + App.Events.addResponses(node, [ + V.cash > loan.full + ? new App.Events.Result(`Pay the man`, pay) + : new App.Events.Result(null, null, `You do not have enough cash to pay the loan back`), + V.slaves.some(slave => slaveCost(slave) > loan.full) + ? new App.Events.Result(`Offer one of your slaves instead`, slave) + : new App.Events.Result(null, null, `You do not have any slaves valuable enough to cover the loan`), + new App.Events.Result(`Refuse`, refuse) + ]); + + function pay() { + cashX(loan.full, "loan"); + V.loans.delete(V.loans.find(loan => loan.name === 'shark')); + + V.nextButton = "Continue"; + App.Utils.scheduleSidebarRefresh(); + + return `No sense in dragging this out. You roll your eyes and order ${V.assistant.name} to transfer the ¤. The envoy, satisfied that all is as it should be, gives a slight bow and a quick nod to his party. Without another word, the men turn on their heels and leave.`; + } + + function slave() { + App.Events.addNode(node, [chooseSlave()]); + V.loans.delete(V.loans.find(loan => loan.name === 'shark')); + + V.nextButton = "Continue"; + App.Utils.scheduleSidebarRefresh(); + + return `With a slight tilt of your head, you inquire as to whether your lender would be willing to accept a different type of currency instead. The envoy nods and replies, "Yes, that would be acceptable – my patron has authorized me to make trades on his behalf."`; + + function chooseSlave() { + const frag = App.UI.DOM.makeElement("div", null, ['margin-top']); + + frag.append(`Choose a slave to send with the group:`); + + V.slaves + .filter(slave => slaveCost(slave) > loan.full) + .sort((a, b) => slaveCost(a) - slaveCost(b)) + .forEach(slave => { + const div = document.createElement("div"); + const {him} = getPronouns(slave); + + App.Events.addNode(div, [ + App.UI.DOM.link(`Send `, () => { + App.UI.DOM.replace(frag, `You call ${SlaveFullName(slave)} in. After the representative has taken a moment to inspect ${him}, he nods in satisfaction and taps something on his tablet. A moment later you receive a notification that your debt with the lender has been concluded. The man turns to you once more. "It's been a pleasure," he says dryly. With that, the group departs, ${slave.slaveName} in tow.`); + + removeSlave(slave); + }), + App.UI.DOM.slaveDescriptionDialog(slave, SlaveFullName(slave)), + ` (worth ${cashFormat(slaveCost(slave))})`, + ], "div", ['indent']); + + frag.append(div); + }); + + return frag; + } + } + + function refuse() { + const text = []; + + if (V.cash > loan.full || V.slaves.some(slave => slaveCost(slave) > loan.full)) { + text.push(`You simply give the man a cold smile and cross your arms, a clear signal of defiance and refusal. The envoy gives a subtle signal to one of his compatriots, and the large soldier takes a step forward, restraints in hand. "As you know," the representative begins, "Anyone with significant enough debt is subject to enslavement, and the contract you signed with my employer states that you are now a slave. You're coming with us."`); + } else { + text.push(`Unfortunately, you're in a little over your head – you have neither the cash needed, nor any slaves valuable enough to cover the cost. Upon hearing this, the envoy nods, his face expressionless. "As you know," he starts, "Anyone with significant enough debt is subject to enslavement, and the contract you signed with my employer states that you are now a slave. You're coming with us."`); + } + + if (S.Bodyguard) { + const {his, him} = getPronouns(S.Bodyguard); + + text.push(`Your bodyguard, ${S.Bodyguard.slaveName}, draws ${his} pistol faster than you would have thought possible and manages to put a round into the nearest mercenary before the other soldiers gun ${him} down. Unarmed and defenseless, you have no choice but to surrender.`); + } + + V.loans.delete(V.loans.find(loan => loan.name === 'shark')); + V.gameover = "loanshark"; + V.nextButton = "Continue"; + V.nextLink = "Gameover"; + App.Utils.scheduleSidebarRefresh(); + + return text.join(' '); + } + } +}; diff --git a/src/events/nonRandomEvent.js b/src/events/nonRandomEvent.js index e149948855e8266e4bfcd5ebcf16fb91326b16df..099becebf49a6b1e683879ba2605dca226488b07 100644 --- a/src/events/nonRandomEvent.js +++ b/src/events/nonRandomEvent.js @@ -9,6 +9,7 @@ App.Events.getNonrandomEvents = function() { // instantiate all possible scheduled/nonrandom events here // ORDER MATTERS - if multiple events from this list trigger in a single week, they are executed in this order + new App.Events.pLoanshark(), new App.Events.conflictOptions(), new App.Events.SEPlayerBirth(), new App.Events.SEpcBirthday(), diff --git a/src/gui/Encyclopedia/encyclopedia.tw b/src/gui/Encyclopedia/encyclopedia.tw index d5f010b8d897a9030ab76566b2a2ca00642279e7..d1e3a78d1ae43cf08bb90464a784aadfff215648 100644 --- a/src/gui/Encyclopedia/encyclopedia.tw +++ b/src/gui/Encyclopedia/encyclopedia.tw @@ -1934,7 +1934,7 @@ LORE: INTERVIEWS <br>''Autistic Boi'' for Mediterranean market preset. <br>''anon'' for the PA subjugationist and supremacist FS appearances. <br>''Editoranon and Milkanon?'' for prison markets and the nursing handjob scene. - <br>''DCoded'' for creating the favicon and adding animals to the Pit, as well as nursery and animal-related content, scenes, facilities and fixes. Also added an oral scene, the reminder system, and created and fixed a number of bugs. + <br>''DCoded'' for creating the favicon and adding animals to the Pit, as well as nursery and animal-related content, scenes, facilities and fixes. Created a food system as well as a loan system. Also added an oral scene, the reminder system, and created and fixed a number of bugs. <br>''HiveBro'' for giving hyperpregnant slaves some serious loving. <br>''Quin2k'' for overwriting save function and expired tweak via Vrelnir & co. <br>''ezsh'' for bugfixing and creating a tool to build twineJS and twineCSS for me. Set up a revised SC update process as well. Has contributed massive revisions to the game's structure. Keeps the RA in line. diff --git a/src/interaction/budgets/recordTemplates.js b/src/interaction/budgets/recordTemplates.js index dfc9618022c4b6454e3f48c98d6c692a3497332e..d9f7f2d6dfdc4d31f6340a225ab78533c94db88c 100644 --- a/src/interaction/budgets/recordTemplates.js +++ b/src/interaction/budgets/recordTemplates.js @@ -133,6 +133,7 @@ App.Data.Records.LastWeeksCash = function() { this.fines = 0; this.event = 0; // poker night etc. Try to file things elsewhere if you can. this.war = 0; + this.loan = 0; // Policies this.food = 0; diff --git a/src/js/slaveListing.js b/src/js/slaveListing.js index 971ffb8a626bc0121f1dda4cce95a6786e9ab37f..6cc2e4c4a2d85d79bc0b06a5858e585044ecafc7 100644 --- a/src/js/slaveListing.js +++ b/src/js/slaveListing.js @@ -507,11 +507,13 @@ App.UI.SlaveList.SlaveInteract.stdInteract = function(slave, text) { App.UI.SlaveList.ScrollPosition.record(); V.AS = slave.ID; }); + if (V.favorites.includes(slave.ID)) { return App.UI.DOM.combineNodes( App.UI.DOM.makeElement("span", String.fromCharCode(0xe800), ["icons", "favorite"]), " ", link); } + return link; };