AGS 3.6.0 - Beta 15

Started by Crimson Wizard, Sun 20/03/2022 20:23:39

Previous topic - Next topic

Crimson Wizard

AGS 3.6.0 - Beta 15
Full release number: 3.6.0.35

ACHTUNG!
This is a BETA version of AGS 3.6.0.
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: 1st September 2022

Previous stable version: AGS 3.5.1 P13 forum thread


This release is brought to you by:

- sonneveld (porting engine to SDL2)
- Alan v. Drake (improvements, fixes)
- Cameron Cawley [ccawley2011] (fixes, improvements to SpriteFont plugin)
- Crimson Wizard (stuff :))
- eri0o (updated Android port, Web port, Editor improvements, etc)
- fernewelten (new fonts outlining, improvements to script compiler, fixes)
- Francesco Ariis (fixes)
- Morgan Willcock (improving templates, help with CI)
- Pablo Navarro [panreyes] (fixes)
- ChamberOfFear (improvements)
- rofl0r (fixes, suggestions)
- Thierry Crozat (fixes, plugin update)
- vga256 (fixes)



What is new in 3.6.0

AGS 3.6.0 is another big change to AGS.
First of all, this release presents a SDL2-based engine. For about 2 decades AGS engine was based on Allegro 4 graphic library, which was discontinued somewhere in the early 2010-ies (only received few patches since). There was an intent to move either to Allegro 5 or SDL (1 or 2) since, but for various reasons this task was continuously postponed. Finally it is done. (NOTE: Allegro 5 is very different in everything, therefore it was not trivial to just go from Allegro 4 to 5. In fact it appeared to be easier to change from Allegro 4 to SDL2).
Secondly the Editor and Engine now have full Unicode support. This means that you may use any language whatsoever in scripts, object descriptions and custom properties, as well as translations; so long as you also provide proper unicode fonts.
Third, we finally have expanded a list of platforms that the Editor can build for: now this includes Android and Web (Emscripten) port.

This version is currently in Beta stage, which means that all major features are present, but there's still a room for improvement, and of course this all has to be tested more and fixed as necessary.
We are also working on updating the documentation, as quite a few of the 3.6.0 changes will require user's attention and learning new things about Editor and script.

For more information please also see "Upgrading to AGS 3.6" topic in the manual: https://adventuregamestudio.github.io/ags-manual/UpgradeTo36.html


Common features:
- Full Unicode support for all game texts: game properties, scripts, translations, input.
  ASCII/ANSI mode is still working, for backwards compatibility. This may be configured in the game project.
- Extended sprite compression options: lossless storage optimization for 16- and 32-bit sprites; LZW compression option for sprites in addition to existing RLE compression.
- GUI controls may now be told to clip their contents, which means that nothing gets drawn outside of their borders (as defined by X, Y, Width, Height properties). The only exception is Sliders, which are more complicated.
- The historical TTF fonts' "fixup" that altered their height and vertical offset is now optional and works only if backwards compatible option is set.
- Max number of AudioChannels is now 16 (was 8).
- Removed game Cursors hard limit (was 20).
- Increased Room Objects limit to 256 (was 40).
- Discontinued "Windows Game Explorer" support in both Editor and Engine.

Editor:
- Editor requires .NET Framework 4.6 to run.
- Added Android build target support (requires "Android component" installed).
- Added Web/Emscripten build target support (requires "Web build component" installed).
- Script editor works in unicode mode.
- Added "Text format" option in General Settings which lets switching between ASCII/ANSI and
  Unicode (UTF-8) modes. This defines which format the game texts will be written in, when saving the game project and compiling the game.
- Added "Use old-style keyboard handling" option to the General Settings, which lets select between classic key press handling and new one meant for unicode chars support in scripts.
- Supports compiling UTF-8 translations. TRS file now has "Encoding" setting that tells how to interpret this TRS text.
- Added support for building multiple speech voxes, by taking files from the Speech subfolders.
- Added support for adding custom files into the game package. This is done by assigning a list of directories to "Package custom data folder" option in General Settings.
- Added "Sprite file compression" option in General Settings, replacing "Compress the sprite file" option. The new option allows a selection of compression algorithm used for sprites. Currently supported: None, RLE (old default compression) and LZW.
- Added "Enable sprite storage optimization" option to the General Settings, that permits the editor to repack sprites in a different storage format, reducing their disk size whenever possible. This option may be used alongside with the sprite compression. Note that this does not change how the sprites work in game.
- Added "GUI controls clip their contents" option to the General Settings.
- Added "TTF fonts height used in the game logic" option to the General Settings, that makes your game use real font's pixel height when arranging text and text-based UI elements, as opposed to the nominal font's size.
- Added "TTF font adjustment" property to Fonts, as well as to General Settings where it serves as a project default for the new fonts. This property lets you choose between "no changes" and backward compatible TTF fixup meant to keep fonts made for AGS displayed as they were meant to.
- In the "Import TTF" dialog added a choice to import the size closest to the given pixel height.
- Fonts now have Auto Outline Style and Auto Outline Thickness properties.
- Fonts now have a readonly Family Name field, that lets user see the original name of a font they've imported (if available).
- Added IdleDelay property to Characters that lets you set time needed to pass before IdleView is activated. This is equivalent to the Character.SetIdleView script function.
- Added Character.IdleAnimationDelay property to let setup idle view's animation speed.
- Added Cursor.AnimationDelay property to let setup cursor's animation speed.
- The TextWindow edges now have distinct names in the dropdown list of the property grid.
- Rooms created from a Blank template will now have default background of a game's resolution.
- When creating new room objects they will now have their script names set to some default value.
- Added Room.BackgroundAnimationEnabled property to let have disabled animation on room load.
- Editor will now create an empty spriteset file (acsprset.spr) if one is missing in the game project. Any existing sprite descriptions in the project will be kept, letting user to reimport these from sources.
- Added "File -> Restore all sprites from sources" menu command.
- Added "Apply" button on editor's Preferences dialog.
- Select script editor's font in the editor's Preferences.
- Added "Help" option to the editor pane's tab context menu.
- Upgraded script editor to Scintilla 3.21.1 and ScintillaNET 3.6.3.
- Cursor's position in script is now displayed on the status bar.
- Dialog scripts now too can open help topics for keywords or script functions under cursor on F1.
- Added zoom controls for the Sprite Manager, Character, Cursor, Inventory and View panes.
- Sprites may now be imported by drag'n'drop into the Sprite manager.
- In sprite manager's "export all" dialog added "skip if local" option.
- In sprite manager's context menu added command "Create source files for all sprites with missing / external sources..."
- On the View pane the frames having set delay and linked sound will be now indicated with icons.
- Editor no longer errors and fails when opening a game project with some script files missing.
- Editor no longer errors on empty translations when compiling the game.
- Editor now exports values of the string type Custom Properties to translations.
- Editor no longer prevents exporting string arguments from Get/SetTextProperty calls to TRS file.
- Editor now cleanups spritefile on game load, identifying any data not referenced by the project and marking it for deletion.
- Fixed editor silently enabling all available Build Targets when upgrading a pre-3.4.0 project. This could be very inconvenient as there are several of them supported now.
- Fixed editor was not preventing from entering Character's and AudioClip's ScriptName too long for the engine to handle.
- Fixed Image and View properties in various objects were allowing negative values.
- Fixed some of the object previews (at least GUI) could crash if user entered a non-existing sprite's number as an Image property.
- Fixed editor displaying unhandled exception if the script which user is trying to open was missing. Instead it will now open a blank script.
- Fixed room editor was suggesting to save the modified room even if no changes were made.
- Fixed a recently imported sprite could be displayed incorrectly scaled up in the room editor for high-resolution games, if the "Allow relative asset resolutions" was enabled in General Settings, and the sprite 0 had "Resolution" property set to "Low".
- Fixed View animation preview stopping at frame 100 (if loop contains over 100 frames).
- Fixed going to a "find all" result in dialog script did not highlight the found text, and sometimes did not scroll down to it.
- Fixed "Goto Definition" not working for Enums and Defines (macros).
- Fixed script autocomplete sometimes was not updated right after opening a script.
- Fixed script autocomplete for function calls was mistreating commas in strings and inline comments as if they were separating actual parameters.
- Fixed script autocomplete was not displaying members of extended structs if the parent struct was declared in another header.
- Fixed script autocomplete was not working for enum names.
- Fixed structs and enums were not highlighted if declared inside a script's body.
- Fixed in dialogs numbers inside names were incorrectly highlighted as numeric values.
- Fixed few editor panes were not opening correct help topics in F1.

