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 - fernewelten

#341
Quote from: Shadow1000 on Tue 02/07/2019 21:51:44
I had the same experience as Cat. I assumed it was pretty much game over so I didn't say anything.

(Edit:) Concerning the ice cream room puzzle:

Spoiler
Yes, the puzzle is RIGHT at the end of the game -- when you solve it you see the end screen immediately afterwards, click on it anywhere and the game terminates without further ado.
[close]
#342
Guess that's what happens if you don't have enough time to do proper playtesting. I did playtest the keypad and that's why I put in the
Spoiler
sticky keys
[close]
: I found that otherwise it takes too long to find the right combination. But I didn't have the time to playtest the ice cream room properly.

Would it be okay to publish a revised version that cuts down the solution length in the ice cream room? Say,
Spoiler
make it 5 steps instead of 6 steps
[close]
? It would only alter one integer in the source code.
#343
Quote from: cat on Tue 02/07/2019 21:32:47
Regarding ice cream
Spoiler
… the order seems to be very random. Can someone give me a hint what the last one is?
[close]

Sorry about that â€"
Spoiler
the order IS random. There are five "buttons" and the solution has length six (not including the start button on the right wall). Exactly one of the "buttons" is repeated. So if you know the first five steps and one "button" has been repeated, then you also know the last button. Otherwise, there's no way around trying all of them.
[close]
.

For reference: Here are the "buttons":
Spoiler

1. The hammer dangling from the box on the right hand side of the room.
2. The grey field in the puddle
3. The button on the window sill
4a. The "on" button on the back wall; 4b. the "off" button beside it.
5. The chain with the purple handle on the right side of the room.
[close]
#344
Hello everyone,

Now I can proudly present an entry to the current competition.

One of the strange quirks that Germans seem to have is their craving for ice cream whenever the sun shines brightly. This in itself isn't unusual, but you can see Germans even buy at the ice cream parlour in cold winter time when snow is lying in the streets (provided the sun is shining brightly).

This is more of an urban thing because traditionally, in rural areas the ice cream parlours close for the winter season. Those parlours are usually run by Italians in Germany, and Italians seemingly like to go visit their family for the Winter months. In big towns, the parlours are open all year.

This facet might also turn out to be the prejudiced view of some vocal foreigners that claim to have noticed it in Germany. Anyway, I thought this could be an inspiration for the current MAGS contest.

My game features a classic BASS interface, DIY voice-acting (if you want to hear what is said, then read the captions aloud :-D ) and some music, but unfortunately no inventory puzzles, nor an inventory at all for that matter.

Starring some Germans as well as an Italian.

Have fun playing.

I've found the deadline tight this time, so there are probably some bugs that haven't been squashed yet. Sorry about that.


Download:
Game entry in the AGS game directory

Thread  with hints and tips for the puzzles

screenshot:


Spoilers moved here

#345
Quote from: VampireWombat on Fri 28/06/2019 14:03:55
Unless the rules changed this month, you can use previous graphics.

Trouble is, I've only got rats yet.  Or a cat or a puppy. Using those would change the script too much. ;)

Quote from: VampireWombat on Fri 28/06/2019 14:03:55
Or you could just simplify your character enough to ensure you can finish it in time.

So that's the way it'll go. I've managed to make just enough graphics to scrape by. The rest will remain a todo for Version 2 -- if there'll ever be a Version 2.

On to finishing Room 2 now!  :)
#346
Quote from: VampireWombat on Thu 27/06/2019 14:22:55
So... Am I the only one making a game this month?

Nope: I'm busy with a game, too.

Quote from: VampireWombat on Thu 27/06/2019 14:22:55
Due to heat and other things, it looks like my game won't be as complex as planned.

Nearly the same. My game will just have two rooms of which one is a street. And it'll have to make do without any inventory puzzles, or any inventory at all for that matter.

