예제 #1
0
        private void GameLoop_UpdateTicking(object sender, StardewModdingAPI.Events.UpdateTickingEventArgs e)
        {
            if (Config.EnableMod && Helper.Input.IsDown(Config.MoveModKey) && (Helper.Input.IsDown(Config.MoveKey) || Helper.Input.IsSuppressed(Config.MoveKey)))
            {
                if (Game1.activeClickableMenu != null)
                {
                    if (currentlyDragging == Game1.activeClickableMenu || Game1.activeClickableMenu.isWithinBounds(Game1.getMouseX(), Game1.getMouseY()))
                    {
                        currentlyDragging = Game1.activeClickableMenu;
                        AdjustMenu(Game1.activeClickableMenu, Game1.getMousePosition() - lastMousePosition, true);
                        Helper.Input.Suppress(Config.MoveKey);
                        if (Game1.activeClickableMenu is ItemGrabMenu && Helper.ModRegistry.IsLoaded("Pathoschild.ChestsAnywhere"))
                        {
                            Game1.activeClickableMenu = Game1.activeClickableMenu.ShallowClone();
                        }
                        goto next;
                    }
                }
                foreach (var menu in Game1.onScreenMenus)
                {
                    if (menu is null)
                    {
                        continue;
                    }
                    if (currentlyDragging == menu || menu.isWithinBounds(Game1.getMouseX(), Game1.getMouseY()))
                    {
                        currentlyDragging = menu;

                        AdjustMenu(menu, Game1.getMousePosition() - lastMousePosition, true);
                        Helper.Input.Suppress(Config.MoveKey);
                        goto next;
                    }
                }
                foreach (var menu in detachedMenus)
                {
                    if (menu is null)
                    {
                        continue;
                    }
                    if (currentlyDragging == menu || menu.isWithinBounds(Game1.getMouseX(), Game1.getMouseY()))
                    {
                        currentlyDragging = menu;

                        AdjustMenu(menu, Game1.getMousePosition() - lastMousePosition, true);
                        Helper.Input.Suppress(Config.MoveKey);
                        goto next;
                    }
                }
            }
            currentlyDragging = null;
next:
            lastMousePosition = Game1.getMousePosition();
            foreach (var menu in detachedMenus)
            {
                if (menu.isWithinBounds(Game1.getMouseX(), Game1.getMouseY()))
                {
                    menu.performHoverAction(Game1.getMouseX(), Game1.getMouseY());
                }
            }
        }
 private void GameLoop_UpdateTicking(object sender, StardewModdingAPI.Events.UpdateTickingEventArgs e)
 {
     if (isActive)
     {
         // if a menu is opened -> make player invincible
         Game1.player.temporarilyInvincible       = true;
         Game1.player.temporaryInvincibilityTimer = 1;
     }
 }
예제 #3
0
        private void GameLoop_UpdateTicking(object sender, StardewModdingAPI.Events.UpdateTickingEventArgs e)
        {
            Farmer farmer = Game1.player;

            if (farmer.health <= 0)
            {
                farmer.health = farmer.maxHealth / 2;
                // remove the shirt (it is consumed)
                farmer.shirtItem.Value = null;
            }
        }
예제 #4
0
        void GameLoop_UpdateTicking(object sender, StardewModdingAPI.Events.UpdateTickingEventArgs e)
        {
            if (Game1.currentLocation == null || !Game1.player.hasPet() || GetPet() == null)
            {
                return;
            }

            if (petState != PetState.Vanilla)
            {
                GetPet().CurrentBehavior = -1;
            }
        }
예제 #5
0
        void GameLoop_UpdateTicking(object sender, StardewModdingAPI.Events.UpdateTickingEventArgs e)
        {
            if (!CanUpdatePet())
            {
                return;
            }

            // if (petState != PetState.Vanilla)
            //     GetPet().CurrentBehavior = -1;

            FacingDirectionBeforeUpdate = GetPet().FacingDirection;
        }
