Playing a healer in an MMORPG is a unique experience that is notably absent in single player games, so I wanted to create a game where the player could partake on their own schedule, without having to worry about the added roadblocks of dealing with strangers, or queues, or the inability to pause to deal with a screaming child.
Yet another (unfortunately) solo dev undertaking, all coding, art, (minus some UI and icons) and animation is by me, done in my free time. (eg “When I should be sleeping.”)
Development is ongoing, as unfortunately I’m much faster at coding than I am at drawing.
Every feature described on this page is already coded and functional, so any potential employers are encouraged to experience a sense of wonder and to give in to any hiring urges you may feel.
Design & Mechanics
ScriptableObjects are probably my favorite part of working in Unity. Nothing’s worse than having to go in and tweak the same value in a dozen different prefabs, and I avoid that nonsense by organizing my data into nested groups of ScriptableObjects.
If I want all Snake-type enemies to drop the Snake Fang vendor trash item I just created, I simply add a reference to it in the SnakeGlobal LootGroup SO, that is itself referenced by the Snake RaceInfo SO, which is in turn referenced by the CharacterRace field on all Snake-type enemies.
One click and I’ve updated the loot tables of every snake enemy.
But what if I only want green snakes to drop a Green Snakeskin? I can create a GreenSnakeLoot LootGroup to add it to, and then add that to all green snakes. Now any time I want to add green-snake-specific loot, I simply add to the GreenSnakeLoot asset.
This system is probably my proudest coding accomplishment. Over 2000 lines of code, and it’s clear enough that I can go in a year later to add a new feature without breaking everything.
- ScriptableObject based Ability assets; Fast prototyping. Create a new Ability asset, add it to a Level list in an existing AbilityGroup asset. Now any character that uses that AbilityGroup can use your new Ability at that level.
- Integrated with SO-based status Effects, allows for character ability kits with depth. Stacking Heal Over Time? Sure. Armor debuff that isn’t cured until you’re healed to full? Okay. Teleport into the middle of a fight and create an explosion that stuns your enemies and spawns an angry rat for every 10% of your missing health? YES
- Dynamic tooltip generation. Write it once, and the values update automatically.
- Custom modular Resource system. Abilities can cost Mana. Rage. Focus. Anxiety? A character can use any number of Resources, allowing for abilities that generate one resource while spending another.
Items & Stats
I created a ScriptableObject-based Item system that integrates with my RPG stat system. Click some dropdowns and fill out some fields, and you’ve got a functional item, ready to populate some loot tables.
- Rich RPG stat system that allows for base stats, derived stats, and even percentage-based modifiers to stats from equipment and abilities.
- Items can be Equipment, Consumables, Quest Items, Crafting Resources, or just common vendor trash.
- Item level scaling system allows different level versions of the same equipment, and automatically scales the stats accordingly
- Spell system integration! An item can have passive on equip spell effects, on use spell effects, or spells that have a chance to activate when you hit an enemy or heal an ally… Or any combination of these.
- Random Affixes. Uncommon rarity items can have a random Suffix, and Rare items can have a Suffix and Prefix, allowing for unique items.
My inventory system is an upgraded version of the one I originally wrote for my Colony Sim prototype. It’s robust, reusable, and packed with features:
- Support for multiple inventories that can interact, including per character, equipped, loot, and bank.
- Item stacks, including automatically adding new items to stacks.
- Modifier keys to allow picking up/placing one item, half the stack, transferring a stack to another inventory, etc
- Auto-sorting based on type, rarity, etc.
I needed a way to track the player’s tutorial progress, which ended up becoming a fully-featured Quest system featuring:
- ScriptableObject based Quests with modular goals & rewards. Creating a new quest can be done in under a minute.
- Robust reward system, add fixed item rewards, randomized rewards, player-selectable reward choices, or a combination of any.
- Flexible Quest Goals include Find Item, Turn In Item, Kill Any Enemy, Kill Enemy with Tag, Kill Specific Enemy, Reach Exit, etc.
- Quests can require completion within the current dungeon, or over multiple sessions.
- Integration with Unlock system. eg “Complete a quest to unlock a character”
Enemy AI target selection is a traditional MMORPG “Threat”-based system; damaging an enemy or healing an ally increases your relative threat score, and having the highest threat past a certain threshold will cause that enemy to change targets. Tanks’ “taunt” abilities force a target switch.
Threat also decays to a normalized amount to prevent any one group member from pulling too far ahead.
Enemy ability usage is chosen randomly with weighting based on the current situation. For instance, an ally at low health will increase their chance of casting a heal spell, or multiple targets clustered together increases their likelihood of using an AOE ability.
Additionally, each Enemy has an aggression rating, ranging from Offensive to Defensive, that additionally modifies the weight of their choices. For instance, a Defensive enemy will almost always choose to heal their allies if they’re hurt, and an Offensive one will wait to heal until their health is critical.
Group Member AI
Since the idea is to simulate an MMORPG grouping experience, friendly NPC target selection is what I call “Intelligent but fallible.”
Damage dealers will tend to target the Tank’s target, or the lowest health enemy, but will sometimes choose the wrong target, drawing the attention of the enemy. Tanks will attempt to keep every enemy’s attention, but won’t always choose the right target.
This is intended to keep the player on their toes by ensuring that combat doesn’t become too predictable.
Unlike enemy NPCs, Group member ability usage is deterministic. For instance, a tank will always prioritize attempting to use a defensive ability when at low health. Since they have quite a few more abilities than NPCs, this prevents their behavior from becoming too unpredictable.
I hate mindless, repetitive tasks. Nothing’s worse than, say, creating dozens of SpriteMesh assets, then individually selecting the correct Sprite for each.
The result of my disdain is that I’ve gotten really good at developing one-click automatic solutions to tedious processes.
For example, my Avatar Setup Helper script takes several raw textures and slices them into individual sprites before creating individual SpriteMesh assets to assign them to.
The end result is I can import an image file for a new character and have it rigged, animated, and ready to use in-game in literally under a minute.