1 using Microsoft.Xna.Framework;
2 using Microsoft.Xna.Framework.Graphics;
4 using System.Collections.Generic;
7 using System.Linq.Expressions;
21 internal static bool loaded =
false;
22 private static int nextNPC = NPCID.Count;
23 internal static readonly IList<ModNPC> npcs =
new List<ModNPC>();
24 internal static readonly IList<GlobalNPC> globalNPCs =
new List<GlobalNPC>();
26 internal static readonly IDictionary<string, int> globalIndexes =
new Dictionary<string, int>();
27 internal static readonly IDictionary<Type, int> globalIndexesByType =
new Dictionary<Type, int>();
28 internal static readonly IDictionary<int, int> bannerToItem =
new Dictionary<int, int>();
29 private static int vanillaSkeletonCount = NPCID.Sets.Skeletons.Count;
30 private static readonly
int[] shopToNPC =
new int[Main.MaxShopIDs - 1];
34 public static readonly IList<int> blockLoot =
new List<int>();
46 private static List<HookList> hooks =
new List<HookList>();
48 private static HookList AddHook<F>(Expression<Func<GlobalNPC, F>> func) {
55 shopToNPC[1] = NPCID.Merchant;
56 shopToNPC[2] = NPCID.ArmsDealer;
57 shopToNPC[3] = NPCID.Dryad;
58 shopToNPC[4] = NPCID.Demolitionist;
59 shopToNPC[5] = NPCID.Clothier;
60 shopToNPC[6] = NPCID.GoblinTinkerer;
61 shopToNPC[7] = NPCID.Wizard;
62 shopToNPC[8] = NPCID.Mechanic;
63 shopToNPC[9] = NPCID.SantaClaus;
64 shopToNPC[10] = NPCID.Truffle;
65 shopToNPC[11] = NPCID.Steampunker;
66 shopToNPC[12] = NPCID.DyeTrader;
67 shopToNPC[13] = NPCID.PartyGirl;
68 shopToNPC[14] = NPCID.Cyborg;
69 shopToNPC[15] = NPCID.Painter;
70 shopToNPC[16] = NPCID.WitchDoctor;
71 shopToNPC[17] = NPCID.Pirate;
72 shopToNPC[18] = NPCID.Stylist;
73 shopToNPC[19] = NPCID.TravellingMerchant;
74 shopToNPC[20] = NPCID.SkeletonMerchant;
75 shopToNPC[21] = NPCID.DD2Bartender;
78 internal static int ReserveNPCID() {
81 int reserveID = nextNPC;
86 public static int NPCCount => nextNPC;
94 return type >= NPCID.Count && type < NPCCount ? npcs[type - NPCID.Count] : null;
101 internal static void ResizeArrays(
bool unloading) {
102 Array.Resize(ref Main.NPCLoaded, nextNPC);
103 Array.Resize(ref Main.townNPCCanSpawn, nextNPC);
104 Array.Resize(ref Main.slimeRainNPC, nextNPC);
105 Array.Resize(ref Main.npcTexture, nextNPC);
106 Array.Resize(ref Main.npcAltTextures, nextNPC);
107 Array.Resize(ref Main.npcCatchable, nextNPC);
108 Array.Resize(ref Main.npcFrameCount, nextNPC);
109 Array.Resize(ref NPC.killCount, nextNPC);
110 Array.Resize(ref NPC.npcsFoundForCheckActive, nextNPC);
111 Array.Resize(ref Lang._npcNameCache, nextNPC);
112 Array.Resize(ref EmoteBubble.CountNPCs, nextNPC);
113 Array.Resize(ref WorldGen.TownManager._hasRoom, nextNPC);
114 Array.Resize(ref NPCID.Sets.TrailingMode, nextNPC);
115 Array.Resize(ref NPCID.Sets.BelongsToInvasionOldOnesArmy, nextNPC);
116 Array.Resize(ref NPCID.Sets.TeleportationImmune, nextNPC);
117 Array.Resize(ref NPCID.Sets.UsesNewTargetting, nextNPC);
118 Array.Resize(ref NPCID.Sets.FighterUsesDD2PortalAppearEffect, nextNPC);
119 Array.Resize(ref NPCID.Sets.StatueSpawnedDropRarity, nextNPC);
120 Array.Resize(ref NPCID.Sets.NoEarlymodeLootWhenSpawnedFromStatue, nextNPC);
121 Array.Resize(ref NPCID.Sets.NeedsExpertScaling, nextNPC);
122 Array.Resize(ref NPCID.Sets.ProjectileNPC, nextNPC);
123 Array.Resize(ref NPCID.Sets.SavesAndLoads, nextNPC);
124 Array.Resize(ref NPCID.Sets.TrailCacheLength, nextNPC);
125 Array.Resize(ref NPCID.Sets.MPAllowedEnemies, nextNPC);
126 Array.Resize(ref NPCID.Sets.TownCritter, nextNPC);
127 Array.Resize(ref NPCID.Sets.HatOffsetY, nextNPC);
128 Array.Resize(ref NPCID.Sets.FaceEmote, nextNPC);
129 Array.Resize(ref NPCID.Sets.ExtraFramesCount, nextNPC);
130 Array.Resize(ref NPCID.Sets.AttackFrameCount, nextNPC);
131 Array.Resize(ref NPCID.Sets.DangerDetectRange, nextNPC);
132 Array.Resize(ref NPCID.Sets.AttackTime, nextNPC);
133 Array.Resize(ref NPCID.Sets.AttackAverageChance, nextNPC);
134 Array.Resize(ref NPCID.Sets.AttackType, nextNPC);
135 Array.Resize(ref NPCID.Sets.PrettySafe, nextNPC);
136 Array.Resize(ref NPCID.Sets.MagicAuraColor, nextNPC);
137 Array.Resize(ref NPCID.Sets.BossHeadTextures, nextNPC);
138 Array.Resize(ref NPCID.Sets.ExcludedFromDeathTally, nextNPC);
139 Array.Resize(ref NPCID.Sets.TechnicallyABoss, nextNPC);
140 Array.Resize(ref NPCID.Sets.MustAlwaysDraw, nextNPC);
141 Array.Resize(ref NPCID.Sets.ExtraTextureCount, nextNPC);
142 Array.Resize(ref NPCID.Sets.NPCFramingGroup, nextNPC);
143 Array.Resize(ref NPCID.Sets.TownNPCsFramingGroups, nextNPC);
144 for (
int k = NPCID.Count; k < nextNPC; k++) {
145 Main.NPCLoaded[k] =
true;
146 Main.npcFrameCount[k] = 1;
147 Lang._npcNameCache[k] = LocalizedText.Empty;
148 NPCID.Sets.TrailingMode[k] = -1;
149 NPCID.Sets.StatueSpawnedDropRarity[k] = -1f;
150 NPCID.Sets.TrailCacheLength[k] = 10;
151 NPCID.Sets.DangerDetectRange[k] = -1;
152 NPCID.Sets.AttackTime[k] = -1;
153 NPCID.Sets.AttackAverageChance[k] = 1;
154 NPCID.Sets.AttackType[k] = -1;
155 NPCID.Sets.PrettySafe[k] = -1;
156 NPCID.Sets.MagicAuraColor[k] = Color.White;
157 NPCID.Sets.BossHeadTextures[k] = -1;
160 InstancedGlobals = globalNPCs.Where(g => g.InstancePerEntity).ToArray();
161 for (
int i = 0; i < InstancedGlobals.Length; i++) {
162 InstancedGlobals[i].instanceIndex = i;
164 foreach (var hook
in hooks) {
165 hook.arr =
ModLoader.BuildGlobalHook(globalNPCs, hook.method);
173 internal static void Unload() {
176 nextNPC = NPCID.Count;
178 globalIndexes.Clear();
179 globalIndexesByType.Clear();
180 bannerToItem.Clear();
181 while (NPCID.Sets.Skeletons.Count > vanillaSkeletonCount) {
182 NPCID.Sets.Skeletons.RemoveAt(NPCID.Sets.Skeletons.Count - 1);
186 internal static bool IsModNPC(NPC npc) {
187 return npc.type >= NPCID.Count;
190 private static HookList HookSetDefaults = AddHook<Action<NPC>>(g => g.SetDefaults);
192 internal static void SetDefaults(NPC npc,
bool createModNPC =
true) {
195 npc.modNPC = GetNPC(npc.type).NewInstance(npc);
202 npc.globalNPCs = InstancedGlobals.Select(g => g.NewInstance(npc)).ToArray();
203 npc.modNPC?.SetDefaults();
209 internal static GlobalNPC GetGlobalNPC(NPC npc,
Mod mod,
string name) {
211 return globalIndexes.TryGetValue(mod.
Name +
':' + name, out index) ? globalNPCs[index].
Instance(npc) : null;
214 internal static GlobalNPC GetGlobalNPC(NPC npc, Type type) {
216 return globalIndexesByType.TryGetValue(type, out index) ? (index > -1 ? globalNPCs[index].Instance(npc) : null) : null;
222 npc.modNPC?.ScaleExpertStats(numPlayers, bossLifeScale);
232 npc.modNPC?.ResetEffects();
242 bool useAiType = npc.modNPC != null && npc.modNPC.aiType > 0;
244 npc.type = npc.modNPC.aiType;
262 if (result && npc.modNPC != null) {
263 return npc.modNPC.PreAI();
268 private static HookList HookAI = AddHook<Action<NPC>>(g => g.
AI);
270 public static void AI(NPC npc) {
281 npc.modNPC?.PostAI();
289 if (npc.modNPC != null) {
291 using (MemoryStream stream =
new MemoryStream()) {
293 npc.modNPC.SendExtraAI(modWriter);
295 data = stream.ToArray();
298 writer.Write((byte)data.Length);
299 if (data.Length > 0) {
306 if (npc.modNPC != null) {
307 byte[] extraAI = reader.ReadBytes(reader.ReadByte());
308 if (extraAI.Length > 0) {
309 using (MemoryStream stream =
new MemoryStream(extraAI)) {
311 npc.modNPC.ReceiveExtraAI(modReader);
320 public static void FindFrame(NPC npc,
int frameHeight) {
322 if (npc.modNPC != null && npc.modNPC.animationType > 0) {
323 npc.type = npc.modNPC.animationType;
325 npc.VanillaFindFrame(frameHeight);
327 npc.modNPC?.FindFrame(frameHeight);
336 public static void HitEffect(NPC npc,
int hitDirection,
double damage) {
337 npc.VanillaHitEffect(hitDirection, damage);
338 npc.modNPC?.HitEffect(hitDirection, damage);
345 private delegate
void DelegateUpdateLifeRegen(NPC npc, ref
int damage);
349 npc.modNPC?.UpdateLifeRegen(ref damage);
359 if (npc.modNPC != null && !npc.modNPC.CheckActive()) {
375 if (npc.modNPC != null) {
376 result = npc.modNPC.CheckDead();
394 if (npc.modNPC != null) {
395 return npc.modNPC.SpecialNPCLoot();
408 if (result && npc.modNPC != null) {
409 result = npc.modNPC.PreNPCLoot();
423 npc.modNPC?.NPCLoot();
431 public static void BossLoot(NPC npc, ref
string name, ref
int potionType) {
432 npc.modNPC?.BossLoot(ref name, ref potionType);
435 public static void BossBag(NPC npc, ref
int bagType) {
436 if (npc.modNPC != null) {
437 bagType = npc.modNPC.bossBag;
443 public static void OnCatchNPC(NPC npc, Player player, Item item) {
444 npc.modNPC?.OnCatchNPC(player, item);
451 private delegate
bool DelegateCanHitPlayer(NPC npc, Player target, ref
int cooldownSlot);
454 public static bool CanHitPlayer(NPC npc, Player target, ref
int cooldownSlot) {
460 if (npc.modNPC != null) {
461 return npc.modNPC.CanHitPlayer(target, ref cooldownSlot);
466 private delegate
void DelegateModifyHitPlayer(NPC npc, Player target, ref
int damage, ref
bool crit);
469 public static void ModifyHitPlayer(NPC npc, Player target, ref
int damage, ref
bool crit) {
470 npc.modNPC?.ModifyHitPlayer(target, ref damage, ref crit);
479 public static void OnHitPlayer(NPC npc, Player target,
int damage,
bool crit) {
480 npc.modNPC?.OnHitPlayer(target, damage, crit);
493 if (canHit.HasValue && !canHit.Value) {
496 if (canHit.HasValue) {
500 if (npc.modNPC != null) {
501 bool? canHit = npc.modNPC.CanHitNPC(target);
502 if (canHit.HasValue && !canHit.Value) {
505 if (canHit.HasValue) {
512 private delegate
void DelegateModifyHitNPC(NPC npc, NPC target, ref
int damage, ref
float knockback, ref
bool crit);
515 public static void ModifyHitNPC(NPC npc, NPC target, ref
int damage, ref
float knockback, ref
bool crit) {
516 npc.modNPC?.ModifyHitNPC(target, ref damage, ref knockback, ref crit);
523 private static HookList HookOnHitNPC = AddHook<Action<NPC, NPC, int, float, bool>>(g => g.
OnHitNPC);
525 public static void OnHitNPC(NPC npc, NPC target,
int damage,
float knockback,
bool crit) {
526 npc.modNPC?.OnHitNPC(target, damage, knockback, crit);
538 if (canHit.HasValue && !canHit.Value) {
541 if (canHit.HasValue) {
545 if (npc.modNPC != null) {
546 bool? canHit = npc.modNPC.CanBeHitByItem(player, item);
547 if (canHit.HasValue && !canHit.Value) {
550 if (canHit.HasValue) {
557 private delegate
void DelegateModifyHitByItem(NPC npc, Player player,
Item item, ref
int damage, ref
float knockback, ref
bool crit);
560 public static void ModifyHitByItem(NPC npc, Player player, Item item, ref
int damage, ref
float knockback, ref
bool crit) {
561 npc.modNPC?.ModifyHitByItem(player, item, ref damage, ref knockback, ref crit);
568 private static HookList HookOnHitByItem = AddHook<Action<NPC, Player, Item, int, float, bool>>(g => g.
OnHitByItem);
570 public static void OnHitByItem(NPC npc, Player player, Item item,
int damage,
float knockback,
bool crit) {
571 npc.modNPC?.OnHitByItem(player, item, damage, knockback, crit);
584 if (canHit.HasValue && !canHit.Value) {
587 if (canHit.HasValue) {
591 if (npc.modNPC != null) {
592 bool? canHit = npc.modNPC.CanBeHitByProjectile(projectile);
593 if (canHit.HasValue && !canHit.Value) {
596 if (canHit.HasValue) {
603 private delegate
void DelegateModifyHitByProjectile(NPC npc, Projectile projectile, ref
int damage, ref
float knockback, ref
bool crit, ref
int hitDirection);
606 public static void ModifyHitByProjectile(NPC npc, Projectile projectile, ref
int damage, ref
float knockback, ref
bool crit, ref
int hitDirection) {
607 npc.modNPC?.ModifyHitByProjectile(projectile, ref damage, ref knockback, ref crit, ref hitDirection);
609 foreach (
GlobalNPC g
in HookModifyHitByProjectile.
arr) {
616 public static void OnHitByProjectile(NPC npc, Projectile projectile,
int damage,
float knockback,
bool crit) {
617 npc.modNPC?.OnHitByProjectile(projectile, damage, knockback, crit);
624 private delegate
bool DelegateStrikeNPC(NPC npc, ref
double damage,
int defense, ref
float knockback,
int hitDirection, ref
bool crit);
627 public static bool StrikeNPC(NPC npc, ref
double damage,
int defense, ref
float knockback,
int hitDirection, ref
bool crit) {
629 if (npc.modNPC != null) {
630 flag = npc.modNPC.StrikeNPC(ref damage, defense, ref knockback, hitDirection, ref crit);
633 if (!g.
Instance(npc).
StrikeNPC(npc, ref damage, defense, ref knockback, hitDirection, ref crit)) {
640 private delegate
void DelegateBossHeadSlot(NPC npc, ref
int index);
644 npc.modNPC?.BossHeadSlot(ref index);
651 private delegate
void DelegateBossHeadRotation(NPC npc, ref
float rotation);
655 npc.modNPC?.BossHeadRotation(ref rotation);
662 private delegate
void DelegateBossHeadSpriteEffects(NPC npc, ref SpriteEffects spriteEffects);
666 npc.modNPC?.BossHeadSpriteEffects(ref spriteEffects);
668 foreach (
GlobalNPC g
in HookBossHeadSpriteEffects.
arr) {
675 public static Color?
GetAlpha(NPC npc, Color lightColor) {
678 if (color.HasValue) {
682 return npc.modNPC?.GetAlpha(lightColor);
685 private delegate
void DelegateDrawEffects(NPC npc, ref Color drawColor);
689 npc.modNPC?.DrawEffects(ref drawColor);
696 private static HookList HookPreDraw = AddHook<Func<NPC, SpriteBatch, Color, bool>>(g => g.
PreDraw);
698 public static bool PreDraw(NPC npc, SpriteBatch spriteBatch, Color drawColor) {
703 if (result && npc.modNPC != null) {
704 return npc.modNPC.PreDraw(spriteBatch, drawColor);
709 private static HookList HookPostDraw = AddHook<Action<NPC, SpriteBatch, Color>>(g => g.
PostDraw);
711 public static void PostDraw(NPC npc, SpriteBatch spriteBatch, Color drawColor) {
712 npc.modNPC?.PostDraw(spriteBatch, drawColor);
721 internal static void DrawBehind(NPC npc,
int index)
723 npc.modNPC?.DrawBehind(index);
730 private delegate
bool? DelegateDrawHealthBar(NPC npc, byte bhPosition, ref
float scale, ref Vector2 position);
734 Vector2 position =
new Vector2(npc.position.X + npc.width / 2, npc.position.Y + npc.gfxOffY);
735 if (Main.HealthBarDrawSettings == 1) {
736 position.Y += npc.height + 10f + Main.NPCAddHeight(npc.whoAmI);
738 else if (Main.HealthBarDrawSettings == 2) {
739 position.Y -= 24f + Main.NPCAddHeight(npc.whoAmI) / 2f;
742 bool? result = g.
Instance(npc).
DrawHealthBar(npc, Main.HealthBarDrawSettings, ref scale, ref position);
743 if (result.HasValue) {
745 DrawHealthBar(npc, position, scale);
751 bool? result = npc.modNPC.DrawHealthBar(Main.HealthBarDrawSettings, ref scale, ref position);
752 if (result.HasValue) {
754 DrawHealthBar(npc, position, scale);
763 float alpha = Lighting.Brightness((
int)(npc.Center.X / 16f), (
int)(npc.Center.Y / 16f));
764 Main.instance.DrawHealthBar(position.X, position.Y, npc.life, npc.lifeMax, alpha, scale);
767 private delegate
void DelegateEditSpawnRate(Player player, ref
int spawnRate, ref
int maxSpawns);
770 public static void EditSpawnRate(Player player, ref
int spawnRate, ref
int maxSpawns) {
776 private delegate
void DelegateEditSpawnRange(Player player, ref
int spawnRangeX, ref
int spawnRangeY,
777 ref
int safeRangeX, ref
int safeRangeY);
780 public static void EditSpawnRange(Player player, ref
int spawnRangeX, ref
int spawnRangeY,
781 ref
int safeRangeX, ref
int safeRangeY) {
783 g.
EditSpawnRange(player, ref spawnRangeX, ref spawnRangeY, ref safeRangeX, ref safeRangeY);
792 IDictionary<int, float> pool =
new Dictionary<int, float>();
794 foreach (
ModNPC npc
in npcs) {
797 pool[npc.
npc.type] = weight;
803 float totalWeight = 0f;
804 foreach (
int type
in pool.Keys) {
805 if (pool[type] < 0f) {
808 totalWeight += pool[type];
810 float choice = (float)Main.rand.NextDouble() * totalWeight;
811 foreach (
int type
in pool.Keys) {
812 float weight = pool[type];
813 if (choice < weight) {
823 public static int SpawnNPC(
int type,
int tileX,
int tileY) {
824 var npc = type >= NPCID.Count ?
825 GetNPC(type).
SpawnNPC(tileX, tileY) :
826 NPC.NewNPC(tileX * 16 + 8, tileY * 16, type);
836 foreach (
ModNPC npc
in npcs) {
837 if (npc.
npc.townNPC && NPC.TypeToHeadIndex(npc.
npc.type) >= 0 && !NPC.AnyNPCs(npc.
npc.type) &&
839 Main.townNPCCanSpawn[npc.
npc.type] =
true;
840 if (WorldGen.prioritizedTownNPC == 0) {
841 WorldGen.prioritizedTownNPC = npc.
npc.type;
848 return GetNPC(type)?.CheckConditions(WorldGen.roomX1, WorldGen.roomX2, WorldGen.roomY1, WorldGen.roomY2) ??
true;
852 return GetNPC(type)?.TownNPCName() ??
"";
856 return npc.modNPC?.UsesPartyHat() ??
true;
861 public static bool CanChat(NPC npc,
bool vanillaCanChat) {
862 bool defaultCanChat = npc.modNPC?.CanChat() ?? vanillaCanChat;
866 if (canChat.HasValue) {
867 if (!canChat.Value) {
870 defaultCanChat =
true;
874 return defaultCanChat;
877 private delegate
void DelegateGetChat(NPC npc, ref
string chat);
880 public static void GetChat(NPC npc, ref
string chat) {
881 if (npc.modNPC != null) {
882 chat = npc.modNPC.GetChat();
884 else if (chat.Equals(
"")) {
885 chat = Language.GetTextValue(
"tModLoader.DefaultTownNPCChat");
893 if (Main.player[Main.myPlayer].talkNPC >= 0) {
894 NPC npc = Main.npc[Main.player[Main.myPlayer].talkNPC];
895 npc.modNPC?.SetChatButtons(ref button, ref button2);
902 NPC npc = Main.npc[Main.LocalPlayer.talkNPC];
910 Main.PlaySound(SoundID.MenuTick);
917 private delegate
void DelegateOnChatButtonClicked(NPC npc,
bool firstButton);
921 NPC npc = Main.npc[Main.LocalPlayer.talkNPC];
924 if (npc.modNPC != null) {
925 npc.modNPC.OnChatButtonClicked(firstButton, ref shop);
926 Main.PlaySound(SoundID.MenuTick);
928 Main.playerInventory =
true;
929 Main.npcChatText =
"";
930 Main.npcShop = Main.MaxShopIDs - 1;
931 Main.instance.shop[Main.npcShop].SetupShop(npc.type);
939 private delegate
void DelegateSetupShop(
int type, Chest shop, ref
int nextSlot);
942 public static void SetupShop(
int type, Chest shop, ref
int nextSlot) {
943 if (type < shopToNPC.Length) {
944 type = shopToNPC[type];
947 GetNPC(type)?.SetupShop(shop, ref nextSlot);
954 private delegate
void DelegateSetupTravelShop(
int[] shop, ref
int nextSlot);
965 public static bool CanGoToStatue(NPC npc,
bool toKingStatue,
bool vanillaCanGo) {
966 bool defaultCanGo = npc.modNPC?.CanGoToStatue(toKingStatue) ?? vanillaCanGo;
970 if (canGo.HasValue) {
984 npc.modNPC?.OnGoToStatue(toKingStatue);
991 private delegate
void DelegateBuffTownNPC(ref
float damageMult, ref
int defense);
994 public static void BuffTownNPC(ref
float damageMult, ref
int defense) {
1015 private delegate
void DelegateTownNPCAttackStrength(NPC npc, ref
int damage, ref
float knockback);
1019 npc.modNPC?.TownNPCAttackStrength(ref damage, ref knockback);
1021 foreach (
GlobalNPC g
in HookTownNPCAttackStrength.
arr) {
1026 private delegate
void DelegateTownNPCAttackCooldown(NPC npc, ref
int cooldown, ref
int randExtraCooldown);
1030 npc.modNPC?.TownNPCAttackCooldown(ref cooldown, ref randExtraCooldown);
1032 foreach (
GlobalNPC g
in HookTownNPCAttackCooldown.
arr) {
1037 private delegate
void DelegateTownNPCAttackProj(NPC npc, ref
int projType, ref
int attackDelay);
1041 npc.modNPC?.TownNPCAttackProj(ref projType, ref attackDelay);
1048 private delegate
void DelegateTownNPCAttackProjSpeed(NPC npc, ref
float multiplier, ref
float gravityCorrection,
1049 ref
float randomOffset);
1053 ref
float randomOffset) {
1054 npc.modNPC?.TownNPCAttackProjSpeed(ref multiplier, ref gravityCorrection, ref randomOffset);
1056 foreach (
GlobalNPC g
in HookTownNPCAttackProjSpeed.
arr) {
1061 private delegate
void DelegateTownNPCAttackShoot(NPC npc, ref
bool inBetweenShots);
1065 npc.modNPC?.TownNPCAttackShoot(ref inBetweenShots);
1072 private delegate
void DelegateTownNPCAttackMagic(NPC npc, ref
float auraLightMultiplier);
1076 npc.modNPC?.TownNPCAttackMagic(ref auraLightMultiplier);
1083 private delegate
void DelegateTownNPCAttackSwing(NPC npc, ref
int itemWidth, ref
int itemHeight);
1087 npc.modNPC?.TownNPCAttackSwing(ref itemWidth, ref itemHeight);
1094 private delegate
void DelegateDrawTownAttackGun(NPC npc, ref
float scale, ref
int item, ref
int closeness);
1098 npc.modNPC?.DrawTownAttackGun(ref scale, ref item, ref closeness);
1105 private delegate
void DelegateDrawTownAttackSwing(NPC npc, ref Texture2D item, ref
int itemSize, ref
float scale, ref Vector2 offset);
1108 public static void DrawTownAttackSwing(NPC npc, ref Texture2D item, ref
int itemSize, ref
float scale, ref Vector2 offset) {
1109 npc.modNPC?.DrawTownAttackSwing(ref item, ref itemSize, ref scale, ref offset);
1116 private static bool HasMethod(Type t,
string method, params Type[] args) {
1117 return t.GetMethod(method, args).DeclaringType != typeof(
GlobalNPC);
1120 internal static void VerifyGlobalNPC(
GlobalNPC npc) {
1121 var type = npc.GetType();
1123 bool hasInstanceFields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
1124 .Any(f => f.DeclaringType != typeof(
GlobalNPC));
1125 if (hasInstanceFields) {
1127 throw new Exception(type +
" has instance fields but does not set InstancePerEntity to true. Either use static fields, or per instance globals");
static void BossLoot(NPC npc, ref string name, ref int potionType)
static void NPCLoot(NPC npc)
static void BossHeadSpriteEffects(NPC npc, ref SpriteEffects spriteEffects)
static void PostDraw(NPC npc, SpriteBatch spriteBatch, Color drawColor)
static bool CheckDead(NPC npc)
static void TownNPCAttackProj(NPC npc, ref int projType, ref int attackDelay)
virtual bool CanHitPlayer(NPC npc, Player target, ref int cooldownSlot)
Allows you to determine whether an NPC can hit the given player. Return false to block the NPC from h...
static void NPCAI(NPC npc)
virtual bool PreNPCLoot(NPC npc)
Allows you to determine whether or not the NPC will drop anything at all. Return false to stop the NP...
static void DrawTownAttackSwing(NPC npc, ref Texture2D item, ref int itemSize, ref float scale, ref Vector2 offset)
This server as a central class to help modders spawn their npcs. It's basically the vanilla spawn cod...
static void BuffTownNPC(ref float damageMult, ref int defense)
This class serves as a place for you to place all your properties and hooks for each NPC...
static int ChooseSpawn(NPCSpawnInfo spawnInfo)
virtual void OnHitByProjectile(NPC npc, Projectile projectile, int damage, float knockback, bool crit)
Allows you to create special effects when an NPC is hit by a projectile.
virtual bool CheckDead(NPC npc)
Whether or not an NPC should be killed when it reaches 0 health. You may program extra effects in thi...
static void TownNPCAttackShoot(NPC npc, ref bool inBetweenShots)
static bool AllowVanillaClients
virtual void DrawTownAttackSwing(NPC npc, ref Texture2D item, ref int itemSize, ref float scale, ref Vector2 offset)
Allows you to customize how a town NPC's weapon is drawn when the NPC is swinging it (the NPC must ha...
virtual void ModifyHitNPC(NPC npc, NPC target, ref int damage, ref float knockback, ref bool crit)
Allows you to modify the damage, knockback, etc., that an NPC does to a friendly NPC.
static void BossHeadRotation(NPC npc, ref float rotation)
static void OnHitByItem(NPC npc, Player player, Item item, int damage, float knockback, bool crit)
static bool DrawHealthBar(NPC npc, ref float scale)
static void UpdateLifeRegen(NPC npc, ref int damage)
virtual bool CanChat(NPC npc)
Allows you to determine whether this NPC can talk with the player. Return true to allow talking with ...
virtual void SetupShop(int type, Chest shop, ref int nextSlot)
Allows you to add items to an NPC's shop. The type parameter is the type of the NPC that this shop be...
virtual float SpawnChance(NPCSpawnInfo spawnInfo)
Whether or not this NPC can spawn with the given spawning conditions. Return the weight for the chanc...
virtual void OnCatchNPC(NPC npc, Player player, Item item)
Allows you to make things happen when an NPC is caught. Ran Serverside.
static void BossBag(NPC npc, ref int bagType)
A struct that stores information regarding where an NPC is naturally spawning and the player it is sp...
static bool PreDraw(NPC npc, SpriteBatch spriteBatch, Color drawColor)
virtual void TownNPCAttackStrength(NPC npc, ref int damage, ref float knockback)
Allows you to determine the damage and knockback of a town NPC's attack before the damage is scaled...
static void PostAI(NPC npc)
static void HitEffect(NPC npc, int hitDirection, double damage)
static bool StrikeNPC(NPC npc, ref double damage, int defense, ref float knockback, int hitDirection, ref bool crit)
static void ScaleExpertStats(NPC npc, int numPlayers, float bossLifeScale)
static void ReceiveExtraAI(NPC npc, BinaryReader reader)
virtual void SpawnNPC(int npc, int tileX, int tileY)
Allows you to customize an NPC (for example, its position or ai array) after it naturally spawns and ...
virtual void ResetEffects(NPC npc)
This is where you reset any fields you add to your subclass to their default states. This is necessary in order to reset your fields if they are conditionally set by a tick update but the condition is no longer satisfied.
static void TownNPCAttackSwing(NPC npc, ref int itemWidth, ref int itemHeight)
virtual void EditSpawnRange(Player player, ref int spawnRangeX, ref int spawnRangeY, ref int safeRangeX, ref int safeRangeY)
Allows you to modify the range at which NPCs can spawn around the given player. The spawnRanges deter...
virtual void SetupTravelShop(int[] shop, ref int nextSlot)
Allows you to add items to the traveling merchant's shop. Add an item by setting shop[nextSlot] to th...
static bool CanHitNPC(NPC npc, NPC target)
virtual void GetChat(NPC npc, ref string chat)
Allows you to modify the chat message of any NPC that the player can talk to.
static void OnCatchNPC(NPC npc, Player player, Item item)
virtual void ScaleExpertStats(NPC npc, int numPlayers, float bossLifeScale)
Allows you to customize an NPC's stats in expert mode.
virtual void UpdateLifeRegen(NPC npc, ref int damage)
Allows you to make the NPC either regenerate health or take damage over time by setting npc...
virtual void BossHeadRotation(NPC npc, ref float rotation)
Allows you to customize the rotation of an NPC's boss head icon on the map.
This serves as the central class which loads mods. It contains many static fields and methods related...
virtual void OnHitNPC(NPC npc, NPC target, int damage, float knockback, bool crit)
Allows you to create special effects when an NPC hits a friendly NPC.
virtual void ModifyHitByProjectile(NPC npc, Projectile projectile, ref int damage, ref float knockback, ref bool crit, ref int hitDirection)
Allows you to modify the damage, knockback, etc., that an NPC takes from a projectile.
static bool CanBeHitByItem(NPC npc, Player player, Item item)
virtual void OnHitByItem(NPC npc, Player player, Item item, int damage, float knockback, bool crit)
Allows you to create special effects when an NPC is hit by a melee weapon.
virtual bool InstancePerEntity
Whether to create a new GlobalNPC instance for every NPC that exists. Useful for storing information ...
static void ModifyHitByProjectile(NPC npc, Projectile projectile, ref int damage, ref float knockback, ref bool crit, ref int hitDirection)
virtual void AI(NPC npc)
Allows you to determine how any NPC behaves. This will only be called if PreAI returns true...
static void ModifyHitNPC(NPC npc, NPC target, ref int damage, ref float knockback, ref bool crit)
virtual void DrawBehind(NPC npc, int index)
When used in conjunction with "npc.hide = true", allows you to specify that this npc should be drawn ...
virtual int SpawnNPC(int tileX, int tileY)
Allows you to customize how this NPC is created when it naturally spawns (for example, its position or ai array). Return the return value of NPC.NewNPC. By default this method spawns this NPC on top of the tile at the given coordinates.
virtual void ModifyHitByItem(NPC npc, Player player, Item item, ref int damage, ref float knockback, ref bool crit)
Allows you to modify the damage, knockback, etc., that an NPC takes from a melee weapon.
virtual void TownNPCAttackProjSpeed(NPC npc, ref float multiplier, ref float gravityCorrection, ref float randomOffset)
Allows you to determine the speed at which a town NPC throws a projectile when it attacks...
NPC npc
The NPC object that this ModNPC controls.
static bool PreNPCLoot(NPC npc)
static void TownNPCAttackCooldown(NPC npc, ref int cooldown, ref int randExtraCooldown)
static void TownNPCAttackProjSpeed(NPC npc, ref float multiplier, ref float gravityCorrection, ref float randomOffset)
virtual void FindFrame(NPC npc, int frameHeight)
Allows you to modify the frame from an NPC's texture that is drawn, which is necessary in order to an...
static int SpawnNPC(int type, int tileX, int tileY)
virtual bool CanGoToStatue(NPC npc, bool toKingStatue)
Whether this NPC can be telported a King or Queen statue. Return true to allow the NPC to teleport to...
virtual void OnHitPlayer(NPC npc, Player target, int damage, bool crit)
Allows you to create special effects when an NPC hits a player (for example, inflicting debuffs)...
static void SetupShop(int type, Chest shop, ref int nextSlot)
virtual void PostAI(NPC npc)
Allows you to determine how any NPC behaves. This will be called regardless of what PreAI returns...
virtual void DrawEffects(NPC npc, ref Color drawColor)
Allows you to add special visual effects to an NPC (such as creating dust), and modify the color in w...
static void DrawTownAttackGun(NPC npc, ref float scale, ref int item, ref int closeness)
virtual bool CanBeHitByItem(NPC npc, Player player, Item item)
Allows you to determine whether an NPC can be hit by the given melee weapon when swung. Return true to allow hitting the NPC, return false to block hitting the NPC, and return null to use the vanilla code for whether the NPC can be hit. Returns null by default.
virtual bool CanBeHitByProjectile(NPC npc, Projectile projectile)
Allows you to determine whether an NPC can be hit by the given projectile. Return true to allow hitti...
static bool PreAI(NPC npc)
static void CanTownNPCSpawn(int numTownNPCs, int money)
virtual void SetDefaults(NPC npc)
Allows you to set the properties of any and every NPC that gets created.
HookList(MethodInfo method)
static bool CanGoToStatue(NPC npc, bool toKingStatue, bool vanillaCanGo)
static void DrawEffects(NPC npc, ref Color drawColor)
virtual bool PreAI(NPC npc)
Allows you to determine how any NPC behaves. Return false to stop the vanilla AI and the AI hook from...
static void SendExtraAI(NPC npc, BinaryWriter writer)
virtual void BossHeadSlot(NPC npc, ref int index)
Allows you to customize the boss head texture used by an NPC based on its state. Set index to -1 to s...
virtual bool CheckActive(NPC npc)
Whether or not to run the code for checking whether an NPC will remain active. Return false to stop t...
static void OnChatButtonClicked(bool firstButton)
This class allows you to modify and use hooks for all NPCs, including vanilla mobs. Create an instance of an overriding class then call Mod.AddGlobalNPC to use this.
static bool CheckActive(NPC npc)
virtual bool StrikeNPC(NPC npc, ref double damage, int defense, ref float knockback, int hitDirection, ref bool crit)
Allows you to use a custom damage formula for when an NPC takes damage from any source. For example, you can change the way defense works or use a different crit multiplier. Return false to stop the game from running the vanilla damage formula; returns true by default.
virtual void TownNPCAttackShoot(NPC npc, ref bool inBetweenShots)
Allows you to tell the game that a town NPC has already created a projectile and will still create mo...
static void EditSpawnRate(Player player, ref int spawnRate, ref int maxSpawns)
static bool HasMethod(Type t, string method, params Type[] args)
static void OnHitByProjectile(NPC npc, Projectile projectile, int damage, float knockback, bool crit)
static bool CheckConditions(int type)
static void BossHeadSlot(NPC npc, ref int index)
static ModNPC GetNPC(int type)
Gets the ModNPC instance corresponding to the specified type.
static void TownNPCAttackMagic(NPC npc, ref float auraLightMultiplier)
virtual void HitEffect(NPC npc, int hitDirection, double damage)
Allows you to make things happen whenever an NPC is hit, such as creating dust or gores...
static string TownNPCName(int type)
GlobalNPC Instance(NPC npc)
virtual bool DrawHealthBar(NPC npc, byte hbPosition, ref float scale, ref Vector2 position)
Allows you to control how the health bar for the given NPC is drawn. The hbPosition parameter is the ...
virtual string Name
Stores the name of the mod. This name serves as the mod's identification, and also helps with saving ...
This serves as the central class from which NPC-related functions are carried out. It also stores a list of mod NPCs by ID.
static void FindFrame(NPC npc, int frameHeight)
static void OnHitNPC(NPC npc, NPC target, int damage, float knockback, bool crit)
static bool UsesPartyHat(NPC npc)
static void GetChat(NPC npc, ref string chat)
virtual void TownNPCAttackProj(NPC npc, ref int projType, ref int attackDelay)
Allows you to determine the projectile type of a town NPC's attack, and how long it takes for the pro...
This serves as the central class from which buff-related functions are supported and carried out...
virtual void ModifyHitPlayer(NPC npc, Player target, ref int damage, ref bool crit)
Allows you to modify the damage, etc., that an NPC does to a player.
static void OnGoToStatue(NPC npc, bool toKingStatue)
virtual bool CanTownNPCSpawn(int numTownNPCs, int money)
Whether or not the conditions have been met for this town NPC to be able to move into town...
readonly MethodInfo method
static bool CanBeHitByProjectile(NPC npc, Projectile projectile)
virtual void EditSpawnRate(Player player, ref int spawnRate, ref int maxSpawns)
Allows you to modify the chance of NPCs spawning around the given player and the maximum number of NP...
static Color GetAlpha(NPC npc, Color lightColor)
static bool SpecialNPCLoot(NPC npc)
virtual void EditSpawnPool(IDictionary< int, float > pool, NPCSpawnInfo spawnInfo)
Allows you to control which NPCs can spawn and how likely each one is to spawn. The pool parameter ma...
virtual bool PreDraw(NPC npc, SpriteBatch spriteBatch, Color drawColor)
Allows you to draw things behind an NPC, or to modify the way the NPC is drawn. Return false to stop ...
Mod is an abstract class that you will override. It serves as a central place from which the mod's co...
virtual bool SpecialNPCLoot(NPC npc)
Allows you to call NPCLoot on your own when the NPC dies, rather then letting vanilla call it on its ...
static void ModifyHitByItem(NPC npc, Player player, Item item, ref int damage, ref float knockback, ref bool crit)
static bool CanChat(NPC npc, bool vanillaCanChat)
static void SetupTravelShop(int[] shop, ref int nextSlot)
virtual bool PreChatButtonClicked(NPC npc, bool firstButton)
Allows you to determine if something can happen whenever a button is clicked on this NPC's chat windo...
virtual void DrawTownAttackGun(NPC npc, ref float scale, ref int item, ref int closeness)
Allows you to customize how a town NPC's weapon is drawn when the NPC is shooting (the NPC must have ...
static bool PreChatButtonClicked(bool firstButton)
virtual void NPCLoot(NPC npc)
Allows you to make things happen when an NPC dies (for example, dropping items and setting ModWorld f...
virtual Color GetAlpha(NPC npc, Color drawColor)
Allows you to determine the color and transparency in which an NPC is drawn. Return null to use the d...
virtual void TownNPCAttackMagic(NPC npc, ref float auraLightMultiplier)
Allows you to control the brightness of the light emitted by a town NPC's aura when it performs a mag...
static void SetChatButtons(ref string button, ref string button2)
virtual bool CanHitNPC(NPC npc, NPC target)
Allows you to determine whether an NPC can hit the given friendly NPC. Return true to allow hitting t...
virtual void PostDraw(NPC npc, SpriteBatch spriteBatch, Color drawColor)
Allows you to draw things in front of this NPC. This method is called even if PreDraw returns false...
virtual void OnChatButtonClicked(NPC npc, bool firstButton)
Allows you to make something happen whenever a button is clicked on this NPC's chat window...
virtual void TownNPCAttackSwing(NPC npc, ref int itemWidth, ref int itemHeight)
Allows you to determine the width and height of the item a town NPC swings when it attacks...
virtual void BossHeadSpriteEffects(NPC npc, ref SpriteEffects spriteEffects)
Allows you to flip an NPC's boss head icon on the map.
static void ModifyHitPlayer(NPC npc, Player target, ref int damage, ref bool crit)
virtual void OnGoToStatue(NPC npc, bool toKingStatue)
Allows you to make things happen when this NPC teleports to a King or Queen statue. This method is only called server side.
static void ResetEffects(NPC npc)
static void TownNPCAttackStrength(NPC npc, ref int damage, ref float knockback)
static void EditSpawnRange(Player player, ref int spawnRangeX, ref int spawnRangeY, ref int safeRangeX, ref int safeRangeY)
virtual void TownNPCAttackCooldown(NPC npc, ref int cooldown, ref int randExtraCooldown)
Allows you to determine the cooldown between each of a town NPC's attack. The cooldown will be a numb...
static void DrawHealthBar(NPC npc, Vector2 position, float scale)
virtual void BuffTownNPC(ref float damageMult, ref int defense)
Allows you to modify the stats of town NPCs. Useful for buffing town NPCs when certain bosses are def...
static bool CanHitPlayer(NPC npc, Player target, ref int cooldownSlot)
static void OnHitPlayer(NPC npc, Player target, int damage, bool crit)