AGS 3.6.2 - Beta 5 -- a WIP 3.6 update

Started by Crimson Wizard, Mon 07/10/2024 23:28:58

Previous topic - Next topic

Crimson Wizard

AGS 3.6.2 - Beta 5
Full release number: 3.6.2.5

ACHTUNG!
This is a BETA version of AGS 3.6.2.
It's considered relatively stable but is not thoroughly tested yet and also may have planned additions.
Use at your own risk. Please back up any games before opening them in this version of AGS.
New settings in this version may make your project files unusable in previous versions after saving with this version.


For Editor
Spoiler

For Android
Spoiler
NOTE: the Editor now includes Android build component letting you prepare your own games for Android
[close]

For Engine/Editor developers
Spoiler


Released: 29th December 2024

Previous stable version: AGS 3.6.1 P8 forum thread


This release is brought to you by:

- Alan v.Drake (palette fix)
- Crimson Wizard
- edmundito (some fixes)
- eri0o
- rofl0r (couple of compatibility reports & fixes)


What is new in 3.6.2

3.6.2 is planned to be a second minor update to 3.6, focusing mostly on convenience of existing Editor and Engine features, and expanding existing script commands. There's however one bigger change: a support for loading saves from older versions of the game.

Common features:
 - Event handler function are now allowed to be located in any script module.
 - New naming rule for the voice clips: full char name, followed by a number, separated by a dot, e.g. "RogerTheGreat.1234.ogg". The old rule may be enabled again by a switch in "Backwards Compatibility" settings.

Editor:
 - In "Start New Game Wizard" game template selection now displays template's description right in the dialog.
 - "Game statistics" now have Ctrl + F2 shortcut instead of F2.
 - F2 can be used for starting editing names of items in the Project Tree (ones that support that) and folders in the Sprite Manager.
 - In General Settings added "Use old-style voice clip naming rule" which lets to select whether the game should expect old-style voice clip filenames (4-letter char name followed by number) or the new one (full char name, followed by a number, separated by a dot).
 - Property Grid now displays Custom Properties right in the main properties list for each item that supports them.
 - Added "WrapText", "TextPaddingHorizontal", "TextPaddingVertical" properties to GUI Button.
 - GUI Labels can select full range of Alignment values in their TextAlignment property.
 - Added "TurnWhenFacing" property to Characters.
 - Textual GUI controls can now select "Null Font" as their font: this will prevent any text to be drawn even if one is assigned, and make it have zero size (when it matters).
 - "Events" tab on the Properties Grid now has "ScriptModule" selection, which lets define in which module should the related script functions be generated and looked for. The GUI Controls use a ScriptModule set in their parent GUI, and Room events always has a fixed room script selected.
 - Added "Open Recent" submenu in the File menu.
 - Sync script editor's commands in Edit menu with the context menu.
 - Added "Toggle Line Comment" command to Edit menu for scripts.
 - More panes in the Editor are DPI-aware (rescale well with the system font scaling).
 - Editor tabs now display icons indicating their contents (may be disabled in Editor Preferences).
 - Room panel tabs now display room names.
 - Editor will now remember certain window states: "Sprite selector" window and splitter position, splitter position in "Sprite manager".
 - Support reordering folders in Project Explorer with drag & drop.
 - Support importing plain script files: ash, asc or both, - besides script modules (*.scm).
 - On "Color Finder" pane also display actual RGB values that the engine will use. They may be different from requested RGB, because historically engine limits drawing color's RGB precision to 16-bit.
 - Font's "SourceFilename" and "Font Size" properties now have buttons that let import another font file, or reimport same font with different size respectively, instead of clicking on a button on the preview window.
 - Global Variables panel now allows to declare arrays.
 - Added "Controls transparency" slider to GUI edit pane.
 - Copy, paste and delete commands now apply to all the selected GUI controls in GUI editor.
 - When pasting a copied GUI control, Locked property of a new control will be turned off.
 - Support editing group properties for selected GUI controls.
 - Added a multiline Text edit window for Button and Label controls, that may be called by Ctrl+E, from context menu, or by pressing "..." button of the Text property in the Properties grid.
 - Support reordering folders in Sprite Manager with drag & drop.
 - Support importing 1-bit (monochrome) and 4-bit images as sprites, room backgrounds and masks (converted to 8-bit).
 - Support importing indexed PNGs as room backgrounds and masks.
 - Do not alter or clamp palette for 8-bit sprites imported in a 16/32-bit game.
 - Removed obsolete "Copy walkable area mask to regions" command from the Room editor.
 - Improved scrolling of drop-down lists in the Room's navigation bar: made scroll buttons larger, and support mouse wheel.
 - In Room Editor, during any area drawing mode Ctrl + LMB now works as area picker regardless of the currently selected tool.
 - Do not delete previously built game exe from Compiled/Windows folder when testing a game from the editor.
 - Editor will now report any missing script functions that are assigned to events, but not present in script, as warnings when compiling the game.
 - Editor will now report any script functions that *look like* event functions, but not assigned to corresponding events, as warnings when compiling the game.
 - Added "/maketemplate" command-line option that tells Editor to run, make template out of the said game, and quit.
 - Fixed Editor refusing to open a project if one or more of the sections are missing in the file.
 - Fixed dragging an item into the folder in Project Explorer could move it into a wrong folder if the folders have similar names only different in letter case.
 - Fixed importing indexed PNG as a sprite, previously Editor would mistakenly treat the source image as 32-bit.
 - Fixed importing 8-bit BMP sprites with no "Remap palette" and "Leave As Is" as a transparency option would still remap palette index 0 to the first found palette entry with Alpha 0, even if that's a filler entry not used by the image.
 - Fixed exporting room backgrounds was always writing a 32-bit image rather than using actual background's color depth.
 - Fixed "Color Finder" and color properties were mapping a color number to RGB values with accuracy mistakes, resulting in slightly different values than the engine would use.
 - Fixed an unhandled exception occuring when rebuilding rooms if any script's header is missing.
 - Fixed a "unterminated string" error in Dialogs was not pointing to the actual error location.
 - Fixed double warning message when trying to close the Editor while a game test is running.

Scripting:
 - Dynamic arrays now have Length readonly property that returns their number of elements.
 - Support zero-length dynamic arrays. This may be useful if you need to have a dynamic array with no elements, but don't want to bother about checking a null pointer.

