Remove unused map environment with index 0 (#7), Implement function to draw the overworld textbox (#10)
@ -19,7 +19,7 @@ DEF MAP_LENGTH EQU _RS
|
|||||||
|
|
||||||
; map environments (wEnvironment)
|
; map environments (wEnvironment)
|
||||||
; EnvironmentColorsPointers indexes (see data/maps/environment_colors.asm)
|
; EnvironmentColorsPointers indexes (see data/maps/environment_colors.asm)
|
||||||
const_def 1
|
const_def
|
||||||
const OUTDOOR_GRASSY
|
const OUTDOOR_GRASSY
|
||||||
const OUTDOOR_MOUNTAIN
|
const OUTDOOR_MOUNTAIN
|
||||||
const OUTDOOR_COAST
|
const OUTDOOR_COAST
|
||||||
@ -29,9 +29,9 @@ DEF INDOOR_ENVIRONMENT EQU const_value
|
|||||||
const INDOOR_CAVE
|
const INDOOR_CAVE
|
||||||
const INDOOR_ICE_CAVE
|
const INDOOR_ICE_CAVE
|
||||||
const INDOOR_BUILDING
|
const INDOOR_BUILDING
|
||||||
DEF NUM_ENVIRONMENTS EQU const_value - 1
|
DEF NUM_ENVIRONMENTS EQU const_value
|
||||||
|
|
||||||
; map palettes (wEnvironment)
|
; map palettes (wMapTimeOfDay)
|
||||||
const_def
|
const_def
|
||||||
const PALETTE_AUTO
|
const PALETTE_AUTO
|
||||||
const PALETTE_DAY
|
const PALETTE_DAY
|
||||||
|
@ -32,6 +32,7 @@ DEF TEXTBOX_INNERY EQU TEXTBOX_Y + 2
|
|||||||
|
|
||||||
; see gfx/frames/*.png
|
; see gfx/frames/*.png
|
||||||
DEF TEXTBOX_FRAME_TILES EQU 6
|
DEF TEXTBOX_FRAME_TILES EQU 6
|
||||||
|
DEF OW_TEXTBOX_FRAME_TILES EQU 14
|
||||||
|
|
||||||
; PrintNum bit flags
|
; PrintNum bit flags
|
||||||
const_def 5
|
const_def 5
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
EnvironmentColorsPointers:
|
EnvironmentColorsPointers:
|
||||||
; entries correspond to environment constants (see constants/map_data_constants.asm)
|
; entries correspond to environment constants (see constants/map_data_constants.asm)
|
||||||
table_width 2, EnvironmentColorsPointers
|
table_width 2, EnvironmentColorsPointers
|
||||||
dw .GrassyColors ; unused
|
|
||||||
dw .GrassyColors ; OUTDOOR_GRASSY
|
dw .GrassyColors ; OUTDOOR_GRASSY
|
||||||
dw .MountainColors ; OUTDOOR_MOUNTAIN
|
dw .MountainColors ; OUTDOOR_MOUNTAIN
|
||||||
dw .CoastColors ; OUTDOOR_COAST
|
dw .CoastColors ; OUTDOOR_COAST
|
||||||
@ -10,7 +9,7 @@ EnvironmentColorsPointers:
|
|||||||
dw .CaveColors ; INDOOR_CAVE
|
dw .CaveColors ; INDOOR_CAVE
|
||||||
dw .IceCaveColors ; INDOOR_ICE_CAVE
|
dw .IceCaveColors ; INDOOR_ICE_CAVE
|
||||||
dw .BuildingColors ; INDOOR_BUILDING
|
dw .BuildingColors ; INDOOR_BUILDING
|
||||||
assert_table_length NUM_ENVIRONMENTS + 1
|
assert_table_length NUM_ENVIRONMENTS
|
||||||
|
|
||||||
; Valid indices: $00 - $35 (see gfx/tilesets/bg_tiles.pal)
|
; Valid indices: $00 - $35 (see gfx/tilesets/bg_tiles.pal)
|
||||||
; assumes that maps with an environment of INDOOR_CAVE and INDOOR_ICE_CAVE always have PALETTE_NITE
|
; assumes that maps with an environment of INDOOR_CAVE and INDOOR_ICE_CAVE always have PALETTE_NITE
|
||||||
|
@ -620,7 +620,7 @@ FlyFunction:
|
|||||||
farcall RespawnPlayer
|
farcall RespawnPlayer
|
||||||
call DelayFrame
|
call DelayFrame
|
||||||
call UpdatePlayerSprite
|
call UpdatePlayerSprite
|
||||||
farcall LoadOverworldFont
|
call LoadOverworldFontAndFrame
|
||||||
ret
|
ret
|
||||||
|
|
||||||
WaterfallFunction:
|
WaterfallFunction:
|
||||||
|
@ -633,7 +633,7 @@ LoadMapPals:
|
|||||||
|
|
||||||
; Which palette group is based on whether we're outside or inside
|
; Which palette group is based on whether we're outside or inside
|
||||||
ld a, [wEnvironment]
|
ld a, [wEnvironment]
|
||||||
maskbits NUM_ENVIRONMENTS + 1
|
maskbits NUM_ENVIRONMENTS
|
||||||
ld e, a
|
ld e, a
|
||||||
ld d, 0
|
ld d, 0
|
||||||
ld hl, EnvironmentColorsPointers
|
ld hl, EnvironmentColorsPointers
|
||||||
|
@ -44,7 +44,7 @@ _LoadFrame::
|
|||||||
ld hl, vTiles0 tile "┌" ; $f0
|
ld hl, vTiles0 tile "┌" ; $f0
|
||||||
lb bc, BANK(Frames), TEXTBOX_FRAME_TILES ; "┌" to "┘"
|
lb bc, BANK(Frames), TEXTBOX_FRAME_TILES ; "┌" to "┘"
|
||||||
call Get1bppViaHDMA
|
call Get1bppViaHDMA
|
||||||
ld hl, vTiles2 tile " " ; $f5
|
ld hl, vTiles2 tile " " ; $7f
|
||||||
ld de, TextboxSpaceGFX
|
ld de, TextboxSpaceGFX
|
||||||
lb bc, BANK(TextboxSpaceGFX), 1
|
lb bc, BANK(TextboxSpaceGFX), 1
|
||||||
call Get1bppViaHDMA
|
call Get1bppViaHDMA
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
LoadOverworldFont::
|
_LoadOverworldFontAndFrame::
|
||||||
ld de, .OverworldFontGFX
|
ld de, .OverworldFontGFX
|
||||||
ld hl, vTiles1
|
ld hl, vTiles1
|
||||||
lb bc, BANK(.OverworldFontGFX), 112
|
lb bc, BANK(.OverworldFontGFX), 112
|
||||||
@ -7,6 +7,16 @@ LoadOverworldFont::
|
|||||||
ld hl, vTiles2 tile " "
|
ld hl, vTiles2 tile " "
|
||||||
lb bc, BANK(.OverworldFontSpaceGFX), 1
|
lb bc, BANK(.OverworldFontSpaceGFX), 1
|
||||||
call Get2bpp
|
call Get2bpp
|
||||||
|
ld a, [wEnvironment]
|
||||||
|
maskbits NUM_ENVIRONMENTS
|
||||||
|
ld bc, OW_TEXTBOX_FRAME_TILES * LEN_2BPP_TILE
|
||||||
|
ld hl, .OverworldFrames
|
||||||
|
call AddNTimes
|
||||||
|
ld d, h
|
||||||
|
ld e, l
|
||||||
|
ld hl, vTiles0 tile "┌" ; $f0
|
||||||
|
lb bc, BANK(.OverworldFrames), OW_TEXTBOX_FRAME_TILES
|
||||||
|
call Get2bpp
|
||||||
ret
|
ret
|
||||||
|
|
||||||
.OverworldFontGFX:
|
.OverworldFontGFX:
|
||||||
@ -14,3 +24,15 @@ INCBIN "gfx/font/overworld.2bpp"
|
|||||||
|
|
||||||
.OverworldFontSpaceGFX:
|
.OverworldFontSpaceGFX:
|
||||||
INCBIN "gfx/font/overworld_space.2bpp"
|
INCBIN "gfx/font/overworld_space.2bpp"
|
||||||
|
|
||||||
|
.OverworldFrames:
|
||||||
|
table_width OW_TEXTBOX_FRAME_TILES * LEN_2BPP_TILE, .OverworldFrames
|
||||||
|
INCBIN "gfx/frames/ow1.2bpp"
|
||||||
|
INCBIN "gfx/frames/ow2.2bpp"
|
||||||
|
INCBIN "gfx/frames/ow3.2bpp"
|
||||||
|
INCBIN "gfx/frames/ow4.2bpp"
|
||||||
|
INCBIN "gfx/frames/ow5.2bpp"
|
||||||
|
INCBIN "gfx/frames/ow6.2bpp"
|
||||||
|
INCBIN "gfx/frames/ow7.2bpp"
|
||||||
|
INCBIN "gfx/frames/ow8.2bpp"
|
||||||
|
assert_table_length NUM_ENVIRONMENTS
|
161
engine/gfx/overworld_textbox.asm
Executable file
@ -0,0 +1,161 @@
|
|||||||
|
const_def "┌" ; $f0
|
||||||
|
const OW_TEXTBOX_FRAME_WHITE
|
||||||
|
const OW_TEXTBOX_FRAME_TOP_LEFT_CORNER
|
||||||
|
const OW_TEXTBOX_FRAME_TOP_2
|
||||||
|
const OW_TEXTBOX_FRAME_TOP_1
|
||||||
|
const OW_TEXTBOX_FRAME_TOP_RIGHT_CORNER
|
||||||
|
const OW_TEXTBOX_FRAME_LEFT_1
|
||||||
|
const OW_TEXTBOX_FRAME_LEFT_2
|
||||||
|
const OW_TEXTBOX_FRAME_BOTTOM_LEFT_CORNER
|
||||||
|
const OW_TEXTBOX_FRAME_BOTTOM_2
|
||||||
|
const OW_TEXTBOX_FRAME_BOTTOM_1
|
||||||
|
const OW_TEXTBOX_FRAME_BOTTOM_RIGHT_CORNER
|
||||||
|
const OW_TEXTBOX_FRAME_RIGHT_1
|
||||||
|
const OW_TEXTBOX_FRAME_RIGHT_2
|
||||||
|
const OW_TEXTBOX_FRAME_BACKGROUND
|
||||||
|
|
||||||
|
OW_TEXTBOX_FRAME_MIN_HEIGHT EQU 4
|
||||||
|
OW_TEXTBOX_FRAME_MIN_WIDTH EQU 6
|
||||||
|
|
||||||
|
OverworldTextbox::
|
||||||
|
; Draw a textbox at de with room for b rows and c columns using the 2bpp overworld frame tiles.
|
||||||
|
ld a, b
|
||||||
|
cp OW_TEXTBOX_FRAME_MIN_HEIGHT - 2
|
||||||
|
jr nc, .got_height
|
||||||
|
ld b, OW_TEXTBOX_FRAME_MIN_HEIGHT - 2
|
||||||
|
.got_height
|
||||||
|
ld a, c
|
||||||
|
cp OW_TEXTBOX_FRAME_MIN_WIDTH - 2
|
||||||
|
jr nc, .got_width
|
||||||
|
ld c, OW_TEXTBOX_FRAME_MIN_WIDTH - 2
|
||||||
|
.got_width
|
||||||
|
ld h, d
|
||||||
|
ld l, e
|
||||||
|
; top row
|
||||||
|
ld [hl], OW_TEXTBOX_FRAME_TOP_LEFT_CORNER
|
||||||
|
inc hl
|
||||||
|
ld e, 0
|
||||||
|
call .GetTileArrangementPointer
|
||||||
|
call .CopyHorizontalTiles
|
||||||
|
ld [hl], OW_TEXTBOX_FRAME_TOP_RIGHT_CORNER
|
||||||
|
; left column
|
||||||
|
inc hl
|
||||||
|
push hl
|
||||||
|
ld e, 4
|
||||||
|
call .GetTileArrangementPointer
|
||||||
|
call .CopyVerticalTiles
|
||||||
|
pop hl
|
||||||
|
; right column
|
||||||
|
push hl
|
||||||
|
ld de, SCREEN_WIDTH - 1
|
||||||
|
add hl, de
|
||||||
|
ld e, 6
|
||||||
|
call .GetTileArrangementPointer
|
||||||
|
call .CopyVerticalTiles
|
||||||
|
; bottom row
|
||||||
|
; we are in the bottom right corner, so first go back to the start of the line
|
||||||
|
ld de, -(SCREEN_WIDTH - 1)
|
||||||
|
add hl, de
|
||||||
|
ld [hl], OW_TEXTBOX_FRAME_BOTTOM_LEFT_CORNER
|
||||||
|
inc hl
|
||||||
|
ld e, 2
|
||||||
|
call .GetTileArrangementPointer
|
||||||
|
call .CopyHorizontalTiles
|
||||||
|
ld [hl], OW_TEXTBOX_FRAME_BOTTOM_RIGHT_CORNER
|
||||||
|
; background
|
||||||
|
pop hl
|
||||||
|
inc hl
|
||||||
|
ld a, OW_TEXTBOX_FRAME_BACKGROUND
|
||||||
|
jp FillBoxWithByte
|
||||||
|
|
||||||
|
.CopyHorizontalTiles:
|
||||||
|
; copy horizontally c tiles from the ow_textbox_tiles pattern at de to hl
|
||||||
|
push bc
|
||||||
|
push de
|
||||||
|
.loop_h
|
||||||
|
ld a, [de]
|
||||||
|
cp -1
|
||||||
|
jr nz, .next_h
|
||||||
|
pop de
|
||||||
|
ld a, [de]
|
||||||
|
push de
|
||||||
|
.next_h
|
||||||
|
ld [hli], a
|
||||||
|
inc de
|
||||||
|
dec c
|
||||||
|
jr nz, .loop_h
|
||||||
|
pop de
|
||||||
|
pop bc
|
||||||
|
ret
|
||||||
|
|
||||||
|
.CopyVerticalTiles:
|
||||||
|
; copy vertically b tiles from the ow_textbox_tiles pattern at de to hl
|
||||||
|
push bc
|
||||||
|
push de
|
||||||
|
.loop_v
|
||||||
|
ld a, [de]
|
||||||
|
cp -1
|
||||||
|
jr nz, .next_v
|
||||||
|
pop de
|
||||||
|
ld a, [de]
|
||||||
|
push de
|
||||||
|
.next_v
|
||||||
|
ld [hl], a
|
||||||
|
push bc
|
||||||
|
ld bc, SCREEN_WIDTH
|
||||||
|
add hl, bc
|
||||||
|
pop bc
|
||||||
|
inc de
|
||||||
|
dec b
|
||||||
|
jr nz, .loop_v
|
||||||
|
pop de
|
||||||
|
pop bc
|
||||||
|
ret
|
||||||
|
|
||||||
|
.GetTileArrangementPointer:
|
||||||
|
; return de pointing to an address from .TileArrangementPointers according to wEnvironment and offset in e
|
||||||
|
push hl
|
||||||
|
push bc
|
||||||
|
ld a, [wEnvironment]
|
||||||
|
maskbits NUM_ENVIRONMENTS
|
||||||
|
ld hl, .TileArrangementPointers
|
||||||
|
ld d, 0
|
||||||
|
add hl, de
|
||||||
|
ld bc, 2 * 4
|
||||||
|
call AddNTimes
|
||||||
|
ld a, [hli]
|
||||||
|
ld d, [hl]
|
||||||
|
ld e, a
|
||||||
|
pop bc
|
||||||
|
pop hl
|
||||||
|
ret
|
||||||
|
|
||||||
|
MACRO ow_textbox_tiles
|
||||||
|
rept _NARG
|
||||||
|
db OW_TEXTBOX_FRAME_\1
|
||||||
|
shift
|
||||||
|
endr
|
||||||
|
db -1
|
||||||
|
ENDM
|
||||||
|
|
||||||
|
.TileArrangementPointers:
|
||||||
|
; entries correspond to environment constants (see constants/map_data_constants.asm)
|
||||||
|
table_width 2 * 4, .TileArrangementPointers
|
||||||
|
dw .TilesTop1, .TilesBottom1, .TilesLeft1, .TilesRight1 ; OUTDOOR_GRASSY
|
||||||
|
dw .TilesTop1, .TilesBottom1, .TilesLeft1, .TilesRight1 ; OUTDOOR_MOUNTAIN
|
||||||
|
dw .TilesTop1, .TilesBottom1, .TilesLeft1, .TilesRight1 ; OUTDOOR_COAST
|
||||||
|
dw .TilesTop1, .TilesBottom1, .TilesLeft1, .TilesRight1 ; OUTDOOR_SEA
|
||||||
|
dw .TilesTop1, .TilesBottom1, .TilesLeft1, .TilesRight1 ; INDOOR_FOREST
|
||||||
|
dw .TilesTop1, .TilesBottom1, .TilesLeft1, .TilesRight1 ; INDOOR_CAVE
|
||||||
|
dw .TilesTop1, .TilesBottom1, .TilesLeft1, .TilesRight1 ; INDOOR_ICE_CAVE
|
||||||
|
dw .TilesTop1, .TilesBottom1, .TilesLeft1, .TilesRight1 ; INDOOR_BUILDING
|
||||||
|
assert_table_length NUM_ENVIRONMENTS
|
||||||
|
|
||||||
|
.TilesTop1:
|
||||||
|
ow_textbox_tiles TOP_1, TOP_1, TOP_2, TOP_2
|
||||||
|
.TilesBottom1:
|
||||||
|
ow_textbox_tiles BOTTOM_1, BOTTOM_1, BOTTOM_2, BOTTOM_2
|
||||||
|
.TilesLeft1:
|
||||||
|
ow_textbox_tiles LEFT_1, LEFT_2
|
||||||
|
.TilesRight1:
|
||||||
|
ow_textbox_tiles RIGHT_1, RIGHT_2
|
@ -2201,9 +2201,6 @@ Script_writeunusedbyte:
|
|||||||
ld [wUnusedScriptByte], a
|
ld [wUnusedScriptByte], a
|
||||||
ret
|
ret
|
||||||
|
|
||||||
UnusedClosetextScript: ; unreferenced
|
|
||||||
closetext
|
|
||||||
|
|
||||||
Script_closetext:
|
Script_closetext:
|
||||||
call _OpenAndCloseMenu_HDMATransferTilemapAndAttrmap
|
call _OpenAndCloseMenu_HDMATransferTilemapAndAttrmap
|
||||||
call CloseText
|
call CloseText
|
||||||
|
@ -288,7 +288,7 @@ LoadMapGraphics:
|
|||||||
ldh [hTileAnimFrame], a
|
ldh [hTileAnimFrame], a
|
||||||
farcall RefreshSprites
|
farcall RefreshSprites
|
||||||
call LoadFrame
|
call LoadFrame
|
||||||
farcall LoadOverworldFont
|
call LoadOverworldFontAndFrame
|
||||||
ret
|
ret
|
||||||
|
|
||||||
LoadMapPalettes:
|
LoadMapPalettes:
|
||||||
|
@ -1537,22 +1537,6 @@ endr
|
|||||||
dbsprite 19, 4, 0, 7, $07, 0
|
dbsprite 19, 4, 0, 7, $07, 0
|
||||||
db -1
|
db -1
|
||||||
|
|
||||||
BillsPC_FillBox: ; unreferenced
|
|
||||||
.row
|
|
||||||
push bc
|
|
||||||
push hl
|
|
||||||
.col
|
|
||||||
ld [hli], a
|
|
||||||
dec c
|
|
||||||
jr nz, .col
|
|
||||||
pop hl
|
|
||||||
ld bc, SCREEN_WIDTH
|
|
||||||
add hl, bc
|
|
||||||
pop bc
|
|
||||||
dec b
|
|
||||||
jr nz, .row
|
|
||||||
ret
|
|
||||||
|
|
||||||
BillsPC_CheckSpaceInDestination:
|
BillsPC_CheckSpaceInDestination:
|
||||||
; If moving within a box, no need to be here.
|
; If moving within a box, no need to be here.
|
||||||
ld hl, wBillsPC_LoadedBox
|
ld hl, wBillsPC_LoadedBox
|
||||||
|
BIN
gfx/frames/ow2.png
Normal file
After Width: | Height: | Size: 169 B |
BIN
gfx/frames/ow3.png
Normal file
After Width: | Height: | Size: 169 B |
BIN
gfx/frames/ow4.png
Normal file
After Width: | Height: | Size: 169 B |
BIN
gfx/frames/ow5.png
Normal file
After Width: | Height: | Size: 169 B |
BIN
gfx/frames/ow6.png
Normal file
After Width: | Height: | Size: 169 B |
BIN
gfx/frames/ow7.png
Normal file
After Width: | Height: | Size: 169 B |
BIN
gfx/frames/ow8.png
Normal file
After Width: | Height: | Size: 169 B |
@ -48,6 +48,10 @@ LoadFrame::
|
|||||||
farcall _LoadFrame
|
farcall _LoadFrame
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
LoadOverworldFontAndFrame::
|
||||||
|
farcall _LoadOverworldFontAndFrame
|
||||||
|
ret
|
||||||
|
|
||||||
DecompressRequest2bpp::
|
DecompressRequest2bpp::
|
||||||
push de
|
push de
|
||||||
ld a, BANK(sScratch)
|
ld a, BANK(sScratch)
|
||||||
|
@ -127,6 +127,14 @@ SpeechTextbox::
|
|||||||
ld b, TEXTBOX_INNERH
|
ld b, TEXTBOX_INNERH
|
||||||
ld c, TEXTBOX_INNERW
|
ld c, TEXTBOX_INNERW
|
||||||
jp Textbox
|
jp Textbox
|
||||||
|
; decoord TEXTBOX_X, TEXTBOX_Y
|
||||||
|
; lb bc, 4, SCREEN_WIDTH - 2
|
||||||
|
; push bc
|
||||||
|
; push de
|
||||||
|
; farcall OverworldTextbox
|
||||||
|
; pop hl
|
||||||
|
; pop bc
|
||||||
|
; jp TextboxPalette
|
||||||
|
|
||||||
RadioTerminator::
|
RadioTerminator::
|
||||||
ld hl, .stop
|
ld hl, .stop
|
||||||
|
@ -129,8 +129,6 @@ UpdateBGMap::
|
|||||||
jr z, .Attr
|
jr z, .Attr
|
||||||
|
|
||||||
; BG Map 1
|
; BG Map 1
|
||||||
dec a ; useless
|
|
||||||
|
|
||||||
ldh a, [hBGMapAddress]
|
ldh a, [hBGMapAddress]
|
||||||
ld l, a
|
ld l, a
|
||||||
ldh a, [hBGMapAddress + 1]
|
ldh a, [hBGMapAddress + 1]
|
||||||
|
@ -41,7 +41,7 @@ CloseText::
|
|||||||
call UpdatePlayerSprite
|
call UpdatePlayerSprite
|
||||||
xor a
|
xor a
|
||||||
ldh [hBGMapMode], a
|
ldh [hBGMapMode], a
|
||||||
farcall LoadOverworldFont
|
call LoadOverworldFontAndFrame
|
||||||
ret
|
ret
|
||||||
|
|
||||||
OpenText::
|
OpenText::
|
||||||
|
1
main.asm
@ -385,6 +385,7 @@ INCLUDE "gfx/emotes.asm"
|
|||||||
INCLUDE "engine/overworld/warp_connection.asm"
|
INCLUDE "engine/overworld/warp_connection.asm"
|
||||||
INCLUDE "engine/battle/used_move_text.asm"
|
INCLUDE "engine/battle/used_move_text.asm"
|
||||||
INCLUDE "engine/gfx/load_overworld_font.asm"
|
INCLUDE "engine/gfx/load_overworld_font.asm"
|
||||||
|
INCLUDE "engine/gfx/overworld_textbox.asm"
|
||||||
|
|
||||||
|
|
||||||
SECTION "Title", ROMX
|
SECTION "Title", ROMX
|
||||||
|
@ -966,15 +966,7 @@ wAttrmap::
|
|||||||
ds SCREEN_WIDTH * SCREEN_HEIGHT
|
ds SCREEN_WIDTH * SCREEN_HEIGHT
|
||||||
wAttrmapEnd::
|
wAttrmapEnd::
|
||||||
|
|
||||||
UNION
|
|
||||||
; addresses dealing with serial comms
|
|
||||||
wcf42:: db
|
|
||||||
wcf44:: db
|
|
||||||
wcf45:: db
|
|
||||||
|
|
||||||
NEXTU
|
|
||||||
wTileAnimBuffer:: ds 1 tiles
|
wTileAnimBuffer:: ds 1 tiles
|
||||||
ENDU
|
|
||||||
|
|
||||||
; link data
|
; link data
|
||||||
UNION
|
UNION
|
||||||
|