Weekly Update – March 18, 2022

The big news this week is that the Quick Switch Slots and Cell Action Indicators are done. I started on these exactly one month ago. They shouldn’t have taken this long to complete, but did because I had less time than usual over the past month and I underestimated the effort to code the features. They are two of the remaining three major UI features that need to be added (the third being Cell Context Menus).

  • Completed Quick Switch Slots. Quick Switch Slots are similar to a hotbar, but are used to quickly change weapons and other held equipment, and enable automatic switching of melee and ranged weapons based on the target’s distance from the player.
Quick Switch Slots
  • Completed Cell Action Indicators. Cell Action Indicators tell the player what will occur when a particular cell is left-clicked. An icon representing the action the player will perform is displayed when the cursor hovers over a cell. If the player first needs to move closer to the cell to perform the action, the Cell Action Indicator will display two icons, one for movement and another for the action to be performed.
Cell Action Indicators
  • Player input and action refactoring. The above UI changes touched one of the uglier parts of the code that is responsible for triggering in-game actions from player input. In the interest of finishing this game, I’m being more selective on rework. However, some rework was unavoidable this time. Previously, there were Player Actions (actions mapped directly to player input, which could translate to in-game actions such as moving the player’s character, or UI actions such as opening the Inventory Panel), Action Types (in-game actions), and Actions (instances of Action Types, but still defined as separate classes for each Action Type due to the evolution of the code). It was messy and redundant. I renamed Player Actions to User Commands, which helped me mentally differentiate these from in-game actions. I added a minimum and maximum range attribute to each action so that the Cell Action Indicators can determine whether the player’s character has to move in range of an entity before interacting with it, replacing some hard-coded logic that only worked in certain scenarios. I standardized User Commands and Actions behavior. I moved some methods into more appropriate classes. I fixed all the little issues that cropped up from the changes. I even found a couple of bugs that predated the recent changes.
  • Wand of Magic Missile. The Wand of Magic Missile was primarily created as a proof of concept for getting wands working, but will most likely stay in the game, and perhaps be a starter weapon for the Wizard class. I’m still deciding how to configure wands in terms of resource consumption. I’m leaning toward unlimited charges, no cooldowns, and eventual destruction from use. Wands will have to be underpowered to support this.
Wand of Magic Missile

Next week, I’ll start working on the final remaining UI feature: Cell Context Menus. Right-clicking a cell will display a Cell Context Menu that lists all of the possible actions that can be performed on the cell (left-clicking performs the default action, as indicated by the Cell Action Indicator).

Weekly Update – February 11, 2022

UI finalization, which started two weeks ago, continued this week. Some questions that have been open since day one, such as available equipment slots, are getting answered because they’re dependencies for completing the UI.

  • Decided on equipment slots. This is finally done. It was one of those things that I overthought. My original philosophy was to keep things simple and have a single armor slot, and some slots for accessories like rings. My thinking changed as the depth of the game expanded. The final equipment slots are Armor, Helm, Gloves, Boots, Necklace, Rings (2), and Shield (note that weapons are handled in a different manner, to be explained in a future post). Adding the new slots to the actor inventory was easy. I had to do a little bit of rework because of the rings. The original logic assumed that there’d only be one slot per equipment type.
Equipment slots and new items
  • Updated damage absorption and evasion calculations. With multiple pieces of equipment potentially affecting damage absorption and evasion, I had to update the combat calculations. This wasn’t difficult, but balancing got more complicated. I now have to consider mixed pieces of equipment, partial equipment, and class restrictions on each equipment type.
  • New items: Leather Gloves, Leather Boots, Leather Cap, Wooden Round Shield, Wand of Magic Missile, Necklace of Protection, Ring of Invisibility. These were created to test the new equipment slots. They may or may not make it into the final game. In particular, the Ring of Invisibility, which grants invisibility as long as it’s worn, is too overpowered.
  • New map elements: Mushrooms and Crystals. Caves are in need of more variety so I added glowing mushrooms and crystals.
Crystals
  • Indefinite status effects. Previously all status effects were temporary; after a certain number of turns the effect disappeared. Now, status effects can last indefinitely. This was needed for the Ring of Invisibility and will be needed for all equipment that gives the player a status effect while worn. 

