@drincs/pixi-vn
Version:
Pixi'VN is a npm package that provides various features for creating visual novels.
3,051 lines (3,012 loc) • 105 kB
JavaScript
var pixi_js = require('pixi.js');
var deepDiff = require('deep-diff');
var sha1 = require('crypto-js/sha1');
var devtools = require('@pixi/devtools');
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
var sha1__default = /*#__PURE__*/_interopDefault(sha1);
var __defProp = Object.defineProperty;
var __defProps = Object.defineProperties;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __propIsEnum = Object.prototype.propertyIsEnumerable;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp.call(b, prop))
__defNormalProp(a, prop, b[prop]);
if (__getOwnPropSymbols)
for (var prop of __getOwnPropSymbols(b)) {
if (__propIsEnum.call(b, prop))
__defNormalProp(a, prop, b[prop]);
}
return a;
};
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
var __decorateClass = (decorators, target, key, kind) => {
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
for (var i = decorators.length - 1, decorator; i >= 0; i--)
if (decorator = decorators[i])
result = (kind ? decorator(target, key, result) : decorator(result)) || result;
if (kind && result) __defProp(target, key, result);
return result;
};
var __async = (__this, __arguments, generator) => {
return new Promise((resolve, reject) => {
var fulfilled = (value) => {
try {
step(generator.next(value));
} catch (e) {
reject(e);
}
};
var rejected = (value) => {
try {
step(generator.throw(value));
} catch (e) {
reject(e);
}
};
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
step((generator = generator.apply(__this, __arguments)).next());
});
};
// src/classes/CanvasEvent.ts
var CanvasEvent = class {
constructor() {
/**
* Get the id of the event. This variable is used in the system to get the event by id, {@link getEventInstanceById}
*/
this.id = "event_id_not_set";
this.id = this.constructor.prototype.id;
}
fn(_event, _element) {
throw new Error("[Pixi'VN] The method CanvasEvent.fn() must be overridden");
}
};
function getStepSha1(step) {
let sha1String = sha1__default.default(step.toString().toLocaleLowerCase());
return sha1String.toString();
}
function checkIfStepsIsEqual(step1, step2) {
return step1 === step2;
}
// src/classes/LabelAbstract.ts
var LabelAbstract = class {
/**
* @param id is the id of the label
* @param props is the properties of the label
*/
constructor(id, props) {
this._id = id;
this._onStepStart = props == null ? void 0 : props.onStepStart;
this._onLoadStep = props == null ? void 0 : props.onLoadStep;
this._onStepEnd = props == null ? void 0 : props.onStepEnd;
this._choiseIndex = props == null ? void 0 : props.choiseIndex;
}
/**
* Get the id of the label. This variable is used in the system to get the label by id, {@link getLabelById}
*/
get id() {
return this._id;
}
/**
* Get the corresponding steps number
* @param externalSteps
* @returns Numer of corresponding steps, for example, if externalSteps is [ABC, DEF, GHI] and the steps of the label is [ABC, GHT], the result will be 1
*/
getCorrespondingStepsNumber(externalSteps) {
if (externalSteps.length === 0) {
return 0;
}
let res = 0;
externalSteps.forEach((step, index) => {
if (checkIfStepsIsEqual(step, this.steps[index])) {
res = index;
}
});
return res;
}
/**
* Is a function that will be executed in {@link Label#onStepStart} and when the user goes back to it or when the user laods a save file.
* @returns Promise<void> or void
*/
get onStepStart() {
return (stepIndex, label) => __async(this, null, function* () {
if (this._onLoadStep) {
yield this._onLoadStep(stepIndex, label);
}
if (this._onStepStart) {
return yield this._onStepStart(stepIndex, label);
}
});
}
/**
* Get the function that will be executed a old step is reloaded. A step is reloaded when the user goes back to it or when the user laods a save file.
* @returns Promise<void> or void
*/
get onLoadStep() {
return this._onLoadStep;
}
/**
* Is a function that will be executed when the step ends.
* @returns Promise<void> or void
*/
get onStepEnd() {
return this._onStepEnd;
}
get choiseIndex() {
return this._choiseIndex;
}
};
// src/classes/Label.ts
var Label = class extends LabelAbstract {
/**
* @param id is the id of the label
* @param steps is the list of steps that the label will perform
* @param props is the properties of the label
*/
constructor(id, steps, props) {
super(id, props);
this._steps = steps;
}
/**
* Get the steps of the label.
*/
get steps() {
if (typeof this._steps === "function") {
return this._steps();
}
return this._steps;
}
};
// src/classes/CloseLabel.ts
var CLOSE_LABEL_ID = "__close-label-id__";
function newCloseLabel(choiseIndex) {
return new Label(CLOSE_LABEL_ID, [], {
choiseIndex
});
}
// src/decorators/LabelDecorator.ts
var registeredLabels = {};
function newLabel(id, steps, props) {
if (registeredLabels[id]) {
console.info(`[Pixi'VN] Label ${id} already exists, it will be overwritten`);
}
let label = new Label(id, steps, props);
registeredLabels[id] = label;
return label;
}
function getLabelById(id) {
let label = registeredLabels[id];
if (!label) {
console.error(`[Pixi'VN] Label ${id} not found`);
return;
}
return label;
}
// src/functions/CanvasUtility.ts
function getTextureMemory(texture) {
let sourceTexture = texture.source;
let textureMemory = {
image: sourceTexture.label
};
return textureMemory;
}
function exportCanvasElement(element) {
return element.memory;
}
function importCanvasElement(memory) {
let element = getCanvasElementInstanceById(memory.pixivnId);
if (element) {
element.memory = memory;
} else {
throw new Error("[Pixi'VN] The element " + memory.pixivnId + " could not be created");
}
return element;
}
// src/classes/canvas/CanvasContainer.ts
var CANVAS_CONTAINER_ID = "CanvasContainer";
var CanvasContainer = class extends pixi_js.Container {
constructor(options) {
super(options);
this.pixivnId = CANVAS_CONTAINER_ID;
this.pixivnId = this.constructor.prototype.pixivnId || CANVAS_CONTAINER_ID;
}
get memory() {
let memory = getMemoryContainer(this);
this.children.forEach((child) => {
memory.elements.push(exportCanvasElement(child));
});
return memory;
}
set memory(value) {
setMemoryContainer(this, value);
value.elements.forEach((child) => {
this.addChild(importCanvasElement(child));
});
}
};
function getMemoryContainer(element) {
let className = "CanvasContainer";
if (element.hasOwnProperty("pixivnId")) {
className = element.pixivnId;
}
return {
pixivnId: className,
elements: [],
width: element.width,
height: element.height,
isRenderGroup: element.isRenderGroup,
blendMode: element.blendMode,
tint: element.tint,
alpha: element.alpha,
angle: element.angle,
renderable: element.renderable,
rotation: element.rotation,
scale: { x: element.scale.x, y: element.scale.y },
pivot: { x: element.pivot.x, y: element.pivot.y },
position: { x: element.position.x, y: element.position.y },
skew: { x: element.skew.x, y: element.skew.y },
visible: element.visible,
x: element.x,
y: element.y,
boundsArea: element.boundsArea,
cursor: element.cursor,
eventMode: element.eventMode,
interactive: element.interactive,
interactiveChildren: element.interactiveChildren,
hitArea: element.hitArea
};
}
function setMemoryContainer(element, memory) {
memory.isRenderGroup && (element.isRenderGroup = memory.isRenderGroup);
memory.blendMode && (element.blendMode = memory.blendMode);
memory.tint && (element.tint = memory.tint);
memory.alpha && (element.alpha = memory.alpha);
memory.angle && (element.angle = memory.angle);
memory.renderable && (element.renderable = memory.renderable);
memory.rotation && (element.rotation = memory.rotation);
if (memory.scale) {
if (typeof memory.scale === "number") {
element.scale.set(memory.scale, memory.scale);
} else {
element.scale.set(memory.scale.x, memory.scale.y);
}
}
if (memory.pivot) {
if (typeof memory.pivot === "number") {
element.pivot.set(memory.pivot, memory.pivot);
} else {
element.pivot.set(memory.pivot.x, memory.pivot.y);
}
}
memory.position && element.position.set(memory.position.x, memory.position.y);
memory.skew && element.skew.set(memory.skew.x, memory.skew.y);
memory.visible && (element.visible = memory.visible);
memory.x && (element.x = memory.x);
memory.y && (element.y = memory.y);
memory.boundsArea && (element.boundsArea = memory.boundsArea);
memory.cursor && (element.cursor = memory.cursor);
memory.eventMode && (element.eventMode = memory.eventMode);
memory.interactive && (element.interactive = memory.interactive);
memory.interactiveChildren && (element.interactiveChildren = memory.interactiveChildren);
memory.hitArea && (element.hitArea = memory.hitArea);
memory.width && (element.width = memory.width);
memory.height && (element.height = memory.height);
}
function getTexture(imageUrl) {
return __async(this, null, function* () {
if (pixi_js.Assets.cache.has(imageUrl)) {
return pixi_js.Assets.get(imageUrl);
}
return pixi_js.Assets.load(imageUrl).then((texture) => {
if (!texture) {
console.error("[Pixi'VN] Texture not found", imageUrl);
return;
}
if (!(texture instanceof pixi_js.Texture)) {
console.error("[Pixi'VN] File not is a image", imageUrl);
return;
}
return texture;
}).catch((e) => {
console.error("[Pixi'VN] Error loading image", e);
return;
});
});
}
function getFillGradientFillPattern(prop, propName) {
if (!(prop instanceof Object)) {
return prop;
}
console.warn(`[Pixi'VN] CanvasText.style.${propName} is a FillGradient or FillPattern, this is not supported yet.`, prop);
return void 0;
}
function getTextStyle(style) {
return {
align: style.align,
breakWords: style.breakWords,
dropShadow: style.dropShadow,
fill: getFillGradientFillPattern(style.stroke, "fill"),
fontFamily: style.fontFamily,
fontSize: style.fontSize,
fontStyle: style.fontStyle,
fontVariant: style.fontVariant,
fontWeight: style.fontWeight,
leading: style.leading,
letterSpacing: style.letterSpacing,
lineHeight: style.lineHeight,
padding: style.padding,
stroke: getFillGradientFillPattern(style.stroke, "stroke"),
textBaseline: style.textBaseline,
trim: style.trim,
whiteSpace: style.whiteSpace,
wordWrap: style.wordWrap,
wordWrapWidth: style.wordWrapWidth
};
}
// src/decorators/EventDecorator.ts
var registeredEvents = {};
function eventDecorator(name) {
return function(target) {
if (!name) {
name = target.name;
}
if (registeredEvents[name]) {
console.info(`[Pixi'VN] Event ${name} already exists, it will be overwritten`);
}
target.prototype.id = name;
registeredEvents[name] = target;
};
}
function getEventTypeById(eventId) {
try {
let eventType = registeredEvents[eventId];
if (!eventType) {
console.error(`[Pixi'VN] Event ${eventId} not found`);
return;
}
new eventType();
return eventType;
} catch (e) {
console.error(`[Pixi'VN] Error while getting Event ${eventId}`, e);
return;
}
}
function getEventInstanceById(eventId) {
try {
let eventType = registeredEvents[eventId];
if (!eventType) {
console.error(`[Pixi'VN] Event ${eventId} not found`);
return;
}
let event = new eventType();
return event;
} catch (e) {
console.error(`[Pixi'VN] Error while getting Event ${eventId}`, e);
return;
}
}
// src/classes/canvas/CanvasSprite.ts
var CANVAS_SPRITE_ID = "CanvasSprite";
var CanvasSprite = class _CanvasSprite extends pixi_js.Sprite {
constructor(options) {
super(options);
this.pixivnId = CANVAS_SPRITE_ID;
this._onEvents = {};
this.pixivnId = this.constructor.prototype.pixivnId || CANVAS_SPRITE_ID;
}
get memory() {
return getMemorySprite(this);
}
set memory(value) {
setMemorySprite(this, value);
}
get onEvents() {
return this._onEvents;
}
/**
* is same function as on(), but it keeps in memory the children.
* @param event The event type, e.g., 'click', 'mousedown', 'mouseup', 'pointerdown', etc.
* @param eventClass The class that extends CanvasEvent.
* @returns
* @example
* ```typescript
* \@eventDecorator()
* export class EventTest extends CanvasEvent<CanvasSprite> {
* override fn(event: CanvasEventNamesType, sprite: CanvasSprite): void {
* if (event === 'pointerdown') {
* sprite.scale.x *= 1.25;
* sprite.scale.y *= 1.25;
* }
* }
* }
* ```
*
* ```typescript
* let sprite = addImage("alien", 'https://pixijs.com/assets/eggHead.png')
* await sprite.load()
*
* sprite.eventMode = 'static';
* sprite.cursor = 'pointer';
* sprite.onEvent('pointerdown', EventTest);
*
* GameWindowManager.addCanvasElement("bunny", sprite);
* ```
*/
onEvent(event, eventClass) {
let id = eventClass.prototype.id;
let instance = getEventInstanceById(id);
this._onEvents[event] = id;
if (instance) {
super.on(event, () => {
instance.fn(event, this);
});
}
return this;
}
/**
* on() does not keep in memory the event class, use onEvent() instead
* @deprecated
* @private
* @param event
* @param fn
* @param context
*/
on(event, fn, context) {
return super.on(event, fn, context);
}
static from(source, skipCache) {
let sprite = pixi_js.Sprite.from(source, skipCache);
let mySprite = new _CanvasSprite();
mySprite.texture = sprite.texture;
return mySprite;
}
};
function getMemorySprite(element) {
let temp = getMemoryContainer(element);
return __spreadProps(__spreadValues({}, temp), {
pixivnId: element.pixivnId,
textureImage: getTextureMemory(element.texture),
anchor: { x: element.anchor.x, y: element.anchor.y },
roundPixels: element.roundPixels,
onEvents: element.onEvents
});
}
function setMemorySprite(element, memory) {
setMemoryContainer(element, memory);
getTexture(memory.textureImage.image).then((texture) => {
if (texture) {
element.texture = texture;
}
});
if (memory.anchor) {
if (typeof memory.anchor === "number") {
element.anchor.set(memory.anchor, memory.anchor);
} else {
element.anchor.set(memory.anchor.x, memory.anchor.y);
}
}
memory.roundPixels && (element.roundPixels = memory.roundPixels);
for (let event in memory.onEvents) {
let id = memory.onEvents[event];
let instance = getEventTypeById(id);
if (instance) {
element.onEvent(event, instance);
}
}
}
// src/classes/canvas/CanvasImage.ts
var CANVAS_IMAGE_ID = "CanvasImage";
var CanvasImage = class _CanvasImage extends CanvasSprite {
constructor(options, imageLink) {
super(options);
this.pixivnId = CANVAS_IMAGE_ID;
this.imageLink = "";
if (imageLink) {
this.imageLink = imageLink;
}
}
get memory() {
return __spreadProps(__spreadValues({}, getMemorySprite(this)), {
pixivnId: this.pixivnId,
imageLink: this.imageLink
});
}
set memory(memory) {
setMemorySprite(this, memory);
this.imageLink = memory.imageLink;
}
static from(source, skipCache) {
let sprite = pixi_js.Sprite.from(source, skipCache);
let mySprite = new _CanvasImage();
mySprite.texture = sprite.texture;
return mySprite;
}
/**
* Load the image from the link and set the texture of the sprite.
* @param image The link of the image. If it is not set, it will use the imageLink property.
* @returns A promise that resolves when the image is loaded.
*/
load(image) {
return __async(this, null, function* () {
if (!image) {
image = this.imageLink;
}
return getTexture(this.imageLink).then((texture) => {
if (texture) {
this.texture = texture;
}
}).catch((e) => {
console.error("[Pixi'VN] Error into CanvasImage.load()", e);
});
});
}
};
var CANVAS_TEXT_ID = "CanvasText";
var CanvasText = class extends pixi_js.Text {
constructor(options) {
super(options);
this.pixivnId = CANVAS_TEXT_ID;
this._onEvents = {};
this.pixivnId = this.constructor.prototype.pixivnId || CANVAS_TEXT_ID;
}
get memory() {
return getMemoryText(this);
}
set memory(value) {
setMemoryText(this, value);
}
get onEvents() {
return this._onEvents;
}
/**
* is same function as on(), but it keeps in memory the children.
* @param event The event type, e.g., 'click', 'mousedown', 'mouseup', 'pointerdown', etc.
* @param eventClass The class that extends CanvasEvent.
* @returns
* @example
* ```typescript
* \@eventDecorator()
* export class EventTest extends CanvasEvent<CanvasText> {
* override fn(event: CanvasEventNamesType, text: CanvasText): void {
* if (event === 'pointerdown') {
* text.scale.x *= 1.25;
* text.scale.y *= 1.25;
* }
* }
* }
* ```
*
* ```typescript
* const text = new CanvasText();
* text.text = "Hello World"
*
* text.eventMode = 'static';
* text.cursor = 'pointer';
* text.onEvent('pointerdown', EventTest);
*
* GameWindowManager.addCanvasElement("text", text);
* ```
*/
onEvent(event, eventClass) {
let id = eventClass.prototype.id;
let instance = getEventInstanceById(id);
this._onEvents[event] = id;
if (instance) {
super.on(event, () => {
instance.fn(event, this);
});
}
return this;
}
/**
* on() does not keep in memory the event class, use onEvent() instead
* @deprecated
* @private
* @param event
* @param fn
* @param context
*/
on(event, fn, context) {
return super.on(event, fn, context);
}
};
function getMemoryText(element) {
let temp = getMemoryContainer(element);
return __spreadProps(__spreadValues({}, temp), {
pixivnId: element.pixivnId,
anchor: { x: element.anchor.x, y: element.anchor.y },
text: element.text,
resolution: element.resolution,
style: getTextStyle(element.style),
roundPixels: element.roundPixels,
onEvents: element.onEvents
});
}
function setMemoryText(element, memory) {
setMemoryContainer(element, memory);
if (memory.anchor) {
if (typeof memory.anchor === "number") {
element.anchor.set(memory.anchor, memory.anchor);
} else {
element.anchor.set(memory.anchor.x, memory.anchor.y);
}
}
memory.text && (element.text = memory.text);
memory.resolution && (element.resolution = memory.resolution);
memory.style && (element.style = memory.style);
memory.roundPixels && (element.roundPixels = memory.roundPixels);
for (let event in memory.onEvents) {
let id = memory.onEvents[event];
let instance = getEventTypeById(id);
if (instance) {
element.onEvent(event, instance);
}
}
}
// src/decorators/CanvasElementDecorator.ts
var registeredCanvasElement = {};
function getCanvasElementInstanceById(canvasId) {
try {
let eventType = registeredCanvasElement[canvasId];
if (!eventType) {
if (canvasId === CANVAS_CONTAINER_ID) {
eventType = CanvasContainer;
} else if (canvasId === CANVAS_IMAGE_ID) {
eventType = CanvasImage;
} else if (canvasId === CANVAS_SPRITE_ID) {
eventType = CanvasSprite;
} else if (canvasId === CANVAS_TEXT_ID) {
eventType = CanvasText;
}
}
if (!eventType) {
console.error(`[Pixi'VN] CanvasElement ${canvasId} not found`);
return;
}
let canvasElement = new eventType();
return canvasElement;
} catch (e) {
console.error(`[Pixi'VN] Error while getting CanvasElement ${canvasId}`, e);
return;
}
}
// src/decorators/CharacterDecorator.ts
var registeredCharacters = {};
function saveCharacter(character) {
if (Array.isArray(character)) {
character.forEach((c) => saveCharacter(c));
return;
}
if (registeredCharacters[character.id]) {
console.info(`[Pixi'VN] Character id ${character.id} already exists, it will be overwritten`);
}
registeredCharacters[character.id] = character;
}
// src/decorators/TickerDecorator.ts
var registeredTickers = {};
function tickerDecorator(name) {
return function(target) {
if (!name) {
name = target.name;
}
if (registeredTickers[name]) {
console.info(`[Pixi'VN] Ticker ${name} already exists, it will be overwritten`);
}
target.prototype.id = name;
registeredTickers[name] = target;
};
}
function geTickerInstanceById(tickerId, args, duration, priority) {
try {
let ticker = registeredTickers[tickerId];
if (!ticker) {
console.error(`[Pixi'VN] Ticker ${tickerId} not found`);
return;
}
return new ticker(args, duration, priority);
} catch (e) {
console.error(`[Pixi'VN] Error while getting Ticker ${tickerId}`, e);
return;
}
}
// src/types/CloseType.ts
var Close = "close";
// src/classes/ChoiceMenuOption.ts
var ChoiceMenuOption = class {
/**
* @param text Text to be displayed in the menu
* @param label Label to be opened when the option is selected or the id of the label
* @param props Properties to be passed to the label and olther parameters that you can use when get all the choice menu options. It be converted to a JSON string, so it cannot contain functions or classes.
* @param type Type of the label to be opened. @default "call"
*/
constructor(text, label, props, type = "call") {
/**
* Properties to be passed to the label and olther parameters that you can use when get all the choice menu options.
* @example
* ```tsx
* setChoiceMenuOptions([
* new ChoiceMenuOption("Hello", helloLabel, { disabled: true }),
* ])
* return <List>
* {getChoiceMenuOptions()?.map((item, index) => {
* return (
* <ChoiceButton
* disabled={item.props.disabled}
* onClick={() => {
* afterSelectChoice(item)
* }}
* >
* {item.text}
* </ChoiceButton>
* )
* })}
* </List>
* ```
*/
this.props = {};
this.text = text;
this._label = label;
this.type = type;
if (props) {
this.props = props;
}
}
/**
* Label to be opened when the option is selected
*/
get label() {
let label = this._label;
if (typeof label === "string") {
let res = getLabelById(label);
if (res) {
label = res;
} else {
console.error(`Label ${label} not found, so it will be closed`);
label = newCloseLabel();
}
}
return label;
}
};
var ChoiceMenuOptionClose = class {
/**
* @param text Text to be displayed in the menu
* @param closeCurrentLabel If true, the current label will be closed. @default false
*/
constructor(text, closeCurrentLabel = false) {
/**
* Label to be opened when the option is selected
*/
this.label = newCloseLabel();
/**
* Type of the label to be opened
*/
this.type = Close;
/**
* Properties to be passed to the label and olther parameters that you can use when get all the choice menu options.
* @example
* ```tsx
* setChoiceMenuOptions([
* new ChoiceMenuOption("Hello", helloLabel, { disabled: true }),
* ])
* return <List>
* {getChoiceMenuOptions()?.map((item, index) => {
* return (
* <ChoiceButton
* disabled={item.props.disabled}
* onClick={() => {
* afterSelectChoice(item)
* }}
* >
* {item.text}
* </ChoiceButton>
* )
* })}
* </List>
* ```
*/
this.props = {};
this.text = text;
this.closeCurrentLabel = closeCurrentLabel;
}
};
// src/functions/FlagsUtility.ts
function setFlag(name, value) {
let flags = GameStorageManager.getVariable(GameStorageManager.keysSystem.FLAGS_CATEGORY_KEY) || [];
{
let index = flags.indexOf(name);
if (index > -1) {
flags.splice(index, 1);
}
}
GameStorageManager.setVariable(GameStorageManager.keysSystem.FLAGS_CATEGORY_KEY, flags);
}
function getFlag(name) {
let flags = GameStorageManager.getVariable(GameStorageManager.keysSystem.FLAGS_CATEGORY_KEY) || [];
return flags.includes(name);
}
// src/functions/DialogueUtility.ts
function setDialogue(props) {
let text = "";
let character = void 0;
let dialogue;
if (typeof props === "string") {
text = props;
dialogue = new DialogueBaseModel(text, character);
} else if (Array.isArray(props)) {
text = props.join();
dialogue = new DialogueBaseModel(text, character);
} else if (!(props instanceof DialogueBaseModel)) {
if (Array.isArray(props.text)) {
text = props.text.join();
} else {
text = props.text;
}
if (props.character) {
if (typeof props.character === "string") {
character = props.character;
} else {
character = props.character.id;
}
}
dialogue = new DialogueBaseModel(text, character);
} else {
dialogue = props;
}
if (getFlag(GameStorageManager.keysSystem.ADD_NEXT_DIALOG_TEXT_INTO_THE_CURRENT_DIALOG_FLAG_KEY)) {
let glueDialogue = getDialogue();
if (glueDialogue) {
dialogue.text = `${glueDialogue.text}${dialogue.text}`;
}
setFlag(GameStorageManager.keysSystem.ADD_NEXT_DIALOG_TEXT_INTO_THE_CURRENT_DIALOG_FLAG_KEY);
}
GameStorageManager.setVariable(GameStorageManager.keysSystem.CURRENT_DIALOGUE_MEMORY_KEY, dialogue);
GameStorageManager.setVariable(GameStorageManager.keysSystem.LAST_DIALOGUE_ADDED_IN_STEP_MEMORY_KEY, GameStepManager.lastStepIndex);
}
function getDialogue() {
return GameStorageManager.getVariable(GameStorageManager.keysSystem.CURRENT_DIALOGUE_MEMORY_KEY);
}
function getChoiceMenuOptions() {
let d = GameStorageManager.getVariable(GameStorageManager.keysSystem.CURRENT_MENU_OPTIONS_MEMORY_KEY);
if (d) {
let options = [];
d.forEach((option, index) => {
if (option.type === Close) {
let itemLabel = newCloseLabel(index);
let choice = new ChoiceMenuOptionClose(option.text, option.closeCurrentLabel);
choice.label = itemLabel;
options.push(choice);
return;
}
let label = getLabelById(option.label);
if (label) {
let itemLabel = new Label(label.id, label.steps, {
onStepStart: label.onStepStart,
choiseIndex: index
});
options.push(new ChoiceMenuOption(option.text, itemLabel, option.props, option.type));
}
});
return options;
}
return void 0;
}
// src/classes/ticker/TickerBase.ts
var TickerBase = class {
/**
* @param args The arguments that you want to pass to the ticker.
* @param duration The duration of the ticker in seconds. If is undefined, the step will end only when the animation is finished (if the animation doesn't have a goal to reach then it won't finish). @default undefined
* @param priority The priority of the ticker. @default UPDATE_PRIORITY.NORMAL
*/
constructor(args, duration, priority) {
/**
* Get the id of the ticker. This variable is used in the system to get the ticker by id, {@link geTickerInstanceById}
*/
this.id = "ticker_id_not_set";
this.args = args;
this.duration = duration;
this.priority = priority;
this.id = this.constructor.prototype.id;
}
/**
* The method that will be called every frame.
* This method should be overridden and you can use GameWindowManager.addCanvasElement() to get the canvas element of the canvas, and edit them.
* @param _ticker The ticker that is calling this method
* @param _args The arguments that you passed when you added the ticker
* @param _tags The tags of the canvas elements that are connected to this ticker
* @param _tickerId The id of the ticker. You can use this to get the ticker from the {@link GameWindowManager.currentTickers}
*/
fn(_ticker, _args, _tags, _tickerId) {
throw new Error("[Pixi'VN] The method TickerBase.fn() must be overridden");
}
};
// src/classes/ticker/FadeAlphaTicker.ts
var FadeAlphaTicker = class extends TickerBase {
fn(ticker, args, tags, tickerId) {
let type = args.type === void 0 ? "hide" : args.type;
let duration = args.duration === void 0 ? 1 : args.duration;
let speed = 1 / (duration * 60);
let limit = args.limit === void 0 ? type === "hide" ? 0 : 1 : args.limit;
let tagToRemoveAfter2 = args.tagToRemoveAfter || [];
if (typeof tagToRemoveAfter2 === "string") {
tagToRemoveAfter2 = [tagToRemoveAfter2];
}
if (type === "hide" && limit < 0) {
limit = 0;
}
if (type === "show" && limit > 1) {
limit = 1;
}
tags.filter((tag) => {
var _a;
let element = GameWindowManager.getCanvasElement(tag);
if (args.startOnlyIfHaveTexture) {
if (element && element instanceof pixi_js.Sprite && ((_a = element.texture) == null ? void 0 : _a.label) == "EMPTY") {
return false;
}
}
return true;
}).forEach((tag) => {
let element = GameWindowManager.getCanvasElement(tag);
if (element && element instanceof pixi_js.Container) {
if (type === "show" && element.alpha < limit) {
element.alpha += speed * ticker.deltaTime;
} else if (type === "hide" && element.alpha > limit) {
element.alpha -= speed * ticker.deltaTime;
}
if (type === "show" && element.alpha >= limit) {
element.alpha = limit;
GameWindowManager.onEndOfTicker(tag, this, tagToRemoveAfter2, tickerId);
} else if (type === "hide" && element.alpha <= limit) {
element.alpha = limit;
GameWindowManager.onEndOfTicker(tag, this, tagToRemoveAfter2, tickerId);
}
}
});
}
};
FadeAlphaTicker = __decorateClass([
tickerDecorator()
], FadeAlphaTicker);
// src/functions/TickerUtility.ts
function updateTickerProgression(args, propertyName, progression, valueConvert) {
let limit = valueConvert && progression.limit ? valueConvert(progression.limit) : progression.limit;
if (args[propertyName] === void 0 || !progression || args[propertyName] === limit) {
return;
}
if (typeof args[propertyName] === "number") {
if (progression.type === "linear") {
args[propertyName] = getLinearProgression(args[propertyName], progression);
} else if (progression.type === "exponential") {
args[propertyName] = getExponentialProgression(args[propertyName], progression);
}
} else if (args[propertyName] !== void 0 && typeof args[propertyName] === "object" && args[propertyName].haveOwnProperty("x") && args[propertyName].haveOwnProperty("y") && typeof args[propertyName].x === "number" && typeof args[propertyName].y === "number") {
if (progression.type === "linear") {
args[propertyName].x = getLinearProgression(args[propertyName].x, progression);
args[propertyName].y = getLinearProgression(args[propertyName].y, progression);
} else if (progression.type === "exponential") {
args[propertyName].x = getExponentialProgression(args[propertyName].x, progression);
args[propertyName].y = getExponentialProgression(args[propertyName].y, progression);
}
}
}
function getLinearProgression(number, progression, valueConvert) {
let limit = valueConvert && progression.limit ? valueConvert(progression.limit) : progression.limit;
let amt = valueConvert ? valueConvert(progression.amt) : progression.amt;
if (limit !== void 0) {
if (number > limit && amt > 0) {
return limit;
} else if (number < limit && amt < 0) {
return limit;
}
}
return number + amt;
}
function getExponentialProgression(number, progression, valueConvert) {
let limit = valueConvert && progression.limit ? valueConvert(progression.limit) : progression.limit;
if (limit !== void 0) {
if (number > limit && progression.percentage > 0) {
return limit;
} else if (number < limit && progression.percentage < 0) {
return limit;
}
}
return number + number * progression.percentage;
}
// src/classes/ticker/MoveTicker.ts
var MoveTicker = class extends TickerBase {
fn(ticker, args, tags, tickerId) {
let xSpeed = 1;
let ySpeed = 1;
if (args.speed) {
if (typeof args.speed === "number") {
xSpeed = this.speedConvert(args.speed);
ySpeed = this.speedConvert(args.speed);
} else {
xSpeed = this.speedConvert(args.speed.x);
ySpeed = this.speedConvert(args.speed.y);
}
}
let destination = args.destination;
let tagToRemoveAfter2 = args.tagToRemoveAfter || [];
if (typeof tagToRemoveAfter2 === "string") {
tagToRemoveAfter2 = [tagToRemoveAfter2];
}
tags.filter((tag) => {
var _a;
let element = GameWindowManager.getCanvasElement(tag);
if (args.startOnlyIfHaveTexture) {
if (element && element instanceof pixi_js.Sprite && ((_a = element.texture) == null ? void 0 : _a.label) == "EMPTY") {
return false;
}
}
return true;
}).forEach((tag) => {
let element = GameWindowManager.getCanvasElement(tag);
if (element && element instanceof pixi_js.Container) {
let xDistance = destination.x - element.x > 0 ? 1 : -1;
if (xDistance != 0) {
element.x += xDistance * xSpeed * ticker.deltaTime;
let newDistance = destination.x - element.x;
if (xDistance < 0 && newDistance > 0 || xDistance > 0 && newDistance < 0) {
element.x = destination.x;
}
}
let yDistance = destination.y - element.y > 0 ? 1 : -1;
if (yDistance != 0) {
element.y += yDistance * ySpeed * ticker.deltaTime;
let newDistance = destination.y - element.y;
if (yDistance < 0 && newDistance > 0 || yDistance > 0 && newDistance < 0) {
element.y = destination.y;
}
}
if (element.x == destination.x && element.y == destination.y) {
GameWindowManager.onEndOfTicker(tag, this, tagToRemoveAfter2, tickerId);
}
}
});
if (args.speedProgression)
updateTickerProgression(args, "speed", args.speedProgression, this.speedConvert);
}
speedConvert(speed) {
return speed / 6;
}
};
MoveTicker = __decorateClass([
tickerDecorator()
], MoveTicker);
var RotateTicker = class extends TickerBase {
fn(ticker, args, tags, tickerId) {
let speed = this.speedConvert(args.speed === void 0 ? 1 : args.speed);
let clockwise = args.clockwise === void 0 ? true : args.clockwise;
let tagToRemoveAfter2 = args.tagToRemoveAfter || [];
if (typeof tagToRemoveAfter2 === "string") {
tagToRemoveAfter2 = [tagToRemoveAfter2];
}
tags.filter((tag) => {
var _a;
let element = GameWindowManager.getCanvasElement(tag);
if (args.startOnlyIfHaveTexture) {
if (element && element instanceof pixi_js.Sprite && ((_a = element.texture) == null ? void 0 : _a.label) == "EMPTY") {
return false;
}
}
return true;
}).forEach((tag) => {
let element = GameWindowManager.getCanvasElement(tag);
if (element && element instanceof pixi_js.Container) {
if (clockwise)
element.rotation += speed * ticker.deltaTime;
else
element.rotation -= speed * ticker.deltaTime;
if (speed < 1e-5 && !(args.speedProgression && args.speedProgression.type == "linear" && args.speedProgression.amt != 0)) {
GameWindowManager.onEndOfTicker(tag, this, tagToRemoveAfter2, tickerId);
}
}
});
if (args.speedProgression)
updateTickerProgression(args, "speed", args.speedProgression, this.speedConvert);
}
speedConvert(speed) {
return speed / 60;
}
};
RotateTicker = __decorateClass([
tickerDecorator()
], RotateTicker);
var ZoomTicker = class extends TickerBase {
fn(ticker, args, tags, tickerId) {
let xSpeed = 0.1;
let ySpeed = 0.1;
if (args.speed) {
if (typeof args.speed === "number") {
xSpeed = this.speedConvert(args.speed);
ySpeed = this.speedConvert(args.speed);
} else {
xSpeed = this.speedConvert(args.speed.x);
ySpeed = this.speedConvert(args.speed.y);
}
}
let tagToRemoveAfter2 = args.tagToRemoveAfter || [];
if (typeof tagToRemoveAfter2 === "string") {
tagToRemoveAfter2 = [tagToRemoveAfter2];
}
let type = args.type || "zoom";
let xLimit = type === "zoom" ? Infinity : 0;
let yLimit = type === "zoom" ? Infinity : 0;
if (args.limit) {
if (typeof args.limit === "number") {
xLimit = args.limit;
yLimit = args.limit;
} else {
xLimit = args.limit.x;
yLimit = args.limit.y;
}
}
tags.filter((tag) => {
var _a;
let element = GameWindowManager.getCanvasElement(tag);
if (args.startOnlyIfHaveTexture) {
if (element && element instanceof pixi_js.Sprite && ((_a = element.texture) == null ? void 0 : _a.label) == "EMPTY") {
return false;
}
}
return true;
}).forEach((tag) => {
let element = GameWindowManager.getCanvasElement(tag);
if (element && element instanceof pixi_js.Container) {
if (type === "zoom" && (element.scale.x < xLimit || element.scale.y < yLimit)) {
element.scale.x += xSpeed * ticker.deltaTime;
element.scale.y += ySpeed * ticker.deltaTime;
} else if (type === "unzoom" && (element.scale.x > xLimit || element.scale.y > yLimit)) {
element.scale.x -= xSpeed * ticker.deltaTime;
element.scale.y -= ySpeed * ticker.deltaTime;
}
if (type === "zoom") {
if (element.scale.x > xLimit) {
element.scale.x = xLimit;
}
if (element.scale.y > yLimit) {
element.scale.y = yLimit;
}
if (element.scale.x >= xLimit && element.scale.y >= yLimit) {
element.scale.x = xLimit;
element.scale.y = yLimit;
this.onEndOfTicker(tag, tickerId, element, tagToRemoveAfter2);
}
} else if (type === "unzoom") {
if (element.scale.x < xLimit) {
element.scale.x = xLimit;
}
if (element.scale.y < yLimit) {
element.scale.y = yLimit;
}
if (element.scale.x <= xLimit && element.scale.y <= yLimit) {
element.scale.x = xLimit;
element.scale.y = yLimit;
this.onEndOfTicker(tag, tickerId, element, tagToRemoveAfter2);
}
}
if (xSpeed < 1e-5 && ySpeed < 1e-5 && !(args.speedProgression && args.speedProgression.type == "linear" && args.speedProgression.amt != 0)) {
this.onEndOfTicker(tag, tickerId, element, tagToRemoveAfter2);
}
}
});
if (args.speedProgression)
updateTickerProgression(args, "speed", args.speedProgression, this.speedConvert);
}
speedConvert(speed) {
return speed / 60;
}
onEndOfTicker(tag, tickerId, _element, tagToRemoveAfter2) {
GameWindowManager.onEndOfTicker(tag, this, tagToRemoveAfter2, tickerId);
}
};
ZoomTicker = __decorateClass([
tickerDecorator()
], ZoomTicker);
// src/constants.ts
var Repeat = "repeat";
// src/functions/ExportUtility.ts
function createExportableElement(element) {
try {
let elementString = JSON.stringify(element);
return JSON.parse(elementString);
} catch (e) {
console.error("[Pixi'VN] Error creating exportable element", e);
throw new Error("[Pixi'VN] Error creating exportable element");
}
}
// src/functions/DiffUtility.ts
function restoreDeepDiffChanges(data, differences) {
let result = createExportableElement(data);
differences.forEach((diff2) => {
let dataToEdit = result;
if (diff2.path && diff2.path.length > 0) {
diff2.path.forEach((path, index) => {
if (diff2.path && index === diff2.path.length - 1) {
if (diff2.kind === "E" || diff2.kind === "D") {
dataToEdit[path] = diff2.lhs;
} else if (diff2.kind === "N") {
if (Number.isInteger(path)) {
if (Array.isArray(dataToEdit)) {
dataToEdit.splice(path, 1);
}
} else if (typeof path === "string") {
delete dataToEdit[path];
}
} else if (diff2.kind === "A") {
let index2 = diff2.index;
if (diff2.item.kind === "N") {
dataToEdit[path].splice(index2, 1);
} else if (diff2.item.kind === "E" || diff2.item.kind === "D") {
dataToEdit[path][index2] = diff2.item.lhs;
} else if (diff2.item.kind === "A") {
console.warn("[Pixi'VN] Nested array found, skipping diff", diff2);
} else {
console.warn("[Pixi'VN] No array found, skipping diff", diff2);
}
}
} else {
dataToEdit = dataToEdit[path];
}
});
} else {
console.warn("[Pixi'VN] No path found, skipping diff", diff2);
}
});
return result;
}
// src/managers/StorageManager.ts
var _GameStorageManager = class _GameStorageManager {
constructor() {
}
static get keysSystem() {
return {
/**
* The key of the current dialogue memory
*/
CURRENT_DIALOGUE_MEMORY_KEY: "___current_dialogue_memory___",
/**
* The key of the last dialogue added in the step memory
*/
LAST_DIALOGUE_ADDED_IN_STEP_MEMORY_KEY: "___last_dialogue_added_in_step_memory___",
/**
* The key of the current menu options memory
*/
CURRENT_MENU_OPTIONS_MEMORY_KEY: "___current_menu_options_memory___",
/**
* The key of the last menu options added in the step memory
*/
LAST_MENU_OPTIONS_ADDED_IN_STEP_MEMORY_KEY: "___last_menu_options_added_in_step_memory___",
/**
* The key of the characters memory
*/
CHARACTER_CATEGORY_KEY: "___character___",
/**
* The key of the flags memory
*/
FLAGS_CATEGORY_KEY: "___flags___",
/**
* This variable is used to add the next dialog text into the current dialog memory.
* This value was added to introduce Ink Glue functionality https://github.com/inkle/ink/blob/master/Documentation/WritingWithInk.md#glue
*/
ADD_NEXT_DIALOG_TEXT_INTO_THE_CURRENT_DIALOG_FLAG_KEY: "___glue___"
};
}
/**
* Set a variable in the storage
* @param key The key of the variable
* @param value The value of the variable. If undefined, the variable will be removed
* @returns
*/
static setVariable(key, value) {
key = key.toLowerCase();
if (value === void 0 || value === null) {
if (_GameStorageManager.storage.hasOwnProperty(key)) {
delete _GameStorageManager.storage[key];
}
return;
}
_GameStorageManager.storage[key] = value;
}
/**
* Get a variable from the storage
* @param key The key of the variable
* @returns The value of the variable. If the variable does not exist, it will return undefined
*/
static getVariable(key) {
key = key.toLowerCase();
if (_GameStorageManager.storage.hasOwnProperty(key)) {
return _GameStorageManager.storage[key];
}
return void 0;
}
/**
* Remove a variable from the storage
* @param key The key of the variable
* @returns
*/
static removeVariable(key) {
key = key.toLowerCase();
if (_GameStorageManager.storage.hasOwnProperty(key)) {
delete _GameStorageManager.storage[key];
}
}
/**
* Clear the storage and the oidsUsed
* @returns
*/
static clear() {
_GameStorageManager.storage = {};
}
static exportJson() {
return JSON.stringify(this.export());
}
static export() {
return createExportableElement(_GameStorageManager.storage);
}
static importJson(dataString) {
_GameStorageManager.import(JSON.parse(dataString));
}
static import(data) {
_GameStorageManager.clear();
try {
if (data) {
_GameStorageManager.storage = data;
} else {
console.warn("[Pixi'VN] No storage data found");
}
} catch (e) {
console.error("[Pixi'VN] Error importing data", e);
}
}
};
_GameStorageManager.storage = {};
var GameStorageManager = _GameStorageManager;
// src/functions/EasterEgg.ts
function asciiArtLog() {
console.info(`
____ _ _ ___ ___ _
| _ \\(_)_ _(_| ) \\ / / \\ | |
| |_) | \\ \\/ / |/ \\ \\ / /| \\| |
| __/| |> <| | \\ V / | |\\ |
|_| |_/_/\\_\\_| \\_/ |_| \\_|
`);
}
// src/types/ticker/TagToRemoveAfterType.ts
var tagToRemoveAfter = "tagToRemoveAfter";
// src/managers/WindowManager.ts
var _GameWindowManager = class _GameWindowManager {
constructor() {
}
/**
* The PIXI Application instance.
* It not recommended to use this property directly.
*/
static get app() {
if (!_GameWindowManager._app) {
throw new Error("[Pixi'VN] GameWindowManager.app is undefined");
}
return _GameWindowManager._app;
}
/**
* If the manager is initialized.
*/
static get isInitialized() {
return _GameWindowManager._isInitialized;
}
static get screen() {
return _GameWindowManager.app.screen;
}
/**
* Initialize the PIXI Application and the interface div.
* This method should be called before any other method.
* @param element The html element where I will put the canvas. Example: document.body
* @param width The width of the canvas
* @param height The height of the canvas
* @param options The options of PIXI Application
* @example
* ```typescript
* const body = document.body
* if (!body) {
* throw new Error('body element not found')
* }
* await GameWindowManager.initialize(body, 1920, 1080, {
* backgroundColor: "#303030"
* })
* ```
*/
static initialize(element, width, height, options) {
return __async(this, null, function* () {
_GameWindowManager.canvasWidth = width;
_GameWindowManager.canvasHeight = height;
_GameWindowManager._app = new pixi_js.Application();
return _GameWindowManager.app.init(__spreadValues({
resolution: window.devicePixelRatio || 1,
autoDensity: true,
width,
height
}, options)).then(() => {
devtools.initDevtools({ app: _GameWindowManager._app });
_GameWindowManager._isInitialized = true;
this.addCanvasIntoHTMLElement(element);
window.addEventListener("resize", _GameWindowManager.resize);
_GameWindowManager.resize();
asciiArtLog();
});
});
}
/**
* Add the canvas into a html element.
* @param element it is the html element where I will put the canvas. Example: document.body
*/
static addCanvasIntoHTMLElement(element) {
if (_GameWindowManager.isInitialized) {
element.appendChild(_GameWindowManager.app.canvas);
} else {
console.error("[Pixi'VN] GameWindowManager is not initialized");
}
}
/**
* Initialize the interface div and add it into a html element.
* @param element it is the html element where I will put the interface div. Example: document.getElementById('root')
* @example
* ```tsx
* const root = document.getElementById('root')
* if (!root) {
* throw new Error('root element not found')
* }
* GameWindowManager.initializeHTMLLayout(root)
* const reactRoot = createRoot(GameWindowManager.htmlLayout)
* reactRoot.render(
* <App />
* )
* ```
*/
static initializeHTMLLayout(element) {
let div = document.createElement("div");
div.style.position = "absolute";
div.style.pointerEvents = "none";
element.appendChild(div);
_GameWindowManager.htmlLayout = div;
_GameWindowManager.resize();
}
/* Resize Metods */
/**
* This method returns the scale of the screen.
*/
static get screenScale() {
let screenWidth = Math.max(document.documentElement.clientWidth, window.innerWidth || 0);
let screenHeight = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
return Math.min(screenWidth / _GameWindowManager.canvasWidth, screenHeight / _GameWindowManager.canvasHeight);
}
/**
* This method returns the width of the screen enlarged by the scale.
*/
static get screenWidth() {
return Math.floor(_GameWindowManager.screenScale * _GameWindowManager.canvasWidth);
}
/**
* This method returns the height of the screen enlarged by the scale.
*/
static get screenHeight() {
return Math.floor(_GameWindowManager.screenScale * _GameWindowManager.canvasHeight);
}
/**
* This method returns the horizontal margin of the screen.
*/
static get horizontalMargin() {
let screenWidth = Math.max(document.documentElement.clientWidth, window.innerWidth || 0);
return (screenWidth - _GameWindowManager.screenWidth) / 2;
}
/**
* This method returns the vertical margin of the screen.
*/
static get verticalMargin() {
let screenHeight = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
return (screenHeight - _GameWindowManager.screenHeight) / 2;
}
/**
* This method is called when the screen is resized.
*/
static resize() {
if (_GameWindowManager.isInitialized) {
let style = _GameWindowManager.app.canvas.style;
style.width = `${_GameWindowManager.screenWidth}px`;
style.height = `${_GameWindowManager.screenHeight}px`;
style.marginLeft = `${_GameWindowManager.horizontalMargin}px`;
style.marginRight = `${_GameWindowManager.horizontalMargin}px`;
style.marginTop = `${_GameWindowManager.verticalMargin}px`;
style.marginBottom = `${_GameWindowManager.verticalMargin}px`;
}
if (_GameWindowManager.htmlLayout) {
_GameWindowManager.htmlLayout.style.width = `${_GameWindowManager.screenWidth}px`;
_GameWindowManager.htmlLayout.style.height = `${_GameWindowManager.screenHeight}px`;
_GameWindowManager.htmlLayout.style.marginLeft = `${_GameWindowManager.horizontalMargin}px`;
_GameWindowManager.htmlLayout.style.marginRight = `${_GameWindowManager.horizontalMargin}px`;
_GameWindowManager.htmlLayout.style.marginTop = `${_GameWindowManager.verticalMargin}px`;
_GameWindowManager.htmlLayout.style.marginBottom = `${_GameWindowManager.verticalMargin}px`;
}
}
/* Edit Canvas Elements Methods */
/**
* This is a dictionary that contains all Canvas Elements of Canvas, currently.
*/
static get currentCanvasElements() {
return _GameWindowManager._children;
}
/**
* Add a canvas element to the canvas.
* If there is a canvas element with the same tag, it will be removed.
* @param tag The tag of the canvas element.
* @param canvasElement The canvas elements to be added.
* @example
* ```typescript
* const texture = await Assets.load('https://pixijs.com/assets/bunny.png');
* const sprite = CanvasSprite.from(texture);
* GameWindowManager.addCanvasElement("bunny", sprite);
* ```
*/
static addCanvasElement(tag, canvasElement) {
if (_GameWindowManager._children[tag]) {
_GameWindowManager.removeCanvasElement(tag);
}
_GameWindowManager.app.stage.addChild(canvasElement);
_GameWindowManager._children[tag] = canvasElement;
_GameWindowManager.childrenTagsOrder.push(tag);
}
/**
* Remove a canvas element from the canvas.
* And remove all tickers that are not connected to any canvas element.
* @param tags The tag of the canvas element to be removed.
* @returns
* @example
* ```typescript
* GameWindowManager.removeCanvasElement("bunny");
* ```
*/
static removeCanvasElement(tags) {
if (typeof tags === "string") {
tags = [tags];
}
tags.forEach((tag) => {
if (_GameWindowManager._children[tag]) {
_GameWindowManager.app.stage.removeChild(_GameWindowManager._children[tag]);
delete _GameWindowManager._children[tag];
_GameWindowManager.removeTickerByCanvasElement(tag);
}
});
_GameWindowManager.childrenTagsOrder = _GameWindowManager.childrenTagsOrder.filter((t) => !tags.includes(t));
}
/**
* Get a canvas element by the tag.
* @param tag The tag of the canvas element.
* @returns The canvas element.
* @example
* ```typescript
* const sprite = GameWindowManager.getCanvasElement<CanvasSprite>("bunny");
* ```
*/
static getCanvasElement(tag) {
return _GameWindowManager._children[tag];
}
/**
* Check if a DisplayObject is on the canvas.
* @param pixiElement The DisplayObject to be checked.
* @returns If the DisplayObject is on the canvas.
*/
static canvasElementIsOnCanvas(pixiElement) {
return _GameWindowManager.app.stage.children.includes(pixiElement);
}
/**
* Remove all canvas elements from the canvas.
* And remove all tickers that are not connected to any canvas element.
*/
static removeCanvasElements() {
_GameWindowManager.app.stage.removeChildren();
_GameWindowManager._children = {};
_GameWindowManager.childrenTagsOrder = [];
_GameWindowManager.removeAllTickers();
}
/**
* Edit the tag of a canvas element.
* @param oldTag The old tag of the canvas element.
* @param newTag The new tag of the canvas element.
*/
static editCanvasElementTag(oldTag, newTag) {
if (_GameWindowManager._children[oldTag]) {
_GameWindowManager._children[newTag] = _GameWindowManager._children[oldTag];
delete _GameWindowManager._children[oldTag];
}
if (_GameWindowManager._currentTickersSteps[oldTag]) {
_GameWindowManager._currentTickersSteps[newTag] = _GameWindowManager._currentTickersSteps[oldTag];
delete _GameWindowManager._currentTickersSteps[oldTag];
}
for (let id in _GameWindowManager._currentTickers) {
let ticker = _GameWindowManager._currentTickers[id];
if (ticker.canvasElementTags.includes(oldTag)) {
ticker.canvasElementTags = ticker.canvasElementTags.map((t) => t === oldTag ? newTag : t);
if (ticker.args.hasOwnProperty(tagToRemoveAfter)) {
let tagToRemoveAfter2 = ticker.args.tagToRemoveAfter;
if (typeof tagToRemoveAfter2 === "string") {
tagToRemoveAfter2 = [tagToRemoveAfter2];
}
if (Array.isArray(tagToRemoveAfter2)) {
ticker.args.tagToRemoveAfter = tagToRemoveAfter2.map((t) => t === oldTag ? newTag : t);
}
}
}
}
for (let timeout in _GameWindowManager._currentTickersTimeouts) {
let TickerTimeout = _GameWindowManager._currentTickersTimeouts[timeout];
if (TickerTimeout.tags.includes(oldTag)) {
TickerTimeout.tags = TickerTimeout.tags.map((t) => t === oldTag ? newTag : t);
}
}
}
/** Edit Tickers Methods */
/**
* Currently tickers that are running.
*/
static get currentTickers() {
return _GameWindowManager._currentTickers;
}
static get currentTickersList() {
return Object.values(_GameWindowManager._currentTickers);
}
static get currentTickersWithoutCreatedBySteps() {
return Object.fromEntries(Object.entries(_GameWindowManager._currentTickers).filter(([_, ticker]) => !ticker.createdByTicketStepsId));
}
/**
* The steps of the tickers
*/
static get currentTickersSteps() {
return _GameWindowManager._currentTickersSteps;
}
static generateTickerId(tickerData) {
try {
return sha1__default.default(JSON.stringify(tickerData)).toString() + "_" + Math.random().toString(36).substring(7);
} catch (e) {
throw new Error(`[Pixi'VN] Error to generate ticker id: ${e}`);
}
}
/**
* Run a ticker. You can run multiple addTicker with the same tag and different tickerClasses.
* If you run a ticker with the same tag and tickerClass, the old ticker will be removed.
* If already exists a sequence of tickers with the same tag, it will be removed.
* @param canvasEslementTag The tag of the canvas element that will use the ticker.
* @param ticker The ticker class to be run.
* @param args The arguments to be used in the ticker.
* @param duration The time to be used in the ticker. This number is in seconds. If it is undefined, the ticker will run forever.
* @param priority The priority to be used in the ticker.
* @returns
* @example
* ```typescript
* GameWindowManager.addTicker("alien", new RotateTicker({ speed: 0.2 }))
* ```
*/
static addTicker(canvasElementTag, ticker) {
let tickerId = ticker.id;
if (typeof canvasElementTag === "string") {
canvasElementTag = [canvasElementTag];
}
if (!geTickerInstanceById(tickerId, ticker.args, ticker.duration, ticker.priority)) {
console.error(`[Pixi'VN] Ticker ${tickerId} not found`);
return;
}
let tickerHistory = {
fn: () => {
},
id: tickerId,
args: createExportableElement(ticker.args),
canvasElementTags: canvasElementTag,
priority: ticker.priority,
duration: ticker.duration
};
let id = _GameWindowManager.generateTickerId(tickerHistory);
_GameWindowManager.pushTicker(id, tickerHistory, ticker);
if (ticker.duration) {
let timeout = setTimeout(() => {
_GameWindowManager.removeTickerTimeoutInfo(timeout);
let tickerTimeoutInfo = _GameWindowManager._currentTickersTimeouts[timeout.toString()];
if (tickerTimeoutInfo) {
_GameWindowManager.removeTicker(id);
}
}, ticker.duration * 1e3);
_GameWindowManager.addTickerTimeoutInfo(canvasElementTag, tickerId, timeout.toString(), true);
}
}
static pushTicker(id, tickerData, ticker) {
_GameWindowManager.removeAssociationBetweenTickerCanvasElement(tickerData.canvasElementTags, ticker);
_GameWindowManager._currentTickers[id] = tickerData;
tickerData.fn = (t) => {
let data = _GameWindowManager._currentTickers[id];
if (data) {
ticker == null ? void 0 : ticker.fn(t, data.args, data.canvasElementTags, id);
}
};
_GameWindowManager.app.ticker.add(tickerData.fn, void 0, tickerData.priority);
}
/**
* Run a sequence of tickers. If exists a ticker steps with the same tag, it will be removed.
* @param tag The tag of canvas element that will use the tickers.
* @param steps The steps of the tickers.
* @param currentStepNumber The current step number. It is used to continue the sequence of tickers.
* @returns
* @example
* ```typescript
* GameWindowManager.addTickersSteps("alien", [
* new RotateTicker({ speed: 0.1, clockwise: true }, 2), // 2 seconds
* Pause(1), // 1 second
* new RotateTicker({ speed: 0.2, clockwise: false }, 2),
* Repeat,
* ])
* ```
*/
static addTickersSteps(tag, steps, currentStepNumber = 0) {
if (steps.length == 0) {
console.warn("[Pixi'VN] The steps of the tickers is empty");
return;
}
_GameWindowManager.removeTickerStepByCanvasElement(tag);
_GameWindowManager._currentTickersSteps[tag] = {
currentStepNumber,
steps: steps.map((step) => {
if (step === Repeat) {
return step;
}
if (step.hasOwnProperty("type") && step.type === "pause") {
return step;
}
let tickerId = step.id;
return {
ticker: tickerId,
args: createExportableElement(step.args),
duration: step.duration
};
})
};
_GameWindowManager.runTickersSteps(tag);
}
static restoneTickersSteps(data) {
for (let tag in data) {
let steps = data[tag];
_GameWindowManager._currentTickersSteps[tag] = steps;
_GameWindowManager.runTickersSteps(tag);
}
}
static runTickersSteps(tag) {
let step = _GameWindowManager._currentTickersSteps[tag].steps[_GameWindowManager._currentTickersSteps[tag].currentStepNumber];
if (step === Repeat) {
step = _GameWindowManager._currentTickersSteps[tag].steps[0];
_GameWindowManager._currentTickersSteps[tag].currentStepNumber = 0;
if (step === Repeat) {
console.error("[Pixi'VN] TikersSteps has a RepeatType in the first step");
return;
}
}
if (step.hasOwnProperty("type") && step.type === "pause") {
let timeout = setTimeout(() => {
let tickerTimeoutInfo = _GameWindowManager._currentTickersTimeouts[timeout.toString()];
if (tickerTimeoutInfo) {
tickerTimeoutInfo.tags.forEach((tag2) => {
_GameWindowManager.nextTickerStep(tag2);
});
}
_GameWindowManager.removeTickerTimeoutInfo(timeout);
}, step.duration * 1e3);
_GameWindowManager.addTickerTimeoutInfo(tag, "steps", timeout.toString(), false);
return;
}
let ticker = geTickerInstanceById(step.ticker, step.args, step.duration, step.priority);
if (!ticker) {
console.error(`[Pixi'VN] Ticker ${step.ticker} not found`);
return;
}
let tickerName = ticker.id;
let tickerHistory = {
fn: () => {
},
id: tickerName,
args: createExportableElement(ticker.args),
canvasElementTags: [tag],
priority: ticker.priority,
duration: ticker.duration,
createdByTicketStepsId: tag
};
let id = _GameWindowManager.generateTickerId(tickerHistory);
_GameWindowManager.pushTicker(id, tickerHistory, ticker);
if (ticker.duration) {
let timeout = setTimeout(() => {
let tickerTimeoutInfo = _GameWindowManager._currentTickersTimeouts[timeout.toString()];
if (tickerTimeoutInfo) {
_GameWindowManager.removeTicker(id);
tickerTimeoutInfo.tags.forEach((tag2) => {
_GameWindowManager.nextTickerStep(tag2);
});
}
_GameWindowManager.removeTickerTimeoutInfo(timeout);
}, ticker.duration * 1e3);
_GameWindowManager.addTickerTimeoutInfo(tag, tickerName, timeout.toString(), false);
}
}
static nextTickerStep(tag) {
if (_GameWindowManager._currentTickersSteps[tag]) {
let steps = _GameWindowManager._currentTickersSteps[tag];
if (steps.currentStepNumber + 1 < steps.steps.length) {
steps.currentStepNumber++;
_GameWindowManager._currentTickersSteps[tag] = steps;
_GameWindowManager.runTickersSteps(tag);
} else {
_GameWindowManager.removeTickerStepByCanvasElement(tag);
}
}
}
static onEndOfTicker(canvasElementTags, ticker, canvasElementTagsToDelete, tickerId) {
let tickerData = _GameWindowManager._currentTickers[tickerId];
_GameWindowManager.removeAssociationBetweenTickerCanvasElement(canvasElementTags, ticker);
_GameWindowManager.removeCanvasElement(canvasElementTagsToDelete);
if (tickerData) {
_GameWindowManager.removeTicker(tickerId);
if (tickerData.duration == void 0 && tickerData.createdByTicketStepsId) {
_GameWindowManager.nextTickerStep(tickerData.createdByTicketStepsId);
}
}
}
/**
* Remove a connection between a canvas element and a ticker.
* And remove the ticker if there is no canvas element connected to it.
* @param tags The tag of the canvas element that will use the ticker.
* @param ticker The ticker class to be removed.
* @example
* ```typescript
* GameWindowManager.removeAssociationBetweenTickerCanvasElement("alien", RotateTicker)
* ```
*/
static removeAssociationBetweenTickerCanvasElement(tags, ticker) {
let tickerId;
if (typeof ticker === "string") {
tickerId = ticker;
} else if (ticker instanceof TickerBase) {
tickerId = ticker.id;
} else {
tickerId = ticker.prototype.id;
}
if (typeof tags === "string") {
tags = [tags];
}
for (let id in _GameWindowManager._currentTickers) {
let ticker2 = _GameWindowManager._currentTickers[id];
if (ticker2.id === tickerId) {
_GameWindowManager._currentTickers[id].canvasElementTags = ticker2.canvasElementTags.filter((e) => !tags.includes(e));
}
}
for (let timeout in _GameWindowManager._currentTickersTimeouts) {
let TickerTimeout = _GameWindowManager._currentTickersTimeouts[timeout];
if (TickerTimeout.ticker === tickerId && TickerTimeout.canBeDeletedBeforeEnd) {
_GameWindowManager._currentTickersTimeouts[timeout].tags = TickerTimeout.tags.filter((t) => !tags.includes(t));
}
}
_GameWindowManager.removeTickersWithoutAssociatedCanvasElement();
}
/**
* Remove all tickers that are not connected to any existing canvas element.
*/
static removeTickersWithoutAssociatedCanvasElement() {
for (let id in _GameWindowManager._currentTickers) {
let ticker = _GameWindowManager._currentTickers[id];
ticker.canvasElementTags = ticker.canvasElementTags.filter((e) => _GameWindowManager._children[e]);
if (ticker.canvasElementTags.length === 0) {
_GameWindowManager.removeTicker(id);
}
}
for (let tag in _GameWindowManager._currentTickersSteps) {
if (_GameWindowManager._children[tag] === void 0) {
delete _GameWindowManager._currentTickersSteps[tag];
}
}
Object.entries(_GameWindowManager._currentTickersTimeouts).forEach(([timeout, { tags }]) => {
if (tags.length === 0) {
_GameWindowManager.removeTickerTimeout(timeout);
}
});
}
static addTickerTimeoutInfo(tags, ticker, timeout, canBeDeletedBeforeEnd) {
if (typeof tags === "string") {
tags = [tags];
}
_GameWindowManager._currentTickersTimeouts[timeout] = {
tags,
ticker,
canBeDeletedBeforeEnd
};
}
static removeTickerTimeoutInfo(timeout) {
if (typeof timeout !== "string") {
timeout = timeout.toString();
}
if (_GameWindowManager._currentTickersTimeouts[timeout]) {
delete _GameWindowManager._currentTickersTimeouts[timeout];
}
}
static removeTickerTimeout(timeout) {
if (typeof timeout !== "string") {
timeout = timeout.toString();
}
clearTimeout(Number(timeout));
_GameWindowManager.removeTickerTimeoutInfo(timeout);
}
static removeTickerTimeoutsByTag(tag, checkCanBeDeletedBeforeEnd) {
for (let timeout in _GameWindowManager._currentTickersTimeouts) {
let tagsWithoutTagToRemove = _GameWindowManager._currentTickersTimeouts[timeout].tags.filter((t) => t !== tag);
if (tagsWithoutTagToRemove.length === 0) {
let canBeDeletedBeforeEnd = _GameWindowManager._currentTickersTimeouts[timeout].canBeDeletedBeforeEnd;
if (!checkCanBeDeletedBeforeEnd || canBeDeletedBeforeEnd) {
_GameWindowManager.removeTickerTimeout(timeout);
}
} else {
_GameWindowManager._currentTickersTimeouts[timeout].tags = tagsWithoutTagToRemove;
}
}
}
/**
* Remove all tickers from the canvas.
*/
static removeAllTickers() {
_GameWindowManager._currentTickersSteps = {};
Object.keys(_GameWindowManager._currentTickers).forEach((id) => {
_GameWindowManager.removeTicker(id);
});
_GameWindowManager._currentTickers = {};
for (let timeout in _GameWindowManager._currentTickersTimeouts) {
_GameWindowManager.removeTickerTimeout(timeout);
}
}
/**
* Remove all tickers from a canvas element.
* @param tag The tag of the canvas element that will use the ticker.
*/
static removeTickerByCanvasElement(tag) {
if (typeof tag === "string") {
tag = [tag];
}
tag.forEach((tag2) => {
for (let id in _GameWindowManager._currentTickers) {
let ticker = _GameWindowManager._currentTickers[id];
if (ticker.canvasElementTags.includes(tag2)) {
_GameWindowManager.removeTicker(id);
}
}
if (_GameWindowManager._currentTickersSteps[tag2]) {
delete _GameWindowManager._currentTickersSteps[tag2];
}
_GameWindowManager.removeTickerTimeoutsByTag(tag2, false);
delete _GameWindowManager._currentTickersSteps[tag2];
});
}
static removeTickerStepByCanvasElement(tag) {
if (_GameWindowManager._currentTickersSteps[tag]) {
delete _GameWindowManager._currentTickersSteps[tag];
}
for (let id in _GameWindowManager._currentTickers) {
let ticker = _GameWindowManager._currentTickers[id];
if (ticker.createdByTicketStepsId === tag) {
_GameWindowManager.removeTicker(id);
}
}
}
static removeTicker(tickerId) {
let ticker = _GameWindowManager._currentTickers[tickerId];
if (ticker) {
if (ticker.args.hasOwnProperty(tagToRemoveAfter)) {
let tagToRemoveAfter2 = ticker.args.tagToRemoveAfter;
_GameWindowManager.removeCanvasElement(tagToRemoveAfter2);
}
_GameWindowManager.app.ticker.remove(ticker.fn);
delete _GameWindowManager._currentTickers[tickerId];
}
}
/**
* Clear the canvas and the tickers.
*/
static clear() {
_GameWindowManager.removeCanvasElements();
}
/* Export and Import Methods */
/**
* Export the canvas and the tickers to a JSON string.
* @returns The JSON string.
*/
static exportJson() {
return JSON.stringify(this.export());
}
/**
* Export the canvas and the tickers to an object.
* @returns The object.
*/
static export() {
let currentElements = {};
for (let tag in _GameWindowManager._children) {
currentElements[tag] = exportCanvasElement(_GameWindowManager._children[tag]);
}
return {
currentTickers: createExportableElement(_GameWindowManager.currentTickersWithoutCreatedBySteps),
currentTickersSteps: createExportableElement(_GameWindowManager._currentTickersSteps),
currentElements: createExportableElement(currentElements),
childrenTagsOrder: createExportableElement(_GameWindowManager.childrenTagsOrder)
};
}
/**
* Import the canvas and the tickers from a JSON string.
* @param dataString The JSON string.
*/
static importJson(dataString) {
_GameWindowManager.import(JSON.parse(dataString));
}
/**
* Import the canvas and the tickers from an object.
* @param data The object.
*/
static import(data) {
_GameWindowManager.clear();
try {
if (data.hasOwnProperty("childrenTagsOrder") && data.hasOwnProperty("currentElements")) {
let currentElements = data["currentElements"];
let childrenTagsOrder = data["childrenTagsOrder"];
childrenTagsOrder.forEach((tag) => {
if (currentElements[tag]) {
let element = importCanvasElement(currentElements[tag]);
_GameWindowManager.addCanvasElement(tag, element);
_GameWindowManager.childrenTagsOrder.push(tag);
}
});
} else {
console.error("[Pixi'VN] The data does not have the properties childrenTagsOrder and currentElements");
return;
}
if (data.hasOwnProperty("currentTickers")) {
let currentTickers = data["currentTickers"];
for (let id in currentTickers) {
let t = currentTickers[id];
let tags = t.canvasElementTags;
let ticker = geTickerInstanceById(t.id, t.args, t.duration, t.priority);
if (ticker) {
_GameWindowManager.addTicker(tags, ticker);
} else {
console.error(`[Pixi'VN] Ticker ${t.id} not found`);
}
}
}
if (data.hasOwnProperty("currentTickersSteps")) {
let currentTickersSteps = data["currentTickersSteps"];
_GameWindowManager.restoneTickersSteps(currentTickersSteps);
}
} catch (e) {
console.error("[Pixi'VN] Error importing data", e);
}
}
};
_GameWindowManager._app = void 0;
_GameWindowManager._isInitialized = false;
_GameWindowManager._children = {};
/**
* The order of the children tags.
*/
_GameWindowManager.childrenTagsOrder = [];
_GameWindowManager._currentTickers = {};
_GameWindowManager._currentTickersSteps = {};
_GameWindowManager._currentTickersTimeouts = {};
var GameWindowManager = _GameWindowManager;
// src/managers/StepManager.ts
var _GameStepManager = class _GameStepManager {
constructor() {
}
static get stepsHistory() {
return _GameStepManager._stepsHistory;
}
/**
* lastStepIndex is the last step index that occurred during the progression of the steps. **Not is the length of the stepsHistory - 1.**
*/
static get lastStepIndex() {
return _GameStepManager._lastStepIndex;
}
/**
* Increase the last step index that occurred during the progression of the steps.
*/
static increaseLastStepIndex() {
_GameStepManager._lastStepIndex++;
}
static get openedLabels() {
return _GameStepManager._openedLabels;
}
/**
* currentLabelId is the current label id that occurred during the progression of the steps.
*/
static get currentLabelId() {
if (_GameStepManager._openedLabels.length > 0) {
let item = _GameStepManager._openedLabels[_GameStepManager._openedLabels.length - 1];
return item.label;
}
return void 0;
}
/**
* currentLabel is the current label that occurred during the progression of the steps.
*/
static get currentLabel() {
if (_GameStepManager.currentLabelId) {
return getLabelById(_GameStepManager.currentLabelId);
}
}
static get currentLabelStepIndex() {
if (_GameStepManager._openedLabels.length > 0) {
let item = _GameStepManager._openedLabels[_GameStepManager._openedLabels.length - 1];
return item.currentStepIndex;
}
return null;
}
/**
* lastHistoryStep is the last history step that occurred during the progression of the steps.
*/
static get lastHistoryStep() {
if (_GameStepManager._stepsHistory.length > 0) {
return _GameStepManager._stepsHistory[_GameStepManager._stepsHistory.length - 1];
}
return null;
}
static get originalStepData() {
if (!_GameStepManager._originalStepData) {
return {
path: "",
storage: {},
canvas: {
childrenTagsOrder: [],
currentElements: {},
currentTickers: {},
currentTickersSteps: {}
},
labelIndex: -1,
openedLabels: []
};
}
return createExportableElement(_GameStepManager._originalStepData);
}
static set originalStepData(value) {
_GameStepManager._originalStepData = createExportableElement(value);
}
static get currentStepData() {
let currentStepData = {
path: window.location.pathname,
storage: GameStorageManager.export(),
canvas: GameWindowManager.export(),
labelIndex: _GameStepManager.currentLabelStepIndex || 0,
openedLabels: createExportableElement(_GameStepManager._openedLabels)
};
return currentStepData;
}
/* Edit History Methods */
/**
* Add a label to the history.
* @param label The label to add to the history.
*/
static addStepHistory(step, choiseMade) {
let stepHistory = getStepSha1(step);
let currentStepData = _GameStepManager.currentStepData;
if (_GameStepManager.originalStepData) {
if (_GameStepManager.originalStepData.openedLabels.length === currentStepData.openedLabels.length) {
try {
let lastStepDataOpenedLabelsString = JSON.stringify(_GameStepManager.originalStepData.openedLabels);
let historyStepOpenedLabelsString = JSON.stringify(currentStepData.openedLabels);
if (lastStepDataOpenedLabelsString === historyStepOpenedLabelsString && _GameStepManager.originalStepData.path === currentStepData.path && _GameStepManager.originalStepData.labelIndex === currentStepData.labelIndex) {
return;
}
} catch (e) {
console.error("[Pixi'VN] Error comparing openedLabels", e);
}
}
}
let data = deepDiff.diff(_GameStepManager.originalStepData, currentStepData);
if (data) {
let dialoge = void 0;
let requiredChoices = void 0;
if (GameStorageManager.getVariable(GameStorageManager.keysSystem.LAST_DIALOGUE_ADDED_IN_STEP_MEMORY_KEY) === _GameStepManager.lastStepIndex) {
dialoge = getDialogue();
}
if (GameStorageManager.getVariable(GameStorageManager.keysSystem.LAST_MENU_OPTIONS_ADDED_IN_STEP_MEMORY_KEY) === _GameStepManager.lastStepIndex) {
requiredChoices = GameStorageManager.getVariable(GameStorageManager.keysSystem.CURRENT_MENU_OPTIONS_MEMORY_KEY);
}
_GameStepManager._stepsHistory.push({
diff: data,
currentLabel: _GameStepManager.currentLabelId,
dialoge,
choices: requiredChoices,
stepSha1: stepHistory,
index: _GameStepManager.lastStepIndex,
choiceIndexMade: choiseMade
});
_GameStepManager.originalStepData = currentStepData;
}
_GameStepManager.increaseLastStepIndex();
}
/**
* Add a label to the history.
* @param label The label to add to the history.
*/
static pushNewLabel(label) {
let currentLabel = getLabelById(label);
if (!currentLabel) {
throw new Error(`[Pixi'VN] Label ${label} not found`);
}
_GameStepManager._openedLabels.push({
label,
currentStepIndex: 0
});
}
/**
* Close the current label and add it to the history.
* @returns
*/
static closeCurrentLabel() {
if (!_GameStepManager.currentLabelId) {
console.warn("[Pixi'VN] No label to close");
return;
}
if (!_GameStepManager.currentLabel) {
console.error("[Pixi'VN] currentLabel not found");
return;
}
_GameStepManager._openedLabels.pop();
}
/**
* Close all labels and add them to the history. **Attention: This method can cause an unhandled game ending.**
*/
static closeAllLabels() {
while (_GameStepManager._openedLabels.length > 0) {
_GameStepManager.closeCurrentLabel();
}
}
/**
* Increase the current step index of the current label.
*/
static increaseCurrentStepIndex() {
let item = _GameStepManager._openedLabels[_GameStepManager._openedLabels.length - 1];
_GameStepManager._openedLabels[_GameStepManager._openedLabels.length - 1] = __spreadProps(__spreadValues({}, item), {
currentStepIndex: item.currentStepIndex + 1
});
}
static restorLastLabelList() {
_GameStepManager._openedLabels = _GameStepManager.originalStepData.openedLabels;
}
/* Run Methods */
static get canGoNext() {
let options = getChoiceMenuOptions();
if (options && options.length > 0) {
return false;
}
return true;
}
/**
* Execute the next step and add it to the history.
* @param props The props to pass to the step.
* @param choiseMade The index of the choise made by the player. (This params is used in the choice menu)
* @returns StepLabelResultType or undefined.
* @example
* ```typescript
* function nextOnClick() {
* setLoading(true)
* GameStepManager.goNext(yourParams)
* .then((result) => {
* setUpdate((p) => p + 1)
* setLoading(false)
* if (result) {
* // your code
* }
* })
* .catch((e) => {
* setLoading(false)
* console.error(e)
* })
* }
* ```
*/
static goNext(props, choiseMade) {
return __async(this, null, function* () {
if (!_GameStepManager.canGoNext) {
console.warn("[Pixi'VN] The player must make a choice");
return;
}
if (_GameStepManager.currentLabel && _GameStepManager.currentLabel.onStepEnd) {
yield _GameStepManager.currentLabel.onStepEnd(_GameStepManager.currentLabelStepIndex || 0, _GameStepManager.currentLabel);
}
_GameStepManager.increaseCurrentStepIndex();
return yield _GameStepManager.runCurrentStep(props, choiseMade);
});
}
/**
* Execute the current step and add it to the history.
* @param props The props to pass to the step.
* @param choiseMade The choise made by the player.
* @returns StepLabelResultType or undefined.
*/
static runCurrentStep(props, choiseMade) {
return __async(this, null, function* () {
if (_GameStepManager.currentLabelId) {
let currentLabelStepIndex = _GameStepManager.currentLabelStepIndex;
if (currentLabelStepIndex === null) {
console.error("[Pixi'VN] currentLabelStepIndex is null");
return;
}
let currentLabel = _GameStepManager.currentLabel;
if (!currentLabel) {
console.error("[Pixi'VN] currentLabel not found");
return;
}
if (currentLabel.steps.length > currentLabelStepIndex) {
let onStepRun = currentLabel.onStepStart;
if (onStepRun) {
yield onStepRun(currentLabelStepIndex, currentLabel);
}
let step = currentLabel.steps[currentLabelStepIndex];
let result = yield step(props);
_GameStepManager.addStepHistory(step, choiseMade);
return result;
} else if (_GameStepManager.openedLabels.length > 1) {
_GameStepManager.closeCurrentLabel();
return yield _GameStepManager.goNext(props, choiseMade);
} else {
_GameStepManager.restorLastLabelList();
if (_GameStepManager.gameEnd) {
return yield _GameStepManager.gameEnd(props);
}
console.error("[Pixi'VN] The end of the game is not managed, so the game is blocked. Read this documentation to know how to manage the end of the game: https://pixi-vn.web.app/start/labels.html#how-manage-the-end-of-the-game");
return;
}
}
});
}
/**
* Execute the label and add it to the history. (It's similar to Ren'Py's call function)
* @param label The label to execute or the id of the label
* @param props The props to pass to the label.
* @returns StepLabelResultType or undefined.
* @example
* ```typescript
* GameStepManager.callLabel(startLabel, yourParams).then((result) => {
* if (result) {
* // your code
* }
* })
* ```
* @example
* ```typescript
* // if you use it in a step label you should return the result.
* return GameStepManager.callLabel(startLabel).then((result) => {
* return result
* })
* ```
*/
static callLabel(label, props) {
return __async(this, null, function* () {
let choiseMade = void 0;
let labelId;
if (typeof label === "string") {
labelId = label;
} else {
labelId = label.id;
if (typeof label.choiseIndex === "number") {
choiseMade = label.choiseIndex;
}
}
try {
if (labelId === CLOSE_LABEL_ID) {
let closeCurrentLabel = newCloseLabel(choiseMade);
let choice = {
label: closeCurrentLabel,
text: "",
closeCurrentLabel: false,
type: "close",
props: {}
};
return _GameStepManager.closeChoiceMenu(choice, props);
}
let tempLabel = getLabelById(labelId);
if (!tempLabel) {
throw new Error(`[Pixi'VN] Label ${labelId} not found`);
}
if (_GameStepManager.currentLabel && _GameStepManager.currentLabel.onStepEnd) {
yield _GameStepManager.currentLabel.onStepEnd(_GameStepManager.currentLabelStepIndex || 0, _GameStepManager.currentLabel);
}
_GameStepManager.pushNewLabel(tempLabel.id);
} catch (e) {
console.error("[Pixi'VN] Error calling label", e);
return;
}
return yield _GameStepManager.runCurrentStep(props, choiseMade);
});
}
/**
* Execute the label, close the current label, execute the new label and add the new label to the history. (It's similar to Ren'Py's jump function)
* @param label The label to execute.
* @param props The props to pass to the label or the id of the label
* @returns StepLabelResultType or undefined.
* @example
* ```typescript
* GameStepManager.jumpLabel(startLabel, yourParams).then((result) => {
* if (result) {
* // your code
* }
* })
* ```
* @example
* ```typescript
* // if you use it in a step label you should return the result.
* return GameStepManager.jumpLabel(startLabel).then((result) => {
* return result
* })
* ```
*/
static jumpLabel(label, props) {
return __async(this, null, function* () {
_GameStepManager.closeCurrentLabel();
let choiseMade = void 0;
let labelId;
if (typeof label === "string") {
labelId = label;
} else {
labelId = label.id;
if (typeof label.choiseIndex === "number") {
choiseMade = label.choiseIndex;
}
}
try {
if (labelId === CLOSE_LABEL_ID) {
let closeCurrentLabel = newCloseLabel(choiseMade);
let choice = {
label: closeCurrentLabel,
text: "",
closeCurrentLabel: false,
type: "close",
props: {}
};
return _GameStepManager.closeChoiceMenu(choice, props);
}
let tempLabel = getLabelById(labelId);
if (!tempLabel) {
throw new Error(`[Pixi'VN] Label ${labelId} not found`);
}
if (_GameStepManager.currentLabel && _GameStepManager.currentLabel.onStepEnd) {
yield _GameStepManager.currentLabel.onStepEnd(_GameStepManager.currentLabelStepIndex || 0, _GameStepManager.currentLabel);
}
_GameStepManager.pushNewLabel(tempLabel.id);
} catch (e) {
console.error("[Pixi'VN] Error jumping label", e);
return;
}
return yield _GameStepManager.runCurrentStep(props, choiseMade);
});
}
/**
* When the player is in a choice menu, can use this function to exit to the choice menu.
* @param choice
* @param props
* @returns StepLabelResultType or undefined.
* @example
* ```typescript
* GameStepManager.closeChoiceMenu(yourParams).then((result) => {
* if (result) {
* // your code
* }
* })
* ```
*/
static closeChoiceMenu(choice, props) {
return __async(this, null, function* () {
let label = choice.label;
let choiseMade = void 0;
if (typeof label.choiseIndex === "number") {
choiseMade = label.choiseIndex;
}
if (choice.closeCurrentLabel) {
_GameStepManager.closeCurrentLabel();
}
return _GameStepManager.goNext(props, choiseMade);
});
}
/* After Update Methods */
// /**
// * After the update or code edit, some steps or labels may no longer match.
// * - In case of step mismatch, the game will be updated to the last matching step.
// * - In case of label mismatch, the game gives an error.
// * @returns
// */
// private static afterUpdate() {
// // TODO: implement
// if (!GameStepManager.currentLabel) {
// // TODO: implement
// return
// }
// let currentLabel = getLabelInstanceByClassName(GameStepManager.currentLabel)
// if (!currentLabel) {
// console.error("Label not found")
// return
// }
// let oldSteps = GameStepManager.stepsAfterLastHistoryLabel
// let currentStepIndex = currentLabel.getCorrespondingStepsNumber(oldSteps)
// let stepToRemove = oldSteps.length - currentStepIndex
// GameStepManager.removeLastHistoryNodes(stepToRemove)
// GameStepManager.loadLastStep()
// }
// private static loadLastStep() {
// // TODO: implement
// }
// /**
// * Remove a number of items from the last of the history.
// * @param itemNumber The number of items to remove from the last of the history.
// */
// private static removeLastHistoryNodes(itemNumber: number) {
// // TODO: implement
// for (let i = 0; i < itemNumber; i++) {
// GameStepManager._stepsHistory.pop()
// }
// }
// /**
// * stepsAfterLastHistoryLabel is a list of steps that occurred after the last history label.
// */
// private static get stepsAfterLastHistoryLabel(): StepHistoryDataType[] {
// let length = GameStepManager._stepsHistory.length
// let steps: StepHistoryDataType[] = []
// for (let i = length - 1; i >= 0; i--) {
// let element = GameStepManager._stepsHistory[i]
// if (typeof element === "object" && "stepSha1" in element) {
// steps.push(element.stepSha1)
// }
// else {
// break
// }
// }
// steps = steps.reverse()
// return steps
// }
/* Go Back & Refresh Methods */
/**
* Go back to the last step and add it to the history.
* @param navigate The navigate function.
* @param steps The number of steps to go back.
* @returns
* @example
* ```typescript
* export function goBack(navigate: (path: string) => void, afterBack?: () => void) {
* GameStepManager.goBack(navigate)
* afterBack && afterBack()
* }
* ```
*/
static goBack(navigate, steps = 1) {
return __async(this, null, function* () {
if (steps <= 0) {
console.warn("[Pixi'VN] Steps must be greater than 0");
return;
}
if (_GameStepManager._stepsHistory.length <= 1) {
console.warn("[Pixi'VN] No steps to go back");
return;
}
let restoredStep = _GameStepManager.goBackInternal(steps, _GameStepManager.originalStepData);
if (restoredStep) {
_GameStepManager._originalStepData = restoredStep;
_GameStepManager._openedLabels = createExportableElement(restoredStep.openedLabels);
if (_GameStepManager.currentLabel && _GameStepManager.currentLabel.onLoadStep) {
yield _GameStepManager.currentLabel.onLoadStep(_GameStepManager.currentLabelStepIndex || 0, _GameStepManager.currentLabel);
}
GameStorageManager.import(createExportableElement(restoredStep.storage));
GameWindowManager.import(createExportableElement(restoredStep.canvas));
navigate(restoredStep.path);
} else {
console.error("[Pixi'VN] Error going back");
}
});
}
static goBackInternal(steps, restoredStep) {
if (steps <= 0) {
return restoredStep;
}
if (_GameStepManager._stepsHistory.length == 0) {
return restoredStep;
}
let lastHistoryStep = _GameStepManager.lastHistoryStep;
if (lastHistoryStep) {
try {
let result = restoreDeepDiffChanges(restoredStep, lastHistoryStep.diff);
_GameStepManager._lastStepIndex = lastHistoryStep.index;
_GameStepManager._stepsHistory.pop();
return _GameStepManager.goBackInternal(steps - 1, result);
} catch (e) {
console.error("[Pixi'VN] Error applying diff", e);
return restoredStep;
}
} else {
return restoredStep;
}
}
/**
* Return true if it is possible to go back.
*/
static get canGoBack() {
return _GameStepManager._stepsHistory.length > 1;
}
/**
* Add a label to the history.
*/
static clear() {
_GameStepManager._stepsHistory = [];
_GameStepManager._openedLabels = [];
}
/* Export and Import Methods */
/**
* Export the history to a JSON string.
* @returns The history in a JSON string.
*/
static exportJson() {
return JSON.stringify(this.export());
}
/**
* Export the history to an object.
* @returns The history in an object.
*/
static export() {
return {
stepsHistory: _GameStepManager._stepsHistory,
openedLabels: _GameStepManager._openedLabels,
lastStepIndex: _GameStepManager._lastStepIndex,
originalStepData: _GameStepManager._originalStepData
};
}
/**
* Import the history from a JSON string.
* @param dataString The history in a JSON string.
*/
static importJson(dataString) {
return __async(this, null, function* () {
yield _GameStepManager.import(JSON.parse(dataString));
});
}
/**
* Import the history from an object.
* @param data The history in an object.
*/
static import(data) {
return __async(this, null, function* () {
_GameStepManager.clear();
try {
if (data.hasOwnProperty("stepsHistory")) {
_GameStepManager._stepsHistory = data["stepsHistory"];
} else {
console.warn("[Pixi'VN] Could not import stepsHistory data, so will be ignored");
}
if (data.hasOwnProperty("openedLabels")) {
_GameStepManager._openedLabels = data["openedLabels"];
} else {
console.warn("[Pixi'VN] Could not import openedLabels data, so will be ignored");
}
if (data.hasOwnProperty("lastStepIndex")) {
_GameStepManager._lastStepIndex = data["lastStepIndex"];
} else {
console.warn("[Pixi'VN] Could not import lastStepIndex data, so will be ignored");
}
if (data.hasOwnProperty("originalStepData")) {
_GameStepManager._originalStepData = data["originalStepData"];
} else {
console.warn("[Pixi'VN] Could not import originalStepData data, so will be ignored");
}
if (_GameStepManager.currentLabel && _GameStepManager.currentLabel.onLoadStep) {
yield _GameStepManager.currentLabel.onLoadStep(_GameStepManager.currentLabelStepIndex || 0, _GameStepManager.currentLabel);
}
} catch (e) {
console.error("[Pixi'VN] Error importing data", e);
}
});
}
};
/**
* stepHistory is a list of label events and steps that occurred during the progression of the steps.
*/
_GameStepManager._stepsHistory = [];
_GameStepManager._lastStepIndex = 0;
_GameStepManager._openedLabels = [];
_GameStepManager._originalStepData = void 0;
/**
* Function to be executed at the end of the game. It should be set in the game initialization.
* @example
* ```typescript
* GameStepManager.gameEnd = async (props) => {
* props.navigate("/end")
* }
* ```
*/
_GameStepManager.gameEnd = void 0;
var GameStepManager = _GameStepManager;
// src/classes/StoredClassModel.ts
var StoredClassModel = class {
/**
* @param categoryId The id of the category. For example if you are storing a character class, you can use "characters" as categoryId. so all instances of the character class will be stored in the "characters" category.
* @param id The id of instance of the class. This id must be unique for the category.
*/
constructor(categoryId, id) {
this.categoryId = categoryId;
this._id = id;
}
/**
* Is id of the stored class. is unique for this class.
*/
get id() {
return this._id;
}
/**
* Update a property in the storage.
* @param propertyName The name of the property to set.
* @param value The value to set. If is undefined, the property will be removed from the storage.
*/
setStorageProperty(propertyName, value) {
let storage = GameStorageManager.getVariable(this.categoryId);
if (!storage) {
storage = {};
}
if (!storage.hasOwnProperty(this.id)) {
storage[this.id] = {};
}
if (value === void 0 || value === null) {
if (storage[this.id].hasOwnProperty(propertyName)) {
delete storage[this.id][propertyName];
}
} else {
storage[this.id] = __spreadProps(__spreadValues({}, storage[this.id]), { [propertyName]: value });
}
if (Object.keys(storage[this.id]).length === 0) {
delete storage[this.id];
}
GameStorageManager.setVariable(this.categoryId, storage);
}
/**
* Get a property from the storage.
* @param propertyName The name of the property to get.
* @returns The value of the property. If the property is not found, returns undefined.
*/
getStorageProperty(propertyName) {
let storage = GameStorageManager.getVariable(this.categoryId);
if (storage && storage.hasOwnProperty(this.id) && storage[this.id].hasOwnProperty(propertyName)) {
return storage[this.id][propertyName];
}
return void 0;
}
};
// src/classes/CharacterBaseModel.ts
var CharacterBaseModel2 = class extends StoredClassModel {
/**
* @param id The id of the character.
* @param props The properties of the character.
*/
constructor(id, props) {
super(GameStorageManager.keysSystem.CHARACTER_CATEGORY_KEY, id);
this.defaultName = "";
this.defaultName = props.name;
this.defaultSurname = props.surname;
this.defaultAge = props.age;
this._icon = props.icon;
this._color = props.color;
}
/***
* The name of the character.
* If you set undefined, it will return the default name.
*/
get name() {
return this.getStorageProperty("name") || this.defaultName;
}
set name(value) {
this.setStorageProperty("name", value);
}
/**
* The surname of the character.
* If you set undefined, it will return the default surname.
*/
get surname() {
return this.getStorageProperty("surname") || this.defaultSurname;
}
set surname(value) {
this.setStorageProperty("surname", value);
}
/**
* The age of the character.
* If you set undefined, it will return the default age.
*/
get age() {
return this.getStorageProperty("age") || this.defaultAge;
}
set age(value) {
this.setStorageProperty("age", value);
}
/**
* The icon of the character.
*/
get icon() {
return this._icon;
}
/**
* The color of the character.
*/
get color() {
return this._color;
}
};
// src/classes/DialogueBaseModel.ts
var DialogueBaseModel = class {
/**
* @param text The text of the dialogue.
* @param character The id of the character that is speaking.
* @param oltherParams Other parameters that can be stored in the dialogue.
*/
constructor(text, character, oltherParams = {}) {
/**
* The text of the dialogue.
*/
this.text = "";
/**
* Other parameters that can be stored in the dialogue.
*/
this.oltherParams = {};
if (typeof text === "string") {
this.text = text;
if (typeof character === "string") {
this.character = character;
} else {
this.character = character == null ? void 0 : character.id;
}
this.oltherParams = oltherParams;
} else {
this.text = text.text;
if (text.character) {
this.character = text.character;
}
this.oltherParams = text.oltherParams || {};
}
}
/**
* Export the dialogue to a DialogueBaseData object.
*
* @returns The data of the dialogue.
*/
export() {
return {
text: this.text,
character: this.character,
oltherParams: this.oltherParams
};
}
};
// src/labels/TestConstant.ts
var juliette = new CharacterBaseModel2("___pixivn_juliette___", {
name: "Juliette",
age: 25,
icon: "https://firebasestorage.googleapis.com/v0/b/pixi-vn.appspot.com/o/public%2Fcharacters%2Fjuliette-square.webp?alt=media",
color: "#ac0086"
});
saveCharacter(juliette);
var bunnyImage = "https://pixijs.com/assets/bunny.png";
var bunnyName = `Bunny`;
// src/labels/CanvasEventsTestLabel.ts
exports.EventTest1 = class EventTest1 extends CanvasEvent {
fn(event, sprite) {
if (event === "pointerdown") {
sprite.scale.x *= 1.25;
sprite.scale.y *= 1.25;
}
}
};
exports.EventTest1 = __decorateClass([
eventDecorator("___pixi_vn_canvas_events_test_event1___")
], exports.EventTest1);
exports.EventTest2 = class EventTest2 extends CanvasEvent {
fn(event, sprite) {
if (event === "pointerdown") {
sprite.isdown = true;
sprite.texture = pixi_js.Texture.from("https://pixijs.com/assets/button_down.png");
sprite.alpha = 1;
} else if (event === "pointerup" || event === "pointerupoutside") {
sprite.isdown = false;
if (sprite.isOver) {
sprite.texture = pixi_js.Texture.from("https://pixijs.com/assets/button_over.png");
} else {
sprite.texture = pixi_js.Texture.from("https://pixijs.com/assets/button.png");
}
} else if (event === "pointerover") {
sprite.isOver = true;
if (sprite.isdown) {
return;
}
sprite.texture = pixi_js.Texture.from("https://pixijs.com/assets/button_over.png");
} else if (event === "pointerout") {
sprite.isOver = false;
if (sprite.isdown) {
return;
}
sprite.texture = pixi_js.Texture.from("https://pixijs.com/assets/button.png");
}
}
};
exports.EventTest2 = __decorateClass([
eventDecorator("___pixi_vn_canvas_events_test_event2___")
], exports.EventTest2);
var CANVAS_EVENTS_TEST_LABEL = "___pixi_vn_canvas_events_test___";
var canvasEventsTestLabel = newLabel(
CANVAS_EVENTS_TEST_LABEL,
[
() => setDialogue({
character: juliette,
text: "This is the test of clickable elements in a canvas."
}),
() => __async(void 0, null, function* () {
setDialogue({
character: juliette,
text: `This is my friend, ${bunnyName}. It's small now, but if you try to click on it it will get bigger and bigger. (This example is from the official [PixiJS website](https://pixijs.com/8.x/examples/events/click).)`
});
const texture = yield pixi_js.Assets.load(bunnyImage);
const sprite = CanvasSprite.from(texture);
sprite.scale.set(3);
sprite.anchor.set(0.5);
sprite.x = GameWindowManager.screen.width / 2;
sprite.y = GameWindowManager.screen.height / 2;
sprite.eventMode = "static";
sprite.cursor = "pointer";
sprite.onEvent("pointerdown", exports.EventTest1);
GameWindowManager.addCanvasElement("bunny", sprite);
}),
() => __async(void 0, null, function* () {
GameWindowManager.clear();
setDialogue({
character: juliette,
text: `This is the test of buttons in a canvas. (This example is from the official [PixiJS website](https://pixijs.com/8.x/examples/events/interactivity).)`
});
const backgroundT = yield pixi_js.Assets.load("https://pixijs.com/assets/bg_button.jpg");
const background = new CanvasSprite(backgroundT);
background.width = GameWindowManager.screen.width;
background.height = GameWindowManager.screen.height;
GameWindowManager.addCanvasElement("bg", background);
const textureButton = yield pixi_js.Assets.load("https://pixijs.com/assets/button.png");
const buttons = [];
const buttonPositions = [175, 75, 655, 75, 410, 325, 150, 465, 685, 445];
for (let i = 0; i < 5; i++) {
const button = new CanvasSprite(textureButton);
button.anchor.set(0.5);
button.x = buttonPositions[i * 2];
button.y = buttonPositions[i * 2 + 1];
button.eventMode = "static";
button.cursor = "pointer";
button.onEvent("pointerdown", exports.EventTest2).onEvent("pointerup", exports.EventTest2).onEvent("pointerupoutside", exports.EventTest2).onEvent("pointerover", exports.EventTest2).onEvent("pointerout", exports.EventTest2);
GameWindowManager.addCanvasElement("button" + i, button);
buttons.push(button);
}
buttons[0].scale.set(1.2);
buttons[2].rotation = Math.PI / 10;
buttons[3].scale.set(0.8);
buttons[4].scale.set(0.8, 1.2);
buttons[4].rotation = Math.PI;
})
],
{
onLoadStep: () => __async(void 0, null, function* () {
yield pixi_js.Assets.load([
"https://pixijs.com/assets/bg_button.jpg",
"https://pixijs.com/assets/button.png",
"https://pixijs.com/assets/button_down.png",
"https://pixijs.com/assets/button_over.png"
]);
})
}
);
exports.canvasEventsTestLabel = canvasEventsTestLabel;
//# sourceMappingURL=CanvasEventsTestLabel.js.map
//# sourceMappingURL=CanvasEventsTestLabel.js.map
;