예제 #6
0
 /// <summary>
 /// Checks for warps from the buildings/animals menu
 /// and ensures the player is returned to their original location
 /// </summary>
 /// <param name="sender"></param>
 /// <param name="e"></param>
 private void GameLoop_UpdateTicking(object sender, StardewModdingAPI.Events.UpdateTickingEventArgs e)
 {
     //Fixes the game warping the player to places we don't want them to warp
     //if buildings/animal purchase menus are brought up from a custom tile
     if (SourceLocation != null && (
             Game1.locationRequest?.Name == "AnimalShop" ||
             Game1.locationRequest?.Name == "WizardHouse" ||
             Game1.locationRequest?.Name == "ScienceHouse"))
     {
         Game1.locationRequest.Location    = SourceLocation;
         Game1.locationRequest.IsStructure = SourceLocation.isStructure.Value;
     }
 }
예제 #7
0
        private void GameLoop_UpdateTicking(object sender, StardewModdingAPI.Events.UpdateTickingEventArgs e)
        {
            if (Game1.player?.currentLocation != null && firing)
            {
                if (ticks % 120 == 0 && Config.FireSound != "")
                {
                    Game1.player.currentLocation.playSound(Config.FireSound, NetAudio.SoundContext.Default);
                }
                if (ticks++ % 3 != 0)
                {
                    return;
                }
                float   fire_angle  = 0f;
                float   mouthOffset = 16f;
                Vector2 shot_origin = new Vector2((float)Game1.player.GetBoundingBox().Center.X - 32f, (float)Game1.player.GetBoundingBox().Center.Y - 80f);
                switch (Game1.player.facingDirection.Value)
                {
                case 0:
                    shot_origin.Y -= mouthOffset;
                    fire_angle     = 90f;
                    break;

                case 1:
                    shot_origin.X += mouthOffset;
                    fire_angle     = 0f;
                    break;

                case 2:
                    fire_angle     = 270f;
                    shot_origin.Y += mouthOffset;
                    break;

                case 3:
                    shot_origin.X -= mouthOffset;
                    fire_angle     = 180f;
                    break;
                }
                fire_angle += (float)Math.Sin((double)((float)ticks * 16 / 1000f * 180f) * 3.1415926535897931 / 180.0) * 25f;
                Vector2 shot_velocity = new Vector2((float)Math.Cos((double)fire_angle * 3.1415926535897931 / 180.0), -(float)Math.Sin((double)fire_angle * 3.1415926535897931 / 180.0));
                shot_velocity *= 10f;
                BasicProjectile projectile = new BasicProjectile((int)Math.Round(Config.FireDamage * (Config.ScaleWithSkill ? Game1.player.getEffectiveSkillLevel(4) / 10f : 1)), 10, 0, 1, 0.196349546f, shot_velocity.X, shot_velocity.Y, shot_origin, "", "", false, true, Game1.player.currentLocation, Game1.player, false, null);
                projectile.ignoreTravelGracePeriod.Value = true;
                projectile.maxTravelDistance.Value       = (int)Math.Round(Config.FireDistance * (Config.ScaleWithSkill ? Game1.player.getEffectiveSkillLevel(4) / 10f : 1));
                Game1.player.currentLocation.projectiles.Add(projectile);
            }
            else
            {
                ticks = 0;
            }
        }
예제 #8
0
        public virtual void UpdateWeirdLights(object sender, StardewModdingAPI.Events.UpdateTickingEventArgs e)
        {
            foreach (LightSource light in _weirdLights)
            {
                float time = (float)Game1.currentGameTime.TotalGameTime.TotalMilliseconds / 1000.0F;

                float color_position = ((float)Math.Sin(time * 0.3F + light.position.X * 1.15F + light.position.Y * 0.33F) + 1) / 2.0F;

                Color light_color = new Color(0, 0, 0);

                if (color_position < 0.33F)
                {
                    float lerp_position = color_position / 0.33F;

                    lerp_position = MathHelper.Clamp(lerp_position, 0, 1);

                    light_color.R = (byte)(255 * MathHelper.Lerp(1.0F, 0, lerp_position));
                    light_color.G = (byte)(255 * MathHelper.Lerp(0, 1.0F, lerp_position));
                }
                else if (color_position < 0.66F)
                {
                    color_position -= .33F;

                    float lerp_position = color_position / 0.33F;

                    lerp_position = MathHelper.Clamp(lerp_position, 0, 1);

                    light_color.G = (byte)(255 * MathHelper.Lerp(1.0F, 0, lerp_position));
                    light_color.B = (byte)(255 * MathHelper.Lerp(0, 1.0F, lerp_position));
                }
                else
                {
                    color_position -= .66F;

                    float lerp_position = color_position / 0.33F;

                    lerp_position = MathHelper.Clamp(lerp_position, 0, 1);

                    light_color.B = (byte)(255 * MathHelper.Lerp(1.0F, 0, lerp_position));
                    light_color.R = (byte)(255 * MathHelper.Lerp(0.0F, 1.0F, lerp_position));
                }


                // TODO: Adjust these light color values.
                light.color.Value = light_color;

                light.radius.Value = 0.3F + ((float)(Math.Sin(time + light.position.X + light.position.Y) + 1) / 2.0F) * 0.3F;
            }
        }
