Inheritance: ConcreteObjectBuilder
Beispiel #1
0
        internal static ItemObject Create(World world, ItemObjectBuilder builder)
        {
            var ob = new ItemObject(builder);

            ob.Initialize(world);
            return(ob);
        }
Beispiel #2
0
        void OnTickStart()
        {
            if (this.Environment == null)
                return;

            if (!this.Environment.GetContents(this.Location).OfType<ItemObject>().Any(o => o.ItemID == Dwarrowdelf.ItemID.Food))
            {
                var builder = new ItemObjectBuilder(ItemID.Food, Dwarrowdelf.MaterialID.Flesh)
                {
                    Color = GameColor.Green,
                    NutritionalValue = 200,
                };
                var ob = builder.Create(this.World);

                var ok = ob.MoveTo(this.Container, this.Location);
                if (!ok)
                    ob.Destruct();
            }

            if (!this.Environment.GetContents(this.Location).OfType<ItemObject>().Any(o => o.ItemID == Dwarrowdelf.ItemID.Drink))
            {
                var builder = new ItemObjectBuilder(ItemID.Drink, Dwarrowdelf.MaterialID.Water)
                {
                    Color = GameColor.Aquamarine,
                    RefreshmentValue = 200,
                };
                var ob = builder.Create(this.World);

                var ok = ob.MoveTo(this.Container, this.Location);
                if (!ok)
                    ob.Destruct();
            }
        }
Beispiel #3
0
        static ItemObject PerformBuildItem(LivingObject builder, BuildableItem buildableItem, IEnumerable<ObjectID> sourceObjects)
        {
            if (!VerifyBuildItem(builder, buildableItem, sourceObjects))
                return null;

            var obs = sourceObjects.Select(oid => builder.World.FindObject<ItemObject>(oid));

            MaterialID materialID;

            if (buildableItem.MaterialID.HasValue)
                materialID = buildableItem.MaterialID.Value;
            else
                materialID = obs.First().MaterialID;

            var skillLevel = builder.GetSkillLevel(buildableItem.SkillID);

            var itemBuilder = new ItemObjectBuilder(buildableItem.ItemID, materialID)
            {
                Quality = skillLevel,
            };
            var item = itemBuilder.Create(builder.World);

            foreach (var ob in obs)
                ob.Destruct();

            if (item.MoveTo(builder.Environment, builder.Location) == false)
                throw new Exception();

            return item;
        }
Beispiel #4
0
        public void Die()
        {
            Trace.TraceInformation("{0} dies", this);

            this.World.AddReport(new DeathReport(this));

            var builder = new ItemObjectBuilder(ItemID.Corpse, this.MaterialID);

            builder.Name = this.Name ?? this.LivingInfo.Name;
            var  corpse = builder.Create(this.World);
            bool ok     = corpse.MoveTo(this.Environment, this.Location);

            if (!ok)
            {
                Trace.TraceWarning("Failed to move corpse");
            }

            // make a copy, as the collection will be modified
            foreach (ItemObject item in this.Inventory.ToList())
            {
                if (item.IsEquipped)
                {
                    UnequipItem(item);
                }

                item.MoveToMustSucceed(this.Environment, this.Location);
            }

            this.Destruct();
        }
Beispiel #5
0
        protected ItemObject(ItemObjectBuilder builder)
            : base(ObjectType.Item, builder)
        {
            Debug.Assert(builder.ItemID != Dwarrowdelf.ItemID.Undefined);
            Debug.Assert(builder.MaterialID != Dwarrowdelf.MaterialID.Undefined);

            this.ItemID        = builder.ItemID;
            m_quality          = builder.Quality;
            m_nutritionalValue = builder.NutritionalValue;
            m_refreshmentValue = builder.RefreshmentValue;
        }
