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 - Snarky

#241
I get the same error if I try to change my profile, @AGA (though my avatar nevertheless still seems to appear). The URL is https://i.imgur.com/ZctiD.jpg
#242
Quote from: Rik_Vargard on Mon 26/08/2024 19:39:01But testing the site just as a user who wants to have access on how to learn AGS, it's not that easy to find.
And I mean: Video tutorials. Because we're in 2024.

Perhaps there could be a front page with Create, Play, Join and LEARN

I don't disagree that video tutorials should be featured, but I'd argue that "Learn" definitely belongs as part of "Create," not its own section. It is only relevant to people who are interested in making games (which, as AGA points out, is only one segment of visitors), and for them it is so relevant that they shouldn't have to go to a different section.
#243
This is generally because you haven't linked the function to the event (in the Character event pane).
#244
A couple of flashbacks:

Patty Griffin – "Flaming Red (Live)"

After Andreas got me thinking back to when I saw Patty Griffin in concert, I've been relistening to some of her stuff. I really love this dark and dirty version of "Flaming Red" (even though the sound quality in this video isn't the best).

Ani DiFranco – "Hide and Seek"

Artists are not necessarily the best spokespeople when it comes to politics, but looking back I think Ani DiFranco's fierce insistence that the personal is political (and vice versa) helped open my eyes on a number of issues.

And one current hit:

Chappell Roan – "God Luck, Babe!"

A+ music video. And the song's flashforward prediction reminds me of (spoiler warning for an excellent film)...

Spoiler
Portrait of a Lady on Fire:
[close]
Antonio Vivaldi – "Summer" (III. Presto)

I made the mistake of reading up to see if the Vivaldi concert was historically plausible. It isn't, as his music had fallen into obscurity at the time the movie is set, but the artistic license is absolutely justified by how powerful that scene is.
#245
One thing not quite clear from the description: Does this mean that any function that includes a waitfor statement must have WaitObject as its return type?
#246
Quote from: Crimson Wizard on Thu 22/08/2024 14:08:43No, it won't run, why would it? The idea was that execution halts at "waitfor" and then proceeds with the next line.

I think we're coming at this from two different directions. My thinking was to simplify the way this problem is typically solved in AGS today (putting all the things that have to wait for a non-blocking action to complete in a separate function, and then wait for a signal that it's time to run it; currently by polling in repeatedly_execute), but keep essentially the same logic. So my assumption was not that the script would really halt at the "waitfor" line (but rather mark the rest of the block as a delegate to be run on callback).

I'm not sure I quite understand how that (i.e. halting) would work. In this talk about coroutines, what level is the coroutine? IOW, how much of the engine/script actually blocks? If this happens in an on_key_press handler, for example, will the program stop processing keypresses until the action completes and the script resumes? (Presumably no.)

Quote from: Crimson Wizard on Thu 22/08/2024 14:08:43Here one part of statements is always run after event, and second part may run either instantly or after event.

No, if waitfor is just syntactic sugar for passing the rest of the block as a callback delegate to an event, the rest of the function will run right away.

Quote from: Crimson Wizard on Thu 22/08/2024 14:08:43Or if waitForComplete is inside a loop.

Code: ags
while (condition)
{
  waitForComplete(action);
}

Will that become a recursive delegate?

Under my proposal, it will assign a no-op function (given that there are no lines in the same block of code below waitForComplete) as an event handler for when the action completes, and then begin running the action. Then it will loop, assign another empty event handler, and immediately begin running the action again. In AGS, this will typically interrupt/cancel the ongoing action, and if we're using waitForComplete, the completed event will not trigger, so the first event handler is discarded. It will continue doing this in a loop, all within the same game cycle, for as long as the condition holds. If there is nothing in the loop to change the condition, it will go into an infinite loop and error out. If it eventually breaks out of the loop, we'll end up with one (empty) event handler assigned as a callback for when the action completes.

Basically, this would not be a reasonable thing to write.

If we modify it slightly to:

Code: ags
while (condition)
{
  waitFor(action);
  someOtherFunction();
}

... it might have the same effect as simply:

Code: ags
  while(condition)
    someOtherFunction();

Since each time it reaches the action line it will start that action and interrupt the ongoing one, raising the OnAction(Interrupted) event. Though the exact effect depends on how events being triggered and callbacks called is scheduled internally. Regardless, it's still probably not a reasonable thing to write.

