#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; }