tAPI [Discontinued] tAPI - A Mod To Make Mods

Status
Not open for further replies.
I told you, look at G realm. MWorld.cs:
Code:
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

using TAPI;
using Terraria;
using BaseMod;

namespace GRealm
{
   public class MWorld : ModWorld
   {
     public static int saveVer = 1;
     public static bool zombieInvasion = false;
     public static bool downedZombieInvasion = false;
     public static bool downedBarbarian = false;
     public static bool downedFolivine = false;

     public static bool spawnedGrovite = false;

     public static void ClearWorldVars()
     {
       zombieInvasion = false;
       downedZombieInvasion = false;
       downedBarbarian = false;
       downedFolivine = false;
       spawnedGrovite = false;
       Tiles.GrovitePylon.ClearPylons();
     }

     public static bool InInvasionArea(CodableEntity ent)
     {
       if (ent.position.Y < Main.worldSurface * 16 + NPC.sHeight)
       {
         return true;
         /*int padding = 3000;
         if (ent.position.X > Main.spawnTileX * 16 - padding && ent.position.X < Main.spawnTileX * 16 + padding)
         {
           return true;
         }*/
       }
       return false;
     }

     public override void Save(BinBuffer bb)
     {
       bb.Write(saveVer);
       bb.Write(zombieInvasion);
       bb.Write(downedZombieInvasion);
       bb.Write(downedBarbarian);
       bb.Write(downedFolivine);
       bb.Write(spawnedGrovite);

       Tiles.GrovitePylon.SavePylons(bb);
     }

     public override void Load(BinBuffer bb)
     {
       ClearWorldVars();
       try
       {
         int v = bb.ReadInt();
         if (v >= 1)
         {
           zombieInvasion = bb.ReadBool();
           downedZombieInvasion = bb.ReadBool();
           downedBarbarian = bb.ReadBool();
           downedFolivine = bb.ReadBool();
           spawnedGrovite = bb.ReadBool();

           //pylon loading
           Tiles.GrovitePylon.LoadPylons(bb);
         }
       }catch { } //prolly bad to do this
     }

     public override void PostUpdate()
     {
       Tiles.GrovitePylon.pylonHit.Clear();
     }

     public override void WorldGenPostGen()
     {
       ClearWorldVars();
       Chest[] chests = BaseMod.BaseTile.GetVanillaChests(0, (int)Main.worldSurface, BaseMod.BaseConstants.CHESTSTYLE_SKY, 1);
       foreach (Chest chest in chests)
       {
         for (int m = 0; m < chest.item.Length; m++)
         {
           Item item = chest.item[m];
           if (Main.rand.Next(3) == 0){ chest.item[1].SetDefaults("GRealm:RapierOfChance"); }
         }
       }
       chests = BaseMod.BaseTile.GetVanillaChests(0, (int)Main.worldSurface, BaseMod.BaseConstants.CHESTSTYLE_VINED, 1);
       foreach (Chest chest in chests)
       {
         if (Main.rand.Next(3) == 0){ chest.item[2].SetDefaults("GRealm:DiviningStick"); }
       }
     }
   }
}
Done, but it doesn't know what LoadBool or LoadInt is.
 
So...he's playing an identical clone of ur char? Idk then.reinstall the 2 prerequisites to make sure they're up to date?

That's the slot the buff is in, -1 if not buffed. I think anyway, been a while. And even if it was timeleft, problem isn't that buff is always on; problem is its not working.
I got the worm Ai and swapped some stuff with NPCDef.byName["TerraMod:"].type and the name of the necessary body part and he still disappears as soon as I spawn him.
There's net code that needs to be called with the spawn code, did you remember to use/change that?
Code:
new_npc = NPC.NewNPC(x_pos_out * 16 + 8, y_pos_out * 16, NPCDef.byName["PostHardModeJungle:Aether_Wraith"].type, 0);
  if (Main.netMode == 2 && new_npc < 200)
  NetMessage.SendData(23, -1, -1, "", new_npc, 0f, 0f, 0f, 0);
Or some such.
How come you don't have the code in the actual buff's code?
What MiraiMai said. Plus, that didn't even work in T config. It works well enough for adding buff Flags, But not removing them. the horseshoe makes you immune to fall damage after buffs are calculated, It's an item effect not a buff. After experimenting a bit, I found where to put it in T config so it would disable buffs from worn items. I haven't actually tried in TAPI but I assume it would be the same.
Grounded: Does it block any of them, and only some fail? Something I thought of is that there is multiple of some of those variables now, since you can triple+ jump now. It could be not working because the one you have equipped uses one of the new versions.