Beispiel #6
0
        protected ItemObject(ItemObjectBuilder builder)
            : base(ObjectType.Item, builder)
        {
            Debug.Assert(builder.ItemID != Dwarrowdelf.ItemID.Undefined);
            Debug.Assert(builder.MaterialID != Dwarrowdelf.MaterialID.Undefined);

            this.ItemID = builder.ItemID;
            m_quality = builder.Quality;
            m_nutritionalValue = builder.NutritionalValue;
            m_refreshmentValue = builder.RefreshmentValue;
        }
Beispiel #7
0
        public static WaterGenerator Create(World world)
        {
            var builder = new ItemObjectBuilder(ItemID.Contraption, MaterialID.Diamond)
            {
                Name = "Water Generator",
                Color = GameColor.Blue,
            };

            var item = new WaterGenerator(builder);
            item.Initialize(world);
            return item;
        }
Beispiel #8
0
        public static void AddGem(LivingObject living)
        {
            var world = living.World;

            var materials = Materials.GetMaterials(MaterialCategory.Gem).ToArray();
            var material = materials[Helpers.GetRandomInt(materials.Length)].ID;

            var itemBuilder = new ItemObjectBuilder(ItemID.Gem, material);
            var item = itemBuilder.Create(world);

            item.MoveToMustSucceed(living);
        }
Beispiel #9
0
        ActionState ProcessAction(FellTreeAction action)
        {
            if (this.ActionTicksUsed == 1)
            {
                this.ActionTotalTicks = GetTicks(SkillID.WoodCutting);
            }

            if (this.ActionTicksUsed < this.ActionTotalTicks)
            {
                return(ActionState.Ok);
            }

            IntVector3 p = this.Location + action.Direction;

            var td = this.Environment.GetTileData(p);

            var report = new FellTreeActionReport(this, action.Direction);

            if (td.HasTree == false)
            {
                SendFailReport(report, "not a tree");
                return(ActionState.Fail);
            }

            report.TileID     = td.ID;
            report.MaterialID = td.MaterialID;

            var grassMaterials = Materials.GetMaterials(MaterialCategory.Grass).ToArray();

            this.Environment.SetTileData(p, new TileData()
            {
                ID         = TileID.Grass,
                MaterialID = grassMaterials[this.World.Random.Next(grassMaterials.Length)].ID,
            });

            if (td.HasFellableTree)
            {
                var builder = new ItemObjectBuilder(ItemID.Log, td.MaterialID)
                {
                    Name  = "Log",
                    Color = GameColor.SaddleBrown,
                };
                var log = builder.Create(this.World);
                log.MoveToMustSucceed(this.Environment, p);
            }

            SendReport(report);

            return(ActionState.Done);
        }
Beispiel #10
0
        public static void AddEquipment(LivingObject living, ItemID itemID)
        {
            var world = living.World;

            var materials = Materials.GetMaterials(MaterialCategory.Metal).ToArray();
            var material = materials[Helpers.GetRandomInt(materials.Length)].ID;

            var itemBuilder = new ItemObjectBuilder(itemID, material);
            var item = itemBuilder.Create(world);

            item.MoveTo(living);

            living.EquipItem(item);
        }
Beispiel #11
0
        ActionState ProcessAction(FellTreeAction action)
        {
            if (this.ActionTicksUsed == 1)
                this.ActionTotalTicks = GetTicks(SkillID.WoodCutting);

            if (this.ActionTicksUsed < this.ActionTotalTicks)
                return ActionState.Ok;

            IntPoint3 p = this.Location + new IntVector3(action.Direction);

            var td = this.Environment.GetTileData(p);
            var id = td.InteriorID;

            var report = new FellTreeActionReport(this, action.Direction);

            if (id.IsTree() == false)
            {
                SendFailReport(report, "not a tree");
                return ActionState.Fail;
            }

            var material = td.InteriorMaterialID;

            report.InteriorID = id;
            report.MaterialID = material;

            var grassMaterials = Materials.GetMaterials(MaterialCategory.Grass).ToArray();
            td.InteriorID = InteriorID.Grass;
            td.InteriorMaterialID = grassMaterials[this.World.Random.Next(grassMaterials.Length)].ID;

            this.Environment.SetTileData(p, td);

            if (id.IsFellableTree())
            {
                var builder = new ItemObjectBuilder(ItemID.Log, material)
                {
                    Name = "Log",
                    Color = GameColor.SaddleBrown,
                };
                var log = builder.Create(this.World);
                var ok = log.MoveTo(this.Environment, p);
                Debug.Assert(ok);
            }

            SendReport(report);

            return ActionState.Done;
        }