Next week, I’m implementing the quick switch slots for weapons and light sources as part of the UI finalization.

Weekly Update – February 4, 2022

It was one of those weeks where most of the time went into thinking rather than doing. Hence, there weren’t many concrete achievements. The thinking was around UI design, specifically how to quickly switch between different weapons, how to automatically use ranged weapons for distant enemies and melee weapons for nearby enemies, how to handle torches, and equipment slots. I wrote out so many different solutions. None of them were perfect; they each had pros and cons. I think I’ve chosen a solution but need to consider how the solution applies to all the possible scenarios. The solution involves an additional hotbar that lets the player quickly change melee weapons, ranged weapons, and ranged weapon ammo, and logic for when the player clicks on a cell that determines whether to use a melee or ranged weapon. It seems sound to me, but only feedback from other players will confirm whether it is intuitive and user-friendly.

I added a few new map elements, which is something I’m trying to do every week to have a wide variety by launch. As always, there were some bug fixes too.

  • Witch’s Chamber. The Witch’s Chamber map element places a cauldron, a witch, and some bookcases and tables in a room. The witch is brewing something in her cauldron, which emits a blue glow. I need to give the witch some abilities. I’m not sure what I’ll do with the cauldron.
Witch’s chamber
  • Summoning Chamber. The Summoning Chamber map element places a summoning circle, demon, and summoner in a room. The summoner has just recently summoned a powerful demon in the summoning circle. I need to build out the demon’s abilities and the summoner’s AI (the summoner lets the demon do the fighting and avoids the player).
Summoning chamber

Also, here are a few examples of the objects added last week:

Pots and varied rubble
A rug
Grass and statues

Next week I’ll implement the UI features I spent this week designing and try them out in the game. This is the next item on the critical path. 

Weekly Update – January 28, 2022

It was a solid week with lots of smaller, but important, improvements and fixes. I added a few new map features and need to make sure that I do this every week, because map content variety is one of the key aims of the game.

  • Fibonacci weighted randomization. This is an extension of the existing weighted randomizer that adds the capability to automatically set weights based on fibonacci numbers. I created this because I kept needing a random number generator where each outcome was less common than the outcome before it, and the number of possible outcomes was variable. Fibonacci numbers naturally worked for this. I start at the second 1, so the outcome weights are 1, 2, 3, 5, 8, 13 and so on, and the weights are assigned in reverse order so that the most common outcome has the largest weight. I use this primarily for rarity-based random selection.
  • New sound effects. I added sounds for hitting webs, stalagmites, and bones and an ambient looping sound for braziers. The physical material-based sound effect configuration, in which the sound played is based on a combination of the weapon used and the physical material of the target, is becoming unwieldy. I will probably remove weapon-specific sound configuration and create a global configuration based on combination of weapon damage type (slashing, chopping, bludgeoning, piercing), weapon physical material, and target physical material.
  • New Map Elements. Added statues, grass, pots, and rugs.
  • Removed redundant Map Elements. Some common patterns emerged as I continued to create new Map Elements and it became evident that I could combine some of the elements. For example, there were dedicated elements to place a single actor such as a fountain or a shrine. The only difference between the elements was the actor. So, I removed these variations and created a single Actor Map Element that takes an actor type as a parameter.
  • Rubble tile variations. I got really tired of seeing the same rubble tile everywhere. I bought the Oryx 16-bit Sci-Fi sprite set primarily because it has two more rubble variations (that’s how much I like making my own art). The variation helps, but some of the rocks are too big. I’ll live with it because all the artwork is going to be replaced anyway.
  • Player corpse. When the player dies, there’s no visible indicator beyond the “Game Over” message. So, I made a corpse sprite (for the Knight; I still need to do the other player classes). As with the enemy corpse sprites I made, I used a simple process of rotating the sprite 90 or 180 degrees, slightly shearing it, and dropping the blood sprites above or below. The results are ugly but serviceable. Now when the player dies, a corpse will be displayed.
  • Animated Bones improvements. Animated Bones, which are piles of bones that come to life when the player approaches them, were improved. Now they animate when the player is diagonally adjacent to them and when the player attacks them from a distance with a ranged weapon. 
  • Equipment hotbar design. Over the past few weeks, I’ve been thinking a lot about how melee weapon switching and ranged weapons should work from a UI standpoint. This week I finally figured out how this should be designed. I still need to implement the design to validate it.
  • Added unit tests for select utility classes. I practiced some test-driven development this week, which is a rarity. I found some issues with the Fibonacci randomizer right out of the gate, so the new unit tests already paid for their effort. 
  • Bug fixes. Fixed ~10 issues that directly affected gameplay, which felt very satisfying.