Compiler:
- Support unicode character literals.
- Support using float literals when defining default values for function arguments.
- Support hexadecimal number literals (e.g. "0xABCDEF").
- Removed 500-characters line limit.

Script API:
- Expanded `on_key_press` callback, now supports two parameters: key code and key modifier flags.
- In the new key handling mode `on_key_press` is called for each actual key press;
  e.g. combinations like Ctrl+Z will result in two `on_key_press` calls, one with eKeyCtrlLeft and second with eKeyZ; added support for "NEW_KEYINPUT_API" macro in scripts.
- Implemented new `on_text_input(int ch)` callback which is called when the engine receives a printable character. This callback is essential for handling unicode chars in script.
- Similarily, expanded `dialog_options_key_press` with the third `mod` argument, and implemented `dialog_options_text_input` callback for receiving unicode chars during the custom dialog options state.
- Implemented `dialog_options_close` callback which is called when custom dialog options are removed from the screen. This allows to perform any required cleanup.
- Added eEventEnterRoomAfterFadein event for `on_event` callback, which corresponds to "enter after fade-in" room event.
- Added eKey constants for Shift, Control and Alt keys.
- Added eKeyMod enum for key modifiers constants.
- String.AppendChar(), ReplaceChar() functions and String.Chars[] property are now working with the unicode characters.
- String.Format("%c") specifier will now be able to print unicode characters.
- Extended Button.Animate() to have blocking style, direction and starting frame parameters, thus matching other Animate commands (of Character and Object).
- Extended all Animate() commands by adding "volume" parameter, that defines volume of the frame-linked sounds for the duration of this animation.
- Added Character.AnimationVolume, defining volume of the frame-linked sounds.
- Added Character.IdleAnimationDelay to let control idle view's animation speed.
- Character.Scaling is no longer limited by a range of 5-200 (now supports 1-32767).
- Hotspot.Name and Object.Name may now be set in script.
- Added Object.ManualScaling and Object.Scaling.
- Deprecated Object.IgnoreScaling (use Object.ManualScaling instead).
- Object.SetView default loop & frame values are now 0 (was -1 which retained loop and frame indexes from the previous view, often unexpected to the user).
- DrawingSurface.DrawImage() and DrawSurface() now support optional source rect coordinates.
- Added functions for getting DrawingSurface of room masks: GetDrawingSurfaceForWalkableArea(), GetDrawingSurfaceForWalkbehind(), Hotspot.GetDrawingSurface(), Region.GetDrawingSurface().
- Added new delay parameter to Mouse.ChangeModeView() to let control cursor's animation speed.
- Added Game.ChangeSpeechVox() and Game.SpeechVoxFilename, support switching the voice-over pack.
- Added Mouse.AutoLock property that toggles automatic mouse lock inside the game window.
- Added Room.Exists().
- Added System.Log().
- Added SkipWait() that skips any active Wait() function.
- Added WaitMouse() to complement existing Wait functions.
- Added InputType enum which defines input devices and lets create their sets as flags.
- Added WaitInput(), a more generic and extendable function that accepts a combination of flags telling which input types to wait for.
- All Wait* functions now may have infinite timeout if you pass a negative timeout parameter.
- All Wait* functions now return the reason they were skipped: a combination of InputType flag and a respective key or button code.
- Added GUIControl.Transparency property.
- Added Overlay.CreateRoomGraphical and CreateRoomTextual. Use these two functions to create "room overlays": that is - overlays that display a sprite inside the room, sorted among other room objects, characters and walk-behinds.
- Added readonly Overlay.InRoom property that tells if this is a room or screen overlay.
- Extended Overlay.CreateGraphical() with a new "clone" parameter that tells whether to assign a sprite index, or make a sprite's copy owned exclusively by this overlay. The former will save program memory but make overlay update if the sprite is edited later. The latter is meant primarily for backwards compatibility. Overlay.CreateRoomGraphical has the same param.
- Added Overlay.Graphic property that lets you change overlay's sprite after it's created.
- Added Overlay.Width and Height properties, that let you freely scale existing Overlay.
- Added readonly Overlay.GraphicWidth and GraphicHeight properties that let read original overlay's graphic size, as not all overlays hold a sprite reference (e.g. textual overlays).
- Added Overlay.Transparency property.
- Added Overlay.ZOrder property that lets you sort Overlays among themselves and other objects in the same "game layer": screen overlays are sorted among GUI, while room overlays are sorted among room objects, characters and walk-behinds.
- Added Speech.TextOverlay and Speech.PortraitOverlay for accessing blocking speech overlay and portrait overlay respectively.
- Added Game.BlockingWaitSkipped which tells the result of the last blocking wait skipping, also including result of the blocking speech skipping.
- SkipSpeechStyle now supports eSkipNone mode; when used it will disable any kind of skipping, such speech can be only skipped by a direct command from script.
- Extended Screen.ScreenToRoomPoint() with an optional "restrictToViewport" argument, which lets to choose whether tests over empty place result in conversion through the default viewport or a null pointer.
- Added AudioClip.PlayOnChannel().
- Added AudioChannel.Pause() and Resume() functions, and IsPaused property.
- Added AudioChannel.SeekMs(), complementing PositionMs (as the Seek() function interprets position differently depending on the audio format).
- PlayVideo() now supports an option to play both game's and video's audio track simultaneously.
- Added File.WriteRawInt() to complement ReadRawInt().
- File paths in script now support $DATA$ token, which tells to read files from the game package.
  This only works for read operations. Functions that support this token currently are: File.Open(), DynamicSprite.CreateFromFile(), ListBox.FillDirList().
