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

#321
Presumably there are some aspects of 3.6 builds that aren't supported on my environment. Did the crash dump tell you anything?
#322
Here you have copies of the project both before and after the version upgrade.
#323
I made a small project with 3.5.0 yesterday. When I tried upgrading, rebuilding and running it with this RC today, it crashes on launch. (Crash dump)
#324
OK, I put together a quick little module to provide the functionality that ChangeRoomAutoPosition is supposed to have.

Code: ags
//Header
#define NO_POSITION -1001

enum RoomEdge
{
  eRoomEdgeOpposite = -1,
  eRoomEdgeNone,
  
  eRoomEdgeTop, 
  eRoomEdgeBottom, 
  eRoomEdgeRight, 
  eRoomEdgeLeft
};

import void ChangeRoomEdge(this Character*, int room, RoomEdge edge=-1, int position=NO_POSITION);

Code: ags
// Script
RoomEdge newEdge;
int newPosition;
#define DISPLACE_EDGE 1

void ChangeRoomEdge(this Character*, int room, RoomEdge edge, int position)
{
  switch(edge)
  {
    case eRoomEdgeNone:
      this.ChangeRoom(room);
      return;
    case eRoomEdgeOpposite:
    {
      int minDist = this.y - Room.TopEdge;
      RoomEdge minEdge = eRoomEdgeBottom;
      int pos = this.x;
      
      int dist = Room.BottomEdge - this.y;
      if(dist<minDist)
      {
        minDist = dist;
        minEdge = eRoomEdgeTop;
        pos = this.x;
      }
      dist = this.x - Room.LeftEdge;
      if(dist <= minDist)
      {
        minDist = dist;
        minEdge = eRoomEdgeRight;
        pos = this.y;
      }
      dist = Room.RightEdge - this.x;
      if(dist < minDist)
      {
        minDist = dist;
        minEdge = eRoomEdgeLeft;
        pos = this.y;
      }
      edge = minEdge;
      if(position == NO_POSITION)
        position = pos;
      // Fallthrough to default
    }  
    default:
      newEdge = edge;
      newPosition = position;
      this.ChangeRoom(room);
      return;
  }
}

function on_event(EventType event, int data)
{
  if(event == eEventEnterRoomBeforeFadein)
  {
    if(newEdge != eRoomEdgeNone)
    {
      switch(newEdge)
      {
        case eRoomEdgeTop:
          player.y = Room.TopEdge + DISPLACE_EDGE;
          if(newPosition != NO_POSITION) player.x = newPosition;
          break;
        case eRoomEdgeBottom:
          player.y = Room.BottomEdge - DISPLACE_EDGE;
          if(newPosition != NO_POSITION) player.x = newPosition;
          break;
        case eRoomEdgeLeft:
          player.x = Room.LeftEdge + DISPLACE_EDGE;
          if(newPosition != NO_POSITION) player.y = newPosition;
          break;
        case eRoomEdgeRight:
          player.x = Room.RightEdge - DISPLACE_EDGE;
          if(newPosition != NO_POSITION) player.y = newPosition;
          break;
      }
      newEdge = eRoomEdgeNone;
      newPosition = NO_POSITION;
    }
  }
}

Note that it uses the Room edges (which can be configured in the Room Editor) to determine which edge of the room you are closest to, and also to position you in the new room.

The API is a little different from Character.ChangeRoomAutoPosition():

Code: ags
  player.ChangeRoomEdge(4); // Change to room 4, on the opposite edge of where you exit
  player.ChangeRoomEdge(4, eRoomEdgeTop); // Change to room 4, on the top edge (with current x)
  player.ChangeRoomEdge(4, eRoomEdgeLeft, 400); // Change to room 4, on the left edge with y=400

Unlike Character.ChangeRoomAutoPosition(), you don't have to be within 10 pixels of an edge for it to move you to the opposite edge in the new room: whichever edge you are closest to (or, if you're outside the edges, the one you're furthest outside) will be used as your "exit" edge, no matter where in the room you are. (In fact, the behavior of ChangeRoomAutoPosition() as described in the manual is undefined if you're not within 10 pixels of an edge; it's probably time to deprecate it.)

Oh, and only call this on player. Calling it on other characters will likely have unexpected effects.
#325
For this type of room transition I would use room edges rather than hotspots or regions. The ChangeRoomAutoPosition() bug is however a showstopper for this approach.

