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

Messages - fernewelten

#221
Hi folks,
Meet Luke:
Luke is a bit of an autist, and so he doesn't know about his surroundings too well. When told to look at something on his right, he sometimes faces to the front â€" or back â€" instead. Sometimes an object is directly behind him, yet looking at it, he turns to the left as if he was only interested in its left edge for some strange reason. See my current game entry to watch him fumbling and bumbling, especially in the tree branch room.

What an awkward fellow this Luke guy is, and AGS makes him that way. Luke is using the standard functions Character.FaceLocation() and Character.FaceObject(), and those functions give results that are at the very least very counterintuitive, not to say plainly wrong.

How come? I've tried to research a bit of context for doing directions in the two-dimensional room, and this is what I've found:

To start off with, AGS doesn't natively know the concept of "looking downwards" as in "looking at your feet" or "looking upwards" as in "looking into the sky". You can code and draw it, of course, but it will be a special animation. Instead, when AGS talks about "down", it means "turned toward the human player (towards the fourth wall)", and when it talks about "up", it means "turned away from the human player (towards the back stage wall)".

Thus, "down" and "up" describe aspects of the depth dimension, not the height dimension.

This is relevant for FaceDirection() and such. No matter what direction you specify, the character will always look straight ahead, but it will be turned in different ways.

  • If a character does FaceDirection(eDirectionUp), it doesn't really look "upwards", it looks upstage instead and you'll see the back of the character's head. If it does "FaceDirection(eDirectionDown)" it looks downstage.
  • Similarly, if it does FaceDirection(eDirectionLeftUp) it looks upstage to the left, etc

Well, FaceObject() seems to often calculate this turn incorrectly.
How calculate a correct turn?

Details inside:
Spoiler
The character will always look straight ahead no matter how high the object is above the floor, so the object's height or elevation must be irrelevant information when calculating how the character should be turned. Instead, exactly two specifications should be relevant:

  • Whether the object is to the left or the right of the character.
  • Whether the object is upstage or downstage with respect to the character.

The easier part is calculating whether the object is to the left of the character and how far. You compare the character's and object's X dimensions. However, the relevant point for this comparison should  be the middle point of the object's width, and the scaling of the object should be taken into account when determining this middle.

It's harder to find out whether the object is in front of the character:

  • Usually, whenever AGS tries to find out whether something is "in front of" something else, it uses the baselines: The (geometrically) lower the baseline of a thing is, the more downstage it is considered to be.
  • If we use the lower edge of the sprite instead of the baseline, we will get into trouble in a lot of very common situations. Take for instance, a cup object that is lying on a table. The lower edge of the cup sprite will be near the table top, that is "high up". If we use this value as a depth information, we would conclude that the cup is "far away in the distance", which is wrong.
  • The only way to tell AGS how distant the object is is setting the baseline of the object. AGS doesn't provide any other way to tell this information. So conversely, AGS should actually consider the baseline for depth calculations whenever it is set; it should not deliberately play dumb and ignore a set baseline, taking the lower edge of the object against better knowledge.

