6 Commits

Author SHA1 Message Date
8e0d374b90 hopefully caseless match for targets, bc updated to 121 2025-10-18 11:27:24 +00:00
d8a4d250d7 110.13.0
* changed assert to only check for undefined by default
* fixes a bug with 0 time offset
* updated the club to R110
2024-12-04 00:50:36 +00:00
07c1fad5f3 Merge remote-tracking branch 'origin/testing'
108.13.1 mainly history fixes and improvements
2024-09-19 14:24:36 +00:00
c3d47fec77 Merge branch 'testing' 2024-08-26 14:52:29 +00:00
fe4248eb8b hotfix: R107 makes the check redundant (it was never a great idea tbh) 2024-08-18 18:32:09 +00:00
d87bfde6f9 Update README.md 2024-06-29 17:18:15 +00:00
3 changed files with 1787 additions and 868 deletions

View File

@@ -1,5 +1,5 @@
// Take a look at the .d.ts for comments. // Take a look at the .d.ts for comments.
export const version = '108.13.1' export const version = '121.13.1'
const W = window, D = W.document, /**fuck money*/$ = undefined, /**@type {''}*/$S = '', /**@type {{}}*/$O = {}, /**@type {Set<string>}*/$Ss = new Set() // /**@type {readonly []}*/$A = [], const W = window, D = W.document, /**fuck money*/$ = undefined, /**@type {''}*/$S = '', /**@type {{}}*/$O = {}, /**@type {Set<string>}*/$Ss = new Set() // /**@type {readonly []}*/$A = [],
const/**@type {TextDictionaryEntry}*/MISSING_PLAYER_DIALOG = {Tag: 'MISSING TEXT IN "Interface.csv": ', Text: '\u200C'} // Zero-width non-joiner, used to break up ligatures, does nothing here, but an empty string is a falsey value const/**@type {TextDictionaryEntry}*/MISSING_PLAYER_DIALOG = {Tag: 'MISSING TEXT IN "Interface.csv": ', Text: '\u200C'} // Zero-width non-joiner, used to break up ligatures, does nothing here, but an empty string is a falsey value
@@ -19,7 +19,7 @@ const/**@type {FP.run}*/run = (fs, ...args) => {fs.forEach(f => fun(f) && void f
const/**@type {FP.yes}*/yes = (...args) => run(args, $) const/**@type {FP.yes}*/yes = (...args) => run(args, $)
const/**@type {FP.mut}*/mut = (v, ...args) => run(args, v) && v const/**@type {FP.mut}*/mut = (v, ...args) => run(args, v) && v
const/**@type {FP.del}*/del = (o, p) => mut(o, Reflect.deleteProperty(o, p)) const/**@type {FP.del}*/del = (o, p) => mut(o, Reflect.deleteProperty(o, p))
const/**@type {FP.ass}*/ass = (x, v, c = Boolean) => {if (v === $ || !c(v)) throw new Error(x); return v} const/**@type {FP.ass}*/ass = (x, v, c) => {if (v === $ || !(c?.(v) ?? true)) throw new Error(x); return v}
const/**@type {FP.asa}*/asa = (p, v) => v instanceof p ? v : $ const/**@type {FP.asa}*/asa = (p, v) => v instanceof p ? v : $
const/**@type {FP.rsc}*/rsc = (f, r) => {try {f($)} catch (x) {r(x)} return true} const/**@type {FP.rsc}*/rsc = (f, r) => {try {f($)} catch (x) {r(x)} return true}
const/**@type {FP.Interval}*/range = new (class { proxy = new Proxy($O, this); min = 0; max = 0; mini = false; maxi = false const/**@type {FP.Interval}*/range = new (class { proxy = new Proxy($O, this); min = 0; max = 0; mini = false; maxi = false
@@ -93,7 +93,7 @@ const/**@type {Utils}*/U = { remove_loader_hook: $, RGB: {Polly: '#81b1e7', Mute
cur(ass(`failed to parse target "${t}"`, U.RE.REL.L.test(t) ? sub : U.RE.REL.R.test(t) ? add : $)(me, t.length), pos => cur(ass(`failed to parse target "${t}"`, U.RE.REL.L.test(t) ? sub : U.RE.REL.R.test(t) ? add : $)(me, t.length), pos =>
cur(pos % U.crc.length, p => U.abs2char(p < 0 ? p + U.crc.length : p)))), cur(pos % U.crc.length, p => U.abs2char(p < 0 ? p + U.crc.length : p)))),
cid2char: id => id === U.cid(W.Player) ? W.Player : ass(`character ${id} not found in the room`, U.crc.find(c => id === U.cid(c))), cid2char: id => id === U.cid(W.Player) ? W.Player : ass(`character ${id} not found in the room`, U.crc.find(c => id === U.cid(c))),
target2char(target) { let t = target.trim(); const /**@type {Set<Character>}*/f = new Set() // FIXME Target should be low case (take a look at this later) target2char(target) { let t = target.toLocaleLowerCase().trim(); const /**@type {Set<Character>}*/f = new Set() // FIXME there may be some fuckery going on with character cases
if (m_t(t)) return W.Player if (m_t(t)) return W.Player
if (t.at(0) === '=') return U.cid2char(ass(`invalid member number "${target}"`, int(t.slice(1)))) if (t.at(0) === '=') return U.cid2char(ass(`invalid member number "${target}"`, int(t.slice(1))))
if ('<>'.includes(t.at(0) ?? '-')) return U.rel2char(t) if ('<>'.includes(t.at(0) ?? '-')) return U.rel2char(t)
@@ -214,7 +214,7 @@ const/**@type {InputHistory}*/H = { input: undefined, ids: undefined, bottom: un
exit: (ic, e) => yes(H.icro(ic, false), H.key[e.key]?.(e, ic), val(H.bottom, b => b && U.scroll()), W.ChatRoomLastMessageIndex = W.ChatRoomLastMessage.length) exit: (ic, e) => yes(H.icro(ic, false), H.key[e.key]?.(e, ic), val(H.bottom, b => b && U.scroll()), W.ChatRoomLastMessageIndex = W.ChatRoomLastMessage.length)
} }
ass('MBCHC found, aborting loading', W.MBCHC === $) ass('MBCHC found, aborting loading', W.MBCHC === $, Boolean)
ass('AsylumGGTSSAddItems() not found, aborting MBCHC loading', W.AsylumGGTSSAddItems) ass('AsylumGGTSSAddItems() not found, aborting MBCHC loading', W.AsylumGGTSSAddItems)
const sdk = ass('SDK not found, please load with (or after) FUSAM or any other mod that uses SDK', W.bcModSdk) const sdk = ass('SDK not found, please load with (or after) FUSAM or any other mod that uses SDK', W.bcModSdk)
const mod = sdk.registerMod({name: 'MBCHC', fullName: 'Mute\'s Bondage Club Hacks Collection', version, repository: 'https://code.fleshless.org/mute/MBCHC/'}) const mod = sdk.registerMod({name: 'MBCHC', fullName: 'Mute\'s Bondage Club Hacks Collection', version, repository: 'https://code.fleshless.org/mute/MBCHC/'})
@@ -364,20 +364,20 @@ const/**@type {SDK.Hook}*/after = (name, f) => mod.hookFunction(name, 0, (na, n)
}, },
donate_data(/**@type {string}*/target) { donate_data(/**@type {string}*/target) {
const char = U.target2char(target) const char = U.target2char(target)
ass('target must not be you', !char.IsPlayer()) ass('target must not be you', !char.IsPlayer(), Boolean)
ass('target must be bound', char.IsRestrained()) ass('target must be bound', char.IsRestrained(), Boolean)
const cost = Math.round(((Math.random() * 10) + 15)) const cost = Math.round(((Math.random() * 10) + 15))
ass('not enough money', W.Player.Money >= cost) ass('not enough money', W.Player.Money >= cost, Boolean)
W.CharacterChangeMoney(W.Player, -cost) W.CharacterChangeMoney(W.Player, -cost)
W.ServerSend('ChatRoomChat', {Content: 'ReceiveSuitcaseMoney', Type: 'Hidden', Target: U.cid(char)}) W.ServerSend('ChatRoomChat', {Content: 'ReceiveSuitcaseMoney', Type: 'Hidden', Target: U.cid(char)})
W.ChatRoomMessage({Sender: ass('...', U.cid(W.Player)), Type: 'Action', Content: `You've bought data for $${cost} and sent it to ${U.dn(char)}.`, Dictionary: [MISSING_PLAYER_DIALOG]}) W.ChatRoomMessage({Sender: ass('...', U.cid(W.Player)), Type: 'Action', Content: `You've bought data for $${cost} and sent it to ${U.dn(char)}.`, Dictionary: [MISSING_PLAYER_DIALOG]})
}, },
run_activity(/**@type {Character}*/char, /**@type {AssetGroupItemName}*/ag, /**@type {ActivityName}*/action) { run_activity(/**@type {Character}*/char, /**@type {AssetGroupItemName}*/ag, /**@type {ActivityName}*/action) {
try { try {
ass('activities disabled in this room', W.ActivityAllowed()) ass('activities disabled in this room', W.ActivityAllowed(), Boolean)
ass('no permissions', W.ServerChatRoomGetAllowItem(W.Player, char)) ass('no permissions', W.ServerChatRoomGetAllowItem(W.Player, char), Boolean)
char.FocusGroup = ass('invalid AssetGroup', n2u(W.AssetGroupGet(char.AssetFamily, ag))) char.FocusGroup = ass('invalid AssetGroup', n2u(W.AssetGroupGet(char.AssetFamily, ag)))
const activity = ass('invalid activity', W.ActivityAllowedForGroup(char, char.FocusGroup.Name).find(a => a.Activity?.Name === action)) const activity = ass('invalid activity', W.ActivityAllowedForGroup(char, char.FocusGroup.Name).find(a => a.Activity?.Name === action), Boolean)
//if ((activity.Name || activity.Activity.Name).endsWith('Item')) { //if ((activity.Name || activity.Activity.Name).endsWith('Item')) {
// const item = this.ensure('no toy found', () => w.Player.Inventory.find(i => i.Asset?.Name === 'SpankingToys' && i.Asset.Group?.Name === char.FocusGroup.Name && w.AssetSpankingToys.DynamicActivity(char) === (activity.Name || activity.Activity.Name))) // const item = this.ensure('no toy found', () => w.Player.Inventory.find(i => i.Asset?.Name === 'SpankingToys' && i.Asset.Group?.Name === char.FocusGroup.Name && w.AssetSpankingToys.DynamicActivity(char) === (activity.Name || activity.Activity.Name)))
// w.DialogPublishAction(char, item) // w.DialogPublishAction(char, item)
@@ -397,7 +397,7 @@ const/**@type {SDK.Hook}*/after = (name, f) => mod.hookFunction(name, 0, (na, n)
}, },
set_timezone(/**@type {string[]}*/args) { set_timezone(/**@type {string[]}*/args) {
const tz = ass(`invalid offset "${args[0]}"`, int(args[0] ?? $S)) const tz = ass(`invalid offset "${args[0]}"`, int(args[0] ?? $S))
ass('offset should be [-12,12]', tz in rng(-12, 12)) ass('offset should be in [-12,12]', tz in rng(-12, 12), Boolean)
const char = U.target2char(args[1] ?? $S) const char = U.target2char(args[1] ?? $S)
return val(U.cid(char), cid => Settings.save(v1 => v1.TZ[cid] = tz) && TZ.memo(cid)) return val(U.cid(char), cid => Settings.save(v1 => v1.TZ[cid] = tz) && TZ.memo(cid))
}, },

2629
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,12 +1,12 @@
{ {
"name": "mbchc", "name": "mbchc",
"version": "108.13.1", "version": "121.13.1",
"description": "Mute's Bondage Club Hacks Collection", "description": "Mute's Bondage Club Hacks Collection",
"author": "Mute", "author": "Mute",
"private": true, "private": true,
"type": "module", "type": "module",
"devDependencies": { "devDependencies": {
"bc-stubs": "^108.0.0", "bc-stubs": "^121.0.0",
"bondage-club-mod-sdk": "^1.2.0", "bondage-club-mod-sdk": "^1.2.0",
"typescript": "^5.5.2", "typescript": "^5.5.2",
"xo": "^0.56.0" "xo": "^0.56.0"