Show Posts

You can view here all posts made by this member. Note that you can only see posts made in areas to which you currently have access.

Messages - Snarky

Pages: [1] 2 3 ... 274
Advanced Technical Forum / Re: Walk Direction Angle
« on: Yesterday at 11:15 »
No, it's not customizable, and because AGS doesn't expose the waypoints of its pathfinding (so there's no general way to know what direction a character is heading in) it's not really feasible to implement it in script, either – unless you commit to building a whole new walk system from scratch.

Uh, yeah.

Damn, I'd forgotten about that! I thought I'd tried everything, but it was such a simple thing. Thanks, CW!

Another thing that seems to break the AGS scripting language: chaining together attributes that represent dynamically generated managed structs.

I'll explain. I have a managed struct that just holds a bunch of related data (I use a managed struct so I can put it inside various other structs and arrays):

Code: Adventure Game Studio
  1. managed struct Data
  2. {
  3.   int a;
  4.   int b;
  5. };

However, I also need to include this in some other managed structs. Since you can't store a managed struct in a managed struct, I've added some functions to convert Data to array form:

Code: Adventure Game Studio
  1. // I've used a static extender function, available with AGS 3.4, but it's the same with a regular static function
  3. Data* fromArray(static Data, int array[])
  4. {
  5.   Data* d = new Data;
  6.   d.a = array[0];
  7.   d.b = array[1];
  9.   return d;
  10. }
  12. int[] toArray(this Data*)
  13. {
  14.   int array[] = new int[2];
  15.   array[0] = this.a;
  16.   array[1] = this.b;
  17.   return array;
  18. }

Now I can store it in an array inside my other managed structs, and use an attribute with getters and setters calling the conversion methods to make the whole thing transparent:

Code: Adventure Game Studio
  1. // Header
  2. managed struct Primary
  3. {
  4.   // Underlying array
  5.   protected int _data[2];
  7.   // Attribute, accessors
  8.   import attribute Data* data;
  9.   import Data* get_data();        // $AUTOCOMPLETEIGNORE$
  10.   import void set_data(Data* d);  // $AUTOCOMPLETEIGNORE$};
  12. // Script
  14. Data* Primary::get_data()
  15. {
  16.   // Has to be a dynamic array, so make a copy
  17.   int array[] = new int[2];
  18.   for(int i=0; i<2; i++)
  19.     array[i]=this._data[i];
  21.   return Data.fromArray(array);
  22. }
  24. // Note this works as pass-by-value, not reference
  25. void Primary::set_data(Data* d)
  26. {
  27.   if(d != null)
  28.   {
  29.     this._data[0] = d.a;
  30.     this._data[1] = d.b;
  31.   }
  32. }

This works fine so far:

Code: Adventure Game Studio
  1.   Data* raw = new Data;
  2.   raw.a = 2; raw.b = 3;
  4.   Primary* p = new Primary;
  5. = raw;
  7.   // These should display the same
  8.   Display("Raw data a:%d b:%d", raw.a, raw.b);            // Displays: "Raw data a:2 b:3"
  9.   Display("Primary data a:%d b:%d",,;  // Displays: "Raw data a:2 b:3"

However, I also have another managed struct that uses Data. The actual link is a bit complex, but basically it's supposed to use the Data values associated with a particular Primary struct that is looked up in an array based on other fields; the Data* attribute is therefore read-only. So I tried to do something like this:

Code: Adventure Game Studio
  1. // Header
  2. import Primary* primaries[10];
  4. managed struct Secondary
  5. {
  6.   int primaryIndex;    // index into primaries[]
  8.   // Attribute, accessor
  9.   import readonly attribute Data* data;
  10.   import Data* get_data();        // $AUTOCOMPLETEIGNORE$
  11. };
  13. // Script
  14. Data* Secondary::get_data()
  15. {
  16.   if(this.primaryIndex != -1)
  17.   {
  18.     Data* d = primaries[this.primaryIndex].data;
  19.     return d;
  20.   }
  21.   return null;
  22. }

So, putting it all together, I try this:

Code: Adventure Game Studio
  1.   Data* raw = new Data;
  2.   raw.a = 2; raw.b = 3;
  4.   primaries[0] = new Primary;
  5.   primaries[0].data = raw;
  7.   Secondary* s = new Secondary;
  8.   s.primaryIndex = 0;
  10.   Display("Raw data a:%d b:%d", raw.a, raw.b);
  11.   Display("Primary data a:%d b:%d", primaries[0].data.a, primaries[0].data.b);
  12.   Display("Secondary data a:%d b:%d",,; // CRASH!

The last line crashes with a null exception. After some testing, it seems that is always null. Doing exactly the same calculation outside of the attribute accessor works:

Code: Adventure Game Studio
  1.   Data* test1 =;                            // This will be null...
  2.   Data* test2 = primaries[s.primaryIndex].data;    // ... while this will be a valid object

So is it a problem with trying to "chain" attribute accessors together like this? If I rewrite Secondary::get_data() as a direct copy of Primary::get_data() (making the _data[] array not protected and accessing it directly), it works, but it's an ugly workaround.

I've also got an inkling that it could have something to do with the readonly tag on the attribute. Oddly, when I take it away and try to provide a dummy setter, I get a hard crash (i.e. not to debugger) at an earlier line instead:

Illegal exception
An exception 0xC0000005 occurred in ACWIN.EXE at EIP = 0x00401633 ; program pointer is +1101, ACI version, gtags (0,0)

AGS cannot continue, this exception was fatal. Please note down the numbers above, remember what you were doing at the time and post the details on the AGS Technical Forum.

in "AttributeTest.asc", line 49
from "room1.asc", line 54
from "room1.asc", line 63

Most versions of Windows allow you to press Ctrl+C now to copy this entire message to the clipboard for easy reporting.

An error file CrashInfo.dmp has been created. You may be asked to upload this file when reporting this problem on the AGS Forums. (code 0)

The line reference is to Data* d = primaries[this.primaryIndex].data; in Secondary::get_data().

I don't really have a good understanding of what's going on.

It's too much, man. I'm impressed by the creativity, the effort and atmosphere you're putting in, it's great stuff, but having to brute-force the puzzle by re-asking the same questions over and over just to be relatively confident in the answers... no thanks.

I'll just guess David Bowie's Goblin King from Labyrinth. It fits some answers, and maybe the ones that don't fit are lies.

Thanks for confirming, Crimson Wizard! That also suggests a simple workaround: at the top of the function body you can just add something like (in your example):

Code: Adventure Game Studio
  1.   DynamicSprite* this_ds = this;

Doing so does increase the reference count, and the bug is averted. (Of course, it would still be nice to have it fixed!)

I'm experiencing... weirdness, and sometimes crashes, in methods of managed structs that use the this-pointer, if I delete/overwrite all external handles to the object partway through the method.

The setup is something like this:

Code: Adventure Game Studio
  1. // Simplified struct
  2. managed struct Job
  3. {
  4.   int value;
  5. };
  7. // A different script:
  9. // I need to keep track of a bunch of jobs
  10. Job* jobPool[100];
  12. // This function manipulates the job pool
  13. void Process(this Job*, int index)
  14. {
  15.   Display("This Job rating: %d", this.value); // I access the value
  18.   // Then delete a particular entry in the jobPool
  19.   jobPool[index] = null;
  20.   // ... and create a new Job
  21.   Job* job = new Job;
  22.   job.value = 20;
  24.   Display("This Job rating recheck: %d", this.value); // I access the value FOR THIS JOB again
  25. }
  27. // And I call that function:
  28. void someOtherFunction()
  29. {
  30.   // Fill the job pool
  31.   for(int i=0; i<100; i++)
  32.   {
  33.     jobPool[i] = new Job;
  34.     jobPool[i].value = i*2;
  35.   }
  37.   // ... and later on
  38.   jobPool[5].Process(5); // The SAME NUMBER
  39. }

So I'm calling Job.Process() on jobPool[5], telling it to remove the entry in jobPool[5] from the array (in my real program, Job.Process() handles the indexes and always removes the job you call it on from the array, but let's keep it simple here). Since this is done with pointers, the object itself should not be affected (though we won't have any way to reference it after the function completes).

However, what actually happens is that it Displays:

This Job rating: 10 (the original value, correctly)
This Job rating recheck: 20 (the value of the new Job we made, job)

In other words, the this pointer is now pointing to the wrong Job!

If I remove the jobPool[index] = null; on line 19, this doesn't happen. I'm guessing that since the only external reference to this object is the entry in jobPool[5], setting that to null reduces its reference count to 0 and marks the object as deleted, even though we're still inside a function that has a local pointer to it, and that the new object is therefore slotted into the newly "free" memory, so that the this-pointer ends up pointing to it by "accident" (supporting this theory, if I add the line Job* j = jobPool[5]; on line 36 right before I call jobPool[5].Process(5); it also doesn't happen).

Under other circumstances, this can cause AGS to crash with the error "Pointer cast failure: the object being pointed to is not in the managed object pool", but I'm not able to recreate that crash in a simple sample program.

Hmm... so Phylactere "fakes" transparency by manually calculating the color of every pixel from combining the background with the overlay, and drawing that pixel-by-pixel. Yikes!

If using an overlay rather than a GUI isn't a major priority for some reason, you could just replace all of this with a semi-transparent GUI (or two GUIs, one for the speech bubble and one for the text, because of the antialising problems you get with text on transparent GUIs). It should be a lot faster, and you won't have these color artifacts.

That looks like an AGS bug, so what AGS version are you using?

The Rumpus Room / Re: *Guess the Movie Title*
« on: 19 Oct 2017, 20:51 »
Spot on.

The Rumpus Room / Re: *Guess the Movie Title*
« on: 19 Oct 2017, 11:36 »
How do you not remember that scene Snarky!? :shocked:

It's been a while since I watched it, I guess?

None of the ones so far.

Critics' Lounge / Re: A thumbnail for gamejolt
« on: 18 Oct 2017, 16:23 »
Gamejolt has a very different understanding of "thumbnail" than I do.

Hmm... I only count five if we're not including Doctor Who:

1. ST Discovery
2. The Orville
3. The Expanse
4. Dark Matter
5. Killjoys

Are you counting Rick & Morty? (Aww jeez, R&M first aired in 2013, so if that counts there were only a couple of years without any space opera on TV.)

The Rumpus Room / Re: *Guess the Movie Title*
« on: 18 Oct 2017, 14:09 »
No, that was my cunning trap.

The Rumpus Room / Re: *Guess the Movie Title*
« on: 18 Oct 2017, 13:22 »
My memory is pretty spotty.

Engine Development / Re: AGS4 cleanup branch
« on: 18 Oct 2017, 10:15 »
Yeah, sorry to not be any help on this, but I can at least add some suggestions for stuff to clean up:

The AGS general settings pane is littered with unnecessary switches, and even a lot of them that aren't explicitly identified as backwards-compatibility options should be rooted out. I'm thinking particularly of "Automatically move the player in Walk mode", "Automatically walk to hotspots in Look mode" and "Override built-in inventory window click handling": there's no reason to provide any built-in behavior here rather than just script it in the appropriate game templates. It's just one more complicating factor when a developer has to try to figure out how the engine behaves. Similarly, the GUI visibility setting "When mouse moves to top of screen" should be eliminated. All this stuff is legacy from when AGS was an engine squarely focused on making games in the  Sierra SCI style, and it is superseded by newer, more general functionality.

Could I possibly implore you to fix your indenting? Seeing how you've formatted these code snippets is almost physically painful. It's like someone who iS deMONSTraBly Aware of CAPital lEtTers, bUT WhO JUST scatters thEm rANDomLy aRound In tHe SeNTeNCe.

This code worked fine for some time, but now, for some reason, it no longer does.

In what way does it not work?

Anyway, I would usually debug a problem like this by setting a breakpoint in the on_key_press() function and seeing where it goes wrong.

I have a system in place where the walk cursor changes to an arrow cursor whenever it's over an exit. An example (under a "Mouse moves over hotspot" section) would be something like:

Wait, you code this individually for each hotspot? That is... not a good way.

I'm not sure what the exact cause of your problem is (it could be that the "mouse moves over hotspot" event doesn't trigger immediately – I've never used it), and the way your logic is organized looks a little odd to me (you test whether the mouse mode is eModeArrow before you potentially set it to eModeArrow, rather than after as I would expect).

But first I would at least factor this out as a separate function (something like setArrowCursorForHotspot(int direction)). Or even better, to avoid having to write a bunch of "mouse moves over hotspot" handlers at all, instead just put a test in repeatedly_execute_always() to check whether it's over a hotspot – you can use a custom property to define whether the hotspot uses an arrow and if so in what direction, and the whole thing will just happen automatically.

The Rumpus Room / Re: *Guess the Movie Title*
« on: 17 Oct 2017, 20:45 »
Ex Machina? I don't remember the scene, though.

Is it a male (or someone who presents as male)?
Does he/she/it eat brains?
Does he/she/it drink blood?

Brilliant! Glad it worked out, and your game will be in good company.

Pages: [1] 2 3 ... 274