Dungeon Illumination

I’m a big fan of Phillip Reed and have backed over a dozen of his Kickstarter projects. (He currently has 76!) He writes a lot of system-less supplements for RPG gamemasters. They’re primarily about adding ‘flair’ to a campaign and are fun to read.

His recent project, Dungeon Illumination, made me think about Fancy lighting for texture and effect. I missed the window to pledge but I’ll pick it up when it comes to DriveThuRPG. How a dungeon is illuminated sounds trivial but I put an enormous amount of effort into getting the lighting right because it really enhanced the aesthetic of the game. For the moment I’ve only implemented torches. At some point perhaps I’ll get inspired to add other types of light sources with different colors and properties.

New dice!

I have a t-shirt that says:

I have enough dice.

no one ever

I must live by this, because for whatever reason, I dropped $80 to buy these.

Oh, yeah. That’s a natural 20 on only my second attempt to make that video.

They are handcrafted, sharp-edged, liquid core RPG Elixir dice. I found them on Kickstarter in July 2020. Apparently I wasn’t the only person who noticed, because the campaign raised over $630,000. I just got a new job at the time and so decided to treat myself. Besides, they have a liquid core! Anyway, they arrived last week, so that only took more than a year. Still, I think it was completely worth it.

Red Matter Review

A colleague recommended that I listen to some past Oculus Connect keynote speeches, so I spent an hour (on 1.5x) watching John Carmack talk about Oculus and the future of AR and VR at OC6. It was remarkable not only because he appears to be speaking extemporaneously for 90 minutes without slides, but also for his impressive level of candor and insights into the industry.

Along with way, he mentioned Red Matter a couple of times:

… on graphics design, the advice I’ve been giving forever on mobile stuff about, “Don’t try to push too hard on the graphics.” Again, Red Matter is sort of an exception that proves the rule a bit where they pushed really hard on the graphics.

John Carmack

I own an Oculus Quest 2 and so decided to check it out for myself. This is a SiFi puzzle-solving quest on VR, as opposed to a fantasy RPG on Android, but I noticed a couple interesting parallels.

First, the visuals are amazing. 2D videos and images do not do it justice. The world is so immersive that on numerous occasions I felt a sense of vertigo. The graphics are exquisite and intricately detailed. I spent a decent amount of time just observing the scenery. I really felt like I was there. The game also did an amazing job with lighting. Recognizing that this is an order of magnitude removed from the lighting tricks I deployed for Mortal Wayfare, the implementation of shadows and various levels of lighting gave the visuals nuance and texture.

The mechanics of the game were also consistent with the limitations of the device running the software. As I pointed out in the Motivation section of my first post, the idea behind Mortal Wayfare was complex game play with simple graphics in order to work well with mobile devices. The feeling of floating through a moon base in a space suit (to the extent I can imagine what that is like) is consistent with the general locomotion of traversing a space in VR. So this works perfectly. Red Matter also anachronistically mixes in Soviet-style Cold War metal machinery with values, dials, levers, knobs and knife switches. These also work really well with the Oculus controller mechanisms and thus enable a tactile perception of naturally interacting with the equipment.

Then there is the game itself. The puzzles are fun, although not too challenging. The story is linear and a bit difficult to follow yet engrossing. The sound effects are well done. The entire thing can be completed in a few hours. There isn’t any compelling motivation for repeat play (it’s pretty much ‘one and done’), but the experience is worth it.

Fancy lighting for texture and effect

When I put together tiles as I started building the game, it was very exciting. Initially there were only a few (stone walls, stone floors, torches and orcs), but it was amazing to see them come together on the screen. After the initial euphoria faded, however, I was left feeling that the experience was a bit flat. I randomly rotated the tiles to create a little variety in the layouts, but the lighting left things feeling a little too uniform. The solution was to add some variation in intensity with a little flickers to simulate illumination from a torch.

How is it done? Every tile is an object with a local illumination variable which range from 0 (pitch dark) to 100 (maximum light). Every source of light, such as a torch, will then increment the values of the tiles within its range (lumensRange) by an amount relative to the inverse of the square of the distance to that tile, as stipulated by the Inverse Square Law. To make things feel a little more dynamic and “real,” I added a random amount of illumination (randomLumens) to simulate a flicker. This effect is primarily visible near the edge of the illumination radius.