I hope I'll have enough time until Sunday. I'm only now finding the time to draw my protagonist at last. He's only been a stick figure so far.
#347
Quote from: Crimson Wizard on Mon 04/02/2019 10:36:12
Yes, that would be awesome if that's going to work!

I've looked at the parser code again and I think that the parts that handle function headers are fairly easy to relocate and repurpose. So I suggest I'll have a go at making the sequence irrelevant in which functions are defined.

For now, this would be strictly within each compilation unit.
#348
Quote from: Crimson Wizard on Sat 02/02/2019 17:12:53
To be honest I am not fully sure what exactly do you suggest from the user perspective. […]
So, do I understand correctly that this will work without any forward declarations for local functions (i.e. C#-style as opposed to C-style, so to speak)?

We _could_ have it this way with moderate effort I think.

So far, my proof-of-concept implementation only adds a "pre-phase" where it skims quickly through the source and collects the names all the locally-defined functions it can find. After the "pre-phase", it backs up to the start of the code and hands over to the old parser code.

We could extend that pre-phase and not only collect the names of the functions, but their headers too. In essence, whenever there's an "int foo(short bar) {" in the code, then don't just collect the "foo", but instead collect the whole "int foo(short bar)". Then, when the "old" parser starts after the pre-phase, it already knows all about all the local functions (except where they start) and can generate proper code when they are called. The sequence of function definitions wouldn't matter any more.

We might need to watch out for strange edge cases if enums or struct definitions are interspersed with the functions, I don't know for sure, but if there are, there will be a way to handle them.

Quote from: fernewelten on Fri 01/02/2019 00:45:35
Also, as of now, you can't have forward declarations in room files -- that is expressly forbidden (I haven't found out the rationale yet, but there's sure to be a very good one).

Quote from: Crimson Wizard on Sat 02/02/2019 17:12:53
Hmm can you elaborate on this, what commands exactly do not work in room script?

That was a false alarm, I think. I found in the code that called the script compiler (file Editor\AGS.Native\ScriptCompiler.cpp around line 75) an option "NOIMPORTOVERRIDE":
Code: c#

ccSetOption(SCOPT_EXPORTALL, 1);
ccSetOption(SCOPT_LINENUMBERS, 1);
// Don't allow them to override imports in the room script
ccSetOption(SCOPT_NOIMPORTOVERRIDE, isRoomScript);
ccSetOption(SCOPT_OLDSTRINGS, !game->Settings->EnforceNewStrings);
if (exceptionToThrow == nullptr)
{
    scrpt = ccCompileText(mainScript, mainScriptName);


However, checking the code of the script compiler itself (including the original one, before I rewrote it), it doesn't query "SCOPT_NOIMPORTOVERRIDE" so the flag is ignored. The context shows that the flag was once used for forbidding that an import declaration was followed by a local function definition after all.

#349
Quote from: Jack on Fri 01/02/2019 01:20:44
What do you
Oops. Fixed my posting now.
#350
Currently, functions in AGS must be ordered with an important restriction in mind: At every point in the source code, we can only call functions that have been defined above that point. This is unfortunate in two ways:

  • Firstly, many programmers like to order the functions differently, for instance to keep similar functions near each other.
  • Secondly, in many algorithms there are functions that mutually call each other: a function A calls a function B and function B calls function A â€" this is known as "mutual recursion". With the restriction as it is now, we can't use any of these algorithms!

In case you're wondering: There's a real-life use case for such algorithms: Right in my very first AGS program ("Commando raid" for the MAGS 2018/5 competition) I wanted to code a maze dynamically. The easiest way to do it was using functions that called each other.

To allow for this, other languages such as C or C++ have a mechanism that says, in effect, “There's a function that I will define later on below; but right now, I'm only telling you its parameters so that I can code calls for it.” That's a forward declaration.

I found out to my delight that the AGS language have a forward declaration, too, using the import keyword:
Code: ags
import function A(int);
means that a function A will follow somewhere below that takes one parameter that is an int.

But I was foiled all the same: Turns out that even though AGS does have forward declarations, you still need to order the functions in such a way that any function that calls another one must have its body completely defined below the body of that other one! (wtf)  What a shame!

So why is this so hard for the AGS compiler?

(Technical reason below...)
Spoiler
There are two quite different uses for the import keyword. On the one hand, it can be a forward declaration as described above - it tells the parameters of a local function that will be defined below later on. On the other hand, it can be a declaration that an external function has been defined and exported in another module, so it must be retrieved from there when the program is bundled together.

So when an "import" comes along, the compiler must guess which meaning is meant. And it guesses that an external, imported function is declared. And it prepares everything for an import in all kinds of lists and tables.

Later on, when the compiler encounters an identically named local function that has a body, it goes, “OOPS!! Eeek! Oh my goodness. I screwed up back then. It had been a forward declaration after all. Let's sweep all those wrong preparations under the rug and pretend that that import never happened.” Then it hides all the traces as well as it can.

Trouble is that under the hood, an external function is called in a completely different way than a local function.  So if that “imported” function has already been called when it turns out it was local after all, it's too late for the compiler to clean up the mess. So that's a technical reason why the compiler insists that all the local functions must have been defined with their bodies before they are called.
[close]

How can we fix that?

(Proposed technical solution below)
Spoiler
Let's first eliminate the “oops” effect, shall we? The compiler would need to quickly scan the input to see what functions are defined locally; then it can process the input as before. Whenever it encounters an “import” statement, it would now know whether it was an import proper or a forward declaration in disguise. So it can avoid doing the wrong preparations from the get-go.

Granted, the compiler would still only know where the local method starts when it had reached and compiled it. So whenever the function is called before that point, the compiler would need to note down somewhere the position of the call in the code. When the body of the function comes along in good time, it could go through its list and patch the address in that it now knows.

We're still not in the clear, because from time to time, the compiler will emit some code, then rip it out of the codebase, then insert it at adifferent place - or even several times at several different places. So the code that keeps that list of calls to be patched needs to be aware of this activity.
[close]

Some snags with this idea:
Spoiler
This approach will only enable arbitrary ordering for functions that reside in the same compilation unit. The reason is that modules must be ordered in such a way that any module that calls another module must be placed below that other module. So you can't have mutual recursion that spans modules.

Also, as of now, you can't have forward declarations in room files -- that is expressly forbidden (I haven't found out the rationale yet, but there's sure to be a very good one). So you can't have mutual recursion in room files, it will only work in globaldata or in custom modules.
[close]


I can offer a “proof-of-concept” implementation on https://github.com/fernewelten/ags in the branch "Mutual_recursion".

(Details below)
Spoiler
It's lined up behind an oversized “monster” pull request that has unfortunately gotten rather huge (I'm at fault for that) and so will take its time, so I'm leaving the proof-of-concept for mutual recursion on my fork for the moment.

I've centralized all the main functionality in the class FuncCallpointMgr of files cs_parser.cpp / cs_parser.h
[close]
What do you think?
#351
Engine Development / Re: Parser cleanup
Tue 15/01/2019 01:53:43
Great! That's exactly what I was looking for. And it contains the line that #defines "function" to mean "int", too.  ;-D
#352
Engine Development / Re: Parser cleanup
Mon 14/01/2019 23:06:34
Quote from: Crimson Wizard on Mon 14/01/2019 20:56:00
If by "properties" you mean ones declared with attribute keyword (e.g. Object.X), user may create these. Unfortunately they were never properly documented in the manual, but there's this wiki topic for the reference: https://www.adventuregamestudio.co.uk/wiki/Keyword:_attribute

I've just gone hunting through the code, and you had the right hunch; thanks for the tip. All the original parsing code and all the relevant comments in the parsing code seem to talk about “properties”, but the word that is actually expected in AGS code for that concept is “attribute”. So you have code, e.g., in Compiler/script/cc_symboltable.cpp, that says:
Code: c++

add_ex("export", SYM_EXPORT, 0);
add_ex("return", SYM_RETURN, 0);
add_ex("readonly", SYM_READONLY, 0);
    ...
add_ex("attribute", SYM_PROPERTY, 0);
add_ex("enum", SYM_ENUM, 0);
add_ex("managed", SYM_MANAGED, 0);


One line in the code above is the odd man out: guess which one it is?  :) Oh well.

