/
driver3.2@242/autoconf/
driver3.2@242/doc/LPC/
driver3.2@242/hosts/
driver3.2@242/hosts/amiga/NetIncl/
driver3.2@242/hosts/amiga/NetIncl/netinet/
driver3.2@242/hosts/amiga/NetIncl/sys/
driver3.2@242/hosts/atari/
driver3.2@242/hosts/fcrypt/
driver3.2@242/mudlib/
driver3.2@242/mudlib/sys/
driver3.2@242/util/
driver3.2@242/util/indent/hosts/next/
driver3.2@242/util/make_docs/
#include <stdio.h>
#include "config.h"
#include "lint.h"
#include "interpret.h"
#include "object.h"
#include "wiz_list.h"
#include "stralloc.h"

#include "lang.h"
#include "instrs.h"

#ifdef AMIGA
#include "hosts/amiga/ixfile.h"
#endif

/*
 * Maintain the wizards high score list about most popular castle.
 */

extern char *string_copy PROT((char *));

struct wiz_list *all_wiz = 0;
static int number_of_wiz = 0;
int wiz_info_extra_size = -1;

/*
 * Sort the wiz list in ascending order.
 */

static struct wiz_list *insert(w, wl)
    struct wiz_list *w, *wl;
{
    if (wl == 0) {
	w->next = 0;
	return w;
    }
    if (w->score > wl->score) {
	wl->next = insert(w, wl->next);
	return wl;
    }
    w->next = wl;
    return w;
}

static void rebuild_list() {
    struct wiz_list *wl, *w, *new_list = 0;

    for (w = all_wiz; w; w = wl) {
	wl = w->next;
	new_list = insert(w, new_list);
    }
    all_wiz = new_list;
}

/*
 * Find the data, if it exists.
 */
static struct wiz_list *find_wiz(name)
    char *name;
{
    struct wiz_list *wl;

    if ( !( name = findstring(name) ) )
	return 0;
    for (wl = all_wiz; wl; wl = wl->next)
        if (wl->name == name)
	    return wl;
    return 0;
}

/*
 * Check that a name exists. Add it, if it doesn't.
 */
struct wiz_list *add_name(str)
    char *str;
{
    struct wiz_list *wl;

    wl = find_wiz(str);
    if (wl)
        return wl;
    number_of_wiz++;
    wl = (struct wiz_list *)xalloc(sizeof (struct wiz_list));
    str = make_shared_string(str);
    wl->name = str;
    wl->length = strlen(str);
    wl->score = 0;
    wl->cost = 0;
    wl->heart_beats = 0;
    wl->total_worth = 0;
    wl->next = all_wiz;
    wl->size_array = 0;
    wl->mapping_total = 0;
    wl->quota_allowance = 0;
    wl->quota_usage = 0;
    wl->file_name = 0;
    wl->error_message = 0;
    if (wiz_info_extra_size >= 0) {
	wl->extra.type  = T_POINTER;
	wl->extra.u.vec = allocate_array(wiz_info_extra_size);
    } else {
	extern struct svalue const0;

	wl->extra = const0;
    }
    wl->last_call_out = 0;
    all_wiz = wl;
    return wl;
}

/*
 * Add score to an existing name.
 */
void add_score(name, score)
    char *name;
    int score;
{
    struct wiz_list *wl;

    wl = find_wiz(name);
    if (!wl)
        fatal("Add_score: could not find wizard %s\n", name);
    wl->score += score;
}

/*
 * This one is called at every complete walkaround of reset.
 */
void wiz_decay() {
    struct wiz_list *wl;
    static int next_time;
    extern int current_time;

    /* Perform this once every hour. */
    if (next_time > current_time)
	return;
    next_time = current_time + 60 * 60;
    for (wl = all_wiz; wl; wl = wl->next) {
        wl->score = wl->score * 99 / 100;
	wl->total_worth = wl->total_worth * 99 / 100;
	wl->cost = wl->cost * .9;  /* integer is prone to overflow */
	wl->heart_beats = wl->heart_beats * 9 / 10;
    }
}

/*
 * Load the wizlist file.
 */
void load_wiz_file()
{
    char buff[1000];		/* I hate not knowing how much I need. */
    FILE *f;

    f = fopen("WIZLIST", "r");
    if (f == NULL)
        return;
    while(fgets(buff, sizeof buff, f) != NULL) {
        char *p;
	int score;

	p = strchr(buff, ' ');
	if (p == 0) {
	    fprintf(stderr, "Bad WIZLIST file.\n");
	    break;
	}
	*p = '\0';
	p++;
	if (*p == '\0') {
	    fprintf(stderr, "Bad WIZLIST file.\n");
	    break;
	}
	score = atoi(p);
	if (score > 0) {
	    (void)add_name(buff);
	    add_score(buff, atoi(p));
	}
    }
    fclose(f);
}