Panther DealtPlayer: I still say you should put this in the AI somewhere. Check if the player's and panther's hitboxs overlap, if they do then treat it like it hit. There's honestly such a low chance that it would touch the player without dealing damage, there's no point getting worried about it.
I'm pretty sure they all fail, except setting rocket time to zero which works even in effects. I've mostly been checking the slow fall and horseshoe effect provided by my wings to debug. I manually looked through all the variables and think I caught all of the new ones, but there are a lot; Anyway that doesn't seem to be the problem. I'll need to experiment a bit more at some point. This debuff is a fundamental part of two of my creature concepts; I've been working my way through alphabetically and I just reached the first one.

Yeah, I'm going to do that with the panther. It's really not that much trouble and it will work cleanly how I want it to. So that's another one solved :). ED– Oh, now that I start I realize TargetClosest(false) is called every tick so I don't even need to cycle through every player. And if I do want to base mod has a function GetPlayersInBox for checking this type of collision.
 
Last edited:
So...he's playing an identical clone of ur char? Idk then.
No, he's running an identical clone of my terraria besides characters, yet i'm the one that crashes, despite my instance being the original and my game being the host.
EDIT: I can trigger the second crash by placing rope on a line that extends into un-loaded terrain
 
Last edited:
This SHOULD work, looking at the code, not sure why it's not. An alternative, is to use ModBase.ChooseTrack(ref string track) , same track names and such, but this hook is run after the NPC/biome based checks so it should be guaranteed.
Update on my issue if it might be of any interest.

First of all, I have no clue of how to use that hook and now that I got it half sorted out, I'm also kinda too lazy to figure out myself as it sounds like something that's not meant to be used under normal circumstances. Altho, I do guess you need to declare it in a MBase file and edit the ref var every time there is a specific occasion in which a specific music should play?

On a side note, I did fix the issue by simply changing the npc.music string to the name of the song I want to play in the npc's AI. Basically, there seems to be an issue with either my json file or the mechanism behind them as changing the var this name seems to work as intended. Still haven't looked into trying to make it play custom music tho. Gotta run some tests about that, but putting my lack of knowledge about how to properly set up custom music to play, the whole issue so far sounds to be centered around the json.

EDIT: if it might interest, just in case I did some really stupid mistake, here's my json file.
Code:
{
    "displayName": "Rathalos",
    "aiStyle": -1,
    "frameCount": 4,
    "npcSlots": 10,
    "size": [100,120],
    "lifeMax": 14000,
    "defense": 18,
    "scale": 1,
    "friendly": false,
    "boss": true,
    "noTileCollide": true,
    "noGravity": true,
    "knockbackResist": 0.0,
    "damage": 48,
    "value": [0,8,0,0],
    "soundHit": 1,
    "soundKilled": 1,
    "music": "Vanilla:Music_25",
    "buffImmune": ["Poisoned","On Fire!","Confused"],

    "drops": [
        {
            "item": "W1K:RathalosScale",
            "stack": [10,15],
            "chance": 1
        },
        {
            "item": "Ruby",
            "stack": [1,2],
            "chance": 0.1
        },
        {
            "item": "W1K:Chao",
            "stack": 1,
            "chance": 0.1
        }
    ]
}
 
Update on my issue if it might be of any interest.

First of all, I have no clue of how to use that hook and now that I got it half sorted out, I'm also kinda too lazy to figure out myself as it sounds like something that's not meant to be used under normal circumstances. Altho, I do guess you need to declare it in a MBase file and edit the ref var every time there is a specific occasion in which a specific music should play?

On a side note, I did fix the issue by simply changing the npc.music string to the name of the song I want to play in the npc's AI. Basically, there seems to be an issue with either my json file or the mechanism behind them as changing the var this name seems to work as intended. Still haven't looked into trying to make it play custom music tho. Gotta run some tests about that, but putting my lack of knowledge about how to properly set up custom music to play, the whole issue so far sounds to be centered around the json.

EDIT: if it might interest, just in case I did some really stupid mistake, here's my json file.
Code:
{
    "displayName": "Rathalos",
    "aiStyle": -1,
    "frameCount": 4,
    "npcSlots": 10,
    "size": [100,120],
    "lifeMax": 14000,
    "defense": 18,
    "scale": 1,
    "friendly": false,
    "boss": true,
    "noTileCollide": true,
    "noGravity": true,
    "knockbackResist": 0.0,
    "damage": 48,
    "value": [0,8,0,0],
    "soundHit": 1,
    "soundKilled": 1,
    "music": "Vanilla:Music_25",
    "buffImmune": ["Poisoned","On Fire!","Confused"],

    "drops": [
        {
            "item": "W1K:RathalosScale",
            "stack": [10,15],
            "chance": 1
        },
        {
            "item": "Ruby",
            "stack": [1,2],
            "chance": 0.1
        },
        {
            "item": "W1K:Chao",
            "stack": 1,
            "chance": 0.1
        }
    ]
}
Thanks for this, found the issue. Apparently music was missed in the copy method, so only the original NPC class has it. (in NPCDef.byName)

