/**
* This is the basic effects module.
* Extracted from Ember's living effects code by Deutha.
* @changed 4-6-1997, Turrican
* To use arrays of classes, and to allow function pointers.
* @changed 17-10-1997 Olorin
* Fixed a bug then adding an effect in the end() function of
* another effect.
* @changed 03-09-2002 Sandoz
* Changed to get shadow objects from the shadows handler.
* @see help::effects
*/
#include <effect.h>
class effect_shadow {
object shad_ob;
int idnum;
}
class effect_event {
int inctime;
mixed func;
int eff_ob_num;
mixed interval;
int flags;
}
void delete_effect( int i );
// This keeps track of the effect number being called (beginning/end/etc.).
private nosave int current_enum;
private nosave int next_id;
#undef DEBUG
#ifdef DEBUG
nosave int logging_effects;
void set_logging_effects( int i ) { logging_effects = i; }
int query_logging_effects() { return logging_effects; }
#endif
// This stores shadows for corresponding effects as shadow_ob, idnum.
private nosave class effect_shadow *shadows;
// This stores effects currently active on player as "effect_ob_name", arg
private class effect *effs;
/*
* effect event queue
*
* This stores all effect events going to be happening...
*
* time_from_previous_event, "function", eff_ob_num, interval, flags
*
* where flags can be
*
* EE_REMOVE
* EE_CONTINUOUS
* EE_ONCE
*
* and interval can be
* number_of_secs
* ({ min_secs, max_secs }) ; "1" dice roll
* ({ min_secs, max_secs, n }) ; "n" dice rolls
*
* ee are added with
* submit_ee("function", interval, flags);
*
*/
private class effect_event *eeq;
protected void create() {
effs = ({ });
shadows = ({ });
eeq = ({ });
next_id = 0;
current_enum = -1;
#ifdef DEBUG
logging_effects = 0;
#endif
} /* create() */
/**
* This method removes all the current effects off the object
* and sets everything back to the initial state.
* @see add_effect()
*/
void reset_effects() {
effs = ({ });
shadows = ({ });
eeq = ({ });
current_enum = -1;
remove_call_out("effect_timer");
#ifdef DEBUG
if( logging_effects )
log_file("EFFECT_WOBBLE", "%d:%s(%d) reset_effects:"
"remove_call_out(\"effect_timer\")\n", time() % 1000,
TO->query_name(), current_enum );
#endif
} /* reset_effects() */
/**
* This method returns the outermost shadow on this object.
* This is useful for making sure functions get called right
* through the shadow chain. If there are no objects being
* shadows, this_object() is returned.
* @return the outermost shadow object
*/
object affected_object() {
object this, other;
this = other = TO;
while( objectp(other) ) {
this = other;
other = query_shadowing(this);
}
return this;
} /* affected_object() */
/**
* This method freezes all the current effects so that they do
* not continue to be processed. Basicly it removes the call_out
* for the effect_timer(). It also ensures the intrval for the
* immediately pending effect
* is correct.
* @see effect_timer()
* @see add_effect()
*/
void effect_freeze() {
/* stop effect_timer call_out and put the remaining
* time value into EEQ_INCTIME of first element */
int timeleft;
timeleft = remove_call_out("effect_timer");
#ifdef DEBUG
if( logging_effects )
log_file("EFFECT_WOBBLE", "%d:%s(%d) effect_freeze:"
"remove_call_out(\"effect_timer\")=%d\n", time() % 1000,
TO->query_name(), current_enum, timeleft );
#endif
if( sizeof( eeq ) )
eeq[ 0 ]->inctime = timeleft;
} /* effect_freeze() */
/** @ignore yes */
private void quit_save_effects( string func ) {
int i, neffs;
string effn;
mixed arg;
neffs = sizeof( effs );
for( i = 0; i < neffs; i++ ) {
effn = effs[ i ]->ob_name;
arg = effs[ i ]->arg;
if( pointerp(arg) && sizeof(arg) == 3 && arg[ 2 ] == BOGUS_OLD_ARG )
arg = arg[ 1 ];
if( effn )
catch( call_other( effn, func, affected_object(), arg, i ) );
}
} /* quit_save_effects() */
/**
* @ignore yes
* This method is called when a player actually saves.
* It calls the quitting method on all the effects.
*/
void effects_saving() { quit_save_effects("saving"); }
/**
* @ignore yes
* This method is called when a player actually quits.
* It calls the quitting method on all the effects.
*/
void effects_quiting() { quit_save_effects("quiting"); }
/**
* This method restarts the internal call_out.
* @see effects_freeze()
* @see add_effect()
*/
void effect_unfreeze() {
/* Restart the timer, checking that it hasn't been restarted
* already by a nested unfreeze.
*/
int time;
if( sizeof( eeq ) ) {
#ifdef DEBUG
if( logging_effects )
log_file("EFFECT_WOBBLE", "%d:%s(%d) effect_unfreeze:"
"call_out(\"effect_timer\", %d )\n", time() % 1000,
TO->query_name(), current_enum, eeq[ 0 ]->inctime );
#endif
time = find_call_out("effect_timer");
if( time != -1 )
remove_call_out("effect_timer");
call_out("effect_timer", eeq[ 0 ]->inctime );
}
} /* effect_unfreeze() */
/** @ignore yes */
protected int int_submit_ee( int eff_ob_num, mixed fun, mixed interval,
int flags ) {
/*
* This calculates next occurence of this ee and inserts it into the eeq.
* Note that it can only be called sandwiched between freeze and
* unfreeze calls.
*/
int i, ntime;
#ifdef DEBUG
if( logging_effects )
log_file("EFFECT_WOBBLE", "%d:%s(%d) int_submit_ee:"
"( %d, %O, %O, %s )\n", time() % 1000, TO->query_name(),
current_enum, eff_ob_num, fun, interval,
({"once", "remove", "continuous"})[flags] );
#endif
if( intp(interval) )
ntime = interval;
else if( pointerp(interval) ) {
switch( sizeof(interval) ) {
case 0:
return -1;
case 1:
ntime = interval[0];
break;
case 2:
ntime = interval[0] + random( interval[1] - interval[0] + 1 );
break;
case 3:
ntime = 0;
for( i = 0; i < interval[2]; i++ )
ntime += interval[0] + random( interval[1] - interval[0] + 1 );
ntime += interval[2] / 2;
ntime /= interval[2];
break;
default:
return -1;
}
} else
return -1;
/* If the flag is EE_REMOVE, and one exists for EEQ_EFF_OB already,
* remove the old one. This is for occasions when an EE_REMOVE is
* called from merge_effect() */
if( flags == EE_REMOVE ) {
for( i = 0; i < sizeof(eeq); i++ )
if( eeq[i]->eff_ob_num == eff_ob_num &&
eeq[i]->flags == EE_REMOVE ) {
eeq = delete( eeq, i, 1 );
break;
}
}
/*
* This removes all scheduled ee's with the
* specified flag and function.
*/
if( ntime < 0 ) {
if( flags != EE_REMOVE ) {
for( i = 0; i < sizeof(eeq); i++ )
if( eeq[i]->eff_ob_num == eff_ob_num &&
eeq[i]->flags == flags && eeq[i]->func == fun )
eeq = delete( eeq, i, 1 );
}
return 0;
}
for( i = 0; i < sizeof(eeq); i++ ) {
/* goes in here! */
if( ntime < eeq[i]->inctime ) {
eeq[i]->inctime -= ntime;
eeq = eeq[0..i-1] + ({ new( class effect_event, inctime : ntime,
func : fun, eff_ob_num : eff_ob_num, interval : interval,
flags : flags ) }) + eeq[i..];
break;
}
ntime -= eeq[i]->inctime;
}
if( i == sizeof(eeq) && eeq ) {
eeq += ({ new( class effect_event,
inctime : ntime,
func : fun,
eff_ob_num : eff_ob_num,
interval : interval,
flags : flags )
});
} else if( !sizeof(eeq) ) {
/* This shouldn't happen, but it does sometimes!
* Note from Olorin: without testing for !sizeof(eeq), this
* code mangles the cases where the queue exists and the event
* already inserted by the for loop.
*/
eeq = ({ new( class effect_event,
inctime : ntime,
func : fun,
eff_ob_num : eff_ob_num,
interval : interval,
flags : flags )
});
}
return i;
} /* int_submit_ee() */
/**
* This submits an effect event schedule. It will call "function name" in
* your effect object after the interval specified in interval_spec, with
* behaviour modified by flags.
* interval_spec can be one of:
* <dl><dt>n
* <dd>time in seconds
* <dt>({ m, n })
* <dd>minimum time m seconds, maximum time n seconds, simple random
* distribution
* <dt>({ m, n, r })
* <dd>as for the ({ m, n }) case, except the random factor is effectively
* "rolled" r times ... the higher r is, the more likely the interval
* is to be close to (m + n)/2.
* <dt>If the interval is a negative figure, any functions with the
* specified function name will be removed from the queue.
* This is useful in removing unwanted things from the effects queue.
* </dl>
* flags may be:
* <dl>
* <dt>EE_REMOVE
* <dd>remove the effect from the player after the function call
* <dt>EE_CONTINUOUS
* <dd>do it repeatedly. Default (EE_ONCE) is only do it once.
* <dt>EE_ONCE
* <dd>do it once
* </dl>
* These are defined in /include/effect.h
* <p>
* Only one EE_REMOVE can be in place at a time. Subsequent EE_REMOVEs
* will wipe previous ones.
* <p>
* NB: submit_ee can ONLY be called from the effect object itself in the
* course of a beginning/handler/end call, or from the effect shadow.
* @see submit_ee2()
* @see /include/effect.h
* @see add_effect()
* @param fun the function to call
* @param interval the interval specifier
* @param flags the flags for the event
*/
void submit_ee( mixed fun, mixed interval, int flags ) {
/* public access point for int_submit_ee ... it uses current_enum or
previous_object (for shadows) to determine what effect it refers to */
int enumb;
#ifdef DEBUG
if( logging_effects )
log_file("EFFECT_WOBBLE", "%d:%s(%d) submit_ee:( %O, %O, %s )\n",
time() % 1000, TO->query_name(), current_enum, fun, interval,
({"once","remove","continuous"})[flags] );
#endif
if( ( enumb = current_enum ) < 0 ) {
enumb = member_array( 1, map( shadows, (: $1 &&
((class effect_shadow)$1)->shad_ob == PO :) ) );
if( enumb < 0 )
error("Cannot submit from that object.");
}
effect_freeze();
int_submit_ee( enumb, fun, interval, flags );
effect_unfreeze();
} /* submit_ee() */
/**
* This submits an effect event for a specific effect.
* Apart from this it is the same as submit_ee()
* @param enum the enum of the effecrt
* @param fun the function to call
* @param interval the interval specifier
* @param flags the flagds associated with the event
*/
void submit_ee2( int enum, mixed fun, mixed interval, int flags ) {
/* public access point for int_submit_ee ... it uses enum
* to determine what effect it refers to (for those cases where
* current_enum isn't defined)
*/
#ifdef DEBUG
if( logging_effects )
log_file("EFFECT_WOBBLE", "%d:%s(%d) int_submit_ee:"
"( %d, %O, %O, %s )\n", time() % 1000,
TO->query_name(), current_enum, enum, fun, interval,
({"once","remove","continuous"})[flags] );
#endif
if( enum < 0 )
error("Cannot submit from that object.");
effect_freeze();
int_submit_ee( enum, fun, interval, flags );
effect_unfreeze();
} /* submit_ee() */
/**
* This method returns the time until any EE_REMOVE effect
* is expected to occur. It will return -1 if no remove event
* is scheduled. If the flag is not set to true, the the
* current enum is checked, otherwise the new_enum is checked.
* @param flag if true, use new_enum not current_enum
* @return the time until the remove event will occur,
* or -1 if none is scheduled
* @see submit_ee()
* @see aff_effect()
*/
int expected_tt( int flag, int new_enum ) {
int timeleft, enum;
if( flag )
enum = new_enum;
else
enum = current_enum;
if( enum < 0 )
return -1;
if( !sizeof(eeq) )
return -1;
// Stop the event timer.
effect_freeze();
// Add up the incremental times in the queue until you get to the
// EE_REMOVE for the one your asking about.
foreach( class effect_event eff in eeq ) {
timeleft += eff->inctime;
if( eff->eff_ob_num == enum && eff->flags == EE_REMOVE ) {
// Restart the event timer.
effect_unfreeze();
return timeleft;
}
}
// Restart the event timer.
effect_unfreeze();
return -1;
} /* expected_tt() */
/**
* This method adds an effect onto the object. The arg is passed
* directly onto the function 'beginning' on the effect object.
* If the result is non-zero then the return value of the begining
* function is used instead of the arg and stored away. If an
* effect of the same type is already on the object then the
* function 'merge_effect' will be called on the effect object.
* If it returns a non-zero value then the arg for the initial
* effect will be updated to the new value, otherwise both effects
* will run with different arguments.
* @see help::effects
* @see submit_ee()
*/
void add_effect( string eff, mixed arg ) {
string shad;
object ob, effob;
mixed hbf, res;
int i, old_current_enum, enum;
#ifdef DEBUG
if( logging_effects )
log_file("EFFECT_WOBBLE", "%d:%s(%d) add_effect:(%s,%O)\n",
time() % 1000, TO->query_name(), current_enum, eff, arg );
#endif
if( !( hbf = (mixed)eff->query_secs_between_hb() ) &&
( hbf = (mixed)eff->query_heart_beat_frequency() ) && intp(hbf) )
hbf *= 60;
old_current_enum = current_enum;
if( !effob = find_object(eff) )
error("Bad effect object.");
for( i = 0; i < sizeof(effs); i++ ) {
if( effs[i]->ob_name == eff ) {
if( function_exists("merge_effect", effob ) ) {
current_enum = i;
if( hbf ) {
if( res = (mixed)effob->merge_effect( affected_object(),
effs[i]->arg[1], arg ) )
effs[i]->arg[1] = res;
} else {
if( res = (mixed)effob->merge_effect( affected_object(),
effs[i]->arg, arg ) )
effs[i]->arg = res;
}
current_enum = old_current_enum;
return;
}
}
}
if( shad = (string)effob->query_shadow_ob() ) {
ob = (object)SHADOW_H->get_shadow(shad);
shadows += ({ new( class effect_shadow, shad_ob : ob,
idnum : next_id ) });
ob->attach_to_player( affected_object(), next_id );
} else {
shadows += ({ new( class effect_shadow, shad_ob : 0,
idnum : next_id ) });
}
current_enum = sizeof(effs);
enum = current_enum;
effs += ({ new( class effect, ob_name : eff, arg : arg ) });
if( function_exists("beginning", effob ) ) {
if( res = (mixed)effob->beginning( affected_object(), arg, next_id ) )
effs[enum]->arg = res;
}
next_id++;
if( hbf ) {
submit_ee("effect_heart_beat", hbf, EE_CONTINUOUS | EE_OLD );
effs[enum]->arg = ({ 0, effs[<1]->arg, BOGUS_OLD_ARG });
}
current_enum = old_current_enum;
} /* add_effect() */
#define EFF_OB_NAME 0
#define EFF_ARG 1
#define EEQ_INCTIME 0
#define EEQ_FUNC 1
#define EEQ_EFF_OB 2
#define EEQ_INTERVAL 3
#define EEQ_FLAGS 4
#define EFF_SIZE 2
#define EEQ_SIZE 5
/** @ignore yes */
protected void convert_arrays() {
int i, neffs, neeq;
mixed old;
if( sizeof(effs) && !classp(effs[0]) ) {
old = effs;
effs = allocate( neffs = sizeof(old) / EFF_SIZE );
for( i = 0; i < neffs; i++ )
effs[i] = new( class effect,
ob_name : old[i*EFF_SIZE+EFF_OB_NAME],
arg : old[i*EFF_SIZE+EFF_ARG] );
}
if( sizeof(eeq) && !classp(eeq[0]) ) {
old = eeq;
eeq = allocate( neeq = sizeof(eeq) / EEQ_SIZE );
for( i = 0; i < neeq; i++ )
eeq[i] = new( class effect_event,
inctime : old[ i * EEQ_SIZE + EEQ_INCTIME ],
func : old[ i * EEQ_SIZE + EEQ_FUNC ],
eff_ob_num : old[ i * EEQ_SIZE + EEQ_EFF_OB ],
interval : old[ i * EEQ_SIZE + EEQ_INTERVAL ],
flags : old[ i * EEQ_SIZE + EEQ_FLAGS ] );
}
} /* convert_arrays() */
/**
* @ignore yes
* This method is called after restore_object is done to init shadows etc.
*/
void init_after_save() {
int i, neffs, *ee_exists;
string shad, effn;
object ob;
mixed arg;
convert_arrays();
shadows = allocate( neffs = sizeof(effs) );
for (i = 0; i < neffs; i++) {
effn = effs[i]->ob_name;
shadows[i] = new( class effect_shadow, idnum : next_id );
if( catch( shad = (string)effn->query_shadow_ob() ) )
continue;
if( shad ) {
ob = (object)SHADOW_H->get_shadow(shad);
shadows[i]->shad_ob = ob;
ob->attach_to_player( affected_object(), next_id );
}
current_enum = i;
arg = effs[i]->arg;
if( pointerp(arg) && sizeof(arg) == 3 && arg[ 2 ] == BOGUS_OLD_ARG )
arg = arg[1];
catch( effn->restart( affected_object(), arg, next_id++ ) );
}
ee_exists = allocate(neffs);
for( i = 0; i < sizeof(eeq); i++ )
ee_exists[eeq[i]->eff_ob_num] = 1;
for( i = sizeof(ee_exists) - 1; i >= 0; i-- ) {
if( catch( ob = load_object(effs[i]->ob_name) ) || !ob ) {
delete_effect(i);
continue;
}
if( !ee_exists[i] && !ob->query_indefinite() )
delete_effect(i);
}
current_enum = -1;
effect_unfreeze();
} /* init_after_save() */
/**
* This method returns an array of effects matching the
* classification. The start part of the classification is
* used to match, so passing "npc." into this function will
* match all the effects which modify how an npc functions.
* @param eff the classification to match
* @return the array of enums corresponding to the effects
* @see add_effect()
*/
int *effects_matching( string eff ) {
int i, neffs, *match;
string clas;
object ob;
match = ({ });
neffs = sizeof(effs);
for( i = 0; i < neffs; i++ ) {
if( catch( ob = load_object(effs[i]->ob_name) ) || !ob )
continue;
if( !stringp( clas = (string)ob->query_classification() ) )
continue;
if( clas[0..strlen(eff)-1] == eff )
match += ({ i });
}
return match;
} /* effects_matching() */
/**
* This removes an effect from the player. It uses the enum as
* returned from sid to enum. This is the number you see in
* the stat of the object next to the effect.
* @param i the enum to remove
* @see add_effect()
*/
void delete_effect( int i ) {
int id, j;
object effect_object, shadow_object;
string effect_file;
mixed arg;
#ifdef DEBUG
if( logging_effects )
log_file("EFFECT_WOBBLE", "%d:%s(%d) delete_effect:(%d) "
"sizeof(eeq)=%d\n", time() % 1000, TO->query_name(),
current_enum, i, sizeof(eeq) );
#endif
if( i < 0 || i >= sizeof( effs ) )
return;
id = shadows[i]->idnum;
arg = effs[i]->arg;
effect_freeze();
for( j = 0; j < sizeof(eeq); j++ ) {
if( eeq[j]->eff_ob_num == i ) {
if( sizeof(eeq)-1 > j )
eeq[j+1]->inctime += eeq[j]->inctime;
eeq = delete( eeq, j--, 1 );
} else {
if( eeq[j]->eff_ob_num > i )
eeq[j]->eff_ob_num--;
}
}
effect_file = effs[i]->ob_name;
effs = delete( effs, i, 1 );
shadow_object = shadows[i]->shad_ob;
shadows = delete( shadows, i, 1 );
effect_unfreeze();
/* Once all bookkeeping's done, it's safe to call end(), since we're
* essentially outside the effects system.
*/
#ifdef DEBUG
if( logging_effects )
log_file("EFFECT_WOBBLE", "%d:%s(%d) delete_effect: before end\n",
time() % 1000, TO->query_name(), current_enum );
#endif
catch( effect_object = load_object(effect_file) );
if( effect_object )
if( pointerp(arg) && sizeof(arg) == 3 && arg[ 2 ] == BOGUS_OLD_ARG )
effect_object->end( affected_object(), arg[1], id );
else
effect_object->end( affected_object(), arg, id );
#ifdef DEBUG
if( logging_effects )
log_file("EFFECT_WOBBLE", "%d:%s(%d) delete_effect: after end\n",
time() % 1000, TO->query_name(), current_enum );
#endif
// Kill the shadow if it exists.
if( objectp(shadow_object) )
shadow_object->remove_effect_shadow(id);
if( !sizeof(effs) )
TO->event_all_effects_deleted();
} /* delete_effect() */
/**
* This method returns the effect number for the given effect id. The
* effect number is an internal nhandle used by delete_effect()
* arg_of() set_arg_of() functions. "id" is passed into the
* begining/end etc functions on the effect object.
* @param sid the effect id
* @return the effect number
* @see submit_ee2()
* @see delete_effect()
* @see add_effect()
* @see arg_of()
* @see set_arg_of()
*/
int sid_to_enum( int sid ) {
return member_array( 1, map( shadows, (: classp($1) &&
((class effect_shadow)$1)->idnum == $(sid) :) ) );
} /* sid_to_enum() */
/**
* This method turns an effect number into an effect id.
* @see sid_to_enum()
* @see add_effect()
* @param enum the effect number
* @return the effect id
*/
int enum_to_sid( int enum ) { return shadows[enum]->idnum; }
/**
* This method returns the effect object for the given effect number.
* @param enum the effect number
* @return the effect object
* @see arg_of()
* @see add_effect()
* @see sid_to_enum()
*/
string eff_of( int enum ) { return effs[enum]->ob_name; }
/**
* This method returns the current arguments associated with the
* given effect number.
* @param enum the effect number
* @return the arguments associated with the effect
* @see add_effect()
* @see set_arg_of()
* @see sid_to_enum()
*/
mixed arg_of( int enum ) {
mixed arg;
if( sizeof(effs) <= enum )
return 0;
if( pointerp( arg = effs[enum]->arg ) && sizeof(arg) == 3 )
if( arg[2] == BOGUS_OLD_ARG )
return copy(arg[1]);
return copy(arg);
} /* arg_of() */
/**
* This sets the argument of the given effect to a new value.
* @param enum the effect number to change
* @param newarg the new argument value
* @see sid_to_enum()
* @see arg_of()
* @see add_effect()
*/
void set_arg_of( int enum, mixed newarg ) { effs[enum]->arg = newarg; }
/** @ignore yes */
class effect *query_effs() { return effs; }
/** @ignore yes */
class effect_shadow *query_effect_shadows() { return shadows; }
/** @ignore yes */
class effect_event *query_eeq() { return eeq; }
/** @ignore yes */
void effect_timer() {
int enum;
object effect_object;
mixed res, last_flags;
class effect_event thisee;
#ifdef DEBUG
if( logging_effects )
log_file("EFFECT_WOBBLE", "%d:%s(%d) effect_timer:() "
"sizeof(eeq)=%d\n", time() % 1000, TO->query_name(),
current_enum, sizeof(eeq) );
#endif
if( !sizeof(eeq) )
return;
thisee = eeq[0];
eeq = eeq[1..];
enum = current_enum = thisee->eff_ob_num;
if( enum >= sizeof(effs) ) {
effect_unfreeze();
if( creatorp(TO) )
tell_object( TO, "Effect number out of range, ignoring.\n");
return;
}
if( thisee->flags & EE_CANCELLED ) {
effect_unfreeze();
return;
}
if( thisee->flags & EE_CONTINUOUS ) {
last_flags = int_submit_ee( enum, thisee->func,
thisee->interval, thisee->flags );
}
// Restart the timer.
effect_unfreeze();
catch( effect_object = load_object( effs[enum]->ob_name ) );
if( !effect_object ) {
if( creatorp(TO) )
tell_object( TO, "Non-existent effect "+
effs[enum]->ob_name+", deleting.\n");
delete_effect(enum);
current_enum = -1;
return;
}
if( thisee->flags & EE_OLD ) {
res = (mixed)effect_object->effect_heart_beat( TO,
++effs[enum]->arg[0], effs[enum]->arg[1], shadows[enum]->idnum );
if( res == REMOVE_THIS_EFFECT )
delete_effect(enum);
else
effs[enum]->arg[1] = res;
} else {
if( stringp(thisee->func) ) {
res = call_other( effect_object, thisee->func, affected_object(),
effs[enum]->arg, shadows[enum]->idnum, enum );
if( res == REMOVE_THIS_EFFECT )
delete_effect(enum);
else if( res == CANCEL_THIS_EE )
eeq[last_flags]->flags |= EE_CANCELLED;
} else if( functionp(thisee->func) ) {
res = evaluate( thisee->func, affected_object(), effs[enum]->arg,
shadows[enum]->idnum, enum );
if( res == REMOVE_THIS_EFFECT )
delete_effect(enum);
else if( res == CANCEL_THIS_EE )
eeq[last_flags]->flags |= EE_CANCELLED;
}
}
if( thisee->flags & EE_REMOVE )
delete_effect(enum);
current_enum = -1;
} /* effect_timer() */
/** @ignore yes */
mixed stats() {
mixed ret;
int i;
object ob;
ret = ({ });
for( i = 0; i < sizeof(effs); i++ ) {
if( catch( ob = load_object(effs[i]->ob_name ) ) || !ob ) {
ret += ({ ({ "effect#" + i, " (buggered)"}) });
continue;
}
if( intp(effs[i]->arg) || stringp(effs[i]->arg) )
ret += ({ ({ "effect#" + i,
effs[i]->ob_name->query_classification()+" ("+
effs[i]->arg+")"}) });
else
ret += ({ ({ "effect#" + i,
effs[i]->ob_name->query_classification()+" (complex)"}) });
}
return ret;
} /* stats() */
/**
* This method removes all the effects as we die. It calls the function
* survive_death() on the effect objects themselves to determine if
* they should be kept when the living dies.
*/
void effects_thru_death() {
int i;
object ob;
i = sizeof( effs );
while( i-- ) {
if( catch( ob = load_object(effs[i]->ob_name) ) || !ob ||
!ob->survive_death() )
delete_effect(i);
}
} /* effects_thru_death() */
/**
* This method returns the current enum.
* @return the current enum
*/
int query_current_effect_enum() { return current_enum; }
/**
* This method is used to force the effects setup in the object to be a
* specified value. This is used in the effects effect which sets up
* effects on someone using a shadow. This should only be used on startup.
* @param args the effects array to overwrite the old one with
*/
protected void set_effs( mixed args ) {
int i, neffs;
if( sizeof( args ) && !classp( args[ 0 ] ) ) {
effs = allocate( neffs = sizeof( args ) / EFF_SIZE );
for( i = 0; i < neffs; i++ )
effs[ i ] = new( class effect,
ob_name : args[ i * EFF_SIZE + EFF_OB_NAME ],
arg : args[ i * EFF_SIZE + EFF_ARG ] );
} else {
effs = args;
}
} /* set_effs() */
/**
* This method is used to force the effects setup in the object to be a
* specified value. This is used in the effects effect which sets up
* effects on someone using a shadow. This should only be used on startup.
* @param args the effects array to overwrite the old one with
*/
protected void set_eeq( mixed args ) {
int i, neeq;
if( sizeof( args ) && !classp( args[ 0 ] ) ) {
eeq = allocate( neeq = sizeof( args ) / EEQ_SIZE );
for( i = 0; i < neeq; i++ )
eeq[ i ] = new( class effect_event,
inctime : args[ i * EEQ_SIZE + EEQ_INCTIME ],
func : args[ i * EEQ_SIZE + EEQ_FUNC ],
eff_ob_num : args[ i * EEQ_SIZE + EEQ_EFF_OB ],
interval : args[ i * EEQ_SIZE + EEQ_INTERVAL ],
flags : args[ i * EEQ_SIZE + EEQ_FLAGS ] );
} else {
eeq = args;
}
} /* set_eeq() */