예제 #9
0
        private void GameLoop_UpdateTicking(object sender, StardewModdingAPI.Events.UpdateTickingEventArgs e)
        {
            GameLocation environment = Game1.currentLocation;
            Farmer       who         = Game1.player;

            if (lightSourceID.HasValue)
            {
                Vector2 offset = Vector2.Zero;
                if (who.shouldShadowBeOffset)
                {
                    offset += (Vector2)who.drawOffset;
                }
                environment.repositionLightSource(lightSourceID.Value, new Vector2(who.Position.X + drawXOffset, who.Position.Y + drawYOffset) + offset);
            }
        }
예제 #10
0
        private void GameLoop_UpdateTicking(object sender, StardewModdingAPI.Events.UpdateTickingEventArgs e)
        {
            int currentXp = Game1.player.experiencePoints[(int)Parameters.Skill];

            // atm the xp which lead to a level gain a not multiplied
            if (lastXp.HasValue && currentXp > lastXp)
            {
                int gainedXp     = currentXp - lastXp.Value;
                int additionalXp = (int)(gainedXp * (Parameters.Multiplier - 1));
                Logger.Debug($"XP = {gainedXp} + {additionalXp}");
                Game1.player.gainExperience((int)Parameters.Skill, additionalXp);
            }

            lastXp = Game1.player.experiencePoints[(int)Parameters.Skill];
        }
예제 #11
0
 private void GameLoop_UpdateTicking(object sender, StardewModdingAPI.Events.UpdateTickingEventArgs e)
 {
     for (int i = animations.Count - 1; i >= 0; i--)
     {
         if (animations[i].update(Game1.currentGameTime))
         {
             animations.RemoveAt(i);
         }
     }
     if (sparklingText != null && sparklingText.update(Game1.currentGameTime))
     {
         sparklingText = null;
     }
     if (fishCaught)
     {
         lastUser.addItemToInventoryBool(new Object(whichFish, caughtDoubleFish ? 2 : 1, false, -1, fishQuality), false);
         fishCaught = false;
     }
 }
예제 #12
0
        private void GameLoop_UpdateTicking(object sender, StardewModdingAPI.Events.UpdateTickingEventArgs e)
        {
            foreach (var npcName in Game1.player.friendshipData.Keys)
            {
                Friendship fdata = Game1.player.friendshipData[npcName];

                if (currentPoints.TryGetValue(npcName, out int p))
                {
                    if (fdata.Points > p)
                    {
                        int gainedPoints     = fdata.Points - p;
                        int additionalPoints = (int)(gainedPoints * (factor - 1));
                        Game1.player.changeFriendship(additionalPoints, Game1.getCharacterFromName(npcName));
                        Logger.Debug($"Friendship increased for {npcName} from {p} to {fdata.Points} + {additionalPoints}");
                    }
                }

                currentPoints[npcName] = fdata.Points;
            }
        }
예제 #13
0
        /// <summary>Raised before the game state is updated (≈60 times per second).</summary>
        /// <param name="sender">The event sender.</param>
        /// <param name="e">Event arguments.</param>
        private void GameLoop_UpdateTicking(object sender, StardewModdingAPI.Events.UpdateTickingEventArgs e)
        {
            if (!Context.IsWorldReady || !e.IsMultipleOf(10))
            {
                return;
            }

            Microsoft.Xna.Framework.Rectangle nextPosition = Game1.player.nextPosition(Game1.player.getDirection());

            IEnumerable <Vector2> positionsToCheck = new[]
            {
                new Vector2((int)(nextPosition.Right / 64.0), (int)(nextPosition.Bottom / 64.0)),
                new Vector2((int)(nextPosition.Right / 64.0), (int)(nextPosition.Top / 64.0)),
                new Vector2((int)(nextPosition.Left / 64.0), (int)(nextPosition.Top / 64.0)),
                new Vector2((int)(nextPosition.Left / 64.0), (int)(nextPosition.Bottom / 64.0))
            };

            foreach (Vector2 position in positionsToCheck)
            {
                this.TryHurtBecauseCactus(Game1.currentLocation, position, Game1.player, false);
            }
        }
