1 /*************************************************************************
2
3 Atari Tunnel Hunt hardware
4
5 *************************************************************************/
6
7 #include "driver.h"
8 #include "vidhrdw/generic.h"
9
10 extern UINT8 tunhunt_control;
11
12 /****************************************************************************************/
13
14 /* Video Hardware Addresses */
15
16 /* Square Generator (13 bytes each) */
17 #define LINEV 0x1403 // LINES VERTICAL START
18 #define LINEVS 0x1483 // LINES VERT STOP
19 #define LINEH 0x1083 // LINES HORIZ START
20 #define LINEC 0x1283 // LINE COLOR, 4 BITS D0-D3
21 #define LINESH 0x1203 // LINES SLOPE 4 BITS D0-D3 (signed)
22 /* LINESH was used for rotation effects in an older version of the game */
23
24 /* Shell Object0 */
25 #define SHEL0H 0x1800 // SHELL H POSITON (NORMAL SCREEN)
26 #define SHL0V 0x1400 // SHELL V START(NORMAL SCREEN)
27 #define SHL0VS 0x1480 // SHELL V STOP (NORMAL SCREEN)
28 #define SHL0ST 0x1200 // SHELL VSTRETCH (LIKE MST OBJ STRECTH)
29 #define SHL0PC 0x1280 // SHELL PICTURE CODE (D3-D0)
30
31 /* Shell Object1 (see above) */
32 #define SHEL1H 0x1A00
33 #define SHL1V 0x1401
34 #define SHL1VS 0x1481
35 #define SHL1ST 0x1201
36 #define SHL1PC 0x1281
37
38 /* Motion Object RAM */
39 #define MOBJV 0x1C00 // V POSITION (SCREEN ON SIDE)
40 #define MOBVS 0x1482 // V STOP OF MOTION OBJECT (NORMAL SCREEN)
41 #define MOBJH 0x1402 // H POSITON (SCREEN ON SIDE) (VSTART - NORMAL SCREEN)
42 #define MOBST 0x1082 // STARTING LINE FOR RAM SCAN ON MOBJ
43 #define VSTRLO 0x1202 // VERT (SCREEN ON SIDE) STRETCH MOJ OBJ
44 #define MOTT 0x2C00 // MOTION OBJECT RAM (00-0F NOT USED, BYT CLEARED)
45 #define MOBSC0 0x1080 // SCAN ROM START FOR MOBJ (unused?)
46 #define MOBSC1 0x1081 // (unused?)
47
48 static struct tilemap *fg_tilemap;
49
50 /****************************************************************************************/
51
WRITE_HANDLER(tunhunt_videoram_w)52 WRITE_HANDLER( tunhunt_videoram_w )
53 {
54 if (videoram[offset] != data)
55 {
56 videoram[offset] = data;
57 tilemap_mark_tile_dirty(fg_tilemap, offset);
58 }
59 }
60
WRITE_HANDLER(tunhunt_mott_w)61 WRITE_HANDLER( tunhunt_mott_w )
62 {
63 if( spriteram[offset]!=data )
64 {
65 spriteram[offset] = data;
66 dirtybuffer[offset>>4] = 1;
67 }
68 }
69
get_fg_tile_info(int tile_index)70 static void get_fg_tile_info(int tile_index)
71 {
72 int attr = videoram[tile_index];
73 int code = attr & 0x3f;
74 int color = attr >> 6;
75 int flags = color ? TILE_IGNORE_TRANSPARENCY : 0;
76
77 SET_TILE_INFO(0, code, color, flags)
78 }
79
VIDEO_START(tunhunt)80 VIDEO_START( tunhunt )
81 {
82 /*
83 Motion Object RAM contains 64 lines of run-length encoded data.
84 We keep track of dirty lines and cache the expanded bitmap.
85 With max RLE expansion, bitmap size is 256x64.
86 */
87 dirtybuffer = auto_malloc(64);
88 if (!dirtybuffer)
89 return 1;
90
91 memset( dirtybuffer, 1, 64 );
92 tmpbitmap = auto_bitmap_alloc( 256, 64 );
93 if (!tmpbitmap)
94 return 1;
95
96 fg_tilemap = tilemap_create(get_fg_tile_info, tilemap_scan_cols,
97 TILEMAP_TRANSPARENT, 8, 8, 32, 32);
98
99 if ( !fg_tilemap )
100 return 1;
101
102 tilemap_set_transparent_pen(fg_tilemap, 0);
103 tilemap_set_scrollx(fg_tilemap, 0, 64);
104
105 return 0;
106 }
107
PALETTE_INIT(tunhunt)108 PALETTE_INIT( tunhunt )
109 {
110 /* Tunnel Hunt uses a combination of color proms and palette RAM to specify a 16 color
111 * palette. Here, we manage only the mappings for alphanumeric characters and SHELL
112 * graphics, which are unpacked ahead of time and drawn using MAME's drawgfx primitives.
113 */
114
115 /* AlphaNumerics (1bpp)
116 * 2 bits of hilite select from 4 different background colors
117 * Foreground color is always pen#4
118 * Background color is mapped as follows:
119 */
120
121 /* alpha hilite#0 */
122 colortable[0] = 0x0; /* background color#0 (transparent) */
123 colortable[1] = 0x4; /* foreground color */
124
125 /* alpha hilite#1 */
126 colortable[2] = 0x5; /* background color#1 */
127 colortable[3] = 0x4; /* foreground color */
128
129 /* alpha hilite#2 */
130 colortable[4] = 0x6; /* background color#2 */
131 colortable[5] = 0x4; /* foreground color */
132
133 /* alpha hilite#3 */
134 colortable[6] = 0xf; /* background color#3 */
135 colortable[7] = 0x4; /* foreground color */
136
137 /* shell graphics; these are either 1bpp (2 banks) or 2bpp. It isn't clear which.
138 * In any event, the following pens are associated with the shell graphics:
139 */
140 colortable[0x8] = 0;
141 colortable[0x9] = 4;//1;
142 colortable[0xa] = 2;
143 colortable[0xb] = 4;
144 }
145
146 /*
147 Color Array Ram Assignments:
148 Location
149 0 Blanking, border
150 1 Mot Obj (10) (D), Shell (01)
151 2 Mot Obj (01) (G), Shell (10)
152 3 Mot Obj (00) (W)
153 4 Alpha & Shell (11) - shields
154 5 Hilight 1
155 6 Hilight 2
156 8-E Lines (as normal) background
157 F Hilight 3
158 */
update_palette(void)159 static void update_palette( void )
160 {
161 // const unsigned char *color_prom = memory_region( REGION_PROMS );
162 /*
163 The actual contents of the color proms (unused by this driver)
164 are as follows:
165
166 D11 "blue/green"
167 0000: 00 00 8b 0b fb 0f ff 0b
168 00 00 0f 0f fb f0 f0 ff
169
170 C11 "red"
171 0020: 00 f0 f0 f0 b0 b0 00 f0
172 00 f0 f0 00 b0 00 f0 f0
173 */
174 int color;
175 int shade;
176 int i;
177 int red,green,blue;
178
179 for( i=0; i<16; i++ )
180 {
181 color = paletteram[i];
182 shade = 0xf^(color>>4);
183
184 color &= 0xf; /* hue select */
185 switch( color )
186 {
187 default:
188 case 0x0: red = 0xff; green = 0xff; blue = 0xff; break; /* white */
189 case 0x1: red = 0xff; green = 0x00; blue = 0xff; break; /* purple */
190 case 0x2: red = 0x00; green = 0x00; blue = 0xff; break; /* blue */
191 case 0x3: red = 0x00; green = 0xff; blue = 0xff; break; /* cyan */
192 case 0x4: red = 0x00; green = 0xff; blue = 0x00; break; /* green */
193 case 0x5: red = 0xff; green = 0xff; blue = 0x00; break; /* yellow */
194 case 0x6: red = 0xff; green = 0x00; blue = 0x00; break; /* red */
195 case 0x7: red = 0x00; green = 0x00; blue = 0x00; break; /* black? */
196
197 case 0x8: red = 0xff; green = 0x7f; blue = 0x00; break; /* orange */
198 case 0x9: red = 0x7f; green = 0xff; blue = 0x00; break; /* ? */
199 case 0xa: red = 0x00; green = 0xff; blue = 0x7f; break; /* ? */
200 case 0xb: red = 0x00; green = 0x7f; blue = 0xff; break; /* ? */
201 case 0xc: red = 0xff; green = 0x00; blue = 0x7f; break; /* ? */
202 case 0xd: red = 0x7f; green = 0x00; blue = 0xff; break; /* ? */
203 case 0xe: red = 0xff; green = 0xaa; blue = 0xaa; break; /* ? */
204 case 0xf: red = 0xaa; green = 0xaa; blue = 0xff; break; /* ? */
205 }
206
207 /* combine color components with shade value (0..0xf) */
208 #define APPLY_SHADE( C,S ) ((C*S)/0xf)
209 red = APPLY_SHADE(red,shade);
210 green = APPLY_SHADE(green,shade);
211 blue = APPLY_SHADE(blue,shade);
212
213 palette_set_color( i,red,green,blue );
214 }
215 }
216
draw_motion_object(struct mame_bitmap * bitmap)217 static void draw_motion_object( struct mame_bitmap *bitmap )
218 {
219 /*
220 * VSTRLO 0x1202
221 * normally 0x02 (gameplay, attract1)
222 * in attract2 (with "Tunnel Hunt" graphic), decrements from 0x2f down to 0x01
223 * goes to 0x01 for some enemy shots
224 *
225 * MOBSC0 0x1080
226 * MOBSC1 0x1081
227 * always 0x00?
228 */
229 const UINT8 *pMem = memory_region( REGION_CPU1 );
230 // int skip = pMem[MOBST];
231 int x0 = 255-pMem[MOBJV];
232 int y0 = 255-pMem[MOBJH];
233 int scalex,scaley;
234 int line,span;
235 int x,span_data;
236 int color;
237 int count,pen;
238 const unsigned char *source;
239 struct rectangle clip = Machine->visible_area;
240
241 for( line=0; line<64; line++ )
242 {
243 if( dirtybuffer[line] )
244 {
245 dirtybuffer[line] = 0;
246 x = 0;
247 source = &spriteram[line*0x10];
248 for( span=0; span<0x10; span++ )
249 {
250 span_data = source[span];
251 if( span_data == 0xff ) break;
252 pen = ((span_data>>6)&0x3)^0x3;
253 color = Machine->pens[pen];
254 count = (span_data&0x1f)+1;
255 while( count-- )
256 {
257 plot_pixel( tmpbitmap, x++,line,color );
258 }
259 }
260 color = Machine->pens[0];
261 while( x<256 )
262 {
263 plot_pixel( tmpbitmap, x++,line,color );
264 }
265 } /* dirty line */
266 } /* next line */
267
268 switch( pMem[VSTRLO] )
269 {
270 case 0x01:
271 scaley = (1<<16)*0.33; /* seems correct */
272 break;
273
274 case 0x02:
275 scaley = (1<<16)*0.50; /* seems correct */
276 break;
277
278 default:
279 scaley = (1<<16)*pMem[VSTRLO]/4; /* ??? */
280 break;
281 }
282 scalex = (1<<16);
283
284 copyrozbitmap(
285 bitmap,tmpbitmap,
286 -x0*scalex,/* startx */
287 -y0*scaley,/* starty */
288 scalex,/* incxx */
289 0,0,/* incxy,incyx */
290 scaley,/* incyy */
291 0, /* no wraparound */
292 &clip,
293 TRANSPARENCY_PEN,Machine->pens[0],
294 0 /* priority */
295 );
296 }
297
draw_box(struct mame_bitmap * bitmap)298 static void draw_box( struct mame_bitmap *bitmap )
299 {
300 /*
301 This is unnecessarily slow, but the box priorities aren't completely understood,
302 yet. Once understood, this function should be converted to use fillbitmap with
303 rectangular chunks instead of plot_pixel.
304
305 Tunnels:
306 1080: 00 00 00 01 e7 18 ae 51 94 6b 88 77 83 7c 80 7f x0
307 1480: 00 f0 17 00 22 22 5b 5b 75 75 81 81 86 86 89 89 y0
308 1400: 00 00 97 ff f1 f1 b8 b8 9e 9e 92 92 8d 8d 8a 8a y1
309 1280: 07 03 00 07 07 0c 0c 0d 0d 0e 0e 08 08 09 09 0a palette select
310
311 Color Bars:
312 1080: 00 00 00 01 00 20 40 60 80 a0 c0 e0 01 2a 50 7a x0
313 1480: 00 f0 00 00 40 40 40 40 40 40 40 40 00 00 00 00 y0
314 1400: 00 00 00 ff ff ff ff ff ff ff ff ff 40 40 40 40 y1
315 1280: 07 03 00 01 07 06 04 05 02 07 03 00 09 0a 0b 0c palette select
316 ->hue 06 02 ff 60 06 05 03 04 01 06 02 ff d2 00 c2 ff
317 */
318 int span,x,y;
319 UINT8 *pMem;
320 int color;
321 int pen;
322 // struct rectangle bbox;
323 int z;
324 int x0,y0,y1;
325 pMem = memory_region( REGION_CPU1 );
326
327 for( y=0; y<256; y++ )
328 {
329 for( x=0; x<256; x++ )
330 {
331 pen = 0;
332 z = 0;
333 for( span=3; span<16; span++ )
334 {
335 x0 = pMem[span+0x1080];
336 y0 = pMem[span+0x1480];
337 y1 = pMem[span+0x1400];
338
339 if( y>=y0 && y<=y1 && x>=x0 && x0>=z )
340 {
341 pen = pMem[span+0x1280]&0xf;
342 z = x0; /* give priority to rightmost spans */
343 }
344 }
345 color = Machine->pens[pen];
346 plot_pixel( bitmap, x, 0xff-y, color );
347 }
348 }
349 return;
350 }
351
352 /* "shell" graphics are 16x16 pixel tiles used for player shots and targeting cursor */
draw_shell(struct mame_bitmap * bitmap,int picture_code,int hposition,int vstart,int vstop,int vstretch,int hstretch)353 static void draw_shell(
354 struct mame_bitmap *bitmap,
355 int picture_code,
356 int hposition,
357 int vstart,
358 int vstop,
359 int vstretch,
360 int hstretch )
361 {
362 if( hstretch )
363 {
364 int sx,sy;
365 for( sx=0; sx<256; sx+=16 )
366 {
367 for( sy=0; sy<256; sy+=16 )
368 {
369 drawgfx( bitmap, Machine->gfx[1],
370 picture_code,
371 0, /* color */
372 0,0, /* flip */
373 sx,sy,
374 &Machine->visible_area,
375 TRANSPARENCY_PEN,0 );
376 }
377 }
378 }
379 else
380 /*
381 vstretch is normally 0x01
382
383 targeting cursor:
384 hposition = 0x78
385 vstart = 0x90
386 vstop = 0x80
387
388 during grid test:
389 vstretch = 0xff
390 hposition = 0xff
391 vstart = 0xff
392 vstop = 0x00
393
394 */
395 drawgfx( bitmap, Machine->gfx[1],
396 picture_code,
397 0, /* color */
398 0,0, /* flip */
399 255-hposition-16,vstart-32,
400 &Machine->visible_area,
401 TRANSPARENCY_PEN,0 );
402 }
403
VIDEO_UPDATE(tunhunt)404 VIDEO_UPDATE( tunhunt )
405 {
406 const UINT8 *pMem = memory_region( REGION_CPU1 );
407
408 update_palette();
409
410 draw_box( bitmap );
411
412 draw_motion_object( bitmap );
413
414 draw_shell( bitmap,
415 pMem[SHL0PC], /* picture code */
416 pMem[SHEL0H], /* hposition */
417 pMem[SHL0V], /* vstart */
418 pMem[SHL0VS], /* vstop */
419 pMem[SHL0ST], /* vstretch */
420 tunhunt_control&0x08 ); /* hstretch */
421
422 draw_shell( bitmap,
423 pMem[SHL1PC], /* picture code */
424 pMem[SHEL1H], /* hposition */
425 pMem[SHL1V], /* vstart */
426 pMem[SHL1VS], /* vstop */
427 pMem[SHL1ST], /* vstretch */
428 tunhunt_control&0x10 ); /* hstretch */
429
430 tilemap_draw(bitmap, cliprect, fg_tilemap, 0, 0);
431 }
432