Exemple #1
0
        /// <summary>
        /// Forcefully adds parsed content elements to this container.
        /// </summary>
        /// <param name="tile">The tile to add content to.</param>
        /// <param name="contentElements">The content elements to add.</param>
        private void AddContent(ITile tile, IEnumerable <IParsedElement> contentElements)
        {
            contentElements.ThrowIfNull(nameof(contentElements));

            // load and add tile flags and contents.
            foreach (var e in contentElements)
            {
                foreach (var attribute in e.Attributes)
                {
                    if (attribute.Name.Equals("Content"))
                    {
                        if (attribute.Value is IEnumerable <IParsedElement> elements)
                        {
                            var thingStack = new Stack <IThing>();

                            foreach (var element in elements)
                            {
                                IItem item = this.ItemFactory.CreateItem(ItemCreationArguments.WithTypeId((ushort)element.Id));

                                if (item == null)
                                {
                                    this.Logger.LogWarning($"Item with id {element.Id} not found in the catalog, skipping.");

                                    continue;
                                }

                                this.SetItemAttributes(item, element.Attributes);

                                thingStack.Push(item);
                            }

                            // Add them in reversed order.
                            while (thingStack.Count > 0)
                            {
                                var thing = thingStack.Pop();

                                tile.AddContent(this.ItemFactory, thing);

                                if (thing is IContainedThing containedThing)
                                {
                                    containedThing.ParentContainer = tile;
                                }
                            }
                        }
                    }
                    else
                    {
                        // it's a flag
                        if (Enum.TryParse(attribute.Name, out TileFlag flagMatch))
                        {
                            tile.SetFlag(flagMatch);
                        }
                        else
                        {
                            this.Logger.LogWarning($"Unknown flag [{attribute.Name}] found on tile at location {tile.Location}.");
                        }
                    }
                }
            }
        }
Exemple #2
0
        /// <summary>
        /// Attempts to load all tiles within a 3 dimensional coordinates window.
        /// </summary>
        /// <param name="fromX">The start X coordinate for the load window.</param>
        /// <param name="toX">The end X coordinate for the load window.</param>
        /// <param name="fromY">The start Y coordinate for the load window.</param>
        /// <param name="toY">The end Y coordinate for the load window.</param>
        /// <param name="fromZ">The start Z coordinate for the load window.</param>
        /// <param name="toZ">The end Z coordinate for the load window.</param>
        /// <returns>A collection of ordered pairs containing the <see cref="Location"/> and its corresponding <see cref="ITile"/>.</returns>
        public IEnumerable <(Location Location, ITile Tile)> Load(int fromX, int toX, int fromY, int toY, sbyte fromZ, sbyte toZ)
        {
            if (fromZ != 7)
            {
                return(Enumerable.Empty <(Location, ITile)>());
            }

            var tuplesAdded = new List <(Location loc, ITile tile)>();

            for (int x = fromX; x <= toX; x++)
            {
                for (int y = fromY; y <= toY; y++)
                {
                    var groundItem = this.ItemFactory.CreateItem(ItemCreationArguments.WithTypeId(GrassTypeId));

                    var location = new Location()
                    {
                        X = x, Y = y, Z = fromZ
                    };
                    var newTuple = (location, this.TileFactory.CreateTile(location, groundItem));

                    tuplesAdded.Add(newTuple);
                }
            }

            foreach (var(loc, tile) in tuplesAdded)
            {
                this.tilesAndLocations.TryAdd(loc, tile);
            }

            return(tuplesAdded);
        }
Exemple #3
0
        /// <summary>
        /// Executes the operation's logic.
        /// </summary>
        /// <param name="context">A reference to the operation context.</param>
        protected override void Execute(IElevatedOperationContext context)
        {
            if (this.Creature is IPlayer player)
            {
                this.SendNotification(context, new TextMessageNotification(() => player.YieldSingleItem(), MessageType.EventAdvance, "You are dead."));

                this.SendNotification(context, new GenericNotification(() => player.YieldSingleItem(), new PlayerCancelWalkPacket(player.Direction), new PlayerDeathPacket()));
            }

            // Remove the creature...
            if (context.Map.GetTileAt(this.Creature.Location) is ITile creatureTile)
            {
                // Add the corpse.
                var corpseCreationArguments = new ItemCreationArguments()
                {
                    TypeId = this.Creature.CorpseTypeId,
                };

                if (context.ItemFactory.Create(corpseCreationArguments) is IThing corpseCreated && this.AddContentToContainerOrFallback(context, creatureTile, ref corpseCreated))
                {
                    context.GameApi.CreateItemAtLocation(creatureTile.Location, context.PredefinedItemSet.FindPoolForBloodType(this.Creature.BloodType));
                }

                this.RemoveCreature(context, this.Creature);
            }
        }
