diff --git a/BESS.md b/BESS.md index e040d90..7c9296e 100644 --- a/BESS.md +++ b/BESS.md @@ -89,7 +89,7 @@ The values of memory-mapped registers should be written 'as-is' to memory as if * Unused register bits have Don't-Care values which should be ignored * If the model is CGB or newer, the value of KEY0 (FF4C) must be valid as it determines DMG mode * Bit 2 determines DMG mode. A value of 0x04 usually denotes DMG mode, while a value of `0x80` usually denotes CGB mode. -* Sprite priority is derived from KEY0 (FF4C) instead of OPRI (FF6C) because OPRI can be modified after booting, but only the value of OPRI during boot ROM execution takes effect +* Object priority is derived from KEY0 (FF4C) instead of OPRI (FF6C) because OPRI can be modified after booting, but only the value of OPRI during boot ROM execution takes effect * If a register doesn't exist on the emulated model (For example, KEY0 (FF4C) on a DMG), its value should be ignored. * BANK (FF50) should be 0 if the boot ROM is still mapped, and 1 otherwise, and must be valid. * Implementations should not start a serial transfer when writing the value of SB diff --git a/Cocoa/Document.h b/Cocoa/Document.h index d6f89de..2cfaa87 100644 --- a/Cocoa/Document.h +++ b/Cocoa/Document.h @@ -30,7 +30,7 @@ @property (nonatomic, strong) IBOutlet NSPanel *vramWindow; @property (nonatomic, strong) IBOutlet NSTextField *vramStatusLabel; @property (nonatomic, strong) IBOutlet NSTableView *paletteTableView; -@property (nonatomic, strong) IBOutlet NSTableView *spritesTableView; +@property (nonatomic, strong) IBOutlet NSTableView *objectsTableView; @property (nonatomic, strong) IBOutlet NSPanel *printerFeedWindow; @property (nonatomic, strong) IBOutlet NSImageView *feedImageView; @property (nonatomic, strong) IBOutlet NSTextView *debuggerSideViewInput; diff --git a/Cocoa/Document.m b/Cocoa/Document.m index bb1fc6f..d539d7d 100644 --- a/Cocoa/Document.m +++ b/Cocoa/Document.m @@ -1466,7 +1466,7 @@ static unsigned *multiplication_table_for_frequency(unsigned frequency) dispatch_async(dispatch_get_main_queue(), ^{ if (!oamUpdating) { oamUpdating = true; - [self.spritesTableView reloadData]; + [self.objectsTableView reloadData]; oamUpdating = false; } }); @@ -1829,7 +1829,7 @@ static unsigned *multiplication_table_for_frequency(unsigned frequency) if (tableView == self.paletteTableView) { return 16; /* 8 BG palettes, 8 OBJ palettes*/ } - else if (tableView == self.spritesTableView) { + else if (tableView == self.objectsTableView) { return oamCount; } return 0; @@ -1848,7 +1848,7 @@ static unsigned *multiplication_table_for_frequency(unsigned frequency) uint16_t index = columnIndex - 1 + (row & 7) * 4; return @((palette_data[(index << 1) + 1] << 8) | palette_data[(index << 1)]); } - else if (tableView == self.spritesTableView) { + else if (tableView == self.objectsTableView) { switch (columnIndex) { case 0: return [Document imageFromData:[NSData dataWithBytesNoCopy:oamInfo[row].image @@ -1882,7 +1882,7 @@ static unsigned *multiplication_table_for_frequency(unsigned frequency) oamInfo[row].flags & 0x20? 'X' : '-', oamInfo[row].flags & 0x10? 1 : 0]; case 7: - return oamInfo[row].obscured_by_line_limit? @"Dropped: Too many sprites in line": @""; + return oamInfo[row].obscured_by_line_limit? @"Dropped: Too many objects in line": @""; } } @@ -1891,7 +1891,7 @@ static unsigned *multiplication_table_for_frequency(unsigned frequency) - (BOOL)tableView:(NSTableView *)tableView shouldSelectRow:(NSInteger)row { - return tableView == self.spritesTableView; + return tableView == self.objectsTableView; } - (BOOL)tableView:(NSTableView *)tableView shouldEditTableColumn:(nullable NSTableColumn *)tableColumn row:(NSInteger)row diff --git a/Cocoa/Document.xib b/Cocoa/Document.xib index c76c148..4c98007 100644 --- a/Cocoa/Document.xib +++ b/Cocoa/Document.xib @@ -25,10 +25,10 @@ + - @@ -502,7 +502,7 @@ - + @@ -770,7 +770,7 @@ - + diff --git a/Core/debugger.c b/Core/debugger.c index b8d88d7..2088ebd 100644 --- a/Core/debugger.c +++ b/Core/debugger.c @@ -1639,9 +1639,9 @@ static bool palettes(GB_gameboy_t *gb, char *arguments, char *modifiers, const d } } - GB_log(gb, "Sprites palettes: \n"); + GB_log(gb, "Object palettes: \n"); for (unsigned i = 0; i < 32; i++) { - GB_log(gb, "%04x ", ((uint16_t *)&gb->sprite_palettes_data)[i]); + GB_log(gb, "%04x ", ((uint16_t *)&gb->object_palettes_data)[i]); if (i % 4 == 3) { GB_log(gb, "\n"); } @@ -1659,7 +1659,7 @@ static bool lcd(GB_gameboy_t *gb, char *arguments, char *modifiers, const debugg } GB_log(gb, "LCDC:\n"); GB_log(gb, " LCD enabled: %s\n",(gb->io_registers[GB_IO_LCDC] & 128)? "Enabled" : "Disabled"); - GB_log(gb, " %s: %s\n", (gb->cgb_mode? "Sprite priority flags" : "Background and Window"), + GB_log(gb, " %s: %s\n", (gb->cgb_mode? "Object priority flags" : "Background and Window"), (gb->io_registers[GB_IO_LCDC] & 1)? "Enabled" : "Disabled"); GB_log(gb, " Objects: %s\n", (gb->io_registers[GB_IO_LCDC] & 2)? "Enabled" : "Disabled"); GB_log(gb, " Object size: %s\n", (gb->io_registers[GB_IO_LCDC] & 4)? "8x16" : "8x8"); diff --git a/Core/display.c b/Core/display.c index 6d54ec6..c859c33 100644 --- a/Core/display.c +++ b/Core/display.c @@ -85,7 +85,7 @@ static void fifo_overlay_object_row(GB_fifo_t *fifo, uint8_t lower, uint8_t uppe /* - Each line is 456 cycles. Without scrolling, sprites or a window: + Each line is 456 cycles. Without scrolling, objects or a window: Mode 2 - 80 cycles / OAM Transfer Mode 3 - 172 cycles / Rendering Mode 0 - 204 cycles / HBlank @@ -354,10 +354,10 @@ uint32_t GB_convert_rgb15(GB_gameboy_t *gb, uint16_t color, bool for_border) void GB_palette_changed(GB_gameboy_t *gb, bool background_palette, uint8_t index) { if (!gb->rgb_encode_callback || !GB_is_cgb(gb)) return; - uint8_t *palette_data = background_palette? gb->background_palettes_data : gb->sprite_palettes_data; + uint8_t *palette_data = background_palette? gb->background_palettes_data : gb->object_palettes_data; uint16_t color = palette_data[index & ~1] | (palette_data[index | 1] << 8); - (background_palette? gb->background_palettes_rgb : gb->sprite_palettes_rgb)[index / 2] = GB_convert_rgb15(gb, color, false); + (background_palette? gb->background_palettes_rgb : gb->object_palettes_rgb)[index / 2] = GB_convert_rgb15(gb, color, false); } void GB_set_color_correction_mode(GB_gameboy_t *gb, GB_color_correction_mode_t mode) @@ -623,7 +623,7 @@ static void render_pixel_if_possible(GB_gameboy_t *gb) *dest = gb->rgb_encode_callback(gb, 0, 0, 0); } else { - *dest = gb->sprite_palettes_rgb[oam_fifo_item->palette * 4 + pixel]; + *dest = gb->object_palettes_rgb[oam_fifo_item->palette * 4 + pixel]; } } @@ -1089,7 +1089,7 @@ void GB_display_run(GB_gameboy_t *gb, uint8_t cycles) gb->position_in_line = - (gb->io_registers[GB_IO_SCX] & 7) - 8; gb->lcd_x = 0; - gb->extra_penalty_for_sprite_at_0 = MIN((gb->io_registers[GB_IO_SCX] & 7), 5); + gb->extra_penalty_for_object_at_0 = MIN((gb->io_registers[GB_IO_SCX] & 7), 5); /* The actual rendering cycle */ gb->fetcher_state = 0; @@ -1160,7 +1160,7 @@ void GB_display_run(GB_gameboy_t *gb, uint8_t cycles) } /* Handle objects */ - /* When the sprite enabled bit is off, this proccess is skipped entirely on the DMG, but not on the CGB. + /* When the object enabled bit is off, this proccess is skipped entirely on the DMG, but not on the CGB. On the CGB, this bit is checked only when the pixel is actually popped from the FIFO. */ while (gb->n_visible_objs != 0 && @@ -1184,11 +1184,11 @@ void GB_display_run(GB_gameboy_t *gb, uint8_t cycles) } /* Todo: Measure if penalty occurs before or after waiting for the fetcher. */ - if (gb->extra_penalty_for_sprite_at_0 != 0) { + if (gb->extra_penalty_for_object_at_0 != 0) { if (gb->obj_comparators[gb->n_visible_objs - 1] == 0) { - gb->cycles_for_line += gb->extra_penalty_for_sprite_at_0; - GB_SLEEP(gb, display, 28, gb->extra_penalty_for_sprite_at_0); - gb->extra_penalty_for_sprite_at_0 = 0; + gb->cycles_for_line += gb->extra_penalty_for_object_at_0; + GB_SLEEP(gb, display, 28, gb->extra_penalty_for_object_at_0); + gb->extra_penalty_for_object_at_0 = 0; if (gb->object_fetch_aborted) { goto abort_fetching_object; } @@ -1466,7 +1466,7 @@ void GB_draw_tileset(GB_gameboy_t *gb, uint32_t *dest, GB_palette_type_t palette palette = gb->background_palettes_rgb + (4 * (palette_index & 7)); break; case GB_PALETTE_OAM: - palette = gb->sprite_palettes_rgb + (4 * (palette_index & 7)); + palette = gb->object_palettes_rgb + (4 * (palette_index & 7)); break; } @@ -1516,7 +1516,7 @@ void GB_draw_tilemap(GB_gameboy_t *gb, uint32_t *dest, GB_palette_type_t palette palette = gb->background_palettes_rgb + (4 * (palette_index & 7)); break; case GB_PALETTE_OAM: - palette = gb->sprite_palettes_rgb + (4 * (palette_index & 7)); + palette = gb->object_palettes_rgb + (4 * (palette_index & 7)); break; case GB_PALETTE_AUTO: break; @@ -1568,31 +1568,31 @@ void GB_draw_tilemap(GB_gameboy_t *gb, uint32_t *dest, GB_palette_type_t palette } } -uint8_t GB_get_oam_info(GB_gameboy_t *gb, GB_oam_info_t *dest, uint8_t *sprite_height) +uint8_t GB_get_oam_info(GB_gameboy_t *gb, GB_oam_info_t *dest, uint8_t *object_height) { uint8_t count = 0; - *sprite_height = (gb->io_registers[GB_IO_LCDC] & 4) ? 16:8; + *object_height = (gb->io_registers[GB_IO_LCDC] & 4) ? 16:8; uint8_t oam_to_dest_index[40] = {0,}; for (signed y = 0; y < LINES; y++) { - object_t *sprite = (object_t *) &gb->oam; - uint8_t sprites_in_line = 0; - for (uint8_t i = 0; i < 40; i++, sprite++) { - signed sprite_y = sprite->y - 16; + object_t *object = (object_t *) &gb->oam; + uint8_t objects_in_line = 0; + for (uint8_t i = 0; i < 40; i++, object++) { + signed object_y = object->y - 16; bool obscured = false; - // Is sprite not in this line? - if (sprite_y > y || sprite_y + *sprite_height <= y) continue; - if (++sprites_in_line == 11) obscured = true; + // Is object not in this line? + if (object_y > y || object_y + *object_height <= y) continue; + if (++objects_in_line == 11) obscured = true; GB_oam_info_t *info = NULL; if (!oam_to_dest_index[i]) { info = dest + count; oam_to_dest_index[i] = ++count; - info->x = sprite->x; - info->y = sprite->y; - info->tile = *sprite_height == 16? sprite->tile & 0xFE : sprite->tile; - info->flags = sprite->flags; + info->x = object->x; + info->y = object->y; + info->tile = *object_height == 16? object->tile & 0xFE : object->tile; + info->flags = object->flags; info->obscured_by_line_limit = false; - info->oam_addr = 0xFE00 + i * sizeof(*sprite); + info->oam_addr = 0xFE00 + i * sizeof(*object); } else { info = dest + oam_to_dest_index[i] - 1; @@ -1609,7 +1609,7 @@ uint8_t GB_get_oam_info(GB_gameboy_t *gb, GB_oam_info_t *dest, uint8_t *sprite_h vram_address += 0x2000; } - for (unsigned y = 0; y < *sprite_height; y++) { + for (unsigned y = 0; y < *object_height; y++) { unrolled for (unsigned x = 0; x < 8; x++) { uint8_t color = (((gb->vram[vram_address ] >> ((~x)&7)) & 1 ) | ((gb->vram[vram_address + 1] >> ((~x)&7)) & 1) << 1 ); @@ -1617,7 +1617,7 @@ uint8_t GB_get_oam_info(GB_gameboy_t *gb, GB_oam_info_t *dest, uint8_t *sprite_h if (!gb->cgb_mode) { color = (gb->io_registers[palette? GB_IO_OBP1:GB_IO_OBP0] >> (color << 1)) & 3; } - dest[i].image[((flags & 0x20)?7-x:x) + ((flags & 0x40)?*sprite_height - 1 -y:y) * 8] = gb->sprite_palettes_rgb[palette * 4 + color]; + dest[i].image[((flags & 0x20)?7-x:x) + ((flags & 0x40)?*object_height - 1 -y:y) * 8] = gb->object_palettes_rgb[palette * 4 + color]; } vram_address += 2; } diff --git a/Core/display.h b/Core/display.h index fdc855f..04b85b3 100644 --- a/Core/display.h +++ b/Core/display.h @@ -56,7 +56,7 @@ typedef enum { void GB_draw_tileset(GB_gameboy_t *gb, uint32_t *dest, GB_palette_type_t palette_type, uint8_t palette_index); void GB_draw_tilemap(GB_gameboy_t *gb, uint32_t *dest, GB_palette_type_t palette_type, uint8_t palette_index, GB_map_type_t map_type, GB_tileset_type_t tileset_type); -uint8_t GB_get_oam_info(GB_gameboy_t *gb, GB_oam_info_t *dest, uint8_t *sprite_height); +uint8_t GB_get_oam_info(GB_gameboy_t *gb, GB_oam_info_t *dest, uint8_t *object_height); uint32_t GB_convert_rgb15(GB_gameboy_t *gb, uint16_t color, bool for_border); void GB_set_color_correction_mode(GB_gameboy_t *gb, GB_color_correction_mode_t mode); void GB_set_light_temperature(GB_gameboy_t *gb, double temperature); diff --git a/Core/gb.c b/Core/gb.c index 1021dd9..ab35b78 100644 --- a/Core/gb.c +++ b/Core/gb.c @@ -1225,13 +1225,13 @@ static void update_dmg_palette(GB_gameboy_t *gb) { const GB_palette_t *palette = gb->dmg_palette ?: &GB_PALETTE_GREY; if (gb->rgb_encode_callback && !GB_is_cgb(gb)) { - gb->sprite_palettes_rgb[4] = gb->sprite_palettes_rgb[0] = gb->background_palettes_rgb[0] = + gb->object_palettes_rgb[4] = gb->object_palettes_rgb[0] = gb->background_palettes_rgb[0] = gb->rgb_encode_callback(gb, palette->colors[3].r, palette->colors[3].g, palette->colors[3].b); - gb->sprite_palettes_rgb[5] = gb->sprite_palettes_rgb[1] = gb->background_palettes_rgb[1] = + gb->object_palettes_rgb[5] = gb->object_palettes_rgb[1] = gb->background_palettes_rgb[1] = gb->rgb_encode_callback(gb, palette->colors[2].r, palette->colors[2].g, palette->colors[2].b); - gb->sprite_palettes_rgb[6] = gb->sprite_palettes_rgb[2] = gb->background_palettes_rgb[2] = + gb->object_palettes_rgb[6] = gb->object_palettes_rgb[2] = gb->background_palettes_rgb[2] = gb->rgb_encode_callback(gb, palette->colors[1].r, palette->colors[1].g, palette->colors[1].b); - gb->sprite_palettes_rgb[7] = gb->sprite_palettes_rgb[3] = gb->background_palettes_rgb[3] = + gb->object_palettes_rgb[7] = gb->object_palettes_rgb[3] = gb->background_palettes_rgb[3] = gb->rgb_encode_callback(gb, palette->colors[0].r, palette->colors[0].g, palette->colors[0].b); // LCD off color @@ -1537,7 +1537,7 @@ static void reset_ram(GB_gameboy_t *gb) if (GB_is_cgb(gb)) { for (unsigned i = 0; i < 64; i++) { gb->background_palettes_data[i] = GB_random(); /* Doesn't really matter as the boot ROM overrides it anyway*/ - gb->sprite_palettes_data[i] = GB_random(); + gb->object_palettes_data[i] = GB_random(); } for (unsigned i = 0; i < 32; i++) { GB_palette_changed(gb, true, i * 2); @@ -1733,9 +1733,9 @@ void *GB_get_direct_access(GB_gameboy_t *gb, GB_direct_access_t access, size_t * *bank = 0; return &gb->background_palettes_data; case GB_DIRECT_ACCESS_OBP: - *size = sizeof(gb->sprite_palettes_data); + *size = sizeof(gb->object_palettes_data); *bank = 0; - return &gb->sprite_palettes_data; + return &gb->object_palettes_data; case GB_DIRECT_ACCESS_IE: *size = sizeof(gb->interrupt_enable); *bank = 0; diff --git a/Core/gb.h b/Core/gb.h index e6b5f41..e5bb128 100644 --- a/Core/gb.h +++ b/Core/gb.h @@ -214,8 +214,8 @@ enum { /* CGB Paletts */ GB_IO_BGPI = 0x68, // CGB Mode Only - Background Palette Index GB_IO_BGPD = 0x69, // CGB Mode Only - Background Palette Data - GB_IO_OBPI = 0x6a, // CGB Mode Only - Sprite Palette Index - GB_IO_OBPD = 0x6b, // CGB Mode Only - Sprite Palette Data + GB_IO_OBPI = 0x6a, // CGB Mode Only - Object Palette Index + GB_IO_OBPD = 0x6b, // CGB Mode Only - Object Palette Data GB_IO_OPRI = 0x6c, // Affects object priority (X based or index based) /* Missing */ @@ -287,8 +287,8 @@ struct GB_watchpoint_s; typedef struct { uint8_t pixel; // Color, 0-3 uint8_t palette; // Palette, 0 - 7 (CGB); 0-1 in DMG (or just 0 for BG) - uint8_t priority; // Sprite priority – 0 in DMG, OAM index in CGB - bool bg_priority; // For sprite FIFO – the BG priority bit. For the BG FIFO – the CGB attributes priority bit + uint8_t priority; // Object priority – 0 in DMG, OAM index in CGB + bool bg_priority; // For object FIFO – the BG priority bit. For the BG FIFO – the CGB attributes priority bit } GB_fifo_item_t; #define GB_FIFO_LENGTH 16 @@ -536,7 +536,7 @@ struct GB_gameboy_internal_s { bool cgb_vram_bank; uint8_t oam[0xA0]; uint8_t background_palettes_data[0x40]; - uint8_t sprite_palettes_data[0x40]; + uint8_t object_palettes_data[0x40]; uint8_t position_in_line; bool stat_interrupt_line; uint8_t effective_scx; @@ -575,7 +575,7 @@ struct GB_gameboy_internal_s { uint8_t n_visible_objs; uint8_t oam_search_index; uint8_t accessed_oam_row; - uint8_t extra_penalty_for_sprite_at_0; + uint8_t extra_penalty_for_object_at_0; uint8_t mode_for_interrupt; bool lyc_interrupt_line; bool cgb_palettes_blocked; @@ -620,7 +620,7 @@ struct GB_gameboy_internal_s { /* I/O */ uint32_t *screen; uint32_t background_palettes_rgb[0x20]; - uint32_t sprite_palettes_rgb[0x20]; + uint32_t object_palettes_rgb[0x20]; const GB_palette_t *dmg_palette; GB_color_correction_mode_t color_correction_mode; double light_temperature; diff --git a/Core/memory.c b/Core/memory.c index de2124c..7ca770a 100644 --- a/Core/memory.c +++ b/Core/memory.c @@ -625,7 +625,7 @@ static uint8_t read_high_memory(GB_gameboy_t *gb, uint16_t addr) uint8_t index_reg = (addr & 0xFF) - 1; return ((addr & 0xFF) == GB_IO_BGPD? gb->background_palettes_data : - gb->sprite_palettes_data)[gb->io_registers[index_reg] & 0x3F]; + gb->object_palettes_data)[gb->io_registers[index_reg] & 0x3F]; } case GB_IO_KEY1: @@ -1453,7 +1453,7 @@ static void write_high_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value) } ((addr & 0xFF) == GB_IO_BGPD? gb->background_palettes_data : - gb->sprite_palettes_data)[gb->io_registers[index_reg] & 0x3F] = value; + gb->object_palettes_data)[gb->io_registers[index_reg] & 0x3F] = value; GB_palette_changed(gb, (addr & 0xFF) == GB_IO_BGPD, gb->io_registers[index_reg] & 0x3F); if (gb->io_registers[index_reg] & 0x80) { gb->io_registers[index_reg]++; diff --git a/Core/save_state.c b/Core/save_state.c index eefdd08..4dc304e 100644 --- a/Core/save_state.c +++ b/Core/save_state.c @@ -67,7 +67,7 @@ typedef struct __attribute__((packed)) { BESS_buffer_t oam; BESS_buffer_t hram; BESS_buffer_t background_palettes; - BESS_buffer_t sprite_palettes; + BESS_buffer_t object_palettes; } BESS_CORE_t; typedef struct __attribute__((packed)) { @@ -604,8 +604,8 @@ static int save_state_internal(GB_gameboy_t *gb, virtual_file_t *file, bool appe if (GB_is_cgb(gb)) { bess_core.background_palettes.size = LE32(sizeof(gb->background_palettes_data)); bess_core.background_palettes.offset = LE32(video_offset + offsetof(GB_gameboy_t, background_palettes_data) - GB_SECTION_OFFSET(video)); - bess_core.sprite_palettes.size = LE32(sizeof(gb->sprite_palettes_data)); - bess_core.sprite_palettes.offset = LE32(video_offset + offsetof(GB_gameboy_t, sprite_palettes_data) - GB_SECTION_OFFSET(video)); + bess_core.object_palettes.size = LE32(sizeof(gb->object_palettes_data)); + bess_core.object_palettes.offset = LE32(video_offset + offsetof(GB_gameboy_t, object_palettes_data) - GB_SECTION_OFFSET(video)); } if (file->write(file, &bess_core, sizeof(bess_core)) != sizeof(bess_core)) { @@ -1088,7 +1088,7 @@ done: read_bess_buffer(&core.oam, file, gb->oam, sizeof(gb->oam)); read_bess_buffer(&core.hram, file, gb->hram, sizeof(gb->hram)); read_bess_buffer(&core.background_palettes, file, gb->background_palettes_data, sizeof(gb->background_palettes_data)); - read_bess_buffer(&core.sprite_palettes, file, gb->sprite_palettes_data, sizeof(gb->sprite_palettes_data)); + read_bess_buffer(&core.object_palettes, file, gb->object_palettes_data, sizeof(gb->object_palettes_data)); if (gb->sgb) { memset(gb->sgb, 0, sizeof(*gb->sgb)); GB_sgb_load_default_data(gb); diff --git a/Core/sm83_cpu.c b/Core/sm83_cpu.c index 85db7ae..035779b 100644 --- a/Core/sm83_cpu.c +++ b/Core/sm83_cpu.c @@ -198,7 +198,7 @@ static void cycle_write(GB_gameboy_t *gb, uint16_t addr, uint8_t value) /* Similar to the palette registers, these interact directly with the LCD, so they appear to be affected by it. Both my DMG (B, blob) and Game Boy Light behave this way though. Additionally, LCDC.1 is very nasty because on the it is read both by the FIFO when popping pixels, - and the sprite-fetching state machine, and both behave differently when it comes to access conflicts. + and the object-fetching state machine, and both behave differently when it comes to access conflicts. Hacks ahead. */