Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .oxlintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
"radix": "off",
"sort-imports": "off",
"sort-keys": "off",
"one-var": "off",
"yoda": ["warn", "never"],
"import/consistent-type-specifier-style": "off",
"import/exports-last": "off",
Expand Down
470 changes: 235 additions & 235 deletions package-lock.json

Large diffs are not rendered by default.

10 changes: 5 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,16 @@
"@zendrex/buttplug.js": "^0.5.0",
"buttplug-wasm-blob": "^3.0.0",
"idb": "^8.0.3",
"rolldown": "^1.2.3"
"rolldown": "^1.2.4"
},
"devDependencies": {
"@total-typescript/ts-reset": "^0.6.1",
"@types/events": "^3.0.3",
"@types/node": "^26.1.2",
"bc-stubs": "^130.0.0",
"@types/node": "^26.2.0",
"bc-stubs": "^131.0.0",
"bondage-club-mod-sdk": "^1.2.0",
"oxfmt": "^0.62.0",
"oxlint": "^1.77.0",
"oxfmt": "^0.63.0",
"oxlint": "^1.78.0",
"oxlint-tsgolint": "^7.0.2001",
"socket.io-client": "4.8.1"
},
Expand Down
2 changes: 1 addition & 1 deletion src/functions/automaticExpressions.js
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ export default async function automaticExpressions() {
}
appearance.Property.Expression = n;
if (color) {
appearance.Color = color;
appearance.Color = Array.isArray(color) ? color : [color];
}
break;
}
Expand Down
118 changes: 62 additions & 56 deletions src/functions/layeringMenu.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { displayText } from "../util/localization";
import { patchFunction, SDK, HOOK_PRIORITIES } from "../util/modding";
import { fbcSettings } from "../util/settings";
import { waitFor, isCharacter, deepCopy, fbcSendAction, parseJSON } from "../util/utils";
import { waitFor, isCharacter, fbcSendAction, parseJSON } from "../util/utils";