Exemple #4
0
        /// <summary>
        /// Attempts to load all tiles within a map window.
        /// </summary>
        /// <param name="window">The parameters to for the window to load.</param>
        /// <returns>A collection of <see cref="ITile"/>s loaded.</returns>
        public IEnumerable <ITile> Load(IMapWindowDimensions window)
        {
            window.ThrowIfNull(nameof(window));

            if (window.FromZ != 7)
            {
                return(Enumerable.Empty <ITile>());
            }

            var tiles = new List <ITile>();

            for (int x = window.FromX; x <= window.ToX; x++)
            {
                for (int y = window.FromY; y <= window.ToY; y++)
                {
                    var groundItem = this.itemFactory.CreateItem(ItemCreationArguments.WithTypeId(GrassTypeId));

                    var location = new Location()
                    {
                        X = x, Y = y, Z = window.FromZ
                    };
                    var newTile = this.tileFactory.CreateTile(location, groundItem);

                    tiles.Add(newTile);
                }
            }

            return(tiles);
        }
Exemple #5
0
        private void SetItemAttributes(IItem item, IList <IParsedAttribute> attributes)
        {
            if (attributes == null)
            {
                return;
            }

            foreach (var attribute in attributes)
            {
                if ("Content".Equals(attribute.Name) && item is IContainerItem containerItem)
                {
                    if (!(attribute.Value is IEnumerable <IParsedElement> contentElements) || !contentElements.Any())
                    {
                        continue;
                    }

                    foreach (var element in contentElements)
                    {
                        IItem contentItem = this.ItemFactory.CreateItem(ItemCreationArguments.WithTypeId((ushort)element.Id));

                        if (contentItem == null)
                        {
                            this.Logger.LogWarning($"Item with id {element.Id} not found in the catalog, skipping.");

                            continue;
                        }

                        this.SetItemAttributes(contentItem, element.Attributes);

                        // TODO: we should be able to go over capacity here.
                        containerItem.AddContent(this.ItemFactory, contentItem, 0xFF);
                    }

                    continue;
                }

                // These are safe to add as Attributes of the item.
                if (!Enum.TryParse(attribute.Name, out CipItemAttribute cipAttr) || !(cipAttr.ToItemAttribute() is ItemAttribute itemAttribute))
                {
                    this.Logger.LogWarning($"Unsupported attribute {attribute.Name} on {item.Type.Name}, ignoring.");

                    continue;
                }

                try
                {
                    item.Attributes[itemAttribute] = attribute.Value as IConvertible;
                }
                catch
                {
                    this.Logger.LogWarning($"Unexpected attribute {attribute.Name} with illegal value {attribute.Value} on item {item.Type.Name}, ignoring.");
                }
            }
        }
        /// <summary>
        /// Executes the operation's logic.
        /// </summary>
        /// <param name="context">A reference to the operation context.</param>
        protected override void Execute(IOperationContext context)
        {
            if (this.Creature is IPlayer player)
            {
                this.SendNotification(context, new TextMessageNotification(() => player.YieldSingleItem(), MessageType.EventAdvance, "You are dead."));

                this.SendNotification(context, new GenericNotification(() => player.YieldSingleItem(), new PlayerCancelWalkPacket(player.Direction), new PlayerDeathPacket()));
            }

            // Give out the experience if this is a monster
            if (this.Creature is IMonster monster && monster.ExperienceToYield > 0 && this.Creature is ICombatant monsterCombatant)
            {
                ulong totalDamageDealt = (ulong)monsterCombatant.DamageTakenInSession.Sum(t => t.Damage);

                foreach (var(combatantId, damage) in monsterCombatant.DamageTakenInSession)
                {
                    if (damage == 0)
                    {
                        continue;
                    }

                    var expPercentage = Convert.ToDecimal(damage) / totalDamageDealt;
                    var expToGive     = (long)Math.Round(monster.ExperienceToYield * expPercentage, 0, MidpointRounding.ToEven);

                    if (expToGive == 0)
                    {
                        continue;
                    }

                    if (context.CreatureFinder.FindCreatureById(combatantId) is ICombatant combatantGainingExp)
                    {
                        combatantGainingExp.AddExperience(expToGive);
                    }
                }
            }

            // Remove the creature...
            if (context.Map.GetTileAt(this.Creature.Location) is ITile creatureTile)
            {
                // Add the corpse.
                var corpseCreationArguments = new ItemCreationArguments()
                {
                    TypeId = this.Creature.CorpseTypeId,
                };

                context.GameApi.RemoveCreatureFromGame(this.Creature);

                if (context.ItemFactory.Create(corpseCreationArguments) is IThing corpseCreated && context.GameApi.AddContentToContainerOrFallback(creatureTile, ref corpseCreated))
                {
                    context.GameApi.CreateItemAtLocation(creatureTile.Location, context.PredefinedItemSet.FindPoolForBloodType(this.Creature.BloodType));
                }
            }
        }
