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