Latest Entries »

Skills that add CellEffects

I like the idea of Skills which can apply CellEffects to an AoE set of Cells; imagine a “poison cloud” skill which when used adds a poison effect to all of the Cells around a Mob for some number of turns.

To support this, I’ve added an Apply_CellEffect action and hooked it into the SkillDefn/CellEffectDefn sheets in the xls.  Now I can define a skill like this:

poisonCloud

That says that when the ‘poisonCloud’ skill is used, it should apply a AoE CellEffect with radius 2, around the caster (vs around a targeted mob) and the effect should last for 5 turns before disappearing.  The CellEffectId “poisonpit” references the CellEffectDefn I discussed in a previous post:

poisonCloud

That says that when an Actor enters the Cell with the CellEffect, take 2 HP.  That’s a fairly simplistic CellEffect, but per earlier posts, that could also just as easily apply a Buff or any other action.

The last column indicates that when the CellEffect is applied to a Cell, it should add the ‘poisonPitAdornment’ to the Cell.  This is a visual (tracked as an ItemDefn) which adds a tile and optionally light(s) and particle effect(s).  It’s defined like this:

poisonCloud

That defines the TileDefn, LightDefn, and ParticeGeneratorDefn to use when the CellEffect is applied to a Cell.

Put all of that together, and now when the user uses that skill, a cloud of poison celleffects appears around them:

Screen Shot 2013-12-29 at 8.48.40 PM

That’s all done without touching code.  It’s also a small leap from the above to a Trap which applies an AoE CellEffect around it when the Cell it’s on is entered.  First though; completing weapons/armor adding buffs and damage (et al) modifiers when equipped…

Advertisements

The reason I bought an Xbox One: http://www.capybaragames.com/below/

So. Excited. For. This. Game.

7YRL site up on ModDB

One of my core lessons learned is that when it comes to games, if you build it != they will come.  Thus, one of my goals is to do more at building community around 7YRL well before the game is live.  In that vein, I’ve started a page to track 7YRL progress on ModDB at http://www.moddb.com/games/7yrl-the-seven-year-roguelike.  I’ll still be posting here as well, but am curious to see what I can do on moddb to drive more awareness (and critical early-on feedback from folks) of 7YRL.

I spent my spare coding hours over the last few days investigating installers for Windows and Mac.  On Windows I leveraged WiX which is simultaneously a life safer and a leading cause of developer suicides; but it works.  Mac is a bit more esoteric as my Xamarin license doesn’t currently include Mac (and for $249 it’ll be a while), which means I have to deal with including Mono myself, and my non-Windows build experience is non-existent.  So: I now have a Windows installer, but Mac will have to wait a bit longer.

Here’s what you can do in the alpha:

  • Precious little.  This isn’t intended to be playable or fun – it’s just testing out infrastructure.  You can move around, single-shot mobs, see the pretty shadows, pick and and equip items, and ascend/descend levels.  All the trademarks of any AAA game!
  • You can move using arrow keys, tap to move, or clicking on the primary CAB button (upper right corner) to Explore (which currently ignores mobs and items and just explores until the map is full).  You can also use the CAB buttons to do other things like pick up items, equip them, and ascend/descend stairs.
  • Main keys: arrow keys to move, enter to perform primary cab action, 1 or 2 to perform skills 1 or 2. I, T, S, C to bring up various panes.  “-” and “+” zoom in and out a bit.

Here’s what you can’t do in the alpha:

  • Pretty much anything.  But why would you want to?

Hopefully that’ll change in time…

Here’s a link to the alpha demo. Run it like any other MSI and it’ll install into prog files with a desktop icon to launch it (and you can uninstall it using the standard Windows uninstall programs UI). Note that it may pop the Smartscreen warning when you try to run it; click ‘more info’ and then ‘run anyways’ to bypass it.

7YRL (Seven Year Roguelike) pre-pre-pre-alpha demo

