Read-only archive of the Armageddon Games Forums Archive (2000–2026) · About this archive

AngelScript: The Revenge

114 replies · 56,127 views · Started 17 January 2017

Almost exactly a year ago there was discussing about switching ZC to using AngelScript instead of ZScript, and it had some support at the time, and Gleeok and Saffith did quite a bit of work on incorporating AngelScript and porting over some of the engine internals... and then it was backtracked.

Gleeok in another thread posted

This would allow new systems to be created that can simply piggy-back off the old ones but also be tightly coupled with scripts that can actually rewrite built-in behaviors without having major issues or losing compatability (or creating bugs with existing quests). The new npc scripts and supporting of various global callbacks I envisioned would be a good test of that experiment before doing anything else with that. ...It's not been worked on really, but it should be. .. :/

I think I'm going to make putting in the compiler/script processor/script engine my next priority besides the few other things I have here. Even if it's not used immediately, if I can get a ZScript->angelscript conversion utility working you might take it more seriously.


and so I wanted to (re)start a discussion about AngelScript in ZC. Some points in particular I'm curious about:

1. What were the lessons learned last year during the effort to incorporate AngelScript? What are the big challenges?
2. Is it feasible to switch to AngelScript while maintaining compatibility with old quests (presumably, this would require only supporting the ZASM interpreter, and ZScript could be dropped entirely)? Or would an AngelScript-driven ZC live in its own ecosystem separate from the existing program and quests?
3. What concrete steps would need to be taken to adopt AngelScript, to minimize the time until we have a functional release candidate, if we decide to do this?

Making a plan sooner rather than later seems prudent, as it will help dictate whether effort should be put into expanding the power of ZScript, vs. working on its replacement.

As I said at the time, I'll mostly be focused on ZScript in any regard. Even if you want to shift over, supporting both, for a while, seems mandatory; and I do not see the problem with crosscompiling. tuning the ZScript parser, introducing some new syntax over time, and slowly migrating would make the whole transition cleaner. I also see no issue with supporting compiling ZScript into AS> The AS model is designed to accept additional syntax types, which is why it was originally an attractive model.

The other end of the question, is that is the change better than say, just making ZScript far more robust, and implementing the types of things that we could do with AS, using the existing language.

I do not see ZScript as something separate from ZC compatibility issues. If you want to support all the qussts ever made, you need to support all the ZScript ever made with them.

Another approach, is to integrate both. I could throw together a block diagram of this, if you want. You could pretty much have a core with two lines of communication, and some interrupts, to allow parsing instructions from both AngelScript, and ZScript, into a core engine; or you could base the core engine on AngelScript entirely, and use ZScript inputs to that, as we do with the present ZC engine. That would probably be my approach to it.

I've said many times, that I do not object to AS in premise, only to the older planned implementation, which was essentially 'We don't want to spend the time to do this properly.'.

Just about everything that AS does, can be implemented in ZScript too, which could allow the user to select their preference, and cross-compile between the two, for the most part, for a while. From there, you can slowly phase out support for ZScript, if you desire; or whatever. I think I plotted out a multi-release timeline for that, and no-one ever wanted to look at it, because they didn't want to ensure that a high level of compatibility exists between old, and new scripts.

There are other options, too. Gleeok wanted to do a C# thing, and I am not a fan of this, mostly because the C# syntax is very much a Microsoft thing, and cross-platform support is--or at least was--farcical. If we wanted to do this, I would like to see the core ZC processes minimised to very basic things, and the script parser take over to handle most events. We can have that conversation separately, but right now you have a total of what, five of us involved?

I would like to focus on ZScript for the next two versions, at least, possibly integrating something new, in part, starting with the second, and slowly progress into it, if we want to do it, over the following two. (That equated to 2.55, 2.60, 2.65, and 3.0.)

I would love to be able to offer both over the long term too, but how problematic that might be, I do not know. The flip side, is that this falls into the same category as shifting to Allegro 5, or other radical changes. The present state of the engine needs encapsulation of some kind first.

[MENTION=38582]Saffith[/MENTION] was the only one who worked on shifting the engine to an AS core. There was a branch with his enemy code, where the internal enemy code was replaced with AS scripting stuff. I recall that he purged it because it was some kind of unworkable nightmare for him, at the time, but I could be mistaken. It would be nice if he documented what he tried to do, what worked, and what did not.

The other end of the question, is that is the change better than say, just making ZScript far more robust, and implementing the types of things that we could do with AS, using the existing language.

Right! This is the key question. I could focus energies on some of the changes that have been discussed on the forums and in chat (making inter-script communication easier, tracking pointers over time easier, scripting weapons and Link, etc). But if it sounds like transitioning to AngelScript makes more sense, I want to avoid introducing new features that will make cross-compilation harder.

I do not see ZScript as something separate from ZC compatibility issues. If you want to support all the qussts ever made, you need to support all the ZScript ever made with them.

Well, it's true that *ZASM* must be supported. But not necessarily ZScript (we guarantee that old quests will play in new versions; I agree it would be very nice if old quests can be edited in new versions too, but this is not as bedrock of a principle IMO.)

Let me ask you this: is there any reason to support ZScript, *other* than backwards compatibility of old scripts? If there were a ZScript cross-compiler, would this be sufficient? Or is there a fundamental benefit to supporting both languages?


There was a branch with his enemy code, where the internal enemy code was replaced with AS scripting stuff. I recall that he purged it because it was some kind of unworkable nightmare for him, at the time, but I could be mistaken. It would be nice if he documented what he tried to do, what worked, and what did not.

Agreed. Taking stock of past lessons is a key first step to planning for how, and if, to transition to ZScript.

DarkDragon wrote:Let me ask you this: is there any reason to support ZScript, *other* than backwards compatibility of old scripts? If there were a ZScript cross-compiler, would this be sufficient? Or is there a fundamental benefit to supporting both languages?

