Anguished is an addon for the roguelike Tales of Maj'Eyal. The addon behaves much like a mod in a typical game, adding or changing content that appears in the game. In the case of Anguished, it adds a new playable "class" (a set of abilities) for the player to play as. It is currently hosted on Github as well as on the game's website.
The Anguished class itself contains roughly 36 uniquely coded "talents" (aka abilities) with a balance between inflicting debuffs (damage and impairment), doing direct damage, and defense. My goal was to create a hybrid caster who had to increase both their spellpower and mindpower, while also relying heavily on debuffs in order to ramp up their damage. This resulted in a class that needed to pay attention to their cooldowns and try to manipulate the battlefield to fight enemies one-on-one, since they had little in the way of AoE.
At the start, both not knowing Lua, nor knowing the engine (T-Engine 4) was a huge issue. A lot of early attempts at scaffolding the class was trial and error and looking at the game's original code, reverse engineering it to suit my own needs. Overall, the project came out well, and I released it to the game's site for people to download. A few bug reports/discussions on the forums about what to buff later, I released a few new versions.
Tales of Maj'eyal has many RPG elements, thus numbers are just about one of the most important things in the game. In order to come up with a baseline for what Anguished's numbers should look like, I took to the game's code and looked for abilities that were similar to abilities that I wanted to include in Anguished's kit. The nice thing about looking directly at the code was that the scaling formulas used for the abilities were directly shown to me. When I was writing the actual code for Anguished, I borrowed a lot of these scaling formulas, helping keep the class in line with the rest of the game's classes. It was a safe, assumption-based approach but it worked.
Tales of Maj'eyal, a tactical, grid-based, turn-based game, has combat that is far more complex than just who has the biggest numbers. I wanted to Anguished to be more than just a "dump all status effects and leave" style of play, so I had to once again, look to the game's existing content in order to construct a fun and flavorful kit that rewarded tactical usage of abilities and management of resources/cooldowns. To accomplish this, I broke down classes similar to what I wanted Anguished to be like in a design document and "reconstructed" bits of them back together, grabbing the functionality I wanted. General outline in hand, I took the reconstructed bits and made them unique and added a few self-written ones to fill the gaps of functionality I had.
A lot of people will tell you that play-testing is one of the most important phases... and I'm inclined to agree with them. I learned more from watching people play the class and discuss the abilities it had than I did from all the research of the existing classes in the game. I learned quickly that if I wanted to make the class fun and interesting and most of all, have people want to play it, I had to emphasize what was fun about it. When I was play-testing and tweaking things, I began to lean on the aggressive side of changes, often making very large changes (both in numbers and mechanics) to abilities, seeing that it was easier to gauge whether it was a good idea or not. It made it a lot easier to focus on what I wanted the class to be about, while still having basic abilities like damage reduction and healing be effective, but not important to the class (and thus take away from the theme).
Lua is an odd little language, and Lua hooked onto C++ through means of libraries is even stranger, so beware of these screenshots.
(To actually view the code I would suggest opening the image in a new tab or zooming in, this image was mostly to demonstrate size of a single talent).
One of the shorter talents in this file, this image shows the general layout of what one ability looks like. In the Anguished class, each talent is defined as a table with set properties, the main parts of a talent are the action function and info function. Everything else is either just a simple property or for organization/cleanliness, such as defining later calculated parts of the talent early. The action function holds everything the actual talent does, handling targeting, damage projection, and status effect projection.
Much like how talents are defined, status effects are tables as well. This image is the status effect that the previous example applies. A status effect's behavior is defined by its activate, deactivate and on_timeout (tick) functions. This one is a simple damage over time status effect (see on_timeout doing a damage projection), that gives the projector some of their casting resource back through use of a special damage type (DamageType.DRAIN_VIM). DamageTypes are also exceedingly useful for getting the right talent behavior.
This is an event-based talent. Named Weaving, it calls this code snippet whenever the "owner" of the talent finishes using a talent. It applies a certain buff to them, or if they already have the buff and cast a talent that meets the requirements, then the buff is consumed and you get a special effect. Callbacks, like most event systems, are exceedingly useful at getting the right effect exactly where you want it and remove the need to deal with the game's code directly. Without a callback, direct override of the game's code is needed... and that is generally very bad for compatibility.
Through a combination of talent definitions, status effect definitions, DamageType definitions and reading a whole lot of engine code, I achieved the expected behavior for Anguished. It was very much a self-teaching process, as each error or question about how to do something meant going back and reading pre-existing code in the game. This gave me important exposure to the process of reading other people's code, a skill that is sadly often not emphasized in coursework.