Your fix works for now though, set the music manually in OnSpawn once and it should be fine. In R15 you'll be able to remove that and use the json again.
 
There's net code that needs to be called with the spawn code, did you remember to use/change that?
Code:
new_npc = NPC.NewNPC(x_pos_out * 16 + 8, y_pos_out * 16, NPCDef.byName["PostHardModeJungle:Aether_Wraith"].type, 0);
  if (Main.netMode == 2 && new_npc < 200)
  NetMessage.SendData(23, -1, -1, "", new_npc, 0f, 0f, 0f, 0);
Or some such.

What MiraiMai said. Plus, that didn't even work in T config. It works well enough for adding buff Flags, But not removing them. the horseshoe makes you immune to fall damage after buffs are calculated, It's an item effect not a buff. After experimenting a bit, I found where to put it in T config so it would disable buffs from worn items. I haven't actually tried in TAPI but I assume it would be the same.

I'm pretty sure they all fail, except setting rocket time to zero which works even in effects. I've mostly been checking the slow fall and horseshoe effect provided by my wings to debug. I manually looked through all the variables and think I caught all of the new ones, but there are a lot; Anyway that doesn't seem to be the problem. I'll need to experiment a bit more at some point. This debuff is a fundamental part of two of my creature concepts; I've been working my way through alphabetically and I just reached the first one.

Yeah, I'm going to do that with the panther. It's really not that much trouble and it will work cleanly how I want it to. So that's another one solved :). ED– Oh, now that I start I realize TargetClosest(false) is called every tick so I don't even need to cycle through every player. And if I do want to base mod has a function GetPlayersInBox for checking this type of collision.
So I do make a variable for each other body part in BaseNet or whatever it's called and then get the, spawned when the head is active?
 
This code didn't work:

public int spawnBody = NPC.NewNPC(x_pos_out * 16 + 8, y_pos_out * 16, NPCDef.byName["TerraMod;WyvernBossBody"].type, 0);
public int spawnBody2 = NPC.NewNPC(x_pos_out * 16 + 8, y_pos_out * 16, NPCDef.byName["TerraMod;WyvernBossBody2"].type, 0);
public int spawnBody3 = NPC.NewNPC(x_pos_out * 16 + 8, y_pos_out * 16, NPCDef.byName["TerraMod;WyvernBossBody3"].type, 0);
public int spawnTail = NPC.NewNPC(x_pos_out * 16 + 8, y_pos_out * 16, NPCDef.byName["TerraMod;WyvernBossTail"].type, 0);

