1 /*
2 	TODO:
3 
4 	- Faster healing
5 
6 	- Play in SLOW speed mode, and see how the rendering messes up.
7 
8 	+ Full original gameplay compliance
9 		+ Pass key
10 			- Lets you pass over monsters
11 			+ Instant chest open
12 			+ Instant pit climb
13 			* Pass key is available in Original and Enhanced modes
14 		+ Overlapped character attacking
15 			+ Hide floating damage
16 
17 	+ Free movement on high levels, 18 and lower, the monster sound is
18 	constantly going. It needs to be shut off, or the moves need to be
19 	slowed down a bit for Free mode, or something
20 	   + I guess you already fixed it? I see no problem in level 20.
21 
22 	- Smoother character/tile interaction
23 
24 
25 	DONE:
26 
27 	+ Joystick support
28 
29 	+ Monster movement timing, on DL 1 it seems to be more like 12 of the
30 	player's steps instead of 19. How come? steptime/global_steps timing is
31 	wrong somehow
32 		+ OK, I think I found a good compromise between synchronized and
33 		flexible, and it still gives you 19 steps like it should. Please
34 		verify.
35 
36 	+ Monsters pick up gold
37 		- Does it just disappear?
38 		395 ifp=47andm2=0orp=0thenp=32:goto397
39 		- I think this is just for the screen, to hide the gold so the monster
40 		sprite is clear
41 	+ Monsters who steal gold should run from you
42 	+ Improve battles
43 	+ Adjust level generation to match original, adjust if necessary
44 	+ Add sword level
45 	+ Better random monster movement, walk longer in one direction
46 	+ go through basic monster movement code and check if it does the same,
47 	+ number of mnsters spawned at level creation
48 
49 	+ Light spell can be turned off and on with 'o':
50 
51 		121 gosub113:ifl1=1thenl1=2:print"(home)light off":gosub112:goto42
52 		122 l1=1:gosub211:print"(home)light on":gosub112:goto42
53 		294 gosub113:ifsf=1thensf=0:print"(home)the sword is stolen!!":gosub112:goto296
54 
55 	+ light spell nullifies invisibility spell
56 	  377 ifv1=0orl1=1then379
57 
58 	+ Remove rendering related calls from game frame logic
59 
60 	+ Include monster movement sound somehow? It sounds cool, and it indicates
61 	the general speed of the monsters
62 
63 	+ There's some really wonky stuff going on in the window if I use GFX_GDI
64 	under Win32. Something to do with dirty rectangles? It's choppy, and it
65 	glitches the graphics as well. Can't debug without crashing in non-GDI
66 	though
67 
68 	+ C64 code:
69 		- Tag relevent portions of code with the associated C64 code, using a
70 		searchable "C64:" tag. We can then convert this C64 code to C and have
71 		all of the original Sword of Fargoal gameplay rules
72 
73 	+ Smarter monster movement
74 		+ Lateral movement when behind a wall, don't just bunch up in a corner
75 	    + creatures fall into traps
76 
77 	+ rule of spawning humans/creatures. spawn from 1 level below
78 
79 	+ Proper function of Beacon spell, IE:
80 		+ "Beacons are an added tool. When you find a mystical BEACON, pick a
81 		convenient spot and place it there by pressing "+'. Within the BEACON's
82 		square you are invisible to the monsters. From there you can TELEPORT to
83 		the TEMPLE by pressing the FIRE BUTTON ... without wasting a TELEPORT! ANY
84 		other time you TELEPORT using your spells, you will appear at the BEACON
85 		that you placed on that level!!"
86 		+ Should be invisible on a Beacon, monsters shouldn't crowd around
87 
88 	+ Cumulative 0-HP attacks... IE, if you lose zero during a round
89 	then add the current damage you did to the next round and attack all at
90 	once. This will allow for more instant slayings.
91 
92 	+ General game/message timing
93 	+ No escape from being attacked
94 		+ Can't escape in the same direction, or into a wall
95 
96 	OBSOLETE:
97 
98 	- Dice rolling... multiple d6 rolls to determine stats for everything?
99 
100 	- Game Research
101 		- Hitpoints increases per level
102 			- From Lv 1 to Lv 2, test game increased from max of 12HP to 27HP,
103 			and 38HP at Lv 3 (3d6?)
104 
105 		- Rate of health recovery
106 			- Lv 1-3: With 13 HP max, looks like about 10 or 12 seconds per
107 			point near the top of health, and 5 seconds near the middle,
108 			and what at the bottom?
109 		- Rate of monster movement
110 		- Monster strength, damage, amount and type per level, frequency of
111 		spawning
112 			-Types seen
113 				- Lv 1: Werebear, Barbarian, Hobgoblin (blue), Dwarf, Elf
114 			- Speed
115 				- Lv 1: 19 player moves per 1 monster move
116 			- Count
117 				- Lv 1: 4 monsters
118 
119 		- Effect of Skill points
120 			- How do they increase?
121 				- Battle Skill 57 after finishing Lv 1 and defeating about
122 				7 monsters
123 		- Effect of Enchanted Weapon
124 		- Trap damage
125 		- Level generation
126 		- Treasure
127 			- On level 1, counted 5 Golds, 3 Secrets
128 			- Gold added directly to EXP at Temple
129 		- Healing potion doesn't heal fully... looks more like 10-15 HP after
130 		one test on dungeon Lv 2
131 
132 
133 	CONSIDERATIONS:
134 
135 	- Assassins stay visible after fight?
136 		- Don't think so
137 
138 	- Battle adjustments
139 		- Slaying a weak or inferior foe should not add any BS,
140 		or perhaps just 1 BS
141 		- Slaying a monster could add only 1-3 instead of 1-5, maybe even only
142 		1-2
143 		- Slaying a strong or superior foe would allow the full BS range of
144 		1-5
145 		- Advancing an experience level should maybe only add 1-6 BS, or 1-8 BS
146 
147 
148 	NOTES:
149 
150 	Legend of C64 Sword of Fargoal variables: (add more)
151 
152 	a
153 	a()		Monster map marker?
154 	a%      human monster count
155 	a%()	Monster health array?
156 	a$()	Creature preposition
157 	a1      Counter for monster spawning?
158 	b       Joystick direction
159 	b()		Human map marker?
160 	b%      Creature monster count
161 	b%()	Human health array?
162 	b$()	Creature name
163 	b1		Beacon is placed
164 	be		Beacon spell count
165 	bs		Battle skill
166 	c		Monster ID?
167 	c()     sword level positions
168 	c$()	Human preposition
169 	cl      clear map after teleport
170 	d
171 	d()     Directions <-> Number conversion
172 	d%
173 	d%()
174 	d$()	Human name
175 	de
176 	e		Experience
177 	el		Level
178 	ep		Experience peak (for next level)
179 	f
180 	fa		Drift spell count
181 	fl
182 	fr      Fire button
183 	g%      hidden gold stashes
184 	gd      gold stashes count
185 	h%		Currently fighting monster health
186 	h()     sword level dirs
187 	h1		Temporary, hit damage, starting HP, etc.
188 	hi
189 	hp      Healing potions
190 	ht		Hit points
191 	i1      Counter for treasure maps
192 	iv		Invisible spell count
193 	j
194 	j%()
195 	jv      Joystick value
196 	k		Current tile
197 	l		Dungeon level
198 	l%		Monster level?
199 	l%()	Monster level array?
200 	l1		Light spell active
201 	lg		Light spell count
202 	lo
203 	m
204 	m%()	Monster position (creatures)
205 	m2      1 = creature, 0 = human
206 	mk		Monsters killed
207 	n
208 	n%()    Monster position (humans)
209 	o
210 	o%()	Monster colour array
211 	p
212 	pt      pit depth
213 	q       Player position
214 	p1
215 	pl		Enchanted weapon count
216 	ql		Quest Level, the level the sword is on
217 	r       trap type
218 	r()     room positions
219 	r%
220 	rg		Regeneration spell count
221 	r1
222 	r2
223 	s       Spawn time?
224 	s%		Monster Skill
225 	s%()	Monster Skill Array
226 	s1		Shield spell active
227 	so      sound related?
228 	s2      "
229 	s3      "
230 	s4      "
231 	s5      "
232 	s6      "
233 	sa%()   "
234 	sb%()   "
235 	sf		Have the Sword of Fargoal
236 	sh		Shield spell count
237 	sk
238 	sn      sprite number?
239 	sp      Healing counter
240 	sr		Start game
241 	sr%
242 	ss%()
243 	st%()
244 	t%()	Map array
245 	t		Treasure(=gold)
246 	t1		Max gold carry (increases by 100 per sack)
247 	t2		Timer?
248 	t3		Timer?
249 	th		Total hit points
250 	ti		Timer?
251 	tm		Total map count
252 	tn%()
253 	tp		Teleport spell count
254 	tr%(,)
255 	u%      number of spawnpoints - 1
256 	v()     Opposite directions
257 	v%		Spawning monster level
258 	v%()    Spawn positions
259 	v%      general variable?
260 	v1		Invisible spell active
261 	v3
262 	w%
263 	x		Temporary
264 	x%
265 	x()
266 	x2		Temporary?
267 	y
268 	y%
269 	y()
270 	y1
271 	z
272 
273 */
274 
275 #include "main.h"
276 #include "map.h"
277 #include "game.h"
278 #include "gfx.h"
279 #include "scroller.h"
280 
281 SAMPLE *human[7];
282 SAMPLE *creature[7];
283 SAMPLE *boom;
284 SAMPLE *crash;
285 SAMPLE *gold;
286 SAMPLE *pit;
287 SAMPLE *spell;
288 SAMPLE *step;
289 SAMPLE *attack;
290 SAMPLE *teleport;
291 SAMPLE *beacon;
292 SAMPLE *potion;
293 SAMPLE *ding;
294 SAMPLE *victory;
295 SAMPLE *up;
296 SAMPLE *down;
297 SAMPLE *climb;
298 SAMPLE *fight;
299 SAMPLE *item;
300 SAMPLE *levelup;
301 SAMPLE *intro;
302 SAMPLE *sacrifice;
303 SAMPLE *slain;
304 SAMPLE *crunch;
305 SAMPLE *monstermove;
306 
307 int extensions_nomonsterpause = 1;
308 int extensions_balance = 1;
309 int extensions_monsteraction = 1;
310 int extensions_controls = 1;
311 int extensions_overlapfight = 1;
312 int extensions_dungeons = 1;
313 int extensions_speed = 1;
314 
315 int notrunning = 1;
316 int won = 0;
317 int gameover = 0;
318 int spiral_map = 0;
319 int swordrun = 0;
320 int global_steps = 0; /* Step counter to trigger monster movement. */
321 int stepcount = 0;
322 int quest_number = 0;
323 
324 /* The global paused state, to halt the game during messages. */
325 int paused = 0;
326 
327 static int stats_redraw = 1;
328 
329 #define try_load_sample(__s, __n) \
330 	__s = load_sample (__n); \
331 	if (!__s) \
332 	{ \
333 		printf ("Could not find %s.\n", __n); \
334 		return 1; \
335 	}
336 
337 void
game_alt_tab(void)338 game_alt_tab (void)
339 {
340 	update_stats ();
341 	DR_add (0, -8, MAP_W - 1, MAP_H - 1);
342 }
343 
344 int
game_init(void)345 game_init (void)
346 {
347 	try_load_sample (human[0], "sfx/chop.wav");
348 	try_load_sample (human[1], "sfx/clang.wav");
349 	try_load_sample (human[2], "sfx/ugh.wav");	//ouch
350 	try_load_sample (human[3], "sfx/thump.wav");	//thud
351 	try_load_sample (human[4], "sfx/clink.wav");
352 	try_load_sample (human[5], "sfx/shriek.wav");
353 	try_load_sample (human[6], "sfx/slash.wav");
354 
355 	creature[0] = human[2];		//ugh
356 	try_load_sample (creature[1], "sfx/claw.wav");
357 	try_load_sample (creature[2], "sfx/crunch.wav");
358 	try_load_sample (creature[3], "sfx/gnarl.wav");
359 	creature[4] = creature[3];	//growl
360 	try_load_sample (creature[5], "sfx/shred.wav");
361 	creature[6] = human[3];		//thump
362 
363 	try_load_sample (boom, "sfx/boom.wav");
364 	try_load_sample (crash, "sfx/crash.wav");
365 	try_load_sample (gold, "sfx/gold.wav");
366 	try_load_sample (pit, "sfx/pit.wav");
367 	try_load_sample (spell, "sfx/spell.wav");
368 	try_load_sample (step, "sfx/step.wav");
369 	try_load_sample (attack, "sfx/attack.wav");
370 	try_load_sample (teleport, "sfx/teleport.wav");
371 	try_load_sample (beacon, "sfx/beacon.wav");
372 	try_load_sample (potion, "sfx/potion.wav");
373 	try_load_sample (ding, "sfx/ding.wav");
374 	try_load_sample (victory, "sfx/victory.wav");
375 	try_load_sample (up, "sfx/up.wav");
376 	try_load_sample (down, "sfx/down.wav");
377 	try_load_sample (climb, "sfx/climb.wav");
378 	try_load_sample (fight, "sfx/fight.wav");
379 	try_load_sample (item, "sfx/item.wav");
380 	try_load_sample (levelup, "sfx/levelup.wav");
381 	try_load_sample (intro, "sfx/intro.wav");
382 	try_load_sample (sacrifice, "sfx/sacrifice.wav");
383 	try_load_sample (slain, "sfx/slain.wav");
384 	try_load_sample (monstermove, "sfx/move.wav");
385 	crunch = creature[2];
386 
387 	if (graphics_init ())
388 		return 1;
389 	chars_init ();
390 	map_init ();
391 
392 	return 0;
393 }
394 
395 void
game_original(int health,int skill)396 game_original (int health, int skill)
397 {
398 	//   26 next:w%=0:gosub175:ifsr=1thensr=0:print"your quest begins!!";:goto28
399 	char_num = 1;
400 	player_create (0, 0, health, skill);
401 	swordlev = rnd (15, 20);
402 	game_start_new ();
403 }
404 /*
405 void
406 game_enhanced1 (void)
407 {
408 	swordlev = rnd (40, 50);
409 	game_start_new ();
410 }
411 
412 void
413 game_enhanced2 (void)
414 {
415 	swordlev = 100;
416 	game_start_new ();
417 }
418 */
419 void
game_start_new(void)420 game_start_new (void)
421 {
422 	list[1].current_level = 1;
423 	list[1].lev = 1;
424 	paused = 0;
425 	messages_init (NULL);
426 	message (FPS * 1, intro, "Your quest begins!!");
427 	gameover = 0;
428 	won = 0;
429 	notrunning = 0;
430 	swordrun = 0;
431 	monster_strength = 0;
432 	map_enter (SPOT_VOID, 0);
433 }
434 
435 
436 void
game_continue(void)437 game_continue (void)
438 {
439 	//   27 print"your quest continues!"
440 	{
441 		paused = 0;
442 		if (gameover)
443 			message (FPS * 1, NULL, "Thou hast already failed in thy quest.");
444 		else if (won)
445 			message (FPS * 1, NULL, "Thou hast already completed thy quest!!");
446 		else
447 			message (FPS * 1, NULL, "Your quest continues!");
448 		update_stats ();
449 		DR_add (0, -6, MAP_W - 1, MAP_H - 1);
450 	}
451 }
452 
453 void
game_exit(void)454 game_exit (void)
455 {
456 }
457 
458 static int hitx[10], hity[10];
459 static int hitv[10], hitt[10];
460 
461 
462 void
add_hit(int mx,int my,int v)463 add_hit (int mx, int my, int v)
464 {
465 	int i;
466 
467 	if (!extensions_overlapfight)
468 		return;
469 
470 	for (i = 0; i < 10; i++)
471 	{
472 		if (!hitt[i])
473 		{
474 			hitx[i] = mx * tw + tw / 2;
475 			hity[i] = TOP + my * th - th;
476 			hitv[i] = v;
477 			hitt[i] = FPS;
478 			return;
479 		}
480 	}
481 	return;
482 }
483 
484 
485 static void
_fly_hits(void)486 _fly_hits (void)
487 {
488 	int i;
489 
490 	for (i = 0; i < 10; i++)
491 	{
492 		if (hitt[i])
493 		{
494 			hity[i]--;
495 			hitt[i]--;
496 			DR_add (hitx[i] / tw - 1, (hity[i] - TOP) / th - 1, hitx[i] / tw + 1, (hity[i] - TOP) / th + 1);
497 		}
498 	}
499 }
500 
501 
502 static void
_draw_hits(void)503 _draw_hits (void)
504 {
505 	int i;
506 
507 	text_mode (-1);
508 	for (i = 0; i < 10; i++)
509 	{
510 		if (hitt[i])
511 		{
512 			if (hitv[i])
513 				textprintf_centre (page, font, hitx[i], hity[i], hitv[i] < 0 ? makecol (255, 0, 0) : makecol (0, 200, 0), "%i", abs (hitv[i]));
514 		}
515 	}
516 }
517 
518 
519 void
update_stats(void)520 update_stats (void)
521 {
522 	stats_redraw = 1;
523 }
524 
525 
get_steptime()526 int get_steptime()
527 {
528 	if(extensions_speed)
529 		return STEPTIME;
530 
531 	return STEPTIME*2;
532 }
533 
534 
535 void
game_frame(void)536 game_frame (void)
537 {
538 	int i;
539 
540 #if defined(DEBUGMODE) || defined(_DEBUG)
541 	if (key[KEY_F1])
542 		clear_to_color (screen, makecol (255, 0, 0));
543 
544 	if (key[KEY_F2])
545 		clear_to_color (page, makecol (0, 255, 0));
546 
547 	if (key[KEY_F3])
548 	{
549 		gameover = 1;
550 		spiral_map = MAP_W * MAP_H / 2;
551 	}
552 	if (key[KEY_F4])
553 	{
554 		map_hide_completely ();
555 		gameover = 0;
556 	}
557 	if (key[KEY_F5])
558 	{
559 		swordrun=5 * FPS;
560 	}
561 	if (key[KEY_F6])
562 	{
563 		swordrun=SWORD_TIME;
564 	}
565 
566 #endif
567 
568 	messages_update ();
569 
570 	if (!gameover && !won)
571 	{
572 		player_process (1);		/* 1 = id of player object */
573 	}
574 	else
575 	{
576 		if (spiral_map && frames % 2 == 0)
577 		{
578 			int x = 0, y = MAP_H;
579 			int dx = 0, dy = -1;
580 			int spiral_steps = MAP_W * MAP_H / 2 - spiral_map;
581 			int  w = MAP_W - 1, h = MAP_H;
582 			int row = w, column = h;
583 			for (i = 0; i <= spiral_steps; i++)
584 			{
585 				if (dx)
586 				{
587 					if (row)
588 						row--;
589 					else
590 					{
591 						dy = dx;
592 						dx = 0;
593 						h -= 2;
594 						column = h;
595 					}
596 				}
597 				if (dy)
598 				{
599 					if (column)
600 						column--;
601 					else
602 					{
603 						dx = -dy;
604 						dy = 0;
605 						w -= 2;
606 						row = w;
607 					}
608 				}
609 				x += dx;
610 				y += dy;
611 			}
612 			map_seen (x, y, 0);
613 			map_seen (MAP_W - 1 - x, MAP_H - 1 - y, 0);
614 			spiral_map--;
615 		}
616 	}
617 
618 	if (won)
619 	{
620 		won++;
621 		if (won > FPS * 5)
622 		{
623 			won = 1;
624 			scroller_init ();
625 		}
626 	}
627 
628 	if (stepcount)
629 	{
630 		if (!list[1].fighting && !paused)
631 			stepcount--;
632 	}
633 	else
634 	{
635 		stepcount = get_steptime();
636 		if (global_steps)
637 			global_steps--;
638 	}
639 
640 	if (!global_steps)
641 	{
642 		monsters_spawn ();
643 
644 		if(monster_count())
645 			message(extensions_nomonsterpause ? 0 : get_steptime()*2, monstermove, NULL);
646 
647 	}
648 
649 	for (i = 2; i < char_num; i++)
650 	{
651 		monster_process (i);
652 	}
653 
654 	if (!global_steps)
655 	{
656 		global_steps = MAX (1, 20 - list[1].current_level);
657 		stepcount = extensions_nomonsterpause ?
658 			(extensions_speed ? FPS : FPS*2) :
659 			get_steptime();
660 	}
661 
662 
663 	if (!won && !gameover && swordrun)
664 	{
665 		swordrun--;
666 		if ((swordrun % FPS) == 0)
667 			update_stats();
668 		if (!swordrun)
669 		{
670 			//  411 print"(down)(down)out of time!"
671 			map_hide_completely();
672 			message (FPS*3.5, crash, "Out of time!");
673 			map_crash();
674 			message(FPS, slain, "Game Over");
675 			player_die (1);
676 		}
677 	}
678 
679 	_fly_hits ();
680 }
681 
682 
683 void
game_render(void)684 game_render (void)
685 {
686 	int spellbook_x = 500;
687 	int spellbook_y = SCREEN_H - 90 + 15;
688 	int inventory_x = 340;
689 	int inventory_y = SCREEN_H - 90 + 15;
690 	int stats_x = 10;
691 	int stats_y = SCREEN_H - 90 + 15;
692 	int info_x = 180;
693 	int info_y = SCREEN_H - 90 + 15;
694 
695 	text_mode (-1);
696 
697 	messages_render ();
698 
699 	map_draw ();
700 
701 	if (stats_redraw || map_check_DRs (0, -3, MAP_W - 1, -3))
702 	{
703 		blit (title, page, 30, TOP - 3 * th, 30, TOP - 3 * th, 120, 8);
704 		textprintf (page, font, 30, 54,
705 			list[1].hit < list[1].maxhit ?
706 			list[1].hit < list[1].maxhit / 3 ?
707 			layout_color (LC_HURT) :
708 			layout_color (LC_HEALTH) :
709 			layout_color (LC_HEALTHY),
710 			"Hits: %i/%i", list[1].hit, list[1].maxhit);
711 
712 		blit (title, page, 280, 54, 280, 54, 80, 8);
713 		textprintf_centre (page, font, 320, 54, layout_color (LC_GOLD),
714 			"Gold: %i", list[1].gold);
715 
716 		if (swordrun)
717 		{
718 			int seconds = (swordrun - 1) / FPS;
719 			int blink = seconds & 1;
720 			blit (title, page, 0, 40, 0, 40, SCREEN_W, 8);
721 			blit (title, page, 480, 54, 480, 54, 130, 8);
722 			textprintf_right (page, font, SCREEN_W - 30, 40,
723 				blink ? layout_color (LC_TIME) :
724 				layout_color (LC_BLINK), "%s", list[1].sword ? "Carrying sword"
725 				: "Sword stolen");
726 			textprintf_right (page, font, SCREEN_W - 30, 54,
727 				blink ? layout_color (LC_TIME) :
728 				layout_color (LC_BLINK), "Time left %02i:%02i", seconds / 60, seconds % 60);
729 		}
730 	}
731 
732 	_draw_hits ();
733 
734 	if (stats_redraw)
735 	{
736 		blit (title, page, 0, SCREEN_H - 90, 0, SCREEN_H - 90, SCREEN_W, 90);
737 
738 		/* Print stats. */
739 		textprintf (page, font, stats_x, stats_y, layout_color (LC_STATS),
740 			"Experience %i", list[1].exp);
741 		textprintf (page, font, stats_x, stats_y + 22, layout_color (LC_STATS),
742 			"Level %i (%i)", list[1].lev, list[1].next);
743 		textprintf (page, font, stats_x, stats_y + 44, layout_color (LC_STATS),
744 			"Skill %i", list[1].dex);
745 
746 		/* Print additional info. */
747 		textprintf (page, font, info_x, info_y, layout_color (LC_INFO),
748 			"Slain foes %7i", list[1].slain_foes[0]);
749 		textprintf (page, font, info_x, info_y + 11, layout_color (LC_INFO),
750 			"Enchanted Sword+%2i", list[1].weapon);
751 		textprintf (page, font, info_x, info_y + 44, layout_color (LC_DUNGEON),
752 			"Dungeon level  %3i", list[1].current_level);
753 		textprintf (page, font, info_x, info_y + 55, layout_color (LC_DUNGEON),
754 			"Deepest Descent%3i", list[1].deepest_level);
755 
756 
757 		/* Display spellbook. */
758 		{
759 			int i;
760 
761 			for (i = 0; i < 6; i++)
762 			{
763 				int c = list[1].spells[i].amount ? layout_color (LC_SPELL) : layout_color (LC_NOSPELL);
764 
765 				if (list[1].spells[i].active)
766 					c =layout_color (LC_CAST);
767 				if (i == SPELL_REGENERATION && list[1].amulets_of_healing)
768 					textprintf (page, font, spellbook_x, spellbook_y + i * 11, c,
769 					"%-12s %2i+%i", spell_names[i], list[1].spells[i].amount,
770 						list[1].amulets_of_healing);
771 				else
772 				if (i == SPELL_LIGHT && list[1].amulets_of_light)
773 					textprintf (page, font, spellbook_x, spellbook_y + i * 11, c,
774 					"%-12s %2i+%i", spell_names[i], list[1].spells[i].amount,
775 						list[1].amulets_of_light);
776 				else
777 					textprintf (page, font, spellbook_x, spellbook_y + i * 11, c,
778 						"%-12s %2i", spell_names[i], list[1].spells[i].amount);
779 			}
780 		}
781 
782 		/* Display inventory. */
783 		textprintf (page, font, inventory_x, inventory_y, list[1].beaconx ? layout_color (LC_BEACON) : list[1].beacons ? layout_color (LC_BEACON) : layout_color (LC_EMPTY),
784 			"Beacons         %2i", list[1].beacons);
785 		textprintf (page, font, inventory_x, inventory_y + 22, list[1].sacks ? layout_color (LC_SACKS) : layout_color (LC_EMPTY),
786 			"Magic sacks     %2i", list[1].sacks);
787 		textprintf (page, font, inventory_x, inventory_y + 44, list[1].potions ? layout_color (LC_POTIONS) : layout_color (LC_NOPOTIONS),
788 			"Healing potions %2i", list[1].potions);
789 	}
790 
791 	if (USE_DRS)
792 	{
793 		acquire_screen ();
794 		map_blit_DRs ();
795 		if (messages_updated ())
796 		{
797 			blit (page, screen, 0, 0, 0, 0, SCREEN_W, 18);
798 		}
799 		if (stats_redraw)
800 		{
801 			if (swordrun)
802 				blit (page, screen, 0, 40, 0, 40, SCREEN_W, 8);
803 			blit (page, screen, 0, 54, 0, 54, SCREEN_W, 8);
804 			blit (page, screen, 0, SCREEN_H - 90, 0, SCREEN_H - 90, SCREEN_W, 90);
805 			stats_redraw = 0;
806 		}
807 		release_screen ();
808 	}
809 	else
810 	{
811 		DR_n = 0;
812 		blit (page, screen, 0, 0, 0, 0, SCREEN_W, SCREEN_H);
813 	}
814 }
815