Next week, I expect to mostly work on UI, specifically the melee and ranged weapon hotbars.

Weekly Update – November 20, 2021

I put limited time into game dev this week, and a large portion of the time went into some difficult code design/architecture thinking rather than coding itself.

  • New Map Elements: Library, Alchemy Chamber, Armory. These are new room types that contain objects arranged in simple patterns (tables, bookcases, weapon racks) and applicable random assortments of items. I want to improve the variety of the object placement patterns. I sketched out some patterns for the library (below) to visualize the end result and work backwards to develop the generation logic. It got me wondering about the feasibility of an alternative approach: training a machine learning algorithm to generate patterns from a set of example patterns. I’m going to research this next week.
Library patterns
  • AI 2.0 Design. Last week’s addition of AI states and actor responses to game events has necessitated more rework than anticipated. The original AI was player-centric; other actors only cared about what the player was doing. The end goal was always to allow actors to respond to a variety of events, but I limited the initial implementation to player events for simplicity. I’m now modifying the design so that actors can potentially act on any event. This requires some optimization as well because, for each event, a check needs to be performed to determine if the actor notices the event. It’s further complicated by the fact that each event may be detected by sight or hearing.

Next week, I’m continuing working on the AI 2.0 coding.

Weekly Update – November 12, 2021

It was a solid week.

  • AI State and Game Event Detection. One of the planned Release 3 features was to display icons next to enemies based on whether the enemies had seen the player. In addition to displaying the icons, I needed to fix some long-standing AI issues that cause enemies to react too soon, or not soon enough, when seeing the player for the first time. I also needed a way for enemies to respond to events other than seeing the player, such as a door opening, and to respond to events that are heard but not seen. To handle all of this, I implemented a simple finite state machine to manage enemy state. I added listeners to enemies that receive all game events, determine whether they are able to perceive the event, and trigger state transitions based on perceivable events. The solution is working well with the first set of test cases; I now need to apply it to all game events.
  • New Decor Map Elements: Braziers, Bookcases, Tables. These Map Elements place these objects in logical patterns (for example, in corners, in a grid, in a rectangle, in the center) in a specified area, typically a room. They are used by different room types such as Libraries and Shrines.
  • Procedural generation improvements. I changed the basis for some enemy/item quantities from a percentage chance per cell to a random number within a range. This prevents situations in which a large room has too many enemies or items. I reduced the number of combat encounters in a level (too much combat nade the game overly difficult and tedious to play).
  • Finished implementing treasure chests. Chests contain random or specific items now and chest contents get transferred to inventory. It wasn’t as straightforward as it sounds. Some odd bugs were introduced (and subsequently fixed). For example, the player started getting two copies of each item in the chest. I spent a few hours trying to figure out what was happening. It turned out that when the chest changed from an open chest to an empty chest in the process of taking the contents of the chest, the chest was being destroyed and dropping its contents (routine behavior).  

Next week, I’ll finish the AI State / Game Event feature. I’ll add a few more Map Elements as well (my goal is to add at least a few each week).

Weekly Update – October 30, 2021

