We Be Jammin'

Still trying to move quickly through features, with an eye toward getting stuff up and running, even if crude.

Today, I finally wrote room-detection code. It's not very sophisticated, and basically treats walls like doors. Small openings/bulkheads are ignored, so rooms will pass through them. Unclosed rooms that adjoin empty space are also "rooms." However, each separate room has an object to track data, and it can set properties on the tiles it covers. I've even ported my tile-based gas exchange over to room-based gas exchange.

For the unclosed rooms, I've just added a boolean flag to say "yes, this room is unsealed." I'll see if it needs more than that later. For now, I'm thinking all it'll do is tell us whether to do a regular gas exchange or treat this room as an infinite volume into space.

In the process, I also finally fixed an AI pathfinding bug. Since there may be tiles that are both walkable yet unreachable, I needed to do a pathfinding check in the AI for such cases. If found, they'll bail out instead of setting it as a pathfinding goal.

I've also started implementing some rough code to swap out closed doors for open ones, and vice versa, when they're clicked in the crew sim mode. It's just for testing purposes, but it might be how I'll handle mode-switching items like doors. Just delete mode 1 and add mode 2 in exactly the same place. (Like NEO Scavenger's item mode switching.) The benefit of this is that I can piggyback on the ship's code which handles tile data for adding/removing parts.

It doesn't work yet, however. Doesn't crash either, though, which is weird. Monday, I'll have to see what's up, and then start pumping air into rooms to see if toggling the doors does anything.

Until then, have a good weekend, all!

Gas Expansion and NEO Scavenger Bugs

Continuing yesterday's thrust toward faster prototyping, I worked on some more gas expansion code today.

First, however, I had to fix something I broke in my haste. I accidentally made all UI overlays use a material for tinting, and it caused selection brackets and AI thought bubbles to be washed out. Splitting the GUI items into tile and not-tile allowed me to restore the different materials for different usages.

Once that was done, I made a few more tweaks to the gas expansion code, and I think it's functional enough to use. The next step will be tricky, though: making use of this simulation.

At first, I was thinking I should make an atmospheric processing unit to spew gas into the surrounding areas. But that isn't very realistic, as a life support system would have the unit pipe air into distant rooms and back again, with various ducts and filters along the way. And my gas expansion code seems to break down at long range. E.g. as soon as you get 15-20 tiles away from the source, the gas takes forever to expand.

This is a limitation of the expansion code, which uses a type of cellular automata code. It checks each tile's neighbors and averages the tiles' pressures so they are more alike. As a result, gas can only move so fast through a system, while in reality, it can move close to Mach 1 (and usually does).

More than a few of you have suggested steering away from per-tile calculations and using a room-based system instead. I've been resistant until now since it's a sometimes complicated problem to solve. However, this may be the straw on the proverbial camel's back. It's come up enough times that maybe I should just do it. Everything seemingly might use it, including gas expansion, lighting, privacy, and designated social usage (e.g. head, canteen, storage, etc.).

Before I go down that route, though, I need to do something about doors. Without them, there are no discrete rooms (unless you have a ship of ghosts or teleporting Trekkies). And doors...well, doors are a famous problem in games.

For now, I'm going to create a simple sliding door. 5x1 tiles in size, 3x1 opening. One version closed, the other open. I'll figure out some quick and dirty way to toggle the different modes, some way for pathfinding to cooperate with them, and then, some way for the game to figure out what a room is. Then, convert my tile-based gas expansion code to room-based, and see if that helps speed, performance, realism, and eventually, hooking up an HVAC/Life Support system.

In other news, I'm also trying to figure out an oft-reported NEO Scavenger bug. People say that Autosave is causing all kinds of issues when enabled.

The trouble is, I can't seem to reproduce it in my debugger. Hours of play on vanilla produce nothing. I've just tried an hour of playing with a mod, and still nothing. If anyone can help pin down the trigger, let me know! I'd love to get this sorted out once and for all.

Have a good night, all!

Gamejam Mode Activated

Okay, I've pulled the trigger on "Gamejam Mode." I wrote a script to yank out all my lights from the big ship layout, cranked the ambient lighting back up, and I'll just ignore that for now. And in it's place, I'll start banging out as many new features as I can. No polish. Just quick and dirty.

First up: ship atmosphere.

I want the ship's HVAC system to be something the player has to carefully design (and maintain) to keep occupants alive. And this means keeping track of O2 pressure on the ship. The simplest solution I can think of is to just have a per-tile pressure that gets smeared to neighboring tiles each update cycle (or some other time period).

To help visualize what's going on, and debug it more easily, I've hooked up the tile grid overlay to the pressure stats of each tile, and they tint green when the pressure is high, and red when it is low. And for testing purposes, tile underneath the cursor is set to 100% pressure as long as the right mouse button is down.

Here's a snapshot of it in action:


Gas propagating from a room's edge.

The white dot in the image above is the source of the gas input, and you can see it expanding outward from there. Walls stop propagation, and the gas slowly expands around corners.

One thing I'm immediately noticing is that this method takes a long time to fill a ship. (Remember 2x2 grid squares is one person in size.) I've been holding the mouse down for close to a minute in that shot, and the small room under the cursor is barely breathable. And this is with each tile updating once per frame.

Per-frame updates on almost 5000 tiles is pretty crazy expensive, so I may have to ramp that frequency down a bit. And that means even slower propagation.

Of course, maybe this is fine. It'd take a while to pressurize a whole ship. Heck, even pressurizing an airlock takes a while with modern tech. And doing so too fast is dangerous for the occupants. So maybe this will work?

In the spirit of gamejamming, I'll probably move on from this to the next thing, since it's "good enough" for now. Maybe the next thing is an air processor, or airlocks, or even AI reacting to lack of pressure. Whatever it is, though, it should be the shortest path from here to some playable system.

More on that tomorrow!

Another Business Admin Day

Not much to report in gamedev-land today, as pretty much the entirety of the day was spent filling out forms, mailing things, calling offices, and sorting out other business tasks. The good news is that the bulk of it involved the final steps to incorporating Blue Bottle Games, LLC. It's pretty much a done deal now, and I'm just waiting for the various parties to sync-up. (I.e. lawyers, government)

I did arrive at a decision last night about what to do next in the prototype, though. I think I'm going to switch to a sort-of "jam mentality" for a little while. Basically, start acting like I've only got days or weeks to get this thing playable, and start hammering out quick-and-dirty (QnD) solutions for all the pieces of the game.

So far, I have the following bare bones pieces:

  • Ship Building/Editing
  • Crew AI Simulation (Both needs-fulfillment and pathfinding)
  • Crew/Ship Inventory

And stuff I think I should knock-out asap:

  • Ship HVAC Simulation (atmo, temperature, humidity, hull breaches)
  • Ship Command Station that launches navigation UI and handles landing
  • Navigation UI
  • Landing on Planet/Moon/Base UI
  • Full Crew UI Portraits (Like party members in Baldur's Gate) to choose and view crew status quickly.
  • Ship Complex Equipment Simulation (e.g. reactor)
  • Airlocks (usable by AI)
  • Hire/Fire Crew
  • Load/Unload Ship Cargo (And fuel, O2, food, water, etc.)
  • In-flight Random Encounters
  • Surface Random Encounters

Total rough draft here. But I think that'll get the game to a more playable state. Basically a large game loop of designing the ship, loading it with crew and supplies, take-off, fly around, deal with encounter, land at destination, repair ship, repeat.

I'll sort out lighting, fancy graphics, AI emotional realism, and all that other nonsense later when there's more game in place :)

Tiles, Lighting, and Stress-Testing

Hey Folks! Hope everyone had a good weekend. Not a lot to report from mine. Mostly a quiet one, which can often be just fine!

I continued pushing the limits of the ship editor today, finishing up the largest layout yet. It's the same 80x50 tile ship from last week, now with floor grates and lighting. As of the end of the day, the ship has (roughly):

Wall Tiles: 750
Floor Tiles: 500
Lights: 80

And we're definitely over our limit. Framerate is lucky to be ~30fps when zoomed into a room, and down near 15-20 when viewing the whole ship. I was able to find and fix a few bottlenecks and performance hogs in my scripting, but I think this new limit is rendering. Specifically, dynamic shadows.

80 lights casting shadows is a lot. Probably more than reasonable. I can see there being more lights on a ship in practice, but not all of them need to cast shadows.

Even so, I'm not sure there is much I can do to improve this number. I've tried reducing the light ranges, which helps a lot. But it also undermines the point of the lights: illuminating the rooms. Turning off shadows works, too, but then we have light spilling into unlit rooms and around corners. None of these things are terrible, they would just mean giving up nice lighting.

On the other hand, this is good info. Part of the reason I spent time building a large ship layout was to see what pitfalls I'd be facing. And now I have a better idea. I can also see how zooming and scrolling around the ship feels, which is currently tedious. (Though, made worse by low framerate.)

I'll have to give this some thought, and see what my options are. E.g. go back to larger tiles, no dynamic lighting, or some sort of clever lightmapping/culling/quadtree magic.

Grid System, and Performance

Hey Folks! As mentioned yesterday, my brain was seriously losing traction on the AI task. By midday, it was getting to the point where all my energy was being spent keeping focused, rather than doing productive work. This usually means it's time for a change of task.

So today was all about the grid system. I resumed yesterday's beginnings of switching the game from a 32-pixel grid to a 16-pixel one. I'll still be keeping the 32-pixel crew for now, though, because my main motivation for the smaller grid is to have more room for ship layout detail. Namely, thinner walls and angled/curved sections.

It took most of the morning to sort out the last of the 32-pixel settings and make it work at a smaller grid size, but I eventually did it. And using a new set of smaller tiles with angled pieces, I was able to get this:


Whatever ship could use this type of layout? Hmm...

It's not a perfect circle or anything, but I think it gets the point across. And nicely shows that non-orthogonal shapes are possible.

In theory, one could even go a step further and make perfectly curved pieces if they wanted. But the elegance of this type of layout is that it only uses a handful of modular tile types. Basically, a 1x1 box, a 1x1 wedge, and a pair of mirrored 1x2 wedge shapes. And using these to make 12-sided rings means each ring is cocentric with room to walk between each.

It's not without issues, though. For one thing, a crew is still 32x32, so it takes up 2 of these tiles. And when it walks close to a wall, it clips into said wall. I think this can be solved by making the wall block pathfinding on grid squares that border solid wall, though.

Another issue is performance. I had a total of 7 of these cocentric rings in a ship's layout at once, plus some decorative outer shapes. And the overall ship dimensions were 80x58 tiles. Assuming this was a working ship, this would mean wall tiles, floor tiles, ship's equipment and hardware, and lighting. I'd estimate I've got about 1000 tiles in this file, and that's just walls. And performance is certainly struggling. I get about 45fps when I zoom out to see the whole thing.

And this is just in building mode. I was kinda hoping to have AIs doing their thing, and physical simulations going on to handle power, air, water, and other ship systems.

That said, I have barely bothered to optimize anything yet. I found a memory leak by accident, and was able to fix that. And there seems to be a bug with the way the tile grid overlay works, because hiding it kills framerate, and showing it again fixes framerate. (The opposite of what one would expect.)

And there's probably some optimization to be had in simulating periodically, rather than continuously. The AI already does this by ticking once per second, instead of per-frame. And maybe the ship simulator can do the same.

Anyway, I feel like today's major accomplishment was a few things: proving that a non-square layout can be drawn, revealing the limits of performance, and getting a view of what a smaller grid looks like with a larger crew sprite.

More to come next week, but this was at least a high note to end on! Have a good weekend, all!

A Bit More AI Before Switching to Ships

I'm starting to burn out on this AI stuff. I spent another morning looking over potential interactions, cribbing example dramatic interactions from summaries of Hamlet, Dr. No, and Casablanca. I was planning on comparing this to my existing list of "payloads" as well as existing interactions, in the hopes of grouping as many as possible into a short list for easier payload creation.

Somehow, doing this put a bullet right through my motivation. Which is weird. I was feeling really good about this process last night. I think I reached a point where I wasn't sure what to do next.

I decided to turn back to the code, to fix up the half-edited changes I was making to support this new master list of stats, needs, and ticks. It involved changing the incremental (integer-based) condition system into a fractional (floating-point-based) system. This allows me to say the blood restores at a rate of 0.0006 liters per hour, as opposed to 6 liters per 10000 hours as I would if decimals weren't allowed. Plus, I can have smaller modifiers/buffs this way.

I got that change made, then ripped out an old feature that added a list of new conditions each time an existing condition incremented (since they don't increment anymore). Plus, I found and fixed a few bugs that regressed somewhere along the way (mostly involving pathfinding breaking the reply logic).

After all this, I still balked at doing any more emotional/drama design. I think my mind is just spent.

So I switched to graphics for a bit. I've been meaning to try a new set of 16x16 tiles to go with my 32x32 crew. The artist I worked with had some compelling reasons to try smaller tiles than 32x32, and what's more, a smaller tile size would allow me to do more detailed ship layouts. (Basically, more granularity for edges, curves, and angles.)

I hacked together some 16x16 tiles for walls, diagonals, and floors, and modified the existing toilet, fridge, and other items to work with the new grid size. I even found a few places to spruce up the furniture, by adding heights and shadows to them. (I think anyway. Let's see if it works.)

And now, I'm in the process of changing the game's grid size. Which, as it turns out, is not as simple as I thought. I must've hard-coded more pieces than I realized. But, this is way easier on the brain right now. Maybe I just needed to switch from conceptual mode to spatial mode, because I feel much fresher on these problems.

Didn't get it finished yet, though. I'll have to resume tomorrow morning. Until then, have a good one!

AI Conditions and Interaction Standards

Today was all about the data.

The first part was spent reviewing conditions from NEO Scavenger for those that would apply to the new space game. Things like nausea, diarrhea, some diseases, headaches, and the various physiological stages such as hunger, hypothermia, etc. These were extremely handy in NS because I could have standardized symptoms and other effects used across multiple situations. Diseases and fumes could both apply the "headache" condition without worrying about double-penalizing or maintaining two sets of headache data.

I have a nice, long list of discomforts now :)

I also converted most of the NEO Scavenger stats and physiology rates (blood restore, healing, temperature, insulation, etc.) to IS units for use in the space prototype. This way, I've got a lot of the same simulation data and algorithms already done and can use it right away in the space game.

Plus, I did a little code-digging, and was able to verify that AI would remember secondary effects of an interaction. At least to a degree. Things which immediately affected an AI as the result of an interaction (e.g. a headache, or being winded) would be logged, but things which took place later (e.g. gastroenteritis, increased metabolic rate leading to hunger) wouldn't be logged. This actually makes sense, as we tend to disassociate results that are too far removed from the cause. (See: smoking, drinking, overeating, making babies.)

This discovery means that my idea yesterday might actually work. Namely, that I can make standardized emotional "payloads" for most interactions. I could have, for example, a standard "praise" payload, which makes an AI feel more self-assured and well-liked, more socially-fulfilled, and a bit closer to needing privacy and altruism. Then, any of the interactions that fall into that category could just point to "praise" instead of having to copy data from one to the next, and update them all in case of a data change.

This approach was further reinforced as I reviewed yesterday's work and started noticing patterns in "payloads." While not exactly the same, most of my interactions seemed to fit into a smaller number of categories with very similar benefit/drawback patterns. So far, this list consists of:

  • Defy
  • Threaten
  • Socialize
  • Insult
  • Praise
  • Comaraderie
  • Flirt

And probably some form of commiserate, surrender, and comfort, too. Probably still more as the list of interactions grows. And so far, most of these have one set of values for the subject, and another for the object. (I.e. "us" vs. "them" in an interaction) This will make the data a lot more manageable and consistent, and if I really need it, I can still tweak individual interactions with plus and minus extras.

Once I have this done for the emotional interactions, I can follow-up with the mixed social/physical ones such as push-ups and toilet use, and the complete socio-physiological picture will be in place.

Then, I think I need to look into the AI conditions system to see if I can get it to support floating-point value changes, instead of simple integers. Ints were sufficient before I started having things like blood and immune system restoration rates, which are fractional values. I could try multiplying those rates by 1000 to shift the decimal point, but even then, adding a RateBloodRestore modifier of +25%, is hard to do if the base rate is non-divisible by 4. We'll see how doable that is, though.

Anyway, I feel like data made some significant steps forward today, despite not having much to show for it. Hopefully, getting this into the game will prove pretty easy, and I can start testing the simulation again soon!

Stats and More Stats

Hey Folks! Still plugging away at a complete stat list for AIs. And let me say, this is getting complex:


Maybe too complex? Nah!

In the above screenshot, the rows are individual interactions (chat, snub, eat, perform trick, etc.), while the columns are stats. As mentioned yesterday, there are now three types of stats. Needs are things like emotional needs, oxygen, and hydration, stats are things like encumbrance, radiation exposure, and poison, and ticks are rates at which each of these needs/stats change over time. The selected columns on the right are the ticks.

The list has expanded slightly since yesterday, and we now have StatAtrophy and NeedHygiene (both of which will be important on long space voyages in a confined area).

As you can probably tell by the coloration, I'm about 3/4 done with choosing values for the list. And the left-most highlighted column shows the net positive or negative effect of the interaction. So far, it seems like a pretty good spread of positive and negative outcomes, so emotions should ebb and flow as AIs do their thing.

I've also made the interactions a bit more modular, as many of the petitioner->granter chains can be broken into component parts and mixed and matched. E.g. "Insult target" is a perfectly valid response for a number of interactions, from chatting to flirting, and even offers to help. This way, we should start to see more variable interaction chains and get more data re-use.

Also, as mentioned earlier, this expanded stat list gives me a chance to tackle some of the more mixed emotional/physical interactions. Things like exercising, sleeping, etc. And as I'm discovering, it raises a lot of interesting questions.

For one thing, I can go two different ways when applying effects of a physical interaction.

One way is to apply stat changes directly, like NeedRest increases when exercising, while NeedAchievement decreases. This has the benefit of working within the current AI decision-making code, since the AI is carefully remembering the direct effects of an interaction for future reference. However, the down side is that the effects are more or less instant and permanent. They get flicked on like a switch, and decay over time with normal AI rates. Not very natural. Also, it means a lot of redundant data as interactions that have similar effects must repeat similar data.

A second way is to make an interaction apply some sort of condition that contains several other conditions. In the above example, maybe the exercise interaction applies "exhausted" and "inspired" conditions, the former affecting NeedRest and the latter NeedAchievement. Doing it this way means those "exhausted" and "inspired" conditions can disappear over time, like temporary buffs. And other interactions with similar effects can just reuse those, making data management easier. The down side, however, is that the AI probably won't remember them as effectively, since they're setup to remember direct effects.

There are ways to make AIs remember things better in the second way, but I've been noodling for so long I'm starting to get antsy. I haven't made visible progress in a while, and my inner project manager is saying "put this on the back burner, or cut it." I feel like I've been refactoring over and over. Of course, a lot of this is the result of seeing how the data is actually being used now that there are more mechanics in place, as compared to the original design which was more theoretical.

I dunno. I'm going to have to take a hard look at this soon. But I might be close enough to finishing this interaction iteration to see if it makes progress, and decide after that.

NEO Scavenger Mobile Progress, and AI Work

Hey folks! Hope everyone had a good weekend. Ours was quite busy! One might say it filled our "NeedContact" and "Need Friendship" stats nicely :)

Back at work, Tiago sent me his latest progress on the mobile port of NEO Scavenger. Have a look!


Ominous reflections not included.

Not bad! It loads the main screen, options, etc., and can start a new game. The player can select skills, and then load an encounter. Though, currently it's loading the wrong encounter (and if you look carefully, you'll notice the next encounter is even wrong-er :)

