diff --git a/devTools/javaSanityCheck/ignoredVariables b/devTools/javaSanityCheck/ignoredVariables index cf7011ee74099424c855ed37f7316ec044e7281b..1b839f16bb14a9c20a0deb915d08653c79756e1b 100644 --- a/devTools/javaSanityCheck/ignoredVariables +++ b/devTools/javaSanityCheck/ignoredVariables @@ -84,6 +84,8 @@ saRules plural orig bimboMaleNames +RuleHasError +DefaultRulesError # PC vision criticalDamage diff --git a/src/004-base/proxies.js b/src/004-base/proxies.js index 9ce94c7366f622e34bf28802f616152f3dc35320..03fc68bf390c917ca8c95735fa47a3463e24287a 100644 --- a/src/004-base/proxies.js +++ b/src/004-base/proxies.js @@ -1,55 +1,122 @@ -window.createReadonlyProxy = function(target) { - if (target.__isReadonlyProxy) { return target; } - return new Proxy(target, { - get: function(o, prop) { - if (prop == '__isReadonlyProxy') { return true; } - return createReadonlyProxy(o[prop]); - }, - set: function(o, prop, value) { - return false; - }, - deleteProperty: function(o, prop) { - return false; +(function() { + const readOnlySymbol = Symbol("readonly proxy"); + window.createReadonlyProxy = function(target) { + if (target == null) return target; //intentionally == + if (target[readOnlySymbol]) { return target; } + if (_.isArray(target)) { + return new Proxy(target, { + get:function(o, prop) { + if(prop === readOnlySymbol) { return true; } + const val = o[prop]; + if (typeof val === 'function') { + if (['push', 'unshift', 'pop'].includes(prop)) { + return function () { + throw Error("Cannot modify a readonly array"); + } + } + return val.bind(target); + } + return createReadonlyProxy(val); + }, + set:function(o, prop, value) { + return true; + }, + deleteProperty:function(o, prop) { + return true; + } + }); } - }); -}; -window.createCheatProxy = function(target) { - if (target.__isCheatProxy) { return target; } - return new Proxy(target, { - get: function(o, prop) { - if (prop == '__isCheatProxy') { return true; } - return createCheatProxy(o[prop]); - }, - set: function(o, prop, value) { - o[prop] = value; - State.variables.cheater = 1; - return true; - }, - deleteProperty: function(o, prop) { - delete o[prop]; - State.variables.cheater = 1; - return false; + if (_.isObject(target)) { + return new Proxy(target, { + get:function(o, prop) { + if(prop === readOnlySymbol) { return true; } + return createReadonlyProxy(o[prop]); + }, + set:function(o, prop, value) { + return true; + }, + deleteProperty:function(o, prop) { + return true; + } + }); } - }); -}; + return target; + }; + const cheaterSymbol = Symbol("cheating proxy"); + window.createCheatProxy = function(target) { + if (target == null) return target; //intentionally == + if (target[cheaterSymbol]) { return target; } + if (_.isArray(target)) { + return new Proxy(target, { + get:function(o, prop) { + if(prop === cheaterSymbol) { return true; } + const val = o[prop]; + if (typeof val === 'function') { + if (['push', 'unshift', 'pop'].includes(prop)) { + return function (el) { + const retval = Array.prototype[prop].apply(o, arguments); + //Make sure we set cheater after calling the function + State.variables.cheater = 1;//Can't use `V` because it probably points to a proxy. + return retval; + } + } + return val.bind(target); + } + return createCheatProxy(val); + }, + set:function(o, prop, value) { + o[prop] = value; + State.variables.cheater = 1;//Can't use `V` because it probably points to a proxy. + return true; + }, + deleteProperty:function(o, prop) { + delete o[prop]; + State.variables.cheater = 1;//Can't use `V` because it probably points to a proxy. + return true; + } + }); + } + if (_.isObject(target)) { + return new Proxy(target, { + get:function(o, prop) { + if(prop === cheaterSymbol) { return true; } + return createCheatProxy(o[prop]); + }, + set:function(o, prop, value) { + o[prop] = value; + State.variables.cheater = 1; + return true; + }, + deleteProperty:function(o, prop) { + delete o[prop]; + State.variables.cheater = 1; + return true; + } + }); + } + return target; + }; +})(); Object.defineProperty(window, "V", { get: function() { if (window.storyProxy != null) { return window.storyProxy; } return State.variables; } }); +//This should be used if the user might use V under normal, non-cheating circumstances but shouldn't be punished for accidentally setting the value. The attempt to make the change will simply be disregarded. window.runWithReadonlyProxy = function(callback) { window.storyProxy = createReadonlyProxy(State.variables); try { - callback(); + return callback(); } finally { window.storyProxy = null; } }; +// This should be used if setting values would constitute cheating. For example, a debug view that shows all variables in an editable form; showing isn't cheating, but making a change would be. window.runWithCheatProxy = function(callback) { window.storyProxy = createCheatProxy(State.variables); try { - callback(); + return callback(); } finally { window.storyProxy = null; } diff --git a/src/SecExp/js/secExp.js b/src/SecExp/js/secExp.js index ba09c63b768a7855443382aab7da976ce1184ed2..e656e4f042c08cdedfcdabe9ce7ded14e7f1fa46 100644 --- a/src/SecExp/js/secExp.js +++ b/src/SecExp/js/secExp.js @@ -456,11 +456,6 @@ App.SecExp.Check = (function() { delete V.difficulty; } - if (V.PCWounded === 1 && V.PCWoundCooldown > 0) { - V.SecExp.pcWounded = V.PCWoundCooldown; - delete V.PCWoundCooldown; - } - V.SecExp.settings.battle = V.SecExp.settings.battle || {}; V.SecExp.settings.battle.enabled = V.SecExp.settings.battle.enabled || 1; if (jsDef(V.battlesEnabled)) { diff --git a/src/gui/css/mainStyleSheet.css b/src/gui/css/mainStyleSheet.css index 269a6c106604d81e519f9a3aedfeb5fdac7922e2..0855e9cf5e27d57a28b441d279a7f0d1e0ae6d3c 100644 --- a/src/gui/css/mainStyleSheet.css +++ b/src/gui/css/mainStyleSheet.css @@ -284,11 +284,19 @@ white-space: normal; color: #68D; margin-right: 1em; } +.rajs-listitem.selected { + color: gray; + text-decoration: none; +} .rajs-listitem:last-of-type { margin-right: 0; } .rajs-listitem:hover { cursor: pointer; text-decoration: underline; } +.rajs-listitem.selected:hover { + cursor: default; + text-decoration: none; +} .rajs-list strong:first-of-type, .rajs-list input { margin-right: 2em; } diff --git a/src/init/storyInit.tw b/src/init/storyInit.tw index 9d372873dea58f2389c0d6de5a61814743df1ef5..dd729bd8ab4313a0b4a310bf0197f18099c1ae03 100644 --- a/src/init/storyInit.tw +++ b/src/init/storyInit.tw @@ -1492,7 +1492,7 @@ You should have received a copy of the GNU General Public License along with thi /* Security Expansion */ <<set $wasToggledBefore = 0>> -<<set $PCWounded = 0>> +<<set $PC.majorInjury = 0>> /* moved first build to post toggle */ <<set $secExpEnabled = $secExpEnabled || 0>> diff --git a/src/interaction/main/mainLinks.js b/src/interaction/main/mainLinks.js index ba03d63c83c30c13e7a52778f37fe8cdfc0c46eb..c375f7ab6605d3831d8c0decea516e59361e127e 100644 --- a/src/interaction/main/mainLinks.js +++ b/src/interaction/main/mainLinks.js @@ -4,7 +4,7 @@ App.UI.View.MainLinks = function() { const PA = Array.isArray(V.personalAttention) ? V.personalAttention.map(x => getSlave(x.ID)) : []; let r = ''; - if (V.PCWounded === 1) { + if (V.PC.majorInjury === 1) { r += `The injuries received in the recent battle prevent you from undertaking tiring efforts.`; } else { switch (V.personalAttention) { @@ -75,7 +75,7 @@ App.UI.View.MainLinks = function() { } } - if (V.PCWounded !== 1) { + if (V.PC.majorInjury !== 1) { r += ` <span id="managePA"><strong><<link "Change plans">><<goto "Personal Attention Select">><</link>></strong></span> <span class="cyan">[A]</span>`; } diff --git a/src/js/DefaultRules.js b/src/js/DefaultRules.js index ad0ec052a1263b54b0acff0a2969e7f30c922c34..cd5fd6efe7a120ac3f2aa55da62c1579d685e8b8 100644 --- a/src/js/DefaultRules.js +++ b/src/js/DefaultRules.js @@ -16,7 +16,8 @@ window.DefaultRules = (function() { if (slave.useRulesAssistant === 0) { return r; } // exempted r = ""; ({he, him, his} = getPronouns(slave)); - let rule = MergeRules(slave); + let slaveReadOnly = createReadonlyProxy(slave); + let rule = runWithReadonlyProxy(()=>MergeRules(slaveReadOnly)); if (Object.keys(rule).length === 0) { return r; } // no rules apply AssignJobToSlave(slave, rule); @@ -2936,5 +2937,20 @@ window.DefaultRules = (function() { } } + const rxCheckEqual = /[^!=<>]=[^=<>]/gi; + const compileCheck = function(code) { + try { + //TODO: This should use a cached Function, which should be the same as below. + new Function(`return ${code}`); + } + catch(e) { + return false; + } + return true; + } + window.RuleHasError = (rule) => rule.condition.function === "custom" + &&(rule.condition.data.match(rxCheckEqual) + || !compileCheck(rule.condition.data)); + window.DefaultRulesError = () => V.defaultRules.some(r => RuleHasError(r)); return DefaultRules; })(); diff --git a/src/js/economyJS.js b/src/js/economyJS.js index 4a707dceb4b9ce00938651141c3ff4c369ab7799..f4200b264b1d9ff5f631829d13cd62a1b007b992 100644 --- a/src/js/economyJS.js +++ b/src/js/economyJS.js @@ -943,12 +943,12 @@ window.NPCSexSupply = function(lowerDemandLeft, lowerTotalDemand, middleDemandLe // Top class calculations const topClassNPCRatio = NPCSexSupply.topClass / topDemandLeft; - const topClassOptimalRatio = 0.5 + V.sexSubsidies.topClass / 10 - V.sexSupplyBarriers.topClass / 10; + const topClassOptimalRatio = 0.5 + V.sexSubsidies.topClass / 8 - V.sexSupplyBarriers.topClass / 10; const topClassOptimal = topDemandLeft * topClassOptimalRatio; if (NPCSexSupply.topClass > topTotalDemand * (0.3 - V.sexSupplyBarriers.topClass / 20)) { - if (topClassNPCRatio >= topClassOptimalRatio + 0.05) { + if (topClassNPCRatio >= topClassOptimalRatio + 0.025) { NPCSexSupply.topClass -= Math.min(NPCSexSupply.topClass - Math.trunc((NPCSexSupply.topClass * 4 + topClassOptimal) / 5), Math.trunc(NPCSexSupply.topClass * 0.1)); - } else if (topClassNPCRatio <= topClassOptimalRatio - 0.05) { + } else if (topClassNPCRatio <= topClassOptimalRatio - 0.025) { NPCSexSupply.topClass += Math.trunc(Math.clamp((NPCSexSupply.topClass * 4 + topClassOptimal) / 5 - NPCSexSupply.topClass, 500, NPCSexSupply.topClass * 0.1) * (1 - V.sexSupplyBarriers.topClass / 5)); } else { NPCSexSupply.topClass = Math.trunc(NPCSexSupply.topClass * (1 + normalRandInt(0, 20) / 1000)); @@ -1166,6 +1166,9 @@ window.slaveJobValues = function(lowerClassSexDemandRef, middleClassSexDemandRef } } } + + // The Madam adding to 'brothel' + SJVBrothel(V.slaves[V.slaveIndices[V.Madam.ID]]); } @@ -1550,14 +1553,7 @@ window.slaveJobValues = function(lowerClassSexDemandRef, middleClassSexDemandRef } // The amount of sexual acts - s.sexAmount = Beauty(s); - - if (s.assignment === "be the Madam") { - if ((BL + toTheBrothelTotal > 0) && (CL + toTheBrothelTotal < 10)) { - s.sexAmount *= ((10 - CL - toTheBrothelTotal) / 10) * 1.5; - } - } - s.sexAmount = Math.trunc(s.sexAmount * beautyMultiplier * (1 + (0.002 * s.skill.whoring))); + s.sexAmount = Math.trunc(Beauty(s) * beautyMultiplier * (1 + (0.002 * s.skill.whoring))); // The quality/value of each sexual act s.sexQuality = FResult(s); @@ -1599,14 +1595,14 @@ window.slaveJobValues = function(lowerClassSexDemandRef, middleClassSexDemandRef // Automatically changing effectiveWhoreClass // what is the initial effective whore class? Are we providing more sex than overal demand? Is the ratio of supply/demand for this tier higher than the one below it? // This also takes into consideration public sluts and ignores the NPC market and arcades - const topSDRatio = slaveJobValues.brothel.topClass / topClassSexDemandRef; - const upperSDRatio = slaveJobValues.brothel.upperClass / upperClassSexDemandRef; + const topSDRatio = slaveJobValues.brothel.topClass / (topClassSexDemandRef - V.NPCSexSupply.topClass); + const upperSDRatio = slaveJobValues.brothel.upperClass / (upperClassSexDemandRef - V.NPCSexSupply.upperClass); const middleClubSupply = slaveJobValues.club * slaveJobValues.clubSP * (middleClassSexDemandRef / (lowerClassSexDemandRef + middleClassSexDemandRef)); const middleSupply = slaveJobValues.brothel.middleClass + middleClubSupply; - const middleSDRatio = middleSupply / middleClassSexDemandRef; + const middleSDRatio = middleSupply / (middleClassSexDemandRef - V.NPCSexSupply.middleClass); const lowerClubSupply = slaveJobValues.club * slaveJobValues.clubSP * (lowerClassSexDemandRef / (lowerClassSexDemandRef + middleClassSexDemandRef)); const lowerSupply = slaveJobValues.brothel.lowerClass + lowerClubSupply; - const lowerSDRatio = lowerSupply / lowerClassSexDemandRef; + const lowerSDRatio = lowerSupply / (lowerClassSexDemandRef - V.NPCSexSupply.lowerClass); if (s.effectiveWhoreClass === 4 && topSDRatio > 1 && topSDRatio > upperSDRatio) { s.effectiveWhoreClass -= 1; } @@ -1619,20 +1615,20 @@ window.slaveJobValues = function(lowerClassSexDemandRef, middleClassSexDemandRef // Calculate the stats if (s.effectiveWhoreClass === 4) { - s.sexAmount = normalRandInt(50, 4); // Bringing sex amount into the desired range - s.sexQuality = Math.trunc(Math.min((income * 1.2) / s.sexAmount, V.whoreBudget.topClass * 0.2)); // Adjusting the price to the correct sex amount with 20% bonus for being of the highest tier + s.sexAmount = Math.clamp(Math.trunc(s.sexAmount * (1/3)), normalRandInt(30, 2), normalRandInt(60, 3)); // Bringing sex amount into the desired range. Beauty improves use amount between values of aprox. 90 and 180. + s.sexQuality = Math.min(Math.trunc(Math.min((income * 1.2) / s.sexAmount, V.whoreBudget.topClass * 0.2)), Math.trunc(V.whoreBudget.topClass * (1/3))); // Adjusting the price to the correct sex amount with 20% bonus for being of the highest tier. The top class will pay a maximum of 33% of their weekly budget per service. slaveJobValues.brothel.topClass += Math.trunc(Math.min(s.sexAmount * s.sexQuality, s.sexAmount * V.whoreBudget.topClass * 0.2)); // Registering the job value in the right slot } else if (s.effectiveWhoreClass === 3) { - s.sexAmount = normalRandInt(60, 5); - s.sexQuality = Math.min(Math.trunc((income * 1.05) / s.sexAmount), V.whoreBudget.upperClass * 0.5); // The upper class will pay a maximum of 60% of their weekly budget per service + s.sexAmount = Math.clamp(Math.trunc(s.sexAmount * (2/3)), normalRandInt(40, 3), normalRandInt(80, 3)); // Beauty improves use amount between values of aprox. 60 and 120. + s.sexQuality = Math.min(Math.trunc((income * 1.05) / s.sexAmount), V.whoreBudget.upperClass * 0.5); // The upper class will pay a maximum of 50% of their weekly budget per service slaveJobValues.brothel.upperClass += Math.trunc(Math.min(s.sexAmount * s.sexQuality, s.sexAmount * V.whoreBudget.upperClass * 0.6)); } else if (s.effectiveWhoreClass === 2) { - s.sexAmount = normalRandInt(70, 6); + s.sexAmount = Math.clamp(Math.trunc(s.sexAmount * 1.25), normalRandInt(50, 3), normalRandInt(120, 3)); // Beauty improves use amount between values of aprox. 40 and 96. s.sexQuality = Math.min(Math.trunc((income * 0.9) / s.sexAmount), V.whoreBudget.middleClass); // The middle class will pay a maximum of 125% of their weekly budget per service slaveJobValues.brothel.middleClass += Math.trunc(Math.min(s.sexAmount * s.sexQuality, s.sexAmount * V.whoreBudget.middleClass * 1.25)); } else { - s.sexAmount = normalRandInt(80, 7); - s.sexQuality = Math.clamp((income * 0.75) / s.sexAmount, 2, V.whoreBudget.lowerClass * 2); // The lower class will pay a maximum of 300% of their weekly budget per service and a minimum of 2 + s.sexAmount = Math.clamp(s.sexAmount * 2, normalRandInt(60, 3), normalRandInt(150, 3)); // Beauty improves use amount between values of approx. 30 and 75. + s.sexQuality = Math.clamp((income * 0.75) / s.sexAmount, 2, V.whoreBudget.lowerClass * 3); // The lower class will pay a maximum of 300% of their weekly budget per service and a minimum of 2 slaveJobValues.brothel.lowerClass += Math.trunc(Math.min(s.sexAmount * s.sexQuality, s.sexAmount * V.whoreBudget.lowerClass * 3)); } } @@ -1641,6 +1637,13 @@ window.slaveJobValues = function(lowerClassSexDemandRef, middleClassSexDemandRef s.whoreClass = 0; } whoreScore(s, lowerClassSexDemandRef, middleClassSexDemandRef, upperClassSexDemandRef, topClassSexDemandRef); + + if (s.assignment === "be the Madam") { + if ((BL + toTheBrothelTotal > 0) && (BL + toTheBrothelTotal < 10)) { + s.sexAmount = Math.trunc(s.sexAmount * ((10 - BL - toTheBrothelTotal) / 10)); + s.sexQuality = Math.trunc(s.sexQuality * 1.2); + } + } } return slaveJobValues; diff --git a/src/js/rulesAssistant.js b/src/js/rulesAssistant.js index a10b2367642d63a911edf29acb5fc964fa9ce593..4f4a1da41b2dd0cf2a7389476262dfa3873cdcb0 100644 --- a/src/js/rulesAssistant.js +++ b/src/js/rulesAssistant.js @@ -209,6 +209,7 @@ window.ruleAppliesP = function ruleAppliesP(cond, slave) { flag = cond.data.value.includes(slave[cond.data.attribute]); break; case "custom": // user provided JS function + //TODO: This should use a cached Function instead of 'eval'ing flag = eval(cond.data)(slave); break; } diff --git a/src/js/rulesAssistantOptions.js b/src/js/rulesAssistantOptions.js index 6c726bb3d8a7b5f4182ee28ac9ad003174ff43e8..3d839b8b7befee682b5af6350fc4247fc26d7033 100644 --- a/src/js/rulesAssistantOptions.js +++ b/src/js/rulesAssistantOptions.js @@ -10,7 +10,7 @@ window.rulesAssistantOptions = (function() { const noDefaultSetting = {value: "!NDS!", text: "no default setting"}; /** @type {App.RA.Rule} */ - let current_rule; + let current_rule, root; function rulesAssistantOptions(element) { V.nextButton = "Back to Main"; @@ -26,19 +26,19 @@ window.rulesAssistantOptions = (function() { current_rule = V.defaultRules[idx]; } } - const root = new Root(element); + root = new Root(element); } function returnP(e) { return e.keyCode === 13; } - function newRule(root) { + function newRule() { const rule = emptyDefaultRule(); V.defaultRules.push(rule); V.currentRule = rule.ID; - reload(root); + reload(); } - function removeRule(root) { + function removeRule() { const idx = V.defaultRules.findIndex(rule => rule.ID === current_rule.ID); V.defaultRules.splice(idx, 1); if (V.defaultRules.length > 0) { @@ -47,33 +47,33 @@ window.rulesAssistantOptions = (function() { } else { V.currentRule = null; } - reload(root); + reload(); } - function lowerPriority(root) { + function lowerPriority() { if (V.defaultRules.length === 1) { return; } // nothing to swap with const idx = V.defaultRules.findIndex(rule => rule.ID === current_rule.ID); if (idx === 0) { return; } // no lower rule arraySwap(V.defaultRules, idx, idx - 1); - reload(root); + reload(); } - function higherPriority(root) { + function higherPriority() { if (V.defaultRules.length === 1) { return; } // nothing to swap with const idx = V.defaultRules.findIndex(rule => rule.ID === current_rule.ID); if (idx === V.defaultRules.length - 1) { return; } // no higher rule arraySwap(V.defaultRules, idx, idx + 1); - reload(root); + reload(); } - function changeName(name, root) { + function changeName(name) { if (name === current_rule.name) { return; } current_rule.name = name; - reload(root); + reload(); } // reload the passage - function reload(root) { + function reload() { const elem = root.element; elem.innerHTML = ""; rulesAssistantOptions(elem); @@ -243,7 +243,7 @@ window.rulesAssistantOptions = (function() { } } - + let _blockCallback=Symbol("Block Callback"); // list of clickable elements // has a short explanation (the prefix) and a value display // value display can optionally be an editable text input field @@ -260,6 +260,7 @@ window.rulesAssistantOptions = (function() { */ constructor(prefix, data = [], allowNullValue = true, editor = false, capitalizeShortcuts = false, ...args) { super(prefix, editor, ...args); + this[_blockCallback] = false; this.selectedItem = null; /** @protected */ this._allowNullValue = allowNullValue; @@ -288,17 +289,42 @@ window.rulesAssistantOptions = (function() { inputEdited() { if (this.selectedItem) { this.selectedItem.deselect(); } + this.setValue(this.getTextData()); this.propagateChange(); } selectItem(item) { if (this.selectedItem) { this.selectedItem.deselect(); } - this.selectedItem = item; this.setValue(item.data); this.propagateChange(); } - + trySetValue(what) { + if(what == null && this._allowNullValue) { + this.setValue(what); + return; + } + const selected = this.children.filter(listItem => _.isEqual(listItem.data, what)); + if(selected != null && selected.length == 1) + { + this.selectItem(selected[0]); + } + else if(this._allowNullValue) { + this.setValue(null); + } + } setValue(what) { + if(what == null && !this._allowNullValue) { what = ""; } + this.realValue = what; + if(this[_blockCallback]) return; + try { + this[_blockCallback] = true; + this.setTextValue(what); + this.updateSelected(); + } finally { + this[_blockCallback] = false; + } + } + setTextValue(what) { const str = what === null ? "no default setting" : `${what}`; if (this.value) { if (this.value.tagName === "INPUT") { @@ -310,6 +336,9 @@ window.rulesAssistantOptions = (function() { } getData() { + return this.realValue; + } + getTextData() { return (this.value.tagName === "INPUT" ? this.parse(this.value.value) : this.selectedItem.data); } @@ -321,6 +350,26 @@ window.rulesAssistantOptions = (function() { this.onchange(this.getData()); } } + updateSelected() { + const dataValue = this.getData(); + let selected; + if(dataValue == null) { + selected = this.children.filter(listItem => listItem.data == null); + } + else { + selected = this.children.filter(listItem => _.isEqual(listItem.data, dataValue)); + } + if (selected.length > 1) throw Error(`Multiple shortcuts matched ${JSON.stringify(dataValue)}`); + if (selected.length == 1) { + const listItem = selected[0]; + listItem.select(false); + if(this.selectedItem != null + && !_.isEqual(this.selectedItem, listItem)) { + this.selectedItem.deselect(); + } + this.selectedItem = listItem; + } + } /** * @private @@ -360,11 +409,11 @@ window.rulesAssistantOptions = (function() { return elem; } - select() { + select(notify = true) { if (this.selected) { return false; } - this.parent.selectItem(this); - this.element.classList.add("selected"); this.selected = true; + this.element.classList.add("selected"); + if(notify) { this.parent.selectItem(this); } return true; } @@ -524,16 +573,16 @@ window.rulesAssistantOptions = (function() { return res; } - getData() { + getTextData() { return this.selectedValue; } - setValue(what) { + setTextValue(what) { this.selectedValue = what; if (this.values.has(what)) { - super.setValue(this.values.get(what)); + super.setTextValue(this.values.get(what)); } else { - super.setValue(what); + super.setTextValue(what); } } } @@ -546,7 +595,7 @@ window.rulesAssistantOptions = (function() { createEditor() { let res = document.createElement("input"); res.setAttribute("type", "text"); - res.classList.add("rajs-value"); // + res.classList.add("rajs-value"); // call the variable binding when the input field is no longer being edited, and when the enter key is pressed res.onblur = () => { this.inputEdited(); @@ -554,14 +603,21 @@ window.rulesAssistantOptions = (function() { res.onkeypress = (e) => { if (returnP(e)) { this.inputEdited(); } }; + $(res).click(()=>res.setAttribute("placeholder", "")); return res; } + setValue(what) { + super.setValue(what); + this.value.setAttribute("placeholder", what == null + ? `(${capFirstChar(noDefaultSetting.text)})` + : ''); + } - getData() { + getTextData() { return this.value.value; } - setValue(what) { + setTextValue(what) { this.value.value = what; } } @@ -677,7 +733,7 @@ window.rulesAssistantOptions = (function() { return what === "" ? null : parseInt(what); } - setValue(what) { + setTextValue(what) { if (typeof what === 'number') { // comes from a pre-set this.numEditor.value = what.toString(); } else if (what === null) { @@ -689,7 +745,7 @@ window.rulesAssistantOptions = (function() { } } - getData() { + getTextData() { const v = this.parse(this.numEditor.value); return v === null ? null : App.RA.makeTarget(this.opSelector.value, v); } @@ -757,7 +813,7 @@ window.rulesAssistantOptions = (function() { return res; } - getData() { + getTextData() { function parse(what) { return what === "" ? null : parseInt(what); } @@ -768,7 +824,7 @@ window.rulesAssistantOptions = (function() { App.RA.makeRange(vMin !== null ? vMin : this._min, vMax !== null ? vMax : this._max); } - setValue(what) { + setTextValue(what) { if (what === null) { this._minEditor.value = null; this._maxEditor.value = null; @@ -905,9 +961,8 @@ window.rulesAssistantOptions = (function() { // rule import field class NewRuleField extends Element { - constructor(root) { + constructor() { super(); - this.root = root; } render() { @@ -940,7 +995,7 @@ window.rulesAssistantOptions = (function() { } else { V.defaultRules.push(App.Entity.Utils.RARuleDatatypeCleanup(rule)); } - reload(this.root); + reload(); } catch (e) { alert(`Couldn't import that rule:\n${e.message}`); } @@ -975,41 +1030,40 @@ window.rulesAssistantOptions = (function() { // options displayed when there are no rules class NoRules extends Options { - constructor(root) { + constructor() { super(); - this.root = root; - const newrule = new OptionsItem("Add a new rule", () => { newRule(this.root); }); + const newrule = new OptionsItem("Add a new rule", () => { newRule(); }); this.appendChild(newrule); - const importrule = new OptionsItem("Import a rule", () => { this.root.appendChild(new NewRuleField(this.root)); }); + const importrule = new OptionsItem("Import a rule", () => { root.appendChild(new NewRuleField()); }); this.appendChild(importrule); } } // buttons for selecting the current rule class RuleSelector extends List { - constructor(root) { - super("Current rule", V.defaultRules.map(i => [i.name, i]), false); + constructor() { + super("Current rule", V.defaultRules.map(i => [(i.name + (!!RuleHasError(i) ? " <span class='yellow'>[!]</span>" : "")), i]), false); this.setValue(current_rule.name); this.onchange = function(rule) { V.currentRule = rule.ID; - reload(root); + reload(); }; } } // buttons for doing transformations on rules class RuleOptions extends Options { - constructor(root) { + constructor() { super(); - this.appendChild(new OptionsItem("New Rule", () => newRule(root))); - this.appendChild(new OptionsItem("Remove Rule", () => removeRule(root))); + this.appendChild(new OptionsItem("New Rule", newRule)); + this.appendChild(new OptionsItem("Remove Rule", removeRule)); this.appendChild(new OptionsItem("Apply rules", () => this.appendChild(new ApplicationLog()))); - this.appendChild(new OptionsItem("Lower Priority", () => lowerPriority(root))); - this.appendChild(new OptionsItem("Higher Priority", () => higherPriority(root))); - this.appendChild(new OptionsItem("Rename", () => this.appendChild(new RenameField(root)))); + this.appendChild(new OptionsItem("Lower Priority", lowerPriority)); + this.appendChild(new OptionsItem("Higher Priority", higherPriority)); + this.appendChild(new OptionsItem("Rename", () => this.appendChild(new RenameField()))); this.appendChild(new OptionsItem("Export this rule", () => this.appendChild(new ExportField(current_rule)))); this.appendChild(new OptionsItem("Export all rules", () => this.appendChild(new ExportField(...V.defaultRules)))); - this.appendChild(new OptionsItem("Import rule(s)", () => this.appendChild(new NewRuleField(root)))); + this.appendChild(new OptionsItem("Import rule(s)", () => this.appendChild(new NewRuleField()))); } } @@ -1024,10 +1078,10 @@ window.rulesAssistantOptions = (function() { } class RenameField extends Element { - constructor(root) { + constructor() { super(); - this.element.onblur = () => changeName(this.element.value, root); - this.element.onkeypress = (e) => { if (returnP(e)) { changeName(this.element.value, root); } }; + this.element.onblur = () => changeName(this.element.value); + this.element.onkeypress = (e) => { if (returnP(e)) { changeName(this.element.value); } }; } render() { @@ -1092,7 +1146,7 @@ window.rulesAssistantOptions = (function() { ["Amputation", "amp"], ]; this.fnlist = new List("Activation function", items); - this.fnlist.setValue(current_rule.condition.function === "between" ? current_rule.condition.data.attribute : current_rule.condition.function); + this.fnlist.setValue(["between", "belongs"].includes(current_rule.condition.function) ? current_rule.condition.data.attribute : current_rule.condition.function); this.fnlist.onchange = (value) => this.fnchanged(value); this.appendChild(this.fnlist); this.fneditor = null; @@ -1197,8 +1251,21 @@ window.rulesAssistantOptions = (function() { const elem = document.createElement("div"); const textarea = document.createElement("textarea"); textarea.innerHTML = data; - textarea.onblur = () => current_rule.condition.data = textarea.value; + $(textarea).blur(() => { + current_rule.condition.data = textarea.value; + //TODO: this would be a good place to cache the Function object that will be used by RuleHasError and ruleAppliesP + reload(); + }); elem.appendChild(textarea); + + if(RuleHasError(current_rule)) + { + const errorMessage = document.createElement("div"); + $(errorMessage).addClass("yellow"); + errorMessage.innerText = "WARNING: There are errors in this condition. Please ensure the syntax is correct and equality is either '==' or '===', not '='"; + elem.appendChild(errorMessage); + } + const explanation = document.createElement("div"); explanation.innerHTML = "Insert a valid <a target='_blank' class='link-external' href='https://www.w3schools.com/js/js_comparisons.asp'>JavaScript comparison and/or logical operation</a>."; elem.appendChild(explanation); @@ -1553,7 +1620,7 @@ window.rulesAssistantOptions = (function() { class ClearLabelSwitch extends BooleanSwitch { constructor() { - super("Remove all tags (Gobal swith)", [false, true]); + super("Remove all tags (Global switch)", [false, true]); this.setValue(current_rule.set.labelTagsClear); this.onchange = (value) => current_rule.set.labelTagsClear = value; } @@ -2576,6 +2643,18 @@ window.rulesAssistantOptions = (function() { } } + const dietAddedText = function(value) { + switch(value) { + case 0: + return "None"; + case 1: + return "Added"; + case 2: + return "Based"; + default: + return value; + } + } class DietBaseList extends List { constructor() { // TODO: better data structure? @@ -2589,16 +2668,20 @@ window.rulesAssistantOptions = (function() { ["Milk-Based", {cum: 0, milk: 2}], ]; super("Diet base", pairs, false); - this.setValue(this.value2string(current_rule.set.dietCum, current_rule.set.dietMilk)); + this.setValue({cum: current_rule.set.dietCum, milk: current_rule.set.dietMilk }); this.onchange = (value) => { current_rule.set.dietCum = value.cum; current_rule.set.dietMilk = value.milk; - this.setValue(this.value2string(current_rule.set.dietCum, current_rule.set.dietMilk)); + this.setValue(value); }; } - - value2string(cum, milk) { - return `cum: ${cum}, milk: ${milk}`; + setTextValue(what) { + if(what.cum == null && what.milk == null) { + super.setTextValue(capFirstChar(noDefaultSetting.text)); + } + else { + super.setTextValue(`Cum: ${dietAddedText(what.cum)}, Milk: ${dietAddedText(what.milk)}`); + } } } @@ -2881,7 +2964,17 @@ window.rulesAssistantOptions = (function() { this.colorlist.setValue(val); this.shapelist.setValue(val); } else { - // + let list = val.split(' '); + if(list.length == 2) + { + this.colorlist.setValue(list[0]); + this.shapelist.setValue(list[1]); + } + else if(list.length == 1) + { + this.colorlist.trySetValue(list[0]); + this.shapelist.trySetValue(list[0]); + } } } super.setValue(val); diff --git a/src/js/slaveSummaryWidgets.js b/src/js/slaveSummaryWidgets.js index 6d9ef784f0c2ff841004cf89aabf2ad5413a169c..b576a0afb403df94032c5838ff77154631197311 100644 --- a/src/js/slaveSummaryWidgets.js +++ b/src/js/slaveSummaryWidgets.js @@ -3348,7 +3348,7 @@ window.SlaveSummaryUncached = (function() { } else if (slave.attrXX <= 35) { makeSpan(c, "not attracted to women", "red", true, slave.attrXX); } else if (slave.attrXX <= 65) { - makeSpan(c, "Disgusted by women", undefined, true, slave.attrXX); + makeSpan(c, "indifferent to women", undefined, true, slave.attrXX); } else if (slave.attrXX <= 85) { makeSpan(c, "attracted to women", "green", true, slave.attrXX); } else if (slave.attrXX <= 95) { diff --git a/src/js/storyJS.js b/src/js/storyJS.js index 32e041e252231fdcdae3a8fb8b84bbc7138c26b6..b9ee7848a2e7fe82b9ba05a42898ac0262412fc6 100644 --- a/src/js/storyJS.js +++ b/src/js/storyJS.js @@ -446,7 +446,7 @@ window.overpowerCheck = function(slave, PC) { strength += (185-slave.height); strength -= (PC.belly/1000); strength += (PC.skill.warfare/3); - strength -= (State.variables.PCWounded * 15); + strength -= (State.variables.PC.majorInjury * 15); return strength; }; diff --git a/src/pregmod/personalNotes.tw b/src/pregmod/personalNotes.tw index 9a272763877f56f023613f726491adc8623ac13b..07f94e3b6d481e1cbec8c4b9027a61582c469fc6 100644 --- a/src/pregmod/personalNotes.tw +++ b/src/pregmod/personalNotes.tw @@ -176,7 +176,7 @@ Your already huge breasts have @@.lime;grown even heavier@@ with your pregnancy. <<set $PC.boobs += 25>> <<if $PC.boobs >= 1400>> - Your desk is steadily starting to dissapear; @@.lime;H-cups will do that.@@ + Your desk is steadily starting to disappear; @@.lime;H-cups will do that.@@ <</if>> <</if>> <<elseif $PC.boobs >= 1000>> @@ -254,4 +254,4 @@ */ <</if>> <</if>> -<</if>> \ No newline at end of file +<</if>> diff --git a/src/pregmod/theBlackMarket.tw b/src/pregmod/theBlackMarket.tw index 8f2424f80e46b76e812776dbc8a9f80e141418c9..154e06b2d1f5b890115bb5077194b120714b4ab6 100644 --- a/src/pregmod/theBlackMarket.tw +++ b/src/pregmod/theBlackMarket.tw @@ -404,12 +404,12 @@ He gestures to a door in the back of the stall. "The good shit's back there<<if <<else>> You cannot afford the asking price of @@.red;<<print cashFormat(25000)>>@@ for animal anal wombs and ovaries. <</if>> - /* TODO: flesh this out some more */ + / TODO: flesh this out some more / "Got something real special this week. These are schematics for implanting non-human organs into humans. My supplier told me they came from some military experiments or something — maybe they were trying to make some kind of super soldier. Not my business, though." <<else>> You lack the facilities required to grow organs. <</if>> - <<else>> /* if all schematics have already been purchased */ + <<else>> / if all schematics have already been purchased / You already possess all of the schematics for implanting animal organs. <<run $merchantIllegalWares.delete("AnimalOrgans")>> <</if>> diff --git a/src/uncategorized/arcmgmt.tw b/src/uncategorized/arcmgmt.tw index 9882b86c4cd962a6503b0154767405edb201c911..edebd87d70bf2b8138bd307e5631bb87750b5128 100644 --- a/src/uncategorized/arcmgmt.tw +++ b/src/uncategorized/arcmgmt.tw @@ -18,14 +18,14 @@ You are providing your citizens with an adequate amount of slaves to be used as sexual objects, as is expected in your degradationist society.<br> <</if>> <</if>> -<<if $sexDemandResult.lowerClass < 400>> +<<if $sexDemandResult.lowerClass < 350>> Your lower class citizens have @@.red;far too few options for sexual relief@@ inside your arcology. <<if $classSatisfied.lowerClass == 0>> They trust you will take care of this issue as soon as you are settled in.<br> <<else>> It is @@.red;causing dissatisfaction@@ among your lower class.<br> <</if>> -<<elseif $sexDemandResult.lowerClass < 600>> +<<elseif $sexDemandResult.lowerClass < 550>> Your lower class citizens need @@.red;some more avenues for sexual relief@@ inside your arcology. <<if $classSatisfied.lowerClass == 1>> They see @@.green;you are on the right track@@ and anticipate further improvements.<br> @@ -34,16 +34,16 @@ <<else>> It is @@.red;causing dissatisfaction@@ among your lower class.<br> <</if>> -<<elseif $sexDemandResult.lowerClass < 800>> +<<elseif $sexDemandResult.lowerClass < 750>> Your lower class citizens have no issue finding the sexual relief they need inside your arcology. <<if $classSatisfied.lowerClass == 1>> They are @@.green;delighted@@ with how quickly you've provided for them.<br> <<else>> <br> <</if>> -<<elseif $sexDemandResult.lowerClass < 1000>> +<<elseif $sexDemandResult.lowerClass < 950>> Your lower class citizens are @@.green;happy with the availability of sexual services@@ inside your arcology.<br> -<<elseif $sexDemandResult.lowerClass == 1000>> +<<elseif $sexDemandResult.lowerClass >= 950>> Your lower class citizens are @@.green;delighted with the abundance of sexual services@@ inside your arcology.<br> <</if>> Lower class satisfaction is at <<print $sexDemandResult.lowerClass/10>>%, <<print $NPCMarketShare.lowerClass/10>>% of the market is serviced by other suppliers operating inside your arcology.<br> @@ -61,14 +61,14 @@ Lower class satisfaction is at <<print $sexDemandResult.lowerClass/10>>%, <<prin <<run cashX($NPCSlaves.lowerClass * Math.pow($sexSubsidies.lowerClass, 2) * 0.25, "policies")>> <</if>> -<<if $sexDemandResult.middleClass < 400>> +<<if $sexDemandResult.middleClass < 350>> Your middle class citizens have @@.red;far too few options for sexual relief@@ inside your arcology. <<if $classSatisfied.middleClass == 0>> They trust you will take care of this issue as soon as you are settled in.<br> <<else>> It is @@.red;causing dissatisfaction@@ among your middle class.<br> <</if>> -<<elseif $sexDemandResult.middleClass < 600>> +<<elseif $sexDemandResult.middleClass < 550>> Your middle class citizens need @@.red;some more avenues for sexual relief@@ inside your arcology. <<if $classSatisfied.middleClass == 1>> They see @@.green;you are on the right track@@ and anticipate further improvements.<br> @@ -77,16 +77,16 @@ Lower class satisfaction is at <<print $sexDemandResult.lowerClass/10>>%, <<prin <<else>> It is @@.red;causing dissatisfaction@@ among your middle class.<br> <</if>> -<<elseif $sexDemandResult.middleClass < 800>> +<<elseif $sexDemandResult.middleClass < 750>> Your middle class citizens have no issue finding the sexual relief they need inside your arcology. <<if $classSatisfied.middleClass == 1>> They are @@.green;delighted@@ with how quickly you've provided for them.<br> <<else>> <br> <</if>> -<<elseif $sexDemandResult.middleClass < 1000>> +<<elseif $sexDemandResult.middleClass < 950>> Your middle class citizens are @@.green;happy with the availability of sexual services@@ inside your arcology.<br> -<<elseif $sexDemandResult.middleClass == 1000>> +<<elseif $sexDemandResult.middleClass >= 950>> Your middle class citizens are @@.green;delighted with the abundance of sexual services@@ inside your arcology.<br> <</if>> Middle class satisfaction is at <<print $sexDemandResult.middleClass/10>>%, <<print $NPCMarketShare.middleClass/10>>% of the market is serviced by other suppliers operating inside your arcology.<br> @@ -104,14 +104,14 @@ Middle class satisfaction is at <<print $sexDemandResult.middleClass/10>>%, <<pr <<run cashX($NPCSlaves.middleClass * Math.pow($sexSubsidies.middleClass, 2) * 0.25, "policies")>> <</if>> -<<if $sexDemandResult.upperClass < 400>> +<<if $sexDemandResult.upperClass < 350>> Your upper class citizens have @@.red;far too few options for sexual relief@@ inside your arcology. <<if $classSatisfied.upperClass == 0>> They trust you will take care of this issue as soon as you are settled in.<br> <<else>> It is @@.red;causing dissatisfaction@@ among your upper class.<br> <</if>> -<<elseif $sexDemandResult.upperClass < 600>> +<<elseif $sexDemandResult.upperClass < 550>> Your upper class citizens need @@.red;some more avenues for sexual relief@@ inside your arcology. <<if $classSatisfied.upperClass == 1>> They see @@.green;you are on the right track@@ and anticipate further improvements.<br> @@ -120,16 +120,16 @@ Middle class satisfaction is at <<print $sexDemandResult.middleClass/10>>%, <<pr <<else>> It is @@.red;causing dissatisfaction@@ among your upper class.<br> <</if>> -<<elseif $sexDemandResult.upperClass < 800>> +<<elseif $sexDemandResult.upperClass < 750>> Your upper class citizens have no issue finding the sexual relief they need inside your arcology. <<if $classSatisfied.upperClass == 1>> They are @@.green;delighted@@ with how quickly you've provided for them.<br> <<else>> <br> <</if>> -<<elseif $sexDemandResult.upperClass < 1000>> +<<elseif $sexDemandResult.upperClass < 950>> Your upper class citizens are @@.green;happy with the availability of sexual services@@ inside your arcology.<br> -<<elseif $sexDemandResult.upperClass == 1000>> +<<elseif $sexDemandResult.upperClass >= 950>> Your upper class citizens are @@.green;delighted with the abundance of sexual services@@ inside your arcology.<br> <</if>> Upper class satisfaction is at <<print $sexDemandResult.upperClass/10>>%, <<print $NPCMarketShare.upperClass/10>>% of the market is serviced by other suppliers operating inside your arcology.<br> @@ -147,14 +147,14 @@ Upper class satisfaction is at <<print $sexDemandResult.upperClass/10>>%, <<prin <<run cashX($NPCSlaves.upperClass * Math.pow($sexSubsidies.upperClass, 2) * 0.25, "policies")>> <</if>> -<<if $sexDemandResult.topClass < 400>> +<<if $sexDemandResult.topClass < 350>> Your arcology's millionaires have @@.red;far too few options for sexual relief@@ inside your arcology. <<if $classSatisfied.topClass == 0>> They trust you will take care of this issue as soon as you are settled in.<br> <<else>> It is @@.red;causing dissatisfaction@@ among your millionaires.<br> <</if>> -<<elseif $sexDemandResult.topClass < 600>> +<<elseif $sexDemandResult.topClass < 550>> Your arcology's millionaires need @@.red;some more avenues for sexual relief@@ inside your arcology. <<if $classSatisfied.topClass == 1>> They see @@.green;you are on the right track@@ and anticipate further improvements.<br> @@ -163,16 +163,16 @@ Upper class satisfaction is at <<print $sexDemandResult.upperClass/10>>%, <<prin <<else>> It is @@.red;causing dissatisfaction@@ among your millionaires.<br> <</if>> -<<elseif $sexDemandResult.topClass < 800>> +<<elseif $sexDemandResult.topClass < 750>> Your arcology's millionaires have no issue finding the sexual relief they need inside your arcology. <<if $classSatisfied.topClass == 1>> They are @@.green;delighted@@ with how quickly you've provided for them.<br> <<else>> <br> <</if>> -<<elseif $sexDemandResult.topClass < 1000>> +<<elseif $sexDemandResult.topClass < 950>> Your arcology's millionaires are @@.green;happy with the availability of sexual services@@ inside your arcology.<br> -<<elseif $sexDemandResult.topClass == 1000>> +<<elseif $sexDemandResult.topClass >= 950>> Your arcology's millionaires are @@.green;delighted with the abundance of sexual services@@ inside your arcology.<br> <</if>> Millionaire satisfaction is at <<print $sexDemandResult.topClass/10>>%, <<print $NPCMarketShare.topClass/10>>% of the market is serviced by other suppliers operating inside your arcology.<br> diff --git a/src/uncategorized/main.tw b/src/uncategorized/main.tw index aab6e91ab2fde5f34fbbf4a921ae2c1059c7fbf1..481b4988cf4f00abe3718a7da18905884c1efeab 100644 --- a/src/uncategorized/main.tw +++ b/src/uncategorized/main.tw @@ -96,17 +96,6 @@ <</if>> <<if ($seeDesk == 1) && ($seeFCNN == 0)>><br><</if>> -/* Check if custom rules have an assignation operator */ -<<set _RL = $defaultRules.length>> -<<set _regex = /[^!=<>]=[^=<>]/gi>> -<<set $rulesError = false>> -<<for _itr = 0; _itr < _RL; _itr++>> - <<if $defaultRules[_itr].condition.function == "custom" && $defaultRules[_itr].condition.data.match(_regex)>> - <<set $rulesError = true>> - <<break>> - <</if>> -<</for>> - __''MAIN MENU''__ //[[Summary Options]]// <<if $rulesAssistantMain != 0>> | //<span id="RAButton"><<link "Rules Assistant Options" "Rules Assistant">><</link>></span>// @@.cyan;[R]@@ @@ -115,7 +104,7 @@ __''MAIN MENU''__ //[[Summary Options]]// <<else>> | //<<link "Stop applying Rules Assistant at week end" "Main">><<set $rulesAssistantAuto = 0>><</link>>// <</if>> - | //<<if $rulesError>>@@.yellow; WARNING: some custom rules will change slave variables @@<</if>><<link "Re-apply Rules Assistant now (this will only check slaves in the Penthouse)" "Main">><<for _i = 0;_i < _SL;_i++>><<if $slaves[_i].assignmentVisible == 1 && $slaves[_i].useRulesAssistant == 1>><<= DefaultRules($slaves[_i])>><</if>><</for>><</link>>// + | //<<if DefaultRulesError()>>@@.yellow; WARNING: One or more rules' custom conditions has errors! @@<</if>><<link "Re-apply Rules Assistant now (this will only check slaves in the Penthouse)" "Main">><<for _i = 0;_i < _SL;_i++>><<if $slaves[_i].assignmentVisible == 1 && $slaves[_i].useRulesAssistant == 1>><<= DefaultRules($slaves[_i])>><</if>><</for>><</link>>// <</if>> <<print App.UI.SlaveList.penthousePage()>> @@ -203,4 +192,4 @@ __''MAIN MENU''__ //[[Summary Options]]// <</if>> <<if ($debugMode == 1)>> //| [[Show all walk past scenes|Walk Past List]]// -<</if>> \ No newline at end of file +<</if>> diff --git a/src/uncategorized/slaveAssignmentsReport.tw b/src/uncategorized/slaveAssignmentsReport.tw index b8ec2375276066a5439e1146aec0d51a0756593a..999c467f35541a292512b9d302e296abfa41cb56 100644 --- a/src/uncategorized/slaveAssignmentsReport.tw +++ b/src/uncategorized/slaveAssignmentsReport.tw @@ -106,28 +106,28 @@ _middleClassClubRatio = (_middleClassSexDemand + _visitorsSexDemand) / _clubDema /*Brothel or street whore sex supply*/ <<if _lowerClassSexDemand < $slaveJobValues.brothel.lowerClass>> - <<set $whorePriceAdjustment.lowerClass = Math.pow(_lowerClassSexDemand / ($slaveJobValues.brothel.lowerClass + $NPCSexSupply.lowerClass), 2), + <<set $whorePriceAdjustment.lowerClass = Math.max(Math.pow(_lowerClassSexDemand / ($slaveJobValues.brothel.lowerClass + $NPCSexSupply.lowerClass), 2), 0.25), _lowerClassSexDemand = 0>> /*This accounts for people having too much choice and getting more picky how they spend their money*/ <<else>> <<set $whorePriceAdjustment.lowerClass = Math.pow(_lowerClassSexDemand / ($slaveJobValues.brothel.lowerClass + $NPCSexSupply.lowerClass), 0.25), _lowerClassSexDemand -= $slaveJobValues.brothel.lowerClass>> /* People are willing to pay more for a scarce good, but within reason */ <</if>> <<if _middleClassSexDemand < $slaveJobValues.brothel.middleClass>> - <<set $whorePriceAdjustment.middleClass = Math.pow(_middleClassSexDemand / ($slaveJobValues.brothel.middleClass + $NPCSexSupply.middleClass), 2), + <<set $whorePriceAdjustment.middleClass = Math.max(Math.pow(_middleClassSexDemand / ($slaveJobValues.brothel.middleClass + $NPCSexSupply.middleClass), 2), 0.25), _middleClassSexDemand = 0>> <<else>> <<set $whorePriceAdjustment.middleClass = Math.pow(_middleClassSexDemand / ($slaveJobValues.brothel.middleClass + $NPCSexSupply.middleClass), 0.25), _middleClassSexDemand -= $slaveJobValues.brothel.middleClass>> <</if>> <<if _upperClassSexDemand < $slaveJobValues.brothel.upperClass>> - <<set $whorePriceAdjustment.upperClass = Math.pow(_upperClassSexDemand / ($slaveJobValues.brothel.upperClass + $NPCSexSupply.upperClass), 2), + <<set $whorePriceAdjustment.upperClass = Math.max(Math.pow(_upperClassSexDemand / ($slaveJobValues.brothel.upperClass + $NPCSexSupply.upperClass), 2), 0.25), _upperClassSexDemand = 0>> <<else>> <<set $whorePriceAdjustment.upperClass = Math.pow(_upperClassSexDemand / ($slaveJobValues.brothel.upperClass + $NPCSexSupply.upperClass), 0.25), _upperClassSexDemand -= $slaveJobValues.brothel.upperClass>> <</if>> <<if _topClassSexDemand < $slaveJobValues.brothel.topClass>> - <<set $whorePriceAdjustment.topClass = Math.pow(_topClassSexDemand / ($slaveJobValues.brothel.topClass + $NPCSexSupply.topClass), 2), + <<set $whorePriceAdjustment.topClass = Math.max(Math.pow(_topClassSexDemand / ($slaveJobValues.brothel.topClass + $NPCSexSupply.topClass), 2), 0.25), _topClassSexDemand = 0>> <<else>> <<set $whorePriceAdjustment.topClass = Math.pow(_topClassSexDemand / ($slaveJobValues.brothel.topClass + $NPCSexSupply.topClass), 0.25), diff --git a/src/uncategorized/storyCaption.tw b/src/uncategorized/storyCaption.tw index 1cf0d746140aab6c0fbfcac2562d74765d73c616..2b58dccd294e4df2728f0471ea874f7b7a0438b0 100644 --- a/src/uncategorized/storyCaption.tw +++ b/src/uncategorized/storyCaption.tw @@ -9,8 +9,8 @@ <strong> <span id="endWeekButton"> <br><br> <<link "$nextButton">> <<goto $nextLink>> <</link>> @@.cyan;[Ent]@@ </span> </strong> - <<if $rulesError && $rulesAssistantAuto == 1>> - <br>@@.yellow;WARNING: some custom rules will change slave variables@@ + <<if $rulesAssistantAuto == 1 && DefaultRulesError()>> + <br>@@.yellow;WARNING: Rules Assistant has rules with errors!@@ <</if>> <<else>> <strong> <span id="nextButton"> <<if $nextButton != " ">> <br><br>