Showing posts with label #EonAltar. Show all posts
Showing posts with label #EonAltar. Show all posts

Wednesday, February 21, 2018

Developer Tales: Aggressively Moderating Aggression

One of the things that I loved about my work on Eon Altar is it taught me a lot of other skills and brought to me many different experiences that I didn't really get to experience at a larger company. On the other hand, sometimes those experiences weren't always positive.

Today I'm going to talk about forum moderation. How I attempted to build a community, and keep that community positive. I'm going to do that through a story of one time I had to banhammer someone with vengeance. Despite having receipts, you won't find names in here. The purpose of this story isn't to shame, but to illustrate. And maybe a small amount of catharsis.

When you ban someone on the Steam forums you get a private thread between the banned person and the moderator, at which point you as the moderator can explain why you banned them, and they can reply, possibly to explain themselves or beg your forgiveness. Of course, in this case the banned got even more aggressive than they were on the forums, and accused me, the dev and moderator, of being biased towards long-term community members.

Me, after dealing with someone aggressive on the forums.

Let Me Tell You a Secret

Surprise, yes, as a dev and moderator I am totally biased towards long-term community members in good standing. Now, caveat, if a long-term member had done what the banned person had done, I'd have similarly banned them, too. But there's really good reasons you as a developer and moderator would actually want to be biased towards long-term community members.

First of all, part of the reason why forums exist is to develop said community. A group of people who identify and enjoy your game, want to help each other out, and communicate with the developers. It benefits us developers, because it lightens the workload with respect to helping customers out in a timely fashion, and it benefits the community members, because they get to have the developers' ears in terms of criticism and feedback.

That's not to say I ignored feedback from people who weren't long-standing community members. Fresh eyes are always useful feedback. But at the same time, it was usually easier to understand where someone was coming from with feedback if I'm already familiar with them. History breeds context, and context increases communication throughput in my experience.

And the other interesting part about said bias is that when a prominent community member brought me feedback to disseminate among the team, if it was hyper-critical, it was often done as a labour of love. They do enjoy our work, and they understand that we're people too, and so reading that hyper-critical feedback is easier on our feelings. That said, you can still tell--even with new community members--who's there to shit on your sandwich and who's there because they truly want to make the game better for them and others; by the language they use, and the specific approach to criticisms.


How Do You Get Banned From a Community?

I know the previous section was a little vague, so here's some meat and potatoes to give some precise examples of the things you can do to get bushwhacked from forums.


1) Accuse the Developers of lying about a specific feature. 7 times in 7 different threads.

One morning I woke up to check the forums, as I was wont to do, and lo, we had like 7 new thread replies. Checking them, they were all by the same person, and they were all variants of, "Your Kickstarter said there'd be an online mode, and now there's no online mode, y'all are liars."

Okay, first of all, that Kickstarter failed. It had failed 3 years before those posts, no less. Sorry, not sorry, but we can't be held accountable to promises made in a funding drive that didn't get us the funding. We had to radically alter the game after that failure to accommodate the fact that the game in it's Kickstarter format wasn't viable, so anything in the Kickstarter barely could be applied anyway.

To top it off, after the ban, the poster accused us of being shady about it, keeping it behind the scenes. At which point I linked about 4 different interviews of us talking about the failed Kickstarter and what it meant.

I mean, really, if you're going to accuse the developers of lying, make sure you've done your research, and make sure you're not making any unreasonable assumptions. And then on top of that, approaching it more diplomatically rather than aggressively spamming the forums would have left things more open to conversation. I don't have the time or lack of emotion to deal with someone who's going to argue with me in bad faith. Not going to happen. I've got video games to make.


2) Slag others on the forums with personal attacks.

After being given a warning about forum spam and a warning (and post deletions) about unfounded attacks on the developer, attacking others on the forums is a Bad Idea™. Now, these attacks were on long-standing community members who were in great standing: they'd contributed significantly in a positive manner, including criticism. And to be fair, said community members didn't hold themselves perfectly in return.

However, as mentioned in the section above, I'm willing to give said long-standing members some leeway. Yeah, it's blatant bias, but frankly I didn't give a damn. They were still a net positive to our forums, whereas this newcomer throwing shade and slagging people directly was a net negative. Each individual action by an individual doesn't get evaluated individually; it's all in aggregate. Eventually we decided it wasn't worth it.


3) Continue to be aggressive in the ban thread.

After we banned this person, they wrote an essay about why we were in the wrong for banning them, and how precisely we were liars, and how this other forum member wronged them so they should be banned too.

The first essay I responded to, with the logic about the Kickstarter failing, the counter-evidence of us being "shady", and why the personal attacks were the last straw.

A few days later another essay came through on the ban thread, conceding some of the points and then getting aggressive again. At which point I switched off and stopped reading the thread, and didn't return until said poster added a 3rd essay months after the fact. Which I also didn't read. Again, I don't have the time or emotional capacity to deal with someone who clearly has a smear agenda against us. I never heard from them again after that, and it was blissful.
 



Consequences

At the end of the day, we as developers eventually decided this person's contributions were a net negative on our business.

From a community building perspective, as they were being extremely negative and extremely mistaken about the accusations they were making. Something like that would turn our community into a bloodbath. The good thing is we had already done a decent job of cultivating a community that many of this person's posts were reported for moderation many times, and quickly, even as we were discussing what to do about the situation.

From a morale perspective internally, it was a very stressful situation. It ate a lot of emotional energy dealing with this person, and time we could have been using to develop features. This is partly why bigger companies have community managers: that level of indirection is extremely helpful to reduce the negative effects of jerks on your development team. The cost of community managers is not being able to directly interact with customers in good faith. Direct interaction is amazing for getting unfiltered, honest feedback, and being able to ask follow-up questions and have a legit discussion is incredibly useful. But sometimes, eventually, it's just not worth it.