- Debug(2, 0) command that displayed walkable areas is superceded by Debug(2, n), where "n" is a mask type: 0 - none, 1 - hotspots, 2 - walkbehinds, 3 - walkable areas, 4 - regions. This command also works as a toggle switch, calling it with the same mask index will turn it off.
- Debug(5, n) command that displayed character's walk paths now also works as a toggle switch.

Engine:
- New SDL2-based backend for graphics, audio and input.
- Hqx graphic filters discontinued (could be temporary).
- Windows-only DirectMedia video playback discontinued (could be temporary).
  Only OGG/OGV videos are kept supported at this point.
- Support resizing game window on desktop systems.
- Support "borderless full-screen window" mode in addition to the real (exclusive) fullscreen.
- Unicode (UTF-8) text support: engine can now switch between ASCII and UTF-8 text mode.
  This is controlled by both game's OPT_GAMETEXTENCODING setting and translation's "Encoding" setting: they tells whether to interpret game texts as UTF-8 or ASCII/ANSI.
- Support optional translation's "GameEncoding" setting: it hints the original game's codepage to help with their conversion. This is mostly meant for translating existing older (ANSI) games.
- Engine now supports using real pixel height of the TTF fonts when arranging text and UI elements on screen; using nominal import size of the font is used as a compatible mode for the old games.
- Also supports separate "normal" and backward compatible "fixup" modes when initializing TTF fonts, letting to display both common TTFs and ones made specifically for AGS in the past to display as they were meant to be.
- Supports scripts using functions and variables from any other scripts, regardless of the script module order in the project.
- Removed limit of simultaneous Button animations.
- Removed limit of Character followers.
- Removed Overlay limit.
- Character.SetWalkSpeed() is no longer restricted by an arbitrary limit of 50.
- Process character's idle view based on real game speed, not hardcoded 40 fps.
- Improved file writing times (e.g. when doing a game save) by using buffered file stream. Initial tests showed 50% faster file writing.
- Engine now renders GUI controls as separate textures when using hardware accelerated renderers.
  This may significantly improve perfomance in the high-resolution games and games with large number of GUI elements on screen.
- Engine now shares the video texture data for all game objects on screen sharing same sprite. This improves perfomance in case there are multiple objects which use same image.
- Engine now ensures that in threaded audio mode the AudioChannel's state only changes once the game is updated, and not while the game script is running. This prevents situations when the clip could begin playing before all properties are set in script, or when AudioChannel's properties' values (such as Position) could change while running a game script.
- 24-bit wav PCM support, comes with the new sound library.
- File.ReadRawLineBack() now always reads full line, and not limited to 200 characters anymore.
- Debug displays, such as showing room mask and character walk paths, are now implemented as non-blocking translucent overlays, allowing you to keep playing the game while they are on.
- Implemented debug key controls for calling a built-in save and restore game dialogs. These controls have to be set in user config as "save_game_key" and "restore_game_key" in "[override]" category. These may be used by testers if the game is missing a save function or one is bugged.
- Engine now supports loading compiled scripts as separate files packed along with the game, along with those embedded into the main game data or inside room files.
- Engine no longer bails out with error if the chosen translation cannot be loaded on startup.
- When reporting script errors, engine will print callstack for all the active script "threads": for example, if there's Wait() function called and error happened in repeatedly_execute_always, then it will print both actual error's location, and Wait() call's location.
- Engine config now has graphic modes defined as a simplier string options: "[graphics] fullscreen" for the fullscreen mode setup, and "[graphics] window" for the windowed.
  Fullscreen option can explicitly define a "borderless full-screen window" mode.
- Added "load_latest_save" and "show_fps" options to config (in "[misc]" category).
- Added "background" option to config in "[misc]" category, that defines the starting run-in-background (aka multitasking) mode (may later be changed by SetMultitaskingMode()).
  Added "--background" command line option for the same purpose.
