I finished translating Re-Hoard’s code from Lua to Chaiscript.

I am surprised at how few days I took after my vacation.

Then again, I was riding the additional hard work I did before the vacation.


Honestly, I still need to write a function that sets the language variable (which would decide whether the game would be in English, Spanish, or Esperanto). While I had the idea of a language-select screen, I also wonder if I could simply have the game read the language setting from Libretro. (After all, does no ChaiLove explicitly target Libretro?) After that, I need to actually draw the Spanish and Esperanto version of the title logo. Then there is the implementation of the priority queue and, subsequently, replacement of the Breadth-First search with the A* algorithm.

However, I would rather debug the game, first. At the current state, the game should run normally. If I debug now, I would have to worry about less possible places where something went wrong.

I am going to ask Mr. Loach again…

Advertisements

Re-Working, Re-Thinking

You are probably wondering what has happened to me during this silent period.

After I left Lua, I assessed my current options. Because a job opportunity already led me to learn JavaScript, a rather delightful language, I decided to first use melon.js, then Phaser. I later realized, though, that not only would me needing to use a web server be a problem with the turnaround when working on the game, but there is also the risk that way too many people would try to play my game at once, causing server overload (and high costs). Meanwhile, I worked on a ChaiLove version. The problem is that ChaiLove does not have that much documentation – the only ones that were helpful to me were the cheatsheet and this tutorial – which meant that I had to request Rob Loach’s aid… which would be the first time. Despite that, ChaiLove seems to be a great alternative, what with the ease of use and better functionality. I mean, not only can I use actual classes, but the audio system has more control.

The tricky thing, however, is re-thinking how the game should work in ChaiLove… especially given that some algorithms are specific to the pico-8.

I may have to go back to being silent, though, because the concentration on this work is intense.

My hoard is nil.

if ecs_single_entity["actor"] == "fireball" or "arrow" and ecs_single_entity["location"] ~= nil then
    if ecs_single_entity["location"][1] > 1 and ecs_single_entity["location"][2] > 1 then
        if ecs_single_entity["sprite"] == sprite_fireball_up or sprite_arrow_up then
            if {ecs_single_entity["location"][1], ecs_single_entity["location"][2] - 1} == value then --the location is nil
                ecs_single_entity[key] = nil
            end
            elseif ecs_single_entity["sprite"] == sprite_fireball_down or sprite_arrow_down then
                if {ecs_single_entity["location"][1], ecs_single_entity["location"][2] + 1} == value then
                    ecs_single_entity[key] = nil
                end
            elseif ecs_single_entity["sprite"] == sprite_fireball_left or sprite_arrow_left then
                if {ecs_single_entity["location"][1] - 1, ecs_single_entity["location"][2]} == value then
                    ecs_single_entity[key] = nil
                end
            elseif ecs_single_entity["sprite"] == sprite_fireball_right or sprite_arrow_right then
                if {ecs_single_entity["location"][1] + 1, ecs_single_entity["location"][2]} == value then
                    ecs_single_entity[key] = nil
                end
            end
        end
    end
end

re-hoard_still-nil

Even after I explicitly checked if the location is nil, I get this error.

In fact, my main issues are how Lua and pico-8 deal with nil values. They always seem to come up and cause big problems every step of my way, no matter how close I get.

I think that my game cannot handle Lua.

I was prepared in case this happened. I am aware that C, being a lower-level language, invites more problems, but I do not think that I can profitably go farther using Lua at this point.

I am not quitting Re-Hoard. However, right now, I shall search for a different game engine. Meanwhile, I shall take a look at the underlying algorithms that run Re-Hoard. Even if this issue is just another algorithm problem, I still plan on switching languages because Lua is just giving me too much grief.

Hoarding on the Dragon

(Disclaimer: a lot has happened here quite some time ago, which means that I have forgotten details here. While the order of the text and the order of the pictures is correct, the pictures might not accurately reflect the state of the game at their point of time in the text.)

 

I was wondering why all of the opponents were knights instead of the variety of emotions I planned. I decided to check the value of the name of one of the opponents.

That value was nil.

In fact, all of the opponents had nil components set to nil values!

The entity-component system that I used is actually a couple of functions that run over tables (the entities) that have a set of keys and values (the components). Other functions (the systems) run on those keys. Because tables are the basis of this entity-components system, I figured that I had two solutions:

  1. Turn the component keys into integers instead of strings. I might also switch from pairs() to all(), which requires a gapless sequence of integers but runs the components in order and had a bigger guarantee of working.
  2. Rewrite the entities, components, and systems in a way that gets rid of syntactic sugar.

