Show Posts

You can view here all posts made by this member. Note that you can only see posts made in areas to which you currently have access.

Topics - Crimson Wizard

Pages: [1] 2 3 ... 11

First of all, this is NOT another "feature request" topic.
This is also NOT "what to add to the next version of AGS" topic.

Sorry for this disclaimer. Please read further :).

There are few new engines underway, being made by people known in AGS community, such as XAGE, MonoAGS, and maybe some others we do not know about. They may copy AGS to some degree or reimagine adventure creating tool in their own way. Since I am currently considering contributing to one of them, and just because I think that might be important for any such undertaking, I would like to make a following survey.

The primary targets for this survey are people who have big experience working with AGS, but others may participate too, of course.

Survey has only two simple questions, but they may need extensive answers:
1) What do you like about AGS, and would like to keep if any new creative tool arrives?
2) What do you think should be changed (added, removed, altered)?

Now, this is NOT about simple and obvious things, like
- not being able to change GUI color at runtime, or
- having a limit of N sprites, or
- running on many platforms, etc

but rather about ones, such as
* editing workflow,
* methods to achieve something you want,
* script API design
(how well does script allow you to control game behavior), and so forth.

If you have experience working with other game creating systems, and may make a comparison, please do so.

I know that similar discussions were held in the past, but that may be hard to find these posts, so I wanted to make something "centralized" for this time. But links to old forum threads are also accepted.

Adventure Related Talk & Chat / Procedural detective game
« on: 02 Jan 2018, 20:42 »

I would like to tell about one idea that interests me. I had it for quite a long time in a form of random thoughts, but recently decided to go and try implementing this even if in a limited form, for starters.

This idea is of procedurically generated detective adventure game.

There was a pretty good number of procedural games in the past, so I guess everyone can imagine what is it in general. I've also seen procedural detective games before. Although I must admit that haven't played much of them, so cannot know many details, but the ones I've seen were mainly based on randomization of predefined roles and scenarios. While that may work perfectly for the game, my intention was to go further (or deeper), and instead of randomly granting every character a role (killer, victim, thief, witness, etc), grant them conflicting personalities and ambitions, that may randomly result in committing a crime under "fortunate" circumstances.

As such this is not only a game project, but also a research project about building a character AI. Or maybe even "story AI".

If you think above is a bit vague, let me give an example.

Imagine there is a mansion full of party guests. Each guest has particular personality traits and wishes assigned at the game's generation. Guests are wandering around the house, following certain rules (like avoiding restricted areas).
Consider one of the guests have a "cleptomaniac" personality, or maybe there is "financial problems" issue troubling them. This character enters a room with some "expensive item" on the showcase. A combination of character's traits and aims gives them a motive to steal the item. They wait for the right moment and do that. This is how the crime takes place.

The peculiarity of this approach that intrigues me much - is that since there are no predefined roles, not only player does not know who the criminal is, but even the game does not "know" that, until crime happened. In fact, there is always a theoretical possibility that more than one crime may take place (with different motives and participants), and maybe even sequences of events following first crime help another one to occur.

As with any AI, it is a matter to programmatically depict decision making. This game would require explaining such things through the code, as the concept of crime itself, clues, motives, ambitions and aims, personality traits and conflicts, and on advanced level - planning a strategy through assuming sequential events, manipulating other people, and so forth.

Obviously such approach also makes it harder to create a flawless scenario, but the challenge is perhaps the interesting part here.
The final goal of this potential project is to create AI that would be flexible and smart enough to generate an interesting game.

Following are the reasons why this project was screwed up from the very beginning. Just for the sake of history. I'd like to believe this may help someone to avoid same mistakes, but people seem to rarely learn on their own, so IDK.

Actually, I cannot think of anything that was made right here, from the first steps every mistake that could be made was made.

1. The problem with AGS was the reliance on old library that was already badly working on contemporary systems in 2012. Instead of immediately moving to better up-to-date library (SDL2 or Allegro5), or framework (like ScummVM) the old library was patched to somehow work on wanted platforms.
Usually the patching was performed by a single person. After such person took their leave, little information remained about their work, and whenever any kind of issue arised with the port, it took a lot of effort to figure out what to do.
Often the library was patched having only one particular port in mind. Sometimes a functionality was added right into this patch, different from the rest of the engine, causing inconsistences.

A lot of additional work related to device controls and graphic modes could be omitted, if we could rely on modern library. For example, I had to rewrite graphics renderers 5 or 6 times adding better display mode selection over those years.

The result: AGS is still based on same old library that work worse and worse on contemporary systems.

2. The problem of AGS was that Windows version was glued to particular old version of MSVS, which was even non-free. Instead of immediately looking for a way to remove that dependency, we kept it for several years.

Result: many potential contributors could not contribute because they could not even build it.

3. The problem with AGS was bad program code. Instead of immediately refactor it from top to bottom, this was only partially complete before we switched to compatibility fixes, and then - adding new functionality. Because of that a lot of time was wasted trying to hack new stuff into existing code. Supposedly, the bad code also scared away other potential contributors.

Additional moment: there was already a refactored code made by ScummVM developer, licensed under same license as AGS, which could be used, even if partially. But it was never used.

The result: AGS still has got a lot of non-refactored code which is barely known, and many features or fixes that were very wanted were never added because of that.

4. The problem with AGS was that the engine and editor contained a lot of legacy support that was practically useless for making game in current day, but cluttered up the code and made it difficult to develop it further.

Instead of splitting out legacy support into separate branch, we not only kept it in the engine, but increased its amount by adding support for even older games.
Because of this, adding any new feature required a lot of extra time, necessity to test whether ancient games still run with this engine after every update. This additionally mixed up with the non-refactored code producing more mess.

It may be hard to fully recognize consequences of this decision. A lot of system limits are there only because of legacy support and old plugin API support. There was a time when I spent over half of a year trying to remove these limits while keeping the legacy support, but in the end just threw the code out, so ugly it was.
Similarily, a lot of features could not be easily added simply because there was some fragile legacy stuff that could break.