- Added "cache_size" and "stream_threshold" options to config in "[sound]" category, they setup the rules for sound caching and choosing whether to load a clip fully into mem or stream one.
- Added "--sdl-log" command line option for setting up SDL2 library output verbosity. The engine log config now has a new "sdl" group meant for SDL2 messages.
- Support "--user-conf-dir" command-line arg (and "user_conf_dir" config option) superceding "--localuserconf"; the new option directly tells the location of user config file.
- Path related command-line and config options, - such as "shared_data_dir", "user_data_dir" and "user_conf_dir", now support $GAMENAME$ token in path which is resolved to the game's title.
- Added "--clear-cache-on-room-change" command-line arg (and similar config option).
- Don't error when DrawingSurface.DrawImage has bad transparency parameter (warning instead).
- Don't error when detecting bad format in File.Read* functions (warning instead).
- Added stubs for agsshell plugin (a contemporary cross-platform variant of ags_shell).
- Added SpriteFont plugin to the list of builtins, for ports that use ones. SpriteFont plugin is updated to support custom "Clifftop Games" font variants.
- Fixed dialog script's "goto-previous" command not working if used from the first sub-topic run using "goto-dialog" (a very-very old bug).
- Fixed potential crash on room load if the walkable area mask contained color values above the supported range.
- Fixed potential crashes if a room-related API function has been called in "game_start"; this is achieved by having a dummy room placeholder object. Still results of such calls are undefined and should not be relied upon.
- Fixed renderer error occuring if room background frames are of different sizes.
- Fixed AGS_EngineInitGfx plugin callback was not called during OpenGL renderer initialization.
- Fixed overlay may fail to be created sometimes, if previously another overlay had been forcefully removed when changing rooms (this is an ancient bug which existed for many years).
- Fixed ListBox.RowCount reporting 0 if called before the control was displayed once.
- Fixed text may be misaligned in gui controls, as its outline thickness is not counted.
- Fixed some TTF fonts could be cut at the bottom when the speech is displayed.
- Fixed scheduled sound fadeout effect was not cancelled by skipping a cutscene.
- Fixed OGV Theora videos positioned incorrectly if they have certain sizes or aspect ratios.
- Fixed multitasking mode persisting if the game was switched from windowed to real fullscreen mode (even though it's not supposed to work in exclusive fullscreen).
- Fixed game fps sped up if SetGameSpeed() is called repeatedly in game script.
- Fixed game not reacting to system close commands when stuck in script, which made it impossible to close the "hanging" game by usual means (other than terminating the process).

Engine Plugin API:
- Added IAGSEngine::GetGameInfo() function which returns information about the game, such as its title and GUID.
- Added new render callback AGSE_POSTROOMDRAW, for handling drawing inside the room above all room objects.
- Added IAGSFontRenderer2 interface, expanding the original font renderer interface, improving font plugins support.
- Added ReplaceFontRenderer2() and NotifyFontUpdated() functions.

Compatibility:
- Fallback to loop 0 if the speech view does not have frames in the current directional loop.
- Set the first loop with frames if current character's loop does not have any for some reason.
- Ignore character having view/loop with no frames while it's not in the current room.
- Legacy behavior of MoveCharacterBlocking's return value.
- Fixed walkable area's continuous scaling was broken for high-res rooms in old games.
- In pre-3.* games force player to walkable area after changing rooms, this is to emulate an unintentional effect created by the old engines.
- Fixed pre-3.4.1 anti-aliased TTF fonts display (their vertical position was broken).
- Support Label.TextAlignment with legacy alignment constants for pre-3.5.0 games made with the custom engine from "Clifftop Games".
- Support native resolution hack for games made with "Clifftop Games" custom engine, where 640x400 games are run as 640x360.

Android:
- Rewrote universal AGS game launcher/player using up-to-date Google guidelines. The former "launcher" is now called "AGS Player".
- Implemented single game project template meant for building your own signed APK.
- In AGS Player added "Browse" button to the game folder selection, which opens default system file picker.
- AGS Player now searches for games recursively, in all the subfolders.

OSX:
- OpenGL renderer is now supported on MacOS.

Web / Emscripten:
- Initial port release.

Windows:
- Installer will create program links with three-digit version in the name.

WinSetup:
- Added "Fullscreen as borderless window" checkbox.
- Remade sound options to reflect the move to the new audio system in the engine.


KNOWN ISSUES
* MIDI no longer plays on its own on Windows. For MIDI you (and your players) must install "sound banks" (also known as "sound font"). Please refer to this article: https://github.com/adventuregamestudio/ags-manual/wiki/MIDI-playback
* AudioChannel.Position and AudioChannel.Seek do not work for MIDI and MOD sounds. Try sticking to PositionMs and SeekMs for now.

eri0o

Yey! We are in beta! Well done! 8-0

Mehrdad

congrats on the beta release!. Nice job !!  ;-D  ;)
My official site: http://www.pershaland.com/

Stranga

Awesome news about the beta! Loving the new AGS features :D

Dave Gilbert

Nice! Dutifully updating.

shaun9991

Amazing work! So many wonderful features here!!!
Support Cloak and Dagger Games on Patreon: https://www.patreon.com/user?u=460039

Stranga

#6
Having a strange problem since updating to the new beta, I think it may have something to do with the new keyboard handling system. I reverted back to the old via General settings but still doesn't seem to fix the problem.

My keyboard movement script is entirely done in repeatedly_execute(), which previously never interfered with hotspot.runinteraction, strangely if you hold down a movement key while interacting with a hotspot after the interaction completes the player is jolted in the direction of the key being held across the room. Seems to only happen if the game has entered a blocking sequence of some sort, maybe remembering key inputs during the hotspot interactions and playing them right after.

Keyboard Movement Script:
Spoiler
Code: ags

// Main script for module '8 Direction Movement'

import int  KeyUp[2];
import int  KeyDown[2];
import int  KeyLeft[2];
import int  KeyRight[2];
import int  KeyAction[2];
import int  KeyBack;
import int  KeyMenu;
import int  KeySprint[2];


//required values

int xm;
int ym;
int _xspeed=9; //Player Speed
int _yspeed=9; //Player Speed
int xwidth=1;
int ywidth=1;
int slide=3;
int a;
int c;
int dir;
bool diagslowdown=true;
int walkanispeed=2;
bool thrust;
int walkingani=2;
bool disablemove;
bool nodirset;
bool eightdir = false;
int animticks;
int animticks2;
bool standing;

static function EightDir::SetSpeed(int x, int y) {
  _xspeed = x;
  _yspeed = y;
}

static function EightDir::SetSize(int x, int y) {
  xwidth = x;
  ywidth = y;
}

static function EightDir::WalkViewSpeed(int speed) {
  walkanispeed = speed;
}  

  static function EightDir::SetWalkView(int view) {
  walkingani = view;
}  

static function EightDir::SetSlide(int value) {
  slide = value;
}  

static function EightDir::Disable(bool value) {
  disablemove = value;
}  

