while ((i>=0)&&(buf==' ')) {
buf = 0;
i--;
}
When a sprite is imported, make part of its property box the name of the original import file (or "Clipboard"): this is becuase it is sometime hard to tell sprites apart!... or make the filename into an enum having the same numerical value as the sprite id number.
while ((i>=0)&&(buf[i]==' ')) {
  buf[i] = 0;
  i--;
}
while (i>=0) {
 if (buf[i]==' ') {
  buf[i] = 0;
  i--;
 } else i=-1; //breaks out whenever it reaches a nonspace character
}
Which I think is quite readible and safe.In the example below the while loop is should stop looping when variable i reaches a value of -1 as detected by the first part of the conditional expression.  In this case the second part of the conditional erpression and the value of buf are irrelevant . However, the bounds check creates a runtime error, when i reaches -1 because of the second part of the conditional expression.while ((i>=0)&&(buf==' '))
Isn't the real problem here that AGS evaluates the right-hand side of an "&&" conditional expression even when the left-hand side failed?Yeah. That occured to me as well but I don't think it's practical. it seems to me that the entire expression needs to be evaluated before you can know for sure if the final result will be true or false. Although in this case it doesn't seem all that complicated I don't think that's true for all possibilities.
Gilbot, your workaround adds an if-else structure and several lines of code. Further, the index i is not preserved in your example. If it's needed then an additinal variable is required to break the loop. At this point it's easy enough for me to live with but it is never the less annoying. It will likely be troublesome to the uninitiated. Although I can't say for certain, I suspect it's not difficult to disable the bounds check for while loop (or other) conditional expressions and that what is lacking is a clear definition of what should be done. If so I think it is at least worth having a short discussion about it.QuoteThe workaround requires additional code complexity to achieve the same functionality.this can be easily worked around (not as complex as you mentioned)
It's entirely practical - a lot of C code relies on it.Quote from: SnarkyIsn't the real problem here that AGS evaluates the right-hand side of an "&&" conditional expression even when the left-hand side failed?Yeah. That occured to me as well but I don't think it's practical. it seems to me that the entire expression needs to be evaluated before you can know for sure if the final result will be true or false.  Although in this case it doesn't seem all that complicated I don't think that's true for all possibilities.
if (ptr != NULL && ptr->Func())
{
// blah
}
Perhaps it's like the mathematical evaluation that goes right to left :=
Gilbot, your workaround adds an if-else structure and several lines of code.ÂIt's nothing in my opinion, and it's worth it, just to ensure stuff works in order.
Further, the index i is not preserved in your example. If it's needed then an additinal variable is required to break the loop.  At this point it's easy enough for me to live with but it is never the less annoying.  It will likely be troublesome to the uninitiated.True. But I think it helps in general, especially for people not quite familiar in programming, to figure out their mistakes.
Although I can't say for certain, I suspect it's not difficult to disable the bounds check for while loop (or other) conditional expressions and that what is lacking is a clear definition of what should be done. If so I think it is at least worth having a short discussion about it.Why? I think if there're checkings elsewhere, why leave while (and probably a few things like 'if' conditions, etc.) alone? One mistake that people can make is thing like this:
As far as access safety is concerned, is not the bounds check a relatively new feature? I thouhgt it was added to aid in locating array index type bugs rather than preventing memory access exceptions? If access saftey is indeed an issue then the bounds check could perhaps substitute a value in place of the invalid array element and then allow the evaluation to continue instead of aborting?ÂWell, maybe aborting is a harsh punishment, but checkings DO help finding bugs, a better compromise, maybe, is to abort the game with an error if it's going to assign/modify the value of an off-bound element, but just add to the warning.log (no aborting) if it's just a reference to it.
When a sprite is imported, make part of its property box the name of the original import file (or "Clipboard"): this is becuase it is sometime hard to tell sprites apart!This is a really great idea! I would even go further and generate enum values from the file name so that individual sprites could be accessed by name rather than number.
Parametrisable #define macrosThis is also a good idea, I support it.
Third-party preprocessor: before AGS runs its compiler, it could run an arbitrary 3rd party tool on a temporary text file containing all the scripts to allow full preprocessing.This is the kind of crazy ideas I usually have and I usually don't talk about them because I don't want people to think I'm crazy *** mad scientist laugh ***. So I am uncertain if I should support this or not ;). Having said that, I am crazy enough to use such a thing if it were available.
I have been working around, since but now with a better understanding of the issue and the experience working around, I am of the opinion that this is really annoying and that it is legitimate for an array index to exceed the bounds of the array in the context of a while conditional expression.I think, while it is legitimate for an index variable to exceed the bounds, it still shouldn't be legitimate to dereference array index, it should return a value that's really in array rather then something outside. Yeah, it's not important for the example you provided but on the other hand there are circumstances when we should really get an error message, for instance:
Isn't the real problem here that AGS evaluates the right-hand side of an "&&" conditional expression even when the left-hand side failed?I think AGS should always evaluate before applying operator. Personally, I always treat && etc operators as functions that need parameters (two in case of &&) and that return a value. Therefore, both parameters (left and right expressions) must be evaluated first before processing. Some sort of a "lazy" evalution is possible, I think, but in my opinion, besides the hassle to implement it could also lead to many hard to track down errors since they can only be traced at run-time.
I belive, the engine should abort in any case really. Developer can't always track down all the possible run-time errors and it would be worse if instead of run-time error message players started experiencing strange behaviour playing the game.QuoteAs far as access safety is concerned, is not the bounds check a relatively new feature? I thouhgt it was added to aid in locating array index type bugs rather than preventing memory access exceptions? If access saftey is indeed an issue then the bounds check could perhaps substitute a value in place of the invalid array element and then allow the evaluation to continue instead of aborting?
Well, maybe aborting is a harsh punishment, but checkings DO help finding bugs, a better compromise, maybe, is to abort the game with an error if it's going to assign/modify the value of an off-bound element, but just add to the warning.log (no aborting) if it's just a reference to it.
I think AGS should always evaluate before applying operator. Personally, I always treat && etc operators as functions that need parameters (two in case of &&) and that return a value. Therefore, both parameters (left and right expressions) must be evaluated first before processing. Some sort of a "lazy" evalution is possible, I think, but in my opinion, besides the hassle to implement it could also lead to many hard to track down errors since they can only be traced at run-time.
And the problem is how to implment it, for instance:
if (func1() && func2()) ...
it is not realy possible to tell which one is needed and which is not (if any), without running at least one function (which function to run is also an issue).
Room and Module Templates
Here is one more suggestion. If the files exist in the Have the editor commands "New Room" and "New Module" populate the newly created room or module with the contents of the corresponding template files template.crm, template scm.
Third-party preprocessor: before AGS runs its compiler, it could run an arbitrary 3rd party tool on a temporary text file containing all the scripts to allow full preprocessing
Parametrisable #define macros
When a sprite is imported, make part of its property box the name of the original import file (or "Clipboard"): this is becuase it is sometime hard to tell sprites apart!
Firstly, yes this whole issue is because AGS does not do lazy evaluation on && and ||. (while it's called lazy, it's actually more complicated since the compiler would need to check the first side and generate JUMP instructions depending on the result).Why not just make comparisons with a non-existent entities always return FALSE? Well maybe there a couple exceptions but couldn't the bounds check do something like the following when encountered in a conditional expression? If something doesn't exist it can never be equal to, greater than, etc to anything.
(buf[-1]==A) = FALSE
(buf[-1]!=A) = FALSE
(buf[-1]>A) = FALSE
(buf[-1]<A) = FALSE
(buf[-1]>=A) = FALSE
(buf[-1]<=A) = FALSE
(buf[-1]&&A) = FALSE
(buf[-1]||A) = FALSE
instead of this....
if ((ptr != null) && (ptr.ID > 0))
if (ptr.ID>0) evaluates to FALSE when ptr==null, you could
just do this...
if (ptr.ID > 0)
if you put a room file called "_blank.crm" in your game folder,...Great!! Maybe one of these days you can get around to doing the same for modules. Thanks...
"Lazy evaluation" (I don't like to call it that as it sounds rather negative - "short-circuit evaluation" is better I think) is not just in every modern compiler, it's written into the specification of languages.The problem is, it was not written into the specification of AGS. If the behaviour is written clearly, it poses no problem to anyone, but if not, it's better kept safe as not many people using AGS are actual C programmers (I'm not a programmer of any computer languages, so common programming practice doesn't apply to me as I had never learned about that).
(And it's actually illogical in mathematical sense to treat these conditions as FALSE, they're actually all TRUE ...I believe that from a rigorous mathematical point of view, the result of operations on non-existent entities is undefined. So when something like a divide by zero happens in a computer program an exception handler is invoked so that something can be done about it. If the program was making scientific calculations to model the orbit of a space craft it would perhaps just stop and report what happened. If it were on board the space craft and actually controling the orbit, instead of stopping, it would likely return a sensible value (likely a really big number) and continue on.
I believe that from a rigorous mathematical point of view, the result of operations on non-existent entities is undefined.  So when something like a divide by zero happens in a computer program an exception handler is invoked so that something can be done about it. If the program was making scientific calculations to model the orbit of a space craft it would perhaps just stop and report what happened. If it were on board the space craft and actually controling the orbit, instead of stopping, it would likely return a sensible value (likely a really big number) and continue on.  ÂSorry if I sounded harsh, you're right that in mathematical sense things like 5/0 are usually not defined (you can define it), but not with comparisons involving nonexisting quantities, logically they're always TRUE as a statement.
From a practical and logical point of view I don't see how a non-existent entity could ever be considerd to be equal to an existing entity of any value. If it don't exist it can't have that value, whatever it is. In the example you give "while (k[-1]=='a') {...}" the while loop would never execute because k[-1] is not equal to 'a', so I would think the programmer would realize the loop wasn't executing, and then go figure out why.ÂIt's just a simple example to demonstrate the scenario, there're many possibilities, for example, if there's no 'a' in k:
while (!(k[j]=='a')){ //to find the first 'a' WEEE!
 j++;
}
Of course he could have coded it (k[j]!='a'), but it's just a demostration and you can't prevent someone write that. In my opinion it should produce an error rather than continuing.IMHO, the best reason to not use my suggestion is that it may not mimick C as closely as one would desire and could therefore cause some confusion or that there is some unforseen, terrible side affect that's a show stopper. Oh well, I think we should stop talking about this anyway. CJ knows about the issue now and will most likely do something we all will be satisfied with as he always does.ÂWell agreed, but what I was just going to point out, was "lazy"-evaluation is a much better solution (though it may be hard to implement) than that workaround of setting it to some fixed value. SInce in lazy-evaluation, it'll ignore a condition only when it's not required to be checked.
QuoteThird-party preprocessor: before AGS runs its compiler, it could run an arbitrary 3rd party tool on a temporary text file containing all the scripts to allow full preprocessing
Do you have a use in mind for this? It sounds a bit of a far fetched feature, to be honest.
QuoteParametrisable #define macros
That would be nice, but I do try to discourage #define usage since it's not type safe and can make bugs hard to track down.
QuoteWhen a sprite is imported, make part of its property box the name of the original import file (or "Clipboard"): this is becuase it is sometime hard to tell sprites apart!
Effectively what you're asking for is a way to name sprites, which has been requested before. In fact, it's probably this very request:
http://www.adventuregamestudio.co.uk/tracker.php?action=detail&id=227
"Lazy evaluation" (I don't like to call it that as it sounds rather negative - "short-circuit evaluation" is better I think) is not just in every modern compiler, it's written into the specification of languages...Yeah, and I'm not against the lazy evaluation, but implementing it now (by means of changing how "&&"/"||" work) would mean the old code may not work as expected. It reminds me the situation with the mathematical operators of the same precedence, you have mentioned, that are evaluated right to left. And, to be honest, I've already written plenty of code relying on '&&' behaviour in AGS. := Ah well, I will then probably replace '&&' with '*' or '&'.
Firstly, yes this whole issue is because AGS does not do lazy evaluation on && and ||. (while it's called lazy, it's actually more complicated since the compiler would need to check the first side and generate JUMP instructions depending on the result).
And yes, it's something I would like to fix to make it behave in common with C, especially as you point out, statements like this will become more common and should be valid:
if ((ptr != null) && (ptr.ID > 0))
while (j > numToDrawUnsorted && ShouldSwapPrims(pzj, pzi))
{
// blah blah
j--;
}
bool swap = ShouldSwapPrims(pzj, pzi);
while (j > numToDrawUnsorted && swap)
{
// blah blah
j--;
if (j > numToDrawUnsorted)
{
swap = ShouldSwapPrims(pzj, pzi);
}
}
bool swap = true;
while (j > numToDrawUnsorted && swap)
{
  swap = ShouldSwapPrims(pzj, pzi);
//Something to update pzj, pzi here?
 j--;
}
if (j==numToDrawUnsorted) swap = ShouldSwapPrims(pzj, pzi); //if you need to call this once more to get the correct index, otherwise not required
while ((list != null) && (list [x] != "some value"))
  doSomething();
if (list != null)
  if (list[x] != "some value")
   doSomething();
You know I'm obsessed with UI and such, and I thought of these looks for AGS the other day:I like this much more than the suggestion in another thread. I really like the "modular" look it goes for, fits the scripting language with object-orientated scripting and all that.
Well it's actually pretty much the same thing, only on a larger scale.Actually, it's VERY different. Take a look at both.
SetGlobalInt(1, Random(2));
if (GetGlobalInt(1)==0) {
AddInventory(13);
}
if (GetGlobalInt(1)==1) {
AddInventory(14);
}
if (GetGlobalInt(1)==2) {
AddInventory(15);
}
Random(int min, int max);
AddInventory(Random(13, 15));
What you can do however, is use a listbox with hidden borders. And then do the text entry/linebreaking in code. I did pretty much this for my conversation log and it works fine.
Edit: As an alternative you could put 6 or 8 labels together to form a page. But the coding wouldn't be much different from when using a listbox.
I understand that the new "String" format has no such character limitation... but I'd appreciate confirmation.
Yep, I thought of that, though it's still kind of weird moving the cursor around... I could have a fake character that you could move to edit the text, but it's quite some work, you know.