private void SpawnMobsInBiomeAndRegion() { NPCManager.SpawnMobsInBiomeAndRegion(); }
private void OnNPCSpawn(NpcSpawnEventArgs args) { //DEBUG TShock.Log.ConsoleInfo("DEBUG [NPCSpawn] NPCIndex {0}", args.NpcId); //DEBUG //If the id falls outside the possible range, we can return. if (args.NpcId < 0 || args.NpcId >= 200) { return; } //This NPC is custom and not dead. if (NPCManager.NPCs[args.NpcId] != null && !NPCManager.NPCs[args.NpcId].isDead) { return; } NPC spawned = Main.npc[args.NpcId]; foreach (CustomNPCDefinition customnpc in NPCManager.Data.CustomNPCs.Values) { if (!customnpc.isReplacement || customnpc.ReplacementChance >= 100 || NPCManager.Chance(customnpc.ReplacementChance) || spawned.netID != customnpc.customBase.netID) { continue; } DateTime[] dt = null; if (customnpc.customProjectiles != null) { dt = Enumerable.Repeat(DateTime.Now, customnpc.customProjectiles.Count).ToArray(); } NPCManager.NPCs[spawned.whoAmI] = new CustomNPCVars(customnpc, dt, spawned); NPCManager.Data.ConvertNPCToCustom(spawned.whoAmI, customnpc); break; } }
/// <summary> /// Checks if any player is within targetable range of the npc, without obstacle and within firing cooldown timer. /// </summary> private void ProjectileCheck() { //Loop through all custom npcs currently spawned foreach (CustomNPCVars obj in NPCManager.NPCs) { //Check if they exists and are active if (obj == null || obj.isDead || !obj.mainNPC.active) { continue; } //We only want the npcs with custom projectiles if (obj.customNPC.customProjectiles == null) { continue; } //Save the current time DateTime savedNow = DateTime.Now; int k = 0; //Loop through all npc projectiles they can fire foreach (CustomNPCProjectiles projectile in obj.customNPC.customProjectiles) { //Check if projectile last fire time is greater then equal to its next allowed fire time if ((savedNow - obj.lastAttemptedProjectile[k]).TotalMilliseconds >= projectile.projectileFireRate) { //Make sure chance is checked too, don't bother checking if its 100 if (projectile.projectileFireChance == 100 || NPCManager.Chance(projectile.projectileFireChance)) { TSPlayer target = null; if (projectile.projectileLookForTarget) { //Find a target for it to shoot that isn't dead or disconnected foreach (TSPlayer player in TShock.Players.Where(x => x != null && !x.Dead && x.ConnectionAlive)) { //Check if that target can be shot ie/ no obstacles, or if it if projectile goes through walls ignore this check if (!projectile.projectileCheckCollision || Collision.CanHit(player.TPlayer.position, player.TPlayer.bodyFrame.Width, player.TPlayer.bodyFrame.Height, obj.mainNPC.position, obj.mainNPC.width, obj.mainNPC.height)) { //Make sure distance isn't further then what tshock allows float currDistance = Vector2.DistanceSquared(player.TPlayer.position, obj.mainNPC.frame.Center()); //Distance^2 < 4194304 is the same as Distance < 2048, but faster if (currDistance < 4194304) { //Set the target player target = player; //Set npcs target to the player its shooting at obj.mainNPC.target = player.Index; //Break since no need to find another target break; } } } } else { target = TShock.Players[obj.mainNPC.target]; } //Check if we found a valid target if (target != null) { //All checks completed. Fire projectile FireProjectile(target, obj, projectile); //Set last attempted projectile to now obj.lastAttemptedProjectile[k] = savedNow; } } else { obj.lastAttemptedProjectile[k] = savedNow; } } //Increment Index k++; } } }
/// <summary> /// Spawn custom npc using /csm <id> [amount] [<x> <y>] /// </summary> /// <param name="args"></param> private void CommandSpawnNPC(CommandArgs args) { //Error if too many or too few params specified if (args.Parameters.Count == 0 || args.Parameters.Count > 4) { args.Player.SendInfoMessage("Usage: /csm <id> [<amount>] [<x> <y>]"); return; } //Get custom npc by id var cdef = NPCManager.Data.GetNPCbyID(args.Parameters[0]); if (cdef == null) { args.Player.SendErrorMessage("Error: The custom npc with id \"{0}\" does not exist!", args.Parameters[0]); return; } //Default to 1 if amount is not defined int amount = 1; //Check if amount is defined if (args.Parameters.Count == 2 || args.Parameters.Count == 4) { int.TryParse(args.Parameters[1], out amount); //Check for too many mobs if (amount > 200) { args.Player.SendErrorMessage("Error: Amount needs to be lower than 200!"); return; } } //Check for X and Y int x; int y; //Not specified, use player's coordinates. (/csm <id> [amount]) if (args.Parameters.Count <= 2) { x = (int)args.Player.X + rand.Next(-8, 9); y = (int)args.Player.Y + rand.Next(-8, 9); } //Specified, no amount (/csm <id> <x> <y>) else if (args.Parameters.Count == 3) { if (!int.TryParse(args.Parameters[1], out x)) { args.Player.SendErrorMessage("Error: Invalid x position defined!"); return; } if (!int.TryParse(args.Parameters[2], out y)) { args.Player.SendErrorMessage("Error: Invalid y position defined!"); return; } } //All arguments specified (/csm <id> <amount> <x> <y>) else { if (!int.TryParse(args.Parameters[2], out x)) { args.Player.SendErrorMessage("Error: Invalid x position defined!"); return; } if (!int.TryParse(args.Parameters[3], out y)) { args.Player.SendErrorMessage("Error: Invalid y position defined!"); return; } } //Keep track of spawns that fail. int failed = 0; //Spawn mobs for (int i = 0; i < amount; i++) { int j = NPCManager.SpawnNPCAtLocation(x, y, cdef); if (j == -1) { failed++; } else { cdef.currSpawnsVar++; } } //Inform player if (failed > 0) { args.Player.SendWarningMessage("Failed to spawn {0} of {1} \"{2}\"'s at ({3}, {4})", failed, amount, args.Parameters[0], x, y); } else { args.Player.SendSuccessMessage("Spawned {0} \"{1}\"'s at ({2}, {3})", amount, args.Parameters[0], x, y); } }