1 /*
2  * PROPRIETARY INFORMATION.  This software is proprietary to POWDER
3  * Development, and is not to be reproduced, transmitted, or disclosed
4  * in any way without written permission.
5  *
6  * Produced by:	Jeff Lait
7  *
8  *      	POWDER Development
9  *
10  * NAME:        gfxengine.cpp ( POWDER Library, C++ )
11  *
12  * COMMENTS:
13  *	This simple set of routines allows a somewhat platform independent
14  *	way of drawing to the GBA.
15  */
16 
17 #include "gfxengine.h"
18 #include "gfxengine.h"
19 
20 #include "mygba.h"
21 
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <ctype.h>
25 
26 #include "gfx/all_bitmaps.h"
27 
28 #include "map.h"
29 #include "creature.h"
30 #include "glbdef.h"
31 #include "assert.h"
32 #include "item.h"
33 #include "control.h"
34 #include "msg.h"
35 #include "stylus.h"
36 #include "victory.h"
37 
38 // The number of 8x8 tiles to have.  The maximum for 256 colours
39 // on the GBA is 512.  SDL is theoritically infinite, except the
40 // 1024 and 2048 bits are used for flip flags.
41 #if defined(USING_SDL)
42 #define TILEARRAY	1023
43 #else
44 #define TILEARRAY	512
45 #endif
46 
47 // This is used for the maximum number the bitmap routines can grab.
48 // We can safely bump this up in the SDL case.
49 #if defined(USING_SDL)
50 // Since it is a 16x16 map, this is sufficient.
51 #define TILESTASH	256
52 #else
53 #define TILESTASH	50
54 #endif
55 
56 // Gets the number of bytes of a tile in our current tileset
57 #ifdef USING_SDL
58 #define BYTEPERTILE (glb_tilesets[glb_tileset].tilewidth*glb_tilesets[glb_tileset].tilewidth)
59 #define WORDPERTILE (glb_tilesets[glb_tileset].tilewidth*glb_tilesets[glb_tileset].tilewidth / 2)
60 #define TILEWIDTH (glb_tilesets[glb_tileset].tilewidth)
61 #define TILEHEIGHT (glb_tilesets[glb_tileset].tilewidth)
62 #else
63 #define BYTEPERTILE 8*8
64 #define WORDPERTILE 4*8
65 #define TILEWIDTH 8
66 #define TILEHEIGHT 8
67 #endif
68 
69 #ifdef USING_DS
70 #define RAW_SCREEN_WIDTH 256
71 #define RAW_SCREEN_HEIGHT 192
72 #define PLATE_WIDTH 256
73 #define PLATE_HEIGHT 192
74 #include <fat.h>
75 #else
76 #ifdef USING_SDL
77 #define RAW_SCREEN_WIDTH (TILEWIDTH * 32)
78 #define RAW_SCREEN_HEIGHT (TILEWIDTH * 24)
79 #define PLATE_WIDTH 256
80 #define PLATE_HEIGHT 192
81 #else
82 #define RAW_SCREEN_WIDTH 240
83 #define RAW_SCREEN_HEIGHT 160
84 #define PLATE_WIDTH 240
85 #define PLATE_HEIGHT 160
86 #endif
87 #endif
88 
89 // Global variables
90 int	glb_newframe = 0;
91 volatile int	glb_framecount = 0;
92 
93 int	glb_gfxmode = -1;
94 
95 // Tileset defaults to Akoi Meexx.
96 #ifndef USE_VIRTUAL_SCREEN
97 int	glb_tileset = 4;
98 #else
99 int	glb_tileset = 2;
100 int	glb_modetilesets[2] = { 2, 2 };
101 int	glb_tilesetmode = 0;
102 #endif
103 // Fonts default to shadowed.
104 int	glb_currentfont = 2;
105 
106 // This is our current tile reference array.
107 // glb_tileidx[TILE_NAME] gives the gba tile index.
108 // This has already been multiplied by 4!
109 u16	glb_tileidx[NUM_TILES];
110 
111 // This is the gba tile that ties to the given character.
112 u16	glb_charidx[256];
113 
114 #define MAX_COLOUR_CHAR 10
115 u8	*glb_colourchardata[MAX_COLOUR_CHAR];
116 
117 // glb_idxcount[gbaidx] gives the number of times that tile
118 // is currently used.
119 u16	glb_idxcount[TILEARRAY];
120 
121 // This is a map of our current 64x64 tile layout.
122 u16	*glb_tilemap, *glb_shadowmap, *glb_mobmap;
123 u16	*glb_abstilemap, *glb_absmobmap, *glb_absshadowmap;
124 
125 // This is 32x24 and matches the currently displayed characters.
126 u8	*glb_charmap;
127 
128 // Used in our compositing engine for building the paper doll
129 u8 *glb_comptiledata = 0;
130 int glb_lastdesttile;
131 
132 // Used in our greyscale sprite engine, must be global so we
133 // can resize this
134 u8 *glb_greyscaletiledata = 0;
135 
136 // Our one lone sprite.
137 u16	 glb_sprite = SPRITE_CURSOR;
138 
139 // This is the current scroll offset of where our tile layout matches
140 // with the tilemap.
141 int	glb_scrollx, glb_scrolly;
142 // This is the tile offset of the center tile.  We use this for inventory.
143 int	glb_offx, glb_offy;
144 // This is the pixel level scroll to nudge all the scrolling planes.
145 s8	glb_nudgex = 0, glb_nudgey = 0;
146 
147 // Current inventory position..  Defaults to where the first added
148 // item will go.
149 int	glb_invx = 1, glb_invy = 0;
150 MOB	*glb_invmob = 0;
151 
152 // Are we in sprite or dungeon mode?
153 bool	glb_usesprites = true;
154 
155 // bg2 tiles.  This maps to the screen with 240/8 = 30 to 160/8 = 20
156 // ratio.  Thus, there are are 600 tiles.
157 tile_info_ptr	 glb_bg2tiles;
158 tile_info_ptr	 glb_bg1tiles;
159 // This has the same format as tiles!  It is XxY for 8x8 blocks,
160 // of which there are 30x20.
161 char		*glb_bg2tiledata;
162 
163 // This the palette entry for each of the standard colours.
164 char		 glb_stdcolor[NUM_COLOURS];
165 
166 // This is the mapping for each colour in the sprite palette into
167 // the greyscale equivalent.
168 u8		*glb_spritegreyscale = 0;
169 
170 // Text look up tables...
171 const char *glb_texttable[] = {
172     "abcdefghij",
173     "klmnopqrst",
174     "uvwxyz" SYMBOLSTRING_HEART SYMBOLSTRING_MAGIC SYMBOLSTRING_NEXT SYMBOLSTRING_DLEVEL,
175     "ABCDEFGHIJ",
176     "KLMNOPQRST",
177     "UVWXYZ" SYMBOLSTRING_LEFT SYMBOLSTRING_RIGHT SYMBOLSTRING_UP SYMBOLSTRING_DOWN,
178     "0123456789",
179     "!@#$%^&*()",
180     "=-\\',./+_|",
181     "\"<>?[]{}`~",
182     ",.<>;:" SYMBOLSTRING_AC SYMBOLSTRING_TRIDUDE SYMBOLSTRING_CURSOR " ",
183     SYMBOLSTRING_UNIQUE "         ",
184     0
185 };
186 
187 u8
rgbtogrey(u8 cr,u8 cg,u8 cb)188 rgbtogrey(u8 cr, u8 cg, u8 cb)
189 {
190     // Roughly a 5:6:1 weighting, but scaled up so we
191     // get to divide by 16 for some meaningless efficiency.
192     int 	grey = cg * 8 + cr * 6 + cb * 2;
193     grey += 7;
194     grey /= 16;
195     if (grey > 255)
196 	grey = 255;
197 
198     return grey;
199 }
200 
201 #ifdef USING_SDL
202 static int
rawtoplate_x(int x)203 rawtoplate_x(int x)
204 {
205     int	sx =  (int) ((x * PLATE_WIDTH) / ((float)(RAW_SCREEN_WIDTH)) + 0.5);
206     if (sx >= PLATE_WIDTH)
207 	sx = PLATE_WIDTH-1;
208     return sx;
209 }
210 
211 static int
rawtoplate_y(int y)212 rawtoplate_y(int y)
213 {
214     int	sy =  (int) ((y * PLATE_HEIGHT) / ((float)(RAW_SCREEN_HEIGHT)) + 0.5);
215     if (sy >= PLATE_HEIGHT)
216 	sy = PLATE_HEIGHT-1;
217     return sy;
218 }
219 #else
220 static int
rawtoplate_x(int x)221 rawtoplate_x(int x)
222 {
223     return x;
224 }
225 
226 static int
rawtoplate_y(int y)227 rawtoplate_y(int y)
228 {
229     return y;
230 }
231 #endif
232 
233 int
gfx_getchartile(char c)234 gfx_getchartile(char c)
235 {
236     int		textline;
237     const char *text;
238     int		pos;
239 
240     // Special cases...
241     switch (c)
242     {
243 	case '\b':
244 	    c = SYMBOL_LEFT;
245 	    break;
246 	case '\n':
247 	case '\r':
248 	    c = SYMBOL_NEXT;
249 	    break;
250 	case '\t':
251 	    c = SYMBOL_UP;
252 	    break;
253     }
254 
255     pos = 0;
256     textline = 0;
257     while (glb_texttable[textline])
258     {
259 	text = glb_texttable[textline];
260 	while (*text)
261 	{
262 	    if (*text == c)
263 		return pos;
264 	    pos++;
265 	    text++;
266 	}
267 	textline++;
268     }
269     // Failure, lower case a.
270     return 1;
271 }
272 
273 u16
gfx_lockColourCharTile(u8 c,COLOUR_NAMES colour,u8 * result)274 gfx_lockColourCharTile(u8 c, COLOUR_NAMES colour, u8 *result)
275 {
276     u8		virtualtile, charnum;
277     int		idx, sourceidx;
278 
279     // Find a free colour tile in our desired range.
280     for (virtualtile = COLOURED_SYMBOLS; virtualtile < COLOURED_SYMBOLS + MAX_COLOUR_CHAR; virtualtile++)
281     {
282 	if (glb_charidx[virtualtile] == INVALID_TILEIDX)
283 	{
284 	    // This is a free index!
285 	    break;
286 	}
287     }
288     // Check to see if we failed, if so, return the no tile.
289     // Flag that we shouldn't unlock this tile.
290     if (virtualtile == COLOURED_SYMBOLS + MAX_COLOUR_CHAR)
291     {
292 	*result = 0xff;
293 	return gfx_lookupTile(TILE_NOTILE);
294     }
295 
296     // Now try and allocate a tile.
297     idx = gfx_findFreeTile(1);
298     if (idx == INVALID_TILEIDX)
299     {
300 	// Bah, ran out of tiles!
301 	*result = 0xff;
302 	return gfx_lookupTile(TILE_NOTILE);
303     }
304 
305     // Now find what origin tile we want to map from.
306     sourceidx = gfx_getchartile(c);
307 
308     charnum = virtualtile - COLOURED_SYMBOLS;
309     // Check to see if our tiledata is available.
310     if (!glb_colourchardata[charnum])
311 	glb_colourchardata[charnum] = (u8 *) new u16[WORDPERTILE];
312 
313     u8		*dst;
314     const u8	*src;
315     u16 	*palette = (u16 *) glb_tilesets[glb_tileset].palette;
316     int		 i;
317 
318     dst = glb_colourchardata[charnum];
319     src = (const u8*)&glb_tilesets[glb_tileset].alphabet[glb_currentfont][sourceidx*BYTEPERTILE];
320 
321     for (i = 0; i < BYTEPERTILE; i++)
322     {
323 	// Anything not black or transparent is turned into
324 	// our desired colour.
325 	if (*src == 0 || *src == glb_stdcolor[COLOUR_BLACK] || !palette[*src] || palette[*src] == 0x842)
326 	    *dst = *src;
327 	else
328 	    *dst = glb_stdcolor[colour];
329 	dst++;
330 	src++;
331     }
332 
333     // And send the resulting tile to VRAM.
334     ham_ReloadTileGfx(glb_bg1tiles,
335 		(u16*) glb_colourchardata[charnum],
336 		idx,
337 		1);
338     glb_idxcount[idx]++;
339     glb_charidx[virtualtile] = idx;
340 
341     // When we unlock, this is the tile we'll actually unlock!
342     *result = virtualtile;
343 
344     return idx;
345 }
346 
347 u16
gfx_lockCharTile(u8 c,u8 * result)348 gfx_lockCharTile(u8 c, u8 *result)
349 {
350     int		idx;
351     int		sourceidx;
352 
353     // Check our character tile array to see if it is already done.
354     *result = c;
355 
356     idx = glb_charidx[c];
357     if (idx != INVALID_TILEIDX)
358     {
359 	// Great, already allocated, inc and return.
360 	glb_idxcount[idx]++;
361 	return idx;
362     }
363 
364     // Must allocate it...
365     idx = gfx_findFreeTile(1);
366 
367     if (idx != INVALID_TILEIDX)
368     {
369 	sourceidx = gfx_getchartile(c);
370 	ham_ReloadTileGfx(glb_bg1tiles,
371 		(u16*)(&glb_tilesets[glb_tileset].alphabet[glb_currentfont][sourceidx * BYTEPERTILE]),
372 		idx,
373 		1);
374 	glb_idxcount[idx]++;
375 	glb_charidx[c] = idx;
376 	return idx;
377     }
378 
379     // Damn, failure to allocate!
380     UT_ASSERT(!"Failure to allocate char tile");
381     // Flag that we shouldn't unlock this tile.
382     *result = 0xff;
383     return gfx_lookupTile(TILE_NOTILE);
384 }
385 
386 void
gfx_unlockCharTile(u8 c)387 gfx_unlockCharTile(u8 c)
388 {
389     u16		idx;
390 
391     if (c == 0xff)
392 	return;		// Blank dude.
393 
394     idx = glb_charidx[c];
395 
396     UT_ASSERT(idx != INVALID_TILEIDX);
397     if (idx == INVALID_TILEIDX)
398 	return;
399 
400     UT_ASSERT(glb_idxcount[idx]);
401     if (glb_idxcount[idx])
402 	glb_idxcount[idx]--;
403     if (!glb_idxcount[idx])
404     {
405 	// TIle is now free.
406 	glb_charidx[c] = INVALID_TILEIDX;
407     }
408 }
409 
410 u16
gfx_findFreeTile(int size)411 gfx_findFreeTile(int size)
412 {
413     int		tile, j;
414 
415     for (tile = 0; tile <= TILEARRAY - size; tile++)
416     {
417 	if (glb_idxcount[tile])
418 	    continue;
419 
420 	// We have a zero, check if next size are zero..
421 	for (j = 0; j < size; j++)
422 	{
423 	    if (glb_idxcount[tile+j])
424 	    {
425 		tile = tile+j;
426 		break;
427 	    }
428 	}
429 
430 	// Making it here implies that we found a free tile.
431 	if (j == size)
432 	    return tile;
433     }
434 
435     // Failure to find a free one.
436     return INVALID_TILEIDX;
437 }
438 
439 u16
gfx_lookupTile(TILE_NAMES tile)440 gfx_lookupTile(TILE_NAMES tile)
441 {
442     if (tile == INVALID_TILEIDX)
443 	return INVALID_TILEIDX;
444 
445     return glb_tileidx[tile];
446 }
447 
448 u16
gfx_lockTile(TILE_NAMES tile,TILE_NAMES * result)449 gfx_lockTile(TILE_NAMES tile, TILE_NAMES *result)
450 {
451     u16		idx;
452 
453     if (result)
454 	*result = tile;
455 
456     if (tile == INVALID_TILEIDX)
457 	return INVALID_TILEIDX;
458     idx = glb_tileidx[tile];
459     if (idx != INVALID_TILEIDX)
460     {
461 	if (tile == TILE_VOID || tile == TILE_NOTILE)
462 	{
463 	    // We only lock these tiles once ever.
464 	    return idx;
465 	}
466 	glb_idxcount[idx]++;
467 	glb_idxcount[idx+1]++;
468 	glb_idxcount[idx+2]++;
469 	glb_idxcount[idx+3]++;
470 	return idx;
471     }
472     idx = gfx_findFreeTile(4);
473     if (idx != INVALID_TILEIDX)
474     {
475 	// A free index!  Return it.
476 	ham_ReloadTileGfx(glb_bg1tiles,
477 		(u16*)(&glb_tilesets[glb_tileset].dungeon[tile * 4 * BYTEPERTILE]),
478 		idx,
479 		4);
480 	glb_idxcount[idx]++;
481 	glb_idxcount[idx+1]++;
482 	glb_idxcount[idx+2]++;
483 	glb_idxcount[idx+3]++;
484 	glb_tileidx[tile] = idx;
485 	return idx;
486     }
487     // Failed to find free...
488     UT_ASSERT(!"FAILED TO ALLOC TILE!");
489     if (result)
490 	*result = (TILE_NAMES) INVALID_TILEIDX;
491     return gfx_lookupTile(TILE_NOTILE);
492 }
493 
494 void
gfx_forceLockTile(TILE_NAMES tile,int mincount)495 gfx_forceLockTile(TILE_NAMES tile, int mincount)
496 {
497     int		idx, j;
498 
499     // See if our tile is already locked.
500     // Problem: If we have a
501     idx = gfx_lookupTile(tile);
502     if (idx == INVALID_TILEIDX)
503     {
504 	// Tile not yet locked, lock it!
505 	idx = gfx_lockTile(tile, 0);
506     }
507 
508     // Verify we have the minimum count.
509     for (j = 0; j < 4; j++)
510     {
511 	if (glb_idxcount[idx+j] < mincount)
512 	    glb_idxcount[idx+j] = mincount;
513     }
514 }
515 
516 void
gfx_unlockTile(TILE_NAMES tile)517 gfx_unlockTile(TILE_NAMES tile)
518 {
519     u16		idx;
520 
521     if (tile == INVALID_TILEIDX)
522 	return;
523 
524     if (tile == TILE_NOTILE || tile == TILE_VOID)
525     {
526 	// Never unlock these special tiles.
527 	// We need to be able to always procur them
528 	return;
529     }
530 
531     idx = glb_tileidx[tile];
532 
533     UT_ASSERT(idx != INVALID_TILEIDX);
534     if (idx == INVALID_TILEIDX)
535 	return;
536 
537     // Must have already locked it...
538     UT_ASSERT(glb_idxcount[idx]);
539     UT_ASSERT(glb_idxcount[idx+1]);
540     UT_ASSERT(glb_idxcount[idx+2]);
541     UT_ASSERT(glb_idxcount[idx+3]);
542     glb_idxcount[idx]--;
543     glb_idxcount[idx+1]--;
544     glb_idxcount[idx+2]--;
545     glb_idxcount[idx+3]--;
546     if (!glb_idxcount[idx])
547     {
548 	// Tile is now free...
549 	glb_tileidx[tile] = INVALID_TILEIDX;
550     }
551 }
552 
553 int
gfx_getNumFreeTiles()554 gfx_getNumFreeTiles()
555 {
556     int		idx, num;
557 
558     num = 0;
559     for (idx = 0; idx < TILEARRAY; idx++)
560     {
561 	if (glb_idxcount[idx] == 0)
562 	    num++;
563     }
564     return num;
565 }
566 
567 //
568 // VBL func
569 //
vblFunc()570 void vblFunc()
571 {
572     glb_newframe = 1;
573     glb_framecount++;
574 }
575 
576 void
gfx_buildstdcolors()577 gfx_buildstdcolors()
578 {
579     COLOUR_NAMES		colour;
580 
581     FOREACH_COLOUR(colour)
582     {
583 	glb_stdcolor[colour] = gfx_lookupcolor(glb_colourdefs[colour].red,
584 				    glb_colourdefs[colour].green,
585 				    glb_colourdefs[colour].blue);
586     }
587     // Build the standard colours...
588     glb_stdcolor[COLOUR_INVISIBLE] = 0;		// Always true.
589 
590     // This is also a good time to update our grey table if we have it.
591     gfx_updatespritegreytable();
592 }
593 
594 void
gfx_init()595 gfx_init()
596 {
597     // Initialize everything...
598     ham_Init();
599 
600     // Install our interrupt handler
601 #if defined(USING_SDL) || defined(USING_DS) || defined(NO_HAM)
602     ham_StartIntHandler(INT_TYPE_VBL, &vblFunc);
603 #else
604     ham_StartIntHandler(INT_TYPE_VBL, (void *)&vblFunc);
605 #endif
606 
607     // These maps store the TILE_NAMES currently at each map position.
608     // The absolute version do the same for absolute overlays.
609     // This allows us to avoid double writes, and load tiles into
610     // VRAM as necessary.
611     // 0xff is used as INVALID_TILEIDX is 65535.
612 
613     glb_tilemap = new u16[32*32];
614     glb_shadowmap = new u16[32*32];
615     glb_mobmap = new u16[32*32];
616     glb_abstilemap = new u16[17*12];
617     glb_absmobmap = new u16[17*12];
618     glb_absshadowmap = new u16[17*12];
619     glb_charmap = new u8[32*24];
620 
621     memset(glb_tilemap, 0xff, 32*32 * sizeof(u16));
622     memset(glb_shadowmap, 0xff, 32*32 * sizeof(u16));
623     memset(glb_mobmap, 0xff, 32*32 * sizeof(u16));
624     memset(glb_abstilemap, 0xff, 17*12*sizeof(u16));
625     memset(glb_absmobmap, 0xff, 17*12*sizeof(u16));
626     memset(glb_absshadowmap, 0xff, 17*12*sizeof(u16));
627     memset(glb_charmap, 0xff, 32*24);
628 }
629 
630 void
gfx_reblitslugandblood()631 gfx_reblitslugandblood()
632 {
633     u16			*screen;
634     int			x, y;
635 
636     screen = hamfake_lockScreen();
637 #if defined(USING_DS) || defined(USING_SDL)
638     // Scroll back the screen since it was in GBA coords.
639     screen -= TILEWIDTH + 2*TILEHEIGHT * RAW_SCREEN_WIDTH;
640 
641     if (RAW_SCREEN_WIDTH != PLATE_WIDTH ||
642 	RAW_SCREEN_HEIGHT != PLATE_HEIGHT)
643     {
644 	for (y = 0; y < RAW_SCREEN_HEIGHT; y++)
645 	{
646 	    int	sy = rawtoplate_y(y);
647 	    for (x = 0; x < RAW_SCREEN_WIDTH; x++)
648 	    {
649 		int	sx = rawtoplate_x(x);
650 
651 		screen[y*RAW_SCREEN_WIDTH+x] = bmp_slug_and_blood[sy*PLATE_WIDTH+sx];
652 	    }
653 	}
654     }
655     else
656     {
657 	for (y = 0; y < PLATE_HEIGHT; y++)
658 	{
659 	    for (x = 0; x < PLATE_WIDTH; x++)
660 	    {
661 		screen[y*RAW_SCREEN_WIDTH+x] = bmp_slug_and_blood[y*PLATE_WIDTH+x];
662 	    }
663 	}
664     }
665 #else
666     for (y = 0; y < PLATE_WIDTH*PLATE_HEIGHT; y++)
667     {
668 	screen[y] = bmp_slug_and_blood[y];
669     }
670 #endif
671     hamfake_unlockScreen(screen);
672 }
673 
674 void
gfx_setmode(int mode)675 gfx_setmode(int mode)
676 {
677     int			x, y;
678     map_info_ptr	bg2mapset;
679 
680     // A no-op.
681     if (mode == glb_gfxmode)
682 	return;
683 
684     glb_gfxmode = mode;
685 
686     if (mode == 3)
687     {
688 	// Intro screen...
689 	ham_SetBgMode(3);
690 
691 	gfx_reblitslugandblood();
692 
693 	// Ensure we have current sprite date.
694 	hamfake_LoadSpritePal((void *)glb_tilesets[glb_tileset].spritepalette, 512);
695 	hamfake_ReloadSpriteGfx((u16*)(&glb_tilesets[glb_tileset].sprite[glb_sprite*4*BYTEPERTILE]),
696 			0, 4);
697 
698 	// NOTE: This actually copies incorrect data!  Likely due to it
699 	// using 32bit copies or ignoring waitstates.
700 	//    memcpy( (unsigned short *) 0x06000000,
701 	//	    bmp_slug_and_blood,
702 	//	    38400*2 );
703 	return;
704     }
705 
706     // Must be tiled mode.
707     UT_ASSERT(mode == 0);
708 
709     // This is all four bgs, no zooming.
710     ham_SetBgMode(0);
711 
712     // Wipe any charmap left over from raw mode.
713     memset(glb_charmap, 0xff, 32*24);
714 
715     ham_LoadBGPal((void *)glb_tilesets[glb_tileset].palette, 512);
716     hamfake_LoadSpritePal((void *)glb_tilesets[glb_tileset].spritepalette, 512);
717 
718     // So, what are our layers?
719 
720     // 0: 32x32: Text and minimap.
721     // 1: 64x64: Terrain tiles
722     // 2: 64x64: Monters/Item tiles
723     // 3: 64x64: Shadow tiles
724 
725 #if 1
726     // We want a 32x32 as we only will use one screen worth.
727     ham_bg[0].mi = ham_InitMapEmptySet(0, 0);
728 
729     // We want a 64x64 screen.
730     ham_bg[1].mi = ham_InitMapEmptySet(3, 0);
731 
732     // 64x64 map
733     bg2mapset = ham_InitMapEmptySet(3, 0);
734 
735     // We want a 64x64 screen.
736     ham_bg[3].mi = ham_InitMapEmptySet(3, 0);
737 #else
738     // We want a 32x32 as we only will use one screen worth.
739     ham_bg[0].mi = ham_InitMapEmptySet(0, 0);
740 
741     // We want a 64x64 screen.
742     ham_bg[1].mi = ham_bg[0].mi;
743 
744     // 32 x 32 map.
745     bg2mapset = ham_bg[0].mi;
746 
747     // We want a 64x64 screen.
748     ham_bg[3].mi = ham_bg[0].mi;
749 #endif
750 
751     ham_bg[1].ti = ham_InitTileEmptySet(TILEARRAY, 1, 1);
752 
753     // Init the dungeon tile set...
754     //   ** EXCESSIVE PROFANITY DETECTED **
755     //   ** DELETING OFFENDING LINES **
756     //   ** RESUMING COMMENT **
757     // to respond to so FOAD, HTH, HAND.
758 
759     // Thus, we now create a single tile set of TILEARRAY size.
760     // NOTE: We now share this with the bitmap cache, so that
761     // code currently assumes it is contiguous and uses 8x8 rather
762     // than 16x16, so for now we'll keep them the same.
763     //ham_bg[1].ti = ham_InitTileSet((void *)&DUNGEONTILES,
764     //				(NUM_TILES-3) * 4 * WORDPERTILE, 1, 1);
765     glb_bg1tiles = ham_bg[1].ti;
766 
767     ham_bg[0].ti = ham_bg[1].ti;
768 
769     // Initialize our arrays to be all empty...
770     memset(glb_tileidx, 0xff, sizeof(u16) * NUM_TILES);
771     memset(glb_charidx, 0xff, sizeof(u16) * 256);
772     memset(glb_idxcount, 0, sizeof(u16) * TILEARRAY);
773 
774     // Create the level 2 bg, where we do all our crazy pixel level
775     // stuff.
776     // You would think this size would have to be 600.  That crashes
777     // due to out of vram, yet I seem to be able to write to it just
778     // fine?  WTF?
779     // Calculations show that we can't fit, even in an ideal case,
780     // this much data in the 64k available in the tile/map data.
781     // One option is to use the object data set (which is 32k), except
782     // the actual screen required is 37.5k.  THus, we instead create
783     // a tilestash which we can read from & deal with that way.
784     // glb_bg2tiles = ham_InitTileEmptySet(TILESTASH, 1, 0);
785     glb_bg2tiles = glb_bg1tiles;
786 
787     // Highest priority as it will sit on top.
788     ham_InitBg(0, 1, 0, 0);
789 
790     ham_InitBg(1, 1, 3, 0);
791 
792     // Create our level 3 background, where we have our lighting overlay
793     // and put blood sprites, etc.
794     ham_bg[3].ti = ham_bg[1].ti;
795     // Above the lower map, but below the text.
796     ham_InitBg(3, 1, 1, 0);
797 
798     memset(glb_tilemap, 0xff, 32*32 * sizeof(u16));
799     memset(glb_shadowmap, 0xff, 32*32 * sizeof(u16));
800     memset(glb_mobmap, 0xff, 32*32 * sizeof(u16));
801     memset(glb_abstilemap, 0xff, 17*12*sizeof(u16));
802     memset(glb_absmobmap, 0xff, 17*12*sizeof(u16));
803     memset(glb_absshadowmap, 0xff, 17*12*sizeof(u16));
804     memset(glb_charmap, 0xff, 32*24);
805 
806     ham_bg[2].ti = glb_bg2tiles;
807     ham_bg[2].mi = bg2mapset;
808 
809     // We allocate a half sized block as u16 and cast back to char
810     // to ensure we are aligned to u16.
811     glb_bg2tiledata = (char *) new u16[WORDPERTILE*TILESTASH];
812     memset(glb_bg2tiledata, 0, BYTEPERTILE*TILESTASH);
813 
814     // No rot.  Above the ground but below the shadow.
815     ham_InitBg(2, 1, 2, 0);
816 
817     gfx_buildstdcolors();
818 
819     // We always want the no tile locked so we can show it when
820     // things go bad...
821     // We want to lock VOID first as it will be tile 0, and thus
822     // our default screen will be sweet, sweet, black.
823     // Actaully, there is apparently no guarantee that the initial
824     // tile values are 0.  Thus, we must manually set all of our
825     // tile planes to void here.
826     int			voidtileidx;
827 
828     // We know these locks must always succeed so we don't care to stash
829     // the result.  In any case, we have engineered it that they are
830     // never freed.
831     voidtileidx = gfx_lockTile(TILE_VOID, 0);
832     gfx_lockTile(TILE_NOTILE, 0);
833 
834     for (y = 0; y < 64; y++)
835     {
836 	for (x = 0; x < 64; x++)
837 	{
838 	    if (x < 32 && y < 32)
839 	    {
840 		ham_SetMapTile(0, x, y, voidtileidx);
841 	    }
842 	    ham_SetMapTile(1, x, y, voidtileidx);
843 	    ham_SetMapTile(2, x, y, voidtileidx);
844 	    ham_SetMapTile(3, x, y, voidtileidx);
845 	}
846     }
847 
848     // Load the sprite.
849     hamfake_ReloadSpriteGfx((u16*)(&glb_tilesets[glb_tileset].sprite[glb_sprite*4*BYTEPERTILE]),
850 		    0, 4);
851 }
852 
853 
854 //
855 // This forces a rebuilding of all the tiles from our cache to the
856 // ham space.
857 //
858 void
gfx_refreshtiles()859 gfx_refreshtiles()
860 {
861     int		x, y, tile, tileidx;
862 
863     // Ignore this if we are not in a graphics mode.
864     if (glb_gfxmode)
865 	return;
866 
867     // A refresh will also clear anything in the abs maps, so we
868     // first unlock those tiles.
869     for (y = 0; y < 12; y++)
870     {
871 	for (x = 0; x < 17; x++)
872 	{
873 	    tile = glb_abstilemap[y * 17 + x];
874 	    if (tile != INVALID_TILEIDX)
875 	    {
876 		gfx_unlockTile((TILE_NAMES)tile);
877 		glb_abstilemap[y * 17 + x] = INVALID_TILEIDX;
878 	    }
879 	    tile = glb_absshadowmap[y * 17 + x];
880 	    if (tile != INVALID_TILEIDX)
881 	    {
882 		gfx_unlockTile((TILE_NAMES)tile);
883 		glb_absshadowmap[y * 17 + x] = INVALID_TILEIDX;
884 	    }
885 	    tile = glb_absmobmap[y * 17 + x];
886 	    if (tile != INVALID_TILEIDX)
887 	    {
888 		gfx_unlockTile((TILE_NAMES)tile);
889 		glb_absmobmap[y * 17 + x] = INVALID_TILEIDX;
890 	    }
891 	}
892     }
893 
894     // TODO: Insert map might prove a tad bit more efficient, though
895     // would need a full size scratch space.
896     for (y = 0; y < 32; y++)
897     {
898 	for (x = 0; x < 32; x++)
899 	{
900 	    tile = glb_tilemap[(y + glb_scrolly) * 32 + x + glb_scrollx];
901 	    tileidx = gfx_lockTile((TILE_NAMES)tile, (TILE_NAMES *) &tile);
902 	    ham_SetMapTile(1, x*2, y*2, tileidx);
903 	    ham_SetMapTile(1, x*2+1, y*2, tileidx+1);
904 	    ham_SetMapTile(1, x*2, y*2+1, tileidx+2);
905 	    ham_SetMapTile(1, x*2+1, y*2+1, tileidx+3);
906 
907 	    // The above lock should be a double count, so we unlock
908 	    // afterwards.  Any write to glb_tilemap must have done
909 	    // a lock!
910 	    gfx_unlockTile((TILE_NAMES)tile);
911 	}
912     }
913 
914     // Update overlay buffer...
915     for (y = 0; y < 32; y++)
916     {
917 	for (x = 0; x < 32; x++)
918 	{
919 	    tile = glb_shadowmap[(y + glb_scrolly) * 32 + x + glb_scrollx];
920 	    tileidx = gfx_lockTile((TILE_NAMES)tile, (TILE_NAMES *) &tile);
921 	    ham_SetMapTile(3, x*2, y*2, tileidx);
922 	    ham_SetMapTile(3, x*2+1, y*2, tileidx+1);
923 	    ham_SetMapTile(3, x*2, y*2+1, tileidx+2);
924 	    ham_SetMapTile(3, x*2+1, y*2+1, tileidx+3);
925 	    // See comment above why this is needed.
926 	    gfx_unlockTile((TILE_NAMES)tile);
927 	}
928     }
929     // Update mob buffer...
930     for (y = 0; y < 32; y++)
931     {
932 	for (x = 0; x < 32; x++)
933 	{
934 	    tile = glb_mobmap[(y + glb_scrolly) * 32 + x + glb_scrollx];
935 	    tileidx = gfx_lockTile((TILE_NAMES)tile, (TILE_NAMES *) &tile);
936 	    ham_SetMapTile(2, x*2, y*2, tileidx);
937 	    ham_SetMapTile(2, x*2+1, y*2, tileidx+1);
938 	    ham_SetMapTile(2, x*2, y*2+1, tileidx+2);
939 	    ham_SetMapTile(2, x*2+1, y*2+1, tileidx+3);
940 	    // See comment above why this is needed.
941 	    gfx_unlockTile((TILE_NAMES)tile);
942 	}
943     }
944 #if 0
945     BUF			buf;
946     buf.sprintf("%d, %d, %d, %d...%d, %d, %d, %d...",
947 	    (int)ham_bg[0].ti->first_block,
948 	    (int)ham_bg[1].ti->first_block,
949 	    (int)ham_bg[2].ti->first_block,
950 	    (int)ham_bg[3].ti->first_block,
951 	    (int)ham_bg[0].mi->first_block,
952 	    (int)ham_bg[1].mi->first_block,
953 	    (int)ham_bg[2].mi->first_block,
954 	    (int)ham_bg[3].mi->first_block);
955     msg_report(buf);
956 #endif
957 }
958 
959 void
gfx_settile(int tx,int ty,int tileno)960 gfx_settile(int tx, int ty, int tileno)
961 {
962     int		hamx, hamy, tileidx;
963 
964     hamx = tx - glb_scrollx;
965     hamy = ty - glb_scrolly;
966     // Only send onto ham if on screen and is a real change.
967     if (glb_tilemap[ty * 32 + tx] != tileno)
968 //	&& hamx < 32 && hamy < 32)
969     {
970 	gfx_unlockTile((TILE_NAMES)glb_tilemap[ty * 32 + tx]);
971 	tileidx = gfx_lockTile((TILE_NAMES)tileno, (TILE_NAMES *) &tileno);
972 	ham_SetMapTile(1, tx*2, ty*2, tileidx);
973 	ham_SetMapTile(1, tx*2+1, ty*2, tileidx+1);
974 	ham_SetMapTile(1, tx*2, ty*2+1, tileidx+2);
975 	ham_SetMapTile(1, tx*2+1, ty*2+1, tileidx+3);
976 
977 	// UPdate our local map.
978 	glb_tilemap[ty * 32 + tx] = tileno;
979     }
980 }
981 
982 void
gfx_setabstile(int tx,int ty,int tileno)983 gfx_setabstile(int tx, int ty, int tileno)
984 {
985     // Handle ability to write to -1 column
986     tx++;
987 
988     UT_ASSERT(tx >= 0);
989     UT_ASSERT(tx < 17);
990     UT_ASSERT(ty >= 0);
991     UT_ASSERT(ty < 12);
992 
993     int		tx1, ty1, tileidx, abstile;
994 
995     // Update the abs map...
996     abstile = glb_abstilemap[ty * 17 + tx];
997     if (abstile == tileno)
998 	return;
999 
1000     gfx_unlockTile((TILE_NAMES)abstile);
1001     tileidx = gfx_lockTile((TILE_NAMES)tileno, (TILE_NAMES *)&tileno);
1002     glb_abstilemap[ty * 17 + tx] = tileno;
1003 
1004     // Extra -1 is for our offset.
1005     tx += glb_offx - 7 - 1;
1006     ty += glb_offy - 5;
1007 
1008     tx *= 2;
1009     ty *= 2;
1010     ty += 1;		// Correct for the off by one nature of glb_offx
1011 
1012     tx1 = tx + 1;
1013     ty1 = ty + 1;
1014     tx &= 63;
1015     ty &= 63;
1016     tx1 &= 63;
1017     ty1 &= 63;
1018 
1019     ham_SetMapTile(1, tx, ty, tileidx);
1020     ham_SetMapTile(1, tx1, ty, tileidx+1);
1021     ham_SetMapTile(1, tx, ty1, tileidx+2);
1022     ham_SetMapTile(1, tx1, ty1, tileidx+3);
1023 }
1024 
1025 void
gfx_setoverlay(int tx,int ty,int tileno)1026 gfx_setoverlay(int tx, int ty, int tileno)
1027 {
1028     int		hamx, hamy, tileidx;
1029 
1030     hamx = tx - glb_scrollx;
1031     hamy = ty - glb_scrolly;
1032     // Only send onto ham if on screen and is a real change.
1033     if (glb_shadowmap[ty * 32 + tx] != tileno)
1034 	// && hamx < 32 && hamy < 32)
1035     {
1036 	gfx_unlockTile((TILE_NAMES)glb_shadowmap[ty * 32 + tx]);
1037 	tileidx = gfx_lockTile((TILE_NAMES)tileno, (TILE_NAMES *)&tileno);
1038 
1039 	ham_SetMapTile(3, tx*2, ty*2, tileidx);
1040 	ham_SetMapTile(3, tx*2+1, ty*2, tileidx+1);
1041 	ham_SetMapTile(3, tx*2, ty*2+1, tileidx+2);
1042 	ham_SetMapTile(3, tx*2+1, ty*2+1, tileidx+3);
1043 
1044 	// UPdate our local map.
1045 	glb_shadowmap[ty * 32 + tx] = tileno;
1046     }
1047 }
1048 
1049 int
gfx_getoverlay(int tx,int ty)1050 gfx_getoverlay(int tx, int ty)
1051 {
1052     return glb_shadowmap[ty * 32 + tx];
1053 }
1054 
1055 void
gfx_setabsoverlay(int tx,int ty,int tileno)1056 gfx_setabsoverlay(int tx, int ty, int tileno)
1057 {
1058     // Correct for ability to write to -1 column
1059     tx++;
1060 
1061     UT_ASSERT(tx >= 0);
1062     UT_ASSERT(tx < 17);
1063     UT_ASSERT(ty >= 0);
1064     UT_ASSERT(ty < 12);
1065 
1066     // Ignore this if we are not in a valid mode.
1067     if (glb_gfxmode)
1068 	return;
1069 
1070     int		tx1, ty1, tileidx, abstile;
1071 
1072     // Update the abs map...
1073     abstile = glb_absshadowmap[ty * 17 + tx];
1074     if (abstile == tileno)
1075 	return;
1076 
1077     gfx_unlockTile((TILE_NAMES)abstile);
1078     tileidx = gfx_lockTile((TILE_NAMES)tileno, (TILE_NAMES *)&tileno);
1079     glb_absshadowmap[ty * 17 + tx] = tileno;
1080 
1081     tx += glb_offx - 7 - 1;	// Extra -1 is for writing to -1 column
1082     ty += glb_offy - 5;
1083 
1084     tx *= 2;
1085     ty *= 2;
1086     ty += 1;		// Correct for the off by one nature of glb_offx
1087 
1088     tx1 = tx + 1;
1089     ty1 = ty + 1;
1090     tx &= 63;
1091     ty &= 63;
1092     tx1 &= 63;
1093     ty1 &= 63;
1094 
1095     ham_SetMapTile(3, tx, ty, tileidx);
1096     ham_SetMapTile(3, tx1, ty, tileidx+1);
1097     ham_SetMapTile(3, tx, ty1, tileidx+2);
1098     ham_SetMapTile(3, tx1, ty1, tileidx+3);
1099 }
1100 
1101 void
gfx_setmoblayer(int tx,int ty,int tileno)1102 gfx_setmoblayer(int tx, int ty, int tileno)
1103 {
1104     int		hamx, hamy, tileidx;
1105 
1106     hamx = tx - glb_scrollx;
1107     hamy = ty - glb_scrolly;
1108     // Only send onto ham if on screen and is a real change.
1109     if (glb_mobmap[ty * 32 + tx] != tileno)
1110 	// && hamx < 32 && hamy < 32)
1111     {
1112 	gfx_unlockTile((TILE_NAMES)glb_mobmap[ty * 32 + tx]);
1113 	tileidx = gfx_lockTile((TILE_NAMES)tileno, (TILE_NAMES *)&tileno);
1114 
1115 	ham_SetMapTile(2, tx*2, ty*2, tileidx);
1116 	ham_SetMapTile(2, tx*2+1, ty*2, tileidx+1);
1117 	ham_SetMapTile(2, tx*2, ty*2+1, tileidx+2);
1118 	ham_SetMapTile(2, tx*2+1, ty*2+1, tileidx+3);
1119 
1120 	// UPdate our local map.
1121 	glb_mobmap[ty * 32 + tx] = tileno;
1122     }
1123 }
1124 
1125 void
gfx_setabsmob(int tx,int ty,int tileno)1126 gfx_setabsmob(int tx, int ty, int tileno)
1127 {
1128     // Handle ability to write to -1 column
1129     tx++;
1130 
1131     UT_ASSERT(tx >= 0);
1132     UT_ASSERT(tx < 17);
1133     UT_ASSERT(ty >= 0);
1134     UT_ASSERT(ty < 12);
1135 
1136     int		tx1, ty1, tileidx, abstile;
1137 
1138     // Update the abs map...
1139     abstile = glb_absmobmap[ty * 17 + tx];
1140     if (abstile == tileno)
1141 	return;
1142 
1143     gfx_unlockTile((TILE_NAMES)abstile);
1144     tileidx = gfx_lockTile((TILE_NAMES)tileno, (TILE_NAMES *)&tileno);
1145     glb_absmobmap[ty * 17 + tx] = tileno;
1146 
1147     // Extra -1 is for our offset.
1148     tx += glb_offx - 7 - 1;
1149     ty += glb_offy - 5;
1150 
1151     tx *= 2;
1152     ty *= 2;
1153     ty += 1;		// Correct for the off by one nature of glb_offx
1154 
1155     tx1 = tx + 1;
1156     ty1 = ty + 1;
1157     tx &= 63;
1158     ty &= 63;
1159     tx1 &= 63;
1160     ty1 &= 63;
1161 
1162     ham_SetMapTile(2, tx, ty, tileidx);
1163     ham_SetMapTile(2, tx1, ty, tileidx+1);
1164     ham_SetMapTile(2, tx, ty1, tileidx+2);
1165     ham_SetMapTile(2, tx1, ty1, tileidx+3);
1166 }
1167 
1168 int
gfx_getmoblayer(int tx,int ty)1169 gfx_getmoblayer(int tx, int ty)
1170 {
1171     return glb_mobmap[ty * 32 + tx];
1172 }
1173 
1174 void
gfx_printtext(int x,int y,const char * text)1175 gfx_printtext(int x, int y, const char *text)
1176 {
1177     // We silently clip at 30.
1178     while (x < 30 && *text)
1179     {
1180 	gfx_printchar(x++, y, *text++);
1181     }
1182 }
1183 
1184 void
gfx_printcharraw(int x,int y,char c)1185 gfx_printcharraw(int x, int y, char c)
1186 {
1187     int		 idx, offx, offy;
1188     u16 	*screen = hamfake_lockScreen();
1189     u8	 	*chardata;
1190     u16		*palette;
1191     u16		*backplate;
1192 
1193     idx = gfx_getchartile(c);
1194 
1195     glb_charmap[(y/TILEHEIGHT)*32 + (x/TILEWIDTH)] = c;
1196 
1197     chardata = (u8 *) (&glb_tilesets[glb_tileset].alphabet[glb_currentfont][idx * BYTEPERTILE]);
1198     palette = (u16 *) glb_tilesets[glb_tileset].palette;
1199     backplate = (u16 *) bmp_slug_and_blood;
1200 
1201     // Find offset for x & y.
1202     // We have to update the backplate location as we were given
1203     // GBA coords and backplate is in DS coords.
1204 #if defined(USING_DS) || defined(USING_SDL)
1205     // This is not tile specific as we don't scale our plate (yet)
1206     backplate += 8 + 16 * PLATE_WIDTH;
1207 #endif
1208 
1209     int backx = x;
1210     int	backoff = 0;
1211 
1212     x += y * RAW_SCREEN_WIDTH;
1213 
1214     screen += x;
1215 
1216     for (offy = 0; offy < TILEHEIGHT; offy++)
1217     {
1218 	backoff = rawtoplate_y(y+offy) * PLATE_WIDTH;
1219 
1220 	for (offx = 0; offx < TILEWIDTH; offx++)
1221 	{
1222 	    if (*chardata)
1223 	    {
1224 		*screen = palette[*chardata];
1225 	    }
1226 	    else // Transparent.
1227 		*screen = backplate[backoff + rawtoplate_x(backx+offx)];
1228 
1229 	    screen++;
1230 	    chardata++;
1231 	}
1232 	screen += RAW_SCREEN_WIDTH - TILEWIDTH;
1233     }
1234 
1235     hamfake_unlockScreen(screen);
1236 }
1237 
1238 void
gfx_printcolourcharraw(int x,int y,char c,COLOUR_NAMES colour)1239 gfx_printcolourcharraw(int x, int y, char c, COLOUR_NAMES colour)
1240 {
1241     int		 idx, offx, offy;
1242     u16 	*screen = hamfake_lockScreen();
1243     u8	 	*chardata;
1244     u16		*palette;
1245     u16		*backplate;
1246     u16		 charcolour, desiredcolour;
1247 
1248     desiredcolour  = (glb_colourdefs[colour].blue >> 3) << 10;
1249     desiredcolour |= (glb_colourdefs[colour].green >> 3) << 5;
1250     desiredcolour |= (glb_colourdefs[colour].red >> 3);
1251 
1252     idx = gfx_getchartile(c);
1253     glb_charmap[(y/TILEHEIGHT)*32 + (x/TILEWIDTH)] = c;
1254 
1255     chardata = (u8 *) (&glb_tilesets[glb_tileset].alphabet[glb_currentfont][idx * BYTEPERTILE]);
1256     palette = (u16 *) glb_tilesets[glb_tileset].palette;
1257     backplate = (u16 *) bmp_slug_and_blood;
1258 
1259     // Find offset for x & y.
1260     // We have to update the backplate location as we were given
1261     // GBA coords and backplate is in DS coords.
1262 #if defined(USING_DS) || defined(USING_SDL)
1263     backplate += 8 + 16 * PLATE_WIDTH;
1264 #endif
1265 
1266     int backx = x;
1267     int	backoff = 0;
1268 
1269     x += y * RAW_SCREEN_WIDTH;
1270 
1271     screen += x;
1272 
1273     for (offy = 0; offy < TILEHEIGHT; offy++)
1274     {
1275 	backoff = rawtoplate_y(y+offy) * PLATE_WIDTH;
1276 
1277 	for (offx = 0; offx < TILEWIDTH; offx++)
1278 	{
1279 	    if (*chardata)
1280 	    {
1281 		// If the palette is black, we pass it through.
1282 		// Otherwise we use our desired colour.
1283 		charcolour = palette[*chardata];
1284 		if (!charcolour || charcolour == 0x842)
1285 		    *screen = charcolour;
1286 		else
1287 		    *screen = desiredcolour;
1288 	    }
1289 	    else
1290 		*screen = backplate[backoff + rawtoplate_x(backx+offx)];
1291 
1292 	    screen++;
1293 	    chardata++;
1294 	}
1295 	screen += RAW_SCREEN_WIDTH - TILEWIDTH;
1296     }
1297 
1298     hamfake_unlockScreen(screen);
1299 }
1300 
1301 void
gfx_printchar(int x,int y,char c)1302 gfx_printchar(int x, int y, char c)
1303 {
1304     int		idx;
1305 
1306     if (glb_gfxmode == 3)
1307     {
1308 	gfx_printcharraw(x * TILEWIDTH, y * TILEHEIGHT, c);
1309 	return;
1310     }
1311 
1312     // If there is no change, don't do anything...
1313     if (glb_charmap[y * 32 + x] == c)
1314 	return;
1315 
1316     // Locking error:
1317     // 1) Attempt lock on 'a'.  Fail and get notile
1318     // 2) Update charmap with 'a'
1319     // 3) Attempt lock on 'a', succeed.
1320     // 4) Unlock this charmap and free the tile despite extra count.
1321     // Thus, we request the actual number to record in our charmap
1322     // that is set to INVALID if lock fails.
1323     // Unlock the old tile...
1324     gfx_unlockCharTile(glb_charmap[y*32 + x]);
1325 
1326     idx = gfx_lockCharTile(c, (u8 *) &c);
1327     glb_charmap[y*32 + x] = c;
1328 
1329     ham_SetMapTile(0, x, y, idx);
1330 }
1331 
1332 void
gfx_printcolourchar(int x,int y,char c,COLOUR_NAMES colour)1333 gfx_printcolourchar(int x, int y, char c, COLOUR_NAMES colour)
1334 {
1335     int		idx;
1336 
1337     if (glb_gfxmode == 3)
1338     {
1339 	gfx_printcolourcharraw(x * TILEWIDTH, y * TILEHEIGHT, c, colour);
1340 	return;
1341     }
1342 
1343     // There is no such thing as no change in the coloured char world.
1344 
1345     // Locking error:
1346     // 1) Attempt lock on 'a'.  Fail and get notile
1347     // 2) Update charmap with 'a'
1348     // 3) Attempt lock on 'a', succeed.
1349     // 4) Unlock this charmap and free the tile despite extra count.
1350     // Thus, we request the actual number to record in our charmap
1351     // that is set to INVALID if lock fails.
1352     // Unlock the old tile...
1353     gfx_unlockCharTile(glb_charmap[y*32 + x]);
1354 
1355     idx = gfx_lockColourCharTile(c, colour, (u8 *) &c);
1356     glb_charmap[y*32 + x] = c;
1357 
1358     ham_SetMapTile(0, x, y, idx);
1359 }
1360 
1361 void
gfx_cleartextline(int y,int startx)1362 gfx_cleartextline(int y, int startx)
1363 {
1364     int		x;
1365 
1366     for (x = startx; x < 30; x++)
1367 	gfx_printchar(x, y, ' ');
1368 }
1369 
1370 void
gfx_nudgecenter(int px,int py)1371 gfx_nudgecenter(int px, int py)
1372 {
1373     int		tx, ty;
1374 
1375     glb_nudgex = px;
1376     glb_nudgey = py;
1377 
1378     gfx_getscrollcenter(tx, ty);
1379     gfx_scrollcenter(tx, ty);
1380 }
1381 
1382 void
gfx_getscrollcenter(int & tx,int & ty)1383 gfx_getscrollcenter(int &tx, int &ty)
1384 {
1385     tx = glb_offx;
1386     ty = glb_offy;
1387 }
1388 
1389 
gfx_scrollcenter(int tx,int ty)1390 void gfx_scrollcenter(int tx, int ty)
1391 {
1392 //    int		dorebuild = 0;
1393 
1394     // Clamp to the size of the map...
1395 
1396 #if 0
1397     if (tx - 8 < 0)
1398 	tx = 8;
1399     if (tx + 8 >= MAP_WIDTH)
1400 	tx = MAP_WIDTH - 8;
1401     if (ty - 5 < 0)
1402 	ty = 5;
1403     if (ty + 5 >= MAP_HEIGHT)
1404 	ty = MAP_HEIGHT - 5;
1405 #endif
1406 
1407     // We want the specified tx/ty to become the center of our tile map.
1408     // The problem is if it doesn't fit on our current screen, we must
1409     // scroll & rebuild.
1410     // Our screen width is 15 tiles and height 10 tiles.
1411 
1412     // This code allows us to have a real screen larger than 32x32
1413     // by scrolling the area.  Sadly, my scroll code sucks and costs
1414     // way too much to do, so results in horrible flickering etc,
1415     // thus I decided to go back to 32x32.
1416 #if 0
1417     if (tx + 8 - glb_scrollx > 16)
1418     {
1419 	glb_scrollx += 16;
1420 	dorebuild = 1;
1421     }
1422     if (tx - 8 < glb_scrollx)
1423     {
1424 	glb_scrollx -= 16;
1425 	dorebuild = 1;
1426     }
1427     if (ty + 5 - glb_scrolly > 16)
1428     {
1429 	glb_scrolly += 16;
1430 	dorebuild = 1;
1431     }
1432     if (ty - 5 < glb_scrolly)
1433     {
1434 	glb_scrolly -= 16;
1435 	dorebuild = 1;
1436     }
1437     if (dorebuild)
1438     {
1439 	gfx_refreshtiles();
1440     }
1441 #endif
1442     // If we are running on the DS we need slightly different magic constants.
1443     // Specifically, we have 256 rather than 240 wide, so need an extra
1444     // 8 offset horizontally.  Likewise, we have 192 rather than 160 vertically
1445     // so need an extra 16 vertically.  Ideally we will eventually use this
1446     // extra space.
1447 #ifdef USE_EXTENDED_HEIGHT
1448     M_BG1SCRLX_SET((tx-glb_scrollx)*TILEWIDTH*2 - 14*TILEWIDTH - TILEWIDTH + glb_nudgex);
1449     M_BG1SCRLY_SET((ty-glb_scrolly)*TILEHEIGHT*2 - 9*TILEHEIGHT - 3*TILEHEIGHT + glb_nudgey);
1450     M_BG2SCRLX_SET((tx-glb_scrollx)*TILEWIDTH*2 - 14*TILEWIDTH - TILEWIDTH + glb_nudgex);
1451     M_BG2SCRLY_SET((ty-glb_scrolly)*TILEHEIGHT*2 - 9*TILEHEIGHT - 3*TILEHEIGHT + glb_nudgey);
1452     M_BG3SCRLX_SET((tx-glb_scrollx)*TILEWIDTH*2 - 14*TILEWIDTH - TILEWIDTH + glb_nudgex);
1453     M_BG3SCRLY_SET((ty-glb_scrolly)*TILEHEIGHT*2 - 9*TILEHEIGHT - 3*TILEHEIGHT + glb_nudgey);
1454     // We also need to set the text port
1455     M_BG0SCRLX_SET(-TILEWIDTH);
1456     M_BG0SCRLY_SET(-TILEHEIGHT*3);
1457 #elif defined(USING_DS) || defined(USING_SDL)
1458     M_BG1SCRLX_SET((tx-glb_scrollx)*TILEWIDTH*2 - 14*TILEWIDTH - TILEWIDTH + glb_nudgex);
1459     M_BG1SCRLY_SET((ty-glb_scrolly)*TILEHEIGHT*2 - 9*TILEHEIGHT - 2*TILEHEIGHT + glb_nudgey);
1460     M_BG2SCRLX_SET((tx-glb_scrollx)*TILEWIDTH*2 - 14*TILEWIDTH - TILEWIDTH + glb_nudgex);
1461     M_BG2SCRLY_SET((ty-glb_scrolly)*TILEHEIGHT*2 - 9*TILEHEIGHT - 2*TILEHEIGHT + glb_nudgey);
1462     M_BG3SCRLX_SET((tx-glb_scrollx)*TILEWIDTH*2 - 14*TILEWIDTH - TILEWIDTH + glb_nudgex);
1463     M_BG3SCRLY_SET((ty-glb_scrolly)*TILEHEIGHT*2 - 9*TILEHEIGHT - 2*TILEHEIGHT + glb_nudgey);
1464     // We also need to set the text port
1465     M_BG0SCRLX_SET(-TILEWIDTH);
1466     M_BG0SCRLY_SET(-TILEHEIGHT*2);
1467 #else
1468     M_BG1SCRLX_SET((tx-glb_scrollx)*TILEWIDTH*2 - 14*TILEWIDTH + glb_nudgex);
1469     M_BG1SCRLY_SET((ty-glb_scrolly)*TILEHEIGHT*2 - 9*TILEHEIGHT + glb_nudgey);
1470     M_BG2SCRLX_SET((tx-glb_scrollx)*TILEWIDTH*2 - 14*TILEWIDTH + glb_nudgex);
1471     M_BG2SCRLY_SET((ty-glb_scrolly)*TILEHEIGHT*2 - 9*TILEHEIGHT + glb_nudgey);
1472     M_BG3SCRLX_SET((tx-glb_scrollx)*TILEWIDTH*2 - 14*TILEWIDTH + glb_nudgex);
1473     M_BG3SCRLY_SET((ty-glb_scrolly)*TILEHEIGHT*2 - 9*TILEHEIGHT + glb_nudgey);
1474     // No need to adjust the textport in raw GBA mode.
1475 #endif
1476 
1477     glb_offx = tx;
1478     glb_offy = ty;
1479 }
1480 
1481 int
gfx_isnewframe()1482 gfx_isnewframe()
1483 {
1484     int result;
1485 
1486     hamfake_rebuildScreen();
1487     hamfake_awaitEvent();
1488     // The event could be a new frame...
1489     result = glb_newframe;
1490     glb_newframe = 0;
1491     return result;
1492 }
1493 
1494 int
gfx_getframecount()1495 gfx_getframecount()
1496 {
1497     return glb_framecount;
1498 }
1499 
1500 
1501 u16 glb_tilestashtiles[TILESTASH];
1502 char glb_tilestashdata[TILESTASH][4];
1503 int glb_tilestashsize = 0;
1504 
1505 void
gfx_updatebitmap()1506 gfx_updatebitmap()
1507 {
1508     int		i;
1509 
1510     // Write out bg2tiledata to the bg2tiles.
1511     //ham_ReloadTileGfx(glb_bg2tiles, (u16 *)glb_bg2tiledata, 0, 600);
1512     //ham_ReloadTileGfx(glb_bg2tiles, (u16 *)glb_bg2tiledata, 0, glb_tilestashsize);
1513 
1514     for (i = 0; i < glb_tilestashsize; i++)
1515     {
1516 	ham_ReloadTileGfx(glb_bg1tiles,
1517 	      &((u16 *) glb_bg2tiledata)[WORDPERTILE * i],
1518 	      glb_tilestashtiles[i], 1);
1519     }
1520 }
1521 
1522 void
gfx_putpixel(char c,int x,int y)1523 gfx_putpixel(char c, int x, int y)
1524 {
1525     int		tx, ty;
1526 
1527     UT_ASSERT(x >= 0 && y >= 0 && x < 240 && y < 160);
1528 
1529     tx = x >> 3;
1530     ty = y >> 3;
1531     x = x & 7;
1532     y = y & 7;
1533 
1534     glb_bg2tiledata[tx * BYTEPERTILE + ty * BYTEPERTILE * 30 + y * TILEWIDTH + x] = c;
1535 }
1536 
1537 void
gfx_drawverline(char c,int x,int ly,int hy)1538 gfx_drawverline(char c, int x, int ly, int hy)
1539 {
1540     while (ly <= hy)
1541 	gfx_putpixel(c, x, ly++);
1542 }
1543 
1544 void
gfx_drawhorline(char c,int lx,int y,int hx)1545 gfx_drawhorline(char c, int lx, int y, int hx)
1546 {
1547     while (lx <= hx)
1548 	gfx_putpixel(c, lx++, y);
1549 }
1550 
1551 void
gfx_drawbox(char c,int lx,int ly,int hx,int hy,int solid)1552 gfx_drawbox(char c, int lx, int ly, int hx, int hy, int solid)
1553 {
1554     if (solid)
1555     {
1556 	while (ly <= hy)
1557 	    gfx_drawhorline(c, lx, ly++, hx);
1558     }
1559     else
1560     {
1561 	gfx_drawhorline(c, lx, ly, hx);
1562 	gfx_drawhorline(c, lx, hy, hx);
1563 	gfx_drawverline(c, lx, ly+1, hy-1);
1564 	gfx_drawverline(c, hx, ly+1, hy-1);
1565     }
1566 }
1567 
1568 // Given a SQUARE number give us the minimap colour.
1569 int
gfx_getcolfromtile(int tile,int mapped)1570 gfx_getcolfromtile(int tile, int mapped)
1571 {
1572     COLOUR_NAMES	c;
1573 
1574     if (mapped)
1575     {
1576 	c = (COLOUR_NAMES) glb_squaredefs[tile].minicolour;
1577     }
1578     else
1579     {
1580 	c = COLOUR_LIGHTBLACK;
1581     }
1582     return gfx_lookupcolor(c);
1583 }
1584 
1585 static void
gfx_resettilestash()1586 gfx_resettilestash()
1587 {
1588     int		i;
1589 
1590     for (i = 0; i < glb_tilestashsize; i++)
1591     {
1592 	// Mark it as freed...
1593 	glb_idxcount[glb_tilestashtiles[i]] = 0;
1594     }
1595     glb_tilestashsize = 0;
1596 }
1597 
1598 #ifdef USING_SDL
1599 void
gfx_fillminimapblock(char * dst,char c[4])1600 gfx_fillminimapblock(char *dst, char c[4])
1601 {
1602     int			 sy, sx;
1603     for (sy = 0; sy < TILEHEIGHT/2; sy++)
1604     {
1605 	for (sx = 0; sx < TILEWIDTH/2; sx++)
1606 	    *dst++ = c[0];
1607 	for (; sx < TILEWIDTH; sx++)
1608 	    *dst++ = c[1];
1609     }
1610 
1611     for (; sy < TILEHEIGHT; sy++)
1612     {
1613 	for (sx = 0; sx < TILEWIDTH/2; sx++)
1614 	    *dst++ = c[2];
1615 	for (; sx < TILEWIDTH; sx++)
1616 	    *dst++ = c[3];
1617     }
1618 }
1619 #else
1620 void
gfx_fillminimapblock(char * dst,char c[4])1621 gfx_fillminimapblock(char *dst, char c[4])
1622 {
1623     int			 sy;
1624     for (sy = 0; sy < 4; sy++)
1625     {
1626 	*dst++ = c[0];
1627 	*dst++ = c[0];
1628 	*dst++ = c[0];
1629 	*dst++ = c[0];
1630 	*dst++ = c[1];
1631 	*dst++ = c[1];
1632 	*dst++ = c[1];
1633 	*dst++ = c[1];
1634     }
1635 
1636     for (sy = 0; sy < 4; sy++)
1637     {
1638 	*dst++ = c[2];
1639 	*dst++ = c[2];
1640 	*dst++ = c[2];
1641 	*dst++ = c[2];
1642 	*dst++ = c[3];
1643 	*dst++ = c[3];
1644 	*dst++ = c[3];
1645 	*dst++ = c[3];
1646     }
1647 }
1648 #endif
1649 
1650 int
gfx_findminimaptilenumber(char c[4])1651 gfx_findminimaptilenumber(char c[4])
1652 {
1653     int		i;
1654     u16		tile;
1655 
1656     // Search the tile stash to see if we are already in it...
1657     for (i = 0; i < glb_tilestashsize; i++)
1658     {
1659 	tile = glb_tilestashtiles[i];
1660 
1661 	// We can flip horizontally, vertically, or both.
1662 	if (c[0] == glb_tilestashdata[i][0])
1663 	{
1664 	    // No flip.
1665 	    if (c[1] == glb_tilestashdata[i][1] &&
1666 		c[2] == glb_tilestashdata[i][2] &&
1667 		c[3] == glb_tilestashdata[i][3])
1668 	    {
1669 		return tile;
1670 	    }
1671 	}
1672 	if (c[0] == glb_tilestashdata[i][1])
1673 	{
1674 	    // Flip horizontally
1675 	    if (c[1] == glb_tilestashdata[i][0] &&
1676 		c[2] == glb_tilestashdata[i][3] &&
1677 		c[3] == glb_tilestashdata[i][2])
1678 	    {
1679 		return tile | 1024;
1680 	    }
1681 	}
1682 	if (c[0] == glb_tilestashdata[i][2])
1683 	{
1684 	    // Flip vertically
1685 	    if (c[1] == glb_tilestashdata[i][3] &&
1686 		c[2] == glb_tilestashdata[i][0] &&
1687 		c[3] == glb_tilestashdata[i][1])
1688 	    {
1689 		return tile | 2048;
1690 	    }
1691 	}
1692 	if (c[0] == glb_tilestashdata[i][3])
1693 	{
1694 	    // Flip both.
1695 	    if (c[1] == glb_tilestashdata[i][2] &&
1696 		c[2] == glb_tilestashdata[i][1] &&
1697 		c[3] == glb_tilestashdata[i][0])
1698 	    {
1699 		return tile | 1024 | 2048;
1700 	    }
1701 	}
1702     }
1703 
1704     // We didn't find the tile.
1705     tile = gfx_findFreeTile(1);
1706 
1707     if (tile == INVALID_TILEIDX)
1708 	return gfx_lookupTile(TILE_NOTILE);
1709     // Ignore for now as we know it occrus on Quizar's map.
1710     // Seems rather mean to keep this limit since we know we have
1711     // a hard limit with gfx_findFreeTile(1).
1712     // Why not allow stash to be bigger and just make sure
1713     // we free the tile's afterwards?
1714     // UT_ASSERT(i < TILESTASH);
1715     if (i >= TILESTASH)
1716     {
1717 	return gfx_lookupTile(TILE_NOTILE);
1718     }
1719 
1720     i = glb_tilestashsize++;
1721 
1722     glb_tilestashtiles[i] = tile;
1723 
1724     glb_idxcount[tile]++;
1725 
1726     // Build the tile.
1727     memcpy(glb_tilestashdata[i], c, 4);
1728 
1729     gfx_fillminimapblock(&glb_bg2tiledata[i * BYTEPERTILE], c);
1730 
1731     return tile;
1732 }
1733 
1734 // Fill in an 8x8 block given the colour array.  Colours are
1735 // (0,0), (1,0), (0,1), (1,1).
1736 void
gfx_drawminimapblock(int bx,int by,char c[4])1737 gfx_drawminimapblock(int bx, int by, char c[4])
1738 {
1739     char		*dst;
1740 
1741     dst = &glb_bg2tiledata[by * BYTEPERTILE * 30 + bx * BYTEPERTILE];
1742     gfx_fillminimapblock(dst, c);
1743 }
1744 
1745 
1746 void
gfx_displayminimap(MAP * level)1747 gfx_displayminimap(MAP *level)
1748 {
1749     gfx_resettilestash();
1750 
1751     // gfx_drawbox(glb_stdcolor[COLOUR_RED], 51, 11, 189, 149, 0);
1752 
1753     char	c[4];
1754     int		ax, ay;		// AVatar position.
1755 
1756     if (MOB::getAvatar())
1757     {
1758 	ax = MOB::getAvatar()->getX();
1759 	ay = MOB::getAvatar()->getY();
1760     }
1761     else
1762     {
1763 	ax = -1;
1764 	ay = -1;
1765     }
1766 
1767     // The map is 32x32.
1768     // With 4 pixel size elements, we have a 128x128 map.
1769     // We draw it from 56 to 184 and 16 to 144
1770     // We have a 10 pixel border on all sides.
1771     int		 x, y, bx, by, tile;
1772 
1773     // For efficiency, we write to one tile at a time.  This greatly
1774     // improves the efficiency...
1775     y = 0;
1776     for (by = 0; by < 16; by++)
1777     {
1778 	x = 0;
1779 	for (bx = 0; bx < 16; bx++)
1780 	{
1781 	    c[0] = gfx_getcolfromtile(level->getTile(x, y),
1782 				  level->getFlag(x, y, SQUAREFLAG_MAPPED));
1783 	    c[1] = gfx_getcolfromtile(level->getTile(x+1, y),
1784 				  level->getFlag(x+1, y, SQUAREFLAG_MAPPED));
1785 	    c[2] = gfx_getcolfromtile(level->getTile(x, y+1),
1786 				  level->getFlag(x, y+1, SQUAREFLAG_MAPPED));
1787 	    c[3] = gfx_getcolfromtile(level->getTile(x+1, y+1),
1788 				  level->getFlag(x+1, y+1, SQUAREFLAG_MAPPED));
1789 
1790 	    if ((ax >> 1) == bx && (ay >> 1) == by)
1791 	    {
1792 		c[(ax & 1) + ((ay &1) << 1)] = glb_stdcolor[COLOUR_WHITE];
1793 	    }
1794 
1795 	    tile = gfx_findminimaptilenumber(c);
1796 	    ham_SetMapTile(0, bx+7, by+2, tile);
1797 	    // gfx_drawminimapblock(bx + 7, by + 2, c);
1798 
1799 	    x += 2;
1800 	}
1801 	y += 2;
1802     }
1803 
1804 #if 0
1805     for (item = level->getItemHead(); item; item = item->getNext())
1806     {
1807 	gfx_drawbox(glb_stdcolor[COLOUR_GREEN],
1808 		    56 + item->getX() * 4 + 1, 16 + item->getY() * 4 + 1,
1809 		    56 + item->getX() * 4 + 2, 16 + item->getY() * 4 + 2,
1810 		    1);
1811     }
1812 
1813     for (mob = level->getMobHead(); mob; mob = mob->getNext())
1814     {
1815 	// Turn this #if off in order to get clarivoyance all the
1816 	// time.
1817 #if 1
1818 	if (level->hasLOS(MOB::getAvatar()->getX(), MOB::getAvatar()->getY(),
1819 			  mob->getX(), mob->getY()))
1820 #endif
1821 	{
1822 	    gfx_drawbox(glb_stdcolor[COLOUR_WHITE],
1823 			56 + mob->getX() * 4 + 1, 16 + mob->getY() * 4 + 1,
1824 			56 + mob->getX() * 4 + 2, 16 + mob->getY() * 4 + 2,
1825 			1);
1826 	}
1827     }
1828 #endif
1829 
1830     gfx_updatebitmap();
1831 
1832 #if 0
1833 {
1834     BUF			buf;
1835     buf.sprintf("%d tiles used", glb_tilestashsize);
1836     msg_report(buf);
1837 }
1838 #endif
1839 }
1840 
1841 void
gfx_hideminimap()1842 gfx_hideminimap()
1843 {
1844     // Free up tiles.
1845     gfx_resettilestash();
1846 
1847     // Erase the tile list.
1848     int		 tile, bx, by;
1849 
1850     tile = gfx_lookupTile(TILE_VOID);
1851 
1852     for (by = 0; by < 16; by++)
1853     {
1854 	// We corrupted the text line so just write spaces over it.
1855 	gfx_cleartextline(by + 2);
1856 
1857 	// The text clear may be a no-op if the tile was already a space
1858 	// we thus explicitly set the tile to void
1859 	for (bx = 0; bx < 16; bx++)
1860 	    ham_SetMapTile(0, bx+7, by+2, tile);
1861     }
1862 }
1863 
1864 int
gfx_lookupcolor(int r,int g,int b)1865 gfx_lookupcolor(int r, int g, int b)
1866 {
1867     return gfx_lookupcolor(r, g, b, glb_tilesets[glb_tileset].palette);
1868 }
1869 
1870 int
gfx_lookupcolor(int r,int g,int b,const u16 * palette)1871 gfx_lookupcolor(int r, int g, int b, const u16 *palette)
1872 {
1873     int		i;
1874     int		minerror, closematch, cr, cg, cb;
1875 
1876     // Larger than any possible match.
1877     minerror = 255*255*3 + 1;
1878     closematch = 0;
1879     // We skip colour 0 as that is invisible.
1880     for (i = 1; i < (int)512 / 2; i++)
1881     {
1882 	// Unpack the given colour from 5:5:5
1883 	cb = (palette[i] >> 10) << 3;
1884 	cg = ((palette[i] >> 5) & 31) << 3;
1885 	cr = (palette[i] & 31) << 3;
1886 
1887 	// Find the difference squared.
1888 	cr -= r;
1889 	cg -= g;
1890 	cb -= b;
1891 	cr *= cr;
1892 	cg *= cg;
1893 	cb *= cb;
1894 	cr += cg;
1895 	cr += cb;
1896 	// cr is now the squared difference.  If this is a new low, keep.
1897 	if (cr < minerror)
1898 	{
1899 	    minerror = cr;
1900 	    closematch = i;
1901 	}
1902     }
1903     UT_ASSERT(closematch);
1904 
1905     // Result is closematch.
1906     return closematch;
1907 }
1908 
1909 int
gfx_lookupcolor(COLOUR_NAMES color)1910 gfx_lookupcolor(COLOUR_NAMES color)
1911 {
1912     UT_ASSERT(color < NUM_COLOURS);
1913     return glb_stdcolor[color];
1914 }
1915 
1916 
1917 void
gfx_sleep(int vcycles)1918 gfx_sleep(int vcycles)
1919 {
1920     if (glbStressTest)
1921 	return;
1922 
1923     int		start = glb_framecount;
1924 
1925     while (glb_framecount < start + vcycles)
1926     {
1927 	hamfake_rebuildScreen();
1928 	hamfake_awaitEvent();
1929     }
1930 }
1931 
1932 void
gfx_updateinventoryline(MOB * mob)1933 gfx_updateinventoryline(MOB *mob)
1934 {
1935     ITEM	*item;
1936 
1937     gfx_cleartextline(18);
1938     if (!mob)
1939     {
1940 	gfx_printtext(0, 18, "No item slot");
1941 	return;
1942     }
1943     item = mob->getItem(glb_invx, glb_invy);
1944     if (item)
1945 	gfx_printtext(0, 18,
1946 		      gram_capitalize(item->getName(false, false, true)));
1947     else if (glb_invx == 0)
1948     {
1949 	ITEMSLOT_NAMES slot = (ITEMSLOT_NAMES) glb_invy;
1950 	if (mob->hasSlot(slot))
1951 	    gfx_printtext(0, 18,
1952 		      gram_capitalize(mob->getSlotName(slot)));
1953 	else
1954 	    gfx_printtext(0, 18, "No item slot");
1955     }
1956     else
1957 	gfx_printtext(0, 18, "Empty slot");
1958 }
1959 
1960 void
gfx_showinventory(MOB * mob)1961 gfx_showinventory(MOB *mob)
1962 {
1963     int		 tx, ty, ix, iy;
1964     ITEM	*item;
1965     BUF		 buf;
1966 
1967     glb_invmob = mob;
1968 
1969     // Clear out all the lines...
1970     for (ty = 2; ty < 19; ty++)
1971 	gfx_cleartextline(ty);
1972 
1973     // Write out the descriptions...
1974     for (iy = 0; iy < NUM_ITEMSLOTS; iy++)
1975     {
1976 	gfx_printtext(0, iy * 2 + 2, glb_itemslotdefs[iy].desc1);
1977 	gfx_printtext(0, iy * 2 + 3, glb_itemslotdefs[iy].desc2);
1978     }
1979 
1980     // Width 12, height 8.
1981     // Our complete size 15 x 10
1982     for (iy = 0; iy < MOBINV_HEIGHT; iy++)
1983     {
1984 	ty = iy + 1;
1985         for (ix = 0; ix < MOBINV_WIDTH; ix++)
1986 	{
1987 	    tx = ix + 2 + (ix!=0);
1988 
1989 	    // Draw the inventory item with pass thru and clear out
1990 	    // the overlay..
1991 	    item = mob->getItem(ix, iy);
1992 	    if (!item)
1993 		gfx_setabstile(tx, ty, TILE_NORMALSLOT);
1994 	    else if (item->isFavorite())
1995 	    {
1996 		gfx_setabstile(tx, ty, TILE_FAVORITESLOT);
1997 	    }
1998 	    else
1999 	    {
2000 		if (item->isKnownCursed())
2001 		{
2002 		    if (item->isBlessed())
2003 			gfx_setabstile(tx, ty, TILE_HOLYSLOT);
2004 		    else if (item->isCursed())
2005 			gfx_setabstile(tx, ty, TILE_CURSEDSLOT);
2006 		    else
2007 			gfx_setabstile(tx, ty, TILE_NORMALSLOT);
2008 		}
2009 		else
2010 		{
2011 		    if (item->isKnownNotCursed())
2012 			gfx_setabstile(tx, ty, TILE_NORMALSLOT);
2013 		    else
2014 			gfx_setabstile(tx, ty, TILE_EMPTYSLOT);
2015 		}
2016 	    }
2017 	    if (!ix)
2018 	    {
2019 		if (!mob->hasSlot((ITEMSLOT_NAMES) iy))
2020 		{
2021 		    gfx_setabsmob(tx, ty, TILE_INVALIDSLOT);
2022 		}
2023 		else
2024 		    gfx_setabsmob(tx, ty,
2025 				    (item ? item->getTile() : TILE_VOID));
2026 	    }
2027 	    else
2028 		gfx_setabsmob(tx, ty,
2029 				    (item ? item->getTile() : TILE_VOID));
2030 	    if (ix == glb_invx && iy == glb_invy)
2031 		gfx_setabsoverlay(tx, ty, TILE_CURSOR);
2032 	    else
2033 		gfx_setabsoverlay(tx, ty, TILE_VOID);
2034 
2035 	    // If the item is quivered, add the q flag.
2036 	    if (item && item->isQuivered())
2037 	    {
2038 		gfx_printtext(tx * 2 + 1, ty * 2, "q");
2039 	    }
2040 	    // Flag artifacts.
2041 	    if (item && item->isArtifact())
2042 	    {
2043 		gfx_printtext(tx * 2, ty * 2, SYMBOLSTRING_UNIQUE);
2044 	    }
2045 	    // If the stack count is non-unit, we add the number.
2046 	    if (item && item->getStackCount() != 1)
2047 	    {
2048 		buf.sprintf("%2d", item->getStackCount());
2049 
2050 		gfx_printtext(tx * 2, ty * 2 + 1, buf);
2051 	    }
2052 	}
2053     }
2054 
2055     // Update the current inventory item...
2056     gfx_updateinventoryline(mob);
2057 }
2058 
2059 void
gfx_hideinventory()2060 gfx_hideinventory()
2061 {
2062     int		ty;
2063 
2064     // Clear out all the lines...
2065     for (ty = 2; ty < 19; ty++)
2066 	gfx_cleartextline(ty);
2067 
2068     gfx_refreshtiles();
2069     glb_invmob = 0;
2070 }
2071 
2072 void
gfx_getinvcursor(int & ix,int & iy)2073 gfx_getinvcursor(int &ix, int &iy)
2074 {
2075     ix = glb_invx;
2076     iy = glb_invy;
2077 }
2078 
2079 void
gfx_setinvcursor(int ix,int iy,bool onlyslots)2080 gfx_setinvcursor(int ix, int iy, bool onlyslots)
2081 {
2082     int		 tx, ty;
2083     ITEM	*item;
2084 
2085     // Erase from old pos...
2086     tx = glb_invx + 2 + (glb_invx != 0);
2087     ty = glb_invy + 1;
2088 
2089     // but only if inventory currently up
2090     if (glb_invmob)
2091 	gfx_setabsoverlay(tx, ty, TILE_VOID);
2092 
2093     // Scroll the cursor as you hit the top of the inventory
2094     // If we are on the equipment column, we always stay on the
2095     // equipment column.
2096     // If we are in the inventory area, we loop only in there.
2097     // Horizontal movement never adjusts y value.
2098     if (iy < 0)
2099     {
2100 	if (ix)
2101 	{
2102 	    ix--;
2103 	    if (!ix)
2104 		ix = MOBINV_WIDTH-1;
2105 	}
2106 	iy = MOBINV_HEIGHT-1;
2107     }
2108     else if (iy >= MOBINV_HEIGHT)
2109     {
2110 	if (ix)
2111 	{
2112 	    ix++;
2113 	    if (ix == MOBINV_WIDTH)
2114 		ix = 1;
2115 	}
2116 	iy = 0;
2117     }
2118     else if (ix < 0)
2119     {
2120 	ix = MOBINV_WIDTH-1;
2121     }
2122     else if (ix >= MOBINV_WIDTH)
2123     {
2124 	ix = 0;
2125     }
2126 
2127     // Ensure we never leave the itemslot list...
2128     if (onlyslots)
2129 	ix = 0;
2130 
2131     // ix/iy might still be out of range, so it makes sense
2132     // to reclamp here.
2133 
2134     // Update new position...
2135     glb_invx = ix % MOBINV_WIDTH;
2136     if (glb_invx < 0) glb_invx += MOBINV_WIDTH;
2137     glb_invy = iy % MOBINV_HEIGHT;
2138     if (glb_invy < 0) glb_invy += MOBINV_HEIGHT;
2139     tx = glb_invx + 2 + (glb_invx != 0);
2140     ty = glb_invy + 1;
2141 
2142     // Rest of this is only needed if inventory is displayed.
2143     if (!glb_invmob)
2144 	return;
2145 
2146     gfx_setabsoverlay(tx, ty, TILE_CURSOR);
2147 
2148     // Update the current inventory item...
2149     gfx_updateinventoryline(glb_invmob);
2150 }
2151 
2152 void
gfx_displaylist(int x,int y,int ylen,const char ** list,int select,int & startoflist,int & endoflist)2153 gfx_displaylist(int x, int y, int ylen, const char **list, int select, int &startoflist, int &endoflist)
2154 {
2155     int		i, j, n, displaylen;
2156     int		scroll;
2157     const char	*entry = "You should stop reading the binary!";
2158 
2159     // Calculate list size.
2160     for (n = 0; list[n]; n++);
2161 
2162     // Determine the scroll offset required for select to be centered.
2163     displaylen = ylen-y;
2164     if (n < displaylen)
2165 	scroll = 0;		// No scrolling necessary.
2166     else
2167     {
2168 	scroll = select - displaylen/2 + 1;
2169 	// Do not scroll down past end.
2170 	if (scroll + displaylen > n)
2171 	{
2172 	    scroll = n - displaylen+1;
2173 	}
2174 	// Do not scroll up past start.
2175 	// Note that a scroll of 1 merely hides the first entry, so
2176 	// isn't at all useful.
2177 	if (scroll <= 1)
2178 	    scroll = 0;
2179     }
2180 
2181     // First, chew up the scrolled entries.
2182     for (i = 0; i < scroll; i++)
2183     {
2184 	entry = list[i];
2185 	if (!entry) break;
2186     }
2187 
2188     startoflist = scroll;
2189 
2190     // Now, display & clear the rest of the text.
2191     j = y;
2192     if (scroll)
2193     {
2194 	// Print the scroll up message
2195 	gfx_cleartextline(j, x-1);
2196 	gfx_printtext(x, j, SYMBOLSTRING_UP SYMBOLSTRING_UP SYMBOLSTRING_UP);
2197 
2198 	j++;
2199     }
2200 
2201     for (; j < ylen; j++)
2202     {
2203 	gfx_cleartextline(j, x-1);
2204 	if (entry)
2205 	{
2206 	    entry = list[i];
2207 	    if (entry)
2208 	    {
2209 		// Last line may be scroll down.  This is true so long as
2210 		// there is extra entries.
2211 		if (list[i+1] && j == (ylen-1))
2212 		{
2213 		    gfx_printtext(x, j,
2214 			SYMBOLSTRING_DOWN SYMBOLSTRING_DOWN SYMBOLSTRING_DOWN);
2215 		}
2216 		else
2217 		{
2218 		    gfx_printtext(x, j, entry);
2219 		    endoflist = i;
2220 		}
2221 
2222 		// Highlight current selection.
2223 		if (i == select)
2224 		{
2225 		    gfx_printtext(x-1, j, SYMBOLSTRING_RIGHT);
2226 		    gfx_printtext(x+strlen(entry), j, SYMBOLSTRING_LEFT);
2227 		}
2228 	    }
2229 	    i++;
2230 	}
2231     }
2232 }
2233 
2234 // Evil!
2235 void writeGlobalActionBar(bool useemptyslot);
2236 
2237 // Returns selected menu entry...
2238 // x & y is where top left of menu will be.  Default is menu[0].
2239 // -1 means the selection was cancelled.
2240 int
gfx_selectmenu(int x,int y,const char ** menu,int & aorb,int def,bool anykey,bool disablepaging,const u8 * menuactions,u8 * actionstrip)2241 gfx_selectmenu(int x, int y, const char **menu, int &aorb, int def,
2242 		bool anykey, bool disablepaging,
2243 		const u8 *menuactions,
2244 		u8 *actionstrip)
2245 {
2246     int		 i, num, select, dx, dy;
2247     const char	*entry;
2248 
2249     aorb = -1;
2250 
2251     num = 0;
2252     for (i = 0; (entry = menu[i]); i++)
2253     {
2254 	num++;
2255     }
2256 
2257     // If there are no items to pick, cancel immediately.
2258     if (!num)
2259 	return -1;
2260 
2261     // Now, we can treat menu as a 0..num-1 array.
2262     select = def;
2263     if (select >= num)
2264 	select = 0;		// Illegal default given.
2265     if (select < 0)
2266 	select = 0;		// Less than zero is also illegal.
2267 
2268     STYLUSLOCK	styluslock((!menuactions) ? REGION_MENU
2269 			    : (REGION_MENU | REGION_BOTTOMBUTTON | REGION_SIDEBUTTON));
2270     int		startoflist = 0, endoflist = 0;
2271 
2272     // If we are in drag mode, we need to free up the borders so they
2273     // can be selected.
2274     if (menuactions)
2275 	styluslock.setRange(x, 0, 29, 20);
2276     else
2277 	styluslock.setRange(x, -1, -1, -1);
2278 
2279     // Display the menu.
2280     gfx_displaylist(x, y, 18, menu, select, startoflist, endoflist);
2281 
2282     // Wait for all buttons to go up to start...
2283     // We only check for buttons that we care about.  We don't want to
2284     // abort key repeat on arrow keys in case someone cancels a popup
2285     // window.
2286 #ifndef HAS_KEYBOARD
2287     while ( (ctrl_rawpressed(BUTTON_A) || ctrl_rawpressed(BUTTON_B))
2288 	    && !hamfake_forceQuit())
2289     {
2290 	if (!gfx_isnewframe())
2291 	    continue;
2292     }
2293 #endif
2294     // Wipe out all of our hit states.
2295     hamfake_clearKeyboardBuffer();
2296     if (menuactions) writeGlobalActionBar(true);
2297 
2298     while (1)
2299     {
2300 	if (!gfx_isnewframe())
2301 	    continue;
2302 
2303 	if (hamfake_forceQuit())
2304 	    return -1;
2305 
2306 #ifdef HAS_KEYBOARD
2307 	int		key;
2308 
2309 	key = hamfake_getKeyPress(false);
2310 
2311 	dx = 0;
2312 	dy = 0;
2313 	switch (key)
2314 	{
2315 	    case GFX_KEYF1:
2316 	    case GFX_KEYF2:
2317 	    case GFX_KEYF3:
2318 	    case GFX_KEYF4:
2319 	    case GFX_KEYF5:
2320 	    case GFX_KEYF6:
2321 	    case GFX_KEYF7:
2322 	    case GFX_KEYF8:
2323 	    case GFX_KEYF9:
2324 	    case GFX_KEYF10:
2325 	    case GFX_KEYF11:
2326 	    case GFX_KEYF12:
2327 	    case GFX_KEYF13:
2328 	    case GFX_KEYF14:
2329 	    case GFX_KEYF15:
2330 		if (menuactions)
2331 		{
2332 		    // Bind the first 15 menu actions to our key
2333 		    int		index = key - GFX_KEYF1;
2334 
2335 		    actionstrip[index] = menuactions[select];
2336 
2337 		    // Rebuild the list.
2338 		    writeGlobalActionBar(true);
2339 		}
2340 		break;
2341 	    case 'k':
2342 	    case GFX_KEYUP:
2343 	    case '8':
2344 		dy = -1;
2345 		break;
2346 	    case 'j':
2347 	    case GFX_KEYDOWN:
2348 	    case '2':
2349 		dy = 1;
2350 		break;
2351 	    case GFX_KEYPGUP:
2352 		dy = MAX(-10, -select);
2353 		break;
2354 	    case GFX_KEYPGDOWN:
2355 		dy = MIN(10, num - select - 1);
2356 		break;
2357 	    case 'l':
2358 	    case 'h':
2359 	    case GFX_KEYLEFT:
2360 	    case GFX_KEYRIGHT:
2361 	    case '4':
2362 	    case '6':
2363 		dy = 0;
2364 		break;
2365 
2366 	    // Press a.
2367 	    case ' ':
2368 	    case '\n':
2369 	    case '\r':
2370 	    case '5':
2371 		aorb = 0;
2372 		if (anykey)
2373 		    aorb = BUTTON_A;
2374 		if (menuactions) writeGlobalActionBar(false);
2375 		return select;
2376 
2377 	    // Press b.
2378 	    case '0':
2379 	    case '\x1b':
2380 		aorb = 1;
2381 		if (anykey)
2382 		    aorb = BUTTON_B;
2383 		if (menuactions) writeGlobalActionBar(false);
2384 		return select;
2385 
2386 	    // Request for more information, a select key!
2387 	    case 'i':
2388 	    case '?':
2389 		if (anykey)
2390 		{
2391 		    aorb = BUTTON_SELECT;
2392 		    if (menuactions) writeGlobalActionBar(false);
2393 		    return select;
2394 		}
2395 
2396 	    default:
2397 		dx = 0;
2398 		dy = 0;
2399 		break;
2400 	}
2401 #else
2402 	dx = dy = 0;
2403 
2404 	if (ctrl_hit(BUTTON_START))
2405 	{
2406 	    // Cancel
2407 	    if (menuactions) writeGlobalActionBar(false);
2408 	    return -1;
2409 	}
2410 
2411 	if (ctrl_hit(BUTTON_A))
2412 	{
2413 	    // Accept....
2414 	    aorb = 0;
2415 	    if (anykey)
2416 		aorb = BUTTON_A;
2417 	    if (menuactions) writeGlobalActionBar(false);
2418 	    return select;
2419 	}
2420 	if (ctrl_hit(BUTTON_B))
2421 	{
2422 	    aorb = 1;
2423 	    if (anykey)
2424 		aorb = BUTTON_B;
2425 	    if (menuactions) writeGlobalActionBar(false);
2426 	    return select;
2427 	}
2428 	if (anykey)
2429 	{
2430 	    if (ctrl_hit(BUTTON_SELECT))
2431 	    {
2432 		aorb = BUTTON_SELECT;
2433 		if (menuactions) writeGlobalActionBar(false);
2434 		return select;
2435 	    }
2436 	    if (ctrl_hit(BUTTON_X))
2437 	    {
2438 		aorb = BUTTON_X;
2439 		if (menuactions) writeGlobalActionBar(false);
2440 		return select;
2441 	    }
2442 	    if (ctrl_hit(BUTTON_Y))
2443 	    {
2444 		aorb = BUTTON_Y;
2445 		if (menuactions) writeGlobalActionBar(false);
2446 		return select;
2447 	    }
2448 	}
2449 	if (anykey && disablepaging)
2450 	{
2451 	    if (ctrl_hit(BUTTON_L))
2452 	    {
2453 		aorb = BUTTON_L;
2454 		if (menuactions) writeGlobalActionBar(false);
2455 		return select;
2456 	    }
2457 	    if (ctrl_hit(BUTTON_R))
2458 	    {
2459 		aorb = BUTTON_R;
2460 		if (menuactions) writeGlobalActionBar(false);
2461 		return select;
2462 	    }
2463 	}
2464 	else
2465 	{
2466 	    // We clamp page up/down to the limits
2467 	    if (ctrl_hit(BUTTON_L))
2468 		dy = MAX(-10, -select);
2469 	    if (ctrl_hit(BUTTON_R))
2470 		dy = MIN(10, num - select - 1);
2471 	}
2472 
2473 
2474 	// Change our position if dy not zero.
2475 	// Only test arrow keys if r or l not pressed
2476 	if (!dx && !dy)
2477 	    ctrl_getdir(dx, dy);
2478 #endif
2479 
2480 	// Process any drag requests.
2481 	if (menuactions)
2482 	{
2483 	    if (styluslock.performDrags(y*TILEHEIGHT, startoflist, endoflist, menuactions, actionstrip))
2484 	    {
2485 		// Update...
2486 		if (menuactions) writeGlobalActionBar(true);
2487 	    }
2488 	}
2489 
2490 	int		styluschoice;
2491 	bool		inbounds = false;
2492 	if (styluslock.selectmenu(styluschoice, x*TILEWIDTH, y*TILEHEIGHT, inbounds))
2493 	{
2494 	    if (!inbounds)
2495 	    {
2496 		// User clicked outside of the menu, consider
2497 		// a cancel.
2498 		aorb = 1;
2499 		if (anykey)
2500 		    aorb = BUTTON_B;
2501 		if (menuactions) writeGlobalActionBar(false);
2502 		return select;
2503 	    }
2504 	    else
2505 	    {
2506 		// A real selection if this was valid.
2507 		// Check for the case of up arrows.
2508 		if (startoflist)
2509 		    styluschoice--;
2510 		if (styluschoice < 0)
2511 		{
2512 		    // Scroll up.
2513 		    dy = MAX(-10, -select);
2514 		}
2515 		else if (startoflist + styluschoice > endoflist)
2516 		{
2517 		    // Scroll down.
2518 		    dy = MIN(10, num - select - 1);
2519 		}
2520 		else
2521 		{
2522 		    aorb = 0;
2523 		    if (anykey)
2524 			aorb = BUTTON_A;
2525 		    if (menuactions) writeGlobalActionBar(false);
2526 		    return startoflist + styluschoice;
2527 		}
2528 	    }
2529 	}
2530 
2531 	if (!dx && !dy)
2532 	{
2533 	    // Nothing to do.
2534 	    continue;
2535 	}
2536 	else if (dx && !dy)
2537 	{
2538 	    // Fast paging with left/right for cases where L/R
2539 	    // are already overload.
2540 	    if (ctrl_hit(BUTTON_L))
2541 		dy = MAX(-10, -select);
2542 	    if (ctrl_hit(BUTTON_R))
2543 		dy = MIN(10, num - select - 1);
2544 	}
2545 
2546 	if (dy)
2547 	{
2548 	    // Adjust selection...
2549 	    select += dy;
2550 
2551 	    // Note: On the libdns system this triggers a compiler bug
2552 	    // of some sort with -O2.  Basically, if dy < 0 we take the
2553 	    // following branch as if select == dy.
2554 	    if (select < 0)
2555 		select = num-1;
2556 	    if (select >= num)		// Not else so zero length lists yield 0
2557 		select = 0;
2558 
2559 	    gfx_displaylist(x, y, 18, menu, select, startoflist, endoflist);
2560 	}
2561     }
2562     if (menuactions) writeGlobalActionBar(false);
2563     return -1;
2564 }
2565 
2566 bool
gfx_yesnomenu(const char * prompt,bool defchoice)2567 gfx_yesnomenu(const char *prompt, bool defchoice)
2568 {
2569     int		aorb;
2570     int		choice, width;
2571     // Prompt...
2572     const char *menu[4] =
2573     {
2574 	"Yes",
2575 	"No",
2576 	0
2577     };
2578 
2579     width = strlen(prompt);
2580 
2581     // Build an overlay for our question...
2582     {
2583 	// Erase all tiles.
2584 	int		sx, sy;
2585 	TILE_NAMES	tile;
2586 	for (sy = 2; sy < 6; sy++)
2587 	{
2588 	    if (sy == 2)
2589 		tile = TILE_SCROLL_TOP;
2590 	    else if (sy == 5)
2591 		tile = TILE_SCROLL_BOTTOM;
2592 	    else
2593 		tile = TILE_SCROLL_BACK;
2594 	    for (sx = 2; sx < 2 + (width+1)/2; sx++)
2595 	    {
2596 		// We don't want to write past the end
2597 		// even for a large prompt.
2598 		if (sx >= 16)
2599 		    break;
2600 		gfx_setabsoverlay(sx, sy, tile);
2601 	    }
2602 	}
2603     }
2604 
2605     // Write out the query.
2606     // This really should be made a horizontal
2607     // yes/no box!
2608     gfx_printtext(4, 6, prompt);
2609 
2610     choice = gfx_selectmenu(8, 8, menu, aorb, !defchoice);
2611     if (aorb)
2612 	choice = -1;
2613     if (choice >= 1)
2614 	choice = -1;
2615 
2616     // Clear
2617     {
2618 	int		y;
2619 	for (y = 3; y < 19; y++)
2620 	    gfx_cleartextline(y);
2621     }
2622     // This is because of our overlay options...
2623     gfx_refreshtiles();
2624 
2625     if (choice == 0)
2626 	return true;
2627     return false;
2628 }
2629 
2630 void
gfx_displayinfoblock(const char * text,bool prevline)2631 gfx_displayinfoblock(const char *text, bool prevline)
2632 {
2633     int		x, y;
2634 
2635     gfx_cleartextline(3);
2636     gfx_cleartextline(18);
2637     if (prevline)
2638     {
2639 	gfx_printchar(0, 3, SYMBOL_UP);
2640 	gfx_printchar(14, 3, SYMBOL_UP);
2641 	gfx_printchar(29, 3, SYMBOL_UP);
2642     }
2643 
2644     for (y = 4; y < 18; y++)
2645     {
2646 	for (x = 0; x < 30; x++)
2647 	{
2648 	    if (!*text)
2649 	    {
2650 		gfx_printchar(x, y, ' ');
2651 	    }
2652 	    else
2653 	    {
2654 		gfx_printchar(x, y, *text);
2655 		text++;
2656 	    }
2657 	}
2658     }
2659 
2660     // If there is more text (which there should be if we get here)
2661     // prompt the fact.
2662     if (*text)
2663     {
2664 	gfx_printchar(0, 18, SYMBOL_DOWN);
2665 	gfx_printchar(14, 18, SYMBOL_DOWN);
2666 	gfx_printchar(29, 18, SYMBOL_DOWN);
2667     }
2668 }
2669 
2670 void
gfx_displayinfotext(const char * text)2671 gfx_displayinfotext(const char *text)
2672 {
2673     const char		*curtext;
2674     int			 dx, dy, y;
2675     STYLUSLOCK		 styluslock(REGION_DISPLAYTEXT);
2676 
2677     gfx_displayinfoblock(text, false);
2678 
2679     curtext = text;
2680     while (1)
2681     {
2682 	if (!gfx_isnewframe())
2683 	    continue;
2684 
2685 	if (hamfake_forceQuit())
2686 	    return;
2687 
2688 #ifdef HAS_KEYBOARD
2689 	int		key;
2690 	bool		stop = false;
2691 
2692 	key = hamfake_getKeyPress(false);
2693 
2694 	dy = 0;
2695 	switch (key)
2696 	{
2697 	    case 'k':
2698 	    case GFX_KEYUP:
2699 	    case '8':
2700 		dy = -1;
2701 		break;
2702 	    case 'j':
2703 	    case GFX_KEYDOWN:
2704 	    case '2':
2705 		dy = 1;
2706 		break;
2707 	    case GFX_KEYPGUP:
2708 		dy = -10;
2709 		break;
2710 	    case GFX_KEYPGDOWN:
2711 		dy = 10;
2712 		break;
2713 	    case 'l':
2714 	    case 'h':
2715 	    case '4':
2716 	    case '6':
2717 	    case GFX_KEYLEFT:
2718 	    case GFX_KEYRIGHT:
2719 		dy = 0;
2720 		break;
2721 	    case ' ':
2722 	    case '5':
2723 	    case '0':
2724 	    case '\r':
2725 	    case '\x1b':
2726 		stop = true;
2727 		break;
2728 	    default:
2729 		dy = 0;
2730 		break;
2731 	}
2732 
2733 	if (stop)
2734 	    break;
2735 #else
2736 	if (ctrl_hit(BUTTON_A))
2737 	    break;
2738 	if (ctrl_hit(BUTTON_B))
2739 	    break;
2740 
2741 	if (ctrl_hit(BUTTON_R))
2742 	{
2743 	    dy = 10;
2744 	}
2745 	else if (ctrl_hit(BUTTON_L))
2746 	{
2747 	    dy = -10;
2748 	}
2749 	else
2750 	{
2751 	    ctrl_getdir(dx, dy);
2752 	}
2753 	hamfake_clearKeyboardBuffer();
2754 #endif
2755 
2756 	if (styluslock.getdisplaytext(dy))
2757 	{
2758 	    dy = dy;
2759 	    if (!dy)
2760 		break;
2761 	}
2762 
2763 	if (!dy)
2764 	    continue;
2765 
2766 	while (dy)
2767 	{
2768 	    if (dy < 0)
2769 	    {
2770 		dy++;
2771 		// User wants to scroll up.
2772 		if (curtext != text)
2773 		{
2774 		    curtext -= 30;
2775 		}
2776 		else
2777 		    dy = 0;
2778 	    }
2779 	    if (dy > 0)
2780 	    {
2781 		dy--;
2782 		// User wants scroll down.
2783 		if (strlen(curtext) >= 30 * (18 - 4))
2784 		{
2785 		    curtext += 30;
2786 		}
2787 		else
2788 		    dy = 0;
2789 	    }
2790 	}
2791 	gfx_displayinfoblock(curtext, curtext != text);
2792     }
2793 
2794     for (y = 3; y < 19; y++)
2795 	gfx_cleartextline(y);
2796 }
2797 
2798 char **glb_pager = 0;
2799 int    glb_pager_curline = -1, glb_pager_size = 0;
2800 int	glb_pager_width = 30;
2801 
2802 void
gfx_pager_setwidth(int width)2803 gfx_pager_setwidth(int width)
2804 {
2805     glb_pager_width = width;
2806 }
2807 
2808 void
gfx_pager_addtext(BUF buf)2809 gfx_pager_addtext(BUF buf)
2810 {
2811     gfx_pager_addtext(buf.buffer());
2812 }
2813 
2814 void
gfx_pager_addtext(const char * text)2815 gfx_pager_addtext(const char *text)
2816 {
2817     // Make sure we have a line...
2818     if (!glb_pager)
2819     {
2820 	glb_pager_curline = -1;
2821 	glb_pager_size = 0;
2822 	gfx_pager_newline();
2823     }
2824 
2825     const char		*src;
2826     char		*dst, *origdst;
2827     int			 dstlen, dstmaxlen;
2828 
2829     // Point to the next write location...
2830     src = text;
2831     origdst = dst = glb_pager[glb_pager_curline];
2832     dstmaxlen = glb_pager_width;
2833     dstlen = strlen(dst);
2834     dst += dstlen;
2835 
2836     while (*src && dstlen < dstmaxlen)
2837     {
2838 	*dst++ = *src++;
2839 	dstlen++;
2840     }
2841 
2842     // If we ran out of source material, done.
2843     if (!*src)
2844     {
2845 	*dst++ = '\0';
2846 	return;
2847     }
2848 
2849     // We have to wrap :<  If src is a space, wrapping is trivial.
2850     // Otherwise, we backup src until it is a space...
2851     while (!isspace(*src) && src > text)
2852     {
2853 	src--;
2854 	dst--;
2855 	dstlen--;
2856     }
2857 
2858     // Now, move forward until we ate all the spaces (this seems odd
2859     // except if *src was a space going into the last loop)
2860     while (*src && isspace(*src))
2861     {
2862 	src++;
2863     }
2864 
2865     // It could be trailing spaces sent us over the bounds.  We will
2866     // thus eat these and ignore them.
2867     if (!*src)
2868     {
2869 	*dst++ = '\0';
2870 	return;
2871     }
2872 
2873     // Avoid throwing this on the stack as we recurse and GBA sucks.
2874     char		 *prefix = new char[30+1];
2875     prefix[0] = '\0';
2876 
2877     // Special case:  If src == str now, yet our dstlen == 0, we have a
2878     // single word over SCREEN_WIDTH.  We resolve this by dumping
2879     // dstmaxlen - 1 chars, a hyphen, and then continuing as if we
2880     // found a space.
2881     if (src == text && !dstlen)
2882     {
2883 	while (*src && dstlen < dstmaxlen-1)
2884 	{
2885 	    *dst++ = *src++;
2886 	    dstlen++;
2887 	}
2888 	// Append a hyphen...
2889 	*dst++ = '-';
2890     }
2891     // Special case: If src == str, dstlen != 0, we are tacking onto
2892     // the end of an existing word.  If that word ends with a space,
2893     // great, we wrap as expected.  However, we often build up
2894     // a string with a series of writes, such as "foo" followed by ", bar".
2895     // We want to wrap the last word on dst.  If dst doesn't have a sub
2896     // word, obviously we avoid this.
2897     // Of course, this isn't the full story.  It could be that the
2898     // previous line got to exactly 30 columns.  Any spaces would be
2899     // silently eaten so it would look like there are no spaces.
2900     // To solve this, we look for special non-breaking characters that
2901     // we feel should be enjoined.  Specifically, a punctuation on the
2902     // LHS means we should break, and a punctuation on the RHS means
2903     // we should not.
2904     else if (src == text)
2905     {
2906 	char		rhs, lhs;
2907 	rhs = src[0];
2908 	lhs = origdst[dstlen-1];
2909 	// Check if LHS is breaking, in which case we always break
2910 	// so ignore this code path.
2911 	if (!isspace(lhs) && lhs != '.' && lhs != ',' && lhs != '!' && lhs != '?')
2912 	{
2913 	    // Find the start of the word in dst...
2914 	    int		wordstart = dstlen - 1;
2915 	    while (!isspace(origdst[wordstart]) && wordstart > 0)
2916 	    {
2917 		wordstart--;
2918 	    }
2919 
2920 	    // If wordstart is now zero, our previuos entry was the
2921 	    // full length.  We might hyphenate here, but I think it
2922 	    // is simpler just to let the break lie where we broke
2923 	    // it before.
2924 	    if (wordstart)
2925 	    {
2926 		// Since wordstart points to a space, we can safely
2927 		// mark wordstart as null & strcpy out wordstart+1
2928 		strcpy(prefix, &origdst[wordstart+1]);
2929 		origdst[wordstart] = '\0';
2930 	    }
2931 	}
2932     }
2933 
2934     // Wrap to the next line.  Null terminate dst and build
2935     // a new line.
2936     *dst++ = '\0';
2937     gfx_pager_newline();
2938 
2939     // And, because we are too lazy to make this a loop, recurse.
2940     gfx_pager_addtext(prefix);
2941     delete [] prefix;
2942     gfx_pager_addtext(src);
2943 }
2944 
2945 void
gfx_pager_addsingleline(const char * text)2946 gfx_pager_addsingleline(const char *text)
2947 {
2948     // Make sure we have a line...
2949     if (!glb_pager)
2950     {
2951 	glb_pager_curline = -1;
2952 	glb_pager_size = 0;
2953 	gfx_pager_newline();
2954     }
2955 
2956     const char		*src;
2957     char		*dst;
2958     int			 dstlen, dstmaxlen;
2959 
2960     // Point to the next write location...
2961     src = text;
2962     dst = glb_pager[glb_pager_curline];
2963     dstmaxlen = glb_pager_width;
2964     dstlen = strlen(dst);
2965 
2966     if (dstlen > 0)
2967 	gfx_pager_newline();
2968 
2969     dst = glb_pager[glb_pager_curline];
2970     dstmaxlen = glb_pager_width;
2971     dstlen = strlen(dst);
2972 
2973     dst += dstlen;
2974 
2975     while (*src && dstlen < dstmaxlen)
2976     {
2977 	*dst++ = *src++;
2978 	dstlen++;
2979     }
2980 
2981     // Even if we didn't run out of source, we truncate and return.
2982     *dst++ = '\0';
2983 
2984     // Ensure next line starts fresh.
2985     gfx_pager_newline();
2986 }
2987 
2988 void
gfx_pager_newline()2989 gfx_pager_newline()
2990 {
2991     // Move to the next line.
2992     glb_pager_curline++;
2993 
2994     // Check for over flow.
2995     if (glb_pager_curline >= glb_pager_size)
2996     {
2997 	// Reallocate.
2998 	char		**newpager;
2999 
3000 	newpager = new char *[glb_pager_size + 32];
3001 
3002 	if (glb_pager)
3003 	    memcpy(newpager, glb_pager, sizeof(char *) * glb_pager_size);
3004 
3005 	glb_pager_size += 32;
3006 	delete [] glb_pager;
3007 	glb_pager = newpager;
3008     }
3009 
3010     // And ensure the new buffer is allocated.
3011     glb_pager[glb_pager_curline] = new char[glb_pager_width+2];
3012     glb_pager[glb_pager_curline][0] = '\0';
3013 }
3014 
3015 void
gfx_pager_separator()3016 gfx_pager_separator()
3017 {
3018     // This is so long so 80 column print outs get a full separator.
3019     gfx_pager_addsingleline("-------------------------------------------------------------------------------");
3020 }
3021 
3022 void
gfx_pager_display_block(int y)3023 gfx_pager_display_block(int y)
3024 {
3025     int		 sx, sy;
3026     const char	*text;
3027 
3028     gfx_cleartextline(3);
3029     gfx_cleartextline(18);
3030     if (y)
3031     {
3032 	gfx_printchar(0, 3, SYMBOL_UP);
3033 	gfx_printchar(14, 3, SYMBOL_UP);
3034 	gfx_printchar(29, 3, SYMBOL_UP);
3035     }
3036 
3037     for (sy = 4; sy < 18; sy++, y++)
3038     {
3039 	if (y > glb_pager_curline)
3040 	    gfx_cleartextline(sy);
3041 	else
3042 	{
3043 	    text = glb_pager[y];
3044 	    for (sx = 0; sx < 30; sx++)
3045 	    {
3046 
3047 		if (!*text)
3048 		{
3049 		    gfx_printchar(sx, sy, ' ');
3050 		}
3051 		else
3052 		{
3053 		    gfx_printchar(sx, sy, *text);
3054 		    text++;
3055 		}
3056 	    }
3057 	}
3058     }
3059 
3060     // If we still have rows left, display down arrows.
3061     if (y < glb_pager_curline)
3062     {
3063 	gfx_printchar(0, 18, SYMBOL_DOWN);
3064 	gfx_printchar(14, 18, SYMBOL_DOWN);
3065 	gfx_printchar(29, 18, SYMBOL_DOWN);
3066     }
3067 }
3068 
3069 void
gfx_pager_savetofile(const char * name)3070 gfx_pager_savetofile(const char *name)
3071 {
3072 #ifdef HAS_DISKIO
3073     if (!hamfake_fatvalid())
3074     {
3075 	gfx_pager_reset();
3076 	return;
3077     }
3078 
3079 #ifdef iPOWDER
3080     if (hamfake_cansendemail())
3081     {
3082 	for (int y = 3; y < 19; y++)
3083 	    gfx_cleartextline(y);
3084 	if (gfx_yesnomenu("Email Game Summary?", false))
3085 	{
3086 	    // Send an email.
3087 	    BUF		body;
3088 	    for (int i = 0; i <= glb_pager_curline; i++)
3089 	    {
3090 		body.strcat(glb_pager[i]);
3091 		body.strcat("\n\r");
3092 	    }
3093 
3094 	    hamfake_sendemail("", name, body.buffer());
3095 	}
3096     }
3097     gfx_pager_reset();
3098     return;
3099 #else
3100 
3101     FILE		*fp;
3102 
3103     fp = hamfake_fopen(name, "wt");
3104     if (!fp)
3105     {
3106 	printf("OPEN %s FAILED!\n", name);
3107 	return;
3108     }
3109 
3110     int			i;
3111     for (i = 0; i <= glb_pager_curline; i++)
3112     {
3113 #if defined(LINUX) || defined(WIN32)
3114 	fprintf(fp, "%s\n", glb_pager[i]);
3115 #else
3116 	// For embedded systems always use line feeds so
3117 	// the windows users can parse it easier.
3118 	// Linux users are more used to crappy line feeds.
3119 	fprintf(fp, "%s\r\n", glb_pager[i]);
3120 #endif
3121     }
3122 
3123     fclose(fp);
3124     gfx_pager_reset();
3125 #endif
3126 #endif
3127 }
3128 
3129 void hideSideActionBar();
3130 
3131 void
gfx_pager_display(int y)3132 gfx_pager_display(int y)
3133 {
3134     if (!glb_pager) return;
3135 
3136     int			 dx, dy;
3137     int			 tile;
3138 
3139     // Make y the center.
3140     y -= (18 - 4) / 2;
3141 
3142     if (y >= glb_pager_curline - (18 - 4))
3143 	y = glb_pager_curline - (18 - 4);
3144 
3145     // Hide the side buttons.
3146     hideSideActionBar();
3147 
3148     // Clip the requested y position.
3149     if (y < 0)
3150 	y = 0;
3151 
3152     // Erase all tiles.
3153     int		sx, sy;
3154     for (sy = 1; sy < 10; sy++)
3155     {
3156 	if (sy == 1)
3157 	    tile = TILE_SCROLL_TOP;
3158 	else if (sy == 9)
3159 	    tile = TILE_SCROLL_BOTTOM;
3160 	else
3161 	    tile = TILE_SCROLL_BACK;
3162 	for (sx = -1; sx < 16; sx++)
3163 	{
3164 	    gfx_setabsoverlay(sx, sy, tile);
3165 	}
3166     }
3167 
3168     gfx_pager_display_block(y);
3169 
3170 #ifndef HAS_KEYBOARD
3171     // Wait for no button to be hit.
3172     while (ctrl_anyrawpressed() && !hamfake_forceQuit())
3173     {
3174 	hamfake_awaitEvent();
3175     }
3176 #endif
3177 
3178     // Clear the repeat queue of SDL
3179     hamfake_clearKeyboardBuffer();
3180 
3181     STYLUSLOCK		 styluslock(REGION_DISPLAYTEXT);
3182     while (1)
3183     {
3184 	if (!gfx_isnewframe())
3185 	    continue;
3186 
3187 	if (hamfake_forceQuit())
3188 	    return;
3189 
3190 	// Quit immediately in stress test
3191 	if (glbStressTest)
3192 	    break;
3193 
3194 #ifdef HAS_KEYBOARD
3195 	int		key;
3196 	bool		stop = false;
3197 
3198 	key = hamfake_getKeyPress(false);
3199 
3200 	dy = 0;
3201 	switch (key)
3202 	{
3203 	    case 'k':
3204 	    case GFX_KEYUP:
3205 	    case '8':
3206 		dy = -1;
3207 		break;
3208 	    case 'j':
3209 	    case GFX_KEYDOWN:
3210 	    case '2':
3211 		dy = 1;
3212 		break;
3213 	    case GFX_KEYPGUP:
3214 		dy = -10;
3215 		break;
3216 	    case GFX_KEYPGDOWN:
3217 		dy = 10;
3218 		break;
3219 	    case 'l':
3220 	    case 'h':
3221 	    case GFX_KEYLEFT:
3222 	    case GFX_KEYRIGHT:
3223 	    case '4':
3224 	    case '6':
3225 		dy = 0;
3226 		break;
3227 	    case ' ':
3228 	    case '\n':
3229 	    case '\r':
3230 	    case '5':
3231 	    case '0':
3232 	    case '\x1b':
3233 		stop = true;
3234 		break;
3235 	    default:
3236 		dy = 0;
3237 		break;
3238 	}
3239 
3240 	if (stop)
3241 	    break;
3242 #else
3243 	if (ctrl_hit(BUTTON_A))
3244 	    break;
3245 	if (ctrl_hit(BUTTON_B))
3246 	    break;
3247 
3248 	if (ctrl_hit(BUTTON_R))
3249 	{
3250 	    dy = 10;
3251 	}
3252 	else if (ctrl_hit(BUTTON_L))
3253 	{
3254 	    dy = -10;
3255 	}
3256 	else
3257 	{
3258 	    ctrl_getdir(dx, dy);
3259 	}
3260 	hamfake_clearKeyboardBuffer();
3261 #endif
3262 	if (styluslock.getdisplaytext(dy))
3263 	{
3264 	    dy = dy;
3265 	    if (!dy)
3266 		break;
3267 	}
3268 
3269 	if (dy < 0)
3270 	{
3271 	    // User wants to scroll up.
3272 	    if (y)
3273 	    {
3274 		y += dy;
3275 		if (y < 0)
3276 		    y = 0;
3277 		gfx_pager_display_block(y);
3278 	    }
3279 	}
3280 	if (dy > 0)
3281 	{
3282 	    if (y < glb_pager_curline - (18 - 4))
3283 	    {
3284 		y += dy;
3285 		if (y > glb_pager_curline - (18 - 4))
3286 		{
3287 		    y = glb_pager_curline - (18 - 4);
3288 		}
3289 		gfx_pager_display_block(y);
3290 	    }
3291 	}
3292     }
3293 
3294     for (y = 3; y < 19; y++)
3295 	gfx_cleartextline(y);
3296 
3297     gfx_pager_reset();
3298 
3299     // Because we did absolute sets, this will restore.
3300     gfx_refreshtiles();
3301 
3302     // Clear the repeat queue of SDL
3303     hamfake_clearKeyboardBuffer();
3304 }
3305 
3306 void
gfx_pager_reset()3307 gfx_pager_reset()
3308 {
3309     int		y;
3310 
3311     // Clear out our pager.
3312     for (y = 0; y <= glb_pager_curline; y++)
3313     {
3314 	delete [] glb_pager[y];
3315     }
3316     delete [] glb_pager;
3317     glb_pager = 0;
3318     glb_pager_size = 0;
3319     glb_pager_curline = -1;
3320 }
3321 
3322 bool
gfx_selecttile(int & tx,int & ty,bool quickselect,int * quickold,int * aorb,bool * stylus)3323 gfx_selecttile(int &tx, int &ty, bool quickselect, int *quickold, int *aorb,
3324 		bool *stylus)
3325 {
3326     int		dx, dy;
3327     int		oldoverlay;
3328     bool	cancel;
3329     STYLUSLOCK	styluslock(REGION_MAPTILES);
3330 
3331     if (stylus)
3332 	*stylus = false;
3333 
3334     // If we are quickselecting, our old overlay may be the cursor
3335     // itself - we require the caller to maintain its value.
3336     oldoverlay = gfx_getoverlay(tx, ty);
3337     if (quickselect)
3338 	oldoverlay = quickold ? *quickold : TILE_VOID;
3339     if (aorb)
3340 	*aorb = 0;
3341     gfx_setoverlay(tx, ty, TILE_CURSOR);
3342     gfx_scrollcenter(tx, ty);
3343     while (1)
3344     {
3345 	if (!gfx_isnewframe())
3346 	    continue;
3347 
3348 	if (hamfake_forceQuit())
3349 	    return false;
3350 
3351 	if (ctrl_hit(BUTTON_A))
3352 	{
3353 	    // Accept....
3354 	    gfx_scrollcenter(MOB::getAvatar()->getX(), MOB::getAvatar()->getY());
3355 	    gfx_setoverlay(tx, ty, oldoverlay);
3356 	    if (aorb)
3357 		*aorb = 0;
3358 	    hamfake_clearKeyboardBuffer();
3359 	    return true;
3360 	}
3361 	if (ctrl_hit(BUTTON_B))
3362 	{
3363 	    // Cancel
3364 	    gfx_scrollcenter(MOB::getAvatar()->getX(), MOB::getAvatar()->getY());
3365 	    gfx_setoverlay(tx, ty, oldoverlay);
3366 	    if (aorb)
3367 		*aorb = 1;
3368 	    hamfake_clearKeyboardBuffer();
3369 	    if (quickselect)
3370 		return true;
3371 	    else
3372 		return false;
3373 	}
3374 
3375 	if (styluslock.getmaptile(dx, dy, cancel))
3376 	{
3377 	    // User pressed on a tile successfully.
3378 	    gfx_scrollcenter(MOB::getAvatar()->getX(), MOB::getAvatar()->getY());
3379 	    gfx_setoverlay(tx, ty, oldoverlay);
3380 
3381 	    // Set the new location
3382 	    tx = dx;
3383 	    ty = dy;
3384 
3385 	    // Determine the overlay value of the new tile that we
3386 	    // are moving the curosr to.
3387 	    oldoverlay = gfx_getoverlay(tx, ty);
3388 	    if (quickselect && quickold)
3389 		*quickold = oldoverlay;
3390 
3391 	    if (aorb)
3392 		*aorb = cancel;
3393 	    if (stylus)
3394 		*stylus = true;
3395 	    hamfake_clearKeyboardBuffer();
3396 	    return !cancel;
3397 	}
3398 
3399 	ctrl_getdir(dx, dy);
3400 	if (!dx && !dy)
3401 	{
3402 	    // Consume any key in case an invalid key was hit
3403 	    hamfake_getKeyPress(false);
3404 	    continue;
3405 	}
3406 
3407 	// Erase old...
3408 	gfx_setoverlay(tx, ty, oldoverlay);
3409 	tx += dx;
3410 	ty += dy;
3411 	tx &= MAP_WIDTH - 1;
3412 	ty &= MAP_HEIGHT - 1;
3413 	oldoverlay = gfx_getoverlay(tx, ty);
3414 	if (quickselect && quickold)
3415 	    *quickold = oldoverlay;
3416 	gfx_setoverlay(tx, ty, TILE_CURSOR);
3417 	gfx_scrollcenter(tx, ty);
3418 
3419 	if (quickselect)
3420 	    return false;
3421     }
3422 }
3423 
3424 void writeYesNoBar();
3425 
3426 bool
gfx_selectinventory(int & selectx,int & selecty)3427 gfx_selectinventory(int &selectx, int &selecty)
3428 {
3429     bool	madechoice = false;
3430     int		button;
3431     int		dx, dy;
3432     bool	apress, bpress;
3433 
3434     STYLUSLOCK	styluslock(REGION_BOTTOMBUTTON);
3435 
3436     writeYesNoBar();
3437 
3438     gfx_setinvcursor(selectx, selecty, false);
3439     while (1)
3440     {
3441 	if (!gfx_isnewframe())
3442 	    continue;
3443 
3444 	if (hamfake_forceQuit())
3445 	    return false;
3446 
3447 	ctrl_getdir(dx, dy);
3448 	apress = ctrl_hit(BUTTON_A);
3449 	bpress = ctrl_hit(BUTTON_B);
3450 
3451 	if (styluslock.getbottombutton(button))
3452 	{
3453 	    // Either a cancel or accept.
3454 	    if (button == 18)
3455 		apress = true;
3456 	    if (button == 26)
3457 		bpress = true;
3458 	}
3459 
3460 	if (bpress)
3461 	{
3462 	    // Cancel
3463 	    madechoice = false;
3464 	    break;
3465 	}
3466 	if (apress)
3467 	{
3468 	    madechoice = true;
3469 	    break;
3470 	}
3471 
3472 	if (stylus_queryinventoryitem(selectx, selecty))
3473 	{
3474 	    gfx_setinvcursor(selectx, selecty, false);
3475 	    continue;
3476 	}
3477 
3478 	// Consume invalid keys.
3479 	hamfake_getKeyPress(false);
3480 
3481 	// We refetch this as this will deal
3482 	// silently with wrap.
3483 	gfx_getinvcursor(selectx, selecty);
3484 	selectx += dx;
3485 	selecty += dy;
3486 	gfx_setinvcursor(selectx, selecty, false);
3487     }
3488 
3489     return madechoice;
3490 }
3491 
3492 bool
gfx_selectdirection(int otx,int oty,int & rdx,int & rdy,int & rdz)3493 gfx_selectdirection(int otx, int oty, int &rdx, int &rdy, int &rdz)
3494 {
3495     int		dx, dy, ndx, ndy, tx, ty;
3496     int		oldoverlay;
3497     bool	chose = false;
3498     STYLUSLOCK	styluslock(REGION_TENDIR);
3499 
3500     hamfake_flushdir();
3501     hamfake_buttonreq(5, 1);
3502 
3503     rdx = rdy = rdz = 0;
3504     tx = otx;
3505     ty = oty;
3506     oldoverlay = gfx_getoverlay(tx, ty);
3507     gfx_setoverlay(tx, ty, TILE_CURSOR);
3508     dx = dy = 0;
3509     while (1)
3510     {
3511 	if (!gfx_isnewframe())
3512 	    continue;
3513 
3514 	if (hamfake_forceQuit())
3515 	    return false;
3516 
3517 	if (ctrl_hit(BUTTON_A))
3518 	{
3519 	    // Accept....
3520 	    gfx_setoverlay(tx, ty, oldoverlay);
3521 	    chose = true;
3522 	    break;
3523 	}
3524 	if (ctrl_hit(BUTTON_B))
3525 	{
3526 	    // Cancel
3527 	    gfx_setoverlay(tx, ty, oldoverlay);
3528 	    chose = false;
3529 	    break;
3530 	}
3531 
3532 	ctrl_getdir(ndx, ndy);
3533 
3534 	if (hamfake_externaldir(dx, dy))
3535 	{
3536 	    gfx_setoverlay(tx, ty, oldoverlay);
3537 	    chose = true;
3538 	    break;
3539 	}
3540 
3541 	if (styluslock.gettendir(rdx, rdy, rdz, chose))
3542 	{
3543 	    // Invert sense of choosing.
3544 	    gfx_setoverlay(tx, ty, oldoverlay);
3545 	    chose = !chose;
3546 	    hamfake_buttonreq(5, 0);
3547 	    return chose;
3548 	}
3549 
3550 	if (!ndx && !ndy)
3551 	{
3552 	    // Consume any key in case an invalid key was hit
3553 	    hamfake_getKeyPress(false);
3554 	    continue;
3555 	}
3556 
3557 	// Erase old...
3558 	gfx_setoverlay(tx, ty, oldoverlay);
3559 
3560 	dx += ndx;
3561 	dy += ndy;
3562 
3563 	// Clamp to our funny shape...
3564 	if (dy >= 2)
3565 	{
3566 	    dy = 2;
3567 	    dx = 0;
3568 	}
3569 	if (dy <= -2)
3570 	{
3571 	    dy = -2;
3572 	    dx = 0;
3573 	}
3574 	if (dx < -1)
3575 	    dx = -1;
3576 	if (dx > 1)
3577 	    dx = 1;
3578 
3579 	tx = otx + dx;
3580 	ty = oty + dy;
3581 	tx &= MAP_WIDTH - 1;
3582 	ty &= MAP_HEIGHT - 1;
3583 
3584 	oldoverlay = gfx_getoverlay(tx, ty);
3585 	gfx_setoverlay(tx, ty, TILE_CURSOR);
3586     }
3587 
3588     // Parse out our dx,dy into rdx, rdy, rdz.
3589 
3590     if (dy == 2)
3591 	rdz = -1;
3592     else if (dy == -2)
3593 	rdz = 1;
3594     else
3595     {
3596 	rdx = dx;
3597 	rdy = dy;
3598     }
3599 
3600     hamfake_buttonreq(5, 0);
3601     return chose;
3602 }
3603 
3604 void
gfx_copytiledata(TILE_NAMES desttile,MINI_NAMES minitile,bool ismale)3605 gfx_copytiledata(TILE_NAMES desttile, MINI_NAMES minitile, bool ismale)
3606 {
3607     const u8		*tiledata;
3608     int			 i;
3609     u16			 tile;
3610 
3611     tile = gfx_lookupTile(desttile);
3612 
3613     if (tile == INVALID_TILEIDX)
3614 	return;
3615 
3616     if (ismale)
3617 	tiledata = &glb_tilesets[glb_tileset].mini[minitile * BYTEPERTILE*4];
3618     else
3619 	tiledata = &glb_tilesets[glb_tileset].minif[minitile * BYTEPERTILE*4];
3620 
3621     if (!glb_comptiledata)
3622     {
3623 	// Allocate a u16 to guarantee alignment.
3624 	u16		*origdata = new u16 [WORDPERTILE*4];
3625 
3626 	glb_comptiledata = (u8 *) origdata;
3627     }
3628     for (i = 0; i < BYTEPERTILE*4; i++)
3629 	glb_comptiledata[i] = tiledata[i];
3630 
3631     // HMm...  I think ReloadTIleGfx needs aligned data, which is not
3632     // guaranteed with a static array.  No idea how the minitiles
3633     // work around this...
3634     glb_lastdesttile = tile;
3635     ham_ReloadTileGfx(glb_bg1tiles, (u16 *) glb_comptiledata, glb_lastdesttile, 4);
3636 }
3637 
3638 u8 *
gfx_extractsprite(int tileset,SPRITE_NAMES tile)3639 gfx_extractsprite(int tileset, SPRITE_NAMES tile)
3640 {
3641     int		w, h, x, y, srcidx;
3642     u8		*data, *dataout;
3643     u16		 c;
3644 
3645     w = glb_tilesets[tileset].tilewidth;
3646     h = glb_tilesets[tileset].tilewidth;
3647 
3648     data = (u8 *) malloc(4 * w * h * 3);
3649     dataout = data;
3650 
3651     for (y = 0; y < h * 2; y++)
3652     {
3653 	for (x = 0; x < w * 2; x++)
3654 	{
3655 	    srcidx = 0;
3656 	    srcidx += y * w;
3657 	    srcidx += x;
3658 	    if (x >= w)
3659 		srcidx += w * h - w;
3660 	    if (y >= h)
3661 		srcidx += w * h * 2 - w * h;
3662 	    c = glb_tilesets[tileset].spritepalette[glb_tilesets[tileset].sprite[tile * w * h * 4 + srcidx]];
3663 
3664 	    int		cb, cg, cr;
3665 
3666 	    cb = (c >> 10) << 3;
3667 	    cg = ((c >> 5) & 31) << 3;
3668 	    cr = (c & 31) << 3;
3669 	    *dataout++ = cr;
3670 	    *dataout++ = cg;
3671 	    *dataout++ = cb;
3672 	}
3673     }
3674 
3675     return data;
3676 }
3677 
3678 u8 *
gfx_extractlargesprite(SPRITE_NAMES tile,int grey,SPRITE_NAMES overlay)3679 gfx_extractlargesprite(SPRITE_NAMES tile, int grey, SPRITE_NAMES overlay)
3680 {
3681 #ifdef USE_VIRTUAL_SCREEN
3682     int		w, h, x, y, srcidx;
3683     u8		*data, *dataout;
3684     u16		 c;
3685 
3686     w = 48;
3687     h = 48;
3688 
3689     grey = 256 - grey;
3690     int		 cutoff = (grey * h + 128) / 256;
3691 
3692     data = (u8 *) malloc(w * h * 4);
3693     dataout = data;
3694 
3695     int		row, col;
3696 
3697     if (tile != SPRITE_INVALID)
3698     {
3699 	row = tile / 24;
3700 	col = tile - row*24;
3701 
3702 	for (y = 0; y < h; y++)
3703 	{
3704 	    for (x = 0; x < w; x++)
3705 	    {
3706 		srcidx = col * w + row * w * h * 24;
3707 		srcidx += y * w * 24;
3708 		srcidx += x;
3709 
3710 		c = bmp_sprite16_3x[srcidx];
3711 
3712 		int		cb, cg, cr;
3713 
3714 		cb = (c >> 10) << 3;
3715 		cg = ((c >> 5) & 31) << 3;
3716 		cr = (c & 31) << 3;
3717 
3718 		if (y < cutoff)
3719 		{
3720 		    cr = rgbtogrey(cr, cg, cb);
3721 		    cg = cb = cr;
3722 		}
3723 
3724 		*dataout++ = cr;
3725 		*dataout++ = cg;
3726 		*dataout++ = cb;
3727 		if (c)
3728 		    *dataout++ = 255;
3729 		else
3730 		    *dataout++ = 0;
3731 	    }
3732 	}
3733     }
3734     else
3735     {
3736 	memset(data, 0, w * h * 4);
3737     }
3738 
3739     if (overlay != SPRITE_INVALID)
3740     {
3741 	row = overlay / 24;
3742 	col = overlay - row*24;
3743 
3744 	dataout = data;
3745 
3746 	for (y = 0; y < h; y++)
3747 	{
3748 	    for (x = 0; x < w; x++)
3749 	    {
3750 		srcidx = col * w + row * w * h * 24;
3751 		srcidx += y * w * 24;
3752 		srcidx += x;
3753 
3754 		c = bmp_sprite16_3x[srcidx];
3755 		if (!c)
3756 		{
3757 		    dataout += 4;
3758 		}
3759 		else
3760 		{
3761 		    int		cb, cg, cr;
3762 
3763 		    cb = (c >> 10) << 3;
3764 		    cg = ((c >> 5) & 31) << 3;
3765 		    cr = (c & 31) << 3;
3766 
3767 		    *dataout++ = cr;
3768 		    *dataout++ = cg;
3769 		    *dataout++ = cb;
3770 		    *dataout++ = 255;
3771 		}
3772 	    }
3773 	}
3774     }
3775 
3776     return data;
3777 #else
3778     return 0;
3779 #endif
3780 }
3781 
3782 void
gfx_compositetile(ITEMSLOT_NAMES dstslot,MINI_NAMES minitile,bool ismale)3783 gfx_compositetile(ITEMSLOT_NAMES dstslot, MINI_NAMES minitile, bool ismale)
3784 {
3785     const u8		*minidata;
3786     int			 x, y, sx, sy;
3787     int			 dstidx, srcidx;
3788 
3789     // The use of the suffix "f" to denote the female tileset is
3790     // derogratory: it implies all humans are male until they are explicitly
3791     // labeled FEmale.  To atone for this, the parameter to determine gender
3792     // has the opposite sense: ismale implies it is the men that must be
3793     // explicitly specified.
3794     if (ismale)
3795 	minidata = &glb_tilesets[glb_tileset].mini[minitile * 4 * BYTEPERTILE];
3796     else
3797 	minidata = &glb_tilesets[glb_tileset].minif[minitile * 4 * BYTEPERTILE];
3798 
3799     // Determine our offset.
3800     int			 offx, offy;
3801     bool		 flipx, flipy;
3802     offx = glb_itemslotdefs[glb_minidefs[minitile].slot].posx;
3803     offx -= glb_itemslotdefs[dstslot].posx;
3804     offy = glb_itemslotdefs[glb_minidefs[minitile].slot].posy;
3805     offy -= glb_itemslotdefs[dstslot].posy;
3806 
3807     // Convert our offset into our new tilespace...
3808     if (TILEWIDTH != 8)
3809     {
3810 	offx = (int) ((offx / 8.0) * TILEWIDTH + 0.5);
3811     }
3812     if (TILEHEIGHT != 8)
3813     {
3814 	offy = (int) ((offy / 8.0) * TILEHEIGHT + 0.5);
3815     }
3816 
3817     flipx = glb_itemslotdefs[glb_minidefs[minitile].slot].flipx ^
3818 	    glb_itemslotdefs[dstslot].flipx;
3819     flipy = glb_itemslotdefs[glb_minidefs[minitile].slot].flipy ^
3820 	    glb_itemslotdefs[dstslot].flipy;
3821 
3822     for (y = 0; y < TILEHEIGHT*2; y++)
3823     {
3824 	for (x = 0; x < TILEWIDTH*2; x++)
3825 	{
3826 	    if (flipx)
3827 		sx = TILEWIDTH*2-1 - x;
3828 	    else
3829 		sx = x;
3830 	    if (flipy)
3831 		sy = TILEHEIGHT*2-1 - y;
3832 	    else
3833 		sy = y;
3834 	    sx += offx;
3835 	    sy += offy;
3836 	    if (sx < 0 || sx >= TILEWIDTH*2)
3837 		continue;
3838 	    if (sy < 0 || sy >= TILEHEIGHT*2)
3839 		continue;
3840 
3841 	    // Get position inside sub tile.
3842 	    dstidx = 0;
3843 	    dstidx += y * TILEWIDTH;
3844 	    dstidx += x;
3845 	    // Find actual sub tile.
3846 	    if (x >= TILEWIDTH)
3847 		dstidx += BYTEPERTILE - TILEWIDTH;
3848 	    if (y >= TILEHEIGHT)
3849 		dstidx += BYTEPERTILE*2 - BYTEPERTILE;
3850 
3851 	    srcidx = 0;
3852 	    srcidx += sy * TILEWIDTH;
3853 	    srcidx += sx;
3854 	    if (sx >= TILEWIDTH)
3855 		srcidx += BYTEPERTILE - TILEWIDTH;
3856 	    if (sy >= TILEHEIGHT)
3857 		srcidx += BYTEPERTILE*2 - BYTEPERTILE;
3858 
3859 	    // Actual comp:
3860 	    if (minidata[srcidx])
3861 		glb_comptiledata[dstidx] = minidata[srcidx];
3862 	}
3863     }
3864 
3865     ham_ReloadTileGfx(glb_bg1tiles, (u16 *) glb_comptiledata,
3866 		      glb_lastdesttile, 4);
3867 }
3868 
3869 int
gfx_getfont()3870 gfx_getfont()
3871 {
3872     return glb_currentfont;
3873 }
3874 
3875 void
gfx_switchfonts(int newfont)3876 gfx_switchfonts(int newfont)
3877 {
3878     if (newfont == glb_currentfont)
3879 	return;
3880 
3881     glb_currentfont = newfont;
3882 
3883     // Do nothing in mode 3 or -1.
3884     if (glb_gfxmode)
3885 	return;
3886 
3887     // Reload all locked font tiles..
3888     int		c;
3889     int		sourceidx;
3890     int		idx;
3891 
3892     // Active alphabet tiles:
3893     for (c = 0; c < 255; c++)
3894     {
3895 	idx = glb_charidx[c];
3896 	if (idx != INVALID_TILEIDX)
3897 	{
3898 	    sourceidx = gfx_getchartile(c);
3899 
3900 	    ham_ReloadTileGfx(glb_bg1tiles,
3901 		(u16*)(&glb_tilesets[glb_tileset].alphabet[glb_currentfont][sourceidx * BYTEPERTILE]),
3902 		idx,
3903 		1);
3904 	}
3905     }
3906 }
3907 
3908 void
gfx_switchtilesets(int newtileset)3909 gfx_switchtilesets(int newtileset)
3910 {
3911     int			i;
3912 
3913     if (newtileset == glb_tileset)
3914 	return;
3915 
3916     glb_tileset = newtileset;
3917 #ifdef USE_VIRTUAL_SCREEN
3918     glb_modetilesets[glb_tilesetmode] = newtileset;
3919 #endif
3920 
3921     // TODO: Guard if sizes match,
3922     hamfake_setTileSize(glb_tilesets[glb_tileset].tilewidth,
3923 			glb_tilesets[glb_tileset].tilewidth);
3924 
3925     // Rebuild our arrays:
3926     delete [] glb_bg2tiledata;
3927     glb_bg2tiledata = (char *) new u16[WORDPERTILE*TILESTASH];
3928     memset(glb_bg2tiledata, 0, BYTEPERTILE*TILESTASH);
3929 
3930     delete [] glb_comptiledata;
3931     glb_comptiledata = (u8 *) (new u16[WORDPERTILE*4]);
3932 
3933     for (i = 0; i < MAX_COLOUR_CHAR; i++)
3934     {
3935 	if (glb_colourchardata[i])
3936 	{
3937 	    delete [] glb_colourchardata[i];
3938 	    glb_colourchardata[i] = (u8 *) new u16[WORDPERTILE];
3939 	}
3940     }
3941 
3942     delete [] glb_greyscaletiledata;
3943     glb_greyscaletiledata = (u8 *) (new u16[WORDPERTILE*4]);
3944 
3945     // If we are in mode 3, reblit our background!
3946     if (glb_gfxmode == 3)
3947     {
3948 	gfx_reblitslugandblood();
3949 	for (int y = 0; y < 20; y++)
3950 	{
3951 	    for (int x = 0; x < 32; x++)
3952 	    {
3953 		if (glb_charmap[y*32+x] != 0xff)
3954 		    gfx_printcharraw(x*TILEWIDTH, y*TILEHEIGHT, glb_charmap[y*32+x]);
3955 	    }
3956 	}
3957     }
3958 
3959     // Do nothing in mode 3 or -1.
3960     if (glb_gfxmode)
3961 	return;
3962 
3963     // Swap palette:
3964     ham_LoadBGPal((void *)glb_tilesets[glb_tileset].palette, 512);
3965     hamfake_LoadSpritePal((void *)glb_tilesets[glb_tileset].spritepalette, 512);
3966 
3967     // Rebuild our standard colours
3968     gfx_buildstdcolors();
3969 
3970     // Reload the sprite.
3971     hamfake_ReloadSpriteGfx((u16*)(&glb_tilesets[glb_tileset].dungeon[glb_sprite*4*BYTEPERTILE]),
3972 		    0, 4);
3973 
3974     // Reload all locked tiles..
3975     int		c;
3976     int		sourceidx;
3977     int		idx;
3978 
3979     // Active alphabet tiles:
3980     for (c = 0; c < 255; c++)
3981     {
3982 	idx = glb_charidx[c];
3983 	if (idx != INVALID_TILEIDX)
3984 	{
3985 	    sourceidx = gfx_getchartile(c);
3986 
3987 	    ham_ReloadTileGfx(glb_bg1tiles,
3988 		(u16*)(&glb_tilesets[glb_tileset].alphabet[glb_currentfont][sourceidx * BYTEPERTILE]),
3989 		idx,
3990 		1);
3991 	}
3992     }
3993 
3994     // Active dungeon tiles:
3995     int		tile;
3996 
3997     for (tile = 0; tile < NUM_TILES; tile++)
3998     {
3999 	idx = glb_tileidx[tile];
4000 
4001 	if (idx == INVALID_TILEIDX)
4002 	    continue;
4003 
4004 	ham_ReloadTileGfx(glb_bg1tiles,
4005 		(u16*)(&glb_tilesets[glb_tileset].dungeon[tile * 4 * BYTEPERTILE]),
4006 		idx,
4007 		4);
4008     }
4009 
4010     // Rebuild custom dude.
4011     if (MOB::getAvatar())
4012 	MOB::getAvatar()->rebuildAppearance();
4013 
4014     // Reset our center as we may have switched to a different sized
4015     // tile and the lower layer stores the offset in pixels
4016     int		tx, ty;
4017     gfx_getscrollcenter(tx, ty);
4018     gfx_scrollcenter(tx, ty);
4019 }
4020 
4021 int
gfx_gettileset()4022 gfx_gettileset()
4023 {
4024     return glb_tileset;
4025 }
4026 
4027 int
gfx_gettilesetmode(int mode)4028 gfx_gettilesetmode(int mode)
4029 {
4030 #ifdef USE_VIRTUAL_SCREEN
4031     return glb_modetilesets[mode];
4032 #else
4033     return glb_tileset;
4034 #endif
4035 }
4036 
4037 void
gfx_tilesetmode(int mode)4038 gfx_tilesetmode(int mode)
4039 {
4040 #ifdef USE_VIRTUAL_SCREEN
4041     if (mode == glb_tilesetmode)
4042 	return;
4043 
4044     glb_tilesetmode = mode;
4045     gfx_switchtilesets(glb_modetilesets[glb_tilesetmode]);
4046 #endif
4047 }
4048 
4049 void
gfx_settilesetmode(int mode,int tileset)4050 gfx_settilesetmode(int mode, int tileset)
4051 {
4052 #ifdef USE_VIRTUAL_SCREEN
4053     glb_modetilesets[mode] = tileset;
4054     if (mode == glb_tilesetmode)
4055 	gfx_switchtilesets(tileset);
4056 #else
4057     if (!mode)
4058 	gfx_switchtilesets(tileset);
4059 #endif
4060 }
4061 
4062 int
gfx_gettilewidth()4063 gfx_gettilewidth()
4064 {
4065     return TILEWIDTH;
4066 }
4067 
4068 int
gfx_gettileheight()4069 gfx_gettileheight()
4070 {
4071     return TILEHEIGHT;
4072 }
4073 
4074 void
gfx_drawcursor(int x,int y)4075 gfx_drawcursor(int x, int y)
4076 {
4077     hamfake_movesprite(0, x-TILEWIDTH, y-TILEHEIGHT);
4078     hamfake_enablesprite(0, true);
4079 }
4080 
4081 void
gfx_removecursor()4082 gfx_removecursor()
4083 {
4084     hamfake_enablesprite(0, false);
4085 }
4086 
4087 void
gfx_cursortile(SPRITE_NAMES tile)4088 gfx_cursortile(SPRITE_NAMES tile)
4089 {
4090     UT_ASSERT(glb_usesprites);
4091     glb_sprite = (u16) tile;
4092     hamfake_ReloadSpriteGfx((u16*)(&glb_tilesets[glb_tileset].sprite[glb_sprite*4*BYTEPERTILE]),
4093 		    0, 4);
4094 }
4095 
4096 void
gfx_spritetile(int spriteno,SPRITE_NAMES tile)4097 gfx_spritetile(int spriteno, SPRITE_NAMES tile)
4098 {
4099     UT_ASSERT(glb_usesprites);
4100 
4101     hamfake_ReloadSpriteGfx((u16*)(&glb_tilesets[glb_tileset].sprite[tile*4*BYTEPERTILE]),
4102 		    spriteno*4, 4);
4103 }
4104 
4105 
4106 u8
gfx_togreyscale(u8 src,const u16 * palette)4107 gfx_togreyscale(u8 src, const u16 *palette)
4108 {
4109     int		cb, cg, cr;
4110 
4111     cb = (palette[src] >> 10) << 3;
4112     cg = ((palette[src] >> 5) & 31) << 3;
4113     cr = (palette[src] & 31) << 3;
4114 
4115     int grey = rgbtogrey(cr, cg, cb);
4116     return gfx_lookupcolor(grey, grey, grey, palette);
4117 }
4118 
4119 void
gfx_updateGreyTables(u8 * greytable,const u16 * palette)4120 gfx_updateGreyTables(u8 *greytable, const u16 *palette)
4121 {
4122     int		i;
4123 
4124     for (i = 0; i < 256; i++)
4125     {
4126 	greytable[i] = gfx_togreyscale(i, palette);
4127     }
4128 }
4129 
4130 void
gfx_updatespritegreytable()4131 gfx_updatespritegreytable()
4132 {
4133     if (!glb_spritegreyscale)
4134 	return;
4135 
4136     gfx_updateGreyTables(glb_spritegreyscale,
4137 			glb_tilesets[glb_tileset].spritepalette);
4138 }
4139 
4140 const u8 *
gfx_getspritegreytable()4141 gfx_getspritegreytable()
4142 {
4143     if (!glb_spritegreyscale)
4144     {
4145 	glb_spritegreyscale = new u8[256];
4146 	gfx_updatespritegreytable();
4147     }
4148 
4149     return glb_spritegreyscale;
4150 }
4151 
4152 
4153 
4154 void
gfx_spritetile_grey(int spriteno,SPRITE_NAMES tile,int grey,SPRITE_NAMES overlay)4155 gfx_spritetile_grey(int spriteno, SPRITE_NAMES tile, int grey, SPRITE_NAMES overlay)
4156 {
4157     const u8 *greytable;
4158 
4159     if (!glb_greyscaletiledata)
4160     {
4161 	u16		*origdata = new u16 [WORDPERTILE*4];
4162 	glb_greyscaletiledata = (u8 *) origdata;
4163     }
4164 
4165     greytable = gfx_getspritegreytable();
4166 
4167     u8 		*src;
4168     grey = 256 - grey;
4169     int		 cutoff = (grey * TILEHEIGHT * 2 + 128) / 256;
4170     int		 i;
4171     int		 x, y, t, yc;
4172 
4173     src = (u8 *) (&glb_tilesets[glb_tileset].sprite[tile*4*BYTEPERTILE]);
4174 
4175     i = 0;
4176     for (t = 0; t < 4; t++)
4177     {
4178 	if (t < 2)
4179 	    y = 0;
4180 	else
4181 	    y = TILEHEIGHT;
4182 
4183 	for (yc = 0; yc < TILEHEIGHT; yc++)
4184 	{
4185 	    if (y + yc >= cutoff)
4186 	    {
4187 		for (x = 0; x < TILEWIDTH; x++)
4188 		{
4189 		    glb_greyscaletiledata[i] = src[i];
4190 		    i++;
4191 		}
4192 	    }
4193 	    else
4194 	    {
4195 		for (x = 0; x < TILEWIDTH; x++)
4196 		{
4197 		    glb_greyscaletiledata[i] = greytable[src[i]];
4198 		    i++;
4199 		}
4200 	    }
4201 	}
4202     }
4203 
4204     if (overlay != SPRITE_INVALID)
4205     {
4206 	src = (u8 *) (&glb_tilesets[glb_tileset].sprite[overlay*4*BYTEPERTILE]);
4207 	for (i = 0; i < BYTEPERTILE * 4; i++)
4208 	{
4209 	    if (src[i])
4210 		glb_greyscaletiledata[i] = src[i];
4211 	}
4212     }
4213 
4214 
4215     hamfake_ReloadSpriteGfx((u16*)glb_greyscaletiledata,
4216 		    spriteno*4, 4);
4217 }
4218 
4219 void
gfx_spritefromdungeon(int spriteno,TILE_NAMES tile)4220 gfx_spritefromdungeon(int spriteno, TILE_NAMES tile)
4221 {
4222     UT_ASSERT(!glb_usesprites);
4223     hamfake_ReloadSpriteGfx((u16*)(&glb_tilesets[glb_tileset].dungeon[tile*4*BYTEPERTILE]),
4224 		    spriteno*4, 4);
4225 }
4226 
4227 void
gfx_spritemode(bool usesprites)4228 gfx_spritemode(bool usesprites)
4229 {
4230     int		i;
4231     // Disable all sprites
4232     for (i = 0; i < 128; i++)
4233 	hamfake_enablesprite(i, false);
4234 
4235     // Swap palette
4236     if (usesprites)
4237 	hamfake_LoadSpritePal((void *)glb_tilesets[glb_tileset].spritepalette, 512);
4238     else
4239 	hamfake_LoadSpritePal((void *)glb_tilesets[glb_tileset].palette, 512);
4240 
4241     glb_usesprites = usesprites;
4242 }
4243 
4244 //
4245 // Fake Ham Functions
4246 //
4247 #if !defined(USING_SDL) && !defined(USING_DS)
4248 
4249 #if !defined(NO_HAM)
4250 void
hamfake_rebuildScreen()4251 hamfake_rebuildScreen()
4252 {
4253 }
4254 
4255 void
hamfake_awaitEvent()4256 hamfake_awaitEvent()
4257 {
4258 }
4259 
4260 u16 *
hamfake_lockScreen()4261 hamfake_lockScreen()
4262 {
4263     return ((u16 *) 0x06000000);
4264 }
4265 
4266 void
hamfake_unlockScreen(u16 *)4267 hamfake_unlockScreen(u16 *)
4268 {
4269 }
4270 
4271 int
hamfake_peekKeyPress()4272 hamfake_peekKeyPress()
4273 {
4274     return 0;
4275 }
4276 
4277 int
hamfake_getKeyPress(bool)4278 hamfake_getKeyPress(bool)
4279 {
4280     return 0;
4281 }
4282 
4283 void
hamfake_clearKeyboardBuffer()4284 hamfake_clearKeyboardBuffer()
4285 {
4286 }
4287 
4288 void
hamfake_insertKeyPress(u8 key)4289 hamfake_insertKeyPress(u8 key)
4290 {
4291 }
4292 
4293 void
hamfake_softReset()4294 hamfake_softReset()
4295 {
4296     return;
4297 }
4298 
4299 #endif
4300 
4301 int
hamfake_getKeyModifiers()4302 hamfake_getKeyModifiers()
4303 {
4304     return 0;
4305 }
4306 
4307 void
hamfake_setFullScreen(bool fullscreen)4308 hamfake_setFullScreen(bool fullscreen)
4309 {
4310 }
4311 
4312 bool
hamfake_isFullScreen()4313 hamfake_isFullScreen()
4314 {
4315     return true;		// Always full :>
4316 }
4317 
4318 bool
hamfake_extratileset()4319 hamfake_extratileset()
4320 {
4321     return false;		// No fat system yet!
4322 }
4323 
4324 void
hamfake_getstyluspos(int & x,int & y)4325 hamfake_getstyluspos(int &x, int &y)
4326 {
4327     x = y = 0;
4328 }
4329 
4330 bool
hamfake_getstylusstate()4331 hamfake_getstylusstate()
4332 {
4333     return false;
4334 }
4335 
4336 void
hamfake_movesprite(int spriteno,int x,int y)4337 hamfake_movesprite(int spriteno, int x, int y)
4338 {
4339 }
4340 
4341 void
hamfake_enablesprite(int spriteno,bool enabled)4342 hamfake_enablesprite(int spriteno, bool enabled)
4343 {
4344 }
4345 
4346 void
hamfake_ReloadSpriteGfx(const u16 * data,int tileno,int numtile)4347 hamfake_ReloadSpriteGfx(const u16 *data, int tileno, int numtile)
4348 {
4349 }
4350 
4351 void
hamfake_LoadSpritePal(void * data,int bytes)4352 hamfake_LoadSpritePal(void *data, int bytes)
4353 {
4354 }
4355 
4356 void
hamfake_setTileSize(int width,int height)4357 hamfake_setTileSize(int width, int height)
4358 {
4359 }
4360 
4361 #endif
4362 
4363 #if !defined(USE_VIRTUAL_SCREEN)
4364 
hamfake_forceQuit()4365 bool hamfake_forceQuit() { return false; }
hamfake_awaitShutdown()4366 void hamfake_awaitShutdown() {}
hamfake_postShutdown()4367 void hamfake_postShutdown() {}
4368 
hamfake_setinventorymode(bool invmode)4369 void hamfake_setinventorymode(bool invmode) {}
hamfake_enableexternalactions(bool enable)4370 void hamfake_enableexternalactions(bool enable) {}
hamfake_isunlocked()4371 bool hamfake_isunlocked() { return true; }
hamfake_externalaction(int & iact,int & ispell)4372 void hamfake_externalaction(int &iact, int &ispell)
4373 { iact = ACTION_NONE; ispell = SPELL_NONE; }
4374 
hamfake_flushdir()4375 void hamfake_flushdir() {}
hamfake_externaldir(int & dx,int & dy)4376 bool hamfake_externaldir(int &dx, int &dy) { return false; }
4377 
hamfake_buttonreq(int mode,int type)4378 void hamfake_buttonreq(int mode, int type) { }
4379 #endif
4380 
4381