root/trunk/src/xtra3.c

Revision 899, 34.3 kB (checked in by takkaria, 16 hours ago)
  • Add "terror" timed effect. This is fear + small speed boost.
  • Add "stoneskin" timed effect. This is +40AC + small speed penalty.
  • (#351) Mushrooms of Clear Mind now cures hallu and gives temp rConf.
  • (#522, #369) Tone down CSW and CCW.
  • Add "deep descent" effect, which lowers recall depth by 2 dungeon levels and teleports/recalls there.
  • Add "line of sight confusion" effect, analagous to the slow/sleep effects.
  • Add few new effects for mushrooms, one commented out.
Line 
1 /*
2  * File: xtra3.c
3  * Purpose: Handles the setting up updating, and cleaning up of the various
4  *          things that are displayed by the game.
5  *
6  * Copyright (c) 1997 Ben Harrison, James E. Wilson, Robert A. Koeneke
7  * Copyright (c) 2007 Antony Sidwell
8  *
9  * This work is free software; you can redistribute it and/or modify it
10  * under the terms of either:
11  *
12  * a) the GNU General Public License as published by the Free Software
13  *    Foundation, version 2, or
14  *
15  * b) the "Angband licence":
16  *    This software may be copied and distributed for educational, research,
17  *    and not for profit purposes provided that this copyright and statement
18  *    are included in all such copies.  Other copyrights may also apply.
19  */
20 #include "angband.h"
21 #include "game-event.h"
22
23 #include "ui-birth.h"
24
25 #include "tvalsval.h"
26
27 /*
28  * There are a few functions installed to be triggered by several
29  * of the basic player events.  For convenience, these have been grouped
30  * in this list.
31  */
32 game_event_type player_events[] =
33 {
34         EVENT_RACE_CLASS,
35         EVENT_PLAYERTITLE,
36         EVENT_EXPERIENCE,
37         EVENT_PLAYERLEVEL,
38         EVENT_GOLD,
39         EVENT_EQUIPMENT,  /* For equippy chars */
40         EVENT_STATS,
41         EVENT_HP,
42         EVENT_MANA,
43         EVENT_AC,
44
45         EVENT_MONSTERHEALTH,
46
47         EVENT_PLAYERSPEED,
48         EVENT_DUNGEONLEVEL,
49 };
50
51 game_event_type statusline_events[] =
52 {
53         EVENT_STUDYSTATUS,
54         EVENT_STATUS,
55         EVENT_DETECTIONSTATUS,
56         EVENT_STATE,
57         EVENT_MOUSEBUTTONS
58 };
59
60
61 /*
62  * Converts stat num into a six-char (right justified) string
63  */
64 void cnv_stat(int val, char *out_val, size_t out_len)
65 {
66         /* Above 18 */
67         if (val > 18)
68         {
69                 int bonus = (val - 18);
70
71                 if (bonus >= 100)
72                         strnfmt(out_val, out_len, "18/%03d", bonus);
73                 else
74                         strnfmt(out_val, out_len, " 18/%02d", bonus);
75         }
76
77         /* From 3 to 18 */
78         else
79         {
80                 strnfmt(out_val, out_len, "    %2d", val);
81         }
82 }
83
84 /* ------------------------------------------------------------------------
85  * Sidebar display functions
86  * ------------------------------------------------------------------------ */
87
88 /*
89  * Print character info at given row, column in a 13 char field
90  */
91 static void prt_field(cptr info, int row, int col)
92 {
93         /* Dump 13 spaces to clear */
94         c_put_str(TERM_WHITE, "             ", row, col);
95
96         /* Dump the info itself */
97         c_put_str(TERM_L_BLUE, info, row, col);
98 }
99
100
101 /*
102  * Print character stat in given row, column
103  */
104 static void prt_stat(int stat, int row, int col)
105 {
106         char tmp[32];
107
108         /* Display "injured" stat */
109         if (p_ptr->stat_cur[stat] < p_ptr->stat_max[stat])
110         {
111                 put_str(stat_names_reduced[stat], row, col);
112                 cnv_stat(p_ptr->stat_use[stat], tmp, sizeof(tmp));
113                 c_put_str(TERM_YELLOW, tmp, row, col + 6);
114         }
115
116         /* Display "healthy" stat */
117         else
118         {
119                 put_str(stat_names[stat], row, col);
120                 cnv_stat(p_ptr->stat_use[stat], tmp, sizeof(tmp));
121                 c_put_str(TERM_L_GREEN, tmp, row, col + 6);
122         }
123
124         /* Indicate natural maximum */
125         if (p_ptr->stat_max[stat] == 18+100)
126         {
127                 put_str("!", row, col + 3);
128         }
129 }
130
131
132 /*
133  * Prints "title", including "wizard" or "winner" as needed.
134  */
135 static void prt_title(int row, int col)
136 {
137         cptr p;
138
139         /* Wizard */
140         if (p_ptr->wizard)
141         {
142                 p = "[=-WIZARD-=]";
143         }
144
145         /* Winner */
146         else if (p_ptr->total_winner || (p_ptr->lev > PY_MAX_LEVEL))
147         {
148                 p = "***WINNER***";
149         }
150
151         /* Normal */
152         else
153         {
154                 p = c_text + cp_ptr->title[(p_ptr->lev - 1) / 5];
155         }
156
157         prt_field(p, row, col);
158 }
159
160
161 /*
162  * Prints level
163  */
164 static void prt_level(int row, int col)
165 {
166         char tmp[32];
167
168         strnfmt(tmp, sizeof(tmp), "%6d", p_ptr->lev);
169
170         if (p_ptr->lev >= p_ptr->max_lev)
171         {
172                 put_str("LEVEL ", row, col);
173                 c_put_str(TERM_L_GREEN, tmp, row, col + 6);
174         }
175         else
176         {
177                 put_str("Level ", row, col);
178                 c_put_str(TERM_YELLOW, tmp, row, col + 6);
179         }
180 }
181
182
183 /*
184  * Display the experience
185  */
186 static void prt_exp(int row, int col)
187 {
188         char out_val[32];
189         bool lev50 = (p_ptr->lev == 50);
190
191         long xp = (long)p_ptr->exp;
192
193
194         /* Calculate XP for next level */
195         if (!lev50)
196                 xp = (long)(player_exp[p_ptr->lev - 1] * p_ptr->expfact / 100L) - p_ptr->exp;
197
198         /* Format XP */
199         strnfmt(out_val, sizeof(out_val), "%8ld", (long)xp);
200
201
202         if (p_ptr->exp >= p_ptr->max_exp)
203         {
204                 put_str((lev50 ? "EXP" : "NXT"), row, col);
205                 c_put_str(TERM_L_GREEN, out_val, row, col + 4);
206         }
207         else
208         {
209                 put_str((lev50 ? "Exp" : "Nxt"), row, col);
210                 c_put_str(TERM_YELLOW, out_val, row, col + 4);
211         }
212 }
213
214
215 /*
216  * Prints current gold
217  */
218 static void prt_gold(int row, int col)
219 {
220         char tmp[32];
221
222         put_str("AU ", row, col);
223         strnfmt(tmp, sizeof(tmp), "%9ld", (long)p_ptr->au);
224         c_put_str(TERM_L_GREEN, tmp, row, col + 3);
225 }
226
227
228 /*
229  * Equippy chars
230  */
231 static void prt_equippy(int row, int col)
232 {
233         int i;
234
235         byte a;
236         char c;
237
238         object_type *o_ptr;
239
240         /* No equippy chars in bigtile mode */
241         if (use_bigtile) return;
242
243         /* Dump equippy chars */
244         for (i = INVEN_WIELD; i < INVEN_TOTAL; i++)
245         {
246                 /* Object */
247                 o_ptr = &inventory[i];
248
249                 a = object_attr(o_ptr);
250                 c = object_char(o_ptr);
251
252                 /* Clear the part of the screen */
253                 if (!o_ptr->k_idx)
254                 {
255                         c = ' ';
256                         a = TERM_WHITE;
257                 }
258
259                 /* Dump */
260                 Term_putch(col + i - INVEN_WIELD, row, a, c);
261         }
262 }
263
264
265 /*
266  * Prints current AC
267  */
268 static void prt_ac(int row, int col)
269 {
270         char tmp[32];
271
272         put_str("Cur AC ", row, col);
273         strnfmt(tmp, sizeof(tmp), "%5d", p_ptr->dis_ac + p_ptr->dis_to_a);
274         c_put_str(TERM_L_GREEN, tmp, row, col + 7);
275 }
276
277
278 /*
279  * Prints Cur hit points
280  */
281 static void prt_hp(int row, int col)
282 {
283         char cur_hp[32], max_hp[32];
284         byte color;
285
286         put_str("HP ", row, col);
287
288         strnfmt(max_hp, sizeof(max_hp), "%4d", p_ptr->mhp);
289         strnfmt(cur_hp, sizeof(cur_hp), "%4d", p_ptr->chp);
290
291         if (p_ptr->chp >= p_ptr->mhp)
292                 color = TERM_L_GREEN;
293         else if (p_ptr->chp > (p_ptr->mhp * op_ptr->hitpoint_warn) / 10)
294                 color = TERM_YELLOW;
295         else
296                 color = TERM_RED;
297
298         c_put_str(color, cur_hp, row, col + 3);
299         c_put_str(TERM_WHITE, "/", row, col + 7);
300         c_put_str(TERM_L_GREEN, max_hp, row, col + 8);
301 }
302
303
304 /*
305  * Prints players max/cur spell points
306  */
307 static void prt_sp(int row, int col)
308 {
309         char cur_sp[32], max_sp[32];
310         byte color;
311
312         /* Do not show mana unless it matters */
313         if (!cp_ptr->spell_book) return;
314
315         put_str("SP ", row, col);
316
317         strnfmt(max_sp, sizeof(max_sp), "%4d", p_ptr->msp);
318         strnfmt(cur_sp, sizeof(cur_sp), "%4d", p_ptr->csp);
319
320         if (p_ptr->csp >= p_ptr->msp)
321                 color = TERM_L_GREEN;
322         else if (p_ptr->csp > (p_ptr->msp * op_ptr->hitpoint_warn) / 10)
323                 color = TERM_YELLOW;
324         else
325                 color = TERM_RED;
326
327         /* Show mana */
328         c_put_str(color, cur_sp, row, col + 3);
329         c_put_str(TERM_WHITE, "/", row, col + 7);
330         c_put_str(TERM_L_GREEN, max_sp, row, col + 8);
331 }
332
333
334 /*
335  * Redraw the "monster health bar"
336  *
337  * The "monster health bar" provides visual feedback on the "health"
338  * of the monster currently being "tracked".  There are several ways
339  * to "track" a monster, including targetting it, attacking it, and
340  * affecting it (and nobody else) with a ranged attack.  When nothing
341  * is being tracked, we clear the health bar.  If the monster being
342  * tracked is not currently visible, a special health bar is shown.
343  */
344 static void prt_health(int row, int col)
345 {
346         /* Not tracking */
347         if (!p_ptr->health_who)
348         {
349                 /* Erase the health bar */
350                 Term_erase(col, row, 12);
351         }
352
353         /* Tracking an unseen monster */
354         else if (!mon_list[p_ptr->health_who].ml)
355         {
356                 /* Indicate that the monster health is "unknown" */
357                 Term_putstr(col, row, 12, TERM_WHITE, "[----------]");
358         }
359
360         /* Tracking a hallucinatory monster */
361         else if (p_ptr->timed[TMD_IMAGE])
362         {
363                 /* Indicate that the monster health is "unknown" */
364                 Term_putstr(col, row, 12, TERM_WHITE, "[----------]");
365         }
366
367         /* Tracking a dead monster (?) */
368         else if (!mon_list[p_ptr->health_who].hp < 0)
369         {
370                 /* Indicate that the monster health is "unknown" */
371                 Term_putstr(col, row, 12, TERM_WHITE, "[----------]");
372         }
373
374         /* Tracking a visible monster */
375         else
376         {
377                 int pct, len;
378
379                 monster_type *m_ptr = &mon_list[p_ptr->health_who];
380
381                 /* Default to almost dead */
382                 byte attr = TERM_RED;
383
384                 /* Extract the "percent" of health */
385                 pct = 100L * m_ptr->hp / m_ptr->maxhp;
386
387                 /* Badly wounded */
388                 if (pct >= 10) attr = TERM_L_RED;
389
390                 /* Wounded */
391                 if (pct >= 25) attr = TERM_ORANGE;
392
393                 /* Somewhat Wounded */
394                 if (pct >= 60) attr = TERM_YELLOW;
395
396                 /* Healthy */
397                 if (pct >= 100) attr = TERM_L_GREEN;
398
399                 /* Afraid */
400                 if (m_ptr->monfear) attr = TERM_VIOLET;
401
402                 /* Confused */
403                 if (m_ptr->confused) attr = TERM_UMBER;
404
405                 /* Stunned */
406                 if (m_ptr->stunned) attr = TERM_L_BLUE;
407
408                 /* Asleep */
409                 if (m_ptr->csleep) attr = TERM_BLUE;
410
411                 /* Convert percent into "health" */
412                 len = (pct < 10) ? 1 : (pct < 90) ? (pct / 10 + 1) : 10;
413
414                 /* Default to "unknown" */
415                 Term_putstr(col, row, 12, TERM_WHITE, "[----------]");
416
417                 /* Dump the current "health" (use '*' symbols) */
418                 Term_putstr(col + 1, row, len, attr, "**********");
419         }
420 }
421
422
423 /*
424  * Prints the speed of a character.
425  */
426 static void prt_speed(int row, int col)
427 {
428         int i = p_ptr->pspeed;
429
430         byte attr = TERM_WHITE;
431         const char *type = NULL;
432         char buf[32] = "";
433
434         /* Hack -- Visually "undo" the Search Mode Slowdown */
435         if (p_ptr->searching) i += 10;
436
437         /* Fast */
438         if (i > 110)
439         {
440                 attr = TERM_L_GREEN;
441                 type = "Fast";
442         }
443
444         /* Slow */
445         else if (i < 110)
446         {
447                 attr = TERM_L_UMBER;
448                 type = "Slow";
449         }
450
451         if (type)
452                 strnfmt(buf, sizeof(buf), "%s (%+d)", type, (i - 110));
453
454         /* Display the speed */
455         c_put_str(attr, format("%-10s", buf), row, col);
456 }
457
458
459 /*
460  * Prints depth in stat area
461  */
462 static void prt_depth(int row, int col)
463 {
464         char depths[32];
465
466         if (!p_ptr->depth)
467         {
468                 my_strcpy(depths, "Town", sizeof(depths));
469         }
470         else
471         {
472                 strnfmt(depths, sizeof(depths), "%d' (L%d)",
473                         p_ptr->depth * 50, p_ptr->depth);
474         }
475
476         /* Right-Adjust the "depth", and clear old values */
477         put_str(format("%-13s", depths), row, col);
478 }
479
480
481
482
483 /* Some simple wrapper functions */
484 static void prt_str(int row, int col) { prt_stat(A_STR, row, col); }
485 static void prt_dex(int row, int col) { prt_stat(A_DEX, row, col); }
486 static void prt_wis(int row, int col) { prt_stat(A_WIS, row, col); }
487 static void prt_int(int row, int col) { prt_stat(A_INT, row, col); }
488 static void prt_con(int row, int col) { prt_stat(A_CON, row, col); }
489 static void prt_chr(int row, int col) { prt_stat(A_CHR, row, col); }
490 static void prt_race(int row, int col) { prt_field(p_name + rp_ptr->name, row, col); }
491 static void prt_class(int row, int col) { prt_field(c_name + cp_ptr->name, row, col); }
492
493
494 /*
495  * Struct of sidebar handlers.
496  */
497 static const struct side_handler_t
498 {
499         void (*hook)(int, int);  /* int row, int col */
500         int priority;            /* 1 is most important (always displayed) */
501         game_event_type type;    /* PR_* flag this corresponds to */
502 } side_handlers[] =
503 {
504         { prt_race,    19, EVENT_RACE_CLASS },
505         { prt_title,   18, EVENT_PLAYERTITLE },
506         { prt_class,   22, EVENT_RACE_CLASS },
507         { prt_level,   10, EVENT_PLAYERLEVEL },
508         { prt_exp,     16, EVENT_EXPERIENCE },
509         { prt_gold,    11, EVENT_GOLD },
510         { prt_equippy, 17, EVENT_EQUIPMENT },
511         { prt_str,      6, EVENT_STATS },
512         { prt_int,      5, EVENT_STATS },
513         { prt_wis,      4, EVENT_STATS },
514         { prt_dex,      3, EVENT_STATS },
515         { prt_con,      2, EVENT_STATS },
516         { prt_chr,      1, EVENT_STATS },
517         { NULL,        15, 0 },
518         { prt_ac,       7, EVENT_AC },
519         { prt_hp,       8, EVENT_HP },
520         { prt_sp,       9, EVENT_MANA },
521         { NULL,        21, 0 },
522         { prt_health,  12, EVENT_MONSTERHEALTH },
523         { NULL,        20, 0 },
524         { NULL,        22, 0 },
525         { prt_speed,   13, EVENT_PLAYERSPEED }, /* Slow (-NN) / Fast (+NN) */
526         { prt_depth,   14, EVENT_DUNGEONLEVEL }, /* Lev NNN / NNNN ft */
527 };
528
529
530 /*
531  * This prints the sidebar, using a clever method which means that it will only
532  * print as much as can be displayed on <24-line screens.
533  *
534  * Each row is given a priority; the least important higher numbers and the most
535  * important lower numbers.  As the screen gets smaller, the rows start to
536  * disappear in the order of lowest to highest importance.
537  */
538 static void update_sidebar(game_event_type type, game_event_data *data, void *user)
539 {
540         int x, y, row;
541         int max_priority;
542         size_t i;
543
544
545         Term_get_size(&x, &y);
546
547         /* Keep the top and bottom lines clear. */
548         max_priority = y - 2;
549
550         /* Display list entries */
551         for (i = 0, row = 1; i < N_ELEMENTS(side_handlers); i++)
552         {
553                 const struct side_handler_t *hnd = &side_handlers[i];
554                 int priority = hnd->priority;
555                 bool from_bottom = FALSE;
556
557                 /* Negative means print from bottom */
558                 if (priority < 0)
559                 {
560                         priority = -priority;
561                         from_bottom = TRUE;
562                 }
563
564                 /* If this is high enough priority, display it */
565                 if (priority <= max_priority)
566                 {
567                         if (hnd->type == type && hnd->hook)
568                         {
569                                 if (from_bottom)
570                                         hnd->hook(Term->hgt - (N_ELEMENTS(side_handlers) - i), 0);
571                                 else
572                                     hnd->hook(row, 0);
573                         }
574
575                         /* Increment for next time */
576                         row++;
577                 }
578         }
579 }
580
581 static void hp_colour_change(game_event_type type, game_event_data *data, void *user)
582 {
583         /*
584          * hack:  redraw player, since the player's color
585          * now indicates approximate health.  Note that
586          * using this command when graphics mode is on
587          * causes the character to be a black square.
588          */
589         if ((hp_changes_color) && (arg_graphics == GRAPHICS_NONE))
590         {
591                 lite_spot(p_ptr->py, p_ptr->px);
592         }
593 }
594
595
596
597 /* ------------------------------------------------------------------------
598  * Status line display functions
599  * ------------------------------------------------------------------------ */
600
601 /* Simple macro to initialise structs */
602 #define S(s)            s, sizeof(s)
603
604 /*
605  * Struct to describe different timed effects
606  */
607 struct state_info
608 {
609         int value;
610         const char *str;
611         size_t len;
612         byte attr;
613 };
614
615 /* TMD_CUT descriptions */
616 static const struct state_info cut_data[] =
617 {
618         { 1000, S("Mortal wound"), TERM_L_RED },
619         {  200, S("Deep gash"),    TERM_RED },
620         {  100, S("Severe cut"),   TERM_RED },
621         {   50, S("Nasty cut"),    TERM_ORANGE },
622         {   25, S("Bad cut"),      TERM_ORANGE },
623         {   10, S("Light cut"),    TERM_YELLOW },
624         {    0, S("Graze"),        TERM_YELLOW },
625 };
626
627 /* TMD_STUN descriptions */
628 static const struct state_info stun_data[] =
629 {
630         {   100, S("Knocked out"), TERM_RED },
631         {    50, S("Heavy stun"),  TERM_ORANGE },
632         {     0, S("Stun"),        TERM_ORANGE },
633 };
634
635 /* p_ptr->hunger descriptions */
636 static const struct state_info hunger_data[] =
637 {
638         { PY_FOOD_FAINT, S("Faint"),    TERM_RED },
639         { PY_FOOD_WEAK,  S("Weak"),     TERM_ORANGE },
640         { PY_FOOD_ALERT, S("Hungry"),   TERM_YELLOW },
641         { PY_FOOD_FULL,  S(""),         TERM_L_GREEN },
642         { PY_FOOD_MAX,   S("Full"),     TERM_L_GREEN },
643         { PY_FOOD_UPPER, S("Gorged"),   TERM_GREEN },
644 };
645
646 /* For the various TMD_* effects */
647 static const struct state_info effects[] =
648 {
649         { TMD_BLIND,     S("Blind"),      TERM_ORANGE },
650         { TMD_PARALYZED, S("Paralyzed!"), TERM_RED },
651         { TMD_CONFUSED,  S("Confused"),   TERM_ORANGE },
652         { TMD_AFRAID,    S("Afraid"),     TERM_ORANGE },
653         { TMD_AFRAID,    S("Terror"),     TERM_ORANGE },
654         { TMD_IMAGE,     S("Halluc"),     TERM_ORANGE },
655         { TMD_POISONED,  S("Poisoned"),   TERM_ORANGE },
656         { TMD_PROTEVIL,  S("ProtEvil"),   TERM_L_GREEN },
657         { TMD_TELEPATHY, S("ESP"),        TERM_L_BLUE },
658         { TMD_INVULN,    S("Invuln"),     TERM_L_GREEN },
659         { TMD_HERO,      S("Hero"),       TERM_L_GREEN },
660         { TMD_SHERO,     S("Berserk"),    TERM_L_GREEN },
661         { TMD_STONESKIN, S("Stone"),      TERM_L_GREEN },
662         { TMD_SHIELD,    S("Shield"),     TERM_L_GREEN },
663         { TMD_BLESSED,   S("Blssd"),      TERM_L_GREEN },
664         { TMD_SINVIS,    S("SInvis"),     TERM_L_GREEN },
665         { TMD_SINFRA,    S("Infra"),      TERM_L_GREEN },
666         { TMD_OPP_ACID,  S("RAcid"),      TERM_SLATE },
667         { TMD_OPP_ELEC,  S("RElec"),      TERM_BLUE },
668         { TMD_OPP_FIRE,  S("RFire"),      TERM_RED },
669         { TMD_OPP_COLD,  S("RCold"),      TERM_WHITE },
670         { TMD_OPP_POIS,  S("RPois"),      TERM_GREEN },
671         { TMD_OPP_CONF,  S("RConf"),      TERM_VIOLET },
672         { TMD_AMNESIA,   S("Amnesiac"),   TERM_ORANGE },
673 };
674
675 #define PRINT_STATE(sym, data, index, row, col) \
676 { \
677         size_t i; \
678         \
679         for (i = 0; i < N_ELEMENTS(data); i++) \
680         { \
681                 if (index sym data[i].value) \
682                 { \
683                         if (data[i].str[0]) \
684                         { \
685                                 c_put_str(data[i].attr, data[i].str, row, col); \
686                                 return data[i].len; \
687                         } \
688                         else \
689                         { \
690                                 return 0; \
691                         } \
692                 } \
693         } \
694 }
695
696
697 /*
698  * Print cut indicator.
699  */
700 static size_t prt_cut(int row, int col)
701 {
702         PRINT_STATE(>, cut_data, p_ptr->timed[TMD_CUT], row, col);
703         return 0;
704 }
705
706
707 /*
708  * Print stun indicator.
709  */
710 static size_t prt_stun(int row, int col)
711 {
712         PRINT_STATE(>, stun_data, p_ptr->timed[TMD_STUN], row, col);
713         return 0;
714 }
715
716
717 /*
718  * Prints status of hunger
719  */
720 static size_t prt_hunger(int row, int col)
721 {
722         PRINT_STATE(<, hunger_data, p_ptr->food, row, col);
723         return 0;
724 }
725
726
727
728 /*
729  * Prints Searching, Resting, or 'count' status
730  * Display is always exactly 10 characters wide (see below)
731  *
732  * This function was a major bottleneck when resting, so a lot of
733  * the text formatting code was optimized in place below.
734  */
735 static size_t prt_state(int row, int col)
736 {
737         byte attr = TERM_WHITE;
738
739         char text[16] = "";
740
741
742         /* Resting */
743         if (p_ptr->resting)
744         {
745                 int i;
746                 int n = p_ptr->resting;
747
748                 /* Start with "Rest" */
749                 my_strcpy(text, "Rest      ", sizeof(text));
750
751                 /* Extensive (timed) rest */
752                 if (n >= 1000)
753                 {
754                         i = n / 100;
755                         text[9] = '0';
756                         text[8] = '0';
757                         text[7] = I2D(i % 10);
758                         if (i >= 10)
759                         {
760                                 i = i / 10;
761                                 text[6] = I2D(i % 10);
762                                 if (i >= 10)
763                                 {
764                                         text[5] = I2D(i / 10);
765                                 }
766                         }
767                 }
768
769                 /* Long (timed) rest */
770                 else if (n >= 100)
771                 {
772                         i = n;
773                         text[9] = I2D(i % 10);
774                         i = i / 10;
775                         text[8] = I2D(i % 10);
776                         text[7] = I2D(i / 10);
777                 }
778
779                 /* Medium (timed) rest */
780                 else if (n >= 10)
781                 {
782                         i = n;
783                         text[9] = I2D(i % 10);
784                         text[8] = I2D(i / 10);
785                 }
786
787                 /* Short (timed) rest */
788                 else if (n > 0)
789                 {
790                         i = n;
791                         text[9] = I2D(i);
792                 }
793
794                 /* Rest until healed */
795                 else if (n == -1)
796                 {
797                         text[5] = text[6] = text[7] = text[8] = text[9] = '*';
798                 }
799
800                 /* Rest until done */
801                 else if (n == -2)
802                 {
803                         text[5] = text[6] = text[7] = text[8] = text[9] = '&';
804                 }
805         }
806
807         /* Repeating */
808         else if (p_ptr->command_rep)
809         {
810                 if (p_ptr->command_rep > 999)
811                         strnfmt(text, sizeof(text), "Rep. %3d00", p_ptr->command_rep / 100);
812                 else
813                         strnfmt(text, sizeof(text), "Repeat %3d", p_ptr->command_rep);
814         }
815
816         /* Searching */
817         else if (p_ptr->searching)
818         {
819                 my_strcpy(text, "Searching ", sizeof(text));
820         }
821
822         /* Display the info (or blanks) */
823         c_put_str(attr, text, row, col);
824
825         return strlen(text);
826 }
827
828
829 /*
830  * Prints trap detection status
831  */
832 static size_t prt_dtrap(int row, int col)
833 {
834         byte info = cave_info2[p_ptr->py][p_ptr->px];
835
836         /* The player is in a trap-detected grid */
837         if (info & (CAVE2_DTRAP))
838         {
839                 /* The player is on the border */
840                 if (dtrap_edge(p_ptr->py, p_ptr->px))
841                         c_put_str(TERM_YELLOW, "DTrap", row, col);
842                 else
843                         c_put_str(TERM_GREEN, "DTrap", row, col);
844
845                 return 5;
846         }
847
848         return 0;
849 }
850
851
852
853 /*
854  * Print whether a character is studying or not.
855  */
856 static size_t prt_study(int row, int col)
857 {
858         if (p_ptr->new_spells)
859         {
860                 char *text = format("Study (%d)", p_ptr->new_spells);
861                 put_str(text, row, col);
862                 return strlen(text) + 1;
863         }
864
865         return 0;
866 }
867
868
869
870 /*
871  * Print all timed effects.
872  */
873 static size_t prt_tmd(int row, int col)
874 {
875         size_t i, len = 0;
876
877         for (i = 0; i < N_ELEMENTS(effects); i++)
878         {
879                 if (p_ptr->timed[effects[i].value])
880                 {
881                         c_put_str(effects[i].attr, effects[i].str, row, col + len);
882                         len += effects[i].len;
883                 }
884         }
885
886         return len;
887 }
888
889 /*
890  * Print mouse buttons
891  */
892 static size_t prt_buttons(int row, int col)
893 {
894         if (mouse_buttons)
895                 return button_print(row, col);
896
897         return 0;
898 }
899
900
901 /* Useful typedef */
902 typedef size_t status_f(int row, int col);
903
904 status_f *status_handlers[] =
905 { prt_state, prt_cut, prt_stun, prt_hunger, prt_study, prt_tmd, prt_dtrap,
906   prt_buttons };
907
908
909 /*
910  * Print the status line.
911  */
912 static void update_statusline(game_event_type type, game_event_data *data, void *user)
913 {
914         int row = Term->hgt - 1;
915         int col = 13;
916         size_t i;
917
918         /* Clear the remainder of the line */
919         prt("", row, col);
920
921         /* Display those which need redrawing */
922         for (i = 0; i < N_ELEMENTS(status_handlers); i++)
923                 col += status_handlers[i](row, col);
924 }
925
926
927