/* /daemon/soul.c
* from Nightmare IV
* fear a soul from Discworld
* created by Pinkfish@Discworld on an unknown date
* ported to Nightmare doing very little by Descartes of Borg 940207
*/
#include <soul.h>
#include <save.h>
#include <daemons.h>
#include <security.h>
private mapping __Soul;
static private string __Adj, __Chunk;
static private object __CurrentTarget;
static private void become_emotional(mapping info, string adj, object *who);
static private void compile_soul(string str);
static private string compile_message(mixed *parts, object *targets);
static private string remove_whitespace(string str);
static string filter_stuff(mixed *parts, object *targets);
static private void save_soul();
static private void restore_soul();
static string handle_names(object ob);
static private void compile_file(string str);
static private void parse_assoc(mapping borg);
static private mixed parse_chunk();
static private mapping parse_mapping();
static private string *parse_array();
void create() {
string *files;
int i;
if(file_exists(SAVE_SOUL+".o")) restore_soul();
if(!__Soul || !sizeof(__Soul)) {
__Soul = ([]);
i = sizeof(files = get_dir(DIR_SOUL_FILES+"/"));
while(i--) compile_soul(files[i]);
}
call_out("save_soul", 60);
}
object *match_living(string nom) {
object *who;
object ob;
if(!nom || nom == "") return ({});
if(nom == "everyone") {
who = filter_array(all_inventory(environment(this_player())),
(: living :));
return who - ({ this_player() });
}
else if(ob = present(lower_case(nom), environment(this_player())))
return (hiddenp(ob) || ob == this_player()) ? ({}) : ({ ob });
else return ({});
}
varargs string match_adj(string str, mapping data1, mapping data2) {
string a, b;
a = (data1["adverbs"] ? data1["adverbs"] : "");
b = (data2["adverbs"] ? data2["adverbs"] : "");
if(str == "" && b[0] == '#' && strlen(b) > 2) b = b[2..strlen(b)-1];
if(a[0] == '#' || b[0] == '#') return str;
if(sscanf(sprintf(",%s,%s,", b, a), "%s,"+str+"%s,", a, b)) {
if(b && strlen(b)) return sprintf("%s%s", str, b);
else return str;
}
return 0;
}
int do_cmd(string verb, string arg) {
mapping data, info;
object *target;
string *args;
string adj;
if(!(data = __Soul[verb])) return 0;
target = ({});
if(!arg) {
info = data["noargs"];
adj = "nothing";
args = ({ arg = "" });
}
if(!info) {
if(!args) {
args = explode(arg, " ");
}
if(data["prepositions"]) args = args - (string *)data["prepositions"];
arg = implode(args, " ");
if(sizeof(args) == 1) {
if(!sizeof(target = match_living(arg))) {
if(!(info = data["undirected"])) {
message("emote", sprintf("%s whom?", capitalize(verb)),
this_player());
return 1;
}
adj = match_adj(arg, data, info);
}
else {
if(!(info = data["directed"]))
return notify_fail("That makes no sense.\n");
adj = match_adj("", data, info);
}
}
else {
if(sizeof(target = match_living(args[0]))) {
if(!(info = data["directed"]))
return notify_fail("That makes no sense.\n");
adj = match_adj(implode(args[1..sizeof(args)-1]," "),data,info);
}
else {
if(sizeof(target = match_living(args[sizeof(args)-1]))) {
if(!(info = data["directed"]))
return notify_fail("That makes no sense.\n");
adj = match_adj(implode(args[0..sizeof(args)-2], " "),
data, info);
}
else {
if(!(info = data["undirected"])) {
message("emote", sprintf("%s whom?", capitalize(verb)),
this_player());
return 1;
}
adj = match_adj(arg, data, info);
}
}
}
}
if(!adj) {
message("emote", sprintf("What an odd way in which to %s!", verb),
this_player());
return 1;
}
become_emotional(info, adj, target);
return 1;
}
void become_emotional(mapping info, string adj, object *who) {
string cmd;
int i;
__Adj = adj;
__CurrentTarget = 0;
message("emote", compile_message(info["mymsg"], who), this_player());
if(!who || !sizeof(who))
message("emote", compile_message(info["theirmsg"], ({})),
environment(this_player()), ({ this_player() }));
else message("emote", compile_message(info["theirmsg"], who),
environment(this_player()), ({ this_player() }) + who);
i = sizeof(who);
while(i--) {
__CurrentTarget = who[i];
if(info["obmsg"])
message("emote", compile_message(info["obmsg"], who), who[i]);
else message("emote", compile_message(info["theirmsg"], who), who[i]);
}
}
void compile_soul(string str) {
compile_file(sprintf("%s/%s", DIR_SOUL_FILES, str));
}
string compile_message(mixed *parts, object *targets) {
return filter_stuff(parts, targets);
}
string compile_names(object *who) {
int x;
if((x = sizeof(who)) == 1) return handle_names(who[0]);
else return implode(map_array(who[1..x-1], "handle_names", this_object()),
", ") + " and " + handle_names(who[0]);
}
static void save_soul() {
save_object(SAVE_SOUL);
}
static private void restore_soul() {
restore_object(SAVE_SOUL);
}
string filter_stuff(mixed *parts, object *targets) {
string *arr;
arr = map_array(parts, "handle_part", this_object(), targets) - ({ "" });
return implode(arr, " ");
}
string handle_names(object ob) {
if(!ob) return "";
if(ob == __CurrentTarget) return "you";
else return (string)ob->query_cap_name();
}
string handle_part(mixed part, object *targets) {
if(stringp(part)) return part;
else switch(part) {
case ADJ: return __Adj;
case TP_NAME: return (string)this_player()->query_cap_name();
case TP_PRONOUN: return nominative(this_player());
case TP_POSSESSIVE: return possessive(this_player());
case TP_NPOSS: return possessive_noun(this_player());
case TP_FOO: return reflexive(this_player());
case OB_NAME: return compile_names(targets);
case OB_PRONOUN: return nominative(targets[0]);
case OB_POSSESSIVE: return possessive(targets[0]);
case OB_NPOSS: return possessive_noun(targets[0]);
case OB_FOO: return reflexive(targets[0]);
}
return part + "";
}
mapping query_soul() { return copy(__Soul); }
static private void compile_file(string file) {
string *cles;
if(!(file = read_file(file))) error("Failed to read file.\n");
file = replace_string(file, "\t", "");
cles = map_array(explode(file, "\n"), "remove_indentation", this_object());
filter_array(explode(implode(cles, ""), "$$"), "decode_file",this_object());
}
static void decode_file(string str) {
call_out("define_action", 0, str);
}
static void define_action(string str) {
__Chunk = remove_whitespace(str);
parse_assoc(__Soul);
}
static private void parse_assoc(mapping borg) {
string str;
mixed val;
if(sscanf(__Chunk, "(%s %s", str, __Chunk) < 2)
error("Syntax error compiling file in parse_assoc().\n");
val = parse_chunk();
__Chunk = __Chunk[1..strlen(__Chunk)-1];
borg[str] = val;
}
static private mixed parse_chunk() {
string str;
__Chunk = remove_whitespace(__Chunk);
switch(__Chunk[0]) {
case '*': return parse_mapping();
case '[': return parse_array();
case '(': return error("Syntax error compiling file in parse_chunk().\n");
}
if(sscanf(__Chunk, "%s)%s", str, __Chunk) == 2) return str;
error("sscanf() failed in parse_chunk().\n");
}
static private mapping parse_mapping() {
mapping borg;
int i;
borg = ([]);
if(!sscanf(__Chunk, "*(%s", __Chunk))
error("Failed: sscanf() in parse_mapping().\n");
while((__Chunk = remove_whitespace(__Chunk))[0] != ')') parse_assoc(borg);
__Chunk = __Chunk[1..strlen(__Chunk)-1];
return borg;
}
static private string *parse_array() {
string str;
if(sscanf(__Chunk, "[%s]%s", str, __Chunk) != 2)
error("Failed: sscanf() in parse_array().\n");
return map_array(explode(str, " "), "fix_macros", this_object());
}
static mixed fix_macros(string foo) {
if(foo[0] == '$') {
switch(foo) {
case "$ADJ": return ADJ;
case "$TP_NAME": return TP_NAME;
case "$OB_NAME": return OB_NAME;
case "$TP_PRONOUN": return TP_PRONOUN;
case "$OB_PRONOUN": return OB_PRONOUN;
case "$TP_POSS": return TP_POSSESSIVE;
case "$OB_POSS": return OB_POSSESSIVE;
case "$TP_NPOSS": return TP_NPOSS;
case "$OB_NPOSS": return OB_NPOSS;
case "$TP_FOO": return TP_FOO;
case "$OB_FOO": return OB_FOO;
}
}
return foo;
}
static string remove_indentation(string str) {
str = remove_whitespace(str);
if(!(['(': 1, '[':1, '*':1 ])[str[0]]) return str;
else return sprintf(" %s", str);
}
void recompile_soul() {
string *files;
int i;
__Soul = ([]);
i = sizeof(files = get_dir(DIR_SOUL_FILES+"/"));
while(i--) compile_soul(files[i]);
save_soul();
}
static private string remove_whitespace(string str) {
while(sscanf(str, " %s", str));
sscanf(str, " %s", str);
sscanf(str, " %s", str);
return str;
}