I picked the 2nd option, other than my run with Scheme making me distrustful of syntactic sugar, because making the underlying structure more apparent should make the game work better.

That did not work, though the whole thing is actually more understandable.

I then found that the populator accidentally overwrites the dragon entity. I fixed that.

re-hoard_half-opponents

…”local ‘c’ “? That variable did not exist in the code!

After some struggling with online searching and looking at the code again, I found that my conversion to the new format was incomplete. Aside from the table-related deletions still using syntactic sugar, the string keys, by virtue of being strings instead of numbers, needed quotation marks, plus the key/value pairs needed commas at their ends. I did all these fixes.

re-hoard_full-opponents

Everyone is there now! The game actually looks playable!

…”looks”. Nobody could move!

The code seemed fine, but the dragon’s movement values were nil! This time, the dragon was completely empty (excluding one entity that had the value of… an empty table)! I tried manually setting the value of the dragon’s movement, but the dragon moved in place once then stopped. I ended up writing a lot of debugging code that printed the value of both the dragon’s vertical movement and position after I manually set the movement, but the movement seemed to go nowhere.

Turns out that everyone still used the old components which split the movement and positions into horizontal and vertical parts. I updated them to the new components that used its own table. In the meantime, I also got rid of some redundant code that checked the current phase in some modules, even though the modules themselves only run in their respective phases.

re-hoard_gang-up

While the opponents can move, they were supposed to touch the dragon if the dragon was next to them. Moreover, the dragon was supposed to lose after one of the opponents touched the dragon, but the game keeps going…

Hoarding Opponents

Shortly after I wrote my previous post, I wondered if I made a mistake when drawing the map. After all, while testing the game, I hard-coded the dungeon plan, which meat that the dungeon-builder was not at fault. Sure enough, I found that the mset() functionality merely says which sprite goes where in the map but does not actually draw the map itself.

I added actual drawing-code.

re-hoard-unbuilt_dungeon

The dungeon actually drew itself. From what you (cannot) see, though, the treasure is gone. Even after I replaced the dummy data with the actual dungeon-generator, the treasure is still invisible. I messed with the treasure’s location.

Turns out that the game draws the treasure before the dungeon, hiding the treasure. I only noticed that because, when the treasure was moved behind a brick tile, I could see part of the treasure. (Black is equivalent to transparent in the pico-8. I saw the treasure through the black lines of the brick tile.) I rearranged the order of the drawing code.

re-hoard_stuck-knights

One thing is that, not only does the dungeon-builder actually work in practice, but I also can see every opponent and the dragon! The problem, though, is that just about everyone is stuck inside the walls. Looking into the code revealed that the sprite-drawing code positioned everyone off by 2 pixels. That worked, but some were still stuck in walls. I then realized that the dungeon-building code had the internal cell-order of “vertical, then horizontal” instead of the more intuitive “horizontal, then vertical” order I used. I switched the order of the opponent-placer to “vertical, then horizontal”.

re-hoard_free-knights

Everyone is now located properly!

(You can see that I restored the original color of the treasure’s metal part.)

Despite these fixes, there are a couple of problems. The first is that they are all of the knight sprite when there is supposed to be only one knight. The second part is that no one, not even the dragon, is moving. I thought that may have to do with the entities not having a variable that declared what opponent they are. (After all, the knight sprite is the default sprite.) However, had the opponent-declarer not worked, neither would the opponent-locator worked either because both are functions! Trying to access the details of the world was fruitless, either.

I let go of this problem right now.

That’s my Hoard!

At this point, I am incredulous to any feeling I have that I would never finish my game. After all, every time I get that feeling, I get a success that deals with the cause of that feeling.

The first part was that I realized that mset() from the pico-8 API merely alters the map data but does not actually draw the map. The second part was that, out of some reason, I wrote code inside the dungeon-building function that explicitly does not run during the setup phase. (Between those two, I ended up fixing a lot of other bugs and even simplified the code a lot. That was a happy side-effect of figuring out the problem with the map not drawing.)

After those fixes, I got this:

re-hoard_single-treasure

That screen was blank yesterday.

I have never been so glad at seeing a single treasure chest.

Cleaning up my Hoard…

After struggling with finding out a possible entry point in solving my problem, I wondered if the dungeon that has the array was too big. I did a couple of dungeons: one normal-sized and one half-sized.

No.

I then wondered if the opportunities were at fault, since the game runs out of memory after printing the opportunities.

No.