/*
 * Save the wizlist file.
 */
void save_wiz_file()
{
    struct wiz_list *wl;
    FILE *f;

    f = fopen("WIZLIST", "w");
    if (f == NULL) {
        fprintf(stderr, "Could not open WIZLIST for write\n");
        return;
    }
    for (wl = all_wiz; wl; wl = wl->next)
        fprintf(f, "%s %d %d\n", wl->name, wl->score, wl->total_worth);
    fclose(f);
}

void wizlist(v)
    char *v;
{
    struct wiz_list *wl, *this_wiz;
    int total = 0, num = 0, this_pos, total_wizards;
    extern struct object *command_giver;
    int all = 0;
    struct svalue *name;

    if (!command_giver)
	return;
    if (v == 0) {
	name = apply("query_real_name", command_giver, 0);
	if (!name || name->type != T_STRING)
	    return;
	v = name->u.string;
    }
    if (strcmp(v, "ALL") == 0)
	all = 1;
    this_wiz = find_wiz(v);
    rebuild_list();
    for (num = 0, wl = all_wiz; wl; wl = wl->next) {
        total += wl->score;
	num++;
	if (wl == this_wiz)
	    this_pos = num;
    }
    total_wizards = num;
    add_message("\nWizard top score list\n\n");
    this_pos = num - this_pos + 1;
    if (total == 0)
	total = 1;
    for (wl = all_wiz; wl; wl = wl->next) {
	if (!all && num > 15 && (num < this_pos - 2 || num > this_pos + 2))
		;
	else
	    add_message("%-15s %5d %2d%% (%d)\t[%4dk,%5d] %6d %d\n", wl->name,
			wl->score, wl->score * 100 / total, num,
			wl->cost / 1000,
			wl->heart_beats, wl->total_worth, wl->size_array);
	num--;
    }
    add_message("\nTotal         %7d     (%d)\n\n", total, total_wizards);
}

struct svalue *wizlist_info(sp)
    struct svalue *sp;
{
    struct vector *all, *entry;
    struct svalue *wsvp, *svp;
    struct wiz_list *w;
    extern struct svalue const0;

    if (_privilege_violation("wizlist_info", &const0, sp) <= 0) {
	all = allocate_array(0);
    } else {
	all = allocate_array(number_of_wiz);
	wsvp = all->item;
	for (w = all_wiz; w; w = w->next) {
	    entry = allocate_array(7);
            wsvp->type = T_POINTER;
            wsvp->u.vec = entry;
            wsvp++;
            svp = entry->item;
	    svp->type          = T_STRING;
	    svp->x.string_type = STRING_SHARED;
	    svp->u.string      = w->name;
	    increment_string_ref(w->name);
	    svp++;
	    svp->u.number      = w->score;
	    svp++;
	    svp->u.number      = w->cost;
	    svp++;
	    svp->u.number      = w->heart_beats;
	    svp++;
	    /* reserved for call_out */
	    svp++;
	    svp->u.number      = w->size_array;
	    svp++;
	    if (w->extra.type == T_POINTER) {
		struct vector *v = w->extra.u.vec;
		svp->type  = T_POINTER;
		svp->u.vec = slice_array(v, 0, v->size - 1);
	    } else
		assign_svalue_no_free(svp, &w->extra);
	} /* end for */
    } /* end if */
    sp++;
    sp->type = T_POINTER;
    sp->u.vec = all;
    return sp;
}

struct wiz_list default_wizlist_entry = {
0, /* name */
0, /* length */
0, /* next */
0, /* score */
0, /* cost */
0, /* heart_beats */
0, /* total_worth */
0, /* size_array */
0, /* mapping_total */
{ T_NUMBER }, /* extra */
0, /* quota_allowance */
0, /* quota_usage */
0, /* error file_name */
0, /* error_message */
0, /* error linue_number */
0, /* last_call_out */
0, /* int call_out_cost */
0, /* quota_state */
};

#ifdef MALLOC_smalloc
void clear_ref_from_wiz_list()
{
    struct wiz_list *w;

    for (w = all_wiz; w; w = w->next) {
	clear_ref_in_vector(&w->extra, 1);
    }
    clear_ref_in_vector(&default_wizlist_entry.extra, 1);
}

void count_ref_from_wiz_list()
{
    struct wiz_list *w;

    for (w = all_wiz; w; w = w->next) {
	count_ref_from_string(w->name);
	count_ref_in_vector(&w->extra, 1);
	if(w->file_name)
	    note_malloced_block_ref(w->file_name);
	if (w->error_message)
	    note_malloced_block_ref(w->error_message);
	note_malloced_block_ref((char *)w);
    }
    count_ref_in_vector(&default_wizlist_entry.extra, 1);
}
#endif /* MALLOC_SMALLOC */

