dev.6
* R86Beta1 compatibility * patch by Lyra for /do item actions * removed handheld penetration patch until R86 release * time zone regexp accepts spaces now * fixed a bug with UTC+0 * better global keydown interception * exception handlers for hooks, shouldn't break the whole club now if something goes wrong * general cleanups and refactor
This commit is contained in:
parent
eaf4e3f26f
commit
45f6f80493
|
@ -1,6 +1,6 @@
|
|||
// ==UserScript==
|
||||
// @name MBCHC
|
||||
// @version dev.5
|
||||
// @version dev.6
|
||||
// @description Mute's Bondage Club Hacks Collection
|
||||
// @author codename.mute@proton.me
|
||||
// @namespace https://code.fleshless.org/mute/
|
||||
|
@ -11,6 +11,8 @@
|
|||
// @match https://www.bondageprojects.elementfx.com/R*
|
||||
// @match https://bondage-europe.com/R*
|
||||
// @match https://www.bondage-europe.com/R*
|
||||
// @match http://localhost:*/*
|
||||
// @match http://127.0.0.1:*/*
|
||||
// @grant none
|
||||
// ==/UserScript==
|
||||
|
||||
|
@ -24,7 +26,7 @@
|
|||
if (!window.AsylumGGTSSAddItems) throw "AsylumGGTSSAddItems() not found, aborting MBCHC loading"
|
||||
if (window.MBCHC) throw "MBCHC found, aborting loading"
|
||||
window.MBCHC = {
|
||||
VERSION: "dev.5",
|
||||
VERSION: "dev.6",
|
||||
TARGET_VERSION: "R85",
|
||||
NEXT_MESSAGE: 1,
|
||||
LOG_MESSAGES: false,
|
||||
|
@ -37,7 +39,7 @@
|
|||
RE_PREF_ACTIVITY_ME: /^@/,
|
||||
RE_PREF_ACTIVITY: /^@@/,
|
||||
RE_ACT_CIDS: /^<(\d+)?:(\d+)?>/,
|
||||
RE_TZ: /(?:GMT|UTC)([+-]\d\d?)/i,
|
||||
RE_TZ: /(?:GMT|UTC)\s*([+-])\s*(\d\d?)/i,
|
||||
RE_ALL_LEFT: /^<+$/,
|
||||
RE_ALL_RIGHT: /^>+$/,
|
||||
RE_SPACES: /\s{2,}/g,
|
||||
|
@ -46,7 +48,6 @@
|
|||
RGB_MUTE: "#6c2132",
|
||||
RGB_POLLY: "#81b1e7",
|
||||
UTC_OFFSET: new Date().getTimezoneOffset() * 60 * 1000,
|
||||
HAND_PENETRATORS: ["Flogger", "Whip", "TennisRacket", "Gavel", "SmallVibratingWand", "LargeDildo", "Vibrator", "Hairbrush", "SmallDildo", "Baguette", "Spatula", "Broom"],
|
||||
HIDE_SPECIAL: ["Activity","Emoticon"],
|
||||
HIDE_BODY: ["Blush","BodyLower","BodyUpper","Eyebrows","Eyes","Eyes2","Face","Fluids","HairBack","HairFront","Hands","Head","LeftHand","Mouth","Nipples","Pussy","RightHand"],
|
||||
HIDE_CLOTHES: [
|
||||
|
@ -287,10 +288,10 @@
|
|||
if (!window.ActivityAllowed()) throw "activities disabled in this room"
|
||||
if (!window.ServerChatRoomGetAllowItem(window.Player, char)) throw "no permissions"
|
||||
char.FocusGroup = this.ensure("invalid AssetGroup", () => window.AssetGroupGet(char.AssetFamily, ag))
|
||||
let activity = this.ensure("invalid activity", () => window.ActivityAllowedForGroup(char, char.FocusGroup.Name, true).find(a => a.Name === action))
|
||||
if (activity.Name.endsWith("Item")) {
|
||||
let item = this.ensure("no toy found", () => window.Player.Inventory.find(i => (i.Asset != null) && (i.Asset.Group.Name == char.FocusGroup.Name) && i.Asset.DynamicAllowInventoryAdd(char)))
|
||||
window.DialogPublishAction(char, window.DialogInventoryCreateItem(char, item, false))
|
||||
let activity = this.ensure("invalid activity", () => window.ActivityAllowedForGroup(char, char.FocusGroup.Name, true).find(a => a.Name === action || a.Activity?.Name === action))
|
||||
if ((activity.Name || activity.Activity.Name).endsWith("Item")) {
|
||||
const item = this.ensure("no toy found", () => window.Player.Inventory.find(i => i.Asset?.Name === "SpankingToys" && i.Asset.Group?.Name === char.FocusGroup.Name && window.AssetSpankingToys.DynamicActivity(char) === (activity.Name || activity.Activity.Name)))
|
||||
window.DialogPublishAction(char, item)
|
||||
} else window.ActivityRun(char, activity)
|
||||
} finally {
|
||||
char.FocusGroup = null
|
||||
|
@ -348,16 +349,6 @@
|
|||
window.TitleSet(title)
|
||||
//window.TitleList.push({Name: title, Requirement: () => true}) // check for existing first
|
||||
},
|
||||
patch_handheld: function() {
|
||||
let options = InventoryItemHandsSpankingToysOptions /* eslint-disable-line no-undef */ // window.InventoryItemHandsSpankingToysOptions is undefined
|
||||
for (let name of this.HAND_PENETRATORS) {
|
||||
let option = options.find(o => o.Name === name)
|
||||
if (option && option.Property) {
|
||||
if (!option.Property.AllowActivity) option.Property.AllowActivity = []
|
||||
if (option.Property.AllowActivity.indexOf("PenetrateItem") < 0) option.Property.AllowActivity.push("PenetrateItem")
|
||||
}
|
||||
}
|
||||
},
|
||||
copy_fbc_trigger: function(trigger) {
|
||||
let result = {
|
||||
Type: "Action",
|
||||
|
@ -377,16 +368,12 @@
|
|||
if (cmd) cmd.AutoComplete = this.complete_fbc_pose
|
||||
},
|
||||
gather_versions: function() { return(window.ChatRoomCharacter.filter(c => c.MBCHC).map(c => ({name: c.dn, cid: c.cid, version: c.MBCHC.VERSION}))) },
|
||||
need_load_hook: function(module, screen) {
|
||||
if (!module || !screen) return(true)
|
||||
if (("Character" === module) && ("Login" === screen)) return(true)
|
||||
return(false)
|
||||
},
|
||||
find_timezone: function(char) {
|
||||
let timezones = this.settings("timezones")
|
||||
if (timezones && timezones[char.cid]) return(timezones[char.cid])
|
||||
let match = (char.Description) ? char.Description.match(this.RE_TZ) : null
|
||||
if (match) return(Number.parseInt(match[1]))
|
||||
const timezones = this.settings("timezones")
|
||||
if (timezones && "number" === typeof timezones[char.cid]) return(timezones[char.cid])
|
||||
const match = (char.Description) ? char.Description.match(this.RE_TZ) : null
|
||||
const int = match ? Number.parseInt(match[1] + match[2]) : 42
|
||||
if (this.in(int, -12, 12)) return(int)
|
||||
return(null)
|
||||
},
|
||||
player_enters_room: function() { // or if the mod is loaded while player is in the room
|
||||
|
@ -432,9 +419,9 @@
|
|||
let type = char.IsPlayer() ? "self" : "others"
|
||||
let available = window.ActivityAllowedForGroup(char, ag)
|
||||
let toy = window.InventoryGet(window.Player, "ItemHands")
|
||||
if (toy && toy.Asset.Name === "SpankingToys") available.push(window.AssetAllActivities(char.AssetFamily).find(a => a.Name === window.InventorySpankingToysGetActivity(window.Player)))
|
||||
if (toy && toy.Asset.Name === "SpankingToys") available.push(window.AssetAllActivities(char.AssetFamily).find(a => a.Name === window.InventorySpankingToysGetActivity?.(window.Player)))
|
||||
let actions = mbchc.ensure(`zone "${zone}" invalid for ("${verb}" "${type}")`, () => types[type])
|
||||
let action = mbchc.ensure(`invalid action (${verb} ${zone} ${target})`, () => actions.find(name => available.find(a => a.Name === name)))
|
||||
let action = mbchc.ensure(`invalid action (${verb} ${zone} ${target})`, () => actions.find(name => available.find(a => a.Name === name || a.Activity?.Name === name)))
|
||||
mbchc.run_activity(char, ag, action)
|
||||
} catch (x) { mbchc.report(x) } },
|
||||
bell: function() {
|
||||
|
@ -534,7 +521,18 @@
|
|||
window.ElementValue("InputChat", history[found])
|
||||
window.ChatRoomLastMessageIndex = found
|
||||
},
|
||||
loader: function() {
|
||||
focus_chat_whitelist(event) {
|
||||
if (event.ctrlKey && "v" === event.key) return true // ctrl+V should paste
|
||||
return false
|
||||
},
|
||||
focus_chat(event) { // TODO: this is not ideal, but it will have to do for now
|
||||
if (event.repeat) return // only unique presses please
|
||||
if ("inline" !== document.getElementById("InputChat")?.style.display) return // input chat missing
|
||||
if (["InputChat","bce-message-input"].includes(document.activeElement.id)) return // focus already set
|
||||
if ([event.altKey, event.ctrlKey, event.metaKey].some(i => i) && !this.focus_chat_whitelist(event)) return // alt, ctrl and meta should all be false
|
||||
window.ElementFocus("InputChat")
|
||||
},
|
||||
loader() {
|
||||
if (this.remove_load_hook) {
|
||||
this.remove_load_hook()
|
||||
delete this.remove_load_hook
|
||||
|
@ -579,90 +577,52 @@
|
|||
document.head.appendChild(css)
|
||||
// Actions
|
||||
this.calculate_maps()
|
||||
this.patch_handheld()
|
||||
window.Player.MBCHC = {VERSION: this.VERSION}
|
||||
window.CommandCombine(COMMANDS)
|
||||
this.LOADED = true
|
||||
this.log("info", `loaded version ${this.VERSION}`)
|
||||
if (window.GameVersion !== this.TARGET_VERSION) console.warn(`Game version doesn't match the target ("${this.TARGET_VERSION}"), beware of incompatibilities`) // TODO: check betas & cheat
|
||||
}
|
||||
} // MBCHC
|
||||
|
||||
// Hooks
|
||||
window.MBCHC.sdk = window.bcModSdk.registerMod("MBCHC", window.MBCHC.VERSION)
|
||||
window.MBCHC.sdk.hookFunction("CharacterOnlineRefresh", 0, (nextargs, next) => {
|
||||
let result = next(nextargs)
|
||||
window.MBCHC.update_char(nextargs[0])
|
||||
return(result)
|
||||
})
|
||||
window.MBCHC.sdk.hookFunction("ChatRoomReceiveSuitcaseMoney", 0, (nextargs, next) => {
|
||||
let result = next(nextargs)
|
||||
if (window.MBCHC.AUTOHACK_ENABLED && window.MBCHC.LAST_HACKED) {
|
||||
window.CurrentCharacter = window.MBCHC.cid2char(window.MBCHC.LAST_HACKED)
|
||||
window.MBCHC.LAST_HACKED = null
|
||||
this.remove_fbc_hook = this.before("MainRun", () => window.bce_ActivityTriggers && this.patch_fbc())
|
||||
this.after("CharacterOnlineRefresh", char => this.update_char(char))
|
||||
this.after("ChatRoomReceiveSuitcaseMoney", () => {
|
||||
if (this.AUTOHACK_ENABLED && this.LAST_HACKED) {
|
||||
window.CurrentCharacter = this.cid2char(this.LAST_HACKED)
|
||||
this.LAST_HACKED = null
|
||||
window.ChatRoomTryToTakeSuitcase()
|
||||
}
|
||||
return(result)
|
||||
})
|
||||
window.MBCHC.sdk.hookFunction("ChatRoomSendChat", 0, (nextargs, next) => {
|
||||
this.before("ChatRoomSendChat", () => {
|
||||
let input = window.ElementValue("InputChat")
|
||||
if (!input.startsWith("@@@") && input.startsWith("@")) {
|
||||
input = input.replace(window.MBCHC.RE_PREF_ACTIVITY, window.MBCHC.PREF_ACTIVITY)
|
||||
input = input.replace(window.MBCHC.RE_PREF_ACTIVITY_ME, window.MBCHC.replace_me)
|
||||
input = input.replace(this.RE_PREF_ACTIVITY, this.PREF_ACTIVITY)
|
||||
input = input.replace(this.RE_PREF_ACTIVITY_ME, this.replace_me)
|
||||
window.ElementValue("InputChat", input)
|
||||
}
|
||||
let result = next(nextargs)
|
||||
let history = window.ChatRoomLastMessage
|
||||
})
|
||||
this.after("ChatRoomSendChat", () => {
|
||||
const history = window.ChatRoomLastMessage
|
||||
if ((history.length > 1) && (history[history.length - 1] === history[history.length - 2])) {history.pop(); window.ChatRoomLastMessageIndex -= 1}
|
||||
return(result)
|
||||
})
|
||||
window.MBCHC.sdk.hookFunction("ChatRoomDrawCharacterOverlay", 0, (nextargs, next) => {
|
||||
let [C, CharX, CharY, Zoom, Pos] = nextargs
|
||||
if ((window.ChatRoomHideIconState < 1) && C.MBCHC) {
|
||||
let colour = (C.MBCHC.VERSION === window.Player.MBCHC.VERSION) ? window.MBCHC.RGB_POLLY : window.MBCHC.RGB_MUTE
|
||||
window.DrawRect(CharX + 175 * Zoom, CharY, 50 * Zoom, 50 * Zoom, colour)
|
||||
this.before("ChatRoomDrawCharacterOverlay", (C, CharX, CharY, Zoom, Pos) => {
|
||||
window.ChatRoomHideIconState < 1 && C.MBCHC && window.DrawRect(CharX + 175 * Zoom, CharY, 50 * Zoom, 50 * Zoom, C.MBCHC.VERSION === window.Player.MBCHC.VERSION ? this.RGB_POLLY : this.RGB_MUTE)
|
||||
if (window.ChatRoomHideIconState < 1 && C.MBCHC_LOCAL && "number" === typeof C.MBCHC_LOCAL.TZ) {
|
||||
const hours = new Date(window.CommonTime() + this.UTC_OFFSET + C.MBCHC_LOCAL.TZ * 60 * 60 * 1000).getHours()
|
||||
window.DrawTextFit(hours < 10 ? "0" + hours.toString() : hours.toString(), CharX + 200 * Zoom, CharY + 25 * Zoom, 46 * Zoom, "white", "black")
|
||||
}
|
||||
if ((window.ChatRoomHideIconState < 1) && C.MBCHC_LOCAL && C.MBCHC_LOCAL.TZ) {
|
||||
let hours = new Date(window.CommonTime() + window.MBCHC.UTC_OFFSET + C.MBCHC_LOCAL.TZ * 60 * 60 * 1000).getHours()
|
||||
let text = (hours < 10) ? "0" + hours.toString() : hours.toString()
|
||||
window.DrawTextFit(text, CharX + 200 * Zoom, CharY + 25 * Zoom, 46 * Zoom, "white", "black")
|
||||
}
|
||||
return(next(nextargs))
|
||||
})
|
||||
window.MBCHC.sdk.hookFunction("ElementValue", 0, (nextargs, next) => { // TODO: layer priority will be locked too if it's the same as difficulty
|
||||
let [ID, Value] = nextargs
|
||||
let result = next(nextargs)
|
||||
if (("bce_LayerPriority" === ID) && window.CurrentCharacter?.FocusGroup && (window.InventoryGet(window.CurrentCharacter, window.CurrentCharacter.FocusGroup.Name)?.Difficulty.toString() === Value) && window.InventoryLocked(window.CurrentCharacter, window.CurrentCharacter.FocusGroup.Name, true)) window.ElementSetAttribute(ID, "disabled", true)
|
||||
return(result)
|
||||
})
|
||||
window.MBCHC.sdk.hookFunction("ChatRoomCreateElement", 0, (nextargs, next) => {
|
||||
let result = next(nextargs)
|
||||
if (!window.MBCHC.COMP_HINT.parentElement) document.body.appendChild(window.MBCHC.COMP_HINT)
|
||||
return(result)
|
||||
})
|
||||
window.MBCHC.sdk.hookFunction("ChatRoomClearAllElements", 0, (nextargs, next) => {
|
||||
window.MBCHC.complete_hint_hide()
|
||||
window.MBCHC.COMP_HINT.remove()
|
||||
return(next(nextargs))
|
||||
})
|
||||
window.MBCHC.sdk.hookFunction("ChatRoomResize", 0, (nextargs, next) => {
|
||||
let result = next(nextargs)
|
||||
if (window.CharacterGetCurrent() == null && window.CurrentScreen == "ChatRoom" && document.getElementById("InputChat") && document.getElementById("TextAreaChatLog") && window.MBCHC.comp_hint_visible()) { // upstream
|
||||
let fontsize = ChatRoomFontSize /* eslint-disable-line no-undef */ // window.ChatRoomFontSize is undefined
|
||||
this.after("ElementValue", (ID, Value, cc = window.CurrentCharacter) => "bce_LayerPriority" === ID && cc?.FocusGroup && window.InventoryGet(cc, cc.FocusGroup.Name)?.Difficulty.toString() === Value && window.InventoryLocked(cc, cc.FocusGroup.Name, true) && window.ElementSetAttribute(ID, "disabled", true))
|
||||
this.after("ChatRoomCreateElement", () => this.COMP_HINT.parentElement || document.body.appendChild(this.COMP_HINT))
|
||||
this.before("ChatRoomClearAllElements", () => !void this.complete_hint_hide() && this.COMP_HINT.remove())
|
||||
this.before("ChatRoomClick", () => this.complete_hint_hide())
|
||||
this.after("ChatRoomResize", () => {
|
||||
if (window.CharacterGetCurrent() == null && window.CurrentScreen == "ChatRoom" && document.getElementById("InputChat") && document.getElementById("TextAreaChatLog") && this.comp_hint_visible()) { // upstream
|
||||
const fontsize = ChatRoomFontSize /* eslint-disable-line no-undef */ // window.ChatRoomFontSize is undefined
|
||||
window.ElementPositionFix("TextAreaChatLog", fontsize, 1005, 66, 988, 630)
|
||||
window.ElementPositionFix(window.MBCHC.COMP_HINT.id, fontsize, 1005, 701, 988, 200)
|
||||
window.MBCHC.COMP_HINT.style.display = "flex"
|
||||
window.ElementPositionFix(this.COMP_HINT.id, fontsize, 1005, 701, 988, 200)
|
||||
this.COMP_HINT.style.display = "flex"
|
||||
}
|
||||
return(result)
|
||||
})
|
||||
window.MBCHC.sdk.hookFunction("DocumentKeyDown", 0, (nextargs, next) => {
|
||||
let [event] = nextargs
|
||||
if ("InputChat" === document.activeElement.id || "bce-message-input" === document.activeElement.id) return(next(nextargs))
|
||||
if ("inline" === document.getElementById("InputChat")?.style.display && [event.altKey, event.ctrlKey, event.metaKey].every(i => !i)) window.ElementFocus("InputChat") // alt, ctrl and meta should all be false
|
||||
// TODO: this is not ideal, but it will have to do for now
|
||||
return(next(nextargs))
|
||||
})
|
||||
window.MBCHC.sdk.hookFunction("ChatRoomKeyDown", 0, (nextargs, next) => {
|
||||
document.addEventListener("keydown", event => this.focus_chat(event))
|
||||
this.SDK.hookFunction("ChatRoomKeyDown", 0, (nextargs, next) => { // this fires on chat input events
|
||||
let [event] = nextargs
|
||||
window.MBCHC.complete_hint_hide()
|
||||
if ((window.KeyPress == 33) || (window.KeyPress == 34)) { // better history
|
||||
|
@ -675,42 +635,43 @@
|
|||
}
|
||||
return(next(nextargs))
|
||||
})
|
||||
window.MBCHC.sdk.hookFunction("ChatRoomClick", 0, (nextargs, next) => {
|
||||
window.MBCHC.complete_hint_hide()
|
||||
return(next(nextargs))
|
||||
})
|
||||
window.MBCHC.remove_fbc_hook = window.MBCHC.sdk.hookFunction("MainRun", 0, (nextargs, next) => {
|
||||
if (window.bce_ActivityTriggers) window.MBCHC.patch_fbc()
|
||||
return(next(nextargs))
|
||||
})
|
||||
|
||||
// Chat room handlers
|
||||
window.ChatRoomRegisterMessageHandler({ Priority: -220, Description: "MBCHC preprocessor",
|
||||
Callback: (data, sender, msg, metadata) => {
|
||||
data.MBCHC_ID = window.MBCHC.NEXT_MESSAGE
|
||||
window.MBCHC.NEXT_MESSAGE += 1
|
||||
if (window.MBCHC.LOG_MESSAGES) console.debug({data, sender, msg, metadata})
|
||||
data.MBCHC_ID = this.NEXT_MESSAGE
|
||||
this.NEXT_MESSAGE += 1
|
||||
if (this.LOG_MESSAGES) console.debug({data, sender, msg, metadata})
|
||||
}
|
||||
})
|
||||
window.ChatRoomRegisterMessageHandler({ Priority: -219, Description: "MBCHC room enter hook",
|
||||
Callback: (data, sender, msg, metadata) => { if (("Action" === data.Type) && ("ServerEnter" === data.Content) && (data.Sender === window.Player.cid)) window.MBCHC.player_enters_room() }
|
||||
Callback: (data, sender, msg, metadata) => { if (("Action" === data.Type) && ("ServerEnter" === data.Content) && (data.Sender === window.Player.cid)) this.player_enters_room() }
|
||||
})
|
||||
window.ChatRoomRegisterMessageHandler({ Priority: -219, Description: "MBCHC specific consumer",
|
||||
Callback: (data, sender, msg, metadata) => { if (("Hidden" === data.Type) && ("MBCHC" === data.Content)) return window.MBCHC.receive(data) }
|
||||
Callback: (data, sender, msg, metadata) => { if (("Hidden" === data.Type) && ("MBCHC" === data.Content)) return this.receive(data) }
|
||||
})
|
||||
window.ChatRoomRegisterMessageHandler({ Priority: -219, Description: "MBCHC autohack lookup",
|
||||
Callback: (data, sender, msg, metadata) => { if (("Hidden" === data.Type) && ("ReceiveSuitcaseMoney" === data.Content)) window.MBCHC.LAST_HACKED = data.Sender }
|
||||
Callback: (data, sender, msg, metadata) => { if (("Hidden" === data.Type) && ("ReceiveSuitcaseMoney" === data.Content)) this.LAST_HACKED = data.Sender }
|
||||
})
|
||||
|
||||
// MAIN SCREEN TURN ON
|
||||
if (window.MBCHC.need_load_hook(window.CurrentModule, window.CurrentScreen)) {
|
||||
window.MBCHC.remove_load_hook = window.MBCHC.sdk.hookFunction("AsylumGGTSSAddItems", 0, (nextargs, next) => {window.MBCHC.loader(); return(next(nextargs))})
|
||||
} else {
|
||||
window.MBCHC.loader()
|
||||
// footer
|
||||
this.LOADED = true
|
||||
this.log("info", `loaded version ${this.VERSION}`)
|
||||
if (window.GameVersion !== this.TARGET_VERSION) this.log("warn", `Game version doesn't match the target ("${this.TARGET_VERSION}"), beware of incompatibilities`) // TODO: betas are like R86Beta1; cheat?
|
||||
if (("Online" === window.CurrentModule) && ("ChatRoom" === window.CurrentScreen)) {
|
||||
window.ChatRoomCharacter.forEach(c => window.MBCHC.update_char(c))
|
||||
window.MBCHC.player_enters_room()
|
||||
window.ChatRoomCharacter.forEach(c => this.update_char(c))
|
||||
this.player_enters_room()
|
||||
}
|
||||
},
|
||||
preloader() {
|
||||
this.SDK = window.bcModSdk.registerMod("MBCHC", this.VERSION)
|
||||
this.before = (name, cb) => this.SDK.hookFunction(name, 0, (nextargs,next) => {try {cb?.(...nextargs)} catch (x) {console.error(x)} finally {return next(nextargs)}})
|
||||
this.after = (name, cb) => this.SDK.hookFunction(name, 0, (nextargs,next) => {const result = next(nextargs); try {cb?.(...nextargs)} catch (x) {console.error(x)} finally {return result}})
|
||||
if (window.CurrentModule && window.CurrentScreen && !("Character" === window.CurrentModule && "Login" === window.CurrentScreen)) return this.loader()
|
||||
this.remove_load_hook = this.before("AsylumGGTSSAddItems", () => this.loader())
|
||||
}
|
||||
} // MBCHC
|
||||
|
||||
window.MBCHC.preloader()
|
||||
|
||||
})()
|
||||
|
|
Loading…
Reference in New Issue
Block a user