diff --git a/BondageClub/Screens/Character/FriendList/FriendList.js b/BondageClub/Screens/Character/FriendList/FriendList.js index a4db0c57dd..655bc8c0b5 100644 --- a/BondageClub/Screens/Character/FriendList/FriendList.js +++ b/BondageClub/Screens/Character/FriendList/FriendList.js @@ -732,7 +732,7 @@ function FriendListLoadFriendList(data) { } else if (Player.SubmissivesList.has(memberNumber)) { Type = "Submissive"; } - const canDelete = Type === "Friend" && Player.FriendList.includes(memberNumber) || Type === "Submissive" && Player.SubmissivesList.has(memberNumber); + const canDelete = Type === "Friend" && Player.HasOnFriendlist(memberNumber) || Type === "Submissive" && Player.SubmissivesList.has(memberNumber); friendRawData.push({ memberName: memberName, @@ -946,7 +946,7 @@ function FriendListLoadFriendList(data) { function FriendListDelete(MemberNumber) { if (FriendListConfirmDelete.includes(MemberNumber)) { FriendListConfirmDelete.splice(FriendListConfirmDelete.indexOf(MemberNumber), 1); - if (Player.FriendList.includes(MemberNumber)) { + if (Player.HasOnFriendlist(MemberNumber)) { Player.FriendList.splice(Player.FriendList.indexOf(MemberNumber), 1); } Player.SubmissivesList.delete(MemberNumber); diff --git a/BondageClub/Screens/Online/ChatRoom/ChatRoom.js b/BondageClub/Screens/Online/ChatRoom/ChatRoom.js index 0dcc1fd096..93b5b7993b 100644 --- a/BondageClub/Screens/Online/ChatRoom/ChatRoom.js +++ b/BondageClub/Screens/Online/ChatRoom/ChatRoom.js @@ -362,42 +362,42 @@ function ChatRoomIsViewActive(viewName) * Checks if the player can add the current character to her whitelist. * @returns {boolean} - TRUE if the current character is not in the player's whitelist nor blacklist. */ -function ChatRoomCanAddWhiteList() { return ((CurrentCharacter != null) && (CurrentCharacter.MemberNumber != null) && (Player.WhiteList.indexOf(CurrentCharacter.MemberNumber) < 0) && (Player.BlackList.indexOf(CurrentCharacter.MemberNumber) < 0)); } +function ChatRoomCanAddWhiteList() { return CurrentCharacter && !CurrentCharacter.IsWhitelisted() && !CurrentCharacter.IsBlacklisted(); } /** * Checks if the player can add the current character to her blacklist. * @returns {boolean} - TRUE if the current character is not in the player's whitelist nor blacklist. */ -function ChatRoomCanAddBlackList() { return ((CurrentCharacter != null) && (CurrentCharacter.MemberNumber != null) && (Player.WhiteList.indexOf(CurrentCharacter.MemberNumber) < 0) && (Player.BlackList.indexOf(CurrentCharacter.MemberNumber) < 0)); } +function ChatRoomCanAddBlackList() { return CurrentCharacter && !CurrentCharacter.IsWhitelisted() && !CurrentCharacter.IsBlacklisted(); } /** * Checks if the player can remove the current character from her whitelist. * @returns {boolean} - TRUE if the current character is in the player's whitelist, but not her blacklist. */ -function ChatRoomCanRemoveWhiteList() { return ((CurrentCharacter != null) && (CurrentCharacter.MemberNumber != null) && (Player.WhiteList.indexOf(CurrentCharacter.MemberNumber) >= 0)); } +function ChatRoomCanRemoveWhiteList() { return CurrentCharacter && CurrentCharacter.IsWhitelisted(); } /** * Checks if the player can remove the current character from her blacklist. * @returns {boolean} - TRUE if the current character is in the player's blacklist, but not her whitelist. */ -function ChatRoomCanRemoveBlackList() { return ((CurrentCharacter != null) && (CurrentCharacter.MemberNumber != null) && (Player.BlackList.indexOf(CurrentCharacter.MemberNumber) >= 0)); } +function ChatRoomCanRemoveBlackList() { return CurrentCharacter && CurrentCharacter.IsBlacklisted(); } /** * Checks if the player can add the current character to her friendlist * @returns {boolean} - TRUE if the current character is not in the player's friendlist yet. */ -function ChatRoomCanAddFriend() { return ((CurrentCharacter != null) && (CurrentCharacter.MemberNumber != null) && (Player.FriendList.indexOf(CurrentCharacter.MemberNumber) < 0)); } +function ChatRoomCanAddFriend() { return CurrentCharacter && !CurrentCharacter.IsFriend(); } /** * Checks if the player can remove the current character from her friendlist. * @returns {boolean} - TRUE if the current character is in the player's friendlist. */ -function ChatRoomCanRemoveFriend() { return ((CurrentCharacter != null) && (CurrentCharacter.MemberNumber != null) && (Player.FriendList.indexOf(CurrentCharacter.MemberNumber) >= 0)); } +function ChatRoomCanRemoveFriend() { return CurrentCharacter && CurrentCharacter.IsFriend(); } /** * Checks if the player can add the current character to her ghostlist * @returns {boolean} - TRUE if the current character is not in the player's ghostlist yet. */ -function ChatRoomCanAddGhost() { return ((CurrentCharacter != null) && (CurrentCharacter.MemberNumber != null) && (Player.GhostList.indexOf(CurrentCharacter.MemberNumber) < 0)); } +function ChatRoomCanAddGhost() { return CurrentCharacter && !CurrentCharacter?.IsGhosted(); } /** * Checks if the player can remove the current character from her ghostlist. * @returns {boolean} - TRUE if the current character is in the player's ghostlist. */ -function ChatRoomCanRemoveGhost() { return ((CurrentCharacter != null) && (CurrentCharacter.MemberNumber != null) && (Player.GhostList.indexOf(CurrentCharacter.MemberNumber) >= 0)); } +function ChatRoomCanRemoveGhost() { return CurrentCharacter && CurrentCharacter.IsGhosted(); } /** * Checks if the player can change the current character's clothes * @returns {boolean} - TRUE if the player can change the character's clothes and is allowed to. @@ -1493,9 +1493,9 @@ function DrawStatus(C, X, Y, Zoom) { */ function ChatRoomDrawCharacterStatusIcons(C, CharX, CharY, Zoom) { - if (Player.WhiteList.includes(C.MemberNumber)) { + if (C.IsWhitelisted()) { DrawImageResize("Icons/Small/WhiteList.png", CharX + 70 * Zoom, CharY, 40 * Zoom, 40 * Zoom); - } else if (Player.BlackList.includes(C.MemberNumber)) { + } else if (C.IsBlacklisted()) { DrawImageResize("Icons/Small/BlackList.png", CharX + 70 * Zoom, CharY, 40 * Zoom, 40 * Zoom); } // Unobtrusive but prominent warnings to alert user they are in focus mode -- drawn on player and all focused (visible) characters @@ -1504,9 +1504,9 @@ function ChatRoomDrawCharacterStatusIcons(C, CharX, CharY, Zoom) DrawImageResize("Icons/Small/FocusEnabledWarning.png", CharX + 30 * Zoom, CharY, 40 * Zoom, 40 * Zoom); DrawImageResize("Icons/Small/FocusEnabledWarning.png", CharX + 30 * Zoom, CharY + 950 * Zoom, 40 * Zoom, 40 * Zoom); } - if (Player.GhostList.includes(C.MemberNumber)) { + if (C.IsGhosted()) { DrawImageResize("Icons/Small/GhostList.png", CharX + 110 * Zoom, CharY, 40 * Zoom, 40 * Zoom); - } else if (Player.FriendList.includes(C.MemberNumber)) { + } else if (C.IsFriend()) { DrawImageResize("Icons/Small/FriendList.png", CharX + 110 * Zoom, CharY, 40 * Zoom, 40 * Zoom); } if (C.IsBirthday()) @@ -3483,7 +3483,7 @@ var ChatRoomMessageHandlers = [ if (data.Type === "Action" && data.Content === "ServerUpdateRoom") return false; - if (Player.GhostList.indexOf(data.Sender) >= 0) + if (Player.HasOnGhostlist(data.Sender)) return true; } }, @@ -6124,7 +6124,7 @@ function ChatRoomNotificationRaiseChatJoin(C) { else if (!settings.Owner && !settings.Lovers && !settings.Friendlist && !settings.Subs) raise = true; else if (settings.Owner && Player.IsOwnedByMemberNumber(C.MemberNumber)) raise = true; else if (settings.Lovers && C.IsLoverOfPlayer()) raise = true; - else if (settings.Friendlist && Player.FriendList.includes(C.MemberNumber)) raise = true; + else if (settings.Friendlist && C.IsFriend()) raise = true; else if (settings.Subs && C.IsOwnedByPlayer()) raise = true; } return raise; @@ -6157,7 +6157,7 @@ function ChatRoomCheckForLastChatRoomUpdates() { // Check whether the chatroom contains at least one "safe" character (a friend, owner, or non-blacklisted player) const ContainsSafeCharacters = ChatRoomCharacter.length === 1 || ChatRoomCharacter.some((Char) => { return !Char.IsPlayer() && ( - Player.FriendList.includes(Char.MemberNumber) || + Char.IsFriend() || Player.IsOwnedByMemberNumber(Char.MemberNumber) || !Blacklist.includes(Char.MemberNumber) ); diff --git a/BondageClub/Screens/Online/ChatSearch/ChatSearch.js b/BondageClub/Screens/Online/ChatSearch/ChatSearch.js index f3e717e1a3..e3d8ad3071 100644 --- a/BondageClub/Screens/Online/ChatSearch/ChatSearch.js +++ b/BondageClub/Screens/Online/ChatSearch/ChatSearch.js @@ -1132,7 +1132,7 @@ function ChatSearchGetFilterReasons(Room) { Reasons.push("TempHidden"); // is creator on ghostlist? - if (Player.GhostList.indexOf(Room.CreatorMemberNumber) != -1) + if (Player.HasOnGhostlist(Room.CreatorMemberNumber)) Reasons.push("GhostList"); return Reasons; diff --git a/BondageClub/Screens/Room/Pandora/Pandora.js b/BondageClub/Screens/Room/Pandora/Pandora.js index c78baee1bd..c6c6d0bc84 100644 --- a/BondageClub/Screens/Room/Pandora/Pandora.js +++ b/BondageClub/Screens/Room/Pandora/Pandora.js @@ -1595,7 +1595,7 @@ function PandoraPenitentiaryDoActivity(Activity) { function PandoraPenitentiaryHiddenMessage(SenderCharacter, Interaction) { // Make sure we can process the Pandora packet - if (!Interaction.startsWith("Pandora") || (Interaction.indexOf("|") <= 0) || !PandoraPenitentiaryIsInmate(Player) || !PandoraPenitentiaryIsGuard(SenderCharacter) || Player.BlackList.includes(SenderCharacter.MemberNumber)) return; + if (!Interaction.startsWith("Pandora") || (Interaction.indexOf("|") <= 0) || !PandoraPenitentiaryIsInmate(Player) || !PandoraPenitentiaryIsGuard(SenderCharacter) || SenderCharacter.IsBlacklisted()) return; // Make sure we target the player (ALL targets everyone) let Target = Interaction.split("|")[1]; diff --git a/BondageClub/Scripts/Character.js b/BondageClub/Scripts/Character.js index 31ae89cfac..0b939435fa 100644 --- a/BondageClub/Scripts/Character.js +++ b/BondageClub/Scripts/Character.js @@ -726,6 +726,30 @@ function CharacterCreate(CharacterAssetFamily, Type, CharacterID) { hooks.forEach((hook) => hook()); // If there's a hook, call it } }, + HasOnGhostlist: function(target) { + return CharacterIsOnList(this, target, "ghost"); + }, + HasOnBlacklist: function(target) { + return CharacterIsOnList(this, target, "black"); + }, + HasOnWhitelist: function(target) { + return CharacterIsOnList(this, target, "white"); + }, + HasOnFriendlist: function(target) { + return CharacterIsOnList(this, target, "friend"); + }, + IsGhosted: function() { + return Player.HasOnGhostlist(this); + }, + IsBlacklisted: function() { + return Player.HasOnBlacklist(this); + }, + IsWhitelisted: function() { + return Player.HasOnWhitelist(this); + }, + IsFriend: function() { + return Player.HasOnFriendlist(this); + } }; // Add the character to the cache @@ -1411,8 +1435,7 @@ function CharacterRefresh(C, Push = true, RefreshDialog = true) { || C.IsPlayer() || !(Player.OnlineSettings && Player.OnlineSettings.DisableAnimations) ) && ( - !Player.GhostList - || Player.GhostList.indexOf(C.MemberNumber) == -1 + !C.IsGhosted() ); C.HasScriptedAssets = !!C.Appearance.find(CA => CA.Asset.DynamicScriptDraw); @@ -2416,3 +2439,23 @@ function CharacterSetActivePose(C, poseName, forceChange=false) { function CharacterCanChangeToPose(C, poseName) { return PoseCanChangeUnaided(C, poseName); } + +/** + * Check a character against another one's access lists + * @param {Character} listOwner - The character to check against + * @param {Character | number} listTarget - The character or member number to check for + * @param {"black" | "white" | "ghost" | "friend"} list + */ +function CharacterIsOnList(listOwner, listTarget, list) { + const num = typeof listTarget === "number" ? listTarget : listTarget.MemberNumber; + switch (list) { + case "black": + return listOwner.BlackList.includes(num); + case "white": + return listOwner.WhiteList.includes(num); + case "ghost": + return listOwner.IsPlayer() && listOwner.GhostList.includes(num); + case "friend": + return listOwner.IsPlayer() && listOwner.FriendList.includes(num); + } +} diff --git a/BondageClub/Scripts/CommonDraw.js b/BondageClub/Scripts/CommonDraw.js index ba3afb70b2..43606a0912 100644 --- a/BondageClub/Scripts/CommonDraw.js +++ b/BondageClub/Scripts/CommonDraw.js @@ -101,7 +101,7 @@ function CommonDrawAppearanceBuild(C, { // Before drawing hook, receives all processed data. Any of them can be overriden if returned inside an object. // CAREFUL! The dynamic function should not contain heavy computations, and should not have any side effects. // Watch out for object references. - if (asset.DynamicBeforeDraw && (!Player.GhostList || Player.GhostList.indexOf(C.MemberNumber) == -1)) { + if (asset.DynamicBeforeDraw && !C.IsGhosted()) { /** @type {DynamicDrawingData} */ const DrawingData = { C, X, Y, CA: item, GroupName: groupName, Color: layerColor, Opacity: opacity, Property: item.Property, A: asset, G: parentAssetName, AG: group, L: layerSegment, Pose: pose, LayerType: layerType, BlinkExpression: blinkExpressionSegment, @@ -257,7 +257,7 @@ function CommonDrawAppearanceBuild(C, { // After drawing hook, receives all processed data. // CAREFUL! The dynamic function should not contain heavy computations, and should not have any side effects. // Watch out for object references. - if (asset.DynamicAfterDraw && (!Player.GhostList || Player.GhostList.indexOf(C.MemberNumber) == -1)) { + if (asset.DynamicAfterDraw && !C.IsGhosted()) { /** @type {DynamicDrawingData} */ const DrawingData = { C, X, Y, CA: item, GroupName: groupName, Property: item.Property, Color: layerColor, Opacity: opacity, A: asset, G: parentAssetName, AG: group, L: layerSegment, Pose: pose, LayerType: layerType, BlinkExpression: blinkExpressionSegment, drawCanvas, drawCanvasBlink, AlphaMasks: masks, diff --git a/BondageClub/Scripts/Inventory.js b/BondageClub/Scripts/Inventory.js index 5c945456e0..091cb61580 100644 --- a/BondageClub/Scripts/Inventory.js +++ b/BondageClub/Scripts/Inventory.js @@ -1703,7 +1703,7 @@ function InventoryIsPermissionLimited(C, AssetName, AssetGroup, AssetType) { function InventoryCheckLimitedPermission(C, Item, ItemType) { if (!InventoryIsPermissionLimited(C, Item.Asset.DynamicName(Player), Item.Asset.Group.Name, ItemType)) return true; if ((C.IsPlayer()) || C.IsLoverOfPlayer() || C.IsOwnedByPlayer()) return true; - if ((C.ItemPermission < 3) && !(C.WhiteList.indexOf(Player.MemberNumber) < 0)) return true; + if ((C.ItemPermission < 3) && C.HasOnWhitelist(Player)) return true; return false; } diff --git a/BondageClub/Scripts/Server.js b/BondageClub/Scripts/Server.js index 771a11c0ea..b12fa340c7 100644 --- a/BondageClub/Scripts/Server.js +++ b/BondageClub/Scripts/Server.js @@ -1031,18 +1031,16 @@ function ServerChatRoomGetAllowItem(Source, Target) { if ((Target.ItemPermission <= 0) || (Source.MemberNumber == Target.MemberNumber) || Target.IsOwnedByCharacter(Source)) return true; // At one, we allow if the source isn't on the blacklist - if ((Target.ItemPermission == 1) && (Target.BlackList.indexOf(Source.MemberNumber) < 0)) return true; - - var LoversNumbers = CharacterGetLoversNumbers(Target, true); + if ((Target.ItemPermission == 1) && !Target.HasOnBlacklist(Source)) return true; // At two, we allow if the source is Dominant compared to the Target (25 points allowed) or on whitelist or a lover - if ((Target.ItemPermission == 2) && (Target.BlackList.indexOf(Source.MemberNumber) < 0) && ((ReputationCharacterGet(Source, "Dominant") + 25 >= ReputationCharacterGet(Target, "Dominant")) || (Target.WhiteList.indexOf(Source.MemberNumber) >= 0) || (LoversNumbers.indexOf(Source.MemberNumber) >= 0))) return true; + if ((Target.ItemPermission == 2) && (!Target.HasOnBlacklist(Source) && ((ReputationCharacterGet(Source, "Dominant") + 25 >= ReputationCharacterGet(Target, "Dominant")) || Target.HasOnWhitelist(Source) || Source.IsLoverOfCharacter(Target)))) return true; // At three, we allow if the source is on the whitelist of the Target or a lover - if ((Target.ItemPermission == 3) && ((Target.WhiteList.indexOf(Source.MemberNumber) >= 0) || (LoversNumbers.indexOf(Source.MemberNumber) >= 0))) return true; + if ((Target.ItemPermission == 3) && (Target.HasOnWhitelist(Source) || Source.IsLoverOfCharacter(Target))) return true; // At four, we allow if the source is a lover - if ((Target.ItemPermission == 4) && (LoversNumbers.indexOf(Source.MemberNumber) >= 0)) return true; + if ((Target.ItemPermission == 4) && (Source.IsLoverOfCharacter(Target))) return true; // No valid combo, we don't allow the item return false; diff --git a/BondageClub/Scripts/Typedef.d.ts b/BondageClub/Scripts/Typedef.d.ts index e05ff62f18..df5bc89955 100644 --- a/BondageClub/Scripts/Typedef.d.ts +++ b/BondageClub/Scripts/Typedef.d.ts @@ -1696,7 +1696,6 @@ interface Character { LimitedItems?: never; /** A record with all asset- and type-specific permission settings */ PermissionItems: Partial<Record<`${AssetGroupName}/${string}`, ItemPermissions>>; - WhiteList: number[]; HeightModifier: number; MemberNumber?: number; ItemPermission: 0 | 1 | 2 | 3 | 4 | 5; @@ -1819,6 +1818,50 @@ interface Character { HasVagina: () => boolean; IsFlatChested: () => boolean; WearingCollar: () => boolean; + /** + * Check if the player is ghosting the given target character (or member number) + */ + HasOnGhostlist: (this: PlayerCharacter, target?: Character | number) => boolean; + /** + * Check if the player is blacklisting the given target character (or member number) + */ + HasOnBlacklist: (target?: Character | number) => boolean; + /** + * Check if the player is whitelisting the given target character (or member number) + */ + HasOnWhitelist: (target?: Character | number) => boolean; + /** + * Check if the player is friend with the given target character (or member number) + */ + HasOnFriendlist: (this: PlayerCharacter, target?: Character | number) => boolean; + /** + * Check if this character is ghosted by the player + */ + IsGhosted: () => boolean; + /** + * Check if this character is blacklisted by the player + */ + IsBlacklisted: () => boolean; + /** + * Check if this character is whitelisted by the player + */ + IsWhitelisted: () => boolean; + /** + * Check if this character is friended by the player + */ + IsFriend: () => boolean; + /** + * List of whitelisted member numbers for the character + * + * Do not manipulate directly. Use {@link ChatRoomListUpdate} + */ + WhiteList: number[]; + /** + * List of blacklisted member numbers for the character + * + * Do not manipulate directly. Use {@link ChatRoomListUpdate} + */ + BlackList: number[]; // Properties created in other places ArousalSettings: ArousalSettingsType; @@ -1831,7 +1874,6 @@ interface Character { OnlineSharedSettings?: CharacterOnlineSharedSettings; // technically never as it is Online-only Game?: CharacterGameParameters; // technically never as it is Online-only MapData?: ChatRoomMapData; - BlackList: number[]; RunScripts?: boolean; HasScriptedAssets?: boolean; Cage?: boolean; @@ -2046,7 +2088,12 @@ interface PlayerCharacter extends Character { GraphicsSettings: GraphicsSettingsType; NotificationSettings: NotificationSettingsType; OnlineSharedSettings: CharacterOnlineSharedSettings; // technically never as it is Online-only - GhostList?: number[]; + /** + * List of ghosted member numbers for the player + * + * Do not manipulate directly. Use {@link ChatRoomListUpdate} + */ + GhostList: number[]; Wardrobe: ItemBundle[][]; WardrobeCharacterNames: string[]; SavedExpressions?: ({ Group: ExpressionGroupName, CurrentExpression?: ExpressionName }[] | null)[]; diff --git a/BondageClub/Scripts/Validation.js b/BondageClub/Scripts/Validation.js index f5dd9fdda5..d9b8ddd699 100644 --- a/BondageClub/Scripts/Validation.js +++ b/BondageClub/Scripts/Validation.js @@ -50,7 +50,7 @@ function ValidationCreateDiffParams(C, sourceMemberNumber) { // We can't know the details about other peoples' friendlist/whitelist, so assume an update is safe - their // validation will correct it if not. const fromFriend = C.IsPlayer() ? C.FriendList.includes(sourceMemberNumber) : true; - const fromWhitelist = C.IsPlayer() ? C.WhiteList.includes(sourceMemberNumber) : true; + const fromWhitelist = C.IsPlayer() ? C.HasOnWhitelist(sourceMemberNumber) : true; const permissions = /** @type {ScriptPermissionLevel[]} */([ fromSelf && ScriptPermissionLevel.SELF, @@ -571,7 +571,7 @@ function ValidationIsItemBlockedOrLimited(C, sourceMemberNumber, groupName, asse if (!InventoryIsPermissionLimited(C, assetName, groupName, type)) return false; if (C.IsLoverOfMemberNumber(sourceMemberNumber) || C.IsOwnedByMemberNumber(sourceMemberNumber)) return false; // The item is limited so if the source is on their whitelist, it's permitted - if (C.WhiteList.includes(sourceMemberNumber)) return false; + if (C.HasOnWhitelist(sourceMemberNumber)) return false; // Otherwise, the item is limited, and the source doesn't have permission return true; }