Result: amount of time just wasted for nothing is impossible to calculate. Neither it is possible to know how much we could have done more if not for this.
Number of potential collaborators probably did not want to participate in project because of confusing code.

5. The problem with AGS was that with very little number of collaborators nevertheless we sometimes wasted time on something that could have been avoided. It was in our interests to take easier routes requiring less job where possible. Instead, the project started with one developer willing to write a class library specifically for AGS instead of using standard one. Another developer kept waiting several months for those classes, purposedly trying to avoid adding standard ones into engine. When it became clear that there will be none, instead of immediately switching to standard library, that second developer, for the reasons he cannot even explain today, decided to follow suggested idea and write these classes himself. In the end he did, kind of, but then realized that with them he will be drawned into maintaining utility classes instead of working on engine itself, so, again, just threw the code away. So, now we do use standard library, but nearly two years were lost.

This is only one such example. I could probably remember other not so useful stuff that I wasted time on, because someone said (in the end many things I did were not even added to the release).

6. The problem with AGS was the lack of automation. Everything had to be made manually. No automatic builds, let alone tests, nothing. If a person wanted to suggest features or changes, developers had to manually build and test their version to just make sure it compiles.
There was no way to know if all ports are still working or were broken by some of the recent additions except for building them all or waiting when someone tries to. And not everyone could build all the ports, naturally.
Making a full release package with all the data - demo game, templates, etc, - became such ordeal, that frankly, I tried to delay release every time until more changes accumulate, simply because I did not want to go through all this too often.

7. The problem with AGS was terrible organization. This was a project without actual leadership nor vision. There was no development plan, no documentation. Everyone just did some stuff as they see fit.
There was very little communication between game developers and AGS developers. With lots of ideas it was difficult to filter out things that were actually important to many people. A lot of critical nuances stayed unknown until occasionally mentioned years later.
A lot of tasks, even mentioned on forums, were never solved, even though several people could state their interest in that. Good example is this thread:
Just look at this:
Add spoiler tag for Hidden:
The help file is getting more and more out of sync with the actual Editor. <...>
The issue with the help file is that it's generated from some old LaTeX dialect, which in turn creates an old-school Windows help file (.chm files). <...>
We need to find a solution.
I can help.
I used to use pandoc and sphinx, I was passing on the AGS topics and this is the first thing I thought "I know how to automate this!"
Can someone point me the source files?
From 2014 to 2018, and it did not move anywhere. Meanwhile, this is not even related to engine code or C++.

