Menu

Show posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Show posts Menu

Topics - Gurok

#21

The Jimi Hendrix Case

Enter the world of Jimi Hendrix, police detective. In a world where everyone is Jimi Hendrix, only Jimi Hendrix can piece together clues and find who killed Jimi Hendrix.

Created for MAGS July, 2015.











>> Download here <<


#22
I don't know how tough this would be to implement, but it would be nice if profiles of users with games in development could have links to the threads of games they're currently working on. Sort of like how finished game credits are listed now. Oftentimes I'll pull up someone's profile, realise they have a game in development but have no way (other than a tedious Games in Production search) to find it. I would do it by writing a query for all threads opened by that user in the Games in Production forum that haven't been locked :D. Don't know how hard this is to add.
#23
If you've ever wanted a *really* efficient way to generate a set of shuffled numbers, then this is the module for you.

Shuffler contains a single function called sequence. You call it like so:

Code: ags
int myArray[ ];

myArray = Shuffler.Sequence(10);


The result is that myArray contains 10 numbers (0-9) in a random order. e.g. (2, 5, 7, 3, 9, 0, 6, 1, 8, 4)

The array will always contain all of the numbers that make up a sequence starting at 0 and ending at N-1 where N is the array size you specified.

It works by using linear feedback shift registers. You can read more about them here.

You can use this function for a variety of things. For instance:

  • Arranging 10 products in a different way on a shelf each time the player plays your game
  • A minigame where the player has to match a random pattern, with one additional step revealed each round
  • A lottery or bingo minigame where every number can be drawn
  • Better emulation of Sierra's dissolve effect (the one with boxes)
  • A shuffled deck:
Code: ags
String GetCardName(int index)
{
	String suit;
	String face;
	int value;

	value = index / 13;
	if(value == 0)
		suit = "spades";
	else
		if(value == 1)
			suit = "hearts";
		else
			if(value == 2)
				suit = "diamonds";
			else
				suit = "clubs";
	value = index % 13;
	if(value == 0)
		face = "ace";
	else
		if(value == 10)
			face = "jack";
		else
			if(value == 11)
				face = "queen";
			else
				if(value == 12)
					face = "king";
				else
					face = String.Format("%d", value + 2);

	return(String.Format("The %s of %s", face, suit));
}

function DrawDeck()
{
	int list[ ];
	int index;
	String output;

	list = Shuffler.Sequence(52);
	output = GetCardName(list[0] + 1);
	for(index = 1; index < 52; index++)
	{
		output = output.Append("[");
		output = output.Append(GetCardName(list[index] + 1));
	}
	Display(output);

	return;
}


Note: If you run DrawDeck in the example above, you'll notice one of the limitations of linear feedback shift registers. The code will most likely give you a different shuffle each time you run it, but you might notice similarities between two shuffles. e.g. One may appear to be a shifted version of another.

