I am attempting to Modify the Explosion FX. My intention is to create a Shrinking Ring where players outside of the ring will take 10 damage per 1 second
The Idea is to work similarly to the Storm in Fortnight)

After seeing the [explosion FX 900 1 1 1 Essentialy 1 Row of fire making a big cicle closing in on itself i realized modifying this script to my needs would probably be the best way to accomplish this. For now i'm working on slowing the animation down dramatically.


What i would like to do is Have the circle shrink by 10 Tiles every 1 minute. During that 1 Minute the animation should Loop in place until closing another 10 tiles and again looping animation in place for 1 full minute... this process should repeat until the circle has closed on itself ( or expanded to max as im only essentually running the animation in reverse)

I have added a Timer to the script that will handle the animation of the explosion. The timer starts with a range of 5 tiles and expands the range by 10 tiles each time it loops. After each loop, it will use the Thread.Sleep(TimeSpan.FromMinutes(1)) method to pause the animation for 1 minute before starting the next loop. The animation will be visible for 1 minute but it will not be continuously expanding during that time. And it will continue this pattern until the range has reached the max range set.

This doent seem to do the trick. The animations Still run in its normal pattern without pausing taking only about 1 minute to complete. The overall goal is to have the animation run for roughly 15 minutes until complete

Below is The part that ive modified..... Any Input or ideas for another method to accomplish this would be helpful please.


Code:
using System;
using System.Collections.Generic;

using Server;
using Server.Commands;

using VitaNex.Network;
#endregion

using System;
using System.Threading;
using System.Timers;
using Server;
using Server.Commands;
using VitaNex.Network;

namespace VitaNex.FX
{
    public enum ExplodeFX
    {
        None = 0,
        Random,
        Smoke,
        Water,
        Fire,
        Earth,
        Air,
        Energy,
        Poison
    }

    public static class ExplodeEffects
    {
        public static void Initialize()
        {
            CommandSystem.Register(
                "ExplodeFXHide",
                AccessLevel.GameMaster,
                ce =>
                {
                    if (ce == null || ce.Mobile == null)
                    {
                        return;
                    }

                    var m = ce.Mobile;

                    if (m.Hidden)
                    {
                        m.Hidden = false;
                        CommandSystem.Entries["ExplodeFX"].Handler(ce);
                    }
                    else
                    {
                        CommandSystem.Entries["ExplodeFX"].Handler(ce);
                        m.Hidden = true;
                    }
                });

            CommandSystem.Register(
                "ExplodeFX",
                AccessLevel.GameMaster,
                ce =>
                {
                    if (ce == null || ce.Mobile == null)
                    {
                        return;
                    }

                    var m = ce.Mobile;
                    ExplodeFX effect;
                    int range, speed, repeat, reverse, maxRange;

                    if (ce.Arguments.Length < 1 || !Enum.TryParse(ce.Arguments[0], true, out effect))
                    {
                        effect = ExplodeFX.None;
                    }

                    if (ce.Arguments.Length < 2 || !Int32.TryParse(ce.Arguments[1], out range))
                    {
                        range = 5;
                    }

                    if (ce.Arguments.Length < 3 || !Int32.TryParse(ce.Arguments[2], out speed))
                    {
                        speed = 10;
                    }

                    if (ce.Arguments.Length < 4 || !Int32.TryParse(ce.Arguments[3], out repeat))
                    {
                        repeat = 0;
                    }

                    if (ce.Arguments.Length < 5 || !Int32.TryParse(ce.Arguments[4], out reverse))
{
reverse = 0;
}
                if (ce.Arguments.Length < 6 || !Int32.TryParse(ce.Arguments[5], out maxRange))
                {
                    maxRange = 100;
                }

                range = Math.Max(0, Math.Min(maxRange, range));
                speed = Math.Max(1, Math.Min(10, speed));
                repeat = Math.Max(0, Math.Min(100, repeat));
                reverse = Math.Max(0, Math.Min(1, reverse));
                maxRange = Math.Max(range, maxRange);

                var timer = new Timer(1000 - ((speed - 1) * 100));
                timer.AutoReset = true;
                timer.Elapsed += (sender, args) =>
                {
                    var e = effect.CreateInstance(
                        m.Location,
                        m.Map,
                        range,
                        repeat,
                        TimeSpan.FromMilliseconds(1000 - ((speed - 1) * 100)));

                    if (e != null)
                    {
                        e.Reversed = (reverse > 0);
                        e.Send();
                    }

                    range += 10;

                    if (range > maxRange)
                    {
                        timer.Stop();
                        Thread.Sleep(TimeSpan.FromMinutes(1));
                        range = 5;
                        timer.Start();
                    }
                };
                timer.Start();
            });
    }
}
 
It seems that the problem is that the Thread.Sleep(TimeSpan.FromMinutes(1)) method is being called within the Elapsed event of the timer, which is causing the entire program to halt for one minute. Instead of using Thread.Sleep, you should use a separate timer to keep track of the time elapsed since the last expansion of the circle.

You could create a new timer that starts when the animation starts and increments a counter each time it elapses. Then, in the Elapsed event of the animation timer, you could check the value of the counter and compare it to the desired time between expansions (1 minute in this case). If the counter is greater than or equal to the desired time, you can shrink the circle by 10 tiles and reset the counter.

Alternatively, you could use a Stopwatch object to keep track of the time elapsed since the last expansion and check its value in the Elapsed event of the animation timer. This way you don't have to worry about creating and managing another timer.

In any case, it's important to keep in mind that Thread.Sleep will freeze the entire program and should be avoided when possible.
 
Im Starting to think i may have to play with the BaseFX script. I think the expanding effects are processed as 1 effect and it doest look like this script control much more then the variables to determine speed / range /ect i dont think ill be able to change the behavior of the animation in this script. I did try the methods you mentioned but essentially just starts the entire animation every 1 minute. the animation will always plays itself out
 
Did you review the Effects.cs in the Server files, this should help you understand how effects are used as for there fields and types?
 
I'm Looking it over now but... Maybe this is above my skill level.
From what I Understand is the code below is essentially Sending the effect at the target in a fixed direction. Basically the effect will start at 1 location and straight-line to the position of the target when initiated. The starting point is determined by the player postion ( range for reverse.) What im struggling to grasp is A. How the pattern is set to spread out equally around the starting pont.
B. How I can I can stall the location of the animation and pick up where it left off....while also leaving the individual EffictID remain looping in place
C. Specifically how the Pattern is formed in a circle around the player before it is sent outward. I dont seen any thing that sets the xyz for multiple effects surrounding the player loc or any code that sets the pattern from the players xyz
Maybe i need a break my head hurts now and i feel like this is much simpler then im making it out to be :(


Code:
public static void SendMovingEffect(
            IEntity from,
            IEntity to,
            int itemID,
            int speed,
            int duration,
            bool fixedDirection,
            bool explodes,
            int hue,
            int renderMode)
        {
            if (from is Mobile)
            {
                ((Mobile)from).ProcessDelta();
            }

            if (to is Mobile)
            {
                ((Mobile)to).ProcessDelta();
            }

            SendPacket(
                from.Location,
                from.Map,
                new MovingEffect(from, to, itemID, speed, duration, fixedDirection, explodes, hue, renderMode));
        }

        public static void SendMovingParticles(
            IEntity from,
            IEntity to,
            int itemID,
            int speed,
            int duration,
            bool fixedDirection,
            bool explodes,
            int effect,
            int explodeEffect,
            int explodeSound)
        {
            SendMovingParticles(
                from, to, itemID, speed, duration, fixedDirection, explodes, 0, 0, effect, explodeEffect, explodeSound, 0);
        }

        public static void SendMovingParticles(
            IEntity from,
            IEntity to,
            int itemID,
            int speed,
            int duration,
            bool fixedDirection,
            bool explodes,
            int effect,
            int explodeEffect,
            int explodeSound,
            int unknown)
        {
            SendMovingParticles(
                from, to, itemID, speed, duration, fixedDirection, explodes, 0, 0, effect, explodeEffect, explodeSound, unknown);
        }

        public static void SendMovingParticles(
            IEntity from,
            IEntity to,
            int itemID,
            int speed,
            int duration,
            bool fixedDirection,
            bool explodes,
            int hue,
            int renderMode,
            int effect,
            int explodeEffect,
            int explodeSound,
            int unknown)
        {
            SendMovingParticles(
                from,
                to,
                itemID,
                speed,
                duration,
                fixedDirection,
                explodes,
                hue,
                renderMode,
                effect,
                explodeEffect,
                explodeSound,
                (EffectLayer)255,
                unknown);
        }
 
The from would be the mobile which has Location a Point3D (x, y, z), you can adjust this by inc/dec the x,y,z by 1, which is one tile, X++; would add one, and X += 5; would add 5 etc etc, I hope that helps, otherwise maybe I'm not following your issue!
also, please use code blocks around your posted code, keeps them neat and tidy =p
 
You can create your own implementation of the FireExplodeEffect and override the target points list:
Code:
    public class FireRingEffect : FireExplodeEffect
    {
        public FireRingEffect(
            IPoint3D start,
            Map map,
            int range = 100,
            int repeat = 0,
            TimeSpan? interval = null,
            Action<EffectInfo> effectHandler = null,
            Action callback = null)
            : base(start, map, range, repeat, interval, effectHandler, callback)
        {
        }

        public override Point3D[][] GetTargetPoints(int count)
        {
            return Start.ScanRangeGet(Map, Range, Range, ComputePoint, AverageZ);
        }
    }
Then you can do this:
Code:
var fx = new FireRingEffect( location, map, 100, 60, TimeSpan.FromSeconds(1.0) );

fx.AverageZ = true;
fx.Reversed = true;

// called after every repetition
fx.Callback = () =>
{
    if ( fx.CurrentProcess + 1 > fx.Repeat ) // ending
    {
        fx.Range = Math.Max( 0, fx.Range - 10 );

        if ( fx.Range > 0 )
            fx.Send(); // start again
    }
    else // repeating
    {
        // loop over event participants list and check range...
        foreach ( var player in MyEvent.Players )
        {
            if ( !player.InRange( fx.Start, fx.Range )
                player.Damage( 10 );
        }
    }
};

fx.Send();

I wouldn't recommend using ranges that are too high as it can cause severe performance issues while allocating the buffer queues.
 
Back