#ifdef DEBUG
void count_extra_ref_from_wiz_list()
{
    struct wiz_list *w;

    for (w = all_wiz; w; w = w->next) {
	count_extra_ref_in_vector(&w->extra, 1);
    }
    count_extra_ref_in_vector(&default_wizlist_entry.extra, 1);
}
#endif

int set_extra_wizinfo(wiz, info)
struct svalue *wiz, *info;
{
    struct wiz_list *user;

    if (wiz->type == T_OBJECT) {
	user = wiz->u.ob->user;
    } else if (wiz->type != T_STRING || !(user = find_wiz(wiz->u.string))) {
	if (wiz->type == T_NUMBER && wiz->u.number == 0)
	    user = 0;
	else
	    return -1; /* Bad argument */
    }
    transfer_svalue(user ? &user->extra : &default_wizlist_entry.extra, info);
    return 1; /* Ok. */
}

int get_extra_wizinfo(wiz)
struct svalue *wiz;
{
    struct wiz_list *user;

    if (wiz->type == T_OBJECT) {
	user = wiz->u.ob->user;
    } else if (wiz->type != T_STRING || !(user = find_wiz(wiz->u.string))) {
	if (wiz->type == T_NUMBER && wiz->u.number == 0)
	    user = 0;
	else
	    return -1; /* Bad argument */
    }
    assign_svalue(wiz, user ? &user->extra : &default_wizlist_entry.extra);
    return 1; /* Ok. */
}
void remove_wiz_list() {
    struct wiz_list *wl, *w;

    for (w = all_wiz; w; w = wl) {
	free_string(w->name);
	wl = w->next;
	xfree((char *)w);
    }
}

void save_error(msg, file, line)
    char *msg;
    char *file;
    int line;
{
    struct wiz_list *wl;
    char name[100];
    char *copy, *p;
    int len;

    p = get_wiz_name(file);
    if(!p)
	return;
    strcpy(name, p);
    wl = add_name(name);
    if (wl->file_name)
	xfree(wl->file_name);
    len = strlen(file);
    copy = xalloc(len + 4); /* May add .c plus the null byte, and / */
    *copy = '/';
    strcpy(copy+1, file);
    /*
     * If it is a cloned object, we have to find out what the file
     * name is, and add '.c'.
     */
    if ( (p = strrchr(copy, '#')) ||
        ((p = copy+len), *p++ != 'c') || p[-2] != '.' ) {
	p[0] = '.';
	p[1] = 'c';
	p[2] = '\0';
    }
    wl->file_name = copy;
    if (wl->error_message)
	xfree(wl->error_message);
    wl->error_message = string_copy(msg);
    wl->line_number = line;
}

struct svalue *get_error_file(sp)
    struct svalue *sp;
{
    char *name;
    int forget;
    struct wiz_list *wl;
    struct vector *vec;
    struct svalue *v;

    if (sp[-1].type != T_STRING)
	bad_efun_arg(1, F_GET_ERROR_FILE-F_OFFSET, sp);
    if (sp->type != T_NUMBER)
	bad_efun_arg(2, F_GET_ERROR_FILE-F_OFFSET, sp);
    name = sp[-1].u.string;
    forget = sp->u.number;
    wl = find_wiz(name);
    sp--;
    free_string_svalue(sp);
    /*
     * The error_message is used as a flag if there has been any error.
     */
    if (!wl || !wl->error_message) {
	sp->type = T_NUMBER;
	sp->u.number = 0;
	return sp;
    }
    vec = allocate_array(4);
    v = vec->item;
    v[0].type = T_STRING;
    v[0].x.string_type = STRING_MALLOC;
    v[0].u.string = string_copy(wl->file_name);
    v[1].u.number = wl->line_number & ~0x40000000;
    v[2].type = T_STRING;
    v[2].x.string_type = STRING_MALLOC;
    v[2].u.string = string_copy(wl->error_message);
    v[3].u.number = (wl->line_number & 0x40000000) != 0;
    if (forget)
	wl->line_number |= 0x40000000;
    sp->type = T_POINTER;
    sp->u.vec = vec;
    return sp;
}

/*
 * Argument is a file name, which we want to get the owner of.
 * Ask the master.c object !
 */
char *get_wiz_name(file)
    char *file;
{
    struct svalue *ret;
    static char buff[50];

    push_volatile_string(file);
    ret = apply_master_ob("get_wiz_name", 1);
    if (ret == 0 || ret->type != T_STRING)
	return 0;
    strncpy(buff, ret->u.string, sizeof buff - 1);
    return buff;
}