1 // license:BSD-3-Clause
2 // copyright-holders:Zsolt Vasvari
3 /***************************************************************************
4
5 video.c
6
7 Functions to emulate the video hardware of the machine.
8
9 Convention: "sl" stands for "searchlight"
10
11 ***************************************************************************/
12
13 #include "emu.h"
14 #include "sound/ay8910.h"
15 #include "includes/dday.h"
16
17
18 /* Note: There seems to be no way to reset this timer via hardware.
19 The game uses a difference method to reset it to 99.
20
21 Thanks Zwaxy for the timer info. */
22
dday_countdown_timer_r()23 uint8_t dday_state::dday_countdown_timer_r()
24 {
25 return ((m_timer_value / 10) << 4) | (m_timer_value % 10);
26 }
27
TIMER_CALLBACK_MEMBER(dday_state::countdown_timer_callback)28 TIMER_CALLBACK_MEMBER(dday_state::countdown_timer_callback)
29 {
30 m_timer_value--;
31
32 if (m_timer_value < 0)
33 m_timer_value = 99;
34 }
35
start_countdown_timer()36 void dday_state::start_countdown_timer()
37 {
38 m_timer_value = 0;
39
40 m_countdown_timer->adjust(attotime::from_seconds(1), 0, attotime::from_seconds(1));
41 }
42
43
44 /***************************************************************************
45
46 Convert the color PROMs into a more useable format.
47
48 ***************************************************************************/
49
dday_palette(palette_device & palette) const50 void dday_state::dday_palette(palette_device &palette) const
51 {
52 uint8_t const *const color_prom = memregion("proms")->base();
53
54 palette.set_shadow_factor(1.0 / 8);
55
56 // create a lookup table for the palette
57 for (int i = 0; i < 0x100; i++)
58 {
59 int const r = pal4bit(color_prom[i + 0x000]);
60 int const g = pal4bit(color_prom[i + 0x100]);
61 int const b = pal4bit(color_prom[i + 0x200]);
62
63 palette.set_indirect_color(i, rgb_t(r, g, b));
64 }
65
66 for (int i = 0; i < 0x100; i++)
67 palette.set_pen_indirect(i, i);
68
69 // HACK!!! This table is handgenerated, but it matches the screenshot. I have no clue how it really works
70 palette.set_pen_indirect(0*8+0+0, 0x00);
71 palette.set_pen_indirect(0*8+0+1, 0x01);
72 palette.set_pen_indirect(0*8+0+2, 0x15);
73 palette.set_pen_indirect(0*8+0+3, 0x02);
74 palette.set_pen_indirect(0*8+4+0, 0x00);
75 palette.set_pen_indirect(0*8+4+1, 0x01);
76 palette.set_pen_indirect(0*8+4+2, 0x15);
77 palette.set_pen_indirect(0*8+4+3, 0x02);
78
79 palette.set_pen_indirect(1*8+0+0, 0x04);
80 palette.set_pen_indirect(1*8+0+1, 0x05);
81 palette.set_pen_indirect(1*8+0+2, 0x03);
82 palette.set_pen_indirect(1*8+0+3, 0x07);
83 palette.set_pen_indirect(1*8+4+0, 0x04);
84 palette.set_pen_indirect(1*8+4+1, 0x05);
85 palette.set_pen_indirect(1*8+4+2, 0x03);
86 palette.set_pen_indirect(1*8+4+3, 0x07);
87
88 palette.set_pen_indirect(2*8+0+0, 0x08);
89 palette.set_pen_indirect(2*8+0+1, 0x15);
90 palette.set_pen_indirect(2*8+0+2, 0x0a);
91 palette.set_pen_indirect(2*8+0+3, 0x03);
92 palette.set_pen_indirect(2*8+4+0, 0x08);
93 palette.set_pen_indirect(2*8+4+1, 0x15);
94 palette.set_pen_indirect(2*8+4+2, 0x0a);
95 palette.set_pen_indirect(2*8+4+3, 0x03);
96
97 palette.set_pen_indirect(3*8+0+0, 0x08);
98 palette.set_pen_indirect(3*8+0+1, 0x15);
99 palette.set_pen_indirect(3*8+0+2, 0x0a);
100 palette.set_pen_indirect(3*8+0+3, 0x03);
101 palette.set_pen_indirect(3*8+4+0, 0x08);
102 palette.set_pen_indirect(3*8+4+1, 0x15);
103 palette.set_pen_indirect(3*8+4+2, 0x0a);
104 palette.set_pen_indirect(3*8+4+3, 0x03);
105
106 palette.set_pen_indirect(4*8+0+0, 0x10);
107 palette.set_pen_indirect(4*8+0+1, 0x11);
108 palette.set_pen_indirect(4*8+0+2, 0x12);
109 palette.set_pen_indirect(4*8+0+3, 0x07);
110 palette.set_pen_indirect(4*8+4+0, 0x10);
111 palette.set_pen_indirect(4*8+4+1, 0x11);
112 palette.set_pen_indirect(4*8+4+2, 0x12);
113 palette.set_pen_indirect(4*8+4+3, 0x07);
114
115 palette.set_pen_indirect(5*8+0+0, 0x1d);
116 palette.set_pen_indirect(5*8+0+1, 0x15);
117 palette.set_pen_indirect(5*8+0+2, 0x16);
118 palette.set_pen_indirect(5*8+0+3, 0x1b);
119 palette.set_pen_indirect(5*8+4+0, 0x1d);
120 palette.set_pen_indirect(5*8+4+1, 0x15);
121 palette.set_pen_indirect(5*8+4+2, 0x16);
122 palette.set_pen_indirect(5*8+4+3, 0x1b);
123
124 palette.set_pen_indirect(6*8+0+0, 0x1d);
125 palette.set_pen_indirect(6*8+0+1, 0x15);
126 palette.set_pen_indirect(6*8+0+2, 0x1a);
127 palette.set_pen_indirect(6*8+0+3, 0x1b);
128 palette.set_pen_indirect(6*8+4+0, 0x1d);
129 palette.set_pen_indirect(6*8+4+1, 0x15);
130 palette.set_pen_indirect(6*8+4+2, 0x1a);
131 palette.set_pen_indirect(6*8+4+3, 0x1b);
132
133 palette.set_pen_indirect(7*8+0+0, 0x1d);
134 palette.set_pen_indirect(7*8+0+1, 0x02);
135 palette.set_pen_indirect(7*8+0+2, 0x04);
136 palette.set_pen_indirect(7*8+0+3, 0x1b);
137 palette.set_pen_indirect(7*8+4+0, 0x1d);
138 palette.set_pen_indirect(7*8+4+1, 0x02);
139 palette.set_pen_indirect(7*8+4+2, 0x04);
140 palette.set_pen_indirect(7*8+4+3, 0x1b);
141 }
142
143
144 /***************************************************************************
145
146 Callbacks for the TileMap code
147
148 ***************************************************************************/
149
TILE_GET_INFO_MEMBER(dday_state::get_bg_tile_info)150 TILE_GET_INFO_MEMBER(dday_state::get_bg_tile_info)
151 {
152 int code;
153
154 code = m_bgvideoram[tile_index];
155 tileinfo.set(0, code, code >> 5, 0);
156 }
157
TILE_GET_INFO_MEMBER(dday_state::get_fg_tile_info)158 TILE_GET_INFO_MEMBER(dday_state::get_fg_tile_info)
159 {
160 int code, flipx;
161
162 flipx = m_colorram[tile_index & 0x03e0] & 0x01;
163 code = m_fgvideoram[flipx ? tile_index ^ 0x1f : tile_index];
164 tileinfo.set(2, code, code >> 5, flipx ? TILE_FLIPX : 0);
165 }
166
TILE_GET_INFO_MEMBER(dday_state::get_text_tile_info)167 TILE_GET_INFO_MEMBER(dday_state::get_text_tile_info)
168 {
169 int code;
170
171 code = m_textvideoram[tile_index];
172 tileinfo.set(1, code, code >> 5, 0);
173 }
174
TILE_GET_INFO_MEMBER(dday_state::get_sl_tile_info)175 TILE_GET_INFO_MEMBER(dday_state::get_sl_tile_info)
176 {
177 int code, sl_flipx, flipx;
178 uint8_t* sl_map;
179
180 sl_map = &memregion("user1")->base()[(m_sl_image & 0x07) * 0x0200];
181
182 flipx = (tile_index >> 4) & 0x01;
183 sl_flipx = (m_sl_image >> 3) & 0x01;
184
185 /* bit 4 is really a flip indicator. Need to shift bits 5-9 to the right by 1 */
186 tile_index = ((tile_index & 0x03e0) >> 1) | (tile_index & 0x0f);
187
188 code = sl_map[flipx ? tile_index ^ 0x0f : tile_index];
189
190 if ((sl_flipx != flipx) && (code & 0x80))
191 /* no mirroring, draw dark spot */
192 code = 1;
193
194 tileinfo.set(3, code & 0x3f, 0, flipx ? TILE_FLIPX : 0);
195 }
196
197
198 /***************************************************************************
199
200 Start the video hardware emulation.
201
202 ***************************************************************************/
203
video_start()204 void dday_state::video_start()
205 {
206 m_bg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(dday_state::get_bg_tile_info)), TILEMAP_SCAN_ROWS, 8, 8, 32, 32);
207 m_fg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(dday_state::get_fg_tile_info)), TILEMAP_SCAN_ROWS, 8, 8, 32, 32);
208 m_text_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(dday_state::get_text_tile_info)), TILEMAP_SCAN_ROWS, 8, 8, 32, 32);
209 m_sl_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(dday_state::get_sl_tile_info)), TILEMAP_SCAN_ROWS, 8, 8, 32, 32);
210
211 m_screen->register_screen_bitmap(m_main_bitmap);
212
213 m_bg_tilemap->set_transmask(0, 0x00f0, 0xff0f); /* pens 0-3 have priority over the foreground layer */
214 m_fg_tilemap->set_transparent_pen(0);
215 m_text_tilemap->set_transparent_pen(0);
216
217 m_countdown_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(dday_state::countdown_timer_callback), this));
218
219 start_countdown_timer();
220 }
221
dday_bgvideoram_w(offs_t offset,uint8_t data)222 void dday_state::dday_bgvideoram_w(offs_t offset, uint8_t data)
223 {
224 m_bgvideoram[offset] = data;
225 m_bg_tilemap->mark_tile_dirty(offset);
226 }
227
dday_fgvideoram_w(offs_t offset,uint8_t data)228 void dday_state::dday_fgvideoram_w(offs_t offset, uint8_t data)
229 {
230 m_fgvideoram[offset] = data;
231 m_fg_tilemap->mark_tile_dirty(offset);
232 m_fg_tilemap->mark_tile_dirty(offset ^ 0x1f); /* for flipx case */
233 }
234
dday_textvideoram_w(offs_t offset,uint8_t data)235 void dday_state::dday_textvideoram_w(offs_t offset, uint8_t data)
236 {
237 m_textvideoram[offset] = data;
238 m_text_tilemap->mark_tile_dirty(offset);
239 }
240
dday_colorram_w(offs_t offset,uint8_t data)241 void dday_state::dday_colorram_w(offs_t offset, uint8_t data)
242 {
243 offset &= 0x03e0;
244
245 m_colorram[offset & 0x3e0] = data;
246
247 for (int i = 0; i < 0x20; i++)
248 m_fg_tilemap->mark_tile_dirty(offset + i);
249 }
250
dday_colorram_r(offs_t offset)251 uint8_t dday_state::dday_colorram_r(offs_t offset)
252 {
253 return m_colorram[offset & 0x03e0];
254 }
255
256
dday_sl_control_w(uint8_t data)257 void dday_state::dday_sl_control_w(uint8_t data)
258 {
259 if (m_sl_image != data)
260 {
261 m_sl_image = data;
262 m_sl_tilemap->mark_all_dirty();
263 }
264 }
265
266
dday_control_w(uint8_t data)267 void dday_state::dday_control_w(uint8_t data)
268 {
269 //if (data & 0xac) logerror("Control = %02X\n", data & 0xac);
270
271 /* bit 0 is coin counter 1 */
272 machine().bookkeeping().coin_counter_w(0, data & 0x01);
273
274 /* bit 1 is coin counter 2 */
275 machine().bookkeeping().coin_counter_w(1, data & 0x02);
276
277 /* bit 4 is sound enable */
278 if (!(data & 0x10) && (m_control & 0x10))
279 m_ay1->reset();
280
281 machine().sound().system_enable(data & 0x10);
282
283 /* bit 6 is search light enable */
284 m_sl_enable = data & 0x40;
285
286 m_control = data;
287 }
288
289 /***************************************************************************
290
291 Display refresh
292
293 ***************************************************************************/
294
screen_update_dday(screen_device & screen,bitmap_ind16 & bitmap,const rectangle & cliprect)295 uint32_t dday_state::screen_update_dday(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
296 {
297 m_bg_tilemap->draw(screen, m_main_bitmap, cliprect, TILEMAP_DRAW_LAYER1, 0);
298 m_fg_tilemap->draw(screen, m_main_bitmap, cliprect, 0, 0);
299 m_bg_tilemap->draw(screen, m_main_bitmap, cliprect, TILEMAP_DRAW_LAYER0, 0);
300 m_text_tilemap->draw(screen, m_main_bitmap, cliprect, 0, 0);
301
302 if (m_sl_enable)
303 {
304 /* apply shadow */
305 bitmap_ind16 &sl_bitmap = m_sl_tilemap->pixmap();
306
307 for (int x = cliprect.min_x; x <= cliprect.max_x; x++)
308 for (int y = cliprect.min_y; y <= cliprect.max_y; y++)
309 {
310 uint16_t src_pixel = m_main_bitmap.pix(y, x);
311
312 if (sl_bitmap.pix(y, x) == 0xff)
313 src_pixel += m_palette->entries();
314
315 bitmap.pix(y, x) = src_pixel;
316 }
317 }
318 else
319 copybitmap(bitmap, m_main_bitmap, 0, 0, 0, 0, cliprect);
320
321 return 0;
322 }
323