Пример #1
0
        private void OnGameUpdate(EventArgs args)
        {
            Utils.TrySpawnForEachPlayer(TrySpawnCustomNpc);

            foreach (var npc in Main.npc.Where(n => n?.active == true))
            {
                var customNpc = GetCustomNpc(npc);
                if (customNpc?.Definition.ShouldAggressivelyUpdate == true)
                {
                    npc.netUpdate = true;
                }

                if (customNpc?.HasChildren == true)
                {
                    customNpc?.UpdateChildren();
                }

                if (customNpc?.HasTransformed == true)
                {
                    var id = customNpc.Npc.whoAmI;
                    customNpc.HasTransformed = false;

                    var definition = customNpc.Definition;

                    if (definition.OnTransformed != null)
                    {
                        try
                        {
                            CustomIDFunctions.CurrentID = definition.Name;
                            definition.OnTransformed(customNpc);
                        }
                        catch (Exception ex)
                        {
                            Utils.LogScriptRuntimeError(ex);
                            definition.OnTransformed = null;
                        }

                        TSPlayer.All.SendData(PacketTypes.NpcUpdate, "", id);
                        TSPlayer.All.SendData(PacketTypes.UpdateNPCName, "", id);
                    }
                }

                var npcId = npc.whoAmI;
                if (_checkNpcForReplacement[npcId])
                {
                    TryReplaceNpc(npc);
                    _checkNpcForReplacement[npcId] = false;
                }
            }

            //player - npc collisions
            foreach (var player in TShock.Players.Where(p => p?.Active == true))
            {
                var tplayer      = player.TPlayer;
                var playerHitbox = tplayer.Hitbox;
                if (!tplayer.immune)
                {
                    player.SetData(IgnoreCollisionKey, false);
                }

                foreach (var npc in Main.npc.Where(n => n?.active == true))
                {
                    var customNpc = GetCustomNpc(npc);
                    if (customNpc != null)
                    {
                        var definition = customNpc.Definition;

                        if (definition.OnCollision != null)
                        {
                            if (npc.Hitbox.Intersects(playerHitbox) && !player.GetData <bool>(IgnoreCollisionKey))
                            {
                                try
                                {
                                    CustomIDFunctions.CurrentID = definition.Name;
                                    definition.OnCollision(customNpc, player);
                                }
                                catch (Exception ex)
                                {
                                    Utils.LogScriptRuntimeError(ex);
                                    definition.OnCollision = null;
                                }

                                //player.SetData(IgnoreCollisionKey, true);
                                //break;//should this be a continue instead??
                            }
                        }
                    }
                }

                if (!tplayer.immune)
                {
                    player.SetData(IgnoreCollisionKey, true);
                }
            }

            //npc - tile collisions
            foreach (var npc in Main.npc.Where(n => n?.active == true))
            {
                var customNpc = GetCustomNpc(npc);
                if (customNpc != null)
                {
                    var definition = customNpc.Definition;

                    if (definition.OnTileCollision != null)
                    {
                        var tileCollisions = TileFunctions.GetOverlappedTiles(npc.Hitbox);
                        if (tileCollisions.Count > 0)
                        {
                            try
                            {
                                CustomIDFunctions.CurrentID = definition.Name;
                                definition.OnTileCollision(customNpc, tileCollisions);
                            }
                            catch (Exception ex)
                            {
                                Utils.LogScriptRuntimeError(ex);
                                definition.OnTileCollision = null;
                            }
                        }
                    }
                }
            }
        }
Пример #2
0
        //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);
        }