Traditional Japanese Script Functions

Joined
Jun 10, 2021
Posts
5
Hello! I'm new to these forums and to Neo Geo Development. A good friend of mine who is a huge Neo Geo enthusiast was telling me all about the system. Until that point I didn't know much about the Neo Geo, I first heard about it when its games were ported to the Wii in the late 2000s. Not being a huge fan of tournament fighters (I like them more now but I'm still bad at them) I mostly wrote the system off as "just a bunch of fighting games" and hadn't actually given them a proper look. My opinion has most definitely changed, however, as I've played games like Super Spy and Magician Lord and was very impressed with the graphics. They were quite incredible for their time and still hold up today.

Anyhow, recently I got on the retro game development train thanks to NESMaker and was trying to make an NES game. Progress was decent and I'm pretty well-versed in 6502 but I was (and still am) eternally frustrated by the difficulty in coding for the system. After trying out the NEOGEO for a bit, and getting over the initial difficulty in creating XML and C1/C2 files, I find the system much easier to work with, in spite of its less robust development tools. So for the time being I'm taking a break from the NES and want to work on the NEOGEO for now. I'd like to share a mini-project that I'm quite proud of (I don't know any C, this was all done with assembly.)


I'm trying to make a ninja game for the Neo Geo so I thought it would be cool if the intro cutscene had a letter written in traditional Japanese style (writing top to bottom, right to left.) The NEOGEO has a built-in Japanese font that makes this pretty easy.

konnichiwa_sekai.PNG

The source code for this looks like absolute spaghetti, it's difficult to follow and I plan on cleaning that up. I'm sure there are improvements to the structure that I could make. I was going to post it below but the formatting is all wrong and nothing is on its own line :(

Edit: It actually works fine when pasting directly from Notepad++ rather than another forum. Go figure. Source code is below, please give me credit if you use it. :)

Edit 2: I used a few macros of my own creation, I'll list what they are below:

pushall = movem.l d0-d7/a0-a6,-(sp)
popall = movem.l (sp)+,d0-d7/a0-a6
ClearDataRegs = CLR.L D0 CLR.L D1 CLR.L D2 CLR.L D3 CLR.L D4 CLR.L D5 CLR.L D6 CLR.L D7
 
Last edited:
Joined
Jun 10, 2021
Posts
5
; JAPANESE STYLE TEXT WRITING
; USES FIX LAYER
; GOES TOP TO BOTTOM, RIGHT TO LEFT.


; THE NEOGEO MAKES VERTICAL WRITING EASY BECAUSE YOU CAN INCREMENT VRAM
; BY ONE TO GET TO THE NEXT CHARACTER.

; THE BAD NEWS IS THAT WRAPPING AROUND 1F TO 20 GOES ONE COLUMN RIGHT,
; NOT LEFT. WHICH DOESN'T WORK WITH WHAT WE'RE TRYING TO DO HERE.

; ALSO JAPANESE TEXT IS A LITTLE BIT TRICKY ON THE NEOGEO SINCE IT DOESN'T USE ASCII.
; JAPANESE TEXT STARTS AT $0180 IN 202_S1.S1


JapaneseScript:
pushall
; GOAL: WRITE A SYLLABLE, MOVE VRAM TO THE RIGHT OF IT, WRITE MODIFIER (IF ANY), MOVE DOWN, REPEAT.
; SMALL HIRAGANA GET WRITTEN BELOW A PARENT SYLLABLE.
; ACCENT MARKS GET WRITTEN TO THE RIGHT OF A SYLLABLE.

;PREP WORK
ClearDataRegs

; D0 = INDEX OF THE CHARACTER WE ARE WRITING TO SCREEN.
; D1 = VRAM ADDRESS
; D2 = THE ACTUAL TILE ADDRESS IN 202.S1 OF THE CHOSEN CHARACTER.
; D3 = SHADOW VRAM ADDRESS USED AS A COMPARATOR FOR REACHING END OF LINE.


;LOAD DATA BLOCK ADDRESSES
LEA TestStringJapanese,A0 ;LOAD THE MESSAGE WE WANT TO TYPE
LEA HIRAGANA_LIST,A1 ;LOAD HIRAGANA TABLE

;PREP VRAM
CLR.W D2 ;RESET D2 FROM THE LAST ITERATION OF THE LOOP.
MOVE.W #FIX_TOPRIGHT-128,D1
ADDQ.W #4,D1

MOVE.W #1,$3C0004 ;SET INCREMENT FACTOR

loop_PrintStringJapanese:
MOVE.W D1,$3C0000 ;LOAD STARTING ADDRESS FOR VRAM WRITING
MOVE.B (A0)+,D0 ;GET INDEX OF NEXT CHARACTER TO PRINT

CMP.B #$FF,D0 ;DID WE REACH THE TERMINATOR BYTE?
BEQ EndOfStringJapanese
LSL.B #2,D0 ;WE ARE INDEXING INTO A TABLE OF LONGS SO MULTIPLY BY 4

;OUR MODIFIERS START AT $BC.
CMP.B #$E0,D0
BCC PrintAccentMark ;WE NEED TO PRINT AN ACCENT MARK NOW.

MOVE.L (0,A1,D0),A2 ;GET EFFECTIVE ADDRESS OF THE DESIRED SYLLABLE.

MOVE.B (A2),D2 ;STORE ITS INDEX FROM 202.S1 INTO D2
ADD.W #$3100,D2 ;ADD PALETTE NUMBER AND DECOMPRESS.
MOVE.W D2,$3C0002 ;WRITE IT TO THE FIX LAYER. VRAMADDR AUTO INCREMENTS DOWNWARD.

CMP.B #0,D0 ;IS THIS THE DUMMY CHARACTER? IF SO DO NOT ADD $100 TO IT.
BEQ noSecondHalf
ADD.W #$100,D2 ;WE JUST WROTE THE TOP HALF. THE BOTTOM HALF IS ALWAYS $100 TILES AWAY.
noSecondHalf:
MOVE.W D2,$3C0002 ;WRITE THE BOTTOM HALF TO THE FIX LAYER.
CLR.L D2
ADDQ.W #2,D1 ;ADD 2 TO VRAM ADDRESS.
MOVE.W D1,D3 ;COPY D1 TO D3 TO USE AS BOUNDS CHECKER.
AND.B #$1A,D3 ;LEAVE A LITTLE ROOM AT THE BOTTOM.
CMP.B #$1A,D3 ;ARE WE AT THE BOTTOM OF THE VISIBLE FIX LAYER?
BEQ NewLineJapanese
BRA loop_PrintStringJapanese
EndOfStringJapanese:
popall
rts

NewLineJapanese:
SUB.W #$1B,D1
SUB.W #$59,D1

;TODO: ADD BOUNDS CHECKING FOR GOING OFF THE LEFT SIDE.

BRA loop_PrintStringJapanese

PrintAccentMark:
ADD.W #$001E,D1 ;SET VRAM ADDRESS TO THE RIGHT SIDE OF THE CHARACTER WE JUST WROTE.
MOVE.W D1,$3C0000
MOVE.L (0,A1,D0),A2 ;GET EFFECTIVE ADDRESS OF THE DESIRED SYLLABLE.

MOVE.B (A2),D2 ;STORE ITS INDEX FROM 202.S1 INTO D2

ADD.W #$3100,D2 ;ADD PALETTE NUMBER AND DECOMPRESS
MOVE.W D2,$3C0002 ;WRITE IT TO THE FIX LAYER. VRAMADDR AUTO INCREMENTS DOWNWARD.

ADD.W #$0100,D2 ;ADD $100 TO GET TO BOTTOM HALF OF THIS.
MOVE.W D2,$3C0002 ;STORE BOTTOM HALF INTO VRAM

SUB.W #$001E,D1 ;CHANGE VRAMADDR BACK TO WHERE WE WERE AS IF NOTHING HAPPENED.
CLR.W D2 ;PREVENTS SKIPPING OF NEXT SYLLABLE
BRA loop_PrintStringJapanese

;BUG (FIXED): ANY SYLLABLE AFTER PUNCTUATION IS SKIPPED.
;THIS WORKS FOR DAKUTEN, MARU, COMMA, AND PERIOD.

; CMP.B #46,D0
; BLT DONTADDMODIFIER ;THIS PART IS NOT NEEDED SINCE THESE GET WRITTEN JUST LIKE NORMAL SYLLABLES.

;CMP.B #55,D0
;BGT ACCENTMARK


TestStringJapanese:
DC.B 10,56,46,22,17,26,0,14,6,2,59,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,12,56,52,1,255
EVEN

; USAGE:
; THE CHARACTER'S INDEX IN THE TABLE "HIRAGANA_LIST" IS WHAT IS READ FROM THE STRING. THIS SAVES A TON OF DATA OVER TIME.
; ACCENT MARKS ARE TREATED AS THEIR OWN CHARACTER. IT WILL GET WRITTEN AUTOMATICALLY IN THE RIGHT PLACE. PUT THEM AFTER THE CHARACTER YOU WANT TO MODIFY.
; EXAMPLE: KO = 10. GO = 10,56
; THERE IS NO ERROR CHECKING FOR SYLLABLES THAT DON'T USE ACCENT MARKS. IT IS UP TO YOU TO USE THEM CORRECTLY!
; COMMAS AND PERIODS NOT IMPLEMENTED YET.


;CHARACTER CHART: TOP HALF, BOTTOM HALF

;HIRAGANA (BOTTOM HALF = TOP HALF + $0100)

HIRAGANA_LIST:
DC.L DUMMY_HIRAGANA ;0

DC.L A_HIRAGANA ;1
DC.L I_HIRAGANA ;2
DC.L U_HIRAGANA ;3
DC.L E_HIRAGANA ;4
DC.L O_HIRAGANA ;5

DC.L KA_HIRAGANA ;6
DC.L KI_HIRAGANA ;7
DC.L KU_HIRAGANA ;8
DC.L KE_HIRAGANA ;9
DC.L KO_HIRAGANA ;10

DC.L SA_HIRAGANA ;11
DC.L SHI_HIRAGANA ;12
DC.L SU_HIRAGANA ;13
DC.L SE_HIRAGANA ;14
DC.L SO_HIRAGANA ;15

DC.L TA_HIRAGANA ;16
DC.L CHI_HIRAGANA ;17
DC.L TSU_HIRAGANA ;18
DC.L TE_HIRAGANA ;19
DC.L TO_HIRAGANA ;20

DC.L NA_HIRAGANA ;21
DC.L NI_HIRAGANA ;22
DC.L NU_HIRAGANA ;23
DC.L NE_HIRAGANA ;24
DC.L NO_HIRAGANA ;25

DC.L HA_HIRAGANA ;26
DC.L HI_HIRAGANA ;27
DC.L FU_HIRAGANA ;28
DC.L HE_HIRAGANA ;29
DC.L HO_HIRAGANA ;30

DC.L MA_HIRAGANA ;31
DC.L MI_HIRAGANA ;32
DC.L MU_HIRAGANA ;33
DC.L ME_HIRAGANA ;34
DC.L MO_HIRAGANA ;35

DC.L YA_HIRAGANA ;36
DC.L YU_HIRAGANA ;37
DC.L YO_HIRAGANA ;38

DC.L RA_HIRAGANA ;39
DC.L RI_HIRAGANA ;40
DC.L RU_HIRAGANA ;41
DC.L RE_HIRAGANA ;42
DC.L RO_HIRAGANA ;43

DC.L WA_HIRAGANA ;44
DC.L WO_HIRAGANA ;45
DC.L N_HIRAGANA ;46

;DECIMAL 0 THRU DECIMAL 46 ARE FULL-SIZE SYLLABLES AND CAN STAND ALONE.

;TREAT THESE AS "OPCODES" THAT MODIFY THE SYLLABLE BEFORE IT.
;THESE ARE WRITTEN BELOW THE SYLLABLE. NOTHING IS WRITTEN TO THE RIGHT OF THEM.
DC.L SMALL_A_HIRAGANA ;47
DC.L SMALL_I_HIRAGANA ;48
DC.L SMALL_U_HIRAGANA ;49
DC.L SMALL_E_HIRAGANA ;50
DC.L SMALL_O_HIRAGANA ;51

DC.L SMALL_YA_HIRAGANA ;52
DC.L SMALL_YU_HIRAGANA ;53
DC.L SMALL_YO_HIRAGANA ;54
DC.L SMALL_TSU_HIRAGANA ;55 (TECHNICALLY THIS MODIFIES THE SYMBOL AFTER IT BUT THE COMPUTER DOESN'T SEE IT DIFFERENTLY.)

;THESE ARE WRITTEN TO THE RIGHT OF THE SYLLABLE.
DC.L DAKUTEN ;56
DC.L MARU ;57
DC.L JP_COMMA ;58
DC.L JP_PERIOD ;59

DUMMY_HIRAGANA: DC.B $FA ;SPACE BETWEEN CHARACTERS. THE LOOP WILL SEE THAT THIS IS THE DUMMY AND WON'T ADD $100 TO IT FOR THE BOTTOM HALF.

A_HIRAGANA: DC.B $80
I_HIRAGANA: DC.B $81
U_HIRAGANA: DC.B $82
E_HIRAGANA: DC.B $83
O_HIRAGANA: DC.B $84

KA_HIRAGANA: DC.B $85
KI_HIRAGANA: DC.B $86
KU_HIRAGANA: DC.B $87
KE_HIRAGANA: DC.B $88
KO_HIRAGANA: DC.B $89

SA_HIRAGANA: DC.B $8A
SHI_HIRAGANA: DC.B $8B
SU_HIRAGANA: DC.B $8C
SE_HIRAGANA: DC.B $8D
SO_HIRAGANA: DC.B $8E

TA_HIRAGANA: DC.B $8F
CHI_HIRAGANA: DC.B $90
TSU_HIRAGANA: DC.B $91
TE_HIRAGANA: DC.B $92
TO_HIRAGANA: DC.B $93

NA_HIRAGANA: DC.B $94
NI_HIRAGANA: DC.B $95
NU_HIRAGANA: DC.B $96
NE_HIRAGANA: DC.B $97
NO_HIRAGANA: DC.B $98

HA_HIRAGANA: DC.B $99
HI_HIRAGANA: DC.B $9A
FU_HIRAGANA: DC.B $9B
HE_HIRAGANA: DC.B $9C
HO_HIRAGANA: DC.B $9D

MA_HIRAGANA: DC.B $9E
MI_HIRAGANA: DC.B $9F
MU_HIRAGANA: DC.B $A0
ME_HIRAGANA: DC.B $A1
MO_HIRAGANA: DC.B $A2

YA_HIRAGANA: DC.B $A3
YU_HIRAGANA: DC.B $A4
YO_HIRAGANA: DC.B $A5

RA_HIRAGANA: DC.B $A6
RI_HIRAGANA: DC.B $A7
RU_HIRAGANA: DC.B $A8
RE_HIRAGANA: DC.B $A9
RO_HIRAGANA: DC.B $AA

WA_HIRAGANA: DC.B $AB
WO_HIRAGANA: DC.B $AC
N_HIRAGANA: DC.B $AD

SMALL_A_HIRAGANA: DC.B $AE
SMALL_I_HIRAGANA: DC.B $AF
SMALL_U_HIRAGANA: DC.B $B0
SMALL_E_HIRAGANA: DC.B $B1
SMALL_O_HIRAGANA: DC.B $B2

SMALL_YA_HIRAGANA: DC.B $B3
SMALL_YU_HIRAGANA: DC.B $B4
SMALL_YO_HIRAGANA: DC.B $B5
SMALL_TSU_HIRAGANA: DC.B $B6

DAKUTEN: DC.B $B7
MARU: DC.B $B8
JP_LEFT_QUOTE: DC.B $B9
JP_RIGHT_QUOTE: DC.B $BA
JP_COMMA: DC.B $FA
JP_PERIOD: DC.B $FB

;;;KATAKANA

; KATAKANA WILL TAKE SOME ADJUSTING OF THE BASE CODE SINCE THE HIRAGANA LIST IS BARELY SMALL ENOUGH TO FIT IN ONE BYTE.
; DECIMAL 57 LSL 2 IS JUST BARELY UNDER $FF.
; DOESN'T SEEM FEASIBLE AT THE MOMENT. WOULD REQUIRE 4 TIMES THE SPACE SINCE I WOULD NO LONGER BE ABLE TO COMPRESS
; THE HIRAGANA CHARACTERS TO ONE BYTE EACH.
 
Top