예제 #14
0
        private void GameLoop_UpdateTicking(object?sender, StardewModdingAPI.Events.UpdateTickingEventArgs e)
        {
            if (Game1.eventUp)
            {
                if (!eventTriggered)
                {
                    Game1.options.musicVolumeLevel = musicInsideEvent;
                    Game1.musicCategory.SetVolume(musicInsideEvent);
                    Game1.musicPlayerVolume = musicInsideEvent;

                    eventTriggered = true;
                }
            }

            else if (eventTriggered)
            {
                Game1.options.musicVolumeLevel = musicOutsideEvent;
                Game1.musicCategory.SetVolume(musicOutsideEvent);
                Game1.musicPlayerVolume = musicOutsideEvent;

                eventTriggered = false;
            }
        }
예제 #15
0
 private void UpdateTicking(object sender, StardewModdingAPI.Events.UpdateTickingEventArgs e)
 {
     CheckForEdits("UpdateTicking");
 }
        private void GameLoop_UpdateTicking(object?sender, StardewModdingAPI.Events.UpdateTickingEventArgs e)
        {
            //this mod does nothing if a game isn't running
            if (!Context.IsWorldReady)
            {
                return;
            }

            //start with checking for events
            if (lastEventCheck != Game1.eventUp)
            {
                //host
                if (Context.IsMainPlayer)
                {
                    eventStatus[Game1.player.UniqueMultiplayerID] = Game1.eventUp;
                }
                //client
                else
                {
                    this.Helper.Multiplayer.SendMessage <bool>(Game1.eventUp, "eventUp", modIDs: new[] { this.ModManifest.UniqueID }, playerIDs: new[] { Game1.MasterPlayer.UniqueMultiplayerID });
                }
                lastEventCheck = Game1.eventUp;
            }

            //set the pause time data to whether or not time should be paused for this player
            var pauseTime2 = (!Context.IsPlayerFree) ? "true" : "false";

            if (!Context.CanPlayerMove)
            {
                pauseTime2 = "true";
            }

            //time should not be paused when using a tool
            if (Game1.player.UsingTool)
            {
                pauseTime2 = "false";
            }

            //checks to see if the fishing rod has been cast. If this is true but the player is in the fishing minigame, the next if statement will pause - otherwise it won't
            if (Game1.player.CurrentItem != null && Game1.player.CurrentItem is StardewValley.Tools.FishingRod && (Game1.player.CurrentItem as StardewValley.Tools.FishingRod).isFishing)
            {
                pauseTime2 = "false";
            }

            if (Game1.activeClickableMenu != null && Game1.activeClickableMenu is StardewValley.Menus.BobberBar)
            {
                pauseTime2 = "true";
            }

            if (Game1.currentMinigame != null)
            {
                pauseTime2 = "true";
            }

            //skip skull cavern fix logic if the main player has it disabled, or if is not multiplayer
            if (!Game1.IsMultiplayer)
            {
                goto endSkullLogic;
            }
            if (Context.IsMainPlayer && !this.config.FixSkullTime)
            {
                goto endSkullLogic;
            }


            //check status to see if player is in Skull Cavern
            if (Game1.player.currentLocation is StardewValley.Locations.MineShaft && (Game1.player.currentLocation as StardewValley.Locations.MineShaft).getMineArea() > 120)
            {
                inSkull = "true";
            }
            else
            {
                inSkull = "false";
            }

            if (inSkull != inSkullLast)
            {
                if (Context.IsMainPlayer)
                {
                    inSkullAll[Game1.player.UniqueMultiplayerID] = inSkull;
                }
                else
                {
                    this.Helper.Multiplayer.SendMessage(inSkull, "inSkull", modIDs: new[] { this.ModManifest.UniqueID }, playerIDs: new[] { Game1.MasterPlayer.UniqueMultiplayerID });
                }

                inSkullLast = inSkull;
            }

            //apply the logic to remove 2000 from the time interval if everyone is in the skull cavern and this hasn't been done yet per this 10 minute day period
            if (Context.IsMainPlayer && Game1.gameTimeInterval > 6000 && allInSkull())
            {
                if (!extraTimeAdded)
                {
                    extraTimeAdded          = true;
                    Game1.gameTimeInterval -= 2000;
                }
            }

            if (Context.IsMainPlayer && Game1.gameTimeInterval < 10)
            {
                extraTimeAdded = false;
            }

endSkullLogic:

            //handle pause time data
            if (Context.IsMainPlayer)
            {
                //host
                if (pauseTime != pauseTime2)
                {
                    pauseTime = pauseTime2;
                    pauseTimeAll[Game1.player.UniqueMultiplayerID] = pauseTime;
                }
            }

            else
            {
                //client
                if (pauseTime != pauseTime2)
                {
                    pauseTime = pauseTime2;
                    this.Helper.Multiplayer.SendMessage(pauseTime, "pauseTime", modIDs: new[] { this.ModManifest.UniqueID }, playerIDs: new[] { Game1.MasterPlayer.UniqueMultiplayerID });
                }
            }

            var shouldPauseNow = shouldPause();

            //this logic only applies for the main player to control the state of the world
            if (Context.IsMainPlayer)
            {
                if (shouldPauseNow)
                {
                    //save the last time interval, if it's not already saved
                    if (Game1.gameTimeInterval >= 0)
                    {
                        timeInterval = Game1.gameTimeInterval;
                    }

                    Game1.gameTimeInterval = -100;

                    //pause all Characters
                    foreach (GameLocation location in Game1.locations)
                    {
                        //I don't know if the game stores null locations, and at this point I'm too afraid to ask
                        if (location == null)
                        {
                            continue;
                        }

                        //pause all NPCs, doesn't seem to work for animals or monsters
                        foreach (Character character in location.characters)
                        {
                            character.movementPause = 1;
                        }

                        //pause all farm animals
                        if (location is Farm)
                        {
                            foreach (FarmAnimal animal in (location as Farm).getAllFarmAnimals())
                            {
                                animal.pauseTimer = 100;
                            }
                        }
                        else if (location is AnimalHouse)
                        {
                            foreach (FarmAnimal animal in (location as AnimalHouse).animals.Values)
                            {
                                animal.pauseTimer = 100;
                            }
                        }
                    }

                    if (!lockMonsters)
                    {
                        goto endMonsterLogic;
                    }
                    //pause all Monsters
                    List <GameLocation> farmerLocations = new List <GameLocation>();
                    foreach (Farmer f in Game1.getOnlineFarmers())
                    {
                        farmerLocations.Add(f.currentLocation);
                    }
                    foreach (GameLocation l in farmerLocations)
                    {
                        foreach (Character c in l.characters)
                        {
                            if (c is StardewValley.Monsters.Monster)
                            {
                                if (!monsterLocks.ContainsKey(c as StardewValley.Monsters.Monster))
                                {
                                    monsterLocks.Add(c as StardewValley.Monsters.Monster, c.Position);
                                }
                                c.Position = monsterLocks[c as StardewValley.Monsters.Monster];
                            }
                        }
                    }
                    endMonsterLogic :;
                }
                else
                {
                    //reset time interval if it hasn't been fixed from the last pause
                    if (Game1.gameTimeInterval < 0)
                    {
                        Game1.gameTimeInterval = timeInterval;
                        timeInterval           = -100;
                    }

                    //reset monsterLocks
                    monsterLocks.Clear();
                }

                if (shouldPauseNow != shouldPauseLast)
                {
                    this.Helper.Multiplayer.SendMessage(shouldPauseNow ? "true" : "false", "pauseCommand", new[] { this.ModManifest.UniqueID });
                }

                shouldPauseLast = shouldPauseNow;
            }

            //check if the player has jumped down a Skull Cavern Shaft
            if (!this.config.DisableSkullShaftFix && inSkull == "true")
            {
                int num = (Game1.player.currentLocation as StardewValley.Locations.MineShaft).mineLevel - lastSkullLevel;

                if (num > 1)
                {
                    if (healthLock != -100)
                    {
                        Game1.player.health = Math.Max(1, Game1.player.health - num * 3);
                        healthLock          = Game1.player.health;
                    }
                }

                lastSkullLevel = (Game1.player.currentLocation as StardewValley.Locations.MineShaft).mineLevel;
            }

            //pause food and drink buff durations must be run for each player independently
            //handle health locks on a per player basis
            if (shouldPauseNow)
            {
                //set temporary duration locks if it has just become paused and/or update Duration if new food is consumed during pause
                if (Game1.buffsDisplay.food != null && Game1.buffsDisplay.food.millisecondsDuration > foodDuration)
                {
                    foodDuration = Game1.buffsDisplay.food.millisecondsDuration;
                }
                if (Game1.buffsDisplay.drink != null && Game1.buffsDisplay.drink.millisecondsDuration > drinkDuration)
                {
                    drinkDuration = Game1.buffsDisplay.drink.millisecondsDuration;
                }

                if (Game1.buffsDisplay.food != null)
                {
                    Game1.buffsDisplay.food.millisecondsDuration = foodDuration;
                }
                if (Game1.buffsDisplay.drink != null)
                {
                    Game1.buffsDisplay.drink.millisecondsDuration = drinkDuration;
                }

                if (!lockMonsters)
                {
                    goto endHealthLogic;
                }
                //health lock
                if (healthLock == -100)
                {
                    healthLock = Game1.player.health;
                }
                //catch edge cases where health has increased but asynchronously will not be applied before locking
                if (Game1.player.health > healthLock)
                {
                    healthLock = Game1.player.health;
                }

                Game1.player.health = healthLock;

                Game1.player.temporarilyInvincible       = true;
                Game1.player.temporaryInvincibilityTimer = -1000000000;


                endHealthLogic :;
            }
            else
            {
                foodDuration  = -100;
                drinkDuration = -100;

                healthLock = -100;

                if (Game1.player.temporaryInvincibilityTimer < -100000000)
                {
                    Game1.player.temporaryInvincibilityTimer           = 0;
                    Game1.player.currentTemporaryInvincibilityDuration = 0;
                    Game1.player.temporarilyInvincible = false;
                }
            }
        }