static function EightDir::NoDirSet(bool value) {
  nodirset = value;
}  

static function EightDir::DiagSlow(bool value) {
  diagslowdown = value;
}  

static function EightDir::Thrust(int x, int y) {
  xm=x;
  ym=y;  
  thrust=true;
}  

static function EightDir::EightLoopsMode(bool value) {
  eightdir = value;
}

static function EightDir::IsMoving() {
  if ((xm!=0)||(ym!=0)) {return 1;}
  if ((xm==0)&&(ym==0)) {return 0;}
}

static function EightDir::IsThrusting() {
  return thrust;
}

bool isInactive() {
  if(player.Room == 0) return true;
  return false;
}

int moveto(int val, int incr, int target)
{
  bool lt = val<target;
  bool gt = val>target;
  int old = val;
  if(lt) val += incr;
  else if(gt) val -= incr;
	if(((old<=target && val>=target) || (old>=target && val<=target)))
		val = target;
  return val;
}

#sectionstart repeatedly_execute  // DO NOT EDIT OR REMOVE THIS LINE
function repeatedly_execute() 
{
if (!InDialogue)// <-----This was a test to see if I could use a global variable to stop being able to move/take inputs in whilst in an interaction...didn't work as well as I'd hoped 
{
int wasdir = dir;
int wasx = player.x;
int wasy = player.y;


  if(isInactive()) return;

  bool up=false;
  bool down=false;
  bool left=false;
  bool right=false;


  if ((IsInterfaceEnabled()==true)&&(IsGamePaused()==false)) 
  {
  
  if (IsKeyPressed(KeyRight[0])||IsKeyPressed(KeyRight[1]))
  {
    right=true;
  }
  else if (IsKeyPressed(KeyLeft[0])||IsKeyPressed(KeyLeft[1]))
  {
    left = true;
  }
  else if (IsKeyPressed(KeyUp[0])||IsKeyPressed(KeyUp[1]))
  {
    up = true;
  }  
  else if (IsKeyPressed(KeyDown[0])||IsKeyPressed(KeyDown[1]))
  {
    down = true;
  }   
  else
  {
    walkanispeed=1;
    return;
  }
  }
 
  if(!up && !down && !left && !right)
  {
    return;
    player.StopMoving();
  }

  if ((IsInterfaceEnabled()==false)||(disablemove==true)) {xm=0;ym=0;}
  
  bool speedup = false; 
  
  if(IsKeyPressed(KeySprint[0])||IsKeyPressed(KeySprint[1])) speedup = true; 

  
  
  int xspeed = _xspeed;
  int yspeed = _yspeed;
  
   if(speedup)//RUN_________________________________RUN
  {
    if (player.View!=68)
    {
      player.LockView(68);
    }
    walkanispeed=4;
    xspeed = 15;
    yspeed = 15;
  }
  else
  {
   if (player.View!=2)
   {
     player.LockView(2);
   }
   walkanispeed=2; 
  }
  
  int accel = 20;

  if ((player.Moving==false)&&(IsInterfaceEnabled()==true)&&(IsGamePaused()==false)&&(disablemove==false)) {

    int b=0;
    
    if ((xm==0) && (ym==0)) {thrust=false;}


    //moving values

      while (b<slide){

        if (thrust==false){
          
          if ((right==true) && (xm < xspeed))  {xm=moveto(xm,accel, xspeed);}   //right
          if ((left==true) && (xm > xspeed*(-1)))  {xm=moveto(xm, accel, -xspeed);}   //left

          if ((down==true) && (ym < yspeed))  {ym=moveto(ym, accel, yspeed);}   //down
          if ((up==true) && (ym > yspeed*(-1)))  {ym=moveto(ym, accel, -yspeed);}   //up

          if ((left==false) && (right==false)) xm = moveto(xm,accel, 0);
          if ((up==false) && (down==false)) ym = moveto(ym,accel,  0);
        
        }  

      if (thrust==true) {
        
        if (xm != 0){xm=moveto(xm, accel, 0);}
        if (ym != 0){ym=moveto(ym, accel, 0);}
      }

    //slowdown

    if (thrust==false){
      if (xm > xspeed){xm=moveto(xm, accel,  xspeed);}
      if (xm < xspeed*(-1)){xm=moveto(xm, accel, -xspeed);}
      if (ym > yspeed){ym=moveto(ym, accel, yspeed);}
      if (ym < yspeed*(-1)){ym=moveto(ym, accel,  -yspeed);}
    }

  b=b+1;
  }

  //diagslowdown

  if (diagslowdown==true){

    int slow=0;
    while (slow <slide+1){

     if ((right==true)&&(down==true)) {
       if (xm>(xspeed*70)/100) {xm=(xm*70)/100;}
       if (ym>(yspeed*70)/100) {ym=(ym*70)/100;}
     }

     if ((left==true)&&(down==true)) {
       if (xm<((xspeed*70)/100)*(-1)) {xm=((xspeed*70)/100)*(-1);}
       if (ym>(yspeed*70)/100) {ym=(ym*70)/100;}
     }

     if ((left==true)&&(up==true)) {
       if (xm<((xspeed*70)/100)*(-1)) {xm=((xspeed*70)/100)*(-1);}
       if (ym<((yspeed*70)/100)*(-1)) {ym=((yspeed*70)/100)*(-1);}
     }

     if ((right==true)&&(up==true)) {
       if (xm>(xspeed*70)/100) {xm=(xm*70)/100;}
       if (ym<((yspeed*70)/100)*(-1)) {ym=((yspeed*70)/100)*(-1);}
     }
   slow=slow+1;
   }
  }

  //right

  int loop=0;

  if (xm>0){

    while (loop <xm) {
      a=a+1;
      if (a>9) {a=0;}
      if (a==5){
        player.x = player.x +xwidth;
        if (GetWalkableAreaAt(player.x - GetViewportX(),player.y - GetViewportY())>0) {player.x=player.x +1;}
        player.x = player.x -xwidth;
      }
    loop=loop+1;
    }
  }


  //left

  loop=0;

  if (xm<0){

    while (loop > xm) {
      a=a+1;
      if (a>9) {a=0;}
      if (a==5){
        player.x = player.x -xwidth;
        if (GetWalkableAreaAt(player.x - GetViewportX(),player.y - GetViewportY())>0) {player.x=player.x -1;}
        player.x = player.x +xwidth;
      }
    loop=loop-1;
   }
  }


  //down

  loop=0;

  if (ym>0){

    while (loop <ym) {
      c=c+1;
      if (c>9) {c=0;}
      if (c==5){
        player.y = player.y +ywidth;
        if (GetWalkableAreaAt(player.x - GetViewportX(),player.y - GetViewportY())>0) {player.y=player.y +1;}
        player.y = player.y -ywidth;
      }
    loop=loop+1;
    }
  }


  //up

  loop=0;

  if (ym<0){
    while (loop >ym) {
      c=c+1;
      if (c>9) {c=0;}
      if (c==5){
        player.y = player.y -ywidth;
        if (GetWalkableAreaAt(player.x - GetViewportX(),player.y - GetViewportY())>0) {player.y=player.y -1;}
        player.y = player.y +ywidth;
      }
    loop=loop-1;
    }
  }


  //outpush

  player.x = player.x -xwidth;
    if (GetWalkableAreaAt(player.x - GetViewportX(),player.y - GetViewportY())==0) {player.x=player.x +1;}
  player.x = player.x +xwidth;

  player.x = player.x +xwidth;
    if (GetWalkableAreaAt(player.x - GetViewportX(),player.y - GetViewportY())==0) {player.x=player.x -1;}
  player.x = player.x -xwidth;

  player.y = player.y -ywidth;
    if (GetWalkableAreaAt(player.x - GetViewportX(),player.y - GetViewportY())==0) {player.y=player.y +1;}
  player.y = player.y +ywidth;

  player.y = player.y +ywidth;
    if (GetWalkableAreaAt(player.x - GetViewportX(),player.y - GetViewportY())==0) {player.y=player.y -1;}
  player.y = player.y -ywidth;

  //outpush #2

  player.y = player.y -ywidth;

  player.x = player.x -xwidth;
    if (GetWalkableAreaAt(player.x - GetViewportX(),player.y - GetViewportY())==0) {player.x=player.x +1;}
  player.x = player.x +xwidth;

  player.y = player.y +ywidth;
  player.y = player.y +ywidth;

  player.x = player.x -xwidth;
    if (GetWalkableAreaAt(player.x - GetViewportX(),player.y - GetViewportY())==0) {player.x=player.x +1;}
  player.x = player.x +xwidth;

  player.y = player.y -ywidth;



  player.y = player.y -ywidth;

  player.x = player.x +xwidth;
    if (GetWalkableAreaAt(player.x - GetViewportX(),player.y - GetViewportY())==0) {player.x=player.x -1;}
  player.x = player.x -xwidth;

  player.y = player.y +ywidth;

  player.y = player.y +ywidth;

  player.x = player.x +xwidth;
    if (GetWalkableAreaAt(player.x - GetViewportX(),player.y - GetViewportY())==0) {player.x=player.x -1;}
  player.x = player.x -xwidth;

  player.y = player.y -ywidth;



  player.x = player.x +xwidth;

  player.y = player.y -ywidth;
  if (GetWalkableAreaAt(player.x - GetViewportX(),player.y - GetViewportY())==0) {player.y=player.y +1;}
  player.y = player.y +ywidth;

  player.x = player.x -xwidth;



  player.x = player.x -xwidth;

  player.y = player.y -ywidth;
    if (GetWalkableAreaAt(player.x - GetViewportX(),player.y - GetViewportY())==0) {player.y=player.y +1;}
  player.y = player.y +ywidth;

  player.x = player.x +xwidth;



  player.x = player.x -xwidth;

  player.y = player.y +ywidth;
    if (GetWalkableAreaAt(player.x - GetViewportX(),player.y - GetViewportY())==0) {player.y=player.y -1;}
  player.y = player.y -ywidth;

  player.x = player.x +xwidth;
 
 
  
  player.x = player.x +xwidth;

  player.y = player.y +ywidth;
    if (GetWalkableAreaAt(player.x - GetViewportX(),player.y - GetViewportY())==0) {player.y=player.y -1;}
  player.y = player.y -ywidth;

  player.x = player.x -xwidth;

 
  //animations

  //set direction

  if (eightdir==false){

    if ((left==true)||(right==true)||(up==true)||(down==true)){

      if (thrust==false){

        if (ym>0) {if ((left==false)&&(right==false))  {dir=0;}}
        if (xm<0) {if ((up==false)&&(down==false))  {dir=1;}}
        if (xm>0) {if ((up==false)&&(down==false))  {dir=2;}}
        if (ym<0) {if ((left==false)&&(right==false))  {dir=3;}}

        if ((ym>0) && (player.Loop==3))  {dir=0;}
        if ((ym<0) && (player.Loop==0))  {dir=3;}
        if ((xm>0) && (player.Loop==1))  {dir=2;}
        if ((xm<0) && (player.Loop==2))  {dir=1;}
      }
    }
  }


  if (eightdir==true){

    if ((left==true)||(right==true)||(up==true)||(down==true)){

      if (thrust==false) {
    
        if ((xm>0)&&(ym==0)) {dir=2;}
        if ((xm<0)&&(ym==0)) {dir=1;}
        if ((xm==0)&&(ym>0)) {dir=0;}
        if ((xm==0)&&(ym<0)) {dir=3;}

        if ((xm>0)&&(ym>0)) {dir=4;}
        if ((xm<0)&&(ym>0)) {dir=6;}
        if ((xm<0)&&(ym<0)) {dir=7;}
        if ((xm>0)&&(ym<0)) {dir=5;}
      }
    }
  }
}
  
  bool any = (left==true)||(right==true)||(up==true)||(down==true);
  
	if(any)
  {
    if(dir != wasdir || player.Loop != dir || standing)
    {
      player.Loop = dir;
			
			//only reset this if we were standing previously
			if(standing)		
			{
				//NOT 0 -- start nudging forward rather than slide in walk frame
				player.Frame = 1;
			}
    }
    else
    {
      animticks++;
      if(animticks>=walkanispeed)
      {
        animticks=0;   
        animticks2++;
        
        int limit = 2;
        if(speedup) limit=1;
                 
        ViewFrame* tmp = Game.GetViewFrame(player.View, player.Loop,  player.Frame);
        
        if(animticks2 > limit)
        {
          animticks2 = 0;
          player.Frame = player.Frame+1;
          if(tmp.LinkedAudio != null)
          {
            tmp.LinkedAudio.Play();
            if(player.Frame >= Game.GetFrameCountForLoop(player.View,  player.Loop))
              player.Frame = 1;
          }
        }
      }
    }
  }
  else
  {
    player.Frame = 0;
		standing = true;
		animticks = 0;
		animticks2 = 0;			
		return;
  }
  if(any) standing = false;

  if (player.Moving==true) {dir=player.Loop;}

  if (nodirset>0) {dir=player.Loop;}

  if (IsInterfaceEnabled()==false) {dir=player.Loop;}
  
  //LogMessage(String.Format("%d, yspeed=%d",player.y, yspeed));
}
else
{
  return;
}
}
#sectionend repeatedly_execute  // DO NOT EDIT OR REMOVE THIS LINE