for (int x = -lumensRange; x <= lumensRange; x++) {
	for (int y = -lumensRange; y <= lumensRange; y++) {
		int randomLumens = (flickerAmt != 0) ? rand.nextInt(flickerAmt) : 0;
		if (x == 0 && y == 0) lumensFlickerCache[x + lumensRange][y + lumensRange] = (lumens + randomLumens) / 4;
		else lumensFlickerCache[x + lumensRange][y + lumensRange] = (lumens + randomLumens) / 4 / ((x*x) + (y*y));
	}
}

To save compute, as well as control the frequency of the flicker, these values are not computed at every update, hence the lumensFlickerCache.

The next step is, of course, is to adjust the color effects (brightness, hue, contrast, saturation) of the tiles as a function of the level of illumination. As is frequently the case, someone on Stack Overflow put together a class with a collection of methods to accomplish all of this. To get the desired effect, I experimented with adjusting all of the effects as a function of the level of illumination, but in the end settled on brightness and contrast. As it turned out, adjusting the brightness was not sufficient to dim the tiles with low illumination.

// method from ColorFilterGenerator class
public static ColorFilter adjustColor(int brightness, int contrast, int saturation, int hue){
    cm.reset();
    adjustHue(cm, hue);
    adjustContrast(cm, contrast);
    adjustBrightness(cm, brightness);
    adjustSaturation(cm, saturation);
    return new ColorMatrixColorFilter(cm);
}

// method that adjusts the tile's color filter during rendering
public OverlayImage(Context context, Entities e) {
    super(context);
    entity = e;
    if (!entity.equals(hero)) { // normal brightness for hero
        int brightness = map.getBrightness(entity.getPos());
        p.setColorFilter(ColorFilterGenerator.adjustColor(brightness, brightness, 0, 0));
    }
}

Here is a short video from the early days of development. You can see the illumination radius and, with careful attention, should be able to see the flicker at the edges. It’s worth noting that I prioritized doing this over building the mechanics of the game, such as combat. At the end of the video you can notice that the orc does not hit back.

While this may seem rudimentary, it’s actually an aspect of the game for which I am the most proud. Not only do I love the way it looks, and the feeling it gives to the experience, but it actually took a lot of time and experimentation to get it to the point where it worked and looked right.

Remnant from the past