Script API:
 - Added eNullFont constant that lets assign or pass a "null font" to any property or function parameter which expects a font's ID. This "null font" will simply make any text not drawn and have no actual measurements (size, spacing, etc).
 - Added global events: eEventDialogStart, eEventDialogStop, eEventDialogRun, eEventDialogOptionsOpen, eEventDialogOptionsClose (these are handled in "on_event").
 - Events eEventGUIMouseDown and eEventGUIMouseUp now get additional parameters: mouse button, mouse x and y positions (relative to the exact GUI).
 - Expanded "on_mouse_click" callback, now supports two more parameters: click x,y coordinates.
 - Added RestoredSaveInfo struct which contains information about game save's contents,
 - Support "validate_restored_save" callback, which lets user to validate restored saves with mismatching data and request cancellation or continuation of restoring this save.
 - Added Button.WrapText, TextPaddingHorizontal, TextPaddingVertical.
 - Added Character.Following property that returns another Character that this one follows after.
 - Added Character.TurnWhenFacing property.
 - Added Character.MoveStraight() complementing WalkStraight().
 - Added DateTime.CreateFromDate() and CreateFromRawTime().
 - Added static Dialog.CurrentDialog property and non-static ExecutedOption and AreOptionsDisplayed properties.
 - Added RenderLayer enum, and optional "layers" parameter to DynamicSprite.CreateFromScreenShot(), that tells which of the game's render layers to capture when making a screenshot.
 - Added File.Copy() and File.Rename().
 - Added FileSortStyle and SortDirection enum, and File.GetFiles() function that returns a dynamic array of filenames found using certain pattern, and optionally sorted by name or time, in ascending or descending order.
 - Added File.GetFileTime() that returns file's modification time.
 - Added Added File.ReadFloat(), WriteFloat(), ReadRawFloat(), WriteRawFloat(), ReadRawBytes() and WriteRawBytes().
 - Added SaveGameSortStyle enum and Game.GetSaveSlots() function that returns a dynamic array of save slot indexes, optionally sorted in certain way.
 - Added Game.GetSaveSlotTime() that returns a time this save slot was last written.
 - Added Game.ScanSaveSlots() that scans a range of game saves and tests them for compatibility, using "validate_restored_save" too if it's present in user script. This action is not run immediately, but is scheduled to be executed after current script ends. It reports of scanning completion by sending eEventSavesScanComplete event.
 - Label.TextAlignment has now type Alignment, rather than HorizontalAlignment, and has full alignment range (both horizontal and vertical).
 - Added optional "fileSortStyle" and "sortDirection" parameters to ListBox.FillDirList().
 - Added optional save slot range (min/max), saveSortStyle and sortDirection parameters to ListBox.FillSaveGameList(). This lets to define the exact range of saves it should fill, and order them in desired way.
 - Added ListBox.FillSaveGameSlots(), which initializes a list of saves from a dynamic array of save slot indexes.
 - Added Object.DestinationX and DestinationY properties, complementing ones in Character.
 - Added Overlay.SetPosition() and SetSize() functions for convenience.
 - Added Speech.SpeakingCharacter that returns currently speaking character (for blocking speech).
 - Added GetTimerPos() that returns timer's position (remaining time), in ticks.
 - Added CopySaveSlot() and MoveSaveSlot(), which moves existing save to another slot.
 - Added optional save slot range (min/max) parameters to RestoreGameDialog() and SaveGameDialog().
 - Added optional "sprite" parameter to SaveGameSlot(), that lets to pass a number of an arbitrary sprite to write into this save instead of a standard "screenshot".
 - Added SendEvent() function that allows to trigger "on_event" function calls in script. Special event value eEventUserEvent may be used as a base index for user-defined events.
 - Added System.DisplayFPS property that toggles FPS counter (a replacement to Debug(4, 1)).
 - Added System.GetEngineInteger() and System.GetEngineString() for returning diagnostic information about engine's runtime state. Possible arguments are defined by EngineValueID enum.
 - Added new game-wide option OPT_SAVEGAMESCREENSHOTLAYER that lets to define which of the game's render layers will be captured when making a standard screenshot for the save game.
 - Add SaveComponentSelection enum and game option OPT_SAVECOMPONENTSIGNORE, which lets to skip certain components when saving or restoring a game. This has dual purpose: reduce number of things in game that may break older saves by simply not having them in a save, and also reducing the size of game saves on disk (e.g. in case of dynamic sprites). Note that all things that were not restored from the save will retain their *current state*.

Engine:
 - Engine now potentially supports reading saves made in older game versions with different content, so long as these saves have *less* data in any given type (i.e. less Characters, or less controls on a certain GUI, or less variables in script, and so forth).
   This feature is enabled by having a special "validate_restored_save" function anywhere in the game script, that accepts an argument of type RestoredSaveInfo. RestoredSaveInfo contains various information about the restored save, and "Cancel" property, that must be explicitly set to "false" in script in order to allow to restore such save.
 - Engine supports returning to previously saved rooms which have less script data.
   It's important to remember though that it does no validation of restored room state on its own.
 - Dropped support for pre-3.5.0 game saves.
 - Increased the cap of simultaneously loaded scripts to 1024 (this includes all regular script modules, a single active dialog script, and a single active room script).
 - Engine no longer quits with error in case a script function assigned to a Room event is missing. Logs warnings about missing script functions assigned to any events.
 - Character.FollowCharacter() can now have a distance parameter up to 32766 (was limited to 255).
 - Ensure that Character.Speaking returns true when a speech is playing even if the character has no speech view.
 - DynamicSprite.CreateFromFile() may now load 1-bit and 4-bit bitmaps, converting to 8-bit.
 - Do not alter or clamp palette for 8-bit sprites loaded into a 16/32-bit game at runtime.
 - Assigning InventoryItem.Graphic will no longer reassign CursorGraphic too even if they were identical previously.
 - Calling DeleteSaveSlot() on a slot within 0-50 range will no longer secretly move a save with the topmost number (within the same range) to fill the emptied slot. If you still like to recreate this behavior, then use MoveSaveSlot() command.
 - Support calling StopDialog() inside a dialog script, that will schedule dialog's stop command at the end of the current option script.
 - Removed arbitrary limit of 2k bytes for the result of String.Format().
 - Ensure that the objects with identical z-order (baseline) always keep same relative sort order when being drawn (note: engine does not guarantee predefined order, only determenistic one).
 - Implemented video buffering on a separate thread. Allow to drop late video frames.
 - Added new accessibility config settings in "access" section: "speechskip", "textskip", "textreadspeed". These let player to override game's skipping style for character speech and text messages, and text reading speed parameter that controls speech timing.
 - Added "max_save" config option in "override" section: this lets to enforce an arbitrary number of saves displayed in a standard save/restore dialogs in game.
 - Added "--no-plugins" command-line argument that denies loading any plugins; also added respective config option "noplugins" in "override" section.
 - Fixed calling Dialog.Start() inside a dialog script would create a nested "dialog state", which could eventually lead to internal mistakes and program stack overflow. Dialog.Start() will now schedule a proper dialog topic switch, equivalent to "goto-dialog" command.
 - Fixed calling Character.Animate() during idling state could cause incorrect error, reporting invalid animation loop.
 - Fixed inventory cursor's crosshair hotspot was drawn incorrectly if active item's sprite has a alpha channel.
 - Fixed displaying room masks with Debug command in legacy "upscale" mode.