(If that isn’t working yet, you can also find it here: http://www.wanderlinggames.com/7yrl/7yrlalpha.msi. )

If you try it out, let me know how it works!

Cheers,
Jeff

Skills are in and data-driven

CellEffects are event/action pairs whose events are always “OnEnter.”  It’s not a huge jump from that to Skills, whose event/action pairs will be similar except they’ll fire “OnUse.”  In fact, it’s done!  I’ve created a few sample skills to test things out; eventually players will learn skills as they play the game and activate/deactivate them as they play.

Here’s the SkillDefn sheet in the xls:

skillsxls

Looks similar to the CellEffectDefns sheet from my earlier post, except it adds a few Skill-specific columns such as which class the Skill belongs to and whether it’s Active (triggered OnUse) or passive (always active – triggered OnGainSkill and removed in OnRemoveSkill).

The code to serialize the SkillDefns into object format is dead-simple thanks to the action parser that I wrote for CellEffectDefn (and the fact that the same Event/Action infrastructure supports both):

static public class SkillPersister
{
    static public void CreateGameModelFromExcelModel(string gameVersion, ExcelQueryFactory sourceData)
    {
        GameDefinition.SkillDefns = new Dictionary<string, SkillDefn>();

        var skills = from i in sourceData.Worksheet<ExcelSkillData>("SkillDefns")
                        where i.GameVer == gameVersion
                        select i;

        foreach (ExcelSkillData skillData in skills)
        {
            // Create a new game-model from each of the Excel-Defns
            string skillId = skillData.Id.ToLower();
            GameDefinition.SkillDefns[skillId] = new SkillDefn()
            {
                Id = skillId,
                Cooldown = skillData.Cooldown,
                CharClass = (CharClass)Enum.Parse(typeof(CharClass), skillData.Class, true),
                SkillTrigger = (SkillTrigger)Enum.Parse(typeof(SkillTrigger), skillData.ActiveOrPassive, true),
                SkillAction = ActionInfoParser.Parse(skillData.OnUseAction)
            };
        }
    }
}

Given that, giving skills to the player is simple; the following code is all that’s needed to give two of the skills listed in the xls above:

newDungeon.Skills.ActiveSkills.Add(new SkillModel(GameDefinition.SkillDefns["renew"]));
newDungeon.Skills.ActiveSkills.Add(new SkillModel(GameDefinition.SkillDefns["minorhealth"]));

When the player clicks on a skill button, the following causes the skill to get used:

Action_UseSkill.Perform(Model.Skills.ActiveSkills[0], Model.PlayerChar, Model.Skills.ActiveSkills[0].SkillDefn.SkillAction);

And then the final bit of code to enable skills to work is Action_UseSkill.Perform:

public static EventResult Perform(EventableModel eventSource, EventableModel actionSource, ActionInfo actionInfo)
{
    EntityModel performingActor = actionSource as EntityModel;
    SkillModel skillModel = eventSource as SkillModel;

    // Notify listeners that the actor is about to use the skill
    if (EventMgr.FireTwoWayEvent(EventType.BeginUsingSkill, EventType.BeginBeingUsed, performingActor, skillModel) == EventResult.Cancelled)
        return EventResult.Cancelled;

    // Fire past-tense 'Performed' event.  This allows chaining of Events
    EventMgr.FireTwoWayEvent(EventType.HasUsedSkill, EventType.HasBeenUsed, performingActor, skillModel);

    return EventResult.Normal;
}

And that’s all the code that was required to add Skills.

Video time

CellEffects were previously created in code similar to this:

<pre><span style="font-family: Menlo;"> // Add poisonpit
 CellEffectTriggerEventDefn eventDefn = new CellEffectTriggerEventDefn(true);
 ActionInfo effectAction = Action_TakeDamageModel.GenerateActionInfo(1);
 GameDefinition.CellEffectDefns["poisonpit1"] = new CellEffectDefn("poisonpit1", eventDefn, effectAction);

 // Add firepit
 eventDefn = new CellEffectTriggerEventDefn(true);
 GameDefinition.BuffDefns["burning1"] =new BuffDefn()
 {
     ActionInfo = Action_TakeDamageModel.GenerateActionInfo(2),
     InitialDuration = 4,
     HasLimitedLifetime = true,
     Name = "Burning",
     Id = "burning1",
     BuffTileId = "burningbuff",
 };
 effectAction = Action_ApplyBuffModel.GenerateActionInfo(GameDefinition.BuffDefns["burning1"]);

 GameDefinition.CellEffectDefns["firepit1"] = new CellEffectDefn("firepit1", eventDefn, effectAction);</span>

Now, those are read from the xlsx like this:

effects

The code reads in the text and parses it using XmlReader to generate the event/action pairs which are attached to an OnCellEntered event on the Cell with the CellEffect.  The parsing was a little challenging because the event/actions can be recursive; the “evilGodShrine” cellEffect above demonstrates that: when an actor enters a cell with that effect, it generates an ApplyBuff action (“Evil Blessing”) which lasts 20 turns and when the actor has moved (event OnMoved), there’s a 5% chance that it will ApplyBuff another buff called “healing” that lasts for 3 turns and every turn (event OnWorldTurn) performs a Heal action on the actor for 10 HP.

Here’s what it looks like after the sub-buff has fired – both buffs are in the buff bar and counting down:

buffs

Holy cow, it worked!

This will enable me to add a ton of different CellEffects without touching code.  The same infrastructure will be used for other game features such as Skills and Item powers (e.g. giving the player a buff on equip).  I’m cautiously optimistic that it’ll be fairly easy to add those…

After adding lights and particles to cell adornment items, adding them to weapons and armor was fairly straightforward:

itemParts

The effects are just intended to show the infrastructure working, not look good.  Above the player is a piece of armor with a green glow and particles, and off to the right is a “burning bow” with light and fire.  The Burning Bow is a nice concept, and it demonstrates how I’m trying to workaround the inherent limitations in 8×8 graphics; you can only draw so many different bow shapes in an 8×8 grid ;).  But by adding lights and particles, the possibilities for adding unique items are increased (without touching code!)

