Ok so I decided posting an example of how I handle status effect adding/removal on my source may be an easier way to explain it. I doubt many if any will get any use out of it cause to implement in something like lotf would take a decent amount of coding AND most people are either too lazy/inexperienced/dumb to do that or already could write something like this or better.
Regardless... here we go.
Client Status Pool
This is a long value which will store ALL active player effects. This is the value sent in your update entity packet. On current patch this is update entity subtype 25 but w/e.
So in my Client.cs I have...
private ulong _Status;
I now create an accessor for it so that I automatically update the client ANY TIME IT IS MODIFIED
Explanation...
My Packets.ToScreen method sends the packet to all characters nearby... You can do this by looping through clients within range (distance check). Personally I have a localClients dict which stores all clients currently within my range. In my spawn code I use this to see if an object is already spawned to a client and therefor I don't need to spawn it again... it also allows for easy access of objects near players which means I don't need to loop through all map objects. This type of system works nicely assuming you update it properly but a distance check would function just as well I suppose.
Now... _Status = value;
value = whatever we enter for Status
Eg:
Client.Status = 50 would set the private _Status variable to = 50. Simple shit but w/e.
,this just means this instance of the Client class. This is just one of the parameters that my send packet requires.. because obviously I need to know WHICH client I'm using.
So now for the fun stuff!
Seeing as this is a giant pool of numbers (with a HUGE range) we do NOT want to add things or remove them twice
Eg, every time you attack adding bluename status... this will mean your status effect rapidly goes up and you have.... undesired consequences.
To get around this we are going to create a dictionary of active stats on our character! YAY!
public Dictionary<Enum.Effect, Status> ActiveStats = new Dictionary<Enum.Effect, Status>();
So... first of all our key is Enum.Effects... this is an enum I created to give easy access to the different status effects.
You can set one up yourself rather easily using something like...
public enum Effect : ulong
{
BlueName = 1,
Poisoned = 2,
}
Simply add more values as you find them. I don't feel the need to post all of them as you can simply run through them all quite quickly (as they are added together you must double them every time for a unique effect... and not all values are used!)
Now the second part of our dictionary you may not know about is "Status". This is a struct that I created to hold effect information. It is as follows...
Quite simply this allows us to know... which effect it is... when it was activated... if it should be removed.. and WHEN it should be removed. Simple stuff!
So now lets write some functions to add effects!
So the first part simply checks if we have already added this stat and if so, we remove it and complain to the client so that we can fix w/e code is trying to do something so stupid.
Now we need a way to remove things!
Rather simple again.. if we DON'T have the effect in our active effects, we bitch to the client and return (in this case I'm not adding it as that's just not a fun thing to do)
Assuming it's there, we remove it and BOOM. Done.
Now... We can add/remove things on commands but what about timeout you ask? Well personally I have two character threads for my server. A slow one and a fast one. These are geared to the type of actions I want them to perform! Personally this goes inside my 'fast' thread as it could occur more often than once every second or two.
All you need to do is something like...
Now... let me explain my "ToRemove" dictionary... it was a quick fix I did due to the fact that I'm iterating through active stats... obviously if you try to remove an item from something you are iterating through you will get an error saying that a collection has been modified, blablabla. To get around this I setup a simple dictionary which will temporarily hold what I want to remove. Once I'm done iterating through objects I use the ones I know I want to remove and use that to modify my original dictionary. It's a rough workaround but w/e it worked and I was tired at the time. I'm sure the pros will offer me all sorts of advice on how to do it better.
SO! This code all we are doing is running through active effects, Checking first to see if we meet the conditions for removing red/black name (as I set the 'remove' bool on them to false meaning they will not remove automatically over a specified amount of time.)
Once that is done we will check the other effects to see if they qualify for timed removal and if so add to our temp dictionary.
Once that is done we simply use this dict to remove from the active effects one.
NOTE: In this instance I'm NOT using my remove method that I already posted.. this is simply cause I coded that AFTER this so yah.. that could easily be changed around but this way WILL work.
Closing:
So I'm positive this will help virtually no one... I simply wanted to post it so that when questions of status effect popped up I had SOMETHING to point to vs just doing some long winded explanation of how I do things personally.
Regardless... here we go.
Client Status Pool
This is a long value which will store ALL active player effects. This is the value sent in your update entity packet. On current patch this is update entity subtype 25 but w/e.
So in my Client.cs I have...
private ulong _Status;
I now create an accessor for it so that I automatically update the client ANY TIME IT IS MODIFIED
Code:
public ulong Status
{
get { return _Status; }
set { _Status = value; Packets.ToScreen(Packets.UpdateEntity(this.UID, Enum.Update.StatusEffect, value), this); }
}
My Packets.ToScreen method sends the packet to all characters nearby... You can do this by looping through clients within range (distance check). Personally I have a localClients dict which stores all clients currently within my range. In my spawn code I use this to see if an object is already spawned to a client and therefor I don't need to spawn it again... it also allows for easy access of objects near players which means I don't need to loop through all map objects. This type of system works nicely assuming you update it properly but a distance check would function just as well I suppose.
Now... _Status = value;
value = whatever we enter for Status
Eg:
Client.Status = 50 would set the private _Status variable to = 50. Simple shit but w/e.
,this just means this instance of the Client class. This is just one of the parameters that my send packet requires.. because obviously I need to know WHICH client I'm using.
So now for the fun stuff!
Seeing as this is a giant pool of numbers (with a HUGE range) we do NOT want to add things or remove them twice
Eg, every time you attack adding bluename status... this will mean your status effect rapidly goes up and you have.... undesired consequences.
To get around this we are going to create a dictionary of active stats on our character! YAY!
public Dictionary<Enum.Effect, Status> ActiveStats = new Dictionary<Enum.Effect, Status>();
So... first of all our key is Enum.Effects... this is an enum I created to give easy access to the different status effects.
You can set one up yourself rather easily using something like...
public enum Effect : ulong
{
BlueName = 1,
Poisoned = 2,
}
Simply add more values as you find them. I don't feel the need to post all of them as you can simply run through them all quite quickly (as they are added together you must double them every time for a unique effect... and not all values are used!)
Now the second part of our dictionary you may not know about is "Status". This is a struct that I created to hold effect information. It is as follows...
Code:
public struct Status
{
public Enum.Effect ID;
public DateTime Activated;
public uint Timeout;
public bool Remove;
}
So now lets write some functions to add effects!
Code:
public void AddEffect(Enum.Effect E, uint Time, bool Remove)
{
if (this.ActiveStats.ContainsKey(E))
{
if (Program.Debug)
Packets.Send(Packets.ColorChat("Error: you trying to add a status already added ID: " + (int)E, "SYSTEM", this.Name, Struct.ChatType.Center), this);
this.ActiveStats.Remove(E);
return;
}
Status S = new Status();
S.Activated = DateTime.Now;
S.ID = E;
S.Remove = Remove;
S.Timeout = Time;
this.Status += (ulong)E;
this.ActiveStats.Add(S.ID, S);
}
Now we need a way to remove things!
Code:
public void RemoveEffect(Enum.Effect E)
{
if (!this.ActiveStats.ContainsKey(E))
{
Packets.Send(Packets.ColorChat("Error: you trying to removed a status already removed ID: " + (int)E, "SYSTEM", this.Name, Struct.ChatType.Center), this);
return;
}
ActiveStats.Remove(E);
this.Status -= (ulong)E;
}
Assuming it's there, we remove it and BOOM. Done.
Now... We can add/remove things on commands but what about timeout you ask? Well personally I have two character threads for my server. A slow one and a fast one. These are geared to the type of actions I want them to perform! Personally this goes inside my 'fast' thread as it could occur more often than once every second or two.
All you need to do is something like...
Code:
Dictionary<Enum.Effect, Status> ToRemove = new Dictionary<Enum.Effect, Status>();
lock (Program.Clients)
{
foreach (KeyValuePair<uint, Client> Client in Program.Clients)
{
if (Client.Value.ActiveStats.Count > 0)
{
lock (Client.Value.ActiveStats)
{
foreach (KeyValuePair<Enum.Effect, Status> Stat in Client.Value.ActiveStats)
{ if (Stat.Key == Enum.Effect.RedName)
{
if (Client.Value.Pk < 30)
ToRemove.Add(Stat.Key, Stat.Value);
}
else if (Stat.Key == Enum.Effect.BlackName)
{
if (Client.Value.Pk < 100)
ToRemove.Add(Stat.Key, Stat.Value);
}
if (DateTime.Now > Stat.Value.Activated.AddMilliseconds(Stat.Value.Timeout) && Stat.Value.Remove)
{
try
{
ToRemove.Add(Stat.Key, Stat.Value);
}
catch { Console.WriteLine("Error: Could not remove stat"); }
}
}
foreach (KeyValuePair<Enum.Effect, Status> ToRem in ToRemove)
{
Client.Value.Status -= (ulong)ToRem.Value.ID;
Client.Value.ActiveStats.Remove(ToRem.Value.ID);
}
ToRemove.Clear() ;
}
}
}
}
SO! This code all we are doing is running through active effects, Checking first to see if we meet the conditions for removing red/black name (as I set the 'remove' bool on them to false meaning they will not remove automatically over a specified amount of time.)
Once that is done we will check the other effects to see if they qualify for timed removal and if so add to our temp dictionary.
Once that is done we simply use this dict to remove from the active effects one.
NOTE: In this instance I'm NOT using my remove method that I already posted.. this is simply cause I coded that AFTER this so yah.. that could easily be changed around but this way WILL work.
Closing:
So I'm positive this will help virtually no one... I simply wanted to post it so that when questions of status effect popped up I had SOMETHING to point to vs just doing some long winded explanation of how I do things personally.