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

#21
Mellon Collie came out 25 years ago today.

Smashing Pumpkins - "Galapogos" [sic]

Over time this has grown to become my favorite track off the whole double album.
#22
Quote from: Ali on Sat 21/10/2023 20:54:52Snarky's guess is, of course, correct

Huzzah!

I've been thinking about twists, and how we often define them as surprises. For example, Hitchcock thought you should prioritize suspense over surprise, and reveal information early on ("there's a bomb under the table") in order to build suspense, rather than hold it back ("some people are sitting around a table, suddenly a bomb goes off")—except in the case of a twist, which he seems to have understood as "a surprise that is the point of the story."

But I question how true that is. Earlier on Ali compared them to joke punchlines, and I think that's right. And of course the thing with hearing a joke is that you're usually waiting for the punchline. It's a very different experience if you don't realize that what someone is telling you is a joke, and the punchline comes out of nowhere. Usually you don't know exactly what the punchline is going to be (sometimes you do), but the enjoyment is as much the anticipation as the reveal.

Similarly, I think the best twists often give you some inkling ahead of time that there is something off, something missing, but not enough to put your finger on exactly what. If it's just a matter of holding back some of the information until the end, it's usually not very satisfying. There should be some unresolved element to the story that the twist completes.

A good twist will often offer suspense and surprise.
#23
Quote from: eri0o on Sun 22/10/2023 12:10:55I really think you don't need to sort, just pick the unit with the maximum speed of a group and then remove it from the group

This is precisely what selectsort does, iteratively, so the only difference is whether you do it all in one go before you start processing the combat actions, or one at a time as the combat advances. Unless actions by earlier units can change the priority of later units, I don't think there is any benefit of one over the other. By which I mean: I think to do what you describe, you'd need pretty much every line of my selectSortMax() function—or some close equivalent—somewhere or other in your code (though the bit that swaps indices might be done differently depending on exactly how you implement "remove it from the group").

Quote from: eri0o on Sun 22/10/2023 12:10:55this should make it easier to add additional conditionals, like, maybe flying units goes first indifferent from speed.

Again, I don't see how it makes a difference, since you'll have to write the same priority/comparison condition either way. (Of course, if AGS allowed delegates or function pointers, that part could be abstracted out, but alas.)

Quote from: eri0o on Sun 22/10/2023 12:10:55Anyway, if your units all share a same index and you want to sort by speed and you have int sort working, a common trick is instead sorting "val= speed*256 + unit_index" and then later just filtering the index out by using "unit_index= val&0xFF".

OK, yeah; that's cool (as long as your array size is <256, of course).
#24
Yeah, for technical reasons, AGS only allows dynamic arrays as arguments to functions.

What I don't quite understand is how, having sorted the speeds, you are then able to tell which unit corresponds to each element in the sorted array and should move first. Do you do a lookup to find which unit has the particular speed? That adds another layer of inefficiency, if so. And what if multiple units have the same speed? (Edit: Ah, I see that you edited your post right before I finished this, and in fact can not tell.)

Also, one tip: It's a great benefit if you can use the same struct both for heroes and enemies, since that means you can, among other things, store them in a common array, which lets you easily do things like sort them or run through them one by one. And you wouldn't need separate .herospeed and .enemyspeed properties (and many other stat properties that are probably duplicated); instead you could just have one .speed property, and a single flag like bool isHero to tell them apart.

So what I would personally do in your situation would be something more like:

Code: ags
  // Assume a managed struct CombatUnit that is used both for hero and enemy units
  CombatUnit* combatUnit[] = new [MAX_COMBAT_SIZE];
  int unitCount = 0;
  combatUnit[unitCount++] = hero[0];
  // ...
  combatUnit[unitCount++]  = enemy[3];
  //  (In reality you wouldn't need the hero[] and enemy[] arrays,
  //   but could just assign the units directly to combatUnit[].) 

  sortByInitiative(combatUnit, unitCount);

This would use a version of the selectSort function that sorted an array of CombatUnit pointers by speed:

Code: ags
void sortByInitiative(CombatUnit* array[], int arraySize)
{
  for(int sortStart=0; sortStart < arraySize; sortStart++)
  {
    int maxIndex = sortStart;
    for(int i = sortStart+1; i < arraySize; i++)
    {
      if(array[i].speed > array[maxIndex].speed) // We use the .speed property to sort
        maxIndex = i;
    }
    if(maxIndex != sortStart)
    {
      CombatUnit* buffer = array[sortStart];
      array[sortStart] = array[maxIndex];
      array[maxIndex] = buffer;
    }
  }
}
#25
In the general case, it's best to implement a performant search algorithm like quicksort or mergesort.