It should be possible to recreate its (correct) functionality in script, though, using on_event(eEventEnterRoomBeforeFadein). I'll see if I can whip up a module—unless Khris wants to beat me to it.
#326
Forum search isn't working either.
#327
Neat! Having never before heard of sprite stacking, I found this article a good introduction: https://www.davidepesce.com/2020/06/26/sprite-stacking-in-godot/
#328
Quote from: KyriakosCH on Thu 24/11/2022 10:06:10This is how I imagine it: the game comes up with arbitrary coefficients and constants (within reason, say single digit numbers 1-9), and calculates the correct answer, then the player is prompted to give the correct answer (enter x,y for the intersection)

OK, so the intersection points may not be at integer coordinates. That means we need to use floats. The problem is that floats are not exact, so we have to use rounding. And you can in theory have the curve and line come very close without intersecting (or before they intersect), so just checking that we are "close" to both curves is not good enough.

In that case, I think the best solution is to solve the equation for the intersection points (if any) using the quadratic formula, and then compare those coordinates to the input coordinates. If they are within tolerance (identical up to some number of significant digits), it's a match.

You can use a function like:

Code: ags
// Find the roots of the quadratic equation ax^2 + bx + c == 0
float[] quadraticRoots(float a, float b, float c)
{
  float discriminant = b*b - 4*a*c;
  if(discriminant < 0.0)
    return null; // no real roots

  // Else, for simplicity, we always return two roots, even if identical
  float[] roots = new float[2];
  float stable = -b / (2.0*a);
  float variant = Maths.Sqrt(discriminant/(4.0*a*a));
  roots[0] = stable - variant;
  roots[1] = stable + variant;
  return roots;
}

// Just a helper function for when coefficients are all ints
float[] quadraticRootsInt(int a, int b, int c)
{
  return quadraticRoots(IntToFloat(a), IntToFloat(b), IntToFloat(c));
}

(Since we need to return two numbers, we create and return an array.)

So you just plug the difference in coefficients into the function to find the roots, which are the x-coordinates of the intersections, calculate the y-coordinates of one of the functions at those x-coordinates, and compare each pair of coordinates to the input to see if they match (to within some tolerance).

Quote from: KyriakosCH on Thu 24/11/2022 10:06:10But - why not ^^ - would AGS code allow for also calculating (through slope; which you can just set up another function to calculate on account of the power rule) the angle of meeting points of the (say) quadratic and linear graphs?

I assume you mean the slope of the quadratic curve at the point of intersection? Sure. Any basic mathematical formula can easily be calculated in AGS. I expect you'll be able to write that function yourself given the examples shown here.
#329
Off the top of my head, given the coordinates (x1,y1) and two functions f(x) and g(x), I think the easiest way would be to calculate the values of f(x) and g(x) at x1. If both equal y1, then you have found an intersection point between them.

If the form of f(x) and g(x) are fixed, so that f(x) is always a quadratic curve and g(x) always a line, you can easily do this check in a single AGS function. Just enter the parameters and coordinates as function arguments, calculate the function values, and compare the results. If the form of the curves can vary arbitrarily, I would probably break up the logic into sub-functions.

It would look something like this:

Code: ags
bool isIntersection(int a, int c, int b, int d, int x1, int y1)
{
  int f_x1 = a*x1*x1 + c;
  int g_x1 = a*b*x1 + d;
  return (f_x1 == y && g_x1 == y1);
}

This approach allows you to easily add in a tolerance for the y value, but if you also want some tolerance in x, you'll need to actually solve the equations.

Edit: Just noticed that you talk about digits in the parameters, so presumably you'd want those as floats. Then it gets a little bit more work, since you can't just do a == comparison, since floats are not exact.
#330
Please start a new thread for new questions, so that each thread deals with one technical issue and so the thread title describes the problem. I have split your post off into a new thread.

There isn't really a "hotspot folder" or file anywhere. The properties (ID/name and events) are stored in the game.xml file, the masks inside a big binary blob (in AGS 4.0 they will be stored as separate image files in a folder, I believe), and the event code in the room scripts. By deleting these in the editor, you should be able to "reset" it. If you're having trouble, please describe what is happening in detail.
#331
George Harrison - My Sweet Lord
#332
Guys, you're forgetting that AGS has this feature built in.

Quote from: multi007 on Tue 22/11/2022 18:23:05Because what I want to happen is just like it does in the KQ games, if the player exits a room on the top of the page, the player appears at the top of the room 2.  If he exits the bottom, he appears on the bottom.

