#include "driver.h"
#include "video/taitoic.h"
#define TC0100SCN_GFX_NUM 1
UINT16 *othunder_ram;
struct tempsprite
{
int gfx;
int code,color;
int flipx,flipy;
int x,y;
int zoomx,zoomy;
int primask;
};
static struct tempsprite *spritelist;
static int taito_hide_pixels;
/**********************************************************/
static VIDEO_START( othunder_core )
{
/* Up to $800/8 big sprites, requires 0x100 * sizeof(*spritelist)
Multiply this by 32 to give room for the number of small sprites,
which are what actually get put in the structure. */
spritelist = auto_malloc(0x2000 * sizeof(*spritelist));
TC0100SCN_vh_start(machine,1,TC0100SCN_GFX_NUM,taito_hide_pixels,0,0,0,0,0,0);
if (has_TC0110PCR())
TC0110PCR_vh_start();
}
VIDEO_START( othunder )
{
/* There is a problem here. 4 is correct for text layer/sprite
alignment, but the bg layers [or one of them] are wrong */
taito_hide_pixels = 4;
video_start_othunder_core(machine);
}
/************************************************************
SPRITE DRAW ROUTINE
It draws a series of small tiles ("chunks") together to
create a big sprite. The spritemap rom provides the lookup
table for this. We look up the 16x8 sprite chunks from
the spritemap rom, creating each 64x64 sprite as follows:
0 1 2 3
4 5 6 7
8 9 10 11
12 13 14 15
16 17 18 19
20 21 22 23
24 25 26 27
28 29 30 31
The game makes heavy use of sprite zooming.
***
NB: unused portions of the spritemap rom contain hex FF's.
It is a useful coding check to warn in the log if these
are being accessed. [They can be inadvertently while
spriteram is being tested, take no notice of that.]
Othunder (modified table from Raine)
Byte | Bit(s) | Description
-----+76543210+-------------------------------------
0 |xxxxxxx.| ZoomY (0 min, 63 max - msb unused as sprites are 64x64)
0 |.......x| Y position (High)
1 |xxxxxxxx| Y position (Low)
2 |x.......| Sprite/BG Priority (0=sprites high)
2 |.x......| Flip X
2 |..?????.| unknown/unused ?
2 |.......x| X position (High)
3 |xxxxxxxx| X position (Low)
4 |xxxxxxxx| Palette bank
5 |?.......| unknown/unused ?
5 |.xxxxxxx| ZoomX (0 min, 63 max - msb unused as sprites are 64x64)
6 |x.......| Flip Y
6 |.??.....| unknown/unused ?
6 |...xxxxx| Sprite Tile high (2 msbs unused - 3/4 of spritemap rom empty)
7 |xxxxxxxx| Sprite Tile low
********************************************************/
static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect,const int *primasks,int y_offs)
{
UINT16 *spritemap = (UINT16 *)memory_region(REGION_USER1);
UINT16 tile_mask = (machine->gfx[0]->total_elements) - 1;
int offs, data, tilenum, color, flipx, flipy;
int x, y, priority, curx, cury;
int sprites_flipscreen = 0;
int zoomx, zoomy, zx, zy;
int sprite_chunk,map_offset,code,j,k,px,py;
int bad_chunks;
/* pdrawgfx() needs us to draw sprites front to back, so we have to build a list
while processing sprite ram and then draw them all at the end */
struct tempsprite *sprite_ptr = spritelist;
for (offs = (spriteram_size/2)-4;offs >=0;offs -= 4)
{
data = spriteram16[offs+0];
zoomy = (data & 0xfe00) >> 9;
y = data & 0x1ff;
data = spriteram16[offs+1];
flipx = (data & 0x4000) >> 14;
priority = (data & 0x8000) >> 15;
x = data & 0x1ff;
data = spriteram16[offs+2];
color = (data & 0xff00) >> 8;
zoomx = (data & 0x7f);
data = spriteram16[offs+3];
tilenum = data & 0x1fff; // $80000 spritemap rom maps up to $2000 64x64 sprites
flipy = (data & 0x8000) >> 15;
if (!tilenum) continue;
map_offset = tilenum << 5;
zoomx += 1;
zoomy += 1;
y += y_offs;
/* treat coords as signed */
if (x>0x140) x -= 0x200;
if (y>0x140) y -= 0x200;
bad_chunks = 0;
for (sprite_chunk=0;sprite_chunk<32;sprite_chunk++)
{
k = sprite_chunk % 4; /* 4 chunks per row */
j = sprite_chunk / 4; /* 8 rows */
px = k;
py = j;
if (flipx) px = 3-k; /* pick tiles back to front for x and y flips */
if (flipy) py = 7-j;
code = spritemap[map_offset + px + (py<<2)] &tile_mask;
if (code==0xffff)
{
bad_chunks += 1;
continue;
}
curx = x + ((k*zoomx)/4);
cury = y + ((j*zoomy)/8);
zx= x + (((k+1)*zoomx)/4) - curx;
zy= y + (((j+1)*zoomy)/8) - cury;
if (sprites_flipscreen)
{
/* -zx/y is there to fix zoomed sprite coords in screenflip.
drawgfxzoom does not know to draw from flip-side of sprites when
screen is flipped; so we must correct the coords ourselves. */
curx = 320 - curx - zx;
cury = 256 - cury - zy;
flipx = !flipx;
flipy = !flipy;
}
sprite_ptr->code = code;
sprite_ptr->color = color;
sprite_ptr->flipx = flipx;
sprite_ptr->flipy = flipy;
sprite_ptr->x = curx;
sprite_ptr->y = cury;
sprite_ptr->zoomx = zx << 12;
sprite_ptr->zoomy = zy << 13;
if (primasks)
{
sprite_ptr->primask = primasks[priority];
sprite_ptr++;
}
else
{
drawgfxzoom(bitmap,machine->gfx[0],
sprite_ptr->code,
sprite_ptr->color,
sprite_ptr->flipx,sprite_ptr->flipy,
sprite_ptr->x,sprite_ptr->y,
cliprect,TRANSPARENCY_PEN,0,
sprite_ptr->zoomx,sprite_ptr->zoomy);
}
}
if (bad_chunks)
logerror("Sprite number %04x had %02x invalid chunks\n",tilenum,bad_chunks);
}
/* this happens only if primsks != NULL */
while (sprite_ptr != spritelist)
{
sprite_ptr--;
pdrawgfxzoom(bitmap,machine->gfx[0],
sprite_ptr->code,
sprite_ptr->color,
sprite_ptr->flipx,sprite_ptr->flipy,
sprite_ptr->x,sprite_ptr->y,
cliprect,TRANSPARENCY_PEN,0,
sprite_ptr->zoomx,sprite_ptr->zoomy,
sprite_ptr->primask);
}
}
/**************************************************************
SCREEN REFRESH
**************************************************************/
VIDEO_UPDATE( othunder )
{
int layer[3];
TC0100SCN_tilemap_update(machine);
layer[0] = TC0100SCN_bottomlayer(0);
layer[1] = layer[0]^1;
layer[2] = 2;
fillbitmap(priority_bitmap,0,cliprect);
/* Ensure screen blanked even when bottom layer not drawn due to disable bit */
fillbitmap(bitmap, machine->pens[0], cliprect);
TC0100SCN_tilemap_draw(machine,bitmap,cliprect,0,layer[0],TILEMAP_DRAW_OPAQUE,1);
TC0100SCN_tilemap_draw(machine,bitmap,cliprect,0,layer[1],0,2);
TC0100SCN_tilemap_draw(machine,bitmap,cliprect,0,layer[2],0,4);
/* Sprites can be under/over the layer below text layer */
{
static const int primasks[2] = {0xf0,0xfc};
draw_sprites(machine, bitmap,cliprect,primasks,3);
}
/* Draw artificial gun targets */
{
int rawx, rawy, centrex, centrey, screenx, screeny;
/* calculate p1 screen co-ords by matching routine at $A932 */
rawx = othunder_ram[0x2848/2];
centrex = othunder_ram[0xa046/2];
if (rawx <= centrex)
{
rawx = centrex - rawx;
screenx = rawx * othunder_ram[0xa04e/2] + (((rawx * othunder_ram[0xa050/2]) & 0xffff0000) >> 16);
screenx = 0xa0 - screenx;
if (screenx < 0) screenx = 0;
}
else
{
if (rawx > othunder_ram[0xa028/2]) rawx = othunder_ram[0xa028/2];
rawx -= centrex;
screenx = rawx * othunder_ram[0xa056/2] + (((rawx * othunder_ram[0xa058/2]) & 0xffff0000) >> 16);
screenx += 0xa0;
if (screenx > 0x140) screenx = 0x140;
}
rawy = othunder_ram[0x284a/2];
centrey = othunder_ram[0xa048/2];
if (rawy <= centrey)
{
rawy = centrey - rawy;
screeny = rawy * othunder_ram[0xa052/2] + (((rawy * othunder_ram[0xa054/2]) & 0xffff0000) >> 16);
screeny = 0x78 - screeny;
if (screeny < 0) screeny = 0;
}
else
{
if (rawy > othunder_ram[0xa030/2]) rawy = othunder_ram[0xa030/2];
rawy -= centrey;
screeny = rawy * othunder_ram[0xa05a/2] + (((rawy * othunder_ram[0xa05c/2]) & 0xffff0000) >> 16);
screeny += 0x78;
if (screeny > 0xf0) screeny = 0xf0;
}
// fudge y to show in centre of scope/hit sprite, note that screenx, screeny
// were confirmed to match those stored by the game at $82732, $82734
screeny += 2;
/* calculate p2 screen co-ords by matching routine at $AA48 */
rawx = othunder_ram[0x284c/2];
centrex = othunder_ram[0xa04a/2];
if (rawx <= centrex)
{
rawx = centrex - rawx;
screenx = rawx * othunder_ram[0xa05e/2] + (((rawx * othunder_ram[0xa060/2]) & 0xffff0000) >> 16);
screenx = 0xa0 - screenx;
if (screenx < 0) screenx = 0;
}
else
{
if (rawx > othunder_ram[0xa038/2]) rawx = othunder_ram[0xa038/2];
rawx -= centrex;
screenx = rawx * othunder_ram[0xa066/2] + (((rawx * othunder_ram[0xa068/2]) & 0xffff0000) >> 16);
screenx += 0xa0;
if (screenx > 0x140) screenx = 0x140;
}
rawy = othunder_ram[0x284e/2];
centrey = othunder_ram[0xa04c/2];
if (rawy <= centrey)
{
rawy = centrey - rawy;
screeny = rawy * othunder_ram[0xa062/2] + (((rawy * othunder_ram[0xa064/2]) & 0xffff0000) >> 16);
screeny = 0x78 - screeny;
if (screeny < 0) screeny = 0;
}
else
{
if (rawy > othunder_ram[0xa040/2]) rawy = othunder_ram[0xa040/2];
rawy -= centrey;
screeny = rawy * othunder_ram[0xa06a/2] + (((rawy * othunder_ram[0xa06c/2]) & 0xffff0000) >> 16);
screeny += 0x78;
if (screeny > 0xf0) screeny = 0xf0;
}
// fudge y to show in centre of scope/hit sprite, note that screenx, screeny
// were confirmed to match those stored by the game at $82736, $82738
screeny += 2;
}
return 0;
}