But there is another problem that I mentioned earlier that has to be considered. Whichever approach one would go with, if a script can be paused/deferred while other scripts continue running, and then resumed, there are going to be a bunch of concurrency issues. Take for example:

Code: ags
int x;

void someFunction()
{
  int y = Random(200);
  waitfor(cEgo.Walk(x, y, eNoBlock));
  cEgo.Say("Arrived at %d,%d), x, y);
}

Now you would expect the (x,y) the character Says to be the same they walked to, but this might not be the case. While the function waited for cEgo.Walk to complete, some other script may have changed the value of x.
#247
Quote from: Crimson Wizard on Thu 22/08/2024 09:58:38I might sound quite rude saying this, but looking at these lambdas makes me shudder. I think both of the examples posted above will only make everyone confused. I mean, beginners are often confused by much simpler things, like having to write commands inside functions, having to put brackets after ifs, or writing their own functions.

I don't disagree that lambda syntax in imperative languages is both ugly and pretty much incomprehensible, and that we should prioritize simplicity.

If the brackets around the block can be omitted, that's great. I was a bit unsure about whether it would be possible to do so in general without breaking the parsing in interesting ways. For example:

Code: ags
function crossChasm()
{
  if(cEgo.HasInventory(iHoverBoard))
  {
    waitfor(cEgo.Walk(EXIT_X, EXIT_Y, eNoBlock))
    cEgo.ChangeRoom(42);
    return;
  }
  waitfor(cEgo.Walk(EDGE_X, EDGE_Y, eNoBlock))
  cEgo.Say("I'm not getting across that on foot!");
}

Will the bit after the if-block run if cEgo has an iHoverBoard? Typically in AGS script you would expect that it doesn't because of the return statement, but if the script actually only runs the waitfor(cEgo.Walk) statement now and schedules the rest of the if-block for later, it won't hit that point, and the rest will run. There are also questions about local variables (both scope and value).

Anyway, while we're throwing ideas at the wall, how about this?

Introduce an event type and a delegate type that can be registered as event handlers. A delegate can be created either from a named function or an inline anonymous one. The syntax could for example be:

Code: ags
  // Add the on_event function as an event handler (delegate) for Entity.Event
  Entity.Event += new delegate on_event;

  // Add an an anonymous function as an event handler for Entity.Event
  Entity.Event += new delegate(Entity e, EventData d) {
    // Event handler body
  };

There's a Character.OnAction event that gets raised whenever an asynchronous action (e.g. a non-blocking walk) completes, running all registered event handler delegates. (Specifically, a "OneTimeEvent" event type that unregisters all event handlers after it's triggered once.) Character.Walk returns a pointer to this event, which makes it convenient to register an event handler for when the non-blocking walk completes.

So you could do:

Code: ags
  cEgo.Walk(x,y, eNoBlock) += new delegate(bool complete)
  {
    if(complete)
    {
      cEgo.Say("I will say this when I reach x and y!");
      cEgo.ChangeRoom(5);
    }
  };

As a piece of syntactic sugar, there's a keyword (or set of keywords) that simplifies this syntax somewhat, for example:

Code: ags
  waitForComplete(cEgo.Walk(x,y,eNoBlock));
  cEgo.Say("I will say this when I reach x and y!");
  cEgo.ChangeRoom(5);

OR if it turns out that this creates too many issues:

Code: ags
  waitForComplete(cEgo.Walk(x,y,eNoBlock))
  {
    cEgo.Say("I will say this when I reach x and y!");
    cEgo.ChangeRoom(5);
  }

Possible keywords could include "waitFor" (wait until the event is raised, unconditionally) and "waitForComplete" (wait until the event is raised, and only if the first, boolean argument is true).

I think this gives a good balance of simplicity and flexibility/power.
#248
If we had anonymous functions and function pointers (lambda expresssions, anonymous functions or delegates), we could do something like:

Code: ags
cEgo.Walk(x, y, eNobBlock,
         (completed) ->
         {
           if(completed)
           {
             cEgo.Say("I will say this when I reach x and y!");
             cEgo.ChangeRoom(5);
           }
         });

(This assumes that Character.Walk accepts an optional delegate, an anonymous function of signature void f(bool), which it calls once the walk completes or is interrupted.)

Personally I don't like the way code using lambdas ends up looking, so if AGS was to introduce something like this I would suggest something more like:

Code: ags
  waitfor(cEgo.Walk(x, y, eNobBlock) => bool completed)
  {
    if(completed)
    {
      cEgo.Say("I will say this when I reach x and y!");
      cEgo.ChangeRoom(5);
    }
  }

