/// <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}."); } } } } }
///// <summary> ///// Gets the type of exhaustion that this operation produces. ///// </summary> // public override ExhaustionType ExhaustionType => ExhaustionType.None; /// <summary> /// Attempts to place a creature on the map. /// </summary> /// <param name="context">A reference to the operation context.</param> /// <param name="targetTile">The tile to place the creature at.</param> /// <param name="creature">The creature to place.</param> /// <returns>True if the creature is successfully added to the map, false otherwise.</returns> protected bool PlaceCreature(IElevatedOperationContext context, ITile targetTile, ICreature creature) { targetTile.ThrowIfNull(nameof(targetTile)); creature.ThrowIfNull(nameof(creature)); var(addSuccessful, _) = targetTile.AddContent(context.ItemFactory, creature); if (addSuccessful) { context.CreatureManager.RegisterCreature(creature); if (creature is ICombatant combatant) { combatant.StatChanged += context.GameApi.CreatureStatChanged; combatant.Death += context.CombatApi.CombatantDeath; combatant.AttackTargetChanged += context.CombatApi.CombatantAttackTargetChanged; combatant.FollowTargetChanged += context.CombatApi.CreatureFollowTargetChanged; combatant.LocationChanged += context.GameApi.AfterThingLocationChanged; // As a creature that can sense. combatant.CreatureSeen += context.CombatApi.CreatureHasSeenCreature; combatant.CreatureLost += context.CombatApi.CreatureHasLostCreature; // As a skilled creature combatant.SkillChanged += context.GameApi.SkilledCreatureSkillChanged; // Find now-spectators of this creature to start tracking that guy. foreach (var spectator in context.Map.CreaturesThatCanSee(creature.Location)) { if (spectator is ICombatant combatantSpectator) { combatant.StartSensingCreature(combatantSpectator); combatantSpectator.StartSensingCreature(combatant); } } } /* * if (creature is IPlayer player) * { * player.Inventory.SlotChanged += context.GameApi.OnPlayerInventoryChanged; * } */ context.Logger.Debug($"Placed {creature.Name} at {targetTile.Location}."); var placedAtStackPos = targetTile.GetStackOrderOfThing(creature); this.SendNotification( context, new CreatureMovedNotification( () => { if (creature is IPlayer player) { return(context.Map.PlayersThatCanSee(creature.Location).Except(player.YieldSingleItem())); } return(context.Map.PlayersThatCanSee(creature.Location)); }, creature.Id,