Kids are up, Christmas is coming, and updates will likely be few for the next few days.  Happy Holidays!

In the last picture I hardcoded the adornments (brazier, campfire, etc) into the test map.  Now, the dungeon generation code has a random chance to pick one of the Level’s Themes’s adornments (listed in the xlsx):

randomAdornments

There are times when infrastructure work can feel like a tax that you have to get through in order to get to the really fun coding; you do a ton of work but don’t necessarily get a “look at what I did!” moment at the end of it.  But when the infrastructure is either (a) cleaning up and refactoring (aka removing code you now know isn’t needed any more; oh it feels good), or (b) enabling yourself to create new features with considerably lower effort, then it becomes more fun.  And when it’s both, it’s definitely fun; that’s what last night and tonight were.

Here’s the net result of all that work:

particles

Before explaining what’s cool about that picture, here’s what’s new in the code:

  • Major cleanup and refactoring of the persistence code.  I had been storing game state as a single monolithic file; since players can go up and down levels, I need to keep all of them around – that meant the gamestate file was eventually going to get unacceptably large.  Also, I didn’t want to store static definitions in the save file since I want the ability to change them in updates.  There are now three sets of files; “gameDefinitions.dat” which stores all ‘immutable definitions’ (mobDefn, lightDefn, cellDefn, and 15 other definition classes), “gameSlot#.dat” which stores data that spans characters (discovered recipes, total mobs killed count, settings, etc), and “level#.dat” which stores the instantiated models for a specific level (mobs, objects, etc).  Much cleaner split of persisted data
  • The problem with that is that while Protobuf-net serializes references without complaint, it can’t do it across files.  So when a model (from level#.dat) references a Defn (from gameDefinitions.dat), what protobuf actually does is store a complete copy of the defn rather than a reference to it.  This was fun to figure out since it’s practically impossible to tell that a copy was created and not a reference.  This is not what I want because I want to be able to change definitions (e.g. tweak fields) in updates, and I can’t do that if the definitions are baked into the level data.  So; Defns can safely reference Defns since both are in one file, and Models can safely reference Models since both are in one file; however, Models cannot reference Defns.  So I went through and added load-time fixups for all instances of Defns and persist the Defn Id instead of the Defns themselves. On the plus side, in the future I can update the game and modify games that are already in progress.
  • ParticleDefn and LightDefn now read from the Xlsx; itemdefns can specify up to three of each and the code handles creating them.
  • I added the concept of ‘adornment items’; in the xlsx, CellDefns can specify inclusion of an item that will automatically be created in the cell – e.g. a Brazier or a poison pit.

Mix those together and now I can define what you see in the above picture just by adding to the xlsx:

* The green circles in the upper left are slightly glowing poison pits with particle “bubbles” and a celleffect that does 1 damage when you step in it

* the burning squares in the top middle are bright glowing firepits with a fire particle effect and a celleffect that adds a debuff that does 2 damage to the actor for 3 turns

* The smaller orange fire in the center left is a new “Brazier” adornment that includes a couple of lights and three particle effects (smoke, fire, and sparks) – all defined in the xls

* The smaller orange/green fire in the center right is a new “campfire” adornment that includes its own light and a different particle effect (cylcing through colors to green as a test).  Again, all from the xls.

* As a test, I also added a dim green light and green particle effect to the skeleton mob (seen in the lower-middle), and again without touching code was able to create an entirely new and unique “poison zombie” mob.  Give it a “poison touch” skill, and you’ve got a totally brand new mob with almost no effort.

And that’s why this infrastructure work was fun