Beispiel #12
0
        ActionState ProcessAction(FellTreeAction action)
        {
            if (this.ActionTicksUsed == 1)
                this.ActionTotalTicks = GetTicks(SkillID.WoodCutting);

            if (this.ActionTicksUsed < this.ActionTotalTicks)
                return ActionState.Ok;

            IntVector3 p = this.Location + action.Direction;

            var td = this.Environment.GetTileData(p);

            var report = new FellTreeActionReport(this, action.Direction);

            if (td.HasTree == false)
            {
                SendFailReport(report, "not a tree");
                return ActionState.Fail;
            }

            report.TileID = td.ID;
            report.MaterialID = td.MaterialID;

            var grassMaterials = Materials.GetMaterials(MaterialCategory.Grass).ToArray();

            this.Environment.SetTileData(p, new TileData()
            {
                ID = TileID.Grass,
                MaterialID = grassMaterials[this.World.Random.Next(grassMaterials.Length)].ID,
            });

            if (td.HasFellableTree)
            {
                var builder = new ItemObjectBuilder(ItemID.Log, td.MaterialID)
                {
                    Name = "Log",
                    Color = GameColor.SaddleBrown,
                };
                var log = builder.Create(this.World);
                log.MoveToMustSucceed(this.Environment, p);
            }

            SendReport(report);

            return ActionState.Done;
        }
Beispiel #13
0
        static ItemObject PerformBuildItem(LivingObject builder, BuildableItem buildableItem, IEnumerable <ObjectID> sourceObjects)
        {
            if (!VerifyBuildItem(builder, buildableItem, sourceObjects))
            {
                return(null);
            }

            var obs = sourceObjects.Select(oid => builder.World.FindObject <ItemObject>(oid));

            MaterialID materialID;

            if (buildableItem.MaterialID.HasValue)
            {
                materialID = buildableItem.MaterialID.Value;
            }
            else
            {
                materialID = obs.First().MaterialID;
            }

            var skillLevel = builder.GetSkillLevel(buildableItem.SkillID);

            var itemBuilder = new ItemObjectBuilder(buildableItem.ItemID, materialID)
            {
                Quality = skillLevel,
            };
            var item = itemBuilder.Create(builder.World);

            foreach (var ob in obs)
            {
                ob.Destruct();
            }

            item.MoveToMustSucceed(builder.Environment, builder.Location);

            return(item);
        }
 static ItemObject CreateItem(EnvironmentObject env, ItemID itemID, MaterialID materialID, IntVector3 p)
 {
     var builder = new ItemObjectBuilder(itemID, materialID);
     var item = builder.Create(env.World);
     item.MoveToMustSucceed(env, p);
     return item;
 }