To please people who use both languages. I myself have not tried AngelScript, but I am to understand that there are quite a few things different with the format of AngelScript then ZScript? Muscle memory is a hard thing to rewire. Isn't AngelScript a more object-based language? Does AngelScript no longer have ints and floats be the same thing like ZScript did? It would take quite a bit to get used to.

Also, there's the fact that people would have to write 2 versions of the same script: one for Angelscript to please the current version users, and one for ZScript to please people still using 2.50.x. People still use 2.50.0, for crying out loud. If we keep ZScript support, people don't have to write 2 versions of the same script.

Finally, think about it: ZScript? As in ZC, or ZQuest? The name just fits. :P

DarkDragon wrote:Right! This is the key question. I could focus energies on some of the changes that have been discussed on the forums and in chat (making inter-script communication easier, tracking pointers over time easier, scripting weapons and Link, etc). But if it sounds like transitioning to AngelScript makes more sense, I want to avoid introducing new features that will make cross-compilation harder.

Well, it's true that *ZASM* must be supported. But not necessarily ZScript (we guarantee that old quests will play in new versions; I agree it would be very nice if old quests can be edited in new versions too, but this is not as bedrock of a principle IMO.)

Let me ask you this: is there any reason to support ZScript, *other* than backwards compatibility of old scripts? If there were a ZScript cross-compiler, would this be sufficient? Or is there a fundamental benefit to supporting both languages?

Agreed. Taking stock of past lessons is a key first step to planning for how, and if, to transition to ZScript.

(Emphasis, mine.)

This is precisely why AS was abandoned over every other concern. The ability to download an existing script, and compile it in ZC, must be preserved, whether we change the extant script engine by adding new things to it, or change it out to something else.

Simply supporting ZASM in quests, is blatantly insufficient. I won't even contribute to a ZC version that breaks this capability. 99% of my output for ZC in the last five years, is script-based. It'd be the biggestr slap int he face, to the community, to say, we won't suppose any of that anymore, and it reduces the amount fo available resources for the questmaker to zero.

If cross-compiling is invisible, all the existing quirks are preserved, and all the extant types are preserved in identical syntax, implementing both engines at one time is not as critical. It would be nice, but not critical. If even one capability of ZScript is un-suppprtable, then we need both. Simple as that. It doesn't prevent compiling down to the same functions on both ends of things.

You saw the reaction of just changing a directive. Magnify that tenfold, for any change as radical as this. The only users interested in AS were hardcore programmers, FWIW.

I honestly can't think of any nuance of the language that is not in use.

If you want to drop ZScript entirely, and can't support its codebase, then you may as well just start from scratch with ZC, make it clean, make it new, make it Z3 scrolling banana cream pie, and enable classic quest emulation, as ZC 3.x. This was the exact plan a year and a half ago. 3.x would be wholly new, with AS, and those of us who wanted to continue developing 2.,x would do that, which is where 2,future came from, and the origin of its name.

If you want to go that route, then I'm pretty much out of it until it is reasonably put together. Building an engine from scratch on top of everything else that I'm doing just isn't feasible for me, but once the basic structure is in place, I'd be willing to work on it. Then again, you need more than two or three people for that to be a realistic venture; so you can see why this was dropped. It went in circles for a year, arguing about flipping implementation, until we resolved just to expand what we have at present, and decide on AS after we get a bunch of other stuff out of the way, and do one or two updates; then bring it back to the table.

I really don't feel like arguing for or against it again until we reach that point, and can do at least a minimalistic implementation in a cleaner engine, and see how it works.
[MENTION=61126]Dimentio[/MENTION]: I could call it PuddingScript-Z if you want. The name isn't the issue. I agree that the only way we could do this is if existing syntax is maintained. I also have zero interest in doing it now.

TBH, it just feels as if we're all reaching here, and that we're getting very far ahead of ourselves.

I should note, that on a purely personal level, I favour a more robust ZScript implementation. As long as we're able to do this, and it seems that we arwe, with three of us willing to work on it, then the point of the AS migration--nobody wanted to work on ZScript--is less of an issue. Over time, I think we could support just about everything that AS supports, and possibly more, with a performance gain at the end of the day.

The main push for AS was additional C Syntax, and stuff like structs, that we are on the verge of adding to the existing language.

I just don't have the answers that you want, I suppose, but I don't think that what we're trying to do would make cross-compilation harder if in three to five years, we decide we want this.

I'm against coalescing ZScript/Zasm/ and angelscript (hereby referred to as "AS"😉 into some kind of hideous amalgamation (at least initially), mainly due to the fact that AS will have no compatibility concerns or other integration nightmares to worry about. Pounding on the keyboard with a free mind can be a powerful tool after all. 😊 The 18-bit "fixed" experiment that is a ZScript integer/float/bool is going the way of the dinosaurs though. If anything ever needs to interact with allegro's fixed it can be done in c++ code.

Since everyone has their own agendas for now, I think I'll just start it and see where it goes. I believe I have the most experience with AS ((I've used it for 2 projects in the past) and I don't particularly like getting into theoretical arguments so we'll just see what happens. I'm a bit rusty with AS however, so it's not like there's going to be a new script setup overnight; the bindings alone can be very time consuming. I will "play nice" with everyone and not integrate into ZC anything into the main branch, so there's no fears of extra libraries or anything that will affect what anyone else is doing, so no one has to worry about it.

The priority at first is getting all the basic stuff together and have the compiler to be separate from ZQ so that eventually scripts can be modified on-the-fly--I imagine a scripter writing a script while testing it in ZC and then just pressing 'R' and within a second it can recompile the scripts for them. We'll see how hard this is in practice. I'll have to look into how the module system in AS might work with this as well, so there's enough preliminary stuff to get out of the way before anything major.

DarkDragon wrote:
1. What were the lessons learned last year during the effort to incorporate AngelScript? What are the big challenges?
2. Is it feasible to switch to AngelScript while maintaining compatibility with old quests (presumably, this would require only supporting the ZASM interpreter, and ZScript could be dropped entirely)? Or would an AngelScript-driven ZC live in its own ecosystem separate from the existing program and quests?
3. What concrete steps would need to be taken to adopt AngelScript, to minimize the time until we have a functional release candidate, if we decide to do this?

