Saturday, May 22, 2010

Rethinking Attacks

So it's been a quiet release day, especially considering the time I posted. I cleaned out the 'EventDB' class which used to handle the wacky reaction dispatch as well as POE timing. Now it's just the latter. I had started a crappy attempt at a turn-based mode as well last summer, but I've cleaned all that code out. I'll start fresh later. It's easiest to think in terms of normal time... action order will easily translate; take the "2.5 second lag" after casting a spell and compare it with the "0.9 movement lag." Presto, a priority queue.

But right now I want to think about attacks, the last thing left to "fix," and also the thing that's keeping cool tricks like the explosion effect working. I'll talk about what exists from the old client-server days, and that process will probably help me realize how I should design it now.

Attacks have effects aside from immediate damage... draining a stat, preventing a stat from regenerating, preventing movement or attacking, stealing an item from the victim, suicide of the attacker, summoning more monsters, cursing an item... really simple stuff, actually. Some of them entail things happening on the clientside, which gets confusing of course when client and server are technically one (the standalone/singleplayer version)... but that just means take out networking and run "fullsim" (full simulation) and graphics code.

The tough part seems to be my stage system. Right now, actions are split into 4 phases... PRE occurs only for human players, that's to figure out an action entirely, as in choosing what to drop or what ability to use. BEFORE happens only in fullsim (server or standalone, not multiplayer client) and ensures the action is valid. I also cheat a few times and perform fullsim-only things. Then ON and AFTER happen everywhere. Most graphical things occur in AFTER's, my new trick is to "inject" these actions into the appropriate object rather than muck about with a wacky event dispatch system or if (we're supposed to draw stuff) { then draw it }. So anyway, the stages presently:

stage 1: transform 'aim west' or whatever into a list of targets. "ranges" could be: adjacent, custom (for fun fireball effects), a straight line that terminates or continues as it hits targets, and a block shape. The challenge is that most of these ranges, even if the attack fails or doesn't hit anything, entail something being drawn. Stage 1 is called in BEFORE, so it's a tad messy to just send a list of map tiles to update if we're the server, yet... we do that! I'm thinking of determining targets in stage 1, serializing that information intelligently, and simulating stages 2 and 3 in ON and AFTER like normal.

stage 2: Ah, I remember why I split these. What about delayed attacks? We calculate targets as soon as the attack is requested, but we don't want to deduct HP and print messages until the attack would hit the right target. The timing right now is completely graphics-based, but it actually makes sense to separate this out a bit.. graphics and damage both depend on timing, which is a game-state concept. (The fireball travels at 1 square per 0.25 seconds) Confusingly, stage2 / ON also calculates damage.. That's problematic. Damage calculation involves random numbers often, so it's too late to distribute more information. But since all stats are maintained by the full-sim component and sent to the client if we're networking... things should still work out.

stage3: Pretty much run through effects. Oh, and this is where I was printing damage messages. Hrmm.

Well it's late now, but I have a better idea of what to rehaul in the morning, and I've given you a startling insight into my thinking process. My apologies.

No comments:

Post a Comment