1 #include "driver.h"
2 #include "state.h"
3 #include "vidhrdw/generic.h"
4 #include "vidhrdw/taitoic.h"
5 
6 #define TC0100SCN_GFX_NUM 1
7 
8 data16_t *othunder_ram;
9 
10 struct tempsprite
11 {
12 	int gfx;
13 	int code,color;
14 	int flipx,flipy;
15 	int x,y;
16 	int zoomx,zoomy;
17 	int primask;
18 };
19 static struct tempsprite *spritelist;
20 
21 static int taito_hide_pixels;
22 
23 
24 
25 /**********************************************************/
26 
VIDEO_START(othunder_core)27 static VIDEO_START( othunder_core )
28 {
29 	/* Up to $800/8 big sprites, requires 0x100 * sizeof(*spritelist)
30 	   Multiply this by 32 to give room for the number of small sprites,
31 	   which are what actually get put in the structure. */
32 
33 	spritelist = auto_malloc(0x2000 * sizeof(*spritelist));
34 	if (!spritelist)
35 		return 1;
36 
37 	if (TC0100SCN_vh_start(1,TC0100SCN_GFX_NUM,taito_hide_pixels,0,0,0,0,0,0))
38 		return 1;
39 
40 	if (has_TC0110PCR())
41 		if (TC0110PCR_vh_start())
42 			return 1;
43 
44 	return 0;
45 }
46 
VIDEO_START(othunder)47 VIDEO_START( othunder )
48 {
49 	/* There is a problem here. 4 is correct for text layer/sprite
50 	   alignment, but the bg layers [or one of them] are wrong */
51 
52 	taito_hide_pixels = 4;
53 	return video_start_othunder_core();
54 }
55 
56 
57 /************************************************************
58 			SPRITE DRAW ROUTINE
59 
60 It draws a series of small tiles ("chunks") together to
61 create a big sprite. The spritemap rom provides the lookup
62 table for this. We look up the 16x8 sprite chunks from
63 the spritemap rom, creating each 64x64 sprite as follows:
64 
65 	 0  1  2  3
66 	 4  5  6  7
67 	 8  9 10 11
68 	12 13 14 15
69 	16 17 18 19
70 	20 21 22 23
71 	24 25 26 27
72 	28 29 30 31
73 
74 The game makes heavy use of sprite zooming.
75 
76 		***
77 
78 NB: unused portions of the spritemap rom contain hex FF's.
79 It is a useful coding check to warn in the log if these
80 are being accessed. [They can be inadvertently while
81 spriteram is being tested, take no notice of that.]
82 
83 
84 		Othunder (modified table from Raine)
85 
86 		Byte | Bit(s) | Description
87 		-----+76543210+-------------------------------------
88 		  0  |xxxxxxx.| ZoomY (0 min, 63 max - msb unused as sprites are 64x64)
89 		  0  |.......x| Y position (High)
90 		  1  |xxxxxxxx| Y position (Low)
91 		  2  |x.......| Sprite/BG Priority (0=sprites high)
92 		  2  |.x......| Flip X
93 		  2  |..?????.| unknown/unused ?
94 		  2  |.......x| X position (High)
95 		  3  |xxxxxxxx| X position (Low)
96 		  4  |xxxxxxxx| Palette bank
97 		  5  |?.......| unknown/unused ?
98 		  5  |.xxxxxxx| ZoomX (0 min, 63 max - msb unused as sprites are 64x64)
99 		  6  |x.......| Flip Y
100 		  6  |.??.....| unknown/unused ?
101 		  6  |...xxxxx| Sprite Tile high (2 msbs unused - 3/4 of spritemap rom empty)
102 		  7  |xxxxxxxx| Sprite Tile low
103 
104 ********************************************************/
105 
106 
othunder_draw_sprites_16x8(struct mame_bitmap * bitmap,const struct rectangle * cliprect,int * primasks,int y_offs)107 static void othunder_draw_sprites_16x8(struct mame_bitmap *bitmap,const struct rectangle *cliprect,int *primasks,int y_offs)
108 {
109 	data16_t *spritemap = (data16_t *)memory_region(REGION_USER1);
110 	UINT16 tile_mask = (Machine->gfx[0]->total_elements) - 1;
111 	int offs, data, tilenum, color, flipx, flipy;
112 	int x, y, priority, curx, cury;
113 	int sprites_flipscreen = 0;
114 	int zoomx, zoomy, zx, zy;
115 	int sprite_chunk,map_offset,code,j,k,px,py;
116 	int bad_chunks;
117 
118 	/* pdrawgfx() needs us to draw sprites front to back, so we have to build a list
119 	   while processing sprite ram and then draw them all at the end */
120 	struct tempsprite *sprite_ptr = spritelist;
121 
122 	for (offs = (spriteram_size/2)-4;offs >=0;offs -= 4)
123 	{
124 		data = spriteram16[offs+0];
125 		zoomy = (data & 0xfe00) >> 9;
126 		y = data & 0x1ff;
127 
128 		data = spriteram16[offs+1];
129 		flipx = (data & 0x4000) >> 14;
130 		priority = (data & 0x8000) >> 15;
131 		x = data & 0x1ff;
132 
133 		data = spriteram16[offs+2];
134 		color = (data & 0xff00) >> 8;
135 		zoomx = (data & 0x7f);
136 
137 		data = spriteram16[offs+3];
138 		tilenum = data & 0x1fff;	// $80000 spritemap rom maps up to $2000 64x64 sprites
139 		flipy = (data & 0x8000) >> 15;
140 
141 		if (!tilenum) continue;
142 
143 		map_offset = tilenum << 5;
144 
145 		zoomx += 1;
146 		zoomy += 1;
147 
148 		y += y_offs;
149 
150 		/* treat coords as signed */
151 		if (x>0x140) x -= 0x200;
152 		if (y>0x140) y -= 0x200;
153 
154 		bad_chunks = 0;
155 
156 		for (sprite_chunk=0;sprite_chunk<32;sprite_chunk++)
157 		{
158 			k = sprite_chunk % 4;   /* 4 chunks per row */
159 			j = sprite_chunk / 4;   /* 8 rows */
160 
161 			px = k;
162 			py = j;
163 			if (flipx)  px = 3-k;	/* pick tiles back to front for x and y flips */
164 			if (flipy)  py = 7-j;
165 
166 			code = spritemap[map_offset + px + (py<<2)] &tile_mask;
167 
168 			if (code==0xffff)
169 			{
170 				bad_chunks += 1;
171 				continue;
172 			}
173 
174 			curx = x + ((k*zoomx)/4);
175 			cury = y + ((j*zoomy)/8);
176 
177 			zx= x + (((k+1)*zoomx)/4) - curx;
178 			zy= y + (((j+1)*zoomy)/8) - cury;
179 
180 			if (sprites_flipscreen)
181 			{
182 				/* -zx/y is there to fix zoomed sprite coords in screenflip.
183 				   drawgfxzoom does not know to draw from flip-side of sprites when
184 				   screen is flipped; so we must correct the coords ourselves. */
185 
186 				curx = 320 - curx - zx;
187 				cury = 256 - cury - zy;
188 				flipx = !flipx;
189 				flipy = !flipy;
190 			}
191 
192 			sprite_ptr->code = code;
193 			sprite_ptr->color = color;
194 			sprite_ptr->flipx = flipx;
195 			sprite_ptr->flipy = flipy;
196 			sprite_ptr->x = curx;
197 			sprite_ptr->y = cury;
198 			sprite_ptr->zoomx = zx << 12;
199 			sprite_ptr->zoomy = zy << 13;
200 
201 			if (primasks)
202 			{
203 				sprite_ptr->primask = primasks[priority];
204 				sprite_ptr++;
205 			}
206 			else
207 			{
208 				drawgfxzoom(bitmap,Machine->gfx[0],
209 						sprite_ptr->code,
210 						sprite_ptr->color,
211 						sprite_ptr->flipx,sprite_ptr->flipy,
212 						sprite_ptr->x,sprite_ptr->y,
213 						cliprect,TRANSPARENCY_PEN,0,
214 						sprite_ptr->zoomx,sprite_ptr->zoomy);
215 			}
216 		}
217 
218 		if (bad_chunks)
219 logerror("Sprite number %04x had %02x invalid chunks\n",tilenum,bad_chunks);
220 	}
221 
222 	/* this happens only if primsks != NULL */
223 	while (sprite_ptr != spritelist)
224 	{
225 		sprite_ptr--;
226 
227 		pdrawgfxzoom(bitmap,Machine->gfx[0],
228 				sprite_ptr->code,
229 				sprite_ptr->color,
230 				sprite_ptr->flipx,sprite_ptr->flipy,
231 				sprite_ptr->x,sprite_ptr->y,
232 				cliprect,TRANSPARENCY_PEN,0,
233 				sprite_ptr->zoomx,sprite_ptr->zoomy,
234 				sprite_ptr->primask);
235 	}
236 }
237 
238 
239 /**************************************************************
240 				SCREEN REFRESH
241 **************************************************************/
242 
VIDEO_UPDATE(othunder)243 VIDEO_UPDATE( othunder )
244 {
245 	int layer[3];
246 
247 	TC0100SCN_tilemap_update();
248 
249 	layer[0] = TC0100SCN_bottomlayer(0);
250 	layer[1] = layer[0]^1;
251 	layer[2] = 2;
252 
253 	fillbitmap(priority_bitmap,0,cliprect);
254 
255 	/* Ensure screen blanked even when bottom layer not drawn due to disable bit */
256 	fillbitmap(bitmap, Machine->pens[0], cliprect);
257 
258 	TC0100SCN_tilemap_draw(bitmap,cliprect,0,layer[0],TILEMAP_IGNORE_TRANSPARENCY,1);
259 	TC0100SCN_tilemap_draw(bitmap,cliprect,0,layer[1],0,2);
260 	TC0100SCN_tilemap_draw(bitmap,cliprect,0,layer[2],0,4);
261 
262 	/* Sprites can be under/over the layer below text layer */
263 	{
264 		int primasks[2] = {0xf0,0xfc};
265 		othunder_draw_sprites_16x8(bitmap,cliprect,primasks,3);
266 	}
267 
268 	/* Draw artificial gun targets */
269 	{
270 		int rawx, rawy, centrex, centrey, screenx, screeny;
271 
272 		/* calculate p1 screen co-ords by matching routine at $A932 */
273 		rawx = othunder_ram[0x2848/2];
274 		centrex = othunder_ram[0xa046/2];
275 		if (rawx <= centrex)
276 		{
277 			rawx = centrex - rawx;
278 			screenx = rawx * othunder_ram[0xa04e/2] + (((rawx * othunder_ram[0xa050/2]) & 0xffff0000) >> 16);
279 			screenx = 0xa0 - screenx;
280 			if (screenx < 0) screenx = 0;
281 		}
282 		else
283 		{
284 			if (rawx > othunder_ram[0xa028/2]) rawx = othunder_ram[0xa028/2];
285 			rawx -= centrex;
286 			screenx = rawx * othunder_ram[0xa056/2] + (((rawx * othunder_ram[0xa058/2]) & 0xffff0000) >> 16);
287 			screenx += 0xa0;
288 			if (screenx > 0x140) screenx = 0x140;
289 		}
290 		rawy = othunder_ram[0x284a/2];
291 		centrey = othunder_ram[0xa048/2];
292 		if (rawy <= centrey)
293 		{
294 			rawy = centrey - rawy;
295 			screeny = rawy * othunder_ram[0xa052/2] + (((rawy * othunder_ram[0xa054/2]) & 0xffff0000) >> 16);
296 			screeny = 0x78 - screeny;
297 			if (screeny < 0) screeny = 0;
298 		}
299 		else
300 		{
301 			if (rawy > othunder_ram[0xa030/2]) rawy = othunder_ram[0xa030/2];
302 			rawy -= centrey;
303 			screeny = rawy * othunder_ram[0xa05a/2] + (((rawy * othunder_ram[0xa05c/2]) & 0xffff0000) >> 16);
304 			screeny += 0x78;
305 			if (screeny > 0xf0) screeny = 0xf0;
306 		}
307 
308 		// fudge y to show in centre of scope/hit sprite, note that screenx, screeny
309 		// were confirmed to match those stored by the game at $82732, $82734
310 		screeny += 2;
311 
312 		/* player 1 */
313 		draw_crosshair(bitmap,screenx,screeny,cliprect);
314 
315 		/* calculate p2 screen co-ords by matching routine at $AA48 */
316 		rawx = othunder_ram[0x284c/2];
317 		centrex = othunder_ram[0xa04a/2];
318 		if (rawx <= centrex)
319 		{
320 			rawx = centrex - rawx;
321 			screenx = rawx * othunder_ram[0xa05e/2] + (((rawx * othunder_ram[0xa060/2]) & 0xffff0000) >> 16);
322 			screenx = 0xa0 - screenx;
323 			if (screenx < 0) screenx = 0;
324 		}
325 		else
326 		{
327 			if (rawx > othunder_ram[0xa038/2]) rawx = othunder_ram[0xa038/2];
328 			rawx -= centrex;
329 			screenx = rawx * othunder_ram[0xa066/2] + (((rawx * othunder_ram[0xa068/2]) & 0xffff0000) >> 16);
330 			screenx += 0xa0;
331 			if (screenx > 0x140) screenx = 0x140;
332 		}
333 		rawy = othunder_ram[0x284e/2];
334 		centrey = othunder_ram[0xa04c/2];
335 		if (rawy <= centrey)
336 		{
337 			rawy = centrey - rawy;
338 			screeny = rawy * othunder_ram[0xa062/2] + (((rawy * othunder_ram[0xa064/2]) & 0xffff0000) >> 16);
339 			screeny = 0x78 - screeny;
340 			if (screeny < 0) screeny = 0;
341 		}
342 		else
343 		{
344 			if (rawy > othunder_ram[0xa040/2]) rawy = othunder_ram[0xa040/2];
345 			rawy -= centrey;
346 			screeny = rawy * othunder_ram[0xa06a/2] + (((rawy * othunder_ram[0xa06c/2]) & 0xffff0000) >> 16);
347 			screeny += 0x78;
348 			if (screeny > 0xf0) screeny = 0xf0;
349 		}
350 
351 		// fudge y to show in centre of scope/hit sprite, note that screenx, screeny
352 		// were confirmed to match those stored by the game at $82736, $82738
353 		screeny += 2;
354 
355 		/* player 2 */
356 		draw_crosshair(bitmap,screenx,screeny,cliprect);
357 	}
358 }
359 
360