diff --git a/include/prop.h b/include/prop.h index e4d3ec7aa..cb4cd3fde 100644 --- a/include/prop.h +++ b/include/prop.h @@ -5,7 +5,11 @@ #ifndef PROP_H #define PROP_H -/*** What the properties are ***/ +/*** What the properties are *** + * + * note: propertynames[] array in timeout.c must be kept in synch with these. + * Property #0 is not used. + */ /* Resistances to troubles */ #define FIRE_RES 1 #define COLD_RES 2 diff --git a/src/cmd.c b/src/cmd.c index fc29aaf6b..de5645d2d 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -1141,41 +1141,94 @@ STATIC_PTR int wiz_intrinsic(VOID_ARGS) { if (wizard) { + extern const char *const propertynames[]; /* timeout.c */ + static const char wizintrinsic[] = "#wizintrinsic"; + static const char fmt[] = "You are%s %s."; winid win; anything any; - int i, n, accelerator; + char buf[BUFSZ]; + int i, n, p, amt, typ; + long oldtimeout, newtimeout; + const char *propname; menu_item *pick_list = (menu_item *) 0; - static const char *const intrinsics[] = { - "deafness", - }; - win = create_nhwindow(NHW_MENU); start_menu(win); - accelerator = 0; - for (i = 0; i < SIZE(intrinsics); ++i) { - accelerator = intrinsics[i][0]; - any.a_int = i + 1; - add_menu(win, NO_GLYPH, &any, accelerator, 0, - ATR_NONE, intrinsics[i], FALSE); + for (i = 1; (propname = propertynames[i]) != 0; ++i) { + if (i == HALLUC_RES) { + /* Grayswandir vs hallucination; ought to be redone to + use u.uprops[HALLUC].blocked instead of being treated + as a separate property; letting in be manually toggled + even only in wizard mode would be asking for trouble... */ + continue; + } + any.a_int = i; + add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, propname, FALSE); } - end_menu(win, "Which intrinsic?"); - n = select_menu(win, PICK_ONE, &pick_list); + end_menu(win, "Which intrinsics?"); + n = select_menu(win, PICK_ANY, &pick_list); destroy_nhwindow(win); - if (n >= 1) { - i = pick_list[0].item.a_int-1; - free((genericptr_t) pick_list); - } else { - return 0; - } + amt = 30; /* TODO: prompt for duration */ + for (i = 0; i < n; ++i) { + p = pick_list[i].item.a_int; + oldtimeout = u.uprops[p].intrinsic & TIMEOUT; + newtimeout = oldtimeout + (long) amt; + switch (p) { + case SICK: + case SLIMED: + case STONED: + if (oldtimeout > 0L && newtimeout > oldtimeout) + newtimeout = oldtimeout; + break; + } - if (!strcmp(intrinsics[i], "deafness")) { - You("go deaf."); - incr_itimeout(&HDeaf, 30); - context.botl = TRUE; + switch (p) { + case BLINDED: + make_blinded(newtimeout, TRUE); + break; + case CONFUSION: + make_confused(newtimeout, TRUE); + break; + case DEAF: + make_deaf(newtimeout, TRUE); + break; + case HALLUC: + make_hallucinated(newtimeout, TRUE, 0L); + break; + case SICK: + typ = !rn2(2) ? SICK_VOMITABLE : SICK_NONVOMITABLE; + make_sick(newtimeout, wizintrinsic, TRUE, typ); + break; + case SLIMED: + Sprintf(buf, fmt, + !Slimed ? "" : " still", "turning into slime"); + make_slimed(newtimeout, buf); + break; + case STONED: + Sprintf(buf, fmt, + !Stoned ? "" : " still", "turning into stone"); + make_stoned(newtimeout, buf, KILLED_BY, wizintrinsic); + break; + case STUNNED: + make_stunned(newtimeout, TRUE); + break; + case VOMITING: + Sprintf(buf, fmt, !Vomiting ? "" : " still", "vomiting"); + make_vomiting(newtimeout, FALSE); + pline1(buf); + break; + default: + pline("Timeout for %s %s %d.", propertynames[p], + oldtimeout ? "increased by" : "set to", amt); + incr_itimeout(&u.uprops[p].intrinsic, amt); + break; + } + context.botl = 1; /* probably not necessary... */ } + if (n >= 1) + free((genericptr_t) pick_list); } else pline("Unavailable command '%s'.", visctrl((int) cmd_from_func(wiz_intrinsic))); @@ -2814,7 +2867,7 @@ struct ext_func_tab extcmdlist[] = { { '\\', "known", "show what object types have been discovered", dodiscovered, IFBURIED | GENERALCMD }, { '`', "knownclass", "show discovered types for one class of objects", - doclassdisco, IFBURIED|GENERALCMD }, + doclassdisco, IFBURIED | GENERALCMD }, { '\0', "levelchange", "change experience level", wiz_level_change, IFBURIED | AUTOCOMPLETE | WIZMODECMD }, { '\0', "lightsources", "show mobile light sources", @@ -2835,11 +2888,11 @@ struct ext_func_tab extcmdlist[] = { dosacrifice, AUTOCOMPLETE }, { 'o', "open", "open a door", doopen }, { 'O', "options", "show option settings, possibly change them", - doset, IFBURIED|GENERALCMD }, + doset, IFBURIED | GENERALCMD }, { C('o'), "overview", "show a summary of the explored dungeon", - dooverview, IFBURIED|AUTOCOMPLETE }, + dooverview, IFBURIED | AUTOCOMPLETE }, { '\0', "panic", "test panic routine (fatal to game)", - wiz_panic, IFBURIED|AUTOCOMPLETE|WIZMODECMD }, + wiz_panic, IFBURIED | AUTOCOMPLETE | WIZMODECMD }, { 'p', "pay", "pay your shopping bill", dopay }, { ',', "pickup", "pick up things at the current location", dopickup }, { '\0', "polyself", "polymorph self", @@ -2851,7 +2904,7 @@ struct ext_func_tab extcmdlist[] = { { M('p'), "pray", "pray to the gods for help", dopray, IFBURIED | AUTOCOMPLETE }, { C('p'), "prevmsg", "view recent game messages", - doprev_message, IFBURIED|GENERALCMD }, + doprev_message, IFBURIED | GENERALCMD }, { 'P', "puton", "put on an accessory (ring, amulet, etc)", doputon }, { 'q', "quaff", "quaff (drink) something", dodrink }, { M('q'), "quit", "exit without saving current game", @@ -2900,7 +2953,7 @@ struct ext_func_tab extcmdlist[] = { { '\0', "terrain", "show map without obstructions", doterrain, IFBURIED | AUTOCOMPLETE }, { 't', "throw", "throw something", dothrow }, - { '\0', "timeout", "look at timeout queue", + { '\0', "timeout", "look at timeout queue and hero's timed intrinsics", wiz_timeout_queue, IFBURIED | AUTOCOMPLETE | WIZMODECMD }, { M('T'), "tip", "empty a container", dotip, AUTOCOMPLETE }, { '_', "travel", "travel to a specific location on the map", dotravel }, diff --git a/src/timeout.c b/src/timeout.c index f6f92283f..66add4ec8 100644 --- a/src/timeout.c +++ b/src/timeout.c @@ -15,6 +15,45 @@ STATIC_DCL void FDECL(see_lamp_flicker, (struct obj *, const char *)); STATIC_DCL void FDECL(lantern_message, (struct obj *)); STATIC_DCL void FDECL(cleanup_burn, (ANY_P *, long)); +/* the order of these must match their numerical sequence in prop.h + because the property number is inferred from the array index; + used by wizard mode #timeout and #wizintrinsic */ +const char *const propertynames[] = { + "0: not used", +/* Resistances */ + /* 1..2 */ "fire resistance", "cold resistance", + /* 3..4 */ "sleep resistance", "disintegration resistance", + /* 5..6 */ "shock resistance", "poison resistance", + /* 7..8 */ "acid resistance", "stoning resistance", + /* 9..10 */ "drain resistance", "sickness resistance", + /* 11..12 */ "invulnerable", "magic resistance", +/* Troubles */ + /* 13..16 */ "stunned", "confused", "blinded", "deafness", + /* 17..20 */ "fatally sick", "petrifying", "strangling", "vomiting", + /* 21..22 */ "slippery fingers", "becoming slime", + /* 23..24 */ "hallucinating", "halluicination resistance", + /* 25..28 */ "fumbling", "wounded legs", "sleepy", "voracious hunger", +/* Vision and senses */ + /* 29..30 */ "see invisible", "telepathic", + /* 31..33 */ "warning", "warn:monster", "warn:undead", + /* 34..37 */ "searching", "clairvoyant", "infravision", "monster detection", +/* Appearance and behavior */ + /* 38..41 */ "adorned (+/-Cha)", "invisible", "displaced", "stealthy", + /* 42..43 */ "monster aggrevation", "conflict", +/* Transportation */ + /* 44..46 */ "jumping", "teleporting", "teleport control", + /* 47..49 */ "levitating", "flying", "water walking", + /* 50..52 */ "swimming", "magical breathing", "pass thru walls", +/* Physical attributes */ + /* 53..55 */ "slow digestion", "half spell damage", "half physical damage", + /* 56..58 */ "HP regeneration", "energy regeneration", "extra protection", + /* 59 */ "protection from shape changers", + /* 60..62 */ "polymorphing", "polymorph control", "unchanging", + /* 63..66 */ "fast", "reflecting", "free action", "fixed abilites", + /* 67 */ "life will be saved", + 0 /* sentinel */ +}; + /* He is being petrified - dialogue by inmet!tower */ static NEARDATA const char *const stoned_texts[] = { "You are slowing down.", /* 5 */ @@ -57,6 +96,9 @@ stoned_dialogue() multi_reason = "getting stoned"; nomovemsg = You_can_move_again; /* not unconscious */ break; + case 2: + if ((HDeaf & TIMEOUT) > 0L && (HDeaf & TIMEOUT) < 5L) + set_itimeout(&HDeaf, 5L); /* avoid Hear_again at tail end */ default: break; } @@ -179,8 +221,9 @@ levitation_dialogue() if (((HLevitation & TIMEOUT) % 2L) && i > 0L && i <= SIZE(levi_texts)) { const char *s = levi_texts[SIZE(levi_texts) - i]; if (index(s, '%')) { - boolean danger = is_pool_or_lava(u.ux, u.uy) - && !Is_waterlevel(&u.uz); + boolean danger = (is_pool_or_lava(u.ux, u.uy) + && !Is_waterlevel(&u.uz)); + pline(s, danger ? "over" : "in", danger ? surface(u.ux, u.uy) : "air"); } else @@ -225,6 +268,8 @@ slime_dialogue() if (multi > 0) nomul(0); } + if (i == 2L && (HDeaf & TIMEOUT) > 0L && (HDeaf & TIMEOUT) < 5L) + set_itimeout(&HDeaf, 5L); /* avoid Hear_again at tail end */ exercise(A_DEX, FALSE); } @@ -1473,7 +1518,7 @@ timer_element *base; char buf[BUFSZ]; if (!base) { - putstr(win, 0, ""); + putstr(win, 0, " "); } else { putstr(win, 0, "timeout id kind call"); for (curr = base; curr; curr = curr->next) { @@ -1492,31 +1537,14 @@ timer_element *base; } } -static boolean print_prop_header = TRUE; -void -print_prop(win, text, prop) -winid win; -const char *text; -long prop; -{ - char buf[BUFSZ]; - if (prop & TIMEOUT) { - if (print_prop_header) { - putstr(win, 0, ""); - putstr(win, 0, "Properties:"); - putstr(win, 0, ""); - print_prop_header = FALSE; - } - Sprintf(buf, " %10s: %ld", text, (prop & TIMEOUT)); - putstr(win, 0, buf); - } -} - int wiz_timeout_queue() { winid win; char buf[BUFSZ]; + const char *propname; + long intrinsic; + int i, count, longestlen, ln; win = create_nhwindow(NHW_MENU); /* corner text window */ if (win == WIN_ERR) @@ -1529,19 +1557,38 @@ wiz_timeout_queue() putstr(win, 0, ""); print_queue(win, timer_base); - print_prop_header = TRUE; - print_prop(win, "Confused", Confusion); - print_prop(win, "Deaf", HDeaf); - print_prop(win, "Levitation", HLevitation); - print_prop(win, "Monster detection", HDetect_monsters); - print_prop(win, "Slimed", Slimed); - print_prop(win, "Slippery hands", Glib); - print_prop(win, "Stoned", Stoned); - print_prop(win, "Strangled", Strangled); - print_prop(win, "Stunned", Stunned); - print_prop(win, "Vomiting", Vomiting); - print_prop(win, "Wounded legs", HWounded_legs); - + /* Timed properies: + * check every one; the majority can't obtain temporary timeouts in + * normal play but those can be forced via the #wizintrinsic command. + */ + count = longestlen = 0; + for (i = 1; (propname = propertynames[i]) != 0; ++i) { /* [0] not used */ + intrinsic = u.uprops[i].intrinsic; + if (intrinsic & TIMEOUT) { + ++count; + if ((ln = (int) strlen(propname)) > longestlen) + longestlen = ln; + } + } + putstr(win, 0, ""); + if (!count) { + putstr(win, 0, "No timed properties."); + } else { + putstr(win, 0, "Timed properties:"); + putstr(win, 0, ""); + for (i = 1; (propname = propertynames[i]) != 0; ++i) { + intrinsic = u.uprops[i].intrinsic; + if (intrinsic & TIMEOUT) { + /* timeout value can be up to 16777215 (0x00ffffff) but + width of 4 digits should result in values lining up + almost all the time (if/when they don't, it won't + look nice but the information will still be accurate) */ + Sprintf(buf, " %*s %4ld", -longestlen, propname, + (intrinsic & TIMEOUT)); + putstr(win, 0, buf); + } + } + } display_nhwindow(win, FALSE); destroy_nhwindow(win); @@ -1557,6 +1604,7 @@ timer_sanity_check() for (curr = timer_base; curr; curr = curr->next) if (curr->kind == TIMER_OBJECT) { struct obj *obj = curr->arg.a_obj; + if (obj->timed == 0) { pline("timer sanity: untimed obj %s, timer %ld", fmt_ptr((genericptr_t) obj), curr->tid);