From a monetary perspective, if they requested a refund of the $15 they paid, I'd have happily given it to them--who knows, maybe they did, it's all automated. Not every customer is a blessing, even in cases where we're desperate for customers. The customer isn't always right, and a customer holding your forums hostage isn't really a customer anymore. If you walked into the GAP and started yelling loudly about how you were promised cardigans because it's fall, and there's no cardigans this season, you would be escorted from the premises. Just because it's online doesn't make the scenario different.

However, our quick and decisive response paid dividends, quickly. The negativity was quarantined, and our community got to go back to talking about the game, the good, the bad, suggestions, interests, ideas, and so on, instead of having to babysit someone who was slagging them. The total negative effect was quite muted. The ban thread was draining, however, and I regret putting so much time into it, honestly. While I wanted to make sure our butts were covered, it was an unnecessary shadow over our developer team.

There are real world productivity and monetary consequences to trolls in your forums, and you need to deal with them quickly and decisively. Bias isn't always a bad thing when it comes to cultivating your community: there are very good business reasons to feed that bias. It was a lesson I had to learn that day, the hard way.
#IndieDev, #EonAltar, #DeveloperTales

Wednesday, July 5, 2017

[IndieDev] Checkpoint Saves: Ugh, Why? And How, Part 2

Last week I chatted about the start of Eon Altar's save system, why it didn't work, and how we fixed it. This week I'll go in-depth about Eon Altar's Checkpoint Save system. 

Fast forward nearly a year from our new save system implemention--Aug/Sept 2015--when we finally entered Early Access. The game was probably about 80% functionally complete and 60% content complete. As I like to say, the last 20% of your game will take about 80% of your time, and Eon Altar was no different. We spent 10 months in Early Access, and initially, the biggest point of feedback we got was, "How can I save my game mid-session?". Our sessions were about 30 minutes to 4 hours depending on the players, and in 2015 shipping an RPG without the ability to save mid-session was, well, pretty bad. So began the process to create a checkpoint save system, and retrofit our levels to save data correctly.


Checkpoint Saves: Less Complex?

Why checkpoint saves, though? Why not save anywhere the player wanted? The answer to that is largely to reduce potential complexity. If a player can save anywhere and anytime they want, it means you have effectively an infinite number of states, and good luck testing that. A specific example of this would be Myrth's Court in Episode 1: The Prelude.

Myrth's Court
That "moment" as a whole had the following:
  • A check to see which player characters were available.
  • A dialogue based on that to posit a vote.
  • A vote to decide which character's solution to use.
  • The actual moment where the party implements aforementioned solution.
  • Potentially a combat as a result of the solution.
If players could save at any point in that process, that would significantly increase the testing complexity around that moment. What happens if you reload with different characters mid-moment? What happens if you have fewer characters? More characters? By only allowing saves to occur at specific points in the level, we can avoid having to test those mid-moment saves.

By using checkpoint saves, we could tie them to an existing checkpoint mechanic we had in the game already--Destiny Markers/Stones. Again, not having to worry about partial encounters is a huge complexity save, but also not worrying about how to turn on/off saving in certain locations. What if we had a bug that prevented save from being turned back on? Or a bug that allowed saving in the midst of a complex moment? Also, how do we communicate if we can save or not to players? And what would the save UI look like? By tying it to an existing checkpoint mechanic, it made it very easy to communicate and very easy for players to grok. No special rules or explanations necessary.

So while checkpoint saves aren't as convenient for players, the reduced complexity was enough to make checkpoint saves doable with our small team and budget.


How to Train Your Save System

We already had a method to quickly save data to disk, and the checkpoint save system would continue using it. The questions then became, where do we store that information at runtime so designers could access it, and how do we design it in such a way that required as little designer input/time as possible?

First we had to determine what we would have to save:
  1. Enemy spawner state: were they dead or alive?
  2. Game object state: was it enabled or disabled?
  3. "Usable" object state: was it waiting or already used?
  4. Finite State Machine (FSM) state: what state was it left in?
  5. Specialized game object state: what is the game object's transform (position, rotation)?
  6. Specialized spawner state: what is the enemy's transform (position, rotation)? What is the enemy's AI settings (aggressive, passive, patrolling; allied to players, or enemies; patrol state)
With those 6 items, we could literally save anything and everything in our levels.

I created specialized game components that could track those states and report them to the save subsystem as they changed, so we wouldn't have to trawl through level data to extract information--remember, we wanted to ensure the save system was fast. All the designers had to do was add them to an object they wanted to save that particular state out for, and give it a unique ID (well, my code autopopulated the ID based on a random GUID and the name of the object in the hierarchy, but the designers could override that if they chose).

This worked extremely well. Design quickly retrofitted our existing levels. The vast majority of our save data is items 1, 2, and 3. FSM save data is rarely used unless the FSM is long-lived (our Destiny Markers are the primary users of this tech). Most FSMs would trigger and finish in one go, or at least in one encounter so we'd not have to worry about partial FSM execution by the time we got to hit a save point (yay checkpoint saves!). 5 was almost never used outside of redirecting patrol nodes for NPCs, and 6 was generally only used on super special NPCs: ones that changed their AI based on designer scripts, or NPCs that were used for escort quests.

Wild Checkpoint Data draws near!
The code took about a week to create/test/deploy for design. The lion's share of the time (and bugs) was designers retrofitting levels. I think it was easily a full man-month of time to get the levels up to snuff, and the amount of testing required was still absolutely immense, despite the reduced complexity of checkpoints.


The Bugs
 
A pitfall of this--and I'm not sure there's an easy way to solve this pitfall, I don't believe it's specific to this solution--is when designers forgot to put save components in levels, or they chained components in such a way that would create a problem on game load.

A specific example of this is a door in Episode 2, Session 1. Level design logic had the door with the following states: unopenable, locked, unlocked, open. Depending on the quests you did in the level, it could become locked, unlocked, or open. However, if you saved and quit and reloaded later, then the door would be unopenable because the door wasn't actually saving its state out, and players would become blocked.

