diff --git a/BondageClub/Assets/Female3DCG/Female3DCG.js b/BondageClub/Assets/Female3DCG/Female3DCG.js index 9574081ad8..05b953476c 100644 --- a/BondageClub/Assets/Female3DCG/Female3DCG.js +++ b/BondageClub/Assets/Female3DCG/Female3DCG.js @@ -5679,8 +5679,8 @@ var AssetFemale3DCG = [ Zone: [[10, 0, 90, 200]], Asset: [ { Name: "MetalPadlock", Value: 15, Time: 10, Wear: false, Effect: [], IsLock: true}, - { Name: "IntricatePadlock", Value: 50, Time: 30, Wear: false, Effect: [], IsLock: true, PickDifficulty: 7, ExclusiveUnlock: true, AllowType: ["LockPickSeed"]}, - { Name: "HighSecurityPadlock", Value: 60, Time: 10, Wear: false, Effect: [], IsLock: true, PickDifficulty: 10, ExclusiveUnlock: true, AllowType: ["LockPickSeed"]}, + { Name: "IntricatePadlock", Value: 50, Time: 30, Wear: false, Effect: [], IsLock: true, PickDifficulty: 7, ExclusiveUnlock: true, }, + { Name: "HighSecurityPadlock", Value: 60, Time: 10, Wear: false, Effect: [], IsLock: true, PickDifficulty: 10, ExclusiveUnlock: true, }, { Name: "TimerPadlock", Value: 80, Wear: false, Effect: [], IsLock: true, MaxTimer: 300, RemoveTimer: 300 }, { Name: "CombinationPadlock", Value: 100, Random: false, Wear: false, Effect: [], IsLock: true, AllowType: ["CombinationNumber"]}, { Name: "PasswordPadlock", Value: 100, BuyGroup: "PasswordPadlock", Random: false, Wear: false, Effect: [], IsLock: true, AllowType: ["Password", "Hint", "LockSet"]}, diff --git a/BondageClub/Scripts/Struggle.js b/BondageClub/Scripts/Struggle.js index 70641412a7..2051fa4cc8 100644 --- a/BondageClub/Scripts/Struggle.js +++ b/BondageClub/Scripts/Struggle.js @@ -1197,6 +1197,39 @@ function StruggleLockPickGetDifficulty(C, Item) { } } +/** + * Generate the lock pin data + * + * @param {object} Lock - the lockpicking data. See StruggleLockPickGetDifficulty. + * @param {Character} Character + * @param {string} Group + * @returns {number[]} + */ +function StruggleLockPickGenerate(Lock, Character, Group) { + if (!Lock || !Character || !Group) + return null; + + // Generate a PRNG for shuffling pins around + let seed = String(Character.IsNpc() ? Character.Name : Character.MemberNumber) + Group + Lock.Difficulty + Lock.NumPins; + const hash = xmur3(seed); + const rand = sfc32(hash(), hash(), hash(), hash()); + + let Order = []; + for (let P = 0; P < Lock.NumPins; P++) { + Order.push(P); + } + + // Randomize array in-place using Durstenfeld shuffle algorithm + // https://stackoverflow.com/questions/2450954/how-to-randomize-shuffle-a-javascript-array + for (var i = Order.length - 1; i > 0; i--) { + var j = Math.floor(rand() * (i + 1)); + var temp = Order[i]; + Order[i] = Order[j]; + Order[j] = temp; + } + return Order; +} + /** * Starts the dialog progress bar for picking a lock * First the challenge level is calculated based on the base lock difficulty, the skill of the rigger and the escapee @@ -1216,12 +1249,6 @@ function StruggleLockPickProgressStart(C, Item) { if (!Lock) return; // Prepares the progress bar and timer - StruggleLockPickOrder = []; - StruggleLockPickSet = []; - StruggleLockPickSetFalse = []; - StruggleLockPickOffset = []; - StruggleLockPickOffsetTarget = []; - StruggleLockPickImpossiblePins = []; StruggleLockPickProgressItem = Item; StruggleLockPickProgressOperation = StruggleLockPickProgressGetOperation(C, Item); StruggleLockPickProgressChallenge = Lock.Difficulty; @@ -1235,39 +1262,22 @@ function StruggleLockPickProgressStart(C, Item) { StruggleLockPickFailTime = 0; DialogMenuButtonBuild(C); + // Generate the combination + StruggleLockPickOrder = []; + StruggleLockPickSet = []; + StruggleLockPickSetFalse = []; + StruggleLockPickOffset = []; + StruggleLockPickOffsetTarget = []; + StruggleLockPickImpossiblePins = []; + + StruggleLockPickOrder = StruggleLockPickGenerate(Lock, C, C.FocusGroup.Name); + for (let P = 0; P < Lock.NumPins; P++) { - StruggleLockPickOrder.push(P); StruggleLockPickSet.push(false); StruggleLockPickSetFalse.push(false); StruggleLockPickOffset.push(0); StruggleLockPickOffsetTarget.push(0); } - /* Randomize array in-place using Durstenfeld shuffle algorithm */ - // https://stackoverflow.com/questions/2450954/how-to-randomize-shuffle-a-javascript-array - for (var i = StruggleLockPickOrder.length - 1; i > 0; i--) { - var j = Math.floor(Math.random() * (i + 1)); - var temp = StruggleLockPickOrder[i]; - StruggleLockPickOrder[i] = StruggleLockPickOrder[j]; - StruggleLockPickOrder[j] = temp; - } - - // Initialize persistent pins - if ((Item.Property == null)) Item.Property = {}; - if (Item.Property != null) - if ((Item.Property.LockPickSeed == null) || (typeof Item.Property.LockPickSeed != "string")) { - Item.Property.LockPickSeed = CommonConvertArrayToString(StruggleLockPickOrder); - StruggleLockPickTotalTries = 0; - } else { - var conv = CommonConvertStringToArray(Item.Property.LockPickSeed); - for (let PP = 0; PP < conv.length; PP++) { - if (typeof conv[PP] != "number") { - Item.Property.LockPickSeed = CommonConvertArrayToString(StruggleLockPickOrder); - conv = StruggleLockPickOrder; - break; - } - } - StruggleLockPickOrder = conv; - } if (Lock.Difficulty > 6 && Lock.Impossible) { // if picking is impossible, then some pins will never set @@ -1275,5 +1285,4 @@ function StruggleLockPickProgressStart(C, Item) { if (Lock.NumPins >= 6) StruggleLockPickImpossiblePins.push(StruggleLockPickOrder[StruggleLockPickOrder.length-2]); if (Lock.NumPins >= 8) StruggleLockPickImpossiblePins.push(StruggleLockPickOrder[StruggleLockPickOrder.length-3]); } - } diff --git a/BondageClub/Scripts/Typedef.d.ts b/BondageClub/Scripts/Typedef.d.ts index 90e21d4f02..514841c7e8 100644 --- a/BondageClub/Scripts/Typedef.d.ts +++ b/BondageClub/Scripts/Typedef.d.ts @@ -1072,7 +1072,6 @@ interface ItemPropertiesCustom { RemoveTimer?: unknown; Password?: string; - LockPickSeed?: string; CombinationNumber?: string; LockMemberNumber?: number | string; MemberNumber?: number; diff --git a/BondageClub/Scripts/Validation.js b/BondageClub/Scripts/Validation.js index befcace4a7..9f5e3d6c95 100644 --- a/BondageClub/Scripts/Validation.js +++ b/BondageClub/Scripts/Validation.js @@ -8,7 +8,7 @@ const ValidationDefaultPassword = "UNLOCK"; const ValidationRemoveTimerToleranceMs = 5000; const ValidationNonModifiableLockProperties = ["LockedBy", "LockMemberNumber"]; const ValidationRestrictedLockProperties = [ - "EnableRandomInput", "RemoveItem", "ShowTimer", "CombinationNumber", "Password", "Hint", "LockSet", "LockPickSeed", + "EnableRandomInput", "RemoveItem", "ShowTimer", "CombinationNumber", "Password", "Hint", "LockSet", ]; const ValidationTimerLockProperties = ["MemberNumberList", "RemoveTimer"]; const ValidationAllLockProperties = ValidationNonModifiableLockProperties @@ -670,29 +670,6 @@ function ValidationSanitizeLock(C, item) { changed = true; } - // Sanitize lockpicking seed - if (typeof property.LockPickSeed === "string") { - const seed = CommonConvertStringToArray(property.LockPickSeed); - if (!seed.length) { - console.warn("Deleting invalid lockpicking seed: ", property.LockPickSeed); - delete property.LockPickSeed; - changed = true; - } else { - // Check that every number from 0 up to the seed length is included in the seed - for (let i = 0; i < seed.length; i++) { - if (!seed.includes(i)) { - console.warn("Deleting invalid lockpicking seed: ", property.LockPickSeed); - delete property.LockPickSeed; - changed = true; - break; - } - } - } - } else if (property.LockPickSeed != null) { - delete property.LockPickSeed; - changed = true; - } - // Sanitize lock password if (typeof property.Password === "string") { if (!ValidationPasswordRegex.test(property.Password)) {