Beispiel #15
0
        ActionState ProcessAction(MineAction action)
        {
            if (this.ActionTicksUsed == 1)
                this.ActionTotalTicks = GetTicks(SkillID.Mining);

            if (this.ActionTicksUsed < this.ActionTotalTicks)
                return ActionState.Ok;

            var env = this.Environment;

            var p = this.Location + action.Direction;

            var report = new MineActionReport(this, p, action.Direction, action.MineActionType);

            var td = env.GetTileData(p);

            switch (action.MineActionType)
            {
                case MineActionType.Mine:
                    {
                        if (!td.IsMinable)
                        {
                            SendFailReport(report, "not mineable");
                            return ActionState.Fail;
                        }

                        var ds = env.GetPossibleMiningPositioning(p, MineActionType.Mine);

                        if (ds.Contains(action.Direction) == false)
                        {
                            SendFailReport(report, "cannot mine to that direction");
                            return ActionState.Fail;
                        }

                        env.SetTileData(p, TileData.EmptyTileData);

                        if (td.ID == TileID.NaturalWall)
                        {
                            MaterialInfo material = Materials.GetMaterial(td.MaterialID);
                            ItemID itemID = ItemID.Undefined;

                            switch (material.Category)
                            {
                                case MaterialCategory.Rock:
                                    itemID = ItemID.Rock;
                                    break;

                                case MaterialCategory.Mineral:
                                    itemID = ItemID.Ore;
                                    break;

                                case MaterialCategory.Gem:
                                    itemID = ItemID.UncutGem;
                                    break;
                                case MaterialCategory.Soil:
                                    break;

                                default:
                                    throw new Exception();
                            }

                            if (itemID != ItemID.Undefined)
                            {
                                if (this.World.Random.Next(21) >= GetSkillLevel(SkillID.Mining) / 25 + 10)
                                {
                                    var builder = new ItemObjectBuilder(itemID, material.ID);
                                    var item = builder.Create(this.World);
                                    item.MoveToMustSucceed(this.Environment, p);
                                }
                            }
                        }
                    }
                    break;

                case MineActionType.Stairs:
                    {
                        if (!td.IsMinable)
                        {
                            SendFailReport(report, "not mineable");
                            return ActionState.Fail;
                        }

                        if (!action.Direction.IsPlanarUpDown())
                        {
                            SendFailReport(report, "not PlanarUpDown direction");
                            return ActionState.Fail;
                        }

                        if (td.ID != TileID.NaturalWall)
                        {
                            SendFailReport(report, "not natural wall");
                            return ActionState.Fail;
                        }

                        // We can always create stairs down, but for other dirs we need access there
                        // XXX ??? When we cannot move in planar dirs?
                        if (action.Direction != Direction.Down && !env.CanMoveFrom(this.Location, action.Direction))
                        {
                            SendFailReport(report, "cannot reach");
                            return ActionState.Fail;
                        }

                        td.ID = TileID.Stairs;
                        env.SetTileData(p, td);
                    }
                    break;

                default:
                    throw new Exception();
            }

            SendReport(report);

            return ActionState.Done;
        }
Beispiel #16
0
 internal static ItemObject Create(World world, ItemObjectBuilder builder)
 {
     var ob = new ItemObject(builder);
     ob.Initialize(world);
     return ob;
 }
Beispiel #17
0
        public void Die()
        {
            Trace.TraceInformation("{0} dies", this);

            this.World.AddReport(new DeathReport(this));

            var builder = new ItemObjectBuilder(ItemID.Corpse, this.MaterialID);
            builder.Name = this.Name ?? this.LivingInfo.Name;
            var corpse = builder.Create(this.World);
            bool ok = corpse.MoveTo(this.Environment, this.Location);
            if (!ok)
                Trace.TraceWarning("Failed to move corpse");

            // make a copy, as the collection will be modified
            foreach (ItemObject item in this.Inventory.ToList())
            {
                if (item.IsEquipped)
                    UnequipItem(item);

                ok = item.MoveTo(this.Environment, this.Location);
                if (!ok)
                    throw new Exception();
            }

            this.Destruct();
        }
