Opportunity Knocks You Down

Finally got the basics of turn-tracking running much more smoothly (could still use some better visual cues in the client). After establishing initiative, I moved the creature with the highest initiative.

Immediately, a prerequisite dialog box pops on the client (the server wants me to provide some feedback). No useful data on the screen (a prerequisite for which I haven’t provided a DataTemplate), and no title (I hadn’t put a key or name on it either!).

The host tells the story…I am being asked if I want to make an opportunistic attack. I realize I have provoked an opportunity against myself!

Apparently I hadn’t excluded the actor from the weapon strike zones capturing the location I am moving from. I imagine attacking myself as I leave my own threatened cube.

OK. So I add a filtering expression to the “where” clause of the LINQ. Now I can walk (both actors in alternating turns) until they get to the middle room (within line of sight of each other). About 4 rounds of game-turn time. Then I get another opportunistic inquiry (even though they are a good 40+ feet from each other. I’ll check the LINQ tomorrow in debug mode to see what’s going on.


Delays

A few days back I ran an initial test with the LocalTurnTracker. Even though the Ikosa Framework is turn-based, I hadn’t really used turn-based tracking yet. Instead I had been doing all my action testing (movement, item slot, and door manipulation) using an alternate mode of operation that I call time-tracking. In this mode, multiple clients can act more-or-less simultaneuously (a read-writer lock is employed to block true simultaneous updates to the game state). The idea is to have this time-tracker auto-pump a single turn-tick on a regular basis (about 6 seconds) if there is no activity, and slow it down if there is pending activity or an “intention” to act. Currently, I don’t have the auto-pump setup, so at least one of the clients has to end the turn, while no one else is using their turn.

Anyway, I fired up a LocalTurnTracker initialized to track initiative. It queues up one roll-check prerequisite for each actor added to the tracker. My first explosion was when I had two clients attempting to send back their results. The service call to set a prerequisite value only uses the BindKey to find the first matching prerequisite, and unfortunately all the roll-check prerequisites had the same key. And then the security kicked in, because the client had to be in the role of the actor associated with the prerequisite, and one of the actors was always finding the other’s roll-check.

That was easy enough to fix, simply make the BindKey based on the actor-id.

Once past that, I ran into another crash on one of the clients (wasn’t running the clients in debug mode). The host was locked with an unfulfilled ActionInquiryPrerequisite, which is a holding prerequisite intended to be cleared after the actor associated with it has acted (or deferred action). Looking at this, I realized I had a bunch of things I needed to re-work in this area; and edge and core cases to ensure I had covered.

So I absorbed what I had coded before (somewhat), overcame the pit in my stomach on hacking through this at this point, and got down to hacking through it…inch by inch. Which is where I am now.

The main complexity is in dealing with delays, and by that, I mean an actor delaying his turn until a future point in time. (And how I get caught up in things that delay me…)


Trade Names

For me, “Ikosa” was always the name of my underlying game-modeling framework. Almost always…in the early stages it was “Icosa”. However, I never intended it to be the name of any game product. Ikosa just doesn’t roll off the tongue. Nor does it imply much about the nature of any game product built on it.

Since I have multiple ideas on how to use the framework, I had multiple ideas of trade names. And these have been through some churn also.

My main motivation (fully automating turn-based pen-and-paper game mechanics for multiple players) is the one I have cared most about. I call that “Guildsmanship”. Of all the non-conflicting names I could think up (with the help of a thesaurus) it is the one that has seemed to resonate the best.

My motivation for Battlescape has been varied. I have gone back and forth several times on whether to push a turn-based team-battle (TB2) system (which doesn’t showcase all the framework features such as searching, disabling, opening doors and chests; versus being able to push out a playable demonstration (with things like various vision modes, lighting, and flight).

Anyway, I settled on Battlescape to get a playable demonstration; versus video captures of the tools. But then I went back and checked the name.

The name “Battlescape” is too loaded with prior products. Hence back to the thesaurus. And the internet. Nothing I found seems to come close to the simplicity of the term (except the very generic TB2: Turn-Based Team-Battles). So I decided to stick with it, and add the unique monicker “Guildsmanship” in front of it to get “Guildsmanship: Battle-Scapes”.

OK. So now I get “Guildsmanship” as a brand-name rather than a product name. What to do about Castle Hackenslash? Punt…worry about it later.


Resizing a C# UNION

I have been testing out the *basic* BattleScape scenario (two creatures in a map with an initiative-based turn-tracker), and noticed a problem with rendering one of the cell-types in the client. At each I was expecting a step, I was getting a block.  Fortunately I knew from the workshop and host that the map cell-data was correct as it rendered correctly.  Also, since the Uzi.Visualize assembly is shared (currently the only bit of code so shared) between the Client and Core assemblies, it wasn’t a rendering glitch.  The problem had to be in marshaling the data between application domains.

For background, I have divided cell structural types into “Template” and “Parameter” parts.  I build cell-structure templates (indexed) that can be used for multiple cells, and keep a list with the local tactical map.  This is the equivalent of deciding what types of bricks I want to use.  Physical characteristics (materials and relative dimensions from cell edges) are stored in the template.  If I want a 1 foot sliver of rock (the rest being air) bound to a face, and a 2 foot sliver of rock bound to a face, I need 2 templates.  The “Parameter” data contains useful situational data, that varies based on the Template base-class needs.  A solid CellSpace doesn’t rely on parameter data for anything, but a SliverCellSpace needs binding face information to know how to orient itself.  Other cell types (such as CornerCellSpace, WedgeCellSpace, LFrameCellSpace and Stairs) need even more data to orient themselves correctly.

To keep room data fairly compact, the room holds information about the room dimensions, and a three dimensional array of structures that holds both the references to the templates, and the parameters, for each cell in the room.  When I serialize the cell data into a data contract for the room, I yield an array of unsigned values, where each value combines one cell’s template index and its parameter data.  Rather than doing this programmatically, I simply used a structure with explicit layout and jammed the fields next to each other so I could read them with an overlapping larger field (similar to a UNION in C).

Herein lay my problem.  When I created this scheme, I was using unsigned short (ushort) values for the index and parameter values, and the complete value was an unsigned integer (uint):

namespace Uzi.Visualize
{
  [StructLayout(LayoutKind.Explicit, Pack=2)]
  public struct IndexStruct
  {
    [FieldOffset(0)]
    public ushort Index;
    [FieldOffset(2)]
    public ushort StateInfo;
    [FieldOffset(0)]
    public uint ID;
  }
}

At some point I found/felt the need to make the parameter an unsigned integer (uint), so naturally I bumped the index as well.  Keep in mind that this re-sizing happened in many more places than this data contract.  And it all worked well in the Host and Workshop (Core assemblies). What I missed was when I refactored the ushorts to uints was the full impact on this structure. What I was left with is:

namespace Uzi.Visualize
{
  [StructLayout(LayoutKind.Explicit, Pack=4)]
  public struct IndexStruct
  {
    [FieldOffset(0)]
    public uint Index;
    [FieldOffset(2)]
    public uint StateInfo;
    [FieldOffset(0)]
    public uint ID;
  }
}

The correct form is:

namespace Uzi.Visualize
{
  [StructLayout(LayoutKind.Explicit, Pack=4)]
  public struct IndexStruct
  {
    [FieldOffset(0)]
    public uint Index;
    [FieldOffset(4)]
    public uint StateInfo;
    [FieldOffset(0)]
    public ulong ID;
  }
}