Engine Plugin API:
 - Added IAGSEngine.CreateDynamicArray(), which lets plugins to create dynamic arrays.
 - Added IAGSEngine.GetDynamicArrayLength() and IAGSEngine.GetDynamicArraySize(), which tell the passed array object's number of elements, and total size in bytes respectively.
 - Added IAGSEngine.Log(), which lets plugins to print using engine's log system.

Compatibility:
 - Fixed loading of games made in AGS 2.55-56 which include plugins.
 - Fixed loading of rare games made with AGS 2.5 or higher, which contained deprecated "room animations" (animations themselves are currently not functional).
 - Fixed old pathfinder imprecision affecting few pre-3.0 games.
 - Allow pre-2.7 games to have RestartGame() command be followed and overridden by a NewRoom(). This is necessary for some older games to be able to proceed.

WinSetup:
 - Redesigned winsetup into a tabbed dialog.
 - Added "Reset To Defaults" button that resets all options to values from the game's default config file.
 - Added "Accessibility" settings for skipping speech and text messages, for text reading speed.
 - In "disabled" section of config "access_skipstyle" setting lets disable all options in setup related to the speech and text skipping.

Crimson Wizard

#1
Since documentation for this version is not ready yet, following are declarations of new enums, to make it easier to learn them:

Code: ags
enum RenderLayer
{
  eRenderLayerNone      = 0x00000000,
  eRenderLayerEngine    = 0x00000001,
  eRenderLayerCursor    = 0x00000002,
  eRenderLayerUI        = 0x00000004,
  eRenderLayerRoom      = 0x00000008,
  eRenderLayerAll       = 0xFFFFFFFF
};

enum FileSortStyle
{
  eFileSort_None = 0,
  eFileSort_Name = 1,
  eFileSort_Time = 2
};

enum SortDirection
{
  eSortNoDirection = 0,
  eSortAscending   = 1,
  eSortDescending  = 2
};

Examples:
Code: ags
DynamicSprite* screenshot = DynamicSprite.CreateFromScreenShot(Screen.Width, Screen.Height, eRenderLayerRoom);
Will make a screenshot that only has room viewport(s) on it, but no GUI or else.



EngineValueID are identifiers of value returned by two functions:
Code: ags
int System.GetEngineInteger(EngineValueID value, optional int index = 0);
String System.GetEngineString(EngineValueID value, optional int index = 0);
These are meant primarily for testing and diagnostic purposes, for example, if you like to display current engine state on screen during game tests.

The enum itself is declared as:
Code: ags
// Engine value constant name pattern:
// ENGINE_VALUE_<I,II,S,SI>_NAME, where
//   I - integer, II - indexed integer, S - string, SI - indexed string.
enum EngineValueID
{
  ENGINE_VALUE_UNDEFINED = 0,            // formality...
  ENGINE_VALUE_SI_VALUENAME,             // get engine value's own name, by its index
  ENGINE_VALUE_S_ENGINE_NAME,
  ENGINE_VALUE_S_ENGINE_VERSION,         // N.N.N.N (with an optional custom tag)
  ENGINE_VALUE_S_ENGINE_VERSION_FULL,    // full, with bitness, endianess and any tag list
  ENGINE_VALUE_S_DISPLAY_MODE_STR,
  ENGINE_VALUE_S_GFXRENDERER,
  ENGINE_VALUE_S_GFXFILTER,
  ENGINE_VALUE_I_SPRCACHE_MAXNORMAL,   // sprite cache capacity limit (in KB)
  ENGINE_VALUE_I_SPRCACHE_NORMAL,  // sprite cache capacity filled (in KB)
  ENGINE_VALUE_I_SPRCACHE_LOCKED,  // amount of locked sprites (in KB)
  ENGINE_VALUE_I_SPRCACHE_EXTERNAL, // amount of external sprites, that means dynamic sprites (in KB)
  ENGINE_VALUE_I_TEXCACHE_MAXNORMAL,   // texture cache capacity limit (in KB)
  ENGINE_VALUE_I_TEXCACHE_NORMAL,  // texture cache capacity filled (in KB)
  ENGINE_VALUE_I_FPS_MAX,    // max fps, this is set by SetGameSpeed
  ENGINE_VALUE_I_FPS,      // real average fps (updates along with the game run)
  ENGINE_VALUE_LAST                      // in case user wants to iterate them
};

Example of use:
Code: ags
int spritecachemax = System.GetEngineInteger(ENGINE_VALUE_I_SPRCACHE_MAXNORMAL);
int spritecachecurrent = System.GetEngineInteger(ENGINE_VALUE_I_SPRCACHE_NORMAL);
int spritecachepercent = spritecachecurrent * 100 / spritecachemax;
lblInfo.Text = String.Format("Sprite cache: %d / %d (%d%%)", spritecachecurrent, spritecachemax, spritecachepercent);

Crimson Wizard

#2
Updated to Beta 2
(Please use download links in the first post)

Among other things, this update includes few simpler script API additions backported from AGS 4 Alpha release.

Editor:
 - Added "WrapText", "TextPaddingHorizontal", "TextPaddingVertical" properties to GUI Button.
 - GUI Labels can select full range of Alignment values in their TextAlignment property.