If organization were better, perhaps a number of other problems not directly related to coding engine could have been solved. (e.g. this:
Simply because people could notice that such task exists.

This is long overdue, but recently my attention was brought again to this old post from 2014 (I think it is by one of the creators of Primordia):

It is nearly 2018 now, but all those issues still exist.

I answered this on gtihub back few years ago, but I guess no one noticed. Perhaps I should've try harder and post here, but, to be honest, don't remember if any game dev has ever asked me about this.


There is this command-line tool pack made by github user rofl0r back in 2012-13:

Among other things they can unpack and repack AGS game file.
A small caveat - they only known to compile under Linux, so probably might need be updated to compile under Windows too.

The solution to game patching is as following:
1. Provide a patch script and patch contents (e.g. in ZIP archive).
2. Patch script (written in any common scripting language, heck even batch for Windows system) -
2a. unpacks patch archive to folder P.
2b. runs unpacker tool to extract game data to folder G.
2c. copies patch files from P to G.
2d. runs packer tool to recreate game file with the new files of folder G.
2e. deletes temporary files.
3. Profit: you have a game exe with new contents.

EDIT: right, how to create patch in the first place:
a. You need to have two game files: old and new one.
b. Unpack both into folders O and N.
c. Compare the contents and find the files in N that do not match O.
d. Create a ZIP archive that onlu contains changed files.

This may be further improved by writing a simple GUI wrapper over those utilities.

Of course with current AGS package system you won't be able to replace certain items without replacing larger chunk. Sprites is the main problem here, because even inside game package they are stored as another monolithic file (sprcache.dat). Another thing is script modules: they are merged together with main game data (game, character, inventory descriptions, etc). Room files (CRM) have both room background, properties and scripts merged altogether. This is indeed something you cannot change without rewriting way AGS handles these.

Personally I would like to think there was an opportunity to have a continually developed runtime using the SCUMMVM backend, that does not maintain backwards compatibility and can have a few more contemporary features.
This is one of the possibilities. I had big doubts in the past, particularily because they did not have hardware-accelerated gfx support, which I'd like to have in AGS. But now they seem to have it, or so I heard.

There may actually be two variants here:
- develop AGS runtime as a part of their framework;
- only take their backends system and develop runtime separately (if that's technically and legally possible).

But I guess this all is a separate topic. [Done! –Snarky]

Sorry, that is kind of weird, what started very recently when I click on some forum links in posts leading to old threads (from 2011 - 2012), Google Chrome shows that red danger screen, and sais that -
"www. shuugouteki. net" is a dangerous site that may install malicious software. I have no idea what this site even is, because link clearly is pointing to***.

Going onto these threads step by step from the main forum page works well nevertheless.

What may this be?

AGS 3.4.1 released
Current release number:

Released: 23th December 2017

Previous stable version: AGS 3.4.0 forum thread

This release is brought to you by:

- Alan v. Drake
- ChamberOfFear
- Crimson Wizard
- Gurok
- monkey0506
- Ryan O'Connor (one bug fix contribution)
- Scorpiorus (improvements to plugin drawing system)

What is new in 3.4.1

Common features:
 - Upgraded Windows version of AGS with Allegro v4.4 library (previously v4.2).
 - Implemented "RenderAtScreenResolution" game setting. When enabled, characters and objects are scaled in screen pixels rather than game pixels. (NOTE: it was always enabled for Direct3D in the past, but now you can set it to your liking)
 - Implemented VerticalOffset and LineSpacing properties for fonts.
 - Removed limit on Dialog Topics (was 500 topics per game).
 - Removed length limit on the names of Inventory, GUI and GUI Controls.
 - Removed length limit on the names of Hotspots and Objects.
 - Removed length limit on event handler names.

 - Removed legacy game compiler.
 - Raw compiled game data is now saved in "Compiled\Data" folder, as opposed to just "Compiled".
 - The speech.vox file is now not recompiled if game is quick-run (using F5). Engine is supposed to find newer files in the Speech folder.
 - Editor can now import games older than 2.72, and newer too (3.*) if you have extracted data files from compiled executable.
 - ScriptAPIVersion and ScriptCompatibilityLevel settings now have "Highest" option, which is meant for automatically enabling newest script API when upgrading old project in a newer editor.
 - Added new "Default Setup" pane, which works similarily to "General Settings" and lets you configure default values for game setup.
 - Added "Font Height (pixels)" readonly property to the Font's pane, which works for both WFN and TTF fonts and may be used as a reference.
 - Made Editor correctly detect modern versions of MS Windows for display on About dialog and when sending anonymous statistics.
 - New application icon to comply with 3.4.0 splash screen.
 - Fixed crash when importing old games which have extended editor version string saved in the project files.
 - Fixed unhandled exception occuring when user types "#undef", "#ifdef" or "#ifndef" on the last line of the script.
 - Fixed #ifver and #ifnver not working properly if version number had only one component (major version).
 - Few improvements to the game compilation made in hope to reduce occasional data corruption.

 - Fixed local variables not working in the switch's case expressions.
 - Fixed Strings in switch, making them compare by value again.
 - Fixed compiler mistakes caused by the use of objects of empty type (that is - struct without any variables in it).
 - Fixed few cases of possible compiler crashing when there is an unfinished statement in the end of the script.

Script API:
 - A new parameter StopMovementStyle is added to following functions: LockView, LockViewAligned, LockViewFrame, LockViewOffset, UnlockView. This parameter can be eStopMoving (default) or eKeepMoving.
 - DynamicSprite.CreateFromFile and SaveToFile now support path tokens and comply to the new file path rules (no writing files to the game's installation directory).
 - Added missing readonly properties to get Lighting/Tinting parameters for Character and Object: HasExplicitLight, HasExplicitTint, LightLevel, TintBlue, TintGreen, TintRed, TintSaturation, TintLuminance.
 - Added Mouse.SelectPreviousMode() and Mouse.IsModeEnabled(CursorMode) functions.
 - Added readonly properties to get Button's animation state: Button.Animating, Button.Frame, Button.Loop, Button.View.
 - Added GetFontHeight(FontType) and GetFontLineSpacing(FontType) functions.
 - Added setter for System.Windowed property, letting to change it at runtime, switching between windowed and fullscreen modes.
 - Added System.RenderAtScreenResolution property to change sprite rendering mode at runtime.

 - Added OpenGL renderer to Windows version.
 - Added support for switching between fullscreen and windowed modes at runtime using Alt+Enter key combination.
 - All supported hardware-accelerated graphic drivers (Direct3D and OpenGL) now run every game in 32-bit display mode by default, and convert game's graphics on load if that is required. This fixes loss of green hue precision in 16-bit games and allows to run 8-bit games, although latter is only partially supported: there are color mismatches and dynamic palette cycling is not working.
 - Partial support for plugins drawing on screen for hardware-accelerated renderers (Direct3D, OpenGL).
 - Added support for global configuration file, which works as configuration for all games and overrides default game's config file. Individual game user's config overrides global one in its turn. Global config's location is platform-dependent (this feature is currently disabled on Windows).
 - Implemented separate config option for game's shared data path, to keep it distinct from user-defined saves path.
 - Engine saves last Windowed and RenderAtScreenResolution mode states to the user config file.
 - Engine no longer writes and reads gamma level in saves, meaning that gamma keeps its current value when restoring a saved game.
 - Removed arbitrary limit on number of sprites rendered at the same time for hardware-accelerated renderers (Direct3D and OpenGL) (was 75), and another limit imposed on drawing entries for all drivers (was 200).
 - Engine now tries to get voice files from the Speech folder first, if one exists, and speech.vox later when quick-run from the Editor.
 - Fixed speech portrait was displayed below GUI, contrary to speech text.
 - Fixed ShakeScreen command was causing graphic artifacts when game is run with software renderer.
 - Fixed calling Character.ChangeView during idle animation results in new view being animated.
 - Fixed Speech.SkipStyle getter return value for eSkipTime case.
 - Fixed Speech.VoiceMode not returning correct values when speech.vox is not enabled/present.
 - Fixed AdjustVolumeWithScaling character's property not working with the new audio system.
 - Fixed volume drop was not applied to audio clips which begin playing during speech voice-over.
 - Fixed Game.SetAudioTypeSpeechVolumeDrop did not affect currently playing clips until next voice-over begins.
 - Fixed Game.TranslationFilename returning "default" instead of empty string if no translation is set.
 - Fixed engine was trying to locate "My Documents" folder on Windows Vista and higher even though it did not need it, and reporting internal error if such folder was not found, even though "Saved Games" folder is used instead.
 - Properly toggle console upon play.debug_mode variable change in script.
 - Added missing stubs for agsjoy plugin.

 - Fixed display mode selection was missing certain items.

KNOWN ISSUES (to be updated)

- Need to make mobile ports (Android, iOS) work with this version.
- When using Direct3D, game misses 1 bottom row and 1 rightmost column of pixels of game image when "Render sprites at screen resolution" is OFF. This also might cause slight image distortion.
NOTE: there's a suspicion that that is a bug in Microsoft's Direct3D driver since Windows 7.
- When running game in OpenGL fullscreen system cursor may be visible when over black borders.


Latest source code may be found here
Git cloning address:

Module supports AGS 3.4.0 and higher

Other script modules by me:
Add spoiler tag for Hidden:

Quick pre-word

Few months back I urgently needed a Timer module with certain functionality, and was hoping to download monkey0506's Timer module, but official links were broken (later I found the only working link, but it lead to an old version). So I wrote my own alternate variant, and posted an initial code in the same thread.

I made certain decisions, such as creating a managed class which you have to operate through pointers, that may cause controversy (this clearly has both advantages and disadvantages).  Even now I keep having doubts about that. In theory it could be possible to remake it into non-managed class if people will find this not convenient (although there may be complications related to AGS scripting limits).
I also do not know whether monkey0506 had any plans on his own module; I would not mind even merging our modules at some point.


The Timer module addresses an issue of built-in timers in AGS: that may be difficult to ensure that you do not reuse same timer for different purpose.
Add spoiler tag for Hidden:
In AGS timers are identified with numbers; this is not a problem on its own, because you can always declare a named constant with #define (like "#define TIMER_BOMB 1") and use that instead. What is the problem, that these IDs are all sharing same "namespace". Basically, you are not creating your own timers, you are reusing same ones from the single list of timer "slots". And there is little way to guarantee that you do not start timer N in another place while the previously created timer N is still running. This requires coder's discipline and planning, but in the big project may become tedious. Additionally, that complicates using timers in the modules and templates (module writer would have to let people customize timer ID's to make sure they don't conflict with anything in game).

Timer class solves this issue, because you are no longer forced to use same available X timers from the list, but can create any number of Timer variables.

For AGS-related technical reasons there is however a limitation: only finite number of timers may be run at the same time. This number is 20 by default, but may be changed at will.
Add spoiler tag for Hidden:
The real problem in AGS is that it's impossible to call repeatedly_execute function explicitly for the managed object, we have to use global repeatedly_execute and call object updates from there. Which in turn means that the module must keep references to active timers in an array.
Of course I could implement self-resizing array, but thought that timers are not kind of things that might need such effort. This still may be done in a future update though.

Timer is implemented as a managed class, which means that you need Timer* pointers to work with it (similar to Character*, DynamicSprite* and so on). This requires certain attention from coder, because pointers may be "null"; on the other hand this lets you to pass Timer object as a function parameter, or return it from a function as return value (something you cannot do with basic structs in AGS).

Timer supports timeout defined in either game ticks or real time. When defining it in real-time you need to keep in mind that the timer's precision depends on FPS (game speed). If your game is running at 40 FPS then the timers are updated only once per 0.025 second (25 ms). In such case setting timeout to, say, 10 ms, won't do much sense (it will still expire after 25 ms).

Timer can be run once (default behavior) or be repeating. Repeating timers will reset themselves after every timeout and never end running. You must remember to stop them yourself when you no longer need them (this is especially important considering that number of running timers is finite).

Timer can be paused and resumed at will. Additionally, you can require all or certain timers to pause and resume with the game (when PauseGame/UnPauseGame is called).

Timers can also be created as local. Local timers remember which room the player was in when they started, and work only while player remains there. If player leaves that room, local timer will stop (default action) or pause. Timers paused this way will resume automatically when the player returns back to their "home" room.

NOTE: From the technical side, it does not matter whether variable is declared in room script or global script, either can be used to make both global and local timers. But remember that if a Timer* variable is in the room script then you won't be able to use it (e.g. stop the timer) and check it for expiration when the player is in another room. Unless that's exactly what you want, better have Timer* variable in the global script.

Since there are three causes for the timer's pause, - script command, autopause with PauseGame and autopause for local timer, - following rule is applied for unpausing the timer: timer only resumes when all three conditions are allowing to. For example, local timer which is configured to automatically pause with the game, will only unpause when in correct room AND game is not paused. If you additionally pause that timer yourself, it will require you resuming it, but resuming the timer in wrong room still won't unpause it until correct room is loaded.

Using Timer

Alright, now to the actual scripting.

Timer pointers are declared simply as:
Code: Adventure Game Studio
  1. Timer *MyTimer;
  2. Timer *tBomb;
  3. Timer *ALotOfTimers[100]; // array of 100 timer pointers

These are pointers, but timer objects are not created yet.

Here is how you create and start the new timer:
Code: Adventure Game Studio
  1. MyTimer = Timer.Start(50); // create a timer that runs 50 game ticks
  2. tBomb = Timer.StartRT(10.0); // create a timer that runs 10 seconds (regardless of game speed).
  3. // RT - means "realtime" ;)
  4. // In case you wondered, you can pass value less than second -
  5. MyTimer = Timer.StartRT(0.3); // this timer will run for 0.3 seconds, or 300 milliseconds
  7. // Creating repeating timers -
  8. SignalTimer = Timer.Start(40, eRepeat); // this timer will "expire" every 40 ticks and run again
  10. // Creating local timers -
  11. RoomTimer = Timer.StartLocal(2000); // this timer will run for 2000 game ticks OR until player leaves the room
  12. ResumingRoomTimer = Timer.StartLocalRT(60.0, eTimerPause); // this timer will run for one minute, but pause if player leaves the room
  13. AnotherLocalTimer = Timer.StartLocal(40, eTimerPause, eRepeat); // repeating local timer
  15. // Making the particular timer automatically pause with the game
  16. SignalTimer.PauseWithGame = true; // do this only after you created one, duh
  18. // Or maybe you want ALL of the timers in the game to pause when game is paused?
  19. Timer.AllPauseWithGame = true; // better do this once in the game_start()

Checking for timer's expiration is done using either of two ways.
First of all you may check timer's property EvtExpired. But because you are using timer pointers, normally you would need to first test if the pointer is not null (unless you are absolutely 100% sure it will always be created at that point):
Code: Adventure Game Studio
  1. if (tBomb != null && tBomb.EvtExpired)
  2. {
  3.     Display("BOOOOM!!!");
  4. }

Another method takes into account the pointer fact, and works as a static function which safely manages even null pointers:
Code: Adventure Game Studio
  1. if (Timer.IsExpired(tBomb)) // you may pass even null-pointer there
  2. {
  3.     Display("BOOOOM!!!");
  4. }

IMPORTANT: the way EvtExpired works is slightly different from built-in AGS timers.
* In AGS this flag is valid until you check it.
* In Timer module this flag is valid until the next game update. This means that you may check same timer several times, but cannot wait to check it later.

At any point in time you may test if the timer is still existing/active like this:
Code: Adventure Game Studio
  1. if (tBomb != null && tBomb.IsActive)
  2. {
  3.     // bomb is still ticking
  4. }
  6. if (tBomb == null || !tBomb.IsActive)
  7. {
  8.     // bomb timer is either did not start yet, or already run out
  9. }

Pausing and stopping a timer is done with the other static functions.
(I was considering to add non-static counterparts but did not make them for now)
Code: Adventure Game Studio
  1. Timer.Pause(MyTimer); // pause it
  2. ...
  3. Timer.Resume(MyTimer); // resume it
  4. ...
  5. Timer.Stop(MyTimer); // stop it completely
  6. // After timer was stopped it is completely useless
  7. MyTimer = null; // you may even nullify pointer now

Speaking of deleting a timer, as was said - only running timers number is finite. As with other managed objects, the timer object will be only deleted after all pointers referencing it are nullified You are not obliged to do this, because timer object is small. Also, if you will assign new timer to same pointer, the old object will be safely removed from memory. But if you know that you won't be using same pointer for a while (or no longer in this game), I'd suggest to do that.

Finally, there is a way to get some information about running timer:
Code: Adventure Game Studio
  1. function repeatedly_execute()
  2. {
  3.     if (tBomb != null && tBomb.IsActive)
  4.     {
  5.         Label1.Text = String.Format("Ticks left: %d, seconds left: %.3f", tBomb.RemainingTicks, tBomb.RemainingSeconds);
  6.         if (tBomb.IsPaused)
  7.             Label2.Text = "Bomb is paused";
  8.         else
  9.             Label2.Text = "Bomb is running";
  10.     }
  11. }

Possible problems

1. Prematurely clearing or replacing pointer value.

The timer object you have in the pointer variable is the only way to control it. For the technical reasons the module itself also keeps a reference to every running timer. This means that if you nullify your pointer variable (or assign another timer to it) before the previous one has stopped, not only you won't be able to control the previous timer anymore, but the timer is not going to be deleted immediately and keep running.

For one-time timers that may not be a big issue, because they will stop on their own eventually and get deleted by the module's update function. But leaving repeatable timer like that will make it run forever, occupying a slot.

So - always Stop a timer when you no longer need it (unless it has already expired and stopped, that is).

2. Timers in non-state-saving rooms.

AGS has two types of rooms, and non-state saving rooms are special in that they do not keep their data when player leaves. What this means is even the variables are lost.
But as explained above, the Timer is a managed object, and will be kept in memory as long as there is at least one pointer referencing it. And the module itself keeps references to all running timers.

So here comes the possible issue: if you have a Timer* variable in non-state-saving room, and created a timer there, as soon as player leaves the room you will loose control over that timer. If it were repeatable timer, it will also keep running forever, as noted in problem 1).

If you need a timer in non-state-saving room:
* If you want a global timer, make a variable in global script, not room script;
* If you want a local timer that will RESUME when you return to the room, STILL declare a variable in global script. This way you will keep pointer to that timer when return to that room again.
* If instead you want a local timer that stops when player leaves the room, then just create it with eTimerStop parameter as usual, and it will get deleted properly.

Timer API reference

Code: Adventure Game Studio
  1.   // Maximal number of simultaneously running timers (not related to built-in AGS limit).
  2.   #define MAX_RUNNING_TIMERS 20
  4.   // Local timer behavior when room has changed
  5.   enum LocalTimerBehavior
  6.   {
  7.     eTimerPause,
  8.     eTimerStop
  9.   };
  11.   // Flags determining the reason for timer's pause (can be combined using bitwise OR)
  12.   #define TIMER_PAUSED_BY_USER 1
  13.   #define TIMER_PAUSED_BY_GAME 2
  14.   #define TIMER_PAUSED_BY_ROOM 4
  17.   //
  18.   // General operations.
  19.   //
  21.   /// Start the timer, giving timeout in game ticks.
  22.   static Timer *Timer.Start(int timeout, RepeatStyle repeat = eOnce);
  23.   /// Start the timer, giving timeout in real time (seconds).
  24.   /// Remember that timer can be only as precise as your GameSpeed (40 checks per
  25.   /// second, or 0.025s by default).
  26.   static Timer *Timer.StartRT(float timeout_s, RepeatStyle repeat = eOnce);
  27.   /// Starts local timer working in game ticks, that may be paused when player leaves the room
  28.   static Timer *Timer.StartLocal(int timeout, LocalTimerBehavior on_leave = eTimerStop, RepeatStyle repeat = eOnce);
  29.   /// Starts local timer working in real time (seconds), that may be paused when player leaves the room
  30.   static Timer *Timer.StartLocalRT(float timeout_s, LocalTimerBehavior on_leave = eTimerStop, RepeatStyle repeat = eOnce);
  32.   /// Tells whether timer has JUST expired. Safe to pass null-pointer.
  33.   static bool   Timer.IsExpired(Timer *t);
  34.   /// Stops the running timer. Safe to pass null-pointer.
  35.   static void   Timer.Stop(Timer *t);
  36.   /// Pause the running timer. Safe to pass null-pointer.
  37.   static void   Timer.Pause(Timer *t);
  38.   /// Resume the running timer. Safe to pass null-pointer.
  39.   static void   Timer.Resume(Timer *t);
  41.   //
  42.   // Additional setup.
  43.   //
  45.   /// Gets/sets whether all timers should pause when game is paused
  46.   static bool  Timer.AllPauseWithGame;
  47.   /// Gets/sets whether this particular timer should pause when game is paused
  48.   bool Timer.PauseWithGame;
  50.   //
  51.   // Current state inspection.
  52.   //
  54.   /// Tells whether timer is currently active (counting down).
  55.   readonly bool  Timer.IsActive;
  56.   /// Signal property telling that the timer has expired. This flag will remain set
  57.   /// for one game tick only and self-reset afterwards.
  58.   readonly bool  Timer.EvtExpired;
  60.   /// Gets the home room of the local timer (returns -1 if timer is global)
  61.   readonly int  Timer.HomeRoom;
  62.   /// Gets what this timer should do when home room gets unloaded
  63.   readonly LocalTimerBehavior Timer.WhenLeavingRoom;
  65.   /// Gets whether this timer is working in real-time
  66.   readonly bool  Timer.IsRealtime;
  67.   /// Gets the timer's timeout in game ticks
  68.   readonly int   Timer.TimeoutTicks;
  69.   /// Gets the timer's timeout in real-time (considering current game speed)
  70.   readonly float Timer.TimeoutSeconds;
  71.   /// Gets the remaining time in current game ticks
  72.   readonly int   Timer.RemainingTicks;
  73.   /// Gets the remaining time in real-time (considering current game speed)
  74.   readonly float Timer.RemainingSeconds;
  75.   /// Gets current timer's paused state (0 - working, >= 1 - suspended)
  76.   readonly int   Timer.IsPaused;

Crimson Wizard and Jim Reed present:
(made for MAGS Novemeber 2017)

Last & Furious

Download links:

Project source licensed under Creative Commons: By Attribution 4.0 (except music, which has its own authors and licenses)


'Last & Furious' is a top-down racing game, featuring single track, two physics modes, wonky collision system and hastily set up opponent AI.

Controls: arrow keys.
Car behavior: can thrust forward, steer and brake (no backpedal, sorry).
Physics setup: when starting new race choose between "Safe" and "Wild" physics mode (they will give you two different experiences!). It is also possible to disable car-vs-car collisions (they still collide with the walls though).

Physics model in this game is actually configurable. If you feel adventurous, go to "Data" subdirectory. There you will find "race_safe.ini" and "race_wild.ini" files which contain parameters for related game modes.

Code: Crimson Wizard;
Art: Jim Reed (was also generating tech ideas);
Music: "Car Theft 101" by Eric Matyas (, "Welcome to the Show" by Kevin MacLeod (

Game DB page:

Well, damn, looks like I just run into one of those obscure AGS bugs. Took me several hours to, first, realize that could not be a mistake in my script, and then find out why is it happening exactly, staring into the engine code.

Following example is based on default game template.
Room 1 script:
Code: Adventure Game Studio
  1. // room script file
  3. DynamicSprite *Sprite;
  5. function room_Load()
  6. {
  7.   Sprite = DynamicSprite.CreateFromExistingSprite(2000);
  8.   ViewFrame *f = Game.GetViewFrame(player.View, 0, 0);
  9.   f.Graphic = Sprite.Graphic;
  10. }
  12. function on_key_press(eKeyCode key)
  13. {
  14.   // These lines cause the bug ======
  15.   //if (Sprite != null)
  16.   //Sprite.Delete();
  17.   // ================================
  19.   DynamicSprite *new_sprite = DynamicSprite.CreateFromExistingSprite(2000 + Random(9));
  20.   Sprite = new_sprite;
  21.   ViewFrame *f = Game.GetViewFrame(player.View, 0, 0);
  22.   f.Graphic = Sprite.Graphic;
  23. }

So, this code is very simple. What it does:
- It takes certain View frame, and replaces original sprite with dynamic sprite, which in turn is a copy of some character sprite.
- On every key press it creates NEW dynamic sprite from the random range of character sprites, and puts it to same View frame.
Don't bother wondering why would I need such script, that's just an example of certain actions.

Run the game and hold any key (e.g. space bar). Character's image will beging to cycle randomly.

Now, the interesting part. See these commented lines where the previous sprite gets explicitly DELETED before assigning new sprite to the same pointer? Thinking logically, that should be right thing to do, and should be safe to assume that nothing bad is going to happen?

Well, uncomment these lines:
Code: Adventure Game Studio
  1. if (Sprite != null)
  2.     Sprite.Delete();
and run the game again. Hold space bar, and... you see that character's looks do not change anymore.
HOWEVER, if you walk a little and then make Roger take original direction, you will see, that the frame 0 sprite actually is different. So it DOES change after all, it's just that AGS did not redraw it in time.

So, why is this happening, and how can DynamicSprite.Delete make any difference?

AGS has character cache, where it stores last character's image with additional effects (tint, lighting, area zoom) applied. On every update it checkes whether anything has changed and if not - it keeps cached sprite.
When you create NEW dynamic sprite, and assign it to the view frame, the number of sprite is now different from old one, so AGS knows that it needs to reset cache.

But when you delete an old sprite FIRST, its SLOT number frees, and the next dynamic sprite gets created on the SAME SLOT, having same index as the old one has had! And AGS cannot detect that the change happened!

To prove this point, change the code:
Code: Adventure Game Studio
  1. function on_key_press(eKeyCode key)
  2. {
  3.   // Temporarily keep an old sprite in another pointer
  4.   DynamicSprite *old_sprite = Sprite;
  6.   DynamicSprite *new_sprite = DynamicSprite.CreateFromExistingSprite(2000 + Random(9));
  7.   Sprite = new_sprite;
  8.   ViewFrame *f = Game.GetViewFrame(player.View, player.Loop, player.Frame);
  9.   f.Graphic = Sprite.Graphic;
  11.   // Now delete the old sprite by referencing the temp pointer
  12.   if (old_sprite != null)
  13.     old_sprite.Delete();
  14. }

If you run this code and hold space bar, the character will be animating again.

Now, the above is just a dummy script example. If you have a more complicated script, with multitude of dynamic sprites, where you cannot reliably keep track of when the old slots are freed (or rather do not want to do that), for that case I found another workaround to force AGS reset character cache:

Code: Adventure Game Studio
  1. DrawingSurface *ds = Sprite.GetDrawingSurface();
  2. ds.DrawPixel(-1, -1);
  3. ds.Release();

Thing is that when DrawinSurface.Release is called, it checks all (supposedly) places where this sprite could be used, and releases all related caches. But some drawing operations MUST be complete to make it do so! Hence we just draw one pixel outside of the sprite. While sprite physically stays unchanged, DrawingSurface object registers modification.

Now this will work too:
Code: Adventure Game Studio
  1. function on_key_press(eKeyCode key)
  2. {
  3.   if (Sprite != null)
  4.     Sprite.Delete();
  6.   DynamicSprite *new_sprite = DynamicSprite.CreateFromExistingSprite(2000 + Random(9));
  7.   Sprite = new_sprite;
  8.   ViewFrame *f = Game.GetViewFrame(player.View, player.Loop, player.Frame);
  9.   f.Graphic = Sprite.Graphic;
  11.   // Poke AGS to make it reset sprite cache
  12.   DrawingSurface *ds = Sprite.GetDrawingSurface();
  13.   ds.DrawPixel(-1, -1);
  14.   ds.Release();
  15. }

The actual reason for this bug is that when DynamicSprite gets deleted, it does not clears related CHARACTER caches. Which is very strange, because it clears GUIs and Room object caches. This makes me think that there could be a simple oversight.

Also, that bothers me, but I have a suspicion that if you don't call DynamicSprite.Delete, but simply overwrite pointer with new sprite, the actual bitmap does not get deleted and stays in system memory (aka "memory leak"). This is explicitly coded so in AGS engine, and I cannot understand why. This might require a separate research.

Recruitment / [HELP FOUND] Artist for a small MAGS project
« on: 03 Nov 2017, 22:39 »
Hello :).

I decided to try making a game for November MAGS, and for that I am looking for a 2D artist.

This is going to be non-adventure, arcade sports (kind of) game, which requires top-down view sprites and backgrounds, featuring simplified (may be tiled) contemporary landscape and objects (vehicles, people, etc).

Game resolution is not set, since it mainly depends on art it may be anything you can handle. I'd prefer to have at least 640x400 if possible, but that's not critical.

Personally, I am going to script the thing, but will be open for any good ideas and suggestions on game design.

I have to frankly admit that sometimes get busy with urgent tasks in my life, but even if we won't make it to the MAGS deadline, I will be willing to release this game anyway.

Please PM me if you are interested, and I will tell you more details about the game.

UPD: I found someone, thanks to everyone who PMed me :).

Engine Development / Debugging AGS engine in MSVS 2015
« on: 14 Oct 2017, 18:25 »
I always had this issue when debugging AGS engine in Visual Studio before: when you break the program execution (e.g. by placing a breakpoint in the code) there was always a delay of few seconds before VS begins to respond to mouse and keyboard input, like if something is locking the input. It was happening only once per debug session, when you break the program for the first time. I had a suspicion that it has to do something with how Allegro 4 works, but could never find anything related in the internet. That was mildly annoying, and in the abscence of solution I decided to just live with it.

Now when we switched to MSVS 2015 in the master branch, this issue became much worse. This input freezing does not go away. It looks like this: program stops at breakpoint, and everything seems to be okay: no extra CPU load, the cursor is flickering in the VS as normal, but as soon as I touch the mouse or press any key, everything freezes for several seconds. This repeats every time after any signal from input device. If I move mouse too much at once I have to sit and wait for a minute before I can even shutdown debugging session forcefully.

Apparently it affects whole system, not just MSVS, because switching to other program windows does not help.
I only found one possible workaround: if I start or continue debugging, then switch to another application quickly, before next breakpoint is hit, everything works normally. But doing this trick really wastes my time alot, besides it's a game of chance.

So, right now I am almost unable to debug the code in the master branch using MSVS debugger.

What confuses me also is that since we changed to MSVS2015 there had to be other people who also tried building and running the engine. Have anyone else noticed similar thing, or it's just me?

I remember finding some kind of solution in the web a long while ago, something about hacking a registry, and IIRC that kinda worked (although not 100%), but seems bit unreliable to me, also unfortunately I forgot what it was and how to search for it.

NOTE: this does NOT occur when debugging Editor, even if I put breakpoints in C++ native code.

EDIT2: After further testing I can confirm, a call to Allegro's function install_mouse causes mouse issues in the debugger, call to install_keyboard locks up keyboard input inside MSVS correspondingly.

EDIT3: Finally was able to find the threads on Allegro forums, confirming and explaining this issue:

Allegro grabs the system keyboard and mouse. So when the game crashes or reaches a breakpoint, the IDE pops up, but all mouse movements and keyboard events have a several seconds lag because the allegro handlers simply do not answer. Mouse buttons do not work at all. Imagine to single step like that.

Another couple of descriptions of the similar problem. I am not completely sure if the cause is same, but description of the symptoms match:

Following package contains latest prebuilt libraries:

- for the Windows engine 3.4.1 (built with VS2008)
- for the Windows engine of master branch (built with VS2015).
- for the Editor of master branch (.NET 4.0 compatible third-party assemblies that need to be copied to References folder)

We probably may find a better place to host these later.

Site & Forum Reports / AGS Error reports
« on: 28 May 2017, 15:48 »

There is a "send report" feature in AGS Editor; user may press a button on error message form to send report to server.
Report is sent to:

Is this feature still works on server side, and is it possible to read sent reports? Right now this functionality seem to be completely useless, because developers cannot access these reports.

General Discussion / Babylon.js game framework
« on: 25 May 2017, 01:46 »
I've never programmed for Web in any way, except for some experiments with HTML and jscript (I think?) more than a decade ago, but recently a former co-worker suggested that I could learn a WebGL framework called Babylon.js to occasionally aid him with some stuff.

Babylon.js is a framework written in TypedScript (which is a kind of JavaScript extension) which works with HTML5 and WebGL. Basically it is a thing to create 3D scenes and games, presentations, etc. This framework is open source too, and 100% free (from what I saw). Their website even have a "sandbox" where you may try out some smaller scripts before making a bigger project.

I do not remember if I ever programmed in JavaScript before, which is a shame I guess; the language appeared to be easy and pleasant to use. There is a very good JS refernce provided by Mozilla, and if you know at least any C-like or other scripting language (even AGS script :) ) you should get into it in no time.
Of course one would have to learn a bit about working with 3D space first, even if you want to make 2D games there (I believe latter should be possible, although I haven't found orthogonal (2D) camera preset yet).

Compared to Unity3D, it does not provide any IDE (Editor). Although you may use some tool to work with JavaScript, like Visual Studio, or another, but that's not required (you may use just a text editor). To run your game you need just an up-to-date browser (you may even create standalone version and run offline if you download Babylon engine files from their site).
This has natural advantages and disadvantages. I think it is easier to create quick prototypes, because you do not need to install Editor and C# tools. On other hand, lack of default visual editor may make more advanced scenes harder to work with. Depends on how you do things, I guess.

Anyway, I spent few days doing tutorials and created this don't-yet-know-what-is-it prototype:

This is just an HTML file, you need to be online to run it because it references Babylon engine from their website. But all my script is right in HTML's body and may be viewed in any text editor. It's a bit mess for now, because I haven't tried to organize it properly, splitting into js files etc. It does not do much for now anyway.

Controls are:
* hold LMB and move mouse to rotate camera
* same with CTRL - move camera
& Mouse wheel - zoom in/out.
* A/S - rise and lower map tiles under cursor
* SPACE - set "marker" thingie on the tile under cursor.
* F5 - restart (obviously)

Engine Development / How large FLIC movies can be?
« on: 15 May 2017, 21:11 »
I've met another trouble with removing hacks from AGS to be able to update it keep every port with latest version of Allegro. I described it here:

In short, there is only one way that will work on all platforms for now: to load up whole FLI movie into memory and play it that way. How good is that? Depends on how large flics are. Is there any limit for them?

Alternatives are:
- patch Windows version of Allegro and let it play FLI from custom game package. But other ports will work only if FLI video is lying in game directory as external file. This effectively breaks all the existing games with FLI videos, until someone rips FLI out of package.
- find another library that plays FLI and add its as a new dependency to AGS.
- copy whole FLI player into AGS.

Engine Development / OpenGL renderer for Windows
« on: 10 May 2017, 23:24 »
I finally seem to make OpenGL work in any display mode under Windows:

"OpenGL" should be available in drivers list in winsetup.

I believe understand making scenes in 3D better now... and also learnt that with 3D it is so much easier to do a lot of unnecessary and duplicating operations, with coordinate translations and camera positioning countering each other. Until you change something you do not notice that.

If I can find time, I may try to make it work on Linux too, because Linux port was suffering from lack of hardware-accelerated renderer all those years.

Engine Development / Giving away the control on project
« on: 01 May 2017, 20:50 »
So, I was not following the thread I myself started for a while, and I do not attend AGS chats (not even sure how many of them are). But from what I know from discussion on github, Alan decided to make next version of AGS stripped of legacy stuff (obsolete features, script commands, and so on).

There may be an argue on what should be considered obsolete and removed, but that's not the point of my post.
The point is that do not want to be the one who controls the project and determines its goals anymore. Putting this simply, I do not want to keep being responsible for this. Think what you want about it; but I am tired and full of doubts.

Currently, the list of repository management is as following:

Administrators (these can add/remove other people and do some highest administration tasks): JJS, me, Nick Sonneveld.
Committers (these can push changes to the code without having to make pull requests): me, Gurok, monkey0506, BigMC, tzachs.

I could add Alan to committers and let him do as he plans. I could also add anyone else, if that would be wanted.

For myself, I would like to retain release-3.4.1 branch, where I finish making AGS 3.4.1.

I was trying to upgrade AGS Editor project to MSVS2015, because C# contributors are very restricted with the old VS2008 projects; then I found out that VS2015 does require C++ projects to target .NET 4.0 by default.

We still have C++ component in the editor, AGS.Native.dll. I experimented a bit, trying to build it with .NET 2.0 or 3.5, but it did not work, because of conflicts between 2.0 Framework and new modern CRT libraries (or so it seems).
I found few unclear answers in the web, which hint that it may be still possible to do, but all this look pretty unguaranteed.

Sorry for all the tech details, I'll get straight to the point.

According to the web, Windows XP still support .NET 4.0 (not 4.5 though), but only if you have Service Pack 3 installed. SP2 support was dropped by Microsoft back in early 2010-ies.

So I wonder, is there anyone who still uses XP SP2 without possibility to upgrade to SP3? What are the chances such AGS users exist?

Seriously, does it? It will soon be FIVE years as I work on it, and haven't yet reach much of the goals we set up when we started. It is still old tech, still mostly software drawing, still no unicode support, and so on and so on.
And project is practically dead. with nearly zero organization, no planning, and no one willing to contribute.

Am I using my time for good purpose, or just wasting it? The efficiency of my work here is incredibly low. People are leaving for other better engines all the time.

For example, there is this Adventure Creator for Unity. I think it was made by people who once worked on AGS games:

It already has much much more than AGS.

And what I do seem to be simply stupid.

Yes, maybe I can try to force some more stuff in AGS, but what's the point? I will never be able to do anything even closely as good.

I think, the only reason why I am still here was that always felt the urge to prove that I can do something good. Since I was failing to reach the defined goals, it kept backfiring. In the end, I feel like I gained nothing from this work, except for endless frustration and despair.

I need to find some other work to put my efforts to, where I would be more productive.

Pages: [1] 2 3 ... 11