Exemple #7
0
        /// <summary>
        /// Executes the operation's logic.
        /// </summary>
        /// <param name="context">A reference to the operation context.</param>
        protected override void Execute(IOperationContext context)
        {
            if (this.Creature is IPlayer player)
            {
                this.SendNotification(context, new PlayerDeathNotification(player));
            }

            // Give out the experience if this is a monster
            if (this.Creature is IMonster monster && monster.ExperienceToYield > 0 && this.Creature is ICombatant monsterCombatant)
            {
                ulong totalDamageDealt = (ulong)monsterCombatant.DamageTakenInSession.Sum(t => t.Damage);

                foreach (var(combatantId, damage) in monsterCombatant.DamageTakenInSession)
                {
                    if (damage == 0)
                    {
                        continue;
                    }

                    var expPercentage = Convert.ToDecimal(damage) / totalDamageDealt;
                    var expToGive     = (long)Math.Round(monster.ExperienceToYield * expPercentage, 0, MidpointRounding.ToEven);

                    if (expToGive == 0)
                    {
                        continue;
                    }

                    if (context.CreatureManager.FindCreatureById(combatantId) is ICombatant combatantGainingExp)
                    {
                        combatantGainingExp.AddExperience(expToGive);
                    }
                }
            }

            // Remove the creature...
            if (context.Map.HasTileAt(this.Creature.Location, out ITile creatureTile))
            {
                // Add the corpse.
                var corpseCreationArguments = new ItemCreationArguments()
                {
                    TypeId = this.Creature.CorpseTypeId,
                };

                context.GameApi.RemoveCreatureFromGame(this.Creature);

                if (context.ItemFactory.CreateItem(corpseCreationArguments) is IItem corpseCreated && creatureTile.AddItemToContainerRecursively(context.ItemFactory, ref corpseCreated))
                {
                    context.GameApi.CreateItemAtLocationAsync(creatureTile.Location, context.PredefinedItemSet.FindPoolForBloodType(this.Creature.BloodType));
                }
            }
        }
Exemple #8
0
        /// <summary>
        /// Executes the operation's logic.
        /// </summary>
        /// <param name="context">A reference to the operation context.</param>
        protected override void Execute(IElevatedOperationContext context)
        {
            const byte FallbackIndex = 0xFF;

            var inThingContainer = this.FromLocation.DecodeContainer(context.Map, context.ContainerManager, out byte index, this.FromCreature);

            // Adjust index if this a map location.
            var existingThing = (this.FromLocation.Type == LocationType.Map && (inThingContainer is ITile fromTile)) ? fromTile.FindItemWithTypeId(this.FromTypeId) : inThingContainer?.FindThingAtIndex(index);

            if (existingThing == null || !(existingThing is IItem existingItem))
            {
                // Silent fail.
                return;
            }

            IThing thingCreated = context.ItemFactory.Create(ItemCreationArguments.WithTypeId(this.ToTypeId));

            if (thingCreated == null)
            {
                return;
            }

            // At this point, we have an item to change, and we were able to generate the new one, let's proceed.
            (bool replaceSuccessful, IThing replaceRemainder) = inThingContainer.ReplaceContent(context.ItemFactory, existingThing, thingCreated, index, existingItem.Amount);

            if (!replaceSuccessful || replaceRemainder != null)
            {
                this.AddContentToContainerOrFallback(context, inThingContainer, ref replaceRemainder, FallbackIndex, includeTileAsFallback: true, this.GetRequestor(context.CreatureFinder));
            }

            if (replaceSuccessful)
            {
                if (inThingContainer is ITile atTile)
                {
                    this.SendNotification(
                        context,
                        new TileUpdatedNotification(
                            () => context.Map.PlayersThatCanSee(atTile.Location),
                            atTile.Location,
                            context.MapDescriptor.DescribeTile));

                    // Evaluate if the new item triggers a collision.
                    // context.EventRulesApi.EvaluateRules(this, EventRuleType.Collision, new CollisionEventRuleArguments(fromCylinder.Location, existingThing, this.GetRequestor(context.CreatureFinder)));
                }
            }
        }