1) No idea. :P Although I'm in the "existing enemies should remain for compatibility reasons, and 2.6 scripted enemies get a whole new class and interface" camp, Saffith showed off a taste that you could indeed script every single enemy type ZC has directly in AS, which is pretty amazing. What I'd like to do is just make it easier to do this.
2) No idea!? :P What do you think?
3) No idea!!! :P

FWIW: There is a horizon effect at play here DD. 😉

DarkDragon wrote:1. What were the lessons learned last year during the effort to incorporate AngelScript? What are the big challenges?
2. Is it feasible to switch to AngelScript while maintaining compatibility with old quests (presumably, this would require only supporting the ZASM interpreter, and ZScript could be dropped entirely)? Or would an AngelScript-driven ZC live in its own ecosystem separate from the existing program and quests?
3. What concrete steps would need to be taken to adopt AngelScript, to minimize the time until we have a functional release candidate, if we decide to do this?

1. All enemies can be recreated in angelscript, but problably shouldn't be since they die after one frame for some reason.
2. Yes, as you said support the ZASM interpreter and I think we're good.
3. A detailed design doc how it's going to work would be nice. Yeah I know most you hate those.

As far as I got with it, it was very easy and worked fine. There was a little issue with the wall masters - for some reason, they made Link scroll to the next screen instead of warping, but it only took a minor adjustment to fix that. Aside from that, everything continued to work perfectly, ZScript and all.

The only real problem I ever had was that it didn't work at all for Gleeok. That seemed to have something to do with how return values were handled, but we never ruled out things like compiler issues, as far as I recall. Really, the reason it was rolled back has more to do with my personal problems than anything else.

There is some question of how much overlap you want between old and new stuff. Should new things continue to be based on the same sprite class, with its fix coordinates and miscellaneous garbage? It would be feasible, and I think not even difficult, for compatibility scripts and new ones to use totally separate base classes and script engines. That's a big plus, in my view - a lot of the legacy cruft can just be moved neatly out of the way.

As for ZScript, it has a variety of issues. The number system doesn't match data types used internally, and the conversion is inefficient and produces unexpected results (2.0/3.0==0). It's difficult to add new built-in functions, and overloading them is currently impossible, as far as I can tell. But the single biggest issue is the extent to which it depends on ZC's internal behavior. In many areas, ZScript was not designed with the notion that things might change.

Consider this simple bit of code:

for(int i=0; i<176; i++) {
if(Screen->ComboT[i]==CT_WATER) {

This iterates over every combo on the screen and does something whenever it finds water, right? Wrong. It iterates over combos 0-175 and does something whever it finds a combo of type 3.

Say scrolling is implemented. Now instead of screens of 176 combos, you've got rooms with varying numbers of combos. This code doesn't necessarily cover the whole screen anymore. It will still work, but not correctly.

But that's the easy problem. Suppose the combo system changes. Instead of a limited number of well-defined combos, you can now give each combo an arbitrary set of properties. Maybe you make combo #3 a magic-reflecting, poundable hookshot trigger. The script isn't checking for anything like that; it just assumes combo #3 is water. Again, it will still work, but not correctly.

ComboF has similar issues and more. What if it becomes possible to place multiple flags on the same combo? ComboF can't handle that at all.

What about DrawZOffset? Currently, it doubles as HitZOffset. That should obviously change, but existing scripts that uses it were made with that quirk in mind. They won't work correctly without being updated.

New warp system? Warp functions break.

Quirks, bugs, and old behavior can often be imitated, but there are limits. In particular, when a feature is used in multiple different ways, they can't all work. For instance, going back to scrolling again, what happens to drawing functions? Currently, coordinates on the screen and coordinates in the world are the same. If the screen can scroll, that's no longer true. It will have to be one or the other in existing scripts, and some will break.

To some degree, these problems are inevitable, and I'm certainly not under the impression that switching to AngelScript automatically fixes everything forever. The point is that the notion that updating ZScript instead will keep existing scripts working is wrong. Many scripts will break, and it's going to be every bit as difficult and confusing for average users, if not more so. Yes, it will be easy to update these scripts most of the time, but it won't be significantly easier than converting them to AngelScript.

There's nothing AngelScript does that can't theoretically be added to ZScript. But it's a lot more work, and the benefit to users is dubious.

I think we all know my views.

(1) Any implementation that does not suport taking a raw, existing zscript file, and processing it, in ZC, is out.
(2) I think that the engine needs heavy reworking before we consider changing the status quo.
(3) I do no tthink that the benefits of AS outweigh the implications of what adding it might do.
( a ) This includes the potential for an exponential number of new bugs.
( b) I do not think that the time involved* versus the benefit is a net gain.
(4) Any option that sacrifices compatibility of any sort, is to me, a bad idea. I do not mean quest binary compatibility, solely.
(5) I worry about the performance hit, which is likely to be notable.
(6) Moreover, I do not have the time to dedicate to properly learning the AS sources at present. i can work on ZC until, probably April. After that, I will likely have a six month or greater gap before I can focus on it readily, and I will be tapering off slowly toward April, as well. I expect it to take months for me to truly understand the AS underpinnings, so that's over a year before I could even know if I would want to work with it.

*I would expect to spent the time required to fully support cross-compiling with no syntax changes, and implement all of the existing features, or quirks. That kind of effort is absurd, and massive, when compared against what changing the engine gains for us. Anything short of this is just a sign that we lack the kind of dedication, or manpower, involved with the project to move it forward from its present engine condition.

This is something that we can still do, a few years down the road, if we still have an interest in it by then. With people actually working on the parser, and ZScript, most of what people want out of AS can be done with what we already have, with fewer risks, better stability, and better acceptance.

Please remember that the old 'plan' was to let us work on 2.x stuff, and make AS a 3.x thing that [MENTION=42714]Gleeok[/MENTION] and [MENTION=38582]Saffith[/MENTION] did, and that they supposedly weren't concerned with some compatibility rifts between these two branches of ZC. I have always wanted to ensure that new versions of the programme are compatible with all of the old materials, including scripts as raw files, not as assembly. I think that we have a plan now, we have focus, and we have people willing to do the work. Rocking the boat, for the fifth time, right now, is just madness.

This changed several times, with lack of communication being the underlying thorn. I'll also note, that seeing a working proof of concept is something I would need, to ultimately decide, but I'm just tired of the whole debate, and want to proceed with whatever amounts to our present, viable plan.

In my honest opinion, I don't think it's wise to go forth with switching to AngelScript in the near future. It's been 4 years since the last big ZC release, not counting bugfixes, and I think time should be devoted into getting an update with a good amount of new features within this year, instead of spending the next couple months (at least) trying to implement a new scripting language with... not all that much to gain in the short term? Longterm, sure, it'd be easier to develop for, but if we take too long to release a new update, people will start getting bored of what they have now and eventually just start moving off to other languages. ZScript might be bad for development, yes, but the last thing we need is another 8 year gap between major releases to add in a replacement coding language people have to learn all over again. Right now, I think the highest priority should be providing a decent sized update to renew interest, or at least keep it sparked. Keeping interest in the program trumps all other concerns, to me, and improving ZScript isn't impossible (Hell, look at what Zoria has been doing the past 2.5 months. Seriously, the guy is insane, props to him).

If we were to add AngelScript in the future, or at any point in time, we need at least one team working on faster 2.50 updates in the meantime, so if it takes 2 or so years to add AngelScript, people have updates to keep them interested long enough to see the big 3.0 or whichever update. We'd also need heavy communication between the two teams to add what the "filler" 2.50 updates add, so that when AngelScript is implemented, it doesn't just feel like a downgrade compared to the current version. If anything, it should be the superior version, so to get the early adopters on to start making content (and it should be superior in a way that's not significant. I highly doubt Angelscript by itself is a "significant" sign of superiority). Actually, the dev team should make quests just to go with the update, so that when people start playing it, they have content they can play immediately, that is exclusive.

Of course, that's just my opinion. I've never been involved with marketing... anything, really, so my opinion might not be worth much.

EDIT: Also, perhaps we should poll PureZC and see what they think?

I've been working on the compiler/zscript converter today. Currently implementing Wait(int frames) which is a bit tricky if we want overly-generic coroutines, which I'm guessing is a no. Right now there are two problems:

1) Nested context calling. It looks like this feature is relatively new, but won't play nice with 1st class objects (eg; think ffc-ish types in ZScript). nested stack space from multiple objects that occupies the same memory sounds like a bad idea to even look into.
2) Modules: Another oldish new feature. Problem is different scripts cannot access anything outside their module unless it's a 'shared' object, which complicates everything from low-level to script level. If there's something like std.as or utility libs I don't know how this will work in practice. It seems like people will get around this by duplicating imported code so the only thing we gain is more RAM usage. :/ Not sure.

Right now I'm defaulting to "a script is it's own fully-featured script and nothing less", so don't over complicate anything right now.

[MENTION=38582]Saffith[/MENTION] : Have you messed with any of the above? Also have you written any angelscript stuff since the old repo? -Just making sure I don't duplicate anything unnecessarily.

Dimentio wrote:
EDIT: Also, perhaps we should poll PureZC and see what they think?

That sounds like a great idea. We all know how much purezc likes random polls! :P I assume it can either be or be by someone whom is unbiased on the matter?

[edit]
Another interesting thing. Consider the following on the same frame:


npc->Update()
{
...
waitframe();
...
}

npc collides with x.
script wants to know about it.

engine calls npc->onCollidesWithX()
{
x.HP -= 2;
this.HP += 2;
waitframes(6876);
this.HP = this.MaxHP; //invalid code path; never gets here
}

I'm assuming that the "intended behavior" is to resume the update method next frame?

Gleeok wrote:1) Nested context calling. It looks like this feature is relatively new, but won't play nice with 1st class objects (eg; think ffc-ish types in ZScript). nested stack space from multiple objects that occupies the same memory sounds like a bad idea to even look into.

I vaguely recall looking at that and thinking the same thing, but I don't think there's really any need for it. If you want to call a draw method or an event handler or something, you can just do it in another context.

2) Modules: Another oldish new feature. Problem is different scripts cannot access anything outside their module unless it's a 'shared' object, which complicates everything from low-level to script level. If there's something like std.as or utility libs I don't know how this will work in practice. It seems like people will get around this by duplicating imported code so the only thing we gain is more RAM usage. :/ Not sure.

Again, I don't think there's any need. I don't think there's anything that needs isolated, and there shouldn't be any harm in putting everything in the same module.

Also have you written any angelscript stuff since the old repo? -Just making sure I don't duplicate anything unnecessarily.

Nope, haven't touched it.

I'm assuming that the "intended behavior" is to resume the update method next frame?

That's a bit tricky. I was thinking event handlers shouldn't be allowed to Waitframe, since that makes things really complicated. Things like enemies that need to change behavior in response to events would either need to use update methods, like they already do, or have their Waitframes throw exceptions, which is of course a terrible way to handle it. It might also be possible to do something like a stack of AIs; when an enemy gets hit, you'd push a knockback state, then pop it when it finishes. That doesn't actually sound like a good idea to me, though.

Edit: Or make a Waitframe wrapper that returns any necessary state change info. You'd think that would be the first thing I think of. 😛

There are *lots* of built-ins. I'm guessing about 100 or so can be deprecated though. Doing one section at a time hopefully wont be too bad.



