/* -*- LPC -*- */
/*
* $Locker: $
* $Id: light.c,v 1.9 2002/01/04 02:45:06 presto Exp $
* $Log: light.c,v $
* Revision 1.9 2002/01/04 02:45:06 presto
* Changed to handle negative light values correctly. Also might be a bit faster
* since I eliminated some redudant call_others
*
* Revision 1.8 2000/04/21 17:13:50 taffyd
* Fixes so that opaque containers don't let light escape.
*
* Revision 1.7 1998/10/30 08:48:08 pinkfish
* Stuff and stuff!
*
* Revision 1.6 1998/08/21 23:56:41 pinkfish
* Whoops. Made it do the wrong thing for propogating light changs through
* non-opaque objects.
*
* Revision 1.5 1998/08/21 00:48:24 pinkfish
* Handling for opaque objects.
*
* Revision 1.4 1998/08/20 12:29:14 pinkfish
* Changes for the new light code.
*
* Revision 1.2 1998/05/23 15:16:49 gototh
* Added a table of light levels to the help for set_light.
*
* Revision 1.1 1998/01/06 03:59:10 ceres
* Initial revision
*
*/
/**
* This method handles the light changing and control.
* @author Pinkfish
* @change Many
* Lots and lots of changes :)
*/
private nosave int _light;
private nosave int _my_light;
private nosave int _need_recalculate;
private nosave object *_inform_of_change;
void new_recalc_light();
mixed query_property(string name);
void add_property(string name, mixed value);
void remove_property(string name);
void create() {
_inform_of_change = ({ });
} /* create() */
/**
* This returns the total light level of the object. This includes the
* light levels of anything that happens to be inside us.
* @return current light level
* @see query_my_light()
* @see set_light()
*/
int query_light() {
if (_need_recalculate) {
_need_recalculate = 0;
new_recalc_light();
}
return _light;
} /* query_light() */
int query_light_needs_inform() {
return _light || _need_recalculate;
} /* query__light_needs_inform() */
/**
* This method returns the light associated with this object. This does
* not count the light levels of anything inside us.
*/
int query_my_light() { return _my_light; }
/**
* This method forces a recalculation of the current light level in this
* object.
*/
varargs void new_recalc_light() {
object *obs;
object ob;
int tmp_light;
_need_recalculate = 0;
/* How do we do this...? */
/*
* Use the square root of the squares to make the differences not so wild.
*/
_light = _my_light * _my_light;
if (_my_light < 0) _light = -_light;
if ( !this_object()->query_opaque() ) {
obs = all_inventory(this_object());
foreach (ob in obs) {
// If it is opaque, we do not count the light of the contents.
if (ob->query_opaque()) {
tmp_light = ob->query_my_light();
} else {
tmp_light = ob->query_light();
}
if (tmp_light >= 0) _light += tmp_light * tmp_light;
else _light -= tmp_light * tmp_light;
}
}
if (_light >= 0) _light = sqrt(_light);
else _light = -sqrt(-_light);
_inform_of_change->event_light_change(this_object(), 0, _light);
} /* new_recalc_light() */
/**
* This method tells us that the light levels have changed and should
* be recalculated when queried.
* @see inform_of_light_level_change()
*/
void light_level_changed() {
_need_recalculate = 1;
} /* light_level_changed() */
/**
* This method tells all our environments that the light level has
* changed.
* @param ob the object whose environment we should tell about the change
* @see light_level_changed()
*/
void inform_of_light_level_change(object ob) {
if (ob) {
ob->light_level_changed();
}
while (ob && !ob->query_opaque()) {
ob->light_level_changed();
ob = environment(ob);
}
} /* inform_of_light_level_change() */
/**
* This method adds an object to be informed of light change events.
* @param ob the object to be informed of light change events
*/
void add_inform_light_change(object ob) {
_inform_of_change += ({ ob });
} /* add_inform_lifht_change() */
/**
* This method removes an object from the current list of things to
* be informed of a light change.
* @param ob the object to remove from the inform list
*/
void remove_inform_light_change(object ob) {
_inform_of_change -= ({ ob });
} /* remove_inform_light_change() */
/**
* This method makes this object opaque. This means that light does not
* escpae from it.
* @see not_obscured_object()
* @see set_light()
*/
void set_opaque() {
add_property( "opaque", 1 );
} /* set_opaque() */
/**
* This method makes the object transparent (default). This means that the
* light from items inside does escape.
* @see set_opaque()
* @see set_light()
*/
void reset_opaque() {
remove_property( "opaque" );
} /* reset_opaque() */
/**
* This method checks to see if the object is opaque or not.
* @return 1 if it is opaque, 0 if not
*/
int query_opaque() {
return query_property("opaque");
} /* query_opaque() */
/**
* This changes the current light level.
* @param number the amount to chage it by
* @see set_light()
* @see query_my_light()
* @see query_light()
*/
int adjust_light( int number ) {
if (number) {
_my_light += number;
inform_of_light_level_change(this_object());
}
return _light;
} /* adjust_light() */
/**
* This sets the current light level. This method calls adjust_light()
* with the correct value to set the light level.
* <BR><BR>
* Light Levels:
* <BR>
* Magically Darkened Room 0-
* <BR>
* Absolutely Dark Room 0
* <BR>
* Standard Dark Room 5
* <BR>
* Dimly Lit Room 20
* <BR>
* Mine Shaft with Candles 30
* <BR>
* Partially Lit Room 50
* <BR>
* Well Lit Room 60
* <BR>
* Shaded Forest 60
* <BR>
* Brightly Lit Room 80
* <BR>
* Direct Sunlight 100
* <BR>
* Explosion or flash 200+
* <BR>
* @param number The new light level.
* @see query_my_light()
* @see query_light()
*/
int set_light(int number) {
return adjust_light(number - _my_light);
} /* set_light() */
/** @ignore yes */
mixed *stats() {
return ({
({ "light", _light, }),
({ "my light", _my_light, }),
});
} /* stats() */