Example #1
0
        public override bool PreAI(Projectile projectile)
        {
            if (goButFaster && projectile.aiStyle == 19)
            {
                goButFaster = false;
                projectile.AI();
            }

            return(true);
        }
        //private void onProjectileSetDefaults(SetDefaultsEventArgs<Projectile,int> args)
        //{
        //	var projectile = args.Object;

        //	var customProjectile = GetCustomProjectile(projectile);
        //	if(customProjectile!=null)
        //	{
        //		Debug.Print("onProjectileSetDefaults!");
        //		var definition = customProjectile.Definition;

        //		definition.ApplyTo(projectile);

        //		lock( locker )
        //		{
        //			Utils.TryExecuteLua(() => definition.OnSpawn?.Call(customProjectile), definition.Name);
        //		}

        //		TSPlayer.All.SendData(PacketTypes.ProjectileNew, "", projectile.whoAmI);

        //		args.Handled = true;
        //	}
        //}

        private HookResult OnProjectilePreUpdate(Projectile projectile, ref int index)
        {
            var result           = HookResult.Continue;
            var customProjectile = GetCustomProjectile(projectile);

            if (customProjectile == null)
            {
                return(HookResult.Continue);
            }

            var definition   = customProjectile.Definition;
            var lastTimeLeft = projectile.timeLeft;             //we capture this to help determine whether we need to decrement timeLeft at the end of this method.
            //terraria has many points where it sets timeLeft internally, but our custom proj modifies whether/when those points run.
            //by the end of this method we hopefully have enough information to tell if terraria modified it, or if we need to do it ourselves.

            //game updates
            var onGameUpdate = definition.OnGameUpdate;

            if (customProjectile.Active && onGameUpdate != null)
            {
                try
                {
                    CustomIDFunctions.CurrentID = definition.Name;
                    var handled = onGameUpdate(customProjectile);
                    result = handled == true ? HookResult.Cancel : HookResult.Continue;

                    if (result == HookResult.Cancel)
                    {
                        //if we dont pass execution onto Terraria's Projectile.Update(), AI() will never get run, so we better run it ourselves.
                        projectile.AI();
                    }

                    customProjectile.SendNetUpdate = true;
                }
                catch (Exception ex)
                {
                    Utils.LogScriptRuntimeError(ex);
                    definition.OnGameUpdate = null;
                }
            }

            //collision tests

            //players
            if (customProjectile.Active && definition.OnCollision != null)
            {
                foreach (var player in TShock.Players)
                {
                    if (player?.Active == true)
                    {
                        var onCollision = definition.OnCollision;
                        if (onCollision != null)
                        {
                            var tplayer      = player.TPlayer;
                            var playerHitbox = tplayer.Hitbox;

                            if (!tplayer.immune && projectile.Hitbox.Intersects(playerHitbox))
                            {
                                try
                                {
                                    CustomIDFunctions.CurrentID = definition.Name;
                                    onCollision(customProjectile, player);
                                    customProjectile.SendNetUpdate = true;
                                }
                                catch (Exception ex)
                                {
                                    Utils.LogScriptRuntimeError(ex);
                                    definition.OnCollision = null;
                                }
                            }
                        }
                    }
                }
            }

            //tiles
            if (customProjectile.Active && projectile.tileCollide)
            {
                // this is a bit convoluted, because of the 2 conditions-- player wants to run custom code on tile collisions and/or player isn't allowing terraria
                // to run Update(), thus the projectile wont be killed in a timely manner. See condition below for result == HookResult.Cancel
                if (definition.OnTileCollision != null || result == HookResult.Cancel)
                {
                    var tileCollisions = TileFunctions.GetOverlappedTiles(projectile.Hitbox);

                    if (tileCollisions.Count > 0)
                    {
                        var killProjectile = false;

                        //if terrarias code won't be running Update(and thus AI() ), we should kill the projectile ourselves if we hit any applicable tile.
                        if (result != HookResult.Continue)
                        {
                            //...we have to scan the list before the player does, to ensure they dont modify anything(we shouldn't have switched from ReadOnlyCollection. )
                            foreach (var hit in tileCollisions)
                            {
                                if (TileFunctions.IsSolidOrSlopedTile(hit.X, hit.Y) ||
                                    (!(definition.BaseOverride.IgnoreWater == true) && TileFunctions.IsLiquidTile(hit.X, hit.Y)))
                                {
                                    killProjectile = true;
                                    break;
                                }
                            }
                        }

                        try
                        {
                            CustomIDFunctions.CurrentID = definition.Name;
                            definition.OnTileCollision?.Invoke(customProjectile, tileCollisions);
                            //customProjectile.SendNetUpdate = true;
                        }
                        catch (Exception ex)
                        {
                            Utils.LogScriptRuntimeError(ex);
                            definition.OnTileCollision = null;
                        }

                        //script hasnt killed projectile, but we did hit a foreground tile, so lets kill it ourselves
                        if (customProjectile.Active && killProjectile == true)
                        {
                            customProjectile.Kill();
                        }
                    }
                }
            }

            //We need to decrement timeLeft ourselves if no other code has, and no code run after this point will do so
            if (customProjectile.Active && result == HookResult.Cancel && customProjectile.TimeLeft == lastTimeLeft)
            {
                customProjectile.TimeLeft--;

                if (customProjectile.TimeLeft < 1)
                {
                    customProjectile.Kill();
                }
            }

            if (customProjectile.Active && customProjectile.SendNetUpdate)
            {
                SendProjectileUpdate(customProjectile.Index);
            }

            return(result);
        }