namespace GlobalBindings
{
int32 Rand(int32 maxvalue);
void Quit();
void Waitframe();
void Waitdraw(); //?

// DEPRICATED ***
void Trace(int32 val);
void TraceB(bool state);
void TraceS(int32 s[]);
void TraceToBase(int32 val, int32 base, int32 mindigits);
void TraceNL();
void ClearTrace();
// DEPRICATED ***

// DEPRICATED ***
float Sin(float deg);
float Cos(float deg);
float Tan(float deg);
// DEPRICATED ***

float RadianSin(float rad);
float RadianCos(float rad);
float RadianTan(float rad);

float ArcTan(int32 x, int32 y);
float ArcSin(float x);
float ArcCos(float x);
float Max(float a, float b);
float Min(float a, float b);
int32 Pow(int32 base, int32 exp);
int32 InvPow(int32 base, int32 exp);
float Log10(float val);
float Ln(float val);
int32 Factorial(int32 val);
float Abs(float val);
float Sqrt(float val);

// DEPRICATED ***
void CopyTile(int32 srctile, int32 desttile);
void SwapTile(int32 firsttile, int32 secondtile);
void ClearTile(int32 tileref);
int32 SizeOfArray(int32 array[]);
// DEPRICATED ***
}

namespace FFCBindings
{
int32 Data;
int32 Script; // DEPRICATED ***
int32 CSet;
int32 Delay;
float X;
float Y;
float Vx;
float Vy;
float Ax;
float Ay;
bool Flags[];
int32 TileWidth;
int32 TileHeight;
int32 EffectWidth;
int32 EffectHeight;
int32 Link;
float InitD[];
float Misc[];
};

namespace LinkBindings
{
int32 X;
int32 Y;
int32 Z;
bool Invisible;
bool CollDetection;
int32 Jump;
int32 SwordJinx;
int32 ItemJinx;
int32 Drunk;
int32 Dir;
int32 HitDir;
int32 HP;
int32 MP;
int32 MaxHP;
int32 MaxMP;
int32 Action;
int32 HeldItem;
int32 LadderX;

// DEPRICATED ***
bool InputStart;
bool InputMap;
bool InputUp;
bool InputDown;
bool InputLeft;
bool InputRight;
bool InputA;
bool InputB;
bool InputL;
bool InputR;
bool InputEx1;
bool InputEx2;
bool InputEx3;
bool InputEx4;
bool InputAxisUp;
bool InputAxisDown;
bool InputAxisLeft;
bool InputAxisRight;
// DEPRICATED ***

// DEPRICATED ***
bool PressStart;
bool PressMap;
bool PressUp;
bool PressDown;
bool PressLeft;
bool PressRight;
bool PressA;
bool PressB;
bool PressL;
bool PressR;
bool PressEx1;
bool PressEx2;
bool PressEx3;
bool PressEx4;
bool PressAxisUp;
bool PressAxisDown;
bool PressAxisLeft;
bool PressAxisRight;
// DEPRICATED ***

// DEPRICATED ***
int32 InputMouseX;
int32 InputMouseY;
int32 InputMouseB;
int32 InputMouseZ;
// DEPRICATED ***

bool Item[];
int32 Equipment;
int32 Tile;
int32 Flip;
int32 HitZHeight;
int32 HitXOffset;
int32 HitYOffset;
int32 DrawXOffset;
int32 DrawYOffset;
int32 DrawZOffset;
float_or_int32 Misc[];
void Warp(int32 DMap, int32 screen);
void PitWarp(int32 DMap, int32 screen);
SelectAWeapon(int32 dir);
SelectBWeapon(int32 dir);
};