That is exactly what Character.ChangeRoomAutoPosition(int RoomNumber) does. If the character exits along one edge, it'll appear at the corresponding position along the edge of the opposite side of the new room, just as in your drawing.
#333
The image I posted was never intended as an entry, for two reasons.

First, I'm not absolutely opposed to AI-generated pictures in contests like the Background Blitz (since although it is a lot less work than drawing a picture yourself, it also has some obvious limitations and weaknesses, so it's not an automatic walkover or anything), but I think it has to be discussed up front, since it is awfully close to cheating. I mean, what if I just searched the internet for spooky pictures and posted one I liked as my entry? That's not so different from this.

Second, even if we say yes to AI-generated (or -assisted) entries, I had this one made as an experiment, with various constraints meant to simulate what a bot might be able to do on its own and to minimize human guidance. So it does not represent an attempt to produce the best possible Background Blitz entry. If I'm to enter the Blitz, I want it to be with a piece of which I can say "this is the best I could do under the circumstances."

On to the voting:

Concept: Creamy
Playability: mattcoles
Artistic execution: Creamy

I like mattcoles' entry a good deal. It has a clear, cartoony look that would work well in a game, and I always appreciate a clearly marked walkable area and exit. But I feel it is badly let down by the lighting, which makes the typical mistake of just turning down the brightness so that everything looks flat and dim. Creamy's entry demonstrates that just because something takes place at night, that doesn't mean you can't use bright colors and dramatic contrasts.

Creamy's entry tells a story, and it is visually interesting to look at. The cyan/purple color scheme is very nice, and the marker-like technique is also cool. I'm having a bit of a hard time imagining what role it would play in a game, though (establishing shots don't count for purposes of the Blitz, IMO). Even the flying saucer doesn't really say "clickable" to me.
#334
Bumping this thread (celebrating its tenth anniversary!) again as a potential suggestion for AGS 4.0.

This particular use-case is probably not a high priority, since you can always just substitute a String.Format call, but it might be useful to have variadic functions in general.
#335
And to add to Crimson Wizard's suggestion...

It sounded like the main reason you didn't want to use a GUI was that TextWindow resizes itself to fit the text. Does that mean you're using a decorated TextWindow with a frame and tiled background?

If so, there are a number of modules and code samples that draw a background and border frame for an arbitrarily sized window. CustomDialogGUI is one, SpeechBubble 0.8.10 another. (You may have to just borrow the relevant code, since both modules have other logic that doesn't quite fit your use-case.)

It's not super-difficult to do yourself, in any case. It basically amounts to:

  • At setup, store the sprite numbers for the window background, borders and corners
  • Draw the text + graphics as CW suggests (this is the hardest part, but it has been done before) to a DynamicSprite
  • Measuring the size of the DynamicSprite and the window borders and corners, determine how large the window should be
  • Draw the borders, corners and tiled background onto another DynamicSprite the size of the window, using loops
  • Draw (copy) the content sprite on top of the background sprite
  • Set the window background to the combined sprite
#336
Sure. It's open source; feel free to make changes. (Just note that I can't really offer support for code that has been heavily modified.)
#337
Quote from: CCrane on Thu 17/11/2022 14:12:54My issue is that after selection that line is repeated/said on screen, which is done using .Say command. (Pic 1a).
In the dialog editor I can only change character replies from .Say to .SayBubble, like this:

Code: ags
  Torres: I was in a plane and now I ...
  cTorres.SayBubble("I was in a plane and now I ...");

Ah. No, I'm afraid that is hardcoded to use .Say() (see the release notes for v3.5.0.P3, under Added "Custom Say/Narrate function in dialog scripts"). The workaround is to uncheck the "Say" checkbox and put a copy of the line in the dialog script instead.

However, that "Custom Say/Narrate function in dialog scripts" could probably save you from having to change the lines in the dialog script, if you can set the function that dialog lines are converted to to .SayBubble(). (I haven't actually tried it, but it ought to work.)

Quote from: CCrane on Thu 17/11/2022 14:12:54Maybe ordering would work if I put all scripts in an own folder. Would that break something?

The folders are merely for keeping things tidy. When compiled it's flattened into a simple list, from top-down. So you can make a folder and put whatever scripts you want in it (except the GlobalScript, which can't be moved) without trouble. You could have one folder just for SpeechBubble, or for any other modules.

In general, it's probably a good idea to keep third-party modules at the top of the list, and put any custom scripts you create below them, whether in a folder or not.
#338
Quote from: CCrane on Thu 17/11/2022 09:36:20Hello there (again  :) ),