Now, when we ran into those issues, we would add the save component in the level data, and then use code that ran on save data load to modify the data before it got applied to the level itself. Basically, we could determine based on what other quests were complete and save object states if the door should be locked, unlocked, or open, and set that state in the upgrade code.

Today we have 10 such save file upgrades that potentially run on a save file to give you an idea of how often we've had to use this, and the lion's share of them are for Episode 2 Session 1. Enough to make me glad we implemented it, but just how different E2S1 was from the rest of the levels really showed how easy it is to screw up save state if you're not careful thinking about it holistically.


The Future: SPARK: Resistance

SPARK won't have need of checkpoint saves, as sessions won't last more than 10-15 minutes at a maximum. Rather, any save data will be related to your "character". Unlocks, experience, statistics, etc. Thankfully, I'll be able to take our save system nearly wholesale from Eon Altar and apply it here, minus the checkpoint stuff.

A Randomly Generated Map and Associated Data
The in-level checkpoint stuff wouldn't work in SPARK anyhow, as the level structures are fairly different to start with thanks to both the procedural nature of the levels as opposed to hand-crafted, and the fact that the levels are networked right from the start, which is very different from a local multiplayer game.


Conclusion

The current save system in Eon Altar is robust, extremely fast, legible, easy to modify, and minimalistic in data requirements aside from the fact that it is XML, but the actual data output is all essential. It requires as little designer input as I could possibly get away with (even most checkpoint save data is attached to prefabs and autopopulates all IDs in the scene at the click of a single button). 

Yes, it took a fair amount of engineering work altogether, but I think that's a result of you just cannot skimp on engineering for a system like this. You get what you pay for, and if you're not willing to put the engineering time in, you're not going to get a great system on the other end. And as mentioned at the beginning, persistence is extremely important to games. A game can't afford to skimp on their persistence systems in my personal opinion.
#IndieDev, #EonAltar

Wednesday, June 28, 2017

[IndieDev] The Nitty Gritty on Save Files, Part 1

Persistence is possibly one of the largest drivers of repeated and extended interaction a game can have. RPGs persist campaign data between sessions; puzzle games persist how far you've been in the game and how well you beat each puzzle; even ye olde arcade games persisted high scores for all to see (until someone rebooted the arcade machine, anyhow). With that in mind, creating a robust save system is one of the most important tasks you could have when developing a video game. For us developing Eon Altar and now SPARK: Resistance, this is no different.

However, even the task of gathering some data, throwing it on disk, and then loading it later comes with a bunch of potential issues, caveats, and work. I'll talk today about our initial attempts at a save system in Eon Altar, why we went that route, why it didn't work, and what the eventual solution came to be.


A Rough Start

When we first created our save system, the primary goal of it was to save character data and what session the players were on. We had a secondary goal of utilizing the same system as our controller reconnect technology, as the character data was originally mirrored on the controllers as it was on the main game: down to character model and everything. We weren't originally planning on having mid-session saves (those came later), so really we only had to worry about saving between levels.

The "easiest" way of doing this, without having to think of any special logic is to copy/paste the state from the main game into the save file, as well as the controllers over the network. In programmer terms, serialize the state, and deserialize it on the other end. Given our time/budget constraints, we thought this was a pretty good idea. Turned out in practice this had some pretty gnarly problems:

  1. The first issue was simply time. The time it took to save out a file or load up a file was in the order of tens of seconds. Serializing character objects and transferring that across the network was measured in minutes, if it succeeded at all.
  2. The second was coupling to code. Since we were serializing objects directly, it meant that any changes to the code could break a save file. If we changed how the object hierarchy worked, or if some fields were deleted and others created, then existing save files would potentially be broken.
  3. The third issue was complexity. The resulting save file was an illegible, uneditable mess. Debugging a broken or corrupt save file was a near impossible task. Editing a broken save file was also quite difficult, if not impossible. Because of this, we couldn't (easily) write save upgrade code to mitigate issue 2. We'd have been locked into some code structures forever.
  4. The fourth was just far too much extraneous data. Because we were performing raw serialization, we were also getting data about textures, character models, what were supposed to be ephemeral objects, hierarchy maintenance objects, and so on
While we had a save system that did what we wanted on the tin, it was untenable. Shipping it would've relegated our small engineering department to an immense amount of time trying to fix or work around those issues. So while this approach was "simple" and "cheap" in terms of up-front engineering cost, it was the wrong solution. We went back to the drawing board.


The Reimagining

About a year after we started development, the team shrank pretty substantially. We'd lost 1/3rd of our engineering team and my time became even more contested as I became the new Lead Programmer. I had to contend with the responsibilities that came with that title, as well as continuing to deliver features and fixes.


However, I had already been noodling on the save and reconnect systems, and had a new plan. The first step was to fix the controller reconnect, which you can read more about here

Given reconnect was taking 8 minutes each time we had to reconnect a controller, it didn't take upper management much convincing that something needed to be done. And since reconnect and save were intimately connected at the time, making a convincing argument to fix save shortly after also wasn't a hard sell. So even though I had to disappear for 2 weeks to fix reconnect, and then another 2 weeks later to fix save files, I think everyone involved believes it was the correct decision.

To fix our 4 issues, it wasn't sufficient that we just be able to save and load character data in any which manner. It needed to be quick, it needed to be decoupled from the code, it needed to be easy to read/edit/maintain, and it needed to be deliberate about what it saved out.



The Reimplementing

For humans, text is easier to read over binary, and a semantic hierarchy is more legible than raw object data. So I knew pretty early on that my save file data was going to be in XML and in plaintext.

Plaintext was important. We often get asked why do not encrypt our save files, and it comes down to maintenance. Human-legible files are easier to read and easier to fix. As an indie studio with extremely limited resources, this was a higher priority for us than preventing people from cheating their save files in a local multiplayer game. If your friend is going to give themselves infinite resources and you catch him, you can dump your coke in his lap. 


