Sunday, May 10, 2020

Mountains

Today has been one of the longest and most arduous and frustrating days of programming I can remember. I started with doing something with the sprites. I failed to find a good way to find a local function pointer. I'm sure it's possible but I just gave up and used a switch... this sort of thing is about the alchemy of the language and it's something I've never done before.

The hard part though was what I expected to be the easiest. I started by adding the code to hide or show adjoining walls to blocks, very simple logic, and this just refused to work. After a lot of experiments, mostly hiding north and south walls, revealing the east/west ones which should have been culled, so I could peer inside, I decided that the map was expecting a block to the right or below (east/south) that wasn't there yet but would be, so I reverted to using 'discovery' rather than 'visibility'. Visibility is whether the block is actually visible, and discovery is whether your team has discovered it, so that is a bit-mask...

That was after I realised that I was checking the block bit-mask rather than the block type/class bit-mask, but I digress, after an hour or two I started to add a new part to add new walls when some were revealed by explosions or other block changes, then I realised that the discovery problem wasn't that at all. I could sense the 'top' code sniggering at my attempts, because all I needed to do was emulate it. Eventually I got it working, but then realised that, like the 'top' code (the code for rendering the tops of blocks which had been there for years) I really needed to either delete or restore the faces of neighbouring blocks there and then, so it would update based on neighbours, and their current visibility or not is not important: if they are visible now, they and all of their visible neighbours will be correct, and invisible ones will be corrected when shown.

The code looked really messy by this stage because the blocks knew about their place in the world via ugly global coordinates which needed to reference a global level object. What I really needed is some simple pointers to neighbours; north, south etc. and as it happens, this is what the above and below blocks used to have for, yes, the 'top' rendering, but I deleted them, wanting a more global view. Bah!

So, at 4pm or so, I added these pointers back, restoring and simplifying everything into simple lines. Then; it all crashed. I just couldn't get the game to run past the equipment screen. I flagged everything new off and it still crashed. I was in a panic. I couldn't remember what I'd switched on or off or why... so I followed standard procedure: keep turning off until it works, then gradually turn on until it doesn't.

I traced it down to the 'top' printing, something that worked fine a week ago and has been stable for years... I couldn't work out why. There was a possible null pointer, but that should never, it seemed, ever be null. But it was. I made it print when it was... and where. The numbers traced the outline of the equipment screen map... it took a lot more tracking, over an hour, to find that the map was erased from the bottom up, which nullified the pointer below. The thing is, that should have always happened, for years... I just could not and still cannot work out why it ever worked before!

After that, I had pointers to the six faces. It was relatively easy to put everything in and it looks much neater and is much easier to read too, and no nasty co-ordinates. The only downside is the doors... the tiny 1% that is causing a problem.

The doors, for some reason, are not merely two blocks, but one with an open/closed switch. This causes all sorts of sillyness; the doors have to change height from 2M to zero whether open or closed, and change opacity, and many of the class level descriptions of them need to be local just to allow them to change this stuff... all annoying... it's not like the doors even look like one block or have any fancy effects... they just vanish and, visually, appear to transform into a floor. I don't know why I did it that way. Perhaps, I will find out because I must now change these because the status about occluding side walls is too big to be made local; that (like height, really) needs to be class-level information. I think a new structure is needed for doors, merely a two pointers to two block types for open and closed. That should be enough for any door switch to know what to do.

At least now, I can accept humility, and expect that this job, an hour at most, 20 minutes if lucky, could take all day or more... but I have to do it. It has to be as good as I can. It has to be right, bug free, perfect, with every part doing exactly the correct thing. Every error or anomaly is ruthlessly traced and understood in its entirety. This is why programming drives me crazy.