[close]
Interaction Script:
Spoiler
Code: ags

//----------------------------------------------------------------------------------------------------
// on_key_press
//----------------------------------------------------------------------------------------------------
import int  KeyUp[2];
import int  KeyDown[2];
import int  KeyLeft[2];
import int  KeyRight[2];
import int  KeyAction[2];
import int  KeyBack;
import int  KeyMenu;
import int  KeySprint[2];
import int KeyInventory[2];

function on_key_press(eKeyCode keycode) 
{   
 
 if (IsGamePaused()) keycode = 0;

    // Action Key--------------------------------------------------------------------------------------------------------------
    if (keycode == KeyAction[0] || keycode == KeyAction[1]) 
    {
      int px = player.x - GetViewportX(),py = player.y - GetViewportY();
      Hotspot*h = Hotspot.GetAtScreenXY(px, py);
      Object*o = Object.GetAtScreenXY(px, py);
      if (h.ID > 0 ) {
        if (player.ActiveInventory != null)
        { 
          player.StopMoving();//These may be redundant 
          h.RunInteraction(eModeUseinv);
        }
        else
        {
          player.StopMoving();//These may be redundant 
          h.RunInteraction(eModeInteract);
        }
      }
    }
}
[close]

Crimson Wizard

#7
Quote from: Stranga on Tue 22/03/2022 23:04:16if you hold down a movement key while interacting with a hotspot after the interaction completes the player is jolted in the direction of the key being held across the room. Seems to only happen if the game has entered a blocking sequence of some sort, maybe remembering key inputs during the hotspot interactions and playing them right after.