Exemple #9
0
        /// <summary>
        /// Executes the operation's logic.
        /// </summary>
        /// <param name="context">A reference to the operation context.</param>
        protected override void Execute(IElevatedOperationContext context)
        {
            var inThingContainer = this.Item.ParentContainer;

            if (!(this.Item is IThing existingThing) || !this.Item.HasExpiration)
            {
                // Silent fail.
                return;
            }

            var creationArguments = new ItemCreationArguments()
            {
                TypeId = this.Item.ExpirationTarget
            };

            if (this.Item.IsLiquidPool)
            {
                creationArguments.Attributes = new[]
Exemple #10
0
        /// <summary>
        /// Executes the condition's logic.
        /// </summary>
        /// <param name="context">The execution context for this condition.</param>
        protected override void Execute(IConditionContext context)
        {
            var inThingContainer = this.Item.ParentContainer;

            if (!(this.Item is IThing existingThing) || !this.Item.HasExpiration || inThingContainer == null)
            {
                // Silent fail.
                return;
            }

            if (this.Item.ExpirationTarget == 0)
            {
                // We will delete this item.
                context.Scheduler.ScheduleEvent(new DeleteItemOperation(requestorId: 0, this.Item));

                return;
            }

            var creationArguments = ItemCreationArguments.WithTypeId(this.Item.ExpirationTarget);

            if (this.Item.IsLiquidPool)
            {
                creationArguments.Attributes = new[]
        /// <summary>
        /// Executes the operation's logic.
        /// </summary>
        /// <param name="context">A reference to the operation context.</param>
        protected override void Execute(IElevatedOperationContext context)
        {
            const byte FallbackIndex = 0xFF;

            var inThingContainer = this.FromLocation.DecodeContainer(context.Map, context.ContainerManager, out byte index, this.FromCreature);

            // Adjust index if this a map location.
            var existingThing = (this.FromLocation.Type == LocationType.Map && (inThingContainer is ITile fromTile)) ? fromTile.FindItemWithTypeId(this.FromTypeId) : inThingContainer?.FindThingAtIndex(index);

            if (existingThing == null || !(existingThing is IItem existingItem))
            {
                // Silent fail.
                return;
            }

            var creationArguments = new ItemCreationArguments()
            {
                TypeId = this.ToTypeId
            };

            IThing thingCreated = context.ItemFactory.Create(creationArguments);

            if (thingCreated == null)
            {
                return;
            }

            // At this point, we have an item to change, and we were able to generate the new one, let's proceed.
            (bool replaceSuccessful, IThing replaceRemainder) = inThingContainer.ReplaceContent(context.ItemFactory, existingThing, thingCreated, index, existingItem.Amount);

            if (!replaceSuccessful || replaceRemainder != null)
            {
                this.AddContentToContainerOrFallback(context, inThingContainer, ref replaceRemainder, FallbackIndex, includeTileAsFallback: true, this.GetRequestor(context.CreatureFinder));
            }

            if (replaceSuccessful)
            {
                if (inThingContainer is ITile atTile)
                {
                    this.SendNotification(
                        context,
                        new TileUpdatedNotification(
                            () => context.Map.PlayersThatCanSee(atTile.Location),
                            atTile.Location,
                            context.MapDescriptor.DescribeTile));

                    // Evaluate if the new item triggers a collision.
                    // context.EventRulesApi.EvaluateRules(this, EventRuleType.Collision, new CollisionEventRuleArguments(fromCylinder.Location, existingThing, this.GetRequestor(context.CreatureFinder)));
                }

                if (thingCreated is IItem itemCreated)
                {
                    // Start decay for items that need it.
                    if (itemCreated.HasExpiration)
                    {
                        // TODO: the item location will change and this will break.
                        var expirationOp = itemCreated.ExpirationTarget == 0 ?
                                           new DeleteItemOperation(requestorId: 0, thingCreated.TypeId, thingCreated.Location)
                            :
                                           new ExpireItemOperation(requestorId: 0, itemCreated) as IOperation;

                        context.Scheduler.ScheduleEvent(expirationOp, itemCreated.ExpirationTimeLeft);
                    }
                }
            }
        }