Sorry for being a nuisance

No worries.  ;-D

Quote from: CCrane on Thu 17/11/2022 09:36:20but I get an error when I replace this
Code: ags
player.Say("Looks like ... %s.", passphraseA_Word);
with that piece of code
Code: ags
player.SayBubble("Looks like ... %s.", passphraseA_Word);
Failed to save room room1.crm; details below
room1.asc(310): Error (line 310): Type mismatch: cannot convert 'String*' to 'GUI*'

SayBubble() doesn't support the string formatting capability that Say() does. When you want to insert dynamic variables in the string, what you'll have to do is to wrap the message argument in a String.Format() call, like so:

Code: ags
player.SayBubble(String.Format("Looks like ... %s.", passphraseA_Word));

Quote from: CCrane on Thu 17/11/2022 09:36:20Another thing is the option text in dialog. While it's no problem to change the lines in dialog script to command style the options stay as they are. I don't even know where to look for them, actually. Is it possible to change them as well? That would be great.

I'm not sure I understand what you mean. How do you want the dialog options to be displayed? In general, to change the look and feel of dialog options, you would have to write your own custom dialog options rendering. (Except for very simple things like the font and the background/text color, for which there are probably some property.)

Quote from: CCrane on Thu 17/11/2022 09:36:20I tried to change Say to SayBubble in abstauber's script, there seem to be only two places of player.Say(lookat) in VerbGui.asc actually, but then it just gave me this message.

SayBubble is not a public member of character

I asked him in his thread but maybe you have an idea too

This is probably an issue of module ordering. In the current AGS version, you can only call functions from modules higher up in the module list. So you would have to place SayBubble above the Tumbleweed module in order to use this function from Tumbleweed. (I don't remember if the module list lets you drag and drop to reorder, or if you have to right-click and choose move up/down.) This restriction will be removed in an upcoming AGS version—not sure whether it's 3.6 or 4.0.
#339
Hi CCrane. I'm happy if the module is of use to you.

Quote from: CCrane on Wed 16/11/2022 16:17:34Some questions I'd like to ask. First, if ...

  SpeechBubble.MaxTextWidth = 250;

... is determined by screen/native game resolution size, i.e. are these relative or absolute values? I would generally prefer dialog in at least two lines for a more proportionate appearance of the bubble but setting some value up for text width won't make much sense with absolute values if the target system has a greatly differing resolution.

The values are in pixels, as are practically all AGS graphics functions. AGS games have a fixed (though customizable) game resolution that (almost) everything is rendered in, and if the screen or window resolution differs from that, the final image is simply scaled up or down. So the screen resolution it's played on should not make a difference to the layout logic: If your game is natively 640x400, then a width of 250 represents slightly less than 40% of the screen/window width.

Quote from: CCrane on Wed 16/11/2022 16:17:34Secondly, is it possible to change border width/line thickness of the bubble? I found no variable for that so I suspect it's kinda similar to automatic text outline which can't be adusted, either. My test game is 640x400 right now and I might go even higher but the border can barely be seen already.

No, this is not currently supported, because it would significantly complicate the logic for drawing rounded corners. However, there is an unofficial version of the module that allows you to assign sprites for the outline and background of the speech bubble. This would allow you to set a thicker outline.

Quote from: CCrane on Wed 16/11/2022 16:17:34If line thickness is hard-coded would it be possible to create two overlaying bubbles, eg. one smaller white and a bigger black one in the background? This won't really work with transparency obviously but some of us might be okay with that. Just a thought ... :)

It's an interesting idea for a workaround, but I think it would be quite complicated to make it work consistently, and that the outline would not look very nice. (Again, the rounded corners, which I think would get "blobby" and uneven.)

Quote from: CCrane on Wed 16/11/2022 16:17:34Finally, you mentioned planning a think bubble. Will this only work for Sierra-style speech, like player.think seems to do currently, or also for LucasArts-style games? That would be great.

Off the top of my head I see no reason why it shouldn't work for LucasArts speech too. However, from my side further development of the module is currently on hold, since I don't have the time or energy to devote to it.
#340
The Rumpus Room / Re: Guess the TV show
Tue 08/11/2022 14:54:15
Yes, good show, and a great solution to doing sci-fi on a low budget. (Continuum is another Canadian show with a similar time-traveler premise, but I couldn't get into it.)
SMF spam blocked by CleanTalk