Thanks to a very rainy weekend and a day off in the middle of the week, I got a lot done this week. The focus remained largely on procedural map content generation.

  • Added a debugging console. A key press displays a prompt. Typing the name of an entity (actor/object/item) creates an instance of the entity in a cell near the player. It’s a time saver because I no longer have to look for an instance of the entity on the map. Why didn’t I add this sooner?! I will extend it in the future as needed.
  • New actor action, Transform, that transforms an actor into another actor. This is used to animate a pile of bones as a skeleton and replace a treasure chest with a mimic.
  • New object, Animated Bones, that changes into a skeleton when the player comes near it.
  • New Map Elements: Animated Bones Area, Debris Area, Storage Cluster. Animated Bones Area places a few piles of animated bones in the specified area. Debris Area adds rubble and other debris to an area. Storage Cluster places storage objects (barrels, crates, etc.) in clusters for more natural-looking placement.
  • Added more Treasure Area Map Element variations. Treasure Areas can be actively used or inactive (abandoned / forgotten), and looted or not looted. The combinations of these parameters produce different effects. For example, an abandoned and looted area will have only empty, open chests, with cobwebs and debris. Conversely, an active, not looted area will have all of its treasure items and chests intact and no cobwebs or debris.
  • New enemies (partially): mimic, gelatinous cube, cultist, bandit, witch. The Unity prefabs, animations, and definition data were created. I still need to add different behaviors for each. I also need to incorporate some of them into Map Elements. As of now, the mimic can appear as a chest in a treasure room, and some shrine rooms may contain cultists.
  • Combat modifier visibility. The cell inspect panel now displays combat modifiers applied by the cell. For example, a cell with rubble, or a cell that is an open door, will modify the chance to hit and/or chance to evade modifiers for any actor occupying the cell.
  • Procedural generation tuning. I fine-tuned some parameters such as probability of caves, numbers of objects and enemies, and non-combat vs combat Map Elements. The final values used for each map are still randomly generated, but the ranges of possible values were adjusted. There’s still a lot of work to do in this area. Some rooms are way too big, or filled with way too many enemies. Some maps have too many rooms, and some don’t have enough.
  • Bug fixes, mostly around map generation. In the course of troubleshooting an AI bug, I discovered that actor tracking was extremely inefficient. Each turn, each actor was checking to see if it could see every other actor. This was occurring because the visibility check was executing before the check for whether the actor was tracking the other actor.

Next week, I need to build expand the utility class responsible for getting cells in different patterns (e.g. room corners, rows/columns, rectangles) to accelerate the creation of new Map Elements that place objects in patterns (e.g. Library, Armory). I also plan on building out the behaviors for the new actors added this week.

Weekly Update – June 25, 2021

  • I stuck to the plan this week (for a change) and finalized the Release 3 features. I’ll publish a summary in next week’s post.
  • Added cell-based status effects. These are effects that are added when an actor moves onto a cell and removed when an actor leaves a cell. An example is a Darkness effect that limits the player’s visibility. This builds on the existing capability to add status effects by using an item or interacting with an object. This feature was unexpectedly difficult to add; a lot of the status effect code and Unity configuration needed to be reworked.
Darkness cell effect
  • Room features. Each room has a room type that determines what’s in the room. For example, a Shop Room contains a shop and a Treasure Room contains treasure. I needed to be able to apply different features to a room to do things like placing a trap inside of a treasure room. I added a base RoomFeature class and some child classes like ShopRoomFeature and TrapRoomFeature. This makes it possible to mix and match different features can create a wider variety of rooms than was possible using room types. I still need to fully incorporate this into the map generator, specifically by replacing the existing room generation with feature-based generation.
  • Overhauled effect triggering. I was never comfortable with the way I originally implemented the configuration of status effects caused by an object or item. Effects inherited from MonoBehaviour so that they could be added to game objects in the Unity editor. It worked, and it was designer-friendly, but it was unintuitive (it wasn’t obvious the purpose of the component was to cause an effect) and too heavyweight (multiple effects required multiple components). I converted effect types to ScriptableObjects and created a new class containing a list of effect types. I called this class TriggeredEffectCollection and used it to replace the individual effect components. Adding effects is now easier (add/remove from a list editor in the Unity inspector) and the purpose of the component is more clear.
  • Removed the limit of one static object per cell. Now cells can have any number of static (not moving) and dynamic (moving) actors/objects. For example, a cell can now have a floor trap and a statue. This also simplified the code because now there’s just a list of actors/objects instead of a list plus the static object.
  • Extensive actor AI logging. Now the log very clearly shows why an actor chose a particular action and not others. Very handy for troubleshooting. The basic AI process is to 1) identify the potential actions and 2) select the best action. The logging explicitly indicates why potential actions were available or unavailable, and why potential actions were rejected or selected.
  • Added new effects: Cure Poison, Darkness, and Paralysis.
  • Added new items: Cure Poison Potion, Throwing Axe.
  • Damage type resistance. Physical materials now have explicit resistances to different damage types. This will be used to do things like making an axe more effective against a wooden door than a short sword.