namespace Screen
{
float_or_int32 D[];
int32 Flags[];
int32 EFlags[];
int32 ComboD[];
int32 ComboC[];
int32 ComboF[];
int32 ComboI[];
int32 ComboT[];
int32 ComboS[];
int32 MovingBlockX;
int32 MovingBlockY;
int32 MovingBlockCombo;
int32 MovingBlockCSet;
int32 UnderCombo;
int32 UnderCSet;
bool State[];
int32 Door[];
int32 RoomType;
int32 RoomData;
void TriggerSecrets();
bool Lit;
int32 Wavy;
int32 Quake;
void SetSideWarp(int32 warp, int32 screen, int32 dmap, int32 type);
void SetTileWarp(int32 warp, int32 screen, int32 dmap, int32 type);
void GetSideWarpDMap(int32 warp);
void GetSideWarpScreen(int32 warp);
void GetSideWarpType(int32 warp);
void GetTileWarpDMap(int32 warp);
void GetTileWarpScreen(int32 warp);
void GetTileWarpType(int32 warp);
int32 LayerMap(int32 n);
int32 LayerScreen(int32 n);
int32 NumItems();
item LoadItem(int32 num);
item CreateItem(int32 id);
ffc LoadFFC(int32 num); // DEPRICATED ***
int32 NumNPCs();
npc LoadNPC(int32 num);
npc CreateNPC(int32 id);
int32 NumLWeapons();
lweapon LoadLWeapon(int32 num);
lweapon CreateLWeapon(int32 type);
int32 NumEWeapons();
eweapon LoadEWeapon(int32 num);
eweapon CreateEWeapon(int32 type);
bool isSolid(int32 x, int32 y);
void ClearSprites(int32 spritelist);

// DEPRICATED ***
void Rectangle(int32 layer, int32 x, int32 y, int32 x2, int32 y2, int32 color, float_or_int32 scale, int32 rx, int32 ry, int32 rangle, bool fill, int32 opacity);
void Circle(int32 layer, int32 x, int32 y, int32 radius, int32 color, float_or_int32 scale, int32 rx, int32 ry, int32 rangle, bool fill, int32 opacity);
void Arc(int32 layer, int32 x, int32 y, int32 radius, int32 startangle, int32 endangle, int32 color, float_or_int32 scale, int32 rx, int32 ry, int32 rangle, bool closed, bool fill, int32 opacity);
void Ellipse(int32 layer, int32 x, int32 y, int32 xradius, int32 yradius, int32 color, float_or_int32 scale, int32 rx, int32 ry, int32 rangle, bool fill, int32 opacity);
void Spline(int32 layer, int32 x1, int32 y1, int32 x2, int32 y2, int32 x3, int32 y3,int32 x4, int32 y4, int32 color, int32 opacity);
void Line(int32 layer, int32 x, int32 y, int32 x2, int32 y2, int32 color, float_or_int32 scale, int32 rx, int32 ry, int32 rangle, int32 opacity);
void PutPixel(int32 layer, int32 x, int32 y, int32 color, int32 rx, int32 ry, int32 rangle, int32 opacity);
void DrawTile(int32 layer, int32 x, int32 y, int32 tile, int32 blockw, int32 blockh, int32 cset, int32 xscale, int32 yscale, int32 rx, int32 ry, int32 rangle, int32 flip, bool transparency, int32 opacity);
void FastTile( int32 layer, int32 x, int32 y, int32 tile, int32 cset, int32 opacity );
void DrawCombo(int32 layer, int32 x, int32 y, int32 combo, int32 w, int32 h, int32 cset, int32 xscale, int32 yscale, int32 rx, int32 ry, int32 rangle, int32 frame, int32 flip, bool transparency, int32 opacity);
void FastCombo( int32 layer, int32 x, int32 y, int32 combo, int32 cset, int32 opacity );
// DEPRICATED ***

void Message(int32 string);

// DEPRICATED ***
void DrawCharacter(int32 layer, int32 x, int32 y, int32 font,int32 color, int32 background_color,int32 width, int32 height, int32 glyph, int32 opacity );
void DrawInteger(int32 layer, int32 x, int32 y, int32 font,int32 color, int32 background_color,int32 width, int32 height, int32 number, int32 number_decimal_places, int32 opacity);
void DrawString( int32 layer, int32 x, int32 y, int32 font,int32 color, int32 background_color,int32 format, int32 ptr[], int32 opacity );
void Quad( int32 layer, int32 x1, int32 y1, int32 x2, int32 y2, int32 x3, int32 y3, int32 x4, int32 y4,int32 w, int32 h, int32 cset, int32 flip, int32 texture, int32 render_mode);
void Triangle( int32 layer, int32 x1, int32 y1, int32 x2, int32 y2, int32 x3, int32 y3,int32 w, int32 h, int32 cset, int32 flip, int32 texture, int32 render_mode);
void Quad3D( int32 layer, int32 pos[], int32 uv[], int32 cset[], int32 size[], int32 flip, int32 texture, int32 render_mode );
void Triangle3D( int32 layer, int32 pos[], int32 uv[], int32 csets[], int32 size[], int32 flip, int32 texture, int32 render_mode );
void SetRenderTarget( int32 bitmap_id );
void DrawBitmap( int32 layer, int32 bitmap_id, int32 source_x, int32 source_y, int32 source_w, int32 source_h, int32 dest_x, int32 dest_y, int32 dest_w, int32 dest_h, float_or_int32 rotation, bool mask);
void DrawLayer(int32 layer, int32 source_map, int32 source_screen, int32 source_layer, int32 x, int32 y, float_or_int32 rotation, int32 opacity);
void DrawScreen(int32 layer, int32 map, int32 source_screen, int32 x, int32 y, float_or_int32 rotation);
// DEPRICATED ***
};

namespace ItemBindings
{
bool isValid();
int32 X;
int32 Y;
int32 Jump;
int32 DrawStyle;
int32 ID;
int32 OriginalTile;
int32 Tile;
int32 CSet;
int32 FlashCSet;
int32 NumFrames;
int32 Frame;
int32 ASpeed;
int32 Delay;
bool Flash;
int32 Flip;
int32 Pickup;
int32 Extend;
int32 TileWidth;
int32 TileHeight;
int32 HitWidth;
int32 HitHeight;
int32 HitZHeight;
int32 HitXOffset;
int32 HitYOffset;
int32 DrawXOffset;
int32 DrawYOffset;
int32 DrawZOffset;
float_or_int32 Misc[];
};

namespace WeaponBindings
{
bool isValid();
void UseSprite(int32 id);
bool Behind;
int32 ID;
int32 X;
int32 Y;
int32 Z;
int32 Jump;
int32 DrawStyle;
int32 Dir;
int32 OriginalTile;
int32 Tile;
int32 OriginalCSet;
int32 CSet;
int32 FlashCSet;
int32 NumFrames;
int32 Frame;
int32 ASpeed;
int32 Damage;
int32 Step;
int32 Angle;
bool Angular;
bool CollDetection;
int32 DeadState;
bool Flash;
int32 Flip;
int32 Extend;
int32 TileWidth;
int32 TileHeight;
int32 HitWidth;
int32 HitHeight;
int32 HitZHeight;
int32 HitXOffset;
int32 HitYOffset;
int32 DrawXOffset;
int32 DrawYOffset;
int32 DrawZOffset;
float_or_int32 Misc[];
};

namespace ItemDataBindings
{
float_or_int32 InitD[];
void GetName(int32 buffer[]);
int32 Family;
int32 Level;
int32 Power;
int32 Amount;
int32 MaxIncrement;
int32 Max;
bool Keep;
int32 Counter;
int32 UseSound;
};

