@sacredcasuals/shared-lib
Version:
Shared game utilities and UI components for Sacred Casuals apps
1,672 lines (1,642 loc) • 212 kB
JavaScript
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __commonJS = (cb, mod) => function __require() {
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
// node_modules/typed-signals/dist/Collector.js
var require_Collector = __commonJS({
"node_modules/typed-signals/dist/Collector.js"(exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Collector = void 0;
var Collector = class {
/**
* Create a new collector.
*
* @param signal The signal to emit.
*/
constructor(signal) {
this.emit = (...args) => {
signal["emitCollecting"](this, args);
};
}
};
exports.Collector = Collector;
}
});
// node_modules/typed-signals/dist/CollectorArray.js
var require_CollectorArray = __commonJS({
"node_modules/typed-signals/dist/CollectorArray.js"(exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CollectorArray = void 0;
var Collector_1 = require_Collector();
var CollectorArray = class extends Collector_1.Collector {
constructor() {
super(...arguments);
this.result = [];
}
handleResult(result) {
this.result.push(result);
return true;
}
/**
* Get the list of results from the signal handlers.
*/
getResult() {
return this.result;
}
/**
* Reset the result
*/
reset() {
this.result.length = 0;
}
};
exports.CollectorArray = CollectorArray;
}
});
// node_modules/typed-signals/dist/CollectorLast.js
var require_CollectorLast = __commonJS({
"node_modules/typed-signals/dist/CollectorLast.js"(exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CollectorLast = void 0;
var Collector_1 = require_Collector();
var CollectorLast = class extends Collector_1.Collector {
handleResult(result) {
this.result = result;
return true;
}
/**
* Get the result of the last signal handler.
*/
getResult() {
return this.result;
}
/**
* Reset the result
*/
reset() {
delete this.result;
}
};
exports.CollectorLast = CollectorLast;
}
});
// node_modules/typed-signals/dist/CollectorUntil0.js
var require_CollectorUntil0 = __commonJS({
"node_modules/typed-signals/dist/CollectorUntil0.js"(exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CollectorUntil0 = void 0;
var Collector_1 = require_Collector();
var CollectorUntil0 = class extends Collector_1.Collector {
constructor() {
super(...arguments);
this.result = false;
}
handleResult(result) {
this.result = result;
return this.result;
}
/**
* Get the result of the last signal handler.
*/
getResult() {
return this.result;
}
/**
* Reset the result
*/
reset() {
this.result = false;
}
};
exports.CollectorUntil0 = CollectorUntil0;
}
});
// node_modules/typed-signals/dist/CollectorWhile0.js
var require_CollectorWhile0 = __commonJS({
"node_modules/typed-signals/dist/CollectorWhile0.js"(exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CollectorWhile0 = void 0;
var Collector_1 = require_Collector();
var CollectorWhile0 = class extends Collector_1.Collector {
constructor() {
super(...arguments);
this.result = false;
}
handleResult(result) {
this.result = result;
return !this.result;
}
/**
* Get the result of the last signal handler.
*/
getResult() {
return this.result;
}
/**
* Reset the result
*/
reset() {
this.result = false;
}
};
exports.CollectorWhile0 = CollectorWhile0;
}
});
// node_modules/typed-signals/dist/SignalConnection.js
var require_SignalConnection = __commonJS({
"node_modules/typed-signals/dist/SignalConnection.js"(exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SignalConnectionImpl = void 0;
var SignalConnectionImpl = class {
/**
* @param link The actual link of the connection.
* @param parentCleanup Callback to cleanup the parent signal when a connection is disconnected
*/
constructor(link, parentCleanup) {
this.link = link;
this.parentCleanup = parentCleanup;
}
disconnect() {
if (this.link !== null) {
this.link.unlink();
this.link = null;
this.parentCleanup();
this.parentCleanup = null;
return true;
}
return false;
}
set enabled(enable) {
if (this.link)
this.link.setEnabled(enable);
}
get enabled() {
return this.link !== null && this.link.isEnabled();
}
};
exports.SignalConnectionImpl = SignalConnectionImpl;
}
});
// node_modules/typed-signals/dist/SignalLink.js
var require_SignalLink = __commonJS({
"node_modules/typed-signals/dist/SignalLink.js"(exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SignalLink = void 0;
var SignalLink = class _SignalLink {
constructor(prev = null, next = null, order = 0) {
this.enabled = true;
this.newLink = false;
this.callback = null;
this.prev = prev !== null && prev !== void 0 ? prev : this;
this.next = next !== null && next !== void 0 ? next : this;
this.order = order;
}
isEnabled() {
return this.enabled && !this.newLink;
}
setEnabled(flag) {
this.enabled = flag;
}
unlink() {
this.callback = null;
this.next.prev = this.prev;
this.prev.next = this.next;
}
insert(callback, order) {
let after = this.prev;
while (after !== this) {
if (after.order <= order)
break;
after = after.prev;
}
const link = new _SignalLink(after, after.next, order);
link.callback = callback;
after.next = link;
link.next.prev = link;
return link;
}
};
exports.SignalLink = SignalLink;
}
});
// node_modules/typed-signals/dist/Signal.js
var require_Signal = __commonJS({
"node_modules/typed-signals/dist/Signal.js"(exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Signal = void 0;
var SignalConnection_1 = require_SignalConnection();
var SignalLink_1 = require_SignalLink();
var Signal3 = class {
constructor() {
this.head = new SignalLink_1.SignalLink();
this.hasNewLinks = false;
this.emitDepth = 0;
this.connectionsCount = 0;
}
/**
* @returns The number of connections on this signal.
*/
getConnectionsCount() {
return this.connectionsCount;
}
/**
* @returns true if this signal has connections.
*/
hasConnections() {
return this.connectionsCount > 0;
}
/**
* Subscribe to this signal.
*
* @param callback This callback will be run when emit() is called.
* @param order Handlers with a higher order value will be called later.
*/
connect(callback, order = 0) {
this.connectionsCount++;
const link = this.head.insert(callback, order);
if (this.emitDepth > 0) {
this.hasNewLinks = true;
link.newLink = true;
}
return new SignalConnection_1.SignalConnectionImpl(link, () => this.decrementConnectionCount());
}
decrementConnectionCount() {
this.connectionsCount--;
}
/**
* Unsubscribe from this signal with the original callback instance.
* While you can use this method, the SignalConnection returned by connect() will not be updated!
*
* @param callback The callback you passed to connect().
*/
disconnect(callback) {
for (let link = this.head.next; link !== this.head; link = link.next) {
if (link.callback === callback) {
this.decrementConnectionCount();
link.unlink();
return true;
}
}
return false;
}
/**
* Disconnect all handlers from this signal event.
*/
disconnectAll() {
while (this.head.next !== this.head) {
this.head.next.unlink();
}
this.connectionsCount = 0;
}
/**
* Publish this signal event (call all handlers).
*/
emit(...args) {
this.emitDepth++;
for (let link = this.head.next; link !== this.head; link = link.next) {
if (link.isEnabled() && link.callback)
link.callback.apply(null, args);
}
this.emitDepth--;
this.unsetNewLink();
}
emitCollecting(collector, args) {
this.emitDepth++;
for (let link = this.head.next; link !== this.head; link = link.next) {
if (link.isEnabled() && link.callback) {
const result = link.callback.apply(null, args);
if (!collector.handleResult(result))
break;
}
}
this.emitDepth--;
this.unsetNewLink();
}
unsetNewLink() {
if (this.hasNewLinks && this.emitDepth === 0) {
for (let link = this.head.next; link !== this.head; link = link.next)
link.newLink = false;
this.hasNewLinks = false;
}
}
};
exports.Signal = Signal3;
}
});
// node_modules/typed-signals/dist/SignalConnections.js
var require_SignalConnections = __commonJS({
"node_modules/typed-signals/dist/SignalConnections.js"(exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SignalConnections = void 0;
var SignalConnections = class {
constructor() {
this.list = [];
}
/**
* Add a connection to the list.
* @param connection
*/
add(connection) {
this.list.push(connection);
}
/**
* Disconnect all connections in the list and empty the list.
*/
disconnectAll() {
for (const connection of this.list) {
connection.disconnect();
}
this.list = [];
}
/**
* @returns The number of connections in this list.
*/
getCount() {
return this.list.length;
}
/**
* @returns true if this list is empty.
*/
isEmpty() {
return this.list.length === 0;
}
};
exports.SignalConnections = SignalConnections;
}
});
// node_modules/typed-signals/dist/index.js
var require_dist = __commonJS({
"node_modules/typed-signals/dist/index.js"(exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SignalConnections = exports.Signal = exports.CollectorWhile0 = exports.CollectorUntil0 = exports.CollectorLast = exports.CollectorArray = exports.Collector = void 0;
var Collector_1 = require_Collector();
Object.defineProperty(exports, "Collector", { enumerable: true, get: function() {
return Collector_1.Collector;
} });
var CollectorArray_1 = require_CollectorArray();
Object.defineProperty(exports, "CollectorArray", { enumerable: true, get: function() {
return CollectorArray_1.CollectorArray;
} });
var CollectorLast_1 = require_CollectorLast();
Object.defineProperty(exports, "CollectorLast", { enumerable: true, get: function() {
return CollectorLast_1.CollectorLast;
} });
var CollectorUntil0_1 = require_CollectorUntil0();
Object.defineProperty(exports, "CollectorUntil0", { enumerable: true, get: function() {
return CollectorUntil0_1.CollectorUntil0;
} });
var CollectorWhile0_1 = require_CollectorWhile0();
Object.defineProperty(exports, "CollectorWhile0", { enumerable: true, get: function() {
return CollectorWhile0_1.CollectorWhile0;
} });
var Signal_1 = require_Signal();
Object.defineProperty(exports, "Signal", { enumerable: true, get: function() {
return Signal_1.Signal;
} });
var SignalConnections_1 = require_SignalConnections();
Object.defineProperty(exports, "SignalConnections", { enumerable: true, get: function() {
return SignalConnections_1.SignalConnections;
} });
}
});
// src/managers/DeviceManager.ts
import { Device } from "@capacitor/device";
import { App } from "@capacitor/app";
import { SafeArea } from "capacitor-plugin-safe-area";
import { SecureStoragePlugin } from "capacitor-secure-storage-plugin";
// src/pixi/AbstractPixiRoot.ts
import * as PIXI7 from "pixi.js";
// src/pixi/base/GameView.ts
import * as PIXI from "pixi.js";
import { Easing } from "@tweenjs/tween.js";
var GameView = class extends PIXI.Container {
constructor(...args) {
super();
}
onResize() {
}
set interactive(value) {
super.interactive = value;
this.interactiveChildren = value;
}
get pulsatingDisplayObject() {
return this;
}
startPulsating(scaleDiff = 0.03, time = 0.6) {
this._pulsateTween?.destroy();
this._pulsateTween = this.juggler.tween(this.pulsatingDisplayObject, 2, {
scale: {
y: this.pulsatingDisplayObject.scale.y - scaleDiff,
x: this.pulsatingDisplayObject.scale.x - scaleDiff * 3
}
}).repeat(Infinity).yoyoFix((t) => Easing.Linear.InOut(t)).start();
}
continuePulsating() {
if (this._pulsateTween) {
this.juggler.addAnimatable(this._pulsateTween);
}
}
stopPulsating() {
if (this._pulsateTween) {
this.juggler.removeAnimatable(this._pulsateTween);
}
}
advanceTime(delta) {
}
addToJuggler() {
this.juggler?.addAnimatable(this);
}
removeFromJuggler() {
this.juggler?.removeAnimatable(this);
}
onRemovedFromJuggler() {
}
get juggler() {
return this._juggler || this.root?.juggler;
}
set juggler(value) {
this._juggler = value;
}
destroyChildren() {
while (this.children.length > 0) {
const child = this.removeChildAt(0);
if ("destroy" in child && typeof child.destroy === "function") {
child.destroy({ children: true });
}
}
}
destroy() {
if (this.destroyed) {
return;
}
this._pulsateTween?.destroy();
this.removeFromJuggler();
this.removeFromParent();
this.destroyChildren();
super.destroy({
children: true
});
}
};
// src/pixi/base/GameObject.ts
import * as PIXI2 from "pixi.js";
var isIDestroy = (obj) => {
return obj && typeof obj.destroy === "function" && typeof obj.destroyed === "boolean";
};
var GameObject = class _GameObject {
constructor() {
this._isDestroyed = false;
this._juggler = null;
}
advanceTime(delta) {
}
addToJuggler() {
this.juggler?.addAnimatable(this);
}
onRemovedFromJuggler() {
}
removeFromJuggler() {
this.juggler?.removeAnimatable(this);
}
get juggler() {
return this._juggler;
}
set juggler(value) {
this._juggler = value;
}
get destroyed() {
return this._isDestroyed;
}
static destroy(object) {
if (!object) {
return null;
}
if (object instanceof _GameObject || object instanceof GameView) {
object.destroy();
return null;
}
if (isIDestroy(object)) {
object.destroy();
return null;
}
if (Array.isArray(object)) {
const objects = object;
if (objects) {
while (objects.length) {
this.destroy(objects.pop());
}
}
return null;
}
if (object instanceof PIXI2.Container) {
let container = object;
container.removeFromParent();
container.destroy({ children: true });
}
return null;
}
onReturnToPool() {
}
onGetFromPool(pool) {
}
destroy() {
if (!this._isDestroyed) {
this._isDestroyed = true;
this.removeFromJuggler();
}
}
};
// src/pixi/base/GameDispatcher.ts
var GameDispatcher = class extends GameObject {
constructor(sender) {
super();
this._sender = sender;
this._listeners = /* @__PURE__ */ new Map();
}
add(listener, context) {
if (this._isDestroyed || !listener) {
return;
}
if (!this._listeners.has(listener)) {
const boundListener = context ? listener.bind(context) : listener;
this._listeners.set(listener, boundListener);
}
}
remove(listener) {
if (this.destroyed || !listener) {
return;
}
if (this._listeners.has(listener)) {
this._listeners.delete(listener);
}
}
dispatch(argument) {
if (this._isDestroyed || !this._listeners) {
return;
}
for (const [, boundListener] of this._listeners) {
boundListener(this._sender, argument);
}
}
hasListener(listener) {
if (this.destroyed || !listener) {
return false;
}
return this._listeners.has(listener);
}
removeAllListeners() {
if (this._listeners) {
this._listeners.clear();
}
}
destroy() {
if (this._listeners) {
this._listeners.clear();
this._listeners = null;
}
this._sender = null;
super.destroy();
}
};
// src/pixi/base/GameScreen.ts
import * as PIXI5 from "pixi.js";
// src/pixi/effects/BackgroundEffect.ts
import * as PIXI3 from "pixi.js";
// src/utils/MathUtils.ts
var _MathUtils = class _MathUtils {
static getMidPoint(startX, startY, endX, endY) {
const distance = _MathUtils.getDistance(startX, startY, endX, endY);
const point = {
x: (startX + endX) / 2,
y: (startY + endY) / 2
};
if (_MathUtils.getRandomInt(0, 1) === 0) {
point.x += 0.01 * _MathUtils.getRandomInt(10, 20) * distance;
} else {
point.x -= 0.01 * _MathUtils.getRandomInt(10, 20) * distance;
}
return point;
}
static getRandomElementOf(array) {
const idx = Math.floor(Math.random() * array.length);
return array[idx];
}
static toArray(iterable) {
return Array.from(iterable);
}
static isEvenInt(value) {
return value % 2 === 0;
}
static getDistance(x1, y1, x2, y2) {
return Math.sqrt((y2 - y1) ** 2 + (x2 - x1) ** 2);
}
static getRandomInt(fromNum, toNum) {
if (fromNum === toNum) {
return fromNum;
}
return Math.floor(fromNum + Math.random() * (toNum - fromNum + 1));
}
static getRandomNumber(fromNum, toNum) {
if (fromNum === toNum) {
return fromNum;
}
return fromNum + Math.random() * (toNum - fromNum);
}
static getAngle(x1, y1, x2, y2) {
if (x2 !== x1) {
let angle = 180 / Math.PI * Math.atan((y2 - y1) / (x2 - x1));
if (x1 < x2) angle += 180;
if (angle < 0) angle += 360;
return angle;
} else {
return y1 < y2 ? 270 : 90;
}
}
static generateRandomArray(length) {
const array = Array.from({ length }, (_, i) => i);
for (let i = 0; i < length; i++) {
const r = _MathUtils.generateRandom(0, length);
[array[i], array[r]] = [array[r], array[i]];
}
return array;
}
static generateRandom(min, max) {
if (min === max) return min;
if (max > min) return _MathUtils.randomInt() % (max - min) + min;
return _MathUtils.randomInt() % (min - max) + max;
}
static randomBoolean() {
return _MathUtils.randomInt() % 2 === 0;
}
static chance(chance) {
if (chance < 2) return true;
return _MathUtils.randomInt() % chance === 0;
}
static chooseWeighedItem(weights) {
const totalWeight = weights.reduce((sum, weight) => sum + weight, 0);
if (totalWeight === 0) return 0;
let randomWeight = _MathUtils.randomInt() % totalWeight;
for (let i = 0; i < weights.length; i++) {
randomWeight -= weights[i];
if (randomWeight < 0) return i;
}
return 0;
}
static randomInt() {
return Math.round(Math.random() * Number.MAX_SAFE_INTEGER);
}
static deg2rad(degrees) {
return degrees * _MathUtils.DEG_TO_RAD;
}
static int(num) {
return Math.floor(num);
}
static float(num, decimals) {
const multiplier = Math.pow(10, decimals);
return Math.round(num * multiplier) / multiplier;
}
static distance(point1, point2) {
if (point1 && point2) {
const dx = point2.x - point1.x;
const dy = point2.y - point1.y;
return Math.sqrt(dx * dx + dy * dy);
}
return 0;
}
};
_MathUtils.DEG_TO_RAD = Math.PI / 180;
var MathUtils = _MathUtils;
// src/pixi/effects/BackgroundEffect.ts
var BackgroundEffectParticle = class extends GameView {
constructor(root, layerNum) {
super();
this._dx = 0;
this._dy = 0;
this._rotSpeed = 0;
this.root = root;
let image = this.createParticleImage();
image.anchor.set(0.5);
this.addChild(image);
this.x = MathUtils.getRandomInt(0, this.root.fixedStageWidth);
this.y = MathUtils.getRandomInt(-32 * this.root.scaleFactor / 4, this.root.fixedStageHeight);
let minSpeed = 0;
let maxSpeed = 0;
switch (layerNum) {
case 1:
this.scale = MathUtils.getRandomInt(20, 30) * 0.01;
minSpeed = 3;
maxSpeed = 4;
break;
case 2:
this.scale = MathUtils.getRandomInt(40, 60) * 0.01;
minSpeed = 4;
maxSpeed = 6;
break;
case 3:
this.scale = MathUtils.getRandomInt(70, 80) * 0.01;
minSpeed = 7;
maxSpeed = 9;
break;
}
if (layerNum == 2 || layerNum == 3) {
if (MathUtils.getRandomInt(0, 1) == 1) {
this._rotSpeed = MathUtils.deg2rad(0.1 * MathUtils.getRandomInt(10, 20));
} else {
this._rotSpeed = MathUtils.deg2rad(0.1 * MathUtils.getRandomInt(-20, -10));
}
}
minSpeed *= this.root.scaleFactor / 4;
maxSpeed *= this.root.scaleFactor / 4;
let fallSpeed = 0.75;
let speed = MathUtils.getRandomInt(minSpeed, maxSpeed) * fallSpeed;
let angle = MathUtils.getRandomInt(250, 290);
this._dx = speed * Math.cos((180 - angle) * Math.PI / 180);
this._dy = -speed * Math.sin((180 - angle) * Math.PI / 180);
}
get horizontalForce() {
return 0;
}
update() {
this.x += this._dx + this.horizontalForce * this.scale.x;
this.y += this._dy;
if (this._rotSpeed != 0) {
this.rotation += this._rotSpeed;
}
if (this.y > this.root.fixedStageHeight || this.x > this.root.fixedStageWidth || this.x < 0) {
this.x = MathUtils.getRandomInt(0, this.root.fixedStageWidth);
this.y = -32 * this.root.scaleFactor / 4;
}
}
createParticleImage() {
return new PIXI3.Sprite(this.root.uiLib.getTexture("petal"));
}
};
var BackgroundEffect = class extends GameView {
constructor(root, particlesCount) {
super();
this._particles = [];
this.root = root;
let particle;
let distribution = this.distribution();
let layer1Count = distribution[0] * particlesCount * 0.01;
let layer2Count = distribution[1] * particlesCount * 0.01;
for (let i = 0; i < particlesCount; i++) {
if (i < layer1Count)
particle = this.createParticle(1);
else if (i > layer1Count && i < layer1Count + layer2Count)
particle = this.createParticle(2);
else
particle = this.createParticle(3);
this.addChild(particle);
this._particles.push(particle);
}
this.addToJuggler();
}
advanceTime() {
for (let i = 0; i < this._particles.length; i++) {
this._particles[i].update();
}
}
destroy() {
GameObject.destroy(this._particles);
super.destroy();
}
createParticle(layer) {
return new BackgroundEffectParticle(this.root, layer);
}
distribution() {
return [30, 40, 50];
}
};
// src/pixi/utils/RectangleUtils.ts
import * as PIXI4 from "pixi.js";
var ScaleMode = /* @__PURE__ */ ((ScaleMode2) => {
ScaleMode2["SHOW_ALL"] = "SHOW_ALL";
ScaleMode2["NO_BORDER"] = "NO_BORDER";
return ScaleMode2;
})(ScaleMode || {});
var RectangleUtils = class {
static fitRectangle(source, target, scaleMode) {
const sourceAspect = source.width / source.height;
const targetAspect = target.width / target.height;
let scale;
if (scaleMode === "NO_BORDER" /* NO_BORDER */) {
scale = sourceAspect > targetAspect ? target.height / source.height : target.width / source.width;
} else {
scale = sourceAspect > targetAspect ? target.width / source.width : target.height / source.height;
}
const width = source.width * scale;
const height = source.height * scale;
const x = (target.width - width) / 2;
const y = (target.height - height) / 2;
return new PIXI4.Rectangle(x, y, width, height);
}
};
// src/pixi/base/GameScreen.ts
var GameScreen = class extends GameView {
constructor() {
super();
this.assetsLoader = null;
this._bgImage = null;
this._bgParticleEffect = null;
this._isAdded = false;
}
getAreaForHtml() {
return this.boundsArea;
}
get screenID() {
return "GameScreen";
}
destroy() {
super.destroy();
this._bgImage = GameObject.destroy(this._bgImage);
this._bgParticleEffect = GameObject.destroy(this._bgParticleEffect);
this.assetsLoader = GameObject.destroy(this.assetsLoader);
}
async onAdded() {
this._isAdded = true;
}
getStateDescription() {
return "GameScreen: ";
}
async loadAssets(onLoad) {
if (onLoad) {
onLoad();
}
}
createBg() {
this._bgImage = new PIXI5.Sprite(this.getBgTexture());
this._bgImage.interactive = false;
const launchImageSize = RectangleUtils.fitRectangle(
new PIXI5.Rectangle(0, 0, this._bgImage.width, this._bgImage.height),
new PIXI5.Rectangle(0, 0, this.root.fixedStageWidth, this.root.fixedStageHeight),
"NO_BORDER" /* NO_BORDER */
);
this._bgImage.width = launchImageSize.width;
this._bgImage.height = launchImageSize.height;
this.addChild(this._bgImage);
}
getBgTexture() {
return this.assetsLoader?.getTextureByName("bg");
}
createBgEffect() {
this._bgParticleEffect = new BackgroundEffect(this.root, 80);
this.addChild(this._bgParticleEffect);
}
onActivate() {
}
onDeActivate() {
}
onExit() {
}
};
// src/pixi/utils/ViewUtils.ts
import { Graphics } from "pixi.js";
var Align = /* @__PURE__ */ ((Align2) => {
Align2["LEFT"] = "left";
Align2["CENTER"] = "center";
Align2["RIGHT"] = "right";
Align2["TOP"] = "top";
Align2["BOTTOM"] = "bottom";
return Align2;
})(Align || {});
var ViewUtils = class {
// Функция возвращает видимое расстояние между двумя контейнерами
static getVisibleGap(containerA, containerB) {
const boundsA = containerA.getBounds();
const boundsB = containerB.getBounds();
let horizontalGap = 0;
if (boundsA.right < boundsB.left) {
horizontalGap = boundsB.left - boundsA.right;
} else if (boundsB.right < boundsA.left) {
horizontalGap = boundsA.left - boundsB.right;
}
let verticalGap = 0;
if (boundsA.bottom < boundsB.top) {
verticalGap = boundsB.top - boundsA.bottom;
} else if (boundsB.bottom < boundsA.top) {
verticalGap = boundsA.top - boundsB.bottom;
}
return {
horizontal: horizontalGap,
vertical: verticalGap
};
}
// Функция для выравнивания pivot
static alignPivot(displayObject, horizontalAlign = "center" /* CENTER */, verticalAlign = "center" /* CENTER */) {
if (displayObject) {
const bounds = displayObject.getLocalBounds();
let pivotX = 0;
let pivotY = 0;
if (horizontalAlign === "left" /* LEFT */) {
pivotX = bounds.x;
} else if (horizontalAlign === "center" /* CENTER */) {
pivotX = bounds.x + bounds.width / 2;
} else if (horizontalAlign === "right" /* RIGHT */) {
pivotX = bounds.x + bounds.width;
}
if (verticalAlign === "top" /* TOP */) {
pivotY = bounds.y;
} else if (verticalAlign === "center" /* CENTER */) {
pivotY = bounds.y + bounds.height / 2;
} else if (verticalAlign === "bottom" /* BOTTOM */) {
pivotY = bounds.y + bounds.height;
}
displayObject.pivot.set(pivotX, pivotY);
} else {
console.warn("alignPivot: displayObject \u043D\u0435 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 getLocalBounds.");
}
}
static isEqualRects(rect1, rect2) {
if (rect1 && rect2) {
return rect1.x === rect2.x && rect1.y === rect2.y && rect1.width === rect2.width && rect1.height === rect2.height;
}
return false;
}
static putOnTop(view) {
if (view && view.parent) {
view.parent.setChildIndex(view, view.parent.children.length - 1);
}
}
static fitToWidth(fitDisplayObject, fitWidth, fitIfBigger = true, fitIfSmaller = true) {
if (fitDisplayObject && fitWidth > 0) {
let fitDisplayObjectWidth = fitDisplayObject.width;
if (fitDisplayObjectWidth != fitWidth) {
if (!fitIfBigger && fitDisplayObjectWidth > fitWidth) {
return;
}
if (!fitIfSmaller && fitDisplayObjectWidth < fitWidth) {
return;
}
fitDisplayObject.scale.set(fitWidth / fitDisplayObjectWidth * fitDisplayObject.scale.x);
}
}
}
static fitToHeight(fitDisplayObject, fitHeight, fitIfBigger = true, fitIfSmaller = true) {
if (fitDisplayObject && fitHeight > 0) {
let fitDisplayObjectHeight = fitDisplayObject.height;
if (fitDisplayObjectHeight != fitHeight) {
if (!fitIfBigger && fitDisplayObjectHeight > fitHeight) {
return;
}
if (!fitIfSmaller && fitDisplayObjectHeight < fitHeight) {
return;
}
fitDisplayObject.scale.set(fitHeight / fitDisplayObjectHeight * fitDisplayObject.scale.x);
}
}
}
static createRoundedRect(width = 1, height = 1, color, cornerRadius, lineWidth = 0, lineColor) {
let bg = new Graphics();
if (lineWidth) {
bg.lineStyle(lineWidth, lineColor);
}
bg.beginFill(color);
bg.drawRoundedRect(0, 0, width, height, cornerRadius);
bg.endFill();
return bg;
}
static createRect(width = 1, height = 1, color = "0x000000") {
let bg = new Graphics();
bg.beginFill(color);
bg.drawRect(0, 0, width, height);
bg.endFill();
return bg;
}
};
// src/pixi/base/GameWaiter.ts
var GameWaiter = class extends GameView {
constructor(root, container) {
super();
this._isShowed = false;
this.root = root;
this._container = container;
}
destroy() {
super.destroy();
}
createSpinner() {
return this.root.uiLib.create("spinner");
}
show() {
if (this._isShowed || this.destroyed) {
return;
}
this._isShowed = true;
this._blackImage = ViewUtils.createRect(this.root.fixedStageWidth, this.root.fixedStageHeight, "0x000000");
this._container.addChild(this._blackImage);
this._spinner = this.createSpinner();
this._spinner.interactive = false;
ViewUtils.alignPivot(this._spinner);
this._spinner.x = this.root.fixedStageWidth / 2;
this._spinner.y = this.root.fixedStageHeight / 2;
this._spinner.alpha = 0.01;
this._spinner.scale.set(0.01);
this._spinner.playLoop();
this._container.addChild(this._spinner);
this._spinnerTween = this.root.juggler.tween(this._spinner, 0.4, {
alpha: 1,
scale: {
x: 1,
y: 1
}
}).delay(0.2).start();
this._blackTween = this.root.juggler.tween(this._blackImage, 0.4, {
alpha: 0.4
}).start();
}
hide() {
if (this._isShowed) {
this._spinnerTween?.destroy();
this._blackTween?.destroy();
GameObject.destroy(this._spinner);
GameObject.destroy(this._blackImage);
this._isShowed = false;
}
}
};
// src/pixi/base/GameDialog.ts
import { Easing as Easing2 } from "@tweenjs/tween.js";
// src/managers/SoundManager.ts
import { Howl } from "howler";
// src/utils/DateUtils.ts
var _DateUtils = class _DateUtils {
static get currentUTCDate() {
const localDate = /* @__PURE__ */ new Date();
return new Date(localDate.getTime() + localDate.getTimezoneOffset() * 6e4);
}
static get currentDateFormatted() {
const date = /* @__PURE__ */ new Date();
const dtf = new Intl.DateTimeFormat("en-US", { year: "numeric", month: "2-digit", day: "2-digit" });
return dtf.format(date);
}
static get currentTime() {
return _DateUtils.dateTime + (performance.now() - _DateUtils.dateTimestamp);
}
static msToSeconds(ms) {
return ms / 1e3;
}
static msToMinutes(ms) {
return _DateUtils.msToSeconds(ms) / 60;
}
static msToHours(ms) {
return ms / 1e3 / 60 / 60;
}
static secondsToDays(sec) {
return _DateUtils.msToHours(_DateUtils.secondsToMs(sec)) / 24;
}
static hoursToSeconds(hours) {
return _DateUtils.minutesToSeconds(_DateUtils.hoursToMinutes(hours));
}
static hoursToMinutes(hours) {
return hours * 60;
}
static daysToMs(days) {
return _DateUtils.hoursToMS(24 * days);
}
static daysToMinutes(days) {
return _DateUtils.hoursToMinutes(24 * days);
}
static minutesToSeconds(min) {
return min * 60;
}
static hoursToMS(hours) {
return _DateUtils.minutesToMs(hours * 60);
}
static minutesToMs(min) {
return _DateUtils.secondsToMs(min * 60);
}
static secondsToMs(sec) {
return sec * 1e3;
}
static getDaysBetween(d1, d2) {
const MS_PER_DAY = 864e5;
const date1 = new Date(d1.getFullYear(), d1.getMonth(), d1.getDate());
const date2 = new Date(d2.getFullYear(), d2.getMonth(), d2.getDate());
return Math.round((date2.getTime() - date1.getTime()) / MS_PER_DAY);
}
static getTimeString(index, fps) {
let sec = Math.round(index / fps);
const min = Math.floor(sec / 60);
sec = sec % 60;
const mStr = min < 10 ? "0" + min : min.toString();
const sStr = sec < 10 ? "0" + sec : sec.toString();
return mStr + ":" + sStr;
}
static getTimeStringFromSeconds(seconds) {
const min = Math.floor(seconds / 60);
seconds = seconds % 60;
const mStr = min < 10 ? "0" + min : min.toString();
const sStr = seconds < 10 ? "0" + seconds : seconds.toString();
return mStr + ":" + sStr;
}
static getNowTimeString() {
const today = /* @__PURE__ */ new Date();
const minutes = today.getMinutes();
const hours = today.getHours();
const seconds = today.getSeconds();
return `${hours}:${minutes}:${seconds}`;
}
static getTimeBetween(d1, d2) {
const date1 = new Date(d1.getFullYear(), d1.getMonth(), d1.getDate(), d1.getHours(), d1.getMinutes(), d1.getSeconds());
const date2 = new Date(d2.getFullYear(), d2.getMonth(), d2.getDate(), d2.getHours(), d2.getMinutes(), d2.getSeconds());
return date2.getTime() - date1.getTime();
}
static isNextDay(d1, d2) {
const d1Year = d1.getFullYear();
const d2Year = d2.getFullYear();
const d1Month = d1.getMonth();
const d2Month = d2.getMonth();
const d1Day = d1.getDate();
const d2Day = d2.getDate();
return d2Year > d1Year || d2Month > d1Month || d2Day > d1Day;
}
static isTheSameDays(d1, d2) {
const d1Year = d1.getFullYear();
const d2Year = d2.getFullYear();
const d1Month = d1.getMonth();
const d2Month = d2.getMonth();
const d1Day = d1.getDate();
const d2Day = d2.getDate();
return d2Year === d1Year && d2Month === d1Month && d2Day === d1Day;
}
static parseDateStringToDate(utcParseString) {
if (!utcParseString) {
return null;
}
const matches = utcParseString.match(/(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})\.(\d{3})Z/);
if (!matches) {
return null;
}
const d = /* @__PURE__ */ new Date();
d.setFullYear(Number(matches[1]));
d.setMonth(Number(matches[2]) - 1);
d.setDate(Number(matches[3]));
d.setHours(Number(matches[4]));
d.setMinutes(Number(matches[5]));
d.setSeconds(Number(matches[6]));
d.setMilliseconds(Number(matches[7]));
return d;
}
static parseObjectToDate(o) {
if (o && o.__type === "Date" && o.iso) {
return _DateUtils.parseDateStringToDate(o.iso);
}
return null;
}
static formatTimeMs(ms, dayLng, hourLng, minLng, secLng) {
let out = "";
let days = 0;
let hours = 0;
let minutes = 0;
let seconds = _DateUtils.msToSeconds(ms);
minutes = Math.floor(seconds / 60);
seconds -= minutes * 60;
hours = Math.floor(minutes / 60);
minutes -= hours * 60;
days = Math.floor(hours / 24);
hours -= days * 24;
if (days > 0) {
out = `${days}${dayLng}${hours > 0 ? ` ${hours}${hourLng}` : ""}`;
} else if (hours > 0) {
out = `${hours}${hourLng}${minutes > 0 ? ` ${minutes}${minLng}` : ""}`;
} else {
out = `${minutes > 0 ? `${minutes}${minLng} ` : ""}${seconds > 0 ? `${seconds}${secLng}` : ""}`;
}
return out;
}
};
_DateUtils.MINUTE = 60 * 1e3;
_DateUtils.HOUR = 60 * _DateUtils.MINUTE;
_DateUtils.DAY = 24 * _DateUtils.HOUR;
_DateUtils.dateTime = (/* @__PURE__ */ new Date()).getTime();
_DateUtils.dateTimestamp = performance.now();
var DateUtils = _DateUtils;
// src/managers/AbstractPreferencesManager.ts
import { Preferences } from "@capacitor/preferences";
var AbstractPreferencesManager = class {
async setBoolValue(key, value) {
await Preferences.set({
key,
value: JSON.stringify(value || false)
});
}
async getBoolValue(key) {
const { value } = await Preferences.get({ key });
return Boolean(JSON.parse(value || "false"));
}
async setValue(key, value) {
await Preferences.set({
key,
value
});
}
async getValue(key) {
const { value } = await Preferences.get({ key });
return value;
}
async removeValue(key) {
await Preferences.remove({ key });
}
};
// src/managers/SoundManager.ts
var _SoundManager = class _SoundManager extends AbstractPreferencesManager {
constructor(app, needPersistence) {
super();
this.howlerSoundPool = /* @__PURE__ */ new Map();
this.howlMusic = null;
this.musicName = "";
this.soundLastPlayed = /* @__PURE__ */ new Map();
this._soundMuted = false;
this._musicMuted = false;
this.app = app;
this._needPersistence = needPersistence;
}
async init() {
if (this._needPersistence) {
this._soundMuted = await this.getBoolValue(_SoundManager.SOUND_MUTED_KEY);
this._musicMuted = await this.getBoolValue(_SoundManager.MUSIC_MUTED_KEY);
}
}
async playSound(soundName, timeGapBetweenNextSameSound = 100) {
if (this.soundMuted) {
return;
}
const lastPlayedTime = this.soundLastPlayed.get(soundName) || 0;
const currentTime = DateUtils.currentTime;
if (currentTime - lastPlayedTime >= timeGapBetweenNextSameSound) {
if (!this.howlerSoundPool.has(soundName)) {
const sound = new Howl({
src: [`assets/sounds/${soundName}.mp3`],
volume: _SoundManager.SOUND_VOLUME,
html5: false
});
this.howlerSoundPool.set(soundName, sound);
}
this.howlerSoundPool.get(soundName)?.play();
this.soundLastPlayed.set(soundName, currentTime);
}
}
async onActivate() {
this.playMusic(this.musicName);
}
async onDeActivate() {
this.unloadSounds();
this.unloadMusic();
Howler.stop();
Howler.unload();
}
playMusic(musicName) {
if (!musicName) {
return;
}
if (this._musicMuted) {
this.musicName = musicName;
return;
}
if (this.musicName === musicName && this.howlMusic) {
return;
}
this.unloadMusic();
this.musicName = musicName;
try {
this.howlMusic = new Howl({
src: [`assets/music/${musicName}.mp3`],
volume: _SoundManager.MUSIC_VOLUME,
loop: true,
html5: false
});
this.howlMusic.play();
this.howlMusic.loop();
} catch (error) {
this.app.error.handleCaughtError(error, "SoundService:playMusic: " + musicName);
}
}
unloadMusic() {
try {
if (this.howlMusic) {
this.howlMusic.stop();
this.howlMusic.unload();
this.howlMusic = null;
}
} catch (error) {
this.app.error.handleCaughtError(error, "SoundService:unloadMusic");
}
}
unloadSounds() {
try {
this.howlerSoundPool.forEach((sound) => {
sound.stop();
sound.unload();
});
this.howlerSoundPool.clear();
} catch (error) {
this.app.error.handleCaughtError(error, "SoundService:unloadSounds");
}
}
get soundMuted() {
return this._soundMuted;
}
set soundMuted(value) {
if (this._soundMuted != value) {
this._soundMuted = value;
if (this._needPersistence) {
void this.setBoolValue(_SoundManager.SOUND_MUTED_KEY, value);
}
if (this._soundMuted) {
this.unloadSounds();
}
}
}
async unmute() {
if (this._musicMuted) {
this._musicMuted = false;
if (this._needPersistence) {
void this.setBoolValue(_SoundManager.MUSIC_MUTED_KEY, false);
}
if (this.musicName) {
this.playMusic(this.musicName);
}
}
}
async mute() {
if (!this._musicMuted) {
this._musicMuted = true;
if (this._needPersistence) {
void this.setBoolValue(_SoundManager.MUSIC_MUTED_KEY, true);
}
this.unloadMusic();
}
}
};
_SoundManager.SOUND_VOLUME = 0.8;
_SoundManager.MUSIC_VOLUME = 0.6;
_SoundManager.Click = "Click";
_SoundManager.DialogOpen = "DialogOpen";
_SoundManager.DialogClose = "DialogClose";
_SoundManager.SOUND_MUTED_KEY = "SOUND_MUTED_KEY";
_SoundManager.MUSIC_MUTED_KEY = "MUSIC_MUTED_KEY";
var SoundManager = _SoundManager;
// src/pixi/base/GameDialog.ts
var _GameDialog = class _GameDialog extends GameView {
constructor() {
super(...arguments);
this.assetsLoader = null;
this._waiter = null;
this._dialog = null;
this._blackBack = null;
this._dialogContent = null;
this._isInHideProcess = false;
}
// internal, used in App, don't assign explicitly
get btnClose() {
return this._dialogContent?.getButtonByLabel("btn_close");
}
get title() {
return null;
}
get dialogContentMoldName() {
return "";
}
get dialogScale() {
let multiplier = 1;
if (this.root.app.device.isTablet || this.root.app.device.isDesktop) {
multiplier = this.tabletMultiplier;
}
if (this.root.app.device.isIOS) {
return 1.3 * multiplier;
}
if (this.root.app.device.isAndroid) {
return 1.2 * multiplier;
}
return multiplier;
}
get tabletMultiplier() {
return 0.8;
}
get backgroundAlpha() {
return 0.5;
}
get createDialogLib() {
return this.root.uiLib;
}
playShowSound() {
void this.root.app.sound.playSound(SoundManager.DialogOpen);
}
async loadAssets(onLoaded) {
if (onLoaded) {
onLoaded();
}
}
onAdded() {
this.createBlackBack();
this.createBackgroundEffect();
}
destroy() {
this._dialog = GameObject.destroy(this._dialog);
this._blackBack = GameObject.destroy(this._blackBack);
this.assetsLoader = GameObject.destroy(this.assetsLoader);
this.hideWaiter();
this._dialogContent = GameObject.destroy(this._dialogContent);
this._shouldDisposeCallback = null;
super.destroy();
}
showWaiter() {
this.hideWaiter();
this._waiter = this.root.uiLib.create("loading_anim");
ViewUtils.fitToHeight(this._waiter, this.root.adapt(150), true, true);
ViewUtils.alignPivot(this._waiter);
this._waiter.x = this.root.fixedStageWidth / 2;
this._waiter.y = this.root.fixedStageHeight / 2;
this._waiter.playLoop();
this.addChildAt(this._waiter, this.children?.length);
}
hideWaiter() {
if (this._waiter) {
this._waiter = GameObject.destroy(this._waiter);
}
}
createDialog() {
this._dialog = new GameView();
this.addChild(this._dialog);
this._dialogContent = this.createDialogLib.create(this.dialogContentMoldName);
this._dialog.addChild(this._dialogContent);
if (this.btnClose) {
this.btnClose.clickCallback = this.onButtonClose.bind(this);
}
this.createTitle();
}
show() {
this.playShowSound();
if (this._dialog) {
this._dialog.interactive = false;
this._dialog.scale = this.dialogScale;
ViewUtils.fitToHeight(this._dialog, this.root.fixedStageSafeHeight - this.root.adapt(100), true, false);
ViewUtils.alignPivot(this._dialog);
this._dialog.x = this.getCenterX();
this._dialog.y = -this._dialog.height;
this.root.juggler.tween(this._dialog, _GameDialog.SHOW_TIME, {
y: this.getCenterY()
}).easing(Easing2.Back.Out).onComplete(this.onDialogShowEnd.bind(this)).start();
}
}
hide() {
if (this._isInHideProcess) {
return;
}
this._isInHideProcess = true;
this.interactive = false;
this.playCloseSound();
this.hideBlackBack();
this.hideDialog();
}
onButtonClose() {
this.interactive = false;
void this.root.app.sound.playSound(SoundManager.Click);
this.hide();
}
createBlackBack() {
this._blackBack = ViewUtils.createRect(this.root.fixedStageWidth, this.root.fixedStageHeight, "0x000000");
this.addChild(this._blackBack);
this._blackBack.interactive = true;
this.root.juggler.tween(this._blackBack, 0.5 * _GameDialog.SHOW_TIME, {
alpha: this.backgroundAlpha
}).start();
}
createBackgroundEffect() {
}
createTitle() {
if (this.title) {
const titlePlacer = this._dialogContent.getPlacerByLabel("txt_title");
titlePlacer.place(this.root.dialogTitleTextLib.createBitmapText(this.title, titlePlacer.width, titlePlacer.height)).fitHeight(true, true).fitWidth(true, false).alignCenter();
}
}
getCenterX() {
return this.root.fixedStageWidth / 2;
}
getCenterY() {
return this.root.safeZoneTop + this.root.fixedStageSafeHeight / 2;
}
hideDialog() {
if (this._dialog) {
this._dialog.interactive = false;
this.root.juggler.tween(this._dialog, _GameDialog.SHOW_TIME, {
delay: 0.1,
y: -this._dialog.height
}).easing(Easing2.Back.In).onComplete(this.disposeFromNavigator.bind(this)).start();
} else {
this.disposeFromNavigator();
}
}
onDialogShowEnd() {
if (this._dialog) {
this._dialog.interactive = true;
}
}
playCloseSound() {
void this.root.app.sound.playSound(SoundManager.DialogClose);
}
disposeFromNavigator() {
if (this._shouldDisposeCallback) {
this._shouldDisposeCallback(this);
}
}
hideBlackBack() {
if (this._blackBack) {
this.root.juggler.tween(this._blackBack, 0.5 * _GameDialog.SHOW_TIME, {
alpha: 0
}).start();
}
}
};
_GameDialog.SHOW_TIME = 0.6;
var GameDialog = _GameDialog;
// src/utils/ObjectUtils.ts
var ObjectUtils = class {
static truncateString(str, maxLength = 10, replace = "..") {
return str.length > maxLength ? str.substring(0, maxLength - replace.length) + replace : str;
}
static getQualifiedClassName(obj) {
if (obj === null || obj === void 0) {
return String(obj);
}
return obj.constructor.name;
}
static getBase64Size(base64String) {
const padding = base64String.endsWith("==") ? 2 : base64String.endsWith("=") ? 1 : 0;
const base64Length = base64String.length;
return base64Length * 3 / 4 - padding;
}
static getKeyObjValue(json, key, fallback = null) {
if (json && json[key]) {
return json[key];
}
return fallback;
}
static getKeyBoolValue(json, key, fallback = false) {
if (json && json.hasOwnProperty(key)) {
return Boolean(json[key]);
}
return fallback;
}
static getKeyStringValue(json, key, fallback = "") {
if (json && typeof json[key] === "string" && json[key].length > 0) {
return json[key];
}
return fallback;
}
static getKeyNumberValue(json, key, fallback = 0) {
if (json && !isNaN(json[key])) {
return Number(json[key]);
}
return fallback;
}
static getKeyIntValue(json, key, fallback = 0) {
if (json && !isNaN(json[key])) {
return Math.floor(Number(json[key]));
}
return fallback;
}
static getKeyArrayValue(json, key, fallback = []) {
if (json && Array.isArray(json[key])) {
return json[key];
}
return fallback;
}
static getKeyDateValue(json, key, fallback = null) {
if (json && json[key] instanceof Date) {
return json[key];
}
if (json && typeof json[key] === "string") {
const