Script API:
 - Added global events: eEventDialogStart, eEventDialogStop, eEventDialogRun, eEventDialogOptionsOpen, eEventDialogOptionsClose (these are handled in "on_event").
 - Added Button.WrapText, TextPaddingHorizontal, TextPaddingVertical.
 - Added DateTime.CreateFromDate() and CreateFromRawTime().
 - Added static Dialog.CurrentDialog property and non-static ExecutedOption and AreOptionsDisplayed properties.
 - Added File.Copy() and File.Rename().
 - Label.TextAlignment has now type Alignment, rather than HorizontalAlignment, and has full alignment range (both horizontal and vertical).
 - Added Overlay.SetPosition() and SetSize() functions for convenience.
 - Added GetTimerPos() that returns timer's position (remaining time), in ticks.
 - Added CopySaveSlot() to complement MoveSaveSlot() and File.Copy() functions.



I suppose that this version may not have any more big additions, with an exception of savegame upgrade feature, which I've been preparing for some time:
https://www.adventuregamestudio.co.uk/forums/engine-development/load-older-game-saves-into-updated-game-attempt-2/

I'd like people to try this version out and test how it works.



Once again, since we don't have an updated manual yet, here's some info about the new Dialog-related events.
These let to do certain actions in your game whenever a Dialog starts, stops, or a topic is run. Which may be useful for adding some custom effects to your game.

All of these events are handled in "on_event" function:
eEventDialogStart - arg1 means dialog ID
eEventDialogStop - arg1 means dialog ID
eEventDialogRun - triggers whenever a dialog entry is run, arg1 is dialog ID, arg2 is entry ID, where starting entry (@S) is 0, and user-made options begin with 1
eEventDialogOptionsOpen - triggers whenever dialog options are shown
eEventDialogOptionsClose - triggers whenever dialog options are hidden

Here's a demo game that illustrates their principal usage:
https://www.dropbox.com/scl/fi/vkezgxxrujldunxn4n55o/362-demo-dialogevents.zip?rlkey=yueyy9uymp0d8c0ypntdnpqh1&st=cdrprje1&dl=0
(use TalkTo verb on a player character to start a dialog)

RootBound

This all sounds good. I'll try this version with my current game and see what happens.
They/them. Here are some of my games:

Laura Hunt

Quote from: Crimson Wizard on Mon 07/10/2024 23:28:58- Expanded `on_mouse_click` callback, now supports two more parameters: click x,y coordinates.

This is amazing, I've been wanting this functionality for so long. No more hacking it with GetAtScreenXY!

Quote from: Crimson Wizard on Mon 07/10/2024 23:28:58WinSetup:
 - Redesigned winsetup into a tabbed dialog.
 - Added "Accessibility" settings for skipping speech and text messages.

Will it be possible to disable these options with the [disable] tag in the cfg file, as we can already do for other options like gfxdrivers, filters, etc?

Crimson Wizard

#5
Quote from: Laura Hunt on Mon 14/10/2024 11:52:05
Quote from: Crimson Wizard on Mon 07/10/2024 23:28:58WinSetup:
 - Added "Accessibility" settings for skipping speech and text messages.

Will it be possible to disable these options with the [disable] tag in the cfg file, as we can already do for other options like gfxdrivers, filters, etc?

Won't this defeat the purpose of these options? The whole point is to let players override the game in case developer made it impossible for them to play the game. If a game developer will disable them, then players who might need them won't be able to use them.

Laura Hunt

Quote from: Crimson Wizard on Mon 14/10/2024 14:28:03Won't this defeat the purpose of these options? The whole point is to let players override the game in case developer made it impossible for them to play the game. If a game developer will disable them, then players who might need them won't be able to use them.

Ultimately I think the final control over what can or can't be done with the game should belong to the developer, and while accessibility features are something that the engine should definitely offer, in the end it should be the decision of the developer whether to actually implement them or not, or which ones to implement. If my game is designed in a way that I feel that overriding my design decisions will cause issues or change the experience somehow, I would prefer to prevent users from tampering with those options.


Crimson Wizard

#7
Very well, I will just remove them from the engine and setup, and then provide an alternate program that gives them for those players that need this.

Or perhaps I should suggest ScummVM team to implement these instead, and redirect players to use ScummVM to run ags games when they have these troubles.

Snarky

Wouldn't it be better to not make these decisions on a whim or based on one person's feedback?

Crimson Wizard

I can add options to disable these.
Because Accessibility group may contain a wide range of settings, then they probably will require separate disable settings per subgroup (or even per individual options in certain cases).

Of course this will open an opportunity for game developers to prevent players from having these options when they might actually need them.

Laura Hunt

Quote from: Crimson Wizard on Mon 14/10/2024 16:45:21I can add options to disable these.
Because Accessibility group may contain a wide range of settings, then they probably will require separate disable settings per subgroup (or even per individual options in certain cases).

Of course this will open an opportunity for game developers to prevent players from having these options when they might actually need them.

Appreciate it, CW. I definitely see no need to remove them completely, just giving us the option to disable them like you just said is perfect.

Dave Gilbert

These are all amazing new features! Since I'm nearing the end of my current project I probably won't upgrade to this, but next time for sure.

Crimson Wizard

#12
Quote from: Dave Gilbert on Wed 16/10/2024 00:08:45These are all amazing new features! Since I'm nearing the end of my current project I probably won't upgrade to this, but next time for sure.

I actually recommend trying out AGS 4 for the new projects instead:
https://www.adventuregamestudio.co.uk/forums/ags-engine-editor-releases/ags-4-0-early-alpha-for-public-test/

It has much more new things, improvements to scripting language, few big features that you've been asking for in the past, such as rooms saved as multiple files (images and data separate) and inspecting script variables during game test.

And frankly we need more people checking it out, to speed up polishing process.

Dave Gilbert

Will the 3.6.2 features be rolled into 3.4?

Crimson Wizard

Quote from: Dave Gilbert on Thu 17/10/2024 13:15:59Will the 3.6.2 features be rolled into 3.4?

Naturally, AGS 4 will contain everything from previous versions, except old deprecated features.

Dave Gilbert

Then I most definitely will! Assuming I survive finishing this project first.  :~(

RootBound

Hey @Crimson Wizard

I'm trying out this version for my MAGS entry this month, and I think there's a bug in the editor - when I import over one of the default fonts, the new (imported) font does not display in the editor, and the default font remains. However, when I run the game, the new (imported) font displays correctly, so it has been imported.

On the plus side, the new GUI transparency slider in the GUI editor is nice and seems to work perfectly. I'm also trying out declaring arrays in global variables, so I'll keep you updated on anything else I find as I keep using this version.  :)
They/them. Here are some of my games:

Crimson Wizard

Quote from: RootBound on Fri 08/11/2024 16:53:54I'm trying out this version for my MAGS entry this month, and I think there's a bug in the editor - when I import over one of the default fonts, the new (imported) font does not display in the editor, and the default font remains. However, when I run the game, the new (imported) font displays correctly, so it has been imported.

Please clarify, what do you mean by "import over default font", which operations do you do?

I think editor may fail to refresh the font in memory on some occasions.

RootBound

Quote from: Crimson Wizard on Fri 08/11/2024 17:27:45
Quote from: RootBound on Fri 08/11/2024 16:53:54I'm trying out this version for my MAGS entry this month, and I think there's a bug in the editor - when I import over one of the default fonts, the new (imported) font does not display in the editor, and the default font remains. However, when I run the game, the new (imported) font displays correctly, so it has been imported.

Please clarify, what do you mean by "import over default font", which operations do you do?

I think editor may fail to refresh the font in memory on some occasions.

I click one of the default fonts from the blank template and select "import over this font" and then select a new font and import it.

It does seem that closing the AGS editor and reopening it updates the font in the display area.
They/them. Here are some of my games:

Crimson Wizard

Quote from: RootBound on Fri 08/11/2024 19:17:13I click one of the default fonts from the blank template and select "import over this font" and then select a new font and import it.

I had a moment of confusion. I've been thinking of a new fonts system in AGS 4, where "import over font" command no longer exists.

Okay, I will test this in 3.6.2.

Crimson Wizard

#20
I need an advice in regards to the new scripting API.

In the version we have an ability to do different file sorting when filling in list boxes using ListBox.FillDirList(). And I'm also currently working on another function which scans for saves and returns a dynamic array with slot numbers (for the purpose of prescanning valid saves etc, but that's a long story). It also can do sorting. This made me think that it's not a too bad idea to add optional sorting args to ListBox.FillSaveGameList() as well.

Currently there are two types of file sorting implemented:
- by name
- by time (modification time)

Here's where I realized that in case of saves there is an ambiguity in what to consider a "name". Initially I thought filename, because it also matches the slot number due to how save files are called; which would make "sort by name" = "sort by slot number".

But now, since ListBox is affected, and when ListBox is filled with saves it fills save descriptions, I begin to have doubts.
Is the description also valid case for sorting saves?

If yes, then how to deal with this situation?

I see 3 variants:
1. Consider sorting by "Name" be sort by description in case of filling ListBox, and loose ability to sort by a slot number.
2. Add another sorting style by "Index" or "Number" into the list of file sorts (it will be called e.g. "eFileSort_Index"), so have both sort by slot number and description.
3. Create a completely separate "save sorting style" which will have sorting by SlotNumber, Description or Time.


EDIT: Hmm, i'm gradually leaning towards separate enum, i.e. SaveSortStyle, because files may in theory be sorted by parameters that are not meaningful for saves at all (like size on disk), and saves may require specific ways to order too.

Crimson Wizard

#21
Updated to Beta 3
(Please use download links in the first post)

Includes all the fixes from 3.6.1 Patch 8.

Own changes:

Editor:
 - In "Start New Game Wizard" game template selection now displays template's description right in the dialog.
 - "Game statistics" now have Ctrl + F2 shortcut instead of F2.
 - F2 can be used for starting editing names of items in the Project Tree (ones that support that) and folders in the Sprite Manager.
 - Added a multiline Text edit window for Button and Label controls, that may be called by Ctrl+E, from context menu, or by pressing "..." button of the Text property in the Properties grid.
 - In Room Editor, during any area drawing mode Ctrl + LMB now works as area picker regardless of the currently selected tool.
 - Editor will now report any missing script functions that are assigned to events but not present in script as warnings when compiling the game.
 - Fixed font preview not updating after importing a new font over. (regression in 3.6.2 Beta)
 - Fixed editing Color property of multiple selected GUI controls.

Scripting:
 - Dynamic arrays now have Length readonly property that returns their number of elements.

Script API:
 - Events eEventGUIMouseDown and eEventGUIMouseUp now get additional parameters: mouse button, mouse x and y positions.
 - Added RestoredSaveInfo struct which contains information about game save's contents,
 - Support "validate_restored_save" callback, which lets user to validate restored saves with mismatching data and request cancellation or continuation of restoring this save.
 - Added FileSortStyle and SortDirection enum, and File.GetFiles() function that returns a dynamic array of filenames found using certain pattern, and optionally sorted by name or time, in ascending or descending order.
 - Added SaveGameSortStyle enum and Game.GetSaveSlots() function that returns a dynamic array of save slot indexes, optionally sorted in certain way.
 - Added Game.ScanSaveSlots() that scans a range of game saves and tests them for compatibility, using "validate_restored_save" too if it's present in user script. This action is not run immediately, but is scheduled to be executed after current script ends. It reports of scanning completion by sending eEventSavesScanComplete event.
 - Added optional "fileSortStyle" and "sortDirection" parameters to ListBox.FillDirList().
 - Added optional saveSortStyle and sortDirection parameters to ListBox.FillSaveGameList().
 - Added ListBox.FillSaveGameSlots(), which initializes a list of saves from a dynamic array of save slot indexes.
 - Added Object.DestinationX and DestinationY properties, complementing ones in Character.
 - Added SendEvent() function that allows to trigger "on_event" function calls in script. Special event value eEventUserEvent may be used as a base index for user-defined events.
 - Add SaveComponentSelection enum and game option OPT_SAVECOMPONENTSIGNORE, which lets to skip certain components when saving or restoring a game. This has dual purpose: reduce number of things in game that may break older saves by simply not having them in a save, and also reducing the size of game saves on disk (e.g. in case of dynamic sprites). Note that all things that were not restored from the save will retain their *current state*.