But if you're dealing with small arrays, on the order of maybe a dozen entries, you can use an inefficient but simple algorithm instead. I'll go with selectsort since it is pretty intuitive:

Code: ags
void selectSortMax(int array[], int arraySize)
{
  // Find the largest element, put it at the start, and then repeat for rest of array
  for(int sortStart=0; sortStart < arraySize; sortStart++)
  {
    // Find the largest remaining element
    int maxIndex = sortStart;
    for(int i = sortStart+1; i < arraySize; i++)
    {
      // If the new element is bigger than any seen so far, we have our max so far
      if(array[i] > array[maxIndex])
        maxIndex = i;
    }
    // Put that element at the top of the unsorted array (if not already in place)
    // by swapping it with the element there at the moment 
    if(maxIndex != sortStart)
    {
      int buffer = array[sortStart];
      array[sortStart] = array[maxIndex];
      array[maxIndex] = buffer;
    }
  }
}

(Untested; may include bugs)
#26
For me, I'm relatively certain that it was King's Quest I VGA* — just like King's Quest I (SCI) was the first adventure game I played as a kid (not counting Shadowgate for the NES, which I only ever got to play a couple of screens of).

(* Not actually VGA)

Quote from: TheFrighter on Sat 21/10/2023 11:51:22Not sure, probably Emerald City Confidential.

That's not an AGS game.
#27
Me too. I just watched this trailer (if that's the word) yesterday:


Those drawings really are wonderful.

Since this thread is about twists, I suppose I will stick my neck out and with confident trepidation guess at the cliffhanger twist in Murder at the Museum:

Spoiler
The person who knows Bonnie's secret is Dana Hornville, right? I feel like it's foreshadowed that they will become friends and partners-in-crimesolving.
[close]

If I got it wrong, I suppose that's proof I'm in the target audience of 8–12-year-olds or adults who are a bit thick.

I also recently read Mr Bowling Buys a Newspaper by Donald Henderson, a really remarkable crime novel from 1944 that tells the story of a depressed serial killer who can't seem to get caught even though he wants to. It's not really a mystery, but still features a twist ending that caught me by surprise. And it doubles as an interesting depiction of life in London during WWII. I would recommend it.
#28
I've let The Algorithm determine most of my listening recently.

She Wants Revenge – "Tear You Apart"

Apparently Joaquin Phoenix directed this music video. Good job, Joaquin!

Talking Heads – "Life During Wartime" (live, from Stop Making Sense)

This performance brought to you by Cocaine™

I got into reading about David Byrne, and came across the quote by former Talking Head Chris Frantz: "If you knew David Byrne, you would not be jealous of him"; which is a bit sad, but honestly also a bit of a relief, because I was starting to feel pretty jealous.

The Dø – A Take Away Show ("Despair, Hangover & Ecstasy" and "Miracles (Back In Time)")

Not sure whether that counts as a Metal Ümlaut

The Divine Comedy – "Something For The Weekend"

Apparently this song was inspired by the loveliness of Kate Beckinsale in Cold Comfort Farm; it must be weird to have a song about yourself by someone you've never met (though in this case the idea was just a jumping-off point)

Purity Ring – "Fineshrine"

Heard them first on the Search Party theme, "Obedear," but they have some other good tracks too
#29
The Rumpus Room / Re: *Guess the Movie Title*
Sat 07/10/2023 13:08:35
It's the old Willy Wonka movie, right? (I didn't know the director; apparently it's Mel Stuart.)

If that's correct, I'm not gonna post another film. There doesn't seem to be enough people interested in playing this forum game any more, so it might be time to close it down. But if anyone else does want to pick it up, feel free.

... Actually, I'm having second thoughts about this guess. I thought the guy in the schoolboy uniform was August Gloop, but it doesn't seem to be him after all.

Is it Popeye? That was a famous director... Coppola?
#30
Just to "bump" this issue again: notifications on watched threads still aren't working (for me).
#31
Quote from: eri0o on Sun 01/10/2023 10:31:35Because I think you can get it from it's audio channel.

Yes, that could work (voice clips always play on channel 0), though I've never quite trusted AudioChannel.PositionMs (a long time ago I had some trouble when it didn't seem to work properly).