declare global {
interface ItemProperties {
Expand All @@ -25,53 +25,72 @@ export default async function layeringMenu(): Promise<void> {
return DialogHasKey(C, Item);
}

SDK.hookFunction("Layering.Load", HOOK_PRIORITIES.AddBehaviour, (args, next) => {
SDK.hookFunction("Layering.Load", HOOK_PRIORITIES.AddBehaviour, async (args, next) => {
if (fbcSettings.allowLayeringWhileBound && (!InventoryItemHasEffect(Layering.Item, "Lock") || DialogCanUnlock2(Layering.Character, Layering.Item))) {
Layering.Readonly = false;
}
if (!Layering.Character.IsPlayer() && Layering.Character.BCECapabilities?.includes("preventLayeringByOthers")) {
Layering.Readonly = true;
}
if (!fbcSettings.layeringHide || CurrentScreen === "Crafting" || !Layering.Character.BCECapabilities?.includes("layeringHide")) return next(args);
const ret = next(args);
const defaultItemHide = Layering.Asset.Hide || [];
if (defaultItemHide.length === 0) return ret;
const overrideItemHide = Layering.Item.Property.wceOverrideHide || defaultItemHide;
const root = document.getElementById(Layering.ID.root);
ElementCreate({
tag: "fieldset",
attributes: { name: "wce-hide", id: "layering-wce-hide-div", "aria-labelledby": "layering-hide-header", disabled: Layering.Readonly },
parent: root.querySelector(".screen-main"),
children: [
{ tag: "h2", attributes: { id: "layering-hide-header" }, children: [displayText("[WCE] Configure layer hiding")] },
{
tag: "fieldset",
classList: ["layering-layer-inner-grid"],
children: [
{ tag: "legend" as const, children: ["Layers"] },
...defaultItemHide.map(h => ({
tag: "div" as const,
classList: ["layering-pair"],
children: [
ElementCheckbox.Create(
`layering-wce-hide-cb-${h}`,
() => {
const hidingInputs = document.getElementById("layering-wce-hide-div")?.querySelectorAll<HTMLInputElement>("input[type='checkbox']:checked");
Layering.Item.Property.wceOverrideHide = Array.from(hidingInputs).map(inp => inp.value as AssetGroupName);
if (defaultItemHide.length === Layering.Item.Property.wceOverrideHide.length) delete Layering.Item.Property.wceOverrideHide;
// oxlint-disable-next-line no-underscore-dangle
Layering._CharacterRefresh(Layering.Character, false, false);
},
{ value: h, checked: overrideItemHide.includes(h) },
{ checkbox: { attributes: { name: "checkbox-hide" } } }
),
{ tag: "label" as const, classList: ["layering-pair-text"], children: [h], attributes: { for: `layering-wce-hide-cb-${h}` } },
],
})),
],
},
],
});

const ret = await next(args);

const btn = ElementButton.Create(
"layering-tab-wce-hide",
() => {
Layering.activeTab = "wce-hide";
const container = document.getElementById("layering-content-container");
if (container) {
container.innerHTML = "";
const defaultItemHide = Layering.Asset.Hide || [];
if (defaultItemHide.length === 0) return ret;
const overrideItemHide = Layering.Item.Property.wceOverrideHide || defaultItemHide;
const content = ElementCreate({
tag: "fieldset",
attributes: { name: "wce-hide", id: "layering-wce-hide-div", "aria-labelledby": "layering-hide-header", disabled: Layering.Readonly },
children: [
{ tag: "h2", attributes: { id: "layering-hide-header" }, children: [displayText("[WCE] Configure layer hiding")] },
{
tag: "fieldset",
classList: ["layering-layer-inner-grid"],
children: [
{ tag: "legend" as const, children: ["Layers"] },
...defaultItemHide.map(h => ({
tag: "div" as const,
classList: ["layering-pair"],
children: [
ElementCheckbox.Create(
`layering-wce-hide-cb-${h}`,
() => {
const hidingInputs = document
.getElementById("layering-wce-hide-div")
?.querySelectorAll<HTMLInputElement>("input[type='checkbox']:checked");
Layering.Item.Property.wceOverrideHide = Array.from(hidingInputs).map(inp => inp.value as AssetGroupName);
if (defaultItemHide.length === Layering.Item.Property.wceOverrideHide.length) delete Layering.Item.Property.wceOverrideHide;
// oxlint-disable-next-line no-underscore-dangle
Layering._CharacterRefresh(Layering.Character, false, false);
},
{ value: h, checked: overrideItemHide.includes(h) },
{ checkbox: { attributes: { name: "checkbox-hide" } } }
),
{ tag: "label" as const, classList: ["layering-pair-text"], children: [h], attributes: { for: `layering-wce-hide-cb-${h}` } },
],
})),
],
},
],
});
container.appendChild(content);
}
return null;
},
{ ariaChecked: Layering.activeTab === "wce-hide", role: "menuitemradio" }
);
btn.classList.add("layering-tab-button");
btn.innerText = "Hide";
document.getElementById("layering-tab-rotate").after(btn);

return ret;
});

Expand Down Expand Up @@ -187,21 +206,8 @@ export default async function layeringMenu(): Promise<void> {

function copyColorTo(item: Item, focusItem: Item): void {
if (item.Asset.Name === focusItem.Asset.Name) {
if (Array.isArray(focusItem.Color)) {
if (Array.isArray(item.Color)) {
for (let i = item.Color.length - 1; i >= 0; i--) {
item.Color[i] = focusItem.Color[i % focusItem.Color.length];
}
} else {
item.Color = focusItem.Color.at(-1);
}
} else if (Array.isArray(item.Color)) {
for (let i = 0; i < item.Color.length; i++) {
item.Color[i] = focusItem.Color ?? "Default";
}
} else {
// Both are array
item.Color = deepCopy(focusItem.Color);
for (let i = item.Color.length - 1; i >= 0; i--) {
item.Color[i] = focusItem.Color[i % focusItem.Color.length];
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions src/functions/wceStyles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,9 @@ export default function wceStyles(): void {
#wce-chat-stutters[data-state="preserve"]::before {
--button-color: #666;
}
#layering-wce-hide-div .layering-pair {
justify-content: start;
}
`;
const head = document.head || document.getElementsByTagName("head")[0];
const style = document.createElement("style");
Expand Down
8 changes: 4 additions & 4 deletions src/util/constants.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
export const FBC_VERSION = "6.3.18";
export const FBC_VERSION = "6.3.19";
export const settingsVersion = 63.9;
export const SUPPORTED_GAME_VERSIONS = ["R129", "R130"];
export const SUPPORTED_GAME_VERSIONS = ["R131"];

export const fbcChangelog = `WCE v6.3.18
* BC R130 compatibility and other fixes
export const fbcChangelog = `WCE v6.3.19
* BC R131 compatibility and other fixes
* update buttplug-js for toySync

WCE v6.3
Expand Down
Loading