Files
Andrey Sharshov 9487728656 initial
2025-11-16 18:54:31 +01:00

152 lines
5.0 KiB
JavaScript

import { Locator } from "@popiplay/slot-game-kit";
import { SKIN_TYPES } from "../src/config";
/**
* Creates a callback function that executes a specific callback after a defined count of invocations.
*
* @param {number} n - The count threshold that triggers the callback execution.
* @param {Function} callback - The function to execute after `n` invocations. Defaults to an empty function.
* @param {Function} eachCallback - The function to execute on each invocation. Defaults to an empty function.
* @return {Function} A new function that increments a count each time it's called, executes `eachCallback`,
* and if the count equals `n`, executes `callback` and resets the count.
*
* @example
* // Logs 'Hello, third time!' every third invocation
* const logEveryTime = (...args) => console.log('Called with', args);
* const sayHelloEveryThirdTime = () => console.log('Hello, third time!');
* const thresholdCallback = createThresholdCallback(3, sayHelloEveryThirdTime, logEveryTime);
*
* thresholdCallback('test'); // Logs 'Called with ["test"]'
* thresholdCallback('again'); // Logs 'Called with ["again"]'
* thresholdCallback('and again'); // Logs 'Called with ["and again"]' and 'Hello, third time!'
* thresholdCallback('another one'); // Logs 'Called with ["another one"]'
*
*/
export function createThresholdCallback(
n,
callback = () => { },
eachCallback = () => { }
) {
let counter = 0;
return function (...args) {
counter++;
eachCallback(...args);
if (n === counter) {
counter = 0;
callback(...args);
}
}
}
/**
* Asynchronously waits for a specified event to be emitted once on the target object.
*
* @async
* @param {EventEmitter} target - The EventEmitter object on which to listen for the event.
* @param {string} event - The name of the event to listen for.
* @return {Promise<void>} A promise that resolves when the specified event is emitted on the target.
*
* Usage:
* ```javascript
* await waitForEventOnce(someObject, 'eventName');
* // Following code won't execute until 'eventName' is emitted on 'someObject' for the first time.
* ```
*/
export async function waitForEventOnce(target, event) {
return new Promise((resolve) => {
target.once(event, () => {
resolve()
});
})
}
/**
* Asynchronously waits for the first event from a list of events to be emitted.
*
* @async
* @param {Array<{ target: EventEmitter, event: string }>} events - An array of objects, each containing an EventEmitter object and the event to listen for.
* @return {Promise<void>} A Promise that resolves as soon as one of the specified events is emitted on its respective EventEmitter.
*
* Usage:
* ```javascript
* const events = [
* { target: someObject1, event: 'eventName1'},
* { target: someObject2, event: 'eventName2'}
* ];
*
* await waitForFirstEmittedEvent(events);
* // Following code won't execute until either 'eventName1' is emitted on 'someObject1' or 'eventName2' is emitted on 'someObject2' for the first time.
* ```
*/
export async function waitForFirstEmittedEvent(events) {
const promises = events.map(({ target, event }) => {
return waitForEventOnce(target, event);
})
return Promise.race(promises)
}
export function capitalizeFirstLetter(str) {
return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
}
export const transpose = (matrix) => matrix[0].map((_, i) => matrix.map(row => row[i]));
export const isObject = (obj) => obj && typeof obj === 'object' && !Array.isArray(obj);
/**
* @description - Deeply merges two objects.
*
* @param {Object} target - The target object to merge properties into.
* @param {Object} source - The source object from which to copy properties.
* @return {Object} The merged object.
*
* @example
* const obj1 = { a: 1, b: { c: 2 } };
* const obj2 = { b: { d: 3 }, e: 4 };
* const result = deepMerge(obj1, obj2);
* // result is { a: 1, b: { c: 2, d: 3 }, e: 4 }
*/
export function deepMerge(target, source) {
if (!isObject(target) || !isObject(source)) {
return source;
}
const merged = { ...target };
Object.keys(source).forEach(key => {
if (isObject(source[key])) {
if (!target[key]) {
merged[key] = source[key];
} else {
merged[key] = deepMerge(target[key], source[key]);
}
} else {
merged[key] = source[key];
}
});
return merged;
}
export const getSkinType = (threshhold) => {
return Locator.viewport.cropWidthRatio < threshhold
? SKIN_TYPES.PORT
: SKIN_TYPES.LAND;
}
export const getStyle = (styleTempl, dynamicStyle, threshhold) => {
const skinType = getSkinType(threshhold);
const hasDynamicStyle = !!dynamicStyle
&& typeof dynamicStyle === 'object'
&& !!Object.entries(dynamicStyle).length;
const additionalStyles = dynamicStyle?.[skinType] || dynamicStyle;
return hasDynamicStyle ? deepMerge(styleTempl, additionalStyles) : styleTempl;
}
export const getRandomInt = (min, max) => {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min;
}