If it were in on_key_press, i would assume that maybe it does not process and clear the key buffer each frame during a blocking action.
But since the action keys are processed in rep-exec, i'm not certain. I will have to do some tests.

Stranga

Well, strangely I did convert the system to on_keypress and didn't seem to find that issue (besides the very jittery/slow/clunky movement of the player character). If I could convert it to run as smoothly as on repeat_exe I would to be honest but this still may cause other problems down the line, possibly for others. I did also notice that it halted an animation after moving to another room  and partly froze the game too whilst doing the same thing (Holding ANY keys down during interactions or cutscenes e.c.t)

vga256

Great to see a beta out - with all the new features, this was enough to push me over the edge into upgrading my project!

I'm seeing an autocomplete bug with this version, but since I did not use any earlier versions of 3.6.0 I can't say where/when it might have emerged.

Behaviour:
Autocomplete does not continue working past the first word in a variable under ... unknown conditions.
Example:
Code: ags

/// reactor pressure and temp constraints
float ReactorMaxPressure = 1000.0; // a made-up number in kpa
float ReactorMinPressure = 1.0;
float ReactorMaxTemp = 1500.0; // a made-up number in *C
float ReactorMinTemp = 1.0; // in *C
float AmbientTemperature = 25.0; // SATP in *C
float AmbientPressure = 100.0; // SATP in kPa


Code: ags

function PlantSystemsToggleSysOps()
{
  Reactor...
}


When "Reactor" is entered, the autocomplete dropdown box correctly pops up and preselects ReactorMaxPressure. However, if I continue typing the variable name, "ReactorM..." the autocomplete box deselects ReactorMaxPressure and will not autocomplete with any variable name when I hit tab.

Workaround:
Code: ags

function PlantSystemsToggleSysOps()
{
    int anyTempVariable;
    Reactor...
}


With the above code, the simple insertion of any new variable causes the autocomplete to work as expected for "ReactorM..." words.

Possible Cause (?):
I tested this behaviour throughout my script, and determined that this function definition causes autocomplete to fail:
Code: ags

int NormalizeFlowRateWithinRange(int flowRate)
{
  for (int i = 0; i < MAX_ANIM_SPEED_GROUPS; i++)
  {
    if (flowRate <= animationSpeedRanges[i])
      return animationSpeedRanges[i];
  }
}


In *any* function below that piece of code, autocomplete will no longer properly autocomplete the word "ReactorM". Any function above this function autocompletes properly. I cannot see anything obvious about the above function that would cause a problem with autocomplete. Even commenting-out the entire function does not help.

Let me know if I can provide any more detail. It's a strange bug.

eri0o

@Stranga
Spoiler

this Keyboard Movement code is around 20 lines of code at least different from the one in Ash Pines. Is anything different there?

I just got


Is this line EXACTLY:
Code: ags
ViewFrame* tmp = Game.GetViewFrame(player.View, player.Loop,  player.Frame);

Because if it is, this another bug, with I thought we had fixed...
https://github.com/adventuregamestudio/ags/issues/802
[close]

So I can reproduce Stranga's reported problem on the engine built for release but when I try to run it on a debugger I keep hitting the bug above under the spoiler. I can't figure any minimal test case that reproduces the error though, everything appears to work.

On Ash Pines what I get is the engine is running and I can see keypresses on the log, but since I can't attach the debugger I don't know if the IsKeyPressed is getting the correct result or not - the character doesn't move anymore. I unfortunately am too much in the dark to even be able to write a bug report.

Stranga

@eri0o
Quotethis Keyboard Movement code is around 20 lines of code at least different from the one in Ash Pines. Is anything different there?

Yes, there's a small difference and it has to do with the number of views in that game. In Ash Pines, the player only has a left and right view rather than my latest/previous games where they have up, down, left, and right views.

Would you like to try a current demo game with your debugger? I can send you a build if you like?