Here waitfor (could also be called "schedule", "async" or some other suitable name) is a new keyword similar to if, for, while, etc., which accepts functions that return an asynchronous result as an argument, and schedules the following block to run (mapping the result to a parameter) once it does.

(Under the hood, what probably happens is that Character.Walk returns a pointer to an event listener, and waitfor adds the block as an event handler to that event.)
#249
Quote from: Crimson Wizard on Thu 22/08/2024 01:01:41No, it was @Snarky originally who mentioned this, but maybe this was just an idea, and he did not need it for himself.

I've no memory of this (and I'm not 100% sure exactly which feature you are referring to), but assuming I did it was probably either in response to some challenge another user had faced, or with the idea that it could be used for something interesting (possibly a module to edit walkable areas etc. in-game; in-game editing is something I've long seen as a promising avenue to explore). But no, I've never used it.
#250
Quote from: Ghostlady on Wed 21/08/2024 20:46:31Should it be working like this?

 ??? It's your game. How do you want it to work?

I see two potential purposes of the little screenshot thumbnail on this GUI. One is to show a thumbnail of the slot you will overwrite if you save now. The other is to give a preview of what the thumbnail will look like if you save now.

So showing the thumbnail of the highlighted save makes sense if that's the slot your game will be saved in (and therefore overwrite). To me that would be the intuitive behavior, and is how the A.S.S. module works. But as already discussed, the find_save_slot() function doesn't do that, so showing the selected item's thumbnail arguably makes it even more misleading.
#251
The screenshot will show the screen as it looks right when you save the game (by calling SaveGameSlot), so you have to hide the GUI (and wait for the screen to update) before you do that. In the A.S.S. module, this is done by:

Code: ags
  gSave.Visible = false;
  mouse.Mode = eModeWalkTo;
  Wait(1);
  SaveGameSlot(totalsaves+1, SL_TEXT);

Your code will likely be a bit different (different text in the SaveGameSlot, for one thing), but apart from perhaps the mouse.Mode line, it should  be essentially equivalent.
#252
Go to the General Settings for your project (it should be on the top of the project tree), and look for the setting "When player interface is disabled, GUI should." Change it to "Display normally."

(I've previously argued that this should be the default setting. What template are you using?)
#253
Quote from: eri0o on Tue 20/08/2024 12:42:49This double click interaction exit is not standard too, each person will develop their own way - what could be done here is have some way to detect double clicks in engine script API itself. Because of all things that CW mentioned I don't think this makes sense in the Engine Script API but someone could write something and put in a module.

https://www.adventuregamestudio.co.uk/forums/modules-plugins-tools/module-doubleclick-keylistener-detect-double-clicks-and-more/

I agree that a "standard library" would be nice. It could even be something as simple as a manual page (maybe an FAQ) with a list of "If you want to do X, we recommend: module A."
#254
Just came across this fascinatingly bizarre and gruesome story, which quite frankly I think Chipping Campden should feature more prominently in its tourism info: https://mulberryhall.medium.com/odd-this-day-76b6031f25b4
#255
Some artists and bands I liked at the Øya music festival last week (I'm skipping Janelle Monáe and PJ Harvey since I was already a fan):

slowdive – "prayer remembered"

I must admit I'd never heard of slowdive, though they've been around since the 80s. Their "wall of sound" show was superb, with droning guitars that swept over you and through your very bones, without relying on deafening volume. (The album cannot fully capture the grand scale of their sound in concert.) Biggest discovery of the festival for me.

Angélica Garcia – "Karma the Knife"

She did a very stripped-down set with just her and a drummer (who also set up part of the stage themselves). She mostly played Spanish material from her latest album (I liked "El Que"), but I thought this was the catchiest.

Blondshell – "Salad"

I wasn't really in shape to enjoy their concert (tired and coming down with a cold), but it sounded intriguing enough to check out later.

HILLARI – "Dangerous"

The opening concert consisted of a bunch of Norwegian artists and bands doing just one song each, backed by the band Orions belte (see below). HILLARI has a bit of a Lianne La Havas thing going on, which I quite like.

Kaja Gunnufsen – "Jazzing med Kaja"

I'm completely out of touch with Norwegian music, or I feel I'd have heard of Kaja Gunnufsen a long time ago. The upbeat tunes and girlish voice contrast beautifully with the ultra-depressing lyrics conveyed through very simple and straightforward (almost naivistic) rhymes.

Orions belte – "Bean"

Another Norwegian act. This instrumental band was a nice way to chill out between other sets.

han gaiden – "Talk of the Town"

More Norwegians. They did a DJ set that sometimes verged on the Blade Runner-y, as in parts of this track.
#256
Wordle 1,152 2/6*

⬜🟨🟩⬜⬜
🟩🟩🟩🟩🟩
#257
Quote from: Ghostlady on Mon 12/08/2024 18:11:04I checked both global scripts and do not find any verbiage using buttonsprite in either, other than what is shown above.

I assume you mean the script and the header? Well, as said it might also be the script name of a game entity. Or a global variable. But the simplest fix is just to rename the variable.

Quote from: Ghostlady on Mon 12/08/2024 18:11:04Can you show me how to code this check so player would not get an "array index out of bounds" exception if nothing is selected in the listbox?

Well, test it without a safety check first. I'm not sure it's necessary; I don't recall if there's any way for players to make it so nothing is selected. But something like this should work:

Code: ags
  if(lstSaveGamesList.SelectedIndex >= 0)  // Savegame selected in list
  {
    txtNewSaveName.Text = lstSaveGamesList.Items[lstSaveGamesList.SelectedIndex];
    buttonSprite = DynamicSprite.CreateFromSaveGame(lstSaveGamesList.SaveGameSlots[lstSaveGamesList.SelectedIndex], 78, 78);
    if (buttonSprite != null) // If there's a screenshot saved, display it
    {
      btnScrnshot.Visible = true;
      btnScrnshot.NormalGraphic = buttonSprite.Graphic;
    }
    else
      btnScrnshot.Visible = false;
  }
  else // No savegame selected, so hide the screenshot button
  {
    txtNewSaveName.Text = "";
    btnScrnshot.Visible = false;
  }
#258
Quote from: LameNick on Mon 12/08/2024 18:52:27The damage another person can cause to your professional life with learning from your work and then deriving work from this knowledge is quite restricted in a way, that again a machine that can, churn out tons of stuff based on features characteristic of your expression, is not.

That's my point: the issue is not the input, but the output. I think it is only (or, at least, mainly) problematic if the output closely resembles "features characteristic of your expression."

Many AI-critics are fond of claiming that they are nothing but plagiarism machines, but I don't agree. They can be used to produce plagiarist work (including outputs that are effectively copies of specific works they were trained on), but not everything they output can meaningfully be called that. In other cases those outputs are a mix of so many separate pieces of training data, recombined in novel ways based on the prompts, that they are clearly novel works. I don't think that using someone's work to train a model that produces such novel works amounts to copyright infringement, or any other infringement on the author/artist's legitimate rights. It is only when the output is plagiarism that the original creators' rights are infringed.

And while writers and artists may claim a generalized harm from the existence of the technology, I don't think they should have the right to withhold their work from such use, any more than movie studios should be able to deny reviewers the right to use clips from the movie in their video reviews, or bands should be able to deny people whose political opinions they don't like the right to play their music, etc. Sharing a creative work with the world does to some degree mean sharing it; it is no longer solely yours.

Of course, this is largely an academic argument, since existing systems do not in any (effective) way stop users from producing plagiarism, deliberately or inadvertently, so creators whose works have been used in training the models have plenty of good reason to object on those grounds.
#259
Is there a tl;dr version of this? There's too much to dig through to figure out what you actually want to show.

In general, to display a visual indicator, you could either:

1. Draw and import all the different possible indicator states as separate sprites, and display the appropriate one depending on the state (e.g. if you were using a traffic light indicator, or for an old-school Doom-style face indicator)
2. Draw it dynamically (for example changing the size, orientation or color) depending on the state, using functions like DrawRectangle, DrawCircle and DrawLine (easy to do health bars, compass needles, radar pings etc. in this way)
3. Use a particular sprite and use rotation, scaling, tinting or some other adjustment to change its appearance
4. Layer multiple sprites on top of each other, optionally using transparency to control the appearance
5. Some clever combination of the above
6. Probably other ways

Of course, you can also do animation (for example a heart rate monitor) by constantly updating the display.

Typically you would display the final sprite on a (non-clickable) button on a GUI, or you could use an overlay.

Any reasonable visual display should be perfectly doable in AGS.
#260
Annoyingly, room_RepExec has to be linked to the room event in the event panel, IIRC.
SMF spam blocked by CleanTalk