namespace GameBindings
{
int32 GetCurScreen();
int32 GetCurDMapScreen();
int32 GetCurLevel();
int32 GetCurMap();
int32 GetCurDMap();
int32 DMapFlags[];
int32 DMapLevel[];
int32 DMapCompass[];
int32 DMapContinue[];
int32 DMapMIDI[];
void GetDMapName(int32 DMap, int32 buffer[]);
void GetDMapTitle(int32 DMap, int32 buffer[]);
void GetDMapIntro(int32 DMap, int32 buffer[]);
int32 DMapOffset[];
int32 DMapMap[];
int32 NumDeaths;
int32 Cheat;
int32 Time;
bool TimeValid;
bool HasPlayed;
bool Standalone;
int32 GuyCount[];
int32 ContinueDMap;
int32 ContinueScreen;
int32 LastEntranceDMap;
int32 LastEntranceScreen;
int32 Counter[];
int32 MCounter[];
int32 DCounter[];
int32 Generic[];
int32 LItems[];
int32 LKeys[];
int32 GetScreenFlags(int32 map, int32 screen, int32 flagset);
int32 GetScreenEFlags(int32 map, int32 screen, int32 flagset);
bool GetScreenState(int32 map, int32 screen, int32 flag);
void SetScreenState(int32 map, int32 screen, int32 flag, bool value);
float_or_int32 GetScreenD(int32 screen, int32 reg);
void SetScreenD(int32 screen, int32 reg, float_or_int32 value);
float_or_int32 GetDMapScreenD(int32 dmap, int32 screen, int32 reg);
void SetDMapScreenD(int32 dmap, int32 screen, int32 reg, float_or_int32 value);
itemdata LoadItemData(int32 item);
void PlaySound(int32 soundid);
void PlayMIDI(int32 MIDIid);
int32 GetMIDI();
bool PlayEnhancedMusic(int32 filename[], int32 track);
void GetDMapMusicFilename(int32 dmap, int32 buf[]);
int32 GetDMapMusicTrack(int32 dmap);
void SetDMapEnhancedMusic(int32 dmap, int32 filename[], int32 track);
int32 GetComboData(int32 map, int32 screen, int32 position);
void SetComboData(int32 map, int32 screen, int32 position, int32 value);
int32 GetComboCSet(int32 map, int32 screen, int32 position);
void SetComboCSet(int32 map, int32 screen, int32 position, int32 value);
int32 GetComboFlag(int32 map, int32 screen, int32 position);
void SetComboFlag(int32 map, int32 screen, int32 position, int32 value);
int32 GetComboType(int32 map, int32 screen, int32 position);
void SetComboType(int32 map, int32 screen, int32 position, int32 value);
int32 GetComboInherentFlag(int32 map, int32 screen, int32 position);
void SetComboInherentFlag(int32 map, int32 screen, int32 position, int32 value);
int32 GetComboSolid(int32 map, int32 screen, int32 position);
void SetComboSolid(int32 map, int32 screen, int32 position, int32 value);
int32 ComboTile(int32 combo);
void GetSaveName(int32 buffer[]);
void SetSaveName(int32 name[]);
void End();
void Save();
bool ShowSaveScreen();
void ShowSaveQuitScreen();
void GetMessage(int32 string, int32 buffer[]);
int32 GetFFCScript(int32 name[]);
bool ClickToFreezeEnabled;
};

namespace NPCBindings
{
bool isValid();
void GetName(int32 buffer[]);
int32 ID;
int32 Type;
int32 X;
int32 Y;
int32 Z;
int32 Jump;
int32 Dir;
int32 Rate;
int32 Haltrate;
int32 Homing;
int32 Hunger;
int32 Step;
bool CollDetection;
int32 ASpeed;
int32 DrawStyle;
int32 HP;
int32 Damage;
int32 WeaponDamage;
int32 Stun;
int32 OriginalTile;
int32 Tile;
int32 Weapon;
int32 ItemSet;
int32 CSet;
int32 BossPal;
int32 SFX;
int32 Extend;
int32 TileWidth;
int32 TileHeight;
int32 HitWidth;
int32 HitHeight;
int32 HitZHeight;
int32 HitXOffset;
int32 HitYOffset;
int32 DrawXOffset;
int32 DrawYOffset;
int32 DrawZOffset;
int32 Defense[];
int32 Attributes[];
int32 MiscFlags;
float_or_int32 Misc[];
void BreakShield();
};


I've put in a preprocessor which greatly simplifies the conversion layer, and can remap many things via macros. It would be a multi-pass "parser." Currently the idea is to load the script buffer, generate a list of all imported files, tag on a conversion file at the top, then process those files into memory, where a third pass can be run before finally outputting the converted scripts or sending it to the AS compiler.

Things like operators '->' to '.' etc., or different script types are trivial so I expect a > 95% initial success rate. Hopefully I can get this part finished and start looking at actual output files next week.
We'll see how well this works. O_o

Gleeok wrote:
Things like operators '->' to '.' etc., or different script types are trivial so I expect a > 95% initial success rate. Hopefully I can get this part finished and start looking at actual output files next week.
We'll see how well this works. O_o

Does that mean in AngelScript you can just do:

[FONT=Fixedsys]example_ptr.foo = 9;[/FONT]

Or do you dereference it with a star and parentheses? Cuz that is more annoying than the arrow operator.

Did some google-fu. AS doesn't have pointers(?), but ...handles... I'm even more confused now.

I like AS! Let's get this going so I can get to really learning it.

I would prefer we actually use Lua this time around.
Angelscript hasn't aged well these pass years.

What are the advantages of LUA over AS?

One concern I have with LUA (which also applies to AS): the only large project I am personally familiar with that uses LUA heavily is ToME, and it had significant performance problems (actions take place is less than real time once many scripts start acting at once). Is this a concern, or just that ToME is poorly designed?

DarkDragon wrote:What are the advantages of LUA over AS?

One concern I have with LUA (which also applies to AS): the only large project I am personally familiar with that uses LUA heavily is ToME, and it had significant performance problems (actions take place is less than real time once many scripts start acting at once). Is this a concern, or just that ToME is poorly designed?

LUA is used by at least hundreds of games. Unfortunately you probably won't get a list by googling for it as most of the titles are by large game studios. If ToME used AS then it would be at least as slow, if not slower, I would assume. Once the spritelist gets optimized and we avoid using the AS GC (reference types) for anything built-in or trivial it shouldn't be an issue.

Would you like to wager on an ZScript vs AS performance comparison? 😉

Also Tamano is just joking. I don't think that was serious.

Also Tamano is just joking. I don't think that was serious.

Ok.

Would you like to wager on an ZScript vs AS performance comparison? 😉