Back when I started this blog, I mentioned how in high school I wrote a simple 2D RPG on the Apple ][+. The story is naturally a little more complicated. At the time I only knew how to program in BASIC. This, however, was much too slow for rendering graphics. So I convinced my parents to drive me all over town looking for a bookstore that sold a book describing how to write code in Apple assembly. At the time, books like this were extremely difficult to come by.

I eventually got the book and proceeded to teach myself how to program in assembly. The Apple ][+ processor didn’t have a multiplication operation, but the book offered a handy subroutine that enabled this through a series of bit-shift operations. I also recall finding a piece of software (no idea where) that enabled writing assembly by entering the operator codes, as opposed to having to do it with hex. Lastly, I figured out how to call assembly routines from BASIC so that I could write the game logic using a simple language while delegating just the graphics operations to assembly.

Worksheet from high school

The assembly routine was past a set of coordinates and then proceeded to move the appropriate 2D images directly to the graphics memory. On the Apple ][+ there was a range of memory somewhere in the 48 Kb that was used to put pixels on the monitor. To complicate matters, the lines on the monitor were interleaved, ostensibly to make rendering more fluid. In any event, using the multiplication routine above, I figure out how to do it.

The happy news is that it worked! I even enabled a version of sprites so that water and humanoids looked like they were moving. I had mountains, trees, cities and oceans. Using the keyboard, characters were able to move up, down, left or right. Naturally, there were encounters with monsters. The battles were turn-based and took place in text. In the end, I had a simple game which vaguely resembled my beloved Ultima.

The sad news is that, with the passage of time, the magnetic materials on my cheap floppies degraded and the game was lost. To my regret, I never saved a printout of the code. That would have been cool to look at today. The only thing left is, regrettably, my memory.

With one exception! Recently my best friend from high school sent me my old Red Box with some D&D papers in it. I have no idea why he had this box, or why he kept it, but I was pretty delighted to see it. In there, I found a single sheet of paper from the game (inset).

As you can see, these are mountains. The 2D images where 3 bytes across (I can’t recall why they’re 7 bits, but I’m sure there was a good reason) and 34 rows, making the final image 21 by 34 pixels. My guess is that these dimensions were even multiples of the screen size. Anyway, while it’s difficult to tell, on the sheet I’m converting the pixels into hex which I then convert into decimal. I don’t recall why I wanted decimal.

Perhaps one day I’ll find a printout or more worksheets. I know that I had copious amounts of both, but they’re probably lost forever. Until then, however, I’ll have to be satisfied with this.

2021-11-27 update: Another page has been found! This one was in the same old Red Box but I didn’t notice it at first. It would appear to be a bitmap for the player’s character, translated into hex, with an idea for the world below.

Invitation only

I have had problems with spammers in the past. It is so annoying to be constantly inundated with robotic registrations requests. I guess the good news is that they are not in the site posting links for male enhancements.

In any event, as no one ever noticed, this website used to have a phpBB forum. It was a bit clunky and didn’t quite look like the blog, but it worked and had tons of functionality. Recently, however, I decided to migrate to bbPress. (The migration tool wasn’t great and I had to install a plug-in to customize the colors, because I didn’t feel like hassling with CSS, but I got everything over and it’s operational.) The reason was because my hosting provider only allows two DBs for my account level and I wanted one of them for something else. I didn’t know if bbPress would just use the same DB as WordPress, but turns out that it does. Win!

Anyway, for the past few years I’ve been wondering why the phpBB registration has been constantly hammered by spammers while the blog registration has not. I finally figured it out; my blog doesn’t have a registration!

I thought about opening the registration, but after doing a bunch of research on anti-spam plug-ins and moderation tools, I decided that invitation only is the best. Perhaps one day this blog will be large enough that I’ll want to invest in all that, but for the time being, anyone who wants in will just need to contact me and request an invitation. For what it’s worth I’m only giving invitations to people I know. Sometimes tiny communities are best.

No cs234 project

It was with a mix of disappointment and relief that I learned cs234, the final course for my Artificial Intelligence Graduate Certificate from Stanford, cancelled the project for this quarter. With the course going fully online due to the pandemic, the rational was to give everyone a bit of a break. That is perfectly reasonable given the work projects often entail, but it would have been pretty cool.

As such, development is once again suspended. (These Stanford courses are a lot of work, and there is a family and a job.) During the December sprint, however, I am happy to say that quite a bit of progress was made:

2020 GitHub Contributions
2020 GitHub Contributions
  1. A line of code was written – Just doing anything after 4 years is an accomplishment.
  2. Automated combat with enhanced messaging and logging – When I do get around to building a deep RL model to train the agents, this will be handy.
  3. Created the wizard class with wizard spells, including touch spell attacks – This one rounds out the fighters, clerics and rouges. I won’t be adding any new classes for a while.
  4. Group combat – Previously it was the ‘hero’ versus the monsters, but now two groups of combatants can fight each other.
  5. Charging, flanking and cover – These add a little more dynamic to the combat.
  6. Ferocity – Orcs just became much more challenging.
  7. Fixed a bunch of bugs – Always a decent idea.

So, what does all this progress look like? Here’s a little demo video set to O Fortuna from Carmina Burana by the MIT Concert Choir.

I’ll try to pick it up again in April, but we have to see how that goes.

A line of code has been written

The title’s deliberately passive voice is intended to comically understate the fact that it has been four years since I last worked on this project. Four years! I previously wrote about the delay, but the long story short is that life got busy and I got distracted with, arguably, much more important things. That being said, I am giving it another go. The renewed motivation comes from an unlikely source: Stanford University.

Over the past several years I have become quite passionate about AI, taking a number if different MOOCs, reading various book and pursuing some personal projects to explore the domain and learn the technology. One day in late 2018, gazing out of my office window at PARC, I spied the spire at the top of Hoover Tower and thought to myself, “I bet they have got some AI classes over there.”

Turns out they do. More specifically, turns out they have a Graduate Certificate in AI which offers a 4-course, 16-unit program of master’s-level instruction in AI. What could be better than that? A statement of motivation and a couple transcripts later, I was in. With a family and demanding full-time job I knew that pursuing graduate coursework would be challenging, but if I took only one course at a time, how hard could it be?

I quickly discovered that it could be very, very hard. Deep Learning (cs230) with Prof. Andrew Ng was the first course I took, which was probably a good choice. It was not a ton of work, until the final project, but the midterm was shockingly difficult. AI Principals and Techniques (cs221) is the only required course for the Certificate, so I took that next. It wasn’t too difficult, and I was more prepared for the midterm, but it was a lot of work and our final project was challenging. Then I took Machine Learning (cs229), again with Prof. Ng. It is notoriously one of the most difficult courses in the department and it lived up to its reputation. It was also an amazing amount of work and really tested my family life, but I survived that, too. In fact, we all did.

So what is this all about? For my last class I am signed up to take Reinforcement Learning (cs234) with Prof. Emma Brunskill. What does that have to do with Mortal Wayfare? Well, like all the courses, there is a final project. I therefore thought it could be really cool, for the final project, to implement RL within the game to ‘teach’ the actors (i.e. monsters and NPCs) to fight optimally. You can tell from game play that most RPGs use a simple rules-based decision engines to control enemies during combat. With a complex D&D-based system, however, constructing those rules can be complicated and the end result is often flat. I am curious to know what sort of dynamic and exciting combat I might be able to get by leveraging the materials from the course. To be able to do that I need to get the game back in working order as well as build a mechanism for fully-automated, repeating combat. After only a week, which I’m chronicling on Twitter, I am getting closer, but we will see how it goes. The course starts in January, so I am running out of time. Whatever happens, however, I will report back here.

In any event, unwilling to stop after course number four, I have already submitted my application for the MSCS program. Wish me luck!

I hate spammers

It’s been a very long time (over 3 years!) since I last wrote a line of code for this project, so my hiatus was obviously significantly extended. I’ll have more on that later, but I’ve decided once again to try to get back at it.

The first thing I did was log into the forum as an admin, only to find over 6272 registration requests. I’m sure that 100% of them are spam. Casually scanning the list, I’m seeing emails like toniagx18@ryoichi.hiroyuki73.kiesag.xyz and n.x.g.s.oft.wa.resolu.ti.o.n.s.co.m@gmail.com. These are not real people. I’ve been getting ~60 requests a day. ~44% are from a “.xyz” domain and ~39% are from “.ru”.

A long time ago (I think it was October 2018), I implemented the phpBB Q&A plugin spambot countermeasure. I choose a question that would not generate an answer if run on Google and would require a small amount of digging on the forum. Well, apparently sometime in July 2019 the spammers actually went to the effort of digging out the answer and programming it into their spambots.

I’ve now effectively disabled registration requests by requests by removing the answer to the Q&A, and it was easy enough to delete all of the requests from the admin panel, but I’m going to need to figure out a way to stop this. CAPTCHAs haven’t worked for a while. Email verification would probably help a ton, but I’d like a way to control registrations after the email is verified.

Also, I’m getting a slew of failed login attempt notifications as spammers try to brute force me admin password (I’m blocking IPs after 3 failure attempts) and and I still getting email spam even after changing the configuration to require being logged into email the admin (they might be guessing the email address).

This is going to require some thinking and research. I hate these people.

Holy hiatus

I’m sure nobody noticed because nobody is actually following this blog, which is fine. That being said, I just looked up my last commit, which was Oct 31th, 2016 – 671 days ago! During this time I have been busy with full-time employment, taking classes in ML and AI, playing around with deep learning, volunteering for a fantastic AI conference, running the books and making a presentation for an amazing non-profit and otherwise life.

In the back of my mind, however, there has always been Mortal Wayfare. I’ve fantasized about finding time to do everything from creating the wizard class (there are already fighters, clerics and rogues) to using reinforcement learning to ‘teach’ the enemies and NPCs policies for optimal decision-making. So why this post now?

Yesterday, in a burst of get-it-done-idness, I fixed the MW email and upgraded the phpBB to v3.2.2. It still needs some tweaks, but I’m now going to try to figure out a system to deflect the relentless spammers, who, for the moment, are the only visitors to this site. Then I’m going to download the repo and try to figure out a plan to, painful inch by inch, move this project forward until, one day, it’s the most amazing retro 2D Android turn-based RPG on planet Earth. If not, I hope to at least have something that is playable. That sounds like a lot, but actually, I don’t think I’m too far off.

Wish me luck, nobody.