Engine:
 - Engine now potentially supports reading saves made in older game versions with different content, so long as these saves have *less* data in any given type (i.e. less Characters, or less controls on a certain GUI, or less variables in script, and so forth). This feature is enabled by having a special "validate_restored_save" function anywhere in the game script, that accepts an argument of type RestoredSaveInfo. RestoredSaveInfo contains various information about the restored save, and "Cancel" property, that must be explicitly set to "false" in script in order to allow to restore such save.
 - Engine supports returning to previously saved rooms which have less script data. It's important to remember though that it does no validation of restored room state on its own.
 - Engine no longer quits with error in case a script function assigned to a Room event is missing. Logs warnings about missing script functions assigned to any events.
 - Support calling StopDialog() inside a dialog script, that will schedule dialog's stop command at the end of the current option script.
 - Added new config setting to "access" section called "textreadspeed" which lets to override game's text reading speed parameter.
 - Fixed calling Dialog.Start() inside a dialog script would create a nested "dialog state", which could eventually lead to internal mistakes and program stack overflow. Dialog.Start() will now schedule a proper dialog topic switch, equivalent to "goto-dialog" command.
 - Fixed Character may get stuck in "move without animating" state if Move called before Walk. (regression in 3.6.2 Beta)
 - Fixed 8-bit room bgs in 32-bit game are imported filled with "magenta". (regression in 3.6.2 Beta)
 - Fixed crash on game quit if there was any queued music. (regression in 3.6.2 Beta)

WinSetup:
 - Added "Text reading speed" to "Accessibility" settings tab.
 - Fixed setup could save wrong setting values in categories located on other tabs, if player never opened these tabs.
 - In "disabled" section of config "access_skipstyle" setting lets disable all options in setup related to the speech and text skipping.



This update finally adds the feature that was one of the reasons to plan 3.6.2 release (at least for me): a support for loading saves from older game version. This function is currently limited in what it can do: you can only load saves with *less* data, and it will be stable so long as you did not change the order of previously existing things. That's why it's primarily purposed for patching already released games, and not for creating multi-chapter games or games with DLCs, for example (although, I suppose, one could try to pull that off too with certain effort).

This is still experimental, and requires testing potential use cases.

Another complementary feature is a function that *prescans* saves without restoring them. This allows to test which saves are "safe" to load prior to displaying them in the save/load menu, for example.

All this have to be properly documented and explained. Unfortunately I'm too tired now, so for the moment I'll give two links to the tickets in our github tracker, which contain overview of these features:
* Support loading older saves: https://github.com/adventuregamestudio/ags/pull/2489
* Prescanning saves: https://github.com/adventuregamestudio/ags/pull/2579

And the forum thread that discusses this all:
https://www.adventuregamestudio.co.uk/forums/engine-development/load-older-game-saves-into-updated-game-attempt-2/



OTOH I'd very much prefer to wrap things up in 3.6.2, stop adding things to it, and focus on testing, fixing and documenting what's already added.

eri0o

On fixing things, we need Length to appear in autocomplete for dynamic arrays and also check if any updates are required in the templates - adding additional data parameters in on_event, check if mouse position handling is done using in event position parameters when possible, descriptions.

I guess if we plan at least one more beta release I could upgrade the dependencies versions - notably SDL2, to see if things are alright.

Crimson Wizard

#23
Well, there still may be few minor additions, for example I wanted to try adding a starting monitor selection in setup.

Also, we could update to VS 2019 at least (which would change the required VC runtime).

There may be as many Beta updates as necessary - until we're certain that things are stable.

Crimson Wizard

I am in doubts about something again...

In the latest update I've expanded eEventGUIMouseDown and eEventGUIMouseUp events with following parameters:
- mouse button
- mouse x
- mouse y

the position is given in screen coordinates.

Would it be better to have them in respective GUI coordinates instead?

eri0o

I think if there's a need there could be an API for that like Point* GetRelativePosition(int x, int y). Does GUI.ProcessClick(int x, int y) uses screen or GUI relative coordinates? (I don't remember)

Crimson Wizard

#26
Quote from: eri0o on Sun 24/11/2024 21:18:21I think if there's a need there could be an API for that like Point* GetRelativePosition(int x, int y). Does GUI.ProcessClick(int x, int y) uses screen or GUI relative coordinates? (I don't remember)

There's no need for this in ags3, as there are no complex transformations, it's simply a matter of subtracting GUI.X or Y. There's already a function for this in ags4, where gui may have more transformations.

But I'm asking not because there is a problem of converting, but because I cannot decide what makes more sense in the context of event params.
Also, I don't remember if it's now in this particular case, but at least in theory triggered events may be processed not instantly, but with certain delay, in which case it may be important to describe the exact state of the context in which the event occured.


EDIT: GUI.ProcessClick uses screen coordinates, because it's not called for specific gui, but for the whole "gui layer".

greg

Quote- Support reordering folders in Project Explorer with drag & drop.

Does this feature include reordering folders in the Sprites tab?

I just installed the latest beta, and I'm not able to reorder my sprites folders.

eri0o

Nope, sprites is implemented very differently. The changes are in the project explorer, where now you can drag things and move them between things there.

greg

While testing out 3.6.2 Beta 3, I've noticed an issue with array scoping.  Here are the reproduction steps:

  • An array is defined within a top-level script.  Its values can be set/get via functions in that same script.
  • A lower-level script sets a value in the top-level script's array via a call to the top-level script's set function.
  • When the lower-level script reads the value from the array via the top-level's script's get function, it gets the value it just set.  However, when the top-level script reads the value directly from the array, it gets the value that preceded the lower-level script's set call.

Here's some sample code:

topMostScript.ash

Code: ags
#define MY_INDEX 1

import function DisplayValues(int value);
import function GetGlobalInt(int index);
import function SetGlobalInt(int index, int value);

topMostScript.asc

Code: ags
int g_global_ints[10];

