1 // license:BSD-3-Clause
2 // copyright-holders:Stefan Jokisch
3 /***************************************************************************
4
5 Atari Tank 8 video emulation
6
7 ***************************************************************************/
8
9 #include "emu.h"
10 #include "includes/tank8.h"
11
12
tank8_palette(palette_device & palette) const13 void tank8_state::tank8_palette(palette_device &palette) const
14 {
15 palette.set_indirect_color(8, rgb_t(0x00, 0x00, 0x00));
16 palette.set_indirect_color(9, rgb_t(0xff, 0xff, 0xff));
17
18 for (int i = 0; i < 8; i++)
19 {
20 palette.set_pen_indirect(2 * i + 0, 8);
21 palette.set_pen_indirect(2 * i + 1, i);
22 }
23
24 /* walls */
25 palette.set_pen_indirect(0x10, 8);
26 palette.set_pen_indirect(0x11, 9);
27
28 /* mines */
29 palette.set_pen_indirect(0x12, 8);
30 palette.set_pen_indirect(0x13, 9);
31 }
32
33
set_pens()34 void tank8_state::set_pens()
35 {
36 if (*m_team & 0x01)
37 {
38 m_palette->set_indirect_color(0, rgb_t(0xff, 0x00, 0x00)); /* red */
39 m_palette->set_indirect_color(1, rgb_t(0x00, 0x00, 0xff)); /* blue */
40 m_palette->set_indirect_color(2, rgb_t(0xff, 0xff, 0x00)); /* yellow */
41 m_palette->set_indirect_color(3, rgb_t(0x00, 0xff, 0x00)); /* green */
42 m_palette->set_indirect_color(4, rgb_t(0xff, 0x00, 0xff)); /* magenta */
43 m_palette->set_indirect_color(5, rgb_t(0xe0, 0xc0, 0x70)); /* puce */
44 m_palette->set_indirect_color(6, rgb_t(0x00, 0xff, 0xff)); /* cyan */
45 m_palette->set_indirect_color(7, rgb_t(0xff, 0xaa, 0xaa)); /* pink */
46 }
47 else
48 {
49 m_palette->set_indirect_color(0, rgb_t(0xff, 0x00, 0x00)); /* red */
50 m_palette->set_indirect_color(2, rgb_t(0xff, 0x00, 0x00)); /* red */
51 m_palette->set_indirect_color(4, rgb_t(0xff, 0x00, 0x00)); /* red */
52 m_palette->set_indirect_color(6, rgb_t(0xff, 0x00, 0x00)); /* red */
53 m_palette->set_indirect_color(1, rgb_t(0x00, 0x00, 0xff)); /* blue */
54 m_palette->set_indirect_color(3, rgb_t(0x00, 0x00, 0xff)); /* blue */
55 m_palette->set_indirect_color(5, rgb_t(0x00, 0x00, 0xff)); /* blue */
56 m_palette->set_indirect_color(7, rgb_t(0x00, 0x00, 0xff)); /* blue */
57 }
58 }
59
60
video_ram_w(offs_t offset,uint8_t data)61 void tank8_state::video_ram_w(offs_t offset, uint8_t data)
62 {
63 m_video_ram[offset] = data;
64 m_tilemap->mark_tile_dirty(offset);
65 }
66
67
68
TILE_GET_INFO_MEMBER(tank8_state::get_tile_info)69 TILE_GET_INFO_MEMBER(tank8_state::get_tile_info)
70 {
71 uint8_t code = m_video_ram[tile_index];
72
73 int color = 0;
74
75 if ((code & 0x38) == 0x28)
76 {
77 if ((code & 7) != 3)
78 color = 8; /* walls */
79 else
80 color = 9; /* mines */
81 }
82 else
83 {
84 if (tile_index & 0x010)
85 color |= 1;
86
87 if (code & 0x80)
88 color |= 2;
89
90 if (tile_index & 0x200)
91 color |= 4;
92 }
93
94 tileinfo.set(code >> 7, code, color, (code & 0x40) ? (TILE_FLIPX | TILE_FLIPY) : 0);
95 }
96
97
98
video_start()99 void tank8_state::video_start()
100 {
101 m_collision_timer = timer_alloc(TIMER_COLLISION);
102
103 m_screen->register_screen_bitmap(m_helper1);
104 m_screen->register_screen_bitmap(m_helper2);
105 m_screen->register_screen_bitmap(m_helper3);
106
107 m_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(tank8_state::get_tile_info)), TILEMAP_SCAN_ROWS, 16, 16, 32, 32);
108
109 // VBLANK starts on scanline #256 and ends on scanline #24
110 m_tilemap->set_scrolly(0, 2 * 24);
111
112 save_item(NAME(m_collision_index));
113 }
114
115
get_x_pos(int n)116 int tank8_state::get_x_pos(int n)
117 {
118 return 498 - m_pos_h_ram[n] - 2 * (m_pos_d_ram[n] & 128); /* ? */
119 }
120
121
get_y_pos(int n)122 int tank8_state::get_y_pos(int n)
123 {
124 return 2 * m_pos_v_ram[n] - 62;
125 }
126
127
draw_sprites(bitmap_ind16 & bitmap,const rectangle & cliprect)128 void tank8_state::draw_sprites(bitmap_ind16 &bitmap, const rectangle &cliprect)
129 {
130 int i;
131
132 for (i = 0; i < 8; i++)
133 {
134 uint8_t code = ~m_pos_d_ram[i];
135
136 int x = get_x_pos(i);
137 int y = get_y_pos(i);
138
139 m_gfxdecode->gfx((code & 0x04) ? 2 : 3)->transpen(bitmap,cliprect,
140 code & 0x03,
141 i,
142 code & 0x10,
143 code & 0x08,
144 x,
145 y, 0);
146 }
147 }
148
149
draw_bullets(bitmap_ind16 & bitmap,const rectangle & cliprect)150 void tank8_state::draw_bullets(bitmap_ind16 &bitmap, const rectangle &cliprect)
151 {
152 int i;
153
154 for (i = 0; i < 8; i++)
155 {
156 int x = get_x_pos(8 + i);
157 int y = get_y_pos(8 + i);
158
159 x -= 4; /* ? */
160
161 rectangle rect(x, x + 3, y, y + 4);
162 rect &= cliprect;
163
164 bitmap.fill((i << 1) | 0x01, rect);
165 }
166 }
167
168
device_timer(emu_timer & timer,device_timer_id id,int param,void * ptr)169 void tank8_state::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
170 {
171 switch (id)
172 {
173 case TIMER_COLLISION:
174 set_collision(param);
175 break;
176 default:
177 throw emu_fatalerror("Unknown id in tank8_state::device_timer");
178 }
179 }
180
181
screen_update(screen_device & screen,bitmap_ind16 & bitmap,const rectangle & cliprect)182 uint32_t tank8_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
183 {
184 set_pens();
185 m_tilemap->draw(screen, bitmap, cliprect, 0, 0);
186
187 draw_sprites(bitmap, cliprect);
188 draw_bullets(bitmap, cliprect);
189 return 0;
190 }
191
192
WRITE_LINE_MEMBER(tank8_state::screen_vblank)193 WRITE_LINE_MEMBER(tank8_state::screen_vblank)
194 {
195 // on falling edge
196 if (!state)
197 {
198 const rectangle &visarea = m_screen->visible_area();
199
200 m_tilemap->draw(*m_screen, m_helper1, visarea, 0, 0);
201
202 m_helper2.fill(8, visarea);
203 m_helper3.fill(8, visarea);
204
205 draw_sprites(m_helper2, visarea);
206 draw_bullets(m_helper3, visarea);
207
208 for (int y = visarea.top(); y <= visarea.bottom(); y++)
209 {
210 int _state = 0;
211
212 uint16_t const *const p1 = &m_helper1.pix(y);
213 uint16_t const *const p2 = &m_helper2.pix(y);
214 uint16_t const *const p3 = &m_helper3.pix(y);
215
216 if ((m_screen->frame_number() ^ y) & 1)
217 continue; /* video display is interlaced */
218
219 for (int x = visarea.left(); x <= visarea.right(); x++)
220 {
221 /* neither wall nor mine */
222 if ((p1[x] != 0x11) && (p1[x] != 0x13))
223 {
224 _state = 0;
225 continue;
226 }
227
228 /* neither tank nor bullet */
229 if ((p2[x] == 8) && (p3[x] == 8))
230 {
231 _state = 0;
232 continue;
233 }
234
235 /* bullets cannot hit mines */
236 if ((p3[x] != 8) && (p1[x] == 0x13))
237 {
238 _state = 0;
239 continue;
240 }
241
242 if (_state)
243 continue;
244
245 uint8_t index;
246 if (p3[x] != 8)
247 {
248 index = ((p3[x] & ~0x01) >> 1) | 0x18;
249
250 if (1)
251 index |= 0x20;
252
253 if (0)
254 index |= 0x40;
255
256 if (1)
257 index |= 0x80;
258 }
259 else
260 {
261 int sprite_num = (p2[x] & ~0x01) >> 1;
262 index = sprite_num | 0x10;
263
264 if (p1[x] == 0x11)
265 index |= 0x20;
266
267 if (y - get_y_pos(sprite_num) >= 8)
268 index |= 0x40; /* collision on bottom side */
269
270 if (x - get_x_pos(sprite_num) >= 8)
271 index |= 0x80; /* collision on right side */
272 }
273
274 m_collision_timer->adjust(m_screen->time_until_pos(y, x), index);
275
276 _state = 1;
277 }
278 }
279 }
280 }
281