Also, there are still plenty of smaller issues to sort out with rendering, GUI sizing, etc. But this is an awesome step forward. I was able to wander the hex map, and this is even running on my old, crappy cheap-o tablet. So there's hope that it will work well for many users! Nice work, Tiago!

Back on the space prototype, I think I'm finally starting to make sense of my AI stats. Last week, we got a sneak peek into the full list and naming convention for AI stats. And I think I was finally able to finish standardizing them.

Basically, all stats are good when lower, and bad when higher. And depending on the concept, some are "needs" while others are "stats."

"Needs" are things which, if we have too little, spell trouble for a human. And they're easier to explain as a deficit rather than an abundance. Examples of "needs" include achievement, contact, and hydration.

"Stats," on the other hand, are things which are harmful in large doses, and are easier to explain as a positive than a lack thereof. Examples of "stats" include encumbrance, radiation, and infection.

So far, I've been able to classify all of the numbers into one of those two categories. And as mentioned already, all of them are on a scale where more is worse. One wrench in the works, however, is body temperature. This is an exception where too much and too little are problems. There are some different ways to approach this, but I'll have to give this some thought.

Also, I'm starting to realize there may be a "third" category to track. "Ticks" or "rates." Certain things about humans increase or decrease over time, and these rates change based on conditions. Examples of this include the rate at which we generate body heat, metabolize food, consume oxygen, etc. The above "needs/stats" measure how much we've lacked, but if we're running a marathon, for example, the rate at which we lack oxygen should be faster.

NEO Scavenger already had this with things like "m_fImmuneRestoreRate," and "fWaterConsumptionRate," so I may just be able to copy a lot of this over. (Both values and code/logic.) There are some benefits to having created a survival simulator before a spaceship crew simulator :)