NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript==
// @name Bondage Club Extension
// @namespace http://tampermonkey.net/
// @version 0.1
// @description UI changes, fixes
// @author NoneNoname
// @license MIT
// @include http://*.bondageprojects.com/college/*/BondageClub/
// @include https://*.bondageprojects.com/college/*/BondageClub/*
// @require https://raw.githubusercontent.com/blueimp/JavaScript-MD5/master/js/md5.min.js
// @grant none
// ==/UserScript==
(function () {
'use strict';
Asset.forEach(e => {
e.SelfBondage = true;
e.PropertyLocked = e.Name == "CollarNameTag";
});
AssetGroup.forEach(e => {
if (["Hat", "HairAccessory1", "HairAccessory2", "Wings", "TailStraps"].indexOf(e.Name) >= 0) e.KeepNaked = true;
});
AssetGroup.forEach(e => {
if (e.IsDefault && ["Cloth", "ClothLower", "Bra", "Panties", "Socks", "Shoes"].indexOf(e.Name) >= 0) e.IsDefault = false;
});
window.LoginValidCollar = function LoginValidCollar() {
if ((InventoryGet(Player, "ItemNeck") == null) && (Player.Owner != "")) InventoryWear(Player, "SlaveCollar", "ItemNeck");
}
DrawBackNextButton = function DrawBackNextButton(Left, Top, Width, Height, Label, Color, Image, BackText, NextText, ThreeWay) {
var SplitWidth = Width / 2;
if (ThreeWay) SplitWidth = Width / 3
var Split = Left + SplitWidth;
// Draw the button rectangle (makes half of the background cyan colored if the mouse is over it)
MainCanvas.beginPath();
MainCanvas.rect(Left, Top, Width, Height);
MainCanvas.fillStyle = Color;
MainCanvas.fillRect(Left, Top, Width, Height);
if (!CommonIsMobile && (MouseX >= Left) && (MouseX <= Left + Width) && (MouseY >= Top) && (MouseY <= Top + Height)) {
MainCanvas.fillStyle = "Cyan";
if (ThreeWay && (MouseX > Left + SplitWidth * 2)) MainCanvas.fillRect(Left + SplitWidth * 2, Top, SplitWidth, Height);
else if (MouseX > Left + SplitWidth) MainCanvas.fillRect(Left + SplitWidth, Top, SplitWidth, Height);
else MainCanvas.fillRect(Left, Top, SplitWidth, Height);
}
MainCanvas.lineWidth = '2';
MainCanvas.strokeStyle = 'black';
MainCanvas.stroke();
MainCanvas.closePath();
// Draw the text or image
DrawTextFit(Label, Left + Width / 2, Top + (Height / 2) + 1, Width - 4, "black");
if ((Image != null) && (Image != "")) DrawImageResize(Image, Left + 2, Top + 2, Width - 4, Height - 4);
if (CommonIsMobile && ThreeWay) return;
// Draw the back arrow
MainCanvas.beginPath();
MainCanvas.fillStyle = "black";
MainCanvas.moveTo(Left + 15, Top + Height / 5);
MainCanvas.lineTo(Left + 5, Top + Height / 2);
MainCanvas.lineTo(Left + 15, Top + Height - Height / 5);
MainCanvas.stroke();
MainCanvas.closePath();
// Draw the next arrow
MainCanvas.beginPath();
MainCanvas.fillStyle = "black";
MainCanvas.moveTo(Left + Width - 15, Top + Height / 5);
MainCanvas.lineTo(Left + Width - 5, Top + Height / 2);
MainCanvas.lineTo(Left + Width - 15, Top + Height - Height / 5);
MainCanvas.stroke();
MainCanvas.closePath();
if (CommonIsMobile) return;
if (BackText == null) BackText = () => "MISSING VALUE FOR: BACK TEXT";
if (NextText == null) NextText = () => "MISSING VALUE FOR: NEXT TEXT";
if (ThreeWay && typeof ThreeWay !== 'function') ThreeWay = () => "MISSING VALUE FOR: THREEWAY TEXT";
// Draw the hovering text
if ((MouseX >= Left) && (MouseX <= Left + Width) && (MouseY >= Top) && (MouseY <= Top + Height)) {
Left = (MouseX > 1000) ? Left - 475 : Left + 115;
Top = Top + (Height - 65) / 2;
MainCanvas.beginPath();
MainCanvas.rect(Left, Top, 450, 65);
MainCanvas.fillStyle = "#FFFF88";
MainCanvas.fillRect(Left, Top, 450, 65);
MainCanvas.fill();
MainCanvas.lineWidth = '2';
MainCanvas.strokeStyle = 'black';
MainCanvas.stroke();
MainCanvas.closePath();
if (ThreeWay && (MouseX > Split && MouseX <= Split + SplitWidth)) DrawTextFit(ThreeWay(), Left + 225, Top + 33, 444, "black");
else DrawTextFit((MouseX > Split) ? NextText() : BackText(), Left + 225, Top + 33, 444, "black");
}
}
MainHallRun = function MainHallRun() {
// If the player is dressed up while being a club slave, the maid intercepts her
if ((CurrentCharacter == null) && ManagementIsClubSlave() && LogQuery("BlockChange", "Rule") && !Player.IsNaked() && (MainHallMaid.Dialog != null) && (MainHallMaid.Dialog.length > 0)) {
MainHallMaid.Stage = "50";
MainHallMaid.CurrentDialog = DialogFind(MainHallMaid, "ClubSlaveMustBeNaked");
CharacterRelease(MainHallMaid);
CharacterSetCurrent(MainHallMaid);
MainHallStartEventTimer = null;
MainHallNextEventTimer = null;
return;
}
// If the player is a Mistress but her Dominant reputation has fallen
if ((CurrentCharacter == null) && LogQuery("ClubMistress", "Management") && (ReputationGet("Dominant") < 50) && Player.CanTalk() && (MainHallMaid.Dialog != null) && (MainHallMaid.Dialog.length > 0)) {
CommonSetScreen("Room", "Management");
CharacterSetCurrent(MainHallMaid);
CurrentScreen = "MainHall";
MainHallMaid.Stage = "60";
MainHallMaid.CurrentDialog = DialogFind(MainHallMaid, "MistressExpulsionIntro");
return;
}
// Draws the character and main hall buttons
DrawCharacter(Player, 750, 0, 1);
// Char, Dressing, Exit & Chat
DrawButton(1645, 25, 90, 90, "", "White", "Icons/Character.png", TextGet("Profile"));
if (Player.CanChange()) DrawButton(1765, 25, 90, 90, "", "White", "Icons/Dress.png", TextGet("Appearance"));
DrawButton(1885, 25, 90, 90, "", "White", "Icons/Exit.png", TextGet("Exit"));
DrawButton(1645, 145, 90, 90, "", "White", "Icons/Chat.png", TextGet("ChatRooms"));
// The options below are only available if the player can move
if (Player.CanWalk()) {
// Shop & Private Room
DrawButton(1765, 145, 90, 90, "", "White", "Icons/Shop.png", TextGet("Shop"));
if (!LogQuery("LockOutOfPrivateRoom", "Rule")) DrawButton(1885, 145, 90, 90, "", "White", "Icons/Private.png", TextGet("PrivateRoom"));
// Introduction, Maid & Management
DrawButton(1645, 265, 90, 90, "", "White", "Icons/Introduction.png", TextGet("IntroductionClass"));
DrawButton(1765, 265, 90, 90, "", "White", "Icons/Maid.png", TextGet("MaidQuarters"));
DrawButton(1885, 265, 90, 90, "", "White", "Icons/Management.png", TextGet("ClubManagement"));
// Kidnap League, Dojo, Explore/Sarah
DrawButton(1645, 385, 90, 90, "", "White", "Icons/Kidnap.png", TextGet("KidnapLeague"));
DrawButton(1765, 385, 90, 90, "", "White", "Icons/Dojo.png", TextGet("ShibariDojo"));
if (SarahRoomAvailable) DrawButton(1885, 385, 90, 90, "", "White", "Icons/Explore.png", TextGet(SarahRoomLabel()));
// Cell, Slave Market & Look for trouble
DrawButton(1645, 505, 90, 90, "", "White", "Icons/Question.png", TextGet("LookForTrouble"));
DrawButton(1765, 505, 90, 90, "", "White", "Icons/Gavel.png", TextGet("SlaveMarket"));
DrawButton(1885, 505, 90, 90, "", "White", "Icons/Cell.png", TextGet("Cell"));
// Asylum & College
if (!ManagementIsClubSlave()) DrawButton(1765, 625, 90, 90, "", "White", "Icons/College.png", TextGet("College"));
DrawButton(1885, 625, 90, 90, "", "White", "Icons/Asylum.png", TextGet("Asylum"));
// Draws the custom content rooms - Gambling, Prison & Photographic
DrawButton(265, 25, 90, 90, "", "White", "Icons/Camera.png", TextGet("Photographic"));
DrawButton(145, 25, 90, 90, "", "White", "Icons/Cage.png", TextGet("Prison"));
DrawButton(25, 25, 90, 90, "", "White", "Icons/Random.png", TextGet("Gambling"));
// Stable, Magic-Theater & Nursery
DrawButton(265, 145, 90, 90, "", "White", "Icons/Diaper.png", TextGet("Nursery"));
DrawButton(145, 145, 90, 90, "", "White", "Icons/Magic.png", TextGet("Magic"));
DrawButton(25, 145, 90, 90, "", "White", "Icons/Horse.png", TextGet("Stable"));
// Cafe
DrawButton(25, 265, 90, 90, "", "White", "Icons/Refreshsments.png", TextGet("Cafe"));
}
// Check if there's a new maid rescue event to trigger
if ((!Player.CanInteract() || !Player.CanWalk() || !Player.CanTalk())) {
if (MainHallNextEventTimer == null) {
MainHallStartEventTimer = CommonTime();
MainHallNextEventTimer = CommonTime() + 40000 + Math.floor(Math.random() * 40000);
}
}
else {
MainHallStartEventTimer = null;
MainHallNextEventTimer = null;
}
// If we must send a maid to rescue the player
if ((MainHallNextEventTimer != null) && (CommonTime() >= MainHallNextEventTimer)) {
MainHallMaid.Stage = "0";
CharacterRelease(MainHallMaid);
CharacterSetCurrent(MainHallMaid);
MainHallStartEventTimer = null;
MainHallNextEventTimer = null;
}
// If we must show a progress bar for the rescue maid. If not, we show the number of online players
if ((!Player.CanInteract() || !Player.CanWalk() || !Player.CanTalk()) && (MainHallStartEventTimer != null) && (MainHallNextEventTimer != null)) {
DrawText(TextGet("RescueIsComing"), 1750, 925, "White", "Black");
DrawProgressBar(1525, 955, 450, 35, (1 - ((MainHallNextEventTimer - CommonTime()) / (MainHallNextEventTimer - MainHallStartEventTimer))) * 100);
}
else DrawText(TextGet("OnlinePlayers") + " " + CurrentOnlinePlayers.toString(), 1750, 960, "White", "Black");
}
let WardrobeSize = 12;
let AppearanceAssets;
let AppearanceUndo = [];
let AppearanceWardrobeOffset = 0;
let AppearanceMode = "";
let AppearanceHeight = 65;
let AppearanceSpace = 30;
let AppearanceItem = null;
let AppearanceColorUndo = true;
let AppearanceItemUndo = true;
let AppearanceItemsOffset = 0;
let AppearanceTempWardrobe = [];
let AppearanceWardrobeShouldUndo = true;
CharacterAppearanceWardrobeLoad = function CharacterAppearanceWardrobeLoad(C) {
if (Player.Wardrobe == null || Player.Wardrobe.length < WardrobeSize) {
WardrobeLoadCharacters(true);
}
else {
WardrobeLoadCharacterNames();
}
ElementCreateInput("InputWardrobeName", "text", C.Name, "20");
AppearanceMode = "Wardrobe";
AppearanceWardrobeShouldUndo = true;
CharacterAppearanceWardrobeText = window.TextGet("WardrobeNameInfo");
}
AppearanceLoad = function AppearanceLoad() {
if (!CharacterAppearanceSelection) CharacterAppearanceSelection = Player;
const C = CharacterAppearanceSelection;
AppearanceUndo = [];
AppearanceTempWardrobe = [];
AppearanceBuildAssets(C);
AppearanceMode = "";
CharacterAppearanceBackup = C.Appearance.map(Item => Object.assign({}, Item));
}
// Run the character appearance selection screen
AppearanceRun = function AppearanceRun() {
const C = CharacterAppearanceSelection;
// Draw the background and the character twice
if (CharacterAppearanceHeaderText == "") {
if (C.ID == 0) CharacterAppearanceHeaderText = TextGet("SelectYourAppearance");
else CharacterAppearanceHeaderText = TextGet("SelectSomeoneAppearance").replace("TargetCharacterName", C.Name);
}
DrawCharacter(C, -600, (C.IsKneeling()) ? -1100 : -100, 4, false);
DrawCharacter(C, 750, 0, 1);
DrawText(CharacterAppearanceHeaderText, 400, 40, "White", "Black");
if (AppearanceMode == "") {
AppearanceNormalRun();
}
else if (AppearanceMode == "Wardrobe") {
AppearanceWardrobeRun();
}
else if (AppearanceMode == "Color") {
AppearanceColorRun();
}
else if (AppearanceMode == "Items") {
AppearanceItemsRun();
}
// Draw the default buttons
DrawButton(1768, 25, 90, 90, "", "White", "Icons/Cancel.png", TextGet("Cancel"));
DrawButton(1885, 25, 90, 90, "", "White", "Icons/Accept.png", TextGet("Accept"));
}
// When the user clicks on the character appearance selection screen
AppearanceClick = function AppearanceClick() {
if (AppearanceMode == "") {
AppearanceNormalClick();
}
else if (AppearanceMode == "Wardrobe") {
AppearanceWardrobeClick();
}
else if (AppearanceMode == "Color") {
AppearanceColorClick();
}
else if (AppearanceMode == "Items") {
AppearanceItemsClick();
}
}
// when the user press escape
AppearanceExit = function AppearanceExit() {
if (AppearanceMode == "") CharacterAppearanceExit(CharacterAppearanceSelection);
else if (AppearanceMode == "Wardrobe") {
AppearanceMode == "";
ElementRemove("InputWardrobeName");
AppearanceAssets.forEach(A => A.ReloadItem());
}
else if (AppearanceMode == "Color") {
AppearanceMode == "";
ElementRemove("InputColor");
if (AppearanceColorUndo) AppearanceRunUndo();
AppearanceItem = null;
}
else if (AppearanceMode == "Items") {
if (AppearanceItemUndo) AppearanceRunUndo();
AppearanceItem = null;
}
}
class AppearanceAssetGroup {
constructor(C, Group) {
const m = new Map();
const AddAsset = A => {
m.set(A.Name, A);
};
Asset
.filter(A => A.Value == 0)
.filter(A => A.Group.Name == Group.Name)
.forEach(AddAsset);
Player.Inventory
.map(I => I.Asset)
.filter(A => A)
.filter(A => A.Group.Name == Group.Name)
.forEach(AddAsset);
C.Inventory
.map(I => I.Asset)
.filter(A => A)
.filter(A => A.Group.Name == Group.Name)
.forEach(AddAsset);
this.C = C;
this.Group = Group;
this.Assets = [];
this.Item = this.C.Appearance.find(I => I.Asset.Group.Name == this.Group.Name);
this.Color = (this.Item && this.Item.Color) || "None";
this.CanChange = this.C.ID == 0 || this.Group.Clothing;
m.forEach(A => this.Assets.push(A));
}
NextColor() {
if (this.Item) {
let I = this.Group.ColorSchema.indexOf(this.Color) + 1;
if (I < 0 || I >= this.Group.ColorSchema.length) I = 0;
this.SetColor(this.Group.ColorSchema[I], true);
}
}
SetColor(Color, Undo) {
if (this.Item) {
if (Undo) {
const G = this;
const OldColor = this.Color;
AppearanceUndo.push(() => G.SetColor(OldColor));
}
this.Item.Color = Color;
this.Color = Color;
CharacterLoadCanvas(this.C);
this.ReloadItem();
}
}
SetItem(AssetName, Undo) {
if (Undo) {
const G = this;
const AssetName = this.Item && this.Item.Asset.Name;
AppearanceUndo.push(() => G.SetItem(AssetName));
}
if (AssetName) InventoryWear(this.C, AssetName, this.Group.Name, this.Color == "None" ? null : this.Color);
else InventoryRemove(this.C, this.Group.Name);
AppearanceAssets.forEach(A => A.ReloadItem());
}
GetNextItem() {
if (this.Item) {
const I = this.Assets.findIndex(A => A.Group.Name == this.Group.Name && A.Name == this.Item.Asset.Name) + 1;
if (I >= this.Assets.length) {
return this.Group.AllowNone ? null : this.Assets[0];
}
else {
return this.Assets[I];
}
}
else {
return this.Assets[0];
}
}
GetPrevItem() {
if (this.Item) {
const I = this.Assets.findIndex(A => A.Group.Name == this.Group.Name && A.Name == this.Item.Asset.Name) - 1;
if (I < 0) {
return this.Group.AllowNone ? null : this.Assets[this.Assets.length - 1];
}
else {
return this.Assets[I];
}
}
else {
return this.Assets[this.Assets.length - 1];
}
}
SetNextPrevItem(Prev) {
let Item;
if (Prev) {
Item = this.GetPrevItem();
}
else {
Item = this.GetNextItem();
}
this.SetItem(Item && Item.Name, true);
}
Strip(Undo) {
if (this.CanStrip()) {
this.SetItem(null, Undo == null || Undo);
}
}
CanStrip() {
return this.CanChange && this.Item && this.Group.AllowNone; // && !this.Group.KeepNaked
}
ReloadItem() {
this.Item = this.C.Appearance.find(I => I.Asset.Group.Name == this.Group.Name);
this.Color = (this.Item && this.Item.Color) || this.Color || "None";
}
}
function AppearanceBuildAssets(C) {
AppearanceAssets = [];
AssetGroup
.filter(G => G.Family == C.AssetFamily)
.filter(G => G.Category == "Appearance")
.filter(G => G.AllowCustomize)
.forEach(G => AppearanceAssets.push(new AppearanceAssetGroup(C, G)));
}
function AppearanceRunUndo(NoPop) {
if (AppearanceUndo.length > 0) {
if (NoPop) AppearanceUndo[AppearanceUndo.length - 1]();
else AppearanceUndo.pop()();
}
}
function AppearanceNormalRun() {
const C = CharacterAppearanceSelection;
// Draw the top buttons with images
if (AppearanceUndo.length > 0) DrawButton(1183, 25, 90, 90, "", "White", "Icons/Magic.png", "Undo");
if (C.ID == 0) {
DrawButton(1300, 25, 90, 90, "", "White", "Icons/" + ((LogQuery("Wardrobe", "PrivateRoom")) ? "Wardrobe" : "Reset") + ".png", TextGet(LogQuery("Wardrobe", "PrivateRoom") ? "Wardrobe" : "ResetClothes"));
DrawButton(1417, 25, 90, 90, "", "White", "Icons/Random.png", TextGet("Random"));
}
else if (LogQuery("Wardrobe", "PrivateRoom")) DrawButton(1417, 25, 90, 90, "", "White", "Icons/Wardrobe.png", TextGet("Wardrobe"));
DrawButton(1534, 25, 90, 90, "", "White", "Icons/Naked.png", TextGet("Naked"));
DrawButton(1651, 25, 90, 90, "", "White", "Icons/Next.png", TextGet("Next"));
let offset = AppearanceHeight + AppearanceSpace;
CharacterAppearanceNumPerPage = parseInt(900 / offset);
for (let A = CharacterAppearanceOffset; A < AppearanceAssets.length && A < CharacterAppearanceOffset + CharacterAppearanceNumPerPage; A++) {
if (AppearanceAssets[A].CanStrip()) {
DrawButton(1210, 145 + (A - CharacterAppearanceOffset) * offset, 65, AppearanceHeight, "", "White", "Icons/Small/Naked.png", TextGet("StripItem"));
}
if (AppearanceAssets[A].CanChange)
DrawBackNextButton(1300, 145 + (A - CharacterAppearanceOffset) * offset, 400, AppearanceHeight, AppearanceAssets[A].Group.Description + ": " + CharacterAppearanceGetCurrentValue(C, AppearanceAssets[A].Group.Name, "Description"), "White", null,
() => {
const Item = AppearanceAssets[A].GetPrevItem();
return Item ? Item.Description : "None"
},
() => {
const Item = AppearanceAssets[A].GetNextItem();
return Item ? Item.Description : "None"
},
() => "Show All Items In Group"
);
else DrawButton(1300, 145 + (A - CharacterAppearanceOffset) * offset, 400, AppearanceHeight, AppearanceAssets[A].Group.Description + ": " + CharacterAppearanceGetCurrentValue(C, AppearanceAssets[A].Group.Name, "Description"), "#AAAAAA");
const Color = AppearanceAssets[A].Color;
DrawButton(1725, 145 + (A - CharacterAppearanceOffset) * offset, 160, AppearanceHeight, Color, ((Color.indexOf("#") == 0) ? Color : "White"));
if (AppearanceAssets[A].Item != null && AppearanceAssets[A].CanChange) DrawButton(1910, 145 + (A - CharacterAppearanceOffset) * offset, 65, AppearanceHeight, "", "White", AppearanceAssets[A].Group.AllowColorize ? "Icons/Color.png" : "Icons/ColorBlocked.png");
}
}
function AppearanceNormalClick() {
const C = CharacterAppearanceSelection;
let offset = AppearanceHeight + AppearanceSpace;
// If we must remove/restore to default the item
if ((MouseX >= 1210) && (MouseX < 1275) && (MouseY >= 145) && (MouseY < 975))
for (let A = CharacterAppearanceOffset; A < AppearanceAssets.length && A < CharacterAppearanceOffset + CharacterAppearanceNumPerPage; A++)
if (AppearanceAssets[A].CanStrip())
if ((MouseY >= 145 + (A - CharacterAppearanceOffset) * offset) && (MouseY <= 145 + AppearanceHeight + (A - CharacterAppearanceOffset) * offset))
AppearanceAssets[A].Strip();
// If we must switch to the next item in the assets
if ((MouseX >= 1300) && (MouseX < 1700) && (MouseY >= 145) && (MouseY < 975))
for (let A = CharacterAppearanceOffset; A < AppearanceAssets.length && A < CharacterAppearanceOffset + CharacterAppearanceNumPerPage; A++)
if ((MouseY >= 145 + (A - CharacterAppearanceOffset) * offset) && (MouseY <= 145 + AppearanceHeight + (A - CharacterAppearanceOffset) * offset)) {
if (AppearanceAssets[A].CanChange) {
if (!CommonIsMobile && MouseX < 1300 + (400 / 3)) {
AppearanceAssets[A].SetNextPrevItem(true);
}
else if (!CommonIsMobile && MouseX >= 1300 + (400 / 3) * 2) {
AppearanceAssets[A].SetNextPrevItem(false);
}
else {
AppearanceItem = AppearanceAssets[A];
AppearanceItem.SetItem(AppearanceItem.Item && AppearanceItem.Item.Asset.Name, true);
AppearanceItemsOffset = 0;
AppearanceItemUndo = true;
AppearanceMode = "Items";
}
}
}
// If we must switch to the next color in the assets
if ((MouseX >= 1725) && (MouseX < 1885) && (MouseY >= 145) && (MouseY < 975))
for (let A = CharacterAppearanceOffset; A < AppearanceAssets.length && A < CharacterAppearanceOffset + CharacterAppearanceNumPerPage; A++)
if ((MouseY >= 145 + (A - CharacterAppearanceOffset) * offset) && (MouseY <= 145 + AppearanceHeight + (A - CharacterAppearanceOffset) * offset) && AppearanceAssets[A].Item != null)
if (AppearanceAssets[A].CanChange)
AppearanceAssets[A].NextColor(C, AppearanceAssets[A].Name);
// If we must open the color panel
if ((MouseX >= 1910) && (MouseX < 1975) && (MouseY >= 145) && (MouseY < 975))
for (let A = CharacterAppearanceOffset; A < AppearanceAssets.length && A < CharacterAppearanceOffset + CharacterAppearanceNumPerPage; A++)
if (AppearanceAssets[A].Group.AllowColorize)
if ((MouseY >= 145 + (A - CharacterAppearanceOffset) * offset) && (MouseY <= 145 + AppearanceHeight + (A - CharacterAppearanceOffset) * offset) && AppearanceAssets[A].Item != null) {
if (AppearanceAssets[A].CanChange) {
AppearanceItem = AppearanceAssets[A];
AppearanceItem.SetColor(AppearanceItem.Color == "None" ? "Default" : AppearanceItem.Color, true);
ElementCreateInput("InputColor", "text", ((AppearanceAssets[A].Color == "Default") || (AppearanceAssets[A].Color == "None")) ? "#" : AppearanceAssets[A].Color, "7");
AppearanceColorUndo = true;
AppearanceMode = "Color";
}
}
// If we must set back the default outfit or set a random outfit
if ((MouseX >= 1183) && (MouseX < 1273) && (MouseY >= 25) && (MouseY < 115)) AppearanceRunUndo();
if ((MouseX >= 1300) && (MouseX < 1390) && (MouseY >= 25) && (MouseY < 115) && (C.ID == 0) && !LogQuery("Wardrobe", "PrivateRoom")) CharacterAppearanceSetDefault(C);
if ((MouseX >= 1300) && (MouseX < 1390) && (MouseY >= 25) && (MouseY < 115) && (C.ID == 0) && LogQuery("Wardrobe", "PrivateRoom")) CharacterAppearanceWardrobeLoad(C);
if ((MouseX >= 1417) && (MouseX < 1507) && (MouseY >= 25) && (MouseY < 115) && (C.ID == 0)) CharacterAppearanceFullRandom(C);
if ((MouseX >= 1417) && (MouseX < 1507) && (MouseY >= 25) && (MouseY < 115) && (C.ID != 0) && LogQuery("Wardrobe", "PrivateRoom")) CharacterAppearanceWardrobeLoad(C);
if ((MouseX >= 1534) && (MouseX < 1624) && (MouseY >= 25) && (MouseY < 115)) {
AppearanceAssets.filter(A => A.CanStrip() && !A.Group.KeepNaked).forEach(A => A.Strip());
}
if ((MouseX >= 1651) && (MouseX < 1741) && (MouseY >= 25) && (MouseY < 115)) CharacterAppearanceMoveOffset(CharacterAppearanceNumPerPage);
if ((MouseX >= 1768) && (MouseX < 1858) && (MouseY >= 25) && (MouseY < 115)) CharacterAppearanceExit(C);
if ((MouseX >= 1885) && (MouseX < 1975) && (MouseY >= 25) && (MouseY < 115)) CharacterAppearanceReady(C);
}
function AppearanceItemsRun() {
if (AppearanceItem == null) {
AppearanceMode = "";
return;
}
let offset = AppearanceHeight + AppearanceSpace;
CharacterAppearanceNumPerPage = parseInt(900 / offset) * 2;
if (AppearanceItem.Assets.length > CharacterAppearanceNumPerPage) DrawButton(1534, 25, 90, 90, "", "White", "Icons/Next.png", TextGet("Next"));
if (AppearanceItem.CanStrip()) DrawButton(1651, 25, 90, 90, "", "White", "Icons/Naked.png", TextGet("StripItem"));
// Creates buttons for all groups
for (let A = AppearanceItemsOffset; A * 2 < AppearanceItem.Assets.length && A * 2 < AppearanceItemsOffset * 2 + CharacterAppearanceNumPerPage; A++) {
const ItemName = AppearanceItem.Item && AppearanceItem.Item.Asset && AppearanceItem.Item.Asset.Name;
DrawButton(1250, 145 + (A - AppearanceItemsOffset) * offset, 350, AppearanceHeight, AppearanceItem.Assets[A * 2].Description, AppearanceItem.Assets[A * 2].Name == ItemName ? "Pink" : "White");
if (A * 2 + 1 >= AppearanceItem.Assets.length || A * 2 + 1 >= AppearanceItemsOffset * 2 + CharacterAppearanceNumPerPage) break;
DrawButton(1630, 145 + (A - AppearanceItemsOffset) * offset, 350, AppearanceHeight, AppearanceItem.Assets[A * 2 + 1].Description, AppearanceItem.Assets[A * 2 + 1].Name == ItemName ? "Pink" : "White");
}
}
function AppearanceItemsClick() {
let offset = AppearanceHeight + AppearanceSpace;
if ((MouseX >= 1250) && (MouseX < 1600) && (MouseY >= 145) && (MouseY < 975))
for (let A = AppearanceItemsOffset; A * 2 < AppearanceItem.Assets.length && A * 2 < AppearanceItemsOffset * 2 + CharacterAppearanceNumPerPage; A++) {
if ((MouseY >= 145 + (A - AppearanceItemsOffset) * offset) && (MouseY <= 145 + AppearanceHeight + (A - AppearanceItemsOffset) * offset)) {
AppearanceItem.SetItem(AppearanceItem.Assets[A * 2].Name);
}
}
if ((MouseX >= 1630) && (MouseX < 1980) && (MouseY >= 145) && (MouseY < 975))
for (let A = AppearanceItemsOffset; A * 2 + 1 < AppearanceItem.Assets.length && A * 2 + 1 < AppearanceItemsOffset * 2 + CharacterAppearanceNumPerPage; A++) {
if ((MouseY >= 145 + (A - AppearanceItemsOffset) * offset) && (MouseY <= 145 + AppearanceHeight + (A - AppearanceItemsOffset) * offset)) {
AppearanceItem.SetItem(AppearanceItem.Assets[A * 2 + 1].Name);
}
}
if ((MouseX >= 1651) && (MouseX < 1741) && (MouseY >= 25) && (MouseY < 115) && AppearanceItem.CanStrip()) AppearanceItem.Strip(false);
if ((MouseX >= 1534) && (MouseX < 1624) && (MouseY >= 25) && (MouseY < 115) && AppearanceItem.Assets.length > CharacterAppearanceNumPerPage) {
AppearanceItemsOffset += CharacterAppearanceNumPerPage / 2;
if (AppearanceItemsOffset * 2 + 1 >= AppearanceItem.Assets.length) AppearanceItemsOffset = 0;
}
if ((MouseX >= 1768) && (MouseX < 1858) && (MouseY >= 25) && (MouseY < 115)) {
AppearanceExit();
}
if ((MouseX >= 1885) && (MouseX < 1975) && (MouseY >= 25) && (MouseY < 115)) {
AppearanceItemUndo = false;
AppearanceExit();
}
}
function AppearanceColorRun() {
if (document.getElementById("InputColor")) ElementPosition("InputColor", 1450, 65, 300);
else AppearanceMode = "";
DrawButton(1610, 37, 65, 65, "", "White", "Icons/Color.png");
DrawImage("Backgrounds/ColorPicker.png", 1300, 145);
}
function AppearanceColorClick() {
if (AppearanceItem == null) {
AppearanceMode = "";
return;
}
// Can set a color manually from the text field
if ((MouseX >= 1610) && (MouseX < 1675) && (MouseY >= 37) && (MouseY < 102))
if (CommonIsColor(ElementValue("InputColor")))
AppearanceItem.SetColor(ElementValue("InputColor").toLowerCase());
// In color picker mode, we can pick a color from the color image
if ((MouseX >= 1300) && (MouseX < 1975) && (MouseY >= 145) && (MouseY < 975)) {
const Color = DrawRGBToHex(MainCanvas.getImageData(MouseX, MouseY, 1, 1).data);
AppearanceItem.SetColor(Color);
ElementValue("InputColor", Color);
}
if ((MouseX >= 1768) && (MouseX < 1858) && (MouseY >= 25) && (MouseY < 115)) {
AppearanceExit();
}
if ((MouseX >= 1885) && (MouseX < 1975) && (MouseY >= 25) && (MouseY < 115)) {
AppearanceColorUndo = false;
AppearanceExit();
}
if (AppearanceMode != "Color") ElementRemove("InputColor");
}
function AppearanceWardrobeRun() {
const C = CharacterAppearanceSelection;
// Draw the wardrobe top controls & buttons
if (!AppearanceWardrobeShouldUndo) DrawButton(1300, 25, 90, 90, "", "White", "Icons/Magic.png", TextGet("Undo"));
DrawButton(1417, 25, 90, 90, "", "White", "Icons/Dress.png", TextGet("DressManually"));
DrawButton(1534, 25, 90, 90, "", "White", "Icons/Naked.png", TextGet("Naked"));
DrawButton(1651, 25, 90, 90, "", "White", "Icons/Next.png", TextGet("Next"));
DrawText(CharacterAppearanceWardrobeText, 1645, 220, "White", "Gray");
if (document.getElementById("InputWardrobeName")) ElementPosition("InputWardrobeName", 1645, 315, 690);
else AppearanceMode = "";
// Draw 6 wardrobe options
for (let W = AppearanceWardrobeOffset; W < Player.Wardrobe.length && W < AppearanceWardrobeOffset + 6; W++) {
DrawButton(1300, 430 + (W - AppearanceWardrobeOffset) * 95, 500, 65, "", "White", "");
DrawTextFit((W + 1).toString() + (W < 9 ? ": " : ": ") + Player.WardrobeCharacterNames[W], 1550, 463 + (W - AppearanceWardrobeOffset) * 95, 496, "Black");
DrawButton(1820, 430 + (W - AppearanceWardrobeOffset) * 95, 160, 65, "Save", "White", "");
}
}
function AppearanceWardrobeClick() {
const C = CharacterAppearanceSelection;
if ((MouseX >= 1651) && (MouseX < 1741) && (MouseY >= 25) && (MouseY < 115)) {
AppearanceWardrobeOffset += 6;
if (AppearanceWardrobeOffset >= Player.Wardrobe.length) AppearanceWardrobeOffset = 0;
}
if ((MouseX >= 1300) && (MouseX < 1800) && (MouseY >= 430) && (MouseY < 970))
for (let W = AppearanceWardrobeOffset; W < Player.Wardrobe.length && W < AppearanceWardrobeOffset + 6; W++)
if ((MouseY >= 430 + (W - AppearanceWardrobeOffset) * 95) && (MouseY <= 495 + (W - AppearanceWardrobeOffset) * 95)) {
if (AppearanceWardrobeShouldUndo) {
const Undo = AppearanceTempWardrobe[AppearanceTempWardrobe.length] = WardrobeSaveData(C);
AppearanceUndo.push(() => {
WardrobeLoadData(C, Undo);
AppearanceTempWardrobe.pop();
});
AppearanceWardrobeShouldUndo = false;
}
WardrobeFastLoad(C, W, false);
}
if ((MouseX >= 1820) && (MouseX < 1975) && (MouseY >= 430) && (MouseY < 970))
for (let W = AppearanceWardrobeOffset; W < Player.Wardrobe.length && W < AppearanceWardrobeOffset + 6; W++)
if ((MouseY >= 430 + (W - AppearanceWardrobeOffset) * 95) && (MouseY <= 495 + (W - AppearanceWardrobeOffset) * 95)) {
WardrobeFastSave(C, W);
const LS = /^[a-zA-Z ]+$/;
const Name = ElementValue("InputWardrobeName").trim();
if (Name.match(LS) || Name.length == 0) {
WardrobeSetCharacterName(W, Name);
CharacterAppearanceWardrobeText = TextGet("WardrobeNameInfo");
}
else {
CharacterAppearanceWardrobeText = TextGet("WardrobeNameError");
}
}
if ((MouseX >= 1300) && (MouseX < 1390) && (MouseY >= 25) && (MouseY < 115) && !AppearanceWardrobeShouldUndo) {
AppearanceRunUndo();
AppearanceWardrobeShouldUndo = true;
}
if ((MouseX >= 1417) && (MouseX < 1507) && (MouseY >= 25) && (MouseY < 115)) {
AppearanceMode = "";
ElementRemove("InputWardrobeName");
}
if ((MouseX >= 1534) && (MouseX < 1624) && (MouseY >= 25) && (MouseY < 115)) CharacterAppearanceNaked(C);
if ((MouseX >= 1768) && (MouseX < 1858) && (MouseY >= 25) && (MouseY < 115)) CharacterAppearanceExit(C);
if ((MouseX >= 1885) && (MouseX < 1975) && (MouseY >= 25) && (MouseY < 115)) CharacterAppearanceReady(C);
}
let ChatCreateMode = "";
let ChatCreateName = "";
let ChatCreateDescription = "";
let ChatCreateSize = "";
let ChatCreateOffset = 0;
// When the chat creation screens loads
function ChatCreateLoad() {
// If the current background isn't valid, we pick the first one
if (ChatCreateBackgroundList.indexOf(ChatCreateBackgroundSelect) < 0) {
ChatCreateBackgroundIndex = 0;
ChatCreateBackgroundSelect = ChatCreateBackgroundList[0];
ChatCreateBackground = ChatCreateBackgroundSelect + "Dark";
}
// Prepares the controls to create a room
ElementRemove("InputSearch");
ElementCreateInput("InputName", "text", "", "20");
ElementCreateInput("InputDescription", "text", "", "100");
ElementCreateInput("InputSize", "text", "10", "2");
ChatCreateMessage = "";
ChatCreatePrivate = false;
ChatCreateMode = "";
ChatCreateOffset = 0;
}
// When the chat creation screen runs
ChatCreateRun = function ChatCreateRun() {
if (ChatCreateMode == "") {
// Draw the controls
if (ChatCreateMessage == "") ChatCreateMessage = "EnterRoomInfo";
DrawText(TextGet(ChatCreateMessage), 1000, 60, "White", "Gray");
DrawText(TextGet("RoomName"), 1000, 150, "White", "Gray");
ElementPosition("InputName", 1000, 200, 500);
DrawText(TextGet("RoomDescription"), 1000, 300, "White", "Gray");
ElementPosition("InputDescription", 1000, 350, 1500);
DrawText(TextGet("RoomPrivate"), 970, 460, "White", "Gray");
DrawButton(1300, 428, 64, 64, "", "White", ChatCreatePrivate ? "Icons/Checked.png" : "");
DrawText(TextGet("RoomSize"), 930, 568, "White", "Gray");
ElementPosition("InputSize", 1400, 560, 150);
DrawText(TextGet("RoomBackground"), 650, 672, "White", "Gray");
DrawButton(1300, 640, 300, 65, "Show All", "White");
DrawBackNextButton(900, 640, 350, 65, TextGet(ChatCreateBackgroundSelect), "White", null,
() => TextGet((ChatCreateBackgroundIndex == 0) ? ChatCreateBackgroundList[ChatCreateBackgroundList.length - 1] : ChatCreateBackgroundList[ChatCreateBackgroundIndex - 1]),
() => TextGet((ChatCreateBackgroundIndex >= ChatCreateBackgroundList.length - 1) ? ChatCreateBackgroundList[0] : ChatCreateBackgroundList[ChatCreateBackgroundIndex + 1]));
DrawButton(600, 800, 300, 65, TextGet("Create"), "White");
DrawButton(1100, 800, 300, 65, TextGet("Cancel"), "White");
}
else if (ChatCreateMode == "ShowGrid") {
DrawButton(1885, 25, 90, 90, "", "White", "Icons/Exit.png");
DrawButton(1785, 25, 90, 90, "", "White", "Icons/Next.png");
let X = 45;
let Y = 170;
for (var i = 0;
(i + ChatCreateOffset) < ChatCreateBackgroundList.length && i < 12; ++i) {
DrawButton(X, Y, 450, 225, "", "White", "Backgrounds/" + ChatCreateBackgroundList[i + ChatCreateOffset] + ".jpg");
X += 450 + 35;
if (i % 4 == 3) {
X = 45;
Y += 225 + 35;
}
}
}
}
// When the player clicks in the chat creation screen
ChatCreateClick = function ChatCreateClick() {
if (ChatCreateMode == "") {
// When the private box is checked
if ((MouseX >= 1300) && (MouseX < 1364) && (MouseY >= 428) && (MouseY < 492)) ChatCreatePrivate = !ChatCreatePrivate;
// When we select a new background
if ((MouseX >= 900) && (MouseX < 1250) && (MouseY >= 640) && (MouseY < 705)) {
ChatCreateBackgroundIndex += MouseX < 1075 ? -1 : 1;
if (ChatCreateBackgroundIndex >= ChatCreateBackgroundList.length) ChatCreateBackgroundIndex = 0;
if (ChatCreateBackgroundIndex < 0) ChatCreateBackgroundIndex = ChatCreateBackgroundList.length - 1;
ChatCreateBackgroundSelect = ChatCreateBackgroundList[ChatCreateBackgroundIndex];
ChatCreateBackground = ChatCreateBackgroundSelect + "Dark";
}
// Show backgrounds in grid
if ((MouseX >= 1300) && (MouseX < 1600) && (MouseY >= 640) && (MouseY < 705)) {
ChatCreateMode = "ShowGrid";
ChatCreateName = ElementValue("InputName");
ChatCreateDescription = ElementValue("InputDescription");
ChatCreateSize = ElementValue("InputSize");
ElementRemove("InputName");
ElementRemove("InputDescription");
ElementRemove("InputSize");
}
// If the user wants to create a room
if ((MouseX >= 600) && (MouseX < 900) && (MouseY >= 800) && (MouseY < 865)) {
ChatCreateRoom();
}
// When the user cancels
if ((MouseX >= 1100) && (MouseX < 1400) && (MouseY >= 800) && (MouseY < 865)) {
ChatCreateExit();
}
}
else if (ChatCreateMode == "ShowGrid") {
if ((MouseX >= 1885) && (MouseX < 1975) && (MouseY >= 25) && (MouseY < 115)) {
ChatCreateExit();
}
if ((MouseX >= 1785) && (MouseX < 1875) && (MouseY >= 25) && (MouseY < 115)) {
ChatCreateOffset += 12;
if (ChatCreateOffset >= ChatCreateBackgroundList.length) ChatCreateOffset = 0;
}
let X = 45;
let Y = 170;
for (var i = 0;
(i + ChatCreateOffset) < ChatCreateBackgroundList.length && i < 12; ++i) {
if ((MouseX >= X) && (MouseX < X + 450) && (MouseY >= Y) && (MouseY < Y + 225)) {
ChatCreateBackgroundIndex = i + ChatCreateOffset;
if (ChatCreateBackgroundIndex >= ChatCreateBackgroundList.length) ChatCreateBackgroundIndex = 0;
if (ChatCreateBackgroundIndex < 0) ChatCreateBackgroundIndex = ChatCreateBackgroundList.length - 1;
ChatCreateBackgroundSelect = ChatCreateBackgroundList[ChatCreateBackgroundIndex];
ChatCreateBackground = ChatCreateBackgroundSelect + "Dark";
}
X += 450 + 35;
if (i % 4 == 3) {
X = 45;
Y += 225 + 35;
}
}
}
}
// When the user press "enter", we create the room
ChatCreateKeyDown = function ChatCreateKeyDown() {
if (KeyPress == 13 && ChatCreateMode == "") ChatCreateRoom();
if (KeyPress == 13 && ChatCreateMode == "ShowGrid") ChatCreateExit();
}
// When the user exit from this screen
ChatCreateExit = function ChatCreateExit() {
if (ChatCreateMode == "") {
ElementRemove("InputName");
ElementRemove("InputDescription");
ElementRemove("InputSize");
CommonSetScreen("Online", "ChatSearch");
}
else if (ChatCreateMode == "ShowGrid") {
ChatCreateMode = "";
ElementCreateInput("InputName", "text", ChatCreateName, "20");
ElementCreateInput("InputDescription", "text", ChatCreateDescription, "100");
ElementCreateInput("InputSize", "text", ChatCreateSize, "2");
}
}
// When the server sends a response
ChatCreateResponse = function ChatCreateResponse(data) {
if ((data != null) && (typeof data === "string") && (data != ""))
ChatCreateMessage = "Response" + data;
}
// Creates the chat room
ChatCreateRoom = function ChatCreateRoom() {
ChatRoomPlayerCanJoin = true;
var NewRoom = {
Name: ElementValue("InputName").trim(),
Description: ElementValue("InputDescription").trim(),
Background: ChatCreateBackgroundSelect,
Private: ChatCreatePrivate,
Space: ChatRoomSpace,
Limit: ElementValue("InputSize").trim()
};
ServerSend("ChatRoomCreate", NewRoom);
ChatCreateMessage = "CreatingRoom";
}
let ChatAdminMode = "";
let ChatAdminOffset = 0;
// When the chat admin screens loads
ChatAdminLoad = function ChatAdminLoad(BackgroundIsSet) {
if (BackgroundIsSet != true) {
// If the current room background isn't valid, we pick the first one
ChatAdminBackgroundSelect = ChatRoomData.Background;
if (ChatCreateBackgroundList.indexOf(ChatAdminBackgroundSelect) < 0) {
ChatAdminBackgroundIndex = 0;
ChatAdminBackgroundSelect = ChatCreateBackgroundList[0];
}
else ChatAdminBackgroundIndex = ChatCreateBackgroundList.indexOf(ChatAdminBackgroundSelect);
}
// Prepares the controls to edit a room
ElementCreateInput("InputName", "text", ChatRoomData.Name, "20");
document.getElementById("InputName").setAttribute("autocomplete", "off");
ElementCreateInput("InputSize", "text", ChatRoomData.Limit.toString(), "2");
document.getElementById("InputSize").setAttribute("autocomplete", "off");
ElementCreateTextArea("InputDescription");
document.getElementById("InputDescription").setAttribute("maxLength", 100);
document.getElementById("InputDescription").setAttribute("autocomplete", "off");
ElementValue("InputDescription", ChatRoomData.Description);
ElementCreateTextArea("InputAdminList");
document.getElementById("InputAdminList").setAttribute("maxLength", 250);
document.getElementById("InputAdminList").setAttribute("autocomplete", "off");
ElementValue("InputAdminList", CommonConvertArrayToString(ChatRoomData.Admin));
ElementCreateTextArea("InputBanList");
document.getElementById("InputBanList").setAttribute("maxLength", 250);
document.getElementById("InputBanList").setAttribute("autocomplete", "off");
ElementValue("InputBanList", CommonConvertArrayToString(ChatRoomData.Ban));
ChatAdminPrivate = ChatRoomData.Private;
ChatAdminLocked = ChatRoomData.Locked;
// If the player isn't an admin, we disable the inputs
if (!ChatRoomPlayerIsAdmin()) {
document.getElementById("InputName").setAttribute("disabled", "disabled");
document.getElementById("InputDescription").setAttribute("disabled", "disabled");
document.getElementById("InputAdminList").setAttribute("disabled", "disabled");
document.getElementById("InputBanList").setAttribute("disabled", "disabled");
document.getElementById("InputSize").setAttribute("disabled", "disabled");
ChatAdminMessage = "AdminOnly";
}
else ChatAdminMessage = "UseMemberNumbers";
}
// When the chat Admin screen runs
ChatAdminRun = function ChatAdminRun() {
if (ChatAdminMode == "") {
// Draw the main controls
DrawText(TextGet(ChatAdminMessage), 650, 870, "Black", "Gray");
DrawText(TextGet("RoomName"), 535, 110, "Black", "Gray");
ElementPosition("InputName", 535, 170, 820);
DrawText(TextGet("RoomSize"), 1100, 110, "Black", "Gray");
ElementPosition("InputSize", 1100, 170, 250);
DrawText(TextGet("RoomDescription"), 675, 265, "Black", "Gray");
ElementPosition("InputDescription", 675, 380, 1100, 160);
DrawText(TextGet("RoomAdminList"), 390, 530, "Black", "Gray");
ElementPosition("InputAdminList", 390, 680, 530, 230);
DrawText(TextGet("RoomBanList"), 960, 530, "Black", "Gray");
ElementPosition("InputBanList", 960, 680, 530, 230);
// Background selection
DrawImageResize("Backgrounds/" + ChatAdminBackgroundSelect + "Dark.jpg", 1300, 75, 600, 400);
DrawBackNextButton(1350, 500, 500, 65, ChatAdminBackgroundSelect, ChatRoomPlayerIsAdmin() ? "White" : "#ebebe4", null,
() => (ChatAdminBackgroundIndex == 0) ? ChatCreateBackgroundList[ChatCreateBackgroundList.length - 1] : ChatCreateBackgroundList[ChatAdminBackgroundIndex - 1],
() => (ChatAdminBackgroundIndex >= ChatCreateBackgroundList.length - 1) ? ChatCreateBackgroundList[0] : ChatCreateBackgroundList[ChatAdminBackgroundIndex + 1]);
// Private and Locked check boxes
DrawText(TextGet("RoomPrivate"), 1514, 640, "Black", "Gray");
DrawButton(1686, 608, 64, 64, "", ChatRoomPlayerIsAdmin() ? "White" : "#ebebe4", ChatAdminPrivate ? "Icons/Checked.png" : "");
DrawText(TextGet("RoomLocked"), 1514, 740, "Black", "Gray");
DrawButton(1686, 708, 64, 64, "", ChatRoomPlayerIsAdmin() ? "White" : "#ebebe4", ChatAdminLocked ? "Icons/Checked.png" : "");
// Save & Cancel/Exit buttons + help text
DrawButton(1325, 840, 250, 65, TextGet("Save"), ChatRoomPlayerIsAdmin() ? "White" : "#ebebe4");
DrawButton(1625, 840, 250, 65, TextGet(ChatRoomPlayerIsAdmin() ? "Cancel" : "Exit"), "White");
}
else if (ChatAdminMode == "ShowGrid") {
DrawButton(1885, 25, 90, 90, "", "White", "Icons/Exit.png");
DrawButton(1785, 25, 90, 90, "", "White", "Icons/Next.png");
let X = 45;
let Y = 170;
for (var i = 0;
(i + ChatAdminOffset) < ChatCreateBackgroundList.length && i < 12; ++i) {
DrawButton(X, Y, 450, 225, "", "White", "Backgrounds/" + ChatCreateBackgroundList[i + ChatAdminOffset] + ".jpg");
X += 450 + 35;
if (i % 4 == 3) {
X = 45;
Y += 225 + 35;
}
}
}
}
// When the player clicks in the chat Admin screen
ChatAdminClick = function ChatAdminClick() {
// When the user cancels/exits
if ((MouseX >= 1625) && (MouseX < 1875) && (MouseY >= 840) && (MouseY < 905)) ChatAdminExit();
// All other controls are for administrators only
if (ChatRoomPlayerIsAdmin()) {
if (ChatAdminMode == "") {
// When we select a new background
if ((MouseX >= 1350) && (MouseX <= 1850) && (MouseY >= 500) && (MouseY <= 565)) {
ChatAdminBackgroundIndex += ((MouseX < 1600) ? -1 : 1);
if (ChatAdminBackgroundIndex >= ChatCreateBackgroundList.length) ChatAdminBackgroundIndex = 0;
if (ChatAdminBackgroundIndex < 0) ChatAdminBackgroundIndex = ChatCreateBackgroundList.length - 1;
ChatAdminBackgroundSelect = ChatCreateBackgroundList[ChatAdminBackgroundIndex];
}
// Private & Locked check boxes + save button
if ((MouseX >= 1686) && (MouseX <= 1750) && (MouseY >= 608) && (MouseY <= 672)) ChatAdminPrivate = !ChatAdminPrivate;
if ((MouseX >= 1686) && (MouseX <= 1750) && (MouseY >= 708) && (MouseY <= 772)) ChatAdminLocked = !ChatAdminLocked;
if ((MouseX >= 1325) && (MouseX < 1575) && (MouseY >= 840) && (MouseY < 905) && ChatRoomPlayerIsAdmin()) ChatAdminUpdateRoom();
if ((MouseX >= 1300) && (MouseX <= 1300 + 600) && (MouseY >= 75) && (MouseY <= 75 + 400)) {
ChatAdminMode = "ShowGrid";
ElementRemove("InputName");
ElementRemove("InputDescription");
ElementRemove("InputSize");
ElementRemove("InputAdminList");
ElementRemove("InputBanList");
}
}
else if (ChatAdminMode == "ShowGrid") {
if ((MouseX >= 1885) && (MouseX < 1975) && (MouseY >= 25) && (MouseY < 115)) {
ChatAdminMode = "";
ChatAdminLoad(true);
}
if ((MouseX >= 1785) && (MouseX < 1875) && (MouseY >= 25) && (MouseY < 115)) {
ChatAdminOffset += 12;
if (ChatAdminOffset >= ChatCreateBackgroundList.length) ChatAdminOffset = 0;
}
let X = 45;
let Y = 170;
for (var i = 0;
(i + ChatAdminOffset) < ChatCreateBackgroundList.length && i < 12; ++i) {
if ((MouseX >= X) && (MouseX < X + 450) && (MouseY >= Y) && (MouseY < Y + 225)) {
ChatAdminBackgroundIndex = i + ChatAdminOffset;
if (ChatAdminBackgroundIndex >= ChatCreateBackgroundList.length) ChatAdminBackgroundIndex = 0;
if (ChatAdminBackgroundIndex < 0) ChatAdminBackgroundIndex = ChatCreateBackgroundList.length - 1;
ChatAdminBackgroundSelect = ChatCreateBackgroundList[ChatAdminBackgroundIndex];
ChatAdminMode = "";
ChatAdminLoad(true);
}
X += 450 + 35;
if (i % 4 == 3) {
X = 45;
Y += 225 + 35;
}
}
}
}
}
// When the user exit from this screen
ChatAdminExit = function ChatAdminExit() {
ElementRemove("InputName");
ElementRemove("InputDescription");
ElementRemove("InputSize");
ElementRemove("InputAdminList");
ElementRemove("InputBanList");
CommonSetScreen("Online", "ChatRoom");
}
// When the server sends a response, if it was updated properly we exit, if not we show the error
ChatAdminResponse = function ChatAdminResponse(data) {
if ((data != null) && (typeof data === "string") && (data != ""))
if (data === "Updated") ChatAdminExit();
else ChatAdminMessage = "Response" + data;
}
// Sends the chat room update packet to the server and waits for the answer
ChatAdminUpdateRoom = function ChatAdminUpdateRoom() {
var UpdatedRoom = {
Name: ElementValue("InputName").trim(),
Description: ElementValue("InputDescription").trim(),
Background: ChatAdminBackgroundSelect,
Limit: ElementValue("InputSize").trim(),
Admin: ChatAdminToNumbers(ElementValue("InputAdminList").trim()),
Ban: ChatAdminToNumbers(ElementValue("InputBanList").trim()).filter(n => n != Player.MemberNumber && n != 65),
Private: ChatAdminPrivate,
Locked: ChatAdminLocked
};
if (!UpdatedRoom.Admin.includes(Player.MemberNumber)) UpdatedRoom.Admin.push(Player.MemberNumber);
ServerSend("ChatRoomAdmin", {
MemberNumber: Player.ID,
Room: UpdatedRoom,
Action: "Update"
});
ChatAdminMessage = "UpdatingRoom";
}
function ChatAdminToNumbers(str) {
str = str.trim();
return (str == "") ? [] : [...new Set(str.split(",").map(Number).filter(isFinite).filter(n => n >= 0))];
}
ServerAccountBeep = function ServerAccountBeep(data) {
if ((data != null) && (typeof data === "object") && !Array.isArray(data) && (data.MemberNumber != null) && (typeof data.MemberNumber === "number") && (data.MemberName != null) && (typeof data.MemberName === "string")) {
const AllowLesh = Player.AllowLeash == true && Player.OwnerNumber != null;
if (AllowLesh && Player.SendBeepToOwner && Player.CurrentChatRoom != null && data.MemberNumber != Player.OwnerNumber && ChatRoomData.Character.some(c => c.MemberNumber == Player.OwnerNumber)) {
let msg = DialogFind(Player, "BeepFrom") + " " + data.MemberName + " (" + data.MemberNumber.toString() + ")";
if (data.ChatRoomName != null) msg = msg + " " + DialogFind(Player, "InRoom") + " \"" + data.ChatRoomName + "\"";
ServerSend("ChatRoomChat", {
Content: msg,
Type: "Whisper",
Target: Player.OwnerNumber
});
return;
}
if (AllowLesh && ServerBeep.Timer >= CurrentTime && data.MemberNumber != Player.OwnerNumber) return;
ServerBeep.MemberNumber = data.MemberNumber;
ServerBeep.MemberName = data.MemberName;
ServerBeep.ChatRoomName = data.ChatRoomName;
if (AllowLesh && ServerBeep.MemberNumber == Player.OwnerNumber) {
if (ServerBeep.Timer >= CurrentTime) {
if (Player.CurrentChatRoom != null && ServerBeep.ChatRoomName != null && Player.CurrentChatRoom != ServerBeep.ChatRoomName) {
ChatRoomLeave();
}
else if (Player.CurrentChatRoom == null && ServerBeep.ChatRoomName != null) {
ChatRoomJoin(ServerBeep.ChatRoomName);
}
else {
ServerBeep.Timer = CurrentTime;
return;
}
}
ServerBeep.Timer = CurrentTime + 30000;
}
else {
ServerBeep.Timer = CurrentTime + 10000;
}
ServerBeep.Message = DialogFind(Player, "BeepFrom") + " " + ServerBeep.MemberName + " (" + ServerBeep.MemberNumber.toString() + ")";
if (ServerBeep.ChatRoomName != null)
ServerBeep.Message = ServerBeep.Message + " " + DialogFind(Player, "InRoom") + " \"" + ServerBeep.ChatRoomName + "\"";
FriendListBeepLog.push({
MemberNumber: data.MemberNumber,
MemberName: data.MemberName,
ChatRoomName: data.ChatRoomName,
Sent: false,
Time: new Date()
});
if (CurrentScreen == "FriendList") ServerSend("AccountQuery", {
Query: "OnlineFriends"
});
if (window.location.protocol.includes("https") && Notification) {
if (Notification.permission !== "granted") {
Notification.requestPermission();
}
else {
let n = new Notification("Bondage Club Beep", {
body: ServerBeep.Message
});
n.onclick = function (x) {
window.focus();
this.close();
};
}
}
if (ServerBeepAudio && Player.AudioSettings && Player.AudioSettings.PlayBeeps) {
if (typeof Player.AudioSettings.Volume === 'number') ServerBeepAudio.volume = Player.AudioSettings.Volume;
ServerBeepAudio.play();
}
}
}
// Bundle an asset in wardrobe format
WardrobeAssetBundle = function WardrobeAssetBundle(A) {
return {
Name: A.Asset.Name,
Group: A.Asset.Group.Name,
Color: A.Color,
Alpha: A.Alpha
};
}
// Load character appearance from wardrobe, only load clothes on others
WardrobeFastLoad = function WardrobeFastLoad(C, W, Update) {
if (Player.Wardrobe != null && Player.Wardrobe[W] != null) {
let AddAll = C.ID == 0 || C.AccountName.indexOf("Wardrobe-") == 0;
C.Appearance = C.Appearance
.filter(a => a.Asset.Group.Category != "Appearance" || (!a.Asset.Group.Clothing && !AddAll))
Player.Wardrobe[W]
.filter(w => w.Name != null && w.Group != null)
.filter(w => C.Appearance.find(a => a.Asset.Group.Name == w.Group) == null)
.forEach(w => {
let A = Asset.find(a =>
a.Group.Name == w.Group &&
a.Group.Category == "Appearance" &&
(AddAll || a.Group.Clothing) &&
a.Name == w.Name &&
(a.Value == 0 || InventoryAvailable(Player, a.Name, a.Group.Name)));
if (A != null) CharacterAppearanceSetItem(C, w.Group, A, w.Color, 0, false);
});
// Adds any critical appearance asset that could be missing, adds the default one
AssetGroup
.filter(g => g.Category == "Appearance" && !g.AllowNone)
.forEach(g => {
if (C.Appearance.find(a => a.Asset.Group.Name == g.Name) == null) {
C.Appearance.push({
Asset: Asset.find(a => a.Group.Name == g.Name),
Difficulty: 0,
Color: g.ColorSchema[0]
});
}
});
CharacterLoadCanvas(C);
if (Update == null || Update) {
if (C.ID == 0 && C.OnlineID != null) ServerPlayerAppearanceSync();
if (C.ID == 0 || C.AccountName.indexOf("Online-") == 0) ChatRoomCharacterUpdate(C);
}
}
}
// Saves character appearance in Player's wardrobe, use Player's body as base for others
WardrobeFastSave = function WardrobeFastSave(C, W, Push) {
if (Player.Wardrobe != null) {
let AddAll = C.ID == 0 || C.AccountName.indexOf("Wardrobe-") == 0;
Player.Wardrobe[W] = C.Appearance
.filter(a => a.Asset.Group.Category == "Appearance")
.filter(a => AddAll || a.Asset.Group.Clothing)
.map(WardrobeAssetBundle);
if (!AddAll) {
// Using Player's body as base
Player.Wardrobe[W] = Player.Wardrobe[W].concat(Player.Appearance
.filter(a => a.Asset.Group.Category == "Appearance")
.filter(a => !a.Asset.Group.Clothing)
.map(WardrobeAssetBundle));
}
let WC = W - WardrobeOffset;
if (WC >= 0 && WC < 12 && WardrobeCharacter != null && WardrobeCharacter[WC] != null && C.AccountName != WardrobeCharacter[WC].AccountName) {
WardrobeFastLoad(WardrobeCharacter[WC], W);
}
if (Push == null || Push) ServerSend("AccountUpdate", {
Wardrobe: Player.Wardrobe
});
}
}
function WardrobeLoadData(C, Data, LoadAll, AllInventory) {
const AddAll = LoadAll || C.ID == 0 || C.AccountName.indexOf("Wardrobe-") == 0;
C.Appearance = C.Appearance
.filter(a => a.Asset.Group.Category != "Appearance" || (!a.Asset.Group.Clothing && !AddAll))
Data
.filter(w => w.Name != null && w.Group != null)
.filter(w => C.Appearance.find(a => a.Asset.Group.Name == w.Group) == null)
.forEach(w => {
let A = Asset.find(a =>
a.Group.Name == w.Group &&
a.Group.Category == "Appearance" &&
(AddAll || a.Group.Clothing) &&
a.Name == w.Name &&
(AllInventory == true || a.Value == 0 || InventoryAvailable(Player, a.Name, a.Group.Name)));
if (A != null) CharacterAppearanceSetItem(C, w.Group, A, w.Color, 0, false);
});
// Adds any critical appearance asset that could be missing, adds the default one
AssetGroup
.filter(g => g.Category == "Appearance" && !g.AllowNone && !C.Appearance.some(a => a.Asset.Group.Name == g.Name))
.forEach(g => C.Appearance.push({
Asset: Asset.find(a => a.Group.Name == g.Name),
Difficulty: 0,
Color: g.ColorSchema[0]
}));
CharacterLoadCanvas(C);
if (C.ID == 0 && C.OnlineID != null) ServerPlayerAppearanceSync();
if (C.ID == 0 || C.AccountName.indexOf("Online-") == 0) ChatRoomCharacterUpdate(C);
}
function WardrobeSaveData(C, SaveAll) {
const AddAll = SaveAll == true || C.ID == 0 || C.AccountName.indexOf("Wardrobe-") == 0;
let Data = C.Appearance
.filter(a => a.Asset.Group.Category == "Appearance")
.filter(a => AddAll || a.Asset.Group.Clothing)
.map(WardrobeAssetBundle);
if (!AddAll) {
// Using Player's body as base
Data = Data.concat(Player.Appearance
.filter(a => a.Asset.Group.Category == "Appearance")
.filter(a => !a.Asset.Group.Clothing)
.map(WardrobeAssetBundle));
}
return Data;
}
function GetGUID(C) {
return md5("NServerId: " + C.MemberNumber.toString() + ":" + ((C.ID == 0) ? Player.OnlineID : C.AccountName.replace("Online-", "")));
}
function PlayerLoadGUID() {
Player.Appearance.forEach(a => {
if (a.Asset.Group.Name == "Eyes") {
if (a.Property == null) {
a.Property = {
GUID: GetGUID(Player)
};
}
else {
a.Property.GUID = GetGUID(Player);
}
}
});
}
function ChatRoomSelfUpdate() {
//if (Player.ProtectClothes != false || LogQuery("BlockChange", "Rule")) WardrobeFastSave(Player, 11);
PlayerLoadGUID();
}
function IsCharacterOnNServer(C) {
if (C.OnNServer == null) {
let G = GetGUID(C);
let Eyes = InventoryGet(C, "Eyes");
let P = Eyes && Eyes.Property && Eyes.Property.GUID;
C.OnNServer = (G == P);
}
return C.OnNServer;
}
function GetCookie(cname) {
let name = cname + "=";
let decodedCookie = decodeURIComponent(document.cookie);
let ca = decodedCookie.split(';');
for (let i = 0; i < ca.length; i++) {
let c = ca[i];
while (c.charAt(0) == ' ') {
c = c.substring(1);
}
if (c.indexOf(name) == 0) {
return c.substring(name.length, c.length);
}
}
return "";
}
function SetCookie(cname, cvalue, exhours) {
let d = new Date();
d.setTime(d.getTime() + (exhours * 60 * 60 * 1000));
let expires = "expires=" + d.toUTCString();
document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/";
}
// Chat room keyboard shortcuts
ChatRoomKeyDown = function ChatRoomKeyDown() {
// The ENTER key sends the chat
if (KeyPress == 13) {
event.preventDefault();
ChatRoomSendChat();
}
// On page up, we show the previous chat typed
if (KeyPress == 33) {
if (ChatRoomLastMessage.length > 0) {
var msg = ElementValue("InputChat").trim();
if (ChatRoomLastMessageIndex == ChatRoomLastMessage.length || (msg != "" && ChatRoomLastMessage[ChatRoomLastMessageIndex] != msg)) {
ChatRoomLastMessage.push(msg);
}
ChatRoomLastMessageIndex--;
}
ElementValue("InputChat", ChatRoomLastMessage[ChatRoomLastMessageIndex]);
}
// On page down, we show the next chat typed
if (KeyPress == 34) {
if (ChatRoomLastMessage.length > 0) {
var msg = ElementValue("InputChat").trim();
if (ChatRoomLastMessageIndex == ChatRoomLastMessage.length || (msg != "" && ChatRoomLastMessage[ChatRoomLastMessageIndex] != msg)) {
ChatRoomLastMessage.push(msg);
}
}
ChatRoomLastMessageIndex++;
if (ChatRoomLastMessageIndex > ChatRoomLastMessage.length - 1) ChatRoomLastMessageIndex = ChatRoomLastMessage.length - 1;
ElementValue("InputChat", ChatRoomLastMessage[ChatRoomLastMessageIndex]);
}
}
// Pushes the new character data/appearance to the server
ChatRoomCharacterUpdate = function ChatRoomCharacterUpdate(C) {
if (C.ID == 0) ChatRoomSelfUpdate();
var data = {
ID: (C.ID == 0) ? Player.OnlineID : C.AccountName.replace("Online-", ""),
ActivePose: C.ActivePose,
Appearance: ServerAppearanceBundle(C.Appearance)
};
ServerSend("ChatRoomCharacterUpdate", data);
}
})();