diff --git a/.eslintrc.json b/.eslintrc.json
index a3c6afbb4..21de30d0c 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -1,247 +1,248 @@
-{
- "root": true,
- "env": {
- "browser": true,
- "commonjs": true,
- "es6": true,
- "node": true
- },
- "plugins": ["pug", "@typescript-eslint"],
- "globals": {
- "alertify": true,
- "dragonBones": true,
- "monaco": true,
- "nw": true,
- "PIXI": true,
- "QRCode": true,
- "riot": true,
- "soundbox": true
- },
- "parser": "@typescript-eslint/parser",
- "parserOptions": {
- "ecmaVersion": 2018
- },
- "extends": [
- "eslint:recommended",
- "plugin:@typescript-eslint/eslint-recommended",
- "plugin:@typescript-eslint/recommended"
- ],
- "rules": {
- "@typescript-eslint/no-var-requires": "off",
- "accessor-pairs": "error",
- "array-bracket-spacing": ["error", "never"],
- "array-callback-return": "error",
- "array-element-newline": ["error", "consistent"],
- "arrow-body-style": "error",
- "arrow-parens": "off",
- "arrow-spacing": ["error", {"after": true, "before": true}],
- "block-scoped-var": "error",
- "block-spacing": ["error", "never"],
- "brace-style": ["error", "1tbs", {"allowSingleLine": false}],
- "callback-return": "off",
- "camelcase": "error",
- "capitalized-comments": ["off", "always"],
- "class-methods-use-this": "error",
- "comma-dangle": ["warn", "never"],
- "comma-spacing": ["error", {"before": false, "after": true}],
- "comma-style": ["error", "last"],
- "complexity": "error",
- "computed-property-spacing": ["error","never"],
- "consistent-return": "error",
- "consistent-this": "error",
- "curly": "error",
- "default-case": "error",
- "dot-location": "off",
- "dot-notation": "error",
- "eol-last": ["error", "always"],
- "eqeqeq": "error",
- "func-call-spacing": ["error", "never"],
- "func-name-matching": "error",
- "func-names": ["error", "as-needed"],
- "func-style": ["error", "expression"],
- "function-paren-newline": ["error", "multiline"],
- "generator-star-spacing": "error",
- "global-require": "off",
- "guard-for-in": "off",
- "handle-callback-err": "error",
- "id-blacklist": ["error", "data", "tag", "element"],
- "id-length": ["error", {"min": 1, "max": 24}],
- "id-match": "error",
- "indent": ["error", 4, {"VariableDeclarator": "first", "MemberExpression": "off", "ignoreComments": true}],
- "init-declarations": "off",
- "jsx-quotes": "error",
- "key-spacing": ["error", {"beforeColon": false, "afterColon": true, "mode": "strict"}],
- "keyword-spacing": ["error", {"after": true, "before": true}],
- "line-comment-position": "off",
- "linebreak-style": ["error", "unix"],
- "lines-around-comment": "off",
- "max-depth": ["error", 4],
- "max-len": ["error", {"code": 100, "ignoreComments": false, "ignoreUrls": true, "ignoreStrings": true, "ignoreTemplateLiterals": true, "ignoreRegExpLiterals": true}],
- "max-lines": "off",
- "max-lines-per-function": ["error", {"max": 80, "skipBlankLines": true, "skipComments": true}],
- "max-nested-callbacks": ["error", 10],
- "max-params": ["error", 5],
- "max-statements": "off",
- "max-statements-per-line": ["error", {"max": 1}],
- "multiline-ternary": ["error", "always-multiline"],
- "new-cap": "warn",
- "new-parens": "error",
- "newline-per-chained-call": ["error", {"ignoreChainWithDepth": 2}],
- "no-alert": "error",
- "no-array-constructor": "error",
- "no-await-in-loop": "error",
- "no-bitwise": "warn",
- "no-caller": "error",
- "no-confusing-arrow": "error",
- "no-console": ["warn", {
- "allow": ["error"]
- }],
- "no-continue": "off",
- "no-div-regex": "error",
- "no-duplicate-imports": "error",
- "no-else-return": "error",
- "no-empty-function": "error",
- "no-eq-null": "error",
- "no-eval": "error",
- "no-extend-native": "error",
- "no-extra-bind": "error",
- "no-extra-label": "error",
- "no-extra-parens": "off",
- "no-floating-decimal": "error",
- "no-implicit-coercion": "error",
- "no-implicit-globals": "error",
- "no-implied-eval": "error",
- "no-inline-comments": "off",
- "no-inner-declarations": [
- "error",
- "functions"
- ],
- "no-invalid-this": "off",
- "no-iterator": "error",
- "no-label-var": "error",
- "no-labels": "error",
- "no-lone-blocks": "error",
- "no-lonely-if": "error",
- "no-loop-func": "error",
- "no-magic-numbers": "off",
- "no-mixed-operators": [
- "error",
- {
- "groups": [
- ["&", "|", "^", "~", "<<", ">>", ">>>"],
- ["==", "!=", "===", "!==", ">", ">=", "<", "<="],
- ["&&", "||"],
- ["in", "instanceof"]
- ],
- "allowSamePrecedence": true
- }
- ],
- "no-mixed-requires": "error",
- "no-mixed-spaces-and-tabs": "error",
- "no-multi-spaces": "error",
- "no-multi-str": "error",
- "no-multiple-empty-lines": ["error", {"max": 2, "maxEOF": 1}],
- "no-negated-condition": "off",
- "no-nested-ternary": "error",
- "no-new": "error",
- "no-new-func": "error",
- "no-new-object": "error",
- "no-new-require": "error",
- "no-new-wrappers": "error",
- "no-octal-escape": "error",
- "no-param-reassign": "off",
- "no-path-concat": "error",
- "no-plusplus": "off",
- "no-process-env": "warn",
- "no-process-exit": "error",
- "no-proto": "error",
- "no-prototype-builtins": "error",
- "no-restricted-globals": "error",
- "no-restricted-imports": "error",
- "no-restricted-modules": "error",
- "no-restricted-properties": "error",
- "no-restricted-syntax": ["error", "WithStatement"],
- "no-return-assign": "error",
- "no-return-await": "error",
- "no-script-url": "error",
- "no-self-compare": "error",
- "no-sequences": "error",
- "no-shadow": "off",
- "no-shadow-restricted-names": "error",
- "no-sync": "off",
- "no-tabs": "error",
- "no-template-curly-in-string": "error",
- "no-ternary": "off",
- "no-throw-literal": "error",
- "no-trailing-spaces": "error",
- "no-undef-init": "error",
- "no-undefined": "error",
- "no-underscore-dangle": ["error", {"allow": ["__dirname"]}],
- "no-unmodified-loop-condition": "error",
- "no-unneeded-ternary": "error",
- "no-unsafe-negation": "error",
- "no-unused-expressions": "error",
- "no-use-before-define": "error",
- "no-useless-call": "error",
- "no-useless-computed-key": "error",
- "no-useless-concat": "error",
- "no-useless-constructor": "error",
- "no-useless-escape": "error",
- "no-useless-rename": "error",
- "no-useless-return": "error",
- "no-var": "off",
- "no-void": "off",
- "no-warning-comments": "warn",
- "no-whitespace-before-property": "error",
- "no-with": "error",
- "object-curly-newline": ["error", {
- "ObjectExpression": {"minProperties": 1},
- "ObjectPattern": "never",
- "ImportDeclaration": "never",
- "ExportDeclaration": {"multiline": true, "minProperties": 2}
- }],
- "object-curly-spacing": ["error", "never"],
- "object-property-newline": ["error", {"allowAllPropertiesOnSameLine": true}],
- "object-shorthand": "error",
- "one-var": "off",
- "one-var-declaration-per-line": ["error", "initializations"],
- "operator-assignment": "error",
- "operator-linebreak": ["error", "after"],
- "padded-blocks": ["error", "never"],
- "prefer-arrow-callback": "off",
- "prefer-const": "error",
- "prefer-destructuring": "error",
- "prefer-exponentiation-operator": "warn",
- "prefer-numeric-literals": "error",
- "prefer-rest-params": "error",
- "prefer-spread": "error",
- "prefer-template": "off",
- "quote-props": ["error", "as-needed"],
- "quotes": ["error", "single"],
- "radix": "error",
- "require-atomic-updates": "error",
- "require-await": "error",
- "rest-spread-spacing": "error",
- "semi": ["error", "always"],
- "semi-spacing": "error",
- "semi-style": ["error", "last"],
- "sort-imports": "off",
- "sort-keys": "off",
- "sort-vars": "off",
- "space-before-blocks": ["error", "always"],
- "space-before-function-paren": ["error", {"anonymous": "always", "named": "never", "asyncArrow": "always"}],
- "space-in-parens": ["error", "never"],
- "space-infix-ops": "error",
- "space-unary-ops": "error",
- "spaced-comment": "error",
- "strict": "off",
- "symbol-description": "error",
- "template-curly-spacing": ["error", "never"],
- "template-tag-spacing": ["error", "never"],
- "unicode-bom": ["error", "never"],
- "vars-on-top": "off",
- "wrap-regex": "off",
- "yield-star-spacing": "error",
- "yoda": ["error", "never"]
- }
-}
+{
+ "root": true,
+ "env": {
+ "browser": true,
+ "commonjs": true,
+ "es6": true,
+ "node": true
+ },
+ "plugins": ["pug", "@typescript-eslint"],
+ "globals": {
+ "alertify": true,
+ "dragonBones": true,
+ "monaco": true,
+ "nw": true,
+ "PIXI": true,
+ "QRCode": true,
+ "riot": true,
+ "soundbox": true
+ },
+ "parser": "@typescript-eslint/parser",
+ "parserOptions": {
+ "ecmaVersion": 2018
+ },
+ "extends": [
+ "eslint:recommended",
+ "plugin:@typescript-eslint/eslint-recommended",
+ "plugin:@typescript-eslint/recommended"
+ ],
+ "rules": {
+ "@typescript-eslint/no-var-requires": "off",
+ "accessor-pairs": "error",
+ "array-bracket-spacing": ["error", "never"],
+ "array-callback-return": "error",
+ "array-element-newline": ["error", "consistent"],
+ "arrow-body-style": "error",
+ "arrow-parens": "off",
+ "arrow-spacing": ["error", {"after": true, "before": true}],
+ "block-scoped-var": "error",
+ "block-spacing": ["error", "never"],
+ "brace-style": ["error", "1tbs", {"allowSingleLine": false}],
+ "callback-return": "off",
+ "camelcase": "error",
+ "capitalized-comments": ["off", "always"],
+ "class-methods-use-this": "error",
+ "comma-dangle": ["warn", "never"],
+ "comma-spacing": ["error", {"before": false, "after": true}],
+ "comma-style": ["error", "last"],
+ "complexity": "error",
+ "computed-property-spacing": ["error","never"],
+ "consistent-return": "error",
+ "consistent-this": "error",
+ "curly": "error",
+ "default-case": "error",
+ "dot-location": "off",
+ "dot-notation": "error",
+ "eol-last": ["error", "always"],
+ "eqeqeq": "error",
+ "func-call-spacing": ["error", "never"],
+ "func-name-matching": "error",
+ "func-names": ["error", "as-needed"],
+ "func-style": ["error", "expression"],
+ "function-paren-newline": ["error", "multiline"],
+ "generator-star-spacing": "error",
+ "global-require": "off",
+ "guard-for-in": "off",
+ "handle-callback-err": "error",
+ "id-blacklist": ["error", "data", "tag", "element"],
+ "id-length": ["error", {"min": 1, "max": 24}],
+ "id-match": "error",
+ "indent": ["error", 4, {"VariableDeclarator": "first", "MemberExpression": "off", "ignoreComments": true}],
+ "init-declarations": "off",
+ "jsx-quotes": "error",
+ "key-spacing": ["error", {"beforeColon": false, "afterColon": true, "mode": "strict"}],
+ "keyword-spacing": ["error", {"after": true, "before": true}],
+ "line-comment-position": "off",
+ "linebreak-style": ["error", "unix"],
+ "lines-around-comment": "off",
+ "max-depth": ["error", 4],
+ "max-len": ["error", {"code": 100, "ignoreComments": false, "ignoreUrls": true, "ignoreStrings": true, "ignoreTemplateLiterals": true, "ignoreRegExpLiterals": true}],
+ "max-lines": "off",
+ "max-lines-per-function": ["error", {"max": 80, "skipBlankLines": true, "skipComments": true}],
+ "max-nested-callbacks": ["error", 10],
+ "max-params": ["error", 5],
+ "max-statements": "off",
+ "max-statements-per-line": ["error", {"max": 1}],
+ "multiline-ternary": ["error", "always-multiline"],
+ "new-cap": "warn",
+ "new-parens": "error",
+ "newline-per-chained-call": ["error", {"ignoreChainWithDepth": 2}],
+ "no-alert": "error",
+ "no-array-constructor": "error",
+ "no-await-in-loop": "error",
+ "no-bitwise": "warn",
+ "no-caller": "error",
+ "no-confusing-arrow": "error",
+ "no-console": ["warn", {
+ "allow": ["error"]
+ }],
+ "no-continue": "off",
+ "no-div-regex": "error",
+ "no-duplicate-imports": "error",
+ "no-else-return": "error",
+ "no-empty-function": "error",
+ "no-eq-null": "error",
+ "no-eval": "error",
+ "no-extend-native": "error",
+ "no-extra-bind": "error",
+ "no-extra-label": "error",
+ "no-extra-parens": "off",
+ "no-floating-decimal": "error",
+ "no-implicit-coercion": "error",
+ "no-implicit-globals": "error",
+ "no-implied-eval": "error",
+ "no-inline-comments": "off",
+ "no-inner-declarations": [
+ "error",
+ "functions"
+ ],
+ "no-invalid-this": "off",
+ "no-iterator": "error",
+ "no-label-var": "error",
+ "no-labels": "error",
+ "no-lone-blocks": "error",
+ "no-lonely-if": "error",
+ "no-loop-func": "error",
+ "no-magic-numbers": "off",
+ "no-mixed-operators": [
+ "error",
+ {
+ "groups": [
+ ["&", "|", "^", "~", "<<", ">>", ">>>"],
+ ["==", "!=", "===", "!==", ">", ">=", "<", "<="],
+ ["&&", "||"],
+ ["in", "instanceof"]
+ ],
+ "allowSamePrecedence": true
+ }
+ ],
+ "no-mixed-requires": "error",
+ "no-mixed-spaces-and-tabs": "error",
+ "no-multi-spaces": "error",
+ "no-multi-str": "error",
+ "no-multiple-empty-lines": ["error", {"max": 2, "maxEOF": 1}],
+ "no-negated-condition": "off",
+ "no-nested-ternary": "error",
+ "no-new": "error",
+ "no-new-func": "error",
+ "no-new-object": "error",
+ "no-new-require": "error",
+ "no-new-wrappers": "error",
+ "no-octal-escape": "error",
+ "no-param-reassign": "off",
+ "no-path-concat": "error",
+ "no-plusplus": "off",
+ "no-process-env": "warn",
+ "no-process-exit": "error",
+ "no-proto": "error",
+ "no-prototype-builtins": "error",
+ "no-restricted-globals": "error",
+ "no-restricted-imports": "error",
+ "no-restricted-modules": "error",
+ "no-restricted-properties": "error",
+ "no-restricted-syntax": ["error", "WithStatement"],
+ "no-return-assign": "error",
+ "no-return-await": "error",
+ "no-script-url": "error",
+ "no-self-compare": "error",
+ "no-sequences": "error",
+ "no-shadow": "off",
+ "no-shadow-restricted-names": "error",
+ "no-sync": "off",
+ "no-tabs": "error",
+ "no-template-curly-in-string": "error",
+ "no-ternary": "off",
+ "no-throw-literal": "error",
+ "no-trailing-spaces": "error",
+ "no-undef-init": "error",
+ "no-undefined": "error",
+ "no-underscore-dangle": ["error", {"allow": ["__dirname"]}],
+ "no-unmodified-loop-condition": "error",
+ "no-unneeded-ternary": "error",
+ "no-unsafe-negation": "error",
+ "no-unused-expressions": "off",
+ "@typescript-eslint/no-unused-expressions": "error",
+ "no-use-before-define": "error",
+ "no-useless-call": "error",
+ "no-useless-computed-key": "error",
+ "no-useless-concat": "error",
+ "no-useless-constructor": "error",
+ "no-useless-escape": "error",
+ "no-useless-rename": "error",
+ "no-useless-return": "error",
+ "no-var": "off",
+ "no-void": "off",
+ "no-warning-comments": "warn",
+ "no-whitespace-before-property": "error",
+ "no-with": "error",
+ "object-curly-newline": ["error", {
+ "ObjectExpression": {"minProperties": 1},
+ "ObjectPattern": "never",
+ "ImportDeclaration": "never",
+ "ExportDeclaration": {"multiline": true, "minProperties": 2}
+ }],
+ "object-curly-spacing": ["error", "never"],
+ "object-property-newline": ["error", {"allowAllPropertiesOnSameLine": true}],
+ "object-shorthand": "error",
+ "one-var": "off",
+ "one-var-declaration-per-line": ["error", "initializations"],
+ "operator-assignment": "error",
+ "operator-linebreak": ["error", "after"],
+ "padded-blocks": ["error", "never"],
+ "prefer-arrow-callback": "off",
+ "prefer-const": "error",
+ "prefer-destructuring": "error",
+ "prefer-exponentiation-operator": "warn",
+ "prefer-numeric-literals": "error",
+ "prefer-rest-params": "error",
+ "prefer-spread": "error",
+ "prefer-template": "off",
+ "quote-props": ["error", "as-needed"],
+ "quotes": ["error", "single"],
+ "radix": "error",
+ "require-atomic-updates": "error",
+ "require-await": "error",
+ "rest-spread-spacing": "error",
+ "semi": ["error", "always"],
+ "semi-spacing": "error",
+ "semi-style": ["error", "last"],
+ "sort-imports": "off",
+ "sort-keys": "off",
+ "sort-vars": "off",
+ "space-before-blocks": ["error", "always"],
+ "space-before-function-paren": ["error", {"anonymous": "always", "named": "never", "asyncArrow": "always"}],
+ "space-in-parens": ["error", "never"],
+ "space-infix-ops": "error",
+ "space-unary-ops": "error",
+ "spaced-comment": "error",
+ "strict": "off",
+ "symbol-description": "error",
+ "template-curly-spacing": ["error", "never"],
+ "template-tag-spacing": ["error", "never"],
+ "unicode-bom": ["error", "never"],
+ "vars-on-top": "off",
+ "wrap-regex": "off",
+ "yield-star-spacing": "error",
+ "yoda": ["error", "never"]
+ }
+}
diff --git a/app/data/Wood_End.wav b/app/data/Wood_End.wav
new file mode 100644
index 000000000..2e0b68c85
Binary files /dev/null and b/app/data/Wood_End.wav differ
diff --git a/app/data/Wood_Start.wav b/app/data/Wood_Start.wav
new file mode 100644
index 000000000..522753469
Binary files /dev/null and b/app/data/Wood_Start.wav differ
diff --git a/app/data/ct.libs/place/index.js b/app/data/ct.libs/place/index.js
index 0c8830fed..d627888cf 100644
--- a/app/data/ct.libs/place/index.js
+++ b/app/data/ct.libs/place/index.js
@@ -286,6 +286,9 @@
drawDebugGraphic(absolute) {
const shape = this._shape || getSSCDShape(this);
const g = this.$cDebugCollision;
+ const inverse = this.transform.localTransform.clone().invert();
+ this.$cDebugCollision.transform.setFromMatrix(inverse);
+ this.$cDebugCollision.position.set(0, 0);
let color = 0x00ffff;
if (this instanceof Copy) {
color = 0x0066ff;
diff --git a/app/data/ct.libs/place/injections/beforedraw.js b/app/data/ct.libs/place/injections/beforedraw.js
index 4a73bb439..b50d023df 100644
--- a/app/data/ct.libs/place/injections/beforedraw.js
+++ b/app/data/ct.libs/place/injections/beforedraw.js
@@ -1,7 +1,9 @@
if ([/*%debugMode%*/][0] && this instanceof ct.templates.Copy) {
- this.$cDebugText.scale.x = this.$cDebugCollision.scale.x = 1 / this.scale.x;
- this.$cDebugText.scale.y = this.$cDebugCollision.scale.y = 1 / this.scale.y;
- this.$cDebugText.angle = this.$cDebugCollision.angle = -this.angle;
+ const inverse = this.transform.localTransform.clone().invert();
+ this.$cDebugCollision.transform.setFromMatrix(inverse);
+ this.$cDebugCollision.position.set(0, 0);
+ this.$cDebugText.transform.setFromMatrix(inverse);
+ this.$cDebugText.position.set(0, 0);
const newtext = `Partitions: ${this.$chashes.join(', ')}
CGroup: ${this.cgroup || 'unset'}
diff --git a/app/data/ct.release/rooms.js b/app/data/ct.release/rooms.js
index 4190dec59..ae8ccbb98 100644
--- a/app/data/ct.release/rooms.js
+++ b/app/data/ct.release/rooms.js
@@ -22,26 +22,28 @@ class Room extends PIXI.Container {
ct.room = ct.rooms.current = this;
}
if (template) {
- if (template.extends) {
- ct.u.ext(this, template.extends);
- }
this.onCreate = template.onCreate;
this.onStep = template.onStep;
this.onDraw = template.onDraw;
this.onLeave = template.onLeave;
this.template = template;
this.name = template.name;
+ this.isUi = template.isUi;
+ if (template.extends) {
+ ct.u.ext(this, template.extends);
+ }
if (this === ct.room) {
ct.pixiApp.renderer.backgroundColor = ct.u.hexToPixi(this.template.backgroundColor);
}
/*%beforeroomoncreate%*/
for (let i = 0, li = template.bgs.length; i < li; i++) {
- // Need to put extensions here, so we don't use ct.backgrounds.add
+ // Need to put additional properties like parallax here,
+ // so we don't use ct.backgrounds.add
const bg = new ct.templates.Background(
template.bgs[i].texture,
null,
template.bgs[i].depth,
- template.bgs[i].extends
+ template.bgs[i]
);
this.addChild(bg);
}
@@ -52,17 +54,22 @@ class Room extends PIXI.Container {
this.addChild(tl);
}
for (let i = 0, li = template.objects.length; i < li; i++) {
- const exts = template.objects[i].exts || {};
+ const copy = template.objects[i];
+ const exts = copy.exts || {};
+ const customProperties = copy.customProperties || {};
ct.templates.copyIntoRoom(
- template.objects[i].template,
- template.objects[i].x,
- template.objects[i].y,
+ copy.template,
+ copy.x,
+ copy.y,
this,
{
- tx: template.objects[i].tx,
- ty: template.objects[i].ty,
- tr: template.objects[i].tr,
- ...exts
+ ...exts,
+ ...customProperties,
+ scaleX: copy.scale.x,
+ scaleY: copy.scale.y,
+ rotation: copy.rotation,
+ alpha: copy.opacity,
+ tint: copy.tint
}
);
}
diff --git a/app/data/ct.release/templates.js b/app/data/ct.release/templates.js
index 6961e1c8d..24019b8c4 100644
--- a/app/data/ct.release/templates.js
+++ b/app/data/ct.release/templates.js
@@ -65,6 +65,7 @@ const Copy = (function Copy() {
this.parent = container;
this.blendMode = t.blendMode || PIXI.BLEND_MODES.NORMAL;
this.loop = t.loopAnimation;
+ this.animationSpeed = t.animationFPS / 60;
if (t.playAnimationOnStart) {
this.play();
}
@@ -89,14 +90,11 @@ const Copy = (function Copy() {
this.timer1 = this.timer2 = this.timer3 = this.timer4 = this.timer5 = this.timer6 = 0;
if (exts) {
ct.u.ext(this, exts);
- if (exts.tx) {
- this.scale.x = exts.tx;
+ if (exts.scaleX) {
+ this.scale.x = exts.scaleX;
}
- if (exts.ty) {
- this.scale.y = exts.ty;
- }
- if (exts.tr) {
- this.angle = exts.tr;
+ if (exts.scaleY) {
+ this.scale.y = exts.scaleY;
}
}
this.uid = ++uid;
diff --git a/app/data/ct.release/tilemaps.js b/app/data/ct.release/tilemaps.js
index 9928663e0..9ffb427c7 100644
--- a/app/data/ct.release/tilemaps.js
+++ b/app/data/ct.release/tilemaps.js
@@ -19,15 +19,21 @@ class Tilemap extends PIXI.Container {
Object.assign(this, template.extends);
}
for (let i = 0, l = template.tiles.length; i < l; i++) {
- const textures = ct.res.getTexture(template.tiles[i].texture);
- const sprite = new PIXI.Sprite(textures[template.tiles[i].frame]);
- sprite.anchor.x = sprite.anchor.y = 0;
+ const tile = template.tiles[i];
+ const textures = ct.res.getTexture(tile.texture);
+ const sprite = new PIXI.Sprite(textures[tile.frame]);
+ sprite.anchor.x = textures[0].defaultAnchor.x;
+ sprite.anchor.y = textures[0].defaultAnchor.y;
sprite.shape = textures.shape;
+ sprite.scale.set(tile.scale.x, tile.scale.y);
+ sprite.rotation = tile.rotation;
+ sprite.alpha = tile.opacity;
+ sprite.tint = tile.tint;
+ sprite.x = tile.x;
+ sprite.y = tile.y;
this.addChild(sprite);
this.pixiTiles.push(sprite);
this.tiles[i].sprite = sprite;
- sprite.x = template.tiles[i].x;
- sprite.y = template.tiles[i].y;
}
} else {
this.tiles = [];
diff --git a/app/data/cursorErase.svg b/app/data/cursorErase.svg
new file mode 100644
index 000000000..c96e113da
--- /dev/null
+++ b/app/data/cursorErase.svg
@@ -0,0 +1,12 @@
+
diff --git a/app/data/cursorRotate.svg b/app/data/cursorRotate.svg
new file mode 100644
index 000000000..d2f8adb9d
--- /dev/null
+++ b/app/data/cursorRotate.svg
@@ -0,0 +1,4 @@
+
diff --git a/app/data/i18n/Brazilian Portuguese.json b/app/data/i18n/Brazilian Portuguese.json
index b22be4a88..e56fc4e58 100644
--- a/app/data/i18n/Brazilian Portuguese.json
+++ b/app/data/i18n/Brazilian Portuguese.json
@@ -67,7 +67,8 @@
"template": "",
"room": "",
"sound": "",
- "tandem": ""
+ "tandem": "",
+ "type": ""
},
"newName": "Novo nome:",
"saveProject": "Salvar projeto",
@@ -125,7 +126,9 @@
"",
""
]
- }
+ },
+ "next": "",
+ "previous": ""
},
"colorPicker": {
"current": "Novo",
@@ -587,7 +590,10 @@
"SpringStream": "Spring Stream",
"LucasDracula": "Lucas Dracula",
"Horizon": "",
- "HCBlack": ""
+ "HCBlack": "",
+ "RosePine": "",
+ "RosePineMoon": "",
+ "RosePineDawn": ""
},
"codeFontDefault": "Padrão (Iosevka Light)",
"codeFontOldSchool": "Old school",
@@ -602,7 +608,10 @@
"translateToYourLanguage": "Traduza o ct.js!",
"disableSounds": "Desabilitar sons de UI",
"changeDataFolder": "",
- "forceProductionForDebug": ""
+ "forceProductionForDebug": "",
+ "settings": "",
+ "prideMode": "",
+ "altTemplateLayout": ""
},
"project": {
"save": "Salvar projeto",
@@ -638,14 +647,36 @@
"sounds": "Sons",
"ui": "UI",
"fx": "FX",
- "templates": "Tipos"
- },
- "copyCustomProperties": {
- "customProperties": "",
- "addProperty": "",
- "property": "",
- "value": "",
- "delete": ""
+ "templates": "Tipos",
+ "tour": {
+ "header": "",
+ "aboutTour": "",
+ "helpPanel": "",
+ "helpPanelTabs": "",
+ "projectResources": "",
+ "tabTextures": "",
+ "tabTexturesImport": "",
+ "tabTexturesGallery": "",
+ "tabTexturesClipboard": "",
+ "tabTexturesPlaceholders": "",
+ "tabTemplates": "",
+ "tabRooms": "",
+ "tabSounds": "",
+ "tabSoundsImport": "",
+ "tabSoundsGallery": "",
+ "tabSoundsRecord": "",
+ "tabInterlude": "",
+ "tabUI": "",
+ "tabFX": "",
+ "tabProject": "",
+ "tabProjectModules": "",
+ "tabProjectModuleDocs": "",
+ "tabMainMenu": "",
+ "tabMainMenuSettings": "",
+ "tabMainMenuMeta": "",
+ "helpPanelReminder": "",
+ "buttonStartTutorial": ""
+ }
},
"assetViewer": {
"addNewGroup": "",
@@ -716,7 +747,13 @@
"copyProperties": {
"position": "",
"rotation": "",
- "scale": ""
+ "scale": "",
+ "multipleValues": ""
+ },
+ "copyCustomProperties": {
+ "addProperty": "",
+ "property": "",
+ "value": ""
},
"customProperties": "",
"restrictCamera": "",
@@ -736,7 +773,19 @@
"deleteTiles": "Remover tiles",
"moveTilesToLayer": "Mover para camada",
"shiftTiles": "Trocar tiles",
- "changeCopyRotation": "Rotacionar"
+ "changeCopyRotation": "Rotacionar",
+ "simulate": "",
+ "toggleDiagonalGrid": "",
+ "changeGridSize": "",
+ "xrayMode": "",
+ "colorizeTileLayers": "",
+ "tools": {
+ "select": "",
+ "addCopies": "",
+ "addTiles": "",
+ "manageBackgrounds": "",
+ "roomProperties": ""
+ }
},
"styleView": {
"active": "Ativo",
@@ -869,7 +918,9 @@
"add": "",
"multiply": "",
"screen": ""
- }
+ },
+ "animationFPS": "",
+ "loopAnimation": ""
},
"assetInput": {
"changeAsset": "",
@@ -889,5 +940,71 @@
"visitAuthorsItch": "",
"visitAuthorsTwitter": "",
"tipAuthor": ""
+ },
+ "scriptables": {
+ "addEvent": "",
+ "removeEvent": "",
+ "removeEventConfirm": "",
+ "changeArguments": "",
+ "eventAlreadyExists": "",
+ "localEventVars": "",
+ "createEventHint": "",
+ "coreEventsCategories": {
+ "lifecycle": "",
+ "actions": "",
+ "pointer": "",
+ "misc": "",
+ "animation": "",
+ "timers": ""
+ },
+ "coreEvents": {
+ "OnCreate": "",
+ "OnRoomStart": "",
+ "OnStep": "",
+ "OnDraw": "",
+ "OnDestroy": "",
+ "OnRoomEnd": "",
+ "OnPointerClick": "",
+ "OnPointerSecondaryClick": "",
+ "OnPointerEnter": "",
+ "OnPointerLeave": "",
+ "OnPointerDown": "",
+ "OnPointerUp": "",
+ "OnPointerUpOutside": "",
+ "OnPointerWheel": "",
+ "OnActionPress": "",
+ "OnActionRelease": "",
+ "OnActionDown": "",
+ "OnFrameChange": "",
+ "OnAnimationLoop": "",
+ "OnAnimationComplete": "",
+ "Timer": ""
+ },
+ "coreParameterizedNames": {
+ "OnActionPress": "",
+ "OnActionRelease": "",
+ "OnActionDown": ""
+ },
+ "coreEventsArguments": {
+ "action": ""
+ },
+ "coreEventsLocals": {
+ "OnActionDown_value": "",
+ "OnActionPress_value": ""
+ },
+ "coreEventsDescriptions": {
+ "OnCreate": "",
+ "OnRoomStart": "",
+ "OnStep": "",
+ "OnDraw": "",
+ "OnDestroy": "",
+ "OnRoomEnd": "",
+ "OnActionPress": "",
+ "OnActionRelease": "",
+ "OnActionDown": "",
+ "OnAnimationLoop": "",
+ "OnAnimationComplete": "",
+ "Timer": ""
+ }
}
}
\ No newline at end of file
diff --git a/app/data/i18n/Chinese Simplified.json b/app/data/i18n/Chinese Simplified.json
index e9f0b1729..f501867a3 100644
--- a/app/data/i18n/Chinese Simplified.json
+++ b/app/data/i18n/Chinese Simplified.json
@@ -67,7 +67,8 @@
"template": "模板",
"room": "房间",
"sound": "声音",
- "tandem": "粒子发射器"
+ "tandem": "粒子发射器",
+ "type": ""
},
"newName": "新名称",
"saveProject": "保存项目",
@@ -125,7 +126,9 @@
"骨骼精灵图形",
"骨骼精灵图形"
]
- }
+ },
+ "next": "",
+ "previous": ""
},
"colorPicker": {
"current": "新建",
@@ -542,7 +545,10 @@
"SpringStream": "Spring Stream",
"LucasDracula": "Lucas Dracula",
"Horizon": "Horizon",
- "HCBlack": "High-contrast Black"
+ "HCBlack": "High-contrast Black",
+ "RosePine": "",
+ "RosePineMoon": "",
+ "RosePineDawn": ""
},
"newFont": "新字体:",
"language": "语言",
@@ -552,7 +558,10 @@
"codeDense": "密集布局",
"disableSounds": "关闭 UI 音效",
"changeDataFolder": "设置数据文件夹位置",
- "forceProductionForDebug": "强制生产任务用于调试导出"
+ "forceProductionForDebug": "强制生产任务用于调试导出",
+ "settings": "",
+ "prideMode": "",
+ "altTemplateLayout": ""
},
"project": {
"heading": "项目",
@@ -588,7 +597,36 @@
"restart": "重新启动",
"launch": "编译并运行",
"launchHotkeys": "(F5; Alt+F5 在默认浏览器中运行)",
- "templates": "类型"
+ "templates": "类型",
+ "tour": {
+ "header": "",
+ "aboutTour": "",
+ "helpPanel": "",
+ "helpPanelTabs": "",
+ "projectResources": "",
+ "tabTextures": "",
+ "tabTexturesImport": "",
+ "tabTexturesGallery": "",
+ "tabTexturesClipboard": "",
+ "tabTexturesPlaceholders": "",
+ "tabTemplates": "",
+ "tabRooms": "",
+ "tabSounds": "",
+ "tabSoundsImport": "",
+ "tabSoundsGallery": "",
+ "tabSoundsRecord": "",
+ "tabInterlude": "",
+ "tabUI": "",
+ "tabFX": "",
+ "tabProject": "",
+ "tabProjectModules": "",
+ "tabProjectModuleDocs": "",
+ "tabMainMenu": "",
+ "tabMainMenuSettings": "",
+ "tabMainMenuMeta": "",
+ "helpPanelReminder": "",
+ "buttonStartTutorial": ""
+ }
},
"docsPanel": {
"documentation": "文档",
@@ -640,13 +678,6 @@
"folderNotWritable": "您没有权限写入这个文件夹. 选择其他试试",
"complete": "文件夹已设置, 一切正常✅"
},
- "copyCustomProperties": {
- "customProperties": "自定义属性",
- "addProperty": "添加属性",
- "property": "属性",
- "value": "值",
- "delete": "删除"
- },
"assetViewer": {
"addNewGroup": "新分组",
"ungrouped": "显示未分组",
@@ -716,7 +747,13 @@
"copyProperties": {
"position": "位置",
"rotation": "旋转",
- "scale": "缩放"
+ "scale": "缩放",
+ "multipleValues": ""
+ },
+ "copyCustomProperties": {
+ "addProperty": "添加属性",
+ "property": "属性",
+ "value": "值"
},
"customProperties": "自定义属性",
"restrictCamera": "保持相机在一个矩形中",
@@ -736,7 +773,19 @@
"deleteTiles": "删除图块",
"moveTilesToLayer": "移至图层",
"shiftTiles": "移动瓷砖",
- "changeCopyRotation": "旋转"
+ "changeCopyRotation": "旋转",
+ "simulate": "",
+ "toggleDiagonalGrid": "",
+ "changeGridSize": "",
+ "xrayMode": "",
+ "colorizeTileLayers": "",
+ "tools": {
+ "select": "",
+ "addCopies": "",
+ "addTiles": "",
+ "manageBackgrounds": "",
+ "roomProperties": ""
+ }
},
"styleView": {
"active": "激活",
@@ -869,7 +918,9 @@
"add": "掺入 (溶解)",
"multiply": "倍增 (变暗)",
"screen": "遮蔽 (变亮)"
- }
+ },
+ "animationFPS": "",
+ "loopAnimation": ""
},
"assetInput": {
"changeAsset": "切换资产",
@@ -889,5 +940,71 @@
"visitAuthorsItch": "访问作者的 itch.io 页面",
"visitAuthorsTwitter": "访问作者的 Twitter 页面",
"tipAuthor": "奖励作者的辛勤工作 :D"
+ },
+ "scriptables": {
+ "addEvent": "",
+ "removeEvent": "",
+ "removeEventConfirm": "",
+ "changeArguments": "",
+ "eventAlreadyExists": "",
+ "localEventVars": "",
+ "createEventHint": "",
+ "coreEventsCategories": {
+ "lifecycle": "",
+ "actions": "",
+ "pointer": "",
+ "misc": "",
+ "animation": "",
+ "timers": ""
+ },
+ "coreEvents": {
+ "OnCreate": "",
+ "OnRoomStart": "",
+ "OnStep": "",
+ "OnDraw": "",
+ "OnDestroy": "",
+ "OnRoomEnd": "",
+ "OnPointerClick": "",
+ "OnPointerSecondaryClick": "",
+ "OnPointerEnter": "",
+ "OnPointerLeave": "",
+ "OnPointerDown": "",
+ "OnPointerUp": "",
+ "OnPointerUpOutside": "",
+ "OnPointerWheel": "",
+ "OnActionPress": "",
+ "OnActionRelease": "",
+ "OnActionDown": "",
+ "OnFrameChange": "",
+ "OnAnimationLoop": "",
+ "OnAnimationComplete": "",
+ "Timer": ""
+ },
+ "coreParameterizedNames": {
+ "OnActionPress": "",
+ "OnActionRelease": "",
+ "OnActionDown": ""
+ },
+ "coreEventsArguments": {
+ "action": ""
+ },
+ "coreEventsLocals": {
+ "OnActionDown_value": "",
+ "OnActionPress_value": ""
+ },
+ "coreEventsDescriptions": {
+ "OnCreate": "",
+ "OnRoomStart": "",
+ "OnStep": "",
+ "OnDraw": "",
+ "OnDestroy": "",
+ "OnRoomEnd": "",
+ "OnActionPress": "",
+ "OnActionRelease": "",
+ "OnActionDown": "",
+ "OnAnimationLoop": "",
+ "OnAnimationComplete": "",
+ "Timer": ""
+ }
}
-}
+}
\ No newline at end of file
diff --git a/app/data/i18n/Comments.json b/app/data/i18n/Comments.json
index b3308135e..a610995ab 100644
--- a/app/data/i18n/Comments.json
+++ b/app/data/i18n/Comments.json
@@ -67,7 +67,8 @@
"template": "",
"room": "",
"sound": "",
- "tandem": ""
+ "tandem": "",
+ "type": ""
},
"newName": "",
"saveProject": "",
@@ -125,7 +126,9 @@
"",
""
]
- }
+ },
+ "next": "",
+ "previous": ""
},
"colorPicker": {
"current": "",
@@ -587,7 +590,10 @@
"SpringStream": "",
"LucasDracula": "",
"Horizon": "",
- "HCBlack": ""
+ "HCBlack": "",
+ "RosePine": "",
+ "RosePineMoon": "",
+ "RosePineDawn": ""
},
"codeFontDefault": "",
"codeFontOldSchool": "",
@@ -602,7 +608,10 @@
"forceProductionForDebug": "",
"heading": "",
"language": "",
- "translateToYourLanguage": ""
+ "translateToYourLanguage": "",
+ "settings": "",
+ "prideMode": "",
+ "altTemplateLayout": ""
},
"project": {
"save": "",
@@ -638,14 +647,36 @@
"fx": "",
"restart": "",
"project": "",
- "templates": ""
- },
- "copyCustomProperties": {
- "customProperties": "",
- "addProperty": "",
- "property": "",
- "value": "",
- "delete": ""
+ "templates": "",
+ "tour": {
+ "header": "",
+ "aboutTour": "",
+ "helpPanel": "",
+ "helpPanelTabs": "",
+ "projectResources": "",
+ "tabTextures": "",
+ "tabTexturesImport": "",
+ "tabTexturesGallery": "",
+ "tabTexturesClipboard": "",
+ "tabTexturesPlaceholders": "",
+ "tabTemplates": "",
+ "tabRooms": "",
+ "tabSounds": "",
+ "tabSoundsImport": "",
+ "tabSoundsGallery": "",
+ "tabSoundsRecord": "",
+ "tabInterlude": "",
+ "tabUI": "",
+ "tabFX": "",
+ "tabProject": "",
+ "tabProjectModules": "",
+ "tabProjectModuleDocs": "",
+ "tabMainMenu": "",
+ "tabMainMenuSettings": "",
+ "tabMainMenuMeta": "",
+ "helpPanelReminder": "",
+ "buttonStartTutorial": ""
+ }
},
"assetViewer": {
"addNewGroup": "",
@@ -716,7 +747,13 @@
"copyProperties": {
"position": "",
"rotation": "",
- "scale": ""
+ "scale": "",
+ "multipleValues": ""
+ },
+ "copyCustomProperties": {
+ "addProperty": "",
+ "property": "",
+ "value": ""
},
"customProperties": "",
"restrictCamera": "",
@@ -736,7 +773,19 @@
"deleteTiles": "",
"moveTilesToLayer": "",
"shiftTiles": "",
- "changeCopyRotation": ""
+ "changeCopyRotation": "",
+ "simulate": "",
+ "toggleDiagonalGrid": "",
+ "changeGridSize": "",
+ "xrayMode": "",
+ "colorizeTileLayers": "",
+ "tools": {
+ "select": "",
+ "addCopies": "",
+ "addTiles": "",
+ "manageBackgrounds": "",
+ "roomProperties": ""
+ }
},
"styleView": {
"active": "",
@@ -869,7 +918,9 @@
"add": "",
"multiply": "",
"screen": ""
- }
+ },
+ "animationFPS": "",
+ "loopAnimation": ""
},
"assetInput": {
"changeAsset": "",
@@ -889,5 +940,71 @@
"visitAuthorsItch": "",
"visitAuthorsTwitter": "",
"tipAuthor": ""
+ },
+ "scriptables": {
+ "addEvent": "",
+ "removeEvent": "",
+ "removeEventConfirm": "",
+ "changeArguments": "",
+ "eventAlreadyExists": "",
+ "localEventVars": "",
+ "createEventHint": "",
+ "coreEventsCategories": {
+ "lifecycle": "",
+ "actions": "",
+ "pointer": "",
+ "misc": "",
+ "animation": "",
+ "timers": ""
+ },
+ "coreEvents": {
+ "OnCreate": "",
+ "OnRoomStart": "",
+ "OnStep": "",
+ "OnDraw": "",
+ "OnDestroy": "",
+ "OnRoomEnd": "",
+ "OnPointerClick": "",
+ "OnPointerSecondaryClick": "",
+ "OnPointerEnter": "",
+ "OnPointerLeave": "",
+ "OnPointerDown": "",
+ "OnPointerUp": "",
+ "OnPointerUpOutside": "",
+ "OnPointerWheel": "",
+ "OnActionPress": "",
+ "OnActionRelease": "",
+ "OnActionDown": "",
+ "OnFrameChange": "",
+ "OnAnimationLoop": "",
+ "OnAnimationComplete": "",
+ "Timer": ""
+ },
+ "coreParameterizedNames": {
+ "OnActionPress": "",
+ "OnActionRelease": "",
+ "OnActionDown": ""
+ },
+ "coreEventsArguments": {
+ "action": ""
+ },
+ "coreEventsLocals": {
+ "OnActionDown_value": "",
+ "OnActionPress_value": ""
+ },
+ "coreEventsDescriptions": {
+ "OnCreate": "",
+ "OnRoomStart": "",
+ "OnStep": "",
+ "OnDraw": "",
+ "OnDestroy": "",
+ "OnRoomEnd": "",
+ "OnActionPress": "",
+ "OnActionRelease": "",
+ "OnActionDown": "",
+ "OnAnimationLoop": "",
+ "OnAnimationComplete": "",
+ "Timer": ""
+ }
}
}
\ No newline at end of file
diff --git a/app/data/i18n/Debug.json b/app/data/i18n/Debug.json
index 1ad1f5a2f..5f0ea7c12 100644
--- a/app/data/i18n/Debug.json
+++ b/app/data/i18n/Debug.json
@@ -64,7 +64,11 @@
"text": "common.fieldTypes.text",
"textfield": "common.fieldTypes.textfield",
"texture": "common.fieldTypes.texture",
- "type": "common.fieldTypes.type"
+ "type": "common.fieldTypes.type",
+ "template": "",
+ "room": "",
+ "sound": "",
+ "tandem": ""
},
"newName": "common.newName",
"saveProject": "common.saveProject",
@@ -77,7 +81,54 @@
"addToNotes": "common.addToNotes",
"noRooms": "common.noRooms",
"tileLayer": "common.tileLayer",
- "ctSite": "common.ctSite"
+ "ctSite": "common.ctSite",
+ "docsShort": "",
+ "docsLong": "",
+ "openAssetGallery": "",
+ "assetTypes": {
+ "textures": [
+ "",
+ "",
+ ""
+ ],
+ "templates": [
+ "",
+ "",
+ ""
+ ],
+ "emitterTandems": [
+ "",
+ "",
+ ""
+ ],
+ "rooms": [
+ "",
+ "",
+ ""
+ ],
+ "fonts": [
+ "",
+ "",
+ ""
+ ],
+ "styles": [
+ "",
+ "",
+ ""
+ ],
+ "sounds": [
+ "",
+ "",
+ ""
+ ],
+ "skeletons": [
+ "",
+ "",
+ ""
+ ]
+ },
+ "next": "",
+ "previous": ""
},
"colorPicker": {
"current": "colorPicker.current",
@@ -97,7 +148,15 @@
"log": "exportPanel.log",
"windowsCrossBuildWarning": "exportPanel.windowsCrossBuildWarning",
"cannotBuildForMacOnWin": "exportPanel.cannotBuildForMacOnWin",
- "firstRunNotice": "exportPanel.firstRunNotice"
+ "firstRunNotice": "exportPanel.firstRunNotice",
+ "projectTitleRequired": "",
+ "appIdRequired": "",
+ "noAndroidSdkFound": "",
+ "envVarNotice": "",
+ "downloadAndroidStudio": "",
+ "requiresInternetNotice": "",
+ "noJdkFound": "",
+ "downloadJDK": ""
},
"intro": {
"loading": "intro.loading",
@@ -132,7 +191,9 @@
"github": "intro.github",
"itch": "intro.itch",
"vkontakte": "intro.vkontakte",
- "patreon": "intro.patreon"
+ "patreon": "intro.patreon",
+ "templates": "",
+ "templatesInfo": ""
},
"modules": {
"author": "modules.author",
@@ -174,7 +235,8 @@
"skeletons": "texture.skeletons",
"createTemplate": "texture.createTemplate",
"importFromClipboard": "texture.importFromClipboard",
- "generatePlaceholder": "texture.generatePlaceholder"
+ "generatePlaceholder": "texture.generatePlaceholder",
+ "textures": ""
},
"sounds": {
"create": "sounds.create",
@@ -365,7 +427,9 @@
"site": "settings.authoring.site",
"title": "settings.authoring.title",
"version": "settings.authoring.version",
- "versionPostfix": "settings.authoring.versionPostfix"
+ "versionPostfix": "settings.authoring.versionPostfix",
+ "appId": "",
+ "appIdExplanation": ""
},
"branding": {
"heading": "settings.branding.heading",
@@ -374,7 +438,11 @@
"icon": "settings.branding.icon",
"iconNotice": "settings.branding.iconNotice",
"invertPreloaderScheme": "settings.branding.invertPreloaderScheme",
- "hideLoadingLogo": "settings.branding.hideLoadingLogo"
+ "hideLoadingLogo": "settings.branding.hideLoadingLogo",
+ "splashScreen": "",
+ "splashScreenNotice": "",
+ "forceSmoothIcons": "",
+ "forceSmoothSplashScreen": ""
},
"modules": {
"heading": "settings.modules.heading"
@@ -392,7 +460,15 @@
"windowed": "settings.rendering.launchModes.windowed"
},
"hideCursor": "settings.rendering.hideCursor",
- "pixelatedRender": "settings.rendering.pixelatedRender"
+ "pixelatedRender": "settings.rendering.pixelatedRender",
+ "usePixiLegacy": "",
+ "mobileBuilds": "",
+ "screenOrientation": "",
+ "screenOrientations": {
+ "unspecified": "",
+ "landscape": "",
+ "portrait": ""
+ }
},
"scripts": {
"heading": "settings.scripts.heading",
@@ -434,13 +510,19 @@
"deleteContentType": "settings.content.deleteContentType",
"confirmDeletionMessage": "settings.content.confirmDeletionMessage",
"gotoEntries": "settings.content.gotoEntries",
- "entries": "settings.content.entries"
+ "entries": "settings.content.entries",
+ "array": ""
},
"contentTypes": "settings.contentTypes"
},
"extensionsEditor": {
"noEntries": "extensionsEditor.noEntries",
- "addRow": "extensionsEditor.addRow"
+ "addRow": "extensionsEditor.addRow",
+ "actions": "",
+ "values": "",
+ "moveDown": "",
+ "moveUp": "",
+ "deleteRow": ""
},
"textureGenerator": {
"name": "textureGenerator.name",
@@ -494,7 +576,8 @@
"exportDesktop": "mainMenu.deploy.exportDesktop",
"successZipExport": "mainMenu.deploy.successZipExport",
"zipExport": "mainMenu.deploy.zipExport",
- "heading": "mainMenu.deploy.heading"
+ "heading": "mainMenu.deploy.heading",
+ "exportAndroid": ""
},
"latestProjects": {
"recentProjects": "mainMenu.latestProjects.recentProjects"
@@ -507,7 +590,10 @@
"SpringStream": "mainMenu.settings.themes.SpringStream",
"LucasDracula": "mainMenu.settings.themes.LucasDracula",
"Horizon": "mainMenu.settings.themes.Horizon",
- "HCBlack": "mainMenu.settings.themes.HCBlack"
+ "HCBlack": "mainMenu.settings.themes.HCBlack",
+ "RosePine": "",
+ "RosePineMoon": "",
+ "RosePineDawn": ""
},
"codeFontDefault": "mainMenu.settings.codeFontDefault",
"codeFontOldSchool": "mainMenu.settings.codeFontOldSchool",
@@ -523,7 +609,9 @@
"forceProductionForDebug": "mainMenu.settings.forceProductionForDebug",
"heading": "mainMenu.settings.heading",
"language": "mainMenu.settings.language",
- "translateToYourLanguage": "mainMenu.settings.translateToYourLanguage"
+ "translateToYourLanguage": "mainMenu.settings.translateToYourLanguage",
+ "prideMode": "",
+ "altTemplateLayout": ""
},
"project": {
"save": "mainMenu.project.save",
@@ -542,7 +630,8 @@
"heading": "mainMenu.meta.heading",
"twitter": "mainMenu.meta.twitter",
"vkontakte": "mainMenu.meta.vkontakte",
- "ctjsForum": "mainMenu.meta.ctjsForum"
+ "ctjsForum": "mainMenu.meta.ctjsForum",
+ "openStylebook": ""
}
},
"appView": {
@@ -558,14 +647,36 @@
"fx": "appView.fx",
"restart": "appView.restart",
"project": "appView.project",
- "templates": "appView.templates"
- },
- "copyCustomProperties": {
- "customProperties": "copyCustomProperties.customProperties",
- "addProperty": "copyCustomProperties.addProperty",
- "property": "copyCustomProperties.property",
- "value": "copyCustomProperties.value",
- "delete": "copyCustomProperties.delete"
+ "templates": "appView.templates",
+ "tour": {
+ "header": "",
+ "aboutTour": "",
+ "helpPanel": "",
+ "helpPanelTabs": "",
+ "projectResources": "",
+ "tabTextures": "",
+ "tabTexturesImport": "",
+ "tabTexturesGallery": "",
+ "tabTexturesClipboard": "",
+ "tabTexturesPlaceholders": "",
+ "tabTemplates": "",
+ "tabRooms": "",
+ "tabSounds": "",
+ "tabSoundsImport": "",
+ "tabSoundsGallery": "",
+ "tabSoundsRecord": "",
+ "tabInterlude": "",
+ "tabUI": "",
+ "tabFX": "",
+ "tabProject": "",
+ "tabProjectModules": "",
+ "tabProjectModuleDocs": "",
+ "tabMainMenu": "",
+ "tabMainMenuSettings": "",
+ "tabMainMenuMeta": "",
+ "helpPanelReminder": "",
+ "buttonStartTutorial": ""
+ }
},
"assetViewer": {
"addNewGroup": "assetViewer.addNewGroup",
@@ -636,7 +747,13 @@
"copyProperties": {
"position": "roomView.copyProperties.position",
"rotation": "roomView.copyProperties.rotation",
- "scale": "roomView.copyProperties.scale"
+ "scale": "roomView.copyProperties.scale",
+ "multipleValues": ""
+ },
+ "copyCustomProperties": {
+ "addProperty": "copyCustomProperties.addProperty",
+ "property": "copyCustomProperties.property",
+ "value": "copyCustomProperties.value"
},
"customProperties": "roomView.customProperties",
"restrictCamera": "roomView.restrictCamera",
@@ -656,7 +773,19 @@
"deleteTiles": "roomView.deleteTiles",
"moveTilesToLayer": "roomView.moveTilesToLayer",
"shiftTiles": "roomView.shiftTiles",
- "changeCopyRotation": "roomView.changeCopyRotation"
+ "changeCopyRotation": "roomView.changeCopyRotation",
+ "simulate": "",
+ "toggleDiagonalGrid": "",
+ "changeGridSize": "",
+ "xrayMode": "",
+ "colorizeTileLayers": "",
+ "tools": {
+ "select": "",
+ "addCopies": "",
+ "addTiles": "",
+ "manageBackgrounds": "",
+ "roomProperties": ""
+ }
},
"styleView": {
"active": "styleView.active",
@@ -779,6 +908,103 @@
"learnAboutTypes": "templateView.learnAboutTypes",
"name": "templateView.name",
"step": "templateView.step",
- "visible": "templateView.visible"
+ "visible": "templateView.visible",
+ "appearance": "",
+ "opacity": "",
+ "blendMode": "",
+ "playAnimationOnStart": "",
+ "blendModes": {
+ "normal": "",
+ "add": "",
+ "multiply": "",
+ "screen": ""
+ },
+ "animationFPS": "",
+ "loopAnimation": ""
+ },
+ "assetInput": {
+ "changeAsset": "",
+ "jumpToAsset": "",
+ "selectAssetHeader": ""
+ },
+ "builtinAssetGallery": {
+ "galleryTip": "",
+ "assetGalleryHeader": "",
+ "importIntoProject": "",
+ "importAll": "",
+ "byAuthorPrefix": "",
+ "cannotImportExplanation": "",
+ "nameOccupied": "",
+ "cannotImportNameOccupied": "",
+ "visitSource": "",
+ "visitAuthorsItch": "",
+ "visitAuthorsTwitter": "",
+ "tipAuthor": ""
+ },
+ "scriptables": {
+ "addEvent": "",
+ "removeEvent": "",
+ "removeEventConfirm": "",
+ "changeArguments": "",
+ "eventAlreadyExists": "",
+ "localEventVars": "",
+ "createEventHint": "",
+ "coreEventsCategories": {
+ "lifecycle": "",
+ "actions": "",
+ "pointer": "",
+ "misc": "",
+ "animation": "",
+ "timers": ""
+ },
+ "coreEvents": {
+ "OnCreate": "",
+ "OnRoomStart": "",
+ "OnStep": "",
+ "OnDraw": "",
+ "OnDestroy": "",
+ "OnRoomEnd": "",
+ "OnPointerClick": "",
+ "OnPointerSecondaryClick": "",
+ "OnPointerEnter": "",
+ "OnPointerLeave": "",
+ "OnPointerDown": "",
+ "OnPointerUp": "",
+ "OnPointerUpOutside": "",
+ "OnPointerWheel": "",
+ "OnActionPress": "",
+ "OnActionRelease": "",
+ "OnActionDown": "",
+ "OnFrameChange": "",
+ "OnAnimationLoop": "",
+ "OnAnimationComplete": "",
+ "Timer": ""
+ },
+ "coreParameterizedNames": {
+ "OnActionPress": "",
+ "OnActionRelease": "",
+ "OnActionDown": ""
+ },
+ "coreEventsArguments": {
+ "action": ""
+ },
+ "coreEventsLocals": {
+ "OnActionDown_value": "",
+ "OnActionPress_value": ""
+ },
+ "coreEventsDescriptions": {
+ "OnCreate": "",
+ "OnRoomStart": "",
+ "OnStep": "",
+ "OnDraw": "",
+ "OnDestroy": "",
+ "OnRoomEnd": "",
+ "OnActionPress": "",
+ "OnActionRelease": "",
+ "OnActionDown": "",
+ "OnAnimationLoop": "",
+ "OnAnimationComplete": "",
+ "Timer": ""
+ }
}
-}
+}
\ No newline at end of file
diff --git a/app/data/i18n/Dutch.json b/app/data/i18n/Dutch.json
index 38bc739b2..27f6095c6 100644
--- a/app/data/i18n/Dutch.json
+++ b/app/data/i18n/Dutch.json
@@ -67,7 +67,8 @@
"template": "Sjabloon",
"room": "Kamer",
"sound": "Geluid",
- "tandem": "Deeltjesverspreider"
+ "tandem": "Deeltjesverspreider",
+ "type": ""
},
"newName": "Nieuwe naam:",
"saveProject": "Project opslaan",
@@ -80,7 +81,7 @@
"addToNotes": "Notitie toevoegen",
"noRooms": "Je hebt ten minste één kamer nodig om de app te compileren.",
"tileLayer": "tegellaag",
- "ctSite": "ct.js thuispagina",
+ "ctSite": "ct.js thuispagina",
"docsShort": "Docs",
"docsLong": "Documentatie",
"openAssetGallery": "Galerij",
@@ -125,7 +126,9 @@
"skeletten",
"skeletten"
]
- }
+ },
+ "next": "",
+ "previous": ""
},
"colorPicker": {
"current": "New",
@@ -589,7 +592,10 @@
"SpringStream": "Lente Stroom",
"LucasDracula": "Lucas Dracula",
"Horizon": "Horizon",
- "HCBlack": "Hoog-contrast Zwart"
+ "HCBlack": "Hoog-contrast Zwart",
+ "RosePine": "",
+ "RosePineMoon": "",
+ "RosePineDawn": ""
},
"codeFontDefault": "Standaard (Iosevka Licht)",
"codeFontOldSchool": "Ouderwets",
@@ -602,7 +608,10 @@
"heading": "Instellingen",
"disableSounds": "Schakel UI geluiden uit",
"changeDataFolder": "Stel maplocatie voor data in",
- "forceProductionForDebug": "Forceer productietaken voor debug exports"
+ "forceProductionForDebug": "Forceer productietaken voor debug exports",
+ "settings": "",
+ "prideMode": "",
+ "altTemplateLayout": ""
},
"project": {
"save": "Sla project op",
@@ -638,14 +647,36 @@
"fx": "FX",
"restart": "Herstart",
"project": "Project",
- "templates": "Sjablonen"
- },
- "copyCustomProperties": {
- "customProperties": "Aangepaste eigenschappen",
- "addProperty": "Voeg eigenschap toe",
- "property": "Eigenschap",
- "value": "Waarde",
- "delete": "Verwijder"
+ "templates": "Sjablonen",
+ "tour": {
+ "header": "",
+ "aboutTour": "",
+ "helpPanel": "",
+ "helpPanelTabs": "",
+ "projectResources": "",
+ "tabTextures": "",
+ "tabTexturesImport": "",
+ "tabTexturesGallery": "",
+ "tabTexturesClipboard": "",
+ "tabTexturesPlaceholders": "",
+ "tabTemplates": "",
+ "tabRooms": "",
+ "tabSounds": "",
+ "tabSoundsImport": "",
+ "tabSoundsGallery": "",
+ "tabSoundsRecord": "",
+ "tabInterlude": "",
+ "tabUI": "",
+ "tabFX": "",
+ "tabProject": "",
+ "tabProjectModules": "",
+ "tabProjectModuleDocs": "",
+ "tabMainMenu": "",
+ "tabMainMenuSettings": "",
+ "tabMainMenuMeta": "",
+ "helpPanelReminder": "",
+ "buttonStartTutorial": ""
+ }
},
"assetViewer": {
"addNewGroup": "Nieuwe groep",
@@ -716,7 +747,13 @@
"copyProperties": {
"position": "Positie",
"rotation": "Rotatie",
- "scale": "Schaal"
+ "scale": "Schaal",
+ "multipleValues": ""
+ },
+ "copyCustomProperties": {
+ "addProperty": "Voeg eigenschap toe",
+ "property": "Eigenschap",
+ "value": "Waarde"
},
"customProperties": "Aangepaste eigenschappen",
"restrictCamera": "Houd camera in een rechthoek",
@@ -736,7 +773,19 @@
"deleteTiles": "Verwijder tegels",
"moveTilesToLayer": "Beweeg naar laag",
"shiftTiles": "Verschuif tegels",
- "changeCopyRotation": "Draai"
+ "changeCopyRotation": "Draai",
+ "simulate": "",
+ "toggleDiagonalGrid": "",
+ "changeGridSize": "",
+ "xrayMode": "",
+ "colorizeTileLayers": "",
+ "tools": {
+ "select": "",
+ "addCopies": "",
+ "addTiles": "",
+ "manageBackgrounds": "",
+ "roomProperties": ""
+ }
},
"styleView": {
"active": "Activeer",
@@ -869,7 +918,9 @@
"add": "Voeg toe (brand)",
"multiply": "Vermenigvuldig (donkerder maken)",
"screen": "Scherm (lichter maken)"
- }
+ },
+ "animationFPS": "",
+ "loopAnimation": ""
},
"assetInput": {
"changeAsset": "Druk om het onderdeel te veranderen",
@@ -889,5 +940,71 @@
"visitAuthorsItch": "De auteurs itch.io pagina bezoeken",
"visitAuthorsTwitter": "De Twitterpagina van de auteur bezoeken",
"tipAuthor": "De auteur een fooi geven voor hun harde werk :D"
+ },
+ "scriptables": {
+ "addEvent": "",
+ "removeEvent": "",
+ "removeEventConfirm": "",
+ "changeArguments": "",
+ "eventAlreadyExists": "",
+ "localEventVars": "",
+ "createEventHint": "",
+ "coreEventsCategories": {
+ "lifecycle": "",
+ "actions": "",
+ "pointer": "",
+ "misc": "",
+ "animation": "",
+ "timers": ""
+ },
+ "coreEvents": {
+ "OnCreate": "",
+ "OnRoomStart": "",
+ "OnStep": "",
+ "OnDraw": "",
+ "OnDestroy": "",
+ "OnRoomEnd": "",
+ "OnPointerClick": "",
+ "OnPointerSecondaryClick": "",
+ "OnPointerEnter": "",
+ "OnPointerLeave": "",
+ "OnPointerDown": "",
+ "OnPointerUp": "",
+ "OnPointerUpOutside": "",
+ "OnPointerWheel": "",
+ "OnActionPress": "",
+ "OnActionRelease": "",
+ "OnActionDown": "",
+ "OnFrameChange": "",
+ "OnAnimationLoop": "",
+ "OnAnimationComplete": "",
+ "Timer": ""
+ },
+ "coreParameterizedNames": {
+ "OnActionPress": "",
+ "OnActionRelease": "",
+ "OnActionDown": ""
+ },
+ "coreEventsArguments": {
+ "action": ""
+ },
+ "coreEventsLocals": {
+ "OnActionDown_value": "",
+ "OnActionPress_value": ""
+ },
+ "coreEventsDescriptions": {
+ "OnCreate": "",
+ "OnRoomStart": "",
+ "OnStep": "",
+ "OnDraw": "",
+ "OnDestroy": "",
+ "OnRoomEnd": "",
+ "OnActionPress": "",
+ "OnActionRelease": "",
+ "OnActionDown": "",
+ "OnAnimationLoop": "",
+ "OnAnimationComplete": "",
+ "Timer": ""
+ }
}
-}
+}
\ No newline at end of file
diff --git a/app/data/i18n/English.json b/app/data/i18n/English.json
index e662c6a48..b3c43288e 100644
--- a/app/data/i18n/English.json
+++ b/app/data/i18n/English.json
@@ -50,6 +50,8 @@
"zoom": "Zoom",
"zoomIn": "Zoom in",
"zoomOut": "Zoom out",
+ "undo": "Undo",
+ "redo": "Redo",
"fieldTypes": {
"checkbox": "Checkbox",
"code": "Codebox",
@@ -71,7 +73,8 @@
"template": "Template",
"room": "Room",
"sound": "Sound",
- "tandem": "Particle emitter"
+ "tandem": "Particle emitter",
+ "type": ""
},
"newName": "New name:",
"saveProject": "Save project",
@@ -160,13 +163,6 @@
"old": "Old",
"projectPalette": "Project's Palette"
},
- "copyCustomProperties": {
- "customProperties": "Custom Properties",
- "addProperty": "Add Property",
- "property": "Property",
- "value": "Value",
- "delete": "Delete"
- },
"curveEditor": {
"curveLineHint": "Click the curve to add a point",
"dragPointHint": "Drag to move the point, right-click to delete it",
@@ -655,7 +651,8 @@
"altTemplateLayout": "Alternative layout for template editor",
"disableSounds": "Disable UI sounds",
"changeDataFolder": "Set data folder location",
- "forceProductionForDebug": "Force production tasks for debug exports"
+ "forceProductionForDebug": "Force production tasks for debug exports",
+ "settings": ""
},
"project": {
"heading": "Project",
@@ -725,11 +722,11 @@
"roomBackgrounds": {
"add": "Add a Background",
"depth": "Depth:",
- "movement": "Movement speed (X, Y):",
- "parallax": "Parallax (X, Y):",
+ "movement": "Movement speed:",
+ "parallax": "Parallax:",
"repeat": "Repeat:",
- "scale": "Scaling (X, Y):",
- "shift": "Shift (X, Y):",
+ "scale": "Scaling:",
+ "shift": "Shift:",
"notBackgroundTextureWarning": "This texture is not marked as a background. It will have gaps when exported.",
"fixBackground": "Fix it.",
"dismissWarning": "Dismiss."
@@ -745,7 +742,14 @@
"width": "View width:",
"height": "View height:",
"isUi": "Is a UI layer?",
- "events": "Room events",
+ "simulate": "Simulate",
+ "grid": "Grid",
+ "toggleDiagonalGrid": "Diagonal grid",
+ "changeGridSize": "Change cell size",
+ "events": "Events",
+ "gridOff": "Disable grid",
+ "xrayMode": "X-ray mode",
+ "colorizeTileLayers": "Colorize tile layers",
"copies": "Copies",
"backgrounds": "Backgrounds",
"backgroundColor": "Background color:",
@@ -754,7 +758,6 @@
"add": "Add",
"none": "Nothing",
"done": "Done",
- "grid": "Set grid",
"hotkeysNotice": "Ctrl = Delete, Alt = No grid, Shift = Multiple",
"hotkeysNoticeMovement": "Ctrl = Delete, Shift = Select",
"shift": "Shift everything",
@@ -769,17 +772,26 @@
"selectAndMove": "Select and Move",
"customProperties": "Custom Properties",
"findTileset": "Find a tileset",
+ "resetView": "Reset view",
"copyProperties": {
"position": "Position",
"rotation": "Rotation",
- "scale": "Scale"
+ "scale": "Scale",
+ "opacity": "Opacity",
+ "tint": "Tint",
+ "multipleValues": "(Multiple)"
+ },
+ "copyCustomProperties": {
+ "addProperty": "Add Property",
+ "property": "Property",
+ "value": "Value",
+ "nameOccupied": "This property is used by ct.js! You should come up with a different name."
},
"restrictCamera": "Keep camera in a rectangle",
"minimumX": "Min X",
"minimumY": "Min Y",
"maximumX": "Max X",
"maximumY": "Max Y",
- "gridOff": "Disable grid",
"gridSize": "Grid size:",
"toCenter": "To center",
"shiftLabel": "Shift by:",
@@ -791,7 +803,14 @@
"deleteTiles": "Delete tiles",
"moveTilesToLayer": "Move to layer",
"shiftTiles": "Shift tiles",
- "changeCopyRotation": "Rotate"
+ "changeCopyRotation": "Rotate",
+ "tools": {
+ "select": "Select tool",
+ "addCopies": "Add copies",
+ "addTiles": "Add tiles",
+ "manageBackgrounds": "Manage backgrounds",
+ "roomProperties": "Room properties"
+ }
},
"styleView": {
"active": "Active",
@@ -984,6 +1003,7 @@
"depth": "Depth:",
"opacity": "Opacity:",
"blendMode": "Blend mode:",
+ "animationFPS": "Animation FPS:",
"playAnimationOnStart": "Play animation on start",
"loopAnimation": "Loop animation",
"blendModes": {
diff --git a/app/data/i18n/French.json b/app/data/i18n/French.json
index 095ed0bb4..108ea31b9 100644
--- a/app/data/i18n/French.json
+++ b/app/data/i18n/French.json
@@ -93,7 +93,8 @@
"template": "",
"room": "",
"sound": "",
- "tandem": ""
+ "tandem": "",
+ "type": ""
},
"newName": "Nouveau nom:",
"saveProject": "Sauvegarder le projet",
@@ -151,7 +152,9 @@
"",
""
]
- }
+ },
+ "next": "",
+ "previous": ""
},
"exportPanel": {
"hide": "Cacher",
@@ -589,7 +592,10 @@
"SpringStream": "",
"LucasDracula": "",
"Horizon": "",
- "HCBlack": ""
+ "HCBlack": "",
+ "RosePine": "",
+ "RosePineMoon": "",
+ "RosePineDawn": ""
},
"codeFontDefault": "Font par défault (Iosevka Light)",
"codeFontOldSchool": "Old school",
@@ -602,7 +608,10 @@
"heading": "Paramètres",
"disableSounds": "",
"changeDataFolder": "",
- "forceProductionForDebug": ""
+ "forceProductionForDebug": "",
+ "settings": "",
+ "prideMode": "",
+ "altTemplateLayout": ""
},
"project": {
"save": "Sauvegarder le projet",
@@ -638,14 +647,36 @@
"fx": "FX",
"restart": "",
"project": "",
- "templates": "Types"
- },
- "copyCustomProperties": {
- "customProperties": "",
- "addProperty": "",
- "property": "",
- "value": "",
- "delete": ""
+ "templates": "Types",
+ "tour": {
+ "header": "",
+ "aboutTour": "",
+ "helpPanel": "",
+ "helpPanelTabs": "",
+ "projectResources": "",
+ "tabTextures": "",
+ "tabTexturesImport": "",
+ "tabTexturesGallery": "",
+ "tabTexturesClipboard": "",
+ "tabTexturesPlaceholders": "",
+ "tabTemplates": "",
+ "tabRooms": "",
+ "tabSounds": "",
+ "tabSoundsImport": "",
+ "tabSoundsGallery": "",
+ "tabSoundsRecord": "",
+ "tabInterlude": "",
+ "tabUI": "",
+ "tabFX": "",
+ "tabProject": "",
+ "tabProjectModules": "",
+ "tabProjectModuleDocs": "",
+ "tabMainMenu": "",
+ "tabMainMenuSettings": "",
+ "tabMainMenuMeta": "",
+ "helpPanelReminder": "",
+ "buttonStartTutorial": ""
+ }
},
"assetViewer": {
"addNewGroup": "",
@@ -716,7 +747,13 @@
"copyProperties": {
"position": "",
"rotation": "",
- "scale": ""
+ "scale": "",
+ "multipleValues": ""
+ },
+ "copyCustomProperties": {
+ "addProperty": "",
+ "property": "",
+ "value": ""
},
"customProperties": "",
"restrictCamera": "",
@@ -736,7 +773,19 @@
"deleteTiles": "Supprimer les Tiles",
"moveTilesToLayer": "Déplacer le calque",
"shiftTiles": "Déplacer les Tiles",
- "changeCopyRotation": ""
+ "changeCopyRotation": "",
+ "simulate": "",
+ "toggleDiagonalGrid": "",
+ "changeGridSize": "",
+ "xrayMode": "",
+ "colorizeTileLayers": "",
+ "tools": {
+ "select": "",
+ "addCopies": "",
+ "addTiles": "",
+ "manageBackgrounds": "",
+ "roomProperties": ""
+ }
},
"styleView": {
"active": "Activer",
@@ -869,7 +918,9 @@
"add": "",
"multiply": "",
"screen": ""
- }
+ },
+ "animationFPS": "",
+ "loopAnimation": ""
},
"assetInput": {
"changeAsset": "",
@@ -889,5 +940,71 @@
"visitAuthorsItch": "",
"visitAuthorsTwitter": "",
"tipAuthor": ""
+ },
+ "scriptables": {
+ "addEvent": "",
+ "removeEvent": "",
+ "removeEventConfirm": "",
+ "changeArguments": "",
+ "eventAlreadyExists": "",
+ "localEventVars": "",
+ "createEventHint": "",
+ "coreEventsCategories": {
+ "lifecycle": "",
+ "actions": "",
+ "pointer": "",
+ "misc": "",
+ "animation": "",
+ "timers": ""
+ },
+ "coreEvents": {
+ "OnCreate": "",
+ "OnRoomStart": "",
+ "OnStep": "",
+ "OnDraw": "",
+ "OnDestroy": "",
+ "OnRoomEnd": "",
+ "OnPointerClick": "",
+ "OnPointerSecondaryClick": "",
+ "OnPointerEnter": "",
+ "OnPointerLeave": "",
+ "OnPointerDown": "",
+ "OnPointerUp": "",
+ "OnPointerUpOutside": "",
+ "OnPointerWheel": "",
+ "OnActionPress": "",
+ "OnActionRelease": "",
+ "OnActionDown": "",
+ "OnFrameChange": "",
+ "OnAnimationLoop": "",
+ "OnAnimationComplete": "",
+ "Timer": ""
+ },
+ "coreParameterizedNames": {
+ "OnActionPress": "",
+ "OnActionRelease": "",
+ "OnActionDown": ""
+ },
+ "coreEventsArguments": {
+ "action": ""
+ },
+ "coreEventsLocals": {
+ "OnActionDown_value": "",
+ "OnActionPress_value": ""
+ },
+ "coreEventsDescriptions": {
+ "OnCreate": "",
+ "OnRoomStart": "",
+ "OnStep": "",
+ "OnDraw": "",
+ "OnDestroy": "",
+ "OnRoomEnd": "",
+ "OnActionPress": "",
+ "OnActionRelease": "",
+ "OnActionDown": "",
+ "OnAnimationLoop": "",
+ "OnAnimationComplete": "",
+ "Timer": ""
+ }
}
}
\ No newline at end of file
diff --git a/app/data/i18n/German.json b/app/data/i18n/German.json
index 67b9c85b0..d43d8e4fb 100644
--- a/app/data/i18n/German.json
+++ b/app/data/i18n/German.json
@@ -67,7 +67,8 @@
"template": "",
"room": "",
"sound": "",
- "tandem": ""
+ "tandem": "",
+ "type": ""
},
"newName": "Neuer Name:",
"saveProject": "Project speichern",
@@ -125,7 +126,9 @@
"",
""
]
- }
+ },
+ "next": "",
+ "previous": ""
},
"colorPicker": {
"current": "Neu",
@@ -589,7 +592,10 @@
"SpringStream": "",
"LucasDracula": "",
"Horizon": "",
- "HCBlack": ""
+ "HCBlack": "",
+ "RosePine": "",
+ "RosePineMoon": "",
+ "RosePineDawn": ""
},
"codeFontDefault": "Standard (Iosevka Light)",
"codeFontOldSchool": "Old School",
@@ -602,7 +608,10 @@
"heading": "Einstellungen",
"disableSounds": "",
"changeDataFolder": "",
- "forceProductionForDebug": ""
+ "forceProductionForDebug": "",
+ "settings": "",
+ "prideMode": "",
+ "altTemplateLayout": ""
},
"project": {
"save": "Projekt speichern",
@@ -638,14 +647,36 @@
"fx": "FX",
"restart": "",
"project": "",
- "templates": "Types"
- },
- "copyCustomProperties": {
- "customProperties": "",
- "addProperty": "",
- "property": "",
- "value": "",
- "delete": ""
+ "templates": "Types",
+ "tour": {
+ "header": "",
+ "aboutTour": "",
+ "helpPanel": "",
+ "helpPanelTabs": "",
+ "projectResources": "",
+ "tabTextures": "",
+ "tabTexturesImport": "",
+ "tabTexturesGallery": "",
+ "tabTexturesClipboard": "",
+ "tabTexturesPlaceholders": "",
+ "tabTemplates": "",
+ "tabRooms": "",
+ "tabSounds": "",
+ "tabSoundsImport": "",
+ "tabSoundsGallery": "",
+ "tabSoundsRecord": "",
+ "tabInterlude": "",
+ "tabUI": "",
+ "tabFX": "",
+ "tabProject": "",
+ "tabProjectModules": "",
+ "tabProjectModuleDocs": "",
+ "tabMainMenu": "",
+ "tabMainMenuSettings": "",
+ "tabMainMenuMeta": "",
+ "helpPanelReminder": "",
+ "buttonStartTutorial": ""
+ }
},
"assetViewer": {
"addNewGroup": "",
@@ -716,7 +747,13 @@
"copyProperties": {
"position": "",
"rotation": "",
- "scale": ""
+ "scale": "",
+ "multipleValues": ""
+ },
+ "copyCustomProperties": {
+ "addProperty": "",
+ "property": "",
+ "value": ""
},
"customProperties": "",
"restrictCamera": "",
@@ -736,7 +773,19 @@
"deleteTiles": "Tiles löschen ",
"moveTilesToLayer": "Auf Ebene verschieben",
"shiftTiles": "Tiles verschieben",
- "changeCopyRotation": ""
+ "changeCopyRotation": "",
+ "simulate": "",
+ "toggleDiagonalGrid": "",
+ "changeGridSize": "",
+ "xrayMode": "",
+ "colorizeTileLayers": "",
+ "tools": {
+ "select": "",
+ "addCopies": "",
+ "addTiles": "",
+ "manageBackgrounds": "",
+ "roomProperties": ""
+ }
},
"styleView": {
"active": "Aktiv",
@@ -869,7 +918,9 @@
"add": "",
"multiply": "",
"screen": ""
- }
+ },
+ "animationFPS": "",
+ "loopAnimation": ""
},
"assetInput": {
"changeAsset": "",
@@ -889,5 +940,71 @@
"visitAuthorsItch": "",
"visitAuthorsTwitter": "",
"tipAuthor": ""
+ },
+ "scriptables": {
+ "addEvent": "",
+ "removeEvent": "",
+ "removeEventConfirm": "",
+ "changeArguments": "",
+ "eventAlreadyExists": "",
+ "localEventVars": "",
+ "createEventHint": "",
+ "coreEventsCategories": {
+ "lifecycle": "",
+ "actions": "",
+ "pointer": "",
+ "misc": "",
+ "animation": "",
+ "timers": ""
+ },
+ "coreEvents": {
+ "OnCreate": "",
+ "OnRoomStart": "",
+ "OnStep": "",
+ "OnDraw": "",
+ "OnDestroy": "",
+ "OnRoomEnd": "",
+ "OnPointerClick": "",
+ "OnPointerSecondaryClick": "",
+ "OnPointerEnter": "",
+ "OnPointerLeave": "",
+ "OnPointerDown": "",
+ "OnPointerUp": "",
+ "OnPointerUpOutside": "",
+ "OnPointerWheel": "",
+ "OnActionPress": "",
+ "OnActionRelease": "",
+ "OnActionDown": "",
+ "OnFrameChange": "",
+ "OnAnimationLoop": "",
+ "OnAnimationComplete": "",
+ "Timer": ""
+ },
+ "coreParameterizedNames": {
+ "OnActionPress": "",
+ "OnActionRelease": "",
+ "OnActionDown": ""
+ },
+ "coreEventsArguments": {
+ "action": ""
+ },
+ "coreEventsLocals": {
+ "OnActionDown_value": "",
+ "OnActionPress_value": ""
+ },
+ "coreEventsDescriptions": {
+ "OnCreate": "",
+ "OnRoomStart": "",
+ "OnStep": "",
+ "OnDraw": "",
+ "OnDestroy": "",
+ "OnRoomEnd": "",
+ "OnActionPress": "",
+ "OnActionRelease": "",
+ "OnActionDown": "",
+ "OnAnimationLoop": "",
+ "OnAnimationComplete": "",
+ "Timer": ""
+ }
}
}
\ No newline at end of file
diff --git a/app/data/i18n/Japanese.json b/app/data/i18n/Japanese.json
index f86390759..6e73f73f0 100644
--- a/app/data/i18n/Japanese.json
+++ b/app/data/i18n/Japanese.json
@@ -69,7 +69,8 @@
"template": "",
"room": "",
"sound": "",
- "tandem": ""
+ "tandem": "",
+ "type": ""
},
"newName": "新しい名前:",
"saveProject": "プロジェクトを保存",
@@ -125,7 +126,9 @@
"",
""
]
- }
+ },
+ "next": "",
+ "previous": ""
},
"assetInput": {
"changeAsset": "アセットを変更する",
@@ -144,13 +147,6 @@
"old": "古い",
"projectPalette": "プロジェクトのパレット"
},
- "copyCustomProperties": {
- "customProperties": "カスタムプロパティ",
- "addProperty": "プロパティを追加",
- "property": "プロパティ",
- "value": "数字",
- "delete": "削除"
- },
"curveEditor": {
"curveLineHint": "カーブをクリックしてポイントを追加",
"dragPointHint": "ドラッグでポイントを移動、右クリックで削除",
@@ -620,7 +616,10 @@
"SpringStream": "春の小川",
"LucasDracula": "ルーカス・ドラキュラ",
"Horizon": "地平線",
- "HCBlack": "高コントラストの黒"
+ "HCBlack": "高コントラストの黒",
+ "RosePine": "",
+ "RosePineMoon": "",
+ "RosePineDawn": ""
},
"language": "言語",
"translateToYourLanguage": "ct.jsを翻訳する!",
@@ -634,7 +633,10 @@
"codeDense": "高密度なレイアウト",
"disableSounds": "UIサウンドを無効化",
"changeDataFolder": "データフォルダの場所を設定",
- "forceProductionForDebug": "デバッグエクスポートのためのプロダクションタスクの強制"
+ "forceProductionForDebug": "デバッグエクスポートのためのプロダクションタスクの強制",
+ "settings": "",
+ "prideMode": "",
+ "altTemplateLayout": ""
},
"project": {
"heading": "プロジェクト",
@@ -670,7 +672,36 @@
"sounds": "音",
"ui": "UI",
"fx": "FX",
- "templates": "テンプレート"
+ "templates": "テンプレート",
+ "tour": {
+ "header": "",
+ "aboutTour": "",
+ "helpPanel": "",
+ "helpPanelTabs": "",
+ "projectResources": "",
+ "tabTextures": "",
+ "tabTexturesImport": "",
+ "tabTexturesGallery": "",
+ "tabTexturesClipboard": "",
+ "tabTexturesPlaceholders": "",
+ "tabTemplates": "",
+ "tabRooms": "",
+ "tabSounds": "",
+ "tabSoundsImport": "",
+ "tabSoundsGallery": "",
+ "tabSoundsRecord": "",
+ "tabInterlude": "",
+ "tabUI": "",
+ "tabFX": "",
+ "tabProject": "",
+ "tabProjectModules": "",
+ "tabProjectModuleDocs": "",
+ "tabMainMenu": "",
+ "tabMainMenuSettings": "",
+ "tabMainMenuMeta": "",
+ "helpPanelReminder": "",
+ "buttonStartTutorial": ""
+ }
},
"roomBackgrounds": {
"add": "背景を追加",
@@ -722,7 +753,13 @@
"copyProperties": {
"position": "位置",
"rotation": "回転",
- "scale": "大きさ"
+ "scale": "大きさ",
+ "multipleValues": ""
+ },
+ "copyCustomProperties": {
+ "addProperty": "プロパティを追加",
+ "property": "プロパティ",
+ "value": "数字"
},
"restrictCamera": "カメラを四角に収める",
"minimumX": "最小 X",
@@ -741,7 +778,19 @@
"deleteTiles": "複数のタイルを削除",
"moveTilesToLayer": "レイヤーに移動",
"shiftTiles": "タイルに移動",
- "changeCopyRotation": "回転"
+ "changeCopyRotation": "回転",
+ "simulate": "",
+ "toggleDiagonalGrid": "",
+ "changeGridSize": "",
+ "xrayMode": "",
+ "colorizeTileLayers": "",
+ "tools": {
+ "select": "",
+ "addCopies": "",
+ "addTiles": "",
+ "manageBackgrounds": "",
+ "roomProperties": ""
+ }
},
"styleView": {
"active": "有効",
@@ -874,7 +923,9 @@
"add": "",
"multiply": "",
"screen": ""
- }
+ },
+ "animationFPS": "",
+ "loopAnimation": ""
},
"builtinAssetGallery": {
"galleryTip": "",
@@ -889,5 +940,71 @@
"visitAuthorsItch": "",
"visitAuthorsTwitter": "",
"tipAuthor": ""
+ },
+ "scriptables": {
+ "addEvent": "",
+ "removeEvent": "",
+ "removeEventConfirm": "",
+ "changeArguments": "",
+ "eventAlreadyExists": "",
+ "localEventVars": "",
+ "createEventHint": "",
+ "coreEventsCategories": {
+ "lifecycle": "",
+ "actions": "",
+ "pointer": "",
+ "misc": "",
+ "animation": "",
+ "timers": ""
+ },
+ "coreEvents": {
+ "OnCreate": "",
+ "OnRoomStart": "",
+ "OnStep": "",
+ "OnDraw": "",
+ "OnDestroy": "",
+ "OnRoomEnd": "",
+ "OnPointerClick": "",
+ "OnPointerSecondaryClick": "",
+ "OnPointerEnter": "",
+ "OnPointerLeave": "",
+ "OnPointerDown": "",
+ "OnPointerUp": "",
+ "OnPointerUpOutside": "",
+ "OnPointerWheel": "",
+ "OnActionPress": "",
+ "OnActionRelease": "",
+ "OnActionDown": "",
+ "OnFrameChange": "",
+ "OnAnimationLoop": "",
+ "OnAnimationComplete": "",
+ "Timer": ""
+ },
+ "coreParameterizedNames": {
+ "OnActionPress": "",
+ "OnActionRelease": "",
+ "OnActionDown": ""
+ },
+ "coreEventsArguments": {
+ "action": ""
+ },
+ "coreEventsLocals": {
+ "OnActionDown_value": "",
+ "OnActionPress_value": ""
+ },
+ "coreEventsDescriptions": {
+ "OnCreate": "",
+ "OnRoomStart": "",
+ "OnStep": "",
+ "OnDraw": "",
+ "OnDestroy": "",
+ "OnRoomEnd": "",
+ "OnActionPress": "",
+ "OnActionRelease": "",
+ "OnActionDown": "",
+ "OnAnimationLoop": "",
+ "OnAnimationComplete": "",
+ "Timer": ""
+ }
}
}
\ No newline at end of file
diff --git a/app/data/i18n/Polish.json b/app/data/i18n/Polish.json
index f79bb9f29..537c723fe 100644
--- a/app/data/i18n/Polish.json
+++ b/app/data/i18n/Polish.json
@@ -67,7 +67,8 @@
"template": "",
"room": "",
"sound": "",
- "tandem": ""
+ "tandem": "",
+ "type": ""
},
"newName": "Nowa nazwa:",
"saveProject": "Zapisz projekt",
@@ -125,7 +126,9 @@
"",
""
]
- }
+ },
+ "next": "",
+ "previous": ""
},
"colorPicker": {
"current": "Nowy",
@@ -589,7 +592,10 @@
"SpringStream": "",
"LucasDracula": "",
"Horizon": "",
- "HCBlack": ""
+ "HCBlack": "",
+ "RosePine": "",
+ "RosePineMoon": "",
+ "RosePineDawn": ""
},
"codeFontDefault": "Domyślny (Iosevka Light)",
"codeFontOldSchool": "Old school",
@@ -602,7 +608,10 @@
"heading": "Ustawienia",
"disableSounds": "",
"changeDataFolder": "",
- "forceProductionForDebug": ""
+ "forceProductionForDebug": "",
+ "settings": "",
+ "prideMode": "",
+ "altTemplateLayout": ""
},
"project": {
"save": "Zapisz projekt",
@@ -638,14 +647,36 @@
"fx": "",
"restart": "",
"project": "",
- "templates": "Typy"
- },
- "copyCustomProperties": {
- "customProperties": "",
- "addProperty": "",
- "property": "",
- "value": "",
- "delete": ""
+ "templates": "Typy",
+ "tour": {
+ "header": "",
+ "aboutTour": "",
+ "helpPanel": "",
+ "helpPanelTabs": "",
+ "projectResources": "",
+ "tabTextures": "",
+ "tabTexturesImport": "",
+ "tabTexturesGallery": "",
+ "tabTexturesClipboard": "",
+ "tabTexturesPlaceholders": "",
+ "tabTemplates": "",
+ "tabRooms": "",
+ "tabSounds": "",
+ "tabSoundsImport": "",
+ "tabSoundsGallery": "",
+ "tabSoundsRecord": "",
+ "tabInterlude": "",
+ "tabUI": "",
+ "tabFX": "",
+ "tabProject": "",
+ "tabProjectModules": "",
+ "tabProjectModuleDocs": "",
+ "tabMainMenu": "",
+ "tabMainMenuSettings": "",
+ "tabMainMenuMeta": "",
+ "helpPanelReminder": "",
+ "buttonStartTutorial": ""
+ }
},
"assetViewer": {
"addNewGroup": "",
@@ -716,7 +747,13 @@
"copyProperties": {
"position": "",
"rotation": "",
- "scale": ""
+ "scale": "",
+ "multipleValues": ""
+ },
+ "copyCustomProperties": {
+ "addProperty": "",
+ "property": "",
+ "value": ""
},
"customProperties": "",
"restrictCamera": "",
@@ -736,7 +773,19 @@
"deleteTiles": "Usuń kafelki",
"moveTilesToLayer": "Przenieś do warstwy",
"shiftTiles": "Przesuń kafelki",
- "changeCopyRotation": ""
+ "changeCopyRotation": "",
+ "simulate": "",
+ "toggleDiagonalGrid": "",
+ "changeGridSize": "",
+ "xrayMode": "",
+ "colorizeTileLayers": "",
+ "tools": {
+ "select": "",
+ "addCopies": "",
+ "addTiles": "",
+ "manageBackgrounds": "",
+ "roomProperties": ""
+ }
},
"styleView": {
"active": "Aktywny",
@@ -869,7 +918,9 @@
"add": "",
"multiply": "",
"screen": ""
- }
+ },
+ "animationFPS": "",
+ "loopAnimation": ""
},
"assetInput": {
"changeAsset": "",
@@ -889,5 +940,71 @@
"visitAuthorsItch": "",
"visitAuthorsTwitter": "",
"tipAuthor": ""
+ },
+ "scriptables": {
+ "addEvent": "",
+ "removeEvent": "",
+ "removeEventConfirm": "",
+ "changeArguments": "",
+ "eventAlreadyExists": "",
+ "localEventVars": "",
+ "createEventHint": "",
+ "coreEventsCategories": {
+ "lifecycle": "",
+ "actions": "",
+ "pointer": "",
+ "misc": "",
+ "animation": "",
+ "timers": ""
+ },
+ "coreEvents": {
+ "OnCreate": "",
+ "OnRoomStart": "",
+ "OnStep": "",
+ "OnDraw": "",
+ "OnDestroy": "",
+ "OnRoomEnd": "",
+ "OnPointerClick": "",
+ "OnPointerSecondaryClick": "",
+ "OnPointerEnter": "",
+ "OnPointerLeave": "",
+ "OnPointerDown": "",
+ "OnPointerUp": "",
+ "OnPointerUpOutside": "",
+ "OnPointerWheel": "",
+ "OnActionPress": "",
+ "OnActionRelease": "",
+ "OnActionDown": "",
+ "OnFrameChange": "",
+ "OnAnimationLoop": "",
+ "OnAnimationComplete": "",
+ "Timer": ""
+ },
+ "coreParameterizedNames": {
+ "OnActionPress": "",
+ "OnActionRelease": "",
+ "OnActionDown": ""
+ },
+ "coreEventsArguments": {
+ "action": ""
+ },
+ "coreEventsLocals": {
+ "OnActionDown_value": "",
+ "OnActionPress_value": ""
+ },
+ "coreEventsDescriptions": {
+ "OnCreate": "",
+ "OnRoomStart": "",
+ "OnStep": "",
+ "OnDraw": "",
+ "OnDestroy": "",
+ "OnRoomEnd": "",
+ "OnActionPress": "",
+ "OnActionRelease": "",
+ "OnActionDown": "",
+ "OnAnimationLoop": "",
+ "OnAnimationComplete": "",
+ "Timer": ""
+ }
}
}
\ No newline at end of file
diff --git a/app/data/i18n/Romanian.json b/app/data/i18n/Romanian.json
index 8807389aa..09d1e5995 100644
--- a/app/data/i18n/Romanian.json
+++ b/app/data/i18n/Romanian.json
@@ -67,7 +67,8 @@
"template": "",
"room": "",
"sound": "",
- "tandem": ""
+ "tandem": "",
+ "type": ""
},
"newName": "Nume nou:",
"saveProject": "Salvează proiectul",
@@ -125,7 +126,9 @@
"",
""
]
- }
+ },
+ "next": "",
+ "previous": ""
},
"colorPicker": {
"current": "Nou",
@@ -589,7 +592,10 @@
"SpringStream": "",
"LucasDracula": "",
"Horizon": "",
- "HCBlack": ""
+ "HCBlack": "",
+ "RosePine": "",
+ "RosePineMoon": "",
+ "RosePineDawn": ""
},
"codeFontDefault": "",
"codeFontOldSchool": "",
@@ -602,7 +608,10 @@
"heading": "Setări",
"disableSounds": "",
"changeDataFolder": "",
- "forceProductionForDebug": ""
+ "forceProductionForDebug": "",
+ "settings": "",
+ "prideMode": "",
+ "altTemplateLayout": ""
},
"project": {
"save": "Salvează proiectul",
@@ -638,14 +647,36 @@
"fx": "",
"restart": "",
"project": "",
- "templates": "Tipuri"
- },
- "copyCustomProperties": {
- "customProperties": "",
- "addProperty": "",
- "property": "",
- "value": "",
- "delete": ""
+ "templates": "Tipuri",
+ "tour": {
+ "header": "",
+ "aboutTour": "",
+ "helpPanel": "",
+ "helpPanelTabs": "",
+ "projectResources": "",
+ "tabTextures": "",
+ "tabTexturesImport": "",
+ "tabTexturesGallery": "",
+ "tabTexturesClipboard": "",
+ "tabTexturesPlaceholders": "",
+ "tabTemplates": "",
+ "tabRooms": "",
+ "tabSounds": "",
+ "tabSoundsImport": "",
+ "tabSoundsGallery": "",
+ "tabSoundsRecord": "",
+ "tabInterlude": "",
+ "tabUI": "",
+ "tabFX": "",
+ "tabProject": "",
+ "tabProjectModules": "",
+ "tabProjectModuleDocs": "",
+ "tabMainMenu": "",
+ "tabMainMenuSettings": "",
+ "tabMainMenuMeta": "",
+ "helpPanelReminder": "",
+ "buttonStartTutorial": ""
+ }
},
"assetViewer": {
"addNewGroup": "",
@@ -716,7 +747,13 @@
"copyProperties": {
"position": "",
"rotation": "",
- "scale": ""
+ "scale": "",
+ "multipleValues": ""
+ },
+ "copyCustomProperties": {
+ "addProperty": "",
+ "property": "",
+ "value": ""
},
"customProperties": "",
"restrictCamera": "",
@@ -736,7 +773,19 @@
"deleteTiles": "Șterge tile-urile",
"moveTilesToLayer": "Mută în layer",
"shiftTiles": "Deplasează tile-urile",
- "changeCopyRotation": ""
+ "changeCopyRotation": "",
+ "simulate": "",
+ "toggleDiagonalGrid": "",
+ "changeGridSize": "",
+ "xrayMode": "",
+ "colorizeTileLayers": "",
+ "tools": {
+ "select": "",
+ "addCopies": "",
+ "addTiles": "",
+ "manageBackgrounds": "",
+ "roomProperties": ""
+ }
},
"styleView": {
"active": "Activ",
@@ -869,7 +918,9 @@
"add": "",
"multiply": "",
"screen": ""
- }
+ },
+ "animationFPS": "",
+ "loopAnimation": ""
},
"assetInput": {
"changeAsset": "",
@@ -889,5 +940,71 @@
"visitAuthorsItch": "",
"visitAuthorsTwitter": "",
"tipAuthor": ""
+ },
+ "scriptables": {
+ "addEvent": "",
+ "removeEvent": "",
+ "removeEventConfirm": "",
+ "changeArguments": "",
+ "eventAlreadyExists": "",
+ "localEventVars": "",
+ "createEventHint": "",
+ "coreEventsCategories": {
+ "lifecycle": "",
+ "actions": "",
+ "pointer": "",
+ "misc": "",
+ "animation": "",
+ "timers": ""
+ },
+ "coreEvents": {
+ "OnCreate": "",
+ "OnRoomStart": "",
+ "OnStep": "",
+ "OnDraw": "",
+ "OnDestroy": "",
+ "OnRoomEnd": "",
+ "OnPointerClick": "",
+ "OnPointerSecondaryClick": "",
+ "OnPointerEnter": "",
+ "OnPointerLeave": "",
+ "OnPointerDown": "",
+ "OnPointerUp": "",
+ "OnPointerUpOutside": "",
+ "OnPointerWheel": "",
+ "OnActionPress": "",
+ "OnActionRelease": "",
+ "OnActionDown": "",
+ "OnFrameChange": "",
+ "OnAnimationLoop": "",
+ "OnAnimationComplete": "",
+ "Timer": ""
+ },
+ "coreParameterizedNames": {
+ "OnActionPress": "",
+ "OnActionRelease": "",
+ "OnActionDown": ""
+ },
+ "coreEventsArguments": {
+ "action": ""
+ },
+ "coreEventsLocals": {
+ "OnActionDown_value": "",
+ "OnActionPress_value": ""
+ },
+ "coreEventsDescriptions": {
+ "OnCreate": "",
+ "OnRoomStart": "",
+ "OnStep": "",
+ "OnDraw": "",
+ "OnDestroy": "",
+ "OnRoomEnd": "",
+ "OnActionPress": "",
+ "OnActionRelease": "",
+ "OnActionDown": "",
+ "OnAnimationLoop": "",
+ "OnAnimationComplete": "",
+ "Timer": ""
+ }
}
}
\ No newline at end of file
diff --git a/app/data/i18n/Russian.json b/app/data/i18n/Russian.json
index 9afbd2a4f..b854d70c8 100644
--- a/app/data/i18n/Russian.json
+++ b/app/data/i18n/Russian.json
@@ -67,7 +67,8 @@
"template": "Шаблон",
"room": "Комната",
"sound": "Звук",
- "tandem": "Система частиц"
+ "tandem": "Система частиц",
+ "type": ""
},
"newName": "Новое имя:",
"saveProject": "Сохранить проект",
@@ -125,7 +126,9 @@
"скелетных спрайта",
"скелетных спрайтов"
]
- }
+ },
+ "next": "",
+ "previous": ""
},
"colorPicker": {
"old": "Старый",
@@ -607,7 +610,8 @@
"disableSounds": "Отключить звуки интерфейса",
"changeDataFolder": "Изменить папку данных ct.js",
"forceProductionForDebug": " Включить релизные функции для дебаг-экспортов",
- "altTemplateLayout": "Альт. вёрстка редактора шаблонов"
+ "altTemplateLayout": "Альт. вёрстка редактора шаблонов",
+ "settings": ""
},
"project": {
"save": "Сохранить проект",
@@ -643,14 +647,36 @@
"ui": "Интерфейс",
"fx": "Эффекты",
"restart": "Перезапустить",
- "templates": "Шаблоны"
- },
- "copyCustomProperties": {
- "customProperties": "Пользовательские поля",
- "addProperty": "Добавить поле",
- "property": "Имя поля",
- "value": "Значение",
- "delete": "Удалить"
+ "templates": "Шаблоны",
+ "tour": {
+ "header": "",
+ "aboutTour": "",
+ "helpPanel": "",
+ "helpPanelTabs": "",
+ "projectResources": "",
+ "tabTextures": "",
+ "tabTexturesImport": "",
+ "tabTexturesGallery": "",
+ "tabTexturesClipboard": "",
+ "tabTexturesPlaceholders": "",
+ "tabTemplates": "",
+ "tabRooms": "",
+ "tabSounds": "",
+ "tabSoundsImport": "",
+ "tabSoundsGallery": "",
+ "tabSoundsRecord": "",
+ "tabInterlude": "",
+ "tabUI": "",
+ "tabFX": "",
+ "tabProject": "",
+ "tabProjectModules": "",
+ "tabProjectModuleDocs": "",
+ "tabMainMenu": "",
+ "tabMainMenuSettings": "",
+ "tabMainMenuMeta": "",
+ "helpPanelReminder": "",
+ "buttonStartTutorial": ""
+ }
},
"assetViewer": {
"addNewGroup": "Новая группа",
@@ -721,7 +747,13 @@
"copyProperties": {
"position": "Позиция",
"rotation": "Поворот",
- "scale": "Размер"
+ "scale": "Размер",
+ "multipleValues": ""
+ },
+ "copyCustomProperties": {
+ "addProperty": "Добавить поле",
+ "property": "Имя поля",
+ "value": "Значение"
},
"customProperties": "Пользовательские поля",
"restrictCamera": "Ограничить камеру в прямоугольнике",
@@ -741,7 +773,19 @@
"deleteTiles": "Удалить плитки",
"moveTilesToLayer": "Переместить в другой слой",
"shiftTiles": "Сместить плитки",
- "changeCopyRotation": "Повернуть"
+ "changeCopyRotation": "Повернуть",
+ "simulate": "",
+ "toggleDiagonalGrid": "",
+ "changeGridSize": "",
+ "xrayMode": "",
+ "colorizeTileLayers": "",
+ "tools": {
+ "select": "",
+ "addCopies": "",
+ "addTiles": "",
+ "manageBackgrounds": "",
+ "roomProperties": ""
+ }
},
"styleView": {
"active": "Активно?",
@@ -875,7 +919,8 @@
"multiply": "Умножить (затемнение)",
"screen": "Экран (осветление)"
},
- "loopAnimation": "Цикличная анимация"
+ "loopAnimation": "Цикличная анимация",
+ "animationFPS": ""
},
"assetInput": {
"changeAsset": "Нажмите, чтобы заменить ассет",
@@ -909,7 +954,8 @@
"actions": "Действия",
"pointer": "События указателя",
"misc": "Разное",
- "animation": "Анимация"
+ "animation": "Анимация",
+ "timers": ""
},
"coreEvents": {
"OnCreate": "Создание",
@@ -931,7 +977,8 @@
"OnActionDown": "Действие нажато",
"OnFrameChange": "Смена кадра",
"OnAnimationLoop": "Перезапуск анимации",
- "OnAnimationComplete": "Конец анимации"
+ "OnAnimationComplete": "Конец анимации",
+ "Timer": ""
},
"coreParameterizedNames": {
"OnActionPress": "При нажатии %%action%%",
@@ -942,7 +989,8 @@
"action": "Действие"
},
"coreEventsLocals": {
- "OnActionDown_value": "Текущее значение действия"
+ "OnActionDown_value": "Текущее значение действия",
+ "OnActionPress_value": ""
},
"coreEventsDescriptions": {
"OnCreate": "Срабатывает при создании копии.",
@@ -955,7 +1003,8 @@
"OnActionRelease": "Срабатывает, когда действие перестаёт быть активно — когда отпускают клавиши, джойстики и т.п.",
"OnActionDown": "Срабатывает каждый кадр, пока методы ввода этого действия активны.",
"OnAnimationLoop": "Срабатывает каждый раз, когда цикличная анимация подходит к концу.",
- "OnAnimationComplete": "Срабатывает один раз, когда нецикличная анимация заканчивается."
+ "OnAnimationComplete": "Срабатывает один раз, когда нецикличная анимация заканчивается.",
+ "Timer": ""
}
}
-}
+}
\ No newline at end of file
diff --git a/app/data/i18n/Spanish.json b/app/data/i18n/Spanish.json
index eff068789..e264772d7 100644
--- a/app/data/i18n/Spanish.json
+++ b/app/data/i18n/Spanish.json
@@ -67,7 +67,8 @@
"template": "",
"room": "",
"sound": "",
- "tandem": ""
+ "tandem": "",
+ "type": ""
},
"newName": "Nombre Nuevo:",
"saveProject": "Guardar proyecto",
@@ -125,7 +126,9 @@
"",
""
]
- }
+ },
+ "next": "",
+ "previous": ""
},
"colorPicker": {
"current": "Nuevo",
@@ -590,7 +593,10 @@
"SpringStream": "Corriente de Primavera",
"LucasDracula": "Lucas Dracula",
"Horizon": "",
- "HCBlack": ""
+ "HCBlack": "",
+ "RosePine": "",
+ "RosePineMoon": "",
+ "RosePineDawn": ""
},
"codeFontDefault": "Predeterminado (Iosevka Light)",
"codeFontOldSchool": "Vieja Escuela",
@@ -602,7 +608,10 @@
"codeDense": "Diseño Denso",
"disableSounds": "",
"changeDataFolder": "",
- "forceProductionForDebug": ""
+ "forceProductionForDebug": "",
+ "settings": "",
+ "prideMode": "",
+ "altTemplateLayout": ""
},
"project": {
"save": "Guardar proyecto",
@@ -638,14 +647,36 @@
"restart": "Reiniciar",
"project": "Proyecto",
"fx": "Effectos",
- "templates": "Tipos"
- },
- "copyCustomProperties": {
- "customProperties": "",
- "addProperty": "",
- "property": "",
- "value": "",
- "delete": ""
+ "templates": "Tipos",
+ "tour": {
+ "header": "",
+ "aboutTour": "",
+ "helpPanel": "",
+ "helpPanelTabs": "",
+ "projectResources": "",
+ "tabTextures": "",
+ "tabTexturesImport": "",
+ "tabTexturesGallery": "",
+ "tabTexturesClipboard": "",
+ "tabTexturesPlaceholders": "",
+ "tabTemplates": "",
+ "tabRooms": "",
+ "tabSounds": "",
+ "tabSoundsImport": "",
+ "tabSoundsGallery": "",
+ "tabSoundsRecord": "",
+ "tabInterlude": "",
+ "tabUI": "",
+ "tabFX": "",
+ "tabProject": "",
+ "tabProjectModules": "",
+ "tabProjectModuleDocs": "",
+ "tabMainMenu": "",
+ "tabMainMenuSettings": "",
+ "tabMainMenuMeta": "",
+ "helpPanelReminder": "",
+ "buttonStartTutorial": ""
+ }
},
"assetViewer": {
"addNewGroup": "",
@@ -716,7 +747,13 @@
"copyProperties": {
"position": "",
"rotation": "",
- "scale": ""
+ "scale": "",
+ "multipleValues": ""
+ },
+ "copyCustomProperties": {
+ "addProperty": "",
+ "property": "",
+ "value": ""
},
"customProperties": "",
"restrictCamera": "",
@@ -736,7 +773,19 @@
"deleteTiles": "Eliminar tiles",
"moveTilesToLayer": "Mover a capa",
"shiftTiles": "Cambiar tiles",
- "changeCopyRotation": "Rotar"
+ "changeCopyRotation": "Rotar",
+ "simulate": "",
+ "toggleDiagonalGrid": "",
+ "changeGridSize": "",
+ "xrayMode": "",
+ "colorizeTileLayers": "",
+ "tools": {
+ "select": "",
+ "addCopies": "",
+ "addTiles": "",
+ "manageBackgrounds": "",
+ "roomProperties": ""
+ }
},
"styleView": {
"active": "Activar",
@@ -869,7 +918,9 @@
"add": "",
"multiply": "",
"screen": ""
- }
+ },
+ "animationFPS": "",
+ "loopAnimation": ""
},
"assetInput": {
"changeAsset": "",
@@ -889,5 +940,71 @@
"visitAuthorsItch": "",
"visitAuthorsTwitter": "",
"tipAuthor": ""
+ },
+ "scriptables": {
+ "addEvent": "",
+ "removeEvent": "",
+ "removeEventConfirm": "",
+ "changeArguments": "",
+ "eventAlreadyExists": "",
+ "localEventVars": "",
+ "createEventHint": "",
+ "coreEventsCategories": {
+ "lifecycle": "",
+ "actions": "",
+ "pointer": "",
+ "misc": "",
+ "animation": "",
+ "timers": ""
+ },
+ "coreEvents": {
+ "OnCreate": "",
+ "OnRoomStart": "",
+ "OnStep": "",
+ "OnDraw": "",
+ "OnDestroy": "",
+ "OnRoomEnd": "",
+ "OnPointerClick": "",
+ "OnPointerSecondaryClick": "",
+ "OnPointerEnter": "",
+ "OnPointerLeave": "",
+ "OnPointerDown": "",
+ "OnPointerUp": "",
+ "OnPointerUpOutside": "",
+ "OnPointerWheel": "",
+ "OnActionPress": "",
+ "OnActionRelease": "",
+ "OnActionDown": "",
+ "OnFrameChange": "",
+ "OnAnimationLoop": "",
+ "OnAnimationComplete": "",
+ "Timer": ""
+ },
+ "coreParameterizedNames": {
+ "OnActionPress": "",
+ "OnActionRelease": "",
+ "OnActionDown": ""
+ },
+ "coreEventsArguments": {
+ "action": ""
+ },
+ "coreEventsLocals": {
+ "OnActionDown_value": "",
+ "OnActionPress_value": ""
+ },
+ "coreEventsDescriptions": {
+ "OnCreate": "",
+ "OnRoomStart": "",
+ "OnStep": "",
+ "OnDraw": "",
+ "OnDestroy": "",
+ "OnRoomEnd": "",
+ "OnActionPress": "",
+ "OnActionRelease": "",
+ "OnActionDown": "",
+ "OnAnimationLoop": "",
+ "OnAnimationComplete": "",
+ "Timer": ""
+ }
}
}
\ No newline at end of file
diff --git a/app/data/i18n/Turkish.json b/app/data/i18n/Turkish.json
index ac128cd89..275b8e8b2 100644
--- a/app/data/i18n/Turkish.json
+++ b/app/data/i18n/Turkish.json
@@ -76,7 +76,8 @@
"template": "Şablon",
"room": "Oda",
"sound": "Ses",
- "tandem": "Partikül dağıtıcısı"
+ "tandem": "Partikül dağıtıcısı",
+ "type": ""
},
"assetTypes": {
"textures": [
@@ -125,7 +126,9 @@
"edit": "Değiştir",
"nothingToShowFiller": "Burada gösterilecek hiçbir şey yok!",
"required": "Gerekli",
- "settings": "Ayarlar"
+ "settings": "Ayarlar",
+ "next": "",
+ "previous": ""
},
"assetInput": {
"changeAsset": "Görseli değiştirmek için tıkla",
@@ -158,13 +161,6 @@
"old": "Eski",
"projectPalette": "Proje'nin paleti"
},
- "copyCustomProperties": {
- "customProperties": "Özel Özellikler",
- "addProperty": "Özellik Ekle",
- "property": "Özellik",
- "value": "Değer",
- "delete": "Sil"
- },
"curveEditor": {
"curveLineHint": "Nokta eklemek için kavise tıkla",
"dragPointHint": "Noktayı hareket ettirmek için sürükle, silmek için sağ tıkla.",
@@ -621,7 +617,10 @@
"SpringStream": "İlkbahar Yayını",
"LucasDracula": "Lucas Drakula",
"Horizon": "Ufuk",
- "HCBlack": "Yüksek-kontrast siyah"
+ "HCBlack": "Yüksek-kontrast siyah",
+ "RosePine": "",
+ "RosePineMoon": "",
+ "RosePineDawn": ""
},
"language": "Dil",
"translateToYourLanguage": "ct.js'i çevir!",
@@ -635,7 +634,10 @@
"codeDense": "Düzeni yoğunlaştır",
"disableSounds": "Arayüz seslerini kapat",
"changeDataFolder": "Veri klasörü yolunu ayarla",
- "forceProductionForDebug": "Hata ayıklamaları dışarı aktarmak için üretim işlemlerini zorla"
+ "forceProductionForDebug": "Hata ayıklamaları dışarı aktarmak için üretim işlemlerini zorla",
+ "settings": "",
+ "prideMode": "",
+ "altTemplateLayout": ""
},
"project": {
"heading": "Proje",
@@ -671,7 +673,36 @@
"sounds": "Sesler",
"ui": "Arayüz",
"fx": "Efektler",
- "templates": "Şablonlar"
+ "templates": "Şablonlar",
+ "tour": {
+ "header": "",
+ "aboutTour": "",
+ "helpPanel": "",
+ "helpPanelTabs": "",
+ "projectResources": "",
+ "tabTextures": "",
+ "tabTexturesImport": "",
+ "tabTexturesGallery": "",
+ "tabTexturesClipboard": "",
+ "tabTexturesPlaceholders": "",
+ "tabTemplates": "",
+ "tabRooms": "",
+ "tabSounds": "",
+ "tabSoundsImport": "",
+ "tabSoundsGallery": "",
+ "tabSoundsRecord": "",
+ "tabInterlude": "",
+ "tabUI": "",
+ "tabFX": "",
+ "tabProject": "",
+ "tabProjectModules": "",
+ "tabProjectModuleDocs": "",
+ "tabMainMenu": "",
+ "tabMainMenuSettings": "",
+ "tabMainMenuMeta": "",
+ "helpPanelReminder": "",
+ "buttonStartTutorial": ""
+ }
},
"roomBackgrounds": {
"add": "Arkaplan ekle",
@@ -736,13 +767,31 @@
"copyProperties": {
"position": "Pozisyon",
"rotation": "Rotasyon",
- "scale": "Boyut"
+ "scale": "Boyut",
+ "multipleValues": ""
+ },
+ "copyCustomProperties": {
+ "addProperty": "Özellik Ekle",
+ "property": "Özellik",
+ "value": "Değer"
},
"restrictCamera": "Kamerayı dörtgende tut",
"minimumX": "Minimum X",
"minimumY": "Minimum Y",
"maximumX": "Maksimum X",
- "maximumY": "Maksimum Y"
+ "maximumY": "Maksimum Y",
+ "simulate": "",
+ "toggleDiagonalGrid": "",
+ "changeGridSize": "",
+ "xrayMode": "",
+ "colorizeTileLayers": "",
+ "tools": {
+ "select": "",
+ "addCopies": "",
+ "addTiles": "",
+ "manageBackgrounds": "",
+ "roomProperties": ""
+ }
},
"styleView": {
"active": "Aktif",
@@ -888,6 +937,74 @@
"add": "Ekle (yanık)",
"multiply": "Çoğalt (karanlık)",
"screen": "Ekran (aydınlık)"
+ },
+ "animationFPS": "",
+ "loopAnimation": ""
+ },
+ "scriptables": {
+ "addEvent": "",
+ "removeEvent": "",
+ "removeEventConfirm": "",
+ "changeArguments": "",
+ "eventAlreadyExists": "",
+ "localEventVars": "",
+ "createEventHint": "",
+ "coreEventsCategories": {
+ "lifecycle": "",
+ "actions": "",
+ "pointer": "",
+ "misc": "",
+ "animation": "",
+ "timers": ""
+ },
+ "coreEvents": {
+ "OnCreate": "",
+ "OnRoomStart": "",
+ "OnStep": "",
+ "OnDraw": "",
+ "OnDestroy": "",
+ "OnRoomEnd": "",
+ "OnPointerClick": "",
+ "OnPointerSecondaryClick": "",
+ "OnPointerEnter": "",
+ "OnPointerLeave": "",
+ "OnPointerDown": "",
+ "OnPointerUp": "",
+ "OnPointerUpOutside": "",
+ "OnPointerWheel": "",
+ "OnActionPress": "",
+ "OnActionRelease": "",
+ "OnActionDown": "",
+ "OnFrameChange": "",
+ "OnAnimationLoop": "",
+ "OnAnimationComplete": "",
+ "Timer": ""
+ },
+ "coreParameterizedNames": {
+ "OnActionPress": "",
+ "OnActionRelease": "",
+ "OnActionDown": ""
+ },
+ "coreEventsArguments": {
+ "action": ""
+ },
+ "coreEventsLocals": {
+ "OnActionDown_value": "",
+ "OnActionPress_value": ""
+ },
+ "coreEventsDescriptions": {
+ "OnCreate": "",
+ "OnRoomStart": "",
+ "OnStep": "",
+ "OnDraw": "",
+ "OnDestroy": "",
+ "OnRoomEnd": "",
+ "OnActionPress": "",
+ "OnActionRelease": "",
+ "OnActionDown": "",
+ "OnAnimationLoop": "",
+ "OnAnimationComplete": "",
+ "Timer": ""
}
}
-}
+}
\ No newline at end of file
diff --git a/app/data/i18n/Ukranian.json b/app/data/i18n/Ukranian.json
index d842a68b8..923a7e622 100644
--- a/app/data/i18n/Ukranian.json
+++ b/app/data/i18n/Ukranian.json
@@ -67,7 +67,8 @@
"template": "Шаблон",
"room": "Кімната",
"sound": "Звук",
- "tandem": "Система частинок"
+ "tandem": "Система частинок",
+ "type": ""
},
"newName": "Нове ім'я:",
"saveProject": "Зберегти проект",
@@ -125,7 +126,9 @@
"скелетного спрайту",
"скелетних спрайтів"
]
- }
+ },
+ "next": "",
+ "previous": ""
},
"colorPicker": {
"old": "Старий",
@@ -607,7 +610,8 @@
"disableSounds": "Вимкнути звуки інтерфейсу",
"changeDataFolder": "Змінити папку даних ct.js",
"forceProductionForDebug": " Включити релізні функції для дебаг-експортів",
- "altTemplateLayout": "Альт. верстка редактора шаблонів"
+ "altTemplateLayout": "Альт. верстка редактора шаблонів",
+ "settings": ""
},
"project": {
"save": "Зберегти проект",
@@ -643,14 +647,36 @@
"ui": "Інтерфейс",
"fx": "Ефекти",
"restart": "Перезапустити",
- "templates": "Шаблони"
- },
- "copyCustomProperties": {
- "customProperties": "Користувацькі поля",
- "addProperty": "Додати поле",
- "property": "Ім'я поля",
- "value": "Значення",
- "delete": "Видалити"
+ "templates": "Шаблони",
+ "tour": {
+ "header": "",
+ "aboutTour": "",
+ "helpPanel": "",
+ "helpPanelTabs": "",
+ "projectResources": "",
+ "tabTextures": "",
+ "tabTexturesImport": "",
+ "tabTexturesGallery": "",
+ "tabTexturesClipboard": "",
+ "tabTexturesPlaceholders": "",
+ "tabTemplates": "",
+ "tabRooms": "",
+ "tabSounds": "",
+ "tabSoundsImport": "",
+ "tabSoundsGallery": "",
+ "tabSoundsRecord": "",
+ "tabInterlude": "",
+ "tabUI": "",
+ "tabFX": "",
+ "tabProject": "",
+ "tabProjectModules": "",
+ "tabProjectModuleDocs": "",
+ "tabMainMenu": "",
+ "tabMainMenuSettings": "",
+ "tabMainMenuMeta": "",
+ "helpPanelReminder": "",
+ "buttonStartTutorial": ""
+ }
},
"assetViewer": {
"addNewGroup": "Нова група",
@@ -721,7 +747,13 @@
"copyProperties": {
"position": "Позиція",
"rotation": "Поворот",
- "scale": "Розмір"
+ "scale": "Розмір",
+ "multipleValues": ""
+ },
+ "copyCustomProperties": {
+ "addProperty": "Додати поле",
+ "property": "Ім'я поля",
+ "value": "Значення"
},
"customProperties": "Користувацькі поля",
"restrictCamera": "Обмежити камеру в прямокутнику",
@@ -741,7 +773,19 @@
"deleteTiles": "Видалити плитки",
"moveTilesToLayer": "Перемістити до іншого шару",
"shiftTiles": "Змістити плитки",
- "changeCopyRotation": "Повернути"
+ "changeCopyRotation": "Повернути",
+ "simulate": "",
+ "toggleDiagonalGrid": "",
+ "changeGridSize": "",
+ "xrayMode": "",
+ "colorizeTileLayers": "",
+ "tools": {
+ "select": "",
+ "addCopies": "",
+ "addTiles": "",
+ "manageBackgrounds": "",
+ "roomProperties": ""
+ }
},
"styleView": {
"active": "Активно?",
@@ -875,7 +919,8 @@
"multiply": "Помножити (затемнення)",
"screen": "Екран (освітлення)"
},
- "loopAnimation": "Циклічна анімація"
+ "loopAnimation": "Циклічна анімація",
+ "animationFPS": ""
},
"assetInput": {
"changeAsset": "Натисніть, щоб замінити ассет",
@@ -883,7 +928,7 @@
"selectAssetHeader": "Вибрати асет"
},
"builtinAssetGallery": {
- "galleryTip": "Це вбудована галерея різних безкоштовних текстур і звуків. Вони всі під ліцензією CCO, WTFPL, або на спец. правах для движка ct.js, і ти можеш використовувати їх як завгодно, в комерційних проектах і не тільки." ,
+ "galleryTip": "Це вбудована галерея різних безкоштовних текстур і звуків. Вони всі під ліцензією CCO, WTFPL, або на спец. правах для движка ct.js, і ти можеш використовувати їх як завгодно, в комерційних проектах і не тільки.",
"assetGalleryHeader": "Асети",
"importIntoProject": "Вставити в проект",
"importAll": "Імпортувати все",
@@ -909,7 +954,8 @@
"actions": "Дії",
"pointer": "Події покажчика",
"misc": "Різне",
- "animation": "Анімація"
+ "animation": "Анімація",
+ "timers": ""
},
"coreEvents": {
"OnCreate": "Створення",
@@ -931,7 +977,8 @@
"OnActionDown": "Дія натиснута",
"OnFrameChange": "Зміна кадру",
"OnAnimationLoop": "Перепуск анімації",
- "OnAnimationComplete": "Кінець анімації"
+ "OnAnimationComplete": "Кінець анімації",
+ "Timer": ""
},
"coreParameterizedNames": {
"OnActionPress": "При натисканні %%action%%",
@@ -942,7 +989,8 @@
"action": "Дія"
},
"coreEventsLocals": {
- "OnActionDown_value": "Поточне значення дії"
+ "OnActionDown_value": "Поточне значення дії",
+ "OnActionPress_value": ""
},
"coreEventsDescriptions": {
"OnCreate": "Спрацьовує під час створення копії.",
@@ -955,7 +1003,8 @@
"OnActionRelease": "Спрацьовує, коли дія перестає бути активною - коли відпускають клавіші, джойстики і т.п.",
"OnActionDown": "Спрацьовує кожен кадр, доки методи введення цієї дії активні.",
"OnAnimationLoop": "Спрацьовує щоразу, коли циклічна анімація добігає кінця.",
- "OnAnimationComplete": "Спрацьовує один раз, коли нециклічна анімація закінчується."
+ "OnAnimationComplete": "Спрацьовує один раз, коли нециклічна анімація закінчується.",
+ "Timer": ""
}
}
-}
+}
\ No newline at end of file
diff --git a/app/package-lock.json b/app/package-lock.json
index 1d68db617..c7973a8be 100644
--- a/app/package-lock.json
+++ b/app/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "ctjs",
- "version": "2.0.2",
+ "version": "2.1.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "ctjs",
- "version": "2.0.2",
+ "version": "2.1.0",
"license": "MIT",
"dependencies": {
"@capacitor/cli": "^3.4.0",
@@ -34,6 +34,7 @@
"nanoid": "^3.1.31",
"npm": "^8.11.0",
"opentype.js": "^1.3.3",
+ "pixi-ease": "^3.0.7",
"pixi-particles": "4.3.1",
"pixi.js": "5.3.11",
"pixi.js-legacy": "5.3.11",
@@ -8071,6 +8072,11 @@
"resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
"integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA="
},
+ "node_modules/penner": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/penner/-/penner-0.1.3.tgz",
+ "integrity": "sha512-UzkaC2L6d9J1VzJAFH0TQwuKE/rerpTZkgW6aPLVeu/LdjWn6rnuY9lXcVN1AE9tZVfHrsJ2gZOBsRjpQECNHA=="
+ },
"node_modules/picomatch": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
@@ -8090,6 +8096,23 @@
"node": ">=4"
}
},
+ "node_modules/pixi-ease": {
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/pixi-ease/-/pixi-ease-3.0.7.tgz",
+ "integrity": "sha512-ew1IzAi2layygHrk8+tk6XTuue3WM6Po5LsA46v+9BtQNMa2sX0PMLzQ4nq1UpTbLg4Dwqep9RTzDRsFhCYJJw==",
+ "dependencies": {
+ "eventemitter3": "^4.0.0",
+ "penner": "^0.1.3"
+ },
+ "peerDependencies": {
+ "pixi.js": ">=4.6.0"
+ }
+ },
+ "node_modules/pixi-ease/node_modules/eventemitter3": {
+ "version": "4.0.7",
+ "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
+ "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw=="
+ },
"node_modules/pixi-particles": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/pixi-particles/-/pixi-particles-4.3.1.tgz",
@@ -8802,6 +8825,21 @@
"integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==",
"optional": true
},
+ "node_modules/rollup": {
+ "version": "2.76.0",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.76.0.tgz",
+ "integrity": "sha512-9jwRIEY1jOzKLj3nsY/yot41r19ITdQrhs+q3ggNWhr9TQgduHqANvPpS32RNpzGklJu3G1AJfvlZLi/6wFgWA==",
+ "peer": true,
+ "bin": {
+ "rollup": "dist/bin/rollup"
+ },
+ "engines": {
+ "node": ">=10.0.0"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.2"
+ }
+ },
"node_modules/rsvp": {
"version": "3.6.2",
"resolved": "https://registry.npmjs.org/rsvp/-/rsvp-3.6.2.tgz",
@@ -9634,6 +9672,19 @@
"is-typedarray": "^1.0.0"
}
},
+ "node_modules/typescript": {
+ "version": "4.7.4",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz",
+ "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==",
+ "peer": true,
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=4.2.0"
+ }
+ },
"node_modules/uc.micro": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz",
@@ -16226,6 +16277,11 @@
"resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
"integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA="
},
+ "penner": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/penner/-/penner-0.1.3.tgz",
+ "integrity": "sha512-UzkaC2L6d9J1VzJAFH0TQwuKE/rerpTZkgW6aPLVeu/LdjWn6rnuY9lXcVN1AE9tZVfHrsJ2gZOBsRjpQECNHA=="
+ },
"picomatch": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
@@ -16236,6 +16292,22 @@
"resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
"integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY="
},
+ "pixi-ease": {
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/pixi-ease/-/pixi-ease-3.0.7.tgz",
+ "integrity": "sha512-ew1IzAi2layygHrk8+tk6XTuue3WM6Po5LsA46v+9BtQNMa2sX0PMLzQ4nq1UpTbLg4Dwqep9RTzDRsFhCYJJw==",
+ "requires": {
+ "eventemitter3": "^4.0.0",
+ "penner": "^0.1.3"
+ },
+ "dependencies": {
+ "eventemitter3": {
+ "version": "4.0.7",
+ "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
+ "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw=="
+ }
+ }
+ },
"pixi-particles": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/pixi-particles/-/pixi-particles-4.3.1.tgz",
@@ -16776,6 +16848,15 @@
}
}
},
+ "rollup": {
+ "version": "2.76.0",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.76.0.tgz",
+ "integrity": "sha512-9jwRIEY1jOzKLj3nsY/yot41r19ITdQrhs+q3ggNWhr9TQgduHqANvPpS32RNpzGklJu3G1AJfvlZLi/6wFgWA==",
+ "peer": true,
+ "requires": {
+ "fsevents": "~2.3.2"
+ }
+ },
"rsvp": {
"version": "3.6.2",
"resolved": "https://registry.npmjs.org/rsvp/-/rsvp-3.6.2.tgz",
@@ -17411,6 +17492,12 @@
"is-typedarray": "^1.0.0"
}
},
+ "typescript": {
+ "version": "4.7.4",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz",
+ "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==",
+ "peer": true
+ },
"uc.micro": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz",
diff --git a/app/package.json b/app/package.json
index 4c8ff0c01..4f0f4db12 100644
--- a/app/package.json
+++ b/app/package.json
@@ -2,7 +2,7 @@
"main": "index.html",
"name": "ctjs",
"description": "ct.js — a free 2D game engine",
- "version": "2.0.2",
+ "version": "2.2.0",
"homepage": "https://ctjs.rocks/",
"author": {
"name": "Cosmo Myzrail Gorynych",
@@ -78,6 +78,7 @@
"nanoid": "^3.1.31",
"npm": "^8.11.0",
"opentype.js": "^1.3.3",
+ "pixi-ease": "^3.0.7",
"pixi-particles": "4.3.1",
"pixi.js": "5.3.11",
"pixi.js-legacy": "5.3.11",
diff --git a/gulpfile.js b/gulpfile.js
index 5f8b05fc7..ac881aa2f 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -253,7 +253,6 @@ const watchRequires = () => {
.on('change', fileChangeNotifier)
.on('error', err => {
notifier.notify(makeErrorObj('Failure of node_requires', err));
- console.error('[node_requires error]', err);
});
};
const watchIcons = () => {
diff --git a/package-lock.json b/package-lock.json
index 87dfd7d30..69791099d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "ctjsbuildenvironment",
- "version": "2.0.2",
+ "version": "2.1.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "ctjsbuildenvironment",
- "version": "2.0.2",
+ "version": "2.1.0",
"license": "MIT",
"dependencies": {
"@ct.js/gulp-typescript": "^6.0.0",
diff --git a/package.json b/package.json
index f94bda427..f8c49215d 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "ctjsbuildenvironment",
- "version": "2.0.2",
+ "version": "2.2.0",
"description": "",
"directories": {
"doc": "docs"
diff --git a/src/examples/DungeonCrawler_tutorial.ict b/src/examples/DungeonCrawler_tutorial.ict
index a405ee2cb..156dd055a 100644
--- a/src/examples/DungeonCrawler_tutorial.ict
+++ b/src/examples/DungeonCrawler_tutorial.ict
@@ -1,4 +1,4 @@
-ctjsVersion: 2.0.2
+ctjsVersion: 2.2.0
notes: /* empty */
libs:
fittoscreen:
@@ -453,7 +453,7 @@ textures:
height: 16
offx: 0
offy: 0
- origname: 'i14d3f53f-a868-4820-84cd-63234ab6e6b9.png}'
+ origname: i14d3f53f-a868-4820-84cd-63234ab6e6b9.png
shape: rect
left: 0
right: 16
@@ -478,7 +478,7 @@ textures:
height: 32
offx: 0
offy: 0
- origname: 'ia42e0dff-69c9-46c3-8996-745aaa769698.png}'
+ origname: ia42e0dff-69c9-46c3-8996-745aaa769698.png
shape: rect
left: 16
right: 16
@@ -729,7 +729,7 @@ templates:
extends:
cgroup: ''
uid: c40336ea-2846-45d5-97ba-d51852d3f6c5
- lastmod: 1656663050756
+ lastmod: 1659098686679
events:
- lib: core
arguments: {}
@@ -738,7 +738,6 @@ templates:
ct.camera.shiftY = -16;
this.maxSpeed = 2;
- this.animationSpeed = 5 / ct.speed;
this.invincibleTimer = 0;
eventKey: OnCreate
- lib: core
@@ -818,6 +817,7 @@ templates:
type: template
loopAnimation: true
playAnimationOnStart: true
+ animationFPS: 5
- name: Crate
depth: 0
texture: 31948760-8965-4768-ab1d-2b87d0b7fc3a
@@ -1271,917 +1271,1193 @@ rooms:
'y': 64
uid: 7fea051e-83e5-4e54-848b-ab3ca861e5cb
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 152
'y': 192
uid: 4e473462-8009-438e-9f53-1032e3a335cf
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 160
'y': 208
uid: 4e473462-8009-438e-9f53-1032e3a335cf
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 168
'y': 192
uid: 4e473462-8009-438e-9f53-1032e3a335cf
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 280
'y': 192
uid: 3b6057ca-f175-4449-ac24-1c5630e0af7c
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 280
'y': 64
uid: 3b6057ca-f175-4449-ac24-1c5630e0af7c
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 96
'y': 88
uid: c40336ea-2846-45d5-97ba-d51852d3f6c5
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 96
'y': 160
uid: c701a029-af09-4fcf-9712-0fcdaa3581be
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
tiles:
- depth: -6000
tiles:
- x: 48
'y': 32
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 48
'y': 48
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 48
'y': 64
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 48
'y': 80
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 48
'y': 96
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 64
'y': 32
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 80
'y': 32
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 96
'y': 32
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 112
'y': 32
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 128
'y': 32
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 128
'y': 48
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 128
'y': 64
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 128
'y': 80
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 128
'y': 96
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 64
'y': 96
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 112
'y': 96
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 112
'y': 112
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 112
'y': 128
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 112
'y': 144
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 128
'y': 144
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 144
'y': 144
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 160
'y': 144
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 176
'y': 144
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 192
'y': 144
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 208
'y': 144
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 272
'y': 144
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 272
'y': 128
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 272
'y': 112
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 272
'y': 96
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 288
'y': 144
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 288
'y': 160
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 288
'y': 176
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 288
'y': 192
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 288
'y': 208
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 272
'y': 208
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 256
'y': 208
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 240
'y': 208
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 224
'y': 208
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 208
'y': 208
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 192
'y': 208
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 176
'y': 208
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 160
'y': 208
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 144
'y': 208
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 128
'y': 208
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 112
'y': 208
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 96
'y': 208
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 80
'y': 208
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 64
'y': 208
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 64
'y': 112
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 64
'y': 128
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 64
'y': 144
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 64
'y': 160
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 64
'y': 176
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 64
'y': 192
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 208
'y': 128
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 208
'y': 112
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 208
'y': 96
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 192
'y': 96
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 192
'y': 80
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 192
'y': 64
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 192
'y': 48
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 192
'y': 32
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 192
'y': 16
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 208
'y': 16
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 240
'y': 16
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 256
'y': 16
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 272
'y': 16
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 288
'y': 16
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 288
'y': 32
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 288
'y': 48
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 288
'y': 64
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 288
'y': 80
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 288
'y': 96
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 208
'y': 32
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 240
'y': 32
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 256
'y': 32
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 272
'y': 32
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 64
'y': 48
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 80
'y': 48
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 96
'y': 48
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 112
'y': 48
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 128
'y': 112
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 192
'y': 112
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 112
'y': 160
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 144
'y': 160
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 176
'y': 160
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 208
'y': 160
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 64
'y': 224
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 80
'y': 224
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 96
'y': 224
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 112
'y': 224
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 128
'y': 224
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 144
'y': 224
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 160
'y': 224
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 176
'y': 224
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 192
'y': 224
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 208
'y': 224
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 224
'y': 224
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 240
'y': 224
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 256
'y': 224
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 272
'y': 224
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 288
'y': 224
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 288
'y': 112
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 48
'y': 112
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 224
'y': 32
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 12
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 4
- - 1
- - 1
- - 1
- x: 224
'y': 16
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 1
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 0
- - 1
- - 1
- x: 128
'y': 160
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 9
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 1
- - 1
- - 1
- x: 192
'y': 160
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 9
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 1
- - 1
- - 1
- x: 160
'y': 160
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 9
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 1
- - 1
- - 1
- x: 272
'y': 160
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 10
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 2
- - 1
- - 1
- - 1
extends:
cgroup: Solid
hidden: false
@@ -2189,764 +2465,954 @@ rooms:
tiles:
- x: 64
'y': 64
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 80
'y': 64
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 96
'y': 64
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 112
'y': 64
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 64
'y': 80
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 80
'y': 80
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 96
'y': 80
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 112
'y': 80
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 80
'y': 96
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 80
'y': 112
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 80
'y': 128
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 80
'y': 144
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 80
'y': 160
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 80
'y': 176
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 80
'y': 192
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 96
'y': 176
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 112
'y': 176
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 128
'y': 176
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 224
'y': 176
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 256
'y': 176
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 272
'y': 176
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 272
'y': 192
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 256
'y': 192
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 240
'y': 192
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 128
'y': 192
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 96
'y': 192
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 96
'y': 96
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 96
'y': 128
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 96
'y': 144
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 208
'y': 48
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 208
'y': 64
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 224
'y': 80
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 256
'y': 80
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 272
'y': 80
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 272
'y': 64
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 272
'y': 48
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 240
'y': 48
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 224
'y': 96
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 224
'y': 112
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 224
'y': 160
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 240
'y': 112
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 256
'y': 96
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 256
'y': 112
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 256
'y': 160
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 128
'y': 128
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 19
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 3
- - 2
- - 1
- - 1
- x: 192
'y': 128
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 19
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 3
- - 2
- - 1
- - 1
- x: 288
'y': 128
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 19
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 3
- - 2
- - 1
- - 1
- x: 48
'y': 128
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 19
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 3
- - 2
- - 1
- - 1
- x: 32
'y': 176
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 26
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 2
- - 3
- - 1
- - 1
- x: 112
'y': 192
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 24
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 3
- - 1
- - 1
- x: 240
'y': 96
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 24
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 3
- - 1
- - 1
- x: 96
'y': 112
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 24
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 3
- - 1
- - 1
- x: 240
'y': 64
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 16
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 2
- - 1
- - 1
- x: 224
'y': 48
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 16
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 2
- - 1
- - 1
- x: 256
'y': 48
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 16
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 2
- - 1
- - 1
- x: 224
'y': 144
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 240
'y': 144
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 256
'y': 144
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 144
'y': 192
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 6
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 6
- - 0
- - 1
- - 1
- x: 144
'y': 176
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 6
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 6
- - 0
- - 1
- - 1
- x: 160
'y': 176
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 6
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 6
- - 0
- - 1
- - 1
- x: 160
'y': 192
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 6
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 6
- - 0
- - 1
- - 1
- x: 192
'y': 176
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 25
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 3
- - 1
- - 1
- x: 96
'y': 160
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 25
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 3
- - 1
- - 1
- x: 240
'y': 160
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 25
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 3
- - 1
- - 1
- x: 208
'y': 80
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 25
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 3
- - 1
- - 1
- x: 208
'y': 176
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 208
'y': 192
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 224
'y': 192
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 192
'y': 192
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 176
'y': 192
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 176
'y': 176
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 224
'y': 128
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 22
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 6
- - 2
- - 1
- - 1
- x: 240
'y': 128
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 22
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 6
- - 2
- - 1
- - 1
- x: 256
'y': 128
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 22
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 6
- - 2
- - 1
- - 1
- x: 240
'y': 80
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 15
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 7
- - 1
- - 1
- - 1
- x: 240
'y': 176
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 15
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 7
- - 1
- - 1
- - 1
- x: 64
'y': 240
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 19
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 3
- - 2
- - 1
- - 1
- x: 80
'y': 240
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 19
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 3
- - 2
- - 1
- - 1
- x: 96
'y': 240
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 19
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 3
- - 2
- - 1
- - 1
- x: 112
'y': 240
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 19
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 3
- - 2
- - 1
- - 1
- x: 128
'y': 240
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 19
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 3
- - 2
- - 1
- - 1
- x: 144
'y': 240
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 19
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 3
- - 2
- - 1
- - 1
- x: 160
'y': 240
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 19
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 3
- - 2
- - 1
- - 1
- x: 176
'y': 240
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 19
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 3
- - 2
- - 1
- - 1
- x: 192
'y': 240
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 19
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 3
- - 2
- - 1
- - 1
- x: 208
'y': 240
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 19
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 3
- - 2
- - 1
- - 1
- x: 224
'y': 240
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 19
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 3
- - 2
- - 1
- - 1
- x: 240
'y': 240
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 19
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 3
- - 2
- - 1
- - 1
- x: 256
'y': 240
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 19
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 3
- - 2
- - 1
- - 1
- x: 272
'y': 240
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 19
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 3
- - 2
- - 1
- - 1
- x: 288
'y': 240
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 19
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 3
- - 2
- - 1
- - 1
- - x: 80
- 'y': 144
+ - x: 96
+ 'y': 160
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: ae954867-1039-43f6-bf6d-d8684cb58612
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 224
'y': 64
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 256
'y': 64
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 25
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 3
- - 1
- - 1
extends:
cgroup: Decor
hidden: false
@@ -2977,6 +3443,8 @@ rooms:
});
eventKey: OnRoomStart
type: room
+ simulate: true
+ isUi: ! ''
- name: Level_02
onstep: ''
ondraw: ''
@@ -2989,1752 +3457,2424 @@ rooms:
'y': 144
uid: c701a029-af09-4fcf-9712-0fcdaa3581be
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 106
'y': 238
uid: 4e473462-8009-438e-9f53-1032e3a335cf
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 359
'y': 239
uid: 3b6057ca-f175-4449-ac24-1c5630e0af7c
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 136
'y': 61
uid: 3b6057ca-f175-4449-ac24-1c5630e0af7c
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 111
'y': 79
uid: c40336ea-2846-45d5-97ba-d51852d3f6c5
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 124
'y': 233
uid: 9fc1fec8-50bb-49e6-8fb4-c10ad589bf0b
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 112
'y': 220
uid: 9fc1fec8-50bb-49e6-8fb4-c10ad589bf0b
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 255
'y': 232
uid: 5e40076f-8a61-4dfd-a517-a6c943ab9991
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 568
'y': 16
uid: 7fea051e-83e5-4e54-848b-ab3ca861e5cb
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 458
'y': 41
uid: 3b6057ca-f175-4449-ac24-1c5630e0af7c
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 451
'y': 47
uid: 3b6057ca-f175-4449-ac24-1c5630e0af7c
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 459
'y': 51
uid: 3b6057ca-f175-4449-ac24-1c5630e0af7c
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 279
'y': 41
uid: 3b6057ca-f175-4449-ac24-1c5630e0af7c
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 387
'y': 58
uid: 3b6057ca-f175-4449-ac24-1c5630e0af7c
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 323
'y': 90
uid: 3b6057ca-f175-4449-ac24-1c5630e0af7c
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 373
'y': 99
uid: 5e40076f-8a61-4dfd-a517-a6c943ab9991
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 447
'y': 68
uid: 5e40076f-8a61-4dfd-a517-a6c943ab9991
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 317
'y': 55
uid: 5e40076f-8a61-4dfd-a517-a6c943ab9991
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 432
'y': 80
uid: 173dfb94-5133-4bbc-9e7d-6ed8c9fef330
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 352
'y': 112
uid: 173dfb94-5133-4bbc-9e7d-6ed8c9fef330
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 368
'y': 48
uid: 173dfb94-5133-4bbc-9e7d-6ed8c9fef330
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 568
'y': 80
uid: 173dfb94-5133-4bbc-9e7d-6ed8c9fef330
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 334
'y': 230
uid: 173dfb94-5133-4bbc-9e7d-6ed8c9fef330
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 224
'y': 184
uid: 0bc3c56b-3bf9-4912-9e3f-c27654c1b910
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 240
'y': 184
uid: 0bc3c56b-3bf9-4912-9e3f-c27654c1b910
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 256
'y': 184
uid: 0bc3c56b-3bf9-4912-9e3f-c27654c1b910
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 272
'y': 184
uid: 0bc3c56b-3bf9-4912-9e3f-c27654c1b910
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 224
'y': 248
uid: 0bc3c56b-3bf9-4912-9e3f-c27654c1b910
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 240
'y': 248
uid: 0bc3c56b-3bf9-4912-9e3f-c27654c1b910
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 256
'y': 248
uid: 0bc3c56b-3bf9-4912-9e3f-c27654c1b910
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 272
'y': 248
uid: 0bc3c56b-3bf9-4912-9e3f-c27654c1b910
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 280
'y': 56
uid: 0bc3c56b-3bf9-4912-9e3f-c27654c1b910
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 280
'y': 72
uid: 0bc3c56b-3bf9-4912-9e3f-c27654c1b910
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 408
'y': 104
uid: 0bc3c56b-3bf9-4912-9e3f-c27654c1b910
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 424
'y': 104
uid: 0bc3c56b-3bf9-4912-9e3f-c27654c1b910
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 440
'y': 104
uid: 0bc3c56b-3bf9-4912-9e3f-c27654c1b910
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 160
'y': 224
uid: 469b9eef-6117-43a5-87d3-7151da7eba06
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 352
'y': 96
uid: 469b9eef-6117-43a5-87d3-7151da7eba06
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 352
'y': 208
uid: b336d91c-2876-4686-b8b4-901045a86ac7
+ exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
tiles:
- depth: -6000
tiles:
- x: 64
'y': 32
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 48
'y': 32
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 48
'y': 48
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 48
'y': 64
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 48
'y': 80
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 48
'y': 96
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 64
'y': 96
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 80
'y': 112
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 128
'y': 112
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 144
'y': 96
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 160
'y': 96
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 160
'y': 80
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 160
'y': 64
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 160
'y': 48
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 160
'y': 32
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 144
'y': 32
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 128
'y': 16
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 112
'y': 16
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 96
'y': 16
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 80
'y': 16
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 80
'y': 128
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 80
'y': 144
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 80
'y': 160
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 80
'y': 176
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 128
'y': 128
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 128
'y': 144
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 128
'y': 160
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 128
'y': 176
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 80
'y': 192
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 80
'y': 208
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 176
'y': 176
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 160
'y': 176
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 144
'y': 176
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 304
'y': 176
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 320
'y': 176
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 80
'y': 240
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 96
'y': 240
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 112
'y': 240
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 128
'y': 240
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 144
'y': 240
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 160
'y': 240
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 176
'y': 240
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 192
'y': 240
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 80
'y': 224
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 304
'y': 240
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 320
'y': 240
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 368
'y': 240
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 352
'y': 240
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 336
'y': 240
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 368
'y': 224
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 368
'y': 208
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 368
'y': 192
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 368
'y': 176
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 368
'y': 160
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 368
'y': 144
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 320
'y': 160
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 320
'y': 144
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 320
'y': 128
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 368
'y': 128
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 320
'y': 192
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 13
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 5
- - 1
- - 1
- - 1
- x: 304
'y': 112
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 288
'y': 112
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 272
'y': 112
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 256
'y': 112
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 256
'y': 96
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 256
'y': 80
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 256
'y': 32
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 256
'y': 16
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 256
'y': 48
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 256
'y': 64
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 256
'y': 0
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 272
'y': 0
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 288
'y': 0
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 304
'y': 0
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 320
'y': 0
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 336
'y': 0
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 352
'y': 0
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 368
'y': 0
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 448
- 'y': -0.0
+ 'y': 0
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 384
'y': 112
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 400
'y': 112
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 416
'y': 112
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 432
'y': 112
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 448
'y': 112
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 464
'y': 112
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 464
'y': 0
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 464
'y': 16
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 464
'y': 96
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 480
'y': 32
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 496
'y': 32
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 512
'y': 32
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 528
'y': 32
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 544
'y': 32
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 480
'y': 80
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 496
'y': 80
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 512
'y': 80
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 528
'y': 80
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 544
'y': 80
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 560
'y': 80
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 576
'y': 80
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 576
'y': 64
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 576
'y': 48
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 576
'y': 32
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 576
'y': 16
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 576
'y': 0
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 544
'y': 0
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 544
'y': 16
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 544
'y': -16
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 544
'y': -32
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 544
'y': -32
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 576
'y': -32
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 560
'y': -32
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 576
'y': -16
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 480
'y': 48
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 10
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 2
- - 1
- - 1
- - 1
- x: 528
'y': 48
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 10
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 2
- - 1
- - 1
- - 1
- x: 544
'y': 48
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 12
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 4
- - 1
- - 1
- - 1
- x: 432
'y': 0
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 416
'y': 0
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 400
- 'y': -0.0
+ 'y': 0
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 384
- 'y': -0.0
+ 'y': 0
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 416
'y': 16
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 13
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 5
- - 1
- - 1
- - 1
- x: 128
'y': 192
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 144
'y': 192
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 160
'y': 192
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 208
'y': 192
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 64
'y': 48
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 144
'y': 48
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 80
'y': 32
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 96
'y': 32
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 112
'y': 32
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 128
'y': 32
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 144
'y': 128
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 160
'y': 112
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 64
'y': 128
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 48
'y': 112
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 288
'y': 192
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 304
'y': 192
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 368
'y': 256
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 352
'y': 256
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 336
'y': 256
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 320
'y': 256
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 288
'y': 256
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 192
'y': 256
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 176
'y': 256
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 160
'y': 256
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 144
'y': 256
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 128
'y': 256
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 112
'y': 256
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 96
'y': 256
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 80
'y': 256
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 464
'y': 128
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 448
'y': 128
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 432
'y': 128
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 384
'y': 128
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 272
'y': 16
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 288
'y': 16
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 320
'y': 16
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 336
'y': 16
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 352
'y': 16
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 368
'y': 16
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 384
'y': 16
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 400
'y': 16
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 432
'y': 16
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 448
'y': 16
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 496
'y': 48
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 512
'y': 48
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 464
'y': 48
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 560
'y': -16
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 576
'y': 96
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 560
'y': 96
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 544
'y': 96
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 528
'y': 96
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 512
'y': 96
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 496
'y': 96
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 480
'y': 96
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 256
'y': 128
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 272
'y': 128
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 304
'y': 128
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 176
'y': 192
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 14
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 6
- - 1
- - 1
- - 1
- x: 304
'y': 256
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 14
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 6
- - 1
- - 1
- - 1
- x: 208
'y': 256
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 14
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 6
- - 1
- - 1
- - 1
- x: 192
'y': 176
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 3
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 3
- - 0
- - 1
- - 1
- x: 64
'y': 112
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 1
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 0
- - 1
- - 1
- x: 144
'y': 112
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 1
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 0
- - 1
- - 1
- x: 144
'y': 16
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 1
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 0
- - 1
- - 1
- x: 64
'y': 16
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 1
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 0
- - 1
- - 1
- x: 208
'y': 176
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 1
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 0
- - 1
- - 1
- x: 288
'y': 176
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 1
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 0
- - 1
- - 1
- x: 208
'y': 240
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 1
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 0
- - 1
- - 1
- x: 288
'y': 240
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 1
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 0
- - 1
- - 1
- x: 192
'y': 192
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 11
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 3
- - 1
- - 1
- - 1
- x: 464
'y': 80
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 1
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 0
- - 1
- - 1
- x: 464
'y': 32
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 1
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 0
- - 1
- - 1
- x: 320
'y': 112
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 2
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 2
- - 0
- - 1
- - 1
- x: 368
'y': 112
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 2
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 2
- - 0
- - 1
- - 1
- x: 304
'y': 16
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 13
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 5
- - 1
- - 1
- - 1
- x: 288
'y': 128
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 13
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 5
- - 1
- - 1
- - 1
- x: 400
'y': 128
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 13
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 5
- - 1
- - 1
- - 1
- x: 416
'y': 128
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 14
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 6
- - 1
- - 1
- - 1
extends:
cgroup: Solid
hidden: false
@@ -4742,1596 +5882,1994 @@ rooms:
tiles:
- x: 96
'y': 208
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 112
'y': 208
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 128
'y': 208
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 144
'y': 208
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 160
'y': 208
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 176
'y': 208
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 320
'y': 208
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 336
'y': 208
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 352
'y': 208
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 96
'y': 224
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 112
'y': 224
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 128
'y': 224
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 144
'y': 224
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 176
'y': 224
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 320
'y': 224
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 336
'y': 224
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 352
'y': 224
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 192
'y': 208
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 25
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 3
- - 1
- - 1
- x: 192
'y': 224
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 24
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 3
- - 1
- - 1
- x: 304
'y': 208
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 96
'y': 80
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 25
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 3
- - 1
- - 1
- x: 112
'y': 144
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 25
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 3
- - 1
- - 1
- x: 96
'y': 176
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 25
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 3
- - 1
- - 1
- x: 80
'y': 48
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 80
'y': 64
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 80
'y': 80
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 80
'y': 96
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 64
'y': 64
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 64
'y': 80
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 96
'y': 48
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 112
'y': 48
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 128
'y': 48
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 96
'y': 64
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 112
'y': 64
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 128
'y': 64
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 144
'y': 64
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 144
'y': 80
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 128
'y': 80
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 112
'y': 80
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 128
'y': 96
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 112
'y': 96
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 96
'y': 96
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 96
'y': 112
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 96
'y': 128
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 96
'y': 144
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 96
'y': 160
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 112
'y': 112
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 112
'y': 128
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 112
'y': 160
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 112
'y': 176
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 112
'y': 192
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 96
'y': 192
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 336
'y': 144
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 16
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 2
- - 1
- - 1
- x: 352
'y': 144
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 16
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 2
- - 1
- - 1
- x: 336
'y': 128
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 352
'y': 128
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 336
'y': 112
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 352
'y': 112
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 176
'y': 144
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 26
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 2
- - 3
- - 1
- - 1
- x: 224
'y': 64
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 26
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 2
- - 3
- - 1
- - 1
- x: 16
'y': 112
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 26
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 2
- - 3
- - 1
- - 1
- x: 48
'y': 192
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 26
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 2
- - 3
- - 1
- - 1
- x: 240
'y': 272
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 26
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 2
- - 3
- - 1
- - 1
- x: 400
'y': 208
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 26
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 2
- - 3
- - 1
- - 1
- x: 512
'y': 128
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 26
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 2
- - 3
- - 1
- - 1
- x: 496
'y': 0
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 26
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 2
- - 3
- - 1
- - 1
- x: 272
'y': 32
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 288
'y': 32
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 304
'y': 32
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 336
'y': 32
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 352
'y': 32
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 368
'y': 32
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 384
'y': 32
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 400
'y': 32
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 416
'y': 32
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 432
'y': 32
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 448
'y': 32
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 304
'y': 48
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 352
'y': 48
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 368
'y': 48
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 416
'y': 48
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 448
'y': 48
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 304
'y': 64
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 400
'y': 64
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 416
'y': 64
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 464
'y': 64
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 480
'y': 64
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 496
'y': 64
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 512
'y': 64
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 528
'y': 64
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 544
'y': 64
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 560
'y': 64
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 560
'y': 0
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 448
'y': 80
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 432
'y': 80
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 416
'y': 80
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 400
'y': 80
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 384
'y': 80
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 368
'y': 80
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 352
'y': 80
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 320
'y': 80
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 304
'y': 80
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 272
'y': 96
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 288
'y': 96
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 304
'y': 96
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 320
'y': 96
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 336
'y': 96
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 352
'y': 96
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 368
'y': 96
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 384
'y': 96
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 336
'y': 64
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 24
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 3
- - 1
- - 1
- x: 448
'y': 64
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 24
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 3
- - 1
- - 1
- x: 432
'y': 48
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 25
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 3
- - 1
- - 1
- x: 384
'y': 64
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 25
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 3
- - 1
- - 1
- x: 400
'y': 48
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 25
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 3
- - 1
- - 1
- x: 336
'y': 80
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 25
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 3
- - 1
- - 1
- x: 320
'y': 64
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 25
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 3
- - 1
- - 1
- x: 384
'y': 48
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 25
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 3
- - 1
- - 1
- x: 432
'y': 64
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 25
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 3
- - 1
- - 1
- x: 320
'y': 48
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 25
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 3
- - 1
- - 1
- x: 336
'y': 48
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 320
'y': 32
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 25
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 3
- - 1
- - 1
- x: 368
'y': 64
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 25
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 3
- - 1
- - 1
- x: 336
'y': 176
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 16
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 2
- - 1
- - 1
- x: 352
'y': 176
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 16
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 2
- - 1
- - 1
- x: 272
'y': 208
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 24
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 3
- - 1
- - 1
- x: 272
'y': 224
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 25
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 3
- - 1
- - 1
- x: 224
'y': 224
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 25
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 3
- - 1
- - 1
- x: 304
'y': 224
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 208
'y': 208
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 5
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 5
- - 0
- - 1
- - 1
- x: 208
'y': 224
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 5
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 5
- - 0
- - 1
- - 1
- x: 288
'y': 208
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 5
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 5
- - 0
- - 1
- - 1
- x: 288
'y': 224
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 5
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 5
- - 0
- - 1
- - 1
- x: 336
'y': 160
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 22
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 6
- - 2
- - 1
- - 1
- x: 352
'y': 160
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 22
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 6
- - 2
- - 1
- - 1
- x: 352
'y': 192
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 22
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 6
- - 2
- - 1
- - 1
- x: 336
'y': 192
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 22
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 6
- - 2
- - 1
- - 1
- x: 560
'y': 48
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 22
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 6
- - 2
- - 1
- - 1
- x: 560
'y': 16
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 22
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 6
- - 2
- - 1
- - 1
- x: 240
'y': 208
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 30
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 6
- - 3
- - 1
- - 1
- x: 256
'y': 208
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 224
'y': 208
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 256
'y': 224
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 24
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 3
- - 1
- - 1
- x: 240
'y': 224
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 80
'y': 272
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 19
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 3
- - 2
- - 1
- - 1
- x: 96
'y': 272
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 19
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 3
- - 2
- - 1
- - 1
- x: 112
'y': 272
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 19
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 3
- - 2
- - 1
- - 1
- x: 128
'y': 272
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 19
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 3
- - 2
- - 1
- - 1
- x: 144
'y': 272
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 19
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 3
- - 2
- - 1
- - 1
- x: 160
'y': 272
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 19
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 3
- - 2
- - 1
- - 1
- x: 176
'y': 272
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 19
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 3
- - 2
- - 1
- - 1
- x: 192
'y': 272
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 19
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 3
- - 2
- - 1
- - 1
- x: 208
'y': 272
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 19
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 3
- - 2
- - 1
- - 1
- x: 64
'y': 144
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 19
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 3
- - 2
- - 1
- - 1
- x: 48
'y': 128
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 19
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 3
- - 2
- - 1
- - 1
- x: 160
'y': 128
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 19
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 3
- - 2
- - 1
- - 1
- x: 144
'y': 144
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 19
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 3
- - 2
- - 1
- - 1
- x: 304
'y': 144
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 19
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 3
- - 2
- - 1
- - 1
- x: 288
'y': 144
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 19
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 3
- - 2
- - 1
- - 1
- x: 272
'y': 144
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 19
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 3
- - 2
- - 1
- - 1
- x: 256
'y': 144
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 19
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 3
- - 2
- - 1
- - 1
- x: 288
'y': 272
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 19
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 3
- - 2
- - 1
- - 1
- x: 304
'y': 272
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 19
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 3
- - 2
- - 1
- - 1
- x: 320
'y': 272
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 19
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 3
- - 2
- - 1
- - 1
- x: 336
'y': 272
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 19
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 3
- - 2
- - 1
- - 1
- x: 352
'y': 272
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 19
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 3
- - 2
- - 1
- - 1
- x: 368
'y': 272
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 19
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 3
- - 2
- - 1
- - 1
- x: 384
'y': 144
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 19
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 3
- - 2
- - 1
- - 1
- x: 400
'y': 144
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 19
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 3
- - 2
- - 1
- - 1
- x: 416
'y': 144
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 19
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 3
- - 2
- - 1
- - 1
- x: 432
'y': 144
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 19
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 3
- - 2
- - 1
- - 1
- x: 448
'y': 144
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 19
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 3
- - 2
- - 1
- - 1
- x: 464
'y': 144
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 19
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 3
- - 2
- - 1
- - 1
- x: 480
'y': 112
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 19
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 3
- - 2
- - 1
- - 1
- x: 496
'y': 112
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 19
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 3
- - 2
- - 1
- - 1
- x: 512
'y': 112
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 19
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 3
- - 2
- - 1
- - 1
- x: 528
'y': 112
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 19
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 3
- - 2
- - 1
- - 1
- x: 544
'y': 112
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 19
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 3
- - 2
- - 1
- - 1
- x: 560
'y': 112
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 19
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 3
- - 2
- - 1
- - 1
- x: 576
'y': 112
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 19
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 3
- - 2
- - 1
- - 1
- x: 160
'y': 224
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 7
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 7
- - 0
- - 1
- - 1
- x: 560
'y': 32
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 15
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 7
- - 1
- - 1
- - 1
- x: 352
'y': 64
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 7
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 7
- - 0
- - 1
- - 1
- x: 224
'y': 240
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 18
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 2
- - 2
- - 1
- - 1
- x: 240
'y': 240
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 18
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 2
- - 2
- - 1
- - 1
- x: 256
'y': 240
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 18
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 2
- - 2
- - 1
- - 1
- x: 272
'y': 240
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 18
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 2
- - 2
- - 1
- - 1
- x: 272
'y': 48
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 20
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 4
- - 2
- - 1
- - 1
- x: 288
'y': 48
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 20
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 4
- - 2
- - 1
- - 1
- x: 272
'y': 80
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 28
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 4
- - 3
- - 1
- - 1
- x: 288
'y': 64
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 28
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 4
- - 3
- - 1
- - 1
- x: 272
'y': 64
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 28
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 4
- - 3
- - 1
- - 1
- x: 288
'y': 80
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 29
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 5
- - 3
- - 1
- - 1
- x: 448
'y': 96
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 20
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 4
- - 2
- - 1
- - 1
- x: 432
'y': 96
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 20
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 4
- - 2
- - 1
- - 1
- x: 416
'y': 96
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 20
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 4
- - 2
- - 1
- - 1
- x: 400
'y': 96
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 20
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 4
- - 2
- - 1
- - 1
- x: 416
'y': 96
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 20
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 4
- - 2
- - 1
- - 1
- - x: 336
- 'y': 128
+ - x: 352
+ 'y': 144
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: ae954867-1039-43f6-bf6d-d8684cb58612
- grid:
- - 0
- - 0
- - 1
- - 1
extends:
cgroup: Decor
hidden: false
@@ -6353,6 +7891,8 @@ rooms:
});
eventKey: OnRoomStart
type: room
+ simulate: true
+ isUi: ! ''
- name: MainMenu
oncreate: ''
onstep: ''
@@ -6364,41 +7904,62 @@ rooms:
copies:
- x: 120
'y': 116
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ rotation: 0
uid: 38f86691-8fcc-44e4-a201-8479ca64935f
exts: {}
+ customProperties: {}
- x: 32
'y': 112
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ rotation: 0
uid: ff0f561c-a96c-4205-a083-01d2a60ebb67
exts: {}
+ customProperties: {}
tiles:
- depth: -10
tiles:
- - x: 16
- 'y': 16
+ - x: 121
+ 'y': 48
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: dc7b9662-c746-403c-9f3e-67425fd480a3
- grid:
- - 0
- - 0
- - 1
- - 1
- - x: 62
- 'y': 151
+ - x: 120
+ 'y': 153
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 9a1f5e9c-16a8-4900-8991-fab3f42fa1fd
- grid:
- - 0
- - 0
- - 1
- - 1
extends: {}
+ hidden: false
uid: eed8a427-1c70-425d-b633-7b6ea00c7b7c
thumbnail: 7b6ea00c7b7c
extends: {}
gridX: 16
gridY: 16
backgroundColor: '#000337'
- lastmod: 1656663135237
+ lastmod: 1661000148459
events: []
type: room
+ simulate: true
+ isUi: ! ''
- name: Level_03
onstep: ''
ondraw: ''
@@ -6410,2340 +7971,3338 @@ rooms:
'y': 64
uid: c40336ea-2846-45d5-97ba-d51852d3f6c5
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 112
'y': 64
uid: 469b9eef-6117-43a5-87d3-7151da7eba06
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 112
'y': 128
uid: c701a029-af09-4fcf-9712-0fcdaa3581be
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 104
'y': 192
uid: 36c82b3e-f5c1-4fff-b24a-417fa9509c96
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 120
'y': 192
uid: 36c82b3e-f5c1-4fff-b24a-417fa9509c96
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 112
'y': 224
uid: 469b9eef-6117-43a5-87d3-7151da7eba06
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 72
'y': 248
uid: 0bc3c56b-3bf9-4912-9e3f-c27654c1b910
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 72
'y': 264
uid: 0bc3c56b-3bf9-4912-9e3f-c27654c1b910
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 104
'y': 272
uid: 36c82b3e-f5c1-4fff-b24a-417fa9509c96
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 120
'y': 272
uid: 36c82b3e-f5c1-4fff-b24a-417fa9509c96
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 72
'y': 280
uid: 0bc3c56b-3bf9-4912-9e3f-c27654c1b910
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 72
'y': 296
uid: 0bc3c56b-3bf9-4912-9e3f-c27654c1b910
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 72
'y': 312
uid: 0bc3c56b-3bf9-4912-9e3f-c27654c1b910
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 104
'y': 320
uid: 36c82b3e-f5c1-4fff-b24a-417fa9509c96
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 120
'y': 320
uid: 36c82b3e-f5c1-4fff-b24a-417fa9509c96
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 152
'y': 328
uid: 0bc3c56b-3bf9-4912-9e3f-c27654c1b910
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 168
'y': 328
uid: 0bc3c56b-3bf9-4912-9e3f-c27654c1b910
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 184
'y': 328
uid: 0bc3c56b-3bf9-4912-9e3f-c27654c1b910
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 200
'y': 328
uid: 0bc3c56b-3bf9-4912-9e3f-c27654c1b910
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 216
'y': 328
uid: 0bc3c56b-3bf9-4912-9e3f-c27654c1b910
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 112
'y': 336
uid: 469b9eef-6117-43a5-87d3-7151da7eba06
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 136
'y': 344
uid: 0bc3c56b-3bf9-4912-9e3f-c27654c1b910
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 232
'y': 344
uid: 0bc3c56b-3bf9-4912-9e3f-c27654c1b910
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 136
'y': 360
uid: 0bc3c56b-3bf9-4912-9e3f-c27654c1b910
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 232
'y': 360
uid: 0bc3c56b-3bf9-4912-9e3f-c27654c1b910
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 181
'y': 362
uid: 3b6057ca-f175-4449-ac24-1c5630e0af7c
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 205
'y': 376
uid: 173dfb94-5133-4bbc-9e7d-6ed8c9fef330
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 152
'y': 376
uid: 0bc3c56b-3bf9-4912-9e3f-c27654c1b910
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 136
'y': 376
uid: 0bc3c56b-3bf9-4912-9e3f-c27654c1b910
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 232
'y': 376
uid: 0bc3c56b-3bf9-4912-9e3f-c27654c1b910
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 216
'y': 392
uid: 0bc3c56b-3bf9-4912-9e3f-c27654c1b910
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 168
'y': 392
uid: 0bc3c56b-3bf9-4912-9e3f-c27654c1b910
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 184
'y': 392
uid: 0bc3c56b-3bf9-4912-9e3f-c27654c1b910
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 200
'y': 392
uid: 0bc3c56b-3bf9-4912-9e3f-c27654c1b910
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 72
'y': 392
uid: 0bc3c56b-3bf9-4912-9e3f-c27654c1b910
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 136
'y': 392
uid: 0bc3c56b-3bf9-4912-9e3f-c27654c1b910
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 112
'y': 393
uid: 9fc1fec8-50bb-49e6-8fb4-c10ad589bf0b
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 72
'y': 408
uid: 0bc3c56b-3bf9-4912-9e3f-c27654c1b910
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 104
'y': 416
uid: 36c82b3e-f5c1-4fff-b24a-417fa9509c96
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 120
'y': 416
uid: 36c82b3e-f5c1-4fff-b24a-417fa9509c96
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 72
'y': 424
uid: 0bc3c56b-3bf9-4912-9e3f-c27654c1b910
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 88
'y': 440
uid: 0bc3c56b-3bf9-4912-9e3f-c27654c1b910
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 72
'y': 440
uid: 0bc3c56b-3bf9-4912-9e3f-c27654c1b910
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 72
'y': 456
uid: 0bc3c56b-3bf9-4912-9e3f-c27654c1b910
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 120
'y': 464
uid: 36c82b3e-f5c1-4fff-b24a-417fa9509c96
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 72
'y': 472
uid: 0bc3c56b-3bf9-4912-9e3f-c27654c1b910
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 136
'y': 472
uid: 0bc3c56b-3bf9-4912-9e3f-c27654c1b910
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 72
'y': 488
uid: 0bc3c56b-3bf9-4912-9e3f-c27654c1b910
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 120
'y': 488
uid: 0bc3c56b-3bf9-4912-9e3f-c27654c1b910
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 72
'y': 504
uid: 0bc3c56b-3bf9-4912-9e3f-c27654c1b910
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 136
'y': 504
uid: 0bc3c56b-3bf9-4912-9e3f-c27654c1b910
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 112
'y': 528
uid: 469b9eef-6117-43a5-87d3-7151da7eba06
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 115
'y': 574
uid: 9fc1fec8-50bb-49e6-8fb4-c10ad589bf0b
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 104
'y': 588
uid: 4e473462-8009-438e-9f53-1032e3a335cf
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 118
'y': 592
uid: 4e473462-8009-438e-9f53-1032e3a335cf
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 110
'y': 597
uid: 4e473462-8009-438e-9f53-1032e3a335cf
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 105
'y': 601
uid: 4e473462-8009-438e-9f53-1032e3a335cf
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 118
'y': 604
uid: 4e473462-8009-438e-9f53-1032e3a335cf
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 104
'y': 614
uid: 4e473462-8009-438e-9f53-1032e3a335cf
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 120
'y': 614
uid: 4e473462-8009-438e-9f53-1032e3a335cf
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 112
'y': 624
uid: c701a029-af09-4fcf-9712-0fcdaa3581be
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 113
'y': 636
uid: 173dfb94-5133-4bbc-9e7d-6ed8c9fef330
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 58
'y': 643
uid: 173dfb94-5133-4bbc-9e7d-6ed8c9fef330
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 122
'y': 648
uid: 173dfb94-5133-4bbc-9e7d-6ed8c9fef330
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 90
'y': 659
uid: 5e40076f-8a61-4dfd-a517-a6c943ab9991
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 112
'y': 672
uid: 7fea051e-83e5-4e54-848b-ab3ca861e5cb
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 74
'y': 680
uid: 173dfb94-5133-4bbc-9e7d-6ed8c9fef330
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 154
'y': 682
uid: 173dfb94-5133-4bbc-9e7d-6ed8c9fef330
exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
- x: 96
'y': 416
uid: b336d91c-2876-4686-b8b4-901045a86ac7
+ exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
tiles:
- depth: -6000
tiles:
- x: 48
'y': 48
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 48
'y': 32
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 48
'y': 16
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 48
'y': 80
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 64
'y': 96
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 80
'y': 0
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 96
'y': 0
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 112
'y': 0
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 128
'y': 0
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 144
'y': 0
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 64
'y': 0
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 144
'y': 96
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 160
'y': 80
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 160
'y': 48
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 160
'y': 32
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 160
'y': 16
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 160
'y': 64
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 80
'y': 128
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 80
'y': 144
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 80
'y': 160
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 128
'y': 128
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 128
'y': 144
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 128
'y': 160
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 128
'y': 176
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 128
'y': 192
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 128
'y': 208
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 128
'y': 112
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 80
'y': 112
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 80
'y': 208
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 80
'y': 192
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 80
'y': 224
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 128
'y': 256
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 128
'y': 272
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 128
'y': 288
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 128
'y': 320
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 128
'y': 224
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 80
'y': 320
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 80
'y': 352
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 80
'y': 368
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 128
'y': 400
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 128
'y': 416
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 128
'y': 448
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 80
'y': 512
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 80
'y': 528
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 80
'y': 544
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 80
'y': 560
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 80
'y': 576
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 128
'y': 528
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 128
'y': 544
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 128
'y': 560
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 128
'y': 576
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 128
'y': 512
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 80
'y': 592
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 64
'y': 592
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 48
'y': 592
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 144
'y': 592
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 160
'y': 592
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 128
'y': 592
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 176
'y': 624
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 176
'y': 640
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 176
'y': 656
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 176
'y': 672
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 160
'y': 688
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 144
'y': 688
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 128
'y': 688
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 32
'y': 656
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 32
'y': 640
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 32
'y': 624
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 32
'y': 608
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 32
'y': 672
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 64
'y': 688
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 80
'y': 688
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 96
'y': 688
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 112
'y': 688
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 48
'y': 688
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 176
'y': 608
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 0
- - 1
- - 1
- x: 80
'y': 240
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 14
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 6
- - 1
- - 1
- - 1
- x: 128
'y': 464
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 14
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 6
- - 1
- - 1
- - 1
- x: 80
'y': 384
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 14
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 6
- - 1
- - 1
- - 1
- x: 128
'y': 336
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 144
'y': 112
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 160
'y': 96
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 48
'y': 96
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 64
'y': 112
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 80
'y': 16
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 10
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 2
- - 1
- - 1
- - 1
- x: 128
'y': 16
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 10
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 2
- - 1
- - 1
- - 1
- x: 96
'y': 16
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 112
'y': 16
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 64
'y': 16
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 144
'y': 16
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 48
'y': 64
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 3
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 3
- - 0
- - 1
- - 1
- x: 144
'y': 608
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 12
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 4
- - 1
- - 1
- - 1
- x: 64
'y': 608
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 12
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 4
- - 1
- - 1
- - 1
- x: 48
'y': 112
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 19
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 3
- - 2
- - 1
- - 1
- x: 64
'y': 128
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 19
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 3
- - 2
- - 1
- - 1
- x: 144
'y': 128
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 19
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 3
- - 2
- - 1
- - 1
- x: 160
'y': 112
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 19
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 3
- - 2
- - 1
- - 1
- x: 48
'y': 704
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 64
'y': 704
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 80
'y': 704
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 112
'y': 704
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 128
'y': 704
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 144
'y': 704
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 160
'y': 704
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 96
'y': 704
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 14
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 6
- - 1
- - 1
- - 1
- x: 80
'y': 608
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 11
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 3
- - 1
- - 1
- - 1
- x: 128
'y': 608
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 160
'y': 608
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 48
'y': 608
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
- x: 80
'y': 96
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 2
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 2
- - 0
- - 1
- - 1
- x: 128
'y': 96
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 2
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 2
- - 0
- - 1
- - 1
- x: 128
'y': 432
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 3
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 3
- - 0
- - 1
- - 1
- x: 80
'y': 336
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 3
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 3
- - 0
- - 1
- - 1
- x: 128
'y': 240
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 1
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 0
- - 1
- - 1
- x: 128
'y': 304
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 1
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 0
- - 1
- - 1
- x: 80
'y': 176
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 1
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 0
- - 1
- - 1
- x: 32
'y': 592
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 1
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 0
- - 1
- - 1
- x: 32
'y': 688
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 1
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 0
- - 1
- - 1
- x: 176
'y': 688
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 1
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 0
- - 1
- - 1
- x: 176
'y': 592
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 1
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 0
- - 1
- - 1
- x: 32
'y': 704
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 14
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 6
- - 1
- - 1
- - 1
- x: 176
'y': 704
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 8
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 1
- - 1
- - 1
extends:
cgroup: Solid
- depth: -7000
tiles:
- x: 208
'y': 352
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 24
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 3
- - 1
- - 1
- x: 192
'y': 368
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 24
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 3
- - 1
- - 1
- x: 192
'y': 352
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 208
'y': 368
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 25
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 3
- - 1
- - 1
- x: 176
'y': 368
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 25
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 3
- - 1
- - 1
- x: 160
'y': 352
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 24
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 3
- - 1
- - 1
- x: 176
'y': 352
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 24
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 3
- - 1
- - 1
- x: 96
'y': 272
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 24
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 3
- - 1
- - 1
- x: 112
'y': 192
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 24
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 3
- - 1
- - 1
- x: 112
'y': 432
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 24
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 3
- - 1
- - 1
- x: 96
'y': 480
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 24
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 3
- - 1
- - 1
- x: 112
'y': 560
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 24
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 3
- - 1
- - 1
- x: 96
'y': 544
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 24
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 3
- - 1
- - 1
- x: 96
'y': 592
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 16
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 2
- - 1
- - 1
- x: 112
'y': 592
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 16
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 2
- - 1
- - 1
- x: 96
'y': 576
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 16
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 2
- - 1
- - 1
- x: 112
'y': 576
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 16
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 2
- - 1
- - 1
- x: 96
'y': 560
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 16
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 2
- - 1
- - 1
- x: 112
'y': 544
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 25
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 3
- - 1
- - 1
- x: 112
'y': 528
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 96
'y': 496
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 96
'y': 464
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 112
'y': 448
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 112
'y': 464
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 96
'y': 416
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 112
'y': 400
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 112
'y': 416
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 25
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 3
- - 1
- - 1
- x: 96
'y': 400
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 25
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 3
- - 1
- - 1
- x: 96
'y': 512
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 25
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 3
- - 1
- - 1
- x: 96
'y': 528
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 112
'y': 512
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 160
'y': 368
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 18
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 2
- - 2
- - 1
- - 1
- x: 176
'y': 384
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 18
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 2
- - 2
- - 1
- - 1
- x: 192
'y': 384
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 18
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 2
- - 2
- - 1
- - 1
- x: 208
'y': 384
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 18
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 2
- - 2
- - 1
- - 1
- x: 112
'y': 480
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 18
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 2
- - 2
- - 1
- - 1
- x: 96
'y': 432
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 18
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 2
- - 2
- - 1
- - 1
- x: 96
'y': 288
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 96
'y': 304
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 96
'y': 320
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 96
'y': 336
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 96
'y': 352
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 96
'y': 368
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 96
'y': 384
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 112
'y': 240
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 112
'y': 256
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 112
'y': 272
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 112
'y': 288
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 112
'y': 336
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 112
'y': 352
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 112
'y': 368
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 112
'y': 384
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 96
'y': 192
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 96
'y': 208
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 96
'y': 224
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 96
'y': 240
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 96
'y': 256
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 112
'y': 208
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 112
'y': 128
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 112
'y': 176
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 96
'y': 128
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 96
'y': 112
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 112
'y': 112
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 96
'y': 96
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 112
'y': 96
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 64
'y': 32
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 80
'y': 32
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 96
'y': 32
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 112
'y': 32
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 128
'y': 32
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 144
'y': 32
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 144
'y': 64
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 144
'y': 80
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 128
'y': 80
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 112
'y': 80
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 96
'y': 80
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 64
'y': 80
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 64
'y': 48
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 80
'y': 64
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 128
'y': 64
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 128
'y': 48
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 96
'y': 64
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 16
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 2
- - 1
- - 1
- x: 112
'y': 64
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 16
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 2
- - 1
- - 1
- x: 112
'y': 48
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 16
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 2
- - 1
- - 1
- x: 96
'y': 48
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 16
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 0
- - 2
- - 1
- - 1
- x: 112
'y': 224
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 25
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 3
- - 1
- - 1
- x: 96
'y': 176
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 25
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 3
- - 1
- - 1
- x: 144
'y': 48
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 25
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 3
- - 1
- - 1
- x: 80
'y': 80
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 25
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 3
- - 1
- - 1
- x: 80
'y': 48
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 25
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 3
- - 1
- - 1
- x: 64
'y': 64
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 25
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 3
- - 1
- - 1
- x: 112
'y': 304
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 25
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 3
- - 1
- - 1
- x: 112
'y': 320
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 25
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 3
- - 1
- - 1
- x: 96
'y': 608
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 112
'y': 608
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 64
'y': 624
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 80
'y': 624
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 96
'y': 624
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 112
'y': 624
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 128
'y': 624
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 144
'y': 624
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 160
'y': 624
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 160
'y': 640
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 160
'y': 656
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 160
'y': 672
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 144
'y': 672
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 128
'y': 672
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 112
'y': 672
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 96
'y': 672
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 80
'y': 672
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 64
'y': 672
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 48
'y': 672
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 48
'y': 656
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 48
'y': 640
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 48
'y': 624
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 80
'y': 640
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 96
'y': 640
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 112
'y': 640
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 128
'y': 640
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 144
'y': 640
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 144
'y': 656
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 128
'y': 656
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 112
'y': 656
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 96
'y': 656
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 80
'y': 656
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 64
'y': 656
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 48
'y': 656
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 64
'y': 656
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 64
'y': 640
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 17
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 1
- - 2
- - 1
- - 1
- x: 96
'y': 144
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 22
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 6
- - 2
- - 1
- - 1
- x: 112
'y': 144
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 22
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 6
- - 2
- - 1
- - 1
- x: 96
'y': 160
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 22
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 6
- - 2
- - 1
- - 1
- x: 112
'y': 160
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 22
+ rotation: 0
texture: 4f8a6124-427b-410b-a467-ac42afec3644
- grid:
- - 6
- - 2
- - 1
- - 1
- - x: 96
- 'y': 112
+ - x: 112
+ 'y': 128
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: ae954867-1039-43f6-bf6d-d8684cb58612
- grid:
- - 0
- - 0
- - 1
- - 1
- - x: 96
- 'y': 608
+ - x: 112
+ 'y': 624
+ opacity: 1
+ tint: 16777215
+ scale:
+ x: 1
+ 'y': 1
+ frame: 0
+ rotation: 0
texture: ae954867-1039-43f6-bf6d-d8684cb58612
- grid:
- - 0
- - 0
- - 1
- - 1
extends:
cgroup: Decor
uid: ae6bb30c-9ad9-4390-b632-127493eb58cf
@@ -8774,6 +11333,8 @@ rooms:
}
eventKey: OnRoomEnd
type: room
+ simulate: true
+ isUi: ! ''
- name: UI_InGame
onstep: ''
onleave: ''
@@ -8784,14 +11345,21 @@ rooms:
- x: 96
'y': 88
uid: ff0f561c-a96c-4205-a083-01d2a60ebb67
+ exts: {}
+ customProperties: {}
+ opacity: 1
+ tint: 16777215
+ rotation: 0
+ scale:
+ x: 1
+ 'y': 1
tiles:
- depth: -10
tiles: []
extends: {}
uid: ee8b4583-614a-44d6-aacc-6569f49f6b80
thumbnail: 6569f49f6b80
- extends:
- isUi: true
+ extends: {}
gridX: 8
gridY: 8
backgroundColor: '#000337'
@@ -8819,6 +11387,8 @@ rooms:
code: this.hearts.width = 16 * ct.room.lives;
eventKey: OnDraw
type: room
+ simulate: true
+ isUi: true
actions:
- name: MoveX
methods:
diff --git a/src/examples/DungeonCrawler_tutorial/img/i14d3f53f-a868-4820-84cd-63234ab6e6b9.png} b/src/examples/DungeonCrawler_tutorial/img/i14d3f53f-a868-4820-84cd-63234ab6e6b9.png
similarity index 100%
rename from src/examples/DungeonCrawler_tutorial/img/i14d3f53f-a868-4820-84cd-63234ab6e6b9.png}
rename to src/examples/DungeonCrawler_tutorial/img/i14d3f53f-a868-4820-84cd-63234ab6e6b9.png
diff --git a/src/examples/DungeonCrawler_tutorial/img/i14d3f53f-a868-4820-84cd-63234ab6e6b9.png}_prev.png b/src/examples/DungeonCrawler_tutorial/img/i14d3f53f-a868-4820-84cd-63234ab6e6b9.png_prev.png
similarity index 100%
rename from src/examples/DungeonCrawler_tutorial/img/i14d3f53f-a868-4820-84cd-63234ab6e6b9.png}_prev.png
rename to src/examples/DungeonCrawler_tutorial/img/i14d3f53f-a868-4820-84cd-63234ab6e6b9.png_prev.png
diff --git a/src/examples/DungeonCrawler_tutorial/img/i14d3f53f-a868-4820-84cd-63234ab6e6b9.png}_prev@2.png b/src/examples/DungeonCrawler_tutorial/img/i14d3f53f-a868-4820-84cd-63234ab6e6b9.png_prev@2.png
similarity index 100%
rename from src/examples/DungeonCrawler_tutorial/img/i14d3f53f-a868-4820-84cd-63234ab6e6b9.png}_prev@2.png
rename to src/examples/DungeonCrawler_tutorial/img/i14d3f53f-a868-4820-84cd-63234ab6e6b9.png_prev@2.png
diff --git a/src/examples/DungeonCrawler_tutorial/img/ia42e0dff-69c9-46c3-8996-745aaa769698.png} b/src/examples/DungeonCrawler_tutorial/img/ia42e0dff-69c9-46c3-8996-745aaa769698.png
similarity index 100%
rename from src/examples/DungeonCrawler_tutorial/img/ia42e0dff-69c9-46c3-8996-745aaa769698.png}
rename to src/examples/DungeonCrawler_tutorial/img/ia42e0dff-69c9-46c3-8996-745aaa769698.png
diff --git a/src/examples/DungeonCrawler_tutorial/img/ia42e0dff-69c9-46c3-8996-745aaa769698.png}_prev.png b/src/examples/DungeonCrawler_tutorial/img/ia42e0dff-69c9-46c3-8996-745aaa769698.png_prev.png
similarity index 100%
rename from src/examples/DungeonCrawler_tutorial/img/ia42e0dff-69c9-46c3-8996-745aaa769698.png}_prev.png
rename to src/examples/DungeonCrawler_tutorial/img/ia42e0dff-69c9-46c3-8996-745aaa769698.png_prev.png
diff --git a/src/examples/DungeonCrawler_tutorial/img/ia42e0dff-69c9-46c3-8996-745aaa769698.png}_prev@2.png b/src/examples/DungeonCrawler_tutorial/img/ia42e0dff-69c9-46c3-8996-745aaa769698.png_prev@2.png
similarity index 100%
rename from src/examples/DungeonCrawler_tutorial/img/ia42e0dff-69c9-46c3-8996-745aaa769698.png}_prev@2.png
rename to src/examples/DungeonCrawler_tutorial/img/ia42e0dff-69c9-46c3-8996-745aaa769698.png_prev@2.png
diff --git a/src/examples/DungeonCrawler_tutorial/img/r127493eb58cf.png b/src/examples/DungeonCrawler_tutorial/img/r127493eb58cf.png
deleted file mode 100644
index 8749b9745..000000000
Binary files a/src/examples/DungeonCrawler_tutorial/img/r127493eb58cf.png and /dev/null differ
diff --git a/src/examples/DungeonCrawler_tutorial/img/r1cd7a8ef-febb-4174-ad90-42846504b06f.png b/src/examples/DungeonCrawler_tutorial/img/r1cd7a8ef-febb-4174-ad90-42846504b06f.png
new file mode 100644
index 000000000..f6cd9432a
Binary files /dev/null and b/src/examples/DungeonCrawler_tutorial/img/r1cd7a8ef-febb-4174-ad90-42846504b06f.png differ
diff --git a/src/examples/DungeonCrawler_tutorial/img/r1cd7a8ef-febb-4174-ad90-42846504b06f@r.png b/src/examples/DungeonCrawler_tutorial/img/r1cd7a8ef-febb-4174-ad90-42846504b06f@r.png
new file mode 100644
index 000000000..f6cce5a41
Binary files /dev/null and b/src/examples/DungeonCrawler_tutorial/img/r1cd7a8ef-febb-4174-ad90-42846504b06f@r.png differ
diff --git a/src/examples/DungeonCrawler_tutorial/img/r326893eb-b9c2-4616-aaee-bb4641e0423e.png b/src/examples/DungeonCrawler_tutorial/img/r326893eb-b9c2-4616-aaee-bb4641e0423e.png
new file mode 100644
index 000000000..ed46f03b9
Binary files /dev/null and b/src/examples/DungeonCrawler_tutorial/img/r326893eb-b9c2-4616-aaee-bb4641e0423e.png differ
diff --git a/src/examples/DungeonCrawler_tutorial/img/r326893eb-b9c2-4616-aaee-bb4641e0423e@r.png b/src/examples/DungeonCrawler_tutorial/img/r326893eb-b9c2-4616-aaee-bb4641e0423e@r.png
new file mode 100644
index 000000000..0c795276f
Binary files /dev/null and b/src/examples/DungeonCrawler_tutorial/img/r326893eb-b9c2-4616-aaee-bb4641e0423e@r.png differ
diff --git a/src/examples/DungeonCrawler_tutorial/img/r342f55fa6324.png b/src/examples/DungeonCrawler_tutorial/img/r342f55fa6324.png
deleted file mode 100644
index 8749b9745..000000000
Binary files a/src/examples/DungeonCrawler_tutorial/img/r342f55fa6324.png and /dev/null differ
diff --git a/src/examples/DungeonCrawler_tutorial/img/r3786dc4c7d4c.png b/src/examples/DungeonCrawler_tutorial/img/r3786dc4c7d4c.png
deleted file mode 100644
index 8749b9745..000000000
Binary files a/src/examples/DungeonCrawler_tutorial/img/r3786dc4c7d4c.png and /dev/null differ
diff --git a/src/examples/DungeonCrawler_tutorial/img/r42846504b06f.png b/src/examples/DungeonCrawler_tutorial/img/r42846504b06f.png
deleted file mode 100644
index 39a24d49b..000000000
Binary files a/src/examples/DungeonCrawler_tutorial/img/r42846504b06f.png and /dev/null differ
diff --git a/src/examples/DungeonCrawler_tutorial/img/r6569f49f6b80.png b/src/examples/DungeonCrawler_tutorial/img/r6569f49f6b80.png
deleted file mode 100644
index d09582a51..000000000
Binary files a/src/examples/DungeonCrawler_tutorial/img/r6569f49f6b80.png and /dev/null differ
diff --git a/src/examples/DungeonCrawler_tutorial/img/r7b6ea00c7b7c.png b/src/examples/DungeonCrawler_tutorial/img/r7b6ea00c7b7c.png
deleted file mode 100644
index 97d86c767..000000000
Binary files a/src/examples/DungeonCrawler_tutorial/img/r7b6ea00c7b7c.png and /dev/null differ
diff --git a/src/examples/DungeonCrawler_tutorial/img/rae6bb30c-9ad9-4390-b632-127493eb58cf.png b/src/examples/DungeonCrawler_tutorial/img/rae6bb30c-9ad9-4390-b632-127493eb58cf.png
new file mode 100644
index 000000000..0a55fb81c
Binary files /dev/null and b/src/examples/DungeonCrawler_tutorial/img/rae6bb30c-9ad9-4390-b632-127493eb58cf.png differ
diff --git a/src/examples/DungeonCrawler_tutorial/img/rae6bb30c-9ad9-4390-b632-127493eb58cf@r.png b/src/examples/DungeonCrawler_tutorial/img/rae6bb30c-9ad9-4390-b632-127493eb58cf@r.png
new file mode 100644
index 000000000..d6730ecc9
Binary files /dev/null and b/src/examples/DungeonCrawler_tutorial/img/rae6bb30c-9ad9-4390-b632-127493eb58cf@r.png differ
diff --git a/src/examples/DungeonCrawler_tutorial/img/rbb4641e0423e.png b/src/examples/DungeonCrawler_tutorial/img/rbb4641e0423e.png
deleted file mode 100644
index 29bb94e95..000000000
Binary files a/src/examples/DungeonCrawler_tutorial/img/rbb4641e0423e.png and /dev/null differ
diff --git a/src/examples/DungeonCrawler_tutorial/img/ree8b4583-614a-44d6-aacc-6569f49f6b80.png b/src/examples/DungeonCrawler_tutorial/img/ree8b4583-614a-44d6-aacc-6569f49f6b80.png
new file mode 100644
index 000000000..71018e25a
Binary files /dev/null and b/src/examples/DungeonCrawler_tutorial/img/ree8b4583-614a-44d6-aacc-6569f49f6b80.png differ
diff --git a/src/examples/DungeonCrawler_tutorial/img/ree8b4583-614a-44d6-aacc-6569f49f6b80@r.png b/src/examples/DungeonCrawler_tutorial/img/ree8b4583-614a-44d6-aacc-6569f49f6b80@r.png
new file mode 100644
index 000000000..0a886df3c
Binary files /dev/null and b/src/examples/DungeonCrawler_tutorial/img/ree8b4583-614a-44d6-aacc-6569f49f6b80@r.png differ
diff --git a/src/examples/DungeonCrawler_tutorial/img/reed8a427-1c70-425d-b633-7b6ea00c7b7c.png b/src/examples/DungeonCrawler_tutorial/img/reed8a427-1c70-425d-b633-7b6ea00c7b7c.png
new file mode 100644
index 000000000..492948a81
Binary files /dev/null and b/src/examples/DungeonCrawler_tutorial/img/reed8a427-1c70-425d-b633-7b6ea00c7b7c.png differ
diff --git a/src/examples/DungeonCrawler_tutorial/img/reed8a427-1c70-425d-b633-7b6ea00c7b7c@r.png b/src/examples/DungeonCrawler_tutorial/img/reed8a427-1c70-425d-b633-7b6ea00c7b7c@r.png
new file mode 100644
index 000000000..6615020cd
Binary files /dev/null and b/src/examples/DungeonCrawler_tutorial/img/reed8a427-1c70-425d-b633-7b6ea00c7b7c@r.png differ
diff --git a/src/examples/DungeonCrawler_tutorial/img/splash.png b/src/examples/DungeonCrawler_tutorial/img/splash.png
index ce0daeb29..6615020cd 100644
Binary files a/src/examples/DungeonCrawler_tutorial/img/splash.png and b/src/examples/DungeonCrawler_tutorial/img/splash.png differ
diff --git a/src/icons/cursor.svg b/src/icons/cursor.svg
new file mode 100644
index 000000000..56102beca
--- /dev/null
+++ b/src/icons/cursor.svg
@@ -0,0 +1,2 @@
+
diff --git a/src/icons/lock.svg b/src/icons/lock.svg
new file mode 100644
index 000000000..de09d9db3
--- /dev/null
+++ b/src/icons/lock.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/icons/redo.svg b/src/icons/redo.svg
new file mode 100644
index 000000000..996380f66
--- /dev/null
+++ b/src/icons/redo.svg
@@ -0,0 +1,4 @@
+
diff --git a/src/icons/undo.svg b/src/icons/undo.svg
new file mode 100644
index 000000000..4a23bbdef
--- /dev/null
+++ b/src/icons/undo.svg
@@ -0,0 +1,4 @@
+
diff --git a/src/icons/unlock.svg b/src/icons/unlock.svg
new file mode 100644
index 000000000..01dc35973
--- /dev/null
+++ b/src/icons/unlock.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/js/3rdparty/alertify.js b/src/js/3rdparty/alertify.js
index c5329270e..d2d0d0222 100644
--- a/src/js/3rdparty/alertify.js
+++ b/src/js/3rdparty/alertify.js
@@ -395,6 +395,7 @@
_alertify.injectCSS();
+ const {soundbox} = require('./data/node_requires/3rdparty/soundbox');
return {
_$$alertify: _alertify,
parent(elem) {
diff --git a/src/js/3rdparty/soundbox.js b/src/js/3rdparty/soundbox.js
deleted file mode 100644
index 6148b18e4..000000000
--- a/src/js/3rdparty/soundbox.js
+++ /dev/null
@@ -1,11 +0,0 @@
-(function () {
- 'use strict';class SoundBox{constructor(){this.sounds={};this.instances=[];this.default_volume=1}load(a,b,d){this.sounds[a]=new Audio(b);if("function"==typeof d)this.sounds[a].addEventListener("canplaythrough",d);else return new Promise((c,b)=>{this.sounds[a].addEventListener("canplaythrough",c);this.sounds[a].addEventListener("error",b)})}remove(a){"undefined"!=typeof this.sounds&&delete this.sounds[a]}play(a,b,d=null){if("undefined"==typeof this.sounds[a])return console.error("Can't find sound called '"+
-a+"'."),!1;var c=this.sounds[a].cloneNode(!0);c.volume=d||this.default_volume;c.play();this.instances.push(c);c.addEventListener("ended",()=>{let a=this.instances.indexOf(c);-1!=a&&this.instances.splice(a,1)});return"function"==typeof b?(c.addEventListener("ended",b),!0):new Promise((a,b)=>c.addEventListener("ended",a))}stop_all(){let a=this.instances.slice();for(let b of a)b.pause(),b.dispatchEvent(new Event("ended"))}}SoundBox.version="0.3.4";
-
- const soundbox = new SoundBox();
-
- soundbox.load('Success', 'data/Success.wav');
- soundbox.load('Failure', 'data/Failure.wav');
-
- window.soundbox = soundbox;
-})();
diff --git a/src/js/addMigrationMethod.js b/src/js/addMigrationMethod.js
new file mode 100644
index 000000000..134239a42
--- /dev/null
+++ b/src/js/addMigrationMethod.js
@@ -0,0 +1,11 @@
+(function addMigrationMethod(window) {
+ window.migrationProcess = window.migrationProcess || [];
+ window.applyMigrationCode = function applyMigrationCode(version) {
+ const process = window.migrationProcess.find(process => process.version === version);
+ if (!process) {
+ throw new Error(`Cannot find migration code for version ${version}`);
+ }
+ process.process(global.currentProject)
+ .then(() => window.alertify.success(`Applied migration code for version ${version}`, 'success', 3000));
+ };
+})(this);
diff --git a/src/js/loadProject.js b/src/js/loadProject.js
deleted file mode 100644
index e012ae300..000000000
--- a/src/js/loadProject.js
+++ /dev/null
@@ -1,239 +0,0 @@
-(function addLoadProjectMethod(window) {
- window.migrationProcess = window.migrationProcess || [];
- window.applyMigrationCode = function applyMigrationCode(version) {
- const process = window.migrationProcess.find(process => process.version === version);
- if (!process) {
- throw new Error(`Cannot find migration code for version ${version}`);
- }
- process.process(global.currentProject)
- .then(() => window.alertify.success(`Applied migration code for version ${version}`, 'success', 3000));
- };
-
- const fs = require('fs-extra'),
- path = require('path');
- // @see https://semver.org/
- const semverRegex = /(\d+)\.(\d+)\.(\d+)(-[A-Za-z.-]*(\d+)?[A-Za-z.-]*)?/;
- const semverToArray = string => {
- const raw = semverRegex.exec(string);
- return [
- raw[1],
- raw[2],
- raw[3],
- // -next- versions and other postfixes will count as a fourth component.
- // They all will apply before regular versions
- raw[4] ? raw[5] || 1 : null
- ];
- };
-
- /**
- * Applies migration scripts to older projects.
- */
- var adapter = async project => {
- var version = semverToArray(project.ctjsVersion || '0.2.0');
-
- const migrationToExecute = window.migrationProcess
- // Sort all the patches chronologically
- .sort((m1, m2) => {
- const m1Version = semverToArray(m1.version);
- const m2Version = semverToArray(m2.version);
-
- for (let i = 0; i < 4; i++) {
- if (m1Version[i] < m2Version[i] || m1Version[i] === null) {
- return -1;
- } else if (m1Version[i] > m2Version[i]) {
- return 1;
- }
- }
- // eslint-disable-next-line no-console
- console.warn(`Two equivalent versions found for migration, ${m1.version} and ${m2.version}.`);
- return 0;
- })
- // Throw out patches for current and previous versions
- .filter((migration) => {
- const migrationVersion = semverToArray(migration.version);
- for (let i = 0; i < 3; i++) {
- // if any of the first three version numbers is lower than project's,
- // skip the patch
- if (migrationVersion[i] < version[i]) {
- return false;
- }
- if (migrationVersion[i] > version[i]) {
- return true;
- }
- }
- // a lazy check for equal base versions
- if (migrationVersion.slice(0, 3).join('.') === version.slice(0, 3).join('.')) {
- // handle the case with two postfixed versions
- if (migrationVersion[3] !== null && version[3] !== null) {
- return migrationVersion[3] > version[3];
- }
- // postfixed source, unpostfixed patch
- if (migrationVersion[3] === null && version[3] !== null) {
- return true;
- }
- return false;
- }
- return true;
- });
-
- if (migrationToExecute.length) {
- // eslint-disable-next-line no-console
- console.debug(`Applying migration sequence: patches ${migrationToExecute.map(m => m.version).join(', ')}.`);
- }
- for (const migration of migrationToExecute) {
- // eslint-disable-next-line no-console
- console.debug(`Migrating project from version ${project.ctjsVersion || '0.2.0'} to ${migration.version}`);
- // We do need to apply updates in a sequence
- // eslint-disable-next-line no-await-in-loop
- await migration.process(project);
- }
-
- // Unfortunately, recent versions of eslint give false positives on this line
- // @see https://github.com/eslint/eslint/issues/11900
- // @see https://github.com/eslint/eslint/issues/11899
- // eslint-disable-next-line require-atomic-updates
- project.ctjsVersion = process.versions.ctjs;
- };
-
- /**
- * Opens the project and refreshes the whole app.
- *
- * @param {Object} projectData Loaded JSON file, in js object form
- * @returns {void}
- */
- var loadProject = async projectData => {
- const glob = require('./data/node_requires/glob');
- global.currentProject = projectData;
- window.alertify.log(window.languageJSON.intro.loadingProject);
- glob.modified = false;
-
- try {
- await adapter(projectData);
- fs.ensureDir(global.projdir);
- fs.ensureDir(global.projdir + '/img');
- fs.ensureDir(global.projdir + '/snd');
-
- const lastProjects = localStorage.lastProjects ? localStorage.lastProjects.split(';') : [];
- if (lastProjects.indexOf(path.normalize(global.projdir + '.ict')) !== -1) {
- lastProjects.splice(lastProjects.indexOf(path.normalize(global.projdir + '.ict')), 1);
- }
- lastProjects.unshift(path.normalize(global.projdir + '.ict'));
- if (lastProjects.length > 15) {
- lastProjects.pop();
- }
- localStorage.lastProjects = lastProjects.join(';');
-
- if (global.currentProject.settings.title) {
- document.title = global.currentProject.settings.title + ' — ct.js';
- }
-
- glob.scriptTypings = {};
- for (const script of global.currentProject.scripts) {
- glob.scriptTypings[script.name] = [
- monaco.languages.typescript.javascriptDefaults.addExtraLib(script.code),
- monaco.languages.typescript.typescriptDefaults.addExtraLib(script.code)
- ];
- }
-
- const {loadAllTypedefs, resetTypedefs} = require('./data/node_requires/resources/modules/typedefs');
- resetTypedefs();
- loadAllTypedefs();
-
- const {unloadAllEvents, loadAllModulesEvents} = require('./data/node_requires/events');
- unloadAllEvents();
- await loadAllModulesEvents();
-
- window.signals.trigger('projectLoaded');
- setTimeout(() => {
- window.riot.update();
- }, 0);
- } catch (err) {
- window.alertify.alert(window.languageJSON.intro.loadingProjectError + err);
- }
- };
-
- /**
- * Checks file format and loads it
- *
- * @param {String} proj The path to the file.
- * @returns {void}
- */
- var loadProjectFile = async proj => {
- const textProjData = await fs.readFile(proj, 'utf8');
- let projectData;
- // Before v1.3, projects were stored in JSON format
- try {
- if (textProjData.indexOf('{') === 0) { // First, make a silly check for JSON files
- projectData = JSON.parse(textProjData);
- } else {
- try {
- const YAML = require('js-yaml');
- projectData = YAML.load(textProjData);
- } catch (e) {
- // whoopsie, wrong window
- // eslint-disable-next-line no-console
- console.warn(`Tried to load a file ${proj} as a YAML, but got an error (see below). Falling back to JSON.`);
- console.error(e);
- projectData = JSON.parse(textProjData);
- }
- }
- } catch (e) {
- window.alertify.error(e);
- throw e;
- }
- if (!projectData) {
- window.alertify.error(window.languageJSON.common.wrongFormat);
- return;
- }
- try {
- loadProject(projectData);
- } catch (e) {
- window.alertify.error(e);
- throw e;
- }
- };
-
- window.loadProject = async proj => {
- if (!proj) {
- const baseMessage = 'An attempt to open a project with an empty path.';
- alertify.error(baseMessage + ' See the console for the call stack.');
- const err = new Error(baseMessage);
- throw err;
- }
- sessionStorage.projname = path.basename(proj);
- global.projdir = path.dirname(proj) + path.sep + path.basename(proj, '.ict');
-
- let recoveryStat;
- try {
- recoveryStat = await fs.stat(proj + '.recovery');
- } catch (err) {
- // no recovery file found
- void 0;
- }
- if (recoveryStat && recoveryStat.isFile()) {
- const targetStat = await fs.stat(proj);
- const voc = window.languageJSON.intro.recovery;
- const userResponse = await window.alertify
- .okBtn(voc.loadRecovery)
- .cancelBtn(voc.loadTarget)
- /* {0} — target file date
- {1} — target file state (newer/older)
- {2} — recovery file date
- {3} — recovery file state (newer/older)
- */
- .confirm(voc.message
- .replace('{0}', targetStat.mtime.toLocaleString())
- .replace('{1}', targetStat.mtime < recoveryStat.mtime ? voc.older : voc.newer)
- .replace('{2}', recoveryStat.mtime.toLocaleString())
- .replace('{3}', recoveryStat.mtime < targetStat.mtime ? voc.older : voc.newer));
- window.alertify
- .okBtn(window.languageJSON.common.ok)
- .cancelBtn(window.languageJSON.common.cancel);
- if (userResponse.buttonClicked === 'ok') {
- return loadProjectFile(proj + '.recovery');
- }
- return loadProjectFile(proj);
- }
- return loadProjectFile(proj);
- };
-})(this);
diff --git a/src/js/projectMigrationScripts/2.1.0.js b/src/js/projectMigrationScripts/2.1.0.js
index 6f2e915f2..d6ed06abf 100644
--- a/src/js/projectMigrationScripts/2.1.0.js
+++ b/src/js/projectMigrationScripts/2.1.0.js
@@ -2,6 +2,7 @@ window.migrationProcess = window.migrationProcess || [];
window.migrationProcess.push({
version: '2.1.0',
+ // eslint-disable-next-line max-lines-per-function
process: project => new Promise(resolve => {
const templateEventMap = {
oncreate: 'OnCreate',
@@ -36,6 +37,7 @@ window.migrationProcess.push({
}
}
for (const room of project.rooms) {
+ room.simulate = true;
if (!room.events) {
room.events = [];
for (const key in roomEventMap) {
@@ -52,6 +54,40 @@ window.migrationProcess.push({
}
room.type = 'room';
}
+ // Break up tile chunks into individual tiles
+ for (const room of project.rooms) {
+ for (const layer of room.tiles) {
+ layer.tiles = layer.tiles.reduce((tiles, tile) => {
+ const tex = project.textures.find(t => t.uid === tile.texture);
+ if (!tile.grid) {
+ tiles.push(tile);
+ return tiles;
+ }
+ // grid: [tileX, tileY, tileSpanX, tileSpanY]
+ // eslint-disable-next-line prefer-destructuring
+ for (let x = tile.grid[0]; x < tile.grid[0] + tile.grid[2]; x++) {
+ // eslint-disable-next-line prefer-destructuring
+ for (let y = tile.grid[1]; y < tile.grid[1] + tile.grid[3]; y++) {
+ tiles.push({
+ x: tile.x + tex.axis[0],
+ y: tile.y + tex.axis[1],
+ opacity: tile.opacity ?? 1,
+ tint: tile.tint ?? 0xffffff,
+ scale: {
+ x: tile.scale?.x ?? 1,
+ y: tile.scale?.y ?? 1
+ },
+ frame: x + y * tex.grid[0],
+ rotation: tile.rotation ?? 0,
+ texture: tile.texture
+ });
+ }
+ }
+ delete tile.grid;
+ return tiles;
+ }, []);
+ }
+ }
resolve();
})
});
diff --git a/src/js/projectMigrationScripts/2.2.0.js b/src/js/projectMigrationScripts/2.2.0.js
new file mode 100644
index 000000000..f8d8c2117
--- /dev/null
+++ b/src/js/projectMigrationScripts/2.2.0.js
@@ -0,0 +1,24 @@
+window.migrationProcess = window.migrationProcess || [];
+
+window.migrationProcess.push({
+ version: '2.2.0',
+ // eslint-disable-next-line max-lines-per-function
+ process: project => new Promise(resolve => {
+ for (const room of project.rooms) {
+ room.isUi = room.extends.isUi;
+ delete room.extends.isUi;
+ for (const copy of room.copies) {
+ copy.exts = copy.exts ?? {};
+ copy.customProperties = copy.customProperties ?? {};
+ copy.opacity = copy.opacity ?? 1;
+ copy.tint = copy.tint ?? 0xffffff;
+ copy.rotation = copy.rotation ?? 0;
+ copy.scale = copy.scale ?? {
+ x: 1,
+ y: 1
+ };
+ }
+ }
+ resolve();
+ })
+});
diff --git a/src/node_requires/3rdparty/soundbox.ts b/src/node_requires/3rdparty/soundbox.ts
new file mode 100644
index 000000000..9633cd912
--- /dev/null
+++ b/src/node_requires/3rdparty/soundbox.ts
@@ -0,0 +1,55 @@
+'use strict';
+
+type knownSoundNames = 'Success' | 'Failure' | 'Wood_Start' | 'Wood_End';
+
+class SoundBox {
+ static version: string;
+ sounds: Record = {};
+ instances: HTMLAudioElement[] = [];
+ default_volume = 1;
+ get mute() {
+ return localStorage.disableSounds === 'on';
+ }
+ load(name: knownSoundNames, url: string, callback?: (this: HTMLAudioElement, ev: Event) => any) {
+ this.sounds[name] = new Audio(url);
+ if ("function" == typeof callback) {
+ this.sounds[name].addEventListener("canplaythrough", callback);
+ } else {
+ return new Promise((c, b) => {
+ this.sounds[name].addEventListener("canplaythrough", c);
+ this.sounds[name].addEventListener("error", b)
+ })
+ }
+ }
+ remove(name: knownSoundNames) {
+ "undefined" != typeof this.sounds && delete this.sounds[name]
+ }
+ play(name: knownSoundNames, callback?: (this: HTMLAudioElement, ev: Event) => any, volume?: number) {
+ if (this.mute) {
+ return;
+ }
+ if ("undefined" == typeof this.sounds[name]) {
+ return console.error(`Can't find sound called '${name}'.`), false;
+ }
+ var audioTag = this.sounds[name].cloneNode(true) as HTMLAudioElement;
+ audioTag.volume = volume ?? this.default_volume;
+ audioTag.play();
+ this.instances.push(audioTag);
+ audioTag.addEventListener("ended", () => {
+ let a = this.instances.indexOf(audioTag); - 1 != a && this.instances.splice(a, 1)
+ });
+ return "function" == typeof callback ? (audioTag.addEventListener("ended", callback), !0) : new Promise((a, b) => audioTag.addEventListener("ended", a))
+ }
+ stop_all() {
+ let a = this.instances.slice();
+ for (let b of a) b.pause(), b.dispatchEvent(new Event("ended"))
+ }
+}
+SoundBox.version = "0.3.4";
+
+export const soundbox = new SoundBox();
+
+soundbox.load('Success', 'data/Success.wav');
+soundbox.load('Failure', 'data/Failure.wav');
+soundbox.load('Wood_Start', 'data/Wood_Start.wav');
+soundbox.load('Wood_End', 'data/Wood_End.wav');
diff --git a/src/node_requires/IMenuItem.d.ts b/src/node_requires/IMenuItem.d.ts
index 14634b731..91bfca164 100644
--- a/src/node_requires/IMenuItem.d.ts
+++ b/src/node_requires/IMenuItem.d.ts
@@ -46,11 +46,14 @@ declare interface IMenuItem {
submenu?: IMenu,
/**
- * E.g. 'Control+c'
+ * E.g. 'Control+c'. Binds the element to hotkey.js library.
*/
hotkey?: string,
/**
* A human-readable variant, e.g. 'Ctrl+C'. Fallbacks to `hotkey`.
+ * If set without `hotkey`, still shows the label but does not
+ * bind the element to the hotkey.js library.
+ * The label is wrapped into (parentheses) automatically.
*/
hotkeyLabel?: string
}
diff --git a/src/node_requires/events/index.ts b/src/node_requires/events/index.ts
index 33097c8da..2422f9e09 100644
--- a/src/node_requires/events/index.ts
+++ b/src/node_requires/events/index.ts
@@ -278,7 +278,7 @@ const unloadAllEvents = (): void => {
}
};
-export = {
+export {
categories,
events,
bakeCategories,
diff --git a/src/node_requires/exporter/index.ts b/src/node_requires/exporter/index.ts
index 7417b171f..a123d06e4 100644
--- a/src/node_requires/exporter/index.ts
+++ b/src/node_requires/exporter/index.ts
@@ -205,6 +205,7 @@ const exportCtProject = async (
projdir: string,
production: boolean
): Promise => {
+ window.signals.trigger('exportProject');
currentProject = project;
await removeBrokenModules(project);
resetEventsCache();
diff --git a/src/node_requires/exporter/rooms.ts b/src/node_requires/exporter/rooms.ts
index c3aee985b..d45477774 100644
--- a/src/node_requires/exporter/rooms.ts
+++ b/src/node_requires/exporter/rooms.ts
@@ -40,8 +40,16 @@ interface IExportedTile {
x: number,
y: number,
width: number,
- height: number
+ height: number,
+ opacity: number,
+ rotation: number,
+ scale: {
+ x: number,
+ y: number
+ },
+ tint: number
}
+type ExportedCopy = Omit & {template: string};
// eslint-disable-next-line max-lines-per-function
const stringifyRooms = (proj: IProject): IScriptablesFragment => {
@@ -52,12 +60,14 @@ const stringifyRooms = (proj: IProject): IScriptablesFragment => {
let rootRoomOnLeave = '';
for (const r of proj.rooms) {
- const roomCopy = JSON.parse(JSON.stringify(r.copies));
- const objs = [];
- for (const copy of roomCopy) {
- copy.template = proj.templates[glob.templatemap[copy.uid]].name;
- delete copy.uid;
- objs.push(copy);
+ const objs: ExportedCopy[] = [];
+ for (const copy of r.copies) {
+ const exportableCopy = {
+ ...copy,
+ template: proj.templates[glob.templatemap[copy.uid]].name
+ };
+ delete exportableCopy.uid;
+ objs.push(exportableCopy);
}
const bgsCopy = JSON.parse(JSON.stringify(r.backgrounds));
for (const bg in bgsCopy) {
@@ -75,19 +85,22 @@ const stringifyRooms = (proj: IProject): IScriptablesFragment => {
extends: tileLayer.extends ? getUnwrappedExtends(tileLayer.extends) : {}
};
for (const tile of tileLayer.tiles) {
- for (let x = 0; x < tile.grid[2]; x++) {
- for (let y = 0; y < tile.grid[3]; y++) {
- const texture = glob.texturemap[tile.texture].g;
- layer.tiles.push({
- texture: texture.name,
- frame: tile.grid[0] + x + (y + tile.grid[1]) * texture.grid[0],
- x: tile.x + x * (texture.width + texture.marginx),
- y: tile.y + y * (texture.height + texture.marginy),
- width: texture.width,
- height: texture.height
- });
- }
- }
+ const texture = glob.texturemap[tile.texture].g;
+ layer.tiles.push({
+ texture: texture.name,
+ frame: tile.frame,
+ x: tile.x,
+ y: tile.y,
+ width: texture.width,
+ height: texture.height,
+ opacity: tile.opacity,
+ rotation: tile.rotation,
+ scale: {
+ x: tile.scale.x,
+ y: tile.scale.y
+ },
+ tint: tile.tint
+ });
}
tileLayers.push(layer);
}
@@ -119,6 +132,7 @@ ct.rooms.templates['${r.name}'] = {
onCreate() {
${scriptableCode.thisOnCreate}
},
+ isUi: ${r.isUi},
extends: ${r.extends ? JSON.stringify(getUnwrappedExtends(r.extends), null, 4) : '{}'}
}
`;
diff --git a/src/node_requires/exporter/templates.ts b/src/node_requires/exporter/templates.ts
index db84234ec..960b09440 100644
--- a/src/node_requires/exporter/templates.ts
+++ b/src/node_requires/exporter/templates.ts
@@ -17,6 +17,7 @@ const stringifyTemplates = function (proj: IProject): IScriptablesFragment {
ct.templates.templates["${template.name}"] = {
depth: ${template.depth},
blendMode: PIXI.BLEND_MODES.${template.blendMode?.toUpperCase() ?? 'NORMAL'},
+ animationFPS: ${template.animationFPS ?? 60},
playAnimationOnStart: ${Boolean(template.playAnimationOnStart)},
loopAnimation: ${Boolean(template.loopAnimation)},
${template.texture !== -1 ? 'texture: "' + getTextureFromId(template.texture).name + '",' : ''}
diff --git a/src/node_requires/extendGlobals.d.ts b/src/node_requires/extendGlobals.d.ts
index 794d1b480..d832d8f3e 100644
--- a/src/node_requires/extendGlobals.d.ts
+++ b/src/node_requires/extendGlobals.d.ts
@@ -11,6 +11,8 @@ declare global {
var monaco: any;
var currentProject: IProject;
var projdir: string;
+ var migrationProcess: any[];
+ var riot: any;
function showOpenDialog(options: any): Promise;
function showSaveDialog(options: any): Promise;
interface Window {
diff --git a/src/node_requires/hotkeys.js b/src/node_requires/hotkeys.js
index 116be69a0..057fb9000 100644
--- a/src/node_requires/hotkeys.js
+++ b/src/node_requires/hotkeys.js
@@ -12,6 +12,13 @@ on key presses in a declarative way, based on HTML markup plus a couple of scopi
On each key press, the lib queries the document for the resulting key combination.
The selector is `[data-hotkey="Your-Code"]`
+Your-Code is in form `Ctrl+Alt+Meta+X`, where X is a pressed letter.
+If you need the Shift key modifier, the letter will be an uppercase one.
+If not, use the lowercase letter.
+The code for Shift+S is just `S`, the code for just S key is `s`.
+Every modifier is optional. Examples: `l`, `5`, `Ctrl+1`, `Ctrl+C`.
+Do follow the order of modifiers: `Ctrl+Alt+c` is valid, but `Alt+Ctrl+c` is not.
+
You can narrow the scope of the query by calling `hotkey.push(scope)`. (See more methods below.)
The scope is nested, forming a stack. If a scope is specified, it is read from the most recently
added part to the outer scope, trying to call the elements that are inside a scoped parent.
@@ -67,6 +74,7 @@ const hotkeyRef = Symbol('hotkey');
class Hotkeys {
constructor(doc) {
+ this.isFormField = isFormField;
this.document = doc;
this.document[hotkeyRef] = this;
this.scopeStack = [];
@@ -74,8 +82,12 @@ class Hotkeys {
this[offDomEventsRef] = new Map();
this[listenerRef] = e => {
+ // Ignore key events when typing into form fields
+ if (isFormField(e.target)) {
+ return;
+ }
const code = getCode(e);
- this.trigger(code);
+ this.trigger(code, e);
};
this.document.body.addEventListener('keydown', this[listenerRef]);
}
@@ -98,12 +110,13 @@ class Hotkeys {
this[offDomEventsRef].set(code, []);
}
}
- trigger(code) {
+ trigger(code, event) {
const offDom = this[offDomEventsRef].get(code);
if (offDom) {
for (const event of offDom) {
event();
}
+ event.preventDefault();
}
// querySelectorAll returns a NodeList, which is not a sortable array. Convert by spreading.
@@ -128,6 +141,7 @@ class Hotkeys {
} else {
elt.click();
}
+ event.preventDefault();
return;
}
}
@@ -143,6 +157,7 @@ class Hotkeys {
} else {
elt.click();
}
+ event.preventDefault();
return;
}
}
diff --git a/src/node_requires/resources/emitterTandems/index.ts b/src/node_requires/resources/emitterTandems/index.ts
index 885ba209e..0237ec0ac 100644
--- a/src/node_requires/resources/emitterTandems/index.ts
+++ b/src/node_requires/resources/emitterTandems/index.ts
@@ -2,7 +2,7 @@ const getThumbnail = function getThumbnail(): string {
return 'sparkles';
};
const getById = function getById(id: string): ITandem {
- const tandem = (window as Window).currentProject.tandems.find((t: ITandem) => t.uid === id);
+ const tandem = (window as Window).currentProject.emitterTandems.find((t: ITandem) => t.uid === id);
if (!tandem) {
throw new Error(`Attempt to get a non-existent tandem with ID ${id}`);
}
diff --git a/src/node_requires/resources/modules/typedefs.ts b/src/node_requires/resources/modules/typedefs.ts
index 7dbfd07a1..074afa003 100644
--- a/src/node_requires/resources/modules/typedefs.ts
+++ b/src/node_requires/resources/modules/typedefs.ts
@@ -55,7 +55,7 @@ const resetTypedefs = function resetTypedefs(): void {
}
};
-export = {
+export {
addTypedefs,
removeTypedefs,
loadAllTypedefs,
diff --git a/src/node_requires/resources/projects/IProject.d.ts b/src/node_requires/resources/projects/IProject.d.ts
index ba44fc28e..c0d420fd5 100644
--- a/src/node_requires/resources/projects/IProject.d.ts
+++ b/src/node_requires/resources/projects/IProject.d.ts
@@ -3,8 +3,44 @@ declare interface IProject {
templates: ITemplate[];
sounds: ISound[];
rooms: IRoom[];
- tandems: ITandem[];
+ emitterTandems: ITandem[];
fonts: IFont[];
styles: IStyle[];
+ settings: {
+ authoring: {
+ author: string,
+ site: string,
+ title: string
+ version: [number, number, number],
+ versionPostfix: string,
+ appId: string
+ },
+ rendering: {
+ usePixiLegacy: boolean,
+ maxFPS: 60,
+ pixelatedrender: boolean,
+ highDensity: boolean,
+ desktopMode: 'maximized' | 'fullscreen' | 'windowed',
+ hideCursor: boolean,
+ mobileScreenOrientation: 'unspecified' | 'landscape' | 'portrait'
+ },
+ export: {
+ windows: boolean,
+ linux: boolean,
+ mac: boolean,
+ functionWrap: boolean,
+ codeModifier: 'none' | 'minify' | 'obfuscate'
+ },
+ branding: {
+ icon: assetRef,
+ /** A hex color */
+ accent: string,
+ invertPreloaderScheme: boolean,
+ splashScreen: assetRef,
+ forceSmoothIcons: boolean,
+ forceSmoothSplashScreen: boolean,
+ hideLoadingLogo: boolean
+ }
+ };
[key: string]: any;
}
diff --git a/src/node_requires/resources/projects/defaultProject.js b/src/node_requires/resources/projects/defaultProject.ts
similarity index 75%
rename from src/node_requires/resources/projects/defaultProject.js
rename to src/node_requires/resources/projects/defaultProject.ts
index d41306d80..a8a23f089 100644
--- a/src/node_requires/resources/projects/defaultProject.js
+++ b/src/node_requires/resources/projects/defaultProject.ts
@@ -1,4 +1,4 @@
-const defaultProjectTemplate = {
+const defaultProjectTemplate: IProject = {
ctjsVersion: process.versions.ctjs,
notes: '/* empty */',
libs: {
@@ -19,6 +19,7 @@ const defaultProjectTemplate = {
templates: [],
sounds: [],
styles: [],
+ fonts: [],
rooms: [],
actions: [],
emitterTandems: [],
@@ -40,14 +41,17 @@ const defaultProjectTemplate = {
site: '',
title: '',
version: [0, 0, 0],
- versionPostfix: ''
+ versionPostfix: '',
+ appId: ''
},
rendering: {
usePixiLegacy: true,
maxFPS: 60,
pixelatedrender: false,
highDensity: true,
- desktopMode: 'maximized'
+ desktopMode: 'maximized',
+ hideCursor: false,
+ mobileScreenOrientation: 'unspecified'
},
export: {
windows: true,
@@ -57,15 +61,19 @@ const defaultProjectTemplate = {
codeModifier: 'none'
},
branding: {
- icon: -1,
accent: '#446adb', // ct.js' crystal blue
- invertPreloaderScheme: true
+ invertPreloaderScheme: true,
+ icon: -1,
+ splashScreen: -1,
+ forceSmoothIcons: false,
+ forceSmoothSplashScreen: false,
+ hideLoadingLogo: false
}
}
};
module.exports = {
- get() {
- return JSON.parse(JSON.stringify(defaultProjectTemplate));
+ get(): IProject {
+ return JSON.parse(JSON.stringify(defaultProjectTemplate)) as IProject;
}
};
diff --git a/src/node_requires/resources/projects/index.ts b/src/node_requires/resources/projects/index.ts
index 3323e1893..c4484b45e 100644
--- a/src/node_requires/resources/projects/index.ts
+++ b/src/node_requires/resources/projects/index.ts
@@ -1,3 +1,250 @@
+import {populatePixiTextureCache, setPixelart} from '../textures';
+import {loadAllTypedefs, resetTypedefs} from '../modules/typedefs';
+import {unloadAllEvents, loadAllModulesEvents} from '../../events';
+import * as path from 'path';
+
+const fs = require('fs-extra');
+
+// @see https://semver.org/
+const semverRegex = /(\d+)\.(\d+)\.(\d+)(-[A-Za-z.-]*(\d+)?[A-Za-z.-]*)?/;
+const semverToArray = (string: string) => {
+ const raw = semverRegex.exec(string);
+ return [
+ raw[1],
+ raw[2],
+ raw[3],
+ // -next- versions and other postfixes will count as a fourth component.
+ // They all will apply before regular versions
+ raw[4] ? raw[5] || 1 : null
+ ];
+};
+
+interface IMigrationPlan {
+ version: string,
+ process: (project: Partial) => Promise;
+}
+
+/**
+* Applies migration scripts to older projects.
+*/
+const adapter = async (project: Partial) => {
+ var version = semverToArray(project.ctjsVersion || '0.2.0');
+
+ const migrationToExecute = window.migrationProcess
+ // Sort all the patches chronologically
+ .sort((m1: IMigrationPlan, m2: IMigrationPlan) => {
+ const m1Version = semverToArray(m1.version);
+ const m2Version = semverToArray(m2.version);
+
+ for (let i = 0; i < 4; i++) {
+ if (m1Version[i] < m2Version[i] || m1Version[i] === null) {
+ return -1;
+ } else if (m1Version[i] > m2Version[i]) {
+ return 1;
+ }
+ }
+ // eslint-disable-next-line no-console
+ console.warn(`Two equivalent versions found for migration, ${m1.version} and ${m2.version}.`);
+ return 0;
+ })
+ // Throw out patches for current and previous versions
+ .filter((migration: IMigrationPlan) => {
+ const migrationVersion = semverToArray(migration.version);
+ for (let i = 0; i < 3; i++) {
+ // if any of the first three version numbers is lower than project's,
+ // skip the patch
+ if (migrationVersion[i] < version[i]) {
+ return false;
+ }
+ if (migrationVersion[i] > version[i]) {
+ return true;
+ }
+ }
+ // a lazy check for equal base versions
+ if (migrationVersion.slice(0, 3).join('.') === version.slice(0, 3).join('.')) {
+ // handle the case with two postfixed versions
+ if (migrationVersion[3] !== null && version[3] !== null) {
+ return migrationVersion[3] > version[3];
+ }
+ // postfixed source, unpostfixed patch
+ if (migrationVersion[3] === null && version[3] !== null) {
+ return true;
+ }
+ return false;
+ }
+ return true;
+ });
+
+ if (migrationToExecute.length) {
+ // eslint-disable-next-line no-console
+ console.debug(`Applying migration sequence: patches ${migrationToExecute.map((m: IMigrationPlan) => m.version).join(', ')}.`);
+ }
+ for (const migration of migrationToExecute) {
+ // eslint-disable-next-line no-console
+ console.debug(`Migrating project from version ${project.ctjsVersion || '0.2.0'} to ${migration.version}`);
+ // We do need to apply updates in a sequence
+ // eslint-disable-next-line no-await-in-loop
+ await migration.process(project);
+ }
+
+ // Unfortunately, recent versions of eslint give false positives on this line
+ // @see https://github.com/eslint/eslint/issues/11900
+ // @see https://github.com/eslint/eslint/issues/11899
+ // eslint-disable-next-line require-atomic-updates
+ project.ctjsVersion = process.versions.ctjs;
+};
+
+/**
+* Opens the project and refreshes the whole app.
+*
+* @param {IProject} projectData Loaded JSON file, in js object form
+* @returns {Promise}
+*/
+const loadProject = async (projectData: IProject): Promise => {
+ const glob = require('../../glob');
+ window.currentProject = projectData;
+ window.alertify.log(window.languageJSON.intro.loadingProject);
+ glob.modified = false;
+
+ try {
+ await adapter(projectData);
+ fs.ensureDir(global.projdir);
+ fs.ensureDir(global.projdir + '/img');
+ fs.ensureDir(global.projdir + '/snd');
+
+ const lastProjects = localStorage.lastProjects ? localStorage.lastProjects.split(';') : [];
+ if (lastProjects.indexOf(path.normalize(global.projdir + '.ict')) !== -1) {
+ lastProjects.splice(lastProjects.indexOf(path.normalize(global.projdir + '.ict')), 1);
+ }
+ lastProjects.unshift(path.normalize(global.projdir + '.ict'));
+ if (lastProjects.length > 15) {
+ lastProjects.pop();
+ }
+ localStorage.lastProjects = lastProjects.join(';');
+
+ if (window.currentProject.settings.authoring.title) {
+ document.title = window.currentProject.settings.authoring.title + ' — ct.js';
+ }
+
+ glob.scriptTypings = {};
+ for (const script of window.currentProject.scripts) {
+ glob.scriptTypings[script.name] = [
+ monaco.languages.typescript.javascriptDefaults.addExtraLib(script.code),
+ monaco.languages.typescript.typescriptDefaults.addExtraLib(script.code)
+ ];
+ }
+
+ resetTypedefs();
+ loadAllTypedefs();
+
+ unloadAllEvents();
+ setPixelart(projectData.settings.rendering.pixelatedrender);
+ await Promise.all([
+ loadAllModulesEvents(),
+ populatePixiTextureCache(projectData)
+ ]);
+
+ window.signals.trigger('projectLoaded');
+ setTimeout(() => {
+ window.riot.update();
+ }, 0);
+ } catch (err) {
+ window.alertify.alert(window.languageJSON.intro.loadingProjectError + err);
+ }
+};
+
+/**
+* Checks file format and loads it
+*
+* @param {String} proj The path to the file.
+* @returns {void}
+*/
+const readProjectFile = async (proj: string) => {
+ const textProjData = await fs.readFile(proj, 'utf8');
+ let projectData;
+ // Before v1.3, projects were stored in JSON format
+ try {
+ if (textProjData.indexOf('{') === 0) { // First, make a silly check for JSON files
+ projectData = JSON.parse(textProjData);
+ } else {
+ try {
+ const YAML = require('js-yaml');
+ projectData = YAML.load(textProjData);
+ } catch (e) {
+ // whoopsie, wrong window
+ // eslint-disable-next-line no-console
+ console.warn(`Tried to load a file ${proj} as a YAML, but got an error (see below). Falling back to JSON.`);
+ console.error(e);
+ projectData = JSON.parse(textProjData);
+ }
+ }
+ } catch (e) {
+ window.alertify.error(e);
+ throw e;
+ }
+ if (!projectData) {
+ window.alertify.error(window.languageJSON.common.wrongFormat);
+ return;
+ }
+ try {
+ loadProject(projectData);
+ } catch (e) {
+ window.alertify.error(e);
+ throw e;
+ }
+};
+
+/**
+ * Opens a project file, checking for recovery files and asking
+ * a user about them if needed.
+ * This is the method that should be used for opening ct.js projects
+ * from within UI.
+ */
+const openProject = async (proj: string): Promise => {
+ if (!proj) {
+ const baseMessage = 'An attempt to open a project with an empty path.';
+ alertify.error(baseMessage + ' See the console for the call stack.');
+ const err = new Error(baseMessage);
+ throw err;
+ }
+ sessionStorage.projname = path.basename(proj);
+ global.projdir = path.dirname(proj) + path.sep + path.basename(proj, '.ict');
+
+ // Check for recovery files
+ let recoveryStat;
+ try {
+ recoveryStat = await fs.stat(proj + '.recovery');
+ } catch (err) {
+ // no recovery file found
+ void 0;
+ }
+ if (recoveryStat && recoveryStat.isFile()) {
+ const targetStat = await fs.stat(proj);
+ const voc = window.languageJSON.intro.recovery;
+ const userResponse = await window.alertify
+ .okBtn(voc.loadRecovery)
+ .cancelBtn(voc.loadTarget)
+ /* {0} — target file date
+ {1} — target file state (newer/older)
+ {2} — recovery file date
+ {3} — recovery file state (newer/older)
+ */
+ .confirm(voc.message
+ .replace('{0}', targetStat.mtime.toLocaleString())
+ .replace('{1}', targetStat.mtime < recoveryStat.mtime ? voc.older : voc.newer)
+ .replace('{2}', recoveryStat.mtime.toLocaleString())
+ .replace('{3}', recoveryStat.mtime < targetStat.mtime ? voc.older : voc.newer));
+ window.alertify
+ .okBtn(window.languageJSON.common.ok)
+ .cancelBtn(window.languageJSON.common.cancel);
+ if (userResponse.buttonClicked === 'ok') {
+ return readProjectFile(proj + '.recovery');
+ }
+ return readProjectFile(proj);
+ }
+ return readProjectFile(proj);
+};
+
const defaultProject = require('./defaultProject');
/**
@@ -55,7 +302,7 @@ const getProjectDir = function (projPath: string): string {
* @param {string} projPath
* @param {boolean} [fs] Whether to return a filesystem path (true) or a URL (false; default).
*/
-const getProjectThumbnail = function (projPath: string, fs?: boolean) {
+const getProjectThumbnail = function (projPath: string, fs?: boolean): string {
const path = require('path');
projPath = getProjectDir(projPath);
if (fs) {
@@ -77,6 +324,7 @@ const getProjectIct = function (projPath: string): string {
};
export {
+ openProject,
defaultProject,
getDefaultProjectDir,
getProjectThumbnail,
diff --git a/src/node_requires/resources/rooms/IRoom.d.ts b/src/node_requires/resources/rooms/IRoom.d.ts
index 5ad1b0330..8dbd837f3 100644
--- a/src/node_requires/resources/rooms/IRoom.d.ts
+++ b/src/node_requires/resources/rooms/IRoom.d.ts
@@ -3,31 +3,45 @@ type canvasPatternRepeat = 'repeat' | 'repeat-x' | 'repeat-y' | 'no-repeat';
interface IRoomBackground {
depth: number,
texture: assetRef,
- extends: {
- parallaxX?: number,
- parallaxY?: number,
- shiftX?: number,
- shiftY?: number,
- repeat: canvasPatternRepeat
- [key: string]: unknown
- }
+ parallaxX: number,
+ parallaxY: number,
+ shiftX: number,
+ shiftY: number,
+ movementX: number,
+ movementY: number,
+ scaleX: number,
+ scaleY: number,
+ repeat: canvasPatternRepeat
}
interface IRoomCopy {
x: number,
y: number,
- uid: assetRef,
- tx?: number,
- ty?: number,
+ uid: string,
+ scale: {
+ x: number,
+ y: number
+ },
+ rotation?: number,
+ tint?: number,
+ opacity?: number,
exts: {
[key: string]: unknown
- }
+ },
+ customProperties: Record
}
interface ITileTemplate {
x: number;
y: number;
- grid: number[];
+ opacity: number;
+ tint: number;
+ frame: number;
+ scale: {
+ x: number,
+ y: number
+ };
+ rotation: number;
texture: string;
}
@@ -35,24 +49,28 @@ interface ITileLayerTemplate {
depth: number;
tiles: Array,
extends?: Record
+ hidden?: boolean;
}
interface IRoom extends IScriptable {
- width: number,
- height: number,
+ width: number;
+ height: number;
/** A CSS color */
- backgroundColor: string,
- backgrounds: Array,
- copies: Array,
- tiles: Array
- gridX: number,
- gridY: number,
- restrictCamera?: boolean,
- restrictMinX?: number,
- restrictMinY?: number,
- restrictMaxX?: number,
- restrictMaxY?: number,
+ backgroundColor: string;
+ backgrounds: Array;
+ copies: Array;
+ tiles: Array;
+ gridX: number;
+ gridY: number;
+ diagonalGrid: boolean;
+ simulate: boolean;
+ restrictCamera?: boolean;
+ restrictMinX?: number;
+ restrictMinY?: number;
+ restrictMaxX?: number;
+ restrictMaxY?: number;
+ isUi: boolean;
extends: {
[key: string]: unknown
- }
+ };
}
diff --git a/src/node_requires/resources/rooms/defaultRoom.ts b/src/node_requires/resources/rooms/defaultRoom.ts
index b5373a7b7..1a1320c9d 100644
--- a/src/node_requires/resources/rooms/defaultRoom.ts
+++ b/src/node_requires/resources/rooms/defaultRoom.ts
@@ -8,8 +8,11 @@ const room = {
onleave: '',
gridX: 64,
gridY: 64,
+ diagonalGrid: false,
+ simulate: true,
width: 1280,
- height: 720
+ height: 720,
+ isUi: false
};
const get = function (): IRoom {
diff --git a/src/node_requires/resources/rooms/index.ts b/src/node_requires/resources/rooms/index.ts
index ec035a573..85d9460d9 100644
--- a/src/node_requires/resources/rooms/index.ts
+++ b/src/node_requires/resources/rooms/index.ts
@@ -1,3 +1,5 @@
+import {outputCanvasToFile} from '../../utils/imageUtils';
+
const getDefaultRoom = require('./defaultRoom').get;
const fs = require('fs-extra');
const path = require('path');
@@ -31,7 +33,6 @@ const getById = getRoomFromId;
* Retrieves the full path to a thumbnail of a given room.
* @param {string|IRoom} room Either the id of the room, or its ct.js object
* @param {boolean} [x2] If set to true, returns a 340x256 image instead of 64x64.
- * (Not implemented, actually!)
* @param {boolean} [fs] If set to true, returns a file system path, not a URI.
* @returns {string} The full path to the thumbnail.
*/
@@ -44,16 +45,39 @@ const getRoomPreview = (room: assetRef | IRoom, x2: boolean, fs: boolean): strin
room = getRoomFromId(room);
}
if (fs) {
- return `${(global as any).projdir}/img/r${room.uid}.png`;
+ return `${(global as any).projdir}/img/r${room.uid}${x2 ? '@r' : ''}.png`;
}
- return `file://${(global as any).projdir}/img/r${room.uid}.png?${room.lastmod}`;
+ return `file://${(global as any).projdir}/img/r${room.uid}${x2 ? '@r' : ''}.png?${room.lastmod}`;
};
const getThumbnail = getRoomPreview;
+const writeRoomPreview = (
+ room: assetRef | IRoom,
+ canvas: HTMLCanvasElement,
+ x2: boolean
+): Promise | Promise => {
+ if (typeof room === 'number') {
+ throw new Error('Cannot write a room preview for a room -1');
+ }
+ if (typeof room === 'string') {
+ room = getRoomFromId(room);
+ }
+ const path = `${(global as any).projdir}/img/r${room.uid}${x2 ? '@r' : ''}.png`;
+ if (x2) {
+ const splash = `${(global as any).projdir}/img/splash.png`;
+ return Promise.all([
+ outputCanvasToFile(canvas, path),
+ outputCanvasToFile(canvas, splash)
+ ]);
+ }
+ return outputCanvasToFile(canvas, path);
+};
+
export {
createNewRoom,
getRoomFromId,
getById,
getRoomPreview,
- getThumbnail
+ getThumbnail,
+ writeRoomPreview
};
diff --git a/src/node_requires/resources/templates/ITemplate.d.ts b/src/node_requires/resources/templates/ITemplate.d.ts
index 0a0923480..415fb4448 100644
--- a/src/node_requires/resources/templates/ITemplate.d.ts
+++ b/src/node_requires/resources/templates/ITemplate.d.ts
@@ -7,6 +7,7 @@ interface ITemplate extends IScriptable {
blendMode?: PixiBlendMode,
playAnimationOnStart: boolean,
loopAnimation: boolean,
+ animationFPS: number,
extends: {
[key: string]: unknown
}
diff --git a/src/node_requires/resources/templates/defaultTemplate.ts b/src/node_requires/resources/templates/defaultTemplate.ts
index 24a410f3f..59a0a81de 100644
--- a/src/node_requires/resources/templates/defaultTemplate.ts
+++ b/src/node_requires/resources/templates/defaultTemplate.ts
@@ -7,6 +7,7 @@ const defaultTemplate = {
texture: -1 as assetRef,
playAnimationOnStart: false,
loopAnimation: true,
+ animationFPS: 30,
visible: true
};
diff --git a/src/node_requires/resources/templates/index.ts b/src/node_requires/resources/templates/index.ts
index 9df58908e..70ecb62b7 100644
--- a/src/node_requires/resources/templates/index.ts
+++ b/src/node_requires/resources/templates/index.ts
@@ -1,4 +1,5 @@
const getDefaultTemplate = require('./defaultTemplate').get;
+import {getPixiTexture as getTexturePixiTexture} from '../textures';
const createNewTemplate = function createNewTemplate(name: string): ITemplate {
const template = getDefaultTemplate();
@@ -47,11 +48,22 @@ const getTemplatePreview = function getTemplatePreview(
};
const getThumbnail = getTemplatePreview;
+const getPixiTexture = (template: ITemplate | assetRef): PIXI.Texture[] => {
+ if (typeof template === 'string') {
+ template = getTemplateFromId(template);
+ }
+ if (template === -1) {
+ throw new Error('Cannot work with -1 assetRefs');
+ }
+ return getTexturePixiTexture(template.texture, void 0, false);
+};
+
export {
getDefaultTemplate,
getTemplateFromId,
getById,
getTemplatePreview,
getThumbnail,
- createNewTemplate
+ createNewTemplate,
+ getPixiTexture
};
diff --git a/src/node_requires/resources/textures/ITexture.d.ts b/src/node_requires/resources/textures/ITexture.d.ts
index e78d9c212..c02c29149 100644
--- a/src/node_requires/resources/textures/ITexture.d.ts
+++ b/src/node_requires/resources/textures/ITexture.d.ts
@@ -3,6 +3,7 @@ interface ITexture extends IAsset {
uid: string;
name: string;
origname: string;
+ /* Number of columns and rows, accordigly */
grid: [number, number];
axis: [number, number];
width: number;
@@ -23,4 +24,5 @@ interface ITexture extends IAsset {
top?: number;
bottom?: number;
tiled?: boolean;
+ ignoreTiledUse?: boolean;
}
diff --git a/src/node_requires/resources/textures/index.ts b/src/node_requires/resources/textures/index.ts
index abaef5b4a..8c7b43b00 100644
--- a/src/node_requires/resources/textures/index.ts
+++ b/src/node_requires/resources/textures/index.ts
@@ -71,6 +71,7 @@ const baseTextureFromTexture = (texture: ITexture): Promise =>
});
});
+const unknownTexture = PIXI.Texture.from('data/img/unknown.png');
const pixiTextureCache: Record} An array of PIXI.Textures
*/
@@ -108,11 +111,20 @@ const texturesFromCtTexture = async function (tex: ITexture) {
}
}
}
+ pixiTextureCache[tex.name] = {
+ lastmod: tex.lastmod,
+ texture: frames
+ };
return frames;
};
-
-let defaultTexture: PIXI.Texture;
-
+const populatePixiTextureCache = async (project: IProject): Promise => {
+ clearPixiTextureCache();
+ const promises = [];
+ for (const texture of project.textures) {
+ promises.push(texturesFromCtTexture(texture));
+ }
+ await Promise.all(promises);
+};
// async
const getDOMImage = function (
texture: assetRef | ITexture,
@@ -136,24 +148,36 @@ const getDOMImage = function (
};
/**
- * @param {string|-1|any} texture Either a uid of a texture, or a ct.js texture object
+ * @param {assetRef | ITexture} texture Either a uid of a texture, or a ct.js texture object
* @param {number} [frame] The frame to extract. If not defined, will return an array of all frames
* @param {boolean} [allowMinusOne] Allows the use of `-1` as a texture uid
* @returns {Array|PIXI.Texture} An array of textures, or an individual one.
*/
-const getPixiTexture = async function (
+function getPixiTexture(texture: assetRef | ITexture): PIXI.Texture[];
+function getPixiTexture(
+ texture: -1
+): never;
+function getPixiTexture(
texture: assetRef | ITexture,
- frame?: number,
+ frame: void | null,
allowMinusOne?: boolean
-): Promise {
+): PIXI.Texture[];
+function getPixiTexture(
+ texture: assetRef | ITexture,
+ frame: number,
+ allowMinusOne?: boolean
+): PIXI.Texture;
+// eslint-disable-next-line func-style
+function getPixiTexture(
+ texture: assetRef | ITexture,
+ frame?: number | void | null,
+ allowMinusOne?: boolean
+): PIXI.Texture | PIXI.Texture[] {
if (allowMinusOne && texture === -1) {
- if (!defaultTexture) {
- defaultTexture = PIXI.Texture.from('data/img/unknown.png');
- }
if (frame || frame === 0) {
- return defaultTexture;
+ return unknownTexture;
}
- return [defaultTexture];
+ return [unknownTexture];
}
if (texture === -1) {
throw new Error('Cannot turn -1 into a pixi texture in getPixiTexture method unless it is explicitly allowed.');
@@ -161,24 +185,11 @@ const getPixiTexture = async function (
if (typeof texture === 'string') {
texture = getTextureFromId(texture);
}
- const {uid} = texture;
- if (!pixiTextureCache[uid] ||
- pixiTextureCache[uid].lastmod !== texture.lastmod
- ) {
- const tex = await texturesFromCtTexture(texture);
- // Everything is constant, and the key gets overridden.
- // Where's the race condition? False positive??
- // eslint-disable-next-line require-atomic-updates
- pixiTextureCache[uid] = {
- lastmod: texture.lastmod,
- texture: tex
- };
- }
if (frame || frame === 0) {
- return pixiTextureCache[uid].texture[frame];
+ return pixiTextureCache[texture.name].texture[frame];
}
- return pixiTextureCache[uid].texture;
-};
+ return pixiTextureCache[texture.name].texture;
+}
/**
* Returns a texture object by its name.
@@ -330,7 +341,13 @@ const importImageToTexture = async (
const getCleanTextureName = (name: string): string =>
name.replace(isBgPostfixTester, '').replace(texturePostfixParser, '');
-const getTexturePivot = (texture: string | ITexture, inPixels?: boolean): [number, number] => {
+const getTexturePivot = (texture: assetRef | ITexture, inPixels?: boolean): [number, number] => {
+ if (texture === -1) {
+ if (inPixels) {
+ return [16, 16];
+ }
+ return [0.5, 0.5];
+ }
if (typeof texture === 'string') {
texture = getTextureFromId(texture);
}
@@ -340,8 +357,18 @@ const getTexturePivot = (texture: string | ITexture, inPixels?: boolean): [numbe
return [texture.axis[0] / texture.width, texture.axis[1] / texture.height];
};
+const setPixelart = (pixelart: boolean): void => {
+ PIXI.settings.SCALE_MODE = pixelart ?
+ PIXI.SCALE_MODES.NEAREST :
+ PIXI.SCALE_MODES.LINEAR;
+ for (const tex in pixiTextureCache) {
+ pixiTextureCache[tex].texture[0].baseTexture.scaleMode = PIXI.settings.SCALE_MODE;
+ }
+};
+
export {
clearPixiTextureCache,
+ populatePixiTextureCache,
getTextureFromId,
getById,
getTextureFromName,
@@ -350,6 +377,8 @@ export {
getThumbnail,
getTexturePivot,
getTextureOrig,
+ texturesFromCtTexture as updatePixiTexture,
+ setPixelart,
getPixiTexture,
getDOMImage,
importImageToTexture,
diff --git a/src/node_requires/roomEditor/IRoomEditorRiotTag.d.ts b/src/node_requires/roomEditor/IRoomEditorRiotTag.d.ts
new file mode 100644
index 000000000..9d7b9f6b6
--- /dev/null
+++ b/src/node_requires/roomEditor/IRoomEditorRiotTag.d.ts
@@ -0,0 +1,39 @@
+import {TileLayer} from './entityClasses/TileLayer';
+
+import {ITilePatch} from './interactions/tiles/ITilePatch';
+import {RoomEditor} from '.';
+
+type tool = 'select' | 'addCopies' | 'addTiles' | 'manageBackgrounds' | 'roomProperties';
+
+export interface IRoomEditorRiotTag {
+ update(): void;
+ tilePatch: ITilePatch;
+ currentTileLayer: TileLayer;
+ opts: {
+ room: IRoom;
+ };
+ refs: {
+ propertiesPanel?: {
+ updatePropList(): void;
+ applyChanges(): void;
+ update(): void;
+ },
+ tileEditor?: {
+ update(): void;
+ },
+ backgroundsEditor?: {
+ update(): void;
+ },
+ zoomLabel: HTMLSpanElement
+ };
+ root: HTMLElement;
+ pixiEditor: RoomEditor;
+ zoom: number;
+ gridOn: boolean;
+ freePlacementMode: boolean;
+ controlMode: boolean;
+ currentTool: tool;
+ currentTemplate: ITemplate | -1;
+ setTool(tool: tool): () => void;
+ changeSelectedTemplate(templateId: string): void;
+}
diff --git a/src/node_requires/roomEditor/common.ts b/src/node_requires/roomEditor/common.ts
new file mode 100644
index 000000000..ead9589f5
--- /dev/null
+++ b/src/node_requires/roomEditor/common.ts
@@ -0,0 +1,116 @@
+interface ISimplePoint {
+ x: number;
+ y: number;
+}
+
+export const defaultTextStyle = new PIXI.TextStyle({
+ dropShadow: true,
+ dropShadowDistance: 2,
+ dropShadowAlpha: 0.35,
+ fill: '#fff',
+ fontFamily: '\'Open Sans\',sans-serif,serif',
+ fontSize: 16
+});
+
+/** Converts global coordinates to coordinates on a diagonal grid */
+export const toDiagonal = (pos: ISimplePoint, gridX: number, gridY: number): ISimplePoint => ({
+ x: pos.y / gridY + pos.x / gridX,
+ y: -pos.x / gridX + pos.y / gridY
+});
+/** Converts coordinates on a diagonal grid to global coordinates */
+export const fromDiagonal = (pos: ISimplePoint, gridX: number, gridY: number): ISimplePoint => ({
+ x: 0.5 * gridX * (pos.x - pos.y),
+ y: 0.5 * gridY * (pos.x + pos.y)
+});
+/** Converts global coordinates to coordinates on a rectangular grid */
+export const toRectangular = (pos: ISimplePoint, gridX: number, gridY: number): ISimplePoint => ({
+ x: pos.x / gridX,
+ y: pos.y / gridY
+});
+/** Converts coordinates on a rectangular grid to global coordinates */
+export const fromRectangular = (pos: ISimplePoint, gridX: number, gridY: number): ISimplePoint => ({
+ x: pos.x * gridX,
+ y: pos.y * gridY
+});
+
+export const snapToDiagonalGrid = (
+ pos: ISimplePoint,
+ gridX: number,
+ gridY: number
+): ISimplePoint => {
+ const diag = toDiagonal({
+ x: pos.x,
+ y: pos.y
+ }, gridX, gridY);
+ return fromDiagonal({
+ x: Math.round(diag.x),
+ y: Math.round(diag.y)
+ }, gridX, gridY);
+};
+export const snapToRectangularGrid = (
+ pos: ISimplePoint,
+ gridX: number,
+ gridY: number
+): ISimplePoint => ({
+ x: Math.round(pos.x / gridX) * gridX,
+ y: Math.round(pos.y / gridY) * gridY
+});
+
+export const eraseCursor = 'url("data/cursorErase.svg") 1 1, default';
+export const rotateCursor = 'url("data/cursorRotate.svg") 12 12, pointer';
+
+/**
+ * Six filters that recolor any DisplayObject to one of the primary+secondary colors.
+ * The colors:
+ *
+ * 0: Red
+ * 1: Yellow
+ * 2: Green
+ * 3: Aqua
+ * 4: Blue
+ * 5: Magenta
+ */
+export const recolorFilters: PIXI.filters.ColorMatrixFilter[] = [];
+for (let i = 0; i < 6; i++) {
+ const filter = new PIXI.filters.ColorMatrixFilter();
+ recolorFilters.push(filter);
+}
+/* eslint-disable array-element-newline, no-underscore-dangle, no-multi-spaces */
+recolorFilters[0]._loadMatrix([
+ 1, 1, 1, 0, 0,
+ 0.1, 0.1, 0.1, 0, 0,
+ 0.1, 0.1, 0.1, 0, 0,
+ 0, 0, 0, 1, 0
+], false);
+recolorFilters[1]._loadMatrix([
+ 0.5, 0.5, 0.5, 0, 0,
+ 0.5, 0.5, 0.5, 0, 0,
+ 0.1, 0.1, 0.1, 0, 0,
+ 0, 0, 0, 1, 0
+], false);
+recolorFilters[2]._loadMatrix([
+ 0.1, 0.1, 0.1, 0, 0,
+ 1, 1, 1, 0, 0,
+ 0.1, 0.1, 0.1, 0, 0,
+ 0, 0, 0, 1, 0
+], false);
+recolorFilters[3]._loadMatrix([
+ 0.1, 0.1, 0.1, 0, 0,
+ 0.5, 0.5, 0.5, 0, 0,
+ 0.5, 0.5, 0.5, 0, 0,
+ 0, 0, 0, 1, 0
+], false);
+recolorFilters[4]._loadMatrix([
+ 0.1, 0.1, 0.1, 0, 0,
+ 0.1, 0.1, 0.1, 0, 0,
+ 1, 1, 1, 0, 0,
+ 0, 0, 0, 1, 0
+], false);
+recolorFilters[5]._loadMatrix([
+ 0.5, 0.5, 0.5, 0, 0,
+ 0.1, 0.1, 0.1, 0, 0,
+ 0.5, 0.5, 0.5, 0, 0,
+ 0, 0, 0, 1, 0
+], false);
+/* eslint-enable array-element-newline, no-underscore-dangle, no-multi-spaces*/
+
diff --git a/src/node_requires/roomEditor/entityClasses/Background.ts b/src/node_requires/roomEditor/entityClasses/Background.ts
new file mode 100644
index 000000000..e48586aae
--- /dev/null
+++ b/src/node_requires/roomEditor/entityClasses/Background.ts
@@ -0,0 +1,125 @@
+import {getPixiTexture} from '../../resources/textures';
+import {RoomEditor} from '..';
+
+class Background extends PIXI.TilingSprite {
+ bgTexture: assetRef;
+ editor: RoomEditor;
+ shiftX = 0;
+ shiftY = 0;
+ parallaxX = 1;
+ parallaxY = 1;
+ movementX = 0;
+ movementY = 0;
+ simulatedMovedX = 0;
+ simulatedMovedY = 0;
+ repeat: canvasPatternRepeat = 'repeat';
+
+ constructor(bgInfo: IRoomBackground, editor: RoomEditor) {
+ super(getPixiTexture(bgInfo.texture, 0, true));
+ this.anchor.x = this.anchor.y = 0;
+ this.editor = editor;
+ this.deserialize(bgInfo);
+ this.tick(0);
+ }
+ destroy(): void {
+ const ind = this.editor.backgrounds.indexOf(this);
+ if (ind !== -1) {
+ this.editor.backgrounds.splice(ind, 1);
+ this.editor.riotEditor.refs.backgroundsEditor.update();
+ }
+ super.destroy();
+ }
+ detach(): this {
+ const ind = this.editor.backgrounds.indexOf(this);
+ if (ind === -1) {
+ throw new Error('Attempt to detach an off-screen background');
+ }
+ this.editor.backgrounds.splice(ind, 1);
+ this.parent.removeChild(this);
+ this.editor.riotEditor.refs.backgroundsEditor.update();
+ return this;
+ }
+ restore(): this {
+ this.editor.backgrounds.push(this);
+ this.editor.room.addChild(this);
+ this.editor.riotEditor.refs.backgroundsEditor.update();
+ return this;
+ }
+
+ changeTexture(id: assetRef): void {
+ this.texture = getPixiTexture(id, 0, true);
+ this.anchor.x = this.anchor.y = 0;
+ this.bgTexture = id;
+ }
+
+ serialize(): IRoomBackground {
+ return {
+ depth: this.zIndex,
+ texture: this.bgTexture as string,
+ shiftX: this.shiftX,
+ shiftY: this.shiftY,
+ parallaxX: this.parallaxX,
+ parallaxY: this.parallaxY,
+ movementX: this.movementX,
+ movementY: this.movementY,
+ scaleX: this.tileScale.x,
+ scaleY: this.tileScale.y,
+ repeat: this.repeat
+ };
+ }
+ deserialize(bg: IRoomBackground): void {
+ this.zIndex = bg.depth;
+ this.bgTexture = bg.texture;
+ this.shiftX = bg.shiftX;
+ this.shiftY = bg.shiftY;
+ this.parallaxX = bg.parallaxX;
+ this.parallaxY = bg.parallaxY;
+ this.movementX = bg.movementX;
+ this.movementY = bg.movementY;
+ this.tileScale.set(bg.scaleX, bg.scaleY);
+ this.repeat = bg.repeat;
+ }
+ refreshTexture(): void {
+ this.texture = getPixiTexture(this.bgTexture, 0);
+ this.anchor.x = this.anchor.y = 0;
+ }
+ tick(deltaTime: number): void {
+ const {camera, screen} = this.editor;
+ const cameraBounds = {
+ x: camera.x - screen.width / 2 * camera.scale.x,
+ y: camera.y - screen.height / 2 * camera.scale.y,
+ width: screen.width * camera.scale.x,
+ height: screen.height * camera.scale.y
+ };
+ if (this.movementX === 0) {
+ this.simulatedMovedX = 0;
+ }
+ if (this.movementY === 0) {
+ this.simulatedMovedY = 0;
+ }
+ if (deltaTime > 0) {
+ this.simulatedMovedX += deltaTime * this.movementX;
+ this.simulatedMovedY += deltaTime * this.movementY;
+ }
+ if (this.repeat !== 'repeat-x' && this.repeat !== 'no-repeat') {
+ this.y = cameraBounds.y;
+ this.tilePosition.y = -this.y * this.parallaxY + this.shiftY + this.simulatedMovedY;
+ this.height = cameraBounds.height + 1;
+ } else {
+ this.y = this.shiftY + this.simulatedMovedY + cameraBounds.y * (this.parallaxY - 1);
+ this.height = this.texture.height * this.tileScale.y;
+ this.tilePosition.y = 0;
+ }
+ if (this.repeat !== 'repeat-y' && this.repeat !== 'no-repeat') {
+ this.x = cameraBounds.x;
+ this.tilePosition.x = -this.x * this.parallaxX + this.shiftX + this.simulatedMovedX;
+ this.width = cameraBounds.width + 1;
+ } else {
+ this.x = this.shiftX + this.simulatedMovedX + cameraBounds.x * (this.parallaxX - 1);
+ this.width = this.texture.width * this.tileScale.x;
+ this.tilePosition.x = 0;
+ }
+ }
+}
+
+export {Background};
diff --git a/src/node_requires/roomEditor/entityClasses/Copy.ts b/src/node_requires/roomEditor/entityClasses/Copy.ts
new file mode 100644
index 000000000..cb53bab6c
--- /dev/null
+++ b/src/node_requires/roomEditor/entityClasses/Copy.ts
@@ -0,0 +1,104 @@
+import {RoomEditor} from '..';
+import {getPixiTexture, getTemplateFromId} from '../../resources/templates';
+import {getTexturePivot} from '../../resources/textures';
+
+/**
+ * @notice This class automatically adds and removes itself from editor's copy list
+ */
+class Copy extends PIXI.AnimatedSprite {
+ templateId: string;
+ copyExts: Record;
+ copyCustomProps: Record;
+ cachedTemplate: ITemplate;
+ isGhost: boolean;
+ editor: RoomEditor;
+ autoUpdate: boolean;
+ update: (deltaTime: number) => void;
+
+ constructor(copyInfo: IRoomCopy, editor: RoomEditor, isGhost?: boolean) {
+ super(getPixiTexture(copyInfo.uid));
+ this.editor = editor;
+ this.templateId = copyInfo.uid;
+ this.autoUpdate = false;
+ const t = getTemplateFromId(this.templateId as string);
+ this.cachedTemplate = t;
+ this.deserialize(copyInfo);
+ this.isGhost = Boolean(isGhost);
+ this.interactive = !this.isGhost;
+ if (t.playAnimationOnStart) {
+ this.play();
+ }
+ if (!this.isGhost) {
+ editor.copies.add(this);
+ }
+ }
+ destroy(): void {
+ if (!this.isGhost) {
+ this.editor.copies.delete(this);
+ }
+ super.destroy();
+ }
+ detach(): this {
+ this.editor.copies.delete(this);
+ this.editor.room.removeChild(this);
+ return this;
+ }
+ restore(): this {
+ this.editor.copies.add(this);
+ this.editor.room.addChild(this);
+ return this;
+ }
+
+ get animated(): boolean {
+ return getTemplateFromId(this.templateId as string).playAnimationOnStart;
+ }
+
+ serialize(): IRoomCopy {
+ return {
+ x: this.x,
+ y: this.y,
+ opacity: this.alpha,
+ tint: this.tint,
+ scale: {
+ x: this.scale.x,
+ y: this.scale.y
+ },
+ rotation: this.rotation,
+ uid: this.templateId,
+ exts: this.copyExts,
+ customProperties: this.copyCustomProps
+ };
+ }
+ deserialize(copy: IRoomCopy): void {
+ this.x = copy.x;
+ this.y = copy.y;
+ this.zIndex = this.cachedTemplate.depth;
+ this.alpha = copy.opacity ?? 1;
+ this.tint = copy.tint ?? 0xffffff;
+ this.scale.x = copy.scale?.x ?? 1;
+ this.scale.y = copy.scale?.y ?? 1;
+ this.rotation = copy.rotation ?? 0;
+ this.templateId = copy.uid;
+ this.copyExts = copy.exts ?? {};
+ this.copyCustomProps = copy.customProperties ?? {};
+ const t = getTemplateFromId(this.templateId as string);
+ this.animationSpeed = t.animationFPS / 60;
+ this.loop = t.loopAnimation ?? true;
+ if (t.texture !== -1) {
+ [this.anchor.x, this.anchor.y] = getTexturePivot(t.texture);
+ } else {
+ this.anchor.x = this.anchor.y = 0.5;
+ }
+ }
+ refreshTexture(): void {
+ const t = this.cachedTemplate;
+ this.textures = getPixiTexture(t);
+ if (t.texture !== -1) {
+ [this.anchor.x, this.anchor.y] = getTexturePivot(t.texture);
+ } else {
+ this.anchor.x = this.anchor.y = 0.5;
+ }
+ }
+}
+
+export {Copy};
diff --git a/src/node_requires/roomEditor/entityClasses/MarqueeBox.ts b/src/node_requires/roomEditor/entityClasses/MarqueeBox.ts
new file mode 100644
index 000000000..947b9560f
--- /dev/null
+++ b/src/node_requires/roomEditor/entityClasses/MarqueeBox.ts
@@ -0,0 +1,24 @@
+import {RoomEditor} from '..';
+import {getPixiSwatch} from '../../themes';
+
+export class MarqueeBox extends PIXI.Graphics {
+ editor: RoomEditor;
+ constructor(editor: RoomEditor, x: number, y: number, width: number, height: number) {
+ super();
+ this.editor = editor;
+ this.redrawBox(x, y, width, height);
+ }
+ redrawBox(x: number, y: number, width: number, height: number): void {
+ const x1 = x,
+ x2 = x + width,
+ y1 = y,
+ y2 = y + height;
+ this.x = Math.min(x1, x2);
+ this.y = Math.min(y1, y2);
+ this.clear();
+ this.lineStyle(3 * this.editor.camera.scale.x, getPixiSwatch('act'))
+ .drawRoundedRect(0, 0, Math.abs(width), Math.abs(height), 0.1);
+ this.lineStyle(this.editor.camera.scale.x, getPixiSwatch('background'))
+ .drawRoundedRect(0, 0, Math.abs(width), Math.abs(height), 0.1);
+ }
+}
diff --git a/src/node_requires/roomEditor/entityClasses/SnapTarget.ts b/src/node_requires/roomEditor/entityClasses/SnapTarget.ts
new file mode 100644
index 000000000..64db149d9
--- /dev/null
+++ b/src/node_requires/roomEditor/entityClasses/SnapTarget.ts
@@ -0,0 +1,95 @@
+import {getPixiSwatch} from '../../themes';
+import {RoomEditor} from '..';
+import {snapToRectangularGrid, snapToDiagonalGrid} from '../common';
+import {getPixiTexture, getTextureFromId, getTexturePivot} from '../../resources/textures';
+import {createTilePatch} from '../interactions/tiles/placeTile';
+
+const unknownTextures = getPixiTexture(-1, void 0, true);
+
+export class SnapTarget extends PIXI.Container {
+ editor: RoomEditor;
+ circle = new PIXI.Graphics();
+ ghost = new PIXI.AnimatedSprite(unknownTextures);
+ ghostCompound = new PIXI.Container();
+ prevGhostTex: ITexture;
+ prevTilePatch: string;
+ constructor(editor: RoomEditor) {
+ super();
+ this.editor = editor;
+ this.ghost.visible = false;
+ this.ghost.alpha = 0.5;
+ [this.ghost.anchor.x, this.ghost.anchor.y] = [0.5, 0.5];
+ this.addChild(this.ghost, this.ghostCompound);
+ this.circle.beginFill(getPixiSwatch('act'));
+ this.circle.drawCircle(0, 0, 4);
+ this.addChild(this.circle);
+ }
+ getPatchString(): string {
+ const {tilePatch} = this.editor.riotEditor;
+ return `${tilePatch.texture.uid}:${tilePatch.startX}:${tilePatch.startY}:${tilePatch.spanX}:${tilePatch.spanY}`;
+ }
+ update(): void {
+ this.circle.scale.x = this.editor.camera.scale.x;
+ this.circle.scale.y = this.editor.camera.scale.y;
+
+ const {riotEditor} = this.editor;
+ const {currentTemplate} = riotEditor;
+ if (riotEditor.currentTool === 'addCopies' && currentTemplate !== -1) {
+ this.ghost.visible = true;
+ if (currentTemplate.texture === -1 &&
+ this.ghost.textures !== unknownTextures
+ ) {
+ this.updateGhost(-1);
+ this.ghost.textures = unknownTextures;
+ }
+ if (currentTemplate.texture !== -1 &&
+ this.prevGhostTex !== getTextureFromId(currentTemplate.texture)
+ ) {
+ this.updateGhost(currentTemplate.texture);
+ this.prevGhostTex = getTextureFromId(currentTemplate.texture);
+ }
+ } else {
+ this.ghost.visible = false;
+ }
+ if (riotEditor.currentTool === 'addTiles' && riotEditor.tilePatch?.texture) {
+ if (this.prevTilePatch !== this.getPatchString()) {
+ this.ghostCompound.removeChildren();
+ this.ghostCompound.visible = true;
+ this.ghostCompound.addChild(...createTilePatch(riotEditor.tilePatch, {
+ x: 0,
+ y: 0
+ }, this.editor, true));
+ this.prevTilePatch = this.getPatchString();
+ }
+ } else {
+ this.ghostCompound.visible = false;
+ if (this.ghostCompound.children.length) {
+ this.ghostCompound.removeChildren();
+ }
+ }
+
+ const {mouse} = this.editor.renderer.plugins.interaction;
+ mouse.getLocalPosition(this.editor.overlays, this.position);
+ if (!riotEditor.gridOn || riotEditor.freePlacementMode) {
+ return;
+ }
+ let snappedPos;
+ if (this.editor.ctRoom.diagonalGrid) {
+ snappedPos = snapToDiagonalGrid({
+ x: this.x,
+ y: this.y
+ }, this.editor.ctRoom.gridX, this.editor.ctRoom.gridY);
+ } else {
+ snappedPos = snapToRectangularGrid({
+ x: this.x,
+ y: this.y
+ }, this.editor.ctRoom.gridX, this.editor.ctRoom.gridY);
+ }
+ this.x = snappedPos.x;
+ this.y = snappedPos.y;
+ }
+ updateGhost(texture: assetRef | ITexture): void {
+ this.ghost.textures = getPixiTexture(texture, void 0, true);
+ [this.ghost.anchor.x, this.ghost.anchor.y] = getTexturePivot(texture);
+ }
+}
diff --git a/src/node_requires/roomEditor/entityClasses/Tile.ts b/src/node_requires/roomEditor/entityClasses/Tile.ts
new file mode 100644
index 000000000..07b01162c
--- /dev/null
+++ b/src/node_requires/roomEditor/entityClasses/Tile.ts
@@ -0,0 +1,85 @@
+import {getPixiTexture, getTexturePivot} from '../../resources/textures';
+import {RoomEditor} from '..';
+import {TileLayer} from './TileLayer';
+
+/**
+ * @notice This class automatically adds and removes itself from editor's tile list
+ */
+class Tile extends PIXI.Sprite {
+ tileTexture: assetRef;
+ tileFrame: number;
+ parent: TileLayer | null;
+ editor: RoomEditor;
+ isGhost: boolean;
+
+ constructor(tileInfo: ITileTemplate, editor: RoomEditor, isGhost?: boolean) {
+ super(getPixiTexture(tileInfo.texture, tileInfo.frame, false));
+ this.editor = editor;
+ this.deserialize(tileInfo);
+ this.isGhost = Boolean(isGhost);
+ this.interactive = !this.isGhost;
+ if (this.isGhost) {
+ this.alpha *= 0.5;
+ } else {
+ editor.tiles.add(this);
+ }
+ }
+ destroy(): void {
+ if (!this.isGhost) {
+ this.editor.tiles.delete(this);
+ }
+ super.destroy();
+ }
+ detach(): this {
+ this.editor.tiles.delete(this);
+ this.parent.removeChild(this);
+ return this;
+ }
+ restore(parent: TileLayer): this {
+ this.editor.tiles.add(this);
+ parent.addChild(this);
+ return this;
+ }
+
+ serialize(): ITileTemplate {
+ return {
+ x: this.x,
+ y: this.y,
+ opacity: this.alpha,
+ tint: this.tint,
+ scale: {
+ x: this.scale.x,
+ y: this.scale.y
+ },
+ frame: this.tileFrame,
+ rotation: this.rotation,
+ texture: this.tileTexture as string
+ };
+ }
+ deserialize(tile: ITileTemplate): void {
+ this.x = tile.x;
+ this.y = tile.y;
+ this.alpha = tile.opacity ?? 1;
+ this.tint = tile.tint ?? 0xffffff;
+ this.scale.x = tile.scale?.x ?? 1;
+ this.scale.y = tile.scale?.y ?? 1;
+ this.rotation = tile.rotation ?? 0;
+ this.tileTexture = tile.texture;
+ this.tileFrame = tile.frame;
+ [this.anchor.x, this.anchor.y] = getTexturePivot(this.tileTexture);
+ }
+ refreshTexture(): void {
+ const frame = getPixiTexture(this.tileTexture, this.tileFrame);
+ if (frame) {
+ this.texture = frame;
+ } else {
+ // eslint-disable-next-line no-console
+ console.warn(`Frame ${this.tileFrame} does not exist in the texture ${this.tileTexture}. Removing the tile.`);
+ // Invalid tile. Desintegrate!
+ this.destroy();
+ }
+ [this.anchor.x, this.anchor.y] = getTexturePivot(this.tileTexture);
+ }
+}
+
+export {Tile};
diff --git a/src/node_requires/roomEditor/entityClasses/TileLayer.ts b/src/node_requires/roomEditor/entityClasses/TileLayer.ts
new file mode 100644
index 000000000..f773ec73d
--- /dev/null
+++ b/src/node_requires/roomEditor/entityClasses/TileLayer.ts
@@ -0,0 +1,68 @@
+import {Tile} from './Tile';
+import {RoomEditor} from '..';
+
+let idCounter = 0;
+
+export class TileLayer extends PIXI.Container {
+ extends: Record;
+ children: Tile[];
+ editor: RoomEditor;
+ id: number;
+ constructor(tileLayer: ITileLayerTemplate, editor: RoomEditor) {
+ super();
+ this.editor = editor;
+ this.id = idCounter++;
+ this.deserialize(tileLayer);
+ }
+ destroy(): void {
+ if (this.parent) {
+ this.parent.removeChild(this);
+ }
+ const ind = this.editor.tileLayers.indexOf(this);
+ if (ind !== -1) {
+ this.editor.tileLayers.splice(ind, 1);
+ }
+ super.destroy({
+ children: true
+ });
+ }
+ detach(writeToHistory?: boolean): this {
+ const ind = this.editor.tileLayers.indexOf(this);
+ if (ind !== -1) {
+ // eslint-disable-next-line no-console
+ console.warn('Detaching a layer that was not in the editor\'s tileLayer list', this);
+ this.editor.tileLayers.splice(ind, 1);
+ }
+ for (const tile of this.children) {
+ this.editor.tiles.delete(tile);
+ }
+ this.parent.removeChild(this);
+ if (writeToHistory) {
+ this.editor.history.pushChange({
+ type: 'tileLayerDeletion',
+ deleted: this
+ });
+ }
+ return this;
+ }
+ restore(): this {
+ this.editor.addTileLayer(this);
+ return this;
+ }
+ serialize(): ITileLayerTemplate {
+ return {
+ depth: this.zIndex,
+ tiles: this.children.map(c => c.serialize()),
+ extends: this.extends,
+ hidden: !this.visible
+ };
+ }
+ deserialize(tileLayer: ITileLayerTemplate): void {
+ this.zIndex = tileLayer.depth;
+ this.extends = tileLayer.extends || {};
+ for (const tile of tileLayer.tiles) {
+ const pixiTile = new Tile(tile, this.editor);
+ this.addChild(pixiTile);
+ }
+ }
+}
diff --git a/src/node_requires/roomEditor/entityClasses/Transformer.ts b/src/node_requires/roomEditor/entityClasses/Transformer.ts
new file mode 100644
index 000000000..f51cba670
--- /dev/null
+++ b/src/node_requires/roomEditor/entityClasses/Transformer.ts
@@ -0,0 +1,289 @@
+import {RoomEditor} from '..';
+
+import {getPixiSwatch} from '../../themes';
+import {rotateCursor} from '../common';
+import {ease} from 'node_modules/pixi-ease';
+
+import {rotateRad, pdc} from '../../utils/trigo';
+
+export class Handle extends PIXI.Graphics {
+ constructor() {
+ super();
+ this.beginFill(getPixiSwatch('act'));
+ this.drawCircle(0, 0, 6);
+ this.interactive = true;
+ this.cursor = 'pointer';
+ }
+}
+type transformSubset = {
+ x: number;
+ y: number;
+ scale: {
+ x: number;
+ y: number;
+ };
+ rotation: number;
+}
+
+export class Transformer extends PIXI.Container {
+ handleTL = new Handle();
+ handleTR = new Handle();
+ handleT = new Handle();
+ handleL = new Handle();
+ handleR = new Handle();
+ handleCenter = new Handle();
+ handleBL = new Handle();
+ handleBR = new Handle();
+ handleB = new Handle();
+ handleRotate = new Handle();
+ scaleHandles = [
+ this.handleTL,
+ this.handleTR,
+ this.handleT,
+ this.handleL,
+ this.handleR,
+ this.handleBL,
+ this.handleBR,
+ this.handleB
+ ];
+ frame = new PIXI.Graphics();
+
+ applyRotation: number;
+ applyScaleX: number;
+ applyScaleY: number;
+ applyTranslateX: number;
+ applyTranslateY: number;
+ transformPivotX: number;
+ transformPivotY: number;
+ frameWidth: number;
+ frameHeight: number;
+ initialTransforms = new Map();
+
+ editor: RoomEditor;
+
+ constructor(editor: RoomEditor) {
+ super();
+ this.editor = editor;
+ this.handleRotate.cursor = rotateCursor;
+
+ this.handleCenter.scale.set(1.25, 1.25);
+ this.handleCenter.cursor = 'move';
+
+ this.addChild(
+ this.frame,
+ this.handleTL,
+ this.handleTR,
+ this.handleT,
+ this.handleL,
+ this.handleR,
+ this.handleCenter,
+ this.handleBL,
+ this.handleBR,
+ this.handleB,
+ this.handleRotate
+ );
+ this.setup();
+ }
+
+ setup(skipHistoryUpdate?: boolean): void {
+ this.initialTransforms.clear();
+ this.applyRotation = 0;
+ this.applyScaleX = this.applyScaleY = 1;
+ this.applyTranslateX = this.applyTranslateY = 0;
+ if (this.editor.currentSelection.size === 0) {
+ this.visible = false;
+ return;
+ }
+ this.visible = true;
+
+ let rect;
+ for (const elt of this.editor.currentSelection) {
+ const w = elt.width,
+ h = elt.height,
+ // IDK why this works
+ px = Math.sign(elt.scale.x) === -1 ? 1 - elt.anchor.x : elt.anchor.x,
+ py = Math.sign(elt.scale.y) === -1 ? 1 - elt.anchor.y : elt.anchor.y;
+ const tl = rotateRad(-w * px, -h * py, elt.rotation),
+ tr = rotateRad(w * (1 - px), -h * py, elt.rotation),
+ bl = rotateRad(-w * px, h * (1 - py), elt.rotation),
+ br = rotateRad(w * (1 - px), h * (1 - py), elt.rotation);
+ const x1 = Math.min(tl[0], bl[0], tr[0], br[0]),
+ x2 = Math.max(tl[0], bl[0], tr[0], br[0]),
+ y1 = Math.min(tl[1], bl[1], tr[1], br[1]),
+ y2 = Math.max(tl[1], bl[1], tr[1], br[1]);
+ if (!rect) {
+ rect = new PIXI.Rectangle(x1, y1, x2 - x1, y2 - y1);
+ rect.x += elt.x;
+ rect.y += elt.y;
+ } else {
+ const newRect = new PIXI.Rectangle(x1, y1, x2 - x1, y2 - y1);
+ newRect.x += elt.x;
+ newRect.y += elt.y;
+ rect.enlarge(newRect);
+ }
+ this.initialTransforms.set(elt, {
+ x: elt.x,
+ y: elt.y,
+ scale: {
+ x: elt.scale.x || 1,
+ y: elt.scale.y || 1
+ },
+ rotation: elt.rotation
+ });
+ }
+ this.frameWidth = rect.width;
+ this.frameHeight = rect.height;
+ this.transformPivotX = rect.x + rect.width / 2;
+ this.transformPivotY = rect.y + rect.height / 2;
+ if (!skipHistoryUpdate) {
+ this.editor.history.initiateTransformChange();
+ }
+ this.updateFrame();
+ }
+ clear(): void {
+ this.editor.currentSelection.clear();
+ this.setup(true);
+ }
+
+ applyTransforms(): void {
+ for (const elt of this.editor.currentSelection) {
+ const initial = this.initialTransforms.get(elt);
+ const delta = {
+ x: ((initial.x + this.applyTranslateX) - this.transformPivotX) * this.applyScaleX,
+ y: ((initial.y + this.applyTranslateY) - this.transformPivotY) * this.applyScaleY
+ };
+ const rotatedDelta = rotateRad(delta.x, delta.y, this.applyRotation);
+ elt.x = this.transformPivotX + rotatedDelta[0];
+ elt.y = this.transformPivotY + rotatedDelta[1];
+ elt.rotation = initial.rotation + this.applyRotation;
+
+ // Skew isn't in ct.js, so something fancy is introduced as an alternative.
+ // Works great at 0, 90, 180, 270 degrees.
+ // Works q̴̿ͅu̵͈͑e̵̖͒s̵͈̎t̸̪̽i̶͈͌o̴̳͊ñ̶̪a̵͜͝b̶̮̈́ĺ̸̲y̸͒͜ on other angles.
+ const flip = Math.sign(this.applyScaleX) !== Math.sign(this.applyScaleY) ? -1 : 1;
+ const sin = Math.sin(initial.rotation),
+ cos = Math.cos(initial.rotation);
+
+ elt.scale.set(
+ initial.scale.x *
+ (cos ** 2 * this.applyScaleX + sin ** 2 * this.applyScaleY * flip),
+ initial.scale.y *
+ (sin ** 2 * this.applyScaleX * flip + cos ** 2 * this.applyScaleY)
+ );
+ }
+ }
+
+ outlineSelected(): void {
+ for (const elt of this.editor.currentSelection) {
+ const w = elt.width,
+ h = elt.height,
+ // IDK why this works
+ px = Math.sign(elt.scale.x) === -1 ? 1 - elt.anchor.x : elt.anchor.x,
+ py = Math.sign(elt.scale.y) === -1 ? 1 - elt.anchor.y : elt.anchor.y,
+ {x, y} = this.editor.room.toGlobal(elt.position),
+ sx = this.editor.camera.scale.x,
+ sy = this.editor.camera.scale.y;
+ const tl = rotateRad(-w * px, -h * py, elt.rotation),
+ tr = rotateRad(w * (1 - px), -h * py, elt.rotation),
+ bl = rotateRad(-w * px, h * (1 - py), elt.rotation),
+ br = rotateRad(w * (1 - px), h * (1 - py), elt.rotation);
+ // this.frame.lineStyle(3, getPixiSwatch('act'));
+ this.frame.lineStyle(1, getPixiSwatch('background'));
+ this.frame.beginFill(getPixiSwatch('act'), 0.15);
+ this.frame.moveTo(x + tl[0] / sx, y + tl[1] / sy);
+ this.frame.lineTo(x + tr[0] / sx, y + tr[1] / sy);
+ this.frame.lineTo(x + br[0] / sx, y + br[1] / sy);
+ this.frame.lineTo(x + bl[0] / sx, y + bl[1] / sy);
+ this.frame.lineTo(x + tl[0] / sx, y + tl[1] / sy);
+ this.frame.endFill();
+ // this.frame.lineStyle(1, getPixiSwatch('background'));
+ // this.frame.moveTo(x + tl[0] / sx, y + tl[1] / sy);
+ // this.frame.lineTo(x + tr[0] / sx, y + tr[1] / sy);
+ // this.frame.lineTo(x + br[0] / sx, y + br[1] / sy);
+ // this.frame.lineTo(x + bl[0] / sx, y + bl[1] / sy);
+ // this.frame.lineTo(x + tl[0] / sx, y + tl[1] / sy);
+ }
+ }
+ updateFrame(): void {
+ const halfDiagonalScaled = {
+ x: this.frameWidth / 2 * this.applyScaleX / this.editor.camera.scale.x,
+ y: this.frameHeight / 2 * this.applyScaleY / this.editor.camera.scale.y
+ };
+ // Compute position of four corners of the selection frame
+ const TR = rotateRad(halfDiagonalScaled.x, -halfDiagonalScaled.y, this.applyRotation),
+ TL = rotateRad(-halfDiagonalScaled.x, -halfDiagonalScaled.y, this.applyRotation),
+ BR = rotateRad(halfDiagonalScaled.x, halfDiagonalScaled.y, this.applyRotation),
+ BL = rotateRad(-halfDiagonalScaled.x, halfDiagonalScaled.y, this.applyRotation);
+ const globalFrom = this.editor.room.toGlobal(new PIXI.Point(
+ this.transformPivotX,
+ this.transformPivotY
+ ));
+
+ TR[0] += globalFrom.x;
+ TL[0] += globalFrom.x;
+ BL[0] += globalFrom.x;
+ BR[0] += globalFrom.x;
+ TR[1] += globalFrom.y;
+ TL[1] += globalFrom.y;
+ BL[1] += globalFrom.y;
+ BR[1] += globalFrom.y;
+
+ // Move handles to appropriate places
+ this.handleCenter.x = globalFrom.x;
+ this.handleCenter.y = globalFrom.y;
+ [this.handleTL.x, this.handleTL.y] = TL;
+ [this.handleTR.x, this.handleTR.y] = TR;
+ [this.handleBL.x, this.handleBL.y] = BL;
+ [this.handleBR.x, this.handleBR.y] = BR;
+ this.handleT.x = (TL[0] + TR[0]) / 2;
+ this.handleT.y = (TL[1] + TR[1]) / 2;
+ this.handleL.x = (TL[0] + BL[0]) / 2;
+ this.handleL.y = (TL[1] + BL[1]) / 2;
+ this.handleR.x = (TR[0] + BR[0]) / 2;
+ this.handleR.y = (TR[1] + BR[1]) / 2;
+ this.handleB.x = (BL[0] + BR[0]) / 2;
+ this.handleB.y = (BL[1] + BR[1]) / 2;
+ // Rotation handle is placed a bit outside the frame
+ const shift = rotateRad(21 * Math.sign(this.applyScaleX), 0, this.applyRotation);
+ this.handleRotate.x = this.handleR.x + shift[0];
+ this.handleRotate.y = this.handleR.y + shift[1];
+
+ // Hide middle handles if they're placed way too close to other elements
+ if (pdc(TL[0], TL[1], BL[0], BL[1]) < 32 || pdc(TL[0], TL[1], TR[0], TR[1]) <= 16) {
+ this.handleL.visible = this.handleR.visible = false;
+ } else {
+ this.handleL.visible = this.handleR.visible = true;
+ }
+ if (pdc(TL[0], TL[1], TR[0], TR[1]) < 32 || pdc(TL[0], TL[1], BL[0], BL[1]) <= 16) {
+ this.handleT.visible = this.handleB.visible = false;
+ } else {
+ this.handleT.visible = this.handleB.visible = true;
+ }
+
+ this.frame.clear();
+ // Outline the selected elements
+ this.outlineSelected();
+ // Draw the frame
+ this.frame.lineStyle(4, getPixiSwatch('act'));
+ this.frame.moveTo(TL[0] - 0.5, TL[1] - 0.5);
+ this.frame.lineTo(TR[0] + 0.5, TR[1] - 0.5);
+ this.frame.lineTo(BR[0] + 0.5, BR[1] + 0.5);
+ this.frame.lineTo(BL[0] - 0.5, BL[1] + 0.5);
+ this.frame.lineTo(TL[0] - 0.5, TL[1] - 0.5);
+ this.frame.lineStyle(2, getPixiSwatch('background'));
+ this.frame.moveTo(TL[0] - 0.5, TL[1] - 0.5);
+ this.frame.lineTo(TR[0] + 0.5, TR[1] - 0.5);
+ this.frame.lineTo(BR[0] + 0.5, BR[1] + 0.5);
+ this.frame.lineTo(BL[0] - 0.5, BL[1] + 0.5);
+ this.frame.lineTo(TL[0] - 0.5, TL[1] - 0.5);
+ }
+
+ blink(): void {
+ this.alpha = 0;
+ ease.add(this, {
+ alpha: 1
+ }, {
+ duration: 150
+ });
+ }
+}
diff --git a/src/node_requires/roomEditor/entityClasses/Viewport.ts b/src/node_requires/roomEditor/entityClasses/Viewport.ts
new file mode 100644
index 000000000..a07d4fd6b
--- /dev/null
+++ b/src/node_requires/roomEditor/entityClasses/Viewport.ts
@@ -0,0 +1,58 @@
+import {getPixiSwatch} from '../../themes';
+import {RoomEditor} from '..';
+
+interface ICtViewport {
+ width: number;
+ height: number;
+ x?: number;
+ y?: number;
+}
+
+class Viewport extends PIXI.Graphics {
+ view: ICtViewport;
+ starting: boolean;
+ startingIcon: PIXI.Graphics;
+ editor: RoomEditor;
+
+ constructor(view: ICtViewport, starting: boolean, editor: RoomEditor) {
+ super();
+ this.editor = editor;
+ this.starting = starting;
+ this.view = view;
+ this.x = this.view.x ?? 0;
+ this.y = this.view.y ?? 0;
+ this.startingIcon = new PIXI.Graphics();
+ this.startingIcon
+ .lineStyle(2, getPixiSwatch('orange'), 1, 0.5)
+ .moveTo(0, 0)
+ .lineTo(17, 10)
+ .lineTo(0, 20)
+ .lineTo(0, 0)
+ .closePath();
+ this.startingIcon.y = 16;
+ this.startingIcon.visible = this.starting;
+ this.addChild(this.startingIcon);
+ this.redrawFrame();
+ }
+ destroy(): void {
+ this.editor.viewports.delete(this);
+ super.destroy();
+ }
+
+ redrawFrame(): void {
+ this.x = this.view.x ?? 0;
+ this.y = this.view.y ?? 0;
+ this.startingIcon.scale.set(this.editor.camera.scale.x);
+ this.startingIcon.visible = this.starting &&
+ (this.view.height / this.editor.camera.scale.x > 48);
+ this.clear();
+ this.lineStyle(4 * this.editor.camera.scale.x, getPixiSwatch('act'))
+ .drawRoundedRect(0, 0, this.view.width, this.view.height, 0.1);
+ this.lineStyle(2 * this.editor.camera.scale.x, getPixiSwatch('background'))
+ .drawRoundedRect(0, 0, this.view.width, this.view.height, 0.1);
+ this.startingIcon.x = this.view.width - (16 + 17) * this.editor.camera.scale.x;
+ this.startingIcon.y = 16 * this.editor.camera.scale.y;
+ }
+}
+
+export {Viewport};
diff --git a/src/node_requires/roomEditor/entityClasses/ViewportRestriction.ts b/src/node_requires/roomEditor/entityClasses/ViewportRestriction.ts
new file mode 100644
index 000000000..a4bd8bce6
--- /dev/null
+++ b/src/node_requires/roomEditor/entityClasses/ViewportRestriction.ts
@@ -0,0 +1,57 @@
+import {getPixiSwatch} from '../../themes';
+import {RoomEditor} from '..';
+
+export class ViewportRestriction extends PIXI.Graphics {
+ icon: PIXI.Graphics;
+ editor: RoomEditor;
+ constructor(editor: RoomEditor) {
+ super();
+ this.editor = editor;
+ this.x = this.editor.ctRoom.restrictMinX;
+ this.y = this.editor.ctRoom.restrictMinY;
+ this.icon = new PIXI.Graphics();
+ this.icon
+ .lineStyle(2, getPixiSwatch('orange'), 1, 0.5);
+ this.icon.drawRect(0, 10, 20, 14);
+ this.icon.arc(10, 6, 6, Math.PI, Math.PI * 2);
+ this.icon.moveTo(10, 14);
+ this.icon.lineTo(10, 20);
+ this.icon.moveTo(4, 6);
+ this.icon.lineTo(4, 10);
+ this.icon.moveTo(4 + 12, 6);
+ this.icon.lineTo(4 + 12, 10);
+ this.icon.y = 16;
+ this.addChild(this.icon);
+ this.redrawFrame();
+ }
+
+ redrawFrame(): void {
+ if (!this.editor.ctRoom.restrictCamera) {
+ this.visible = false;
+ return;
+ }
+ this.visible = true;
+ this.x = this.editor.ctRoom.restrictMinX;
+ this.y = this.editor.ctRoom.restrictMinY;
+ let width = this.editor.ctRoom.restrictMaxX - this.editor.ctRoom.restrictMinX,
+ height = this.editor.ctRoom.restrictMaxY - this.editor.ctRoom.restrictMinY;
+ if (width < 0) {
+ width = Math.abs(width);
+ this.x = this.editor.ctRoom.restrictMaxX;
+ }
+ if (height < 0) {
+ height = Math.abs(height);
+ this.y = this.editor.ctRoom.restrictMaxY;
+ }
+ this.icon.scale.set(this.editor.camera.scale.x);
+ this.icon.visible = (height / this.editor.camera.scale.x > 48);
+ this.clear();
+ this.lineStyle(4 * this.editor.camera.scale.x, getPixiSwatch('act'))
+ .drawRoundedRect(0, 0, width, height, 0.1);
+ this.lineStyle(2 * this.editor.camera.scale.x, getPixiSwatch('background'))
+ .drawRoundedRect(0, 0, width, height, 0.1);
+ this.icon.x = width - (16 + 20) * this.editor.camera.scale.x;
+ this.icon.y = 16 * this.editor.camera.scale.y;
+ }
+}
+
diff --git a/src/node_requires/roomEditor/history.ts b/src/node_requires/roomEditor/history.ts
new file mode 100644
index 000000000..1efebcb1e
--- /dev/null
+++ b/src/node_requires/roomEditor/history.ts
@@ -0,0 +1,290 @@
+import {Copy} from './entityClasses/Copy';
+import {Tile} from './entityClasses/Tile';
+import {TileLayer} from './entityClasses/TileLayer';
+import {Background} from './entityClasses/Background';
+import {RoomEditor} from '.';
+
+type transformationSnapshot = {
+ position: {
+ x: number;
+ y: number;
+ }
+ rotation: number;
+ scale: {
+ x: number;
+ y: number;
+ }
+ tint: number;
+ alpha: number;
+};
+
+/**
+ * In order: The entity that was changed, transformation before the change, and after it.
+ */
+type transformation = {
+ type: 'transformation',
+ transformations: Map
+};
+
+type deletion = {
+ type: 'deletion',
+ deleted: Set<[Copy | Tile, TileLayer?]>
+};
+type creation = {
+ type: 'creation',
+ created: Set<[Copy | Tile, TileLayer?]>
+};
+
+type tileLayerCreation = {
+ type: 'tileLayerCreation',
+ created: TileLayer
+}
+type tileLayerDeletion = {
+ type: 'tileLayerDeletion',
+ deleted: TileLayer
+}
+
+type backgroundCreation = {
+ type: 'backgroundCreation',
+ created: Background
+}
+type backgroundDeletion = {
+ type: 'backgroundDeletion',
+ deleted: Background
+}
+
+type propChange = {
+ type: 'propChange',
+ key: string,
+ target: unknown,
+ before: unknown,
+ after: unknown
+}
+
+export type change = transformation | deletion | creation |
+ tileLayerCreation | tileLayerDeletion |
+ backgroundCreation | backgroundDeletion |
+ propChange;
+
+const snapshotTransform = (entity: PIXI.Sprite): transformationSnapshot => ({
+ position: {
+ x: entity.position.x,
+ y: entity.position.y
+ },
+ rotation: entity.rotation,
+ scale: {
+ x: entity.scale.x,
+ y: entity.scale.y
+ },
+ tint: entity.tint,
+ alpha: entity.alpha
+});
+
+export class History {
+ stack: change[] = [];
+ /**
+ * Describes the last change made in the given period of time in history.
+ * Undo operation undos this change, while redo operation redos the change next to it.
+ */
+ currentChange?: change;
+ editor: RoomEditor;
+
+ constructor(editor: RoomEditor) {
+ this.editor = editor;
+ }
+
+ undo(): boolean {
+ if (!this.currentChange) {
+ return false;
+ }
+ const change = this.currentChange;
+ // eslint-disable-next-line default-case
+ switch (change.type) {
+ case 'transformation':
+ this.editor.transformer.clear();
+ for (const transform of change.transformations) {
+ const [entity, [before]] = transform;
+ entity.position.set(before.position.x, before.position.y);
+ entity.scale.set(before.scale.x, before.scale.y);
+ entity.alpha = before.alpha;
+ entity.rotation = before.rotation;
+ entity.tint = before.tint;
+ this.editor.currentSelection.add(entity);
+ }
+ this.editor.transformer.setup(true);
+ this.editor.riotEditor.refs.propertiesPanel?.updatePropList();
+ break;
+ case 'deletion':
+ for (const deletion of change.deleted) {
+ const [entity, parent] = deletion;
+ entity.restore(parent);
+ }
+ break;
+ case 'creation':
+ this.editor.transformer.clear();
+ for (const creation of change.created) {
+ const [entity] = creation;
+ entity.detach();
+ }
+ break;
+ case 'tileLayerCreation':
+ change.created.detach();
+ if (!this.editor.tileLayers.includes(this.editor.riotEditor.currentTileLayer)) {
+ [this.editor.riotEditor.currentTileLayer] = this.editor.tileLayers;
+ }
+ this.editor.riotEditor.refs.tileEditor?.update();
+ break;
+ case 'tileLayerDeletion':
+ change.deleted.restore();
+ this.editor.riotEditor.currentTileLayer = change.deleted;
+ this.editor.riotEditor.refs.tileEditor?.update();
+ break;
+ case 'backgroundCreation':
+ change.created.detach();
+ this.editor.riotEditor.refs.backgroundsEditor?.update();
+ break;
+ case 'backgroundDeletion':
+ change.deleted.restore();
+ this.editor.riotEditor.refs.backgroundsEditor?.update();
+ break;
+ case 'propChange':
+ (change.target as Record)[change.key] = change.before;
+ this.updateUiFor(change);
+ break;
+ }
+ const prevChangeType = change.type;
+ this.currentChange = this.stack[this.stack.indexOf(change) - 1];
+ if (prevChangeType === 'transformation' && !change) {
+ // If we reached history's end with transformation reversal, leave
+ // this last change as current one, as the transformer selects the same set
+ // of entities and initial transforms are totally correct.
+ [this.currentChange] = this.stack;
+ }
+ this.editor.riotEditor.update();
+ return true;
+ }
+ redo(): boolean {
+ if (this.currentChange === this.stack[this.stack.length - 1]) {
+ return false;
+ }
+ const newChange = this.stack[this.stack.indexOf(this.currentChange) + 1];
+ // eslint-disable-next-line default-case
+ switch (newChange.type) {
+ case 'transformation':
+ this.editor.transformer.clear();
+ for (const change of newChange.transformations) {
+ const [entity, [, after]] = change;
+ entity.position.set(after.position.x, after.position.y);
+ entity.scale.set(after.scale.x, after.scale.y);
+ entity.alpha = after.alpha;
+ entity.rotation = after.rotation;
+ entity.tint = after.tint;
+ this.editor.currentSelection.add(entity);
+ }
+ this.editor.transformer.setup(true);
+ this.editor.riotEditor.refs.propertiesPanel?.updatePropList();
+ break;
+ case 'deletion':
+ this.editor.transformer.clear();
+ for (const deletion of newChange.deleted) {
+ const [entity] = deletion;
+ entity.detach();
+ }
+ break;
+ case 'creation':
+ for (const creation of newChange.created) {
+ const [entity, parent] = creation;
+ entity.restore(parent);
+ }
+ break;
+ case 'tileLayerCreation':
+ newChange.created.restore();
+ this.editor.riotEditor.currentTileLayer = newChange.created;
+ this.editor.riotEditor.refs.tileEditor?.update();
+ break;
+ case 'tileLayerDeletion':
+ newChange.deleted.detach();
+ if (!this.editor.tileLayers.includes(newChange.deleted)) {
+ [this.editor.riotEditor.currentTileLayer] = this.editor.tileLayers;
+ }
+ this.editor.riotEditor.refs.tileEditor?.update();
+ break;
+ case 'backgroundCreation':
+ newChange.created.restore();
+ this.editor.riotEditor.refs.backgroundsEditor?.update();
+ break;
+ case 'backgroundDeletion':
+ newChange.deleted.detach();
+ this.editor.riotEditor.refs.backgroundsEditor?.update();
+ break;
+ case 'propChange':
+ (newChange.target as Record)[newChange.key] = newChange.after;
+ this.updateUiFor(newChange);
+ break;
+ }
+ this.currentChange = newChange;
+ this.editor.riotEditor.update();
+ return true;
+ }
+ pushChange(change: change): void {
+ const id = this.stack.indexOf(this.currentChange);
+ this.stack = this.stack.slice(0, id + 1);
+ this.stack.push(change);
+ this.currentChange = change;
+ if (this.stack.length > 30) {
+ this.stack.shift();
+ }
+ this.editor.riotEditor.update();
+ }
+ initiateTransformChange(): void {
+ const transform: change = {
+ type: 'transformation',
+ transformations: new Map()
+ };
+ for (const entity of this.editor.currentSelection) {
+ const initialTransform = snapshotTransform(entity);
+ transform.transformations.set(entity as Copy | Tile, [
+ initialTransform,
+ {
+ ...initialTransform
+ }
+ ]);
+ }
+ this.pushChange(transform);
+ }
+ snapshotTransforms(): void {
+ if (this.currentChange.type !== 'transformation') {
+ throw new Error('Cannot snapshot transforms as the current change\'s type is not "transformation"');
+ }
+ for (const [entity, value] of this.currentChange.transformations) {
+ value[1] = snapshotTransform(entity);
+ }
+ void this;
+ }
+ updateUiFor(change: propChange): void {
+ const {target, key} = change,
+ {editor} = this,
+ riot = editor.riotEditor;
+ if (target instanceof TileLayer) {
+ riot.refs.tileEditor?.update();
+ } else if (target === editor.ctRoom) {
+ riot.refs.propertiesPanel?.update();
+ if (key === 'backgroundColor') {
+ editor.renderer.backgroundColor =
+ PIXI.utils.string2hex(editor.ctRoom.backgroundColor);
+ }
+ } else if (target instanceof Background) {
+ if (key === 'bgTexture') {
+ target.changeTexture(target.bgTexture);
+ }
+ riot.refs.backgroundsEditor?.update();
+ }
+ }
+
+ get canUndo(): boolean {
+ return Boolean(this.currentChange);
+ }
+ get canRedo(): boolean {
+ return this.currentChange !== this.stack[this.stack.length - 1];
+ }
+}
diff --git a/src/node_requires/roomEditor/index.ts b/src/node_requires/roomEditor/index.ts
new file mode 100644
index 000000000..d5bcaaf38
--- /dev/null
+++ b/src/node_requires/roomEditor/index.ts
@@ -0,0 +1,561 @@
+import {History} from './history';
+
+import {Copy} from './entityClasses/Copy';
+import {Tile} from './entityClasses/Tile';
+import {TileLayer} from './entityClasses/TileLayer';
+import {Background} from './entityClasses/Background';
+import {Viewport} from './entityClasses/Viewport';
+
+import {SnapTarget} from './entityClasses/SnapTarget';
+import {MarqueeBox} from './entityClasses/MarqueeBox';
+import {Transformer} from './entityClasses/Transformer';
+import {ViewportRestriction} from './entityClasses/ViewportRestriction';
+
+import {IRoomEditorRiotTag} from './IRoomEditorRiotTag';
+import {IRoomEditorInteraction, AllowedListener, allowedListeners, interactions} from './interactions';
+import {getPixiSwatch} from './../themes';
+import {defaultTextStyle, recolorFilters, eraseCursor} from './common';
+import {ease} from 'node_modules/pixi-ease';
+
+const roomEditorDefaults = {
+ width: 10,
+ height: 10,
+ autoDensity: true,
+ transparent: false,
+ sharedLoader: true,
+ sharedTicker: false,
+ resolution: devicePixelRatio,
+ antialias: true,
+ preserveDrawingBuffer: true
+};
+
+export type tileClipboardData = ['tile', ITileTemplate, TileLayer];
+export type copyClipboardData = ['copy', IRoomCopy];
+
+class RoomEditor extends PIXI.Application {
+ history = new History(this);
+ riotEditor: IRoomEditorRiotTag;
+ ctRoom: IRoom;
+ currentSelection: Set = new Set();
+ clipboard: Set = new Set();
+ /** A sprite that catches any click events */
+ clicktrap = new PIXI.Sprite(PIXI.Texture.WHITE);
+ /** A small circle that shows currently snapped position and a ghost for copy/tile placement */
+ snapTarget = new SnapTarget(this);
+ /** A secondary ghost container for more complex prefabs and constructions */
+ compoundGhost = new PIXI.Container();
+ /**
+ * An empty Container that will be used as a camera.
+ * The camera provides inverted transforms for proper view placement.
+ */
+ camera = new PIXI.Container();
+ /** An overlay showing current rectangular selection */
+ marqueeBox = new MarqueeBox(this, 0, 0, 10, 10);
+ /** A container for all the room's entities */
+ room = new PIXI.Container();
+ /** A container for viewport boxes, grid, and other overlays */
+ overlays = new PIXI.Container();
+ /** A free transform widget that exists in **global** coordinates. */
+ transformer = new Transformer(this);
+ primaryViewport: Viewport;
+ restrictViewport: ViewportRestriction;
+ grid = new PIXI.Graphics();
+ /**
+ * A label that will display current mouse coords relative to a room,
+ * in a left-bottom corner. Useful for lining up things in a level.
+ */
+ pointerCoords = new PIXI.Text('(0;0)', defaultTextStyle);
+ /**
+ * Whether the room editor currently processes a user interaction.
+ * While this is true, no new interactions can be started.
+ */
+ interacting = false;
+ interactions: IRoomEditorInteraction[];
+ currentInteraction: IRoomEditorInteraction;
+ affixedInteractionData: unknown;
+
+ copies = new Set();
+ tiles = new Set();
+ backgrounds: Background[] = [];
+ viewports = new Set();
+ tileLayers: TileLayer[] = [];
+
+ /**
+ * Creates a pixi.js app — a room editor
+ * Its `stage` manipulates the camera, managing panning and zooming.
+ * All the CRUD operations are in the Room class.
+ *
+ * @param {Object} opts A partial set of PIXI.Application options that must
+ * include a mounting point (`view`)
+ * @param {RiotTag} editor a tag instance of a `room-editor`
+ */
+ constructor(opts: unknown, editor: IRoomEditorRiotTag, pixelart: boolean) {
+ super(Object.assign({}, roomEditorDefaults, opts, {
+ resizeTo: editor.root,
+ roundPixels: pixelart
+ }));
+ this.ticker.maxFPS = 60;
+
+ const {room} = editor.opts;
+ this.ctRoom = room;
+ this.riotEditor = editor;
+
+ this.clicktrap.alpha = 0;
+ this.stage.addChild(this.clicktrap);
+ this.resizeClicktrap();
+ this.room.sortableChildren = true;
+
+ this.camera.x = room.width / 2;
+ this.camera.y = room.height / 2;
+ this.stage.addChild(this.camera);
+
+ this.stage.addChild(this.room);
+ this.redrawGrid();
+ this.overlays.addChild(this.grid);
+ this.stage.addChild(this.overlays);
+ this.compoundGhost.alpha = 0.5;
+ this.overlays.addChild(this.compoundGhost);
+ this.marqueeBox.visible = false;
+ this.overlays.addChild(this.marqueeBox);
+ this.overlays.addChild(this.snapTarget);
+ this.deserialize(editor.opts.room);
+ this.stage.addChild(this.transformer);
+
+ this.pointerCoords.zIndex = Infinity;
+ this.pointerCoords.x = 8;
+ this.stage.addChild(this.pointerCoords);
+
+ this.ticker.add(() => {
+ this.resizeClicktrap();
+ this.realignCamera();
+ this.snapTarget.update();
+ this.repositionCoordLabel();
+ this.tickBackgrounds();
+ this.tickCopies();
+ if (this.transformer.visible) {
+ this.transformer.updateFrame();
+ }
+ if (['addCopies', 'addTiles'].includes(this.riotEditor.currentTool)) {
+ if (this.riotEditor.controlMode && ['default', 'inherit'].includes(this.view.style.cursor)) {
+ this.view.style.cursor = eraseCursor;
+ this.snapTarget.visible = false;
+ }
+ if (!this.riotEditor.controlMode && this.view.style.cursor.includes('Erase')) {
+ this.view.style.cursor = 'default';
+ this.snapTarget.visible = true;
+ }
+ }
+ });
+
+ this.stage.interactive = true;
+ this.interactions = interactions;
+ for (const event of allowedListeners) {
+ this.stage.on(event, (e: PIXI.InteractionEvent) => {
+ this.listen(e, event);
+ });
+ }
+
+ // Riot's observable objects lose function's context, so pass an anonymous function instead
+ this.updateTexturesHandle = (textureId: string) => this.updateTextures(textureId);
+ this.updateCopiesHandle = (templateId: string) => this.updateCopies(templateId);
+ window.signals.on('pixiTextureChanged', this.updateTexturesHandle);
+ window.signals.on('templateChanged', this.updateCopiesHandle);
+ }
+ destroy(removeView: boolean, stageOptions: {
+ children?: boolean;
+ texture?: boolean;
+ baseTexture?: boolean;
+ }): void {
+ window.signals.off('pixiTextureChanged', this.updateTexturesHandle);
+ window.signals.off('templateChanged', this.updateCopiesHandle);
+ super.destroy(removeView, stageOptions);
+ }
+
+ listen(event: PIXI.InteractionEvent, listener: AllowedListener): void {
+ var callback = () => {
+ this.interacting = false;
+ this.currentInteraction = this.affixedInteractionData = void 0;
+ };
+ for (const interaction of this.interactions) {
+ if (!this.interacting && interaction.ifListener === listener) {
+ if (interaction.if.apply(this, [event, this.riotEditor])) {
+ this.interacting = true;
+ this.currentInteraction = interaction;
+ this.affixedInteractionData = {};
+ break;
+ }
+ }
+ }
+ for (const interaction of this.interactions) {
+ if (this.interacting && this.currentInteraction === interaction) {
+ if (listener in this.currentInteraction.listeners) {
+ this.currentInteraction.listeners[listener].apply(
+ this,
+ [event, this.riotEditor, this.affixedInteractionData, callback]
+ );
+ }
+ }
+ }
+ }
+
+ deserialize(room: IRoom): void {
+ this.simulate = room.simulate ?? true;
+ this.renderer.backgroundColor = PIXI.utils.string2hex(room.backgroundColor);
+ // Add primary viewport
+ this.primaryViewport = new Viewport(room, true, this);
+ this.restrictViewport = new ViewportRestriction(this);
+ this.overlays.addChild(this.restrictViewport);
+ this.overlays.addChild(this.primaryViewport);
+ this.viewports.add(this.primaryViewport);
+ // Add the remaining entities
+ for (const bg of room.backgrounds) {
+ this.addBackground(bg);
+ }
+ for (const copy of room.copies) {
+ const pixiCopy = new Copy(copy, this);
+ this.room.addChild(pixiCopy);
+ }
+ for (const tileLayer of room.tiles) {
+ this.addTileLayer(tileLayer);
+ }
+ }
+ serialize(): void {
+ this.ctRoom.copies = [...this.copies].map(c => c.serialize());
+ this.ctRoom.tiles = this.tileLayers.map(tl => tl.serialize());
+ this.ctRoom.backgrounds = this.backgrounds.map(bg => bg.serialize());
+ this.ctRoom.lastmod = Number(new Date());
+ }
+
+ /**
+ * It is separated into a method to be usable externally.
+ * room-tile-editor uses it to add new layers.
+ */
+ addTileLayer(tileLayer: ITileLayerTemplate | TileLayer, writeToHistory?: boolean): TileLayer {
+ const pixiTileLayer = tileLayer instanceof TileLayer ?
+ tileLayer :
+ new TileLayer(tileLayer, this);
+ if (this.colorizeTileLayers) {
+ pixiTileLayer.filters = [recolorFilters[pixiTileLayer.id % 6]];
+ }
+ this.room.addChild(pixiTileLayer);
+ this.tileLayers.push(pixiTileLayer);
+ this.tileLayers.sort((a, b) => b.zIndex - a.zIndex);
+ if (pixiTileLayer.children) {
+ for (const tile of pixiTileLayer.children) {
+ this.tiles.add(tile);
+ }
+ }
+ if (writeToHistory) {
+ this.history.pushChange({
+ type: 'tileLayerCreation',
+ created: pixiTileLayer
+ });
+ }
+ return pixiTileLayer;
+ }
+
+ /**
+ * It is separated as well to be usable by UI written with Riot.
+ */
+ addBackground(bgTemplate: IRoomBackground): Background {
+ const bg = new Background(bgTemplate, this);
+ this.backgrounds.push(bg);
+ this.room.addChild(bg);
+ return bg;
+ }
+
+ resizeClicktrap(): void {
+ this.clicktrap.width = this.screen.width;
+ this.clicktrap.height = this.screen.height;
+ }
+ redrawGrid(): void {
+ const w = this.ctRoom.gridX,
+ h = this.ctRoom.gridY;
+ this.grid.clear();
+ if (!this.riotEditor.gridOn) {
+ // Grid isn't needed
+ return;
+ }
+ // Don't draw too fine grid
+ if (w / this.camera.scale.x < 8 || h / this.camera.scale.y < 8) {
+ return;
+ }
+ this.grid.lineStyle(this.camera.scale.x, getPixiSwatch('act'), 0.3);
+ // Camera boundaries with extra tiles around the border
+ const cw = this.screen.width * this.camera.scale.x + w * 2,
+ ch = this.screen.height * this.camera.scale.y + h * 2,
+ cx = this.camera.x - this.screen.width / 2 * this.camera.scale.x - w,
+ cy = this.camera.y - this.screen.height / 2 * this.camera.scale.y - h;
+ const xstart = cx;
+ const ystart = cy;
+ this.grid.x = -(cx % w);
+ this.grid.y = -(cy % h);
+ if (this.ctRoom.diagonalGrid) {
+ const angle1 = Math.atan(h / w);
+ const angle2 = Math.PI - angle1;
+ const cos1 = Math.cos(angle1),
+ cos2 = Math.cos(angle2),
+ sin1 = Math.sin(angle1),
+ sin2 = Math.sin(angle2);
+ const max = Math.sqrt(cw * cw + ch * ch);
+ for (let x = xstart; x < cx + cw; x += w) {
+ this.grid.moveTo(x, cy);
+ this.grid.lineTo(x + cos1 * max, cy + sin1 * max);
+ this.grid.moveTo(x, cy);
+ this.grid.lineTo(x + cos2 * max, cy + sin2 * max);
+ }
+ for (let y = ystart + h; y < cy + ch; y += h) {
+ this.grid.moveTo(cx, y);
+ this.grid.lineTo(cx + cos1 * max, y + sin1 * max);
+ }
+ const cwCorrected = Math.ceil(cw / w) * w;
+ for (let y = ystart; y < cy + ch; y += h) {
+ this.grid.moveTo(cx + cwCorrected, y);
+ this.grid.lineTo(cx + cwCorrected + cos2 * max, y + sin2 * max);
+ }
+ } else {
+ for (let x = xstart; x < cx + cw; x += w) {
+ this.grid.moveTo(x, cy);
+ this.grid.lineTo(x, cy + ch);
+ }
+ for (let y = ystart; y < cy + ch; y += h) {
+ this.grid.moveTo(cx, y);
+ this.grid.lineTo(cx + cw, y);
+ }
+ }
+ }
+ redrawViewports(): void {
+ for (const viewport of this.viewports) {
+ viewport.redrawFrame();
+ }
+ this.restrictViewport.redrawFrame();
+ }
+ /**
+ * Updates room position based on the camera position.
+ * @returns {void}
+ */
+ realignCamera(): void {
+ this.room.transform.setFromMatrix(this.camera.worldTransform
+ .clone()
+ .invert()
+ .translate(
+ this.view.width / devicePixelRatio / 2,
+ this.view.height / devicePixelRatio / 2
+ ));
+ this.overlays.transform = this.room.transform;
+ this.redrawGrid();
+ this.redrawViewports();
+ }
+ tickBackgrounds(): void {
+ for (const background of this.backgrounds) {
+ background.tick(this.ticker.deltaTime);
+ }
+ }
+ tickCopies(): void {
+ if (!this.simulate) {
+ return;
+ }
+ for (const copy of this.copies) {
+ copy.update(this.ticker.deltaTime);
+ }
+ }
+ repositionCoordLabel(): void {
+ this.pointerCoords.y = this.screen.height - 30;
+ }
+
+ updateTextures(textureId: string): void {
+ for (const child of this.room.children) {
+ if (child instanceof Copy) {
+ if (child.cachedTemplate.texture === textureId) {
+ child.refreshTexture();
+ }
+ } else if (child instanceof Tile) {
+ if (child.tileTexture === textureId) {
+ child.refreshTexture();
+ }
+ } else if (child instanceof Background) {
+ if (child.bgTexture === textureId) {
+ child.refreshTexture();
+ }
+ }
+ }
+ }
+ updateCopies(templateId: string): void {
+ for (const child of this.room.children) {
+ if (child instanceof Copy) {
+ if (child.templateId === templateId) {
+ child.refreshTexture();
+ }
+ }
+ }
+ }
+ updateTexturesHandle: (textureId: string) => void;
+ updateCopiesHandle: (templateId: string) => void;
+
+ #simulate: boolean;
+ get simulate(): boolean {
+ return this.#simulate;
+ }
+ set simulate(value: boolean) {
+ this.#simulate = value;
+ if (this.#simulate) {
+ this.ticker.speed = 1;
+ } else {
+ this.ticker.speed = 0;
+ }
+ }
+
+ #copiesVisible = true;
+ #tilesVisible = true;
+ #backgroundsVisible = true;
+ #xrayMode = false;
+ #colorizeTileLayers = false;
+ get copiesVisible(): boolean {
+ return this.#copiesVisible;
+ }
+ set copiesVisible(value: boolean) {
+ value = Boolean(value);
+ if (value === this.#copiesVisible) {
+ return;
+ }
+ this.#copiesVisible = value;
+ for (const copy of this.copies) {
+ copy.visible = this.#copiesVisible;
+ }
+ }
+ get tilesVisible(): boolean {
+ return this.#tilesVisible;
+ }
+ set tilesVisible(value: boolean) {
+ value = Boolean(value);
+ if (value === this.#tilesVisible) {
+ return;
+ }
+ this.#tilesVisible = value;
+ for (const layer of this.tileLayers) {
+ layer.visible = this.#tilesVisible;
+ }
+ }
+ get backgroundsVisible(): boolean {
+ return this.#backgroundsVisible;
+ }
+ set backgroundsVisible(value: boolean) {
+ value = Boolean(value);
+ if (value === this.#backgroundsVisible) {
+ return;
+ }
+ this.#backgroundsVisible = value;
+ for (const bg of this.backgrounds) {
+ bg.visible = this.#backgroundsVisible;
+ }
+ }
+ get xrayMode(): boolean {
+ return this.#xrayMode;
+ }
+ set xrayMode(value: boolean) {
+ this.#xrayMode = Boolean(value);
+ this.room.alpha = this.#xrayMode ? 0.5 : 1;
+ }
+ get colorizeTileLayers(): boolean {
+ return this.#colorizeTileLayers;
+ }
+ set colorizeTileLayers(value: boolean) {
+ this.#colorizeTileLayers = Boolean(value);
+ for (const layer of this.tileLayers) {
+ if (this.#colorizeTileLayers) {
+ layer.filters = [recolorFilters[layer.id % 6]];
+ } else {
+ layer.filters = [];
+ }
+ layer.visible = this.#tilesVisible;
+ }
+ }
+
+ #selectCopies = true;
+ #selectTiles = true;
+ get selectCopies(): boolean {
+ return this.#selectCopies;
+ }
+ set selectCopies(value: boolean) {
+ value = Boolean(value);
+ this.#selectCopies = value;
+ }
+ get selectTiles(): boolean {
+ return this.#selectTiles;
+ }
+ set selectTiles(value: boolean) {
+ value = Boolean(value);
+ this.#selectTiles = value;
+ }
+
+ goHome(): void {
+ this.riotEditor.zoom = 1;
+ ease.add(this.camera, {
+ x: this.ctRoom.width / 2,
+ y: this.ctRoom.height / 2,
+ scale: 1
+ }, {
+ duration: 500
+ })
+ .on('each', () => {
+ this.riotEditor.refs.zoomLabel.innerHTML = `${Math.round(this.getZoom())}%`;
+ });
+ }
+ zoomTo(zoom: number): void {
+ const scale = 1 / zoom * 100;
+ ease.add(this.camera, {
+ scale
+ }, {
+ duration: 500
+ })
+ .on('each', () => {
+ this.riotEditor.refs.zoomLabel.innerHTML = `${Math.round(this.getZoom())}%`;
+ });
+ }
+ getZoom(): number {
+ // Somehow, when updating a room-editor tag, it loses camera but not the editor itself
+ return this.camera ? (1 / this.camera.scale.x * 100) : 100;
+ }
+
+ /**
+ * Returns a base64 string of a room's main viewport.
+ * It is expected to be run when the room editor is no longer needed,
+ * as it repositions the room.
+ */
+ getSplashScreen(big: boolean): HTMLCanvasElement {
+ const w = big ? 340 : 64,
+ h = big ? 256 : 64;
+ const renderTexture = PIXI.RenderTexture.create({
+ width: w,
+ height: h
+ });
+ this.overlays.visible = false;
+ this.transformer.visible = false;
+ this.pointerCoords.visible = false;
+ this.clicktrap.width = w;
+ this.clicktrap.height = h;
+ this.clicktrap.alpha = 1;
+ this.clicktrap.tint = this.renderer.backgroundColor;
+ this.room.scale.set(Math.min(w / this.ctRoom.width, h / this.ctRoom.height));
+ this.room.x = (w - this.ctRoom.width * this.room.scale.x) / 2;
+ this.room.y = (h - this.ctRoom.height * this.room.scale.y) / 2;
+ this.renderer.render(this.stage, renderTexture);
+ return this.renderer.extract.canvas(renderTexture);
+ }
+}
+
+
+const setup = (canvas: HTMLCanvasElement, editorTag: IRoomEditorRiotTag): RoomEditor => {
+ const pixelart = Boolean(currentProject.settings.rendering.pixelatedrender);
+ editorTag.pixiEditor = new RoomEditor({
+ view: canvas
+ }, editorTag, pixelart);
+ return editorTag.pixiEditor;
+};
+
+
+export {
+ setup,
+ IRoomEditorInteraction,
+ RoomEditor
+};
diff --git a/src/node_requires/roomEditor/interactions/camera/home.ts b/src/node_requires/roomEditor/interactions/camera/home.ts
new file mode 100644
index 000000000..9f5f81583
--- /dev/null
+++ b/src/node_requires/roomEditor/interactions/camera/home.ts
@@ -0,0 +1,16 @@
+import {IRoomEditorInteraction} from '..';
+
+const goHome: IRoomEditorInteraction = {
+ ifListener: 'home',
+ if() {
+ return true;
+ },
+ listeners: {
+ home(e, riotTag, affixedData, callback) {
+ this.goHome();
+ callback();
+ }
+ }
+};
+
+export {goHome};
diff --git a/src/node_requires/roomEditor/interactions/camera/move.ts b/src/node_requires/roomEditor/interactions/camera/move.ts
new file mode 100644
index 000000000..603a8b427
--- /dev/null
+++ b/src/node_requires/roomEditor/interactions/camera/move.ts
@@ -0,0 +1,46 @@
+import {IRoomEditorInteraction} from '..';
+
+interface IMoveCameraAffixedData {
+ cameraFromPos: {
+ x: number,
+ y: number
+ },
+ fromOffsetPos: {
+ x: number,
+ y: number
+ }
+}
+
+const moveCameraOnWheelPress: IRoomEditorInteraction = {
+ ifListener: 'pointerdown',
+ if(e) {
+ // Checks for a pressed mouse wheel
+ return e.data.button === 1;
+ },
+ listeners: {
+ pointerdown(e, roomTag, affixedData) {
+ affixedData.cameraFromPos = {
+ x: this.camera.x,
+ y: this.camera.y
+ };
+ affixedData.fromOffsetPos = {
+ x: e.data.global.x,
+ y: e.data.global.y
+ };
+ },
+ pointermove(e, roomTag, affixedData) {
+ const cfp = affixedData.cameraFromPos,
+ op = affixedData.fromOffsetPos;
+ this.camera.x = cfp.x + (op.x - e.data.global.x) * this.camera.scale.x;
+ this.camera.y = cfp.y + (op.y - e.data.global.y) * this.camera.scale.y;
+ this.camera.updateTransform();
+ this.tickBackgrounds();
+ },
+ pointerup: (e, roomTag, affixedData, callback) => {
+ callback();
+ }
+ }
+};
+moveCameraOnWheelPress.listeners.pointerupoutside = moveCameraOnWheelPress.listeners.pointerup;
+
+export {moveCameraOnWheelPress};
diff --git a/src/node_requires/roomEditor/interactions/camera/zoom.ts b/src/node_requires/roomEditor/interactions/camera/zoom.ts
new file mode 100644
index 000000000..d3bcb17f2
--- /dev/null
+++ b/src/node_requires/roomEditor/interactions/camera/zoom.ts
@@ -0,0 +1,48 @@
+import {IRoomEditorInteraction} from '../..';
+import {ease, Easing} from 'node_modules/pixi-ease';
+
+interface IZoomData {
+ ease: Easing
+}
+
+const zoomInteraction: IRoomEditorInteraction = {
+ ifListener: 'wheel',
+ if() {
+ return true;
+ },
+ listeners: {
+ wheel(e, roomTag, affixedData, finishCallback) {
+ const oldZoom = roomTag.zoom;
+ const dx = this.screen.width / 2 - e.data.global.x,
+ dy = this.screen.height / 2 - e.data.global.y;
+ let newZoom;
+ if ((e.data.originalEvent as WheelEvent).deltaY < 0) {
+ newZoom = oldZoom * 0.75;
+ } else {
+ newZoom = oldZoom * 1.25;
+ }
+ if (Math.abs(newZoom - 1) < 0.1) {
+ newZoom = 1;
+ }
+ roomTag.zoom = newZoom;
+ if (affixedData.ease) {
+ affixedData.ease.remove();
+ }
+ affixedData.ease = ease.add(this.camera, {
+ scale: newZoom,
+ x: this.camera.x + dx * (newZoom - this.camera.scale.x),
+ y: this.camera.y + dy * (newZoom - this.camera.scale.y)
+ }, {
+ duration: 200
+ })
+ .on('each', () => {
+ this.camera.updateTransform();
+ this.realignCamera();
+ roomTag.refs.zoomLabel.innerHTML = `${Math.round(this.getZoom())}%`;
+ })
+ .once('complete', finishCallback);
+ }
+ }
+};
+
+export {zoomInteraction};
diff --git a/src/node_requires/roomEditor/interactions/copies/deleteCopies.ts b/src/node_requires/roomEditor/interactions/copies/deleteCopies.ts
new file mode 100644
index 000000000..b442bb650
--- /dev/null
+++ b/src/node_requires/roomEditor/interactions/copies/deleteCopies.ts
@@ -0,0 +1,40 @@
+import {IRoomEditorInteraction} from '../..';
+import {Copy} from '../../entityClasses/Copy';
+
+type affixedData = {
+ deleted: Set<[Copy]>;
+}
+
+export const deleteCopies: IRoomEditorInteraction = {
+ ifListener: 'pointerdown',
+ if(e) {
+ if (this.riotEditor.currentTool !== 'addCopies') {
+ return false;
+ }
+ return e.data.button === 0 && e.data.originalEvent.ctrlKey;
+ },
+ listeners: {
+ pointerdown(e, riotTag, affixedData) {
+ affixedData.deleted = new Set();
+ if (e.target instanceof Copy) {
+ affixedData.deleted.add([e.target.detach()]);
+ }
+ },
+ pointermove(e, riotTag, affixedData) {
+ if (e.target instanceof Copy) {
+ affixedData.deleted.add([e.target.detach()]);
+ }
+ },
+ pointerup(e, roomTag, affixedData, callback) {
+ if (affixedData.deleted.size) {
+ this.history.pushChange({
+ type: 'deletion',
+ deleted: affixedData.deleted
+ });
+ }
+ callback();
+ }
+ }
+};
+
+deleteCopies.listeners.pointerupoutside = deleteCopies.listeners.pointerup;
diff --git a/src/node_requires/roomEditor/interactions/copies/placeCopy.ts b/src/node_requires/roomEditor/interactions/copies/placeCopy.ts
new file mode 100644
index 000000000..16f83a4ce
--- /dev/null
+++ b/src/node_requires/roomEditor/interactions/copies/placeCopy.ts
@@ -0,0 +1,148 @@
+import {IRoomEditorInteraction, RoomEditor} from '../..';
+import {Copy} from '../../entityClasses/Copy';
+
+import {calcPlacement} from '../placementCalculator';
+
+import {soundbox} from '../../../3rdparty/soundbox';
+
+interface IAffixedData {
+ mode: 'free' | 'straight';
+ startPos: PIXI.IPoint;
+ prevPos: PIXI.IPoint;
+ prevLength: number;
+ stepX: number;
+ stepY: number;
+ diagonalGrid: boolean;
+ gridX: number;
+ gridY: number;
+ noGrid: boolean;
+ created: Set<[Copy]>;
+}
+
+const createCopy = (
+ pos: PIXI.IPoint,
+ template: ITemplate,
+ editor: RoomEditor,
+ ghost?: boolean
+) => new Copy({
+ x: pos.x,
+ y: pos.y,
+ exts: {},
+ customProperties: {},
+ scale: {
+ x: 1,
+ y: 1
+ },
+ uid: template.uid,
+ opacity: 1,
+ rotation: 0,
+ tint: 0xffffff
+}, editor, ghost);
+
+export const placeCopy: IRoomEditorInteraction = {
+ ifListener: 'pointerdown',
+ if(e, riotTag) {
+ if (this.riotEditor.currentTool !== 'addCopies') {
+ return false;
+ }
+ if (e.data.button !== 0) {
+ return false;
+ }
+ return riotTag.currentTemplate && riotTag.currentTemplate !== -1;
+ },
+ listeners: {
+ pointerdown(e, roomTag, affixedData) {
+ this.compoundGhost.removeChildren();
+ affixedData.created = new Set();
+ // Two possible modes: placing in straight vertical/horizontal/diagonal lines
+ // and in a free form, like drawing with a brush.
+ // Straight method creates a ghost preview before actually creating all the copies,
+ // while the free form places copies as a user moves their cursor.
+ if (e.data.originalEvent.shiftKey) {
+ affixedData.mode = 'straight';
+ affixedData.prevLength = 1;
+ } else {
+ affixedData.mode = 'free';
+ }
+ affixedData.gridX = this.ctRoom.gridX;
+ affixedData.gridY = this.ctRoom.gridY;
+ affixedData.diagonalGrid = this.ctRoom.diagonalGrid;
+ affixedData.startPos = affixedData.prevPos = this.snapTarget.position.clone();
+ affixedData.noGrid = !roomTag.gridOn || roomTag.freePlacementMode;
+ const newCopy = createCopy(
+ affixedData.startPos,
+ this.riotEditor.currentTemplate as ITemplate,
+ this
+ );
+ affixedData.created.add([newCopy]);
+ this.room.addChild(newCopy);
+ affixedData.stepX = affixedData.stepY = 1;
+ soundbox.play('Wood_Start');
+ },
+ pointermove(e, roomTag, affixedData) {
+ affixedData.noGrid = !roomTag.gridOn || roomTag.freePlacementMode;
+ const newPos = this.snapTarget.position.clone();
+ const ghosts = calcPlacement(
+ newPos,
+ affixedData,
+ ((position): Copy => {
+ soundbox.play('Wood_Start');
+ const copy = createCopy(
+ position,
+ this.riotEditor.currentTemplate as ITemplate,
+ this
+ );
+ this.room.addChild(copy);
+ affixedData.created.add([copy]);
+ return copy;
+ })
+ );
+ // Play feedback sound on length change
+ if (ghosts.length !== affixedData.prevLength) {
+ affixedData.prevLength = ghosts.length;
+ soundbox.play('Wood_Start');
+ }
+ // Remove excess ghost instances
+ if (this.compoundGhost.children.length > ghosts.length) {
+ this.compoundGhost.removeChildren(ghosts.length);
+ }
+ // Add missing ghost instances
+ while (this.compoundGhost.children.length < ghosts.length) {
+ this.compoundGhost.addChild(createCopy(
+ affixedData.startPos,
+ this.riotEditor.currentTemplate as ITemplate,
+ this,
+ true
+ ));
+ }
+ for (let i = 0; i < ghosts.length; i++) {
+ const ghost = this.compoundGhost.children[i];
+ ghost.x = ghosts[i].x;
+ ghost.y = ghosts[i].y;
+ }
+ },
+ pointerup(e, roomTag, affixedData, callback) {
+ if (affixedData.mode === 'straight') {
+ // Replace all the preview copies with real ones
+ for (const ghost of this.compoundGhost.children) {
+ const copy = createCopy(
+ ghost.position,
+ this.riotEditor.currentTemplate as ITemplate,
+ this
+ );
+ this.room.addChild(copy);
+ affixedData.created.add([copy]);
+ }
+ }
+ soundbox.play('Wood_End');
+ this.compoundGhost.removeChildren();
+ this.history.pushChange({
+ type: 'creation',
+ created: affixedData.created
+ });
+ callback();
+ }
+ }
+};
+
+placeCopy.listeners.pointerupoutside = placeCopy.listeners.pointerup;
diff --git a/src/node_requires/roomEditor/interactions/copyPaste.ts b/src/node_requires/roomEditor/interactions/copyPaste.ts
new file mode 100644
index 000000000..fbdd3cf12
--- /dev/null
+++ b/src/node_requires/roomEditor/interactions/copyPaste.ts
@@ -0,0 +1,126 @@
+import {IRoomEditorInteraction} from '..';
+import {Copy} from '../entityClasses/Copy';
+import {Tile} from '../entityClasses/Tile';
+import {TileLayer} from '../entityClasses/TileLayer';
+
+import {snapToDiagonalGrid, snapToRectangularGrid} from '../common';
+
+import {getTemplateFromId} from '../../resources/templates';
+
+export const copy: IRoomEditorInteraction = {
+ ifListener: 'copy',
+ if() {
+ return this.riotEditor.currentTool === 'select' && this.currentSelection.size > 0;
+ },
+ listeners: {
+ copy(e, riotEditor, affixedData, callback) {
+ this.clipboard.clear();
+ for (const stuff of this.currentSelection) {
+ if (stuff instanceof Copy) {
+ this.clipboard.add([
+ 'copy',
+ stuff.serialize()
+ ]);
+ } else if (stuff instanceof Tile) {
+ this.clipboard.add([
+ 'tile',
+ stuff.serialize(),
+ stuff.parent
+ ]);
+ }
+ }
+ this.transformer.blink();
+ callback();
+ }
+ }
+};
+
+export const paste: IRoomEditorInteraction = {
+ ifListener: 'paste',
+ if() {
+ return this.clipboard.size > 0;
+ },
+ listeners: {
+ paste(e, riotEditor, affixedData, callback) {
+ const createdSet = new Set<[Copy | Tile, TileLayer?]>();
+ if (riotEditor.currentTool === 'select' &&
+ this.currentSelection.size &&
+ this.history.currentChange?.type === 'transformation'
+ ) {
+ this.history.snapshotTransforms();
+ }
+ this.transformer.clear();
+ const extraTileLayer = this.tileLayers.find(tl => tl.zIndex === 0) || new TileLayer({
+ depth: 0,
+ tiles: []
+ }, this);
+ for (const copied of this.clipboard) {
+ let created;
+ if (copied[0] === 'tile') {
+ const [, template, layer] = copied;
+ const target = this.tileLayers.includes(layer) ? layer : extraTileLayer;
+ created = new Tile(template, this, false);
+ target.addChild(created);
+ createdSet.add([created, target]);
+ } else if (copied[0] === 'copy') {
+ const [, template] = copied;
+ // Skip copies that no longer exist in the project
+ try {
+ getTemplateFromId(template.uid);
+ created = new Copy(template, this, false);
+ this.room.addChild(created);
+ createdSet.add([created]);
+ } catch (_) {
+ continue;
+ }
+ } else {
+ // Unsupported selectable entity
+ continue;
+ }
+ this.currentSelection.add(created);
+ }
+ if (extraTileLayer.children.length && !this.tileLayers.includes(extraTileLayer)) {
+ this.addTileLayer(extraTileLayer);
+ this.history.pushChange({
+ type: 'tileLayerCreation',
+ created: extraTileLayer
+ });
+ } else {
+ extraTileLayer.destroy();
+ }
+ this.history.pushChange({
+ type: 'creation',
+ created: createdSet
+ });
+ if (riotEditor.currentTool !== 'select') {
+ riotEditor.setTool('select')();
+ riotEditor.update();
+ }
+ this.transformer.setup(true);
+
+ // place the stuff under mouse cursor but do take the grid into account
+ const {mouse} = this.renderer.plugins.interaction;
+ const mousePos = mouse.getLocalPosition(this.room);
+ let dx = mousePos.x - this.transformer.transformPivotX,
+ dy = mousePos.y - this.transformer.transformPivotY;
+ if (this.riotEditor.gridOn) {
+ const snap = this.ctRoom.diagonalGrid ? snapToDiagonalGrid : snapToRectangularGrid;
+ const snapped = snap({
+ x: dx,
+ y: dy
+ }, this.ctRoom.gridX, this.ctRoom.gridY);
+ dx = snapped.x;
+ dy = snapped.y;
+ }
+ this.transformer.transformPivotX += dx;
+ this.transformer.transformPivotY += dy;
+ this.transformer.applyTranslateX += dx;
+ this.transformer.applyTranslateY += dy;
+ this.transformer.applyTransforms();
+ this.transformer.setup();
+ riotEditor.refs.propertiesPanel.updatePropList();
+ this.transformer.blink();
+ callback();
+ }
+ }
+};
diff --git a/src/node_requires/roomEditor/interactions/history.ts b/src/node_requires/roomEditor/interactions/history.ts
new file mode 100644
index 000000000..c5040c91a
--- /dev/null
+++ b/src/node_requires/roomEditor/interactions/history.ts
@@ -0,0 +1,37 @@
+import {IRoomEditorInteraction} from '..';
+
+export const undo: IRoomEditorInteraction = {
+ ifListener: 'undo',
+ if() {
+ // History object has its internal checks,
+ // and this is the only interaction that uses this listener,
+ // so always returning true is okay.
+ return true;
+ },
+ listeners: {
+ undo(e, roomTag, affixedData, callback) {
+ if (this.history.undo()) {
+ e.data.originalEvent.preventDefault();
+ }
+ callback();
+ }
+ }
+};
+
+export const redo: IRoomEditorInteraction = {
+ ifListener: 'redo',
+ if() {
+ // History object has its internal checks,
+ // and this is the only interaction that uses this listener,
+ // so always returning true is okay.
+ return true;
+ },
+ listeners: {
+ redo(e, roomTag, affixedData, callback) {
+ if (this.history.redo()) {
+ e.data.originalEvent.preventDefault();
+ }
+ callback();
+ }
+ }
+};
diff --git a/src/node_requires/roomEditor/interactions/index.ts b/src/node_requires/roomEditor/interactions/index.ts
new file mode 100644
index 000000000..9c4f228ba
--- /dev/null
+++ b/src/node_requires/roomEditor/interactions/index.ts
@@ -0,0 +1,96 @@
+/* slint-disable no-use-before-define */
+import {RoomEditor} from '..';
+import {IRoomEditorRiotTag} from '../IRoomEditorRiotTag';
+
+export enum EAllowedListeners {
+ pointertap,
+ pointerup,
+ pointerupoutside,
+ pointerdown,
+ pointermove,
+ pointerleave,
+
+ // Custom events below
+ wheel,
+
+ home,
+
+ delete,
+ copy,
+ paste,
+ undo,
+ redo,
+
+ nudgeright,
+ nudgeleft,
+ nudgeup,
+ nudgedown
+}
+export type AllowedListener = keyof typeof EAllowedListeners;
+export const allowedListeners: AllowedListener[] =
+ Object.keys(EAllowedListeners) as AllowedListener[];
+
+export type InteractionListener = (
+ this: RoomEditor,
+ e: PIXI.InteractionEvent,
+ roomTag: IRoomEditorRiotTag,
+ affixedData: affixedInterface,
+ finishCallback: () => void
+) => void;
+export interface IRoomEditorInteraction {
+ ifListener: AllowedListener;
+ /**
+ * Checks if it is possible to run an interaction now.
+ * If this method returns true, all the further interactions will be skipped
+ * until the startingAction calls the provided finishCallback
+ */
+ if: (this: RoomEditor, e: PIXI.InteractionEvent, roomTag: IRoomEditorRiotTag) => boolean;
+ listeners: Partial>>;
+}
+
+import {updateMousePosition} from './mousePosLabel';
+import {moveCameraOnWheelPress} from './camera/move';
+import {goHome} from './camera/home';
+import {zoomInteraction} from './camera/zoom';
+import {placeCopy} from './copies/placeCopy';
+import {deleteCopies} from './copies/deleteCopies';
+import {placeTile} from './tiles/placeTile';
+import {deleteTiles} from './tiles/deleteTiles';
+import {select} from './transformer/select';
+import {nudgeLeft, nudgeRight, nudgeUp, nudgeDown} from './transformer/nudge';
+import {rotateSelection} from './transformer/rotate';
+import {moveSelection} from './transformer/move';
+import {scaleSelection} from './transformer/scale';
+import {deleteSelected} from './transformer/delete';
+import {copy, paste} from './copyPaste';
+import {undo, redo} from './history';
+
+export const interactions = [
+ updateMousePosition, // Ambient interaction — never blocks the queue
+
+ nudgeLeft,
+ nudgeRight,
+ nudgeUp,
+ nudgeDown,
+
+ copy,
+ paste,
+ undo,
+ redo,
+
+ rotateSelection,
+ moveSelection,
+ scaleSelection,
+ deleteSelected,
+ select,
+
+ deleteCopies,
+ placeCopy,
+
+ deleteTiles,
+ placeTile,
+
+ zoomInteraction,
+ moveCameraOnWheelPress,
+ goHome
+];
diff --git a/src/node_requires/roomEditor/interactions/mousePosLabel.ts b/src/node_requires/roomEditor/interactions/mousePosLabel.ts
new file mode 100644
index 000000000..52a0def47
--- /dev/null
+++ b/src/node_requires/roomEditor/interactions/mousePosLabel.ts
@@ -0,0 +1,15 @@
+import {IRoomEditorInteraction} from '..';
+
+const updateMousePosition: IRoomEditorInteraction = {
+ ifListener: 'pointermove',
+ if() {
+ const x = Math.round(this.snapTarget.x * 100) / 100,
+ y = Math.round(this.snapTarget.y * 100) / 100;
+ this.pointerCoords.text = `(${x}; ${y})`;
+ // This interaction never actually marks itself as valid
+ return false;
+ },
+ listeners: {}
+};
+
+export {updateMousePosition};
diff --git a/src/node_requires/roomEditor/interactions/placementCalculator.ts b/src/node_requires/roomEditor/interactions/placementCalculator.ts
new file mode 100644
index 000000000..0c3ff99ad
--- /dev/null
+++ b/src/node_requires/roomEditor/interactions/placementCalculator.ts
@@ -0,0 +1,136 @@
+/*
+This code was separated for DRY principle, as almost the same code
+is used while placing tiles and copies.
+
+This code is intended to be used as part of pointermove event,
+and returns a list of locations of ghost objects, which is not empty
+only while using parallel placement.
+
+During the free placement, it may call placeImmediately as a callback
+when a new object should be placed.
+*/
+
+import {fromRectangular, fromDiagonal, toRectangular, toDiagonal} from '../common';
+
+type PlacementData = {
+ mode: 'free' | 'straight';
+ startPos: PIXI.IPoint;
+ prevPos: PIXI.IPoint;
+ prevLength: number;
+ stepX: number;
+ stepY: number;
+ diagonalGrid: boolean;
+ gridX: number;
+ gridY: number;
+ noGrid: boolean;
+};
+
+type ghostPoints = {
+ x: number;
+ y: number;
+}[];
+type ISimplePoint = {
+ x: number;
+ y: number;
+};
+
+// eslint-disable-next-line max-lines-per-function
+export const calcPlacement = (
+ newPos: PIXI.IPoint,
+ affixedData: PlacementData,
+ placeImmediately: (position: PIXI.IPoint) => void
+): ghostPoints => {
+ const from = affixedData.diagonalGrid ? fromDiagonal : fromRectangular;
+ const to = affixedData.diagonalGrid ? toDiagonal : toRectangular;
+ // Correct placement position based on step size.
+ const newPosOnGrid = to(newPos, affixedData.gridX, affixedData.gridY),
+ startPosOnGrid = to(affixedData.startPos, affixedData.gridX, affixedData.gridY);
+ let newPosWSkips: ISimplePoint | PIXI.IPoint = from({
+ x: newPosOnGrid.x - ((startPosOnGrid.x - newPosOnGrid.x) % affixedData.stepX),
+ y: newPosOnGrid.y - ((startPosOnGrid.y - newPosOnGrid.y) % affixedData.stepY)
+ }, affixedData.gridX, affixedData.gridY);
+ newPosWSkips = new PIXI.Point(newPosWSkips.x, newPosWSkips.y);
+
+ // Free placement (drawing)
+ if (affixedData.mode === 'free') {
+ // When working without a grid, place copies in a strip,
+ // spacing of which depends on the grid size.
+ if (affixedData.noGrid) {
+ let dx = (newPos.x - affixedData.prevPos.x) / affixedData.gridX,
+ dy = (newPos.y - affixedData.prevPos.y) / affixedData.gridY;
+ const l = Math.sqrt(dx * dx + dy * dy);
+ if (l >= 1) {
+ dx /= l;
+ dy /= l;
+ const placeX = dx * affixedData.gridX + affixedData.prevPos.x,
+ placeY = dy * affixedData.gridY + affixedData.prevPos.y;
+ const newPlace = new PIXI.Point(placeX, placeY);
+ placeImmediately(newPlace);
+ affixedData.prevPos = newPlace;
+ }
+ return [];
+ }
+ // Skip spawning if position on-grid didn't change from the previous frame.
+ if (newPosWSkips.x === affixedData.prevPos.x && newPosWSkips.y === affixedData.prevPos.y) {
+ return [];
+ }
+ placeImmediately(newPosWSkips as PIXI.Point);
+ affixedData.prevPos = newPosWSkips as PIXI.Point;
+ return [];
+ }
+
+ affixedData.prevPos = newPos;
+
+ // Straight-line placement
+ const startGrid = to(
+ affixedData.startPos,
+ affixedData.gridX,
+ affixedData.gridY
+ );
+ const endGrid = to(
+ newPos,
+ affixedData.gridX,
+ affixedData.gridY
+ );
+ const dx = Math.abs(startGrid.x - endGrid.x),
+ dy = Math.abs(startGrid.y - endGrid.y);
+ const straightEndGrid: ISimplePoint = {
+ x: 0,
+ y: 0
+ };
+ const angle = Math.atan2(dy, dx);
+ if (Math.abs(angle) > Math.PI * 0.375 && Math.abs(angle) < Math.PI * 0.525) {
+ // Seems to be a vertical line
+ straightEndGrid.x = startGrid.x;
+ straightEndGrid.y = endGrid.y;
+ } else if (Math.abs(angle) < Math.PI * 0.125) {
+ // Seems to be a horizontal line
+ straightEndGrid.x = endGrid.x;
+ straightEndGrid.y = startGrid.y;
+ } else {
+ // It is more or so diagonal
+ const max = Math.max(dx, dy);
+ straightEndGrid.x = endGrid.x > startGrid.x ?
+ startGrid.x + max :
+ startGrid.x - max;
+ straightEndGrid.y = endGrid.y > startGrid.y ?
+ startGrid.y + max :
+ startGrid.y - max;
+ }
+ const incX = Math.sign(straightEndGrid.x - startGrid.x) * affixedData.stepX,
+ incY = Math.sign(straightEndGrid.y - startGrid.y) * affixedData.stepY;
+ const l = Math.max(dx / affixedData.stepX, dy / affixedData.stepY);
+ const ghosts = [];
+ // Calculate ghost positions
+ for (let i = 0, {x, y} = startGrid;
+ i < l;
+ i++, x += incX, y += incY
+ ) {
+ const localPos = from({
+ x: x + incX,
+ y: y + incY
+ }, affixedData.gridX, affixedData.gridY);
+ ghosts.push(localPos);
+ }
+ return ghosts;
+};
diff --git a/src/node_requires/roomEditor/interactions/tiles/ITilePatch.d.ts b/src/node_requires/roomEditor/interactions/tiles/ITilePatch.d.ts
new file mode 100644
index 000000000..675800135
--- /dev/null
+++ b/src/node_requires/roomEditor/interactions/tiles/ITilePatch.d.ts
@@ -0,0 +1,7 @@
+export interface ITilePatch {
+ startX: number;
+ startY: number;
+ spanX: number;
+ spanY: number;
+ texture: ITexture;
+}
diff --git a/src/node_requires/roomEditor/interactions/tiles/deleteTiles.ts b/src/node_requires/roomEditor/interactions/tiles/deleteTiles.ts
new file mode 100644
index 000000000..f8e3a2ae5
--- /dev/null
+++ b/src/node_requires/roomEditor/interactions/tiles/deleteTiles.ts
@@ -0,0 +1,43 @@
+import {IRoomEditorInteraction} from '../..';
+import {Tile} from '../../entityClasses/Tile';
+import {TileLayer} from '../../entityClasses/TileLayer';
+
+type affixedData = {
+ deleted: Set<[Tile, TileLayer]>;
+}
+
+export const deleteTiles: IRoomEditorInteraction = {
+ ifListener: 'pointerdown',
+ if(e) {
+ if (this.riotEditor.currentTool !== 'addTiles' || !this.riotEditor.currentTileLayer) {
+ return false;
+ }
+ return e.data.button === 0 && e.data.originalEvent.ctrlKey;
+ },
+ listeners: {
+ pointerdown(e, riotTag, affixedData) {
+ affixedData.deleted = new Set();
+ if (e.target instanceof Tile && e.target.parent === riotTag.currentTileLayer) {
+ const {parent} = e.target;
+ affixedData.deleted.add([e.target.detach(), parent]);
+ }
+ },
+ pointermove(e, riotTag, affixedData) {
+ if (e.target instanceof Tile && e.target.parent === riotTag.currentTileLayer) {
+ const {parent} = e.target;
+ affixedData.deleted.add([e.target.detach(), parent]);
+ }
+ },
+ pointerup(e, roomTag, affixedData, callback) {
+ if (affixedData.deleted.size) {
+ this.history.pushChange({
+ type: 'deletion',
+ deleted: affixedData.deleted
+ });
+ }
+ callback();
+ }
+ }
+};
+
+deleteTiles.listeners.pointerupoutside = deleteTiles.listeners.pointerup;
diff --git a/src/node_requires/roomEditor/interactions/tiles/placeTile.ts b/src/node_requires/roomEditor/interactions/tiles/placeTile.ts
new file mode 100644
index 000000000..399863478
--- /dev/null
+++ b/src/node_requires/roomEditor/interactions/tiles/placeTile.ts
@@ -0,0 +1,192 @@
+import {Tile} from '../../entityClasses/Tile';
+import {TileLayer} from '../../entityClasses/TileLayer';
+import {IRoomEditorInteraction, RoomEditor} from '../..';
+import {calcPlacement} from '../placementCalculator';
+import {ITilePatch} from './ITilePatch';
+
+import {soundbox} from '../../../3rdparty/soundbox';
+
+interface IAffixedData {
+ mode: 'free' | 'straight';
+ startPos: PIXI.IPoint;
+ prevPos: PIXI.IPoint;
+ prevLength: number;
+ stepX: number;
+ stepY: number;
+ diagonalGrid: boolean;
+ gridX: number;
+ gridY: number;
+ noGrid: boolean;
+ created: Set<[Tile, TileLayer]>;
+}
+
+interface ISimplePoint {
+ x: number;
+ y: number;
+}
+
+const createTile = (
+ pos: ISimplePoint,
+ texture: string,
+ frame: number,
+ editor: RoomEditor,
+ ghost?: boolean
+) => new Tile({
+ x: pos.x,
+ y: pos.y,
+ scale: {
+ x: 1,
+ y: 1
+ },
+ opacity: 1,
+ rotation: 0,
+ tint: 0xffffff,
+ frame,
+ texture
+}, editor, ghost);
+
+export const createTilePatch = (
+ tilePatch: ITilePatch,
+ startPos: ISimplePoint,
+ editor: RoomEditor,
+ ghost?: boolean
+): Tile[] => {
+ const tiles: Tile[] = [];
+ const {texture} = tilePatch;
+ for (let x = 0; x < tilePatch.spanX; x++) {
+ for (let y = 0; y < tilePatch.spanY; y++) {
+ const frame = x + tilePatch.startX +
+ (y + tilePatch.startY) * texture.grid[0];
+ tiles.push(createTile({
+ x: startPos.x + x * texture.width,
+ y: startPos.y + y * texture.height
+ }, texture.uid, frame, editor, ghost));
+ }
+ }
+ return tiles;
+};
+
+export const placeTile: IRoomEditorInteraction = {
+ ifListener: 'pointerdown',
+ if(e, riotTag) {
+ if (this.riotEditor.currentTool !== 'addTiles' || !this.riotEditor.currentTileLayer) {
+ return false;
+ }
+ if (e.data.button !== 0) {
+ return false;
+ }
+ return Boolean(riotTag.tilePatch?.texture);
+ },
+ listeners: {
+ pointerdown(e, riotTag, affixedData) {
+ this.compoundGhost.removeChildren();
+ affixedData.created = new Set();
+ // Two possible modes: placing in straight vertical/horizontal/diagonal lines
+ // and in a free form, like drawing with a brush.
+ // Straight method creates a ghost preview before actually creating all the copies,
+ // while the free form places copies as a user moves their cursor.
+ if (e.data.originalEvent.shiftKey) {
+ affixedData.mode = 'straight';
+ affixedData.prevLength = 1;
+ } else {
+ affixedData.mode = 'free';
+ }
+ affixedData.gridX = this.ctRoom.gridX;
+ affixedData.gridY = this.ctRoom.gridY;
+ const {texture} = riotTag.tilePatch;
+ // Allow skipping grid cells if texture's and room's grids match
+ if (this.ctRoom.gridX === texture.width && this.ctRoom.gridY === texture.height) {
+ affixedData.stepX = riotTag.tilePatch.spanX;
+ affixedData.stepY = riotTag.tilePatch.spanY;
+ } else {
+ affixedData.stepX = affixedData.stepY = 1;
+ }
+ affixedData.diagonalGrid = this.ctRoom.diagonalGrid;
+ affixedData.noGrid = !riotTag.gridOn || riotTag.freePlacementMode;
+ affixedData.startPos = affixedData.prevPos = this.snapTarget.position.clone();
+ const newTiles = createTilePatch(
+ riotTag.tilePatch,
+ affixedData.startPos,
+ this
+ );
+ riotTag.currentTileLayer.addChild(...newTiles);
+ for (const tile of newTiles) {
+ affixedData.created.add([tile, tile.parent]);
+ }
+ soundbox.play('Wood_Start');
+ },
+ pointermove(e, riotTag, affixedData) {
+ affixedData.noGrid = !riotTag.gridOn || riotTag.freePlacementMode;
+ const newPos = this.snapTarget.position.clone();
+ const ghosts = calcPlacement(
+ newPos,
+ affixedData,
+ (position => {
+ soundbox.play('Wood_Start');
+ const newTiles = createTilePatch(
+ riotTag.tilePatch,
+ position,
+ this
+ );
+ riotTag.currentTileLayer.addChild(...newTiles);
+ for (const tile of newTiles) {
+ affixedData.created.add([tile, tile.parent]);
+ }
+ })
+ );
+ // Play feedback sound on length change
+ if (ghosts.length !== affixedData.prevLength) {
+ affixedData.prevLength = ghosts.length;
+ soundbox.play('Wood_Start');
+ }
+ // Remove excess ghost instances
+ if (this.compoundGhost.children.length > ghosts.length) {
+ this.compoundGhost.removeChildren(ghosts.length);
+ }
+ // Add missing ghost instances
+ // Tile patches are grouped into containers
+ while (this.compoundGhost.children.length < ghosts.length) {
+ const ghostTilePatch = new PIXI.Container();
+ ghostTilePatch.addChild(...createTilePatch(riotTag.tilePatch, {
+ x: 0,
+ y: 0
+ }, this, true));
+ this.compoundGhost.addChild(ghostTilePatch);
+ }
+ // Reposition ghost containers
+ for (let i = 0; i < ghosts.length; i++) {
+ const ghost = this.compoundGhost.children[i];
+ ghost.x = ghosts[i].x;
+ ghost.y = ghosts[i].y;
+ }
+ },
+ pointerup(e, riotTag, affixedData, callback) {
+ if (affixedData.mode === 'straight') {
+ // Replace all the preview copies with real ones
+ for (const ghost of this.compoundGhost.children) {
+ const newTiles = createTilePatch(
+ riotTag.tilePatch,
+ ghost.position,
+ this
+ );
+ riotTag.currentTileLayer.addChild(...newTiles);
+ for (const tile of newTiles) {
+ affixedData.created.add([tile, tile.parent]);
+ }
+ }
+ }
+ soundbox.play('Wood_End');
+ this.compoundGhost.removeChildren();
+ this.stage.interactive = true; // Causes to rediscover nested elements
+ if (affixedData.created.size) {
+ this.history.pushChange({
+ type: 'creation',
+ created: affixedData.created
+ });
+ }
+ callback();
+ }
+ }
+};
+
+placeTile.listeners.pointerupoutside = placeTile.listeners.pointerup;
diff --git a/src/node_requires/roomEditor/interactions/transformer/delete.ts b/src/node_requires/roomEditor/interactions/transformer/delete.ts
new file mode 100644
index 000000000..da6ac95e0
--- /dev/null
+++ b/src/node_requires/roomEditor/interactions/transformer/delete.ts
@@ -0,0 +1,32 @@
+import {IRoomEditorInteraction} from '..';
+import {Copy} from '../../entityClasses/Copy';
+import {Tile} from '../../entityClasses/Tile';
+import {TileLayer} from '../../entityClasses/TileLayer';
+
+export const deleteSelected: IRoomEditorInteraction = {
+ ifListener: 'delete',
+ if() {
+ return this.riotEditor.currentTool === 'select' && this.currentSelection.size > 0;
+ },
+ listeners: {
+ delete(e, riotEditor, affixedData, callback) {
+ const changes = new Set<[Copy | Tile, TileLayer?]>();
+ for (const stuff of this.currentSelection) {
+ if (stuff instanceof Tile) {
+ const {parent} = stuff;
+ changes.add([stuff.detach(), parent]);
+ } else if (stuff instanceof Copy) {
+ changes.add([stuff.detach()]);
+ }
+ }
+ this.history.pushChange({
+ type: 'deletion',
+ deleted: changes
+ });
+ this.transformer.clear();
+ riotEditor.refs.propertiesPanel.updatePropList();
+
+ callback();
+ }
+ }
+};
diff --git a/src/node_requires/roomEditor/interactions/transformer/move.ts b/src/node_requires/roomEditor/interactions/transformer/move.ts
new file mode 100644
index 000000000..d31176eae
--- /dev/null
+++ b/src/node_requires/roomEditor/interactions/transformer/move.ts
@@ -0,0 +1,57 @@
+import {IRoomEditorInteraction} from '../..';
+import {snapToRectangularGrid, snapToDiagonalGrid} from '../../common';
+
+interface IAffixedData {
+ startingGlobalPos: PIXI.Point;
+ startingTranslateX: number;
+ startingTranslateY: number;
+ startingPivotX: number;
+ startingPivotY: number;
+}
+
+export const moveSelection: IRoomEditorInteraction = {
+ ifListener: 'pointerdown',
+ if(e) {
+ if (this.riotEditor.currentTool !== 'select') {
+ return false;
+ }
+ if (this.currentSelection.size === 0) {
+ return false;
+ }
+ return e.target === this.transformer.handleCenter;
+ },
+ listeners: {
+ pointerdown(e, roomTag, affixed) {
+ affixed.startingGlobalPos = e.data.global.clone();
+ affixed.startingTranslateX = this.transformer.applyTranslateX;
+ affixed.startingTranslateY = this.transformer.applyTranslateY;
+ affixed.startingPivotX = this.transformer.transformPivotX;
+ affixed.startingPivotY = this.transformer.transformPivotY;
+ },
+ pointermove(e, roomTag, affixed) {
+ let delta = {
+ x: (e.data.global.x - affixed.startingGlobalPos.x) * this.camera.scale.x,
+ y: (e.data.global.y - affixed.startingGlobalPos.y) * this.camera.scale.x
+ };
+ // Ignore grid when alt key is pressed, or when the grid is disabled
+ if (!e.data.originalEvent.altKey && roomTag.gridOn) {
+ // Otherwise, snap delta to a grid
+ if (this.ctRoom.diagonalGrid) {
+ delta = snapToDiagonalGrid(delta, this.ctRoom.gridX, this.ctRoom.gridY);
+ } else {
+ delta = snapToRectangularGrid(delta, this.ctRoom.gridX, this.ctRoom.gridY);
+ }
+ }
+ this.transformer.applyTranslateX = affixed.startingTranslateX + delta.x;
+ this.transformer.applyTranslateY = affixed.startingTranslateY + delta.y;
+ this.transformer.transformPivotX = affixed.startingPivotX + delta.x;
+ this.transformer.transformPivotY = affixed.startingPivotY + delta.y;
+ this.transformer.applyTransforms();
+ this.riotEditor.refs.propertiesPanel.updatePropList();
+ },
+ pointerup(e, roomTag, affixedData, callback) {
+ this.history.snapshotTransforms();
+ callback();
+ }
+ }
+};
diff --git a/src/node_requires/roomEditor/interactions/transformer/nudge.ts b/src/node_requires/roomEditor/interactions/transformer/nudge.ts
new file mode 100644
index 000000000..addc0bc2c
--- /dev/null
+++ b/src/node_requires/roomEditor/interactions/transformer/nudge.ts
@@ -0,0 +1,66 @@
+import {IRoomEditorInteraction} from '..';
+
+export const nudgeDown: IRoomEditorInteraction = {
+ ifListener: 'nudgedown',
+ if() {
+ return Boolean(this.riotEditor.currentTool === 'select' && this.currentSelection.size);
+ },
+ listeners: {
+ nudgedown(e, roomTag, affixedData, callback) {
+ const delta = e.data.originalEvent.ctrlKey ? 1 : this.ctRoom.gridY;
+ this.transformer.applyTranslateY += delta;
+ this.transformer.transformPivotY += delta;
+ this.transformer.applyTransforms();
+ callback();
+ }
+ }
+};
+
+export const nudgeUp: IRoomEditorInteraction = {
+ ifListener: 'nudgeup',
+ if() {
+ return Boolean(this.riotEditor.currentTool === 'select' && this.currentSelection.size);
+ },
+ listeners: {
+ nudgeup(e, roomTag, affixedData, callback) {
+ const delta = e.data.originalEvent.ctrlKey ? 1 : this.ctRoom.gridY;
+ this.transformer.applyTranslateY -= delta;
+ this.transformer.transformPivotY -= delta;
+ this.transformer.applyTransforms();
+ callback();
+ }
+ }
+};
+
+export const nudgeLeft: IRoomEditorInteraction = {
+ ifListener: 'nudgeleft',
+ if() {
+ return Boolean(this.riotEditor.currentTool === 'select' && this.currentSelection.size);
+ },
+ listeners: {
+ nudgeleft(e, roomTag, affixedData, callback) {
+ const delta = e.data.originalEvent.ctrlKey ? 1 : this.ctRoom.gridX;
+ this.transformer.applyTranslateX -= delta;
+ this.transformer.transformPivotX -= delta;
+ this.transformer.applyTransforms();
+ callback();
+ }
+ }
+};
+
+export const nudgeRight: IRoomEditorInteraction = {
+ ifListener: 'nudgeright',
+ if() {
+ return Boolean(this.riotEditor.currentTool === 'select' && this.currentSelection.size);
+ },
+ listeners: {
+ nudgeright(e, roomTag, affixedData, callback) {
+ const delta = e.data.originalEvent.ctrlKey ? 1 : this.ctRoom.gridX;
+ this.transformer.applyTranslateX += delta;
+ this.transformer.transformPivotX += delta;
+ this.transformer.applyTransforms();
+ this.history.snapshotTransforms();
+ callback();
+ }
+ }
+};
diff --git a/src/node_requires/roomEditor/interactions/transformer/rotate.ts b/src/node_requires/roomEditor/interactions/transformer/rotate.ts
new file mode 100644
index 000000000..d77c3a3c3
--- /dev/null
+++ b/src/node_requires/roomEditor/interactions/transformer/rotate.ts
@@ -0,0 +1,46 @@
+import {IRoomEditorInteraction} from '../..';
+
+import {pdn, degToRad, radToDeg} from '../../../utils/trigo';
+
+export const rotateSelection: IRoomEditorInteraction = {
+ ifListener: 'pointerdown',
+ if(e) {
+ if (this.riotEditor.currentTool !== 'select') {
+ return false;
+ }
+ if (this.currentSelection.size === 0) {
+ return false;
+ }
+ return e.target === this.transformer.handleRotate;
+ },
+ listeners: {
+ pointermove(e) {
+ const globalPivot = this.room.toGlobal(new PIXI.Point(
+ this.transformer.transformPivotX,
+ this.transformer.transformPivotY
+ ));
+ let rad = pdn(
+ globalPivot.x,
+ globalPivot.y,
+ e.data.global.x,
+ e.data.global.y
+ );
+ // When the group is mirrored horizontally,
+ // the handle appears on the left side, not on the right side.
+ if (this.transformer.applyScaleX < 0) {
+ rad += Math.PI;
+ }
+ if (e.data.originalEvent.shiftKey) {
+ // Snap at 15 degrees
+ rad = degToRad(Math.round(radToDeg(rad) / 15) * 15);
+ }
+ this.transformer.applyRotation = rad;
+ this.transformer.applyTransforms();
+ this.riotEditor.refs.propertiesPanel.updatePropList();
+ },
+ pointerup(e, roomTag, affixedData, callback) {
+ this.history.snapshotTransforms();
+ callback();
+ }
+ }
+};
diff --git a/src/node_requires/roomEditor/interactions/transformer/scale.ts b/src/node_requires/roomEditor/interactions/transformer/scale.ts
new file mode 100644
index 000000000..75d46bc24
--- /dev/null
+++ b/src/node_requires/roomEditor/interactions/transformer/scale.ts
@@ -0,0 +1,154 @@
+import {IRoomEditorInteraction} from '../..';
+import {Handle} from '../../entityClasses/Transformer';
+
+import {rotateRad} from '../../../utils/trigo';
+import {snapToRectangularGrid, snapToDiagonalGrid} from '../../common';
+
+interface IAffixedData {
+ axes: 'x' | 'y' | 'xy';
+ startingSX: number;
+ startingSY: number;
+ startingTX: number;
+ startingTY: number;
+ startingPX: number;
+ startingPY: number;
+ startDragRoom: PIXI.IPoint;
+}
+
+export const scaleSelection: IRoomEditorInteraction = {
+ ifListener: 'pointerdown',
+ if(e) {
+ if (this.riotEditor.currentTool !== 'select') {
+ return false;
+ }
+ if (this.currentSelection.size === 0) {
+ return false;
+ }
+ return this.transformer.scaleHandles.includes(e.target as Handle);
+ },
+ listeners: {
+ pointerdown(e, roomTag, affixedData) {
+ // Fix scaling to zero
+ affixedData.startingSX = this.transformer.applyScaleX || 1;
+ affixedData.startingSY = this.transformer.applyScaleY || 1;
+ affixedData.startingTX = this.transformer.applyTranslateX;
+ affixedData.startingTY = this.transformer.applyTranslateY;
+ affixedData.startingPX = this.transformer.transformPivotX;
+ affixedData.startingPY = this.transformer.transformPivotY;
+ affixedData.startDragRoom = this.room.toLocal(e.target.position);
+ const t = this.transformer;
+ if ([t.handleBL, t.handleBR, t.handleTL, t.handleTR].includes(e.target as Handle)) {
+ affixedData.axes = 'xy';
+ } else if ([t.handleR, t.handleL].includes(e.target as Handle)) {
+ affixedData.axes = 'x';
+ } else {
+ affixedData.axes = 'y';
+ }
+ },
+ // eslint-disable-next-line max-lines-per-function
+ pointermove(e, riotTag, affixedData) {
+ const {transformer} = this;
+ const scaleSymmetrically = e.data.originalEvent.ctrlKey;
+ const proportionalScale = e.data.originalEvent.shiftKey && affixedData.axes === 'xy';
+ const snapToGrid = !e.data.originalEvent.altKey && riotTag.gridOn;
+ const {axes} = affixedData;
+ const dragEndRoom = this.room.toLocal(e.data.global);
+ if (snapToGrid) {
+ if (this.ctRoom.diagonalGrid) {
+ ({x: dragEndRoom.x, y: dragEndRoom.y} = snapToDiagonalGrid(
+ dragEndRoom,
+ this.ctRoom.gridX,
+ this.ctRoom.gridY
+ ));
+ } else {
+ ({x: dragEndRoom.x, y: dragEndRoom.y} = snapToRectangularGrid(
+ dragEndRoom,
+ this.ctRoom.gridX,
+ this.ctRoom.gridY
+ ));
+ }
+ }
+
+ const startUnrotated = rotateRad(
+ affixedData.startDragRoom.x - affixedData.startingPX,
+ affixedData.startDragRoom.y - affixedData.startingPY,
+ -transformer.applyRotation
+ );
+ const endUnrotated = rotateRad(
+ dragEndRoom.x - affixedData.startingPX,
+ dragEndRoom.y - affixedData.startingPY,
+ -transformer.applyRotation
+ );
+ // kx and ky describe how much a container expanded relative to its starting width
+ let kx = endUnrotated[0] / startUnrotated[0],
+ ky = endUnrotated[1] / startUnrotated[1];
+ if (!Number.isFinite(kx)) {
+ kx = 1;
+ }
+ if (!Number.isFinite(ky)) {
+ ky = 1;
+ }
+ if (proportionalScale) {
+ const max = Math.max(Math.abs(kx), Math.abs(ky));
+ kx = (Math.sign(kx) || 1) * max;
+ ky = (Math.sign(ky) || 1) * max;
+ if (Math.sign(kx * ky) === -1) {
+ // Constraint handles to its own diagonal
+ kx *= -1;
+ }
+ // Project an end point along a diagonal
+ endUnrotated[0] = kx * startUnrotated[0];
+ endUnrotated[1] = ky * startUnrotated[1];
+ }
+ if (!scaleSymmetrically) {
+ kx = kx * 0.5 + 0.5;
+ ky = ky * 0.5 + 0.5;
+ }
+ transformer.applyTranslateX = affixedData.startingTX;
+ transformer.applyTranslateY = affixedData.startingTY;
+ transformer.transformPivotX = affixedData.startingPX;
+ transformer.transformPivotY = affixedData.startingPY;
+ if (axes === 'x' || axes === 'xy') {
+ transformer.applyScaleX = affixedData.startingSX * kx || 1;
+ if (!scaleSymmetrically) {
+ // Shift the pivot and update the translate values of the transformer widget
+ // so entities slide in the specified direction,
+ // keeping the opposing side in its place
+ const shift = rotateRad(
+ endUnrotated[0] - startUnrotated[0],
+ 0,
+ transformer.applyRotation
+ );
+ transformer.applyTranslateX += shift[0] / 2;
+ transformer.applyTranslateY += shift[1] / 2;
+ transformer.transformPivotX += shift[0] / 2;
+ transformer.transformPivotY += shift[1] / 2;
+ }
+ }
+ if (axes === 'y' || axes === 'xy') {
+ transformer.applyScaleY = affixedData.startingSY * ky || 1;
+ if (!scaleSymmetrically) {
+ // Shift the pivot and update the translate values of the transformer widget
+ // so entities slide in the specified direction,
+ // keeping the opposing side in its place
+ const shift = rotateRad(
+ 0,
+ endUnrotated[1] - startUnrotated[1],
+ transformer.applyRotation
+ );
+ transformer.applyTranslateX += shift[0] * 0.5;
+ transformer.applyTranslateY += shift[1] * 0.5;
+ transformer.transformPivotX += shift[0] * 0.5;
+ transformer.transformPivotY += shift[1] * 0.5;
+ }
+ }
+
+ transformer.applyTransforms();
+ this.riotEditor.refs.propertiesPanel.updatePropList();
+ },
+ pointerup(e, roomTag, affixedData, callback) {
+ this.history.snapshotTransforms();
+ callback();
+ }
+ }
+};
diff --git a/src/node_requires/roomEditor/interactions/transformer/select.ts b/src/node_requires/roomEditor/interactions/transformer/select.ts
new file mode 100644
index 000000000..12964be48
--- /dev/null
+++ b/src/node_requires/roomEditor/interactions/transformer/select.ts
@@ -0,0 +1,162 @@
+import {IRoomEditorInteraction} from '../..';
+import {Copy} from '../../entityClasses/Copy';
+import {Tile} from '../../entityClasses/Tile';
+
+interface IAffixedData {
+ startRoomPos: PIXI.IPoint;
+ startClientPos: PIXI.IPoint;
+ startSelected: PIXI.DisplayObject;
+ mode: 'pick' | 'add' | 'remove' | 'toggle';
+}
+
+const modifySet = (
+ set: Set,
+ delta: PIXI.DisplayObject[],
+ mode: IAffixedData['mode']
+) => {
+ switch (mode) {
+ case 'add':
+ for (const elt of delta) {
+ set.add(elt);
+ }
+ break;
+ case 'remove':
+ for (const elt of delta) {
+ set.delete(elt);
+ }
+ break;
+ case 'toggle':
+ for (const elt of delta) {
+ if (set.has(elt)) {
+ set.delete(elt);
+ } else {
+ set.add(elt);
+ }
+ }
+ break;
+ default:
+ set.clear();
+ for (const elt of delta) {
+ set.add(elt);
+ }
+ break;
+ }
+};
+
+const getCenter = function (obj: PIXI.DisplayObject, room: PIXI.Container): PIXI.IPoint {
+ const bounds = obj.getBounds();
+ const centerGlobal = new PIXI.Point(bounds.x + bounds.width / 2, bounds.y + bounds.height / 2);
+ return room.toLocal(centerGlobal);
+};
+
+/**
+ * An interaction that selects individual objects on clicks
+ * and multiple ones on click+drag, in a rectangular selection.
+ * Manages RoomEditor.marqueeBox position.
+ *
+ * Depending on what keys were pressed on selection start (ctrl, shift, alt),
+ * the operation shifts between three different modes (toggle, add, remove)
+ */
+const select: IRoomEditorInteraction = {
+ ifListener: 'pointerdown',
+ if(e) {
+ if (e.data.button !== 0) {
+ return false;
+ }
+ return this.riotEditor.currentTool === 'select';
+ },
+ listeners: {
+ pointerdown(e, riotTag, affixedData) {
+ if (e.data.originalEvent.shiftKey) {
+ affixedData.mode = 'add';
+ } else if (e.data.originalEvent.ctrlKey) {
+ affixedData.mode = 'toggle';
+ } else if (e.data.originalEvent.altKey) {
+ affixedData.mode = 'remove';
+ } else {
+ affixedData.mode = 'pick';
+ }
+ affixedData.startClientPos = e.data.global.clone();
+ affixedData.startRoomPos = this.room.toLocal(e.data.global);
+ this.marqueeBox.redrawBox(affixedData.startRoomPos.x, affixedData.startRoomPos.y, 0, 0);
+ affixedData.startSelected = e.target;
+ },
+ pointermove(e, riotTag, affixedData) {
+ const roomPos = this.room.toLocal(e.data.global);
+ this.marqueeBox.visible = true;
+ this.marqueeBox.redrawBox(
+ affixedData.startRoomPos.x,
+ affixedData.startRoomPos.y,
+ roomPos.x - affixedData.startRoomPos.x,
+ roomPos.y - affixedData.startRoomPos.y
+ );
+ },
+ pointerup(e, riotTag, affixedData, callback) {
+ // Apply any possible property changes to the previous selectio set
+ this.riotEditor.refs.propertiesPanel.applyChanges();
+
+ const selectMap: [boolean, Iterable][] = [
+ [this.selectCopies, this.copies],
+ [this.selectTiles, this.tiles]
+ ];
+ const roomPos = this.room.toLocal(e.data.global);
+ const dxClient = e.data.global.x - affixedData.startClientPos.x,
+ dyClient = e.data.global.y - affixedData.startClientPos.y;
+ const lClient = Math.sqrt(dxClient ** 2 + dyClient ** 2);
+ // Too small selections on a client scale count as clicks
+ if (lClient < 8) {
+ let s = affixedData.startSelected,
+ currentSelection;
+ // Pick a suitable entity under the cursor (try both from pointerdown and pointerup)
+ if ((s instanceof Copy && this.selectCopies) ||
+ (s instanceof Tile && this.selectTiles)
+ ) {
+ currentSelection = s;
+ } else {
+ s = e.target;
+ if ((s instanceof Copy && this.selectCopies) ||
+ (s instanceof Tile && this.selectTiles)
+ ) {
+ currentSelection = s;
+ }
+ }
+ if (currentSelection) {
+ modifySet(this.currentSelection, [s], affixedData.mode);
+ } else if (affixedData.mode === 'pick') {
+ // If no keyboard modifiers were active and a user clicked, clear the selection
+ this.currentSelection.clear();
+ }
+ } else {
+ // Rectangular selection
+ // Loop through all the selectable elements in the room and put into the selection
+ // those which *visible* centers are inside the rectangle (ignore pivots).
+ const delta = [];
+ const rect = new PIXI.Rectangle(
+ Math.min(affixedData.startRoomPos.x, roomPos.x),
+ Math.min(affixedData.startRoomPos.y, roomPos.y),
+ Math.abs(roomPos.x - affixedData.startRoomPos.x),
+ Math.abs(roomPos.y - affixedData.startRoomPos.y)
+ );
+ for (const selectType of selectMap) {
+ if (selectType[0]) {
+ for (const object of selectType[1]) {
+ const {x, y} = getCenter(object, this.room);
+ if (rect.contains(x, y)) {
+ delta.push(object);
+ }
+ }
+ }
+ }
+ modifySet(this.currentSelection, delta, affixedData.mode);
+ }
+ this.transformer.setup();
+ this.marqueeBox.visible = false;
+ this.riotEditor.refs.propertiesPanel.updatePropList();
+ callback();
+ }
+ }
+};
+
+select.listeners.pointerupoutside = select.listeners.pointerup;
+
+export {select};
diff --git a/src/node_requires/themes/index.ts b/src/node_requires/themes/index.ts
index 6900086a8..7c67350bc 100644
--- a/src/node_requires/themes/index.ts
+++ b/src/node_requires/themes/index.ts
@@ -1,4 +1,4 @@
-const path = require('path');
+import {join} from 'path';
const defaultTheme = 'Day';
const defaultMonacoTheme = defaultTheme;
@@ -25,6 +25,21 @@ interface ITheme {
css: string;
}
+// @see https://mmazzarolo.com/blog/2021-10-10-on-toggling-stylesheets/
+const waitForStylesheet = (): Promise => {
+ const stylesheet = [...document.styleSheets].find(s => s.ownerNode === document.getElementById('themeCSS'));
+ const oldHref = stylesheet?.href;
+ return new Promise((resolve) => {
+ const interval = setInterval(() => {
+ const stylesheet2 = [...document.styleSheets].find(s => s.ownerNode === document.getElementById('themeCSS'));
+ if (stylesheet2 && (!oldHref || (stylesheet2.href && oldHref !== stylesheet2.href))) {
+ clearInterval(interval);
+ resolve();
+ }
+ }, 20);
+ });
+};
+
var currentSwatches: Record;
const registeredThemes: ITheme[] = [];
@@ -37,7 +52,7 @@ const updateSwatches = (): void => {
swatchTester.style.display = 'none';
document.body.appendChild(swatchTester);
swatchTester.innerText = 'sausage';
- for (const swatch of ['act', 'acttext', 'accent1', 'borderPale', 'borderBright', 'text', 'backgroundDeeper', 'act-contrast', 'acttext-contrast', 'accent1-contrast']) {
+ for (const swatch of ['act', 'acttext', 'accent1', 'borderPale', 'borderBright', 'text', 'background', 'backgroundDeeper', 'act-contrast', 'acttext-contrast', 'accent1-contrast', 'red', 'green', 'orange']) {
swatchTester.setAttribute('css-swatch', swatch);
const style = window.getComputedStyle(swatchTester);
currentSwatches[swatch] = style.getPropertyValue('color');
@@ -52,12 +67,12 @@ const mod = {
}
let monacoTheme;
try {
- monacoTheme = require(path.join('./data/node_requires/monaco-themes', `${name}.json`));
+ monacoTheme = require(join('./data/node_requires/monaco-themes', `${name}.json`));
(window as Window).monaco.editor.defineTheme(name, monacoTheme);
} catch (e) {
// eslint-disable-next-line no-console
console.warn('Could not load a monaco theme due to an error:', e, '\nFalling back to the default theme.');
- monacoTheme = require(path.join('./data/node_requires/monaco-themes', `${defaultMonacoTheme}.json`));
+ monacoTheme = require(join('./data/node_requires/monaco-themes', `${defaultMonacoTheme}.json`));
(window as Window).monaco.editor.defineTheme(name, monacoTheme);
}
const css = `./data/theme${name}.css`;
@@ -92,20 +107,19 @@ const mod = {
}
await fs.lstat(theme.css);
const link = (document.getElementById('themeCSS') as HTMLLinkElement);
- link.addEventListener('load', () => {
- updateSwatches();
- }, {
- once: true
- });
// Avoid flickering on startup theme reloading
if (link.href !== theme.css) {
+ const theWait = waitForStylesheet();
link.href = theme.css;
+ await theWait;
+ updateSwatches();
}
(window as Window).monaco.editor.setTheme(theme.name);
(window as Window).signals.trigger('UIThemeChanged', name);
localStorage.UItheme = name;
} catch (oO) {
(window as Window).alertify.error(`Could not load theme ${name}. Rolling back to the default ${defaultTheme}.`);
+ console.error(oO);
await mod.switchToTheme(defaultTheme);
}
},
@@ -126,6 +140,18 @@ const mod = {
...currentSwatches
};
},
+ getPixiSwatch(color: string): number {
+ if (!currentSwatches) {
+ updateSwatches();
+ }
+ return PIXI.utils.rgb2hex(currentSwatches[color].split(', ').map(i => parseInt(i.replace(/[^0-9]/g, ''), 10) / 255));
+ },
+ getSwatch(color: string): string {
+ if (!currentSwatches) {
+ updateSwatches();
+ }
+ return currentSwatches[color];
+ },
updateSwatches
};
diff --git a/src/node_requires/imageUtils.ts b/src/node_requires/utils/imageUtils.ts
similarity index 100%
rename from src/node_requires/imageUtils.ts
rename to src/node_requires/utils/imageUtils.ts
diff --git a/src/node_requires/utils/propUtils.ts b/src/node_requires/utils/propUtils.ts
new file mode 100644
index 000000000..108357dc0
--- /dev/null
+++ b/src/node_requires/utils/propUtils.ts
@@ -0,0 +1,30 @@
+const getProp = function (context: unknown, path: string): unknown {
+ var way = path.split(/(? 1) {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ context = (context as any)[way[0]];
+ way.shift();
+ }
+ return context;
+};
+
+const writeProp = function (context: unknown, path: string, value: unknown): void {
+ var way = path.split(/(? 2) {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ if (!(way[0] in (context as any))) {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ (context as any)[way[0]] = {};
+ }
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ context = (context as any)[way[0]];
+ way.shift();
+ }
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ (context as any)[way[0]] = value;
+};
+
+export {
+ getProp,
+ writeProp
+};
diff --git a/src/node_requires/utils/trigo.ts b/src/node_requires/utils/trigo.ts
new file mode 100644
index 000000000..9e460f5f4
--- /dev/null
+++ b/src/node_requires/utils/trigo.ts
@@ -0,0 +1,51 @@
+/** lengthdir_x */
+export var ldx = function ldx(l: number, d: number): number {
+ return l * Math.cos(d);
+};
+/** lengthdir_y */
+export var ldy = function ldy(l: number, d: number): number {
+ return l * Math.sin(d);
+};
+/** Point-point DirectioN */
+export var pdn = function pdn(x1: number, y1: number, x2: number, y2: number): number {
+ return Math.atan2(y2 - y1, x2 - x1);
+};
+/** Point-point DistanCe */
+export var pdc = function pdc(x1: number, y1: number, x2: number, y2: number): number {
+ return Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
+};
+export var degToRad = function degToRad(deg: number): number {
+ return deg * Math.PI / -180;
+};
+export var radToDeg = function radToDeg(rad: number): number {
+ return rad / Math.PI * -180;
+};
+/**
+ * Rotates a vector (x; y) by rad around (0; 0)
+ * @param {number} x The x component
+ * @param {number} y The y component
+ * @param {number} rad The radian value to rotate by
+ * @returns {Array} A pair of new `x` and `y` parameters.
+ */
+export var rotateRad = function rotateRad(x: number, y: number, rad: number): [number, number] {
+ const sin = Math.sin(rad),
+ cos = Math.cos(rad);
+ return [
+ cos * x - sin * y,
+ cos * y + sin * x
+ ];
+};
+export var deltaDirRad = function deltaDirRad(dir1: number, dir2: number): number {
+ dir1 = ((dir1 % (Math.PI * 2)) + Math.PI * 2) % (Math.PI * 2);
+ dir2 = ((dir2 % (Math.PI * 2)) + Math.PI * 2) % (Math.PI * 2);
+ var t = dir1,
+ h = dir2,
+ ta = h - t;
+ if (ta > Math.PI) {
+ ta -= Math.PI * 2;
+ }
+ if (ta < -Math.PI) {
+ ta += Math.PI * 2;
+ }
+ return ta;
+};
diff --git a/src/pug/index.pug b/src/pug/index.pug
index b3b3e1314..01b528b00 100644
--- a/src/pug/index.pug
+++ b/src/pug/index.pug
@@ -30,6 +30,15 @@ html
process.versions.ctjs = require('./package.json').version;
// Use the legacy version to support low-spec and dated devices running ct.IDE
script(src="node_modules/pixi.js-legacy/dist/pixi-legacy.min.js")
+ script.
+ // PIXI-mousewheel plugin from https://github.com/Mwni/pixi-mousewheel
+ /* example usage:
+ displayObject.interactiveMousewheel = true
+ displayObject.on('mousewheel', (delta, event) => {
+ myOtherDisplayObject.y += delta * 100
+ })
+ */
+ "use strict";!function(){var e=function(){function e(e){var t=this;this.app=e,this.eventHandler=function(e){return t.onMouseWheel(e)},this.app.view.addEventListener("mousewheel",this.eventHandler,{passive:!1}),this.app.view.addEventListener("DOMMouseScroll",this.eventHandler,{passive:!1})}var t=e.prototype;return t.onMouseWheel=function(e){var t=this.findScrollTarget({x:e.offsetX,y:e.offsetY});t&&(e.preventDefault(),t.emit("mousewheel",this.deriveNormalizedWheelDelta(e),e))},t.findScrollTarget=function(e){var t=this.app.renderer.plugins.interaction.hitTest(e);if(t&&t.interactiveMousewheel)return t},t.deriveNormalizedWheelDelta=function(e){return e.detail?e.wheelDelta?e.wheelDelta/e.detail/40*(e.detail>0?1:-1):-e.detail/3:e.wheelDelta/120},t.destroy=function(){this.app.view.removeEventListener("mousewheel",this.eventHandler),this.app.view.removeEventListener("DOMMouseScroll",this.eventHandler)},e}();Object.defineProperty(PIXI.DisplayObject.prototype,"interactiveMousewheel",{get:function(){return this._interactiveMousewheel},set:function(e){this._interactiveMousewheel=e,e&&!this.interactive&&(this.interactive=!0)}}),PIXI.Application.registerPlugin({init:function(t){this._mousewheelPlugin=new e(this)},destroy:function(){this._mousewheelPlugin.destroy()}})}();
script(src="data/ct.release/DragonBones.min.js")
script(src="node_modules/pixi-particles/dist/pixi-particles.min.js")
script.
diff --git a/src/riotTags/debugger/debugger-toolbar.tag b/src/riotTags/debugger/debugger-toolbar.tag
index 0d32664d4..00502ef38 100644
--- a/src/riotTags/debugger/debugger-toolbar.tag
+++ b/src/riotTags/debugger/debugger-toolbar.tag
@@ -159,9 +159,8 @@ debugger-toolbar
const buff = new Buffer(shotBase64, 'base64');
const stream = fs.createWriteStream(fullPath);
stream.on('finish', () => {
- if (localStorage.disableSounds !== 'on') {
- window.soundbox.play('Success');
- }
+ const {soundbox} = require('./data/node_requires/3rdparty/soundbox');
+ soundbox.play('Success');
// eslint-disable-next-line no-new
new Notification('Done!', {
body: `Saved to ${fullPath} 👌`,
@@ -211,4 +210,4 @@ debugger-toolbar
nw.Window.get().close();
};
- nw.Window.get().on('close', this.closeItself);
\ No newline at end of file
+ nw.Window.get().on('close', this.closeItself);
diff --git a/src/riotTags/main-menu/export-mobile-panel.tag b/src/riotTags/main-menu/export-mobile-panel.tag
index a9ddeb3ce..c18836bee 100644
--- a/src/riotTags/main-menu/export-mobile-panel.tag
+++ b/src/riotTags/main-menu/export-mobile-panel.tag
@@ -211,7 +211,7 @@ export-mobile-panel.aDimmer
const {getDOMImage} = require('./data/node_requires/resources/textures');
const iconsSplashesPromises = [];
const {imageCover, imageContain, imagePlaceInRect, imageRound, outputCanvasToFile} =
- require('./data/node_requires/imageUtils');
+ require('./data/node_requires/utils/imageUtils');
const projIconImage = await getDOMImage(projSettings.branding.icon || -1, 'ct_ide.png');
for (const name in androidIcons) {
const icon = imageContain(
diff --git a/src/riotTags/main-menu/main-menu-latest-projects.tag b/src/riotTags/main-menu/main-menu-latest-projects.tag
index cc1765bf5..a89d6f840 100644
--- a/src/riotTags/main-menu/main-menu-latest-projects.tag
+++ b/src/riotTags/main-menu/main-menu-latest-projects.tag
@@ -21,8 +21,9 @@ main-menu-latest-projects
this.loadLatestProject = projPath => {
alertify.confirm(window.languageJSON.common.reallyExitConfirm, e => {
if (e) {
+ const {openProject} = require('./data/node_requires/resources/projects');
window.signals.trigger('resetAll');
- window.loadProject(projPath);
+ openProject(projPath);
}
});
};
diff --git a/src/riotTags/main-menu/main-menu-project.tag b/src/riotTags/main-menu/main-menu-project.tag
index 5a8f86834..5ae1c39c7 100644
--- a/src/riotTags/main-menu/main-menu-project.tag
+++ b/src/riotTags/main-menu/main-menu-project.tag
@@ -86,7 +86,8 @@ main-menu-project
return;
}
window.signals.trigger('resetAll');
- window.loadProject(projFile);
+ const {openProject} = require('./data/node_requires/resources/projects');
+ openProject(projFile);
});
};
diff --git a/src/riotTags/notepad-panel.tag b/src/riotTags/notepad-panel.tag
index 56f4a5b92..bb783dfa0 100644
--- a/src/riotTags/notepad-panel.tag
+++ b/src/riotTags/notepad-panel.tag
@@ -59,7 +59,9 @@ notepad-panel#notepad.aPanel.dockright(class="{opened: opened}")
setTimeout(() => {
if (this.tab && this.refs[this.tab] && this.refs[this.tab].codeEditor) {
this.refs[this.tab].codeEditor.layout();
- this.refs[this.tab].codeEditor.focus();
+ if (this.opened) {
+ this.refs[this.tab].codeEditor.focus();
+ }
}
}, 0);
});
diff --git a/src/riotTags/project-selector.tag b/src/riotTags/project-selector.tag
index 603423827..ae3d5861a 100644
--- a/src/riotTags/project-selector.tag
+++ b/src/riotTags/project-selector.tag
@@ -133,6 +133,7 @@ project-selector
script.
const fs = require('fs-extra'),
path = require('path');
+ const {openProject} = require('./data/node_requires/resources/projects');
this.ctjsVersion = process.versions.ctjs;
this.requirePath = path;
this.namespace = 'intro';
@@ -243,7 +244,7 @@ project-selector
}
});
}, 0);
- window.loadProject(path.join(way, codename + '.ict'));
+ openProject(path.join(way, codename + '.ict'));
};
/**
@@ -251,7 +252,7 @@ project-selector
*/
this.loadProjectByPath = e => {
const projectPath = e.item.project;
- window.loadProject(projectPath);
+ openProject(projectPath);
};
/**
* Prompts user to clone a project into a different folder/under a different name.
@@ -273,7 +274,7 @@ project-selector
}
await fs.copy(project, newIctLocation);
await fs.copy(project.slice(0, -4), newIctLocation.slice(0, -4));
- window.loadProject(newIctLocation);
+ openProject(newIctLocation);
})();
};
/**
@@ -330,7 +331,7 @@ project-selector
return;
}
if (path.extname(proj).toLowerCase() === '.ict') {
- window.loadProject(proj);
+ openProject(proj);
sessionStorage.projname = path.basename(proj);
global.projdir = path.dirname(proj) + path.sep + path.basename(proj, '.ict');
} else {
diff --git a/src/riotTags/project-settings/tabs/rendering-settings.tag b/src/riotTags/project-settings/tabs/rendering-settings.tag
index f6fc61ec3..e03500a2f 100644
--- a/src/riotTags/project-settings/tabs/rendering-settings.tag
+++ b/src/riotTags/project-settings/tabs/rendering-settings.tag
@@ -7,7 +7,7 @@ rendering-settings
input.short(type="number" min="1" value="{renderSettings.maxFPS || 60}" onchange="{wire('this.renderSettings.maxFPS')}")
fieldset
label.block.checkbox
- input(type="checkbox" value="{renderSettings.pixelatedrender}" checked="{renderSettings.pixelatedrender}" onchange="{wire('this.renderSettings.pixelatedrender')}")
+ input(type="checkbox" value="{renderSettings.pixelatedrender}" checked="{renderSettings.pixelatedrender}" onchange="{wireAndUpdatePixelated('this.renderSettings.pixelatedrender')}")
span {voc.pixelatedRender}
label.block.checkbox
input(type="checkbox" value="{renderSettings.highDensity}" checked="{renderSettings.highDensity}" onchange="{wire('this.renderSettings.highDensity')}")
@@ -40,3 +40,9 @@ rendering-settings
this.mixin(window.riotWired);
this.currentProject = global.currentProject;
this.renderSettings = this.currentProject.settings.rendering;
+
+ this.wireAndUpdatePixelated = path => e => {
+ this.wire(path)(e);
+ const {setPixelart} = require('./data/node_requires/resources/textures');
+ setPixelart(currentProject.settings.rendering.pixelatedrender);
+ }
diff --git a/src/riotTags/rooms/copy-custom-properties-modal.tag b/src/riotTags/rooms/copy-custom-properties-modal.tag
deleted file mode 100644
index 39c3023ef..000000000
--- a/src/riotTags/rooms/copy-custom-properties-modal.tag
+++ /dev/null
@@ -1,93 +0,0 @@
-//
- Shows a table of a copy's extensions object that is modifiable
-
- @attribute closestcopy (object)
- The copy to show its extensions object
-
- @attribute showme (function)
- A function that changes whether this modal is shown
-
-copy-custom-properties-modal
- .aPanel.flexfix(ref="widget" style='overflow: auto; max-height: 600px')
- h2.flexfix-header {voc.customProperties}
- .flexfix-body
- table.wide.aPaddedTable
- tr
- th {voc.property}
- th {voc.value}
- th
- tr(each="{val, prop in opts.closestcopy.exts}")
- td
- input.wide(name="copyCustomProp" type="text" value="{prop}" onchange="{onTableChange}")
- td
- input.wide(name="copyCustomValue" type="text" value="{JSON.stringify(val)}" onchange="{onTableChange}")
- td
- button.toright.square.inline(onclick="{deleteCustomProperty.bind(null, prop)}" title="{voc.delete}")
- svg.feather
- use(xlink:href="#trash")
- .clear
- p
- .flexrow.flexfix-footer
- .filler
- button.nogrow(onclick="{addCustomProperty}")
- svg.feather
- use(xlink:href="#plus")
- span {voc.addProperty}
- button.nogrow(onclick="{finished}")
- svg.feather
- use(xlink:href="#check")
- span {vocGlob.apply}
- script.
- this.namespace = 'copyCustomProperties';
- this.mixin(window.riotVoc);
- if (!this.opts.closestcopy.exts) {
- this.opts.closestcopy.exts = {};
- }
- // an ID to use as newly created property names
- this.currentId = 1;
-
- this.onTableChange = () => {
- // read all properties from the table
- var propElements = document.getElementsByName('copyCustomProp');
- var props = [];
- for (const prop of propElements) {
- props.push(prop.value);
- }
-
- // read all values from the table
- var valueElements = document.getElementsByName('copyCustomValue');
- var values = [];
-
- for (const value of valueElements) {
- // attempt to parse the value
- // only strings will be unparsable with the JSON.parse method
- var trueValue;
- try {
- trueValue = JSON.parse(value.value); // JSON, number, boolean
- } catch {
- trueValue = value.value; // string
- }
- values.push(trueValue);
- }
-
- var newExts = {};
-
- props.forEach((prop, index) => {
- newExts[prop] = values[index];
- });
-
- this.opts.closestcopy.exts = newExts;
- };
-
- this.addCustomProperty = () => {
- this.opts.closestcopy.exts['newProperty' + this.currentId] = '';
- this.currentId++;
- };
-
- this.deleteCustomProperty = (prop) => {
- delete this.opts.closestcopy.exts[prop];
- };
-
- this.finished = () => {
- this.opts.showme(false);
- };
diff --git a/src/riotTags/rooms/room-backgrounds-editor.tag b/src/riotTags/rooms/room-backgrounds-editor.tag
index 366d30d38..614fbce31 100644
--- a/src/riotTags/rooms/room-backgrounds-editor.tag
+++ b/src/riotTags/rooms/room-backgrounds-editor.tag
@@ -1,74 +1,157 @@
-room-backgrounds-editor.room-editor-Backgrounds.tabbed.tall
- ul
- li.bg(each="{background, ind in opts.room.backgrounds}" oncontextmenu="{onContextMenu}")
- img(src="{getTexturePreview(background.texture)}" onclick="{onChangeBgTexture}")
- span
- span(class="{active: detailedBackground === background}" onclick="{editBackground}")
- svg.feather
- use(xlink:href="#settings")
- | {getTextureFromId(background.texture).name} ({background.depth})
- .clear
- .anErrorNotice(if="{background.texture && background.texture !== -1 && !getTextureFromId(background.texture).tiled && !getTextureFromId(background.texture).ignoreTiledUse}")
- | {voc.notBackgroundTextureWarning}
+//
+ @attribute backgrounds (Background[])
+ @attribute addbackground (riot function)
+ @attribute room (IRoom)
+ @attribute history (History)
+
+room-backgrounds-editor
+ collapsible-section(
+ each="{background, ind in opts.backgrounds}"
+ icon="settings"
+ ).aPanel
+ yield(to="header")
+ asset-input(
+ assettype="textures"
+ assetid="{background.bgTexture}"
+ compact="true"
+ onchanged="{parent.changeBgTexture(background)}"
+ ref="assetInput"
+ )
+ error-notice(
+ if="{background.bgTexture && background.bgTexture !== -1 && !parent.getTextureFromId(background.bgTexture).tiled && !parent.getTextureFromId(background.bgTexture).ignoreTiledUse}"
+ target="{refs.assetInput}"
+ )
+ | {parent.parent.voc.notBackgroundTextureWarning}
|
- span.a(onclick="{fixTexture(background)}") {voc.fixBackground}
+ span.a(onclick="{parent.parent.fixTexture}") {parent.parent.voc.fixBackground}
|
|
- span.a(onclick="{dismissWarning(background)}") {voc.dismissWarning}
- div(if="{detailedBackground === background}")
- .clear
- label
- b {voc.depth}
- input.wide(type="number" value="{background.depth || 0}" step="0" oninput="{onChangeBgDepth}")
-
- b {voc.shift}
- .clear
- label.fifty.npl.npt
- input.wide(type="number" value="{background.extends.shiftX || 0}" step="8" oninput="{wire('this.detailedBackground.extends.shiftX')}")
- label.fifty.npr.npt
- input.wide(type="number" value="{background.extends.shiftY || 0}" step="8" oninput="{wire('this.detailedBackground.extends.shiftY')}")
-
- b {voc.scale}
- .clear
- label.fifty.npl.npt
- input.wide(type="number" value="{background.extends.scaleX || 1}" step="0.01" oninput="{wire('this.detailedBackground.extends.scaleX')}")
- label.fifty.npr.npt
- input.wide(type="number" value="{background.extends.scaleY || 1}" step="0.01" oninput="{wire('this.detailedBackground.extends.scaleY')}")
-
- b {voc.movement}
- .clear
- label.fifty.npl.npt
- input.wide(type="number" value="{background.extends.movementX || 0}" step="0.1" oninput="{wire('this.detailedBackground.extends.movementX')}")
- label.fifty.npr.npt
- input.wide(type="number" value="{background.extends.movementY || 0}" step="0.1" oninput="{wire('this.detailedBackground.extends.movementY')}")
-
- b {voc.parallax}
- .clear
- label.fifty.npl.npt
- input.wide(type="number" value="{background.extends.parallaxX !== void 0 ? background.extends.parallaxX : 1}" step="0.01" oninput="{wire('this.detailedBackground.extends.parallaxX')}")
- label.fifty.npr.npt
- input.wide(type="number" value="{background.extends.parallaxY !== void 0 ? background.extends.parallaxY : 1}" step="0.01" oninput="{wire('this.detailedBackground.extends.parallaxY')}")
- .clear
-
- b {voc.repeat}
- select(onchange="{wire('this.detailedBackground.extends.repeat')}")
- option(value="repeat" selected="{detailedBackground.extends.repeat === 'repeat'}") repeat
- option(value="repeat-x" selected="{detailedBackground.extends.repeat === 'repeat-x'}") repeat-x
- option(value="repeat-y" selected="{detailedBackground.extends.repeat === 'repeat-y'}") repeat-y
- option(value="no-repeat" selected="{detailedBackground.extends.repeat === 'no-repeat'}") no-repeat
-
+ span.a(onclick="{parent.parent.dismissWarning}") {parent.parent.voc.dismissWarning}
+ fieldset
+ label
+ b {parent.voc.depth}
+ input.wide(
+ type="number" step="1"
+ onfocus="{parent.rememberValue}"
+ value="{background.zIndex}"
+ oninput="{parent.tweak(background, 'zIndex')}"
+ onchange="{parent.recordChange(background, 'zIndex')}"
+ )
+ fieldset
+ b {parent.voc.shift}
+ .aPoint2DInput.compact.wide
+ label.flexrow
+ span.nogrow X:
+ input.nmr(
+ type="number" step="8" placeholder="0"
+ onfocus="{parent.rememberValue}"
+ oninput="{parent.tweak(background, 'shiftX')}"
+ onchange="{parent.recordChange(background, 'shiftX')}"
+ value="{background.shiftX}"
+ )
+ .aSpacer.noshrink.nogrow
+ label.flexrow
+ span.nogrow Y:
+ input.nmr(
+ type="number" step="8" placeholder="0"
+ onfocus="{parent.rememberValue}"
+ oninput="{parent.tweak(background, 'shiftY')}"
+ onchange="{parent.recordChange(background, 'shiftY')}"
+ value="{background.shiftY}"
+ )
+ b {parent.voc.scale}
+ .aPoint2DInput.compact.wide
+ label.flexrow
+ span.nogrow X:
+ input.nmr(
+ type="number" step="0.1" placeholder="1"
+ onfocus="{parent.rememberValue}"
+ oninput="{parent.tweak(background.tileScale, 'x')}"
+ onchange="{parent.recordChange(background.tileScale, 'x')}"
+ value="{background.tileScale.x}"
+ )
+ .aSpacer.noshrink.nogrow
+ label.flexrow
+ span.nogrow Y:
+ input.nmr(
+ type="number" step="0.1" placeholder="1"
+ onfocus="{parent.rememberValue}"
+ oninput="{parent.tweak(background.tileScale, 'y')}"
+ onchange="{parent.recordChange(background.tileScale, 'y')}"
+ value="{background.tileScale.y}"
+ )
+ fieldset
+ b {parent.voc.movement}
+ .aPoint2DInput.compact.wide
+ label.flexrow
+ span.nogrow X:
+ input.nmr(
+ type="number" step="1" placeholder="0"
+ onfocus="{parent.rememberValue}"
+ oninput="{parent.tweak(background, 'movementX')}"
+ onchange="{parent.recordChange(background, 'movementX')}"
+ value="{background.movementX}"
+ )
+ .aSpacer.noshrink.nogrow
+ label.flexrow
+ span.nogrow Y:
+ input.nmr(
+ type="number" step="1" placeholder="0"
+ onfocus="{parent.rememberValue}"
+ oninput="{parent.tweak(background, 'movementY')}"
+ onchange="{parent.recordChange(background, 'movementY')}"
+ value="{background.movementY}"
+ )
+ b {parent.voc.parallax}
+ .aPoint2DInput.compact.wide
+ label.flexrow
+ span.nogrow X:
+ input.nmr(
+ type="number" step="0.1" placeholder="1"
+ onfocus="{parent.rememberValue}"
+ oninput="{parent.tweak(background, 'parallaxX')}"
+ onchange="{parent.recordChange(background, 'parallaxX')}"
+ value="{background.parallaxX}"
+ )
+ .aSpacer.noshrink.nogrow
+ label.flexrow
+ span.nogrow Y:
+ input.nmr(
+ type="number" step="0.1" placeholder="1"
+ onfocus="{parent.rememberValue}"
+ oninput="{parent.tweak(background, 'parallaxY')}"
+ onchange="{parent.recordChange(background, 'parallaxY')}"
+ value="{background.parallaxY}"
+ )
+ fieldset
+ b {parent.voc.repeat}
+ |
+ select(
+ onfocus="{parent.rememberValue}"
+ onchange="{parent.recordAndTweak(background, 'repeat')}"
+ )
+ option(value="repeat" selected="{background.repeat === 'repeat'}") repeat
+ option(value="repeat-x" selected="{background.repeat === 'repeat-x'}") repeat-x
+ option(value="repeat-y" selected="{background.repeat === 'repeat-y'}") repeat-y
+ option(value="no-repeat" selected="{background.repeat === 'no-repeat'}") no-repeat
+ .aSpacer
+ button.wide(onclick="{parent.removeBg}")
+ svg.feather
+ use(xlink:href="#trash")
+ span {parent.vocGlob.delete}
+ .aSpacer(if="{opts.backgrounds.length}")
button.inline.wide(onclick="{addBg}")
svg.feather
use(xlink:href="#plus")
span {voc.add}
+ // Used for selecting a texture for newly created backgrounds
asset-selector(
ref="texturePicker"
- if="{pickingBackground}"
+ if="{newBg}"
assettype="textures"
oncancelled="{onTextureCancel}"
onselected="{onTextureSelected}"
)
- context-menu(menu="{roomBgMenu}" ref="roomBgMenu")
script.
const glob = require('./data/node_requires/glob');
this.glob = glob;
@@ -80,85 +163,119 @@ room-backgrounds-editor.room-editor-Backgrounds.tabbed.tall
this.pickingBackground = false;
this.namespace = 'roomBackgrounds';
this.mixin(window.riotVoc);
- this.mixin(window.riotWired);
- this.on('update', () => {
- if (this.parent.tab === 'roombackgrounds') {
- this.parent.refreshRoomCanvas();
+
+ this.tweak = (obj, field) => e => {
+ const input = e.target;
+ if (input.type === 'radio' || input.type === 'checkbox') {
+ obj[field] = input.checked;
+ } else if (input.type === 'number') {
+ obj[field] = Number(input.value);
+ } else {
+ obj[field] = input.value;
}
- });
+ };
+
+ // These two are only for newly created backgrounds, for which an asset selection modal
+ // is automatically created
this.onTextureSelected = textureId => {
- this.editingBackground.texture = textureId;
- this.pickingBackground = false;
- this.creatingBackground = false;
+ this.newBg.changeTexture(textureId);
+ this.opts.history.pushChange({
+ type: 'backgroundCreation',
+ created: this.newBg
+ });
+ this.newBg = void 0;
this.update();
};
this.onTextureCancel = () => {
this.pickingBackground = false;
- if (this.creatingBackground) {
- const bgs = this.opts.room.backgrounds;
- bgs.splice(bgs.indexOf(this.editingBackground), 1);
- this.parent.resortRoom();
- this.creatingBackground = false;
+ if (this.newBg) {
+ this.newBg.destroy();
}
+ this.newBg = false;
this.update();
};
+
this.addBg = () => {
- var newBg = {
+ const bgTemplate = {
depth: 0,
texture: -1,
- extends: {}
+ parallaxX: 1,
+ parallaxY: 1,
+ shiftX: 0,
+ shiftY: 0,
+ scaleX: 1,
+ scaleY: 1,
+ movementX: 0,
+ movementY: 0,
+ repeat: 'repeat'
};
- this.opts.room.backgrounds.push(newBg);
- this.editingBackground = newBg;
+ const bg = this.opts.addbackground(bgTemplate);
+ this.newBg = bg;
this.pickingBackground = true;
- this.creatingBackground = true;
- this.opts.room.backgrounds.sort((a, b) => a.depth - b.depth);
- this.parent.resortRoom();
- this.update();
};
- this.onContextMenu = e => {
- this.editedBg = Number(e.item.ind);
- this.refs.roomBgMenu.popup(e.clientX, e.clientY);
- e.preventDefault();
+
+ this.changeBgTexture = background => textureId => {
+ const prevId = background.bgTexture;
+ background.changeTexture(textureId);
+ this.opts.history.pushChange({
+ type: 'propChange',
+ key: 'bgTexture',
+ target: background,
+ before: prevId,
+ after: textureId
+ });
+ this.update();
};
- this.roomBgMenu = {
- opened: false,
- items: [{
- label: window.languageJSON.common.delete,
- click: () => {
- this.opts.room.backgrounds.splice(this.editedBg, 1);
- this.parent.resortRoom();
- this.update();
- }
- }]
+
+ this.removeBg = e => {
+ const {background} = e.item;
+ background.detach();
+ this.opts.history.pushChange({
+ type: 'backgroundDeletion',
+ deleted: background
+ });
};
- this.onChangeBgTexture = e => {
- this.pickingBackground = true;
- this.editingBackground = e.item.background;
+
+ this.fixTexture = e => {
+ const {background} = e.item;
+ const tex = getTextureFromId(background.bgTexture);
+ tex.tiled = true;
+ e.stopPropagation();
this.update();
};
- this.onChangeBgDepth = e => {
- e.item.background.depth = Number(e.target.value);
- this.opts.room.backgrounds.sort((a, b) => a.depth - b.depth);
- this.parent.resortRoom();
+ this.dismissWarning = e => {
+ const {background} = e.item;
+ const tex = getTextureFromId(background.bgTexture);
+ tex.ignoreTiledUse = true;
+ e.stopPropagation();
+ this.update();
};
- this.editBackground = e => {
- if (this.detailedBackground === e.item.background) {
- this.detailedBackground = void 0;
+ var prevValue;
+ this.rememberValue = e => {
+ if (e.target.type === 'number') {
+ prevValue = Number(e.target.value);
} else {
- this.detailedBackground = e.item.background;
- if (!('extends' in this.detailedBackground)) {
- this.detailedBackground.extends = {};
- }
+ prevValue = e.target.value;
}
};
-
- this.fixTexture = background => () => {
- const tex = getTextureFromId(background.texture);
- tex.tiled = true;
+ this.recordChange = (entity, key) => e => {
+ if (!this.opts.history) {
+ return;
+ }
+ let value = e.target.value;
+ if (e.target.type === 'number') {
+ value = Number(value);
+ }
+ this.opts.history.pushChange({
+ type: 'propChange',
+ key,
+ target: entity,
+ before: prevValue,
+ after: value
+ });
};
- this.dismissWarning = background => () => {
- const tex = getTextureFromId(background.texture);
- tex.ignoreTiledUse = true;
+ this.recordAndTweak = (entity, key) => e => {
+ this.tweak(entity, key)(e);
+ this.recordChange(entity, key)(e);
};
diff --git a/src/riotTags/rooms/room-copy-properties.tag b/src/riotTags/rooms/room-copy-properties.tag
deleted file mode 100644
index cdf4520b6..000000000
--- a/src/riotTags/rooms/room-copy-properties.tag
+++ /dev/null
@@ -1,65 +0,0 @@
-room-copy-properties.aPanel
- b {voc.position}:
- .aPoint2DInput.compact.wide
- label
- span X:
- |
- input.compact(
- step="8" type="number"
- oninput="{wire('this.opts.copy.x')}"
- value="{opts.copy.x}"
- )
- .aSpacer
- label
- span.nogrow Y:
- |
- input.compact(
- step="8" type="number"
- oninput="{wire('this.opts.copy.y')}"
- value="{opts.copy.y}"
- )
- b {voc.scale}:
- .aPoint2DInput.compact.wide
- label
- span X:
- |
- input.compact(
- step="0.1" type="number"
- oninput="{wire('this.opts.copy.tx')}"
- value="{opts.copy.tx === void 0 ? 1 : opts.copy.tx}"
- )
- .aSpacer
- label
- span.nogrow Y:
- |
- input.compact(
- step="0.1" type="number"
- oninput="{wire('this.opts.copy.ty')}"
- value="{opts.copy.ty === void 0 ? 1 : opts.copy.ty}"
- )
- b {voc.rotation}:
- dd
- .flexrow
- .aSliderWrap
- input.compact(
- type="range" min="0" max="360" step="1"
- value="{opts.copy.tr || 0}"
- oninput="{wire('this.opts.copy.tr')}"
- )
- .aSpacer
- input.compact(
- min="0" max="360" step="1" type="number"
- value="{opts.copy.tr || 0}"
- oninput="{wire('this.opts.copy.tr')}"
- )
- extensions-editor(entity="{opts.copy.exts}" type="copy" compact="yes" wide="yup")
- script.
- this.namespace = 'roomView.copyProperties';
- this.mixin(window.riotVoc);
- this.mixin(window.riotWired);
-
- this.on('update', () => {
- if (this.opts.copy && !this.opts.copy.exts) {
- this.opts.copy.exts = {};
- }
- });
diff --git a/src/riotTags/rooms/room-editor.tag b/src/riotTags/rooms/room-editor.tag
index a08798161..cd78cb6eb 100644
--- a/src/riotTags/rooms/room-editor.tag
+++ b/src/riotTags/rooms/room-editor.tag
@@ -1,805 +1,472 @@
-room-editor.aPanel.aView
- .toolbar.tall(style="width: {sidebarWidth}px")
- copy-custom-properties-modal(if="{showCopyPropertiesModal}" closestcopy="{closestCopy}" showme="{toggleCopyProperties}")
- .settings.nogrow.noshrink
- b {voc.name}
- br
- input.wide(type="text" value="{room.name}" onchange="{wire('this.room.name')}")
- .anErrorNotice(if="{nameTaken}" ref="errorNotice") {vocGlob.nameTaken}
- button.wide(onclick="{openRoomEvents}")
- svg.feather(if="{room.events && room.events.length}")
- use(xlink:href="#check")
- span {voc.events}
- .palette
- .tabwrap.flexfix
- ul.tabs.aNav.noshrink.nogrow.flexfix-header
- li(onclick="{changeTab('roomcopies')}" title="{voc.copies}" class="{active: tab === 'roomcopies'}")
- svg.feather
- use(xlink:href="#template")
- span(if="{sidebarWidth > 500}") {voc.copies}
- li(onclick="{changeTab('roombackgrounds')}" title="{voc.backgrounds}" class="{active: tab === 'roombackgrounds'}")
- svg.feather
- use(xlink:href="#image")
- span(if="{sidebarWidth > 500}") {voc.backgrounds}
- li(onclick="{changeTab('roomtiles')}" title="{voc.tiles}" class="{active: tab === 'roomtiles'}")
- svg.feather
- use(xlink:href="#texture")
- span(if="{sidebarWidth > 500}") {voc.tiles}
- li(onclick="{changeTab('properties')}" title="{voc.properties}" class="{active: tab === 'properties'}")
- svg.feather
- use(xlink:href="#settings")
- span(if="{sidebarWidth > 500}") {voc.properties}
- .relative.flexfix-body
- room-template-picker(show="{tab === 'roomcopies'}" current="{currentTemplate}")
- room-backgrounds-editor(show="{tab === 'roombackgrounds'}" room="{room}")
- room-tile-editor(show="{tab === 'roomtiles'}" room="{room}")
- .pad.aPanel(show="{tab === 'properties'}")
- fieldset
- .fifty.npt.npb.npl
- b {voc.width}
- br
- input.wide(type="number" value="{room.width}" onchange="{wireAndRedraw('this.room.width')}")
- .fifty.npt.npb.npr
- b {voc.height}
- br
- input.wide(type="number" value="{room.height}" onchange="{wireAndRedraw('this.room.height')}")
- .clear
- fieldset
- label.checkbox
- input(type="checkbox" checked="{room.restrictCamera}" onchange="{wireAndRedraw('this.room.restrictCamera')}")
- span {voc.restrictCamera}
- .aPoint2DInput.compact.wide(if="{room.restrictCamera}")
- label
- span {voc.minimumX}:
- |
- input.compact(
- step="{room.gridX}" type="number"
- oninput="{wireAndRedraw('this.room.restrictMinX')}"
- value="{room.restrictMinX === void 0 ? 0 : room.restrictMinX}"
- )
- .aSpacer
- label
- span.nogrow {voc.minimumY}:
- |
- input.compact(
- step="{room.gridY}" type="number"
- oninput="{wireAndRedraw('this.room.restrictMinY')}"
- value="{room.restrictMinY === void 0 ? 0 : room.restrictMinY}"
- )
- .aPoint2DInput.compact.wide(if="{room.restrictCamera}")
- label
- span {voc.maximumX}:
- |
- input.compact(
- step="{room.gridX}" type="number"
- oninput="{wireAndRedraw('this.room.restrictMaxX')}"
- value="{room.restrictMaxX === void 0 ? room.width : room.restrictMaxX}"
- )
- .aSpacer
- label
- span.nogrow {voc.maximumY}:
- |
- input.compact(
- step="{room.gridY}" type="number"
- oninput="{wireAndRedraw('this.room.restrictMaxY')}"
- value="{room.restrictMaxY === void 0 ? room.height : room.restrictMaxY}"
- )
-
- fieldset
- b {voc.backgroundColor}
- br
- color-input.wide(onchange="{updateRoomBackground}" color="{room.backgroundColor || '#000000'}")
-
- fieldset
- extensions-editor(entity="{room.extends}" type="room" wide="aye" compact="sure")
+//
+ @attribute room
+ The room to edit
+ @attribute onclose (riot function)
- fieldset
- label.block.checkbox
- input(type="checkbox" checked="{room.extends.isUi}" onchange="{wire('this.room.extends.isUi')}")
- b {voc.isUi}
-
- .done.nogrow
- button.wide#roomviewdone(onclick="{roomSave}")
+room-editor.aPanel.aView
+ canvas(ref="canvas" onwheel="{triggerWheelEvent}")
+ // Toolbar
+ .room-editor-aToolsetHolder
+ .room-editor-aToolbar.aButtonGroup.vertical
+ button.forcebackground(
+ onclick="{setTool('select')}"
+ class="{active: currentTool === 'select'}"
+ title="{voc.tools.select} (Q)"
+ data-hotkey="q"
+ data-hotkey-require-scope="rooms"
+ )
svg.feather
- use(xlink:href="#check")
- span {voc.done}
- .aResizer.vertical(ref="gutter" onmousedown="{gutterMouseDown}")
- .editor(ref="canvaswrap")
- canvas(
- ref="canvas"
- onclick="{onCanvasClick}"
- onmousedown="{onCanvasPress}"
- onmousemove="{onCanvasMove}"
- onmouseup="{onCanvasMouseUp}"
- onmouseout="{refreshRoomCanvas}"
- onmousewheel="{onCanvasWheel}"
- oncontextmenu="{onCanvasContextMenu}"
- )
- .shift.flexrow
- button.inline.square.forcebackground(title="{voc.shift}" onclick="{roomShift}")
+ use(xlink:href="#cursor")
+ button.forcebackground(
+ onclick="{setTool('addCopies')}"
+ class="{active: currentTool === 'addCopies'}"
+ title="{voc.tools.addCopies} (W)"
+ data-hotkey="w"
+ data-hotkey-require-scope="rooms"
+ )
svg.feather
- use(xlink:href="#move")
- .aButtonGroup
- button.inline.square.forcebackground(
- title="{voc.sortHorizontally}"
- onclick="{sortHorizontally}"
- if="{tab === 'roomcopies' || tab === 'roomtiles'}"
- )
- svg.feather
- use(xlink:href="#sort-horizontal")
- button.inline.square.forcebackground(
- title="{voc.sortVertically}"
- onclick="{sortVertically}"
- if="{tab === 'roomcopies' || tab === 'roomtiles'}"
+ use(xlink:href="#template")
+ button.forcebackground(
+ onclick="{setTool('addTiles')}"
+ class="{active: currentTool === 'addTiles'}"
+ title="{voc.tools.addTiles} (E)"
+ data-hotkey="e"
+ data-hotkey-require-scope="rooms"
+ )
+ svg.feather
+ use(xlink:href="#grid")
+ button.forcebackground(
+ onclick="{setTool('manageBackgrounds')}"
+ class="{active: currentTool === 'manageBackgrounds'}"
+ title="{voc.tools.manageBackgrounds} (R)"
+ data-hotkey="r"
+ data-hotkey-require-scope="rooms"
+ )
+ svg.feather
+ use(xlink:href="#image")
+ button.forcebackground(
+ onclick="{setTool('roomProperties')}"
+ class="{active: currentTool === 'roomProperties'}"
+ title="{voc.tools.roomProperties} (T)"
+ data-hotkey="t"
+ data-hotkey-require-scope="rooms"
+ )
+ svg.feather
+ use(xlink:href="#settings")
+
+ // Contextual panels for tools
+ .room-editor-aContextPanel(
+ if="{currentTool === 'select' && pixiEditor}"
+ )
+ h3.nogrow.nm.inlineblock {vocGlob.select}:
+ .aSpacer.inlineblock
+ .aButtonGroup.nm
+ button.inline.square(
+ each="{lockable in lockableTypes}"
+ class="{active: parent.pixiEditor && parent.pixiEditor[lockable.key]}"
+ onclick="{toggleSelectables}"
+ title="{voc[lockable.hintVocKey]}"
)
svg.feather
- use(xlink:href="#sort-vertical")
- span.aContrastingPlaque(if="{window.innerWidth - sidebarWidth > 940}") {voc.hotkeysNotice}
- .zoom.flexrow
- b.aContrastingPlaque
- span(if="{window.innerWidth - sidebarWidth > 980}") {vocGlob.zoom}:
- |
- |
- span {Math.round(zoomFactor * 100)}%
- .aSpacer
- zoom-slider(onchanged="{setZoom}" ref="zoomslider" value="{zoomFactor}")
- .grid
- button#roomgrid.forcebackground(onclick="{roomToggleGrid}" class="{active: room.gridX > 0}")
- span {voc[room.gridX > 0? 'gridOff' : 'grid']}
- .center
- button#roomcenter.forcebackground(onclick="{roomToCenter}") {voc.toCenter}
- b.aMouseCoord.aContrastingPlaque(show="{window.innerWidth - sidebarWidth > 470}" ref="mousecoords") ({mouseX}:{mouseY})
- room-copy-properties(
- if="{this.selectedCopies && this.selectedCopies.length === 1}"
- copy="{this.selectedCopies[0]}"
- onchange="{refreshRoomCanvas}" oninput="{refreshRoomCanvas}"
+ use(xlink:href="#{lockable.icon}")
+ room-entities-properties(ref="propertiesPanel" pixieditor="{pixiEditor}" ontransformchange="{updateSelectFrame}")
+ room-properties.room-editor-aContextPanel(
+ if="{currentTool === 'roomProperties'}"
+ room="{opts.room}"
+ history="{pixiEditor?.history}"
+ updatebg="{changeBgColor}"
+ ref="propertiesPanel"
+ )
+ room-template-picker.room-editor-aContextPanel(
+ if="{currentTool === 'addCopies'}"
+ onselect="{changeSelectedTemplate}"
+ selected="{currentTemplate}"
+ )
+ room-tile-editor.room-editor-aContextPanel(
+ if="{currentTool === 'addTiles'}"
+ layer="{currentTileLayer}"
+ layers="{pixiEditor.tileLayers}"
+ onchangetile="{changeTilePatch}"
+ onchangelayer="{changeTileLayer}"
+ pixieditor="{pixiEditor}"
+ removelayer="{pixiEditor?.removeLayer?.bind(pixiEditor)}"
+ addlayer="{pixiEditor?.addTileLayer?.bind(pixiEditor)}"
+ ref="tileEditor"
)
- room-events-editor(if="{editingCode}" room="{room}")
- context-menu(menu="{roomCanvasCopiesMenu}" ref="roomCanvasCopiesMenu")
- context-menu(menu="{roomCanvasMenu}" ref="roomCanvasMenu")
- context-menu(menu="{roomCanvasTileMenu}" ref="roomCanvasTileMenu")
- context-menu(menu="{roomCanvasTilesMenu}" ref="roomCanvasTilesMenu")
+ room-backgrounds-editor.room-editor-aContextPanel(
+ if="{currentTool === 'manageBackgrounds'}"
+ backgrounds="{pixiEditor?.backgrounds}"
+ addbackground="{pixiEditor?.addBackground?.bind(pixiEditor)}"
+ room="{opts.room}"
+ history="{pixiEditor?.history}"
+ ref="backgroundsEditor"
+ )
+
+ // Global controls placed at the top-center
+ .room-editor-aTopPanel
+ button.slim(onclick="{pixiEditor?.history.undo.bind(pixiEditor.history)}" title="{vocGlob.undo}" class="{dim: !pixiEditor?.history.canUndo}")
+ svg.feather
+ use(xlink:href="#undo")
+ button.slim(onclick="{pixiEditor?.history.redo.bind(pixiEditor.history)}" title="{vocGlob.redo}" class="{dim: !pixiEditor?.history.canRedo}")
+ svg.feather
+ use(xlink:href="#redo")
+ label.checkbox(title="Shift+S")
+ input(
+ type="checkbox"
+ onchange="{changeSimulated}"
+ checked="{pixiEditor?.simulate}"
+ data-hotkey="S"
+ data-hotkey-require-scope="rooms"
+ )
+ span {voc.simulate}
+ button(onclick="{openZoomMenu}")
+ span(ref="zoomLabel") {Math.round(pixiEditor?.getZoom() || 100)}%
+ button(onclick="{openGridMenu}")
+ span {voc.grid}
+ button.slim(onclick="{openVisibilityMenu}")
+ svg.feather
+ use(xlink:href="#eye")
+ button(onclick="{openEventsList}")
+ span {voc.events}
+ button(onclick="{saveRoom}")
+ svg.feather
+ use(xlink:href="#check")
+ span {vocGlob.save}
+
+ room-events-editor(if="{editingEvents}" room="{opts.room}" onsave="{closeRoomEvents}")
+ context-menu(menu="{gridMenu}" ref="gridMenu")
+ context-menu(menu="{zoomMenu}" ref="zoomMenu")
+ context-menu(menu="{visibilityMenu}" ref="visibilityMenu" if="{pixiEditor}")
script.
- const minSizeW = 250;
- const getMaxSizeW = () => window.innerWidth - 300;
- this.sidebarWidth = Math.max(
- minSizeW,
- Math.min(getMaxSizeW(), localStorage.roomSidebarWidth || 300)
- );
+ this.namespace = 'roomView';
+ this.mixin(window.riotVoc);
- this.gutterMouseDown = () => {
- this.draggingGutter = true;
- };
- const gutterMove = e => {
- if (!this.draggingGutter) {
+ this.freePlacementMode = false;
+ const modifiersDownListener = e => {
+ if (e.repeat ||
+ !window.hotkeys.inScope('rooms') ||
+ window.hotkeys.isFormField(e.target)
+ ) {
return;
}
- this.sidebarWidth = Math.max(minSizeW, Math.min(getMaxSizeW(), e.clientX));
- localStorage.roomSidebarWidth = this.sidebarWidth;
- this.update();
- var {canvas} = this.refs,
- sizes = this.refs.canvaswrap.getBoundingClientRect();
- if (canvas.width !== sizes.width || canvas.height !== sizes.height) {
- canvas.width = sizes.width;
- canvas.height = sizes.height;
+ if (e.key === 'Alt') {
+ this.freePlacementMode = true;
+ e.preventDefault();
+ } else if (e.key === 'Control') {
+ this.controlMode = true;
+ e.preventDefault();
}
- this.refreshRoomCanvas();
};
- const gutterUp = () => {
- if (this.draggingGutter) {
- this.draggingGutter = false;
- // updateCanvasSize();
- // document.body.removeChild(catcher);
+ const modifiersUpListener = e => {
+ if (e.repeat ||
+ !window.hotkeys.inScope('rooms') ||
+ window.hotkeys.isFormField(e.target)
+ ) {
+ return;
+ }
+ if (e.key === 'Alt') {
+ this.freePlacementMode = false;
+ e.preventDefault();
+ } else if (e.key === 'Control') {
+ this.controlMode = false;
+ e.preventDefault();
}
};
- document.addEventListener('mousemove', gutterMove);
- document.addEventListener('mouseup', gutterUp);
- this.on('unmount', () => {
- document.removeEventListener('mousemove', gutterMove);
- document.removeEventListener('mouseup', gutterUp);
- });
-
- this.editingCode = false;
- this.forbidDrawing = false;
- const fs = require('fs-extra');
- const glob = require('./data/node_requires/glob');
- this.namespace = 'roomView';
- this.mixin(window.riotVoc);
- this.mixin(window.riotWired);
- this.mixin(window.roomCopyTools);
- this.mixin(window.roomTileTools);
- this.wireAndRedraw = way => e => {
- this.wire(way)(e);
- this.refreshRoomCanvas();
- };
-
- this.room = this.opts.room;
- if (!this.room.extends) {
- this.room.extends = {};
- }
-
- this.mouseX = this.mouseY = 0;
- this.roomx = this.room.width / 2;
- this.roomy = this.room.height / 2;
- this.zoomFactor = 1;
- this.room.gridX = this.room.gridX || this.room.grid || 64;
- this.room.gridY = this.room.gridY || this.room.grid || 64;
- this.dragging = false;
- this.tab = 'roomcopies';
-
- this.toggleCopyProperties = value => {
- this.showCopyPropertiesModal = value;
- this.update();
- this.refreshRoomCanvas();
- };
-
- this.updateRoomBackground = (e, color) => {
- this.room.backgroundColor = color;
- this.refreshRoomCanvas();
+ const blurListener = () => {
+ // Specifically designed to catch Alt+Tab
+ this.freePlacementMode = false;
};
-
- var updateCanvasSize = () => {
- // Firstly, check that we don't need to reflow the layout due to window shrinking
- const oldSidebarWidth = this.sidebarWidth;
- this.sidebarWidth = Math.max(minSizeW, Math.min(getMaxSizeW(), this.sidebarWidth));
- if (oldSidebarWidth !== this.sidebarWidth) {
- this.update();
- }
- var {canvas} = this.refs,
- sizes = this.refs.canvaswrap.getBoundingClientRect();
- if (canvas.width !== sizes.width || canvas.height !== sizes.height) {
- canvas.width = sizes.width;
- canvas.height = sizes.height;
+ const tabListener = e => {
+ if (!window.hotkeys.inScope('rooms') || window.hotkeys.isFormField(e.target)) {
+ return;
}
- setTimeout(this.refreshRoomCanvas, 10);
+ this.gridOn = !this.gridOn;
};
- this.on('update', () => {
- if (global.currentProject.rooms.find(room =>
- this.room.name === room.name && this.room !== room)) {
- this.nameTaken = true;
- } else {
- this.nameTaken = false;
- }
- });
this.on('mount', () => {
- this.room = this.opts.room;
- this.refs.canvas.x = this.refs.canvas.getContext('2d');
- this.gridCanvas = document.createElement('canvas');
- this.gridCanvas.x = this.gridCanvas.getContext('2d');
- this.redrawGrid();
- window.addEventListener('resize', updateCanvasSize);
- updateCanvasSize();
+ window.hotkeys.push('roomEditor');
+ window.hotkeys.on('Control+g', tabListener);
+ document.addEventListener('keydown', modifiersDownListener);
+ document.addEventListener('keyup', modifiersUpListener);
+ window.addEventListener('blur', blurListener);
});
this.on('unmount', () => {
- window.removeEventListener('resize', updateCanvasSize);
+ window.hotkeys.exit('roomEditor');
+ window.hotkeys.off('Control+g', tabListener);
+ document.removeEventListener('keydown', modifiersDownListener);
+ document.removeEventListener('keyup', modifiersUpListener);
+ window.addEventListener('blur', blurListener);
});
- this.openRoomEvents = () => {
- this.editingCode = true;
+ this.lockableTypes = [{
+ icon: 'template',
+ hintVocKey: 'copies',
+ key: 'selectCopies'
+ }, {
+ icon: 'grid',
+ hintVocKey: 'tiles',
+ key: 'selectTiles'
+ }];
+ this.toggleSelectables = e => {
+ this.pixiEditor[e.item.lockable.key] = !this.pixiEditor[e.item.lockable.key];
};
-
- // Навигация по комнате, настройки вида
- this.roomToggleZoom = zoomFactor => () => {
- this.zoomFactor = zoomFactor;
- this.redrawGrid();
- this.refreshRoomCanvas();
- };
- this.roomToCenter = () => {
- this.roomx = this.room.width / 2;
- this.roomy = this.room.height / 2;
- this.refreshRoomCanvas();
- };
- this.redrawGrid = () => {
- this.gridCanvas.width = this.room.gridX;
- this.gridCanvas.height = this.room.gridY;
- this.gridCanvas.x.clearRect(0, 0, this.room.gridX, this.room.gridY);
- this.gridCanvas.x.globalAlpha = 0.3;
- this.gridCanvas.x.strokeStyle = localStorage.UItheme === 'Night' ? '#44dbb5' : '#446adb';
- this.gridCanvas.x.lineWidth = 1 / this.zoomFactor;
- this.gridCanvas.x.strokeRect(
- 0.5 / this.zoomFactor, 0.5 / this.zoomFactor,
- this.room.gridX, this.room.gridY
- );
- };
- this.roomToggleGrid = () => {
- if (this.room.gridX === 0) {
- window.alertify
- .confirm(this.voc.gridSize + '
x ')
- .then(e => {
- if (e.buttonClicked === 'ok') {
- this.room.gridX = Number(document.getElementById('theGridSizeX').value);
- this.room.gridY = Number(document.getElementById('theGridSizeY').value);
- }
- this.redrawGrid();
- this.refreshRoomCanvas();
- this.update();
- });
- } else {
- this.refreshRoomCanvas();
- this.room.gridX = 0;
- this.room.gridY = 0;
- }
+ this.updateSelectFrame = () => {
+ this.pixiEditor.transformer.setup();
};
- // Работа с копиями
- this.tab = 'roomcopies';
- this.changeTab = tab => () => {
- this.tab = tab;
- this.selectedCopies = this.selectedTiles = false;
- if (tab === 'roombackgrounds' || tab === 'properties') {
- this.roomUnpickTemplate();
- }
- if (tab !== 'roomcopies') {
- this.toggleCopyProperties(false);
- }
- };
- this.roomUnpickTemplate = () => {
- this.currentTemplate = -1;
+ const setup = require('./data/node_requires/roomEditor').setup;
+ this.on('mount', () => {
+ setup(this.refs.canvas, this);
+ // adds this.pixiEditor
+ [this.currentTileLayer] = this.pixiEditor.tileLayers;
+ this.update();
+ });
+ this.on('unmount', () => {
+ this.pixiEditor.destroy(false, {
+ children: true
+ });
+ });
+ this.triggerWheelEvent = e => {
+ e.preventUpdate = true;
+ // pixi v5 doesn't have a wheel event! we will have to fabricate one.
+ this.pixiEditor.stage._events.wheel.fn({
+ type: 'wheel',
+ target: this.pixiEditor.stage,
+ currentTarget: this.pixiEditor.stage,
+ data: {
+ global: {
+ x: e.offsetX,
+ y: e.offsetY
+ },
+ originalEvent: e
+ }
+ });
};
-
- /** Преобразовать x на канвасе в x на комнате */
- this.xToRoom = x => (x - Math.floor(this.refs.canvas.width / 2)) / this.zoomFactor + this.roomx;
- /** Преобразовать y на канвасе в y на комнате */
- this.yToRoom = y => (y - Math.floor(this.refs.canvas.height / 2)) / this.zoomFactor + this.roomy;
- /** Преобразовать x в комнате в x на канвасе */
- this.xToCanvas = x => (x - this.roomx) * this.zoomFactor + Math.floor(this.refs.canvas.width / 2);
- /** Преобразовать y в комнате в y на канвасе */
- this.yToCanvas = y => (y - this.roomy) * this.zoomFactor + Math.floor(this.refs.canvas.height / 2);
-
- this.onCanvasClick = e => {
- if (this.tab === 'roomcopies') {
- this.onCanvasClickCopies(e);
- } else if (this.tab === 'roomtiles') {
- this.onCanvasClickTiles(e);
+ // Keyboard events
+ const phabricateEvent = (name, e) => {
+ if (!(name in this.pixiEditor.stage._events)) {
+ console.error(`An event ${name} was triggered on the room editor, but it is not allowed.`);
+ return;
}
+ this.pixiEditor.stage._events[name].fn({
+ type: name,
+ target: this.pixiEditor.stage,
+ currentTarget: this.pixiEditor.stage,
+ data: {
+ originalEvent: e
+ }
+ });
};
- /** При нажатии на канвас, если не выбрана копия, то начинаем перемещение */
- this.onCanvasPress = e => {
- this.mouseDown = true;
- this.startx = e.offsetX;
- this.starty = e.offsetY;
-
- if (this.tab === 'roomcopies' && this.onCanvasPressCopies(e)) {
+ const triggerKeyboardEvent = e => {
+ if (['input', 'textarea', 'select'].includes(e.target.nodeName.toLowerCase())) {
return;
}
- if ((this.currentTemplate === -1 && !e.shiftKey && this.tab !== 'roomtiles' && e.button === 0 && !e.ctrlKey) ||
- e.button === 1) {
- this.dragging = true;
- }
- };
- /** и безусловно прекращаем перемещение при отпускании мыши */
- this.onCanvasMouseUp = e => {
- this.mouseDown = false;
- this.lastCopyX = null;
- this.lastCopyY = null;
- this.lastTileX = null;
- this.lastTileY = null;
- if (this.dragging) {
- this.dragging = false;
- this.roomx = Math.round(this.roomx);
- this.roomy = Math.round(this.roomy);
- this.refreshRoomCanvas();
- } else if (this.tab === 'roomtiles') {
- this.onCanvasMouseUpTiles(e);
- } else if (this.tab === 'roomcopies') {
- this.onCanvasMouseUpCopies(e);
+ if (e.key === 'Delete') {
+ return phabricateEvent('delete', e);
+ } else if (e.code === 'KeyC' && e.ctrlKey) {
+ return phabricateEvent('copy', e);
+ } else if (e.code === 'KeyV' && e.ctrlKey) {
+ return phabricateEvent('paste', e);
+ } else if (e.code === 'KeyZ' && e.ctrlKey && e.shiftKey) {
+ return phabricateEvent('redo', e);
+ } else if (e.code === 'KeyZ' && e.ctrlKey) {
+ return phabricateEvent('undo', e);
+ } else if (e.code === 'KeyH') {
+ return phabricateEvent('home', e);
+ } else if (e.key === 'ArrowRight') {
+ return phabricateEvent('nudgeright', e);
+ } else if (e.key === 'ArrowLeft') {
+ return phabricateEvent('nudgeleft', e);
+ } else if (e.key === 'ArrowUp') {
+ return phabricateEvent('nudgeup', e);
+ } else if (e.key === 'ArrowDown') {
+ return phabricateEvent('nudgedown', e);
}
- setTimeout(() => {
- this.movingStuff = false;
- }, 0);
- };
- this.drawDeleteCircle = e => {
- // Рисовка кружка для удаления копий
- var maxdist = Math.max(this.room.gridX, this.room.gridY) || 32;
- this.refreshRoomCanvas(e);
- var cx = this.refs.canvas.x;
- cx.fillStyle = '#F00';
- cx.strokeStyle = '#000';
- cx.globalAlpha = 0.5;
- cx.beginPath();
- cx.arc(this.xToRoom(e.offsetX), this.yToRoom(e.offsetY), maxdist, 0, 2 * Math.PI);
- cx.fill();
- cx.stroke();
};
+ this.on('mount', () => {
+ window.addEventListener('keydown', triggerKeyboardEvent);
+ });
+ this.on('unmount', () => {
+ window.removeEventListener('keydown', triggerKeyboardEvent);
+ });
- /**
- * Updating mouse coordinates display at the bottom-left corner
- */
- this.updateMouseCoords = function updateMouseCoords(e) {
- var dx = Math.floor(this.xToRoom(e.offsetX)),
- dy = Math.floor(this.yToRoom(e.offsetY));
- if (this.room.gridX === 0 || e.altKey) {
- this.mouseX = dx;
- this.mouseY = dy;
- } else {
- this.mouseX = Math.round(dx / this.room.gridX) * this.room.gridX;
- this.mouseY = Math.round(dy / this.room.gridY) * this.room.gridY;
- }
- this.refs.mousecoords.innerHTML = `(${this.mouseX}:${this.mouseY})`;
+ this.currentTool = 'select';
+ const mandatoryVisibilityMap = {
+ addCopies: 'copiesVisible',
+ addTiles: 'tilesVisible',
+ manageBackgrounds: 'backgroundsVisible'
};
-
- /** Start moving or show a placement preview **/
- this.onCanvasMove = e => {
- e.preventUpdate = true;
- if (this.dragging && !this.movingStuff) {
- // Drag the viewport
- this.roomx -= e.movementX / this.zoomFactor;
- this.roomy -= e.movementY / this.zoomFactor;
- this.refreshRoomCanvas(e);
- } else if ( // Make more tiles or copies if Shift key is down
- e.shiftKey && this.mouseDown &&
- (
- (this.tab === 'roomcopies' && this.currentTemplate !== -1) ||
- this.tab === 'roomtiles'
- )
- ) {
- this.onCanvasClick(e);
- } else if (this.tab === 'roomcopies') {
- this.onCanvasMoveCopies(e);
- } else if (this.tab === 'roomtiles') {
- this.onCanvasMoveTiles(e);
+ this.setTool = tool => () => {
+ this.currentTool = tool;
+ if (tool in mandatoryVisibilityMap) {
+ this.pixiEditor[mandatoryVisibilityMap[tool]] = true;
}
- this.updateMouseCoords(e);
- };
-
- /** Change zoom on mouse wheel */
- this.onCanvasWheel = e => {
- if (e.wheelDelta > 0) {
- this.refs.zoomslider.zoomIn();
- } else {
- this.refs.zoomslider.zoomOut();
+ if (tool !== 'select') {
+ this.pixiEditor.transformer.clear();
}
- };
- this.setZoom = zoom => {
- this.zoomFactor = zoom;
- this.update();
- this.redrawGrid();
- this.refreshRoomCanvas();
- };
-
- this.onCanvasContextMenu = e => {
- this.dragging = false;
- this.mouseDown = false;
- if (this.tab === 'roomcopies') {
- if (this.selectedCopies && this.selectedCopies.length) {
- this.onCanvasContextMenuMultipleCopies(e);
- } else {
- this.onCanvasContextMenuCopies(e);
- }
- } else if (this.tab === 'roomtiles') {
- if (this.selectedTiles && this.selectedTiles.length) {
- this.onCanvasContextMenuMultipleTiles(e);
- } else {
- this.onCanvasContextMenuTiles(e);
- }
+ if (tool === 'addTiles' && !this.pixiEditor.tileLayers.includes(this.currentTileLayer)) {
+ this.currentTileLayer = this.pixiEditor.tileLayers[0];
}
- e.preventDefault();
- return true;
};
- // Prompts a modal window then and shifts all the copies in a room at once.
- this.roomShift = () => {
- window.alertify.confirm(`
- ${window.languageJSON.roomView.shiftLabel}
-
-
- `)
- .then(e => {
- if (e.buttonClicked === 'ok') {
- var dx = Number(document.getElementById('roomshiftx').value) || 0,
- dy = Number(document.getElementById('roomshifty').value) || 0;
- for (const copy of this.room.copies) {
- copy.x += dx;
- copy.y += dy;
- }
- for (const tileLayer of this.room.tiles) {
- for (const tile of tileLayer.tiles) {
- tile.x += dx;
- tile.y += dy;
+ this.currentTemplate = -1;
+ this.changeSelectedTemplate = template => {
+ this.currentTemplate = template;
+ };
+
+ this.tilePatch = void 0;
+ this.changeTilePatch = tilePatch => {
+ this.tilePatch = tilePatch;
+ };
+ this.changeTileLayer = layer => {
+ this.currentTileLayer = layer;
+ };
+
+ this.zoom = 1;
+
+ this.changeBgColor = (e, color) => {
+ this.opts.room.backgroundColor = color;
+ this.pixiEditor.renderer.backgroundColor = PIXI.utils.string2hex(color);
+ };
+
+ this.changeSimulated = () => {
+ this.pixiEditor.simulate = !this.pixiEditor.simulate;
+ };
+
+ this.gridOn = true;
+ this.gridMenu = {
+ opened: false,
+ items: [{
+ label: this.voc.gridOff,
+ click: () => {
+ this.gridOn = !this.gridOn;
+ },
+ type: 'checkbox',
+ checked: () => !this.gridOn,
+ hotkeyLabel: 'Ctrl+G'
+ }, {
+ label: this.voc.toggleDiagonalGrid,
+ click: () => {
+ this.opts.room.diagonalGrid = !this.opts.room.diagonalGrid;
+ },
+ type: 'checkbox',
+ checked: () => this.opts.room.diagonalGrid
+ }, {
+ label: this.voc.changeGridSize,
+ click: () => {
+ window.alertify
+ .confirm(this.voc.gridSize + `
x `)
+ .then(e => {
+ if (e.buttonClicked === 'ok') {
+ this.opts.room.gridX = Number(document.getElementById('theGridSizeX').value);
+ this.opts.room.gridY = Number(document.getElementById('theGridSizeY').value);
}
- }
- this.refreshRoomCanvas();
+ this.update();
+ });
}
- });
+ }]
+ };
+ this.openGridMenu = e => {
+ this.refs.gridMenu.popup(e.clientX, e.clientY);
};
- this.roomSave = () => {
- if (this.nameTaken) {
- // animate the error notice
- require('./data/node_requires/jellify')(this.refs.errorNotice);
- if (localStorage.disableSounds !== 'on') {
- window.soundbox.play('Failure');
+ this.zoomMenu = {
+ opened: false,
+ items: [...[12.5, 25, 50, 100, 200, 400, 800].map(zoom => ({
+ label: `${zoom}%`,
+ click: () => {
+ this.zoom = 1 / zoom * 100;
+ this.pixiEditor.zoomTo(zoom);
}
- return false;
- }
- this.room.lastmod = Number(new Date());
- this.roomGenSplash()
- .then(() => {
- glob.modified = true;
- this.parent.editing = false;
- this.parent.update();
+ })), {
+ type: 'separator'
+ }, {
+ label: this.voc.resetView,
+ click: () => {
+ this.pixiEditor.goHome();
+ },
+ hotkeyLabel: 'H'
+ }]
+ };
+ this.openZoomMenu = e => {
+ this.refs.zoomMenu.popup(e.clientX, e.clientY);
+ };
+
+ const entityToIconMap = {
+ copies: 'template',
+ tiles: 'grid',
+ backgrounds: 'image'
+ };
+ const entityVisibilityItems = [];
+ for (const entityType in entityToIconMap) {
+ const icon = entityToIconMap[entityType];
+ entityVisibilityItems.push({
+ label: this.voc[entityType],
+ click: () => {
+ this.pixiEditor[entityType + 'Visible'] = !this.pixiEditor[entityType + 'Visible'];
+ },
+ type: 'checkbox',
+ checked: () => this.pixiEditor[entityType + 'Visible']
})
- .catch(err => {
- console.error(err);
- glob.modified = true;
- this.parent.editing = false;
- this.parent.update();
- });
- return true;
};
-
- this.sortHorizontally = () => {
- if (this.tab === 'roomcopies') {
- this.room.copies.sort((a, b) => a.x - b.x);
- } else {
- // tiles
- this.currentTileLayer.tiles.sort((a, b) => a.x - b.x);
- }
- this.resortRoom();
- this.refreshRoomCanvas();
+ this.visibilityMenu = {
+ opened: false,
+ items: [
+ ...entityVisibilityItems,
+ {
+ type: 'separator'
+ }, {
+ label: this.voc.xrayMode,
+ click: () => {
+ this.pixiEditor.xrayMode = !this.pixiEditor.xrayMode;
+ },
+ type: 'checkbox',
+ checked: () => this.pixiEditor.xrayMode
+ }, {
+ label: this.voc.colorizeTileLayers,
+ click: () => {
+ this.pixiEditor.colorizeTileLayers = !this.pixiEditor.colorizeTileLayers;
+ },
+ type: 'checkbox',
+ checked: () => this.pixiEditor.colorizeTileLayers
+ }
+ ]
};
- this.sortVertically = () => {
- if (this.tab === 'roomcopies') {
- this.room.copies.sort((a, b) => a.y - b.y);
- } else {
- // tiles
- this.currentTileLayer.tiles.sort((a, b) => a.y - b.y);
- }
- this.resortRoom();
- this.refreshRoomCanvas();
+ this.openVisibilityMenu = e => {
+ this.refs.visibilityMenu.popup(e.clientX, e.clientY);
};
- this.resortRoom = () => {
- // Make an array of all the backgrounds, tile layers and copies, and then sort it.
- this.stack = this.room.copies.concat(this.room.backgrounds).concat(this.room.tiles);
- const projTemplates = global.currentProject.templates;
- this.stack.sort((a, b) => {
- const depthA = a.depth !== void 0 ? a.depth : projTemplates[glob.templatemap[a.uid]].depth,
- depthB = b.depth !== void 0 ? b.depth : projTemplates[glob.templatemap[b.uid]].depth;
- return depthA - depthB;
- });
+ this.editingEvents = false;
+ this.openEventsList = () => {
+ this.editingEvents = true;
};
- this.resortRoom();
- var templatesChanged = () => {
- this.currentTemplate = -1;
- this.resortRoom();
+ this.closeRoomEvents = () => {
+ this.editingEvents = false;
+ this.update();
};
- window.signals.on('templatesChanged', templatesChanged);
- this.on('unmount', () => {
- window.signals.off('templatesChanged', templatesChanged);
- });
- /** Canvas redrawing, with all the backgrounds, tiles and copies */
- // eslint-disable-next-line max-lines-per-function, complexity
- this.refreshRoomCanvas = () => {
- if (this.forbidDrawing) {
- return;
- }
- const {canvas} = this.refs,
- sizes = this.refs.canvaswrap.getBoundingClientRect();
- // Make sure the canvas size is of correct width
- if (Number(canvas.width) !== sizes.width || Number(canvas.height) !== sizes.height) {
- canvas.width = sizes.width;
- canvas.height = sizes.height;
- }
-
- // Reset drawing transforms
- canvas.x.setTransform(1, 0, 0, 1, 0, 0);
- canvas.x.globalAlpha = 1;
- // Clear the canvas
- canvas.x.clearRect(0, 0, canvas.width, canvas.height);
- // Fill it with a background color
- canvas.x.fillStyle = this.room.backgroundColor || '#000000';
- canvas.x.fillRect(0, 0, canvas.width, canvas.height);
-
- // Apply camera movement + zoom
- canvas.x.translate(Math.floor(canvas.width / 2), Math.floor(canvas.height / 2));
- canvas.x.scale(this.zoomFactor, this.zoomFactor);
- canvas.x.translate(-this.roomx, -this.roomy);
-
- // Disable pixel interpolation, if needed
- canvas.x.imageSmoothingEnabled = !global.currentProject.settings.rendering.pixelatedrender;
-
- for (let i = 0, li = this.stack.length; i < li; i++) {
- if (this.stack[i].tiles) { // a tile layer
- const layer = this.stack[i];
- if (!layer.hidden) {
- for (const tile of layer.tiles) {
- const img = glob.texturemap[tile.texture],
- tex = img.g;
- const x = tex.offx + (tex.width + tex.marginx) * tile.grid[0] - tex.marginx,
- y = tex.offy + (tex.height + tex.marginy) * tile.grid[1] - tex.marginy,
- w = (tex.width + tex.marginx) * tile.grid[2] - tex.marginx,
- h = (tex.height + tex.marginy) * tile.grid[3] - tex.marginy;
- canvas.x.drawImage(
- img,
- x, y, w, h,
- tile.x, tile.y, w, h
- );
- }
- }
- } else if (this.stack[i].texture) { // a background layer
- if (this.stack[i].texture !== -1) {
- if (!('extends' in this.stack[i])) {
- this.stack[i].extends = {};
- }
- const scx = this.stack[i].extends.scaleX || 1,
- scy = this.stack[i].extends.scaleY || 1,
- shx = this.stack[i].extends.shiftX || 0,
- shy = this.stack[i].extends.shiftY || 0;
- canvas.x.save();
- canvas.x.fillStyle = canvas.x.createPattern(glob.texturemap[this.stack[i].texture], this.stack[i].extends.repeat || 'repeat');
- canvas.x.translate(shx, shy);
- canvas.x.scale(scx, scy);
- canvas.x.fillRect(
- (this.xToRoom(0) - shx) / scx, (this.yToRoom(0) - shy) / scy,
- canvas.width / scx / this.zoomFactor,
- canvas.height / scy / this.zoomFactor
- );
- canvas.x.restore();
- }
- } else { // A copy
- const copy = this.stack[i],
- template = global.currentProject.templates[glob.templatemap[copy.uid]];
- let texture, gra, w, h, ox, oy,
- grax, gray; // texture's drawing center
- if (template.texture !== -1) {
- texture = glob.texturemap[template.texture];
- gra = glob.texturemap[template.texture].g;
- w = gra.width;
- h = gra.height;
- ox = gra.offx;
- oy = gra.offy;
- [grax, gray] = gra.axis;
- } else {
- texture = glob.texturemap[-1];
- w = h = 32;
- grax = gray = 16;
- ox = oy = 0;
- }
- if ((copy.tx || copy.tx === 0) ||
- (copy.ty || copy.ty === 0) ||
- (copy.tr && copy.tr !== 0)) {
- canvas.x.save();
- canvas.x.translate(copy.x, copy.y);
- canvas.x.rotate((copy.tr || 0) * Math.PI / -180);
- canvas.x.scale(copy.tx ?? 1, copy.ty ?? 1);
- canvas.x.drawImage(
- texture,
- ox, oy, w, h,
- -grax, -gray, w, h
- );
- canvas.x.restore();
- } else {
- const tex = glob.texturemap[template.texture].g;
- canvas.x.drawImage(
- texture,
- tex.offx, tex.offy, w, h,
- copy.x - grax, copy.y - gray, w, h
- );
- }
- }
- }
-
- // Grid drawing
- if (this.room.gridX > 1) {
- canvas.x.globalCompositeOperation = 'exclusion';
- canvas.x.fillStyle = canvas.x.createPattern(this.gridCanvas, 'repeat');
- canvas.x.fillRect(
- this.xToRoom(0), this.yToRoom(0),
- canvas.width / this.zoomFactor, canvas.height / this.zoomFactor
- );
- canvas.x.globalCompositeOperation = 'source-over';
- }
- // Outline selected tiles
- if (this.tab === 'roomtiles' && this.selectedTiles && this.selectedTiles.length) {
- for (const tile of this.selectedTiles) {
- const {g} = glob.texturemap[tile.texture];
- this.drawSelection(
- tile.x,
- tile.y,
- tile.x + g.width * tile.grid[2],
- tile.y + g.height * tile.grid[3]
- );
- }
- }
- // Outline selected copies
- if (this.tab === 'roomcopies' && this.selectedCopies && this.selectedCopies.length) {
- for (const copy of this.selectedCopies) {
- this.drawSelection(copy);
- }
- }
-
- // Outline the starting viewport frame
- this.drawSelection(-1.5, -1.5, this.room.width + 1.5, this.room.height + 1.5);
-
- // Outline room's limits
- if (this.room.restrictCamera) {
- this.drawSelection(
- (this.room.restrictMinX || 0) - 1.5,
- (this.room.restrictMinY || 0) - 1.5,
- (this.room.restrictMaxX === void 0 ? this.room.width : this.room.restrictMaxX) + 1.5,
- (this.room.restrictMaxY === void 0 ? this.room.height : this.room.restrictMaxY) + 1.5
- );
- }
+ this.saveRoom = async () => {
+ const {writeRoomPreview} = require('./data/node_requires/resources/rooms');
+ this.pixiEditor.serialize();
+ await Promise.all([
+ writeRoomPreview(this.opts.room, this.pixiEditor.getSplashScreen(true), true),
+ writeRoomPreview(this.opts.room, this.pixiEditor.getSplashScreen(false), false)
+ ]);
+ this.opts.onclose();
};
- this.drawSelection = (x1, y1, x2, y2) => {
- const cx = this.refs.canvas.x;
- cx.lineJoin = 'round';
- cx.lineCap = 'round';
- if (typeof x1 !== 'number') {
- const copy = x1,
- template = global.currentProject.templates[glob.templatemap[copy.uid]],
- texture = glob.texturemap[template.texture].g;
- var left, top, height, width;
- if (copy.tr) {
- cx.strokeStyle = localStorage.UItheme === 'Night' ? '#44dbb5' : '#446adb';
- cx.lineWidth = 3;
- cx.beginPath();
- cx.moveTo(copy.x - 32, copy.y);
- cx.lineTo(copy.x + 32, copy.y);
- cx.moveTo(copy.x, copy.y - 32);
- cx.lineTo(copy.x, copy.y + 32);
- cx.stroke();
- cx.strokeStyle = localStorage.UItheme === 'Night' ? '#1C2B42' : '#fff';
- cx.lineWidth = 1;
- cx.moveTo(copy.x - 32, copy.y);
- cx.lineTo(copy.x + 32, copy.y);
- cx.moveTo(copy.x, copy.y - 32);
- cx.lineTo(copy.x, copy.y + 32);
- cx.stroke();
- return;
- }
- if (template.texture !== -1) {
- left = copy.x - texture.axis[0] * (copy.tx ?? 1) - 1.5;
- top = copy.y - texture.axis[1] * (copy.ty ?? 1) - 1.5;
- width = texture.width * (copy.tx ?? 1) + 3;
- height = texture.height * (copy.ty ?? 1) + 3;
- } else {
- left = copy.x - 16 - 1.5;
- top = copy.y - 16 - 1.5;
- height = 32 + 3;
- width = 32 + 3;
- }
- x1 = left;
- y1 = top;
- x2 = left + width;
- y2 = top + height;
- }
- cx.strokeStyle = localStorage.UItheme === 'Night' ? '#44dbb5' : '#446adb';
- cx.lineWidth = 3;
- cx.strokeRect(x1, y1, x2 - x1, y2 - y1);
- cx.strokeStyle = localStorage.UItheme === 'Night' ? '#1C2B42' : '#fff';
- cx.lineWidth = 1;
- cx.strokeRect(x1, y1, x2 - x1, y2 - y1);
+ const resizeEditor = () => {
+ setTimeout(() => {
+ this.pixiEditor.resize();
+ }, 10);
};
-
- /**
- * Генерирует миниатюру комнаты
- */
- this.roomGenSplash = function roomGenSplash() {
- const {imageCover, toBuffer} = require('./data/node_requires/imageUtils');
- return new Promise((accept, decline) => {
- const c = imageCover(this.refs.canvas, 340, 256);
- const buf = toBuffer(c);
- const roomSplashName = global.projdir + '/img/r' + this.room.uid + '.png';
- fs.writeFile(roomSplashName, buf, err => {
- if (err) {
- decline(err);
- } else {
- accept(roomSplashName);
- }
- });
- const projSplashName = global.projdir + '/img/splash.png';
- fs.writeFile(projSplashName, buf, err => {
- if (err) {
- decline(err);
- }
- });
- });
+ const serialize = () => {
+ this.pixiEditor.serialize();
};
+ this.on('mount', () => {
+ window.signals.on('exportProject', serialize);
+ window.signals.on('roomsFocus', resizeEditor);
+ });
+ this.on('unmount', () => {
+ window.signals.off('exportProject', serialize);
+ window.signals.off('roomsFocus', resizeEditor);
+ });
diff --git a/src/riotTags/rooms/room-entities-properties.tag b/src/riotTags/rooms/room-entities-properties.tag
new file mode 100644
index 000000000..1d3870f59
--- /dev/null
+++ b/src/riotTags/rooms/room-entities-properties.tag
@@ -0,0 +1,482 @@
+//
+ @attribute pixieditor (RoomEditor)
+ The reference to the current pixi editor
+
+ @attribute ontransformchange (riot function)
+ This function is called when this widget makes transformation
+ changes to selected objects. Used to update the selection box.
+
+ @method applyChanges
+ Call this on selection change to apply changes to the current selection
+ @method updatePropList
+ Call this on selection change to re-scan the selection for values
+
+room-entities-properties
+ div(if="{opts.pixieditor?.currentSelection.size}")
+ // Basic properties
+ virtual(each="{prop in basicProps}")
+ b {voc.copyProperties[prop.vocKey]}:
+ // Point2D
+ .aPoint2DInput.compact.wide(if="{prop.type === 'xy'}")
+ label.flexrow
+ span.nogrow X:
+ input.nmr(
+ type="number"
+ oninput="{wireAndApply('this.changes.basic.' + prop.key + '.x')}"
+ onchange="{memorizeChanges}"
+ value="{changes.basic[prop.key].x}"
+ placeholder="{String(changes.basic[prop.key].x)}"
+ step="{prop.step}"
+ )
+ .aSpacer.noshrink.nogrow
+ label.flexrow
+ span.nogrow Y:
+ input.nmr(
+ type="number"
+ oninput="{wireAndApply('this.changes.basic.' + prop.key + '.y')}"
+ onchange="{memorizeChanges}"
+ value="{changes.basic[prop.key].y}"
+ placeholder="{String(changes.basic[prop.key].y)}"
+ step="{prop.step}"
+ )
+ .flexrow(if="{prop.type === 'slider'}")
+ .aSliderWrap
+ input.compact(
+ type="range" min="{prop.from}" max="{prop.to}" step="{prop.step}"
+ value="{(changes.basic[prop.key] === parent.multipleType) ? 0 : (changes.basic[prop.key] || 0)}"
+ oninput="{wireAndApply('this.changes.basic.' + prop.key)}"
+ onchange="{memorizeChanges}"
+ list="{prop.datalist}"
+ )
+ .DataTicks(if="{prop.datalist}")
+ .aDataTick(each="{value in [-180, -90, 0, 90, 180]}" style="left: {(value + 180) / 3.6}%")
+ .aSpacer
+ input.compact(
+ min="{prop.from}" max="{prop.to}" step="{prop.step}" type="number"
+ value="{String(changes.basic[prop.key])}"
+ oninput="{wireAndApply('this.changes.basic.' + prop.key)}"
+ onchange="{memorizeChanges}"
+ placeholder="{String(changes.basic[prop.key])}"
+ )
+ color-input(
+ if="{prop.type === 'color'}"
+ color="{PIXI.utils.hex2string(changes.basic[prop.key])}"
+ onchange="{writeColor(prop.key)}"
+ onapply="{writeColorAndMemorize(prop.key)}"
+ hidealpha="true"
+ )
+
+ // Copies' extensions that come from mods
+ extensions-editor(show="{hasCopies}" entity="{changes.exts}" ref="exts" type="copy" compact="yes" wide="yup")
+
+ // Custom properties for copies
+ div(if="{hasCopies}")
+ h3 {voc.customProperties}
+ table.wide.aPaddedTable.cellsmiddle
+ tr
+ th {voc.copyCustomProperties.property}
+ th {voc.copyCustomProperties.value}
+ th
+ tr(each="{val, prop in changes.customProps}")
+ td
+ input.wide(
+ type="text"
+ value="{prop}"
+ onchange="{renameProp}"
+ )
+ p.anErrorNotice(if="{reservedProps.includes(prop)}") {voc.copyCustomProperties.nameOccupied}
+ td
+ input.wide(
+ type="text"
+ value="{val === multipleType ? '' : JSON.stringify(val)}"
+ placeholder="{val === multipleType ? String(multipleType) : ''}"
+ onchange="{changeValue}"
+ )
+ td
+ button.toright.square.inline.nm(onclick="{deleteCustomProperty(prop)}" title="{vocGlob.delete}")
+ svg.feather
+ use(xlink:href="#trash")
+ .clear
+ button.nogrow(onclick="{addCustomProperty}")
+ svg.feather
+ use(xlink:href="#plus")
+ span {voc.copyCustomProperties.addProperty}
+ datalist#theDatalistDegrees
+ option(value="-180")
+ option(value="-90")
+ option(value="0")
+ option(value="90")
+ option(value="180")
+ script.
+ this.namespace = 'roomView';
+ this.mixin(window.riotVoc);
+ this.mixin(window.riotWired);
+
+ const {Copy} = require('./data/node_requires/roomEditor/entityClasses/Copy');
+
+ this.changes = {
+ exts: {},
+ basic: {},
+ customProps: {}
+ };
+
+ this.basicProps = [{
+ // An i18n key to look for in roomView.copyProperties, for a label
+ vocKey: 'position',
+ // A key to write to
+ key: 'position',
+ // The type of this field. `xy` stands for 2D point input
+ type: 'xy',
+ step: 8
+ }, {
+ vocKey: 'scale',
+ key: 'scale',
+ type: 'xy',
+ step: 0.1
+ }, {
+ vocKey: 'rotation',
+ key: 'angle',
+ type: 'slider',
+ from: -180,
+ to: 180,
+ step: 1,
+ datalist: 'theDatalistDegrees'
+ }, {
+ vocKey: 'opacity',
+ key: 'alpha',
+ type: 'slider',
+ from: 0,
+ to: 1,
+ step: 0.01
+ }, {
+ vocKey: 'tint',
+ key: 'tint',
+ type: 'color'
+ }];
+
+ // Utilities for writing basic properties
+ const typeWrap = (prop, entity) => {
+ if (prop.type == 'xy') {
+ return {
+ x: entity[prop.key].x,
+ y: entity[prop.key].y
+ };
+ }
+ return entity[prop.key];
+ };
+ this.writeColor = key => (e, value) => {
+ this.changes.basic[key] = PIXI.utils.string2hex(value);
+ this.applyChanges();
+ };
+ this.wireAndApply = path => e => {
+ this.wire(path)(e);
+ this.applyChanges();
+ this.opts.ontransformchange();
+ e.stopPropagation();
+ };
+
+ const Magic = function Magic() {
+ void 'sparkles';
+ };
+ Magic.prototype.toString = () => this.voc.copyProperties.multipleValues;
+ Magic.prototype.toNumber = () => 0;
+ this.multipleType = new Magic();
+
+ this.firstRun = true;
+ /**
+ * Rescans the list of selected items and forms a list of matching and different properties.
+ * Different changes are reflected as this.multipleType.
+ *
+ * Before the rescan, it always writes applied changes to the previous selection.
+ */
+ this.updatePropList = () => {
+ this.firstRun = false;
+ this.changes = {
+ exts: {},
+ basic: {},
+ customProps: {}
+ };
+
+ this.hasCopies = false;
+ const {basic} = this.changes;
+ const selection = this.opts.pixieditor.currentSelection;
+ // Quicker run for built-in properties
+ for (const property of this.basicProps) {
+ for (const entity of selection) {
+ if (!(property.key in basic)) {
+ basic[property.key] = typeWrap(property, entity);
+ } else if (property.type === 'xy') {
+ if (basic[property.key].x !== this.multipleType) {
+ if (basic[property.key].x !== entity[property.key].x) {
+ basic[property.key].x = this.multipleType;
+ }
+ }
+ if (basic[property.key].y !== this.multipleType) {
+ if (basic[property.key].y !== entity[property.key].y) {
+ basic[property.key].y = this.multipleType;
+ }
+ }
+ if (basic[property.key].x === this.multipleType &&
+ basic[property.key].y === this.multipleType
+ ) {
+ break;
+ }
+ } else if (basic[property.key] !== entity[property.key]) {
+ basic[property.key] = this.multipleType;
+ break;
+ }
+ }
+ }
+ let copyCount = 0;
+ const propCount = {};
+ // Separate run for custom properties and extensions
+ for (const entity of selection) {
+ // Skip stuff that doesn't support custom properties
+ if (!(entity instanceof Copy)) {
+ continue;
+ }
+ this.hasCopies = true;
+ copyCount++;
+ for (const property in entity.copyCustomProps) {
+ if (!(property in this.changes.customProps)) {
+ this.changes.customProps[property] = entity.copyCustomProps[property];
+ propCount[property] = 1;
+ } else if (this.changes.customProps[property] !== entity.copyCustomProps[property]) {
+ this.changes.customProps[property] = this.multipleType;
+ propCount[property] ++;
+ } else {
+ propCount[property] ++;
+ }
+ }
+ }
+ // check if some copies did not have particular custom properties and mark such as (Multiple)
+ for (const property in propCount) {
+ if (propCount[property] !== copyCount) {
+ this.changes.customProps[property] = this.multipleType;
+ console.log(`Marked property '${property}' as multiple, got ${propCount[property]} properties for ${copyCount} copies`);
+ }
+ }
+ this.update();
+ };
+
+ // an ID to use as newly created property names
+ this.currentId = 1;
+ this.renameProp = e => {
+ const {prop, val} = e.item;
+ const newName = e.target.value.trim();
+ delete this.changes.customProps[prop];
+ this.changes.customProps[newName] = val;
+ };
+ this.changeValue = e => {
+ const {prop} = e.item;
+ // attempt to parse the value
+ // only strings will be unparsable with the JSON.parse method
+ let trueValue;
+ try {
+ trueValue = JSON.parse(e.target.value); // JSON, number, boolean
+ } catch {
+ trueValue = e.target.value; // string
+ }
+ this.changes.customProps[prop] = trueValue;
+ };
+ this.addCustomProperty = () => {
+ this.changes.customProps['newProperty' + this.currentId] = '';
+ this.currentId++;
+ };
+ this.deleteCustomProperty = (prop) => e => {
+ delete this.changes.customProps[prop];
+ this.applyChanges();
+ };
+
+ this.reservedProps = [
+ '_accessibleActive',
+ '_accessibleDiv',
+ '_bounds',
+ '_boundsID',
+ '_boundsRect',
+ '_cachedTint',
+ '_destroyed',
+ '_enabledFilters',
+ '_height',
+ '_lastSortedIndex',
+ '_localBounds',
+ '_localBoundsRect',
+ '_mask',
+ '_tempDisplayObjectParent',
+ '_tintedCanvas',
+ '_width',
+ '_zIndex',
+ 'accessible',
+ 'accessibleChildren',
+ 'accessibleHint',
+ 'accessiblePointerEvents',
+ 'accessibleTitle',
+ 'accessibleType',
+ 'alpha',
+ 'anchor',
+ 'angle',
+ 'animationSpeed',
+ 'autoUpdate',
+ 'blendMode',
+ 'buttonMode',
+ 'cacheAsBitmap',
+ 'children',
+ 'currentFrame',
+ 'cursor',
+ 'filterArea',
+ 'filters',
+ 'height',
+ 'hitArea',
+ 'interactive',
+ 'interactiveChildren',
+ 'isMask',
+ 'isSprite',
+ 'localTransform',
+ 'loop',
+ 'mask',
+ 'onComplete',
+ 'onFrameChange',
+ 'onLoop',
+ 'parent',
+ 'pivot',
+ 'playing',
+ 'pluginName',
+ 'position',
+ 'renderable',
+ 'rotation',
+ 'roundPixels',
+ 'scale',
+ 'skew',
+ 'sortableChildren',
+ 'sortDirty',
+ 'texture',
+ 'textures',
+ 'tint',
+ 'totalFrames',
+ 'transform',
+ 'updateAnchor',
+ 'visible',
+ 'width',
+ 'worldAlpha',
+ 'worldTransform',
+ 'worldVisible',
+ 'x',
+ 'y',
+ 'zIndex',
+ 'fromFrames',
+ 'fromImages',
+ '_calculateBounds',
+ '_onTextureUpdate',
+ '_recursivePostUpdateTransform',
+ '_render',
+ 'addChild',
+ 'addChildAt',
+ 'calculateBounds',
+ 'calculateTrimmedVertices',
+ 'calculateVertices',
+ 'containerUpdateTransform',
+ 'containsPoint',
+ 'destroy',
+ 'disableTempParent',
+ 'displayObjectUpdateTransform',
+ 'enableTempParent',
+ 'getBounds',
+ 'getChildAt',
+ 'getChildByName',
+ 'getChildIndex',
+ 'getGlobalPosition',
+ 'getLocalBounds',
+ 'gotoAndPlay',
+ 'gotoAndStop',
+ 'onChildrenChange',
+ 'play',
+ 'removeChild',
+ 'removeChildAt',
+ 'removeChildren',
+ 'render',
+ 'renderAdvanced',
+ 'renderAdvancedWebGL',
+ 'renderCanvas',
+ 'renderWebGL',
+ 'setChildIndex',
+ 'setParent',
+ 'setTransform',
+ 'sortChildren',
+ 'stop',
+ 'swapChildren',
+ 'toGlobal',
+ 'toLocal',
+ 'update',
+ 'updateTransform'
+ ];
+
+ this.applyChanges = () => {
+ if (this.firstRun) {
+ return;
+ }
+ const selection = this.opts.pixieditor.currentSelection || [];
+ for (const entity of selection) {
+ // basic properties are applied to everything
+ for (const property in this.changes.basic) {
+ const value = this.changes.basic[property];
+ if (value === this.multipleType) {
+ continue;
+ }
+ const type = this.basicProps.find(prop => prop.key === property).type;
+ switch (type) {
+ case 'xy':
+ if (value.x !== this.multipleType) {
+ entity[property].x = value.x;
+ }
+ if (value.y !== this.multipleType) {
+ entity[property].y = value.y;
+ }
+ break;
+ case 'color':
+ case 'slider':
+ entity[property] = value;
+ break;
+ default:
+ console.error(`Ignoring unknown property type: ${type}`);
+ break;
+ }
+ }
+ // Extensions and custom properties are supported for copies only
+ if (!(entity instanceof Copy)) {
+ continue;
+ }
+ // Write custom properties
+ for (const property in this.changes.customProps) {
+ const value = this.changes.customProps[property];
+ if (value === this.multipleType) {
+ continue;
+ }
+ entity.copyCustomProps[property] = value;
+ }
+ // Custom properties that are missing from the changeset are removed
+ for (const property in entity.copyCustomProps) {
+ if (!(property in this.changes.customProps)) {
+ delete entity.copyCustomProps[property];
+ }
+ }
+ // Write modded extensions
+ if (!this.refs.exts) {
+ // Nothing to write
+ continue;
+ }
+ for (const extension in this.refs.exts.extensions) {
+ const value = this.changes.exts[extension.key];
+ if (value === this.multipleType) {
+ continue;
+ }
+ entity.copyExts[extension.key] = value;
+ }
+ }
+ };
+ this.memorizeChanges = () => {
+ this.opts.pixieditor.history.snapshotTransforms();
+ };
+ this.writeColorAndMemorize = key => (e, value) => {
+ this.writeColor(key)(e, value);
+ this.opts.pixieditor.history.snapshotTransforms();
+ }
diff --git a/src/riotTags/rooms/room-events-editor.tag b/src/riotTags/rooms/room-events-editor.tag
index 97c21783c..1fd2d54e9 100644
--- a/src/riotTags/rooms/room-events-editor.tag
+++ b/src/riotTags/rooms/room-events-editor.tag
@@ -1,3 +1,6 @@
+//
+ @attribute room (IRoom)
+ @attribute onsave (riot function)
room-events-editor.aView.flexrow.pad
.tall.flexfix.aPanel.pad.room-events-editor-Properties.nogrow
.flexfix-body
@@ -53,6 +56,5 @@ room-events-editor.aView.flexrow.pad
};
this.roomSaveEvents = () => {
- this.parent.editingCode = false;
- this.parent.update();
+ this.opts.onsave();
};
diff --git a/src/riotTags/rooms/room-properties.tag b/src/riotTags/rooms/room-properties.tag
new file mode 100644
index 000000000..e1d22a274
--- /dev/null
+++ b/src/riotTags/rooms/room-properties.tag
@@ -0,0 +1,161 @@
+//
+ @attribute room
+ @attribute updatebg (riot function)
+ @attribute history (History)
+room-properties
+ fieldset
+ label
+ b {voc.name}
+ br
+ input.wide(
+ type="text"
+ onfocus="{rememberValue}"
+ oninput="{wire('this.opts.room.name')}"
+ onchange="{recordChange(opts.room, 'name')}"
+ value="{opts.room.name}"
+ )
+ fieldset
+ .aPoint2DInput.compact.wide
+ label
+ b {voc.width}
+ br
+ input.wide(
+ type="number" min="1" step="8"
+ onfocus="{rememberValue}"
+ oninput="{wire('this.opts.room.width')}"
+ onchange="{recordChange(opts.room, 'width')}"
+ value="{opts.room.width}"
+ )
+ .aSpacer
+ label
+ b {voc.height}
+ br
+ input.wide(
+ type="number" min="1" step="8"
+ onfocus="{rememberValue}"
+ oninput="{wire('this.opts.room.height')}"
+ onchange="{recordChange(opts.room, 'height')}"
+ value="{opts.room.height}"
+ )
+ fieldset
+ label.checkbox
+ input(
+ type="checkbox"
+ checked="{opts.room.restrictCamera}"
+ onchange="{handleToggle(opts.room, 'restrictCamera')}"
+ )
+ span {voc.restrictCamera}
+ fieldset
+ .aPoint2DInput.compact.wide(if="{opts.room.restrictCamera}")
+ label
+ b {voc.minimumX}:
+ |
+ input.compact(
+ step="{opts.room.gridX}" type="number"
+ onfocus="{rememberValue}"
+ oninput="{wire('this.opts.room.restrictMinX')}"
+ onchange="{recordChange(opts.room, 'restrictMinX')}"
+ value="{opts.room.restrictMinX === void 0 ? 0 : opts.room.restrictMinX}"
+ )
+ .aSpacer
+ label
+ b.nogrow {voc.minimumY}:
+ |
+ input.compact(
+ step="{opts.room.gridY}" type="number"
+ onfocus="{rememberValue}"
+ oninput="{wire('this.opts.room.restrictMinY')}"
+ onchange="{recordChange(opts.room, 'restrictMinY')}"
+ value="{opts.room.restrictMinY === void 0 ? 0 : opts.room.restrictMinY}"
+ )
+ .aPoint2DInput.compact.wide(if="{opts.room.restrictCamera}")
+ label
+ b {voc.maximumX}:
+ |
+ input.compact(
+ step="{opts.room.gridX}" type="number"
+ onfocus="{rememberValue}"
+ oninput="{wire('this.opts.room.restrictMaxX')}"
+ onchange="{recordChange(opts.room, 'restrictMaxX')}"
+ value="{opts.room.restrictMaxX === void 0 ? opts.room.width : opts.room.restrictMaxX}"
+ )
+ .aSpacer
+ label
+ b.nogrow {voc.maximumY}:
+ |
+ input.compact(
+ step="{opts.room.gridY}" type="number"
+ onfocus="{rememberValue}"
+ oninput="{wire('this.opts.room.restrictMaxY')}"
+ onchange="{recordChange(opts.room, 'restrictMaxY')}"
+ value="{opts.room.restrictMaxY === void 0 ? opts.room.height : opts.room.restrictMaxY}"
+ )
+
+ fieldset
+ b {voc.backgroundColor}
+ br
+ color-input.wide(onchange="{changeBgColor}" color="{opts.room.backgroundColor || '#000000'}")
+
+ fieldset
+ label.block.checkbox
+ input(
+ type="checkbox" checked="{opts.room.isUi}"
+ onchange="{handleToggle(opts.room, 'isUi')}"
+ )
+ b {voc.isUi}
+
+ fieldset
+ extensions-editor(entity="{opts.room.extends}" type="room" wide="true" compact="true")
+
+ script.
+ this.namespace = 'roomView';
+ this.mixin(window.riotVoc);
+ this.mixin(window.riotWired);
+
+ var prevValue;
+ this.rememberValue = e => {
+ if (e.target.type === 'number') {
+ prevValue = Number(e.target.value);
+ } else {
+ prevValue = e.target.value;
+ }
+ };
+ this.recordChange = (entity, key) => e => {
+ if (!this.opts.history) {
+ return;
+ }
+ let value = e.target.value;
+ if (e.target.type === 'number') {
+ value = Number(value);
+ }
+ this.opts.history.pushChange({
+ type: 'propChange',
+ key,
+ target: entity,
+ before: prevValue,
+ after: value
+ });
+ };
+
+ this.changeBgColor = (e, color) => {
+ const prevChange = this.opts.room.backgroundColor;
+ this.opts.updatebg(e, color);
+ this.opts.history.pushChange({
+ type: 'propChange',
+ key: 'backgroundColor',
+ target: this.opts.room,
+ before: prevChange,
+ after: this.opts.room.backgroundColor
+ });
+ };
+ this.handleToggle = (entity, key) => e => {
+ const prevValue = entity[key];
+ entity[key] = !entity[key];
+ this.opts.history.pushChange({
+ type: 'propChange',
+ key,
+ target: entity,
+ before: prevValue,
+ after: entity[key]
+ });
+ };
diff --git a/src/riotTags/rooms/room-template-picker.tag b/src/riotTags/rooms/room-template-picker.tag
new file mode 100644
index 000000000..2be51b586
--- /dev/null
+++ b/src/riotTags/rooms/room-template-picker.tag
@@ -0,0 +1,23 @@
+//
+ @attribute onselect (riot function)
+ This function is called when a template is selected.
+ The only argument passed to this function is the selected template.
+ @attribute selected (ITemplate | -1)
+ Currently selected template, piped back from the room editor
+room-template-picker
+ asset-viewer(
+ collection="{currentProject.templates}"
+ namespace="templates"
+ assettype="templates"
+ forcelayout="list"
+ click="{selectTemplate}"
+ thumbnails="{thumbnails}"
+ compact="true"
+ shownone="true"
+ selected="{opts.selected}"
+ )
+ script.
+ this.thumbnails = require('./data/node_requires/resources/templates').getTemplatePreview;
+ this.selectTemplate = template => () => {
+ this.opts.onselect(template);
+ };
diff --git a/src/riotTags/rooms/room-tile-editor.tag b/src/riotTags/rooms/room-tile-editor.tag
index e6bd5224f..8e4a1e43b 100644
--- a/src/riotTags/rooms/room-tile-editor.tag
+++ b/src/riotTags/rooms/room-tile-editor.tag
@@ -1,34 +1,56 @@
-room-tile-editor.room-editor-Tiles.tabbed.tall.flexfix
+//
+ @attribute layer (TileLayer)
+ A pixi.js container with all its tiles.
+ @attribute layers (Iterable)
+ All exising tile layers in the current room.
+ @attribute pixieditor (RoomEditor)
+ When other attributes are not enough
+
+ @attribute onchangetile (riot function)
+ Called with ITileSelection instance as its only argument
+ @attribute onchangelayer (riot function)
+ Called with TileLayer as its only argument.
+
+ @attribute addlayer (riot function)
+ Called when a user wants to add a layer.
+ The only argument is an ITileLayerTemplate instance.
+
+room-tile-editor.room-editor-Tiles.flexfix(class="{opts.class}")
+ .flexfix-header
+ button.inline.wide(onclick="{openTextureSelector}")
+ svg.feather
+ use(xlink:href="#search")
+ span {voc.findTileset}
.flexfix-body
- canvas(
+ canvas.room-tile-editor-aCanvas(
ref="tiledImage"
- onmousedown="{startTileSelection}"
- onmouseup="{stopTileSelection}"
- onmousemove="{moveTileSelection}"
+ onpointerdown="{startTileSelection}"
+ onpointerup="{stopTileSelection}"
+ onpointermove="{moveTileSelection}"
)
.flexfix-footer
- button.inline.wide(onclick="{switchTiledImage}")
+ ul.aMenu.room-tile-editor-aLayerList
+ li.checkbox(each="{layer in opts.layers}" onclick="{changeTileLayer}" class="{active: layer === parent.opts.layer}")
+ input(type="checkbox" name="tileLayers" checked="{layer.alpha === 1}" onchange="{toggleTileLayer}")
+ b {layer.zIndex}
+ span.a(title="{parent.voc.moveTileLayer}")
+ svg.feather(onclick="{moveTileLayer}")
+ use(xlink:href="#shuffle")
+ span.a(title="{parent.vocGlob.delete}")
+ svg.feather(onclick="{deleteTileLayer}")
+ use(xlink:href="#trash")
+ button.inline.wide(onclick="{addTileLayer}")
svg.feather
- use(xlink:href="#search")
- span {voc.findTileset}
- .flexrow
- select.wide(onchange="{changeTileLayer}" value="{parent.currentTileLayerId}")
- option(each="{layer, ind in opts.room.tiles}" selected="{parent.currentTileLayerId === ind}" value="{ind}") {layer.hidden? '❌' : '✅'} {layer.depth}
-
- span.act(title="{vocGlob.delete}" onclick="{deleteTileLayer}")
- svg.feather
- use(xlink:href="#trash")
- span.act(title="{parent.currentTileLayer.hidden? voc.show: voc.hide}" onclick="{toggleTileLayer}")
- svg.feather
- use(xlink:href="#{parent.currentTileLayer.hidden? 'eye' : 'eye-off'}")
- span.act(title="{voc.moveTileLayer}" onclick="{moveTileLayer}")
- svg.feather
- use(xlink:href="#shuffle")
- span.act(title="{vocGlob.add}" onclick="{addTileLayer}")
- svg.feather
- use(xlink:href="#plus")
+ use(xlink:href="#plus")
+ span {voc.addTileLayer || vocGlob.add}
.block
- extensions-editor(type="tileLayer" entity="{parent.currentTileLayer.extends}" compact="yep" wide="sure")
+ extensions-editor(
+ if="{opts.layer}"
+ type="tileLayer"
+ entity="{opts.layer.extends}"
+ compact="true"
+ wide="true"
+ )
asset-selector(
ref="tilesetPicker"
if="{pickingTileset}"
@@ -37,43 +59,35 @@ room-tile-editor.room-editor-Tiles.tabbed.tall.flexfix
onselected="{onTilesetSelected}"
)
script.
- this.parent.tileX = 0;
- this.parent.tileY = 0;
- this.parent.tileSpanX = 1;
- this.parent.tileSpanY = 1;
- if (!('tiles' in this.opts.room) || !this.opts.room.tiles.length) {
- this.opts.room.tiles = [{
- depth: -10,
- tiles: [],
- extends: {}
- }];
- this.parent.resortRoom();
- }
- [this.parent.currentTileLayer] = this.opts.room.tiles;
- this.parent.currentTileLayerId = 0;
+ this.tileX = 0;
+ this.tileY = 0;
+ this.tileSpanX = 1;
+ this.tileSpanY = 1;
this.namespace = 'roomTiles';
this.mixin(window.riotVoc);
this.mixin(window.riotWired);
- this.deleteTileLayer = () => {
+ this.on('update', () => {
+ if (!this.opts.layer && this.opts.layers.length) {
+ this.opts.onchangelayer(this.opts.layers[0]);
+ this.update();
+ } else if (this.opts.layer && !this.opts.layers.length) {
+ this.opts.onchangelayer(void 0);
+ this.update();
+ }
+ });
+
+ this.deleteTileLayer = e => {
+ const {layer} = e.item;
window.alertify
.okBtn(window.languageJSON.common.delete)
.cancelBtn(window.languageJSON.common.cancel)
.confirm(window.languageJSON.common.confirmDelete.replace('{0}', window.languageJSON.common.tileLayer))
.then(e => {
if (e.buttonClicked === 'ok') {
- var tiles = this.opts.room;
- var index = tiles.tiles.indexOf(this.parent.currentTileLayer);
- tiles.tiles.splice(index, 1);
- if (tiles.tiles.length) {
- [this.parent.currentTileLayer] = tiles.tiles;
- this.parent.currentTileLayerId = 0;
- } else {
- this.parent.currentTileLayer = false;
- }
- this.parent.resortRoom();
- this.parent.refreshRoomCanvas();
+ layer.detach(true);
+ this.opts.onchangelayer(this.opts.layers[0]);
this.update();
window.alertify
.okBtn(window.languageJSON.common.ok)
@@ -81,15 +95,25 @@ room-tile-editor.room-editor-Tiles.tabbed.tall.flexfix
}
});
};
- this.moveTileLayer = () => {
+ this.moveTileLayer = e => {
+ const {layer} = e.item;
window.alertify
- .defaultValue(this.parent.currentTileLayer.depth)
+ .defaultValue(layer.zIndex)
+ .okBtn(window.languageJSON.common.ok)
+ .cancelBtn(window.languageJSON.common.cancel)
.prompt(window.languageJSON.roomView.newDepth)
.then(e => {
if (e.inputValue && Number(e.inputValue)) {
- this.parent.currentTileLayer.depth = Number(e.inputValue);
- this.parent.resortRoom();
- this.parent.refreshRoomCanvas();
+ const before = layer.zIndex;
+ layer.zIndex = Number(e.inputValue);
+ this.opts.layers.sort((a, b) => b.zIndex - a.zIndex);
+ this.opts.pixieditor.history.pushChange({
+ type: 'propChange',
+ key: 'zIndex',
+ target: layer,
+ before,
+ after: layer.zIndex
+ });
this.update();
}
});
@@ -100,71 +124,68 @@ room-tile-editor.room-editor-Tiles.tabbed.tall.flexfix
.prompt(window.languageJSON.roomView.newDepth)
.then(e => {
if (e.inputValue && Number(e.inputValue)) {
- var layer = {
+ const layer = {
depth: Number(e.inputValue),
tiles: [],
extends: {}
};
- this.opts.room.tiles.push(layer);
- this.parent.currentTileLayer = layer;
- this.parent.currentTileLayerId = this.opts.room.tiles.length - 1;
- this.parent.resortRoom();
+ const pixiTileLayer = this.opts.addlayer(layer, true);
+ this.opts.onchangelayer(pixiTileLayer);
this.update();
}
});
};
this.toggleTileLayer = () => {
- this.parent.currentTileLayer.hidden = !this.parent.currentTileLayer.hidden;
- this.parent.refreshRoomCanvas();
+ this.opts.layer.visible = !this.opts.layer.visible;
};
this.changeTileLayer = e => {
- this.parent.currentTileLayer = this.opts.room.tiles[Number(e.target.value)];
- if (!this.parent.currentTileLayer.extends) {
- this.parent.currentTileLayer.extends = {};
- }
- this.parent.currentTileLayerId = Number(e.target.value);
+ this.opts.onchangelayer(e.item.layer);
};
- this.switchTiledImage = () => {
+ this.openTextureSelector = () => {
this.pickingTileset = true;
};
this.onTilesetCancel = () => {
this.pickingTileset = false;
this.update();
};
- this.onTilesetSelected = textureId => {
- const textures = require('./data/node_requires/resources/textures');
- this.parent.currentTileset = textures.getById(textureId);
+ this.onTilesetSelected = async textureId => {
+ const {getById, getDOMImage} = require('./data/node_requires/resources/textures');
+ this.currentTexture = getById(textureId);
this.pickingTileset = false;
+ this.update();
+ this.currentTextureImg = await getDOMImage(this.currentTexture);
this.redrawTileset();
+ this.tileX = this.tileY = 0;
+ this.tileSpanX = this.tileSpanY = 1;
+ this.sendTileSelection();
this.update();
};
this.redrawTileset = () => {
- const glob = require('./data/node_requires/glob');
var c = this.refs.tiledImage,
cx = c.getContext('2d'),
- g = this.parent.currentTileset,
- i = glob.texturemap[g.uid];
- c.width = i.width;
- c.height = i.height;
+ tex = this.currentTexture,
+ img = this.currentTextureImg;
+ c.width = img.width;
+ c.height = img.height;
if (global.currentProject.settings.rendering.pixelatedrender) {
c.style.imageRendering = 'pixelated';
} else {
c.style.imageRendering = 'unset';
}
cx.globalAlpha = 1;
- cx.drawImage(i, 0, 0);
+ cx.drawImage(img, 0, 0);
cx.strokeStyle = '#0ff';
cx.lineWidth = 1;
cx.globalAlpha = 0.5;
cx.globalCompositeOperation = 'exclusion';
- for (let i = 0, l = Math.min(g.grid[0] * g.grid[1], g.untill || Infinity); i < l; i++) {
- const xx = i % g.grid[0],
- yy = Math.floor(i / g.grid[0]),
- x = g.offx + xx * (g.marginx + g.width),
- y = g.offy + yy * (g.marginy + g.height),
- w = g.width,
- h = g.height;
+ for (let i = 0, l = Math.min(tex.grid[0] * tex.grid[1], tex.untill || Infinity); i < l; i++) {
+ const xx = i % tex.grid[0],
+ yy = Math.floor(i / tex.grid[0]),
+ x = tex.offx + xx * (tex.marginx + tex.width),
+ y = tex.offy + yy * (tex.marginy + tex.height),
+ w = tex.width,
+ h = tex.height;
cx.strokeRect(x, y, w, h);
}
cx.globalCompositeOperation = 'source-over';
@@ -172,33 +193,33 @@ room-tile-editor.room-editor-Tiles.tabbed.tall.flexfix
cx.lineJoin = 'round';
cx.strokeStyle = localStorage.UItheme === 'Night' ? '#44dbb5' : '#446adb';
cx.lineWidth = 3;
- const selX = g.offx + this.parent.tileX * (g.width + g.marginx),
- selY = g.offy + this.parent.tileY * (g.height + g.marginy),
- selW = g.width * this.parent.tileSpanX + g.marginx * (this.parent.tileSpanX - 1),
- selH = g.height * this.parent.tileSpanY + g.marginy * (this.parent.tileSpanY - 1);
+ const selX = tex.offx + this.tileX * (tex.width + tex.marginx),
+ selY = tex.offy + this.tileY * (tex.height + tex.marginy),
+ selW = tex.width * this.tileSpanX + tex.marginx * (this.tileSpanX - 1),
+ selH = tex.height * this.tileSpanY + tex.marginy * (this.tileSpanY - 1);
cx.strokeRect(-0.5 + selX, -0.5 + selY, selW + 1, selH + 1);
cx.strokeStyle = localStorage.UItheme === 'Night' ? '#1C2B42' : '#fff';
cx.lineWidth = 1;
cx.strokeRect(-0.5 + selX, -0.5 + selY, selW + 1, selH + 1);
};
this.startTileSelection = e => {
- if (!this.parent.currentTileset) {
+ if (!this.currentTexture) {
return;
}
// Adjust the pointer coordinates to account for potential scaling
const bbox = e.target.getBoundingClientRect();
const px = e.layerX / bbox.width * e.target.width,
py = e.layerY / bbox.height * e.target.height;
- var g = this.parent.currentTileset;
- this.parent.tileSpanX = 1;
- this.parent.tileSpanY = 1;
+ const tex = this.currentTexture;
+ this.tileSpanX = 1;
+ this.tileSpanY = 1;
this.selectingTile = true;
- this.tileStartX = Math.round((px - g.offx - g.width * 0.5) / (g.width + g.marginx));
- this.tileStartX = Math.max(0, Math.min(g.grid[0], this.tileStartX));
- this.tileStartY = Math.round((py - g.offy - g.height * 0.5) / (g.height + g.marginy));
- this.tileStartY = Math.max(0, Math.min(g.grid[1], this.tileStartY));
- this.parent.tileX = this.tileStartX;
- this.parent.tileY = this.tileStartY;
+ this.tileStartX = Math.round((px - tex.offx - tex.width * 0.5) / (tex.width + tex.marginx));
+ this.tileStartX = Math.max(0, Math.min(tex.grid[0], this.tileStartX));
+ this.tileStartY = Math.round((py - tex.offy - tex.height * 0.5) / (tex.height + tex.marginy));
+ this.tileStartY = Math.max(0, Math.min(tex.grid[1], this.tileStartY));
+ this.tileX = this.tileStartX;
+ this.tileY = this.tileStartY;
this.redrawTileset();
};
this.moveTileSelection = e => {
@@ -209,21 +230,32 @@ room-tile-editor.room-editor-Tiles.tabbed.tall.flexfix
const bbox = e.target.getBoundingClientRect();
const px = e.layerX / bbox.width * e.target.width,
py = e.layerY / bbox.height * e.target.height;
- var g = this.parent.currentTileset;
- this.tileEndX = Math.round((px - g.offx - g.width * 0.5) / (g.width + g.marginx));
- this.tileEndX = Math.max(0, Math.min(g.grid[0], this.tileEndX));
- this.tileEndY = Math.round((py - g.offy - g.height * 0.5) / (g.height + g.marginy));
- this.tileEndY = Math.max(0, Math.min(g.grid[1], this.tileEndY));
- this.parent.tileSpanX = 1 + Math.abs(this.tileStartX - this.tileEndX);
- this.parent.tileSpanY = 1 + Math.abs(this.tileStartY - this.tileEndY);
- this.parent.tileX = Math.min(this.tileStartX, this.tileEndX);
- this.parent.tileY = Math.min(this.tileStartY, this.tileEndY);
+ const tex = this.currentTexture;
+ this.tileEndX = Math.round((px - tex.offx - tex.width * 0.5) / (tex.width + tex.marginx));
+ this.tileEndX = Math.max(0, Math.min(tex.grid[0], this.tileEndX));
+ this.tileEndY = Math.round((py - tex.offy - tex.height * 0.5) / (tex.height + tex.marginy));
+ this.tileEndY = Math.max(0, Math.min(tex.grid[1], this.tileEndY));
+ this.tileSpanX = 1 + Math.abs(this.tileStartX - this.tileEndX);
+ this.tileSpanY = 1 + Math.abs(this.tileStartY - this.tileEndY);
+ this.tileX = Math.min(this.tileStartX, this.tileEndX);
+ this.tileY = Math.min(this.tileStartY, this.tileEndY);
this.redrawTileset();
};
+
this.stopTileSelection = e => {
if (!this.selectingTile) {
return;
}
this.moveTileSelection(e);
+ this.sendTileSelection();
this.selectingTile = false;
};
+ this.sendTileSelection = () => {
+ this.opts.onchangetile({
+ startX: this.tileX,
+ startY: this.tileY,
+ spanX: this.tileSpanX,
+ spanY: this.tileSpanY,
+ texture: this.currentTexture
+ });
+ };
diff --git a/src/riotTags/rooms/room-type-picker.tag b/src/riotTags/rooms/room-type-picker.tag
deleted file mode 100644
index c20849b85..000000000
--- a/src/riotTags/rooms/room-type-picker.tag
+++ /dev/null
@@ -1,89 +0,0 @@
-room-template-picker.room-editor-TemplateSwatches.tabbed.tall
- .aSearchWrap
- input.inline(type="text" onkeyup="{fuseSearch}" ref="fusesearch")
- svg.feather
- use(xlink:href="#search")
- .room-editor-aTemplateSwatch(
- if="{!searchResults}"
- onclick="{parent.roomUnpickTemplate}"
- class="{active: opts.current === -1}"
- )
- span {voc.selectAndMove}
- svg.feather
- use(xlink:href="#move")
- .room-editor-aTemplateSwatch(
- each="{template in (searchResults? searchResults : templates)}"
- title="{template.name}"
- onclick="{selectTemplate(template)}"
- class="{active: parent.opts.current === template}"
- )
- span {template.name}
- img(
- src="{template.texture === -1? 'data/img/notexture.png' : (glob.texturemap[template.texture].src.split('?')[0] + '_prev.png?' + getTextureRevision(template))}"
- draggable="false"
- )
- .room-editor-aTemplateSwatch.filler
- .room-editor-aTemplateSwatch.filler
- .room-editor-aTemplateSwatch.filler
- .room-editor-aTemplateSwatch.filler
- .room-editor-aTemplateSwatch.filler
- .room-editor-aTemplateSwatch.filler
- .room-editor-aTemplateSwatch.filler
-
- script.
- const glob = require('./data/node_requires/glob');
- this.glob = glob;
- this.namespace = 'roomView';
- this.mixin(window.riotVoc);
- this.mixin(window.riotWired);
-
- this.getTextureRevision = template => glob.texturemap[template.texture].g.lastmod;
-
- const fuseOptions = {
- shouldSort: true,
- tokenize: true,
- threshold: 0.5,
- location: 0,
- distance: 100,
- maxPatternLength: 32,
- minMatchCharLength: 1,
- keys: ['name']
- };
- const Fuse = require('fuse.js');
- this.fuseSearch = e => {
- if (!this.mounted) {
- this.searchResults = null;
- return;
- }
- var val = (e ? e.target.value : this.refs.fusesearch.value).trim();
- if (val) {
- var fuse = new Fuse(this.templates, fuseOptions);
- this.searchResults = fuse.search(val);
- } else {
- this.searchResults = null;
- }
- };
- this.selectTemplate = template => () => {
- this.parent.currentTemplate = template;
- this.parent.selectedCopies = false;
- };
-
- this.updateTemplateList = () => {
- this.templates = [...global.currentProject.templates];
- this.templates.sort((a, b) => a.name.localeCompare(b.name));
- this.fuseSearch();
- };
- this.updateTemplateList();
- var templatesChanged = () => {
- this.updateTemplateList();
- this.update();
- };
-
- window.signals.on('templatesChanged', templatesChanged);
- this.on('unmount', () => {
- window.signals.off('templatesChanged', templatesChanged);
- });
-
- this.on('mount', () => {
- this.mounted = true;
- });
diff --git a/src/riotTags/rooms/rooms-panel.tag b/src/riotTags/rooms/rooms-panel.tag
index 8fdbc8a03..914d7b7f9 100644
--- a/src/riotTags/rooms/rooms-panel.tag
+++ b/src/riotTags/rooms/rooms-panel.tag
@@ -15,7 +15,7 @@ rooms-panel.aPanel.aView
svg.feather
use(xlink:href="#plus")
span {parent.voc.create}
- room-editor(if="{editing}" room="{editingRoom}")
+ room-editor(if="{editing}" room="{editingRoom}" onclose="{closeRoomEditor}")
context-menu(menu="{roomMenu}" ref="roomMenu")
script.
const generateGUID = require('./data/node_requires/generateGUID');
@@ -44,6 +44,11 @@ rooms-panel.aPanel.aView
this.editingRoom = room;
this.editing = true;
};
+ this.closeRoomEditor = () => {
+ this.editingRoom = void 0;
+ this.editing = false;
+ this.update();
+ };
this.roomMenu = {
items: [{
diff --git a/src/riotTags/shared/asset-input.tag b/src/riotTags/shared/asset-input.tag
index 9ed4fc1f4..499383d00 100644
--- a/src/riotTags/shared/asset-input.tag
+++ b/src/riotTags/shared/asset-input.tag
@@ -78,11 +78,12 @@ asset-input
}
this.openAsset = e => {
- e.stopPropagation();
window.orders.trigger('openAsset', `${this.opts.assettype}/${this.currentAsset.uid}`);
+ e.stopPropagation();
};
- this.openSelector = () => {
+ this.openSelector = e => {
this.showingSelector = true;
+ e.stopPropagation();
};
this.closeSelector = () => {
this.showingSelector = false;
diff --git a/src/riotTags/shared/asset-selector.tag b/src/riotTags/shared/asset-selector.tag
index c4e40c558..cd65f5ca6 100644
--- a/src/riotTags/shared/asset-selector.tag
+++ b/src/riotTags/shared/asset-selector.tag
@@ -58,8 +58,9 @@ asset-selector.aDimmer.pointer.pad.fadein(onclick="{closeOnDimmer}" ref="dimmer"
this.opts.oncancelled();
}
}
+ e.stopPropagation();
};
- this.onAssetPicked = asset => () => {
+ this.onAssetPicked = asset => e => {
if (this.opts.onselected) {
if (asset === -1) {
this.opts.onselected(-1);
@@ -67,4 +68,5 @@ asset-selector.aDimmer.pointer.pad.fadein(onclick="{closeOnDimmer}" ref="dimmer"
this.opts.onselected(asset.uid);
}
}
+ e.stopPropagation();
};
diff --git a/src/riotTags/shared/asset-viewer.tag b/src/riotTags/shared/asset-viewer.tag
index c4e27f517..d8f3d4ae2 100644
--- a/src/riotTags/shared/asset-viewer.tag
+++ b/src/riotTags/shared/asset-viewer.tag
@@ -7,38 +7,45 @@
@attribute class (string)
This tag has its own CSS classes, but allows arbitrary ones added as an attribute.
- @attribute namespace (string)
+ @attribute [namespace] (string)
A unique namespace used to store settings. Fallbacks to 'default'.
- @attribute defaultlayout (string)
+ @attribute [defaultlayout] (string)
The default listing layout used if the user has not selected one yet.
Can be "cards", "list", "largeCards".
+ @attribute [forcelayout] (string)
+ Similar to [defaultlayout]
+ @attribute [compact] (atomic)
+ If set, the viewer hides several elements to fit in a more tight layout.
@attribute assettype (string)
The type of assets shown. The attribute is needed for groups to function.
@attribute collection (riot function)
A collection of items to iterate over while generating markup, sorting and firing events.
- @attribute names (riot function)
+ @attribute [shownone] (atomic)
+ If set, shows a "none" asset that returns -1 in opts.click event.
+ @attribute [selected] (IAsset | -1)
+ Currently selected asset. If set, it will be highlighted in UI.
+
+ @attribute [names] (riot function)
A mapping funtion that takes a collection object and returns its human-readable name.
Fallbacks to `item.name` if not defined.
- @attribute thumbnails (riot function)
+ @attribute [thumbnails] (riot function)
A mapping funtion that takes a collection object and returns a url for its thumbnail.
The function is passed with the collection object, `true` or `false` depending on whether
the large-card view is active, and `false`, which match the arguments used to get
a URL for the thumbnail of the proper size in many get{X}Preview methods.
- @attribute useicons (atomic)
+ @attribute [useicons] (atomic)
Tells the asset viewer to use SVG icons instead of img tag.
The `thumbnails` function should then return the name of the SVG icon.
- @attribute shownone (atomic)
- If set, shows a "none" asset that returns -1 in opts.click event.
-
- @attribute icons (riot function)
+ @attribute [icons] (riot function)
A mapping funtion that takes a collection object and returns an array of icon names.
The icons are shown near the asset's name and are used to convey some metadata.
+
@attribute click (riot function)
A two-fold callback (item => e => {…}) fired when a user clicks on an item,
passing the associated collection object as its only argument in the first function,
and a MouseEvent in a second function
- @attribute contextmenu (riot function)
+ @attribute [contextmenu] (riot function)
A two-fold callback (item => e => {…}) that is given a collection object
as its only argument in the first function, and a MouseEvent in a second function,
when a user tries to call a context menu on an item.
@@ -51,11 +58,11 @@
category is selected. Otherwise, groups are meant to be distinguished by their
`uid` property.
-asset-viewer.flexfix(class="{opts.namespace} {opts.class}")
+asset-viewer.flexfix(class="{opts.namespace} {opts.class} {compact: opts.compact}")
.flexfix-header
- .toright
- b {vocGlob.sort}
- .aButtonGroup
+ .toright(class="{flexrow: opts.compact}")
+ b(if="{!opts.compact}") {vocGlob.sort}
+ .aButtonGroup.nml
button.inline.square(
onclick="{switchSort('date')}"
class="{selected: sort === 'date' && !searchResults}"
@@ -68,17 +75,17 @@ asset-viewer.flexfix(class="{opts.namespace} {opts.class}")
)
svg.feather
use(xlink:href="#sort-alphabetically")
- .aSearchWrap
+ .aSearchWrap(style="{opts.compact ? 'width: auto;' : ''}")
input.inline(type="text" onkeyup="{fuseSearch}")
svg.feather
use(xlink:href="#search")
- button.inline.square(onclick="{switchLayout}")
+ button.inline.square(if="{!opts.forcelayout}" onclick="{switchLayout}")
svg.feather
use(xlink:href="#{layoutToIconMap[currentLayout]}")
- button.inline.square.nogrow(onclick="{addNewGroup}")
+ button.inline.square.nogrow.nmr(onclick="{addNewGroup}")
svg.feather
use(xlink:href="#folder-plus")
- span {voc.addNewGroup}
+ span(if="{!opts.compact}") {voc.addNewGroup}
.toleft
.clear
@@ -86,6 +93,7 @@ asset-viewer.flexfix(class="{opts.namespace} {opts.class}")
.aSpacer
ul.Cards.nmt(
if="{opts.assettype}"
+ class="{list: opts.compact}"
)
li.aCard(
onclick="{openGroup({isUngroupedGroup: true})}"
@@ -116,14 +124,15 @@ asset-viewer.flexfix(class="{opts.namespace} {opts.class}")
use(xlink:href="data/img/weirdFoldersIllustration.svg#illustration")
br
span {vocGlob.nothingToShowFiller}
- ul.Cards(class="{layoutToClassListMap[currentLayout]}")
- li.aCard(if="{opts.shownone}" onclick="{opts.click && opts.click(-1)}")
+ ul.Cards(class="{layoutToClassListMap[opts.forcelayout || currentLayout]}")
+ li.aCard(if="{opts.shownone}" onclick="{opts.click && opts.click(-1)}" class="{active: opts.selected === -1}")
.aCard-aThumbnail
img(src="data/img/notexture.png")
.aCard-Properties
span {vocGlob.none}
li.aCard(
each="{asset in (searchResults? searchResults : getGrouped(collection))}"
+ class="{active: opts.selected === asset}"
oncontextmenu="{parent.opts.contextmenu && parent.opts.contextmenu(asset)}"
onlong-press="{parent.opts.contextmenu && parent.opts.contextmenu(asset)}"
onclick="{parent.opts.click && parent.opts.click(asset)}"
@@ -143,7 +152,7 @@ asset-viewer.flexfix(class="{opts.namespace} {opts.class}")
.asset-viewer-Icons(if="{parent.opts.icons}")
svg.feather(each="{icon in parent.opts.icons(asset)}" class="feather-{icon}")
use(xlink:href="#{icon}")
- span.date(if="{asset.lastmod}") {niceTime(asset.lastmod)}
+ span.date(if="{asset.lastmod && !parent.opts.compact}") {niceTime(asset.lastmod)}
group-editor(
if="{showingGroupEditor}"
onapply="{closeGroupEditor}"
diff --git a/src/riotTags/shared/collapsible-section.tag b/src/riotTags/shared/collapsible-section.tag
index c66631211..52a0460a7 100644
--- a/src/riotTags/shared/collapsible-section.tag
+++ b/src/riotTags/shared/collapsible-section.tag
@@ -11,33 +11,35 @@
@attribute [heading] (string)
The heading to display
- @attribute hlevel (integer)
+ @attribute [hlevel] (integer)
A heading level from 1 to 7. Can be empty; if it is, a regular h3 is shown.
- @attribute defaultstate ("opened"|"closed")
+ @attribute [icon] (string)
+ An icon that will be displayed instead of the default chevron.
+ @attribute [defaultstate] ("opened"|"closed")
Sets the default state of the section. If it is not set, the section will appear closed.
- @attribute storestatekey (string)
+ @attribute [storestatekey] (string)
If set, remembers the state of this section in localStorage under the specified key.
- @attribute preservedom (atomic)
+ @attribute [preservedom] (atomic)
Whether or not to hide the content instead of removing it from DOM. It is recommended
to turn this on for larger layouts.
- @attribute ontoggle (riot function)
+ @attribute [ontoggle] (riot function)
A callback that triggers when a user folds/unfolds the section. Passes the new state
and this tag as two arguments.
collapsible-section(class="{opts.class} {opened ? 'opened' : 'closed'}")
- .flexrow(onclick="{toggle}")
- span(if="{opts.heading}")
- h1(if="{opts.hlevel == 1}") {opts.heading}
- h2(if="{opts.hlevel == 2}") {opts.heading}
- h3(if="{opts.hlevel == 3 || !opts.hlevel}") {opts.heading}
- h4(if="{opts.hlevel == 4}") {opts.heading}
- h5(if="{opts.hlevel == 5}") {opts.heading}
- h6(if="{opts.hlevel == 6}") {opts.heading}
- h7(if="{opts.hlevel == 7}") {opts.heading}
- yield(from="header")
+ .collapsible-section-aHeader(onclick="{toggle}")
+ span
+ h1(if="{opts.heading && opts.hlevel == 1}") {opts.heading}
+ h2(if="{opts.heading && opts.hlevel == 2}") {opts.heading}
+ h3(if="{opts.heading && (opts.hlevel == 3 || !opts.hlevel)}") {opts.heading}
+ h4(if="{opts.heading && opts.hlevel == 4}") {opts.heading}
+ h5(if="{opts.heading && opts.hlevel == 5}") {opts.heading}
+ h6(if="{opts.heading && opts.hlevel == 6}") {opts.heading}
+ h7(if="{opts.heading && opts.hlevel == 7}") {opts.heading}
+ yield(from="header")
svg.feather.a(class="{rotated: this.opened}")
- use(xlink:href="#chevron-up")
+ use(xlink:href="#{opts.icon ? opts.icon : 'chevron-up'}")
.collapsible-section-aWrapper(if="{opened || opts.preservedom}" hide="{!opened && opts.preservedom}")
script.
diff --git a/src/riotTags/shared/context-menu.tag b/src/riotTags/shared/context-menu.tag
index ddda3478d..7c3941462 100644
--- a/src/riotTags/shared/context-menu.tag
+++ b/src/riotTags/shared/context-menu.tag
@@ -31,7 +31,7 @@ context-menu(class="{opened: opts.menu.opened}" ref="root" style="{opts.menu.col
use(xlink:href="#{item.icon instanceof Function? item.icon() : item.icon}")
input(type="checkbox" checked="{item.checked instanceof Function? item.checked() : item.checked}" if="{item.type === 'checkbox'}")
span(if="{!item.type !== 'separator'}") {item.label}
- span.hotkey(if="{!item.type !== 'separator' && item.hotkey}") ({item.hotkeyLabel || item.hotkey})
+ span.hotkey(if="{!item.type !== 'separator' && (item.hotkey || item.hotkeyLabel)}") ({item.hotkeyLabel || item.hotkey})
svg.feather.context-menu-aChevron(if="{item.submenu && item.type !== 'separator'}")
use(xlink:href="#chevron-right")
context-menu(if="{item.submenu && item.type !== 'separator'}" menu="{item.submenu}")
diff --git a/src/riotTags/shared/error-notice.tag b/src/riotTags/shared/error-notice.tag
new file mode 100644
index 000000000..8e8799fd7
--- /dev/null
+++ b/src/riotTags/shared/error-notice.tag
@@ -0,0 +1,21 @@
+//
+ @slot
+ @attribute target
+error-notice.anErrorNotice
+
+ script.
+ const reposition = () => {
+ let {target} = this.opts;
+ if (target.root) {
+ target = target.root;
+ }
+ const box = target.getBoundingClientRect();
+ this.root.style.top = (box.top + box.height) + 'px';
+ this.root.style.left = (box.left + box.width / 2) + 'px';
+ };
+ this.on('update', reposition);
+ this.on('mount', reposition);
+ const interval = setInterval(reposition, 150);
+ this.on('unmount', () => {
+ clearInterval(interval);
+ });
diff --git a/src/riotTags/shared/zoom-slider.tag b/src/riotTags/shared/zoom-slider.tag
index f5d25e28b..577dd898d 100644
--- a/src/riotTags/shared/zoom-slider.tag
+++ b/src/riotTags/shared/zoom-slider.tag
@@ -5,6 +5,8 @@
Calls the funtion when a user changes the zoom value.
Passes the new zoom value as the one argument.
+ @method setZoom
+ Call this with a new zoom value in percents to manually update this zoom slider.
@method zoomIn
Call this property to advance the zoom value. This will call opts.onchage callback.
@method zoomOut
@@ -65,6 +67,11 @@ zoom-slider
this.opts.onchanged(this.rawToZoom(e.target.value));
}
};
+ this.setZoom = newZoom => {
+ const rawValue = this.zoomToRaw(newZoom);
+ this.refs.zoomslider.value = rawValue;
+ this.update();
+ };
this.zoomIn = () => {
const rawValue = Math.min(Number(this.refs.zoomslider.value) + 10, 100);
diff --git a/src/riotTags/sounds/sound-editor.tag b/src/riotTags/sounds/sound-editor.tag
index f72fca24e..51d38f37b 100644
--- a/src/riotTags/sounds/sound-editor.tag
+++ b/src/riotTags/sounds/sound-editor.tag
@@ -53,9 +53,8 @@ sound-editor.aDimmer
if (this.nameTaken) {
// animate the error notice
require('./data/node_requires/jellify')(this.refs.errorNotice);
- if (localStorage.disableSounds !== 'on') {
- soundbox.play('Failure');
- }
+ const {soundbox} = require('./data/node_requires/3rdparty/soundbox');
+ soundbox.play('Failure');
return false;
}
diff --git a/src/riotTags/style-editor.tag b/src/riotTags/style-editor.tag
index f213fd470..728ab8409 100644
--- a/src/riotTags/style-editor.tag
+++ b/src/riotTags/style-editor.tag
@@ -284,9 +284,8 @@ style-editor.aPanel.aView
if (this.nameTaken) {
// animate the error notice
require('./data/node_requires/jellify')(this.refs.errorNotice);
- if (localStorage.disableSounds !== 'on') {
- soundbox.play('Failure');
- }
+ const {soundbox} = require('./data/node_requires/3rdparty/soundbox');
+ soundbox.play('Failure');
return false;
}
this.styleobj.lastmod = Number(new Date());
diff --git a/src/riotTags/template-editor.tag b/src/riotTags/template-editor.tag
index 7c5111e5d..a62718302 100644
--- a/src/riotTags/template-editor.tag
+++ b/src/riotTags/template-editor.tag
@@ -27,6 +27,10 @@ mixin templateProperties
option(value="multiply" selected="{parent.template.blendMode === 'multiply'}") {parent.voc.blendModes.multiply}
option(value="screen" selected="{parent.template.blendMode === 'screen'}") {parent.voc.blendModes.screen}
fieldset
+ label.flexrow
+ b.nogrow.alignmiddle {parent.voc.animationFPS}
+ .aSpacer.nogrow
+ input.alignmiddle(type="number" max="60" min="1" step="1" value="{parent.template.animationFPS ?? 60}" onchange="{parent.wire('this.template.animationFPS')}")
label.block.checkbox
input(type="checkbox" checked="{parent.template.playAnimationOnStart}" onchange="{parent.wire('this.template.playAnimationOnStart')}")
span {parent.voc.playAnimationOnStart}
@@ -160,9 +164,8 @@ template-editor.aPanel.aView.flexrow
this.update();
// animate the error notice
require('./data/node_requires/jellify')(this.refs.errorNotice);
- if (localStorage.disableSounds !== 'on') {
- soundbox.play('Failure');
- }
+ const {soundbox} = require('./data/node_requires/3rdparty/soundbox');
+ soundbox.play('Failure');
return false;
}
glob.modified = true;
@@ -171,6 +174,7 @@ template-editor.aPanel.aView.flexrow
this.parent.fillTemplateMap();
this.parent.update();
window.signals.trigger('templatesChanged');
+ window.signals.trigger('templateChanged', this.template.uid);
return true;
};
this.changeCodeTab = scriptableEvent => {
diff --git a/src/riotTags/textures/texture-editor.tag b/src/riotTags/textures/texture-editor.tag
index 7ef4e1cdf..f835c92f1 100644
--- a/src/riotTags/textures/texture-editor.tag
+++ b/src/riotTags/textures/texture-editor.tag
@@ -856,15 +856,18 @@ texture-editor.aPanel.aView
if (this.nameTaken) {
// animate the error notice
require('./data/node_requires/jellify')(this.refs.errorNotice);
- if (localStorage.disableSounds !== 'on') {
- soundbox.play('Failure');
- }
+ const {soundbox} = require('./data/node_requires/3rdparty/soundbox');
+ soundbox.play('Failure');
return false;
}
this.parent.fillTextureMap();
glob.modified = true;
this.texture.lastmod = Number(new Date());
- const {textureGenPreview} = require('./data/node_requires/resources/textures');
+ const {textureGenPreview, updatePixiTexture} = require('./data/node_requires/resources/textures');
+ updatePixiTexture(this.texture)
+ .then(() => {
+ window.signals.trigger('pixiTextureChanged', this.texture.uid);
+ });
textureGenPreview(this.texture, global.projdir + '/img/' + this.texture.origname + '_prev@2.png', 128);
textureGenPreview(this.texture, global.projdir + '/img/' + this.texture.origname + '_prev.png', 64)
.then(() => {
diff --git a/src/riotTags/textures/texture-generator.tag b/src/riotTags/textures/texture-generator.tag
index 3a8a2f19d..d9d3bc2c8 100644
--- a/src/riotTags/textures/texture-generator.tag
+++ b/src/riotTags/textures/texture-generator.tag
@@ -195,9 +195,8 @@ texture-generator.aView
if (this.nameTaken) {
this.update();
require('./data/node_requires/jellify')(this.refs.errorNotice);
- if (localStorage.disableSounds !== 'on') {
- soundbox.play('Failure');
- }
+ const {soundbox} = require('./data/node_requires/3rdparty/soundbox');
+ soundbox.play('Failure');
return false;
}
diff --git a/src/styl/buildingBlocks.styl b/src/styl/buildingBlocks.styl
index 4a50fe26d..000d37210 100644
--- a/src/styl/buildingBlocks.styl
+++ b/src/styl/buildingBlocks.styl
@@ -1,6 +1,9 @@
.aSpacer
width 1rem
height @width
+ &.small
+ width 0.5rem
+ height @width
.aDimmer
position fixed
@@ -277,6 +280,8 @@
.aCard
background background
padding 0.8em
+ &.compact
+ padding 0.4em 0.8em
margin 0
box-sizing border-box
border 1px solid borderPale
@@ -332,6 +337,16 @@
pointer-events none
&:hover img
background rgba(act, 0.35)
+ .aCard.compact &
+ width 1.5rem
+ svg
+ width 1.5rem
+ height 1.5rem
+ stroke-width 2
+ img
+ width 2rem
+ height 2rem
+ margin -0.25rem 0 -0.25rem -0.25rem
.aCard-Actions
position absolute
top 0.5rem
@@ -380,6 +395,9 @@ sounds-panel, rooms-panel
th
border-bottom 1px solid borderBright
text-align left
+ &.cellsmiddle
+ td, th
+ vertical-align middle
.aNiceTable
margin 1rem 0
border 1px solid borderBright
diff --git a/src/styl/common.styl b/src/styl/common.styl
index e6b4bcc39..0200d7a60 100644
--- a/src/styl/common.styl
+++ b/src/styl/common.styl
@@ -188,3 +188,11 @@ icon(icon = 'slash', color = act)
color text
[css-swatch="backgroundDeeper"]
color backgroundDeeper
+[css-swatch="background"]
+ color background
+[css-swatch="red"]
+ color red
+[css-swatch="green"]
+ color green
+[css-swatch="orange"]
+ color orange
diff --git a/src/styl/inputs.styl b/src/styl/inputs.styl
index 3973dfe81..eea69c34f 100644
--- a/src/styl/inputs.styl
+++ b/src/styl/inputs.styl
@@ -222,6 +222,25 @@ input[type="reset"],
margin 0
button, .button
flex 1 1 auto
+ &.vertical
+ flex-flow column nowrap
+ button, .button
+ margin 0
+ border-radius 0
+ border-bottom-width 0
+ border-right-width 1px
+ if themeThickBorders
+ border-right-width 2px
+ @extend button.square
+ &:first-child
+ border-top-left-radius br
+ border-top-right-radius br
+ &:last-child
+ border-bottom-left-radius br
+ border-bottom-right-radius br
+ border-bottom-width 1px
+ if themeThickBorders
+ border-bottom-width 2px
button,
input[type="button"],
input[type="submit"],
@@ -336,6 +355,8 @@ fieldset
&::after
content ''
icon(check, background)
+ // a hack to fix pixelization of icons in certain context menus
+ transform scale(1)
width 0.85rem
height 1rem
position absolute
diff --git a/src/styl/tags/rooms/room-backgrounds-editor.styl b/src/styl/tags/rooms/room-backgrounds-editor.styl
new file mode 100644
index 000000000..f5d4ea756
--- /dev/null
+++ b/src/styl/tags/rooms/room-backgrounds-editor.styl
@@ -0,0 +1,3 @@
+room-backgrounds-editor
+ collapsible-section asset-input > .aButtonGroup
+ margin-right 0
diff --git a/src/styl/tags/rooms/room-copy-properties.styl b/src/styl/tags/rooms/room-copy-properties.styl
deleted file mode 100644
index 1d7f834ca..000000000
--- a/src/styl/tags/rooms/room-copy-properties.styl
+++ /dev/null
@@ -1,9 +0,0 @@
-room-copy-properties
- display block
- padding 1rem
- room-editor &.aPanel
- {shadamb}
- position absolute
- right 1rem
- top 4rem
- width 20rem
\ No newline at end of file
diff --git a/src/styl/tags/rooms/room-editor.styl b/src/styl/tags/rooms/room-editor.styl
index c86cd3814..e61b31318 100644
--- a/src/styl/tags/rooms/room-editor.styl
+++ b/src/styl/tags/rooms/room-editor.styl
@@ -1,173 +1,101 @@
room-editor
- display flex
- flex-direction row
- .room-editor-TemplateSwatches .aSearchWrap
- display block
- flex 1 1 100%
- margin 0 0 3px
- input
- box-sizing border-box
- width 100%
- font-size 90%
- border-radius 0
- .toolbar
- display flex
- flex-direction column
- padding 0.5em
- width 17em
- box-sizing border-box
- flex 0 0 auto
- flex-grow 0
- .settings .fifty
- padding 0.5rem
- .palette
- flex 1 1 auto
- .settings button
- margin 0.5em 0
- .aNav
- border-bottom-right-radius 0
- border-bottom-left-radius 0
- .palette
- position relative
- .tabwrap
- position absolute
- left 0
- right 0
- top 0
- bottom 0
- .editor
- display flex
- position relative
- flex 1 1 auto
- .shift
- position absolute
- top 0.5rem
- left 0.5rem
- .zoom
- position absolute
- top 0.5rem
- right 0.5rem
- zoom-slider
- width 20rem
- .grid
- position absolute
- bottom 0.5rem
- right 0.5rem
- .center
- position absolute
- bottom 0.5rem
- left 0.5rem
- canvas
- width 100%
- height 100%
-
-.room-editor-TemplateSwatches, .room-editor-Backgrounds, .room-editor-Tiles
- overflow-y scroll
- position absolute
- width 100%
-.room-editor-TemplateSwatches
- padding 0 0 0 1px !important
- display flex
- flex-flow row wrap
- align-content start
- align-items flex-start
-.room-editor-aTemplateSwatch
- list-style none
- border 1px solid borderPale
- flex 1 0 5rem
- display inline-block
- box-sizing border-box
- text-align center
- margin -1px 0 0 -1px
- cursor pointer
- padding 1.75rem 0.4em 0
- font-size 80%
- line-height 1.7
- {trans}
- position relative
- z-index 1
- svg
- width 2.5rem
- height @width
- color act
- line-height 3rem
- margin 1.35rem auto 0
- display block
- padding-bottom 0.5rem
- span
- display block
- text-overflow ellipsis
- overflow hidden
- width auto
+ background backgroundDeeper
+ & > canvas
position absolute
- left 0.5rem
- top 0.25rem
- right 0.5rem
- &:hover
- border-color act
- z-index 10
- {transshort}
- &.active
- border-color accent1
- z-index 10
- img
- height 64px
- width 64px
- &.filler
- height 0
- visibility hidden
-
-.room-editor-Backgrounds
- &.tabbed
- padding 0.5rem
- ul
+ left 0
+ top 0
+ width 100%
+ height 100%
+ .&-aToolsetHolder
+ pointer-events none
+ & > *
+ pointer-events initial
+ position absolute
+ left 0
+ right 0
+ top 0
+ bottom 0
+ overflow hidden
+ padding 1rem
+ display grid
+ grid-template-columns auto auto 1fr
+ grid-gap 0 1rem
+ align-items start
+ .&-aToolbar
+ border-radius br
margin 0
- padding 0
- .bg
- list-style none
- padding 0.3em 0.8em
+ {shad}
+ button
+ border-color borderBright
+ .&-aContextPanel
+ @extends .aPanel
+ display block
+ width 18rem
+ padding 1rem
border-radius br
- border 1px solid borderBright
- margin-bottom 0.2em
- img
- float left
- width 64px
- height 64px
- border-radius br
- cursor pointer
- margin-right 1rem
- & > span
- display block
- vertical-align middle
- margin-top 1em
- span
- cursor pointer
- {trans}
- float right
- margin-left 0.5rem
- .active
- color act
- label + label
- margin-top 0
- .fifty
- padding 0.5rem 0.25rem
-
-.room-editor-Tiles
- canvas
- cursor pointer
- min-width 100%
- .act
- color text
- cursor pointer
+ overflow auto
+ z-index 2
+ {shadamb}
+ resize both
+ min-width 15rem
+ max-width 50vw // why would you need it any longer
+ min-height 4rem
+ max-height calc(100% - 2rem)
+ .&-aTopPanel
+ border-radius br
+ border borderBright
+ {shad}
+ display flex
+ flex-flow row nowrap
+ background background
+ width max-content
+ justify-self center
+ grid-column 3
+ & > *
+ padding 0.25rem 1rem
+ box-shadow none
+ border-top 0
+ border-bottom 0
+ border-left 0
+ border-right 1px solid borderBright
+ margin 0
+ border-radius 0
+ &:first-child
+ border-radius br 0 0 br
+ &:last-child
+ border 0
+ border-radius 0 br br 0
+ & > .slim
+ padding 0.25rem 0.5rem
+ & > .checkbox
+ padding-left 2.5rem
+ [type="checkbox"]
+ top 50%
+ margin-left 1rem
+ transform translate(0, -50%)
+ & > zoom-slider
+ width 10rem
+ .&-aSelectionToggle
display inline-block
- padding 0.35rem 0
- line-height 1
- margin-left 0.5rem
- {trans}
- &:hover
- color act
- {transshort}
- .flexfix-footer button
- margin-bottom 0.25rem
- select
- padding 0.25rem
+ position relative
+ padding 0 1rem 0.5rem 0
+ cursor pointer
+ &.active
+ svg
+ color act
+ &:last-child
+ color accent1
+ svg
+ {trans}
+ &:last-child
+ width 1rem
+ height @width
+ padding 0.25rem
+ display block
+ //background background
+ border-radius 100%
+ overflow visible
+ position absolute
+ bottom 0
+ right 0
+ //{shad}
diff --git a/src/styl/tags/rooms/room-tile-editor.styl b/src/styl/tags/rooms/room-tile-editor.styl
new file mode 100644
index 000000000..ee05996a1
--- /dev/null
+++ b/src/styl/tags/rooms/room-tile-editor.styl
@@ -0,0 +1,26 @@
+room-tile-editor
+ .&-aCanvas
+ min-width 100%
+ margin 1rem 0
+ display block
+ .&-aLayerList
+ max-height 10rem
+ li.checkbox
+ border-radius br
+ display flex
+ padding-left 2rem
+ padding-right 0.5rem
+ &:hover
+ padding-left 2rem
+ padding-right 0.5rem
+ [type="checkbox"]
+ left 0.5rem
+ *
+ flex 0 0 auto
+ b
+ flex 1 1 auto
+ .a
+ margin-left 0.5rem
+ &.active
+ background rgba(act, 0.25)
+ color text
diff --git a/src/styl/tags/shared/asset-input.styl b/src/styl/tags/shared/asset-input.styl
index 770badcd8..938fe3516 100644
--- a/src/styl/tags/shared/asset-input.styl
+++ b/src/styl/tags/shared/asset-input.styl
@@ -1,4 +1,20 @@
asset-input
+ line-height 0
+ & > *
+ line-height 1.5
+ & > .aButtonGroup
+ max-width 100%
+ :first-child
+ display flex
+ flex-flow row nowrap
+ align-items center
+ overflow hidden
+ & img, & svg
+ flex 0 0 auto
+ & span
+ flex 1 1 auto
+ overflow hidden
+ text-overflow ellipsis
&.wide
& > .aButtonGroup
@extends .aButtonGroup.wide
diff --git a/src/styl/tags/shared/asset-viewer.styl b/src/styl/tags/shared/asset-viewer.styl
index adc408f30..cfcd1506f 100644
--- a/src/styl/tags/shared/asset-viewer.styl
+++ b/src/styl/tags/shared/asset-viewer.styl
@@ -22,3 +22,9 @@ asset-viewer
height @width
& + svg
margin-left 0.5rem
+ &.compact
+ .aSearchWrap
+ flex 1 1 auto
+ input
+ width 100%
+ box-sizing border-box
diff --git a/src/styl/tags/shared/collapsible-section.styl b/src/styl/tags/shared/collapsible-section.styl
index ca1de5bd3..0adf8c73f 100644
--- a/src/styl/tags/shared/collapsible-section.styl
+++ b/src/styl/tags/shared/collapsible-section.styl
@@ -3,33 +3,36 @@ collapsible-section
display block
&:first-child
margin-top 0
- & > .flexrow
+ .&-aHeader
padding 0.5rem 0
- align-items center
- cursor pointer
+ align-items center
border-bottom 1px solid borderBright
- h1, h2, h3, h4, h5, h6
- padding 0
- margin 0
- flex 1 1 auto
+ display grid
+ grid-template-columns 1fr auto
+ grid-gap 0.5rem
+ & > :first-child
+ display contents
+ & > h1, & > h2, & > h3, & > h4, & > h5, & > h6
+ padding 0
+ margin 0
+ overflow hidden
+ text-overflow ellipsis
+ white-space nowrap
+ asset-input
overflow hidden
- text-overflow ellipsis
- white-space nowrap
- svg
+ & > svg
{trans}
- margin-left 0.5rem
flex 0 0 auto
- align-self flex-end
+ cursor pointer
&.rotated
transform rotate(180deg)
.&-aWrapper
padding 1rem 0 0.5rem
&.aPanel
- & > .flexrow
- h1, h2, h3, h4, h5, h6
+ .collapsible-section-aHeader
+ padding 0.5rem 1rem
+ & > h1, & > h2, & > h3, & > h4, & > h5, & > h6
margin 0 1rem
- svg
- margin-right 0.5rem
&.closed > .flexrow
border-bottom 0
.collapsible-section-aWrapper
diff --git a/src/styl/tags/shared/error-notice.styl b/src/styl/tags/shared/error-notice.styl
new file mode 100644
index 000000000..cc1689dd2
--- /dev/null
+++ b/src/styl/tags/shared/error-notice.styl
@@ -0,0 +1,6 @@
+error-notice.anErrorNotice
+ position fixed
+ width 15rem
+ z-index 10
+ transform translate(-50%, 0)
+ {trans}
diff --git a/src/styl/themeSpringStream.styl b/src/styl/themeSpringStream.styl
index cbcfa372b..6e07d11ab 100644
--- a/src/styl/themeSpringStream.styl
+++ b/src/styl/themeSpringStream.styl
@@ -109,6 +109,8 @@ input[type="reset"],
color background
&.selected
background acttext
+.aButtonGroup.vertical button, .aButtonGroup.vertical .button
+ border 0
#theIntroBg
background introBg
diff --git a/tsconfig.json b/tsconfig.json
index 2d4568437..14a6200fb 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -4,6 +4,16 @@
"module": "umd",
"noImplicitAny": true,
"moduleResolution": "node",
- "baseUrl": "./"
+ "baseUrl": "./",
+ "typeRoots": [
+ "./node_modules/@types/",
+ "./app/node_modules/@types/"
+ ],
+ "paths": {
+ "node_modules/*": [
+ "./app/node_modules/*",
+ "./node_modules/*"
+ ],
+ }
}
}