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