Plaintext has saved our bacon multiple times: if there is a bug that is blocking our playerbase, more enterprising players have been able to repair their own save files with careful instructions from us (and a lot of WARNING caveats) until we can get around to fixing it. Also, being able to just quickly get information from broken save files without having to decrypt them.

The benefit of using XML is we could serialize to and deserialize from programmatically without any extra work on our part: tools to do so already existed. In fact, we were already using those tools to do the old save files. The difference was instead of serializing the character object instances directly, I created an intermediate set of data that was decoupled from the objects that made up the character data instances in-game, and this data was going to be organized according to game-play semantics rather than raw object hierarchy.

An example of a simple data class, and the resultant XML.
Having actual data classes meant we could lean on the compiler to ensure data types matched up, and that we could just use existing serialization tools to spit out the save data. It did mean a fair bit of manual work to determine what goes into the save file and where, but the benefits of that work more than made up for the upfront time. Adding new fields to save data is trivial, and populating new fields via upgrade code isn't terribly difficult. Editing existing save files became super easy because the save file format was now extremely legible. Legible enough that we've had users edit their own save files easily. And good news, because the data was decoupled we could actually write save upgrade code!

Collating the data into the data classes at runtime is a super speedy process. Less than 1ms on even the slowest machines. We're only serializing the simplest of objects--data classes are generally only made up of value types, other data classes, or generic Lists of other data classes or value types. And since we weren't serializing a ton of extraneous objects that only were supposed to exist at runtime, the amount of data we'd save out was significantly reduced: 29KB for a file with 2 characters, instead of multiple MBs. We put the actual writing of the save file to disk on a background thread; once we had the data collated, there was no reason to stall the main thread any longer, and disk writes are notoriously slow.

The difficult part was going from the data classes to instanced data. Previously it would get hydrated automatically because that's what deserializing does. However, in this case we hydrated data classes, I had to write a bunch of code that recreated the instanced runtime character data based on those data classes. This required a lot of combing over how we normally generated these object instances, and basically trying to "edit" a base character by programmatically adding abilities, inventory, etc. based on the save data. It wasn't particularly hard, but it was time consuming, and potentially where most of our bugs were going to lie. But by using the same methods we call when adding these things normally at runtime allowed me to reuse a lot of existing code.


Part 2: Checkpoint Saves
 
We had our new save system, and it was pretty awesome. The original save system was done in approximately a week, if my memory serves, maybe a little longer. The new system took a month to implement after research, programming, and testing. Basically, you get what you invest in. Skimping on engineering time on this feature was a bad decision in my 20/20 hindsight, but we fixed it, so all is well today!


Next blog post I'll discuss the next step we took for Eon Altar: Checkpoint saves. Why checkpoints? What did we need to do to retrofit the game to handle checkpoint saves? What implementation?  What pitfalls we ran into? And then, what can we reuse for SPARK: Resistance? #IndieDev, #EonAltar

Monday, October 24, 2016

PAX DEV 2016 Talk: Mobile Enhanced--Designing for Multiple Simultaneous Screens

So I've been away from my blog for a while. We've been super busy with Eon Altar, including PAX West, shipping Episode 2, and I gave a talk at PAX DEV, which was super awesome (and well received).

