I’ve finished the refactoring of the Events and Actions system.  I’m quite happy with the results; it removes the need for derived Event objects, works for Items and (when they’re in place :)) Skills, Buffs, and CellEffects.  It’s still hookable so that any event can be filtered or modified.  As an example, here’s the Item that the Player starts with for now:

    <Weapon Id="Axe1" Name="Rusty Hatchet" Subclass="Axe" WeaponPower="10" ItemLevel="1" Level="1-3"
            Tile="AxeBeaked" Description="A rusty hatchet">
      <Event Type="MeleeAttackHit">
        <MagicMapping Amount="10%"/>
        <Heal Amount="1%" Target="Self" />
      </Event>
    </Weapon>

When a MeleeAttack hits, the above actions are triggered automatically. The cool thing is that those same Actions can be triggered in a Skill by a SkillUsed event or by a Cell by a CellEntered event.

Here’s the list of currently hookable events; as new Actions come online, they’ll get added as well:

    public enum EventType
    {
        Unassigned,
        MeleeAttackStarted, MeleeAttackMissed, MeleeAttackDodged, MeleeAttackBlocked, MeleeAttackHit,
        DidDamageToActor, DamageDoneByActor,
        EnteringCell, ExitingCell,
        AddingBuff, BuffAdded,
        StartMagicMapping, DoneMagicMapping,
        StartHealing, DoneHealing,
        StartTeleporting, DoneTeleporting,
        OpeningDoor, OpenedDoor,
        StartResting, DoneResting,
    };

The hooking opportunity itself is provided by the Actions themselves. For instance, here’s the code for an OpenDoor Action:

    public class Action_OpenDoor : Action
    {
        internal static Action_OpenDoor Create(Actor actor, Direction nextDir)
        {
            // Obtain an Action from the object pool (or if none are in it, alloc a new one).
            Action_OpenDoor action = ObjectPool.IsEmpty ? new Action_OpenDoor() : ObjectPool.GetFreeObject();

            // Initialize fields in the newly obtained Action.
            action.Info.PerformingObject = actor;
            action.Info.Direction = nextDir;

            return action;
        }

        internal override void Release()
        {
            ObjectPool.Release(this);
        }

        public override void Perform(ActionInfo actionInfo)
        {
            Actor movingActor = actionInfo.PerformingActor;

            // Notify the system that we're performing this Action; this allows other things to hook into it and modify/filter the event
            if (!FireEvent(actionInfo, EventType.OpeningDoor))
                return;
            
            // Get a pointer to the neighboring Door Cell's state, and set it to open
            Cell_Door doorCell = movingActor.Location.Neighbor(actionInfo.Direction)  as Cell_Door;
            doorCell.Open();

            FireEvent(actionInfo, EventType.OpenedDoor);
        }

        static ObjectPool ObjectPool = new ObjectPool();
    }

So in the above example, a Map could opt to – for whatever reason – disallow Events of type OpeningDoor, and filter out the event above.

Updated source: http://wanderlinggames.com/files/dungeon/dungeon-3-29-11.zip

Updated executable: http://wanderlinggames.com/files/dungeon/dungeonexe-3-29-11.zip

 

Advertisements