1 // license:BSD-3-Clause
2 // copyright-holders:Zsolt Vasvari
3 #include "emu.h"
4 #include "includes/mermaid.h"
5
6
common_palette(palette_device & palette) const7 void mermaid_state::common_palette(palette_device &palette) const
8 {
9 uint8_t const *const color_prom = memregion("proms")->base();
10 for (int i = 0; i < 0x40; i++)
11 {
12 int const r = 0x21 * BIT(color_prom[i], 0) + 0x47 * BIT(color_prom[i], 1) + 0x97 * BIT(color_prom[i], 2);
13 int const g = 0x21 * BIT(color_prom[i], 3) + 0x47 * BIT(color_prom[i], 4) + 0x97 * BIT(color_prom[i], 5);
14 int const b = 0x47 * BIT(color_prom[i], 6) + 0x97 * BIT(color_prom[i], 7);
15
16 palette.set_indirect_color(i, rgb_t(r, g, b));
17 }
18 }
19
mermaid_palette(palette_device & palette) const20 void mermaid_state::mermaid_palette(palette_device &palette) const
21 {
22 common_palette(palette);
23
24 // blue background
25 palette.set_indirect_color(0x40, rgb_t(0, 0, 0xff));
26
27 // char/sprite palette
28 for (int i = 0; i < 0x40; i++)
29 palette.set_pen_indirect(i, i);
30
31 // background palette
32 palette.set_pen_indirect(0x40, 0x20);
33 palette.set_pen_indirect(0x41, 0x21);
34 palette.set_pen_indirect(0x42, 0x40);
35 palette.set_pen_indirect(0x43, 0x21);
36 }
37
rougien_palette(palette_device & palette) const38 void mermaid_state::rougien_palette(palette_device &palette) const
39 {
40 common_palette(palette);
41
42 // black background
43 palette.set_indirect_color(0x40, rgb_t(0, 0, 0));
44
45 // char/sprite palette
46 for (int i = 0; i < 0x40; i++)
47 palette.set_pen_indirect(i, i);
48
49 // background palette
50 palette.set_pen_indirect(0x40, 0x40);
51 palette.set_pen_indirect(0x41, 0x00);
52 palette.set_pen_indirect(0x42, 0x00);
53 palette.set_pen_indirect(0x43, 0x02);
54 }
55
56
mermaid_videoram2_w(offs_t offset,uint8_t data)57 void mermaid_state::mermaid_videoram2_w(offs_t offset, uint8_t data)
58 {
59 m_videoram2[offset] = data;
60 m_bg_tilemap->mark_tile_dirty(offset);
61 }
62
mermaid_videoram_w(offs_t offset,uint8_t data)63 void mermaid_state::mermaid_videoram_w(offs_t offset, uint8_t data)
64 {
65 m_videoram[offset] = data;
66 m_fg_tilemap->mark_tile_dirty(offset);
67 }
68
mermaid_colorram_w(offs_t offset,uint8_t data)69 void mermaid_state::mermaid_colorram_w(offs_t offset, uint8_t data)
70 {
71 m_colorram[offset] = data;
72 m_fg_tilemap->mark_tile_dirty(offset);
73 }
74
WRITE_LINE_MEMBER(mermaid_state::flip_screen_x_w)75 WRITE_LINE_MEMBER(mermaid_state::flip_screen_x_w)
76 {
77 flip_screen_x_set(state);
78 }
79
WRITE_LINE_MEMBER(mermaid_state::flip_screen_y_w)80 WRITE_LINE_MEMBER(mermaid_state::flip_screen_y_w)
81 {
82 flip_screen_y_set(state);
83 }
84
mermaid_bg_scroll_w(offs_t offset,uint8_t data)85 void mermaid_state::mermaid_bg_scroll_w(offs_t offset, uint8_t data)
86 {
87 m_bg_scrollram[offset] = data;
88 m_bg_tilemap->set_scrolly(offset, data);
89 }
90
mermaid_fg_scroll_w(offs_t offset,uint8_t data)91 void mermaid_state::mermaid_fg_scroll_w(offs_t offset, uint8_t data)
92 {
93 m_fg_scrollram[offset] = data;
94 m_fg_tilemap->set_scrolly(offset, data);
95 }
96
WRITE_LINE_MEMBER(mermaid_state::rougien_gfxbankswitch1_w)97 WRITE_LINE_MEMBER(mermaid_state::rougien_gfxbankswitch1_w)
98 {
99 m_rougien_gfxbank1 = state;
100 }
101
WRITE_LINE_MEMBER(mermaid_state::rougien_gfxbankswitch2_w)102 WRITE_LINE_MEMBER(mermaid_state::rougien_gfxbankswitch2_w)
103 {
104 m_rougien_gfxbank2 = state;
105 }
106
mermaid_collision_r()107 uint8_t mermaid_state::mermaid_collision_r()
108 {
109 /*
110 collision register active LOW:
111
112 with coll = spriteram[offs + 2] & 0xc0
113
114 Bit 0 - Sprite (coll = 0x40) - Sprite (coll = 0x00)
115 Bit 1 - Sprite (coll = 0x40) - Foreground
116 Bit 2 - Sprite (coll = 0x40) - Background
117 Bit 3 - Sprite (coll = 0x80) - Sprite (coll = 0x00)
118 Bit 4
119 Bit 5
120 Bit 6 - Sprite (coll = 0x40) - Sprite (coll = 0x80)
121 Bit 7
122 */
123
124 int collision = 0xff;
125
126 if (m_coll_bit0) collision ^= 0x01;
127 if (m_coll_bit1) collision ^= 0x02;
128 if (m_coll_bit2) collision ^= 0x04;
129 if (m_coll_bit3) collision ^= 0x08;
130 if (m_coll_bit6) collision ^= 0x40;
131
132 return collision;
133 }
134
TILE_GET_INFO_MEMBER(mermaid_state::get_bg_tile_info)135 TILE_GET_INFO_MEMBER(mermaid_state::get_bg_tile_info)
136 {
137 int code = m_videoram2[tile_index];
138 int sx = tile_index % 32;
139 int color = (sx >= 26) ? 0 : 1;
140
141 tileinfo.set(2, code, color, 0);
142 }
143
TILE_GET_INFO_MEMBER(mermaid_state::get_fg_tile_info)144 TILE_GET_INFO_MEMBER(mermaid_state::get_fg_tile_info)
145 {
146 int attr = m_colorram[tile_index];
147 int code = m_videoram[tile_index] + ((attr & 0x30) << 4);
148 int color = attr & 0x0f;
149 int flags = TILE_FLIPYX((attr & 0xc0) >> 6);
150
151 code |= m_rougien_gfxbank1 * 0x2800;
152 code |= m_rougien_gfxbank2 * 0x2400;
153
154 tileinfo.set(0, code, color, flags);
155 }
156
video_start()157 void mermaid_state::video_start()
158 {
159 m_bg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(mermaid_state::get_bg_tile_info)), TILEMAP_SCAN_ROWS, 8, 8, 32, 32);
160 m_bg_tilemap->set_scroll_cols(32);
161
162 m_fg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(mermaid_state::get_fg_tile_info)), TILEMAP_SCAN_ROWS, 8, 8, 32, 32);
163 m_fg_tilemap->set_scroll_cols(32);
164 m_fg_tilemap->set_transparent_pen(0);
165
166 m_screen->register_screen_bitmap(m_helper);
167 m_screen->register_screen_bitmap(m_helper2);
168 }
169
draw_sprites(bitmap_ind16 & bitmap,const rectangle & cliprect)170 void mermaid_state::draw_sprites( bitmap_ind16 &bitmap, const rectangle &cliprect )
171 {
172 const rectangle spritevisiblearea(0 * 8, 26 * 8 - 1, 2 * 8, 30 * 8 - 1);
173 const rectangle flip_spritevisiblearea(6 * 8, 31 * 8 - 1, 2 * 8, 30 * 8 - 1);
174
175 uint8_t *spriteram = m_spriteram;
176 int offs;
177
178 for (offs = m_spriteram.bytes() - 4; offs >= 0; offs -= 4)
179 {
180 int attr = spriteram[offs + 2];
181 int bank = (attr & 0x30) >> 4;
182 int code = (spriteram[offs] & 0x3f) | (bank << 6);
183 int color = attr & 0x0f;
184 int flipx = spriteram[offs] & 0x40;
185 int flipy = spriteram[offs] & 0x80;
186 int sx = spriteram[offs + 3] + 1;
187 int sy = 240 - spriteram[offs + 1];
188
189 if (sx >= 0xf0) sx -= 256;
190
191 code |= m_rougien_gfxbank1 * 0x2800;
192 code |= m_rougien_gfxbank2 * 0x2400;
193
194 if (flip_screen_x())
195 {
196 flipx = !flipx;
197 sx = 240 - sx;
198 }
199
200 if (flip_screen_y())
201 {
202 flipy = !flipy;
203 sy = 240 - sy;
204 }
205
206
207 m_gfxdecode->gfx(1)->transpen(bitmap,(flip_screen_x() ? flip_spritevisiblearea : spritevisiblearea), code, color, flipx, flipy, sx, sy, 0);
208 }
209 }
210
screen_update_mermaid(screen_device & screen,bitmap_ind16 & bitmap,const rectangle & cliprect)211 uint32_t mermaid_state::screen_update_mermaid(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
212 {
213 m_bg_tilemap->draw(screen, bitmap, cliprect, 0, 0);
214 m_fg_tilemap->draw(screen, bitmap, cliprect, 0, 0);
215 draw_sprites(bitmap, cliprect);
216 return 0;
217 }
218
collision_check(rectangle & rect)219 uint8_t mermaid_state::collision_check( rectangle& rect )
220 {
221 uint8_t data = 0;
222
223 for (int y = rect.top(); y <= rect.bottom(); y++)
224 for (int x = rect.left(); x <= rect.right(); x++)
225 {
226 uint16_t const a = m_palette->pen_indirect(m_helper.pix(y, x)) & 0x3f;
227 uint16_t const b = m_palette->pen_indirect(m_helper2.pix(y, x)) & 0x3f;
228
229 if (b && a)
230 data |= 0x01;
231 }
232
233 return data;
234 }
235
collision_update()236 void mermaid_state::collision_update()
237 {
238 const rectangle &visarea = m_screen->visible_area();
239 uint8_t *spriteram = m_spriteram;
240
241 int offs, offs2;
242
243 m_coll_bit0 = 0;
244 m_coll_bit1 = 0;
245 m_coll_bit2 = 0;
246 m_coll_bit3 = 0;
247 m_coll_bit6 = 0;
248
249 // check for bit 0 (sprite-sprite), 1 (sprite-foreground), 2 (sprite-background)
250
251 for (offs = m_spriteram.bytes() - 4; offs >= 0; offs -= 4)
252 {
253 int attr = spriteram[offs + 2];
254 int bank = (attr & 0x30) >> 4;
255 int coll = (attr & 0xc0) >> 6;
256 int code = (spriteram[offs] & 0x3f) | (bank << 6);
257 int flipx = spriteram[offs] & 0x40;
258 int flipy = spriteram[offs] & 0x80;
259 int sx = spriteram[offs + 3] + 1;
260 int sy = 240 - spriteram[offs + 1];
261
262 rectangle rect;
263
264 if (coll != 1) continue;
265
266 code |= m_rougien_gfxbank1 * 0x2800;
267 code |= m_rougien_gfxbank2 * 0x2400;
268
269 if (flip_screen_x())
270 {
271 flipx = !flipx;
272 sx = 240 - sx;
273 }
274
275 if (flip_screen_y())
276 {
277 flipy = !flipy;
278 sy = 240 - sy;
279 }
280
281 rect.set(
282 sx, sx + m_gfxdecode->gfx(1)->width() - 1,
283 sy, sy + m_gfxdecode->gfx(1)->height() - 1);
284 rect &= visarea;
285
286 // check collision sprite - background
287
288 m_helper.fill(0, rect);
289 m_helper2.fill(0, rect);
290
291 m_bg_tilemap->draw(*m_screen, m_helper, rect, 0, 0);
292
293 m_gfxdecode->gfx(1)->transpen(m_helper2,rect, code, 0, flipx, flipy, sx, sy, 0);
294
295 m_coll_bit2 |= collision_check(rect);
296
297 // check collision sprite - foreground
298
299 m_helper.fill(0, rect);
300 m_helper2.fill(0, rect);
301
302 m_fg_tilemap->draw(*m_screen, m_helper, rect, 0, 0);
303
304 m_gfxdecode->gfx(1)->transpen(m_helper2,rect, code, 0, flipx, flipy, sx, sy, 0);
305
306 m_coll_bit1 |= collision_check(rect);
307
308 // check collision sprite - sprite
309
310 m_helper.fill(0, rect);
311 m_helper2.fill(0, rect);
312
313 for (offs2 = m_spriteram.bytes() - 4; offs2 >= 0; offs2 -= 4)
314 if (offs != offs2)
315 {
316 int attr2 = spriteram[offs2 + 2];
317 int bank2 = (attr2 & 0x30) >> 4;
318 int coll2 = (attr2 & 0xc0) >> 6;
319 int code2 = (spriteram[offs2] & 0x3f) | (bank2 << 6);
320 int flipx2 = spriteram[offs2] & 0x40;
321 int flipy2 = spriteram[offs2] & 0x80;
322 int sx2 = spriteram[offs2 + 3] + 1;
323 int sy2 = 240 - spriteram[offs2 + 1];
324
325 if (coll2 != 0) continue;
326
327 code2 |= m_rougien_gfxbank1 * 0x2800;
328 code2 |= m_rougien_gfxbank2 * 0x2400;
329
330 if (flip_screen_x())
331 {
332 flipx2 = !flipx2;
333 sx2 = 240 - sx2;
334 }
335
336 if (flip_screen_y())
337 {
338 flipy2 = !flipy2;
339 sy2 = 240 - sy2;
340 }
341
342 m_gfxdecode->gfx(1)->transpen(m_helper,rect, code2, 0, flipx2, flipy2, sx2, sy2, 0);
343 }
344
345 m_gfxdecode->gfx(1)->transpen(m_helper2,rect, code, 0, flipx, flipy, sx, sy, 0);
346
347 m_coll_bit0 |= collision_check(rect);
348 }
349
350 // check for bit 3 (sprite-sprite)
351
352 for (offs = m_spriteram.bytes() - 4; offs >= 0; offs -= 4)
353 {
354 int attr = spriteram[offs + 2];
355 int bank = (attr & 0x30) >> 4;
356 int coll = (attr & 0xc0) >> 6;
357 int code = (spriteram[offs] & 0x3f) | (bank << 6);
358 int flipx = spriteram[offs] & 0x40;
359 int flipy = spriteram[offs] & 0x80;
360 int sx = spriteram[offs + 3] + 1;
361 int sy = 240 - spriteram[offs + 1];
362
363 rectangle rect;
364
365 if (coll != 2) continue;
366
367 code |= m_rougien_gfxbank1 * 0x2800;
368 code |= m_rougien_gfxbank2 * 0x2400;
369
370 if (flip_screen_x())
371 {
372 flipx = !flipx;
373 sx = 240 - sx;
374 }
375
376 if (flip_screen_y())
377 {
378 flipy = !flipy;
379 sy = 240 - sy;
380 }
381
382 rect.set(
383 sx, sx + m_gfxdecode->gfx(1)->width() - 1,
384 sy, sy + m_gfxdecode->gfx(1)->height() - 1);
385 rect &= visarea;
386
387 // check collision sprite - sprite
388
389 m_helper.fill(0, rect);
390 m_helper2.fill(0, rect);
391
392 for (offs2 = m_spriteram.bytes() - 4; offs2 >= 0; offs2 -= 4)
393 if (offs != offs2)
394 {
395 int attr2 = spriteram[offs2 + 2];
396 int bank2 = (attr2 & 0x30) >> 4;
397 int coll2 = (attr2 & 0xc0) >> 6;
398 int code2 = (spriteram[offs2] & 0x3f) | (bank2 << 6);
399 int flipx2 = spriteram[offs2] & 0x40;
400 int flipy2 = spriteram[offs2] & 0x80;
401 int sx2 = spriteram[offs2 + 3] + 1;
402 int sy2 = 240 - spriteram[offs2 + 1];
403
404 if (coll2 != 0) continue;
405
406 code2 |= m_rougien_gfxbank1 * 0x2800;
407 code2 |= m_rougien_gfxbank2 * 0x2400;
408
409 if (flip_screen_x())
410 {
411 flipx2 = !flipx2;
412 sx2 = 240 - sx2;
413 }
414
415 if (flip_screen_y())
416 {
417 flipy2 = !flipy2;
418 sy2 = 240 - sy2;
419 }
420
421 m_gfxdecode->gfx(1)->transpen(m_helper,rect, code2, 0, flipx2, flipy2, sx2, sy2, 0);
422 }
423
424 m_gfxdecode->gfx(1)->transpen(m_helper2,rect, code, 0, flipx, flipy, sx, sy, 0);
425
426 m_coll_bit3 |= collision_check(rect);
427 }
428
429 // check for bit 6
430
431 for (offs = m_spriteram.bytes() - 4; offs >= 0; offs -= 4)
432 {
433 int attr = spriteram[offs + 2];
434 int bank = (attr & 0x30) >> 4;
435 int coll = (attr & 0xc0) >> 6;
436 int code = (spriteram[offs] & 0x3f) | (bank << 6);
437 int flipx = spriteram[offs] & 0x40;
438 int flipy = spriteram[offs] & 0x80;
439 int sx = spriteram[offs + 3] + 1;
440 int sy = 240 - spriteram[offs + 1];
441
442 rectangle rect;
443
444 if (coll != 1) continue;
445
446 code |= m_rougien_gfxbank1 * 0x2800;
447 code |= m_rougien_gfxbank2 * 0x2400;
448
449 if (flip_screen_x())
450 {
451 flipx = !flipx;
452 sx = 240 - sx;
453 }
454
455 if (flip_screen_y())
456 {
457 flipy = !flipy;
458 sy = 240 - sy;
459 }
460
461 rect.set(
462 sx, sx + m_gfxdecode->gfx(1)->width() - 1,
463 sy, sy + m_gfxdecode->gfx(1)->height() - 1);
464 rect &= visarea;
465
466 // check collision sprite - sprite
467
468 m_helper.fill(0, rect);
469 m_helper2.fill(0, rect);
470
471 for (offs2 = m_spriteram.bytes() - 4; offs2 >= 0; offs2 -= 4)
472 if (offs != offs2)
473 {
474 int attr2 = spriteram[offs2 + 2];
475 int bank2 = (attr2 & 0x30) >> 4;
476 int coll2 = (attr2 & 0xc0) >> 6;
477 int code2 = (spriteram[offs2] & 0x3f) | (bank2 << 6);
478 int flipx2 = spriteram[offs2] & 0x40;
479 int flipy2 = spriteram[offs2] & 0x80;
480 int sx2 = spriteram[offs2 + 3] + 1;
481 int sy2 = 240 - spriteram[offs2 + 1];
482
483 if (coll2 != 2) continue;
484
485 code2 |= m_rougien_gfxbank1 * 0x2800;
486 code2 |= m_rougien_gfxbank2 * 0x2400;
487
488 if (flip_screen_x())
489 {
490 flipx2 = !flipx2;
491 sx2 = 240 - sx2;
492 }
493
494 if (flip_screen_y())
495 {
496 flipy2 = !flipy2;
497 sy2 = 240 - sy2;
498 }
499
500 m_gfxdecode->gfx(1)->transpen(m_helper,rect, code2, 0, flipx2, flipy2, sx2, sy2, 0);
501 }
502
503 m_gfxdecode->gfx(1)->transpen(m_helper2,rect, code, 0, flipx, flipy, sx, sy, 0);
504
505 m_coll_bit6 |= collision_check(rect);
506 }
507 }
508
WRITE_LINE_MEMBER(mermaid_state::screen_vblank_mermaid)509 WRITE_LINE_MEMBER(mermaid_state::screen_vblank_mermaid)
510 {
511 // rising edge
512 if (state)
513 {
514 collision_update();
515
516 if (m_nmi_mask)
517 m_maincpu->set_input_line(INPUT_LINE_NMI, ASSERT_LINE);
518 }
519 }
520