Tuesday, January 24, 2012

And now for something completely different - how I'd fix the Final Fantasy series

First, a professional update: I haven't had much time to dabble with .NET lately since I've been doing PHP work for two different clients.  That said, my MVC projects are still going forward.  They're just on hiatus.

Okay, so that said, now to the meat of this post.

I decided to bite the bullet and play the Final Fantasy XIII-2 (there's a catchy name) demo this afternoon.  I was curious to see if all of the negativity surrounding XIII-proper was justified, even though fans of the series (which I used to be) told me that the demo fixed a lot of what was wrong with the original game.  Having now played (but not finished...) the demo, my response can only be: really?  The sequel's demo shows improvement over the original?  Man....

First, a quick rundown of my problems with the demo:

For starters, it's confusing/convoluted as hell.  The main characters in the demo don't have much in terms of personality or character, aside from being really, really earnest.  The backstory presented in the menu says that the girl's older sister saved the world 3 years ago, but disappeared.  The boy is a time traveler.  Shenanigans await the duo.  Of course, that's all couched in made up words and terms like fal'cie, l'cie, etc.  I was hoping for a pop'cicle, but no dice.

Combat was...odd.  It's a weird mix of a watered down job system and gambit (Bioware fans - DA tactics, but not nearly as well implemented) system.  Characters have roles - like Commando, Ravager, Sentinel, etc. - which gives them access to certain abilities.  Combinations of these jobs (like, setting the girl as Medic and the guy as Commando) are called Paradigms.  These Paradigms can be changed on the fly by pressing LB/L1 and selecting a new mix.  Cleverly(?), this is known as a Paradigm Shift. 

Confused yet?  It actually makes sense in play.  Unfortunately, since the game rewards speed, generally all one needs to do is select Auto Attack, which will let the AI do what it thinks is best.  As a longtime fan of the FF series, this strikes me as funny.  The series has always been derided for its combat because in the vast majority of cases simply choosing Attack is the most efficient way to progress.  XIII adds all these layers to combat, yet Auto Attack is still the best option.  I've heard that Paradigm Shifting is necessary for the endgame/hidden content, but still, press A/X to win is still the name of the game 25 years after the original Final Fantasy was released.

There are some other small things, like the camera being too close to the characters while walking, the continued existence of battle screens, poor UI, etc.  Ultimately, as I played the demo, one thought kept repeating itself in my head - for a game that's all about speed (battles are timed, the pace in battles is the fastest its ever been in a FF game), it sure is slow.  Walking around is boring.  Conversations are needlessly wordy.  There's no emotion aside from a vague desire to stop/find something/someone.  And as someone who can handle, and even enjoy, badly paced games (hello Xenogears and Xenosaga), that's saying something.

---

So, how would I change things?

First, remove random encounters.  They've never been challenging, and they're really just a time sink.  All encounters should be relevant to the main plot or side quest.  Since that would likely limit the number of encounters, make them more difficult.  Ultimately, the goal should be to make encounters meaningful.  Having to kill a group of imps every 10-20 steps only serves to annoy the player.

Second, give the player multiple ways to complete a quest.  Final Fantasy quests fall into three categories:

Ultimate weapon/summoned monster quests, which require a bit of exploration and a lot of annoying mini-games.

Fetch/return quests.

Combat.

Sometimes they're mixed together (do hidden thing X, take secret thing Y, and kill super monster Z), but those are the general categories.  While there is something to be said about solving a convoluted puzzle (and, really, classic gaming is all about that), they feel increasingly rigid in settings as large and detailed as a FF game's.

Third, better character balance.  FF characters have the annoying tendency to be functionally the same (see: FF VI, VII, VIII, XII (to a certain extent)).  Jobs (character classes - fighter, white mage, black mage, ninja, etc.) are a great way to provide party balance, as they force the player to define roles for their characters early on.  Deviating from those roles is exceedingly inefficient, and not worth the hassle (unless you're playing a FF Tactics game, which is a different can of worms).

The problem with jobs is that there's not a lot of choice within the jobs themselves.  Usually, players will choose a job to learn key abilities, then ditch it for another. 

I suggest going the opposite route: have characters be locked into their jobs, but give the player a myriad of abilities to choose from.  From a story perspective, it makes more sense - a highly trained warrior isn't going to say "You know what?  I'm going to be a mystic healer today." - and it gives each character a role to call their own, eliminating the sameness problem.

My final suggestion deals with plot and presentation.  FF games have been pretty batshit insane/convoluted over the last 15 years or so.  Not that that's bad in and of itself.  My problem is that, generally speaking, whatever good ideas are in a FF story are buried under a mound of jargon and/or minutia, to say nothing of the Japanese-style "Say, don't show" storytelling.  If we're talking economy of plot, FF games need some TARP money.

Obviously, a good deal of this is cultural, so I'm trying to tread carefully.  That said, the older, technologically limited games in the series still had insane stories, but they were conveyed in a more concise, and thus more powerful, way.  Hell, IV's endgame has the heroes fly to a moon in a damn whale-shaped spaceship.  The moon is also a spaceship.  Crazy is part of the series, and I wouldn't want it any other way.

Unfortunately, the games have become increasingly suffocating.  The signal-to-noise ratio has dipped to 24.4k modem levels, complete with shrieking sound.  There are whole sections of IX, X, and XII that could be removed without affecting the plot at all.  That, to me, is a very large problem, and one that seems to be getting worse as the series moves on.

So, to tie this back to my first suggestion, make things meaningful.  This doesn't mean that everything must tie into the main plot.  I love side quests that flesh out settings and characters, even if it doesn't move the main plot forward an inch.  Just, remove the crap and clutter.  Let the setting and characters breathe.  Don't be afraid of emotions beyond earnestness, vague evil, and the ever Japanese protection promise.  Make the world's heart and soul shine as much as its graphics.

Monday, August 15, 2011

Small update

Still breathing, still wrapping things up.  Trying to do a fair amount of testing before unleashing the first site on the world.  Next up: uploaded image validation testing.

With all of my previous EF4 issues, I had a lot of duplicate table rows, which really screwed up some of my model structure, so I've spent the last little bit rebuilding my test db and EF model.  Should be ready to go tomorrow.

Something to add to my "Microsoft should focus on the following when trying to get people in on the ground floor" list:

A crash course in core OOP patterns.  Factories, IoC, Repositories, various data patterns, etc.  The kinds of things a MVC coder will undoubtedly run across early on.  Just an idea.

Monday, July 18, 2011

Objects in mirror are closer than they appear

What's this?  A non-bitchy, non-whining, perhaps even HAPPY blog post?!

Yup.

I'm inching closer to the finish line.  A bunch of not hard, tedious stuff (tightening up the graphics on level 5, and whatnot), and one non-trivial design decision (nothing major, just trying to figure out how to address something in a somewhat intelligent way), and it's done.

I've actually learned a lot during this process.  I'm anxious to see how things flow with a fresh project, to see if I've learned what I think I've learned.

Tuesday, June 28, 2011

Our long national nightmare is over

Creating/editing my complex EF4 entity graph with a many-to-many relationship finally works the way I intended.  I... I'm not sure what to say.  More shock than happiness right now.

My biggest issue, as you know, was figuring out what the ObjectContext expected of me.  When to attach/detach/add/remove... it's a frustrating dance to engage in, and at times even complex.  A lot of that fumbling stemmed from my inexperience, which is part of the reason why I'm doing this.  I need to get this right, even if I go kicking and screaming.

The other problem is myself (cue: "I could've told you that").  I get tunnel vision, and I'm stubborn as a mule.  That's not a good combination.

Unsurprisingly, the solution was simple, so simple it's embarrassing.  That's something else I do - write convoluted code, and then whittle it down (again, while kicking and screaming) until the solution is a mere handful of lines.  I guess my brain needs to contort itself for a bit before discovering the right way to go.

A special shout out to Julie Lerman, who humored me both on Stack Overflow and Twitter, and who must surely think I'm some sort of psycho stalker.  Thank you.

So... maybe I can get this thing finished this month.  Whodathunkit?

Friday, June 24, 2011

AutoMapper? More like DeciptiMapper

Well, it looks like AutoMapper has a bug in its AfterMap and BeforeMap methods.  Specifically, if you try to use a loop in order to populate the destination object with values derived from the source object, the Map methods themselves are invoked multiple times.  Not cool when dealing with EF4.  I now have several copies of the same Platforms in my test db.  Yay four extra XBox 360, PS3, and PC entities!

As always, a link to SO: http://stackoverflow.com/questions/6460177/extra-iterations-in-a-foreach-in-an-automapper-map/6473451#6473451

Thursday, June 23, 2011

Same as it ever was reprise

More 'fun' with Entity Framework 4, ASP.NET MVC, and many-to-many relationships.

Change tracking in EF4 is actually pretty good.  The problem comes when you're trying to edit an existing Entity with data from an outside source.  Then, the whole thing goes to shit, and you're forced trying to figure out exactly what to do all while the system is throwing vague exceptions telling you you can't do what you want to do.  And, naturally, all of the demos/tutorials I've seen are based on moronic demoware that anyone could figure out.  No real world examples anywhere to see.

I don't feel like blowing up the project structure I have simply because EF4 is acting like a bitch.  Part of this project is so I can learn how to do things the right, professional, ideal way, which is what I'm going to do.

Even if it kills me.

Like always, a link to SO: http://stackoverflow.com/questions/6460071/ef4-problems-w-mvc-entitykey-many-to-many-relationships-etc-what-fundamental

Thursday, June 2, 2011

I'll give YOU an ObjectContext! *angry fist shake*

Here's what's going on with my ASP.NET MVC 2/Entity Framework 4.0 project:

I have two VS projects in my solution.  One is the domain, which contains my EF entities and repositories, and the other is the web UI, which contains the MVC bits and pieces.  I'm trying to do things the right way, so my web UI can have references to the domain, but the domain shouldn't have references to the UI.  My repositories are injected into my controllers via Ninject interface injection.  Simple enough.

I had my Create/Edit Game code working, but it was ugly.  I was partially binding directly to a Game entity, but for the complex stuff I was passing along other form data directly to the repo's Save method, wherein I would do what I needed to do to build/rebuild the many-to-many relationship between Games and their respective Platforms.  It worked, but it was ugly, especially since it required one of my repository interfaces (remember, they're injected into the controllers by the interface, so I use that API in the controllers rather than casting them as their concrete selves) to accept extra data in order to do its job.  That seems like a layer/coupling issue to my novice senses.  I just want a nice, clean public void SaveGame(Game game) method.  So, it was both a cosmetic and design decision to bind incoming data to a DTO, and then map it to the Game entity.

The problem is now the many-to-many relationship I'm trying to (re)build between Games and Platforms is throwing ObjectContext exceptions at me, and I'm not sure why.  I'm getting two kinds of exceptions - one is telling me that my Platform entities cannot be Added to my Game because they exist in different ObjectContexts.  The other I'll explain a little later.  I've tried 'registering' a new, null Game object by Attach/AddObject-ing it to my context like so:

Controller:
Game game = new Game();
_gameRepository.RegisterGame(game);

Repository:
public void RegisterGame(Game game)
{
    _siteDB.Games.Attach(game);
}

I tried all the variants in the register method: _siteDB.Attach(game), _siteDB.Games.Attach(game), _siteDB.Games.AddObject(game).  All gave me the same exception.

When I tried Adding the Platforms by just their EntityKeys (game.Platforms.Add(new Platform { EntityKey = src.EntityKey })), I would get an exception informing me that the entities I was trying to save had EntityKeys which already matched those within the ObjectContextManager, most likely because the Platforms already exist.

So, at this point, I'm not 100% sure how to move forward.  I don't understand why my old version of attaching the entity to the context and manipulating the Platform data originally worked, but now its not.  It's almost as though my Attach/AddObject invocations are losing scope because I'm doing it through a repository interface.  Odd, and frustrating.

Code and more detail here: http://stackoverflow.com/questions/6195167/problems-trying-to-attach-a-new-ef4-entity-to-objectcontext-while-its-entity-coll