So. This is the first phantomnation screenshot ever. I don't remember if this was before I even got the file-loading part working; I might have written this 'map' into the code itself.

This was me trying to figure out how the weird hexagonal co-ordinate system worked. Answer: weirdly. The fading red and blue lines are the X and Y axes (axises? axii?), the bright blue lines are -x +x/+x -x coordinates, the green tiles are +x +x/-x -x coordinates. I think the orange tiles are +x*2 +x coordinates, but I've totally forgotten; I'm on screenshot 33 at the time I write this.

This is really the only screenshot of the join-drawing bug, first form. I think this particular shot is of the time joins were drawn upside-down. That is to say, if the top of tile was angled and the bottom was flat, it was drawn with the bottom angled and the top flat. yeah.

Note how it looks just fine on the flat tile.

This was a wireframe shot of the first version of the join code. You'll note there were no angled tiles on this map. Because of this, I didn't notice the tile joins totally exploded when dealing with angled tiles. (sadly, there aren't any screenshots of the original code in action-- it was kind impressive)

This was an amusing bug stemming from me accidently placing the joins based on a tile's co-ordinates, not its location. So they all appeared clustered around the 0,0 tile. whoops.

Getting screenshots of the various join-drawing bugs was hard, because a lot of the time you can't see specifically what the problem is unless you can rotate the scene. Like, say, there are no screenshots of all the backwards joins, because I just couldn't get a view of them that would be visually informative.

Wireframe isn't very illustrive, but this is after (finally!) getting all the joins drawn 1) correctly, and 2) without really stupid, inexplicable code. Technically I got the join-drawing code working right the first time I tried, but it really, really sucked. seriously.

There were some... issues with tile heights matching, and they only worked because I spent a lot of time randomly changing variables around (okay so they draw one-off here... let's just change this variable by one and see if that changes anything! (repeat x20)) until it worked.

And then I thought to myself, "maybe I should try actually thinking about this problem", and I jotted down co-ordinates and enums and matched everything up.

Or not. Of note in this screenshot: the hole in the join to the left, and then more obviously the join bug to the right when dealing with multiple tiles on one co-ordinate.

So. Dynamic map resizing action! But the lines... well, clearly the grid lines could be improved. But it's really helpful for telling just how large the map is.

Fixed the last (hopefully) bug with tile joins— excepting, of course, the one where tiles on top of each other don't autojoin correctly. But that annoying missing triangle is gone! (for the record, it was caused by me typing MID_R instead of MID_L.)

Moving on to random map generation, even though I'm not technically done with the tile join code. I honestly thought tile joins would be easy until I started working on them, but even though I haven't fully bugfixed it I'm moving on to something else, because there's only so long I can keep going on fixing my own dumb bugs. Once I get the map gen algorithm working I'll have to fix the remaining tile join bugs, anyway.

This is... one of the maps generated using the first random map function. It simply starts at 0,0, then randomly skitters around leaving tiles behind until it reaches a certain amount of tiles placed. Clearly, it's not that good. I'm pretty sure there are a lot of overlapping tiles.

(also note I changed the way tile colour generation is done)

So, I made the random map generator work better.

Wait, I'm getting ahead of myself.

I totally redid the way phantomnation handles maps. there are a lot less inexplicable functions now. This is good! Still picking the bugs out of the new code, though. Which is why joins aren't drawing right now. And why there are no colours or textures.

But don't those miniature maps look awesome? especially considering how terrible the first 'version' of the random map generator was? They are pretty neat.

Two issues: Firstly, the height & overlap parts of the random map generator aren't coded yet, so there are a lot of overlaps. Overlaps aren't a bad thing, but they are when they're not handled properly (in this case, by replacement and decremention of the size value) Secondly: these five maps? They were all generated with the exact same function call. That's... not good. I mean, yeah, part of it is that I maybe weighted 120-degree turns too high, because they really add to the 'randomness' of a map, but there is a big issue of it tending to create very diverse maps with the same exact arguments. I guess that'll be next on the list of things to do.

...after finishing the height & overlap portions of the generator, of course. And finding out why joins aren't drawing. ...And adding texture support. So, uh, pretty far down there.

With this update, I totally removed the map-file reading code, so everything after this is going to be a randomly generated map. Once I started work on the random map generator, I figured it'd be better to invest a lot of time on map generation and no time on making maps, instead of investing a little time on map generation and a lot of time on making maps.

Here's a nice example of the working tile join code, feat. a generated map & tile overlaps. That's, uh, not the real height code there. That's me being lazy and making every tile placed one higher than the one before it. This is important because making the penultimate tile join calculation function will change how these joins are drawn in a significant manner. But that can wait until I get the real height step working. And then I can finally stop worrying about negative heights causing trouble.

The height code does not work as planned.

newheight = buffer->height[0] + (hvar[0] - (random()%hrange)); vs. newheight = buffer->height[0] + (hvar[0] + (random()%hrange));. Oh, such a small difference. The first: the generated height is always LOWER than the lowest possible variance in height between tiles. (in this map, that was -2) The second: the generated height is somewhere between lowest and the highest possible variance between tiles. Big difference! The crazy joins are due to the general suckiness of the join code, esp. when it's dealing with negative heights (hence my note about wanting to redo the join code so I don't have to worry about that anymore in the above note) and that one incredibly sloped tile is due to the slope code, at that point in time, grabbing the first tile off the coordinate where the last tile was placed as the last_tile value, instead of the actual last tile. Which is a problem when there's an overlap and there's a height difference of 40+ between the two tiles on the coordinate. As in this example!

The sloping code still doesn't work right, though— it's sloping the wrong edges.

Sloping works! Also overlapping is handled correctly. Not that it's really possible to tell; these three-colour screenshots really lack noticable depth. In fact, the most noticable part of these shots are the multiple undrawn joins.

See, I never really anticipated my maps having criss-crossing joins. As a result, my tile join code just kind of... dies when confronted with them. It's actually quite a quandary as to how I'd go about drawing criss-crossing joins in the first place (because each tile has to draw half the join). It's... difficult. And this new tile join code doesn't appear to draw triangular joins, either. Oh, woe is me.

But hey, the make_path() function is finally done! Now I have to do the exact same thing, only with clusters instead of paths. And then code some symmetry functions.

...and fix that inexplicable infinite loop when height variance range equals one.

(p.s. the infinite loop was because at one point in the code I typed buffer->height[0] instead of buffer->height[CENTER]. See, because 0 is one of the corner vertices (as are all the vertices except for CENTER, really) and if you have a map that slopes and you get a tile that slopes down on the vertex that 0 corresponds to, the height value enters a loop— which in a repeating (incremental) map (which I don't have any screenshots of, yet) causes an infinite loop, because the height never gets high enough to place any overlapping tiles. in a non-repeating (percentage) map you just get a lot of inexplicably-sloped tiles. It only happened when the variance was one because if there was any amount of range, eventually it would break out of the loop. It would just take longer and longer to generate the map the closer the range was to one.)

Dude, I don't even know. I'm editing the tile join calculation code. It's... not going as planned. On the upside, triangular (but not criss-crossing) joins are now being drawn.

(sadly, this wasn't even the most bizarre map generated.)

Once again, something I think will be fairly simple is instead a horrifying ordeal. This is the new join code! It sucks less. It's kind of a tradeoff— in exchange for incredibly long tile join occluding lower tiles, I have recieved short tile joins occasionally showing the hollow insides of tiles. Also, they're choppy and sometimes ugly. Sigh.

But they are a big improvement over the old tile join code. The biggest issue here is for 'smooth' joins you have to refer to the joins of neighboring tiles, but it's impossible to be sure the neighboring tile's joins have been calculated unless you run calculate_region_walls() twice in a row. Which I don't want to do, because it's sloppy. (it's also possible to recurse onto neighboring tiles, but, um, recursion scares me. well, that and I think it'd increase map generation time significantly. and potentially cause infinite loops.)

The second screenshot here is a map that starts at, um, 4 or 8 or something, and goes down from there. Compare to that "the height code does not work as planned" map. Negative heights: not a problem!

Sadly, the joins are now ugly to look at.

But now to figure out what's causing the crazy sloping. Again. Didn't I fix that bug? I think I did. sigh.

But then instead of finding & fixing the crazy sloping bug, I added a wireframe view mode and changed the tile join draw code. Compare to some of the early screenshots above to see the difference. The first screenshot here is with outside joins to 0, and it shows off the difference a lot better than the 'real' second screenshot, because with the new tile join code it's unusual to see joins above 12 deep.

Not actually knowing how textures work, but I /assume/ this setup would be better. I mean, I know I have to draw at least two parts of the join (one for the top texture, another for the rest of the join) but I should probably check to see if I'm not just wasting polygons.

I've been trying to root out the random segfault bug (every so often, generating a map causes a segfault, but it's rare enough I can't even begin to tell you why), but I stumbled upon this map while generating maps waiting to get a seed that caused a segfault. This is a good example of what I have been calling "the crazy sloping bug". I mean, look at it! Usually it's one corner sloping down too much, though, instead of one corner jutting up like that.

And in crazy sloping bug news, found it & fixed it... I think. See, I had a hunch it had something to do with skipping tiles. An older version of the make_path() code kept doing height steps when tiles couldn't be placed (and as I was typing that, I realized incremental paths have to do height steps when tiles can't be placed or else they get stuck in an infinite loop, so there was a slight aside for bugfixing) and that's bad for selected/random maps (for the record, the two path types are WEIGHTED (as in, you give weights for the various movement actions and one is picked randomly from them) and INCREMENTAL (as in you give weights and then counters are established that increment each movement step), and they're different enough that there's a fair amount of code tweaking that needs to be done to make sure both types are working properly) so I disallowed height steps when there wasn't a tile placed last time through the path loop. My hunch was that sometimes the last_tile value wasn't getting set to NULL, and so there was sometimes the wrong last_tile value, so that's why weird slopes were happening— because they were sensible joins to some tile, but not to the tile next to it.

But that's not what was happening. I'm actually not quite sure what was going wrong, but resetting the tile's slope on tile skip and checking slope chance independant of the rest of the height step seems to have fixed both the stuttering slopes (when several tiles in a row have the exact same slopes) and the weirdly sloped tiles (which I think were due to a tile getting sloped twice in a row). So.

while(traverser->next != tile || traverser->next != NULL) {
 traverser = traverser->next;
if(traverser->next == NULL) {

Find the segfault-causing error! Here is a hint: OR is not what you want to use for that loop. The segfault only occured occasionally because the code was in a rarely-used part of the tile removal code.

Here is one of the maps that caused the bug! with seed 1182877604, and an argument list of {0,0}, random()%6, {1, 0, 1, 0, 1, 0}, 1.0, 0.6, 0.4, 0.3, 0.3, 0.0, 0.0, 0, 4, {-2, 4}, .85, 20, 1, .67, {15, 50}, TYPE_DEBUG.

Second screenshot: the "tilt up" view. Because hey, it's useful. One of the major gameplay issues I foresee are tiles that are totally occluded at all angles due to tiles overhead or taller neighbors. Normally, a 'tilt up' is enough to fix that, but since phantomnation allows overlapping tiles that's not a magic fix. I'll have to see if increasing the min. distance between overlapping tiles will be enough to fix that.

Aug 31st, 2007

After a lengthy time away from any coding whatsoever, I decide to rewrite the way make_path() makes, uh, paths! THIS IS BOUND TO END WELL. This is a screenshot of the 'new' path engine, still in its initial very-buggy stage. The trail leaving the edge of the screen went on for about three or four screens without ever clustering again. But that's not even the most disconcerting information!

__audit(): The following memory locations are allocated:
__audit(): address: 0x1, size: 120.
__audit(): address: 0x1, size: 120.
__audit(): address: 0x1, size: 120.
__audit(): address: 0x1, size: 120.
__audit(): 480 bytes listed as allocated.

And that's if phantomnation even manages to exit— most of the time it errors out with, no joke, glibc free() errors: *** glibc detected *** free()Aborted or *** glibc detected *** double free or corruption (out): 0x0804f7e8 ***. Sometimes, it's just a regular segmentation fault! I get the feeling my stack implimentation (among other things) is... less than optimal.

First thing: remember you made your implementation return error codes in the case of overflow or underflow. second thing: make phantomnation error out on stack error instead of silently ignoring errors. Does not fix problem. gee, here's a clue: initial directions tried check: 134537361. That huge number there? Should be a number between 0 and 6. Yeah, so. I wrote a few small functions to automate some of the more annoying array functions (add up all the values in this array! set all values in this array to x! etc) and as it turns out I'm dumb and they were very, very badly written, and they were the main problem, because they were overwriting other memory locations and. and they sucked.

So now the new path engine is technically correct, but it doesn't do what I want yet, really. See, the old version did a lot of replacement and walking over its own path, and those actions are forbidden in the new version. what this means: paths tend to be a lot more... pathlike. instead of usually clustering together, now they actually make paths. This is ostensibly a good thing, but since I had basically given up on the make_platform() function and was depending on make_path() to make clusters of tiles, that's bad.

But now I could probably just use, like. add a new variable, distance, that increments every push and decrements every pop. add another variable, limit, that limits the maximum value of distance. Something as simple as that should generate a uneven cluster that's centered around the path origin. LET'S SEE.


(the variables ended up named maxDistance and curDistance)

At this point I notice that I apparently broke sloping (AGAIN) while rewriting the path engine. GG.

Sloping wasn't so much "broken" as "oddly implemented". And it still is! The screenshot to the left is with a slope percentage of 100%. Basically, every time a tile gets popped, the slope data becomes inaccurate and it's not possible to recalculate slope data. This is kind of a problem. But not a really big problem, especially since I anticipate I'll edit it to actually, like, pay attention to the surrounding tiles instead of relying on a last_tile variable. So then you can have tiles sloping in more than one direction! Oh, the technical complexity of it all.

Now that all that is programmed, maybe I should, like, fix the tile joins once and for all. Then I can finally move on to, oh, ANYTHING ELSE jesus I have been working on the tile generation since... since a long time. maybe I should date these messages.

Sept 1st, 2007

This screenshot doesn't showcase any new and amazing features, but it's awesome because it's got three layers of height. ...not that you can tell. Just trust me, it was awesome. This path was around 230~ tiles, I think, with a minOverlapHeight of 32 (which is actually at the low end of visibility re: overlapping heights)

Correctly implemented the array functions so that they didn't break things. here is a question for you C programmers: what happens when you cast a character array to an int pointer and send that to a function designed for summing int arrays? ...yeah, essentially what you see happening in the previous post. gg me. But they're fixed now, so.

full explanation: in C, an array is basically a self-referential pointer— if you have the variable int numbers[10], the value in numbers is its own memory address (i.e., &numbers), so the main difference between int *numbers = malloc(sizeof(int)*2) and int numbers[2] is that the value of the pointer ≠ the pointer's memory address. This is only important tengentally, because I assumed since all you need to traverse an array is an offset, that all you need to traverse a pointer to an array is a offset. this is not true. You need to know the offset/size of the array, and you need to know its type. see the sizeof(int) up there? when I cast the character array pointer to int type, the pointer arithmatic I did assumed it was actually, uh, an int array, which meant that it skipped over values. (chars are always size 1, ints are usually 2 or 4.) so, for each value the function assigned, it skipped over one or three of the values, rapidly going off the edge of the array and overwriting other memory, causing havok. AND NOW YOU KNOW. the best way to make the functions I wanted to make is probably to use void pointers with an explicit size variable being passed to the function. But I lazed out and wrote different functions for each data type.

I'm getting ready to implement a sloping method that shouldn't suck. We'll see how that goes.

First screenshot using the new sloping method. note the complete lack of any angled tiles. whoops.

There's another screenshot I could post here, but it's very boring— I removed all the references to last_tile (because nothing uses it anymore!) and recompiled, and, uh. No tiles showed up. that's not good. And that is why you should pay attention when you remove old variables: last_tile = at2region(path, buffer); yeah i wonder what happens when you remove that line because you're scanning through removing all lines that reference to last_tile? ...the "at2region" is short for "add tile to region", and. yeah. you get it now.

more dumb mistakes:

if(bestmatch && abs(buffer->height[CENTER] - traverser->height[CENTER]) < abs(buffer->height[CENTER] - bestmatch->height[CENTER])) {
 bestmatch = traverser;

yes, that was the only place bestmatch was assigned to (it's initialized to NULL), and bestmatch is what determines how to slope a tile.

That's like better.

(50th screenshot, woot)

Okay, so. part of the issue was due to bugs in the program; the code for setting slope was:
buffer->height[(edge+3)%6] = bestmatch->height[(edge+1)%6];
buffer->height[(edge+4)%6] = bestmatch->height[edge]

instead of:
buffer->height[edge] = bestmatch->height[(edge+3)%6];
buffer->height[(edge+1)%6] = bestmatch->height[(edge+4)%6];

In short, it was kind of backwards. but even after I fixed those bugs...

...There are still problems. Part of the problem is due to when the sloping happens— at the time a tile is placed into the region, which means it's not going to calcuate slope WRT any tiles that have yet to be placed. (duh.) maybe placing the sloping action after the region generation has completed would make it work better...

...yeah, not so much.

But even though this new sloping method is just as inherently flawed WRT creating smooth maps, I think the uneven surfaces are a perfectly fine way to make a map. sometimes. the main issue is simply being unable to create a smooth map, no matter how good or bad the alternatives are.