/** * Handle a "-d<dir>=<path>" option. * * Sets any of angband's special directories to <path>. * * The "<path>" can be any legal path for the given system, and should * not end in any special path separator (i.e. "/tmp" or "~/.ang-info"). */ static void change_path(const char *info) { char *info_copy = NULL; char *path = NULL; char *dir = NULL; unsigned int i = 0; char dirpath[512]; if (!info || !info[0]) quit_fmt("Try '-d<dir>=<path>'.", info); info_copy = string_make(info); path = strtok(info_copy, "="); dir = strtok(NULL, "="); for (i = 0; i < N_ELEMENTS(change_path_values); i++) { if (my_stricmp(path, change_path_values[i].name) == 0) { #ifdef SETGID if (!change_path_values[i].setgid_ok) quit_fmt("Can't redefine path to %s dir on multiuser setup", path); #endif string_free(*change_path_values[i].path); *change_path_values[i].path = string_make(dir); /* the directory may not exist and may need to be created. */ path_build(dirpath, sizeof(dirpath), dir, ""); if (!dir_create(dirpath)) quit_fmt("Cannot create '%s'", dirpath); return; } } quit_fmt("Unrecognised -d paramater %s", path); }
/* * Handle a "-d<what>=<path>" option * * The "<what>" can be any string starting with the same letter as the * name of a subdirectory of the "lib" folder (i.e. "i" or "info"). * * The "<path>" can be any legal path for the given system, and should * not end in any special path separator (i.e. "/tmp" or "~/.ang-info"). */ static void change_path(const char *info) { if (!info || !info[0]) quit_fmt("Try '-d<path>'.", info); string_free(ANGBAND_DIR_USER); ANGBAND_DIR_USER = string_make(info); }
/* More angband-specific bits of the parser * These require hooks into other parts of the code, and are a candidate for * moving elsewhere. */ static void print_error(struct file_parser *fp, struct parser *p) { struct parser_state s; parser_getstate(p, &s); msg("Parse error in %s line %d column %d: %s: %s", fp->name, s.line, s.col, s.msg, parser_error_str[s.error]); message_flush(); quit_fmt("Parse error in %s line %d column %d.", fp->name, s.line, s.col); }
/* * Handle a "-d<what>=<path>" option * * The "<what>" can be any string starting with the same letter as the * name of a subdirectory of the "lib" folder (i.e. "i" or "info"). * * The "<path>" can be any legal path for the given system, and should * not end in any special path separator (i.e. "/tmp" or "~/.ang-info"). */ static void change_path(cptr info) { if (!info || !info[0]) quit_fmt("Try '-d<path>'.", info); string_free(reposband_DIR_USER); reposband_DIR_USER = string_make(info); }
static void print_error(struct file_parser *fp, struct parser *p) { struct parser_state s; parser_getstate(p, &s); msg("Parse error in %s line %d column %d: %s: %s", fp->name, s.line, s.col, s.msg, parser_error_str[s.error]); event_signal(EVENT_MESSAGE_FLUSH); quit_fmt("Parse error in %s line %d column %d.", fp->name, s.line, s.col); }
/* * Process the player name and extract a clean "base name". * * If "sf" is TRUE, then we initialize "savefile" based on player name. * * Some platforms (Windows, Macintosh, Amiga) leave the "savefile" empty * when a new character is created, and then when the character is done * being created, they call this function to choose a new savefile name. * * This also now handles the turning on and off of the automatic * sequential numbering of character names with Roman numerals. */ void process_player_name(bool sf) { int i; /* Process the player name */ for (i = 0; op_ptr->full_name[i]; i++) { char c = op_ptr->full_name[i]; /* No control characters */ if (iscntrl((unsigned char)c)) { /* Illegal characters */ quit_fmt("Illegal control char (0x%02X) in player name", c); } /* Convert all non-alphanumeric symbols */ if (!isalpha((unsigned char)c) && !isdigit((unsigned char)c)) c = '_'; /* Build "base_name" */ op_ptr->base_name[i] = c; } #if defined(WINDOWS) /* Max length */ if (i > 8) i = 8; #endif /* Terminate */ op_ptr->base_name[i] = '\0'; /* Require a "base" name */ if (!op_ptr->base_name[0]) { my_strcpy(op_ptr->base_name, "PLAYER", sizeof(op_ptr->base_name)); } /* Pick savefile name if needed */ if (sf) { char temp[128]; #if defined(SET_UID) /* Rename the savefile, using the player_uid and base_name */ strnfmt(temp, sizeof(temp), "%d.%s", player_uid, op_ptr->base_name); #else /* Rename the savefile, using the base name */ strnfmt(temp, sizeof(temp), "%s", op_ptr->base_name); #endif /* Build the filename */ path_build(savefile, sizeof(savefile), reposband_DIR_SAVE, temp); } }
static struct parser_value *parser_getval(struct parser *p, const char *name) { struct parser_value *v; for (v = p->fhead; v; v = (struct parser_value *)v->spec.next) { if (!strcmp(v->spec.name, name)) { return v; } } quit_fmt("parser_getval error: name is %s\n", name); return 0; /* Needed to avoid Windows compiler warning */ }
/* * Create any missing directories. We create only those dirs which may be * empty (user/, save/, apex/, info/, help/). The others are assumed * to contain required files and therefore must exist at startup * (edit/, pref/, file/, xtra/). * * ToDo: Only create the directories when actually writing files. */ void create_needed_dirs(void) { char dirpath[512]; path_build(dirpath, sizeof(dirpath), ANGBAND_DIR_USER, ""); if (!dir_create(dirpath)) quit_fmt("Cannot create '%s'", dirpath); path_build(dirpath, sizeof(dirpath), ANGBAND_DIR_SAVE, ""); if (!dir_create(dirpath)) quit_fmt("Cannot create '%s'", dirpath); path_build(dirpath, sizeof(dirpath), ANGBAND_DIR_APEX, ""); if (!dir_create(dirpath)) quit_fmt("Cannot create '%s'", dirpath); path_build(dirpath, sizeof(dirpath), ANGBAND_DIR_INFO, ""); if (!dir_create(dirpath)) quit_fmt("Cannot create '%s'", dirpath); path_build(dirpath, sizeof(dirpath), ANGBAND_DIR_HELP, ""); if (!dir_create(dirpath)) quit_fmt("Cannot create '%s'", dirpath); }
static errr finish_parse_r(struct parser *p) { struct monster_race *r, *n; size_t i; /* scan the list for the max id */ z_info->r_max -= 1; /*z_info->r_max = 0; fails to load existing save file because of * too high value in old limits.txt. Change to this line when save file * compatibility changes and remove line from limits.txt */ r = parser_priv(p); while (r) { if (r->ridx > z_info->r_max) z_info->r_max = r->ridx; r = r->next; } /* allocate the direct access list and copy the data to it */ r_info = mem_zalloc((z_info->r_max+1) * sizeof(*r)); for (r = parser_priv(p); r; r = n) { memcpy(&r_info[r->ridx], r, sizeof(*r)); n = r->next; if (n) r_info[r->ridx].next = &r_info[n->ridx]; else r_info[r->ridx].next = NULL; mem_free(r); } z_info->r_max += 1; /* convert friend names into race pointers */ for (i = 0; i < z_info->r_max; i++) { struct monster_race *r = &r_info[i]; struct monster_friends *f; for (f = r->friends; f; f = f->next) { if (!my_stricmp(f->name, "same")) f->race = r; else f->race = lookup_monster(f->name); if (!f->race) quit_fmt("Monster '%s' has friend '%s' but I couldn't find any monster of that name", r->name, f->name); string_free(f->name); } } eval_r_power(r_info); parser_destroy(p); return 0; }
const struct magic_realm *lookup_realm(const char *name) { struct magic_realm *realm = realms; while (realm) { if (!my_stricmp(name, realm->name)) { return realm; } realm = realm->next; } /* Fail horribly */ quit_fmt("Failed to find %s magic realm", name); return realm; }
/* * Display a parser error message. */ static void display_parse_error(cptr filename, errr err, cptr buf) { cptr oops; /* Error string */ oops = (((err > 0) && (err < PARSE_ERROR_MAX)) ? err_str[err] : "unknown"); /* Oops */ msg_format("Error at line %d of '%s.txt'.", error_line, filename); msg_format("Record %d contains a '%s' error.", error_idx, oops); msg_format("Parsing '%s'.", buf); message_flush(); /* Quit */ quit_fmt("Error in '%s.txt' file.", filename); }
/** * Find a terrain feature index by name */ static int lookup_feat(const char *name) { int i; /* Look for it */ for (i = 0; i < z_info->f_max; i++) { struct feature *feat = &f_info[i]; if (!feat->name) continue; /* Test for equality */ if (streq(name, feat->name)) return i; } /* Fail horribly */ quit_fmt("Failed to find terrain feature %s", name); return -1; }
bool flag_has_dbg(const bitflag *flags, const size_t size, const int flag, const char *fi, const char *fl) { const size_t flag_offset = FLAG_OFFSET(flag); const int flag_binary = FLAG_BINARY(flag); if (flag == FLAG_END) return FALSE; if (flag_offset >= size) { quit_fmt("Error in flag_has(%s, %s): FlagID[%d] Size[%u] FlagOff[%u] FlagBV[%d]\n", fi, fl, flag, (unsigned int) size, (unsigned int) flag_offset, flag_binary); } assert(flag_offset < size); if (flags[flag_offset] & flag_binary) return TRUE; return FALSE; }
/** * Move an object from a floor pile to the player's gear */ static void player_pickup_aux(struct object *obj, bool domsg) { /* Confirm the object can be picked up*/ if (!inven_carry_okay(obj)) quit_fmt("Failed pickup of %s", obj->kind->name); /* Set ignore status */ player->upkeep->notice |= PN_IGNORE; /* Automatically sense artifacts */ object_sense_artifact(obj); /* Log artifacts if found */ if (obj->artifact) history_add_artifact(obj->artifact, object_is_known(obj), TRUE); /* Carry the object */ square_excise_object(cave, player->py, player->px, obj); inven_carry(player, obj, domsg); }
bool flag_on_dbg(bitflag *flags, const size_t size, const int flag, const char *fi, const char *fl) { const size_t flag_offset = FLAG_OFFSET(flag); const int flag_binary = FLAG_BINARY(flag); /* EFG this assert needs to be in most functions, or else the need for * it removed. Without it, got a crash with no ability to backtrace. */ assert (flag >= FLAG_START); if (flag_offset >= size) { quit_fmt("Error in flag_on(%s, %s): FlagID[%d] Size[%u] FlagOff[%u] FlagBV[%d]\n", fi, fl, flag, (unsigned int) size, (unsigned int) flag_offset, flag_binary); } assert(flag_offset < size); if (flags[flag_offset] & flag_binary) return FALSE; flags[flag_offset] |= flag_binary; return TRUE; }
static enum parser_error parse_rb_f(struct parser *p) { struct monster_base *rb = parser_priv(p); char *flags; char *s; if (!rb) return PARSE_ERROR_MISSING_RECORD_HEADER; if (!parser_hasval(p, "flags")) return PARSE_ERROR_NONE; flags = string_make(parser_getstr(p, "flags")); s = strtok(flags, " |"); while (s) { if (grab_flag(rb->flags, RF_SIZE, r_info_flags, s)) { mem_free(flags); quit_fmt("bad f-flag: %s", s); return PARSE_ERROR_INVALID_FLAG; } s = strtok(NULL, " |"); } mem_free(flags); return PARSE_ERROR_NONE; }
/** * List all savefiles this player can access. */ static void list_saves(void) { char fname[256]; ang_dir *d = my_dopen(ANGBAND_DIR_SAVE); #ifdef SETGID char uid[10]; strnfmt(uid, sizeof(uid), "%d.", player_uid); #endif if (!d) quit_fmt("Can't open savefile directory"); printf("Savefiles you can use are:\n"); while (my_dread(d, fname, sizeof fname)) { char path[1024]; const char *desc; #ifdef SETGID /* Check that the savefile name begins with the user'd ID */ if (strncmp(fname, uid, strlen(uid))) continue; #endif path_build(path, sizeof path, ANGBAND_DIR_SAVE, fname); desc = savefile_get_description(path); if (desc) printf(" %-15s %s\n", fname, desc); else printf(" %-15s\n", fname); } my_dclose(d); printf("\nUse angband -u<name> to use savefile <name>.\n"); }
static enum parser_error parse_r_s(struct parser *p) { struct monster_race *r = parser_priv(p); char *flags; char *s; int pct; int ret = PARSE_ERROR_NONE; if (!r) return PARSE_ERROR_MISSING_RECORD_HEADER; flags = string_make(parser_getstr(p, "spells")); s = strtok(flags, " |"); while (s) { if (1 == sscanf(s, "1_IN_%d", &pct)) { if (pct < 1 || pct > 100) { ret = PARSE_ERROR_INVALID_SPELL_FREQ; break; } r->freq_spell = 100 / pct; r->freq_innate = r->freq_spell; } else { if (grab_flag(r->spell_flags, RSF_SIZE, r_info_spell_flags, s)) { quit_fmt("bad sf-flag: %s", s); ret = PARSE_ERROR_INVALID_FLAG; break; } } s = strtok(NULL, " |"); } /* Add the "base monster" flags to the monster */ if (r->base) rsf_union(r->spell_flags, r->base->spell_flags); mem_free(flags); return ret; }
/* * Read a Win32 BMP file. * * Assumes that the bitmap has a size such that no padding is needed in * various places. Currently only handles bitmaps with 3 to 256 colors. */ static byte *ReadBMP(char *Name, int *bw, int *bh) { FILE *f; BITMAPFILEHEADER fileheader; BITMAPINFOHEADER infoheader; byte *Data; int ncol; int total; int i; u16b x, y; /* Open the BMP file */ f = fopen(Name, "r"); /* No such file */ if (!f) { quit ("No bitmap to load!"); } /* Read the "BITMAPFILEHEADER" */ rd_u16b(f, &(fileheader.bfType)); rd_u32b(f, &(fileheader.bfSize)); rd_u16b(f, &(fileheader.bfReserved1)); rd_u16b(f, &(fileheader.bfReserved2)); rd_u32b(f, &(fileheader.bfOffBits)); /* Read the "BITMAPINFOHEADER" */ rd_u32b(f, &(infoheader.biSize)); rd_u32b(f, &(infoheader.biWidth)); rd_u32b(f, &(infoheader.biHeight)); rd_u16b(f, &(infoheader.biPlanes)); rd_u16b(f, &(infoheader.biBitCount)); rd_u32b(f, &(infoheader.biCompresion)); rd_u32b(f, &(infoheader.biSizeImage)); rd_u32b(f, &(infoheader.biXPelsPerMeter)); rd_u32b(f, &(infoheader.biYPelsPerMeter)); rd_u32b(f, &(infoheader.biClrUsed)); rd_u32b(f, &(infoheader.biClrImportand)); /* Verify the header */ if (feof(f) || (fileheader.bfType != 19778) || (infoheader.biSize != 40)) { quit_fmt("Incorrect BMP file format %s", Name); } /* The two headers above occupy 54 bytes total */ /* The "bfOffBits" field says where the data starts */ /* The "biClrUsed" field does not seem to be reliable */ /* Compute number of colors recorded */ ncol = (fileheader.bfOffBits - 54) / 4; for (i = 0; i < ncol; i++) { RGBQUAD clrg; /* Read an "RGBQUAD" */ rd_byte(f, &(clrg.b)); rd_byte(f, &(clrg.g)); rd_byte(f, &(clrg.r)); rd_byte(f, &(clrg.filler)); /* Analyze the color */ pal[i * 3] = clrg.b; pal[i * 3 + 1] = clrg.g; pal[i * 3 + 2] = clrg.r; } /* Look for illegal bitdepths. */ if ((infoheader.biBitCount == 1) || (infoheader.biBitCount == 24)) { quit_fmt("Illegal biBitCount %d in %s", infoheader.biBitCount, Name); } /* Determine total bytes needed for image */ total = infoheader.biWidth * (infoheader.biHeight + 2); /* Allocate image memory */ C_MAKE(Data, total, byte); for (y = 0; y < infoheader.biHeight; y++) { int y2 = infoheader.biHeight - y - 1; for (x = 0; x < infoheader.biWidth; x++) { int ch = getc(f); /* Verify not at end of file XXX XXX */ if (feof(f)) quit_fmt("Unexpected end of file in %s", Name); if (infoheader.biBitCount == 8) { Data[x + y2 * infoheader.biWidth] = ch; } else if (infoheader.biBitCount == 4) { Data[x + y2 * infoheader.biWidth] = ch / 16; x++; Data[x + y2 * infoheader.biWidth] = ch % 16; } } } fclose(f); /* Save the size for later */ *bw = infoheader.biWidth; *bh = infoheader.biHeight; return (Data); }
/* * Handle a "-d<what>=<path>" option * * The "<what>" can be any string starting with the same letter as the * name of a subdirectory of the "lib" folder (i.e. "i" or "info"). * * The "<path>" can be any legal path for the given system, and should * not end in any special path separator (i.e. "/tmp" or "~/.ang-info"). */ static void change_path(cptr info) { cptr s; /* Find equal sign */ s = strchr(info, '='); /* Verify equal sign */ if (!s) quit_fmt("Try '-d<what>=<path>' not '-d%s'", info); /* Analyze */ switch (tolower(info[0])) { case 'a': { string_free(ANGBAND_DIR_APEX); ANGBAND_DIR_APEX = string_make(s+1); break; } case 'f': { string_free(ANGBAND_DIR_FILE); ANGBAND_DIR_FILE = string_make(s+1); break; } case 'h': { string_free(ANGBAND_DIR_HELP); ANGBAND_DIR_HELP = string_make(s+1); break; } case 'i': { string_free(ANGBAND_DIR_INFO); ANGBAND_DIR_INFO = string_make(s+1); break; } case 'u': { string_free(ANGBAND_DIR_USER); ANGBAND_DIR_USER = string_make(s+1); break; } case 'x': { string_free(ANGBAND_DIR_XTRA); ANGBAND_DIR_XTRA = string_make(s+1); break; } #ifdef VERIFY_SAVEFILE case 'b': case 'd': case 'e': case 's': { quit_fmt("Restricted option '-d%s'", info); } #else /* VERIFY_SAVEFILE */ case 'b': { string_free(ANGBAND_DIR_BONE); ANGBAND_DIR_BONE = string_make(s+1); break; } case 'd': { string_free(ANGBAND_DIR_DATA); ANGBAND_DIR_DATA = string_make(s+1); break; } case 'e': { string_free(ANGBAND_DIR_EDIT); ANGBAND_DIR_EDIT = string_make(s+1); break; } case 's': { string_free(ANGBAND_DIR_SAVE); ANGBAND_DIR_SAVE = string_make(s+1); break; } case 'z': { string_free(ANGBAND_DIR_SCRIPT); ANGBAND_DIR_SCRIPT = string_make(s+1); break; } #endif /* VERIFY_SAVEFILE */ default: { quit_fmt("Bad semantics in '-d%s'", info); } } }
/* * Process the player name and extract a clean "base name". * * If "sf" is TRUE, then we initialize "savefile" based on player name. * * Some platforms (Windows, Macintosh, Amiga) leave the "savefile" empty * when a new character is created, and then when the character is done * being created, they call this function to choose a new savefile name. */ void process_player_name(bool sf) { int i; /* Process the player name */ for (i = 0; op_ptr->full_name[i]; i++) { char c = op_ptr->full_name[i]; /* No control characters */ if (iscntrl((unsigned char)c)) { /* Illegal characters */ quit_fmt("Illegal control char (0x%02X) in player name", c); } /* Convert all non-alphanumeric symbols */ if (!isalpha((unsigned char)c) && !isdigit((unsigned char)c)) c = '_'; /* Build "base_name" */ op_ptr->base_name[i] = c; } #if defined(WINDOWS) || defined(MSDOS) /* Max length */ if (i > 8) i = 8; #endif /* Terminate */ op_ptr->base_name[i] = '\0'; /* Require a "base" name */ if (!op_ptr->base_name[0]) { strcpy(op_ptr->base_name, "PLAYER"); } /* Pick savefile name if needed */ if (sf) { char temp[128]; #ifdef SAVEFILE_USE_UID /* Rename the savefile, using the player_uid and base_name */ strnfmt(temp, sizeof(temp), "%d.%s", player_uid, op_ptr->base_name); #else /* Rename the savefile, using the base name */ strnfmt(temp, sizeof(temp), "%s", op_ptr->base_name); #endif #ifdef VM /* Hack -- support "flat directory" usage on VM/ESA */ strnfmt(temp, sizeof(temp), "%s.sv", op_ptr->base_name); #endif /* VM */ /* Build the filename */ path_build(savefile, sizeof(savefile), ANGBAND_DIR_SAVE, temp); } }
/** * Generate a random level. * * Confusingly, this function also generate the town level (level 0). * \param c is the level we're going to end up with, in practice the global cave * \param p is the current player struct, in practice the global player */ void cave_generate(struct chunk **c, struct player *p) { const char *error = "no generation"; int y, x, tries = 0; struct chunk *chunk; assert(c); /* Generate */ for (tries = 0; tries < 100 && error; tries++) { struct dun_data dun_body; error = NULL; /* Mark the dungeon as being unready (to avoid artifact loss, etc) */ character_dungeon = FALSE; /* Allocate global data (will be freed when we leave the loop) */ dun = &dun_body; dun->cent = mem_zalloc(z_info->level_room_max * sizeof(struct loc)); dun->door = mem_zalloc(z_info->level_door_max * sizeof(struct loc)); dun->wall = mem_zalloc(z_info->wall_pierce_max * sizeof(struct loc)); dun->tunn = mem_zalloc(z_info->tunn_grid_max * sizeof(struct loc)); /* Choose a profile and build the level */ dun->profile = choose_profile(p->depth); chunk = dun->profile->builder(p); if (!chunk) { error = "Failed to find builder"; mem_free(dun->cent); mem_free(dun->door); mem_free(dun->wall); mem_free(dun->tunn); continue; } /* Ensure quest monsters */ if (is_quest(chunk->depth)) { int i; for (i = 1; i < z_info->r_max; i++) { monster_race *r_ptr = &r_info[i]; int y, x; /* The monster must be an unseen quest monster of this depth. */ if (r_ptr->cur_num > 0) continue; if (!rf_has(r_ptr->flags, RF_QUESTOR)) continue; if (r_ptr->level != chunk->depth) continue; /* Pick a location and place the monster */ find_empty(chunk, &y, &x); place_new_monster(chunk, y, x, r_ptr, TRUE, TRUE, ORIGIN_DROP); } } /* Clear generation flags. */ for (y = 0; y < chunk->height; y++) { for (x = 0; x < chunk->width; x++) { sqinfo_off(chunk->squares[y][x].info, SQUARE_WALL_INNER); sqinfo_off(chunk->squares[y][x].info, SQUARE_WALL_OUTER); sqinfo_off(chunk->squares[y][x].info, SQUARE_WALL_SOLID); sqinfo_off(chunk->squares[y][x].info, SQUARE_MON_RESTRICT); } } /* Regenerate levels that overflow their maxima */ if (cave_monster_max(chunk) >= z_info->level_monster_max) error = "too many monsters"; if (error) ROOM_LOG("Generation restarted: %s.", error); mem_free(dun->cent); mem_free(dun->door); mem_free(dun->wall); mem_free(dun->tunn); } if (error) quit_fmt("cave_generate() failed 100 times!"); /* Free the old cave, use the new one */ if (*c) cave_free(*c); *c = chunk; /* Place dungeon squares to trigger feeling (not in town) */ if (player->depth) place_feeling(*c); /* Save the town */ else if (!chunk_find_name("Town")) { struct chunk *town = chunk_write(0, 0, z_info->town_hgt, z_info->town_wid, FALSE, FALSE, FALSE); town->name = string_make("Town"); chunk_list_add(town); } (*c)->feeling = calc_obj_feeling(*c) + calc_mon_feeling(*c); /* Validate the dungeon (we could use more checks here) */ chunk_validate_objects(*c); /* The dungeon is ready */ character_dungeon = TRUE; /* Free old and allocate new known level */ if (cave_k) cave_free(cave_k); cave_k = cave_new(cave->height, cave->width); if (!cave->depth) cave_known(); (*c)->created_at = turn; }
/* * Initialize a term_data */ static errr term_data_init(term_data *td, int i) { term *t = &td->t; cptr name = angband_term_name[i]; cptr font; int x = 0; int y = 0; int cols = 80; int rows = 24; int ox = 1; int oy = 1; int wid, hgt, num; char buf[80]; cptr str; int val; XClassHint *ch; char res_name[20]; char res_class[20]; XSizeHints *sh; /* Get default font for this term */ font = get_default_font(i); /* Window specific location (x) */ sprintf(buf, "ANGBAND_X11_AT_X_%d", i); str = getenv(buf); x = (str != NULL) ? atoi(str) : -1; /* Window specific location (y) */ sprintf(buf, "ANGBAND_X11_AT_Y_%d", i); str = getenv(buf); y = (str != NULL) ? atoi(str) : -1; /* Window specific cols */ sprintf(buf, "ANGBAND_X11_COLS_%d", i); str = getenv(buf); val = (str != NULL) ? atoi(str) : -1; if (val > 0) cols = val; /* Window specific rows */ sprintf(buf, "ANGBAND_X11_ROWS_%d", i); str = getenv(buf); val = (str != NULL) ? atoi(str) : -1; if (val > 0) rows = val; /* Hack the main window must be at least 80x24 */ if (!i) { if (cols < 80) cols = 80; if (rows < 24) rows = 24; } /* Window specific inner border offset (ox) */ sprintf(buf, "ANGBAND_X11_IBOX_%d", i); str = getenv(buf); val = (str != NULL) ? atoi(str) : -1; if (val > 0) ox = val; /* Window specific inner border offset (oy) */ sprintf(buf, "ANGBAND_X11_IBOY_%d", i); str = getenv(buf); val = (str != NULL) ? atoi(str) : -1; if (val > 0) oy = val; /* Prepare the standard font */ MAKE(td->fnt, infofnt); Infofnt_set(td->fnt); if (Infofnt_init_data(font)) quit_fmt("Couldn't load the requested font. (%s)", font); /* Hack -- key buffer size */ num = ((i == 0) ? 1024 : 16); /* Assume full size windows */ wid = cols * td->fnt->wid + (ox + ox); hgt = rows * td->fnt->hgt + (oy + oy); /* Create a top-window */ MAKE(td->win, infowin); Infowin_set(td->win); Infowin_init_top(x, y, wid, hgt, 0, Metadpy->fg, Metadpy->bg); /* Ask for certain events */ Infowin_set_mask(ExposureMask | StructureNotifyMask | KeyPressMask); /* Set the window name */ Infowin_set_name(name); /* Save the inner border */ Infowin->ox = ox; Infowin->oy = oy; /* Make Class Hints */ ch = XAllocClassHint(); if (ch == NULL) quit("XAllocClassHint failed"); my_strcpy(res_name, name, sizeof(res_name)); res_name[0] = FORCELOWER(res_name[0]); ch->res_name = res_name; strcpy(res_class, "Angband"); ch->res_class = res_class; XSetClassHint(Metadpy->dpy, Infowin->win, ch); /* Make Size Hints */ sh = XAllocSizeHints(); /* Oops */ if (sh == NULL) quit("XAllocSizeHints failed"); /* Main window has a differing minimum size */ if (i == 0) { /* Main window min size is 80x24 */ sh->flags = PMinSize | PMaxSize; sh->min_width = 80 * td->fnt->wid + (ox + ox); sh->min_height = 24 * td->fnt->hgt + (oy + oy); sh->max_width = 255 * td->fnt->wid + (ox + ox); sh->max_height = 255 * td->fnt->hgt + (oy + oy); } /* Other windows can be shrunk to 1x1 */ else { /* Other windows */ sh->flags = PMinSize | PMaxSize; sh->min_width = td->fnt->wid + (ox + ox); sh->min_height = td->fnt->hgt + (oy + oy); sh->max_width = 255 * td->fnt->wid + (ox + ox); sh->max_height = 255 * td->fnt->hgt + (oy + oy); } /* Resize increment */ sh->flags |= PResizeInc; sh->width_inc = td->fnt->wid; sh->height_inc = td->fnt->hgt; /* Base window size */ sh->flags |= PBaseSize; sh->base_width = (ox + ox); sh->base_height = (oy + oy); /* Use the size hints */ XSetWMNormalHints(Metadpy->dpy, Infowin->win, sh); /* Map the window */ Infowin_map(); /* Move the window to requested location */ if ((x >= 0) && (y >= 0)) Infowin_impell(x, y); /* Initialize the term */ term_init(t, cols, rows, num); /* Use a "soft" cursor */ t->soft_cursor = TRUE; /* Erase with "white space" */ t->attr_blank = TERM_WHITE; t->char_blank = ' '; /* Hooks */ t->xtra_hook = Term_xtra_x11; t->curs_hook = Term_curs_x11; t->bigcurs_hook = Term_bigcurs_x11; t->wipe_hook = Term_wipe_x11; t->text_hook = Term_text_x11; /* Save the data */ t->data = td; /* Activate (important) */ Term_activate(t); /* Success */ return (0); }