*** empty log message ***
This commit is contained in:
430
src/o_init.c
Normal file
430
src/o_init.c
Normal file
@@ -0,0 +1,430 @@
|
||||
/* SCCS Id: @(#)o_init.c 3.3 1999/12/09 */
|
||||
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
|
||||
/* NetHack may be freely redistributed. See license for details. */
|
||||
|
||||
#include "hack.h"
|
||||
#include "lev.h" /* save & restore info */
|
||||
|
||||
STATIC_DCL void FDECL(setgemprobs, (d_level*));
|
||||
STATIC_DCL void FDECL(shuffle,(int,int,BOOLEAN_P));
|
||||
STATIC_DCL void NDECL(shuffle_all);
|
||||
STATIC_DCL boolean FDECL(interesting_to_discover,(int));
|
||||
|
||||
|
||||
static NEARDATA short disco[NUM_OBJECTS] = DUMMY;
|
||||
|
||||
#ifdef USE_TILES
|
||||
STATIC_DCL void NDECL(shuffle_tiles);
|
||||
extern short glyph2tile[]; /* from tile.c */
|
||||
|
||||
/* Shuffle tile assignments to match descriptions, so a red potion isn't
|
||||
* displayed with a blue tile and so on.
|
||||
*
|
||||
* Tile assignments are not saved, and shouldn't be so that a game can
|
||||
* be resumed on an otherwise identical non-tile-using binary, so we have
|
||||
* to reshuffle the assignments from oc_descr_idx information when a game
|
||||
* is restored. So might as well do that the first time instead of writing
|
||||
* another routine.
|
||||
*/
|
||||
STATIC_OVL void
|
||||
shuffle_tiles()
|
||||
{
|
||||
int i;
|
||||
short tmp_tilemap[NUM_OBJECTS];
|
||||
|
||||
for (i = 0; i < NUM_OBJECTS; i++)
|
||||
tmp_tilemap[i] =
|
||||
glyph2tile[objects[i].oc_descr_idx + GLYPH_OBJ_OFF];
|
||||
|
||||
for (i = 0; i < NUM_OBJECTS; i++)
|
||||
glyph2tile[i + GLYPH_OBJ_OFF] = tmp_tilemap[i];
|
||||
}
|
||||
#endif /* USE_TILES */
|
||||
|
||||
STATIC_OVL void
|
||||
setgemprobs(dlev)
|
||||
d_level *dlev;
|
||||
{
|
||||
int j, first, lev;
|
||||
|
||||
if (dlev)
|
||||
lev = (ledger_no(dlev) > maxledgerno())
|
||||
? maxledgerno() : ledger_no(dlev);
|
||||
else
|
||||
lev = 0;
|
||||
first = bases[GEM_CLASS];
|
||||
|
||||
for(j = 0; j < 9-lev/3; j++)
|
||||
objects[first+j].oc_prob = 0;
|
||||
first += j;
|
||||
if (first > LAST_GEM || objects[first].oc_class != GEM_CLASS ||
|
||||
OBJ_NAME(objects[first]) == (char *)0) {
|
||||
raw_printf("Not enough gems? - first=%d j=%d LAST_GEM=%d",
|
||||
first, j, LAST_GEM);
|
||||
wait_synch();
|
||||
}
|
||||
for (j = first; j <= LAST_GEM; j++)
|
||||
objects[j].oc_prob = (171+j-first)/(LAST_GEM+1-first);
|
||||
}
|
||||
|
||||
/* shuffle descriptions on objects o_low to o_high */
|
||||
STATIC_OVL void
|
||||
shuffle(o_low, o_high, domaterial)
|
||||
int o_low, o_high;
|
||||
boolean domaterial;
|
||||
{
|
||||
int i, j, num_to_shuffle;
|
||||
short sw;
|
||||
#ifdef TEXTCOLOR
|
||||
int color;
|
||||
#endif /* TEXTCOLOR */
|
||||
|
||||
for (num_to_shuffle = 0, j=o_low; j <= o_high; j++)
|
||||
if (!objects[j].oc_name_known) num_to_shuffle++;
|
||||
if (num_to_shuffle < 2) return;
|
||||
|
||||
for (j=o_low; j <= o_high; j++) {
|
||||
if (objects[j].oc_name_known) continue;
|
||||
do
|
||||
i = j + rn2(o_high-j+1);
|
||||
while (objects[i].oc_name_known);
|
||||
sw = objects[j].oc_descr_idx;
|
||||
objects[j].oc_descr_idx = objects[i].oc_descr_idx;
|
||||
objects[i].oc_descr_idx = sw;
|
||||
sw = objects[j].oc_tough;
|
||||
objects[j].oc_tough = objects[i].oc_tough;
|
||||
objects[i].oc_tough = sw;
|
||||
#ifdef TEXTCOLOR
|
||||
color = objects[j].oc_color;
|
||||
objects[j].oc_color = objects[i].oc_color;
|
||||
objects[i].oc_color = color;
|
||||
#endif /* TEXTCOLOR */
|
||||
/* shuffle material */
|
||||
if (domaterial) {
|
||||
sw = objects[j].oc_material;
|
||||
objects[j].oc_material = objects[i].oc_material;
|
||||
objects[i].oc_material = sw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
init_objects()
|
||||
{
|
||||
register int i, first, last, sum;
|
||||
register char oclass;
|
||||
#ifdef TEXTCOLOR
|
||||
# define COPY_OBJ_DESCR(o_dst,o_src) \
|
||||
o_dst.oc_descr_idx = o_src.oc_descr_idx,\
|
||||
o_dst.oc_color = o_src.oc_color
|
||||
#else
|
||||
# define COPY_OBJ_DESCR(o_dst,o_src) o_dst.oc_descr_idx = o_src.oc_descr_idx
|
||||
#endif
|
||||
|
||||
/* bug fix to prevent "initialization error" abort on Intel Xenix.
|
||||
* reported by mikew@semike
|
||||
*/
|
||||
for (i = 0; i < MAXOCLASSES; i++)
|
||||
bases[i] = 0;
|
||||
/* initialize object descriptions */
|
||||
for (i = 0; i < NUM_OBJECTS; i++)
|
||||
objects[i].oc_name_idx = objects[i].oc_descr_idx = i;
|
||||
/* init base; if probs given check that they add up to 1000,
|
||||
otherwise compute probs */
|
||||
first = 0;
|
||||
while( first < NUM_OBJECTS ) {
|
||||
oclass = objects[first].oc_class;
|
||||
last = first+1;
|
||||
while (last < NUM_OBJECTS && objects[last].oc_class == oclass) last++;
|
||||
bases[(int)oclass] = first;
|
||||
|
||||
if (oclass == GEM_CLASS) {
|
||||
setgemprobs((d_level *)0);
|
||||
|
||||
if (rn2(2)) { /* change turquoise from green to blue? */
|
||||
COPY_OBJ_DESCR(objects[TURQUOISE],objects[SAPPHIRE]);
|
||||
}
|
||||
if (rn2(2)) { /* change aquamarine from green to blue? */
|
||||
COPY_OBJ_DESCR(objects[AQUAMARINE],objects[SAPPHIRE]);
|
||||
}
|
||||
switch (rn2(4)) { /* change fluorite from violet? */
|
||||
case 0: break;
|
||||
case 1: /* blue */
|
||||
COPY_OBJ_DESCR(objects[FLUORITE],objects[SAPPHIRE]);
|
||||
break;
|
||||
case 2: /* white */
|
||||
COPY_OBJ_DESCR(objects[FLUORITE],objects[DIAMOND]);
|
||||
break;
|
||||
case 3: /* green */
|
||||
COPY_OBJ_DESCR(objects[FLUORITE],objects[EMERALD]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
check:
|
||||
sum = 0;
|
||||
for(i = first; i < last; i++) sum += objects[i].oc_prob;
|
||||
if(sum == 0) {
|
||||
for(i = first; i < last; i++)
|
||||
objects[i].oc_prob = (1000+i-first)/(last-first);
|
||||
goto check;
|
||||
}
|
||||
if(sum != 1000)
|
||||
error("init-prob error for class %d (%d%%)", oclass, sum);
|
||||
first = last;
|
||||
}
|
||||
/* shuffle descriptions */
|
||||
shuffle_all();
|
||||
#ifdef USE_TILES
|
||||
shuffle_tiles();
|
||||
#endif
|
||||
}
|
||||
|
||||
STATIC_OVL void
|
||||
shuffle_all()
|
||||
{
|
||||
int first, last, oclass;
|
||||
|
||||
for (oclass = 1; oclass < MAXOCLASSES; oclass++) {
|
||||
first = bases[oclass];
|
||||
last = first+1;
|
||||
while (last < NUM_OBJECTS && objects[last].oc_class == oclass)
|
||||
last++;
|
||||
|
||||
if (OBJ_DESCR(objects[first]) != (char *)0 &&
|
||||
oclass != TOOL_CLASS &&
|
||||
oclass != WEAPON_CLASS &&
|
||||
oclass != ARMOR_CLASS &&
|
||||
oclass != GEM_CLASS) {
|
||||
int j = last-1;
|
||||
|
||||
if (oclass == POTION_CLASS)
|
||||
j -= 1; /* only water has a fixed description */
|
||||
else if (oclass == AMULET_CLASS ||
|
||||
oclass == SCROLL_CLASS ||
|
||||
oclass == SPBOOK_CLASS) {
|
||||
while (!objects[j].oc_magic || objects[j].oc_unique)
|
||||
j--;
|
||||
}
|
||||
|
||||
/* non-magical amulets, scrolls, and spellbooks
|
||||
* (ex. imitation Amulets, blank, scrolls of mail)
|
||||
* and one-of-a-kind magical artifacts at the end of
|
||||
* their class in objects[] have fixed descriptions.
|
||||
*/
|
||||
shuffle(first, j, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
/* shuffle the helmets */
|
||||
shuffle(HELMET, HELM_OF_TELEPATHY, FALSE);
|
||||
|
||||
/* shuffle the gloves */
|
||||
shuffle(LEATHER_GLOVES, GAUNTLETS_OF_DEXTERITY, FALSE);
|
||||
|
||||
/* shuffle the cloaks */
|
||||
shuffle(CLOAK_OF_PROTECTION, CLOAK_OF_DISPLACEMENT, FALSE);
|
||||
|
||||
/* shuffle the boots [if they change, update find_skates() below] */
|
||||
shuffle(SPEED_BOOTS, LEVITATION_BOOTS, FALSE);
|
||||
}
|
||||
|
||||
/* find the object index for snow boots; used [once] by slippery ice code */
|
||||
int
|
||||
find_skates()
|
||||
{
|
||||
register int i;
|
||||
register const char *s;
|
||||
|
||||
for (i = SPEED_BOOTS; i <= LEVITATION_BOOTS; i++)
|
||||
if ((s = OBJ_DESCR(objects[i])) != 0 && !strcmp(s, "snow boots"))
|
||||
return i;
|
||||
|
||||
impossible("snow boots not found?");
|
||||
return -1; /* not 0, or caller would try again each move */
|
||||
}
|
||||
|
||||
void
|
||||
oinit() /* level dependent initialization */
|
||||
{
|
||||
setgemprobs(&u.uz);
|
||||
}
|
||||
|
||||
void
|
||||
savenames(fd, mode)
|
||||
int fd, mode;
|
||||
{
|
||||
register int i;
|
||||
unsigned int len;
|
||||
|
||||
if (perform_bwrite(mode)) {
|
||||
bwrite(fd, (genericptr_t)bases, sizeof bases);
|
||||
bwrite(fd, (genericptr_t)disco, sizeof disco);
|
||||
bwrite(fd, (genericptr_t)objects,
|
||||
sizeof(struct objclass) * NUM_OBJECTS);
|
||||
}
|
||||
/* as long as we use only one version of Hack we
|
||||
need not save oc_name and oc_descr, but we must save
|
||||
oc_uname for all objects */
|
||||
for (i = 0; i < NUM_OBJECTS; i++)
|
||||
if (objects[i].oc_uname) {
|
||||
if (perform_bwrite(mode)) {
|
||||
len = strlen(objects[i].oc_uname)+1;
|
||||
bwrite(fd, (genericptr_t)&len, sizeof len);
|
||||
bwrite(fd, (genericptr_t)objects[i].oc_uname, len);
|
||||
}
|
||||
if (release_data(mode)) {
|
||||
free((genericptr_t)objects[i].oc_uname);
|
||||
objects[i].oc_uname = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
restnames(fd)
|
||||
register int fd;
|
||||
{
|
||||
register int i;
|
||||
unsigned int len;
|
||||
|
||||
mread(fd, (genericptr_t) bases, sizeof bases);
|
||||
mread(fd, (genericptr_t) disco, sizeof disco);
|
||||
mread(fd, (genericptr_t) objects, sizeof(struct objclass) * NUM_OBJECTS);
|
||||
for (i = 0; i < NUM_OBJECTS; i++)
|
||||
if (objects[i].oc_uname) {
|
||||
mread(fd, (genericptr_t) &len, sizeof len);
|
||||
objects[i].oc_uname = (char *) alloc(len);
|
||||
mread(fd, (genericptr_t)objects[i].oc_uname, len);
|
||||
}
|
||||
#ifdef USE_TILES
|
||||
shuffle_tiles();
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
discover_object(oindx, mark_as_known, credit_hero)
|
||||
register int oindx;
|
||||
boolean mark_as_known;
|
||||
boolean credit_hero;
|
||||
{
|
||||
if (!objects[oindx].oc_name_known) {
|
||||
register int dindx, acls = objects[oindx].oc_class;
|
||||
|
||||
/* Loop thru disco[] 'til we find the target (which may have been
|
||||
uname'd) or the next open slot; one or the other will be found
|
||||
before we reach the next class...
|
||||
*/
|
||||
for (dindx = bases[acls]; disco[dindx] != 0; dindx++)
|
||||
if (disco[dindx] == oindx) break;
|
||||
disco[dindx] = oindx;
|
||||
|
||||
if (mark_as_known) {
|
||||
objects[oindx].oc_name_known = 1;
|
||||
if (credit_hero) exercise(A_WIS, TRUE);
|
||||
}
|
||||
if (moves > 1L) update_inventory();
|
||||
}
|
||||
}
|
||||
|
||||
/* if a class name has been cleared, we may need to purge it from disco[] */
|
||||
void
|
||||
undiscover_object(oindx)
|
||||
register int oindx;
|
||||
{
|
||||
if (!objects[oindx].oc_name_known) {
|
||||
register int dindx, acls = objects[oindx].oc_class;
|
||||
register boolean found = FALSE;
|
||||
|
||||
/* find the object; shift those behind it forward one slot */
|
||||
for (dindx = bases[acls];
|
||||
dindx < NUM_OBJECTS && disco[dindx] != 0
|
||||
&& objects[dindx].oc_class == acls; dindx++)
|
||||
if (found)
|
||||
disco[dindx-1] = disco[dindx];
|
||||
else if (disco[dindx] == oindx)
|
||||
found = TRUE;
|
||||
|
||||
/* clear last slot */
|
||||
if (found) disco[dindx-1] = 0;
|
||||
else impossible("named object not in disco");
|
||||
update_inventory();
|
||||
}
|
||||
}
|
||||
|
||||
STATIC_OVL boolean
|
||||
interesting_to_discover(i)
|
||||
register int i;
|
||||
{
|
||||
/* Pre-discovered objects are now printed with a '*' */
|
||||
return((boolean)(objects[i].oc_uname != (char *)0 ||
|
||||
(objects[i].oc_name_known && OBJ_DESCR(objects[i]) != (char *)0)));
|
||||
}
|
||||
|
||||
/* items that should stand out once they're known */
|
||||
static short uniq_objs[] = {
|
||||
AMULET_OF_YENDOR,
|
||||
SPE_BOOK_OF_THE_DEAD,
|
||||
CANDELABRUM_OF_INVOCATION,
|
||||
BELL_OF_OPENING,
|
||||
};
|
||||
|
||||
int
|
||||
dodiscovered() /* free after Robert Viduya */
|
||||
{
|
||||
register int i, dis;
|
||||
int ct = 0;
|
||||
char *s, oclass, prev_class, classes[MAXOCLASSES];
|
||||
winid tmpwin;
|
||||
char buf[BUFSZ];
|
||||
|
||||
tmpwin = create_nhwindow(NHW_MENU);
|
||||
putstr(tmpwin, 0, "Discoveries");
|
||||
putstr(tmpwin, 0, "");
|
||||
|
||||
/* gather "unique objects" into a pseudo-class; note that they'll
|
||||
also be displayed individually within their regular class */
|
||||
for (i = dis = 0; i < SIZE(uniq_objs); i++)
|
||||
if (objects[uniq_objs[i]].oc_name_known) {
|
||||
if (!dis++)
|
||||
putstr(tmpwin, ATR_INVERSE, "Unique Items");
|
||||
Sprintf(buf, " %s", OBJ_NAME(objects[uniq_objs[i]]));
|
||||
putstr(tmpwin, 0, buf);
|
||||
++ct;
|
||||
}
|
||||
/* display any known artifacts as another pseudo-class */
|
||||
ct += disp_artifact_discoveries(tmpwin);
|
||||
|
||||
/* several classes are omitted from packorder; one is of interest here */
|
||||
Strcpy(classes, flags.inv_order);
|
||||
if (!index(classes, VENOM_CLASS)) {
|
||||
s = eos(classes);
|
||||
*s++ = VENOM_CLASS;
|
||||
*s = '\0';
|
||||
}
|
||||
|
||||
for (s = classes; *s; s++) {
|
||||
oclass = *s;
|
||||
prev_class = oclass + 1; /* forced different from oclass */
|
||||
for (i = bases[(int)oclass];
|
||||
i < NUM_OBJECTS && objects[i].oc_class == oclass; i++) {
|
||||
if ((dis = disco[i]) && interesting_to_discover(dis)) {
|
||||
ct++;
|
||||
if (oclass != prev_class) {
|
||||
putstr(tmpwin, ATR_INVERSE, let_to_name(oclass, FALSE));
|
||||
prev_class = oclass;
|
||||
}
|
||||
Sprintf(buf, "%s %s",(objects[dis].oc_pre_discovered ? "*" : " "),
|
||||
obj_typename(dis));
|
||||
putstr(tmpwin, 0, buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ct == 0) {
|
||||
You("haven't discovered anything yet...");
|
||||
} else
|
||||
display_nhwindow(tmpwin, TRUE);
|
||||
destroy_nhwindow(tmpwin);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*o_init.c*/
|
||||
Reference in New Issue
Block a user