I then wondered if what was at fault was the function that runs at an intermission, since everything prints right before running out of memory. After selectively commenting out sections, I found that the music-handling system was at fault.

I looked the code itself.

music_stop = function()
 music_stop()
 music_playing = false
end

…doh. I meant to write music(-1), instead. The game was stuck in an infinite loop.

I fixed that, but I got a new problem:

re-hoard_too-big

I read about that restriction a lot, but this is the first time this has happened to me.

I got rid of the commented-out debugging code in testing the dungeon, but the fact that I am extremely close to hitting that restriction is surprising and frightening.

 

Despite this, the game still does not go to regular gameplay. I wonder what now?

Re-Building Dungeons

I thought that all I needed to resolve was dealing with the old algorithms. However, because running computer programs reveal only one error at a time, I found out that the dungeon-building code crashed the game because the code apparently tried to index a nil value. That burned me so much; I did not want to deal with the game until late at night, even though I fixed the previous problems early in the same day.

Because the dungeon-building code is based on my own implementation of the Recursive Backtracking algorithm, I decided to pick someone else’s implementation, instead. I ended up getting one from Rosetta Code. I then took my time adapting the code closer to my code style and integrating the code into my game. Subsequently, I brought the imported code to a separate cartridge because I wanted to make sure I understood the algorithm and got the algorithm right. I took this time in changing the all() iterator to ipairs() because all() is very slow, from what I have read at Lexaloffle. all() guarantees order in iteration, but this is a randomly-generated dungeon; the risk of iteration out-of-order would only add to the randomness in generation.

From what I expected, the adapted code broke, too. After doing more adaptions in light of the pico-8 environment, the pico-8 still got problems with nil values. Turned out that a constant table that had the corners needed to be renamed.

After the algorithm ran without a problem, I decided to try to get a dungeon preview. The problem is that trying to print only one character at a time led to the pico-8 printing one newline after character, which meant that my preview was just a column of wall characters. I could concatenate the characters, but, because the dungeon is generated, I would not be able to know what character goes next. Though I could put the characters in an array, I also found that the pico-8 does not print a newline after a character if I specify the screen position, which I can calculate from the sentinel values the algorithm uses when iterating over the rows and columns the dungeon structure has. After adjusting the positions, I got the preview.

However, that used an all-wall dungeon. Once I started using an actually-generated dungeon, the nil error returned. I decided to comment out all of the code, write a few lines of debugging code that mentioned the values certain variables had, then uncomment the code one piece at a time. I found that, because I used pico-8’s random-number generator instead of the one in the table library, I risked getting a value of 0, even though arrays in Lua start at 1 by default. Adding 1 to that value solved that problem.

I ran the generation algorithm, which ran without a hitch. However, the dungeon seemed to not have a wall perimeter despite there being code that specifically printed some. After inspecting and testing that the code ran correctly, I wrote new debugging code that printed the variables of any factor that could affect this mistake. I started by printing the dungeon’s dimensions then adjusting them accordingly. There was no correlation. I then tested the arguments that were fed to the walk() submodule, that is, the part that actually generated the dungeon’s path. (A positive side effect of this technique was that I separated into their own variables the complex calculations that went into walk(). ) After going through 20 test cases, I found that the dungeon had the wall perimeter only when the values were fed into walk() were both even. After writing code that made those values even, the generated dungeon now has a proper perimeter every time.

 

These changes did not work even when fed back into the main one. I tried hard to check how the code was different, even switching between the ipairs() and all() iterators, but to no avail. Turns out that, while copying the algorithm to the actual game, I forgot again about renaming the constant that had corners, since the game put all of the constants at the top of the source code… away from the algorithm which was closer to the middle.

The game now stopped whining about nil values.

 

What comes next… the game fails to switch from the title screen to the intermission screen, failing to set the variable that activates the intermission phase.

I want to take a break from this, too, until I figure out how to even define the problem.

Re-Hoarding discarded algorithms

After I got the title screen working properly, I found that the Lua used in pico-8 does not support metatables, thus messing with the queue code, which used plain Lua.

I ended up analyzing more closely the queue code used in the Pico Zine.*

At the same time, a bit of looking into the Lexaloffle Forums said that I should review the collision demonstration that pico-8 has because of how robust the collision system is there. I already picked apart the game code there one time, but, given that the alternative that went into the game is not working, I should look into the demonstration again.

On the other hand, there is nothing stopping me from switching to LÖVE again, which uses plain Lua… The way code is structured in the pico-8 is similar to the way code is structured in LÖVE…

 

  • = I wish the Pico Zine continued…