Crimson Wizard

When testing under debugger it may be a good idea to enable "Multitasking mode" either using script command or config setting. Without "miltitasking" mode the input buffers are cleared on switching in and out of the game window, which also happens when breakpoint is hit.

Crimson Wizard

#13
Quote from: eri0o on Thu 24/03/2022 00:39:46
Is this line EXACTLY:
Code: ags
ViewFrame* tmp = Game.GetViewFrame(player.View, player.Loop,  player.Frame);

Because if it is, this another bug, with I thought we had fixed...
https://github.com/adventuregamestudio/ags/issues/802


This is happening as a combination of 2 reasons.
1) Engine allows to set Character's Frame directly without checking for validity, not even a warning. This is a surprise to me.

2) The game script has a mistake:
Code: ags

          player.Frame = player.Frame+1;
          if(tmp.LinkedAudio != null)
          {
            tmp.LinkedAudio.Play();
            if(player.Frame >= Game.GetFrameCountForLoop(player.View,  player.Loop))
              player.Frame = 1;
          }

if you notice, the player's frame range is only tested if linked audio is not null. Normally it should be checked always, outside of the LinkedAudio "if".

3) The question remaining is, why does this error happen only when the key was held down during blocking action, and not all the time.


UPDATE After fixing the above script error I was able to reproduce the problem Stranga was talking about: if i hold down a movement key during the blocking action, the character jumps across the screen after blocking action is over.

Code: ags

          player.Frame = player.Frame+1;
          if(tmp.LinkedAudio != null)
          {
            tmp.LinkedAudio.Play();
          }
          if(player.Frame >= Game.GetFrameCountForLoop(player.View,  player.Loop))
              player.Frame = 1;

Crimson Wizard

#14
So, in regards to jumping after blocking action. After some debugging, it's confirmed that there are a lot of repeatedly_execute events get queued and then called at once as soon as blocking action ends. Basically, instead of 1 rep-exec, there's like 20 rep-execs called in a quick succession.

This may be related to some recent changes in the engine, because previously AGS did not let schedule more than 5 events at once and would simply quit the game with "internal error" if this happens. Removal of event queue limit is not a problem itself, but it seem to hide some other problem where it would keep accumulate rep-exec events when it really should not.

UPDATE:

This is the temp build with fix: https://cirrus-ci.com/task/6054112394477568

greg

#15
Thanks for putting this beta together!  I'm very excited to try it out, and I just updated from 3.5.1.14 to the build in the previous comment.

I've noticed a couple strange things with object animations:

1. When I play an object's animation as eRepeat, it plays once and then stops.

2. When I play an object's animation backwards, it plays the first few frames of the animation (i.e. the last few frames of the loop) backwards and then starts playing in forward motion again.  This occurs whether or not I explicitly specify the starting frame.

Code: ags

// context: loop 0 of view my_view has 12 frames
// this appears to play frame id 11, then 10, then 9, then 10, then 11
oObject.SetView(my_view, 0);
oObject.Animate(0, 5, eOnce, eBlock, eBackwards);

// and this does the same thing
oObject.SetView(my_view, 0, 11);
oObject.Animate(0, 5, eOnce, eBlock, eBackwards, 11);


Also, I noticed that the numerical values of internal enums (eBlock, eNoBlock, eForwards, eBackwards) have changed from AGS 3.5.1.  For example, instead of 0/1, eForwards and eBackwards are 1062/1063.  I'm assuming that's intended?

Crimson Wizard

#16
@greg, sorry for that! I've been adding something to animation commands, which will be announced for the next update, and there was one small mistake...

Here's a link to another fixed build (it will be available roughly 20 mins after posting):
https://cirrus-ci.com/task/6209775263285248

Quote
Also, I noticed that the numerical values of internal enums (eBlock, eNoBlock, eForwards, eBackwards) have changed from AGS 3.5.1.  For example, instead of 0/1, eForwards and eBackwards are 1062/1063.  I'm assuming that's intended?

These constants did not change at least since 3.2.1 (this is as far as we can look back into the code history), but I know that Animate functions also must accept 1 and 0 (or true and false) for Direction and Blocking parameters.

greg

#17
Thank you very much, CW!  That build fixed both object animation issues I had encountered.

Separately, I noticed that ch.PositionMs is now returning how long AudioChannel ch has been playing, not the position of the audio clip that's playing on ch.

Here's my test for this:

Code: ags
AudioChannel* ch = aMusTest.Play(eAudioPriorityHigh);
// Msg("foo") is a simple function which prints "foo" to the screen.
Msg(String.Format("%d", ch.PositionMs));  // This prints 0, as expected.
// My gamespeed is 40, so each Wait(80) is roughly two seconds.
Wait(80);
Msg(String.Format("%d", ch.PositionMs));  // This prints ~2000, as expected
Wait(80);
ch.Seek(79500);
Msg(String.Format("%d", ch.PositionMs));  // This prints ~4000, where I'd expect ~79500.
Wait(80);
Msg(String.Format("%d", ch.PositionMs));  // This prints ~6000, where I'd expect ~81500.

Crimson Wizard

@greg, thank you for reporting; i now fixed couple of mistakes in both Seek and position reporting after seek. Besides wrong position report it also played one buffered chunk of previous position after Seek.

Here's goes another build:
https://cirrus-ci.com/task/6670891743444992

greg

#19
Thanks so much, CW!  That fixed the issues I was experiencing with GetPositionMs.

As I was testing further, I also noticed the following:

1. For audio clips of type MP3 and length < ~1.5 seconds, aClip.Play() plays the first 0.15-0.40 seconds of the sound and then stops.  In AGS 3.5.1, this occurred for MP3s under ~0.5 seconds, and my workaround was to convert to OGG.  In AGS 3.6, I'm observing it for MP3s up to 1.5 seconds.  This doesn't appear to affect MP3s over 2.5 seconds or OGGs.

2. The editor no longer automatically highlights matching braces as I type.  Instead, after typing the brace, I need to press Ctrl+B to highlight the corresponding brace.  Is that intended?

3. For the masks toggled by the Debug(2, n), is there a way to adjust their size (e.g. to make them full screen)?  I tried adjusting General Settings > Rooms > Default mask resolution, but it had no effect.

SMF spam blocked by CleanTalk