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); } })();