Beispiel #18
0
        LivingObject CreateDwarf(int i)
        {
            var builder = new LivingObjectBuilder(LivingID.Dwarf)
            {
                Color = (GameColor)m_random.Next(GameColorRGB.NUMCOLORS - 1) + 1,
            };

            switch (i)
            {
                case 0:
                    builder.Name = "Doc";
                    builder.SetSkillLevel(SkillID.Fighting, 100);
                    break;

                case 1:
                    builder.Name = "Grumpy";
                    builder.SetSkillLevel(SkillID.Fighting, 100);
                    break;

                case 2:
                    builder.Name = "Happy";
                    builder.SetSkillLevel(SkillID.Fighting, 100);
                    break;

                case 3:
                    builder.Name = "Sleepy";
                    builder.SetSkillLevel(SkillID.Fighting, 100);
                    break;

                case 4:
                    builder.Name = "Bashful";
                    builder.SetSkillLevel(SkillID.Fighting, 100);
                    break;

                case 5:
                    builder.Name = "Sneezy";
                    builder.SetSkillLevel(SkillID.Fighting, 100);
                    break;

                case 6:
                    builder.Name = "Dopey";
                    builder.SetSkillLevel(SkillID.Fighting, 100);
                    break;
            }

            var dwarf = builder.Create(this.World);

            dwarf.SetAI(new DwarfAI(dwarf));

            var gemMaterials = Materials.GetMaterials(MaterialCategory.Gem).ToArray();
            var material = gemMaterials[m_random.Next(gemMaterials.Length)].ID;

            var itemBuilder = new ItemObjectBuilder(ItemID.Gem, material);
            var item = itemBuilder.Create(this.World);

            item.MoveTo(dwarf);

            return dwarf;
        }
Beispiel #19
0
        ActionState ProcessAction(MineAction action)
        {
            if (this.ActionTicksUsed == 1)
            {
                this.ActionTotalTicks = GetTicks(SkillID.Mining);
            }

            if (this.ActionTicksUsed < this.ActionTotalTicks)
            {
                return(ActionState.Ok);
            }

            var env = this.Environment;

            var p = this.Location + action.Direction;

            var report = new MineActionReport(this, p, action.Direction, action.MineActionType);

            var td = env.GetTileData(p);

            switch (action.MineActionType)
            {
            case MineActionType.Mine:
            {
                if (!td.IsMinable)
                {
                    SendFailReport(report, "not mineable");
                    return(ActionState.Fail);
                }

                var ds = env.GetPossibleMiningPositioning(p, MineActionType.Mine);

                if (ds.Contains(action.Direction) == false)
                {
                    SendFailReport(report, "cannot mine to that direction");
                    return(ActionState.Fail);
                }

                env.SetTileData(p, TileData.EmptyTileData);

                if (td.ID == TileID.NaturalWall)
                {
                    MaterialInfo material = Materials.GetMaterial(td.MaterialID);
                    ItemID       itemID   = ItemID.Undefined;

                    switch (material.Category)
                    {
                    case MaterialCategory.Rock:
                        itemID = ItemID.Rock;
                        break;

                    case MaterialCategory.Mineral:
                        itemID = ItemID.Ore;
                        break;

                    case MaterialCategory.Gem:
                        itemID = ItemID.UncutGem;
                        break;

                    case MaterialCategory.Soil:
                        break;

                    default:
                        throw new Exception();
                    }

                    if (itemID != ItemID.Undefined)
                    {
                        if (this.World.Random.Next(21) >= GetSkillLevel(SkillID.Mining) / 25 + 10)
                        {
                            var builder = new ItemObjectBuilder(itemID, material.ID);
                            var item    = builder.Create(this.World);
                            item.MoveToMustSucceed(this.Environment, p);
                        }
                    }
                }
            }
            break;

            case MineActionType.Stairs:
            {
                if (!td.IsMinable)
                {
                    SendFailReport(report, "not mineable");
                    return(ActionState.Fail);
                }

                if (!action.Direction.IsPlanarUpDown())
                {
                    SendFailReport(report, "not PlanarUpDown direction");
                    return(ActionState.Fail);
                }

                if (td.ID != TileID.NaturalWall)
                {
                    SendFailReport(report, "not natural wall");
                    return(ActionState.Fail);
                }

                // We can always create stairs down, but for other dirs we need access there
                // XXX ??? When we cannot move in planar dirs?
                if (action.Direction != Direction.Down && !env.CanMoveFrom(this.Location, action.Direction))
                {
                    SendFailReport(report, "cannot reach");
                    return(ActionState.Fail);
                }

                td.ID = TileID.Stairs;
                env.SetTileData(p, td);
            }
            break;

            default:
                throw new Exception();
            }

            SendReport(report);

            return(ActionState.Done);
        }
        static ItemObject CreateItem(EnvironmentObject env, ItemID itemID, MaterialID materialID, IntPoint3 p)
        {
            var builder = new ItemObjectBuilder(itemID, materialID);
            var item = builder.Create(env.World);
            var ok = item.MoveTo(env, p);
            if (!ok)
                throw new Exception();

            return item;
        }