The plan for next week is to replace Room Type-based room generation with Room Feature-based room generation and start on two new features: Enemy Alerts and Knowledge. The former provides visual indicators for whether enemies have seen the player and the former varies the descriptions of things based on the player’s knowledge.

Weekly Update – April 30, 2021

Good momentum again this week. Things are easier to add and fix after the recent refactoring.

  • Replicate actor action. This is a new action that allows actors to replicate themselves. The actor’s AI controller provides the replication parameters. This action was created primarily to enable effects to spread. For example, a fire will spread to adjacent cells that contain a flammable object.
  • Converted cell effects to actors. I originally created a class called CellEffect for objects that could cause status effects on actors and move independently. I realized that these objects were better implemented as actors so that they could take turns like other active actors and their unique behaviors could be defined in AI controllers. I call these Effect Actors. There are currently two Effect Actors: Fire and Poisonous Gas.
  • Items can now have status effects and be damaged. This allows items on the map and items in an actor’s inventory to be affected by status effects and damaged. For example, if an actor becomes engulfed in flames, the actor’s flammable items may be damaged or destroyed. This was previously implemented, but in a kludgy, hard-coded way.
  • Fire Arrow. It’s been months since any new items have been added to the game. The Fire Arrow starts a fire where it lands.
  • Arrows can create actors upon hitting a target. This was required to enable the Fire Arrow to create a fire when it strikes something flammable. This functionality can be used in many other ways, for instance a wand that summons a pet.
  • Replaced some enums with ScriptableObjects. I’ve used a lot of enums in because they are an easy way to define a range of values and they work in the Unity inspector (just don’t rearrange them because the inspector stores enum values by index). But, they have limitations. You can’t store any additional info on an enum. Also, new values have to be coded; they can’t be added in the editor. ScriptableObjects are a great alternative to enums because you can define additional attributes for each value and you can add new values in the editor. I’m in the process of moving the majority of enums to ScriptableObjects.
  • Materials. Objects now have a primary material, such as wood, stone, paper. These are defined as ScriptableObjects and have physical properties like hardness and flammability.
  • Basic material / element interactions. Implemented basic rules for interactions of different objects based on material. Examples: poisonous gas doesn’t affect a table, fire doesn’t affect a stone wall.
  • Message log improvements. Added messages for status effects and grammar fixes.

Next week, lots of miscellaneous improvements and fixes pertaining to combat animation, message log, fog of war, player detection, enum to ScriptableObject conversion, and object interactions. Roadmap-wise, I’m closing out open issues in the scope of Release 2.

Weekly Update – February 13, 2021

Last week I started a major refactoring to make it easier to add new features, reduce the number of bugs introduced from poorly architected code, and decrease average troubleshooting time. I made massive progress on this effort this week thanks to having three days off from work.

When I started developing Legend over a year ago, I used some source code from a Unity tutorial, most of which has since been culled or replaced. The source code included a GameManager class. I wasn’t sure what the appropriate use of this class was in Unity, and over time it grew into a 2000-line monstrosity and a textbook example of how to misuse singletons. It contains game turn management, multiple finite state machines, movement and combat logic, public references to other classes such as the map class (making the classes globally accessible), and miscellaneous utility methods. I began dismantling the GameManager class this week. It’s been a painful process but well worth the effort because it’s greatly reducing cognitive load.

I added one new feature this week: when the map is fully revealed by a “reveal map” scroll, the revealed map locations are shown with a blue tint to distinguish where the player has and hasn’t been. Here’s an example:

Revealing a level map

I moved the legendrl.com website to a new host, SiteGround, because the website was extremely slow on the former host. The site is much faster now!

Next week I’ll complete the major refactoring and squeeze in a new feature or two.