You might be thinking, hang on, this module is a huge chunk of code. Why would I use this instead of a naive approach (like choose a number, scan the list to see if it's already been chosen, if so, choose again)? And to top it off it's also flawed (see note above).

Well, it's fast. VERY fast. In computer science terms, its speed is also pretty well defined. Big O for this algorithm is just under 2N. That means at worst, it performs half as well as a linear function. The naive alternative? That might run forever.

It's also predictable. There's a second parameter to the Shuffler.Sequence function that lets you specify a seed number. A seeded sequence is guaranteed to give you the same sequence for that seed every time. That means you can save an entire sequence by saving a single number. The limit for seed numbers is the next power of 2 above your chosen limit. So for 52, unique seed numbers are 1-64 and they repeat after that. 0 means let Shuffler choose one.

Download here:



(Requires AGS 3.4.0.3 or better)
#24
Over the past few weeks, I've been looking through a rather large AGS project being migrated from 3.3.3 to 3.4.0. One of the bugs reported was an apparent failure of DynamicSprite::CreateFromScreenShot. I managed to reduce this down to a pretty simple test case:

Code: ags
// Ensure alpha blending is set to "Proper Alpha Blending" under settings

DynamicSprite *sprite;

function room_AfterFadeIn()
{
	sprite = DynamicSprite.CreateFromScreenShot(); // This should be a screenshot of the room
	Button1.NormalGraphic = sprite.Graphic; // Button1 is a button on gGui1
	gGui1.Visible = true;
}


Under 3.3.3, the code above shows a screenshot of the room.
Under 3.4.0, the code above shows the background of the GUI (grey by default).

For convenience, I've made test projects for 3.3.3 and 3.4.0 you can download here: http://goo.gl/qOaDFp?gdriveurl
(It's the same code in both projects, just a slightly updated project file for 3.4.0.)

At first, I suspected problems in either of two areas that were changed fairly recently: the alpha blending code or the DirectX back buffer code. A little more poking around revealed that the blending code was fine. I mangled the code a bit, incorporating the stuff that was there before CW's recent changes and the outcome was the same. The reason why screenshots weren't being drawn was a transparent alpha channel (0x00) on screenshots.

I also found the alpha channel was 0x00 in both DirectX 5 and DirectX 9 mode, so I'm tentatively ruling out the back buffer changes. I'm at a loss for the cause or even probable causes of the regression. I also tried to build the head at "3.4.0.1 alpha 2" and while I could build AGS, compiling and running a project crashed the engine :/.

I have a commit I've made here: https://github.com/gurok/ags/commit/fde355548f58c0099573628488afe5207ddeddf3

As I tend to be a bit hasty making pull requests, I thought I'd try asking for opinions here first. The commit fixes the problem, but I'm not sure if it's the right way to fix the problem.

Maybe someone here will have a suspicion of what's causing it and suggest I look at a particular area.
Maybe someone knows why I couldn't build a project with the head from that long ago.
Maybe I'm making a too big a deal of this and I should just make a pull request (it does after all fix the problem).
Maybe someone (CW?) will make a pull request based on this that's a lot smarter.

I just need some assistance here, guys ???.
#25
I have something like this in a room in my current project:

Code: ags

if(aChannelPhoneRing != null && aChannelPhoneRing.IsPlaying)
{
	aChannelPhoneRing.Stop(); // Stop the phone ring sound from playing
	oPhone.StopAnimating();
	oPhone.Graphic = 831;
}
cShelly.Say("Hello?");
cAubrey.Say("Hello.");
Quest.Mark(qBaggage, 1);


And in another module, I have this code for Quest.Mark:

Code: ags

function Mark(static Quest, QuestType quest, int value)
{
	if(!Quest.HasPoint(quest, value))
	{
		Quest.SetPoint(quest, value);
		Title.Announce(quest);
		aPlotPoint.Play(); // Play the awarded one point sound
	}

	return;
}


For some reason, calling .Stop on the sound aChannelPhoneRing seems to prevent aPlotPoint from being played.

If I put the code to stop aChannelPhoneRing after the call to my Quest.Mark function, everything works as expected.
If I put Quest.Mark in the same room, it also works as expected.
I think perhaps AGS is reserving the same audio channel for aPlotPoint as aChannelPhoneRing, and perhaps the .Stop command is queued to happen at the end of the script. I don't know enough about AGS' sound system to say.

Does anybody have any ideas? A nice workaround?
#26
Engine Development / on_mouse_move
Sat 01/11/2014 08:29:21
I'm just going to propose this. If it gets shot down in flames, that's fine.

We have a few modules to handle two-click interfaces. Some of them automatically change the cursor based on what you're currently hovering over. Extended ALARCOST is one that comes to mind.

They all seem to suffer from the same flaw I pointed out in this thread: http://www.adventuregamestudio.co.uk/forums/index.php?topic=51211.0. That is, due to the structure of the game loop, there's a one frame delay before cursors get updated when the cursors change. I got no responses from the thread and my source diving has led me to believe it's not currently possible to avoid this delay.

Note: If you have trouble seeing the problem, you can try lowering the FPS of a game to 10 and moving the mouse cursor rapidly. You should see flashes of the previous cursor in places where it shouldn't be.

I have a patch for an on_mouse_move callback, but I don't know whether it's right. Here's the commit:

https://github.com/gurok/ags/commit/1bb68aa0b127506765b2e284fc59b6e1c40da5b7

I need opinions though:

Is this generic enough to go in mainline AGS or does it seem silly? It makes sense to me. We have a global on_mouse_click. We should have a global on_mouse_move.

This could quite easily be repeatedly_execute_always_before_render. (Whew! That's a mouthful.) Should I remove the checks for mouse position changes and just run it on every loop? Would that be more generic/useful?

To be clear, I'm proposing to insert it here in the game loop:
1. Update mouse x/y position
--> Run on_mouse_move callback <--
2. Render screen + mouse cursor
3. Process events (and run repeatedly_execute_always)


Please ignore this. I've found a better solution and it was doing weird things with blocking functions anyway.
#27
I have a repeatedly_execute_always function that handles changing mouse cursors as the player moves his/her mouse around the screen. e.g. When the mouse is near an exit, it changes to an arrow. When it is over a hotspot, it animates with a glow. I think this is pretty standard and there are quite a few modules that do similar things.

I've noticed that AGS seems to process a frame in this order:
1. Update mouse x/y position
2. Render screen + mouse cursor
3. Process events

My problem is that when I change the mouse cursor to reflect the player hovering over an exit or a hotspot, it doesn't get shown until then next frame. That means there's always one frame of the previous cursor shown in the wrong place.

Is there a way to run an event before the screen+mouse are rendered? Alternatively, is there a way to force the mouse cursor to be redrawn after processing events like repeatedly_execute_always?
#28

Notes for AGS

Ever wanted to attach arbitrary text files to your AGS project? Do you find yourself putting comments in odd places, like a to do list in your global script header? Notes is a plugin for the AGS editor that allows you to tie text documents closely to your project while maintaining the semantic separation between text file and source code that you crave.

Here are some screenshots of it in action:





Known Issues
  • AGS will automatically close one of your text files when you close the editor. Not sure why this happens. I believe it's an editor issue and I'm looking into it
  • Renaming text files is suboptimal right now. AGS doesn't seem to expose a way to handle renaming like the Scripts branch does

Planned Features
  • Reordering text files, placing them in folders (may not be possible due to plugin limitations)
  • Providing access to the editor's Find/Replace tools and other edit menu items (or at least a reasonable facsimile)

Download

Notes for AGS 1.1 (21 KB)
#29
Hello,

In my game, I have a small overlay that appears whenever the player scores a point. After a while, the overlay fades out, but I'd like it to fade out immediately if the player starts talking to someone. I don't want to write a custom Say method because I don't want to break the Create Voice Acting Script feature. For the moment, I've resorted to an extra function call before any .Say() commands:

Code: ags
Dialog.StartConversation(); // Special method to see if the overlay is visible and fade it out.
cShelly.Say("Good morning, how are you today?");
cJeanette.Say("Grumpy as always.");
cShelly.Say("Gosh!");


Unfortunately, this is prone to error. It's really easy to miss a conversation and it's rather hard to search the source for the start of a conversation. Is there something like an "on_say" event in AGS that I could use instead? Is there another way I could do this without breaking Create Voice Acting Script?
#30
I don't know whether it's adventure games or not, but check out the teaser site:

http://www.sierra.com/
#31
I'm running into some trouble with my current project and I think it's an AGS quirk. I created a simple test case for it and it seems to be reproducible outside of my game. The problem is that the default .Say() command right aligns text to about 70 pixels from the right, regardless of the size of the speech view. Here are a couple of demonstrative screenshots from my testing project:





To reproduce, create a blank project and set the speech style to "SierraWithBackground", create a speech view for Roger (e.g. the cup) and ensure this code gets run:

Code: ags
		SetGameOption(OPT_PORTRAITPOSITION, 0);
		cEgo.Say("Test left");
		SetGameOption(OPT_PORTRAITPOSITION, 1);
		cEgo.Say("Test right");


Now, I could be wrong, but I suspect it's a bug/quirk/limitation of AGS. I'd like to know if I'm missing something here and/or I just don't understand how left and right alignment should work. If I've misinterpreted things, please ignore this little section below.

Spoiler


Tinkering as I do, I was able to fix the problem by changing line 2283-2284 of character.cpp from:

Code: ags
    if (bwidth < 0)
        bwidth = scrnwid/2 + scrnwid/4;


To:

Code: ags
    if (bwidth < 0)
        bwidth = scrnwid;


This has the side effect that the maximum width of a .Say() speech box is the width of the screen, not 3/4 of the screen, but it fixes an issue later on where "bwidth" is used to determine the auto-sized position of the speech box.

There are several checks later in the code that sanitise the value of bwidth to ensure it has adequate margins from the edge of the screen. Part of the reason why this issue couldn't just be fixed by adding scrnwid/4 to the x-position of the speech box.
[close]
#32
Site & Forum Reports / No Blue Cups
Sun 08/06/2014 20:42:57
Couldn't find a better place for this.

When searching through old threads for AGS scripting tips, there are often posts with links to bigbluecup.com. It's a pain to modify the links all the time, so I wrote this Greasemonkey script that does it automatically.

https://greasyfork.org/scripts/2269-no-blue-cups

Tested in Firefox. Could we someday get a find+replace done on the database to fix this for good?
#33
In the default game, if Roger is standing at the bottom of the screen, his feet don't touch the bottom. Here's the output of me walking to the bottom and hitting CTRL+D:

[imgzoom]http://i.imgur.com/Eq8cdOH.png[/imgzoom]

I checked a few of his sprites and there was no space at the bottom of them. Does anyone know why this happens? And is there a better solution than using player.z to adjust his position?

EDIT: It's possible, but it should be noted that it basically means redoing existing rooms. As far as I can tell, there are two equally impractical solutions:

- Change all of your rooms to be 320x201 and fix the viewport to the top of the screen. Not a big hassle, but you'll have to re-import the walkable area masks because the BG size changed.
- Shift the player using player.z = -1. A bit awkward because existing walkable areas won't line up with the player anymore.
#34
Engine Development / Pathfinding bug?
Wed 21/05/2014 11:25:50
I think I'm slowly going mad. I think I've found a bug, but I'm not sure if I'm missing something or maybe it's a known issue or something. Here are the steps:

1. Create a new Default Game
2. In the first room, use this as the background and the walkable areas mask:

3. Place a new label on the status line. Call it "lblStatus" and put this code in the global repeatedly_execute_always:
Code: ags
lblStatus.Text = String.Format("Player: (%d, %d)   Mouse: (%d, %d)", player.x, player.y, mouse.x, mouse.y);

4. Start the game
5. Move the mouse to (158, 69) and click. Roger walks there (expected). Let him finish walking.
6. Move the mouse to (158, 183) and click. Nothing happens. In fact this seems to be true for (158, n) as far as I've tested.

Can anyone else replicate this and does anyone know what's going on here? I'm presuming it's a pathfinding bug, but I'm open to suggestions. I thought my paths were pretty safe (no areas < 3 pixels wide).
#35
Kate and Shelly Stick Together (Working Title)

Blurb:

Kate and Shelly are best friends who share everything from toothbrushes to
totally embarrassing gossip. It's no surprise that on their first day at
university, they should both fall for the same boy. He's a dark and charming
stranger, but his mysterious past threatens to divide them. While one girl
can't keep her hands off him, the other begins to suspect there's something
very wrong. Are their lives in danger or is she just paranoid? It's times
like these you need a best friend who doesn't think you're going crazy!

Features:
  • Engrossing mystery/thriller with a huge glob of Sweet Valley High romance
  • Friendships will be put to the test
  • I don't want to spoil anything, but there might be some betrayal
  • Two distinct endings
  • Two playable characters
  • State-of-the-art 320x200 graphics
  • Hand-painted backgrounds
  • Pixel art sprites and portraits
  • Clear progress system that punctuates your adventure
  • Simplified two button user interface with a radial menu for extra actions

Planned:
  • Animated cutscenes
  • Voice acting of some sort

Projected release:
  • Not before June, 2015 2016

Progress:

20% -- Art and scripting are well on their way. Story is finalised. Introduction is blocked out. First third of the game is completable. First few cutscenes are complete.

Team:
  • Writing and programming: Benjamin Penney (that's me!)
  • Background art, storyboarding and animation planning: K. Williams
  • Sprites, portraits and general animation: Richard Mallory / Andrei ??? / Various

Screenshots:



Outside the library.


Colour-coded inventories.


A spooky corner of the campus.


Near the gate.


Radial menu for extra actions.


More dialogue and... suitcases! OOoh
#36
The Rumpus Room / Party like it's 1992
Wed 19/03/2014 03:28:58








Sophie B. Hawkins and Ace of Base are borderline '91 and '93 respectively.
#37
Hello all,

I invite you to try...

AGS 3.3.1 Alpha 2

Download 3.3.1 alpha 2 as a .zip archive

Previous alphas:
Spoiler

ACHTUNG!
This is an early version of AGS 3.3.1.
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 3.3.0 after saving with this version.

Last updated: 1st of August, 2014



Engine

Full Screen VSync for Direct3D

This feature was previously available (but always on) in Draconian editions of AGS. With AGS 3.3.1, it has been integrated into the mainline builds. It's now possible to toggle VSync using the "Vertical sync" checkbox in Winsetup.exe. If it's checked, the game starts with vertical sync turned ON. In DirectX 5 mode, you can still toggle this by setting System.VSync to true/false. In DirectX 9 mode, the System.VSync property is now read-only (as opposed to being useless previously).

Bug Fixes

  • The engine now moves the portrait with the speaking character when using BasedOnCharacterPosition if the speaking character moves between calls to Say
  • Fixed internal handling of defaults when they can't be read from the config file
  • Fixed precision loss when getting/setting a transparency value, e.g. player.Transparency
  • Fixed occasional pathfinding failure on straight lines with complex walkable areas (reported here)
  • Printing [ no longer consumes all of the backslashes before it (e.g. "\\[" should now print \[ as expected)



Scripting

For statement

In addition to a while loop, you can now use a for loop in AGS script. The syntax is:
Code: ags
for([initialisation];[condition];[increment])
{
    [loop body]
}

Example:
Code: ags
for(player.x = 0; player.x < 100; player.x++)
    Wait(1);

Important: You cannot declare a variable inside a for loop's initialisation section. For instance, "for(x = 0; ..." is fine, but "for(int x = 0; ..." is not valid. It might be valid someday.

Break statement

You can now break out of loops using the break statement. For example:
Code: ags
i = length - 1;
while(i >= 0)
{
    if(page[i] == target)
        break;
    i--;
}

Will halt the loop when a match is found or leave i as -1 if there was no match.

Continue statement

You can now continue to the next iteration of a loop using the continue statement. For example:
Code: ags
for(x = 0; x < 100; x++)
{
    if(x % 2 == 0)
        continue;
    Display("%d", x);
}

Will display only odd numbers between 0 and 100.

Do...While loops

The Do...While loop construct is now supported. For example:
Code: ags
x = 1;
do
{
    x++;
    Display("%d", x);
} while(x < 1);

Unlike While, Do...While runs the loop iteration *before* evaluating the condition. The loop above will run once.

Dynamic Arrays in Structs

Dynamic arrays are now permitted inside structs. You can declare a struct like so:
Code: ags

struct DieRoll
{
    int BaseModifier;
    int DieCount;
    int Dice[ ];
    import function GetTotalValueOfRoll();
};

function PrepareDice()
{
    DieRoll a;

    a.DieCount = 3;
    a.Dice = new int[a.DieCount];
    a.Dice[0] = 6; // d6
    a.Dice[1] = 6; // d6
    a.Dice[2] = 8; // d8
    ...
}

And the dynamic array "Dice" can be initialised and used like any other dynamic array.

Managed User Structs

In AGS parlance, a managed struct is a struct that can be created dynamically. You must use pointers to refer to them (similar to built-in types like Region or Hotspot). You declare them with the keyword "managed" and construct new instances with "new", like so:
Code: ags

managed struct Point
{
    int X;
    int Y;
};

Point *GetPosition()
{
    Point *result;

    result = new Point;
    result.X = 30;
    result.Y = 40;

    return result;
}

Important: Managed structs are currently VERY limited in that they can't contain pointers (including dynamic arrays). It is hoped that this restriction will be lifted in the future.

#define Improvements

#define can now refer to other #define'd constants. Like VC++, #define symbol expansion only needs to make sense at the time of reference. Also like VC++, the order of previously defined constants isn't important, making stuff like this possible:
Code: ags

#define RED    GREEN
#define BLUE   456
#define GREEN  BLUE
Display("%d", RED); // Prints 456
#undef BLUE
#define BLUE  123
Display("%d", RED); // Prints 123

Note: To prevent circular references, a #define cannot refer to itself or anything previously used to expand the #define symbol.

Static extender functions

You can now declare the first parameter of a function as a static identifier that corresponds to a struct, e.g.
Code: ags
function AbsInt(static Maths, int value)
{
    if(value < 0)
        value = 0 - value;
     
    return(value);
}

This works in the same way as the normal extender method syntax (e.g. this Character *) but for static methods. The above code will define a new method in the static Maths called AbsInt. You can then import it in a header:
Code: ags
import function AbsInt(static Maths, int value);

And then use it elsewhere in your code just like it were a built-in Maths function:
Code: ags
int x = Maths.AbsInt(-3);


Extra Assignment Operators

The following C-style assignment operators are now supported:
*=   (Multiply by and assign)
/=   (Divide by and assign)
&=   (Bitwise AND and assign)
|=   (Bitwise OR and assign)
^=   (Bitwise XOR and assign)
<<=  (Bitshift left and assign)
>>=  (Bitshift right and assign)

Direction parameter for Character.ChangeRoom

This feature was previously available Draconian editions of AGS. The Character.ChangeRoom function now looks like this:
Code: ags
Character.ChangeRoom(int room, optional int x, optional int y, optional CharacterDirection direction)

Where CharacterDirection is a new built-in enum defined for facings (eDirectionUp, eDirectionUpLeft and so forth).

Character.DestinationX and Character.DestinationY

Two new read-only properties that can be used to determine where a character is currently heading (via a Walk command). If the character is currently stationary, these values are the same as Character.x and Character.y, respectively.

IsInteractionAvailable() for Other Types

This is another feature from Draconian editions of AGS. The IsInteractionAvailable() method can now be called on Hotspots, Objects and Characters.

Audio Clips API

There are two new properties for dealing with audio clips in this version.
Code: ags
Game.AudioClipCount

Retrieves the number of clips and
Code: ags
Game.AudioClips[n]

Allows you to access a particular audio clip.

Plugin API

There is now a new function that can be used to detect whether a plugin has been loaded:
Code: ags
Game.IsPluginLoaded(const string name)

Where name is the filename of the plugin

Dialog Options

The highlight colour for dialog options (default rendering) is no longer hard coded as yellow (14). You can use:
Code: ags
game.dialog_options_highlight_color = xxx;

And set the dialog options highlight colour to whatever you like. The default is 14.

Code Regions

This was previously available in Draconian editions of AGS. You can define an arbitrary region for code folding in your script like so:
Code: ags
#region MyRegion
do stuff;
do stuff;
do stuff;
#endregion MyRegion

The AGS editor will allow you to fold and unfold this region as though it were a code block. This has no effect on compiled code.

Bug Fixes



Common

Extended WFN Font Support

Support was added for extended characters in WFN fonts (those with codes 128 - 255).



Editor

Padding for Text GUI Windows

Text GUI windows now have a padding property which lets you control how much space appears between the border and the text inside a text GUI window. Previously, this value was hardcoded as 3 pixels. It now defaults to 3 pixels.


Clickable for Objects

The Clickable property of objects is now exposed in the editor so that you can set it at design time. Previously, this value was embedded in the room file format but only toggleable via scripting.


Bug Fixes

  • Undo history will no longer be deleted when a tab changes its docked state
  • Fixed crashes under certain circumstances when a script editor is closed
  • Fixed crash if selecting a character without a normal view in the room designer
  • Ctrl+Tabbing now works the first time when cycling through open editor tabs
  • Go to Line... now goes to the correct line and doesn't select it
  • The project is now completely rebuilt whenever Enable Debug Mode in General Settings differs from the setting used for the last build
  • The sprite editor now highlights drop targets when you drag sprites around
  • Moving folders of scripts around in the Explore Project pane no longer screws up compilation



Please enjoy this build and use responsibly.

Contributors
Crimson Wizard
Tzachs
monkey_05_06
salty-horse
Me
#38
Hello,

When conversing with another character, is there an easy way to allow the player to press ESC to exit the dialog? Ideally I'd like to be able to have the player say goodbye when ESC is pressed, but I'd settle for just stopping the dialog.
#39
I am working on save and load GUIs at the moment and I'd like to know what other people do to avoid using those terrible built-in scrollbars. At the moment, I am thinking of doing this:



But I'd like to know if somebody has implemented proper scrollbars as a module that I can just use.
#40
I created a new game using the default template and added this line to the top of on_key_press:

Code: ags
Display("Keycode: %d", keycode);


If I play the game, then hit Ctrl+Q, I see a quick message about the keypress, then the quit dialogue is displayed. If I click the "Play" button with the mouse, the game won't recognise me hitting Escape until I hit another key.

Is this a bug or some feature I don't know about?

Can anyone else test and verify that this happens? I am using AGS 3.3.0.
SMF spam blocked by CleanTalk