I do also want to support syncing without an audio file, for more general-purpose synced/scripted animations, but the frame counter should be fine for that purpose.
#32
Quote from: eri0o on Sun 01/10/2023 08:30:48I don't think you can get system clock from the API today

You can: DateTime.Now

Incidentally, this is one of those cases that demonstrates how much harder things get when you go from a basic module to a more general one: If using the system clock fixes any desync problems related to game slowdown, and is simple to do (it is), doing so should be fine, right?

Well, not quite. Because what if the game, including audio, is paused in the middle of the animation? (For example by tabbing away from the window, if not set to run in the background?) Then the system clock progress will not match the audio progress. And if the module is extended to support syncing during background speech, we get another complication, because then the game can be saved and restored in the middle of a sync animation.

Probably the most robust solution would be to use the system clock unless there is a major discrepancy with the last frame (say, more than a second), and in that case use the game speed as a fallback.
#33
Quote from: Crimson Wizard on Sun 01/10/2023 05:47:15what was the adventure genre's main problem and a weak spot historically, that is: a lack of a system.

That's one way of looking at it. Another is that this is almost the defining characteristic and unique strength of adventure games: each gameplay challenge is a puzzle that has been separately designed, written and scripted by a person, and therefore has the potential to be more creative and more meaningful than posed problems or emergent challenges that arise from a "system" or general game mechanic.

I think a game where the puzzles are mostly variations on situations in a "system" that you explore and learn strategies to solve will tend away from being an adventure game. (For example, if Monkey Island's gameplay consisted predominantly of insult sword fighting, I don't think it would be an adventure game.)

To quote myself from an old discussion thread:

Quote from: Snarky on Wed 13/05/2009 00:33:41The point about "heavily scripted" is an important one that is often overlooked: It is characteristic of adventures that instead of offering a general "mechanic" of actions (run, jump, shoot, punch,...) which more or less work the same way every time, adventure games respond in a different, context-specific way every time you perform an important action, and this is usually accomplished by manually scripting each individual event. (I think this ties into the concept of "puzzles", which you might define as "intellectual challenges with pre-defined solutions".)
#34
Quote from: Dave Gilbert on Sat 30/09/2023 23:36:53So I'm wondering if the problem lies with the rhubarb end, or if me changing the code like this messed things up. For example, what was the reason that frame 7 was originally unassigned? Was it essential to keep that?

Hmm, changing the mapping should be fine (but see below), though I would strongly recommend that instead of changing the AutoMapPhonemes implementation in the module code, you set up a manual mapping outside of the module when you initialize it—so, instead of calling AutoMapPhonemes, you use those exact AddPhonemeMapping calls yourself to set it up the way you want it.