function DisplayValues(int value) {
  Display(String.Format("%d:%d", g_global_ints[MY_INDEX], value);
}

function GetGlobalInt(int index) {
  return g_global_ints[index];
}

function SetGlobalInt(int index, int value) {
  g_global_ints[index] = value;
}

lowerLevelScript.asc

Code: ags
function test() {
  SetGlobalInt(MY_INDEX, 1);
  
  // I'd expect this to display "1:1". Instead, it displays "0:1".
  DisplayValues(GetGlobalInt(MY_INDEX));
}


Crimson Wizard

#30
@greg that's because SetGlobalInt and GetGlobalInt are engine API functions, so engine actually calls its own functions instead of yours.

https://adventuregamestudio.github.io/ags-manual/Globalfunctions_General.html#getglobalint

Simply rename the functions, and you will see expected values.


The problem is that engine is not made to differentiate between selected script api levels, and always links its deprecated api, even if not requested by the game settings. I think this issue may be already recorded in our bug tracker, and it must be resolved.

Alternatively, you may still import these old engine functions by declaring them, but not defining their bodies.

eri0o

Also the above code won't compile because it's parentheses are unbalanced.

Crimson Wizard

#32
Quote from: eri0o on Sat 30/11/2024 16:44:44Also the above code won't compile because it's parentheses are unbalanced.

That's just a typo in a forum post. The problem in the engine is real.

EDIT: That's quite strange, I had memories of someone having these deprecated functions recreated in their game scripts. How would they work then, I wonder. Maybe these are false memories, and it was something else.


greg

Thanks, CW!  I'd been using the built-in, long-deprecated GetGlobalInt and SetGlobalInt in 3.6.1.  When I upgraded to 3.6.2, I got a compilation error of "undefined symbol 'GetGlobalInt'", so I'd assumed the functions had finally been removed and created my own version with the same name.

I've renamed my version to GetGlobalIntQ and SetGlobalIntQ, and now everything is working as expected.  Thanks!

Crimson Wizard

Quote from: greg on Sat 30/11/2024 17:49:22Thanks, CW!  I'd been using the built-in, long-deprecated GetGlobalInt and SetGlobalInt in 3.6.1.  When I upgraded to 3.6.2, I got a compilation error of "undefined symbol 'GetGlobalInt'", so I'd assumed the functions had finally been removed and created my own version with the same name.

No, they were not removed, they were hidden under the script API setting, as they should have long time ago.

If you are actually using these in your games, they may be enabled again, if you wish, like any of the deprecated functions:
https://adventuregamestudio.github.io/ags-manual/GeneralSettings.html#backwards-compatibility
These two in particular require "Enforce post-2.62 scripting" set to false.

Alternatively, you may explicitly declare these functions in any of your headers. This will allow scripts to use them, since they are still available in the engine.


greg

Understood, thanks!  In anticipation of 4.0 (which will remove GetGlobalInt, SetGlobalInt, and all deprecated functionality), I've switched over to my version rather than relying on deprecated functions.

Crimson Wizard

Quote from: greg on Sat 30/11/2024 18:00:02Understood, thanks!  In anticipation of 4.0 (which will remove GetGlobalInt, SetGlobalInt, and all deprecated functionality), I've switched over to my version rather than relying on deprecated functions.

Is there a reason why are you not using normal global variables instead?

greg

QuoteIs there a reason why are you not using normal global variables instead?

With Game.InputBox(), I've created a mini-console that allows me to view and edit global variables while play testing.

For example, I can parse input string "SetGlobalInt 1 10" and use that to call SetGlobalInt(1, 10).  To do this, I parse out tokens "SetGlobalInt", "1", and "10", use a switch statement to map "SetGlobalInt" to SetGlobalInt(), and use String.AsInt to convert "1" and "10" to 1 and 10.

If I switched to the normal global variables, I'd need to parse "SetGlobalInt myVar 10" and use that to call myVar = 10.  To do this, IIUC, I'd need a switch statement that mapped every global variable's name ("myVar") to the global variable itself (myVar), and that's more cumbersome than referring to global variables by index.

Crimson Wizard

Quote from: greg on Fri 29/11/2024 16:07:07
Quote- Support reordering folders in Project Explorer with drag & drop.

Does this feature include reordering folders in the Sprites tab?

I just installed the latest beta, and I'm not able to reorder my sprites folders.

I wrote a variant that supports dragging Sprite folders, copying the Project Tree functionality;
if you like you may download this temporary build and test it out:
https://cirrus-ci.com/task/5728199629340672

greg

Thanks, CW!  This is fantastic.  I just tested it out, and I'm now able to re-organize and alphabetize sprite folders!

Crimson Wizard

Updated to Beta 4
(Please use download links in the first post)

Editor:
- Property Grid now displays Custom Properties right in the main properties list for each item that supports them.
- Support reordering folders in Sprite Manager with drag & drop.
- Script's Autocomplete will now work for dynamic array's Length property.
- Editor will now report any script functions that *look like* event functions, but not assigned to corresponding events, as warnings when compiling the game.
- Fixed dragging an item into the folder in Project Explorer could move it into a wrong folder if the folders have similar names only different in letter case.

Scripting:
- Support zero-length dynamic arrays. This may be useful if you need to have a dynamic array with no elements, but don't want to bother about checking a null pointer.

Script API:
- Added Character.Following property that returns another Character that this one follows after.
- Added System.DisplayFPS property that toggles FPS counter (a replacement to Debug(4, 1)).

Engine:
- Removed arbitrary limit of 2k bytes for the result of String.Format().
- Fixed calling Character.Animate() during idling state could cause incorrect error, reporting invalid animation loop. (This is regression in 3.6.1)
- Fixed GUI controls get shuffled when restoring saves made by pre-3.6.2 engines (regression since 3.6.2 Beta 3).
- Fixed Game.ScanSaveSlots() erroring on GUI in saves made by pre-3.6.2 engines.

Crimson Wizard

We started documenting new 3.6.2 features. Their partial documentation may already be found in the manual along with the latest Beta, more will follow.

For the reference here's a wip version of "Upgrading to 3.6.2" article, that discusses important new features:
https://github.com/adventuregamestudio/ags-manual/wiki/UpgradeTo362

Crimson Wizard

#43
There's a bug found in the latest 3.6.2 and 4.0 updates,

I'm not entirely certain, but i think it happens when you either declared a function without parameter names (only types), or when you are typing a function declaration and delete one of the parameters and retype its type, or something like that.

In such case editor shows error message with "index out of bounds". But you can continue to work.
The error comes from autocomplete, so while annoying, should not affect your game.

I will be posting a fixed builds soon.



UPDATE: following temp build should have this fixed:
https://cirrus-ci.com/task/6216491441324032

Crimson Wizard

#44
I really wish to have any feedback on this:

Quote from: Crimson Wizard on Sun 24/11/2024 19:28:54I am in doubts about something again...

In the latest update I've expanded eEventGUIMouseDown and eEventGUIMouseUp events with following parameters:
- mouse button
- mouse x
- mouse y

the position is given in screen coordinates.

Would it be better to have them in respective GUI coordinates instead?

Because we are gradually approaching final 3.6.2 release, and this has to be resolved soon.



My own thinking of this is following:
the event is "mouse down/up on gui", and it refers to particular GUI, as one may notice from the parameter list, not "all or any guis".
Because it relates to particular GUI, it may be desired to know exact relative position of a click, as opposed to a case when have a "click on screen" for example.
Similarly to the case when the mouse changes position before "on_mouse_click" gets called (and that's why we need to pass click position as arguments),
a GUI may also change position before "on_event" is called. This may happen, for instance, if it's changed in gui's own OnClick event, or if there are multiple on_event functions in multiple scripts and one of them changes gui position. Not very likely in practice, but still theoretically possible.

These two considerations combined: that this event refers to a click on particular gui, and that gui position may change in between, - they make me think that it's better to pass relative gui coordinates for them.

Crimson Wizard

Updated to Beta 5
(Please use download links in the first post)

Editor:
- Fixed a "unterminated string" error in Dialogs was not pointing to the actual error location.
- Fixed a possible "index out of range" exception that may occur while user types a function declaration (a regression in previous 3.6.2 Beta).

Script API:
- Changed eEventGUIMouseDown and eEventGUIMouseUp events to receive click position in GUI-relative coordinates.
- Renamed File.ReadBytes() and WriteBytes() to ReadRawBytes() and WriteRawBytes() respectively, in sake of consistency with other File functions.
- Added File.ReadFloat() and WriteFloat() that safeguards the written value with a tag.

Engine:
- Increased the cap of simultaneously loaded scripts to 1024 (this includes all regular script modules, a single active dialog script, and a single active room script).
- Character.FollowCharacter() can now have a distance parameter up to 32766 (was limited to 255).
- Ensure that the objects with identical z-order (baseline) always keep same relative sort order when being drawn (note: engine does not guarantee a predefined order, only a persistent one).
- Fixed inventory cursor's crosshair hotspot was drawn incorrectly if active item's sprite has a alpha channel.

Engine Plugin API:
- Added IAGSEngine.CreateDynamicArray(), which lets plugins to create dynamic arrays.
- Added IAGSEngine.GetDynamicArrayLength() and IAGSEngine.GetDynamicArraySize(), which tell the passed array object's number of elements, and total size in bytes respectively.

Snarky

Quote from: Crimson Wizard on Sun 29/12/2024 07:10:16a GUI may also change position before "on_event" is called. This may happen, for instance, if it's changed in gui's own OnClick event, or if there are multiple on_event functions in multiple scripts and one of them changes gui position. Not very likely in practice, but still theoretically possible.

In AGS4 it's also possible to rotate GUIs, right? So presumably the eEventGUIMouseDown/Up coordinates will be relative to the rotated coordinate system. This, to me, is the main reason to prefer the GUI coordinate system, as otherwise it would be hard to work out where on the GUI you actually clicked.


greg

I don't think 3.6.2 is handling alpha channels correctly when importing new sprites.

Reproduction steps:

1. Select "Import new sprite(s) from files..."
2. Select a file that has an alpha channel.
3. Make sure "Import alpha channel (if available)" is selected, and click Import.

Expected Behavior: The imported sprite should have a transparent background.

Observed Behavior: The imported sprite has a background color in the Sprites tab, as well as when running the game.

Note that this only affects sprites imported in 3.6.2.  It doesn't affect sprites that were already imported before upgrading to 3.6.2.

Crimson Wizard

Quote from: greg on Tue 14/01/2025 03:39:59Reproduction steps:

1. Select "Import new sprite(s) from files..."
2. Select a file that has an alpha channel.
3. Make sure "Import alpha channel (if available)" is selected, and click Import.

Please double check what is selected in "Transparent colour" option when you import the sprite.

greg

This image shows the same png file imported with the following options (from left to right):

1. Imported with an earlier version of AGS: ImportAlphaChannel=True, TransparentColour=LeaveAsIs
2. Imported with AGS 3.6.2 Beta 5: ImportAlphaChannel=True, TransparentColour=LeaveAsIs
3. Imported with AGS 3.6.2 Beta 5: ImportAlphaChannel=True, TransparentColour=NoTransparency
4. Imported with AGS 3.6.2 Beta 5: ImportAlphaChannel=True, TransparentColour=TopLeft

Here's what I see:

#1 uses the alpha channel as the transparency.  This is the intended behavior.

#2 and #4 appear to be using the transparent color rather than the alpha channel.  (You can see a black outline around the sprite.)

#3 has no transparency.  This is a change in behavior from pre-3.6.2 where, even if TransparentColour == NoTransparency, the imported sprite would still use the alpha channel.

Crimson Wizard

#51
@greg could you upload a original png that you are using so that I could test this? I was not able to see this black outline with the random sprites; and I cannot see any difference from 3.6.1, or 3.6.0 for example, regardless of the options.

About TransparentColour=NoTransparency, I tried with the same random sprite, and it maintains alpha transparency for some reason, although I did not expect that. I am not fully certain, but i think that this option was supposed to make the sprite opaque.

greg

Sure, here's the png I'm testing with:

https://www.dropbox.com/scl/fi/z1fgxxvnahpw0yfwjw84v/NE-01-SS-000.png?rlkey=w9i6bj0dqhp4cp6z4vzw3pkmm&st=lap4p1ze&dl=0

I've tested with other png files as well, though they were also created through the same pipeline (using ImageMagick).

Crimson Wizard

#53
Quote from: greg on Wed 15/01/2025 03:34:35Sure, here's the png I'm testing with:

https://www.dropbox.com/scl/fi/z1fgxxvnahpw0yfwjw84v/NE-01-SS-000.png?rlkey=w9i6bj0dqhp4cp6z4vzw3pkmm&st=lap4p1ze&dl=0

I can see what is happening now.
When importing this file in previous versions, they see this file as "32-bit ARGB".
When importing the same file in 3.6.2, it sees this file as "8 bit indexed", and thinks that the image does not have any alpha channel.
This is displayed at the left-bottom corner of the Import Sprite window; and "Alpha Channel" property is false in the sprite's properties after import.

The PNG file is actually 8-bit, but I suppose that it contains translucent colors in its palette, and 3.6.2 misses this fact.

Crimson Wizard


greg

Yes, that build fixed the issue.  Thank you!

I used "Replace sprite(s) from source" to refresh all the character's sprites, and the alpha channel is now displaying correctly.

Crimson Wizard

Quote from: greg on Yesterday at 04:46:30I used "Replace sprite(s) from source" to refresh all the character's sprites, and the alpha channel is now displaying correctly.

Hmm, interesting, I did not expect "Replace from source" to work like that, but probably it works because it remembers "Use Alpha Channel" option, and automatically combines that with the new knowledge about the source image.

SMF spam blocked by CleanTalk