1 using Microsoft.Xna.Framework;
2 using Microsoft.Xna.Framework.Graphics;
4 using System.Collections.Generic;
31 private static int nextTile = TileID.Count;
32 internal static readonly IList<ModTile> tiles =
new List<ModTile>();
33 internal static readonly IList<GlobalTile> globalTiles =
new List<GlobalTile>();
34 internal static readonly IDictionary<int, ModTree> trees =
new Dictionary<int, ModTree>();
35 internal static readonly IDictionary<int, ModPalmTree> palmTrees =
new Dictionary<int, ModPalmTree>();
36 internal static readonly IDictionary<int, ModCactus> cacti =
new Dictionary<int, ModCactus>();
37 private static bool loaded =
false;
38 private static readonly
int vanillaChairCount = TileID.Sets.RoomNeeds.CountsAsChair.Length;
39 private static readonly
int vanillaTableCount = TileID.Sets.RoomNeeds.CountsAsTable.Length;
40 private static readonly
int vanillaTorchCount = TileID.Sets.RoomNeeds.CountsAsTorch.Length;
41 private static readonly
int vanillaDoorCount = TileID.Sets.RoomNeeds.CountsAsDoor.Length;
44 private delegate
void DelegateNumDust(
int i,
int j,
int type,
bool fail, ref
int num);
46 private delegate
bool DelegateCreateDust(
int i,
int j,
int type, ref
int dustType);
48 private delegate
void DelegateDropCritterChance(
int i,
int j,
int type, ref
int wormChance, ref
int grassHopperChance, ref
int jungleGrubChance);
50 private static Func<int, int, int, bool>[]
HookDrop;
51 private delegate
bool DelegateCanKillTile(
int i,
int j,
int type, ref
bool blockDamaged);
53 private delegate
void DelegateKillTile(
int i,
int j,
int type, ref
bool fail, ref
bool effectOnly, ref
bool noItem);
57 private delegate
void DelegateModifyLight(
int i,
int j,
int type, ref
float r, ref
float g, ref
float b);
60 private delegate
void DelegateSetSpriteEffects(
int i,
int j,
int type, ref SpriteEffects spriteEffects);
63 private static Func<int, int, int, SpriteBatch, bool>[]
HookPreDraw;
64 private delegate
void DelegateDrawEffects(
int i,
int j,
int type, SpriteBatch spriteBatch, ref Color drawColor, ref
int nextSpecialDrawIndex);
69 private delegate
bool DelegateTileFrame(
int i,
int j,
int type, ref
bool resetFrame, ref
bool noBreak);
79 private static Func<int, int, int, bool>[]
HookSlope;
81 private delegate
void DelegateChangeWaterfallStyle(
int type, ref
int style);
83 private delegate
int DelegateSaplingGrowthType(
int type, ref
int style);
87 internal static int ReserveTileID() {
90 int reserveID = nextTile;
95 public static int TileCount => nextTile;
103 return type >= TileID.Count && type < TileCount ? tiles[type - TileID.Count] : null;
106 private static void Resize2DArray<T>(ref T[,] array,
int newSize) {
107 int dim1 = array.GetLength(0);
108 int dim2 = array.GetLength(1);
109 T[,] newArray =
new T[newSize, dim2];
110 for (
int j = 0; j < newSize && j < dim1; j++) {
111 for (
int k = 0; k < dim2; k++) {
112 newArray[j, k] = array[j, k];
118 internal static void ResizeArrays(
bool unloading =
false) {
119 Array.Resize(ref Main.tileSetsLoaded, nextTile);
120 for (
int k = TileID.Count; k < nextTile; k++) {
121 Main.tileSetsLoaded[k] =
true;
123 Array.Resize(ref Main.highlightMaskTexture, nextTile);
124 Resize2DArray(ref Main.tileAltTexture, nextTile);
125 Resize2DArray(ref Main.tileAltTextureInit, nextTile);
126 Resize2DArray(ref Main.tileAltTextureDrawn, nextTile);
127 Array.Resize(ref Main.tileTexture, nextTile);
128 Array.Resize(ref Main.tileLighted, nextTile);
129 Array.Resize(ref Main.tileMergeDirt, nextTile);
130 Array.Resize(ref Main.tileCut, nextTile);
131 Array.Resize(ref Main.tileAlch, nextTile);
132 Array.Resize(ref Main.tileShine, nextTile);
133 Array.Resize(ref Main.tileShine2, nextTile);
134 Array.Resize(ref Main.tileStone, nextTile);
135 Array.Resize(ref Main.tileAxe, nextTile);
136 Array.Resize(ref Main.tileHammer, nextTile);
137 Array.Resize(ref Main.tileWaterDeath, nextTile);
138 Array.Resize(ref Main.tileLavaDeath, nextTile);
139 Array.Resize(ref Main.tileTable, nextTile);
140 Array.Resize(ref Main.tileBlockLight, nextTile);
141 Array.Resize(ref Main.tileNoSunLight, nextTile);
142 Array.Resize(ref Main.tileDungeon, nextTile);
143 Array.Resize(ref Main.tileSpelunker, nextTile);
144 Array.Resize(ref Main.tileSolidTop, nextTile);
145 Array.Resize(ref Main.tileSolid, nextTile);
146 Array.Resize(ref Main.tileBouncy, nextTile);
147 Array.Resize(ref Main.tileValue, nextTile);
148 Array.Resize(ref Main.tileLargeFrames, nextTile);
149 Array.Resize(ref Main.tileRope, nextTile);
150 Array.Resize(ref Main.tileBrick, nextTile);
151 Array.Resize(ref Main.tileMoss, nextTile);
152 Array.Resize(ref Main.tileNoAttach, nextTile);
153 Array.Resize(ref Main.tileNoFail, nextTile);
154 Array.Resize(ref Main.tileObsidianKill, nextTile);
155 Array.Resize(ref Main.tileFrameImportant, nextTile);
156 Array.Resize(ref Main.tilePile, nextTile);
157 Array.Resize(ref Main.tileBlendAll, nextTile);
158 Array.Resize(ref Main.tileGlowMask, nextTile);
159 Array.Resize(ref Main.tileContainer, nextTile);
160 Array.Resize(ref Main.tileSign, nextTile);
161 Array.Resize(ref Main.tileMerge, nextTile);
162 for (
int k = 0; k < nextTile; k++)
164 Array.Resize(ref Main.tileMerge[k], nextTile);
166 Array.Resize(ref Main.tileSand, nextTile);
167 Array.Resize(ref Main.tileFlame, nextTile);
168 Array.Resize(ref Main.tileFrame, nextTile);
169 Array.Resize(ref Main.tileFrameCounter, nextTile);
170 Array.Resize(ref Main.screenTileCounts, nextTile);
171 Array.Resize(ref WorldGen.tileCounts, nextTile);
172 Array.Resize(ref WorldGen.houseTile, nextTile);
173 Array.Resize(ref GameContent.Biomes.CaveHouseBiome._blacklistedTiles, nextTile);
174 Array.Resize(ref GameContent.Biomes.CorruptionPitBiome.ValidTiles, nextTile);
175 Array.Resize(ref TileID.Sets.Conversion.Grass, nextTile);
176 Array.Resize(ref TileID.Sets.Conversion.Stone, nextTile);
177 Array.Resize(ref TileID.Sets.Conversion.Ice, nextTile);
178 Array.Resize(ref TileID.Sets.Conversion.Sand, nextTile);
179 Array.Resize(ref TileID.Sets.Conversion.HardenedSand, nextTile);
180 Array.Resize(ref TileID.Sets.Conversion.Sandstone, nextTile);
181 Array.Resize(ref TileID.Sets.Conversion.Thorn, nextTile);
182 Array.Resize(ref TileID.Sets.Conversion.Moss, nextTile);
183 Array.Resize(ref TileID.Sets.ForAdvancedCollision.ForSandshark, nextTile);
184 Array.Resize(ref TileID.Sets.Platforms, nextTile);
185 Array.Resize(ref TileID.Sets.DrawsWalls, nextTile);
186 Array.Resize(ref TileID.Sets.GemsparkFramingTypes, nextTile);
187 Array.Resize(ref TileID.Sets.TeamTiles, nextTile);
188 Array.Resize(ref TileID.Sets.ConveyorDirection, nextTile);
189 Array.Resize(ref TileID.Sets.HasSlopeFrames, nextTile);
190 Array.Resize(ref TileID.Sets.TileInteractRead, nextTile);
191 Array.Resize(ref TileID.Sets.HasOutlines, nextTile);
192 Array.Resize(ref TileID.Sets.AllTiles, nextTile);
193 Array.Resize(ref TileID.Sets.Stone, nextTile);
194 Array.Resize(ref TileID.Sets.Grass, nextTile);
195 Array.Resize(ref TileID.Sets.Mud, nextTile);
196 Array.Resize(ref TileID.Sets.Snow, nextTile);
197 Array.Resize(ref TileID.Sets.Ices, nextTile);
198 Array.Resize(ref TileID.Sets.IcesSlush, nextTile);
199 Array.Resize(ref TileID.Sets.IcesSnow, nextTile);
200 Array.Resize(ref TileID.Sets.GrassSpecial, nextTile);
201 Array.Resize(ref TileID.Sets.JungleSpecial, nextTile);
202 Array.Resize(ref TileID.Sets.HellSpecial, nextTile);
203 Array.Resize(ref TileID.Sets.Leaves, nextTile);
204 Array.Resize(ref TileID.Sets.GeneralPlacementTiles, nextTile);
205 Array.Resize(ref TileID.Sets.BasicChest, nextTile);
206 Array.Resize(ref TileID.Sets.BasicChestFake, nextTile);
207 Array.Resize(ref TileID.Sets.CanBeClearedDuringGeneration, nextTile);
208 Array.Resize(ref TileID.Sets.CanBeClearedDuringOreRunner, nextTile);
209 Array.Resize(ref TileID.Sets.Corrupt, nextTile);
210 Array.Resize(ref TileID.Sets.Hallow, nextTile);
211 Array.Resize(ref TileID.Sets.Crimson, nextTile);
212 Array.Resize(ref TileID.Sets.BlocksStairs, nextTile);
213 Array.Resize(ref TileID.Sets.BlocksStairsAbove, nextTile);
214 Array.Resize(ref TileID.Sets.NotReallySolid, nextTile);
215 Array.Resize(ref TileID.Sets.NeedsGrassFraming, nextTile);
216 Array.Resize(ref TileID.Sets.NeedsGrassFramingDirt, nextTile);
217 Array.Resize(ref TileID.Sets.ChecksForMerge, nextTile);
218 Array.Resize(ref TileID.Sets.FramesOnKillWall, nextTile);
219 Array.Resize(ref TileID.Sets.AvoidedByNPCs, nextTile);
220 Array.Resize(ref TileID.Sets.InteractibleByNPCs, nextTile);
221 Array.Resize(ref TileID.Sets.HousingWalls, nextTile);
222 Array.Resize(ref TileID.Sets.BreakableWhenPlacing, nextTile);
223 Array.Resize(ref TileID.Sets.TouchDamageVines, nextTile);
224 Array.Resize(ref TileID.Sets.TouchDamageSands, nextTile);
225 Array.Resize(ref TileID.Sets.TouchDamageHot, nextTile);
226 Array.Resize(ref TileID.Sets.TouchDamageOther, nextTile);
227 Array.Resize(ref TileID.Sets.Falling, nextTile);
228 Array.Resize(ref TileID.Sets.Ore, nextTile);
229 Array.Resize(ref TileID.Sets.ForceObsidianKill, nextTile);
230 for (
int k = TileID.Count; k < nextTile; k++) {
231 TileID.Sets.AllTiles[k] =
true;
232 TileID.Sets.GeneralPlacementTiles[k] =
true;
233 TileID.Sets.CanBeClearedDuringGeneration[k] =
true;
235 while (TileObjectData._data.Count < nextTile) {
236 TileObjectData._data.Add(null);
239 ModLoader.BuildGlobalHook(ref HookKillSound, globalTiles, g => g.KillSound);
240 ModLoader.BuildGlobalHook(ref HookNumDust, globalTiles, g => g.NumDust);
241 ModLoader.BuildGlobalHook(ref HookCreateDust, globalTiles, g => g.CreateDust);
242 ModLoader.BuildGlobalHook(ref HookDropCritterChance, globalTiles, g => g.DropCritterChance);
243 ModLoader.BuildGlobalHook(ref HookDrop, globalTiles, g => g.Drop);
244 ModLoader.BuildGlobalHook(ref HookCanKillTile, globalTiles, g => g.CanKillTile);
245 ModLoader.BuildGlobalHook(ref HookKillTile, globalTiles, g => g.KillTile);
246 ModLoader.BuildGlobalHook(ref HookCanExplode, globalTiles, g => g.CanExplode);
247 ModLoader.BuildGlobalHook(ref HookNearbyEffects, globalTiles, g => g.NearbyEffects);
248 ModLoader.BuildGlobalHook(ref HookModifyLight, globalTiles, g => g.ModifyLight);
249 ModLoader.BuildGlobalHook(ref HookDangersense, globalTiles, g => g.Dangersense);
250 ModLoader.BuildGlobalHook(ref HookSetSpriteEffects, globalTiles, g => g.SetSpriteEffects);
251 ModLoader.BuildGlobalHook(ref HookAnimateTile, globalTiles, g => g.AnimateTile);
252 ModLoader.BuildGlobalHook(ref HookPreDraw, globalTiles, g => g.PreDraw);
253 ModLoader.BuildGlobalHook(ref HookDrawEffects, globalTiles, g => g.DrawEffects);
254 ModLoader.BuildGlobalHook(ref HookPostDraw, globalTiles, g => g.PostDraw);
255 ModLoader.BuildGlobalHook(ref HookSpecialDraw, globalTiles, g => g.SpecialDraw);
256 ModLoader.BuildGlobalHook(ref HookRandomUpdate, globalTiles, g => g.RandomUpdate);
257 ModLoader.BuildGlobalHook(ref HookTileFrame, globalTiles, g => g.TileFrame);
258 ModLoader.BuildGlobalHook(ref HookCanPlace, globalTiles, g => g.CanPlace);
259 ModLoader.BuildGlobalHook(ref HookAdjTiles, globalTiles, g => g.AdjTiles);
260 ModLoader.BuildGlobalHook(ref HookRightClick, globalTiles, g => g.RightClick);
261 ModLoader.BuildGlobalHook(ref HookMouseOver, globalTiles, g => g.MouseOver);
262 ModLoader.BuildGlobalHook(ref HookMouseOverFar, globalTiles, g => g.MouseOverFar);
263 ModLoader.BuildGlobalHook(ref HookAutoSelect, globalTiles, g => g.AutoSelect);
264 ModLoader.BuildGlobalHook(ref HookPreHitWire, globalTiles, g => g.PreHitWire);
265 ModLoader.BuildGlobalHook(ref HookHitWire, globalTiles, g => g.HitWire);
266 ModLoader.BuildGlobalHook(ref HookSlope, globalTiles, g => g.Slope);
267 ModLoader.BuildGlobalHook(ref HookFloorVisuals, globalTiles, g => g.FloorVisuals);
268 ModLoader.BuildGlobalHook(ref HookChangeWaterfallStyle, globalTiles, g => g.ChangeWaterfallStyle);
269 ModLoader.BuildGlobalHook(ref HookSaplingGrowthType, globalTiles, g => g.SaplingGrowthType);
270 ModLoader.BuildGlobalHook(ref HookPlaceInWorld, globalTiles, g => g.PlaceInWorld);
277 internal static void Unload() {
280 nextTile = TileID.Count;
285 Array.Resize(ref TileID.Sets.RoomNeeds.CountsAsChair, vanillaChairCount);
286 Array.Resize(ref TileID.Sets.RoomNeeds.CountsAsTable, vanillaTableCount);
287 Array.Resize(ref TileID.Sets.RoomNeeds.CountsAsTorch, vanillaTorchCount);
288 Array.Resize(ref TileID.Sets.RoomNeeds.CountsAsDoor, vanillaDoorCount);
289 while (TileObjectData._data.Count > TileID.Count) {
290 TileObjectData._data.RemoveAt(TileObjectData._data.Count - 1);
298 if (WorldGen.destroyObject) {
301 TileObjectData tileData = TileObjectData.GetTileData(type, 0, 0);
302 if (tileData == null) {
305 int frameX = Main.tile[i, j].frameX;
306 int frameY = Main.tile[i, j].frameY;
307 int subX = frameX / tileData.CoordinateFullWidth;
308 int subY = frameY / tileData.CoordinateFullHeight;
309 int wrap = tileData.StyleWrapLimit;
313 int subTile = tileData.StyleHorizontal ? subY * wrap + subX : subX * wrap + subY;
314 int style = subTile / tileData.StyleMultiplier;
315 int alternate = subTile % tileData.StyleMultiplier;
316 for (
int k = 0; k < tileData.AlternatesCount; k++) {
317 if (alternate >= tileData.Alternates[k].Style && alternate <= tileData.Alternates[k].Style + tileData.RandomStyleRange) {
322 tileData = TileObjectData.GetTileData(type, style, alternate + 1);
323 int partFrameX = frameX % tileData.CoordinateFullWidth;
324 int partFrameY = frameY % tileData.CoordinateFullHeight;
325 int partX = partFrameX / (tileData.CoordinateWidth + tileData.CoordinatePadding);
327 int remainingFrameY = partFrameY;
328 while (remainingFrameY > 0) {
329 remainingFrameY -= tileData.CoordinateHeights[partY] + tileData.CoordinatePadding;
334 int originX = i + tileData.Origin.X;
335 int originY = j + tileData.Origin.Y;
336 TileObject objectData;
337 bool partiallyDestroyed =
false;
338 for (
int x = i; x < i + tileData.Width; x++) {
339 for (
int y = j; y < j + tileData.Height; y++) {
340 if (!Main.tile[x, y].active() || Main.tile[x, y].type != type) {
341 partiallyDestroyed =
true;
345 if (partiallyDestroyed) {
349 if (partiallyDestroyed || !TileObject.CanPlace(originX, originY, type, style, 0, out objectData,
true,
true)) {
350 WorldGen.destroyObject =
true;
351 for (
int x = i; x < i + tileData.Width; x++) {
352 for (
int y = j; y < j + tileData.Height; y++) {
353 if (Main.tile[x, y].type == type && Main.tile[x, y].active()) {
354 WorldGen.KillTile(x, y,
false,
false,
false);
358 KillMultiTile(i, j, frameX - partFrameX, frameY - partFrameY, type);
359 WorldGen.destroyObject =
false;
360 for (
int x = i - 1; x < i + tileData.Width + 2; x++) {
361 for (
int y = j - 1; y < j + tileData.Height + 2; y++) {
362 WorldGen.TileFrame(x, y,
false,
false);
366 TileObject.objectPreview.Active =
false;
371 ModTile modTile = GetTile(tile.type);
372 if (modTile != null) {
380 ModTile modTile = GetTile(tile.type);
381 if (modTile != null) {
390 ModTile modTile = GetTile(tile.type);
391 if (modTile != null) {
394 if (tile.type == TileID.ClosedDoor && (tile.frameY < 594 || tile.frameY > 646 || tile.frameX >= 54)) {
395 return TileID.OpenDoor;
404 ModTile modTile = GetTile(tile.type);
405 if (modTile != null) {
408 if (tile.type == TileID.OpenDoor) {
409 return TileID.ClosedDoor;
414 ModTile modTile = GetTile(tile.type);
415 if (modTile != null) {
418 return tile.type == TileID.ClosedDoor;
422 ModTile modTile = GetTile(type);
423 if (modTile != null) {
424 return modTile.
chest;
430 if (type == TileID.Dressers) {
433 return ModDresserName(type).Length > 0;
437 ModTile modTile = GetTile(type);
438 if (modTile != null) {
445 ModTile modTile = GetTile(type);
446 if (modTile == null) {
453 ModTile modTile = GetTile(type);
454 if (modTile == null) {
455 return type == TileID.Torches;
457 return modTile.
torch;
461 ModTile modTile = GetTile(type);
462 if (modTile == null) {
463 return type == TileID.Saplings;
469 return SoundLoader.tileToMusic.ContainsKey(tile.type)
470 &&
SoundLoader.tileToMusic[tile.type].ContainsKey(tile.frameY / 36 * 36);
474 internal static void SetDefaults(
ModTile tile) {
476 if (TileObjectData.newTile.Width > 1 || TileObjectData.newTile.Height > 1) {
477 TileObjectData.FixNewTile();
478 throw new Exception(
"It appears that you have an error surrounding TileObjectData.AddTile in " + tile.GetType().FullName) { HelpLink =
"https://github.com/tModLoader/tModLoader/wiki/Basic-tModLoader-Modding-FAQ#tileobjectdataaddtile-issues" };
480 if (Main.tileLavaDeath[tile.
Type]) {
481 Main.tileObsidianKill[tile.
Type] =
true;
483 if (Main.tileSolid[tile.
Type]) {
484 Main.tileNoSunLight[tile.
Type] =
true;
490 return GetTile(type)?.HasSmartInteract() ??
false;
493 public static void FixSmartInteractCoords(
int type, ref
int width, ref
int height, ref
int frameWidth, ref
int frameHeight, ref
int extraX, ref
int extraY) {
494 ModTile modTile = GetTile(type);
495 if (modTile != null) {
496 TileObjectData data = TileObjectData.GetTileData(type, 0);
498 height = data.Height;
499 frameWidth = data.CoordinateWidth + data.CoordinatePadding;
500 frameHeight = data.CoordinateHeights[0] + data.CoordinatePadding;
501 extraY = data.CoordinateFullHeight % frameHeight;
507 foreach (var hook
in HookKillSound) {
508 if (!hook(i, j, type)) {
512 ModTile modTile = GetTile(type);
513 if (modTile != null) {
524 public static void NumDust(
int i,
int j,
int type,
bool fail, ref
int numDust) {
525 GetTile(type)?.NumDust(i, j, fail, ref numDust);
527 foreach (var hook
in HookNumDust) {
528 hook(i, j, type, fail, ref numDust);
533 public static bool CreateDust(
int i,
int j,
int type, ref
int dustType) {
534 foreach (var hook
in HookCreateDust) {
535 if (!hook(i, j, type, ref dustType)) {
539 return GetTile(type)?.CreateDust(i, j, ref dustType) ??
true;
543 public static void DropCritterChance(
int i,
int j,
int type, ref
int wormChance, ref
int grassHopperChance, ref
int jungleGrubChance) {
544 GetTile(type)?.DropCritterChance(i, j, ref wormChance, ref grassHopperChance, ref jungleGrubChance);
546 foreach (var hook
in HookDropCritterChance) {
547 hook(i, j, type, ref wormChance, ref grassHopperChance, ref jungleGrubChance);
553 public static bool Drop(
int i,
int j,
int type) {
554 foreach (var hook
in HookDrop) {
555 if (!hook(i, j, type)) {
559 ModTile modTile = GetTile(type);
560 if (modTile != null) {
561 if (!modTile.
Drop(i, j)) {
564 if (modTile.
drop > 0) {
565 Item.NewItem(i * 16, j * 16, 16, 16, modTile.
drop, 1,
false, -1);
573 public static bool CanKillTile(
int i,
int j,
int type, ref
bool blockDamaged) {
574 foreach (var hook
in HookCanKillTile) {
575 if (!hook(i, j, type, ref blockDamaged)) {
579 return GetTile(type)?.CanKillTile(i, j, ref blockDamaged) ??
true;
583 public static void KillTile(
int i,
int j,
int type, ref
bool fail, ref
bool effectOnly, ref
bool noItem) {
584 GetTile(type)?.KillTile(i, j, ref fail, ref effectOnly, ref noItem);
586 foreach (var hook
in HookKillTile) {
587 hook(i, j, type, ref fail, ref effectOnly, ref noItem);
591 public static void KillMultiTile(
int i,
int j,
int frameX,
int frameY,
int type) {
592 GetTile(type)?.KillMultiTile(i, j, frameX, frameY);
596 int type = Main.tile[i, j].type;
597 ModTile modTile = GetTile(type);
598 if (modTile != null && !modTile.
CanExplode(i, j)) {
601 foreach (var hook
in HookCanExplode) {
602 if (!hook(i, j, type)) {
611 GetTile(type)?.NearbyEffects(i, j, closer);
613 foreach (var hook
in HookNearbyEffects) {
614 hook(i, j, type, closer);
619 public static void ModifyLight(
int i,
int j,
int type, ref
float r, ref
float g, ref
float b) {
620 if (!Main.tileLighted[type]) {
623 GetTile(type)?.ModifyLight(i, j, ref r, ref g, ref b);
625 foreach (var hook
in HookModifyLight) {
626 hook(i, j, type, ref r, ref g, ref b);
630 public static bool Dangersense(
int i,
int j,
int type, Player player) {
631 ModTile modTile = GetTile(type);
632 if (modTile != null && modTile.
Dangersense(i, j, player)) {
635 foreach (var hook
in HookDangersense) {
636 if (hook(i, j, type, player)) {
644 public static void SetSpriteEffects(
int i,
int j,
int type, ref SpriteEffects spriteEffects) {
645 GetTile(type)?.SetSpriteEffects(i, j, ref spriteEffects);
647 foreach (var hook
in HookSetSpriteEffects) {
648 hook(i, j, type, ref spriteEffects);
653 public static void SetDrawPositions(
int i,
int j, ref
int width, ref
int offsetY, ref
int height) {
654 Tile tile = Main.tile[i, j];
655 if (tile.type >= TileID.Count) {
656 TileObjectData tileData = TileObjectData.GetTileData(tile.type, 0, 0);
657 if (tileData != null) {
658 int partFrameY = tile.frameY % tileData.CoordinateFullHeight;
660 while (partFrameY > 0) {
661 partFrameY -= tileData.CoordinateHeights[partY] + tileData.CoordinatePadding;
664 width = tileData.CoordinateWidth;
665 offsetY = tileData.DrawYOffset;
666 height = tileData.CoordinateHeights[partY];
668 GetTile(tile.type).
SetDrawPositions(i, j, ref width, ref offsetY, ref height);
674 for (
int i = 0; i < tiles.Count; i++) {
676 modTile.
AnimateTile(ref Main.tileFrame[modTile.
Type], ref Main.tileFrameCounter[modTile.
Type]);
678 foreach (var hook
in HookAnimateTile) {
694 public static void SetAnimationFrame(
int type,
int i,
int j, ref
int frameXOffset, ref
int frameYOffset) {
695 ModTile modTile = GetTile(type);
696 if (modTile != null) {
705 public static bool PreDraw(
int i,
int j,
int type, SpriteBatch spriteBatch) {
706 foreach (var hook
in HookPreDraw) {
707 if (!hook(i, j, type, spriteBatch)) {
711 return GetTile(type)?.PreDraw(i, j, spriteBatch) ??
true;
714 public static void DrawEffects(
int i,
int j,
int type, SpriteBatch spriteBatch, ref Color drawColor, ref
int nextSpecialDrawIndex) {
715 GetTile(type)?.DrawEffects(i, j, spriteBatch, ref drawColor, ref nextSpecialDrawIndex);
716 foreach (var hook
in HookDrawEffects) {
717 hook(i, j, type, spriteBatch, ref drawColor, ref nextSpecialDrawIndex);
722 public static void PostDraw(
int i,
int j,
int type, SpriteBatch spriteBatch) {
723 GetTile(type)?.PostDraw(i, j, spriteBatch);
725 foreach (var hook
in HookPostDraw) {
726 hook(i, j, type, spriteBatch);
733 public static void SpecialDraw(
int type,
int specX,
int specY, SpriteBatch spriteBatch) {
734 GetTile(type)?.SpecialDraw(specX, specY, spriteBatch);
736 foreach (var hook
in HookSpecialDraw) {
737 hook(specX, specY, type, spriteBatch);
745 if (!Main.tile[i, j].active()) {
748 GetTile(type)?.RandomUpdate(i, j);
750 foreach (var hook
in HookRandomUpdate) {
756 public static bool TileFrame(
int i,
int j,
int type, ref
bool resetFrame, ref
bool noBreak) {
757 ModTile modTile = GetTile(type);
759 if (modTile != null) {
760 flag = modTile.
TileFrame(i, j, ref resetFrame, ref noBreak);
762 foreach (var hook
in HookTileFrame) {
763 flag &= hook(i, j, type, ref resetFrame, ref noBreak);
771 public static void MineDamage(
int minePower, ref
int damage) {
772 Tile target = Main.tile[Player.tileTargetX, Player.tileTargetY];
773 ModTile modTile = GetTile(target.type);
774 damage += modTile != null ? (int)(minePower / modTile.
mineResist) : minePower;
779 ModTile modTile = GetTile(target.type);
780 if (modTile != null && pickPower < modTile.
minPick) {
786 public static bool CanPlace(
int i,
int j,
int type) {
787 foreach (var hook
in HookCanPlace) {
788 if (!hook(i, j, type)) {
792 return GetTile(type)?.CanPlace(i, j) ??
true;
796 public static void AdjTiles(Player player,
int type) {
797 ModTile modTile = GetTile(type);
798 if (modTile != null) {
799 foreach (
int k
in modTile.
adjTiles) {
800 player.adjTile[k] =
true;
803 foreach (var hook
in HookAdjTiles) {
804 int[] adjTiles = hook(type);
805 foreach (
int k
in adjTiles) {
806 player.adjTile[k] =
true;
813 bool returnValue =
false;
814 int type = Main.tile[i, j].type;
815 GetTile(type)?.RightClick(i, j);
816 if (GetTile(type)?.NewRightClick(i, j) ??
false)
819 foreach (var hook
in HookRightClick) {
827 int type = Main.tile[i, j].type;
828 GetTile(type)?.MouseOver(i, j);
830 foreach (var hook
in HookMouseOver) {
836 int type = Main.tile[i, j].type;
837 GetTile(type)?.MouseOverFar(i, j);
839 foreach (var hook
in HookMouseOverFar) {
845 if (!Main.tile[i, j].active()) {
848 int type = Main.tile[i, j].type;
849 ModTile modTile = GetTile(type);
850 for (
int k = 0; k < 50; k++) {
851 Item item = player.inventory[k];
852 if (item.type == 0 || item.stack == 0) {
855 if (modTile != null && modTile.
AutoSelect(i, j, item)) {
858 foreach (var hook
in HookAutoSelect) {
859 if (hook(i, j, type, item)) {
868 foreach (var hook
in HookPreHitWire) {
869 if (!hook(i, j, type)) {
879 public static void HitWire(
int i,
int j,
int type) {
880 GetTile(type)?.HitWire(i, j);
882 foreach (var hook
in HookHitWire) {
888 GetTile(type)?.FloorVisuals(player);
890 foreach (var hook
in HookFloorVisuals) {
896 public static bool Slope(
int i,
int j,
int type) {
897 foreach (var hook
in HookSlope) {
898 if (!hook(i, j, type)) {
902 return !GetTile(type)?.Slope(i, j) ??
false;
906 return GetTile(type)?.HasWalkDust() ??
false;
909 public static void WalkDust(
int type, ref
int dustType, ref
bool makeDust, ref Color color) {
910 GetTile(type)?.WalkDust(ref dustType, ref makeDust, ref color);
914 GetTile(type)?.ChangeWaterfallStyle(ref style);
915 foreach (var hook
in HookChangeWaterfallStyle) {
916 hook(type, ref style);
921 int originalType = saplingType;
922 int originalStyle = style;
924 ModTile modTile = GetTile(type);
925 if (modTile != null) {
927 if (IsSapling(saplingType)) {
928 originalType = saplingType;
929 originalStyle = style;
933 saplingType = originalType;
934 style = originalStyle;
937 foreach (var hook
in HookSaplingGrowthType) {
938 saplingType = hook(type, ref style);
939 if (IsSapling(saplingType)) {
940 originalType = saplingType;
941 originalStyle = style;
945 saplingType = originalType;
946 style = originalStyle;
953 return trees.ContainsKey(type);
956 public static void TreeDust(Tile tile, ref
int dust) {
957 if (tile.active() && trees.ContainsKey(tile.type)) {
958 dust = trees[tile.type].CreateDust();
963 if (trees.ContainsKey(type)) {
964 gore = trees[type].GrowthFXGore();
969 return trees.ContainsKey(type) ? trees[type].CanDropAcorn() :
false;
973 if (trees.ContainsKey(type)) {
974 wood = trees[type].DropWood();
979 return tile.active() && trees.ContainsKey(tile.type) ? trees[tile.type].GetTexture() : null;
983 ref
int frameWidth, ref
int frameHeight, ref
int xOffsetLeft, ref
int yOffset) {
984 return trees.ContainsKey(type) ? trees[type].GetTopTextures(i, j, ref frame,
985 ref frameWidth, ref frameHeight, ref xOffsetLeft, ref yOffset) : null;
989 return trees.ContainsKey(type) ? trees[type].GetBranchTextures(i, j, trunkOffset, ref frame) : null;
993 return palmTrees.ContainsKey(type);
997 if (tile.active() && palmTrees.ContainsKey(tile.type)) {
998 dust = palmTrees[tile.type].CreateDust();
1003 if (palmTrees.ContainsKey(type)) {
1004 gore = palmTrees[type].GrowthFXGore();
1009 if (palmTrees.ContainsKey(type)) {
1010 wood = palmTrees[type].DropWood();
1015 return tile.active() && palmTrees.ContainsKey(tile.type) ? palmTrees[tile.type].GetTexture() : null;
1019 return palmTrees.ContainsKey(type) ? palmTrees[type].GetTopTextures() : null;
1023 return cacti.ContainsKey(type);
1027 return cacti.ContainsKey(type) ? cacti[type].GetTexture() : null;
1031 int type = item.createTile;
1035 foreach (var hook
in HookPlaceInWorld) {
1039 GetTile(type)?.PlaceInWorld(i, j, item);
1043 return GetTile(type)?.IsLockedChest(i, j) ??
false;
1046 public static bool UnlockChest(
int i,
int j,
int type, ref
short frameXAdjustment, ref
int dustType, ref
bool manual) {
1047 return GetTile(type)?.UnlockChest(i, j, ref frameXAdjustment, ref dustType, ref manual) ??
false;
static Func< int, int[]>[] HookAdjTiles
static void NumDust(int i, int j, int type, bool fail, ref int numDust)
static void FixSmartInteractCoords(int type, ref int width, ref int height, ref int frameWidth, ref int frameHeight, ref int extraX, ref int extraY)
static int AutoSelect(int i, int j, Player player)
This class represents a type of tile that can be added by a mod. Only one instance of this class will...
static void DropCritterChance(int i, int j, int type, ref int wormChance, ref int grassHopperChance, ref int jungleGrubChance)
static DelegateSaplingGrowthType[] HookSaplingGrowthType
static Action[] HookAnimateTile
static void RandomUpdate(int i, int j, int type)
static void PlaceInWorld(int i, int j, Item item)
static Func< int, int, int, Player, bool >[] HookDangersense
static void DropPalmTreeWood(int type, ref int wood)
static Action< int, int, int >[] HookHitWire
static bool AllowVanillaClients
int minPick
The minimum pickaxe power required for pickaxes to mine this block. Defaults to 0.
static bool CanGrowModTree(int type)
static Func< int, int, int, bool >[] HookPreHitWire
static bool IsModBed(int type)
static string ModDresserName(int type)
int soundStyle
The default style of sound made when this tile is hit. Defaults to 1.
static bool TileFrame(int i, int j, int type, ref bool resetFrame, ref bool noBreak)
static bool CanPlace(int i, int j, int type)
static Action< int, int, int, bool >[] HookNearbyEffects
virtual bool CanExplode(int i, int j)
Whether or not the tile at the given coordinates can be killed by an explosion (ie. bombs). Returns true by default; return false to stop an explosion from destroying it.
static Texture2D GetTreeTexture(Tile tile)
static Func< int, int, int, bool >[] HookDrop
static bool UnlockChest(int i, int j, int type, ref short frameXAdjustment, ref int dustType, ref bool manual)
int closeDoorID
The ID of the tile that this door transforms into when it is closed. Defaults to -1, which means this tile isn't a door.
static void KillTile(int i, int j, int type, ref bool fail, ref bool effectOnly, ref bool noItem)
static void PalmTreeDust(Tile tile, ref int dust)
static void MineDamage(int minePower, ref int damage)
static void AnimateTiles()
static Texture2D GetCactusTexture(int type)
static DelegateCanKillTile[] HookCanKillTile
static int OpenDoorID(Tile tile)
static void PostDraw(int i, int j, int type, SpriteBatch spriteBatch)
static Func< int, int, int, bool >[] HookCanExplode
static ModTile GetTile(int type)
Gets the ModTile instance with the given type. If no ModTile with the given type exists, returns null.
static Action< int, int, int >[] HookMouseOverFar
static DelegateSetSpriteEffects[] HookSetSpriteEffects
static Texture2D GetPalmTreeTexture(Tile tile)
This serves as the central class which loads mods. It contains many static fields and methods related...
This serves as the central class from which tile-related functions are supported and carried out...
static Func< int, int, int, bool >[] HookKillSound
static void DrawEffects(int i, int j, int type, SpriteBatch spriteBatch, ref Color drawColor, ref int nextSpecialDrawIndex)
static Texture2D GetTreeBranchTextures(int type, int i, int j, int trunkOffset, ref int frame)
int[] adjTiles
An array of the IDs of tiles that this tile can be considered as when looking for crafting stations...
static DelegateDrawEffects[] HookDrawEffects
static void SetSpriteEffects(int i, int j, int type, ref SpriteEffects spriteEffects)
virtual bool AutoSelect(int i, int j, Item item)
Allows you to determine whether the given item can become selected when the cursor is hovering over t...
static void ModifyLight(int i, int j, int type, ref float r, ref float g, ref float b)
int drop
The default type of item dropped when this tile is killed. Defaults to 0, which means no item...
static void DisableSmartInteract(Tile tile, ref bool disable)
static bool IsModMusicBox(Tile tile)
virtual void SetDrawPositions(int i, int j, ref int width, ref int offsetY, ref int height)
Allows you to customize the position in which this tile is drawn. Width refers to the width of one fr...
int animationFrameHeight
The height of a group of animation frames for this tile. Defaults to 0, which disables animations...
static int CloseDoorID(Tile tile)
static void ChangeWaterfallStyle(int type, ref int style)
static void PickPowerCheck(Tile target, int pickPower, ref int damage)
static bool IsDresser(int type)
static void TreeGrowthFXGore(int type, ref int gore)
virtual bool Dangersense(int i, int j, Player player)
Allows you to determine whether this block glows red when the given player has the Dangersense buff...
static Func< int, int, int, Item, bool >[] HookAutoSelect
static bool PreDraw(int i, int j, int type, SpriteBatch spriteBatch)
static bool IsLockedChest(int i, int j, int type)
static void MouseOverFar(int i, int j)
static void SetDrawPositions(int i, int j, ref int width, ref int offsetY, ref int height)
static void MouseOver(int i, int j)
This class is used to keep track of and support the existence of custom sounds that have been added t...
static DelegateTileFrame[] HookTileFrame
static void SpecialDraw(int type, int specX, int specY, SpriteBatch spriteBatch)
Special Draw calls ModTile and GlobalTile SpecialDraw methods. Special Draw is called from DrawTiles ...
static bool CanDropAcorn(int type)
static Texture2D GetPalmTreeTopTextures(int type)
static bool Drop(int i, int j, int type)
bool bed
Whether or not this tile is a valid spawn point. Defaults to false. If you set this to true...
static bool Dangersense(int i, int j, int type, Player player)
bool sapling
Whether or not this tile is a sapling, which can grow into a modded tree or palm tree.
static void CheckModTile(int i, int j, int type)
static bool HasWalkDust(int type)
static DelegateNumDust[] HookNumDust
int openDoorID
The ID of the tile that this door transforms into when it is opened. Defaults to -1, which means this tile isn't a door.
static Func< int, int, int, bool >[] HookSlope
string dresser
Same as chest, except use this if your block is a dresser (has a size of 3x2 instead of 2x2)...
static DelegateKillTile[] HookKillTile
static DelegateChangeWaterfallStyle[] HookChangeWaterfallStyle
static bool CanKillTile(int i, int j, int type, ref bool blockDamaged)
static void WalkDust(int type, ref int dustType, ref bool makeDust, ref Color color)
static Action< int, int, int, SpriteBatch >[] HookPostDraw
static bool IsSapling(int type)
static bool CanGrowModPalmTree(int type)
static bool IsClosedDoor(Tile tile)
virtual void AnimateTile(ref int frame, ref int frameCounter)
Allows you to animate your tile. Use frameCounter to keep track of how long the current frame has bee...
ushort Type
The internal ID of this type of tile.
static void KillMultiTile(int i, int j, int frameX, int frameY, int type)
static Action< int, int, int >[] HookRandomUpdate
static void DisableSmartCursor(Tile tile, ref bool disable)
static Action< int, int, Item >[] HookPlaceInWorld
bool disableSmartCursor
Whether or not the smart cursor function is disabled when the cursor hovers above this tile...
static Func< int, int, int, bool >[] HookCanPlace
float mineResist
A multiplier describing how much this block resists harvesting. Higher values will make it take longe...
static bool PreHitWire(int i, int j, int type)
static void AdjTiles(Player player, int type)
virtual void PostSetDefaults()
Allows you to override some default properties of this tile, such as Main.tileNoSunLight and Main...
static void PalmTreeGrowthFXGore(int type, ref int gore)
static Func< int, int, int, SpriteBatch, bool >[] HookPreDraw
virtual bool Drop(int i, int j)
Allows you to customize which items the tile at the given coordinates drops. Remember that the x...
virtual void AnimateIndividualTile(int type, int i, int j, ref int frameXOffset, ref int frameYOffset)
Animates an individual tile. i and j are the coordinates of the Tile in question. frameXOffset and fr...
static string ModChestName(int type)
static DelegateModifyLight[] HookModifyLight
static Action< int, int, int, SpriteBatch >[] HookSpecialDraw
static Texture2D GetTreeTopTextures(int type, int i, int j, ref int frame, ref int frameWidth, ref int frameHeight, ref int xOffsetLeft, ref int yOffset)
static void FloorVisuals(int type, Player player)
static bool Slope(int i, int j, int type)
static void HitWire(int i, int j, int type)
bool torch
Whether or not this tile behaves like a torch. If you are making a torch tile, then setting this to t...
static DelegateDropCritterChance[] HookDropCritterChance
static Action< int, Player >[] HookFloorVisuals
static bool SaplingGrowthType(int type, ref int saplingType, ref int style)
string chest
The default name of this chest that is displayed when this 2x2 chest is open. Defaults to the empty s...
static void NearbyEffects(int i, int j, int type, bool closer)
static Action< int, int, int >[] HookMouseOver
virtual void SetDefaults()
Allows you to set the properties of this tile. Many properties are stored as arrays throughout Terrar...
static bool KillSound(int i, int j, int type)
bool disableSmartInteract
Whether or not the smart tile interaction function is disabled when the cursor hovers above this tile...
virtual bool TileFrame(int i, int j, ref bool resetFrame, ref bool noBreak)
Called whenever this tile updates due to being placed or being next to a tile that is changed...
static bool RightClick(int i, int j)
static bool HasSmartInteract(int type)
static bool CreateDust(int i, int j, int type, ref int dustType)
int soundType
The default type of sound made when this tile is hit. Defaults to 0.
static bool CanExplode(int i, int j)
static bool IsTorch(int type)
static DelegateCreateDust[] HookCreateDust
virtual int SaplingGrowthType(ref int style)
Allows this tile to support a sapling that can eventually grow into a tree. The type of the sapling s...
static void DropTreeWood(int type, ref int wood)
static Action< int, int, int >[] HookRightClick
static bool CanGrowModCactus(int type)
static void SetAnimationFrame(int type, int i, int j, ref int frameXOffset, ref int frameYOffset)
Sets the animation frame. Sets frameYOffset = modTile.animationFrameHeight * Main.tileFrame[type]; and then calls ModTile.AnimateIndividualTile
virtual bool KillSound(int i, int j)
Allows you to customize which sound you want to play when the tile at the given coordinates is hit...
static void TreeDust(Tile tile, ref int dust)