Beispiel #21
0
        void CreateItems(LivingObject living, int numItems)
        {
            var gemMaterials = Materials.GetMaterials(MaterialCategory.Gem).ToArray();

            for (int i = 0; i < numItems; ++i)
            {
                var material = gemMaterials[m_random.Next(gemMaterials.Length)].ID;
                var builder = new ItemObjectBuilder(ItemID.Gem, material);
                var item = builder.Create(living.World);

                item.MoveTo(living);
            }
        }
Beispiel #22
0
 WaterGenerator(ItemObjectBuilder builder)
     : base(builder)
 {
 }
Beispiel #23
0
        ActionState ProcessAction(MineAction action)
        {
            if (this.ActionTicksUsed == 1)
                this.ActionTotalTicks = GetTicks(SkillID.Mining);

            if (this.ActionTicksUsed < this.ActionTotalTicks)
                return ActionState.Ok;

            var env = this.Environment;

            var p = this.Location + action.Direction;

            var report = new MineActionReport(this, p, action.Direction, action.MineActionType);

            switch (action.MineActionType)
            {
                case MineActionType.Mine:
                    {
                        var terrain = env.GetTerrain(p);
                        var id = terrain.ID;

                        if (!terrain.IsMinable)
                        {
                            SendFailReport(report, "not mineable");
                            return ActionState.Fail;
                        }

                        if (!action.Direction.IsPlanar() && action.Direction != Direction.Up)
                        {
                            SendFailReport(report, "not planar or up direction");
                            return ActionState.Fail;
                        }

                        // XXX is this necessary for planar dirs? we can always move in those dirs
                        if (!EnvironmentHelpers.CanMoveFrom(env, this.Location, action.Direction))
                        {
                            SendFailReport(report, "cannot reach");
                            return ActionState.Fail;
                        }

                        ItemObject item = null;

                        if (id == TerrainID.NaturalWall && this.World.Random.Next(21) >= GetSkillLevel(SkillID.Mining) / 25 + 10)
                        {
                            ItemID itemID;
                            MaterialInfo material;

                            if (env.GetInteriorID(p) == InteriorID.Ore)
                            {
                                material = env.GetInteriorMaterial(p);
                            }
                            else
                            {
                                material = env.GetTerrainMaterial(p);
                            }

                            switch (material.Category)
                            {
                                case MaterialCategory.Rock:
                                    itemID = ItemID.Rock;
                                    break;

                                case MaterialCategory.Mineral:
                                    itemID = ItemID.Ore;
                                    break;

                                case MaterialCategory.Gem:
                                    itemID = ItemID.UncutGem;
                                    break;

                                default:
                                    throw new Exception();
                            }

                            var builder = new ItemObjectBuilder(itemID, material.ID);
                            item = builder.Create(this.World);
                        }

                        var td = new TileData()
                        {
                            TerrainID = TerrainID.NaturalFloor,
                            TerrainMaterialID = env.GetTerrainMaterialID(p),
                            InteriorID = InteriorID.Empty,
                            InteriorMaterialID = Dwarrowdelf.MaterialID.Undefined,
                            Flags = TileFlags.None,
                            WaterLevel = 0,
                        };

                        env.SetTileData(p, td);

                        if (item != null)
                        {
                            var ok = item.MoveTo(this.Environment, p);
                            if (!ok)
                                throw new Exception();
                        }
                    }
                    break;

                case MineActionType.Stairs:
                    {
                        var terrain = env.GetTerrain(p);
                        var id = terrain.ID;

                        if (!terrain.IsMinable)
                        {
                            SendFailReport(report, "not mineable");
                            return ActionState.Fail;
                        }

                        if (!action.Direction.IsPlanarUpDown())
                        {
                            SendFailReport(report, "not PlanarUpDown direction");
                            return ActionState.Fail;
                        }

                        if (id != TerrainID.NaturalWall)
                        {
                            SendFailReport(report, "not natural wall");
                            return ActionState.Fail;
                        }

                        // We can always create stairs down, but for other dirs we need access there
                        // XXX ??? When we cannot move in planar dirs?
                        if (action.Direction != Direction.Down &&
                            !EnvironmentHelpers.CanMoveFrom(env, this.Location, action.Direction))
                        {
                            SendFailReport(report, "cannot reach");
                            return ActionState.Fail;
                        }

                        var td2 = env.GetTileData(p + Direction.Up);
                        if (td2.TerrainID == TerrainID.NaturalFloor)
                        {
                            td2.TerrainID = TerrainID.StairsDown;
                            if (td2.InteriorID == InteriorID.Grass)
                            {
                                td2.InteriorID = InteriorID.Empty;
                                td2.InteriorMaterialID = Dwarrowdelf.MaterialID.Undefined;
                            }
                            env.SetTileData(p + Direction.Up, td2);
                        }

                        var td = new TileData()
                        {
                            TerrainID = TerrainID.NaturalFloor,
                            TerrainMaterialID = env.GetTerrainMaterialID(p),
                            InteriorID = InteriorID.Stairs,
                            InteriorMaterialID = env.GetTerrainMaterialID(p),
                            Flags = TileFlags.None,
                            WaterLevel = 0,
                        };

                        env.SetTileData(p, td);
                    }
                    break;

                case MineActionType.Channel:
                    {
                        if (!action.Direction.IsPlanar())
                        {
                            SendFailReport(report, "not planar direction");
                            return ActionState.Fail;
                        }

                        // XXX is this necessary for planar dirs? we can always move in those dirs
                        if (!EnvironmentHelpers.CanMoveFrom(env, this.Location, action.Direction))
                        {
                            SendFailReport(report, "cannot reach");
                            return ActionState.Fail;
                        }

                        var td = env.GetTileData(p);

                        if (td.IsClear == false)
                        {
                            SendFailReport(report, "wrong type of tile");
                            return ActionState.Fail;
                        }

                        if (!env.Contains(p + Direction.Down))
                        {
                            SendFailReport(report, "tile not inside map");
                            return ActionState.Fail;
                        }

                        var tdd = env.GetTileData(p + Direction.Down);

                        bool clearDown;

                        if (tdd.TerrainID == TerrainID.NaturalWall)
                        {
                            clearDown = true;
                        }
                        else if (tdd.InteriorID == InteriorID.Empty)
                        {
                            clearDown = false;
                        }
                        else
                        {
                            SendFailReport(report, "tile down not empty");
                            return ActionState.Fail;
                        }

                        td.TerrainID = TerrainID.Empty;
                        td.TerrainMaterialID = Dwarrowdelf.MaterialID.Undefined;
                        td.InteriorID = InteriorID.Empty;
                        td.InteriorMaterialID = Dwarrowdelf.MaterialID.Undefined;
                        env.SetTileData(p, td);

                        if (clearDown)
                        {
                            tdd.TerrainID = TerrainID.NaturalFloor;
                            tdd.InteriorID = InteriorID.Empty;
                            tdd.InteriorMaterialID = Dwarrowdelf.MaterialID.Undefined;
                            env.SetTileData(p + Direction.Down, tdd);
                        }
                    }
                    break;

                default:
                    throw new Exception();
            }

            SendReport(report);

            return ActionState.Done;
        }