//This needs to be called from SetupRecipies, because chests are made in SetupContent. private void LoadChestAdapters() { ChestAdapter chestAdapter = new ChestAdapter(this); List <int> chestTypes = new List <int>(); for (int i = 0; i < TileLoader.TileCount; i++) { if (TileID.Sets.BasicChest[i] || TileID.Sets.BasicChestFake[i] || TileLoader.IsDresser(i)) { chestTypes.Add(i); } } Call(registerAdapterReflection, chestAdapter, chestTypes.ToArray()); }
// Modded version of Terraria's original method. private Item PutItemInNearbyChest(TSPlayer player, Item itemToStore, Vector2 position) { bool isStored = false; for (int i = 0; i < Main.chest.Length; i++) { if (i == ChestManager.DummyChestIndex) continue; Chest tChest = Main.chest[i]; if (tChest == null || !Main.tile[tChest.x, tChest.y].active()) continue; bool isPlayerInChest = Main.player.Any((p) => p.chest == i); if (!isPlayerInChest) { IChest chest = new ChestAdapter(i, tChest); isStored = this.TryToStoreItemInNearbyChest(player, position, itemToStore, chest); if (isStored) break; } } if (!isStored) { lock (this.WorldMetadata.ProtectorChests) { foreach (DPoint chestLocation in this.WorldMetadata.ProtectorChests.Keys) { if (!TerrariaUtils.Tiles[chestLocation].active()) continue; bool isPlayerInChest = this.ChestPlayerIndexDictionary.ContainsKey(chestLocation); if (!isPlayerInChest) { IChest chest = this.WorldMetadata.ProtectorChests[chestLocation]; isStored = this.TryToStoreItemInNearbyChest(player, position, itemToStore, chest); if (isStored) break; } } } } return itemToStore; }
public bool TrySwapChestData(TSPlayer player, DPoint anyChestTileLocation, out IChest newChest) { newChest = null; if (TerrariaUtils.Tiles[anyChestTileLocation].type != TileID.Containers && TerrariaUtils.Tiles[anyChestTileLocation].type != TileID.Dressers) { player.SendErrorMessage("The selected tile is not a chest or dresser."); return false; } DPoint chestLocation = TerrariaUtils.Tiles.MeasureObject(anyChestTileLocation).OriginTileLocation; IChest chest = this.ChestManager.ChestFromLocation(chestLocation, player); if (chest == null) return false; ItemData[] content = new ItemData[Chest.maxItems]; for (int i = 0; i < Chest.maxItems; i++) content[i] = chest.Items[i]; if (chest.IsWorldChest) { lock (this.WorldMetadata.ProtectorChests) { bool isChestAvailable = this.WorldMetadata.ProtectorChests.Count < this.Config.MaxProtectorChests; if (!isChestAvailable) { player?.SendErrorMessage("The maximum of possible Protector chests has been reached."); return false; } int playerUsingChestIndex = Chest.UsingChest(chest.Index); if (playerUsingChestIndex != -1) Main.player[playerUsingChestIndex].chest = -1; Main.chest[chest.Index] = null; newChest = new ProtectorChestData(chestLocation, content); this.WorldMetadata.ProtectorChests.Add(chestLocation, (ProtectorChestData)newChest); //TSPlayer.All.SendData(PacketTypes.ChestName, string.Empty, chest.Index, chestLocation.X, chestLocation.Y); // Tell the client to remove the chest with the given index from its own chest array. TSPlayer.All.SendData(PacketTypes.TileKill, string.Empty, 1, chestLocation.X, chestLocation.Y, 0, chest.Index); TSPlayer.All.SendTileSquare(chestLocation.X, chestLocation.Y, 2); player?.SendWarningMessage("This chest is now a Protector chest."); } } else { int availableUnnamedChestIndex = -1; int availableEmptyChestIndex = -1; for (int i = 0; i < Main.chest.Length; i++) { if (i == ChestManager.DummyChestIndex) continue; Chest tChest = Main.chest[i]; if (tChest == null) { availableEmptyChestIndex = i; break; } else if (availableUnnamedChestIndex == -1 && string.IsNullOrWhiteSpace(tChest.name)) { availableUnnamedChestIndex = i; } } // Prefer unset chests over unnamed chests. int availableChestIndex = availableEmptyChestIndex; if (availableChestIndex == -1) availableChestIndex = availableUnnamedChestIndex; bool isChestAvailable = (availableChestIndex != -1); if (!isChestAvailable) { player?.SendErrorMessage("The maximum of possible world chests has been reached."); return false; } lock (this.WorldMetadata.ProtectorChests) this.WorldMetadata.ProtectorChests.Remove(chestLocation); Chest availableChest = Main.chest[availableChestIndex]; bool isExistingButUnnamedChest = (availableChest != null); if (isExistingButUnnamedChest) { if (!this.TrySwapChestData(null, new DPoint(availableChest.x, availableChest.y), out newChest)) return false; } availableChest = Main.chest[availableChestIndex] = new Chest(); availableChest.x = chestLocation.X; availableChest.y = chestLocation.Y; availableChest.item = content.Select(i => i.ToItem()).ToArray(); newChest = new ChestAdapter(availableChestIndex, availableChest); player?.SendWarningMessage("This chest is now a world chest."); } return true; }
public IChest PlaceChest(ushort tileType, int style, DPoint placeLocation) { Contract.Requires<ArgumentException>(tileType == TileID.Containers || tileType == TileID.Dressers); IChest chest; bool isDresser = (tileType == TileID.Dressers); int chestIndex = WorldGen.PlaceChest(placeLocation.X, placeLocation.Y, tileType, false, style); bool isWorldFull = (chestIndex == -1 || chestIndex == ChestManager.DummyChestIndex); if (!isWorldFull) { chest = new ChestAdapter(chestIndex, Main.chest[chestIndex]); } else { lock (this.WorldMetadata.ProtectorChests) { isWorldFull = (this.WorldMetadata.ProtectorChests.Count >= this.Config.MaxProtectorChests); if (isWorldFull) throw new LimitEnforcementException(); if (isDresser) WorldGen.PlaceDresserDirect(placeLocation.X, placeLocation.Y, tileType, style, chestIndex); else WorldGen.PlaceChestDirect(placeLocation.X, placeLocation.Y, tileType, style, chestIndex); DPoint chestLocation = TerrariaUtils.Tiles.MeasureObject(placeLocation).OriginTileLocation; chest = new ProtectorChestData(chestLocation); this.WorldMetadata.ProtectorChests.Add(chestLocation, (ProtectorChestData)chest); chestIndex = ChestManager.DummyChestIndex; } } int storageType = 0; if (isDresser) storageType = 2; TSPlayer.All.SendData(PacketTypes.TileKill, string.Empty, storageType, placeLocation.X, placeLocation.Y, style, chestIndex); // The client will always show open / close animations for the latest chest index. But when there are multiple chests with id 999 // this will look awkard, so instead tell the client about another 999 chest on a location where the animation will never be noticed by the player. if (chestIndex == ChestManager.DummyChestIndex) TSPlayer.All.SendData(PacketTypes.TileKill, string.Empty, storageType, 0, 0, style, chestIndex); return chest; }
public IChest ChestFromLocation(DPoint chestLocation, TSPlayer reportToPlayer = null) { Tile tile = TerrariaUtils.Tiles[chestLocation]; if (!tile.active() || (tile.type != (int)BlockType.Chest && tile.type != (int)BlockType.Dresser)) { reportToPlayer?.SendErrorMessage("There is no chest at this position."); return null; } IChest chest = null; int chestIndex = Chest.FindChest(chestLocation.X, chestLocation.Y); bool isWorldDataChest = (chestIndex != -1 && chestIndex != ChestManager.DummyChestIndex); if (isWorldDataChest) { Chest tChest = Main.chest[chestIndex]; if (tChest != null) chest = new ChestAdapter(chestIndex, Main.chest[chestIndex]); else reportToPlayer?.SendErrorMessage($"World data for this chest (id {chestIndex}) were expected, but was not present."); } else { lock (this.WorldMetadata.ProtectorChests) { ProtectorChestData protectorChest; if (this.WorldMetadata.ProtectorChests.TryGetValue(chestLocation, out protectorChest)) chest = protectorChest; else reportToPlayer?.SendErrorMessage("The data record of this chest is missing in both world data and Protector's data."); } } return chest; }