The reason why the auto-setup is arranged the way it is (skipping frame 7) is because the other lipsync data formats, Moho and Pamela/Annosoft, distinguish between "ooh" sounds and "w" sounds, but Rhubarb uses the same phoneme/mouth shape for both. The auto-setup maps the frames the same way for all the formats, allowing you to set up the animation view once, and then use whichever lipsync data format you like. You can even switch formats along the way, if for example you want to hand-sync some scenes in Pamela format and do others automatically in Rhubarb (though you'd need to reset the module with the new format and mappings whenever you switch). I don't remember precisely why it's frame 7 that is the "optional" one rather than the last frame, but I would guess I based the order on some standard or convention for lipsync setups.

Anyway, to get to the point of your question: looking over the code, it does assume that Frame 0 is the non-speaking frame, as in the AGS convention for NormalView and SpeechView; this frame is set when the animation file does not specify a frame. (This is necessary because some of the data formats can have gaps, but I don't remember if this applies to Rhubarb.) You could try to change it here:

Code: ags
void _playFrame(int frame)
{
  // Look up the frame based on phoneme, unless argument is -1, in which case use frame 0
  if(frame == -1)
  {
    _currentPhoneme = "";
    _currentFrame = 0; // <-- Change this to 8
  }
  // ...

If that doesn't help, I would be inclined to believe the problem is with Rhubarb, but another potential problem could be that the animation and the audio drift out of sync because AGS isn't running at its set game speed (which is pretty likely with a high-res game like Old Skies, if that's where you're using it). If so, that would probably be fixable fairly easily by basing the calculation of the current time code on the system clock rather than on counting game frames.
#35
Glad you liked Rebecca, @cat. It's a good one! I guess ThreeOhFour will answer when he sees your post, but the big twist is usually considered to be:

(Again, huge spoilers)

Spoiler
The fact that Rebecca was a very unpleasant person, that her marriage to Mr. de Winter was unhappy, and that his passionate feeling for her was hate, not love. (And that the second Mrs. de Winter has therefore misinterpreted her husband's reactions any time her name was brought up.)

Personally I knew the twist before I read it, and even if I hadn't, the foreword—which IIRC tried to offer a revisionist take on Rebecca as a positive female character, a feminist rebel against a suffocating patriarchal society—gave it away.
[close]

So when not otherwise specified, that's most likely what they are talking about. I would consider the secondary (more conventional) twist to be:

Spoiler
The reveal that she deliberately goaded her husband into killing her because she had discovered that she had terminal cancer.
[close]

... But I don't think that's as well known/remembered, perhaps in part because the Hitchcock movie, produced under the Hollywood "Hays Code" censorship rules, changed the details:

Spoiler
Because Mr. De Winter goes free in the end, he could not be revealed as a wife-murderer. Instead, Rebecca's death is portrayed as an accident (although IIRC we only have De Winter's word for this), and so her non-pregnancy and connivance in her own death makes less difference.
[close]
#36
The Rumpus Room / Re: What grinds my gears!
Wed 27/09/2023 10:57:29
Quote from: cat on Wed 27/09/2023 09:59:03To be fair, I think it's a nice thing when car drivers slow down and let you pass.

Yeah, but if I'm not right at the crossing, and would actually have to suddenly sprint towards it and across the road to have any hope of getting hit, while at my current pace (and its steady speed) I would easily pass behind the car without either of us slowing down, then it makes everything more awkward if they do slow down and stop.

Before, I could ignore the car: it would have gone safely past before I had to enter the roadway. Now I have to take it into account, make sure it really is stopping, perhaps increase my pace or jog across to be considerate of its time, maybe even give a sign of acknowledgment. Sometimes other cars are affected and change their behavior in ways I need to keep a watch on (e.g. in an intersection). It becomes a considerably more stressful situation.

So it's often preferable to feign complete disinterest in crossing the road and pretend that you're going in a different direction until the car has passed and you can cross at your leisure. In some cases I've actually walked past the crossing I wanted to use, only to double back once the car had gone by.

I would compare it to merging onto the highway: things flow better if the cars already on the highway don't slow down (unless clearly necessary to avoid an accident). And in terms of social dynamics it's like people who hold the door for you even when you're too far away.

I should perhaps also mention that I live in the city, on a block where most cars drive fairly slowly (more slowly than most bicyclists), and right next to a five-way intersection with no traffic lights, so I have to deal with this on a daily basis.
#37
The Rumpus Room / Re: What grinds my gears!
Wed 27/09/2023 08:07:22
As a pedestrian, I usually want to cross the road behind any traffic, but if you make the slightest gesture in that direction, cars will typically slow down (even if they could have safely passed before I got out into the road if they had just maintained speed), and therefore I have to elaborately pretend that I don't intend to cross the road while waiting for them to pass.

This is rarely an issue with bicyclists. (Which is reasonable enough, as they can usually swerve to avoid a crossing pedestrian.)
#38
You might try
Code: ags
Display(String.Format("%s",s));
#40
Quote from: AndreasBlack on Tue 26/09/2023 10:34:24Then i could use the tool first and look for all the silences that are synced and take away the rest and justcopy/paste in the stored "full animation running" settings. Thoughts? Edit: The lipsync tool looks great for highres games, i'm only talking about lowres pixelart games here and yes having full on lipsync IS overkill.

What I'd probably do to minimize the work would be to keep the Rhubarb files as-is without any manual editing, but map all the phoneme codes to the same frame number in AGS, namely 1 (so, whenever the character is not speaking, the frame is 0, and when it is speaking the frame is 1, regardless of which phoneme/mouth shape it has). Then I'd make a slight change to the TLS code, so that instead of setting the displayed frame directly, the frame number controls whether the speech animation is playing or not.

This would also work with Papagayo files, if you find that Rhubarb's automatic analysis is not sufficiently accurate.
SMF spam blocked by CleanTalk