diff --git a/devTools/FC.d.ts b/devTools/FC.d.ts index 19c0f79fbcc87ee64d8e3b3912141584e2d10edc..46779cb572d3dcc6ea6f0322200434680a81b0e5 100644 --- a/devTools/FC.d.ts +++ b/devTools/FC.d.ts @@ -42,6 +42,10 @@ declare namespace App { namespace Debug {} namespace Desc {} + namespace Encyclopedia { + namespace Entries {} + } + namespace Entity { class Serializable {} diff --git a/js/002-config/fc-js-init.js b/js/002-config/fc-js-init.js index 7f6482afd104d9f214bd39cf9002e64c8796d2f4..c3a378971a317816924c8ba2f1e11da0f662b2c0 100644 --- a/js/002-config/fc-js-init.js +++ b/js/002-config/fc-js-init.js @@ -10,6 +10,8 @@ App.Arcology = { App.Art = {}; App.Data = {}; App.Debug = {}; +App.Encyclopedia = {}; +App.Encyclopedia.Entries = {}; App.Entity = {}; App.Entity.Utils = {}; App.MainView = {}; diff --git a/src/002-config/mousetrapConfig.js b/src/002-config/mousetrapConfig.js index bae8064f053960b41c22fb8489e3122a81ab75b3..1007d1f07271562f06aea98bcc4a3df159143d88 100644 --- a/src/002-config/mousetrapConfig.js +++ b/src/002-config/mousetrapConfig.js @@ -54,10 +54,10 @@ Mousetrap.bind("h", function() { $("#manageHG a").trigger("click"); }); Mousetrap.bind("s", function() { - $("#buySlaves a.macro-link").trigger("click"); + $("#buySlaves a").trigger("click"); }); Mousetrap.bind("a", function() { - $("#managePA a.macro-link").trigger("click"); + $("#managePA a").trigger("click"); }); Mousetrap.bind("b", function() { $("#manageBG a").trigger("click"); diff --git a/src/003-assets/CSS/slaveList.css b/src/003-assets/CSS/slaveList.css index 02752b4df4063806c8b2144b96f5c587ae99facb..a6a15b2b3d30a9cb5982777fa761e3360dfae282 100644 --- a/src/003-assets/CSS/slaveList.css +++ b/src/003-assets/CSS/slaveList.css @@ -2,8 +2,13 @@ div.slaveSummary { clear: both; } -div.slaveSummary.card { +.slaveSummary.card { border-radius: 8px; + border-top: 2px #333333; + border-left: 2px #333333; + border-bottom: 0; + border-right: 0; + border-style: solid; background-color: #1a1a1a; box-shadow: 10px 10px 5px black; padding: 10px; diff --git a/src/003-assets/CSS/tabs.css b/src/003-assets/CSS/tabs.css index 125de5fdfcf5c0839480d0bc0ae8234b8a24de4c..1f972210d691fff9990db931f5c2d915e8d3537e 100644 --- a/src/003-assets/CSS/tabs.css +++ b/src/003-assets/CSS/tabs.css @@ -14,6 +14,16 @@ div.tabbar button { font-size: large; } +div.tabbar button.card { + border-top-left-radius: 15px; + border-top-right-radius: 15px; + border: none; +} + +div.tabbar button.card.active { + background-color: #1a1a1a; +} + div.tabbar button:hover { background-color: #414141; } @@ -23,13 +33,31 @@ div.tabbar button.active { color: #c7cedf; } -.tabcontent { +div.tabbar a.active { + color: white; + pointer-events: none; + cursor: default; +} + +.tabcontent:not(.noFade) { display: none; padding: 6px 12px; -webkit-animation: fadeEffect 0.3s; animation: fadeEffect 0.3s; } +.tabcontent.card { + border-radius: 0 8px 8px 8px; + background-color: #1a1a1a; + box-shadow: 10px 10px 5px black; + margin-bottom: 15px; +} + + +.tabcontent.card .slaveSummary.card { + background-color: #252525; +} + @-webkit-keyframes fadeEffect { from { opacity: 0; diff --git a/src/gui/Encyclopedia/encyclopedia.css b/src/gui/Encyclopedia/encyclopedia.css new file mode 100644 index 0000000000000000000000000000000000000000..9cd84398b514dfad886a5eef12650c5f4a6fc474 --- /dev/null +++ b/src/gui/Encyclopedia/encyclopedia.css @@ -0,0 +1,3 @@ +.encyclopedia.topic { + font-weight: bold; +} diff --git a/src/gui/Encyclopedia/encyclopedia.tw b/src/gui/Encyclopedia/encyclopedia.tw index adff1a2a021c54671033d639aff5ab8c88ebcab7..37deb257ed0749ab4255f99a304521a631f5d60b 100644 --- a/src/gui/Encyclopedia/encyclopedia.tw +++ b/src/gui/Encyclopedia/encyclopedia.tw @@ -867,56 +867,56 @@ SLAVE ASSIGNMENTS: SLAVE ASSIGNMENTS (COMMON): **********/ <<case "Attending Classes">> - <<encyclopediaEntryAttendingClasses>> + <<print App.UI.DOM.includeDOM(App.Encyclopedia.Entries.attendingClasses(), "encyclasses")>> //Associated facility: [[Schoolroom|Encyclopedia][$encyclopedia = "Schoolroom"]]// <<case "Confinement">> - <<encyclopediaEntryConfinement>> + <<print App.UI.DOM.includeDOM(App.Encyclopedia.Entries.confinement(), "encyconfine")>> //Associated facility: [[Cellblock|Encyclopedia][$encyclopedia = "Cellblock"]]// <<case "Fucktoy">> - <<encyclopediaEntryFucktoy>> + <<print App.UI.DOM.includeDOM(App.Encyclopedia.Entries.fucktoy(), "encyfucktoy")>> //Associated facility: [[Master Suite|Encyclopedia][$encyclopedia = "Master Suite"]]// <<case "Glory Hole">> - <<encyclopediaEntryGloryHole>> + <<print App.UI.DOM.includeDOM(App.Encyclopedia.Entries.gloryHole(), "encyglory")>> //Associated facility: [[Arcade|Encyclopedia][$encyclopedia = "Arcade"]]// <<case "Milking">> - <<encyclopediaEntryMilking>> + <<print App.UI.DOM.includeDOM(App.Encyclopedia.Entries.milking(), "encymilk")>> //Associated facility: [[Dairy|Encyclopedia][$encyclopedia = "Dairy"]]// <<case "Farming">> - <<encyclopediaEntryFarming>> + <<print App.UI.DOM.includeDOM(App.Encyclopedia.Entries.farming(), "encyfarm")>> //Associated facility: [[Farmyard|Encyclopedia][$encyclopedia = "Farmyard"]]// <<case "Public Service">> - <<encyclopediaEntryPublicService>> + <<print App.UI.DOM.includeDOM(App.Encyclopedia.Entries.publicService(), "encypublic")>> //Associated facility: [[Club|Encyclopedia][$encyclopedia = "Club"]]// <<case "Rest">> - <<encyclopediaEntryRest>> + <<print App.UI.DOM.includeDOM(App.Encyclopedia.Entries.rest(), "encyrest")>> //Associated facilities: [[Spa|Encyclopedia][$encyclopedia = "Spa"]], [[Clinic|Encyclopedia][$encyclopedia = "Clinic"]]// <<case "Sexual Servitude">> - <<encyclopediaEntrySexualServitude>> + <<print App.UI.DOM.includeDOM(App.Encyclopedia.Entries.sexualServitude(), "encysexServ")>> <<case "Servitude">> - <<encyclopediaEntryServitude>> + <<print App.UI.DOM.includeDOM(App.Encyclopedia.Entries.servitude(), "encyserve")>> //Associated facility: [[Servants' Quarters|Encyclopedia][$encyclopedia = "Servants' Quarters"]]// <<case "Whoring">> - <<encyclopediaEntryWhoring>> + <<print App.UI.DOM.includeDOM(App.Encyclopedia.Entries.whoring(), "encywhore")>> //Associated facility: [[Brothel|Encyclopedia][$encyclopedia = "Brothel"]]// /********** diff --git a/src/gui/Encyclopedia/encyclopediaEntries.js b/src/gui/Encyclopedia/encyclopediaEntries.js new file mode 100644 index 0000000000000000000000000000000000000000..d001c999475654e7b3b2f0812d0499db8dee2b09 --- /dev/null +++ b/src/gui/Encyclopedia/encyclopediaEntries.js @@ -0,0 +1,96 @@ +/* TODO: add entries for Nursery */ + +App.Encyclopedia.Entries = (function() { + /** + * @param {string} topic + * @returns {HTMLElement} + */ + function topic(topic) { + return App.UI.DOM.makeElement("span", topic, ["encyclopedia", "topic"]); + } + + /** + * @param {string} linkText + * @param {string} topic + * @returns {HTMLElement} + */ + function encyLink(linkText, topic) { + return App.UI.DOM.passageLink(linkText, "Encyclopedia", () => { + V.encyclopedia = topic; + if (passage() !== "Encyclopedia") { + V.nextButton = "Back"; + V.nextLink = "Main"; + } + }); + } + + const entries = {}; + + entries.attendingClasses = () => + App.UI.DOM.combineNodes(topic("Attending classes"), + " is an assignment which educates the slave, raising intelligence if possible. Being educated raises value and is useful for some jobs and leadership positions."); + + entries.confinement = () => + App.UI.DOM.combineNodes(topic("Confinement"), + " is an assignment which accelerates breaking for disobedient slaves. If a slave isn't obedient enough to work and isn't ", + encyLink("unhealthy", "Health"), " enough to need rest, this will make them useful sooner."); + + entries.fucktoy = () => + App.UI.DOM.combineNodes(topic("Fucktoy service"), + " is an assignment which keeps the slave close and under the player's eye. It's mostly just for fun, but fucktoys can improve reputation based on their beauty, and the player character's attention can be targeted to areas of the slave's body with possible fetish effects on happy slaves."); + + entries.gloryHole = () => + App.UI.DOM.combineNodes(topic("Occupying a glory hole"), + " is an assignment which makes money off of slaves regardless of their beauty, skills, or feelings; it's not fun or ", + encyLink("healthy", "Health"), " but very powerful for extracting ¤ out of otherwise useless slaves."); + + entries.milking = () => { + const fragment = document.createDocumentFragment(); + + fragment.append(topic("Getting milked"), + " is an assignment which makes money from lactation based on a slave's breasts, ", encyLink("health", "Health"), + " and hormonal status."); + if (V.seeDicks > 0) { + fragment.append(" Cows with balls will also give semen."); + } + fragment.append(` Creates profit quickly from slaves with big tits${V.seeDicks ? " or balls" : ""}.`); + + return fragment; + }; + + entries.farming = function() { + const fragment = document.createDocumentFragment(); + fragment.append(topic("Farming"), " is an assignment which produces ", encyLink("food", "Food"), + " from your slaves' hard work"); + if (V.seeBestiality === 1) { + fragment.append(" and allows you to breed slaves with animals"); + } + fragment.append(". Can also reduce arcology upkeep with upgrades in the ", + encyLink("Farmyard", "Farmyard")); + return fragment; + }; + + entries.publicService = () => + App.UI.DOM.combineNodes(topic("Public Service"), + " is an assignment which increases reputation based on a slave's beauty, sexual appeal, and skills. Very similar to whoring, but for reputation rather than money."); + + entries.rest = () => + App.UI.DOM.combineNodes(topic("Rest"), " is an assignment mostly used to improve ", encyLink("health", "Health"), + ". It can be useful to order slaves you wish to intensively modify to rest, since most modifications damage health. It will synergize with curative treatments, providing bonus healing when both are simultaneously applied."); + + + entries.sexualServitude = () => + App.UI.DOM.combineNodes(topic("Sexual servitude"), + " is an assignment which pleases other slaves by forcing the slave to service them sexually. Useful for driving the targeted slave's ", + encyLink("devotion", "Devotion"), "up quickly."); + + entries.servitude = () => + App.UI.DOM.combineNodes(topic("Servitude"), " is an assignment which reduces your upkeep based on the slave's ", + encyLink("devotion", "Devotion"), + " Available at lower obedience than other jobs, is insensitive to the quality of a slave's body, and doesn't require skills; a good transitional assignment. Unusually, low sex drive is advantageous as a servant, since it reduces distraction. Lactating slaves are slightly better at this job, since they can contribute to their fellow slaves' nutrition."); + + entries.whoring = () => + App.UI.DOM.combineNodes(topic("Whoring"), " is an assignment which makes money based on a slave's beauty, sexual appeal, and skills. Good whores take a long time to train and beautify but become very profitable."); + + return entries; +})(); diff --git a/src/gui/Encyclopedia/encyclopediaWidgets.tw b/src/gui/Encyclopedia/encyclopediaWidgets.tw deleted file mode 100644 index e8e0bca00256ac1afdb7bf7e4af1038f2784fa89..0000000000000000000000000000000000000000 --- a/src/gui/Encyclopedia/encyclopediaWidgets.tw +++ /dev/null @@ -1,94 +0,0 @@ -:: Encyclopedia Widgets [nobr widget] - -/* TODO: add entries for Nursery */ - -<<widget "encyclopediaEntryAttendingClasses">> -''Attending classes'' is an assignment which educates the slave, raising intelligence if possible. Being educated raises value and is useful for some jobs and leadership positions. -<</widget>> - -<<widget "encyclopediaEntryConfinement">> -''Confinement'' is an assignment which accelerates breaking for disobedient slaves. If a slave isn't obedient enough to work and isn't -<<if passage() == "Encyclopedia">> - [[unhealthy|Encyclopedia][$encyclopedia = "Health"]] -<<else>> - [[unhealthy|Encyclopedia][$encyclopedia = "Health",$nextButton = "Back",$nextLink = "Main"]] -<</if>> -enough to need rest, this will make them useful sooner. -<</widget>> - -<<widget "encyclopediaEntryFucktoy">> -''Fucktoy service'' is an assignment which keeps the slave close and under the player's eye. It's mostly just for fun, but fucktoys can improve reputation based on their beauty, and the player character's attention can be targeted to areas of the slave's body with possible fetish effects on happy slaves. -<</widget>> - -<<widget "encyclopediaEntryGloryHole">> -''Occupying a glory hole'' is an assignment which makes money off of slaves regardless of their beauty, skills, or feelings; it's not fun or -<<if passage() == "Encyclopedia">> - [[healthy|Encyclopedia][$encyclopedia = "Health"]], -<<else>> - [[healthy|Encyclopedia][$encyclopedia = "Health",$nextButton = "Back",$nextLink = "Main"]], -<</if>> -but very powerful for extracting ¤ out of otherwise useless slaves. -<</widget>> - -<<widget "encyclopediaEntryMilking">> -''Getting milked'' is an assignment which makes money from lactation based on a slave's breasts, -<<if passage() == "Encyclopedia">> - [[health|Encyclopedia][$encyclopedia = "Health"]], -<<else>> - [[health|Encyclopedia][$encyclopedia = "Health",$nextButton = "Back",$nextLink = "Main"]], -<</if>> -and hormonal status.<<if $seeDicks > 0>> Cows with balls will also give semen.<</if>> Creates profit quickly from slaves with big tits<<if $seeDicks > 0>> or balls<</if>>. -<</widget>> - -<<widget "encyclopediaEntryFarming">> -''Farming'' is an assignment which produces -<<if passage() == "Encyclopedia">> - [[food|Encyclopedia][$encyclopedia = "Food"]] -<<else>> - [[food|Encyclopedia][$encyclopedia = "Food",$nextButton = "Back",$nextLink = "Main"]] -<</if>> -from your slaves' hard work<<if $seeBestiality == 1>> and allows you to breed slaves with animals<</if>>. Can also reduce arcology upkeep with upgrades in the -<<if passage() == "Encyclopedia">> - [[Farmyard|Encyclopedia][$encyclopedia = "Farmyard"]]. -<<else>> - [[Farmyard|Encyclopedia][$encyclopedia = "Farmyard",$nextButton = "Back",$nextLink = "Main"]]. -<</if>> -<</widget>> - -<<widget "encyclopediaEntryPublicService">> -''Public Service'' is an assignment which increases reputation based on a slave's beauty, sexual appeal, and skills. Very similar to whoring, but for reputation rather than money. -<</widget>> - -<<widget "encyclopediaEntryRest">> -''Rest'' is an assignment mostly used to improve -<<if passage() == "Encyclopedia">> - [[health|Encyclopedia][$encyclopedia = "Health"]]. -<<else>> - [[health|Encyclopedia][$encyclopedia = "Health",$nextButton = "Back",$nextLink = "Main"]]. -<</if>> -It can be useful to order slaves you wish to intensively modify to rest, since most modifications damage health. It will synergize with curative treatments, providing bonus healing when both are simultaneously applied. -<</widget>> - -<<widget "encyclopediaEntrySexualServitude">> -''Sexual servitude'' is an assignment which pleases other slaves by forcing the slave to service them sexually. Useful for driving the targeted slave's -<<if passage() == "Encyclopedia">> - [[devotion|Encyclopedia][$encyclopedia = "Devotion"]] -<<else>> - [[devotion|Encyclopedia][$encyclopedia = "Devotion",$nextButton = "Back",$nextLink = "Main"]] -<</if>> -up quickly. -<</widget>> - -<<widget "encyclopediaEntryServitude">> -''Servitude'' is an assignment which reduces your upkeep based on the slave's -<<if passage() == "Encyclopedia">> - [[devotion|Encyclopedia][$encyclopedia = "Devotion"]]. -<<else>> - [[devotion|Encyclopedia][$encyclopedia = "Devotion",$nextButton = "Back",$nextLink = "Main"]]. -<</if>> -Available at lower obedience than other jobs, is insensitive to the quality of a slave's body, and doesn't require skills; a good transitional assignment. Unusually, low sex drive is advantageous as a servant, since it reduces distraction. Lactating slaves are slightly better at this job, since they can contribute to their fellow slaves' nutrition. -<</widget>> - -<<widget "encyclopediaEntryWhoring">> -''Whoring'' is an assignment which makes money based on a slave's beauty, sexual appeal, and skills. Good whores take a long time to train and beautify but become very profitable. -<</widget>> \ No newline at end of file diff --git a/src/gui/css/mainStyleSheet.css b/src/gui/css/mainStyleSheet.css index 9e98b1be2a78444bc9956dab8910bfb53eb1ad7c..d61e54a15f8738f5d0197921bc35ab11d7752641 100644 --- a/src/gui/css/mainStyleSheet.css +++ b/src/gui/css/mainStyleSheet.css @@ -373,6 +373,10 @@ h3 + p { margin: 0 auto; } +.major-link { + font-weight: bold; +} + .clear-formatting { color: white; font-weight: normal; @@ -387,3 +391,13 @@ h3 + p { font-weight: bold; color: red; } + +div.center { + margin-left: auto; + margin-right: auto; + text-align: center; +} + +div.flex-container { + display: flex; +} diff --git a/src/interaction/main/mainLinks.js b/src/interaction/main/mainLinks.js index 7347394b22558a227880ed65eb54590a0875c4d0..c3556d512d2028c67df0c571d88f543a0b1153aa 100644 --- a/src/interaction/main/mainLinks.js +++ b/src/interaction/main/mainLinks.js @@ -1,121 +1,142 @@ -/* OPEN MAIN */ -App.UI.View.MainLinks = function() { +/** + * @returns {DocumentFragment} + */ +App.UI.View.mainLinks = function() { "use strict"; const PA = Array.isArray(V.personalAttention) ? V.personalAttention.map(x => getSlave(x.ID)) : []; - let r = ''; + let fragment = document.createDocumentFragment(); if (V.PC.health.shortDamage >= 30) { - r += `The injuries received in the recent battle prevent you from undertaking tiring efforts.`; + fragment.append(`The injuries received in the recent battle prevent you from undertaking tiring efforts.`); } else { switch (V.personalAttention) { case "business": - r += `You plan to focus on business this week.`; + fragment.append(`You plan to focus on business this week.`); break; case "whoring": - r += `You plan to focus on earning extra money this week.`; + fragment.append(`You plan to focus on earning extra money this week.`); break; case "upkeep": - r += `You plan to focus on cleaning the penthouse this week.`; + fragment.append(`You plan to focus on cleaning the penthouse this week.`); break; case "defensive survey": - r += `You plan to survey ${V.arcologies[0].name}'s defenses in person this week.`; + fragment.append(`You plan to survey ${V.arcologies[0].name}'s defenses in person this week.`); break; case "development project": - r += `You plan on contributing to a local development project this week.`; + fragment.append(`You plan on contributing to a local development project this week.`); break; case "smuggling": - r += `You plan to make some easy (but dirty) money this week.`; + fragment.append(`You plan to make some easy (but dirty) money this week.`); break; case "HG": - r += `You plan to support your Head Girl this week, `; + fragment.append(`You plan to support your Head Girl this week, `); if (V.HeadGirl) { const {he, his} = getPronouns(V.HeadGirl); - r += `so ${he} can give more slaves ${his} attention.`; + fragment.append(`so ${he} can give more slaves ${his} attention.`); } else { - r += `should you assign one.`; + fragment.append(`should you assign one.`); } break; case "sex": - r += `You plan to have as much sex with your slaves as possible this week.`; + fragment.append(`You plan to have as much sex with your slaves as possible this week.`); break; case "trading": - r += `This week you will learn trading.`; + fragment.append(`This week you will learn trading.`); break; case "warfare": - r += `This week you will learn modern combat tactics.`; + fragment.append(`This week you will learn modern combat tactics.`); break; case "slaving": - r += `This week you will learn slaving.`; + fragment.append(`This week you will learn slaving.`); break; case "engineering": - r += `This week you will learn engineering.`; + fragment.append(`This week you will learn engineering.`); break; case "medicine": - r += `This week you will learn medicine.`; + fragment.append(`This week you will learn medicine.`); break; case "hacking": - r += `This week you will learn hacking.`; + fragment.append(`This week you will learn hacking.`); break; case "proclamation": - r += `This week you plan to issue a proclamation about ${V.SecExp.proclamation.type}.`; + fragment.append(`This week you plan to issue a proclamation about ${V.SecExp.proclamation.type}.`); break; case "technical accidents": - r += `This week you plan to sell your technical skills to the highest bidder.`; + fragment.append(`This week you plan to sell your technical skills to the highest bidder.`); break; default: if (PA.length > 0) { - r += `You plan to train `; - let l = PA.length; - for (let dwi = 0; dwi < l; dwi++) { - if (dwi > 0 && dwi === l - 1) { - r += ` and `; - } - r += `<strong><u><span class="pink">${SlaveFullName(PA[dwi])}</span></u></strong> to ${V.personalAttention[dwi].trainingRegimen}`; - if (dwi > 0 && dwi < l - 2) { - r += `,`; + fragment.append(`You plan to train `); + + const trainees = []; + PA.forEach((trainee, i) => { + trainees.push(App.UI.DOM.combineNodes(App.UI.DOM.makeElement("span", SlaveFullName(trainee), "slave-name"), + ` to ${V.personalAttention[i].trainingRegimen}`)); } - } - r += ` this week.`; + ); + fragment.append(App.UI.DOM.arrayToList(trainees)); + + fragment.append(` this week.`); } break; } } if (V.PC.health.shortDamage < 30) { - r += ` <span id="managePA"><strong>${App.UI.passageLink("Change plans", "Personal Attention Select")}</strong></span> <span class="cyan">[A]</span>`; + const link = App.UI.DOM.makeElement("span", App.UI.DOM.passageLink("Change plans", "Personal Attention Select"), "major-link"); + link.id = "managePA"; + fragment.append(" ", link, " ", App.UI.DOM.makeElement("span", "[A]", "hotkey")); } - if (V.useSlaveSummaryOverviewTab !== 1) { + if (V.useSlaveSummaryOverviewTab === 0) { + let div = document.createElement("div"); if (typeof V.slaveIndices[V.HeadGirl.ID] !== 'undefined') { - r += `<br><strong><u><span class="pink">${SlaveFullName(V.HeadGirl)}</span></u></strong> is serving as your Head Girl`; + div.append(App.UI.DOM.makeElement("span", SlaveFullName(V.HeadGirl), "slave-name"), " is serving as your Head Girl"); if (V.arcologies[0].FSEgyptianRevivalistLaw === 1) { - r += ` and Consort`; + div.append(` and Consort`); } - r += `. <span id="manageHG"><strong>${App.UI.passageLink("Manage Head Girl", "HG Select")}</strong></span> <span class="cyan">[H]</span>`; - } else if (typeof V.slaveIndices[V.HeadGirl.ID] === 'undefined' && (V.slaves.length > 1)) { - r += `<br>You have not selected a Head Girl`; + div.append(". ", + App.UI.DOM.makeElement("span", App.UI.DOM.passageLink("Manage Head Girl", "HG Select"), "major-link"), + " ", App.UI.DOM.makeElement("span", "[H]", "hotkey")); + div.id = "manageHG"; + } else if (V.slaves.length > 1) { + div.append(`You have not selected a Head Girl`); if (V.arcologies[0].FSEgyptianRevivalistLaw === 1) { - r += ` and Consort`; + div.append(` and Consort`); } - r += `. <span id="manageHG"><strong>${App.UI.passageLink("Select one", "HG Select")}</strong></span> <span class="cyan">[H]</span>`; - } else if (typeof V.slaveIndices[V.HeadGirl.ID] === 'undefined') { - r += `<br><span class="note">You do not have enough slaves to keep a Head Girl</span>`; + div.append(". ", + App.UI.DOM.makeElement("span", App.UI.DOM.passageLink("Select One", "HG Select"), "major-link"), + " ", App.UI.DOM.makeElement("span", "[H]", "hotkey")); + div.id = "manageHG"; + } else { + div.append(App.UI.DOM.makeElement("span", "You do not have enough slaves to keep a Head Girl", "note")); } - r += `<br>`; + fragment.append(div); + div = document.createElement("div"); if (typeof V.slaveIndices[V.Recruiter.ID] !== 'undefined') { - r += `<strong><u><span class="pink">${SlaveFullName(V.Recruiter)}</span></u></strong> is working to recruit girls. <span id="manageRecruiter"><strong>${App.UI.passageLink("Manage Recruiter", "Recruiter Select")}</strong></span> <span class="cyan">[U]</span>`; + div.append(App.UI.DOM.makeElement("span", SlaveFullName(V.Recruiter), "slave-name"), " is working to recruit girls. ", + App.UI.DOM.makeElement("span", App.UI.DOM.passageLink("Manage Recruiter", "Recruiter Select"), "major-link")); } else { - r += `You have not selected a Recruiter. <span id="manageRecruiter"><strong>${App.UI.passageLink("Select one", "Recruiter Select")}</strong></span> <span class="cyan">[U]</span>`; + div.append("You have not selected a Recruiter. ", + App.UI.DOM.makeElement("span", App.UI.DOM.passageLink("Select one", "Recruiter Select"), "major-link")); } + div.append(" ", App.UI.DOM.makeElement("span", "[U]", "hotkey")); + div.id = "manageRecruiter"; + fragment.append(div); if (V.dojo) { - r += `<br>`; + div = document.createElement("div"); if (typeof V.slaveIndices[V.Bodyguard.ID] !== 'undefined') { - r += `<strong><u><span class="pink">${SlaveFullName(V.Bodyguard)}</span></u></strong> is serving as your bodyguard. <span id="manageBG"><strong>${App.UI.passageLink("Manage Bodyguard", "BG Select")}</strong></span> <span class="cyan">[B]</span>`; + div.append(App.UI.DOM.makeElement("span", SlaveFullName(V.Bodyguard), "slave-name"), " is serving as your bodyguard. ", + App.UI.DOM.makeElement("span", App.UI.DOM.passageLink("Manage Bodyguard", "BG Select"), "major-link")); } else { - r += `You have not selected a Bodyguard. <span id="manageBG"><strong>${App.UI.passageLink("Select one", "BG Select")}</strong></span> <span class="cyan">[B]</span>`; + div.append("You have not selected a Bodyguard. ", + App.UI.DOM.makeElement("span", App.UI.DOM.passageLink("Select one", "BG Select"), "major-link")); } + div.append(" ", App.UI.DOM.makeElement("span", "[B]", "hotkey")); + div.id = "manageBG"; + fragment.append(div); } } @@ -129,19 +150,24 @@ App.UI.View.MainLinks = function() { const slaveOrgans = V.completedOrgans.reduce((acc, organ) => organ.ID === V.slaves[i].ID ? acc + 1 : acc, 0); /* if the interrogated slave has one or more organs ready: */ if (slaveOrgans > 0) { - r += '<br><span class="yellow">The fabricator has completed '; + const div = document.createElement("div"); + div.classList.add("yellow"); + div.append("The fabricator has completed "); if (slaveOrgans > 1) { - r += `${slaveOrgans} organs`; + div.append(`${slaveOrgans} organs`); } else { - r += 'an organ'; + div.append('an organ'); } - r += ` for </span>${App.UI.link(V.slaves[i].slaveName, () => { V.activeSlave = V.slaves[i]; }, [], "Slave Interact")}, <span class="yellow">which `; + div.append(" for ", + App.UI.DOM.makeElement("span", App.UI.link(V.slaves[i].slaveName, () => { V.activeSlave = V.slaves[i]; }, [], "Slave Interact"), "clear-formatting"), + " which "); if (slaveOrgans > 1) { - r += 'are'; + div.append('are'); } else { - r += 'is'; + div.append('is'); } - r += ' ready to be implanted.</span>'; + div.append(' ready to be implanted.'); + fragment.append(div); } } } @@ -151,7 +177,12 @@ App.UI.View.MainLinks = function() { if (getSlave(V.adjustProsthetics[j].slaveID) !== undefined) { const i = V.slaveIndices[V.adjustProsthetics[j].slaveID]; if (V.adjustProsthetics[j].workLeft <= 0) { - r += `<br><span class="yellow">The lab has completed ${addA(setup.prosthetics[V.adjustProsthetics[j].id].name)} for</span> <span id="name">${App.UI.link(SlaveFullName(V.slaves[i]), () => { V.activeSlave = V.slaves[i]; }, [], "Slave Interact")},</span> <span class="yellow"> which is ready to be attached.</span>`; + const div = document.createElement("div"); + div.classList.add("yellow"); + div.append(`The lab has completed ${addA(setup.prosthetics[V.adjustProsthetics[j].id].name)} for `, + App.UI.DOM.makeElement("span", App.UI.link(SlaveFullName(V.slaves[i]), () => { V.activeSlave = V.slaves[i]; }, [], "Slave Interact"), "clear-formatting"), + " which is ready to be attached."); + fragment.append(div); } } else { V.adjustProsthetics.splice(j, 1); @@ -161,57 +192,90 @@ App.UI.View.MainLinks = function() { } if (V.completedOrgans.length > 0 && V.adjustProstheticsCompleted > 0) { - r += `<br>${App.UI.passageLink("Implant and Attach", "Multiple Organ Implant")} <span class="yellow">all organs and prosthetics that are ready.</span>`; + const div = document.createElement("div"); + div.append(App.UI.DOM.passageLink("Implant and Attach", "Multiple Organ Implant"), + App.UI.DOM.makeElement("span", " all organs and prosthetics that are ready.", "yellow")); + fragment.append(div); } else if (V.completedOrgans.length > 1) { - r += `<br>${App.UI.passageLink("Implant", "Multiple Organ Implant")} <span class="yellow">all organs that are ready for implantation.</span>`; + const div = document.createElement("div"); + div.append(App.UI.DOM.passageLink("Implant", "Multiple Organ Implant"), + App.UI.DOM.makeElement("span", " all organs that are ready for implantation.", "yellow")); + fragment.append(div); } else if (V.adjustProstheticsCompleted > 1) { - r += `<br>${App.UI.passageLink("Attach", "Multiple Organ Implant")} <span class="yellow">all prosthetics that are ready to be attached.</span>`; + const div = document.createElement("div"); + div.append(App.UI.DOM.passageLink("Attach", "Multiple Organ Implant"), + App.UI.DOM.makeElement("span", " all prosthetics that are ready to be attached.", "yellow")); + fragment.append(div); } - if (V.slaveCostFactor > 1.05) { - r += `<br><span class="yellow">There is a bull market for slaves; the price of slaves is very high.</span>`; - } else if (V.slaveCostFactor > 1) { - r += `<br><span class="yellow">The slave market is bullish; the price of slaves is high.</span>`; - } else if (V.slaveCostFactor < 0.95) { - r += `<br><span class="yellow">There is a bear market for slaves; the price of slaves is very low.</span>`; - } else if (V.slaveCostFactor < 1) { - r += `<br><span class="yellow">The slave market is bearish; the price of slaves is low.</span>`; + const div = document.createElement("div"); + if (V.slaveCostFactor === 1) { + div.append("The slave market is stable; the price of slaves is average."); } else { - r += `<br>The slave market is stable; the price of slaves is average.`; + let r; + if (V.slaveCostFactor > 1) { + if (V.slaveCostFactor > 1.05) { + r = "There is a bull market for slaves; the price of slaves is very high."; + } else { + r = "The slave market is bullish; the price of slaves is high."; + } + } else { + if (V.slaveCostFactor < 0.95) { + r = "There is a bear market for slaves; the price of slaves is very low."; + } else { + r = "The slave market is bearish; the price of slaves is low."; + } + } + div.append(App.UI.DOM.makeElement("span", r, "yellow")); + } + + const buySlaves = App.UI.DOM.makeElement("span", App.UI.DOM.passageLink("Buy Slaves", "Buy Slaves"), "major-link"); + buySlaves.id = "buySlaves"; + div.append(" ", buySlaves, " ", App.UI.DOM.makeElement("span", "[S]", "hotkey")); + + fragment.append(div); + + /** + * @param {string} school + */ + function schoolSale(school) { + const div = document.createElement("div"); + div.append(App.UI.DOM.makeElement("span", "For your first purchase, ", "yellow"), + App.UI.DOM.passageLink(school, school, () => { V.slavesSeen += 1; }), + App.UI.DOM.makeElement("span", " will sell at half price this week.", "yellow")); + fragment.append(div); } - r += ` <span id="buySlaves"><strong>${App.UI.passageLink("Buy Slaves", "Buy Slaves")}</strong></span> <span class="cyan">[S]</span>`; if (V.seeDicks !== 100) { if (V.TSS.schoolSale !== 0) { - r += `<br><span class="yellow">For your first purchase, </span><strong>[[The Slavegirl School][$slavesSeen += 1]]</strong><span class="yellow"> will sell at half price this week.</span>`; + schoolSale("The Slavegirl School"); } if (V.GRI.schoolSale !== 0) { - r += `<br><span class="yellow">For your first purchase, </span><strong>[[Growth Research Institute][$slavesSeen += 1]]</strong><span class="yellow"> will sell at half price this week.</span>`; + schoolSale("Growth Research Institute"); } if (V.SCP.schoolSale !== 0) { - r += `<br><span class="yellow">For your first purchase, </span><strong>[[St. Claver Preparatory][$slavesSeen += 1]]</strong><span class="yellow"> will sell at half price this week.</span>`; + schoolSale("St. Claver Preparatory"); } if (V.TCR.schoolSale !== 0) { - r += `<br><span class="yellow">For your first purchase, </span><strong>[[The Cattle Ranch][$slavesSeen += 1]]</strong><span class="yellow"> will sell at half price this week.</span>`; + schoolSale("The Cattle Ranch"); } if (V.HA.schoolSale !== 0) { - r += `<br><span class="yellow">For your first purchase, </span><strong>[[The Hippolyta Academy][$slavesSeen += 1]]</strong><span class="yellow"> will sell at half price this week.</span>`; + schoolSale("The Hippolyta Academy"); } } if (V.seeDicks !== 0) { if (V.LDE.schoolSale !== 0) { - r += `<br><span class="yellow">For your first purchase, </span><strong>[[L'École des Enculées][$slavesSeen += 1]]</strong><span class="yellow"> will sell at half price this week.</span>`; + schoolSale("L'École des Enculées"); } if (V.TGA.schoolSale !== 0) { - r += `<br><span class="yellow">For your first purchase, </span><strong>[[The Gymnasium-Academy][$slavesSeen += 1]]</strong><span class="yellow"> will sell at half price this week.</span>`; + schoolSale("The Gymnasium-Academy"); } if (V.TFS.schoolSale !== 0) { - r += `<br><span class="yellow">For your first purchase, </span><strong>[[The Futanari Sisters][$slavesSeen += 1]]</strong><span class="yellow"> will sell at half price this week.</span>`; + schoolSale("The Futanari Sisters"); } } if (V.NUL.schoolSale !== 0) { - r += `<br><span class="yellow">For your first purchase, </span><strong>[[Nueva Universidad de Libertad][$slavesSeen += 1]]</strong><span class="yellow"> will sell at half price this week.</span>`; + schoolSale("Nueva Universidad de Libertad"); } - return r; + return fragment; }; -/* CLOSE MAIN */ diff --git a/src/js/main.js b/src/js/main.js index 913b1275da1d3819012cf796cd48a3f0e9431265..6460d82940e77d8e43ad90c963ca653f1fb58f7c 100644 --- a/src/js/main.js +++ b/src/js/main.js @@ -158,7 +158,7 @@ App.MainView.useGuard = function() { const outerDiv = document.createElement("div"); - if (guard === undefined || guard.assignment !== "guard you" || V.useSlaveSummaryOverviewTab === 1) { + if (guard === undefined || guard.assignment !== "guard you") { return outerDiv; } diff --git a/src/js/slaveListing.js b/src/js/slaveListing.js index 558bcc1b4e4ba26003ba30057dc2f4d314ddbd25..9fee57e17683f7aa829292c94f14a931c9b03802 100644 --- a/src/js/slaveListing.js +++ b/src/js/slaveListing.js @@ -383,7 +383,7 @@ App.UI.SlaveList.render = function() { * <<print 'pass/count/indexed/flag::[' + passageName + '/' + _Count + '/' + _indexed + '/' + $SlaveSummaryFiler + ']'>> */ - if (indices.length > 1 && passageName === "Main" && V.useSlaveSummaryTabs === 0) { + if (indices.length > 1 && passageName === "Main") { const _buttons = []; let _offset = -50; if (/Select/i.test(passageName)) { @@ -593,6 +593,31 @@ App.UI.SlaveList.sortingLinks = function(passage) { return r; }; +/** + * @param {string} passage + * @returns {*} + */ +App.UI.SlaveList.sortingLinksDOM = function(passage) { + const outerDiv = document.createElement("div"); + outerDiv.classList.add("flex-container"); + const textify = string => capFirstChar(string.replace(/([A-Z])/g, " $1")); + + let innerDiv = App.UI.DOM.makeElement("div", "Sort by: ", "indent"); + let order = ["devotion", "name", "assignment", "seniority", "actualAge", "visualAge", "physicalAge", "weeklyIncome"] + .map(so => V.sortSlavesBy !== so ? + App.UI.DOM.passageLink(textify(so), passage, () => { V.sortSlavesBy = so; }) : textify(so)); + innerDiv.append(App.UI.DOM.arrayToList(order, " | ", " | ")); + outerDiv.append(innerDiv); + + innerDiv = App.UI.DOM.makeElement("div", "Sort: ", "indent"); + order = ["descending", "ascending"].map(so => V.sortSlavesOrder !== so ? + App.UI.DOM.passageLink(textify(so), passage, () => { V.sortSlavesOrder = so; }) : textify(so)); + innerDiv.append(App.UI.DOM.arrayToList(order, " | ", " | ")); + outerDiv.append(innerDiv); + + return outerDiv; +}; + /** * Standard tabs for a facility with a single job (SJ) * @param {App.Entity.Facilities.Facility} facility @@ -617,8 +642,8 @@ App.UI.SlaveList.listSJFacilitySlaves = function(facility, facilityPassage, show r += '<div class="tabbar">' + App.UI.tabbar.tabButton('assign', tabCaptions.assign) + App.UI.tabbar.tabButton('remove', tabCaptions.remove) + - (showTransfersTab ? App.UI.tabbar.tabButton('transfer', tabCaptions.transfer) : '')+ - '</div>'; + (showTransfersTab ? App.UI.tabbar.tabButton('transfer', tabCaptions.transfer) : '') + + '</div>'; if (facility.hostedSlaves > 0) { let facilitySlaves = job.employeesIndices(); @@ -705,14 +730,19 @@ App.UI.SlaveList.listNGPSlaves = function() { r += '<div class="tabbar">' + App.UI.tabbar.tabButton('assign', 'Import a slave') + App.UI.tabbar.tabButton('remove', 'Remove from import') + - '</div>'; + '</div>'; const NGPassignment = "be imported"; /** @type {App.Entity.SlaveState[]} */ const slaves = V.slaves; if (V.slavesToImport > 0) { - const importedSlavesIndices = slaves.reduce((acc, s, i) => { if (s.assignment === NGPassignment) { acc.push(i); } return acc; }, []); + const importedSlavesIndices = slaves.reduce((acc, s, i) => { + if (s.assignment === NGPassignment) { + acc.push(i); + } + return acc; + }, []); SlaveSort.indices(importedSlavesIndices); r += App.UI.tabbar.makeTab("remove", App.UI.SlaveList.render.listMarkup(importedSlavesIndices, [], App.UI.SlaveList.makeNameDecorator(["emphasizedSlave", "pink"]), @@ -770,169 +800,137 @@ App.UI.SlaveList.stdFacilityPage = function(facility, showTransfersPage) { App.UI.SlaveList.penthousePage = function() { const ph = App.Entity.facilities.penthouse; - const listElementId = 'summarylist'; // for the untabbed mode only - - function span(text, cls, id) { - return `<span${cls ? ` class="${cls}"` : ''}${id ? ` id="${id}"` : ''}>${text}</span>`; - } function overviewTabContent() { - let r = ''; - const thisArcology = V.arcologies[0]; + const fragment = document.createDocumentFragment(); + const A = V.arcologies[0]; + let slaveWrapper = document.createElement("div"); // first is a div so we have no space between slave and buttons if (V.HeadGirl) { /** @type {App.Entity.SlaveState} */ const HG = V.HeadGirl; - r += `${span(SlaveFullName(HG), "emphasizedSlave pink")} is serving as your Head Girl`; - if (thisArcology.FSEgyptianRevivalistLaw === 1) { - r += ' and Consort'; + slaveWrapper.append(App.UI.DOM.makeElement("span", SlaveFullName(HG), "slave-name"), + " is serving as your Head Girl"); + if (A.FSEgyptianRevivalistLaw === 1) { + slaveWrapper.append(" and Consort"); } - r += `. <strong> ${span(App.UI.passageLink("Manage Head Girl", "HG Select"), null, "manageHG")}</strong> ${span("[H]", "cyan")}`; - r += App.UI.SlaveList.render.listMarkup([App.Utils.slaveIndexForId(HG.ID)], [], - App.UI.SlaveList.SlaveInteract.penthouseInteract); + slaveWrapper.append(". "); + const link = App.UI.DOM.makeElement("span", App.UI.DOM.passageLink("Manage Head Girl", "HG Select"), "major-link"); + link.id = "manageHG"; + slaveWrapper.append(link, " ", App.UI.DOM.makeElement("span", "[H]", "hotkey")); + slaveWrapper.append(App.UI.SlaveList.render.listDOM([App.Utils.slaveIndexForId(HG.ID)], [], + App.UI.SlaveList.SlaveInteract.penthouseInteract)); } else { if (V.slaves.length > 1) { - r += `You have ${span("not", "red")} selected a Head Girl`; - if (thisArcology.FSEgyptianRevivalistLaw === 1) { - r += ' and Consort'; + slaveWrapper.append("You have ", App.UI.DOM.makeElement("span", "not", "warning"), " selected a Head Girl"); + if (A.FSEgyptianRevivalistLaw === 1) { + slaveWrapper.append(" and Consort"); + } + slaveWrapper.append(". ", App.UI.DOM.makeElement("span", App.UI.DOM.passageLink("Select One", "HG Select"), "major-link"), + " ", App.UI.DOM.makeElement("span", "[H]", "hotkey")); + slaveWrapper.id = "manageHG"; + if (V.slavePanelStyle === 2) { + slaveWrapper.classList.add("slaveSummary", "card"); } - r += `. <strong>${span(App.UI.passageLink("Select One", "HG Select"), null, "manageHG")}</strong> ${span("[H]", "cyan")}`; } else { - r += '<em>You do not have enough slaves to keep a Head Girl</em>'; + slaveWrapper.append("You do not have enough slaves to keep a Head Girl"); + slaveWrapper.classList.add("note"); } } - r += '<br>'; + fragment.append(slaveWrapper); + slaveWrapper = document.createElement("p"); if (V.Recruiter) { /** @type {App.Entity.SlaveState} */ const RC = V.Recruiter; - const p = getPronouns(RC); - r += `${span(SlaveFullName(RC), "emphasizedSlave pink")} is working `; + const {he} = getPronouns(RC); + slaveWrapper.append(App.UI.DOM.makeElement("span", SlaveFullName(RC), "slave-name"), + " is working"); if (V.recruiterTarget !== "other arcologies") { - r += 'to recruit girls'; + slaveWrapper.append(" to recruit girls"); } else { - r += 'as a Sexual Ambassador'; - if (thisArcology.influenceTarget === -1) { - r += ', but ' + span(p.object + ' has no target to influence', "red"); + slaveWrapper.append(" as a Sexual Ambassador"); + if (A.influenceTarget === -1) { + slaveWrapper.append(", but ", App.UI.DOM.makeElement("span", `${he} has no target to influence.`, "warning")); } else { - const targetName = V.arcologies.find(a => a.direction === thisArcology.influenceTarget).name; - r += ' to ' + targetName; + const targetName = V.arcologies.find(a => a.direction === A.influenceTarget).name; + slaveWrapper.append(` to ${targetName}.`); } } - r += `${span('. <strong>' + App.UI.passageLink("Manage Recruiter", "Recruiter Select") + '</strong>', null, "manageRecruiter")} ${span("[U]", "cyan")}`; - r += App.UI.SlaveList.render.listMarkup([App.Utils.slaveIndexForId(RC.ID)], [], - App.UI.SlaveList.SlaveInteract.penthouseInteract); + slaveWrapper.append(". "); + const link = App.UI.DOM.makeElement("span", App.UI.DOM.passageLink("Manage Recruiter", "Recruiter Select"), "major-link"); + link.id = "manageRecruiter"; + slaveWrapper.append(link, " ", App.UI.DOM.makeElement("span", "[U]", "hotkey")); + slaveWrapper.append(App.UI.SlaveList.render.listDOM([App.Utils.slaveIndexForId(RC.ID)], [], + App.UI.SlaveList.SlaveInteract.penthouseInteract)); } else { - r += `You have ${span("not", "red")} selected a Recruiter. `; - r += `${span('<strong>' + App.UI.passageLink("Select one", "Recruiter Select") + '</strong>', null, "manageRecruiter")} ${span("[U]", "cyan")}`; + slaveWrapper.append("You have ", App.UI.DOM.makeElement("span", "not", "warning"), " selected a Recruiter. ", + App.UI.DOM.makeElement("span", App.UI.DOM.passageLink("Select one", "Recruiter Select"), "major-link"), + " ", App.UI.DOM.makeElement("span", "[U]", "hotkey")); + slaveWrapper.id = "manageRecruiter"; + if (V.slavePanelStyle === 2) { + slaveWrapper.classList.add("slaveSummary", "card"); + } } + fragment.append(slaveWrapper); if (V.dojo) { - r += '<br>'; + slaveWrapper = document.createElement("p"); /** @type {App.Entity.SlaveState} */ const BG = V.Bodyguard; if (BG) { - r += `${span(SlaveFullName(BG), "emphasizedSlave pink")} is serving as your bodyguard. `; - r += span(`<strong>${App.UI.passageLink("Manage Bodyguard", "BG Select")}</strong> `, null, "manageBG") + - span("[B]", "cyan"); - r += App.UI.SlaveList.render.listMarkup([App.Utils.slaveIndexForId(BG.ID)], [], - App.UI.SlaveList.SlaveInteract.penthouseInteract); + slaveWrapper.append(App.UI.DOM.makeElement("span", SlaveFullName(BG), "slave-name"), + " is serving as your bodyguard. "); + const link = App.UI.DOM.makeElement("span", App.UI.DOM.passageLink("Manage Bodyguard", "BG Select"), "major-link"); + link.id = "manageBG"; + slaveWrapper.append(link, " ", App.UI.DOM.makeElement("span", "[B]", "hotkey")); + slaveWrapper.append(App.UI.SlaveList.render.listDOM([App.Utils.slaveIndexForId(BG.ID)], [], + App.UI.SlaveList.SlaveInteract.penthouseInteract)); + slaveWrapper.append(App.MainView.useGuard()); } else { - r += `You have ${span("not", "red")} selected a Bodyguard. `; - r += span(`<strong>${App.UI.passageLink("Select one", "BG Select")}</strong> `, null, "manageBG") + - span("[B]", "cyan"); - } - - /* Start Italic event text */ - if (BG && BG.assignment === "guard you") { - const p = getPronouns(BG); - V.i = App.Utils.slaveIndexForId(BG.ID); - const interactLinkSetters = `$activeSlave = $slaves[${V.i}], $nextButton = "Back", $nextLink = "AS Dump", $returnTo = "Main"`; - r += `<br><span class='scene-intro'>${App.Interact.guardPose(BG)}</span>`; - let useHimLinks = []; - useHimLinks.push(App.UI.passageLink(`Use ${p.his} mouth`, "FLips", interactLinkSetters)); - useHimLinks.push(App.UI.passageLink(`Play with ${p.his} tits`, "FBoobs", interactLinkSetters)); - if (canDoVaginal(BG)) { - useHimLinks.push(App.UI.passageLink(`Fuck ${p.him}`, "FVagina", interactLinkSetters)); - if (canDoAnal(BG)) { - useHimLinks.push(App.UI.passageLink(`Use ${p.his} holes`, "FButt", interactLinkSetters)); - } - if (BG.belly >= 300000) { - useHimLinks.push(App.UI.passageLink(`Fuck ${p.him} over ${p.his} belly`, "FBellyFuck", interactLinkSetters)); - } - } - /* check */ - if (canPenetrate(BG)) { - useHimLinks.push(App.UI.passageLink(`Ride ${p.him}`, "FDick", interactLinkSetters)); + slaveWrapper.append("You have ", App.UI.DOM.makeElement("span", "not", "warning"), " selected a Bodyguard. ", + App.UI.DOM.makeElement("span", App.UI.DOM.passageLink("Select one", "BG Select"), "major-link"), + " ", App.UI.DOM.makeElement("span", "[B]", "hotkey")); + slaveWrapper.id = "manageBG"; + if (V.slavePanelStyle === 2) { + slaveWrapper.classList.add("slaveSummary", "card"); } - if (canDoAnal(BG)) { - useHimLinks.push(App.UI.passageLink(`Fuck ${p.his} ass`, "FAnus", interactLinkSetters)); - } - useHimLinks.push(App.UI.passageLink(`Abuse ${p.him}`, "Gameover", '$gameover ="idiot ball"')); - - r += `<br> ${useHimLinks.join(' | ')}`; - /* End Italic event text */ } - r += "<br/>"; + + fragment.append(slaveWrapper); } - return r; + return fragment; } /** * @param {string} job - * @returns {{n: number, text: string}} + * @returns {{n: number, dom: DocumentFragment}} */ function _slavesForJob(job) { const employeesIndices = job === 'all' ? ph.employeesIndices() : ph.job(job).employeesIndices(); - if (employeesIndices.length === 0) { return {n: 0, text: ''}; } + if (employeesIndices.length === 0) { + return {n: 0, dom: document.createDocumentFragment()}; + } SlaveSort.indices(employeesIndices); return { n: employeesIndices.length, - text: App.UI.SlaveList.render.listMarkup(employeesIndices, [], App.UI.SlaveList.SlaveInteract.penthouseInteract) + dom: App.UI.SlaveList.render.listDOM(employeesIndices, [], App.UI.SlaveList.SlaveInteract.penthouseInteract) }; } - /** - * Displays job filter links, whose action are generated by the callback - * @param {assignmentFilterGenerateCallback} callback - * @returns {string} - */ - function _jobFilter(callback) { - const jd = App.Data.Facilities.penthouse.jobs; - let links = []; - links.push(`<<link "All">>${callback('all')}<</link>>`); - // seems like SC2 does not process data-setter when data-passage is not set - for (const jn in jd) { - links.push(`<<link "${capFirstChar(jd[jn].position)}">>${callback(jn)}<</link>>`); - } - - return links.join(' | '); - } - - function _updateList(job) { - State.temporary.mainPageUpdate.job = job; - const e = document.getElementById(listElementId); - e.innerHTML = ''; - const employeesIndices = job === 'all' ? ph.employeesIndices() : ph.job(job).employeesIndices(); - if (employeesIndices.length === 0) { - return; - } - SlaveSort.indices(employeesIndices); - e.appendChild(App.UI.SlaveList.render.listDOM(employeesIndices, [], App.UI.SlaveList.SlaveInteract.penthouseInteract)); - } /** * @typedef tabDesc * @property {string} tabName * @property {string} caption - * @property {string} content + * @property {Node} content */ /** * @param {string} tabName * @param {string} caption - * @param {string} content + * @param {Node} content * @returns {tabDesc} */ function makeTabDesc(tabName, caption, content) { @@ -945,111 +943,131 @@ App.UI.SlaveList.penthousePage = function() { /** * Displays encyclopedia entries for occupations at the top of the tab, if enabled - * @returns {string} + * @returns {HTMLSpanElement} */ function encycTips(jn) { - let r =`<span class="note">`; + const span = document.createElement("span"); + span.classList.add("note"); if (V.showTipsFromEncy) { switch (jn) { case "rest": - r += `<<encyclopediaEntryRest>>`; + span.append(App.Encyclopedia.Entries.rest()); break; case "chooseOwn": break; /* no entry written for choose own */ case "fucktoy": - r += `<<encyclopediaEntryFucktoy>>`; + span.append(App.Encyclopedia.Entries.fucktoy()); break; case "classes": - r += `<<encyclopediaEntryAttendingClasses>>`; + span.append(App.Encyclopedia.Entries.attendingClasses()); break; case "houseServant": - r += `<<encyclopediaEntryServitude>>`; + span.append(App.Encyclopedia.Entries.servitude()); break; case "whore": - r += `<<encyclopediaEntryWhoring>>`; + span.append(App.Encyclopedia.Entries.whoring()); break; case "publicServant": - r += `<<encyclopediaEntryPublicService>>`; + span.append(App.Encyclopedia.Entries.publicService()); break; case "subordinateSlave": - r += `<<encyclopediaEntrySexualServitude>>`; + span.append(App.Encyclopedia.Entries.sexualServitude()); break; case "cow": - r += `<<encyclopediaEntryMilking>>`; + span.append(App.Encyclopedia.Entries.milking()); break; case "gloryhole": - r += `<<encyclopediaEntryGloryHole>>`; + span.append(App.Encyclopedia.Entries.gloryHole()); break; case "confinement": - r += `<<encyclopediaEntryConfinement>>`; + span.append(App.Encyclopedia.Entries.confinement()); break; default: - r += `missing tip for this tab`; + span.append(App.UI.DOM.makeElement("span", "missing tip for this tab", "error")); break; } } - return r += `</span>`; + return span; } - let r = ''; + function allTab() { + const penthouseSlavesIndices = ph.employeesIndices(); + SlaveSort.indices(penthouseSlavesIndices); + return makeTabDesc('all', `All${V.useSlaveSummaryTabs > 0 ? ` (${penthouseSlavesIndices.length})` : ""}`, + App.UI.SlaveList.render.listDOM(penthouseSlavesIndices, [], App.UI.SlaveList.SlaveInteract.penthouseInteract)); + } + + let fragment = document.createDocumentFragment(); if (V.positionMainLinks >= 0) { - r += '<center>' + App.UI.View.MainLinks() + '</center><br>'; + fragment.append(App.UI.DOM.makeElement("div", App.UI.View.mainLinks(), "center")); } if (V.sortSlavesMain) { - r += '<br>' + this.sortingLinks("Main") + '<br>'; + fragment.append(this.sortingLinksDOM("Main")); } - if (V.useSlaveSummaryTabs) { - /** @type {tabDesc[]} */ - let tabs = []; + /** @type {tabDesc[]} */ + let tabs = []; - // Overview tab - if (V.useSlaveSummaryOverviewTab) { - tabs.push(makeTabDesc('overview', 'Overview', overviewTabContent())); - } + // Overview tab + if (V.useSlaveSummaryOverviewTab) { + tabs.push(makeTabDesc('overview', "Special Roles", overviewTabContent())); + } - // tabs for each assignment - for (const jn of ph.jobsNames) { - const slaves = _slavesForJob(jn); - if (slaves.n > 0) { - tabs.push(makeTabDesc(jn, `${ph.desc.jobs[jn].position} (${slaves.n})`, encycTips(jn) + slaves.text)); - } - } + if (V.useSlaveSummaryTabs === 0) { + tabs.push(allTab()); + } - // now generate the "All" tab - const penthouseSlavesIndices = ph.employeesIndices(); - SlaveSort.indices(penthouseSlavesIndices); - tabs.push(makeTabDesc('all', `All (${penthouseSlavesIndices.length})`, - this.render.listMarkup(penthouseSlavesIndices, [], App.UI.SlaveList.SlaveInteract.penthouseInteract))); + // tabs for each assignment + for (const jn of ph.jobsNames) { + const slaves = _slavesForJob(jn); + if (slaves.n > 0) { + tabs.push(makeTabDesc(jn, `${ph.desc.jobs[jn].position}${V.useSlaveSummaryTabs > 0 ? ` (${slaves.n})` : ""}`, App.UI.DOM.combineNodes(encycTips(jn), slaves.dom))); + } else if (V.useSlaveSummaryTabs === 0) { + tabs.push(makeTabDesc(jn, ph.desc.jobs[jn].position, encycTips(jn))); + } + } + if (V.useSlaveSummaryTabs > 0) { + tabs.push(allTab()); + } - r += '<div class="tabbar">'; + const div = document.createElement("div"); + div.classList.add("tabbar"); + if (V.useSlaveSummaryTabs === 0) { + const links = []; for (const tab of tabs) { - r += App.UI.tabbar.tabButton(tab.tabName, tab.caption); + links.push(App.UI.tabbar.tabButtonDOM(tab.tabName, tab.caption, true)); } - r += '</div>'; - + div.append(App.UI.DOM.arrayToList(links, " | ", " | ")); + } else { for (const tab of tabs) { - r += App.UI.tabbar.makeTab(tab.tabName, tab.content); + const button = App.UI.tabbar.tabButtonDOM(tab.tabName, tab.caption); + if (V.useSlaveSummaryTabs === 2) { + button.classList.add("card"); + } + div.append(button); } - } else { - State.temporary.mainPageUpdate = { - job: State.temporary.mainPageUpdate ? State.temporary.mainPageUpdate.job : 'all', - update: _updateList - }; - - $(document).one(':passagedisplay', () => { _updateList(State.temporary.mainPageUpdate.job); }); - r += `<div>${_jobFilter(s => `<<run _mainPageUpdate.update("${s}")>>`)} <div id=${listElementId}></div></div>`; + } + fragment.append(div); + + for (const tab of tabs) { + const div = App.UI.tabbar.makeTabDOM(tab.tabName, tab.content); + if (V.useSlaveSummaryTabs === 0) { + div.classList.add("noFade"); + } else if (V.useSlaveSummaryTabs === 2) { + div.classList.add("card"); + } + fragment.append(div); } if (V.positionMainLinks <= 0) { - r += '<br><center>' + App.UI.View.MainLinks() + '</center>'; + fragment.append(App.UI.DOM.makeElement("div", App.UI.View.mainLinks(), "center")); } App.UI.tabbar.handlePreSelectedTab(); - return r; + return App.UI.DOM.includeDOM(fragment, "penthouseDOM"); }; /** diff --git a/src/js/utilsDOM.js b/src/js/utilsDOM.js index 67f70fb1ec862bef704507e3312cc0340b297940..e087b7c3730b08681221f1ee14bd496366acd918 100644 --- a/src/js/utilsDOM.js +++ b/src/js/utilsDOM.js @@ -247,6 +247,46 @@ App.UI.DOM.colorInput = function(defaultValue, onEnter) { return input; }; +/** + * @param {Node} node + * @param {string} uniqueID - should be unique in the whole passage + * @param {string} [tag] + * @returns {string} + */ +App.UI.DOM.includeDOM = function(node, uniqueID, tag = "span") { + $(document).one(':passagedisplay', () => { $(`#inclDOM${uniqueID}`).append(node); }); + + return `<${tag} id='inclDOM${uniqueID}'></${tag}>`; +}; + +/** + * Concats an array of DOM nodes or strings into a human readable list. + * + * @param {Array<Node|string>} content + * @param {string} [delimiter] + * @param {string} [lastDelimiter] + * @returns {Node|string} + */ +App.UI.DOM.arrayToList = function(content, delimiter = ", ", lastDelimiter = " and ") { + if (content.length === 0) { + return "none"; + } + if (this.length === 1) { + return content[0]; + } + const fragment = document.createDocumentFragment(); + const last = content.pop(); + for (let i = 0; i < content.length; i++) { + fragment.append(content[i]); + if (i < content.length - 1) { + fragment.append(delimiter); + } + } + content.push(last); // don't leave the array modified + fragment.append(lastDelimiter, last); + return fragment; +}; + /** * @param {string} text * @returns {HTMLElement} diff --git a/src/js/utilsSC.js b/src/js/utilsSC.js index 0750f1ffeae7d7b18fae4b2d91d08dd24c327d8a..5e1e5008faf948cbb7dfed1f6c0bb62c6a2ee708 100644 --- a/src/js/utilsSC.js +++ b/src/js/utilsSC.js @@ -147,7 +147,9 @@ App.UI.tabbar = function() { return { openTab: openTab, tabButton: tabButton, + tabButtonDOM: tabButtonDOM, makeTab: makeTab, + makeTabDOM: makeTabDOM, handlePreSelectedTab: handlePreSelectedTab, tabChoiceVarName: tabChoiceVarName }; @@ -176,6 +178,34 @@ App.UI.tabbar = function() { return `<button class="tablinks" onclick="App.UI.tabbar.openTab(event, '${name}')" id="tab ${name}">${text}</button>`; } + /** + * @param {string} name + * @param {string} text + * @param {boolean} [plainLink] + * @returns {HTMLButtonElement|HTMLAnchorElement} + */ + function tabButtonDOM(name, text, plainLink = false) { + if (plainLink) { + const link = document.createElement("a"); + link.classList.add("tablinks", "pure"); + link.id = `tab ${name}`; + link.textContent = text; + link.addEventListener('click', event => { + openTab(event, name); + }); + return link; + } else { + const button = document.createElement("button"); + button.classList.add("tablinks"); + button.id = `tab ${name}`; + button.textContent = text; + button.addEventListener('click', event => { + openTab(event, name); + }); + return button; + } + } + /** * @param {string} name * @param {string} content @@ -185,20 +215,41 @@ App.UI.tabbar = function() { return `<div id="${name}" class="tabcontent"><div class="content">${content}</div></div>`; } + /** + * @param {string} name + * @param {Node} content + * @returns {HTMLDivElement} + */ + function makeTabDOM(name, content) { + const outerDiv = document.createElement("div"); + outerDiv.id = name; + outerDiv.classList.add("tabcontent"); + const innerDiv = document.createElement("div"); + innerDiv.classList.add("content"); + innerDiv.append(content); + outerDiv.append(innerDiv); + return outerDiv; + } + function handlePreSelectedTab(defaultTab = "assign", immidiate = false) { let selectedTab = State.variables.tabChoice[tabChoiceVarName()]; - if (!selectedTab) { selectedTab = defaultTab; } + if (!selectedTab) { + selectedTab = defaultTab; + } + function selectTab() { let tabBtn = document.getElementById(`tab ${selectedTab}`); if (!tabBtn) { tabBtn = document.getElementsByClassName('tablinks').item(0); } - if (tabBtn) { tabBtn.click(); } + if (tabBtn) { + tabBtn.click(); + } } if (immidiate) { selectTab(); } else { - $(document).one(':passagedisplay', selectTab); + $(document).one(':passageend', selectTab); } } diff --git a/src/uncategorized/main.tw b/src/uncategorized/main.tw index 6e72d937b2de51578c43dac0fcd4be49da88a4d2..b877403e3fb57a8b7a6c943c7bb3bcfe03f2eb5f 100644 --- a/src/uncategorized/main.tw +++ b/src/uncategorized/main.tw @@ -106,14 +106,16 @@ __''MAIN MENU''__ //[[Summary Options]]// <</script>> <</if>> -<span id="BG"></span> -<<script>> - $(document).one(':passageend', () => { - $('#BG').append( - App.MainView.useGuard(), - ); - }); -<</script>> +<<if $useSlaveSummaryOverviewTab === 0>> + <span id="BG"></span> + <<script>> + $(document).one(':passageend', () => { + $('#BG').append( + App.MainView.useGuard(), + ); + }); + <</script>> +<</if>> <<set $activeSlave = $slaves.random()>> <<if $activeSlave && ($activeSlave.assignment != "please you") && ($activeSlave.assignment != "guard you")>> diff --git a/src/uncategorized/options.tw b/src/uncategorized/options.tw index b45be0ef4dbaa77c07b1615fcca3ea5be7945603..d7160133660929bda66e83906de8137e5b48c4a1 100644 --- a/src/uncategorized/options.tw +++ b/src/uncategorized/options.tw @@ -223,6 +223,7 @@ This save was created using FC version $ver build $releaseID. Main menu slave tabs are <<option 1 "Enabled">> <<option 0 "Disabled">> + <<option 2 "Cardstyle">> <</options>> <<options $useSlaveListInPageJSNavigation>> @@ -231,14 +232,11 @@ This save was created using FC version $ver build $releaseID. <<option 0 "Disabled">> <</options>> - <<if $useSlaveSummaryTabs > 0>> - <br> - <<options $useSlaveSummaryOverviewTab>> - Condense special slaves into an overview tab - <<option 1 "Enabled">> - <<option 0 "Disabled">> - <</options>> - <</if>> + <<options $useSlaveSummaryOverviewTab>> + Condense special slaves into their own tab + <<option 1 "Enabled">> + <<option 0 "Disabled">> + <</options>> <<options $lineSeparations "Summary Options">> Line separations are