#353
Engine Development / Parser cleanup
Mon 14/01/2019 14:17:04
So, I am back.  :)

I've done my best to touch up the parser code. I'm providing googletests that cover 75 % of the code lines and prove that the rewritten parser generates exactly the same bytecode as the pre-rewrite parser, byte for byte. Nearly all the work is in solution Compiler.Lib, file script/cs_parser.cpp. Details in the note to the change request I posted (to the AGS4 branch).

Tell me what you think.

Now I am unsure how to proceed.

Up to now, I had a "closed, self-contained system" consisting of just the parser files and googletests.  I've pushed that as far as it would go. But now integration comes into play. For instance, when I write a program in the AGS studio, it has predefined macros:

Code: ags

for (function Loop = 0; Loop < 10; Loop ++) {
    break;
}

This is legal AGS code, and the only way this makes sense is assuming that "function" has been #defined as "int" somewhere. I don't know where the macros and stuff are set up, or more generally, just what happens at all before cc_parse() is called.

Also, as far as I know, you can call predefined properties in AGS code, but you can't define your own properties in AGS code -- so I can't write self-contained googletests that check property parsing code.

I also don't know what happens after cc_parse() has done its thing. There's bound to be a linking step somewhere?

So how do I widen the horizon (efficiently)?


#354
Engine Development / Speak of the devil ...!
Thu 26/07/2018 12:27:27
Well, speak of the devil and he'll come along. Here's a prime example:

