[RESOLVED} Getting compiler error when using Defined values

Started by Joacim Andersson, Thu 21/11/2024 17:35:06

Previous topic - Next topic

Joacim Andersson

I have this in a scripts header file:
Code: ags
#define PLAYER_ON_PORTAL 13;
Then elsewhere I have this:
Code: ags
function PlayerOnPortal()
{
  Object* portal = Object.GetByName("oPortal");
  if (portal != null)
  {
    if (Object.GetAtRoomXY(player.x, player.y) == portal)
    {
      player.StopMoving();
      player.FaceDirection(eDirectionDown, eBlock);
      CallRoomScript(PLAYER_ON_PORTAL); 
    }
  }
}
If I replace the line CallRoomScript(PLAYER_ON_PORTAL) to CallRoomScript(13) it works, but when I try to use the defined value I get "Parse error in expr. near '13', so the parser has replaced the PLAYER_ON_PORTAL macro with the value 13, yet it doesn't work. Any help?

eri0o

Remove the trailing ; character, define is a text macro replacement, you are placing a ; inside the function parameter.

Joacim Andersson

#2
Oh, yes. of course! Thank you. You know I started my development career as a C/C++ developer, I should know this stuff, but I think I just added the trailing semicolon out of habit. Yet I have several defined macros above this line with no trailing semicolons.

eri0o

For this case specifically you can also use an enum instead, enum can fakely be a const int or typedef like in feelings. You just can't use an enum for non-dynamic array size.

In ags4 with the new compiler, I believe readonly is the keyword you use for const like behavior. And there I believe that it also works in non-dynamic array size.

Crimson Wizard

#4
Quote from: eri0o on Thu 21/11/2024 20:38:49In ags4 with the new compiler, I believe readonly is the keyword you use for const like behavior. And there I believe that it also works in non-dynamic array size.

AGS 4 supports both "const" and "readonly",
where "const" is a compile-time constant, and it is replaced with actual value during compilation;
while "readonly" is a runtime-time constant, meaning it may be initialized by any expression, including calling a function, which result can be only calculated at runtime.

Joacim Andersson

Quote from: Crimson Wizard on Thu 21/11/2024 22:07:50"readonly" is a runtime-time constant, meaning it may be initialized by any expression, including calling a function, which result can be only calculated at runtime.
So does that mean that a readonly can be initialized once, much like a readonly in C# can be initialized in the constructor. However, since AGS doesn't have classes and constructors, does that mean that a readonly is not initialized when created like a normal int is initialized to 0?

eri0o

I think that it's simply single assignment - in ags4.

QuoteYou may have readonly global variables, local variables, function parameters, and struct attributes.

Two most common uses of a readonly variable are function parameters and local variables. This works as a "failproof" method to ensure that they are only assigned, but are never changed within the function by programmer's mistake.

In ags4 managed structs will have constructors soon - CW has a PR with them already.

Crimson Wizard

#7
Quote from: Joacim Andersson on Thu 21/11/2024 22:24:26So does that mean that a readonly can be initialized once, much like a readonly in C# can be initialized in the constructor. However, since AGS doesn't have classes and constructors, does that mean that a readonly is not initialized when created like a normal int is initialized to 0?

AGS has "structs", which are like something in between struct and class in functionality.
But you are right that it does not have constructors just yet. There will be soon in AGS 4.0 though (we're working on that).

Traditional use of "readonly" in structs was for attributes (aka properties). That would make these gettable but not settable.

This may be done in 3.* already, and is thoroughly used in standard engine API:

Example of user script:
Code: ags
struct MyStruct
{
    import void InitMe(int data);
    import readonly attribute int Data;

    protected int _data;
};

Code: ags
void MyStruct::InitMe(int data)
{
     _data = data;
}

int MyStruct::get_Data()
{
    return _data;
}

Joacim Andersson

Will AGS 4 have both getter and setter properties? I would love that, to get rid of all global variables.

Crimson Wizard

#9
Quote from: Joacim Andersson on Sat 23/11/2024 01:58:19Will AGS 4 have both getter and setter properties? I would love that, to get rid of all global variables.

AGS already has properties with getters and setters, as well as ways to protect fields of structs from public access

The manual is a bit lacking in regards to this topic unfortunately, but the general explanation may be found here:
https://adventuregamestudio.github.io/ags-manual/OOProgramming.html

Joacim Andersson

#10

Yeah ok, so basically you have to create a Get and a Set method (much like Java) but above it looked like the read-only data variable could be read by the int MyStruct::get_Data() method, which isn't declared. So it looks like that would be called when you use
value = myStructInstance.Data
Have I understood that correctly? If so it's still different from having a GetData() and a SetData() method.

Crimson Wizard

#11
Quote from: Joacim Andersson on Sat 23/11/2024 02:28:01Yeah ok, so basically you have to create a Get and a Set method (much like Java) but above it looked like the read-only data variable could be read by the int MyStruct::get_Data() method, which isn't declared. So it looks like that would be called when you use
Code: ags
value = myStructInstance.Data
Have I understood that correctly? If so it's still different from having a GetData() and a SetData() method.

Yes, that is correct, if you have declared an attribute Data, then you don't need GetData and SetData methods, but you need to define get_Data and set_Data methods.

I made a small mistake in the example above, in case get_Data was not declared in the struct explicitly, then its definition has to be done using an "extender function" syntax

Code: ags
int get_Data(this MyStruct*)
{
    return this._data;
}

This is also explained in the article that I linked above.

Joacim Andersson

You're confusing me, the get_Data and set_Data (or whatever you like to call them) still have to be declared but they are automatically called when you use code like this:
Code: ags
int value = myStructInstance.Data;
value++;
myStructInstance.Data = value;
So you don't have to use this code:
Code: ags
int value = myStructInstance.get_Data();
myStructInstance.set_Date(value * 2);
So basically they work like property getter and setters in C#?

So you can also use extension methods? That's cool. I wish the documentation were a bit more extensive on all of the OOP stuff.

Joacim Andersson


Crimson Wizard


Joacim Andersson

Thank you so much for your replies and explanations. I promise that this will be my last post in this thread since we got a bit off-topic.

But what is the plan for AGS, will there be more 3.x releases before 4.0 is ready?

I also hope that you guys get constructors to work properly, then I will eagerly await the release of 4.0.

Crimson Wizard

Quote from: Joacim Andersson on Sat 23/11/2024 02:42:57I wish the documentation were a bit more extensive on all of the OOP stuff.

Yes it is true, some parts of the manual have unfortunately been neglected for a while. This is mostly because of small number of contributors to the engine.

Quote from: Joacim Andersson on Sat 23/11/2024 02:58:20But what is the plan for AGS, will there be more 3.x releases before 4.0 is ready?

Eventually we'd like to focus on AGS 4, and only do patch releases to 3.x.
AGS 4 has been delayed for too long, because of inconsistent planning...

3.x is a backwards compatible engine which can run many old games. Plus it's a way to upgrade game projects from earlier years, if someone wants to move them to AGS 4 they'd have to go through 3.x first. So it will be around as a backup version.

SMF spam blocked by CleanTalk