예제 #17
0
 static void GameLoop_UpdateTicking(object sender, StardewModdingAPI.Events.UpdateTickingEventArgs e)
 {
     PlayerIsMounted = Game1.player.mount != null;
 }
예제 #18
0
파일: ModEntry.cs 프로젝트: ClxS/SDVMods
 private void GameLoop_UpdateTicking(object sender, StardewModdingAPI.Events.UpdateTickingEventArgs e)
 {
     this.systemManager.Tick();
 }
예제 #19
0
        public void GameLoop_UpdateTicking(object sender, StardewModdingAPI.Events.UpdateTickingEventArgs e)
        {
            //Monitor.Log($"player sprite frame {Game1.player.Sprite.currentFrame}");
            if (weaponAnimationFrame > -1 && advancedWeaponAnimating != null)
            {
                MeleeActionFrame frame = advancedWeaponAnimating.frames[weaponAnimationFrame];
                Farmer           user  = weaponAnimating.getLastFarmerToUse();

                if (weaponAnimationFrame == 0 && weaponAnimationTicks == 0)
                {
                    weaponStartFacingDirection = user.facingDirection.Value;
                    //Monitor.Log($"Starting animation, facing {weaponStartFacingDirection}");
                }

                if (user.CurrentTool != weaponAnimating)
                {
                    //Monitor.Log($"Switched tools to {Game1.player.CurrentTool?.DisplayName}");
                    weaponAnimating         = null;
                    weaponAnimationFrame    = -1;
                    weaponAnimationTicks    = 0;
                    advancedWeaponAnimating = null;
                    return;
                }
                if (frame.invincible != null)
                {
                    //Monitor.Log($"Setting invincible as {frame.invincible}");
                    user.temporarilyInvincible = (bool)frame.invincible;
                }

                if (weaponAnimationTicks == 0)
                {
                    //Monitor.Log($"Starting frame {weaponAnimationFrame}");

                    user.faceDirection((weaponStartFacingDirection + frame.relativeFacingDirection) % 4);
                    //Monitor.Log($"facing {user.getFacingDirection()}, relative {frame.relativeFacingDirection}");

                    if (frame.special != null)
                    {
                        try
                        {
                            switch (frame.special.name)
                            {
                            case "lightning":
                                LightningStrike(user, weaponAnimating, frame.special.parameters);
                                break;

                            case "explosion":
                                Explosion(user, weaponAnimating, frame.special.parameters);
                                break;
                            }
                        }
                        catch (Exception ex)
                        {
                            Monitor.Log($"Exception thrown on special effect:\n{ex}", LogLevel.Error);
                        }
                    }

                    if (frame.action == WeaponAction.NORMAL)
                    {
                        //Monitor.Log($"Starting normal attack");
                        user.completelyStopAnimatingOrDoingAction();
                        user.CanMove        = false;
                        user.UsingTool      = true;
                        user.canReleaseTool = true;
                        weaponAnimating.setFarmerAnimating(user);
                    }
                    else if (frame.action == WeaponAction.SPECIAL)
                    {
                        //Monitor.Log($"Starting special attack");
                        weaponAnimating.animateSpecialMove(user);
                    }

                    if (frame.trajectoryX != 0 || frame.trajectoryY != 0)
                    {
                        float   trajectoryX   = frame.trajectoryX;
                        float   trajectoryY   = frame.trajectoryY;
                        Vector2 rawTrajectory = TranslateVector(new Vector2(trajectoryX, trajectoryY), user.FacingDirection);
                        user.setTrajectory(new Vector2(rawTrajectory.X, -rawTrajectory.Y)); // game trajectory y is backwards idek
                        //Monitor.Log($"player trajectory {user.xVelocity},{user.yVelocity}");
                    }

                    if (frame.sound != null)
                    {
                        //Monitor.Log($"Playing sound {frame.sound}");
                        user.currentLocation.playSound(frame.sound, NetAudio.SoundContext.Default);
                    }
                    foreach (AdvancedWeaponProjectile p in frame.projectiles)
                    {
                        Vector2 velocity = TranslateVector(new Vector2(p.xVelocity, p.yVelocity), user.FacingDirection);
                        Vector2 startPos = TranslateVector(new Vector2(p.startingPositionX, p.startingPositionY), user.FacingDirection);

                        int damage = advancedWeaponAnimating.type > 0 ? p.damage * myRand.Next(weaponAnimating.minDamage, weaponAnimating.maxDamage) : p.damage;

                        //Monitor.Log($"player position: {user.Position}, start position: { new Vector2(startingPositionX, startingPositionY) }");

                        user.currentLocation.projectiles.Add(new BasicProjectile(damage, p.parentSheetIndex, p.bouncesTillDestruct, p.tailLength, p.rotationVelocity, velocity.X, velocity.Y, user.Position + new Vector2(0, -64) + startPos, p.collisionSound, p.firingSound, p.explode, p.damagesMonsters, user.currentLocation, user, p.spriteFromObjectSheet));
                    }
                }
                if (++weaponAnimationTicks >= frame.frameTicks)
                {
                    weaponAnimationFrame++;
                    weaponAnimationTicks = 0;
                    //Monitor.Log($"Advancing to frame {weaponAnimationFrame}");
                }
                if (weaponAnimationFrame >= advancedWeaponAnimating.frames.Count)
                {
                    //Monitor.Log($"Ending weapon animation");
                    user.completelyStopAnimatingOrDoingAction();
                    user.CanMove   = true;
                    user.UsingTool = false;
                    user.setTrajectory(Vector2.Zero);

                    if (user.IsLocalPlayer)
                    {
                        int cd = advancedWeaponAnimating.cooldown;
                        if (user.professions.Contains(28))
                        {
                            cd /= 2;
                        }
                        if (weaponAnimating.hasEnchantmentOfType <ArtfulEnchantment>())
                        {
                            cd /= 2;
                        }

                        switch (weaponAnimating.type.Value)
                        {
                        case 1:
                            MeleeWeapon.daggerCooldown = cd;
                            break;

                        case 2:
                            MeleeWeapon.clubCooldown = cd;
                            break;

                        case 3:
                            MeleeWeapon.defenseCooldown = cd;
                            break;
                        }
                    }
                    weaponAnimationFrame    = -1;
                    weaponAnimating         = null;
                    advancedWeaponAnimating = null;
                    weaponAnimationTicks    = 0;
                }

                return;
            }
        }