ID:151925
 
Currently, I manage different actions and states in one variable called state. Each state/action is a bit flag and I turn the bits on and off to check whether the action/state is being done or not.

Some examples are: ATTACKING, CANTATTACK, FROZEN, etc.

The problem is, a lot of these are time-based, meaning that they turn on/off after a given period of time when they are turned on/off. So I need help on figuring on how to go about it.

I currently have one method in mind, but I would like to see what you guys think because the ideas might be much better than mine.

(My method involves creating a datum that uses the Event Loop.)
Personally, I would just call another proc being the procedural programmer I am >_>

I like the idea of using a datum personally, and speaking of which, I think I'll use bit flags for status effects in my game (I didn't know how bits worked when I made it, so I have like 10 worthless Boolean vars).
In response to Jeff8500
I am interested in your method, mind explaining what you mean by calling a proc? (I know what calling a proc is, but how is it going to work?)

You might also want to read my article on bitwise operators (if you feel like you want to know more) by clicking here.
In response to Kakashi24142
I assume he simply means something along the lines of this:
mob/proc/GiveEffect(effect,delay=50)
//src.effects += effect //whatever implementation you use
src.effects |= effect
spawn(delay)
src.effects &= ~effect


That works, though with an implementation like this, if a status effect can be caused by multiple different things at the same time, you'd have problems. eg a player is given a paralyzed effect by a spell (that lasts 10 seconds), then gets another paralyze effect from a strong melee attack, or just another spell (that lasts 3 seconds). After 3 seconds, the proc used to add the melee attack's effect will remove the paralysis, and because bit flags are only merely on or off, it will remove all paralysis effects, so in effect it will cancel out the spell too soon, ie bug.

So bit flags are generally nice, but don't really cut it for this*. If you use datums (or other objects) for effects for the flexibility and what not already, having a list of the datums currently affecting the object(=mob) would be foolproof, and also useful of course.

EDIT:
*: You'd do fine with a separate variable with bit flags for the pure on-or-off states, though, like ATTACKING, JUMPING, etc. Just not FROZEN, PARALYZED etc, those states need to keep track of either what caused them or how many times they were induced. Even if you only have one Paralysis spell in your entire game or something that always works for 5 seconds, say if someone casted that spell twice on someone while he was still paralyzed, it'd already cause the problem.
In response to Kaioken
Ok thanks! I have already begun my work on my datum and it works like so:
Action
var
time=-1 //-1 indicates that it is not a timed action, and any value > 0 indicated that that is the time in tenths of a second to take out the action
Action1
Action2
...


ActionList
var/list/encapsulated_list //this list contains all the actions
proc/Add()
proc/Remove()
proc/Find()
In response to Kakashi24142
Well, you didn't ask anything but I'm just going to discuss some things I thought about. =P

--About the time value, escaping 'special' values as values under 0 (ie -1) etc when able is indeed nice, but you don't need to in this case! If the effect is permanent, just leave time at its default value of null (or 0 if you prefer, though it's unrequired). Then you can just do if(Action.time) to check if it's timed.

--I've barely seen much, of course, but the ActionList datum seems extraneous at best. Just have a regular list and procs that effect the targets instead, it's more straightforward and those procs are slightly more useful anyway.

--We're talking 'effects', right? =P Just making sure, 'cause again, for things like pure states or actions, you'd very well be better off with a bit field than a list. Since if you're already set to ATTACKING (...or RESTING, MEDITATING, KNOCKEDOUT, SITTING, STANDING...), you're not going to ATTACK again while that flag is set - in fact often the purpose of the flag (as is in the case of ATTACKING) is to block the action from actually happening again. Then you're safe because it only happens once "at once", and then also gets removed once with no problems.

So you'd probably have (if you use Kaioken NamesTM, that is ;D) something like this
//states definitions
#define ATTACKING 1
#define RESTING 2
#define SWIMMING 4

//effects definitions
effect
var/mob/character/owner //mob, or perhaps a list.
var/name,time
proc/Add(mob/character/M) //apply the effect.
if(!M.effects) src.effects = new
M.effects += src
src.Apply(M)
if(src.time)
spawn(src.time) src.Remove(M)
proc/Apply()
return 0 //by default do nothing
proc/Unapply()
return 0 //by default do nothing, some effects won't do anything here as well
proc/Remove(mob/character/M)
if(M.effects) //failsafe
M.effects -= src
if(!M.effects.len) //if the list is empty
M.effects = null //delete it to save space (it will be intercepted by the garbage collector)
src.Unapply(M)
damage
var/element,dmg=1
Apply(mob/character/M)
M.TakeDamage(src.dmg,src.element)
fire_damage
element = ELEM_FIRE
kk_touch
name = "Kaioken's Touch"
dmg = 1000
drain //temporary damage
var/stat,dmg=1
time=1
Apply(mob/character/M)
M.ModifyStat(src.stat,-src.dmg)
Unapply(mob/character/M)
M.ModifyStat(src.stat,src.dmg) //add it back
kk_breath
name = "Kaioken's Breath"
dmg = 300
time = 10
stat = "hp"
//or...
stat = "str"
//'stat' would be the name of the stat to be accessed\
from the 'vars' list. it's up to ModifyStat() to \
properly call TakeDamage() for hp modifications, etc

paralysis
//no apply or unapply required per se
Apply(mob/character/M)
M << "You're paralyzed."
mob/character
var/list/effects //the effects that are currently affecting this char
/*(the list is not initialized at compile-time/New() to
save resources so when no effects are present there is no
list)*/

var/states //stores bit flags

proc
AddEffect(effect/E,time = E.time)
if(ispath(E)) //possibility to take paths
E = new E
E.Add(src)
AddState(state,time)
src.states |= state
spawn(time)
src.RemoveState(state)
RemoveState(state)
src.states &= ~state

//usage
client/Move()
var/mob/character/M = src.mob
if(istype(M)) //failsafe, not necessary depending on game
if(M.states & RESTING || \
locate(/effect/paralysis) in M.effects)
return 0 //can't move
return ..() //can


That's more or less probably how I'd have it. Of course it could get even more complex and with even more procs (maybe O_o), and some effects' Apply() could actually be adding states, then their Unapply() would remove the state if there are no effects in the effects list of that same type (that controls the state) active in the effects list, and what not. I'm too tired for more, anyway. =p

EDIT: Some small "typos" fix in the code after a long time. ;D
In response to Kaioken
Thanks! That was pretty interesting. But I think I forgot to mention that a proc needs to be called every tenth of a second when a certain flag is turned on and I need the time to be able to pause once in a while. (I achieved all that by using Deadron's Event Loop.)
In response to Kaioken
For a second there I was wondering how the heck you managed to swipe my effects system. Then I noticed subtle differences. =)

It's interesting seeing how sometimes BYOND code can parallel so closely with that written by someone else entirely, even without any form of standard algorithm.

(In my case, I have the following: /effect/Add(), /effect/Remove(), /effect/Maintain(), /effect/CanAffect(), /effect/Apply(), and /effect/Expire().)