/*
* transient.c - reaction object, resulting from the mixing of two
* substances.
*
* The following pseudo-objects may be used in progress strings:
* #obj# - replaced by the filename of this object (virtual objects
* don't seem to handle file_name correctly)
* #env# - replaced by the filename of the environment
* #env2# - replaced by the filename of the environment of the environment
* #result# - replaced by the filename of the result object
*/
// This use to be /obj/cont_medium, but /obj/food has more features
inherit "/obj/food";
#include <move_failures.h>
// Default amount per unit weight (for setting weight of non-continuous
// items)
#define AMT_PER_WGT 200
// progress_msg is an array of data structures of the form:
// ({({ msg_1, ({function_str1a, function_str1b, ...})}),
// ({ msg_2, ({function_str2a, function_str2b, ...})}),
// ...
// })
// At interval n, msg_n is printed out and function_strnx is called, after
// having the substitutions above performed and being passed through
// process_string. This should give plenty of functionality (if not, I
// can always add more :).
mixed *progress_msg = ({});
int duration, interval, counter, hp_base;
float result_amt;
string result, result_alias;
string final = "boom";
int in_progress;
void set_progress_msg(mixed *msg) { progress_msg = msg; }
void set_final(string s) { final = s; }
void set_result(string s) { result = s; }
void set_result_alias(string s) { result_alias = s; }
void set_result_amt(float amt) { result_amt = amt; }
void set_duration(int time) {
// NOTE that this must be called after the progress_msg has been set
duration = time;
if (sizeof(progress_msg)) {
interval = duration / sizeof(progress_msg);
} else {
interval = duration;
}
}
void add_progress_msg(mixed *msg) {
progress_msg += ({msg});
set_duration(duration); // calculate new interval
}
// Note: hp_base is hps of damage done per unit. If it's being carried
// by a living thing, it does full damage. Otherwise, it does 1/5 damage
// to everyone in the room (sort of an arbitrary decision, but I'm trying
// to keep the number of parameters down).
void set_hp_base(int hp) { hp_base = hp; }
void start_reaction() {
/*
* NOTE: this is the function that sets off the call_outs. Call it
* after everything else has been set up.
*/
if (sizeof(progress_msg) > 1) {
call_out("progress", interval);
} else {
call_out(final, interval);
}
in_progress = 1;
}
void stop_reaction() {
if (counter < sizeof(progress_msg)-1) {
remove_call_out("progress");
} else {
remove_call_out(final);
}
in_progress = 0;
}
void restart_reaction() {
if (counter < sizeof(progress_msg)-1) {
call_out("progress", interval);
} else {
call_out(final, interval);
}
in_progress = 1;
}
void progress() {
object env, env2;
string msg, fcn;
int i;
env = environment(this_object());
env2 = environment(env);
if (progress_msg[counter][0]) {
msg = replace(progress_msg[counter][0],
({"#env#", file_name(env),
"#env2#", env2?file_name(env2):0,
"#obj#", file_name(this_object()),
"#result#", ""}));
msg = process_string(msg);
tell_room(env2, msg);
}
if (progress_msg[counter][1]) {
for (i = 0; i < sizeof(progress_msg[counter][1]); i++) {
fcn = replace(progress_msg[counter][1][i],
({"#env#", file_name(env),
"#env2#", env2?file_name(env2):0,
"#obj#", file_name(this_object()),
"#result#", ""}));
process_string("@@"+fcn+"@@");
}
}
counter++;
if (counter < sizeof(progress_msg)-1) {
call_out("progress", interval);
} else {
call_out(final, interval);
}
}
void boom() {
object env, env2, cont, new_env;
object *victims, *contents;
object result_ob;
int hp, i, amt, tmp;
string msg, fcn;
// Assume substance is in a container
env = environment(this_object());
env2 = environment(env);
amt = query_amount();
if (living(env)) {
// Held by a living
hp = hp_base*amt;
env->adjust_hp(-hp);
} else if (living(env2)) {
// In a container held by a living
hp = (hp_base*amt)/2;
env2->adjust_hp(-hp);
} else if (env->query_co_ord()) {
// Sitting in a room
hp = (hp_base*amt)/2;
victims = all_inventory(env);
for (i = 0; i < sizeof(victims); i++) {
if (living(victims[i])) {
victims[i]->adjust_hp(-hp);
}
}
} else if (env2->query_co_ord()) {
// Sitting in a container in a room
hp = (hp_base*amt)/5;
victims = all_inventory(env2);
for (i = 0; i < sizeof(victims); i++) {
if (living(victims[i])) {
victims[i]->adjust_hp(-hp);
}
}
}
if (result) {
result_ob = clone_object(result);
if (result_alias) {
// result_alias should be 0 if this isn't a cont_medium
result_ob->set_medium_alias(result_alias);
}
if (function_exists("set_amount", result_ob)) {
result_ob->set_amount(to_int(result_amt*query_amount()));
} else if (result_amt > 0.0) {
result_ob->set_weight(to_int(result_amt*query_amount()/AMT_PER_WGT));
}
}
if (sizeof(progress_msg)) {
if (progress_msg[counter][0]) {
msg = replace(progress_msg[counter][0],
({"#env#", file_name(env),
"#env2#", env2?file_name(env2):0,
"#obj#", file_name(this_object()),
"#result#", result_ob?file_name(result_ob):0}));
msg = process_string(msg);
tell_room(env2, msg);
}
if (progress_msg[counter][1]) {
for (i = 0; i < sizeof(progress_msg[counter][1]); i++) {
fcn = replace(progress_msg[counter][1][i],
({"#env#", file_name(env),
"#env2#", env2?file_name(env2):0,
"#obj#", file_name(this_object()),
"#result#", ""}));
process_string("@@"+fcn+"@@");
}
}
}
move("/room/void");
// Destroy container (unless living or a room) and move contents
// up.
contents = all_inventory(env);
if (result_ob) contents += ({result_ob});
for (i = 0; i < sizeof(contents); i++) {
if (contents[i]->query_continuous()) {
contents[i]->dest_me();
continue;
}
new_env = env2;
while (new_env && ((tmp=contents[i]->move(new_env)) != MOVE_OK)) {
new_env = environment(new_env);
}
if (!new_env) contents[i]->dest_me();
}
if (!living(env) && !function_exists("query_co_ord", env)) {
env->dest_me();
}
call_out("dest_me", 0);
}
object morph() {
// Returns the object created...
object env, env2, result_ob, new_env, *contents;
string msg, fcn;
int i, mv_stat;
env = environment(this_object());
env2 = environment(env);
// Need to move out of the container to make room
move("/room/void");
if (stringp(result)) {
result_ob = clone_object(result);
if (stringp(result_alias)) {
// result_alias should be 0 if this isn't a cont_medium
result_ob->set_medium_alias(result_alias);
result_ob->set_amount(to_int(result_amt*query_amount()));
} else if (result_amt > 0.0) {
result_ob->set_weight(to_int(result_amt*query_amount()/AMT_PER_WGT));
}
mv_stat = result_ob->move(env);
if (mv_stat) {
//write("Uh oh, move error: " + mv_stat + "\n");
// Destroy container (unless living or a room) and contents.
contents = all_inventory(env);
for (i = 0; i < sizeof(contents); i++) {
contents[i]->dest_me();
}
if (!living(env) && !function_exists("query_co_ord", env)) {
tell_room(env2, "The " + env->short(0) +
" explodes, splattering the contents all over.\n");
env->dest_me();
}
result_ob->dest_me();
result_ob = 0;
}
}
if (sizeof(progress_msg)) {
if (progress_msg[counter][0]) {
msg = replace(progress_msg[counter][0],
({"#env#", env?file_name(env):0,
"#env2#", env2?file_name(env2):0,
"#obj#", file_name(this_object()),
"#result#", result_ob?file_name(result_ob):0}));
msg = process_string(msg);
tell_room(env2, msg);
}
if (progress_msg[counter][1]) {
for (i = 0; i < sizeof(progress_msg[counter][1]); i++) {
fcn = replace(progress_msg[counter][1][i],
({"#env#", env?file_name(env):0,
"#env2#", env2?file_name(env2):0,
"#obj#", file_name(this_object()),
"#result#", result_ob?file_name(result_ob):0}));
process_string("@@"+fcn+"@@");
}
}
}
call_out("dest_me", 0);
return result_ob;
}
string query_pounds() { return "about " + ::query_weight()/9; }
void query_progress_msg() {
int i, j;
write("({\n");
for (i = 0; i < sizeof(progress_msg); i++) {
write(progress_msg[i][0] + " ({\n");
if (!progress_msg[i][0]) {
write("0})\n");
} else {
for (j = 0; j < sizeof(progress_msg[i][1]); j++) {
write(progress_msg[i][1][j] + "\n");
}
write("})\n");
}
}
}
mixed stats() {
return ::stats() + ({
({ "duration", duration }),
({ "interval", interval }),
({ "counter", counter }),
({ "hp base", hp_base }),
({ "result amt", result_amt }),
({ "result", result }),
({ "result alias", result_alias }),
({ "final", final }),
({ "in progress", in_progress }),
});
} /* stats() */
mapping query_dynamic_auto_load() {
return ([
"::": ::query_dynamic_auto_load(),
"progress_msg" : progress_msg,
"duration" : duration,
"interval" : interval,
"counter" : counter,
"hp_base" : hp_base,
"result_amt" : result_amt,
"result" : result,
"result_alias" : result_alias,
"final" : final,
"in_progress" : in_progress,
]);
} /* query_dynamic_auto_load() */
void init_dynamic_arg(mapping args) {
if (args["::"])
::init_dynamic_arg(args["::"]);
if (!undefinedp(args["progress_msg"]))
progress_msg = args["progress_msg"];
if (!undefinedp(args["duration"]))
duration = args["duration"];
if (!undefinedp(args["interval"]))
interval = args["interval"];
if (!undefinedp(args["counter"]))
counter = args["counter"];
if (!undefinedp(args["hp_base"]))
hp_base = args["hp_base"];
if (!undefinedp(args["result_amt"]))
result_amt = args["result_amt"];
if (!undefinedp(args["result"]))
result = args["result"];
if (!undefinedp(args["result_alias"]))
result_alias = args["result_alias"];
if (!undefinedp(args["final"]))
final = args["final"];
if (!undefinedp(args["in_progress"])) {
in_progress = args["in_progress"];
if (in_progress)
restart_reaction();
}
} /* init_dynamic_arg() */
mapping int_query_static_auto_load() {
return ([
"::": ::int_query_static_auto_load(),
]);
} /* int_query_static_auto_load() */
mapping query_static_auto_load() {
if ( file_name( this_object() )[ 0 .. 22 ] == "/obj/reagents/transient" )
return int_query_static_auto_load();
return 0;
} /* query_static_auto_load() */
void init_static_arg( mapping map ) {
if ( map[ "::" ] )
::init_static_arg( map[ "::" ] );
} /* init_static_arg() */