Bug: Messing with the compiler line numbering

Seems that the tokenizer is written in such a way that any constant string of the form "__NEWSCRIPTSTART_" anywhere in any context whatsoever (except for comments) will reset the line numbering of the compiler. :-/ I haven't definitely ruled out yet that the parser _needs_ that for some strange reason, but preliminary analysis says it doesn't. There's no place in all the AGS code where either that string or the #define for it is referenced a second time.  It's only in the tokenizer. It's never automatically generated.
#355
You're quite right: It might easily be that this tangle hides something strange somewhere - some construct that the code does NOT forbid although it ought to be forbidden, or the opposite. Also, we might find out that some parts of the interface have strange quirks in special cases, for instance that some externs interact in unwanted ways in special cases. When we find out how some code is generated, we might not like that generated code.

Whenever that happens we can still decide to flag those user inputs as errors or to change the interface or at least to provide some additional safeguarding or to change the code generation.

This is just meant as an intermediate step to make the code easier to work with and to make any weak points that need fixing more conspicuous to see.
#356
So, I've checked with Gurok, and he doesn't think it probable either that I'd step on another programmer's toes.

So I'm having a crack at refactoring cs_parser.cpp, at first trying my hardest to not change anything except for the "tangledness". It's a strictly localized effort -- 1 file --, so it will be easy to roll back or ignore if it doesn't work out. I'll try to stress-test that continually as much as possible.

If it does work out, the next step might be to try and make the code more "c++"sy. That is, replacing homegrown structures by established ones wherever they exist while still not changing anything in the behaviour or output. Perhaps better object boundaries emerge, perhaps concerns can be better separated.

If that works out, too, then we can see where we might take the code from there.
#357
Thanks for the fast response!

Quote from: Crimson Wizard on Wed 25/07/2018 01:32:04
because currently [the] code [of the compiler] is perhaps the messiest of all AGS.

Er, I've noticed that. :-D

