From 5df1e0a27a6e22ecd53c1c4647f996195fc5ac3b Mon Sep 17 00:00:00 2001 From: Cosmo Myzrail Gorynych Date: Fri, 1 Nov 2024 16:47:53 +1200 Subject: [PATCH 01/21] :bug: Fix catnip blocks ignoring translations when there was a translated name without a translated label --- src/node_requires/catnip/blockUtils.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/node_requires/catnip/blockUtils.ts b/src/node_requires/catnip/blockUtils.ts index 973a88a03..b5573c67e 100644 --- a/src/node_requires/catnip/blockUtils.ts +++ b/src/node_requires/catnip/blockUtils.ts @@ -93,8 +93,12 @@ export const convertFromDtsToBlocks = (usefuls: usableDeclaration[], lib: 'core' name = node.comment.toString(); } else if (String(node.tagName.escapedText).startsWith('catnipName_') && node.comment) { // Localized names for this block - const key = String(node.tagName.escapedText).replace('catnipName_', 'name_'); + const key = String(node.tagName.escapedText).replace('catnipName_', 'name_'), + displayNameKey = String(node.tagName.escapedText).replace('catnipName_', 'displayName_'); extraNames[key] = node.comment.toString().trim(); + if (!extraNames[displayNameKey]) { + extraNames[displayNameKey] = extraNames[key]; + } } else if (String(node.tagName.escapedText).startsWith('catnipLabel_') && node.comment) { // Localized display names for this block const key = String(node.tagName.escapedText).replace('catnipLabel_', 'displayName_'); From 1ed06a9243404937f6a92988b931dd1782357e6e Mon Sep 17 00:00:00 2001 From: Cosmo Myzrail Gorynych Date: Fri, 1 Nov 2024 16:48:34 +1200 Subject: [PATCH 02/21] :zap: Improve Russian translations for ct.place --- app/data/ct.libs/place/blocks.js | 4 ++-- app/data/ct.libs/place/types.d.ts | 14 ++++++++------ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/app/data/ct.libs/place/blocks.js b/app/data/ct.libs/place/blocks.js index 008f7ea59..5457265a7 100644 --- a/app/data/ct.libs/place/blocks.js +++ b/app/data/ct.libs/place/blocks.js @@ -1,6 +1,6 @@ module.exports = [{ name: 'Move this copy along a line stopping at', - name_Ru: 'Переместить эту копию по линии, останавливаясь перед', + name_Ru: 'Переместиться по линии, останавливаясь перед группой', type: 'command', code: 'move template bullet', icon: 'move', @@ -29,7 +29,7 @@ module.exports = [{ } }, { name: 'Move this copy stopping at', - name_Ru: 'Переместить эту копию, останавливаясь перед', + name_Ru: 'Переместиться, останавливаясь перед группой', type: 'command', code: 'move template smart', icon: 'move', diff --git a/app/data/ct.libs/place/types.d.ts b/app/data/ct.libs/place/types.d.ts index ba6e64e2b..04d703fc0 100644 --- a/app/data/ct.libs/place/types.d.ts +++ b/app/data/ct.libs/place/types.d.ts @@ -104,6 +104,8 @@ declare namespace place { * * @param {Copy} me The object to check collisions on * @param {String} [cgroup] The collision group to check against + * @catnipName place is free for copy + * @catnipName_Ru место для копии свободно */ function free(me: Copy, cgroup?: string): boolean; @@ -131,6 +133,8 @@ declare namespace place { * @param {String} [cgroup] The collision group to check against * @returns {Copy|PIXI.Sprite|false} The collided copy, or `false` * if there were no collisions. + * @catnipName occupying object for + * @catnipName_Ru занимает место для */ function occupied(me: Copy, cgroup?: string): Copy | false; /** @@ -168,6 +172,8 @@ declare namespace place { * @param {String} [template] The name of the template to check agains * @catnipAsset template:template * @returns {Copy|Array} The collided copy or `false`, if there was no collision. + * @catnipName occupied by a template + * @catnipName_Ru занято шаблоном */ function meet(me: Copy, template: string): Copy | false; /** @@ -275,9 +281,7 @@ declare namespace place { * returns `false`. If a copy met an obstacle as another copy, returns this copy. * If there was a tile, returns `true`. * - * @catnipSaveReturn - * @catnipName Move a copy along a line - * @catnipName_Ru Передвинуть копию вдоль линии + * @catnipIgnore */ function moveAlong( me: Copy, direction: number, maxLength: number, cgroup?: string, stepSize?: number @@ -299,9 +303,7 @@ declare namespace place { * @returns {false|ISeparateMovementResult} `false` if it reached its target, * an object with each axis specified otherwise. * - * @catnipSaveReturn - * @catnipName Move a copy by distance - * @catnipName_Ru Передвинуть копию на расстояние + * @catnipIgnore */ function moveByAxes(me: Copy, dx: number, dy: number, cgroup?: string, stepSize?: number): false | ISeparateMovementResult; From 98a62381d03888c2d992917e9f25605620fa7795 Mon Sep 17 00:00:00 2001 From: Cosmo Myzrail Gorynych Date: Fri, 1 Nov 2024 17:52:06 +1200 Subject: [PATCH 03/21] :globe_with_meridians: Catnip: Translate the Random catmod's blocks to Russian --- app/data/ct.libs/random/index.js | 9 +++--- app/data/ct.libs/random/types.d.ts | 47 ++++++++++++++++++++++++++---- 2 files changed, 47 insertions(+), 9 deletions(-) diff --git a/app/data/ct.libs/random/index.js b/app/data/ct.libs/random/index.js index e4c14b262..a7489821f 100644 --- a/app/data/ct.libs/random/index.js +++ b/app/data/ct.libs/random/index.js @@ -3,12 +3,12 @@ const random = function random(x) { return Math.random() * x; }; -function processRandomInput(input) { - if (input.length === 1 && typeof input[0] === "string") { - return input[0].split(","); +const processRandomInput = function (input) { + if (input.length === 1 && typeof input[0] === 'string') { + return input[0].split(','); } return input; -} +}; Object.assign(random, { dice(...variants) { const dices = processRandomInput(variants); @@ -17,6 +17,7 @@ Object.assign(random, { const parsedResult = parseFloat(result); return isNaN(parsedResult) ? result : parsedResult; } + return null; }, histogram(...histogram) { const coeffs = [...processRandomInput(histogram)]; diff --git a/app/data/ct.libs/random/types.d.ts b/app/data/ct.libs/random/types.d.ts index 083145930..0c686cbac 100644 --- a/app/data/ct.libs/random/types.d.ts +++ b/app/data/ct.libs/random/types.d.ts @@ -3,12 +3,19 @@ interface IPoint { y: number; } -/** Returns a random float value between 0 and x, exclusive. */ +/** + * Returns a random float value between 0 and x, exclusive. + * @catnipName random from 0 to + * @catnipName_Ru случайное число от 0 до + */ declare function random(x: number): number; declare namespace random { /** * Returns random argument from comma separated arguments (without spaces): - * Numbers will return float. Words will return string. These can be mixed. + * Numbers will return float. Words will return string. These can be mixed. + * + * @catnipName random from list + * @catnipName_Ru случайное из списка */ function dice(...dices: T[]): T; function dice(...dices: any): any; @@ -17,9 +24,10 @@ declare namespace random { * Returns a weighted random number from 0 to 1 according to a given histogram. * Each argument defines the probability of a random value to appear in a bucket. * Example: - * If you call `random.histogram(1, 10, 2)`, the method will return values + * If you call `random.histogram(1, 10, 2)`, the method will return values * in a range [0.333;0.667) ten times more often than in a range [0;0.333) * and five times more often than in a range [0.667;1). + * @catnipIgnore */ function histogram(...coeffs: number[]): number; @@ -27,6 +35,8 @@ declare namespace random { * Returns a random value from 0 to 1 that tends to be close to 0. * @param {number} [exp] An optional value that sets the power of the effect. * This value should be larger than 1, and equals to 2 by default. + * + * @catnipName_Ru случайное пессимистичное */ function pessimistic(exp?: number): number; @@ -34,24 +44,37 @@ declare namespace random { * Returns a random value from 0 to 1 that tends to be close to 1. * @param {number} [exp] An optional value that sets the power of the effect. * This value should be larger than 1, and equals to 2 by default. + * + * @catnipName_Ru случайное оптимистичное */ function optimistic(exp?: number): number; - /** Returns a random float value between `x1` and `x2`, exclusive. */ + /** + * Returns a random float value between `x1` and `x2`, exclusive. + * + * @catnipName random number in range + * @catnipName_Ru случайное число в диапазоне + */ function range(x1: number, x2: number): number /** * Returns a random float value between 0 and 360, exclusive. * @catnipName random angle + * @catnipName_Ru случайный угол */ function deg(): number; - /** Returns a pair of random coordinates from 0 to a corresponding room side. */ + /** + * Returns a pair of random coordinates from 0 to a corresponding room side. + * @catnipName random coordinate + * @catnipName_Ru случайные координаты + */ function coord(): IPoint; /** * Returns a random element from the passed array * @catnipName random from array + * @catnipName_Ru случайный элемент из массива */ function from(a: T[]): T; function from(a: any[]): any; @@ -61,11 +84,18 @@ declare namespace random { * with tokens inside { } separated by a | symbol. * * Example: randomText('a very {very |}tasty {{beef |chicken |}sausage|carrot}')); + * Possible outputs: "a very very tasty carrot", "a very tasty chicken sausage". + * + * @catnipName random text + * @catnipName_Ru случайный текст */ function text(text: string): string; /** * Returns a random value from a given enumeration. + * + * @catnipName random from enum + * @catnipName_Ru случайное из перечисления */ function enumValue(en: Record): number; @@ -74,17 +104,23 @@ declare namespace random { * out of `y`. When given only a value between 0…100, returns `true` * approximately `x` times out of 100. E.g. `random.chance(30)` means * a 30% success rate. + * + * @catnipName_Ru шанс */ function chance(x: number, y?: number): boolean; /** * Returns next seeded random number. + * + * @catnipName next seeded random number + * @catnipName_Ru следующее сидированное случайное число */ function seeded(): number; /** * Sets the seed of the `random.seeded()` method. * @catnipName Set the seed for the "random seeded" block + * @catnipName_Ru Установить сид для блока "сидированное случайное число" */ function setSeed(seed: number): void; @@ -92,6 +128,7 @@ declare namespace random { * Creates a new seeded random number generator. It is a function that you can store * and use in the same way as `random.seeded()`. * @catnipName Create a seeded randomizer function with seed + * @catnipName_Ru Cоздать функцию сидированного случайного числа с сидом * @catnipSaveReturn */ function createSeededRandomizer(seed: number): () => number; From 7e7dd284f8ddb9078faefac83da5aa0c7e78a189 Mon Sep 17 00:00:00 2001 From: Cosmo Myzrail Gorynych Date: Fri, 1 Nov 2024 18:13:29 +1200 Subject: [PATCH 04/21] :globe_with_meridians: Catnip: Translate Pointer catmod to Russian and add more human-readable English names --- app/data/ct.libs/pointer/types.d.ts | 90 +++++++++++++++++++++++++++-- 1 file changed, 86 insertions(+), 4 deletions(-) diff --git a/app/data/ct.libs/pointer/types.d.ts b/app/data/ct.libs/pointer/types.d.ts index 1a03523db..0a3ea3fbc 100644 --- a/app/data/ct.libs/pointer/types.d.ts +++ b/app/data/ct.libs/pointer/types.d.ts @@ -101,30 +101,55 @@ declare namespace pointer { * @catnipIgnore */ var released: IPointer[]; - /** The horizontal position at which the primary pointer is positioned. */ + /** + * The horizontal position at which the primary pointer is positioned. + * @catnipName pointer's x + * @catnipName_Ru x указателя + */ var x: number; - /** The vertical position at which the primary pointer is positioned. */ + /** + * The vertical position at which the primary pointer is positioned. + * @catnipName pointer's y + * @catnipName_Ru y указателя + */ var y: number; - /** The horizontal position at which the primary pointer is positioned, in UI space.*/ + /** + * The horizontal position at which the primary pointer is positioned, in UI space. + * @catnipName pointer's x for ui + * @catnipName_Ru x указателя для ui + */ var xui: number; - /** The vertical position at which the primary pointer is positioned, in UI space.*/ + /** + * The vertical position at which the primary pointer is positioned, in UI space. + * @catnipName pointer's y for ui + * @catnipName_Ru y указателя для ui + */ var yui: number; /** * The horizontal position of the primary pointer in the previous frame, * in gameplay coordinates. + * @catnipName pointer's previous x + * @catnipName_Ru предыдущий x указателя */ var xprev: number; /** * The vertical position of the primary pointer in the previous frame, * in gameplay coordinates. + * @catnipName pointer's previous y + * @catnipName_Ru предыдущий y указателя */ var yprev: number; /** + * * The horizontal position of the primary pointer in the previous frame, in UI coordinates. + * @catnipName pointer's previous x in ui + * @catnipName_Ru предыдущий x указателя в ui */ var xuiprev: number; /** * The vertical position of the primary pointer in the previous frame, in UI coordinates. + * @catnipName pointer's previous y in ui + * @catnipName_Ru предыдущий y указателя в ui */ var yuiprev: number; /** @@ -132,6 +157,8 @@ declare namespace pointer { * Note that it only changes when ct.pointer works in the locking mode. * The initial value of the locked pointer is set to the last known position * of the unlocked primary pointer. + * @catnipName locked pointer's x + * @catnipName_Ru x захвач. указателя */ var xlocked: number; /** @@ -139,16 +166,22 @@ declare namespace pointer { * Note that it only changes when ct.pointer works in the locking mode. * The initial value of the locked pointer is set to the last known position * of the unlocked primary pointer. + * @catnipName locked pointer's y + * @catnipName_Ru y захвач. указателя */ var ylocked: number; /** * The current movement speed of a locked pointer relative to UI space. * Note that it only changes when ct.pointer works in the locking mode. + * @catnipName locked pointer's x movement + * @catnipName_Ru движение по x захвач. указателя */ var xmovement: number; /** * The current movement speed of a locked pointer relative to UI space. * Note that it only changes when ct.pointer works in the locking mode. + * @catnipName locked pointer's y movement + * @catnipName_Ru движение по y захвач. указателя */ var ymovement: number; /** @@ -156,46 +189,62 @@ declare namespace pointer { * Note that this property is usually defined for special pointer types, * e.g. for graphic tablet's digital pens. * You will usually get 0.5 for mouse and touch events of regular devices. + * @catnipName pointer's pressure + * @catnipName_Ru нажим указателя */ var pressure: number; /** * A number that, with a proper bitmask, tells which buttons are currently pressed. * Use ct.pointer.isButtonPressed(buttonName, ct.pointer.buttons) to check * for specific buttons. + * @catnipName pressed buttons + * @catnipName_Ru нажатые кнопки */ var buttons: number; /** * The plane angle (in degrees, in the range of -90 to 90) * between the Y–Z plane and the plane containing both the pointer * (e.g. pen stylus) axis and the Y axis. + * @catnipName pointer's x tilt + * @catnipName_Ru наклон указателя по x */ var tiltX: number; /** * the plane angle (in degrees, in the range of -90 to 90) * between the X–Z plane and the plane containing both the pointer * (e.g. pen stylus) axis and the X axis. + * @catnipName pointer's y tilt + * @catnipName_Ru наклон указателя по y */ var tiltY: number; /** * The clockwise rotation of the pointer (e.g. pen stylus) around its major axis in degrees, * with a value in the range 0 to 359. + * @catnipName pointer's twist + * @catnipName_Ru поворот указателя */ var twist: number; /** * The size of the primary pointer, in UI coordinates. * Depending on the type of the pointer, this property may not be available * and will be equal to 0 or something close to 1. + * @catnipName pointer's width + * @catnipName_Ru ширина указателя */ var width: number; /** * The size of the primary pointer, in UI coordinates. * Depending on the type of the pointer, this property may not be available * and will be equal to 0 or something close to 1. + * @catnipName pointer's height + * @catnipName_Ru высота указателя */ var height: number; /** * The type of the pointer used most recently (the one that was pressed). * It usually equals to either 'mouse', 'touch', or 'pen'. + * @catnipName pointer's type + * @catnipName_Ru тип указателя */ var type: string; @@ -204,16 +253,25 @@ declare namespace pointer { * It can be used to reset the state of ct.pointer, but note that hover events * are reset as well meaning that pointers (like mouse) will report them only * when they become active again (for example, with a mouse click). + * + * @catnipName Clear pointers' events + * @catnipName_Ru Очистить события указателей */ function clear(): void; /** * Clears all the memorized pointer events that were released in the current frame. + * + * @catnipName Clear pointers' "released" event + * @catnipName_Ru Очистить события отпущенных указателей */ function clearReleased(): void; /** * Either returns the pointer that is currently colliding with the passed copy that exists * in gameplay coordinates, or returns `false` if there is no collision. * Collisions happen only if the pointer is currently held down. + * + * @catnipName pointer touches + * @catnipName_Ru указатель касается */ function collides( copy: Copy, @@ -224,6 +282,9 @@ declare namespace pointer { * Either returns the pointer that is currently colliding with the passed copy that exists * in UI coordinates, or returns `false` if there is no collision. * Collisions happen only if the pointer is currently held down. + * + * @catnipName pointer touches ui + * @catnipName_Ru указатель касается ui */ function collidesUi( copy: Copy, @@ -233,20 +294,41 @@ declare namespace pointer { /** * Either returns the pointer that is currently hovering over the passed copy that exists * in gameplay coordinates, or returns `false` if there is no such pointers. + * + * @catnipName pointer hovers + * @catnipName_Ru указатель над */ function hovers(copy: Copy, pointer?: IPointer): false | IPointer; /** * Either returns the pointer that is currently hovering over the passed copy that exists * in UI coordinates, or returns `false` if there is no such pointers. + * + * @catnipName pointer hovers ui + * @catnipName_Ru указатель над ui */ function hoversUi(copy: Copy, pointer?: IPointer): false | IPointer; + /** + * @catnipName is pointer's button pressed + * @catnipName_Ru кнопка указателя нажата + */ function isButtonPressed(button: PointerButtonName, pointer: IPointer): boolean; + /** + * @catnipName Lock the pointer + * @catnipName_Ru Заблокировать указатель + */ function lock(): void; + /** + * @catnipName Unlock the pointer + * @catnipName_Ru Разблокировать указатель + */ function unlock(): void; /** * Equals to `true` when the pointer is locked. * Note that the pointer can still be unlocked while the locking mode is on, * for example after a player pressed ESC key or switched to a different window. + * + * @catnipName is pointer locked + * @catnipName_Ru указатель заблокирован */ var locked: boolean; } From 4ffb6a56c7fdd46d505e213c9a307a7eed545c4b Mon Sep 17 00:00:00 2001 From: Cosmo Myzrail Gorynych Date: Fri, 1 Nov 2024 19:26:18 +1200 Subject: [PATCH 05/21] :bug: Fix minor styling issues on the homepage --- src/styl/tags/home-news.styl | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/styl/tags/home-news.styl b/src/styl/tags/home-news.styl index 4d904b68d..e4548429a 100644 --- a/src/styl/tags/home-news.styl +++ b/src/styl/tags/home-news.styl @@ -1,15 +1,22 @@ home-news display block + h2 + color white + if (themeDark) + color act .&-aNewsRow position relative align-items center gap 1rem + margin-bottom 1rem img flex 0 0 auto height 128px p margin 0.25rem 0 1rem line-height 1.5 + h2 + color acttext .&-aNewsBg position absolute top 0 @@ -23,6 +30,7 @@ home-news filter blur(5px) opacity 0.35 .&-FeaturedGames, .&-LearningResources + margin-top 0.5rem .Cards grid-template-columns repeat(auto-fill, minmax(21em, 1fr)) align-items start From 7f015458f06ca0971508cf4b0cacc9ce80a88c0d Mon Sep 17 00:00:00 2001 From: Cosmo Myzrail Gorynych Date: Sat, 2 Nov 2024 20:07:49 +1200 Subject: [PATCH 06/21] :bug: Add missing translation keys to Math operators --- app/data/i18n/English.json | 19 ++++++++++++++++++- app/data/i18n/Russian.json | 17 +++++++++++++++++ src/node_requires/catnip/stdLib/math.ts | 4 ++-- 3 files changed, 37 insertions(+), 3 deletions(-) diff --git a/app/data/i18n/English.json b/app/data/i18n/English.json index ede759614..25d3a1002 100644 --- a/app/data/i18n/English.json +++ b/app/data/i18n/English.json @@ -563,7 +563,24 @@ "delete from storage": "Delete from storage the key", "load from storage": "load from storage from key", "is key in storage": "is key in storage", - "owning room": "copy's owning room" + "owning room": "copy's owning room", + "math abs": "absolute", + "math sign": "sign of", + "math floor": "floor", + "math ceil": "ceil", + "math round": "round", + "math sqrt": "square root", + "math sin": "sin", + "math cos": "cos", + "math tan": "tan", + "math asin": "asin", + "math acos": "acos", + "math atan": "atan", + "math atan2": "atan2", + "math pow": "power", + "math log": "log", + "math min": "minimum of", + "math max": "maximum of" }, "blockDisplayNames": { "write": "Write", diff --git a/app/data/i18n/Russian.json b/app/data/i18n/Russian.json index 373920281..0a3f195e5 100644 --- a/app/data/i18n/Russian.json +++ b/app/data/i18n/Russian.json @@ -502,6 +502,23 @@ "load from storage": "загрузить из ключа", "is key in storage": "ключ в хранилище?", "owning room": "комната-родитель копии", + "math abs": "положительное", + "math sign": "знак", + "math floor": "окр. до нижнего", + "math ceil": "окр. до верхнего", + "math round": "округлить", + "math sqrt": "квадратный корень", + "math sin": "sin", + "math cos": "cos", + "math tan": "tan", + "math asin": "asin", + "math acos": "acos", + "math atan": "atan", + "math atan2": "atan2", + "math pow": "степень", + "math log": "log", + "math min": "минимум из", + "math max": "максимум из", "x prev": "предыдущий x", "y prev": "предыдущий y", "content type entries": "записи контента" diff --git a/src/node_requires/catnip/stdLib/math.ts b/src/node_requires/catnip/stdLib/math.ts index 8a48ce572..7760f4e39 100644 --- a/src/node_requires/catnip/stdLib/math.ts +++ b/src/node_requires/catnip/stdLib/math.ts @@ -48,7 +48,7 @@ const makeMathUnary = (operator: string): IBlockComputedDeclaration => ({ type: 'computed', typeHint: 'number', hideIcon: true, - i18nKey: operator, + i18nKey: 'math ' + operator, jsTemplate: (vals) => `Math.${operator}(${vals.a})`, lib: 'core.math', pieces: [{ @@ -66,7 +66,7 @@ const makeMathBinary = (operator: string): IBlockComputedDeclaration => ({ type: 'computed', typeHint: 'number', hideIcon: true, - i18nKey: operator, + i18nKey: 'math ' + operator, jsTemplate: (vals) => `Math.${operator}(${vals.a}, ${vals.b})`, lib: 'core.math', pieces: [{ From 58692741284fb9ffd6de6a6cc166f42826e967ff Mon Sep 17 00:00:00 2001 From: Cosmo Myzrail Gorynych Date: Sat, 2 Nov 2024 20:12:16 +1200 Subject: [PATCH 07/21] :zap: Add mutators to timer blocks --- src/node_requires/catnip/stdLib/timers.ts | 28 +++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/src/node_requires/catnip/stdLib/timers.ts b/src/node_requires/catnip/stdLib/timers.ts index a854623c4..27b8f6a6c 100644 --- a/src/node_requires/catnip/stdLib/timers.ts +++ b/src/node_requires/catnip/stdLib/timers.ts @@ -37,11 +37,35 @@ const makeTimerGetter = (index: number): IBlockComputedDeclaration => ({ }); const blocks: (IBlockCommandDeclaration | IBlockComputedDeclaration)[] = []; +const setters: IBlockCommandDeclaration[] = [], + getters: IBlockComputedDeclaration[] = []; + for (let i = 1; i <= 6; i++) { - blocks.push(makeTimerSetter(i)); + const block = makeTimerSetter(i); + blocks.push(block); + setters.push(block); } for (let i = 1; i <= 6; i++) { - blocks.push(makeTimerGetter(i)); + const block = makeTimerGetter(i); + blocks.push(block); + getters.push(block); +} + +for (const getter of getters) { + getter.mutators = getters + .filter(m => m.code !== getter.code) + .map(g => ({ + lib: g.lib, + code: g.code + })); +} +for (const setter of setters) { + setter.mutators = setters + .filter(m => m.code !== setter.code) + .map(s => ({ + lib: s.lib, + code: s.code + })); } export default blocks; From 0c4194bebde1d3827d26f4df79dfa7e862b56d0e Mon Sep 17 00:00:00 2001 From: Cosmo Myzrail Gorynych Date: Sat, 2 Nov 2024 20:20:28 +1200 Subject: [PATCH 08/21] :zap: Ct.js now checks whether recovery file actually differs from the regular project file --- src/node_requires/resources/projects/index.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/node_requires/resources/projects/index.ts b/src/node_requires/resources/projects/index.ts index d09b22df1..2bbdd14d2 100644 --- a/src/node_requires/resources/projects/index.ts +++ b/src/node_requires/resources/projects/index.ts @@ -306,6 +306,16 @@ const openProject = async (proj: string): Promise> void 0; } if (recoveryStat && recoveryStat.isFile()) { + // Make sure recovery and target files are not the same + const [recoveryContent, targetContent] = await Promise.all([ + fs.readFile(proj + '.recovery', 'utf8'), + fs.readFile(proj, 'utf8') + ]); + if (recoveryContent === targetContent) { + // Files match, load as usual + return readProjectFile(proj); + } + // Files differ, ask user if they want to load the recovery file const targetStat = await fs.stat(proj); const voc = getLanguageJSON().intro.recovery; const userResponse = await window.alertify From aaa17816a2e1493f2e897e4254b2d1c84fc76656 Mon Sep 17 00:00:00 2001 From: Cosmo Myzrail Gorynych Date: Sat, 2 Nov 2024 20:41:57 +1200 Subject: [PATCH 09/21] :bug: Fix ct.js saving projects' scripts with CRLF sequence instead of LF, which caused them to be one-lined in the .ict file, making merging changes harder for Git users. You can fix the existing scripts by cutting and pasting their contents back. --- src/node_requires/resources/projects/scripts.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/node_requires/resources/projects/scripts.ts b/src/node_requires/resources/projects/scripts.ts index 6329ee4c0..6d52328a5 100644 --- a/src/node_requires/resources/projects/scripts.ts +++ b/src/node_requires/resources/projects/scripts.ts @@ -8,10 +8,12 @@ export const dropScriptModel = (script: Script) => { }; /** This method is to be used when loading a project or creating a new script */ export const addScriptModel = (script: Script) => { - scriptModels.set(script, monaco.editor.createModel( + const model = monaco.editor.createModel( script.code, 'typescript' - )); + ); + model.setEOL(monaco.editor.EndOfLineSequence.LF); + scriptModels.set(script, model); }; /** Resets the monaco file models and loads in all the script */ export const loadScriptModels = (project: IProject) => { From 3b01e04e6b49fe8564d8838f9ac5e21843412a8e Mon Sep 17 00:00:00 2001 From: Cosmo Myzrail Gorynych Date: Sat, 2 Nov 2024 21:52:29 +1200 Subject: [PATCH 10/21] :zap: Catnip: Add mutators for "action is down/pressed/released" blocks --- src/node_requires/catnip/stdLib/actions.ts | 27 +++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/src/node_requires/catnip/stdLib/actions.ts b/src/node_requires/catnip/stdLib/actions.ts index 27f123677..84fbf7662 100644 --- a/src/node_requires/catnip/stdLib/actions.ts +++ b/src/node_requires/catnip/stdLib/actions.ts @@ -27,7 +27,14 @@ const blocks: (IBlockCommandDeclaration | IBlockComputedDeclaration)[] = [{ typeHint: 'string', key: 'action' }], - jsTemplate: (values) => `actions[${values.action}].pressed` + jsTemplate: (values) => `actions[${values.action}].pressed`, + mutators: [{ + code: 'action down', + lib: 'core.actions' + }, { + code: 'action released', + lib: 'core.actions' + }] }, { name: 'is action down', type: 'computed', @@ -42,7 +49,14 @@ const blocks: (IBlockCommandDeclaration | IBlockComputedDeclaration)[] = [{ typeHint: 'string', key: 'action' }], - jsTemplate: (values) => `actions[${values.action}].down` + jsTemplate: (values) => `actions[${values.action}].down`, + mutators: [{ + code: 'action pressed', + lib: 'core.actions' + }, { + code: 'action released', + lib: 'core.actions' + }] }, { name: 'is action released', type: 'computed', @@ -57,7 +71,14 @@ const blocks: (IBlockCommandDeclaration | IBlockComputedDeclaration)[] = [{ typeHint: 'string', key: 'action' }], - jsTemplate: (values) => `actions[${values.action}].released` + jsTemplate: (values) => `actions[${values.action}].released`, + mutators: [{ + code: 'action down', + lib: 'core.actions' + }, { + code: 'action pressed', + lib: 'core.actions' + }] }]; export default blocks; From 6f6ad0d64e7fd38689255c0788663344c1cea821 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 3 Nov 2024 04:49:24 +0000 Subject: [PATCH 11/21] :arrow_up: Bump axios from 1.6.8 to 1.7.7 Bumps [axios](https://github.com/axios/axios) from 1.6.8 to 1.7.7. - [Release notes](https://github.com/axios/axios/releases) - [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md) - [Commits](https://github.com/axios/axios/compare/v1.6.8...v1.7.7) --- updated-dependencies: - dependency-name: axios dependency-type: indirect ... Signed-off-by: dependabot[bot] --- package-lock.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4d43e55b7..a3c181368 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "ctjsbuildenvironment", - "version": "5.1.0", + "version": "5.2.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "ctjsbuildenvironment", - "version": "5.1.0", + "version": "5.2.0", "license": "MIT", "dependencies": { "@capacitor/cli": "^5.5.0", @@ -4224,9 +4224,9 @@ } }, "node_modules/axios": { - "version": "1.6.8", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz", - "integrity": "sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==", + "version": "1.7.7", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz", + "integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==", "dev": true, "dependencies": { "follow-redirects": "^1.15.6", @@ -26426,9 +26426,9 @@ } }, "axios": { - "version": "1.6.8", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz", - "integrity": "sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==", + "version": "1.7.7", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz", + "integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==", "dev": true, "requires": { "follow-redirects": "^1.15.6", From cd454e99e3ee110b5ea9dc39b9b636c3daf06188 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 3 Nov 2024 04:49:13 +0000 Subject: [PATCH 12/21] :arrow_up: Bump path-to-regexp and serve-handler Bumps [path-to-regexp](https://github.com/pillarjs/path-to-regexp) to 3.3.0 and updates ancestor dependency [serve-handler](https://github.com/vercel/serve-handler). These dependencies need to be updated together. Updates `path-to-regexp` from 2.2.1 to 3.3.0 - [Release notes](https://github.com/pillarjs/path-to-regexp/releases) - [Changelog](https://github.com/pillarjs/path-to-regexp/blob/master/History.md) - [Commits](https://github.com/pillarjs/path-to-regexp/compare/v2.2.1...v3.3.0) Updates `serve-handler` from 6.1.5 to 6.1.6 - [Release notes](https://github.com/vercel/serve-handler/releases) - [Commits](https://github.com/vercel/serve-handler/compare/6.1.5...6.1.6) --- updated-dependencies: - dependency-name: path-to-regexp dependency-type: indirect - dependency-name: serve-handler dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- package-lock.json | 60 ++++++++++++----------------------------------- package.json | 2 +- 2 files changed, 16 insertions(+), 46 deletions(-) diff --git a/package-lock.json b/package-lock.json index a3c181368..c6110158f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -42,7 +42,7 @@ "qreator": "^9.1.0", "resedit": "^2.0.2", "riot": "3.6.1", - "serve-handler": "^6.1.5", + "serve-handler": "^6.1.6", "sucrase": "^3.25.0", "terser": "^5.14.2", "ttf2woff": "^2.0.2", @@ -8643,19 +8643,6 @@ "resolved": "https://registry.npmjs.org/fast-plist/-/fast-plist-0.1.3.tgz", "integrity": "sha512-d9cEfo/WcOezgPLAC/8t8wGb6YOD6JTCPMw2QcG2nAdFmyY+9rTUizCTaGjIZAloWENTEUMAPpkUAIJJJ0i96A==" }, - "node_modules/fast-url-parser": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/fast-url-parser/-/fast-url-parser-1.1.3.tgz", - "integrity": "sha512-5jOCVXADYNuRkKFzNJ0dCCewsZiYo0dz8QNYljkOpFC6r2U4OBmKtvm/Tsuh4w1YYdDqDb31a8TVhBJ2OJKdqQ==", - "dependencies": { - "punycode": "^1.3.2" - } - }, - "node_modules/fast-url-parser/node_modules/punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==" - }, "node_modules/fastest-levenshtein": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz", @@ -16622,9 +16609,9 @@ } }, "node_modules/path-to-regexp": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-2.2.1.tgz", - "integrity": "sha512-gu9bD6Ta5bwGrrU8muHzVOBFFREpp2iRkVfhBJahwJ6p6Xw20SjT0MxLnwkjOibQmGSYhiUnf2FLe7k+jcFmGQ==" + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-3.3.0.tgz", + "integrity": "sha512-qyCH421YQPS2WFDxDjftfc1ZR5WKQzVzqsp4n9M2kQhVOo/ByahFoUNJfl58kOcEGfQ//7weFTDhm+ss8Ecxgw==" }, "node_modules/path-type": { "version": "1.1.0", @@ -20240,17 +20227,16 @@ } }, "node_modules/serve-handler": { - "version": "6.1.5", - "resolved": "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.5.tgz", - "integrity": "sha512-ijPFle6Hwe8zfmBxJdE+5fta53fdIY0lHISJvuikXB3VYFafRjMRpOffSPvCYsbKyBA7pvy9oYr/BT1O3EArlg==", + "version": "6.1.6", + "resolved": "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.6.tgz", + "integrity": "sha512-x5RL9Y2p5+Sh3D38Fh9i/iQ5ZK+e4xuXRd/pGbM4D13tgo/MGwbttUk8emytcr1YYzBYs+apnUngBDFYfpjPuQ==", "dependencies": { "bytes": "3.0.0", "content-disposition": "0.5.2", - "fast-url-parser": "1.1.3", "mime-types": "2.1.18", "minimatch": "3.1.2", "path-is-inside": "1.0.2", - "path-to-regexp": "2.2.1", + "path-to-regexp": "3.3.0", "range-parser": "1.2.0" } }, @@ -29882,21 +29868,6 @@ "resolved": "https://registry.npmjs.org/fast-plist/-/fast-plist-0.1.3.tgz", "integrity": "sha512-d9cEfo/WcOezgPLAC/8t8wGb6YOD6JTCPMw2QcG2nAdFmyY+9rTUizCTaGjIZAloWENTEUMAPpkUAIJJJ0i96A==" }, - "fast-url-parser": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/fast-url-parser/-/fast-url-parser-1.1.3.tgz", - "integrity": "sha512-5jOCVXADYNuRkKFzNJ0dCCewsZiYo0dz8QNYljkOpFC6r2U4OBmKtvm/Tsuh4w1YYdDqDb31a8TVhBJ2OJKdqQ==", - "requires": { - "punycode": "^1.3.2" - }, - "dependencies": { - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==" - } - } - }, "fastest-levenshtein": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz", @@ -36004,9 +35975,9 @@ } }, "path-to-regexp": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-2.2.1.tgz", - "integrity": "sha512-gu9bD6Ta5bwGrrU8muHzVOBFFREpp2iRkVfhBJahwJ6p6Xw20SjT0MxLnwkjOibQmGSYhiUnf2FLe7k+jcFmGQ==" + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-3.3.0.tgz", + "integrity": "sha512-qyCH421YQPS2WFDxDjftfc1ZR5WKQzVzqsp4n9M2kQhVOo/ByahFoUNJfl58kOcEGfQ//7weFTDhm+ss8Ecxgw==" }, "path-type": { "version": "1.1.0", @@ -38754,17 +38725,16 @@ } }, "serve-handler": { - "version": "6.1.5", - "resolved": "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.5.tgz", - "integrity": "sha512-ijPFle6Hwe8zfmBxJdE+5fta53fdIY0lHISJvuikXB3VYFafRjMRpOffSPvCYsbKyBA7pvy9oYr/BT1O3EArlg==", + "version": "6.1.6", + "resolved": "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.6.tgz", + "integrity": "sha512-x5RL9Y2p5+Sh3D38Fh9i/iQ5ZK+e4xuXRd/pGbM4D13tgo/MGwbttUk8emytcr1YYzBYs+apnUngBDFYfpjPuQ==", "requires": { "bytes": "3.0.0", "content-disposition": "0.5.2", - "fast-url-parser": "1.1.3", "mime-types": "2.1.18", "minimatch": "3.1.2", "path-is-inside": "1.0.2", - "path-to-regexp": "2.2.1", + "path-to-regexp": "3.3.0", "range-parser": "1.2.0" }, "dependencies": { diff --git a/package.json b/package.json index d8c9393c3..e36a0f5d4 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "qreator": "^9.1.0", "resedit": "^2.0.2", "riot": "3.6.1", - "serve-handler": "^6.1.5", + "serve-handler": "^6.1.6", "sucrase": "^3.25.0", "terser": "^5.14.2", "ttf2woff": "^2.0.2", From 4cadb966b72f4f63e3e6357b8dfd6c6012f3d405 Mon Sep 17 00:00:00 2001 From: Cosmo Myzrail Gorynych Date: Mon, 4 Nov 2024 00:21:14 +1200 Subject: [PATCH 13/21] :zap: Room editor: you can now navigate around with Spacebar + Left mouse button Closes what irritates #545 --- src/node_requires/roomEditor/IRoomEditorRiotTag.d.ts | 1 + src/node_requires/roomEditor/interactions/camera/move.ts | 5 +++-- src/riotTags/editors/room-editor/room-editor.tag | 6 ++++++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/node_requires/roomEditor/IRoomEditorRiotTag.d.ts b/src/node_requires/roomEditor/IRoomEditorRiotTag.d.ts index 6ad4116e0..b8f584657 100644 --- a/src/node_requires/roomEditor/IRoomEditorRiotTag.d.ts +++ b/src/node_requires/roomEditor/IRoomEditorRiotTag.d.ts @@ -30,6 +30,7 @@ export interface IRoomEditorRiotTag extends IRiotTag { gridOn: boolean; freePlacementMode: boolean; controlMode: boolean; + spacebarMode: boolean; currentTool: tool; currentTemplate: ITemplate | -1; setTool(tool: tool): () => void; diff --git a/src/node_requires/roomEditor/interactions/camera/move.ts b/src/node_requires/roomEditor/interactions/camera/move.ts index c06a7b60a..91767205f 100644 --- a/src/node_requires/roomEditor/interactions/camera/move.ts +++ b/src/node_requires/roomEditor/interactions/camera/move.ts @@ -16,9 +16,10 @@ interface IMoveCameraAffixedData { const moveCameraOnWheelPress: IRoomEditorInteraction = { ifListener: 'pointerdown', if(e: PIXI.FederatedPointerEvent) { - // Checks for a pressed mouse wheel + // Checks for a pressed mouse wheel, or Alt+Shift dragging, or Spacebar return e.button === 1 || - (e.altKey && e.shiftKey); + (e.altKey && e.shiftKey) || + this.riotEditor.spacebarMode; }, listeners: { pointerdown(e: PIXI.FederatedPointerEvent, roomTag, affixedData) { diff --git a/src/riotTags/editors/room-editor/room-editor.tag b/src/riotTags/editors/room-editor/room-editor.tag index eceb25261..c91fd9f87 100644 --- a/src/riotTags/editors/room-editor/room-editor.tag +++ b/src/riotTags/editors/room-editor/room-editor.tag @@ -218,6 +218,9 @@ room-editor.aPanel.aView(data-hotkey-scope="{asset.uid}") e.preventDefault(); } else if (e.key === 'Shift') { this.controlMode = false; + } else if (e.key === ' ') { + this.spacebarMode = true; + e.preventDefault(); } }; const modifiersUpListener = e => { @@ -233,6 +236,9 @@ room-editor.aPanel.aView(data-hotkey-scope="{asset.uid}") } else if (e.key === 'Control' || e.key.Meta) { this.controlMode = false; e.preventDefault(); + } else if (e.key === ' ') { + this.spacebarMode = false; + e.preventDefault(); } }; const blurListener = () => { From 7869c432992824e20c6e7fef82529f84e5c67762 Mon Sep 17 00:00:00 2001 From: Cosmo Myzrail Gorynych Date: Mon, 4 Nov 2024 00:24:25 +1200 Subject: [PATCH 14/21] :bug: Fields with invalid values should be outlined red --- src/styl/inputs.styl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/styl/inputs.styl b/src/styl/inputs.styl index b34694d4a..57732947f 100644 --- a/src/styl/inputs.styl +++ b/src/styl/inputs.styl @@ -35,6 +35,8 @@ textarea {transshort} &:focus border-color acttext + &:invalid + border-color error .compact padding 0.2em 0.3em line-height 1 From 6d0a4e955d36e2c004d734982664d22b94934a22 Mon Sep 17 00:00:00 2001 From: Cosmo Myzrail Gorynych Date: Mon, 4 Nov 2024 00:33:52 +1200 Subject: [PATCH 15/21] :bug: Make sure there are no special characters in the project name when creating one Closes #543 --- app/data/i18n/English.json | 2 +- app/data/i18n/Russian.json | 2 +- src/riotTags/project-selector.tag | 5 ++++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/app/data/i18n/English.json b/app/data/i18n/English.json index 25d3a1002..a0ec52627 100644 --- a/app/data/i18n/English.json +++ b/app/data/i18n/English.json @@ -798,7 +798,7 @@ "projectName": "Name:", "language": "Coding language:", "saveFolder": "Project's folder:", - "input": "(letters and digits only)", + "input": "(latin letters, underscore, and digits only)", "selectProjectFolder": "Select a folder in which to store your project", "nameError": "Wrong project name", "languageError": "You must specify a programming language" diff --git a/app/data/i18n/Russian.json b/app/data/i18n/Russian.json index 0a3f195e5..56a32fc89 100644 --- a/app/data/i18n/Russian.json +++ b/app/data/i18n/Russian.json @@ -678,7 +678,7 @@ "loading": "Подождите, коты набирают скорость света…", "loadingProject": "Загрузка проекта…", "newProject": { - "input": "Имя проекта, латиница и цифры…", + "input": "Латиница, нижний пробел и цифры…", "selectProjectFolder": "Выберите папку, в которой сохранить проект", "nameError": "Ошибка в имени проекта", "header": "Создать новый", diff --git a/src/riotTags/project-selector.tag b/src/riotTags/project-selector.tag index b49af51ce..2e977e383 100644 --- a/src/riotTags/project-selector.tag +++ b/src/riotTags/project-selector.tag @@ -70,6 +70,7 @@ project-selector placeholder="{voc.newProject.input}" pattern="[a-zA-Z_0-9]\\{1,\\}" oninput="{setProjectName}" + value="{projectName}" width="20" maxlength="64" ) @@ -408,11 +409,13 @@ project-selector }; this.setProjectName = e => { this.projectName = e.target.value.trim(); + this.projectName = this.projectName.replace(/[^a-zA-Z_0-9]/g, ''); + e.target.value = this.projectName; }; /** A button listener for triggering a project creation process. */ this.createProject = () => { const codename = this.projectName; - if (codename.length === 0) { + if (codename.length === 0 || /[^a-zA-Z_0-9]/.test(codename)) { alertify.error(this.voc.newProject.nameError); return; } From e4bd50d798a9b919d817948bfe37ffa2defbad6d Mon Sep 17 00:00:00 2001 From: Cosmo Myzrail Gorynych Date: Mon, 4 Nov 2024 00:45:49 +1200 Subject: [PATCH 16/21] :bug: Fix random.dice trying to convert string values to floats Closes #544 --- app/data/ct.libs/random/README.md | 1 + app/data/ct.libs/random/index.js | 9 +++++---- app/data/ct.libs/random/types.d.ts | 6 +++--- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/app/data/ct.libs/random/README.md b/app/data/ct.libs/random/README.md index 69c84e924..174b56c17 100644 --- a/app/data/ct.libs/random/README.md +++ b/app/data/ct.libs/random/README.md @@ -8,6 +8,7 @@ Returns a random float value between 0 and x, exclusive. ### `random.dice(dice1,dice2,...diceN)` Returns a random given argument. +When given just one string value, the string will be split by `,` separator and a random item will be returned. ### `random.range(x1, x2)` Returns a random float value between `x1` and `x2`, exclusive. diff --git a/app/data/ct.libs/random/index.js b/app/data/ct.libs/random/index.js index a7489821f..d247cf02a 100644 --- a/app/data/ct.libs/random/index.js +++ b/app/data/ct.libs/random/index.js @@ -13,9 +13,7 @@ Object.assign(random, { dice(...variants) { const dices = processRandomInput(variants); if (Array.isArray(dices) && dices.length > 0) { - const result = dices[Math.floor(Math.random() * dices.length)]; - const parsedResult = parseFloat(result); - return isNaN(parsedResult) ? result : parsedResult; + return dices[Math.floor(Math.random() * dices.length)]; } return null; }, @@ -51,7 +49,10 @@ Object.assign(random, { return Math.random() * 360; }, coord() { - return [Math.floor(Math.random() * camera.width), Math.floor(Math.random() * camera.height)]; + return [ + Math.floor(Math.random() * camera.width), + Math.floor(Math.random() * camera.height) + ]; }, chance(x, y) { if (y) { diff --git a/app/data/ct.libs/random/types.d.ts b/app/data/ct.libs/random/types.d.ts index 0c686cbac..8c99beb5c 100644 --- a/app/data/ct.libs/random/types.d.ts +++ b/app/data/ct.libs/random/types.d.ts @@ -11,9 +11,9 @@ interface IPoint { declare function random(x: number): number; declare namespace random { /** - * Returns random argument from comma separated arguments (without spaces): - * Numbers will return float. Words will return string. These can be mixed. - * + * Returns random argument from comma separated arguments (without spaces), + * or a random argument when given several arguments. + * * @catnipName random from list * @catnipName_Ru случайное из списка */ From 54ae869ae96b9d2fb61b3fa7bc7163ec34c029db Mon Sep 17 00:00:00 2001 From: Cosmo Myzrail Gorynych Date: Mon, 4 Nov 2024 00:52:32 +1200 Subject: [PATCH 17/21] :bookmark: Bump version number --- app/package-lock.json | 4 ++-- app/package.json | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/package-lock.json b/app/package-lock.json index a2f6340b3..6380d43df 100644 --- a/app/package-lock.json +++ b/app/package-lock.json @@ -1,12 +1,12 @@ { "name": "ctjs", - "version": "5.1.0", + "version": "5.2.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "ctjs", - "version": "5.1.0", + "version": "5.2.1", "license": "MIT", "dependencies": { "@neutralinojs/neu": "^11.0.1", diff --git a/app/package.json b/app/package.json index cd527347a..2fb466709 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": "5.2.0", + "version": "5.2.1", "homepage": "https://ctjs.rocks/", "author": { "name": "Cosmo Myzrail Gorynych", diff --git a/package-lock.json b/package-lock.json index c6110158f..d18f7e09b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "ctjsbuildenvironment", - "version": "5.2.0", + "version": "5.2.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "ctjsbuildenvironment", - "version": "5.2.0", + "version": "5.2.1", "license": "MIT", "dependencies": { "@capacitor/cli": "^5.5.0", diff --git a/package.json b/package.json index e36a0f5d4..4ed63fb52 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ctjsbuildenvironment", - "version": "5.2.0", + "version": "5.2.1", "description": "", "directories": { "doc": "docs" From 31062047a17a6916fd9ca32bdf7f87584482b77d Mon Sep 17 00:00:00 2001 From: Cosmo Myzrail Gorynych Date: Mon, 4 Nov 2024 00:53:48 +1200 Subject: [PATCH 18/21] :bento: Pull the latest docs --- docs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs b/docs index 46e970587..fdab0a3d7 160000 --- a/docs +++ b/docs @@ -1 +1 @@ -Subproject commit 46e970587c902b6a8a52b0b41cb7855896005b0a +Subproject commit fdab0a3d7fd8654b50ebdc3abf921b90cb9af0f4 From 4ea9b0e2836c3d4beb9fdfc597ec8d16596a2134 Mon Sep 17 00:00:00 2001 From: Cosmo Myzrail Gorynych Date: Mon, 4 Nov 2024 01:06:48 +1200 Subject: [PATCH 19/21] :bug: Catnip: Properly mark the required arguments in the Logic category --- src/node_requires/catnip/stdLib/logic.ts | 54 ++++++++++++++++-------- 1 file changed, 36 insertions(+), 18 deletions(-) diff --git a/src/node_requires/catnip/stdLib/logic.ts b/src/node_requires/catnip/stdLib/logic.ts index e80b410d8..eb2fc410c 100644 --- a/src/node_requires/catnip/stdLib/logic.ts +++ b/src/node_requires/catnip/stdLib/logic.ts @@ -14,7 +14,8 @@ const blocks: (IBlockCommandDeclaration | IBlockComputedDeclaration)[] = [{ pieces: [{ type: 'argument', key: 'condition', - typeHint: 'boolean' + typeHint: 'boolean', + required: true }, { placeholder: 'doNothing', type: 'blocks', @@ -38,7 +39,8 @@ const blocks: (IBlockCommandDeclaration | IBlockComputedDeclaration)[] = [{ pieces: [{ type: 'argument', key: 'condition', - typeHint: 'boolean' + typeHint: 'boolean', + required: true }, { placeholder: 'doNothing', type: 'blocks', @@ -72,7 +74,8 @@ const blocks: (IBlockCommandDeclaration | IBlockComputedDeclaration)[] = [{ pieces: [{ type: 'argument', key: 'condition', - typeHint: 'boolean' + typeHint: 'boolean', + required: true }, { type: 'blocks', key: 'body' @@ -95,7 +98,8 @@ const blocks: (IBlockCommandDeclaration | IBlockComputedDeclaration)[] = [{ pieces: [{ type: 'argument', key: 'N', - typeHint: 'number' + typeHint: 'number', + required: true }, { type: 'label', name: 'times', @@ -109,7 +113,8 @@ const blocks: (IBlockCommandDeclaration | IBlockComputedDeclaration)[] = [{ }, { type: 'argument', key: 'variableName', - typeHint: 'wildcard' + typeHint: 'wildcard', + required: true }, { type: 'blocks', key: 'body' @@ -127,7 +132,8 @@ const blocks: (IBlockCommandDeclaration | IBlockComputedDeclaration)[] = [{ pieces: [{ type: 'argument', key: 'variableName', - typeHint: 'wildcard' + typeHint: 'wildcard', + required: true }, { type: 'label', name: 'of array', @@ -135,7 +141,8 @@ const blocks: (IBlockCommandDeclaration | IBlockComputedDeclaration)[] = [{ }, { type: 'argument', key: 'array', - typeHint: 'wildcard' + typeHint: 'wildcard', + required: true }, { type: 'blocks', key: 'body' @@ -162,7 +169,8 @@ const blocks: (IBlockCommandDeclaration | IBlockComputedDeclaration)[] = [{ pieces: [{ type: 'argument', key: 'a', - typeHint: 'boolean' + typeHint: 'boolean', + required: true }, { type: 'label', name: 'and', @@ -170,7 +178,8 @@ const blocks: (IBlockCommandDeclaration | IBlockComputedDeclaration)[] = [{ }, { type: 'argument', key: 'b', - typeHint: 'boolean' + typeHint: 'boolean', + required: true }], jsTemplate: (args) => `(${args.a} && ${args.b})` }, { @@ -186,7 +195,8 @@ const blocks: (IBlockCommandDeclaration | IBlockComputedDeclaration)[] = [{ pieces: [{ type: 'argument', key: 'a', - typeHint: 'boolean' + typeHint: 'boolean', + required: true }, { type: 'label', name: 'and', @@ -194,7 +204,8 @@ const blocks: (IBlockCommandDeclaration | IBlockComputedDeclaration)[] = [{ }, { type: 'argument', key: 'b', - typeHint: 'boolean' + typeHint: 'boolean', + required: true }, { type: 'label', name: 'and', @@ -202,7 +213,8 @@ const blocks: (IBlockCommandDeclaration | IBlockComputedDeclaration)[] = [{ }, { type: 'argument', key: 'c', - typeHint: 'boolean' + typeHint: 'boolean', + required: true }], jsTemplate: (args) => `(${args.a} && ${args.b} && ${args.c})` }, { @@ -218,7 +230,8 @@ const blocks: (IBlockCommandDeclaration | IBlockComputedDeclaration)[] = [{ pieces: [{ type: 'argument', key: 'a', - typeHint: 'boolean' + typeHint: 'boolean', + required: true }, { type: 'label', name: 'or', @@ -226,7 +239,8 @@ const blocks: (IBlockCommandDeclaration | IBlockComputedDeclaration)[] = [{ }, { type: 'argument', key: 'b', - typeHint: 'boolean' + typeHint: 'boolean', + required: true }], jsTemplate: (args) => `(${args.a} || ${args.b})` }, { @@ -242,7 +256,8 @@ const blocks: (IBlockCommandDeclaration | IBlockComputedDeclaration)[] = [{ pieces: [{ type: 'argument', key: 'a', - typeHint: 'boolean' + typeHint: 'boolean', + required: true }, { type: 'label', name: 'or', @@ -250,7 +265,8 @@ const blocks: (IBlockCommandDeclaration | IBlockComputedDeclaration)[] = [{ }, { type: 'argument', key: 'b', - typeHint: 'boolean' + typeHint: 'boolean', + required: true }, { type: 'label', name: 'or', @@ -258,7 +274,8 @@ const blocks: (IBlockCommandDeclaration | IBlockComputedDeclaration)[] = [{ }, { type: 'argument', key: 'c', - typeHint: 'boolean' + typeHint: 'boolean', + required: true }], jsTemplate: (args) => `(${args.a} || ${args.b} || ${args.c})` }, { @@ -275,7 +292,8 @@ const blocks: (IBlockCommandDeclaration | IBlockComputedDeclaration)[] = [{ pieces: [{ type: 'argument', key: 'a', - typeHint: 'boolean' + typeHint: 'boolean', + required: true }], jsTemplate: (args) => `!${args.a}` }, { From 8cecdabdfafa718ddbdf3ec3b896558778999fb1 Mon Sep 17 00:00:00 2001 From: Cosmo Myzrail Gorynych Date: Mon, 4 Nov 2024 01:15:17 +1200 Subject: [PATCH 20/21] :bug: Fix inability to compile Script assets with Catnip code --- src/node_requires/exporter/scripts.ts | 44 +++++++++++++++++++-------- 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/src/node_requires/exporter/scripts.ts b/src/node_requires/exporter/scripts.ts index ff2c02238..4c5c4db9a 100644 --- a/src/node_requires/exporter/scripts.ts +++ b/src/node_requires/exporter/scripts.ts @@ -1,5 +1,6 @@ import {ExporterError, highlightProblem} from './ExporterError'; import {coffeeScriptOptions} from './scriptableProcessor'; +import {compile as compileCatnip} from '../catnip/compiler'; const compileCoffee = require('coffeescript').CoffeeScript.compile; const typeScript = require('sucrase').transform; @@ -8,22 +9,41 @@ export const stringifyScripts = (scripts: IScript[]): string => scripts.reduce((acc, script) => { let code; try { // Apply converters to the user's code first - code = script.language === 'coffeescript' ? - compileCoffee(script.code, coffeeScriptOptions) : - typeScript(script.code, { + switch (script.language) { + case 'typescript': + ({code} = typeScript(script.code, { transforms: ['typescript'] - }).code; + })); + break; + case 'coffeescript': + code = compileCoffee(script.code, coffeeScriptOptions); + break; + case 'catnip': + code = compileCatnip(script.code as BlockScript, { + resourceId: script.uid, + resourceName: script.name, + resourceType: script.type, + eventKey: 'onRun' + }); + break; + default: throw new Error(`Unsupported script language: ${script.language}`); + } return acc + `'${script.name}': function (options) {${code}},`; } catch (e) { const errorMessage = `${e.name || 'An error'} occured while compiling script ${script.name}`; - const exporterError = new ExporterError(errorMessage, { - resourceId: script.uid, - resourceName: script.name, - resourceType: script.type, - problematicCode: highlightProblem(e.code || code, e.location || e.loc), - clue: 'syntax' - }, e); - throw exporterError; + if (e instanceof ExporterError) { + // Passthrough already formatted errors, mainly coming from Catnip + throw e; + } else { + const exporterError = new ExporterError(errorMessage, { + resourceId: script.uid, + resourceName: script.name, + resourceType: script.type, + problematicCode: highlightProblem(e.code || code, e.location || e.loc), + clue: 'syntax' + }, e); + throw exporterError; + } } }, ''); From 9e188b214f2c0ee6c91e05c6bda68f0b709ca7af Mon Sep 17 00:00:00 2001 From: Cosmo Myzrail Gorynych Date: Mon, 4 Nov 2024 01:16:03 +1200 Subject: [PATCH 21/21] :pencil: Update the changelog --- app/Changelog.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/app/Changelog.md b/app/Changelog.md index ca1c0cbd5..14fa07aa5 100644 --- a/app/Changelog.md +++ b/app/Changelog.md @@ -1,3 +1,33 @@ +## v5.2.1 + +*Mon Nov 04 2024* + +### ⚡️ General Improvements + +* Catnip: Add mutators to timer blocks +* Catnip: Add mutators for "action is down/pressed/released" blocks +* Ct.js now checks whether recovery file actually differs from the regular project file +* Room editor: you can now navigate around with Spacebar + Left mouse button (Closes #526) +* :globe_with_meridians: Catnip: Improve Russian translations for ct.place +* :globe_with_meridians: Catnip: Translate Pointer catmod to Russian and add more human-readable English names +* :globe_with_meridians: Catnip: Translate the Random catmod's blocks to Russian + +### 🐛 Bug Fixes + +* Catnip: Add missing translation keys to Math operators +* Catnip: Fix catnip blocks ignoring translations when there was a translated name without a translated label +* Catnip: Fix inability to compile Script assets with Catnip code +* Catnip: Properly mark the required arguments in the Logic category +* Fields with invalid values should be outlined red +* Fix ct.js saving projects' scripts with CRLF sequence instead of LF, which caused them to be one-lined in the .ict file, making merging changes harder for Git users. You can fix the existing scripts by cutting and pasting their contents back. +* Fix minor styling issues on the homepage +* Fix `random.dice` trying to convert string values to floats (Closes #544) +* Make sure there are no special characters in the project name when creating one (Closes #543) + +### 📝 Docs + +* :bug: Fix brainless translation with room.append in Russian version of the JettyCat tutorial (Closes #141) + ## v5.2.0 *Sun Oct 13 2024*