So while I am still crazy busy (Episode 3's gotta get made!), I'm dropping by to let folks know hey, I have a legit game design talk that I wrote/hosted.


Sorry about the sound quality. I had recorded this with the thanks of OutOfBeta using my Lumia 1020 in a LEGO setup and it didn't pick the sound up super well :( So you'll have to crank the volume.

High Tech Recording Setup
#IndieDev, #EonAltar

Thursday, August 25, 2016

[IndieDev] The Aftermath of Launching Our Game

Okay, so it's been like 2 months since I've done a blog post, and it's not for the lack of wanting so much as the lack of time. But let's talk about the launch of Eon Altar, and where we're at today.


Launch and Beyond

Launch itself went relatively smoothly, if a little disappointingly quietly.

Only one major game breaking bug at launch that I had to hunt down, which actually only repro'd on specific devices on Android 4.4. It was bizarre to say the least, and I ended up buying two phones via Craigslist, and our Studio Manager drove down from Vancouver, BC to Seattle, WA to get a device that could repro the issue into my hands. It would've cost $300 to ship, apparently, so he and his fiancé made a day trip out of it. But I managed to use that to get a fix within 2 days of the bug being reported, so our customers really appreciated the responsiveness especially since the fix got pushed out on a Sunday evening. Instead of going to Seattle Pride I got to stay in and debug. Fun times, that. But such is the life of a developer.


We were in the Top Sellers for Newly Released Games on Steam for over a week, though, and even made #1 in the Popular New Releases for a brief period of time, which was pretty cool. Sadly we haven't been able to keep that many eyeballs on the game since, which is a little worrying. However, hopefully with PAX West upcoming we'll be able to remedy that a bit!

Taken August 23rd, 2016
The game itself has been absolutely gangbusters as far as Steam reviews go. We're at 92% lifetime, and 95% recent. At one point we were at 100% recent, but someone left a negative review because our game won't work on a publicly-run network that blocks UDP and P2P network traffic, which I mean, yeah, that sucks and is true, but feels bad that there's pretty close to nothing I can do about it. That said, given at launch we started at 88% lifetime from Early Access, our review score going up is frankly massive success as far as I'm concerned.


Post-Launch Development and Marketing

We've managed to put out an update at least once a month since a few months before launch, and even the past couple months as well post-launch, which is great for players. Content fixes and bug squashing continue apace!


But even more, we've been extremely hard at work on Episode 2: Whispers in the Catacombs. Our teaser trailer for that launched just a few hours ago, which you can see above. We're hard at work on a new Combat Arena of sorts for Episode 2, which is less an arena and more just a standalone scenario that takes shades of the Arkham Horror board game mechanically. We've done plenty of streaming every Thursday at 1 PM PST showing off us in active development, including design work, programming, and testing. And of course, can't forget the next part of the campaign, either!

Add to that what we call "dev confessionals", which is basically a micro-vlog of sorts where we talk about what we did that week and what we're excited about. These have proven moderately popular, though we missed last week's because PAX madness upcoming.



PAX West 2016

Speaking of PAX, once again we'll have a booth, and it's going to be our biggest booth yet. This is it, we've launched, we're well on our way to delivering our first piece of DLC, so we'll have lots to show (including a working Combat Arena from Episode 2!), and lots of folks at the booth to show off the game and answer questions (and give out sweet buttons). If you're going to PAX West this year, check us out on the 6th floor of the Expo Hall, booth 6909.

I'll be doing a panel at PAX Dev as well: "Mobile Enhanced: Designing for Multiple Simultaneous Screens". The talk is basically what it says on the tin, but I'm super excited. Our Lead Designer/Art guy also made me a cool social media poster, so come check that out if you're interested. I'm hoping to have it recorded, but logistics have eluded me so far.


We'll also have some folks on another panel during the convention proper, "AAA to Indie; The Struggle is Real" which will be pretty awesome. Sadly I'll be at the booth so I won't get to watch it, but it should be great, so check that out too!



Full Steam Ahead

Last year PAX West was absolutely exhausting, and frankly, I expect this one will be as well. We're going to miss the boat on an August update to the live game because PAX and marketing is pretty much all-encompassing as far as developer time goes right now. The perils of a tiny team, unfortunately.

Immediately after we're back to the grindstone to get Episode 2 done and dusted and out the door, so no rest for the wicked. I'll fully admit I'm going to need a vacation, and probably soon. My blogging will likely also continue to take a backseat until I have a few more hours in the day to myself. We're definitely crunching, and crunching hard, but there's little we can do about that. We don't have infinite money to take the extra time we'd like.

But at the same time, I'm extremely excited that we're doing as well as we are, and I can only hope that we get the eyeballs we need so we can continue doing this post Season 1, because I think we have something pretty amazing here, and based on our reviews, the folks who've played it think so too. #IndieDev, #EonAltar

Tuesday, June 14, 2016

[IndieDev] My Game Eon Altar Gets a Release Date!


So for folks who've been following my blog, I've been doing the indie dev thing for nearly 2 years now--will be 2 years as of July 1st. Eon Altar has been my baby, and what a baby it's been! But eventually children leave the nest, and we'll be pushing Eon Altar into the light, blinking and disoriented, Thursday, June 23rd.

Our announcement is here, but I wanted to talk a little about our decision making process on my blog. Some behind the scenes, if you will.


Early Access

First of all, let's chat Early Access. We've been in Early Access since August 29th, 2015. Just under 10 months. That's a decent chunk of time, but we've also had to contend with folks having other full time jobs, contract work, and losing some employees because indie and keeping the lights on is hard.

But that being said, I think slowing down a bit and getting a lot of feedback and bake time has been amazing for the game. We were nowhere near ready for release on our original launch trajectory, which would've been around May of 2015. We needed that extra year. Turns out making an RPG is hard! Who knew?

But our Early Access response has been amazing. Not as many folks as we may have hoped, but the folks who helped us out were absolutely fantastic, going the extra mile to help us narrow down bug repros, get us logs, and be patient with some of our quirks and issues. Being candid about the state of the game, what's working, and what wasn't also helped. Without their feedback, our game would be in a much worse state today.

Which led to the discussion of somehow rewarding our Early Access customers. Luke--our financial dude/lore guy/streamer/tester/other things because I'm bad at titles and indie is a lot of hats--had this really cool idea. We ran with it, of course.

Intense Tactical Discussion

Pricing

Early Access was priced extremely cheap because for us, getting our name and game out there was more important at the time than trying to wring dollars out of our (relatively few) customers. $4.99 USD is a steal for what we delivered in Early Access--Combat Arena plus about 4 hours of quality co-op RPG game play. We've had a number of reviews mention price seemed really low for what we delivered.

But for our Early Access customers we decided that we'd give them the entirety of Season 1 (Episodes 1-3) for their $4.99 USD they already gave us. It was a great way to reward them for helping us and supporting us. Folks who come in to buy Season 1 now will pay $14.99 USD (or $6.99 USD per episode if you want piecemeal).

Still damn cheap given the entirety of Season 1 runs about 12 - 15 hours of game play, plus Combat Arenas which are technically endless (a massive hit at Dreamhack and PAX East), and you can play with up to 4 players at the same time on a single copy. But we're also an unknown company, so we're cognizant that if we price ourselves too high, people won't want to take the risk. On the other hand, if we don't make money soon, continuing development becomes an issue.


Quality

We're polished enough that I'm confident in our game, even if we have a few issues remaining. Pro-tip, you'll never actually hit zero bugs in software development. Ever. Seriously.

I had 120 bugs on my plate as of two months ago, half of those blockers or criticals (versus major or minor). I've bounced between 30 and 45 I think six times now over the past three weeks? Mind you, I'm down to a total of 8 criticals and 0 blockers, so the quality is still going up; many of the bugs being logged now are major at worst, which for our definitions is not great, but shippable.

My point being is we could be here forever fixing bugs. Perfection is unattainable, despite the fact that I really, really, really, really want it to be perfect. Like the child analogy earlier, eventually you need to let them out into the daylight and hope you gave them the skills and qualities to survive and thrive.

That's not to say we won't continue releasing fixes and patches. The reality of software development--especially games--is that you're never really done. Look at Stardew Valley, continuing to make major additions and fixes after ship. But the base game is awesome and still totally worth the $15 I paid for it. But again, need to eat and keep the lights on, and our build is in fact very stable, so to release we go.



Timing

A few months back we pegged June 1st, 2016 as our release date. Thankfully we were bright enough (this time) not to promise anything too early, so when we realized we had a few more things to do, and timing-wise it was kind of crappy, so we could push the date. E3 of course is a huge blackout period. Other timings I can't discuss also nudged the date here or there, until we settled on June 23rd. Unfortunately, it's Luke's anniversary with his fiancé, but turns out our tertiary date would've been his birthday, so he couldn't win either way.

Summer in general also keeps us out of harm's way of major blockbusters, at the risk of yeah, it's summer. But being a local co-op game, maybe being summer will work for us as people want to hang out? I'm not so certain of my reasoning there.

Ideally we'll have Episode 2 out soonish after. I won't commit to a timing,but I will say if it's like 6 months after Episode 1, I will be an extremely sad panda.


Excitement and Terror

I am beyond excited for our release. Eon Altar has been my life basically for 2 years. My dream job of making a game, an RPG, and making a game that plays like no other video game that exists today. We're pushing game play, UI, and form factor boundaries that very few developers have even tried, let alone shipped.

And yeah, I've had my doubts along the way; I've had total imposter syndrome moments. Other times I've had moments where I'm like, "this is crazy, it'll never fly." But watching people play our game on Twitch, on YouTube, at PAX, Dreamhack, Casual Connect, and even in person at play tests in my apartment, I know, empirically, that we have something unique and awesome.

I'm also terrified. What if we hit it big and something horrible happens and things break? What if we never get the eyeballs we need and we fade into obscurity--which, to be brutally honest, is the more likely of the two scenarios because marketing budget and indie dev. What if, despite all evidence so far to the contrary, people just don't get it? What if people don't read my troubleshooting instructions and I just drown in debugging people's networks over forum post?

Putting the game out there to be judged on its own merits as a shipped product is a lot of pressure. And when I look at it from an analytical perspective, I'm confident we're ready for this. But that visceral, emotional reaction is still there.

9 days.#IndieDev, #EonAltar

Friday, May 27, 2016

[IndieDev] Eon Altar's Combat Loop and Power Designs

Welcome to Part 2 of my posts on Eon Altar's combat design. You can find Part 1 here. Today I'll be talking about the myriad combat loops that we've built into the game and talk about the designs that support each.

Eon Altar has what I would call about 3.5 different combat loops. 3.5 is a strange number, and you'll see why I sort of call out two combat loops that are really a single loop, but when watching players, there's a distinct progression in terms of thoughts and planning. The loops would be classified as follows:
  1. Your Turn--Look for a target, use a power, wait for your next turn.
  2. Your Turn and Enemies' Turn--Use powers that position you to an advantage for or alter your opponents' turn.
  3. Multiple Turns--Plan your energy, fortitude, cooldowns, and gear usage over multiple turns. Planning multiple character combos (or even self-combos) can fall under here as well.
  4. Multiple Combats--Plan your progression and gear crafting/choices over multiple combats.
1 and 2 are pretty well a single loop (given combat is alternating turns), but there's a definite skill difference between players who understand loop 1, and players who understand loop 2. It's not a huge jump mind, but a discrete one.

Last time we talked a lot about loop 1, and hinted at loop 2 with talk about positioning. I'll break down some specifics about each system supporting the loops as we designed them, and how each evolved over the course of development.


Contextual Powers


The basic turn flow is pretty, well, basic. You look at the battlefield, figure out who or what you want to target, and then you're presented with an array of different powers. Once you've decided on your power, you execute it.

The trick here is the powers we present to you are based on context from combat: what is your status and where are you in relation to your target.

When we designed combat, we wanted to ensure that there was a feedback loop between your actions now (and your opponents' actions) and the powers that would be available to you next. Examples of this would be Silent Thorn gaining Assassin powers when she's Concealed; Shasek gaining Berserker powers when he's Bloodied; ranged attacks becoming unavailable when you get Engaged (locked down by a tank). Your range in relation to the target is also important, as some attacks become unavailable if the target is too far.

Earlier on in development, we also had powers that only showed up if you were Engaged. Other powers also only showed up if you were at range and not in melee. Like positioning requirements, later in development we decided these were too restrictive. Part of it was depending on context you might only have a single power available to you which is no fun at all because you literally have no choices, and part of it was just player confusion. It's easy to justify gaining new powers for a special status, and the no-ranged-when-engaged is pretty easy to grok, but a lot of cases where powers you thought you should have (like a big melee attack) only appearing when you're engaged or at a specific distance was difficult to communicate effectively, and felt arbitrarily restrictive in play testing.

Marcus Engaged with a Sellsword
Another change related to this was Engagement itself. Originally, all melee attacks Engaged the other party. When you're Engaged, you're locked in 1v1 combat with another party and can't escape without either killing the other party, or using a special Disengage power (which usually felt like wasting your turn). Engagement was extremely restrictive--by design--but play testing showed that it wasn't a fun restriction, especially given our penchant for battles where the players are outnumbered two-to-one. It was far too easy for ranged characters to get locked down and become basically useless.

Later on we changed Engagement to be something only tank characters used. Some enemies can engage, like the Bloodguard, and all three melee PCs can engage--though Shasek is less likely to want to unless the situation is dire or you really want him to take some damage to activate his Berserker powers. This made the status dangerous and a lot more uncommon, but in this case less is more: engagement is now an extremely powerful tool when used judiciously and deliberately. But those strategies are encroaching on Loop 2.


Combat Resource Economy

I'm jumping ahead to Loop 3 here a bit first, because the resource economy we built informs the design of Loop 2 to a certain extent. So while it may make sense to discuss each loop in ever-broadening order, that's not really how things worked when building the system.

In the first couple iterations, we had two primary resources: energy, and cooldowns. Attacks generated energy, and the harder you hit, the more energy you'd get returned. This created a bit of a runaway virtuous cycle where Fireballing a large group would generate so much energy that you could basically just spam the spell over and over again, so we introduced cooldowns on some of the more powerful abilities.

Every character had a couple of "Farmer" powers--that is, powers that cost 0 energy. Their primary purpose was to generate energy to use on some of your bigger attacks, the Mighty and Mythic powers.

We decided we needed to cut off that runaway virtuous cycle. Despite cooldowns, you could still alternate Mythic attacks and still generate enough energy to spam big powers all combat long once you were rolling. The first step was cutting down energy rewards from every hit to only the best hit if the attack was an AoE. Later on, we actually stopped granting energy on non-Farmer powers entirely. We beefed up the amount of energy Farmer powers granted (including on a miss so they never felt like a total waste), and the current energy economy was completed.

Muran gaining energy from a Stone Strike
As far as numbers are concerned, a miss is 3 energy, a hit is 3 or 5 energy, and a critical is 8 energy. We wanted to have that fist-pump moment where crits felt better than normal hits, especially since a crit in Eon Altar just guarantees you roll maximum damage rather than doing extra. The other aspect to this is we standardized energy costs to 5 and 12 energy for Mighty and Mythic attacks respectively. 

With energy costs set, it became really easy to map out what an expected energy curve would look like. You could alternate a hit (+5 energy) with a Mighty power (-5 energy), or if you were saving energy, you knew it would take 3 - 4 attacks for a Mythic attack, or 2 if you're lucky with a crit or two. Crits in general just allowed you to slowly bank extra energy over a medium period of time, especially given crit rates generally fall in the 25% to 40% range.

With energy gains under control, we decided we could remove the cooldowns off most powers. If you had 24 energy banked, Fireball with Muran two turns in a row if you'd like, or if you have 15 energy banked, Shield Slam on Marcus 3 times in a single turn to build up for a giant final strike. The only powers that have cooldowns remaining are Shadowstep for Silent Thorn so she can't sit in Concealment forever, and Revive to prevent players from spamming it to zerg the encounter until they get lucky. Some gear have cooldowns as well, but they're usually massive boosts or extremely powerful to compensate.

Basically, cooldowns are no longer a "resource" per se and more a balancing mechanism. A subtle distinction, but an important one as it means players have far more options at their disposal on a turn-to-turn basis.


Gaining An Advantage

Once we decided to ditch Engagement as a thing all the time, and removed some of the more restrictive contextual requirements for powers, it often meant that you had anywhere from 3 to 7 (or more!) actions available to you at any given time. This meant we needed differentiation.
Muran has a lot of options at her disposal. The two slots on the lower right could also contain equippable items like arrows or potions, meaning she could have up to 9 powers total in this context.
It's not sufficient to just have Swing Your Sword, and then a more powerful Swing Your Sword Harder. We wanted to make sure that even your "worst" least expensive powers had some tactical advantage to using. Since every character has two power archetypes, even within a single character we needed to ensure that your two Farmer powers were unique. We also wanted to ensure that using a Farmer power instead of a Mighty or Mythic power was a valid tactical decision aside from saving energy.

We have three mechanisms to realize this vision: stances, power bonuses, and status effects.

Stances and power bonuses are probably the more subtle effects, but they're also the most prevalent. They're also the hardest to communicate to players (we still don't communicate them well).

All powers activate a stance when used. Fireball and Flame Aura, for example, share Muran's Fire stance, whereas Shatter and Stone Strike share her Earth stance. Muran's Earth stance often comes with defensive bonuses, versus her Fire stance which is more damage at the expense of defense. This makes choosing Earth powers a better decision if you're going to be in melee a lot, but if you can get safely at range, you can unload with Fire powers to scorch the enemy without having to worry about the relatively lowered defenses.

On top of that, many powers have bonuses on top of the stance. Marcus' Lunge III, for example, activates his Phalanx stance for some physical resistances, but the power itself adds a +4 Defense bonus that other Phalanx powers would not, making it a natural choice if you need to turtle up.

Finally, status effects. Many powers give you buffs, or the enemy debuffs. Again, this helps differentiate powers. To use Marcus as an example again, Lunge gives Marcus the Protected status (+25% Defense) whereas Sunder causes the enemy to be Sundered as the name suggests (-25% Defense). Both are Farmer powers, and while Lunge is more accurate and Sunder does more damage, the status effects are powerful enough to perhaps use one of those instead of a more expensive power if the situation calls for it.

Silent Thorn has a good example with her Void Arrow versus her Quick Shot. Despite Quick Shot being free and weaker, since it slows the enemy (-50% Movement), it's the better attack to use if you're kiting a melee enemy. Void Arrow, however, does a fair bit more damage for 5 energy, but it also Blinds (-25% Accuracy, -50% Range), so it becomes a great decision to use against a ranged sniper or if there's nowhere for you to kite.

And then of course utilizing these effects with your allies allows you to really boost your party's power. Sunder with Marcus to allow others to hit more easily then Slay with Shasek to Weaken the enemy and get a second turn. Muran's Flame Aura reduces Radiant resistance, then use Baryson's Blade of Glory to do Radiant damage and leave a Radiant DoT to tick for even more damage. Or use Marcus' Shield Slam to knock an enemy backwards into another opponent so Silent Thorn can Volley both of them.


Part 3 Coming Soon

Loops 1, 2, and 3 often aren't quite as neat and tidy as I first laid them out. There's lots of overlap between them, and even when we were designing, different aspects of the system came online and iterated at different rates. What we have today is a pretty well-oiled machine, and we have loads of evidence from our play tests and demos at conventions such as PAX East and PAX West that we've created a very tactical game that rewards players who're aware of and plan around the different combat loops. But it definitely took a lot of iteration, thought, and play testing to get where we are now.

Next time I'll discuss progression, archetype design, and the role of gear and craftable items as the 4th and final broader combat loop.
#IndieDev, #EonAltar, #GameDesign

Friday, May 20, 2016

[IndieDev] Eon Altar's Team Turn Based TRPG Combat Design

Eon Altar's combat systems have been iterated on over the past 2 years pretty significantly, but the core tenets have stayed pretty constant. When we first set out to make this version of Eon Altar, combat came out of the gate relatively early in the process with a very strong design vision set by Christoph Sapinsky (@XophRA on Twitter). Later on after Christoph moved on from the team Scott Penner (@AltheusStone on Twitter), our lead designer, continued iterating on the system. Throughout the entire process, I've definitely made opinions and suggestions known.

Combat today is a team turn-based affair, with each player having a strong class identity and an array of unique-to-the-character powers they can pick and choose from each turn. Being able to take your turns simultaneously or in any order you choose allows for fast paced combat that you can slow down and plan at your choice. A clear energy economy for spending on bigger powers gives an ebb and flow over the course of a single fight. Many powers have secondary effects that make each one worthwhile in different situations. Outside of combat itself, character progression in the form of upgrading existing and unlocking new powers, stat boosts, weapon/armour upgrades, and consumable items help round out the longer planning game.



As evidenced by watching people play at PAX East, we've certainly succeeded in making an engaging, tactical combat system. But where did we start from, and why have we made some of the decisions we have along the way?


Original Vision

We had a few design goals we needed to keep in mind as we created combat and evolved it. The current system bears many of these out--though to a lesser degree than we'd like for some, admittedly. Some of the vision we've had to leave due to just not being able to build the tech, or as we built the game, that aspect of the vision came into conflict with providing good game play.
Tactical
Letting smart player decisions really maximize their results in battle, including proper physical placement, equipment management, using and progressing individual abilities, and cooperation with other players. Epic battles should engage players with strategy that requires group discussion.

Fast Paced
Not every battle needs to be epic; most fights will be fast and brutal and serve to contrast the fewer, more strategic fights. Players should feel that once they've committed to an action that the result is quick. Turns will be team-based, so turns go by quickly and players won't have to wait long to make their next decision.

Cinematic
When the time is right, we will reward players with a display of how bad-ass their character has become. Some monsters and battle ends should trigger "death blows"--special animated sequences. These cinematic sequences will be rare, but valuable interruptions to the regular flow of an otherwise fast-paced combat experience.
From the start, we had the team turn-based tactical combat vision. It was important to us that combat was fast and fluid, but you could take the time to make nitty gritty decisions if you really wanted to (or in the case of some combats, need to).


Vision Variation

I'm of the opinion that we succeeded in spades with the tactical and fast paced aspects of the vision, but some parts of the vision had to be left behind.

One of the biggest omissions is probably the Cinematic portion. By the time we got combat in a nascent working state, we realized that interrupting the flow of combat was going to be difficult to do in a way that wasn't frustrating to the players. Since turns are simultaneous, when a player went in for a critical hit, if we did a cinematic zoom it would interrupt the other players' targeting. Similarly, if three enemies are attacking simultaneously, and one of them gets a critical and we did a zoom, players wouldn't see the other enemies attacking, which is problematic from an informational standpoint.

I believe one day we'd still like to do finishing blows for the end of combat, but given everything else we needed to get running, it fell down on the priority list until it was cut for our current release. Something to revisit if we do well enough to release more seasons.

Cinematic has evolved since to be more about ensuring powers look and feel great. Fireball, Blood Rage, and Shield Slam are all incredibly satisfying powers to use because they look powerful. It's not just the numbers, but the visuals and sounds enforcing that.


Powers and Positioning

One of the things that I would've liked to have more of from our tactical paragraph is physical positioning. To be sure, physical position does matter. If an enemy attacks you from behind, they have an accuracy bonus; if you're too close an ally may accidentally nail you with a fireball or a cleave attack; and enemies can "block" you from making melee attacks on their friends behind them as a sort of "melee line of sight" deal.

But each action in combat is actually a series of actions, which makes having fine-grained control over positioning difficult. You decide what the top-level action is going to be, and then the action itself performs a series of sub-actions that's entirely AI controlled.

Basic Turn Flow; Thinking, Targeting, and Executing occur on the main game while Deciding occurs on your Controller App.
A simple example of this would be Muran's Aetherbolt. You select your target, and decide you want to Aetherbolt them. The Aetherbolt action has two sub-actions: Move, Attack. The Move sub-action calculates the furthest point you can be from the target and still hit them and moves you to that location. The attack sub-action actually performs the ranged attack.

A more complicated example would be Marcus' Lance Assault. It has six sub-actions: Disengage, Move to Target, AoE Smash/Knockback, Find Random Enemy Target, Move to Target, Attack. This power has two move sub-actions in it, letting Marcus rip around the battlefield, but you don't know where you'll end up.

Because the AI is doing the movement for you, it's doing its best to guess where you should be and makes the attack. But you don't have much direct control over your position or facing when the attack is complete.

The benefit to this is each turn is important; we can ensure that nearly every turn you're doing something that has direct impact on the fight. While you can decide to just move to a specific location, most of the time you want to be doing actual actions and rolling movement into those actions allows you to spend more time doing and less time jockeying. Being too far away to do anything at all isn't something that occurs most of the time if your party is moving together as a group (if you have a laggard, well, your marching order may need work).
The left is what a Fireball would've looked like for damage areas early in development. You can see enemies acting as physical barriers. Today, it just hits everything in the AoE. However, the left side is still how we determine if you can attack someone with via melee.
The negative is, as mentioned before, lack of control over various sub-actions, including positioning. Because of that lack of control, we can't enforce too many positional requirements or it will become an exercise in frustration for players. Over the course of development, we've relaxed positional restrictions over time, allowing for ranged attacks and AoEs to go through people, deciding not to implement D&D-style attacks of opportunity, and allowing any position that isn't directly in front of someone count as "flanking".

Measuring via play testing, this relaxation has noticeably reduced player confusion and frustration. Some of it was figuring a way to communicate this information (and for the record, I don't think we're communicating the melee line of sight restriction at all currently), but a lot of it was just...the restriction wasn't fun. Players like having options, and many of the restrictions reduced what options you had on a turn-to-turn basis.


Part 2 Coming Soon

This post I talked about the original vision and what we've managed to keep from it and what we've missed, as well as the combat loop from a single-turn perspective. Part 2 next week I'll talk a bit more about the full combat loop, as well as the longer multi-combat loop.
#IndieDev #EonAltar #GameDesign