Example #3
0
        internal static void CalculateCatches(Vector2 spawnPosition, int bobberType, out int poolSize, out bool lava, out bool honey)
        {
            poolSize = 0;
            lava     = false;
            honey    = false;
            Player     player           = Main.LocalPlayer;
            Vector2    originalCenter   = player.Center;
            bool       originalWet      = player.wet;
            bool       originalHoneyWet = player.honeyWet;
            bool       originalLavaWet  = player.lavaWet;
            Projectile bobber           = null;

            try {
                // Spawn bobber with downward starting velocity
                int index = Projectile.NewProjectile(spawnPosition, Vector2.UnitY * 8, bobberType, 0, 0f, Main.myPlayer);
                if (index >= Main.maxProjectiles)
                {
                    return;
                }

                bobber = Main.projectile[index];

                // Debug: Visualize bobber spawn location
                //for (int i = 0; i < 10; i++)
                //{
                //	Dust.NewDust(bobber.position, 16, 16, DustID.Fire);
                //}

                catches.Clear();

                currentlyTesting = true;
                int failureCount = 0;

                player.Center   = spawnPosition - new Vector2(0f, bobber.height * 2);               //Temporarily teleport player above the bobber + twice the bobbers height
                player.wet      = false;
                player.honeyWet = false;
                player.lavaWet  = false;

                for (int i = 0; i < Tries; i++)
                {
                    failureCount++;

                    if (!bobber.wet)
                    {
                        // If not wet, call Update so it moves into liquid first (handles everything including AI)
                        bobber.Update(index);
                        i--;                         // Make sure we actually test Tries times, the bobber does not catch if not wet
                    }
                    else
                    {
                        // Once wet, just call AI. Calling Update will reel the bobber back to the player otherwise, which is not intended
                        bobber.AI();

                        if (poolSize == 0)
                        {
                            poolSize = GetPoolStats(bobber.Center, out lava, out honey);
                        }
                    }

                    if (failureCount >= 2 * Tries)
                    {
                        break;
                    }
                }
            }
            finally {
                player.Center    = originalCenter;
                player.wet       = originalWet;
                player.honeyWet  = originalHoneyWet;
                player.lavaWet   = originalLavaWet;
                currentlyTesting = false;
                bobber?.Kill();
            }


            // Debug: Visualize bobber final location
            //for (int i = 0; i < 10; i++)
            //{
            //	Dust.NewDust(bobber.position, 16, 16, DustID.Fire);
            //}
        }