So to recap, a preliminary outline of a correct algorithm for ch.FaceDirection(o) would be:
Turn to eDirectionAB, where

  • A is "Up" when the baseline of o is geometrically higher than the baseline of ch, otherwise "Down" (use the lower edge of the sprite iff the baseline isn't set);
  • B is "Left" when the middle of o is geometrically to the left of the middle of ch, otherwise "Right" (and consider the scaling when determining the middle).

This preliminary outline must be adapted because the character can turn straight to the right or left and straight upstage or downstage, too. A good predictable calculation might be: Draw a vector in the 2d space from the middle of the baseline of the character to the middle of the baseline of the object. Then turn the vector to the nearest multiple of 45°. Then convert this angle into the direction we are looking for.

Also, some characters can only turn to the straight orthogonal directions, they don't have views for eDirectionLeftUp etc. â€" the calculation above should then use multiples of 90° in these cases.
[close]

Does AGS do this? No, and as far as I can determine it hasn't done this for decades:

  • When dealing with objects, it uses their left edge, so FaceObject() makes characters strangely prefer their left-hand side.
  • When the objects have a baseline set, it ignores the baseline, so FaceObject() wrongly assumes for a lot of objects that they are in the background when they are on a table etc. instead.
  • I haven't analysed the code that far, but I think that the function doesn't cleanly round to nearest multiples of 45° (90°) either; for instance, it seems to prefer the "DownRight" direction unless the lower left corner of the object is nearly directly under the character and only then switches to the "Down" direction.

Whole generations of adventure coders must have struggled with those functions and come to the conclusion that they must be broken in some elusive way. Oodles of adventures must contain kludgy workarounds. So there must be a very tenacious reason to keep those broken functions broken or else they would have been fixed long ago. And based on these experiences, I doubt that they can ever be fixed in future, either.

In the light of this it might be better to fix this on the AGS program side and provide drop-in replacements for FaceLocation(), FaceObject(), and FaceCharacter(). This is what I try to offer below:

  • FaceLocationBetter() offers directions in clean 45° multiples and so short-circuits any angle rounding operations that FaceLocation() might do.
  • FaceObjectBetter() and FaceCharacterBetter() use the baseline when set.
  • FaceObjectBetter() determines the object width whilst considering the scaling and uses the middle of this width. It uses an auxiliary function CurrentSprite() that gets the sprite that the object currently displays.

Perhaps the code might be useful in some way. It should go into GlobalScript.asc, and GlobalScript.h should get some suitable definitions. Or if you keep a module with often-used functions, you could stick it there instead.

The code might still have some bugs.

Code below:
Spoiler

Code: ags
int CurrentSprite(this Object *)
{
    readonly int view = this.View;
    if (0 == view)
        return this.Graphic;
    readonly ViewFrame *frame = 
        Game.GetViewFrame(view, this.Loop, this.Frame);
    return frame.Graphic;
}

function FaceLocationBetter(this Character *, int dest_x, int dest_y,  BlockingStyle bs)
{
    readonly int diff_x = dest_x - this.x;
    readonly int diff_y = dest_y - this.y;
    int sign_of_diff_x = 2 * (diff_x >= 0) - 1;
    int sign_of_diff_y = 2 * (diff_y >= 0) - 1;
    readonly int abs_x = diff_x * sign_of_diff_x;
    readonly int abs_y = diff_y * sign_of_diff_y;
    
    if (abs_x < abs_y)
    {
        readonly int tan_val = diff_x * 29 / diff_y; // 12/29 is an approximation for tan 22.5°
        if (tan_val >= -12 && tan_val <= 12)
            sign_of_diff_x = 0;
    }
    else
    {
        readonly int tan_val = diff_y * 29 / diff_x; // 12/29 is an approximation for tan 22.5°
        if (tan_val >= -12 && tan_val <= 12)
            sign_of_diff_y = 0;
    }
    return this.FaceLocation(
        this.x + 10 * sign_of_diff_x, this.y + 10 * sign_of_diff_y, bs);
}

function FaceObjectBetter(this Character *, Object *o, BlockingStyle bs)
{
    int y = o.Y;
    if (o.Baseline != 0)
        y = o.Baseline;
    int x = o.X;
    int width = Game.SpriteWidth[o.CurrentSprite()];
    if (!o.IgnoreScaling)
        width *= GetScalingAt(o.X, o.Y) / 100;
    x += width / 2;
    this.FaceLocationBetter(x, y, bs);
}

function FaceCharacterBetter(this Character *, Character *ch, BlockingStyle bs)
{
    int y = ch.y;
    if (ch.Baseline != 0)
        y = ch.Baseline;
    this.FaceLocationBetter(this.x, y, bs);
}
[close]
#222
Quote from: Khris on Thu 14/05/2020 08:23:34
Here's a module: TextArea v0.0.1.1 BETA - Multi-line textboxes!

Heh. That thread started in 2008, so I wasn't very far off with my estimate of "about a decade ago".  8-) Thanks for the tip, I'll look into it.
#223
Hello,

Seemingly, the standard GUI textbox can have any dimensions. However, no matter how large its height is, it will only accept text on one single line. I would have expected a way to configure the textbox so that long text wraps around and fills several lines, but alas, no dice.

I'd even hoped for a mechanism by which a textbox would accept a typed shift-return and convert it into '[' internally or at least accept a typed '[' and display it as a newline or at the very least accept a typed '[' and put a '[' into the Text string. Nope. It seems to simply gobble both shift-returns and '['s without further ado.

My mind boggles. I can't “wrap”  (pun intended) my mind around the fact that this sort of thing wouldn't have been implemented into the engine about a decade ago.  8-0  Anyway, never mind that. So, what would be the least painful way to get a "proper" textbox into a GUI that would wrap long text?




#224
Last time I tried to vote on a game, I was given a questionnaire that asked for my rates on several aspects. For each aspect, there was a specific scale that I should adhere to. Okay, fair enough.

But I had the impression that the system then wanted to calculate an overall score from my individual rates, using some formula that wasn't disclosed. And that I did NOT think fair. I wanted to reserve the right of deciding what aspects I find particularly important or particularly off putting in a specific game (i.e., depending on its genre, style, subject matter, etc.). I wanted it to be _me_ instead of some calculation to decide the overall score that I assigned to the game!

Also, the questionnaire seemed to _force_ a vote on each of the aspects, without giving the option of saying "No vote" or "No opinion" or "Not applicable".

I resented that system so much  that I refused to rate that game on any aspect -- and I closed the browser window on the questionnaire without sending it off.

So, well, yeah, sorry.
I might have misunderstood something at that time. It might have been changed in the meantime. I wouldn't know.
#225
Quote from: Intense Degree on Fri 01/05/2020 21:59:18
I thought that too! If so how many variations are there...?

I adapted an idea called "Recursive division" for generating a maze. Here's the idea for grids of square cells:

Take a piece of chequered paper (aka. grid paper, the paper you use for doing math, a grid of squares). Imagine that all the cell edges can either be solid "walls" or open "doors".

Now fold that paper along any line of cell edges. You get two smaller areas that have the fold line in common. Assume that you already know for both smaller areas that within each area, each cell can be reached from each other cell. Then this will be true for the whole paper, too, if the whole fold consists of walls except for just one door on the fold line. (Why? We already assumed that you can travel from each cell to each cell if those cells are within the same area. To travel from one area to a cell in the other area, first travel from the source cell to the cell that is next to the fold door. Cross areas through this fold door. From there, travel to your destination cell.)

So do exactly that after creating your fold: Make the whole fold into walls, then randomly choose just one wall on the fold and make that a door.

Now repeat that for each of the two smaller areas separately: Fold the area somewhere, make all the edges of the fold into walls, then open one door on the fold. You get four areas that are even smaller.

Rinse, repeat for ever dwindling areas until each area either contains two cells or just one cell. If the area has exactly two cells then connect them with a door and you are done; if it consists of just one cell, you are done.

Here's a good description of the algorithm.
Here's a page that will show this algorithm in action visually (and lots of others, too).

I've adapted that idea to hexagonal grids with the following idea. In a grid of squares, you have TWO angles for the folds to choose from: A fold can be either horizontal or vertical. In contrast, there are THREE angles for the folds to choose from in hexagonal grids. This means that the folding operations can yield "irregular" shapes, and you must take great care to keep track of just what cells are on both sides of the folding lines.
#226
Quote from: Intense Degree on Fri 01/05/2020 21:59:18
Unfortunately I also had a game breaking bug, sounds pretty similar to JackP

Yes - same bug. I'd taken out a plank for visual reasons and then renamed all the planks with higher numbers so as not to leave a "numbering hole". So oPlank9 became oPlank8. Unfortunately, I wasn't thorough and let myself be distracted, so I forgot to edit the events grids and change the function names there, too.

I've fixed and re-uploaded the code.
#227
Hi Jack,

concerning that bug, bummer, I probably left the name of a deleted function in the events grid for an object. Thanks, I'll iron out that kink.
Edit: Found the problem.
Edit: Uploaded a version that has the bug fixed.

Concerning the maze:
Spoiler
You're right: The maze is randomly generated on-the-fly. It will be different in each game.
[close]
#228
So, I can now proudly present:

Vertigo


Meet Luke, a tiny hermit living in a tall, tall tree. He would have loved to stay in his seclusion, but he must come out of his tree flat to prevent disaster from happening.

Will he manage?
Can you help him save his father?

Standard BASS interface. Get the inventory and main menu either via the "hamburger" icon or by pressing "i".
Download the game here

Have fun playing, and tell me what you think!
#229
I will be able to present a "sky-high" adventure game. But I'm not sure whether it'll be quite ready at midnight today yet .

Can I have an extension, please?
#230
Sorry for waking up this thread.

I've been using this plug-in without trouble for a long time. However, I recently upgraded to AGS Editor 3.5.0.24 (AGS 3.5.0-P2). I was still able to create a note in the "Explore Project" tree of the Editor. However, when I double-clicked the new note, the editor crashed on me, cf. the death message below.

The plug-in seems to miss "AGS.Controls, Version=3.4.0.6, Culture=neutral, PublicKeyToken=null" or a dependency.
System.IO.FileNotFoundException
AGS.Plugin.Notes.NotesPane.GetEditor()

The death message, quoted:
Spoiler

PublicKeyToken=null" oder eine Abhängigkeit davon wurde nicht gefunden. Das System kann die angegebene Datei nicht finden.
Version: AGS 3.5.0.24

System.IO.FileNotFoundException: Die Datei oder Assembly "AGS.Controls, Version=3.4.0.6, Culture=neutral, PublicKeyToken=null" oder eine Abhängigkeit davon wurde nicht gefunden. Das System kann die angegebene Datei nicht finden.
Dateiname: "AGS.Controls, Version=3.4.0.6, Culture=neutral, PublicKeyToken=null" ---> System.IO.FileNotFoundException: Die Datei oder Assembly "file:///C:\Users\Peter G Bouillon\Documents\AGS\vertigo\AGS.Controls.dll" oder eine Abhängigkeit davon wurde nicht gefunden. Das System kann die angegebene Datei nicht finden.
Dateiname: "file:///C:\Users\Peter G Bouillon\Documents\AGS\vertigo\AGS.Controls.dll"
   bei System.Reflection.RuntimeAssembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, RuntimeAssembly locationHint, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks)
   bei System.Reflection.RuntimeAssembly.nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, RuntimeAssembly locationHint, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks)
   bei System.Reflection.RuntimeAssembly.InternalLoadAssemblyName(AssemblyName assemblyRef, Evidence assemblySecurity, RuntimeAssembly reqAssembly, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks)
   bei System.Reflection.RuntimeAssembly.InternalLoadFrom(String assemblyFile, Evidence securityEvidence, Byte[] hashValue, AssemblyHashAlgorithm hashAlgorithm, Boolean forIntrospection, Boolean suppressSecurityChecks, StackCrawlMark& stackMark)
   bei System.Reflection.Assembly.UnsafeLoadFrom(String assemblyFile)
   bei AGS.Editor.Program.CurrentDomain_AssemblyResolve(Object sender, ResolveEventArgs args)
   bei System.AppDomain.OnAssemblyResolveEvent(RuntimeAssembly assembly, String assemblyFullName)

WRN: Protokollierung der Assemblybindung ist AUS.
Sie können die Protokollierung der Assemblybindungsfehler aktivieren, indem Sie den Registrierungswert [HKLM\Software\Microsoft\Fusion!EnableLog] (DWORD) auf 1 festlegen.
Hinweis: Die Protokollierung der Assemblybindungsfehler führt zu einer gewissen Leistungseinbuße.
Sie können dieses Feature deaktivieren, indem Sie den Registrierungswert [HKLM\Software\Microsoft\Fusion!EnableLog] entfernen.

   bei AGS.Plugin.Notes.NotesPane.GetEditor()
   bei AGS.Plugin.Notes.NotesComponent.OpenItem(Int32 index)
   bei AGS.Plugin.Notes.NotesComponent.AGS.Types.IEditorComponent.CommandClick(String control)
   bei AGS.Editor.ProjectTree.ProcessClickOnNode(String nodeID, MouseButtons button)
   bei AGS.Editor.ProjectTree.projectTree_NodeMouseDoubleClick(Object sender, TreeNodeMouseClickEventArgs e)
   bei System.Windows.Forms.TreeView.OnNodeMouseDoubleClick(TreeNodeMouseClickEventArgs e)
   bei System.Windows.Forms.TreeView.WndProc(Message& m)
   bei System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
   bei System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
   bei System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
[close]
#231
I've just uploaded version 1.01 of the Hexagons module.

  • Provide explicit function Hx_GetTileUnderMouse()
  • Minor fixes to the documentation

Get the new version here: http://www.loquimur-online.de/ags/Hexagons/Hexagons-1.01.zip
#232
Modules, Plugins & Tools / MODULE: Hexagons
Tue 07/04/2020 04:46:29
Hello,

I've used the last lockdown days to learn about grids of hexagonal tiles, and I've made a module out of it -- mainly for my own use, in minigames and such. If you think it useful, you're free to use it as you like. I've put the module under a CC-BY license.

Summary
This AGS module provides a framework for managing grids of hexagonal tiles.

  • Define a grid in arbitrary shape. Shortcuts for defining rectangular and hexagonal grids.
  • The tiles may be squashed.
  • Assign each tile on the grid a unique index (tile number) â€" so that you can keep the tile information in a (one-dimensional) dynamic array
  • Get the co-ordinates that correspond to a tile index.
  • Get the position of the centre of any tile -- so that you can position ,e.g., an object to it.
  • Convert the mouse position to the tile that the mouse is over.
  • Draw tile outlines onto a DrawingSurface., e.g., the room background.
  • Fill tiles with any colour (realized by drawing onto a DrawingSurface).
  • Print a sprite into the centre of a tile (onto a DrawingSurface).
  • Convert pixel co-ordinates (e.g., mouse co-ordinates) to Cube co-ordinates and Cube co-
    ordinates to the pixel co-ordinates of the centre of the tile.
  • Loop through a grid along any grid dimensions.
  • Convert from Rectangular co-ordinates to Cube (Axial) co-ordinates and vice versa.

Main limitation: Hexagonal grids have tiles with either “pointy tops” or “flat tops” -- I've only implemented flat tops so far.

The module is designed for AGS 3.5. You'll probably be able to make it work in AGS 3.x if you provide a declaration for managed struct Point { int x, y; }.

I'm providing documentation as well as a demo AGS program that uses these features. The program features some simple games and a maze generator for hex mazes.



Get the module here: http://www.loquimur-online.de/ags/Hexagons/Hexagons-1.01.zip
(The module proper and the documentation are in the Assets subdirectory, as stated in the README file.)
#233
Quote from: Crimson Wizard on Wed 25/03/2020 16:35:59
No, I am not in UK, and ... does not matter.

Once, the British were very famous in the whole world for NOT doing any shake-hands ever. Except for the very first time they met, and that would be a very formal occasion where they went, "How do you do. â€" How do you do."

Times have changed, of course, but the concept of British workers constantly shaking hands is be still surprising. That was the reason for the question, I suppose.
#234
Quote from: Slasher on Sun 22/03/2020 10:22:47
Two whistle blowers silenced...

You don't need a whistleblower to get to the conclusion that the future is in peril of becoming very dire, very soon. You only need a pocket calculator.

Let's do this for Germany (where I'm currently based).

Day by day for more than a week or so, our confirmed Corona cases have increased to the tune of 25 % to 33 %. Per day. So a daily increase rate of ~30 % is what we actually seem to be able to achieve in reality and practice. Let's use that number.

10 days ago, there were only 7 % (that is, 1.3 to the power of -10) of the cases we have now. Experts say that those who need ventilators need them for around 10 days. So we can only rely on 7 % of the ventilators to be re-usable as the patients of 10 days ago now recover or die. And this extends into the future for the people that start needing the ventilators today. For all intents and purposes, we'll need all our ventilators at the same time. With that increase rate of ~30 %, we are failing completely to "flatten the curve".

Now let's check our capacity. We've got around 15,000 intensive care beds with ventilators that can be reserved for Corona. (There are 28,000 intensive care beds in Germany overall, but we can't reserve them all because others need them too, and not all the beds have a ventilator)  Experts say that about 1 Corona case out of 20 needs a ventilator, so we've got capacity for 300,000 Corona cases. That's it.

Two days ago, we passed the 5-digit mark and had 10,000 "confirmed" Corona cases in Germany.  Start then and repeatedly multiply by 1.3.
Just considering the "confirmed" cases we'll reach capacity in only eleven days. After that, it's triage time.

But the actual number or Corona patients will be higher than the "confirmed" illnesses: Our test capacity is limited (by manpower, not by money). That's why we only test those with symptoms that have come into contact with Corona patients or have been in risk areas. We can't "confirm" any of the cases that we don't test, so there's bound to be a hefty dark figure of Corona cases that we don't know about.

Go figure ....
#235
Quote from: Crimson Wizard on Fri 20/03/2020 23:24:25
how to hide player character in particular room (main menu, intro, etc).

To the best of searching abilities, indeed, "Character.on" isn't described anywhere in the in-Editor doc of the newest official AGS version.

The way to do this that I'd think of first: Set player.on to false in room_Load() and set it to true again in room_Leave().
#236
Trouble is, you actually have to physically tie down each citizen into a chair or else they are going to gang up in Corona parties. Which is what has actually happened in Freiburg in Germany whilst only a few kilometres away in Mülhausen in France, ventilators are woefully lacking to fill the demand. So the city had to decree extensive curfews that are in force as of today.

You can't trust humanity to have a smithereen of common sense. Everyone would be able to enjoy a great sunny spring in nature if they wouldn't insist on ganging up when doing it.
#237
This Washington Post article has some nice simulations that you can run in your own browser and that show the rationale behind the lockdown. There isn't any (mandatory) paywall, but Europeans must jump through some stupid hoops because of GDPR.
#238
Quote from: fernewelten on Thu 05/03/2020 23:06:37
To circumvent the standard mechanisms and do my own animation, this is how I would do it:

If you don't want to push pixels in room_RepeatExec() but only want to choose pre-made sprites, you can use a similar, simpler approach:

2. becomes:
Code: ags
player.LockView(VWSPEC); 
Room17PlayerLocked = true;


3. becomes:
Code: ags
function room_RepeatExec()
{
    ViewFrame *frame = Game.GetViewFrame(VWSPEC, 0, 0);
    frame.Graphic = MySpecialWayOfSelectingASpriteNumber();
}

(You don't need to do anything special with the variable frame, it will be automatically taken care of when the function ends.)

4. becomes:
Code: ags
function ReleasePlayer()
{
    player.UnlockView();
}
#239
To circumvent the standard mechanisms and do my own animation, this is how I would do it:

1. In the Editor, make a view, say VwSpec, that contains just one loop with one frame.

2. In code, when you want to start pushing your own character pixels,

  • lock the player character view to VwSpec.
  • Set some global variable, say Room17PlayerLocked, to true as soon as this has happened.
  • At this point, also create a dynamic sprite that you will use for your hand-written pixel pushing, and assign it to loop 0 of frame 0 of VwSpec.
This all should happen outside of the function room_RepExec() since it only needs to happen once, when you start the hand-written animation.
Something like this:
Code: ags
player.LockView(VWSPEC); 
Room17PlayerDS = DynamicSprite.Create(50, 50);
ViewFrame *frame = Game.GetViewFrame(VWSPEC, 0, 0);
frame.Graphic = Room17PlayerDS.Graphic;
Room17PlayerLocked = true;


(Room17PlayerLocked could be a global bool variable, perhaps defined at the start of your room file since it will only be read within this file. Room17PlayerDS is a global variable of type DynamicSprite *; we'll need to refer to it later on when we free the sprite.)

So after this has run, the player character is forced to show the graphic of frame 0 in loop 0 of view VwSpec all the time, and all automatic processing that the Engine does has been shortcut. This frame contains your dynamic sprite, ready for pixel pushing.

3. In room_RepExec(), just do the pixel pushing
Something like
Code: ags
function room_RepeatExec()
{
    if (!Room17PlayerLocked)
        return; // character hasn't been set up yet
    
    DrawingSurface *dsu = Room17PlayerDS.GetDrawingSurface();
    // torture the pixels of dsu to your liking
    dsu.Release();   
}


You don't need to do anything special additionally for the variable "dsu" within the function room_RepeatExe(); the variable will be automatically destroyed when the code leaves the function.

4. However when you are done animating, your character should be released and the dynamic sprite should probably be released, too. So code something like the following and call that function whenever you are done animating.
Code: ags
function ReleasePlayer()
{
    Room17PlayerLocked = false;
    player.UnlockView();
    ViewFrame *frame = Game.GetViewFrame(VWSPEC, 0, 0);
    frame.Graphic = 0;
    Room17PlayerDS.Destroy();
}
#240
Hi folks,

The Preferences of the AGS Editor used to ask whether the Editor should collect anonymous usage information and send them to a centralized server. I can't find this preference in version 3.5.0 (Build 3.5.0.23).

Where is this configured now?
SMF spam blocked by CleanTalk