Depends on the context. Presumably AngelScript is at least mildly optimized, in which case I would expect it to outperform ZScript handily for running equivalent code. But I am not so sure about ZScript user code+C++ internal engine vs AngelScript user code + AngelScript engine.

Yeah, an angelscript engine is probably just a horrible and slower form of a Java engine without any of the positives. That's why I'm never going to be in favor of moving c++ code to AS. In fact, I want to do the opposite: Move common usage patterns to c++! We just couldn't without adding tons of new code to the ZScript compiler.

Take the most common script ever as an example:


for(int i = 1; i <= Screen->NumEWeapons(); i++)
{
eweapon w = Screen->LoadEWeapon(i);
if(Abs(w->X-8)<someX && Abs(w->Y-8)<someY) // probably more stuff too
{
//collision or whatever
}
}

Which is horribly inefficient. Basically scripts are doing low-level stuff and I can tell you while I am able to optimize scripts to a degree most users can not.
The fact that most scripts use "ZScript engines" (ghost.zh, etc.) kind of compounds the issue.

Here's another example:


void foo(int, a, b, c, d, e, f, g){ // a is false
if(a && b && c && d && e && f && g && bar(a,b,c))
{
/....
}
}

Even though 'a' is false every other statement is evaluated and bar(...) is also called.

Yes I'm all in favor of better built-in library support for common ZC tasks.

Short-circuit boolean operations may or may not be a good thing -- it's useful in some cases, but also one of the often-criticized features of C.

My main concern with short circuiting is if it'll kill any existing scripts. I'd really like it to be added, but I'm pretty sure there's some script out there that does a() && b() && c() or similar.

Maybe some sort of flag at the top of the script/function/whatever?

Gleeok wrote:Yeah, an angelscript engine is probably just a horrible and slower form of a Java engine without any of the positives. That's why I'm never going to be in favor of moving c++ code to AS. In fact, I want to do the opposite: Move common usage patterns to c++! We just couldn't without adding tons of new code to the ZScript compiler.

Take the most common script ever as an example:


for(int i = 1; i <= Screen->NumEWeapons(); i++)
{
eweapon w = Screen->LoadEWeapon(i);
if(Abs(w->X-8)<someX && Abs(w->Y-8)<someY) // probably more stuff too
{
//collision or whatever
}
}

Which is horribly inefficient. Basically scripts are doing low-level stuff and I can tell you while I am able to optimize scripts to a degree most users can not.
The fact that most scripts use "ZScript engines" (ghost.zh, etc.) kind of compounds the issue.

Here's another example:


void foo(int, a, b, c, d, e, f, g){ // a is false
if(a && b && c && d && e && f && g && bar(a,b,c))
{
/....
}
}

Even though 'a' is false every other statement is evaluated and bar(...) is also called.

The first issue can be solved by checking collision internally, as an option, in both cases. Either way, users will want self-defined collision, and you fall back on needing to check bounding areas of objects. I don;t see the difference, save that we don;t have an internal collision call now, which we could add to give the user engine collision checking.

The second, needs a parsing correction. If a statement reaches a condition that would evaluate false, exit, but I don;t think that the risk is worth the reward at all. If we added this, it would need to be a compiler directive that is disabled by default; and I would also point out that code may expect bar() to be called in that statement, even if the conditions are false. Short-circuiting belongs in languages where it is anticipated from the onset.

If you don't favour the AS engine with the parser, than I really don;t see the point. TO me, the entire reason for even wanting this paradigm shift, was to open the engine up to more fluidic control by the scripter. This comes at a performance hit, which is why I was happy to accept it for ZC3, a rewrite, that changed the entire ZC dynamic, moved us to modern libs, added scrolling, and essentially provided an emulation layer to play classic quests. Pretty much, Solarus in ZC style, with AS, and the ability to play most, but not all, older quests.

This is why we were going to work on 2.x, while you worked on the initial set-up for something of that scope. The discussion on AS and the discussion on a modernisation rewrite, to me, are intertwined. The average user couldn't care what script engine is under the hood: They only care that the scripters supply them with free goodies. What they want, more than anything, is to make SNES style games, and they can;t, so they beg the scripters to supply them with the 'next-best-thing'.

I think this constant debate on what scripting engine to use, is just side-stepping the real issue, of how ZC needs to evolve in the next five years, to avoid being surpassed, overshadowed, and forgotten. 2.xx is a stopgap measure, toward that type of goal, and I feel as if you are spending energy trying to hammer in a new engine when the entire thing needs to be blown up and rebuild from the ground up in the near future. I just hope I'm still alive, to see it.

I'll certainly be willing to entertain whatever you create, but I think it will be offset a version or two, no-matter what. I do like the updates we've already managed to get working, and I feel that they should be deployed, and allow users to utilise them. Give them a learning curve that isn't just a cold slap in the face, and they will be more appreciative of the entire thing, and more welcoming of controversial change, in the future.

Maybe we should use the AS engine instead of cpp, and have the ZScript parser output AS instead of ZASM. 😉 [/sarcasm]

Oh no I'm very serious, one project that has done incredible things with lua is Starbound which also uses JSON along with it and was created to be moddable from the bottom up. This is the sort of approach we need to take when implementing a new language, in fact I'd rather just rewrite zc from scratch. But ya'll too damn lazy for that.

Tamamo wrote:Oh no I'm very serious, one project that has done incredible things with lua is Starbound which also uses JSON along with it and was created to be moddable from the bottom up. This is the sort of approach we need to take when implementing a new language, in fact I'd rather just rewrite zc from scratch. But ya'll too damn lazy for that.

Lua is gross, though. What advantage would it have over AS? Atleast AS is somewhat similar to ZScript. I think that is a big factor in it being the right choice. Most people who script in ZC aren't programmers. They only learn what they need of ZScript and would probably be scared off by something so ... different.

That's a good point. As much as I like Lua, AS is much closer to ZScript. At least as far as the average scripter is concerned.