public override bool? UseItem(Player p)
{
if (Main.netMode == 2 && spawnBody2 < 200 && spawnBody < 200 && spawnBody3 < 200 && spawnTail < 200)
{
NetMessage.SendData(23, -1, -1, "", spawnBody2, 0f, 0f, 0f, 0);
NetMessage.SendData(23, -1, -1, "", spawnBody2, 0f, 0f, 0f, 0);
NetMessage.SendData(23, -1, -1, "", spawnBody2, 0f, 0f, 0f, 0);
NetMessage.SendData(23, -1, -1, "", spawnBody2, 0f, 0f, 0f, 0);
}

if (Main.dayTime)
{
NPC.SpawnOnPlayer(p.whoAmI, NPCDef.byName["TerraMod:WyvernBossHead"].type);
return true;
}

else
return false;

This is the code for the summoning item.
 
I just joined this forum to report some bugs I experienced playing tAPI recently.

I have been getting duplicate town npcs showing up in my worlds. Multiple chefs, multiple blacksmiths, etc. I also had a few supposedly hardmode npcs join in a non-hardmode world, specifically the druid, blacksmith, zombie, and weapon master. Now that I list them out, it looks like those are all thorium+ npcs, so it could be that mod's fault. I'll post in that thread as well.

In the dungeon post-plantera, the Diabolist doest appear to spawn anywhere. All of the other enemy spawns appear to match the background/banners as outlined in the wiki, but instead of Diabolists I get Ragged Casters.

And it looks like my timer glitch was already reported and fixed.

I'm running r14a. My mod list:
Shockah's base r3
Accessory Slots+ r1
Enhanced Tooltip r2
Inventory Tweaks r2
ThoriumMod+
 
No, he's running an identical clone of my terraria besides characters, yet i'm the one that crashes, despite my instance being the original and my game being the host.
Maybe your character is carrying an item that his isn't?
Also, you could try running the game server separately as a dedicated process on your computer and joining multiplayer the same way he does. That might make it easier to locate which process is crashing. It might even solve the problem. The server executable is sitting in the terraria folder.
So I do make a variable for each other body part in BaseNet or whatever it's called and then get the, spawned when the head is active?
If I remember correctly it uses a single variable in worm and cycles through each body part. But that's not the point. The point is for each new NPC call you need a net message call to inform the (clients ?) That the body part exists. And if worm uses net message during cleanup after a piece dies, remember to do that too_Once again, if I remember correctly, worm types use their AI variables to keep track of their parent and child parts so when one dies it can trigger a chain reaction and kill the entire thing
 
I just joined this forum to report some bugs I experienced playing tAPI recently.

I have been getting duplicate town npcs showing up in my worlds. Multiple chefs, multiple blacksmiths, etc. I also had a few supposedly hardmode npcs join in a non-hardmode world, specifically the druid, blacksmith, zombie, and weapon master. Now that I list them out, it looks like those are all thorium+ npcs, so it could be that mod's fault. I'll post in that thread as well.

In the dungeon post-plantera, the Diabolist doest appear to spawn anywhere. All of the other enemy spawns appear to match the background/banners as outlined in the wiki, but instead of Diabolists I get Ragged Casters.

And it looks like my timer glitch was already reported and fixed.

I'm running r14a. My mod list:
Shockah's base r3
Accessory Slots+ r1
Enhanced Tooltip r2
Inventory Tweaks r2
ThoriumMod+
Given by what you say are their versions, I'm not surprised.
 
This code didn't work:

public int spawnBody = NPC.NewNPC(x_pos_out * 16 + 8, y_pos_out * 16, NPCDef.byName["TerraMod;WyvernBossBody"].type, 0);
public int spawnBody2 = NPC.NewNPC(x_pos_out * 16 + 8, y_pos_out * 16, NPCDef.byName["TerraMod;WyvernBossBody2"].type, 0);
public int spawnBody3 = NPC.NewNPC(x_pos_out * 16 + 8, y_pos_out * 16, NPCDef.byName["TerraMod;WyvernBossBody3"].type, 0);
public int spawnTail = NPC.NewNPC(x_pos_out * 16 + 8, y_pos_out * 16, NPCDef.byName["TerraMod;WyvernBossTail"].type, 0);

public override bool? UseItem(Player p)
{
if (Main.netMode == 2 && spawnBody2 < 200 && spawnBody < 200 && spawnBody3 < 200 && spawnTail < 200)
{
NetMessage.SendData(23, -1, -1, "", spawnBody2, 0f, 0f, 0f, 0);
NetMessage.SendData(23, -1, -1, "", spawnBody2, 0f, 0f, 0f, 0);
NetMessage.SendData(23, -1, -1, "", spawnBody2, 0f, 0f, 0f, 0);
NetMessage.SendData(23, -1, -1, "", spawnBody2, 0f, 0f, 0f, 0);
}

if (Main.dayTime)
{
NPC.SpawnOnPlayer(p.whoAmI, NPCDef.byName["TerraMod:WyvernBossHead"].type);
return true;
}

else
return false;

This is the code for the summoning item.
Firstly, for some reason you informed the clients that you had spawned four new NPC's when you hadn't. Secondly, you informed it that the second segment had been spawned all four times, so even if those parts existed, it would just think there are four copies of segment two and nothing else. The idea is that at the same time you call new NPC, you send a net message to announce the NPC's existence.I'll post summoning item code in a second.
Code:
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using System.Reflection;

using TAPI;
using Terraria;

namespace PostHardModeJungle.Items
{
  public class Aether_Wraith_Summoning_Wand : ModItem
  {
  public override bool? UseItem(Player p)
  {
  if (Main.netMode != 1)
  {
  int j = p.whoAmI;
  int spawnRangeX = (int)typeof(NPC).GetField("spawnRangeX", BindingFlags.NonPublic | BindingFlags.Static).GetValue(null);
  int spawnRangeY = (int)typeof(NPC).GetField("spawnRangeX", BindingFlags.NonPublic | BindingFlags.Static).GetValue(null);
  int spawnSpaceX = (int)typeof(NPC).GetField("spawnSpaceX", BindingFlags.NonPublic | BindingFlags.Static).GetValue(null);
  int spawnSpaceY = (int)typeof(NPC).GetField("spawnSpaceY", BindingFlags.NonPublic | BindingFlags.Static).GetValue(null);
  #region set xmin,xmax,ymin,ymax,safe_xmin,safe_xmax,safe_ymin,safe_ymax
  int xmin = (int)(Main.player[j].position.X / 16f) - spawnRangeX;
  int xmax = (int)(Main.player[j].position.X / 16f) + spawnRangeX;
  int ymin = (int)(Main.player[j].position.Y / 16f) - spawnRangeY;
  int ymax = (int)(Main.player[j].position.Y / 16f) + spawnRangeY;
  int safe_xmin = (int)(Main.player[j].position.X / 16f) - NPC.safeRangeX;
  int safe_xmax = (int)(Main.player[j].position.X / 16f) + NPC.safeRangeX;
  int safe_ymin = (int)(Main.player[j].position.Y / 16f) - NPC.safeRangeY;
  int safe_ymax = (int)(Main.player[j].position.Y / 16f) + NPC.safeRangeY;
  if (xmin < 0)
  xmin = 0;
  if (xmax > Main.maxTilesX)
  xmax = Main.maxTilesX;
  if (ymin < 0)
  ymin = 0;
  if (ymax > Main.maxTilesY)
  ymax = Main.maxTilesY;
  #endregion

  bool spawn_valid = false;
  int x_pos_out = 0;
  int y_pos_out = 0;
  int k = 0;
  while (k < 50) // try 50 times
  {
  #region look for valid spawn point
  int x_pos = Main.rand.Next(xmin, xmax);
  int y_pos = Main.rand.Next(ymin, ymax);

  if (Main.tile[x_pos, y_pos].active() && TileDef.solid[(int)Main.tile[x_pos, y_pos].type]) // solid block
  goto IL_C34; // spawn failed

  if (!TileDef.wallHouse[(int)Main.tile[x_pos, y_pos].wall]) // not inside a house
  {
  #region trace down to find a tile with solid ground, away from player (x_pos_out,y_pos_out)
  int l = y_pos;
  while (l < Main.maxTilesY) // trace downwards
  {
  if (Main.tile[x_pos, l].active() && TileDef.solid[(int)Main.tile[x_pos, l].type]) // hit a solid tile
  {
  if (x_pos < safe_xmin || x_pos > safe_xmax || l < safe_ymin || l > safe_ymax) // away from spawning player
  {
  //byte arg_B5A_0 = Main.tile[x_pos, l].type;
  x_pos_out = x_pos;
  y_pos_out = l;
  spawn_valid = true;
  break; // found a candidate - stop tracing down
  }
  break; // hit a solid tile - stop tracing down
  }
  else // keep tracing down
  l++;
  } // END trace downwards
  #endregion

  if (!spawn_valid)
  goto IL_C34;

  #region set cavity_xmin,cavity_xmax,cavity_ymin,cavity_ymax; check if there is space for npc
  int cavity_x_min = x_pos_out - spawnSpaceX / 2;
  int cavity_x_max = x_pos_out + spawnSpaceX / 2;
  int cavity_y_min = y_pos_out - spawnSpaceY;
  int cavity_y_max = y_pos_out;
  if (cavity_x_min < 0)
  spawn_valid = false;
  if (cavity_x_max > Main.maxTilesX)
  spawn_valid = false;
  if (cavity_y_min < 0)
  spawn_valid = false;
  if (cavity_y_max > Main.maxTilesY)
  spawn_valid = false;

  if (spawn_valid)
  {
  for (int m = cavity_x_min; m < cavity_x_max; m++)
  {
  for (int n = cavity_y_min; n < cavity_y_max; n++)
  {
  if (Main.tile[m, n].active() && TileDef.solid[(int)Main.tile[m, n].type])
  {
  spawn_valid = false;
  break;
  }
  if (Main.tile[m, n].lava())
  {
  spawn_valid = false;
  break;
  }
  }
  }
  goto IL_C34;
  }
  #endregion

  goto IL_C34;
  }

  #region dont spawn on other players' screens either
  if (spawn_valid)
  {
  Rectangle spawn_rect = new Rectangle(x_pos_out * 16, y_pos_out * 16, 16, 16);
  for (int other_player = 0; other_player < 255; other_player++)
  {
  if (Main.player[other_player].active)
  {
  Rectangle other_player_rect = new Rectangle((int)(Main.player[other_player].position.X + (float)(Main.player[other_player].width / 2) - (float)(NPC.sWidth / 2) - (float)NPC.safeRangeX), (int)(Main.player[other_player].position.Y + (float)(Main.player[other_player].height / 2) - (float)(NPC.sHeight / 2) - (float)NPC.safeRangeY), NPC.sWidth + NPC.safeRangeX * 2, NPC.sHeight + NPC.safeRangeY * 2);
  if (spawn_rect.Intersects(other_player_rect))
  spawn_valid = false;
  }
  }
  }
  #endregion

  IL_C3A:
  k++;
  continue; // try again
  IL_C34:
  if (!spawn_valid)
  goto IL_C3A; // try again
  break; // found legal spot
  #endregion
  } // END try 50 times

  if (spawn_valid)
  {
  int new_npc = 255;
  new_npc = NPC.NewNPC(x_pos_out * 16 + 8, y_pos_out * 16, NPCDef.byName["PostHardModeJungle:Aether_Wraith"].type, 0);
  if (Main.netMode == 2 && new_npc < 200)
  NetMessage.SendData(23, -1, -1, "", new_npc, 0f, 0f, 0f, 0);
  }
  }
  if (Main.netMode != 2)
  {
  Main.PlaySound(2, (int)p.Center.X, (int)p.Center.Y, 37);
  Vector2 npcPos = p.position - new Vector2(0, 200);
  for (int m = 0; m < 15; m++)
  {
  int dustID = Dust.NewDust(npcPos, p.width, p.height, 60, Main.rand.Next(-10, 10) * 1f, Main.rand.Next(-10, 10) * 1f, 100, Color.White, 3.5f);
  Main.dust[dustID].noGravity = true;
  }
  }
  return true;
  }
  }
}
this code spends a lot of effort mimicking natural spawn behavior, I'll post an old simplified one that just spawns the creature next to you if I can find it in another second
.
Code:
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;

using TAPI;
using Terraria;

namespace TemplateMod.Items
{
  public class ExampleMobNPCWand : ModItem
  {
  public override bool? UseItem(Player p)
  {
  if(Main.netMode != 1)
  {
  int npcID = NPC.NewNPC((int)p.Center.X, (int)p.Center.Y - 200, NPCDef.byName["TemplateMod:ExampleMobNPC"].type, 0);
         if (Main.netMode == 2)
           NetMessage.SendData(23, -1, -1, "", npcID, 0.0f, 0.0f, 0.0f, 0);
  }
       return true;
  }
  }
}
there, this is from grox's code, So that's the simplest way to spawn to creature that I'm sure is reliable. Five lines of code.

That said, you shouldn't have your summoning items summon the entire thing, you should have it summon just the head, and in the heads on spawn method have the head summon the other body parts. I believe this is how worms do it.

I don't have a custom worm AI, but I do have an AI that summons multiple creatures on spawn. It's from T config so the code will work as is but I'll post it in case it will help.
Code:
public void AI()  //  bat ai
{
  int beaker1,beaker2,beaker3;
     Vector2 npc_center = new Vector2(npc.position.X + (float)npc.width * 0.5f, npc.position.Y + (float)npc.height * 0.5f);
  beaker1=NPC.NewNPC((int)npc_center.X, (int)npc_center.Y + (int)(npc.height * 0.5f), Config.npcDefs.byName["Jungle Beaker"].type, 0);
  beaker2=NPC.NewNPC((int)npc_center.X, (int)npc_center.Y + (int)(npc.height * 0.5f), Config.npcDefs.byName["Jungle Beaker"].type, 0);
  beaker3=NPC.NewNPC((int)npc_center.X, (int)npc_center.Y + (int)(npc.height * 0.5f), Config.npcDefs.byName["Jungle Beaker"].type, 0);
  Main.npc[beaker1].velocity.X=npc.velocity.X-1;
  Main.npc[beaker1].velocity.Y=npc.velocity.Y-6;
  Main.npc[beaker2].velocity.X=npc.velocity.X;
  Main.npc[beaker2].velocity.Y=npc.velocity.Y-5;
  Main.npc[beaker3].velocity.X=npc.velocity.X+1;
  Main.npc[beaker3].velocity.Y=npc.velocity.Y-6;

  npc.life = 0;
   npc.active = false;

   if (Main.netMode == 2 && npc.whoAmI < 200)
     NetMessage.SendData(23, -1, -1, "", npc.whoAmI, 0f, 0f, 0f, 0);
   if (Main.netMode == 2 && beaker1 < 200)
     NetMessage.SendData(23, -1, -1, "", beaker1, 0f, 0f, 0f, 0);
   if (Main.netMode == 2 && beaker2 < 200)
     NetMessage.SendData(23, -1, -1, "", beaker2, 0f, 0f, 0f, 0);
   if (Main.netMode == 2 && beaker3 < 200)
     NetMessage.SendData(23, -1, -1, "", beaker3, 0f, 0f, 0f, 0);
}
This spawns three beakers at the target tile. I give them different starting velocities so they'll spread out and not be exactly on top of each other.Since this is a spawn or NPC and not an actual NPC, instead of putting the code in on spawn I put it directly in AI but had the AI delete itself at the same time it spawns the beakers is.
 
Last edited:
Hello fellow Terrarians,

I ran into a bit of a snag making a fairly simple accessory today that will simply resets Wingtime to grant infinite flight for whatever wings you may be wearing. However it seems like I cannot get it to work at all. The code works, that I know as applying it into say Armor set bonus it resets the time perfectly fine. But on an accessory it seems to fail. As you can see it works if you equip/unequipped the item. Is this an error on my part or a bug with tapi?

On another note, might there be a way to restrict use of items such as the Developer only items? I've not looked much at Steams API but can we obtain users Steam64ID somehow and prevent use that way? I have a few custom made vanity items that a friend of mine made for herself and I'd like to keep it that way. Thanks in advance!


Code:
namespace TearlowsMod.Items
{
    public class TestAccessory : ModItem
    {
        public override void OnEquip(Player p, TAPI.UIKit.ItemSlot slot)
        {
            // This code should reset the Wingtime to max every time it is equipped. But due to effects it resets to 0 wont work untill the acc. is unequipped.
            //p.wingTime = p.wingTimeMax;
            TConsole.Clear();
        }

        public override void Effects(Player p)
        {
            // This very same short code should reset the timer every time Effects is updated but it simply sets Wingtime to 0. Tconsole is simply there so you can see it quick/dirty on screen. Uncomment to test.
            //p.wingTime = p.wingTimeMax;
            TConsole.Print(p.wingTime);
        }
    }
}

Code:
{
    "displayName": "Test Accessory",
    "size": [20,20],
    "maxStack": 1,
    "value": [0,0,0,0],
    "rare": 6,
    "tooltip": ["Grants unlimited flight."],
    "accessory": true,
  
    "recipes":
    [{
        "creates": 1 
    }] 
}
 
I just joined this forum to report some bugs I experienced playing tAPI recently.

I have been getting duplicate town npcs showing up in my worlds. Multiple chefs, multiple blacksmiths, etc. I also had a few supposedly hardmode npcs join in a non-hardmode world, specifically the druid, blacksmith, zombie, and weapon master. Now that I list them out, it looks like those are all thorium+ npcs, so it could be that mod's fault. I'll post in that thread as well.

In the dungeon post-plantera, the Diabolist doest appear to spawn anywhere. All of the other enemy spawns appear to match the background/banners as outlined in the wiki, but instead of Diabolists I get Ragged Casters.

And it looks like my timer glitch was already reported and fixed.

I'm running r14a. My mod list:
Shockah's base r3
Accessory Slots+ r1
Enhanced Tooltip r2
Inventory Tweaks r2
ThoriumMod+
I would assume that it is ThoriumMod's fault for the multiple town npcs, so hopefully asking there helps. It could be that they are using CanSpawn instead of CanTownNPCSpawn.

Thanks for the Diabolists thing though, someone made a typo in the spawn code which made it impossible for them to spawn. Fixed for R15.

Hello fellow Terrarians,

I ran into a bit of a snag making a fairly simple accessory today that will simply resets Wingtime to grant infinite flight for whatever wings you may be wearing. However it seems like I cannot get it to work at all. The code works, that I know as applying it into say Armor set bonus it resets the time perfectly fine. But on an accessory it seems to fail. As you can see it works if you equip/unequipped the item. Is this an error on my part or a bug with tapi?

On another note, might there be a way to restrict use of items such as the Developer only items? I've not looked much at Steams API but can we obtain users Steam64ID somehow and prevent use that way? I have a few custom made vanity items that a friend of mine made for herself and I'd like to keep it that way. Thanks in advance!


Code:
namespace TearlowsMod.Items
{
    public class TestAccessory : ModItem
    {
        public override void OnEquip(Player p, TAPI.UIKit.ItemSlot slot)
        {
            // This code should reset the Wingtime to max every time it is equipped. But due to effects it resets to 0 wont work untill the acc. is unequipped.
            //p.wingTime = p.wingTimeMax;
            TConsole.Clear();
        }

        public override void Effects(Player p)
        {
            // This very same short code should reset the timer every time Effects is updated but it simply sets Wingtime to 0. Tconsole is simply there so you can see it quick/dirty on screen. Uncomment to test.
            //p.wingTime = p.wingTimeMax;
            TConsole.Print(p.wingTime);
        }
    }
}

Code:
{
    "displayName": "Test Accessory",
    "size": [20,20],
    "maxStack": 1,
    "value": [0,0,0,0],
    "rare": 6,
    "tooltip": ["Grants unlimited flight."],
    "accessory": true,
 
    "recipes":
    [{
        "creates": 1
    }]
}
Can I assume your wings are in a lower slot than your accessory, while testing this? The issue with how you coded this is that it essentially has a race condition. If it runs before the wings, then p.wingTimeMax is 0. If you're not aware, the way Terraria works, all item/buff related player variables are reset at the beginning of each tick, then they are set, then effects take place.

Your best bet to fix this, is to make a ModPlayer with a flag for your effect, say, bool infiniteFlight. In the PreUpdate hook, set it to false. In MidUpdate, apply your effect ( "if (infiniteFlight) player.wingTime = player.wingTimeMax;" )

To access the ModPlayer from your item, use p.GetSubClass<yourclassname>();


Also, since steam isn't the only way to get the game now, checking based on that may cause crashes on non-steam copies. I'd suggest you just make your friend a separate mod for their stuff for just them to use.
 
Hello fellow Terrarians,

I ran into a bit of a snag making a fairly simple accessory today that will simply resets Wingtime to grant infinite flight for whatever wings you may be wearing. However it seems like I cannot get it to work at all. The code works, that I know as applying it into say Armor set bonus it resets the time perfectly fine. But on an accessory it seems to fail. As you can see it works if you equip/unequipped the item. Is this an error on my part or a bug with tapi?

On another note, might there be a way to restrict use of items such as the Developer only items? I've not looked much at Steams API but can we obtain users Steam64ID somehow and prevent use that way? I have a few custom made vanity items that a friend of mine made for herself and I'd like to keep it that way. Thanks in advance!
I don't know, but worst case you can check for the accessory and call the code from elsewhere, somewhere where it does work. Or make it add a buff, setting wing time to zero in buffs certainly works.

As for the other matter, do you have a mod you expect a lot of people to be playing? Or is this just like, to stop one or two more friends from getting the items on your personal server? It seems to me you should just prevent use by character name and leave it at that. Very simple, and still effective.
 
Last edited:
Can I assume your wings are in a lower slot than your accessory, while testing this? The issue with how you coded this is that it essentially has a race condition. If it runs before the wings, then p.wingTimeMax is 0. If you're not aware, the way Terraria works, all item/buff related player variables are reset at the beginning of each tick, then they are set, then effects take place.

Your best bet to fix this, is to make a ModPlayer with a flag for your effect, say, bool infiniteFlight. In the PreUpdate hook, set it to false. In MidUpdate, apply your effect ( "if (infiniteFlight) player.wingTime = player.wingTimeMax;" )

To access the ModPlayer from your item, use p.GetSubClass<yourclassname>();


Also, since steam isn't the only way to get the game now, checking based on that may cause crashes on non-steam copies. I'd suggest you just make your friend a separate mod for their stuff for just them to use.

Alas not, that was in fact a throught at the time. So tested with the wings after/before the accessory. That's what sort of threw me off since ArmorSetBonus worked out just fine. I've not tested out your idea but after taking another look at the documentation I have a few ideas- Thank you!

As this is on our own server leaving it clientside only would do no good hence the need for a check of sorts...

I don't know, but worst case you can check for the accessory and call the code from elsewhere, somewhere where it does work. Or make it add a buff, setting wing time to zero in buffs certainly works.

As for the other matter, do you have a mod you expect a lot of people to be playing? Or is this just like, to stop one or two more friends from getting the items on your personal server? It seems to me you should just prevent use by character name and leave it at that. Very simple, and still effective.

If you're seriously talking about "copywriting" your friends work, that's obviously impossible, and legally and morally wrong as well. Think about it: if it were easily possible to restrict access to the code of a game, you wouldn't be here modding in the first place. Furthermore, if you release a modification of a game like this, legally, it is derivative of the original owners intellectual property, even if it includes your original work, he owns the intellectual property for it. And he's made his position pretty clear: modding is okay, even encouraged, as long as no one's making a profit off it. And even morally, it's pretty uncool someone else's life's work as leverage to jerk people around. I mean, seriously, write your OWN game and restrict access to that.

Oh dear...

I might have been too vague with what I said... We're only a few people on our server with a vanity set of our own and simply want to restrict them to whoever made them so if another random John Doe joins the server they wont be able to craft said item and use it. Though saying that I doubt It's possible to prevent crafting it but at least apply a few debuffs to discourage use. (frozen or such). One method would be to remove craftig recipe and spawn in said items and give it to each person but was hoping for a solution like the dev. items.

Hopefully that makes a bit more sense :)
 
Regarding your SteamID idea - you'd have to basically replace the steam_api.dll yourself with some other one handling the call. The vanilla DLL only handles initializing and killing Steamworks, nothing else.
 
Oh dear...
I removed that last part anyway, it was needlessly argumentative and didn't really help with your issue. Sorry about that.Like I said, I' D just go with the name thing. Unless Joe takes the time to study your mod code he won't know how to defeat it. And if he doesn't know there is a workaround, he has no reason to study your mod code in the first place.
 
Last edited:
Every time I save and exit a world, it says an item with the same key has already been added ever since I saved and loaded my megaHardmode Boolean. Is there a way to stop this?
 
Status
Not open for further replies.
Back
Top Bottom