mirror of
https://gitgud.io/BondageProjects/Bondage-College.git
synced 2025-04-14 12:29:15 +00:00
Use a PRNG to build the lock pin combination
As we were saving the lockpick combination onto the item, but not sending the update, a concurrent update from the lockpicked character (which wouldn't have had the property set as it wouldn't have opened the lockpicking UI) caused a reset of the lockpicking combination, apparently randomly. Fix the bug by building the lockpicking combination using the PRNG, seeded with a combination of the lockpicked character's ID, the group being lockpicked, and the difficulty of the lock, which itself is a depends on the lockpicker's state (skill and blocking, mostly). This allows removing the validation handling for that property, and makes the lock-pick combination unique per lockpicker.
This commit is contained in:
parent
5fd8d9eb9d
commit
18e736d1c6
4 changed files with 46 additions and 61 deletions
BondageClub
|
@ -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"]},
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
1
BondageClub/Scripts/Typedef.d.ts
vendored
1
BondageClub/Scripts/Typedef.d.ts
vendored
|
@ -1072,7 +1072,6 @@ interface ItemPropertiesCustom {
|
|||
|
||||
RemoveTimer?: unknown;
|
||||
Password?: string;
|
||||
LockPickSeed?: string;
|
||||
CombinationNumber?: string;
|
||||
LockMemberNumber?: number | string;
|
||||
MemberNumber?: number;
|
||||
|
|
|
@ -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)) {
|
||||
|
|
Loading…
Add table
Reference in a new issue