I'm new to the project and don't know any details, so I can't give an informed opinion. But in general, I would prefer refactoring the compiler first and porting it to C# next: Usually, messy code isn't written that way from the get-go. It usually starts out with a clear, understandable concept. But life is complicated, and programmers learn the little snags and details step by step as they show up. Thus, the tangles come in and accumulate more and more. They've all been bought with sweat and tears, one by one.

In such a situation, if the code is simply rewritten from scratch, we do regain a nice-looking, structured code. But it is impossible to understand the tangled old one, so it is impossible to port all the bells and whistles of the old code into the new one, and tons of information get lost.

Trouble is, life still is complicated, and all the lost bells and whistles will have to be re-bought a second time with sweat and tears, one by one. This might be much more than estimated originally.

So it might be worth the pain to refactor the code and keep the bells and whistles in. When the code is in shape, it shouldn't be too hard to port it to C# in a second step.

This is just a general opinion; I don't know whether it really applies here. You've probably had lots of discussions about it already in the team.

The compiler already has a rudimentary test suite, which is a good thing. As far as I can see, it is fully functional (except for that one test): You just compile it, link it against the compiler object file and let it run.

This could be extended into a safety net for refactoring: After each rewriting step, the tests could be run "at the push of a button" to ensure that the new output is exactly like the old one. Thus any errors or omissions that creep in would be caught as early as possible. With luck, the compiler would never leave a state where it is fully usable. This would be very desirable IMO since it is a central core component.


Quote from: Crimson Wizard on Wed 25/07/2018 01:32:04
We have a description of the script format in the repository's wiki:
https://github.com/adventuregamestudio/ags/wiki/Script-memory
https://github.com/adventuregamestudio/ags/wiki/Script-execution

I've looked at them and found them quite helpful in understanding the code.

I've also seen that there's a "fixup" step involved. There seem to be two parallel arrays, one for the bytecode proper and another for "fixups". Each bytecode has an associated 8-bit field in that other array that denotes whether the integer is left as is or whether it is translated in one of several ways. I've preliminary decided that this must be some sort of one-pass linking.
#358
Engine Development / Two compilers, one cup?
Wed 25/07/2018 01:12:35
At first blush, this project seems to have two compilers:

  • The one in Editor/AGS.CScript.Compiler
  • The one in Compiler/script/cs_parser.cpp (the main entry seems to be the function __cc_compile_file())

How are they related? Which should I delve into first?
#359
So, I've used the last days for heavy-handed looking through the AGS code base, in order to get an overview on the coding. I've kept to the AGS4 branch for the time being. I'm still at it. --

Is anyone actively working on the parser right now? Because I'm noticing that the parser module is currently failing its own Googletest tests. It seems to correctly catch a type conversion error, but in a different way than the author of one of the tests expected.

Spoiler

(ags/Solutions/Compiler.Lib.sln, project Compiler.Lib.Test, testfile ags/compiler/test/cs_parser_test.cpp, line 77)
error: Value of: last_seen_cc_error
Actual: "Type mismatch: cannot convert 'DynamicSprite' to 'int'"
Expected: "Type mismatch: cannot convert 'DynamicSprite*[]' to 'int[]'
[close]
#360
General Discussion / Re: Translations
Fri 13/07/2018 11:12:50
I'm afraid English has drawn the short straw. It's rapidly going the way Latin has gone in the mediaeval ages: Everyone is speaking and writing it to make themselves understood, claiming to be proficient in it no matter whether they are or are not. At best, they use the grammar and idioms of their mother tongue with English words. At worst, they speak a muddled, brutal, bloated dialect called "Companese" that doesn't even adhere to foreign idioms: It _sounds_ English, but no Brit or American would speak it that way. Some say that the Germans in particular are spearheading these "efforts". The end result is that the language as a whole loses massively.

Our lowly adventure games are just joining the huge bandwagon after the song texts and advertising slogans. The argument is always the same: Well, we _might_ do this in <insert language here>, but if we do this in English, our audience will be much larger for the same effort, so let's do this in English from the get-go. We all know English, don't we?
SMF spam blocked by CleanTalk