Merge pull request #4 from kanzure/fix-split-predefs-specials-stds

Fix split predefs specials stds
This commit is contained in:
yenatch 2013-09-09 14:14:33 -07:00
commit d3fa77253a
6 changed files with 246 additions and 760 deletions

View File

@ -1,3 +1,4 @@
PYTHON := python
.SUFFIXES: .asm .tx .o .gbc .png .2bpp .lz
TEXTFILES := $(shell find ./ -type f -name '*.asm' | grep -v pokecrystal.asm | grep -v constants.asm | grep -v gbhw.asm | grep -v hram.asm | grep -v constants | grep -v wram.asm)
@ -14,35 +15,35 @@ clean:
@echo 'rm -f $(TEXTFILES:.asm=.tx)'
@rm -f $(TEXTFILES:.asm=.tx)
pokecrystal.o: $(TEXTFILES:.asm=.tx) wram.asm constants.asm $(shell find constants/ -type f -name '*.asm') hram.asm gbhw.asm $(LZ_GFX) $(TWOBPP_GFX)
python prequeue.py $(TEXTQUEUE)
$(PYTHON) prequeue.py $(TEXTQUEUE)
rgbasm -o pokecrystal.o pokecrystal.asm
.asm.tx:
$(eval TEXTQUEUE := $(TEXTQUEUE) $<)
@rm -f $@
baserom.gbc:
python -c "import os; assert 'baserom.gbc' in os.listdir('.'), 'Wait! Need baserom.gbc first. Check README and INSTALL for details.';"
$(PYTHON) -c "import os; assert 'baserom.gbc' in os.listdir('.'), 'Wait! Need baserom.gbc first. Check README and INSTALL for details.';"
pokecrystal.gbc: pokecrystal.o
rgblink -n pokecrystal.sym -m pokecrystal.map -o $@ $<
rgbfix -Cjv -i BYTE -k 01 -l 0x33 -m 0x10 -p 0 -r 3 -t PM_CRYSTAL $@
pngs:
python extras/pokemontools/gfx.py mass-decompress
python extras/pokemontools/gfx.py dump-pngs
$(PYTHON) extras/pokemontools/gfx.py mass-decompress
$(PYTHON) extras/pokemontools/gfx.py dump-pngs
lzs: $(LZ_GFX) $(TWOBPP_GFX)
@:
gfx/pics/%/front.lz: gfx/pics/%/tiles.2bpp gfx/pics/%/front.png
python extras/pokemontools/gfx.py png-to-lz --front $^
$(PYTHON) extras/pokemontools/gfx.py png-to-lz --front $^
gfx/pics/%/tiles.2bpp: gfx/pics/%/tiles.png
python extras/pokemontools/gfx.py png-to-2bpp $<
$(PYTHON) extras/pokemontools/gfx.py png-to-2bpp $<
gfx/pics/%/back.lz: gfx/pics/%/back.png
python extras/pokemontools/gfx.py png-to-lz --vert $<
$(PYTHON) extras/pokemontools/gfx.py png-to-lz --vert $<
gfx/trainers/%.lz: gfx/trainers/%.png
python extras/pokemontools/gfx.py png-to-lz --vert $<
$(PYTHON) extras/pokemontools/gfx.py png-to-lz --vert $<
.png.lz:
python extras/pokemontools/gfx.py png-to-lz $<
$(PYTHON) extras/pokemontools/gfx.py png-to-lz $<
.png.2bpp:
python extras/pokemontools/gfx.py png-to-lz $<
$(PYTHON) extras/pokemontools/gfx.py png-to-lz $<

View File

@ -9328,72 +9328,102 @@ BattleCommand50: ; 37492
ld a, [hBattleTurn]
and a
jr nz, .asm_374ce ; 37495 $37
call .asm_37501
jr nz, .enemy
; The player needs to be able to steal an item.
call .playeritem
ld a, [hl]
and a
ret nz
call .asm_3750c
; The enemy needs to have an item to steal.
call .enemyitem
ld a, [hl]
and a
ret z
; Can't steal mail.
ld [$d265], a
ld d, a
ld a, $2e
ld hl, $5e76
rst FarCall
callba ItemIsMail
ret c
ld a, [EffectFailed]
and a
ret nz
ld a, [InLinkBattle]
and a
jr z, .asm_374be ; 374b7 $5
jr z, .stealenemyitem
ld a, [IsInBattle]
dec a
ret z
.asm_374be
call .asm_3750c
.stealenemyitem
call .enemyitem
xor a
ld [hl], a
ld [de], a
call .asm_37501
call .playeritem
ld a, [$d265]
ld [hl], a
ld [de], a
jr .asm_374f8 ; 374cc $2a
.asm_374ce
call .asm_3750c
jr .stole
.enemy
; The enemy can't already have an item.
call .enemyitem
ld a, [hl]
and a
ret nz
call .asm_37501
; The player must have an item to steal.
call .playeritem
ld a, [hl]
and a
ret z
; Can't steal mail!
ld [$d265], a
ld d, a
ld a, $2e
ld hl, $5e76
rst FarCall
callba ItemIsMail
ret c
ld a, [EffectFailed]
and a
ret nz
call .asm_37501
; If the enemy steals your item,
; it's gone for good if you don't get it back.
call .playeritem
xor a
ld [hl], a
ld [de], a
call .asm_3750c
call .enemyitem
ld a, [$d265]
ld [hl], a
ld [de], a
.asm_374f8
.stole
call GetItemName
ld hl, StoleText
jp StdBattleTextBox
.asm_37501
.playeritem
ld a, 1
call BattlePartyAttr
ld d, h
@ -9401,9 +9431,9 @@ BattleCommand50: ; 37492
ld hl, BattleMonItem
ret
.asm_3750c
.enemyitem
ld a, 1
call $396d ; GetOTStat_Battle
call OTPartyAttr
ld d, h
ld e, l
ld hl, EnemyMonItem
@ -9413,17 +9443,27 @@ BattleCommand50: ; 37492
BattleCommand51: ; 37517
; arenatrap
; Doesn't work on an absent opponent.
call CheckHiddenOpponent
jr nz, .asm_37530 ; 3751a $14
jr nz, .failed
; Don't trap if the opponent is already trapped.
ld a, BATTLE_VARS_SUBSTATUS5
call GetBattleVarPair
bit 7, [hl]
jr nz, .asm_37530 ; 37523 $b
set 7, [hl]
bit SUBSTATUS_CANT_RUN, [hl]
jr nz, .failed
; Otherwise trap the opponent.
set SUBSTATUS_CANT_RUN, [hl]
call Function0x37e01
ld hl, CantEscapeNowText
jp StdBattleTextBox
.asm_37530
.failed
call Function0x37e77
jp PrintButItFailed
; 37536
@ -9432,23 +9472,38 @@ BattleCommand51: ; 37517
BattleCommand52: ; 37536
; nightmare
; Can't hit an absent opponent.
call CheckHiddenOpponent
jr nz, .asm_3755d ; 37539 $22
jr nz, .failed
; Can't hit a substitute.
call CheckSubstituteOpp
jr nz, .asm_3755d ; 3753e $1d
jr nz, .failed
; Only works on a sleeping opponent.
ld a, BATTLE_VARS_STATUS_OPP
call GetBattleVarPair
and $7
jr z, .asm_3755d ; 37547 $14
and SLP
jr z, .failed
; Bail if the opponent is already having a nightmare.
ld a, BATTLE_VARS_SUBSTATUS1_OPP
call GetBattleVarPair
bit 0, [hl]
jr nz, .asm_3755d ; 37550 $b
set 0, [hl]
bit SUBSTATUS_NIGHTMARE, [hl]
jr nz, .failed
; Otherwise give the opponent a nightmare.
set SUBSTATUS_NIGHTMARE, [hl]
call Function0x37e01
ld hl, StartedNightmareText
jp StdBattleTextBox
.asm_3755d
.failed
call Function0x37e77
jp PrintButItFailed
; 37563
@ -9457,22 +9512,30 @@ BattleCommand52: ; 37536
BattleCommand53: ; 37563
; defrost
; Thaw the user.
ld a, BATTLE_VARS_STATUS
call GetBattleVarPair
bit 5, [hl]
bit FRZ, [hl]
ret z
res 5, [hl]
res FRZ, [hl]
; Don't update the enemy's party struct in a wild battle.
ld a, [hBattleTurn]
and a
jr z, .asm_37578 ; 37570 $6
jr z, .party
ld a, [IsInBattle]
dec a
jr z, .asm_3757f ; 37576 $7
.asm_37578
ld a, $20
jr z, .done
.party
ld a, PartyMon1Status - PartyMon1
call UserPartyAttr
res 5, [hl]
.asm_3757f
res FRZ, [hl]
.done
call RefreshBattleHuds
ld hl, WasDefrostedText
jp StdBattleTextBox
@ -9486,25 +9549,40 @@ BattleCommand54: ; 37588
ld bc, PlayerStatLevels
ld a, [hBattleTurn]
and a
jr z, .asm_37599 ; 37591 $6
jr z, .go
ld de, EnemyMonType1
ld bc, EnemyStatLevels
.asm_37599
.go
; Curse is different for Ghost-types.
ld a, [de]
cp $8
jr z, .asm_375d7 ; 3759c $39
cp GHOST
jr z, .ghost
inc de
ld a, [de]
cp $8
jr z, .asm_375d7 ; 375a2 $33
cp GHOST
jr z, .ghost
; If no stats can be increased, don't.
; Attack
ld a, [bc]
cp $d
jr c, .asm_375af ; 375a7 $6
cp 13 ; max
jr c, .raise
; Defense
inc bc
ld a, [bc]
cp $d
jr nc, .asm_3760a ; 375ad $5b
.asm_375af
cp 13 ; max
jr nc, .cantraise
.raise
; Raise Attack and Defense, and lower Speed.
ld a, $1
ld [$c689], a
call Function0x37e01
@ -9519,29 +9597,43 @@ BattleCommand54: ; 37588
call ResetMiss
call BattleCommand71
jp BattleCommand8c
.asm_375d7
.ghost
; Cut HP in half and put a curse on the opponent.
call CheckHiddenOpponent
jr nz, .asm_37604 ; 375da $28
jr nz, .failed
call CheckSubstituteOpp
jr nz, .asm_37604 ; 375df $23
jr nz, .failed
ld a, BATTLE_VARS_SUBSTATUS1_OPP
call GetBattleVarPair
bit 1, [hl]
jr nz, .asm_37604 ; 375e8 $1a
jr nz, .failed
set 1, [hl]
call Function0x37e01
ld hl, $4c9f
ld hl, GetHalfMaxHP
call CallBankF
ld hl, $4c3f
ld hl, Function3cc3f
call CallBankF
call UpdateUserInParty
ld hl, PutACurseText
jp StdBattleTextBox
.asm_37604
.failed
call Function0x37e77
jp PrintButItFailed
.asm_3760a
ld b, $8
.cantraise
; Can't raise either stat.
ld b, $8 ; ABILITY
call GetStatName
call Function0x37e77
ld hl, WontRiseAnymoreText

2
extras

@ -1 +1 @@
Subproject commit 016f0206b5029fc83a6200be29b0f980c76dfd90
Subproject commit 276111f04dcc3e937f1a16f4b7066934409f8ad4

128
main.asm
View File

@ -26733,11 +26733,11 @@ OpenMartDialog: ; 15a45
; 15a57
.dialogs
dw MartDialog
dw HerbShop
dw BargainShop
dw Pharmacist
dw VendingMachine
dw MartDialog
dw HerbShop
dw BargainShop
dw Pharmacist
dw VendingMachine
; 15a61
MartDialog: ; 15a61
@ -26865,12 +26865,12 @@ Function15b47: ; 15b47
ret
.table_15b56
dw Function15b62
dw Function15b6e
dw Function15b8d
dw Function15b9a
dw Function15ba3
dw Function15baf
dw Function15b62
dw Function15b6e
dw Function15b8d
dw Function15b9a
dw Function15ba3
dw Function15baf
; 15b62
Function15b62: ; 15b62
@ -27107,11 +27107,11 @@ Function15ca3: ; 15ca3
; 15cb0
.data_15cb0 ; 15cb0
dwb $5cbf, 0
dwb $5ccb, 0
dwb $5cd7, 1
dwb $5ce3, 0
dwb $5cbf, 2
dwb $5cbf, 0
dwb $5ccb, 0
dwb $5cd7, 1
dwb $5ce3, 0
dwb $5cbf, 2
; 15cbf
INCBIN "baserom.gbc", $15cbf, $15cef - $15cbf
@ -27791,7 +27791,7 @@ Function16798: ; 16798
ld a, [CurPartyMon]
call AddNTimes
ld d, [hl]
callba Functionb9e76
callba ItemIsMail
jr c, .asm_167ed
ld hl, PartyMon1Nickname
ld a, [CurPartyMon]
@ -30906,7 +30906,7 @@ Function24dd4: ; 24dd4
ld a, $1
call GetPartyParamLocation
ld d, [hl]
callba Functionb9e76
callba ItemIsMail
pop hl
ld a, $14
jr c, .asm_24e2c
@ -34522,7 +34522,7 @@ Function29bfb: ; 29bfb
push hl
push bc
ld d, [hl]
callba Functionb9e76
callba ItemIsMail
pop bc
pop hl
jr c, .asm_29c5e
@ -53392,14 +53392,14 @@ StatsScreenMain: ; 0x4dcd2
INCBIN "baserom.gbc", $4dcf7, $4dd2a - $4dcf7
StatsScreenPointerTable: ; 4dd2a
dw $5d72 ; regular pokémon
dw EggStatsInit ; egg
dw $5de6
dw $5dac
dw $5dc6
dw $5de6
dw $5dd6
dw $5d6c
dw $5d72 ; regular pokémon
dw EggStatsInit ; egg
dw $5de6
dw $5dac
dw $5dc6
dw $5de6
dw $5dd6
dw $5d6c
; 4dd3a
@ -53416,10 +53416,10 @@ EggStatsInit: ; 4dda1
INCBIN "baserom.gbc", $4ddac, $4e21e - $4ddac
IDNoString: ; 4e21e
db $73, "№.@"
db $73, "№.@"
OTString: ; 4e222
db "OT/@"
db "OT/@"
; 4e226
INCBIN "baserom.gbc", $4e226, $4e33a - $4e226
@ -53481,22 +53481,22 @@ EggStatsScreen: ; 4e33a
; 0x4e3c0
EggString: ; 4e3c0
db "EGG@"
db "EGG@"
FiveQMarkString: ; 4e3c4
db "?????@"
db "?????@"
EggSoonString: ; 0x4e3ca
db "It's making sounds", $4e, "inside. It's going", $4e, "to hatch soon!@"
db "It's making sounds", $4e, "inside. It's going", $4e, "to hatch soon!@"
EggCloseString: ; 0x4e3fd
db "It moves around", $4e, "inside sometimes.", $4e, "It must be close", $4e, "to hatching.@"
db "It moves around", $4e, "inside sometimes.", $4e, "It must be close", $4e, "to hatching.@"
EggMoreTimeString: ; 0x4e43d
db "Wonder what's", $4e, "inside? It needs", $4e, "more time, though.@"
db "Wonder what's", $4e, "inside? It needs", $4e, "more time, though.@"
EggALotMoreTimeString: ; 0x4e46e
db "This EGG needs a", $4e, "lot more time to", $4e, "hatch.@"
db "This EGG needs a", $4e, "lot more time to", $4e, "hatch.@"
; 0x4e497
@ -55357,35 +55357,35 @@ PrintPartyMenuText: ; 5049a
; 0x504d2
PartyMenuStrings: ; 0x504d2
dw ChooseAMonString
dw UseOnWhichPKMNString
dw WhichPKMNString
dw TeachWhichPKMNString
dw MoveToWhereString
dw UseOnWhichPKMNString
dw ChooseAMonString ; Probably used to be ChooseAFemalePKMNString
dw ChooseAMonString ; Probably used to be ChooseAMalePKMNString
dw ToWhichPKMNString
dw ChooseAMonString
dw UseOnWhichPKMNString
dw WhichPKMNString
dw TeachWhichPKMNString
dw MoveToWhereString
dw UseOnWhichPKMNString
dw ChooseAMonString ; Probably used to be ChooseAFemalePKMNString
dw ChooseAMonString ; Probably used to be ChooseAMalePKMNString
dw ToWhichPKMNString
ChooseAMonString: ; 0x504e4
db "Choose a #MON.@"
db "Choose a #MON.@"
UseOnWhichPKMNString: ; 0x504f3
db "Use on which ", $e1, $e2, "?@"
db "Use on which ", $e1, $e2, "?@"
WhichPKMNString: ; 0x50504
db "Which ", $e1, $e2, "?@"
db "Which ", $e1, $e2, "?@"
TeachWhichPKMNString: ; 0x5050e
db "Teach which ", $e1, $e2, "?@"
db "Teach which ", $e1, $e2, "?@"
MoveToWhereString: ; 0x5051e
db "Move to where?@"
db "Move to where?@"
ChooseAFemalePKMNString: ; 0x5052d ; UNUSED
db "Choose a ♀", $e1, $e2, ".@"
db "Choose a ♀", $e1, $e2, ".@"
ChooseAMalePKMNString: ; 0x5053b ; UNUSED
db "Choose a ♂", $e1, $e2, ".@"
db "Choose a ♂", $e1, $e2, ".@"
ToWhichPKMNString: ; 0x50549
db "To which ", $e1, $e2, "?@"
db "To which ", $e1, $e2, "?@"
YouHaveNoPKMNString: ; 0x50556
db "You have no ", $e1, $e2, "!@"
db "You have no ", $e1, $e2, "!@"
Function50566: ; 50566
@ -69675,14 +69675,26 @@ Functionb92b8: ; b92b8
INCBIN "baserom.gbc", $b92f7, $b9e76 - $b92f7
Functionb9e76: ; b9e76
ItemIsMail: ; b9e76
ld a, d
ld hl, $5e80
ld de, $0001
ld hl, .items
ld de, 1
jp IsInArray
; b9e80
INCBIN "baserom.gbc", $b9e80, $b9e8b - $b9e80
.items
db FLOWER_MAIL
db SURF_MAIL
db LITEBLUEMAIL
db PORTRAITMAIL
db LOVELY_MAIL
db EON_MAIL
db MORPH_MAIL
db BLUESKY_MAIL
db MUSIC_MAIL
db MIRAGE_MAIL
db $ff
; b9e8b
SECTION "bank2F",ROMX,BANK[$2F]
@ -86674,7 +86686,7 @@ RegionCheck: ; 0x1caea1
SECTION "bank73",ROMX,BANK[$73]
; Pokedex entries III
; Pokedex entries III
; 129-192
PokedexEntries3:
INCLUDE "stats/pokedex/entries_3.asm"

View File

@ -3,6 +3,8 @@
import sys
import extras.pokemontools.preprocessor as preprocessor
from extras.pokemontools.crystal import (
command_classes,
Warp,
@ -39,636 +41,15 @@ def load_pokecrystal_macros():
return ourmacros
chars = {
"": 0x05,
"": 0x06,
"": 0x07,
"": 0x08,
"": 0x09,
"": 0x0A,
"": 0x0B,
"": 0x0C,
"": 0x0D,
"": 0x0E,
"": 0x0F,
"": 0x10,
"": 0x11,
"": 0x12,
"": 0x13,
"": 0x19,
"": 0x1A,
"": 0x1B,
"": 0x1C,
"": 0x26,
"": 0x27,
"": 0x28,
"": 0x29,
"": 0x2A,
"": 0x2B,
"": 0x2C,
"": 0x2D,
"": 0x2E,
"": 0x2F,
"": 0x30,
"": 0x31,
"": 0x32,
"": 0x33,
"": 0x34,
"": 0x3A,
"": 0x3B,
"": 0x3C,
"": 0x3D,
"": 0x3E,
"": 0x40,
"": 0x41,
"": 0x42,
"": 0x43,
"": 0x44,
"": 0x45,
"": 0x46,
"": 0x47,
"": 0x48,
"": 0x80,
"": 0x81,
"": 0x82,
"": 0x83,
"": 0x84,
"": 0x85,
"": 0x86,
"": 0x87,
"": 0x88,
"": 0x89,
"": 0x8A,
"": 0x8B,
"": 0x8C,
"": 0x8D,
"": 0x8E,
"": 0x8F,
"": 0x90,
"": 0x91,
"": 0x92,
"": 0x93,
"": 0x94,
"": 0x95,
"": 0x96,
"": 0x97,
"": 0x98,
"": 0x99,
"": 0x9A,
"": 0x9B,
"": 0x9C,
"": 0x9D,
"": 0x9E,
"": 0x9F,
"": 0xA0,
"": 0xA1,
"": 0xA2,
"": 0xA3,
"": 0xA4,
"": 0xA5,
"": 0xA6,
"": 0xA7,
"": 0xA8,
"": 0xA9,
"": 0xAA,
"": 0xAB,
"": 0xAC,
"": 0xAD,
"": 0xAE,
"": 0xAF,
"": 0xB0,
"": 0xB1,
"": 0xB2,
"": 0xB3,
"": 0xB4,
"": 0xB5,
"": 0xB6,
"": 0xB7,
"": 0xB8,
"": 0xB9,
"": 0xBA,
"": 0xBB,
"": 0xBC,
"": 0xBD,
"": 0xBE,
"": 0xBF,
"": 0xC0,
"": 0xC1,
"": 0xC2,
"": 0xC3,
"": 0xC4,
"": 0xC5,
"": 0xC6,
"": 0xC7,
"": 0xC8,
"": 0xC9,
"": 0xCA,
"": 0xCB,
"": 0xCC,
"": 0xCD,
"": 0xCE,
"": 0xCF,
"": 0xD0,
"": 0xD1,
"": 0xD2,
"": 0xD3,
"": 0xD4,
"": 0xD5,
"": 0xD6,
"": 0xD7,
"": 0xD8,
"": 0xD9,
"": 0xDA,
"": 0xDB,
"": 0xDC,
"": 0xDD,
"": 0xDE,
"": 0xDF,
"": 0xE0,
"": 0xE1,
"": 0xE2,
"": 0xE3,
"": 0xE9,
"@": 0x50,
"#": 0x54,
"": 0x75,
"": 0x79,
"": 0x7A,
"": 0x7B,
"": 0x7C,
"": 0x7D,
"": 0x7E,
"": 0x74,
" ": 0x7F,
"A": 0x80,
"B": 0x81,
"C": 0x82,
"D": 0x83,
"E": 0x84,
"F": 0x85,
"G": 0x86,
"H": 0x87,
"I": 0x88,
"J": 0x89,
"K": 0x8A,
"L": 0x8B,
"M": 0x8C,
"N": 0x8D,
"O": 0x8E,
"P": 0x8F,
"Q": 0x90,
"R": 0x91,
"S": 0x92,
"T": 0x93,
"U": 0x94,
"V": 0x95,
"W": 0x96,
"X": 0x97,
"Y": 0x98,
"Z": 0x99,
"(": 0x9A,
")": 0x9B,
":": 0x9C,
";": 0x9D,
"[": 0x9E,
"]": 0x9F,
"a": 0xA0,
"b": 0xA1,
"c": 0xA2,
"d": 0xA3,
"e": 0xA4,
"f": 0xA5,
"g": 0xA6,
"h": 0xA7,
"i": 0xA8,
"j": 0xA9,
"k": 0xAA,
"l": 0xAB,
"m": 0xAC,
"n": 0xAD,
"o": 0xAE,
"p": 0xAF,
"q": 0xB0,
"r": 0xB1,
"s": 0xB2,
"t": 0xB3,
"u": 0xB4,
"v": 0xB5,
"w": 0xB6,
"x": 0xB7,
"y": 0xB8,
"z": 0xB9,
"Ä": 0xC0,
"Ö": 0xC1,
"Ü": 0xC2,
"ä": 0xC3,
"ö": 0xC4,
"ü": 0xC5,
"'d": 0xD0,
"'l": 0xD1,
"'m": 0xD2,
"'r": 0xD3,
"'s": 0xD4,
"'t": 0xD5,
"'v": 0xD6,
"'": 0xE0,
"-": 0xE3,
"?": 0xE6,
"!": 0xE7,
".": 0xE8,
"&": 0xE9,
"é": 0xEA,
"": 0xEB,
"": 0xEC,
"": 0xED,
"": 0xEE,
"": 0xEF,
"¥": 0xF0,
"×": 0xF1,
"/": 0xF3,
",": 0xF4,
"": 0xF5,
"0": 0xF6,
"1": 0xF7,
"2": 0xF8,
"3": 0xF9,
"4": 0xFA,
"5": 0xFB,
"6": 0xFC,
"7": 0xFD,
"8": 0xFE,
"9": 0xFF
}
class PreprocessorException(Exception):
"""
There was a problem in the preprocessor.
"""
class MacroException(PreprocessorException):
"""
There was a problem with a macro.
"""
def separate_comment(l):
"""
Separates asm and comments on a single line.
"""
in_quotes = False
for i in xrange(len(l)):
if not in_quotes:
if l[i] == ";":
break
if l[i] == "\"":
in_quotes = not in_quotes
return l[:i], l[i:] or None
def quote_translator(asm):
"""
Writes asm with quoted text translated into bytes.
"""
# split by quotes
asms = asm.split('"')
# skip asm that actually does use ASCII in quotes
if "SECTION" in asms[0]\
or "INCBIN" in asms[0]\
or "INCLUDE" in asms[0]:
return asm
print_macro = False
if asms[0].strip() == 'print':
asms[0] = asms[0].replace('print','db 0,')
print_macro = True
output = ''
even = False
for token in asms:
if even:
characters = []
# token is a string to convert to byte values
while len(token):
# read a single UTF-8 codepoint
char = token[0]
if ord(char) < 0xc0:
token = token[1:]
# certain apostrophe-letter pairs are considered a single character
if char == "'" and token:
if token[0] in 'dlmrstv':
char += token[0]
token = token[1:]
elif ord(char) < 0xe0:
char = char + token[1:2]
token = token[2:]
elif ord(char) < 0xf0:
char = char + token[1:3]
token = token[3:]
elif ord(char) < 0xf8:
char = char + token[1:4]
token = token[4:]
elif ord(char) < 0xfc:
char = char + token[1:5]
token = token[5:]
else:
char = char + token[1:6]
token = token[6:]
characters += [char]
if print_macro:
line = 0
while len(characters):
last_char = 1
if len(characters) > 18 and characters[-1] != '@':
for i, char in enumerate(characters):
last_char = i + 1
if ' ' not in characters[i+1:18]: break
output += ", ".join("${0:02X}".format(chars[char]) for char in characters[:last_char-1])
if characters[last_char-1] != " ":
output += ", ${0:02X}".format(characters[last_char-1])
if not line & 1:
line_ending = 0x4f
else:
line_ending = 0x51
output += ", ${0:02X}".format(line_ending)
line += 1
else:
output += ", ".join(["${0:02X}".format(chars[char]) for char in characters[:last_char]])
characters = characters[last_char:]
if len(characters): output += ", "
# end text
line_ending = 0x57
output += ", ${0:02X}".format(line_ending)
output += ", ".join(["${0:02X}".format(chars[char]) for char in characters])
else:
output += token
even = not even
return output
def extract_token(asm):
return asm.split(" ")[0].strip()
def make_macro_table(macros):
return dict(((macro.macro_name, macro) for macro in macros))
def macro_test(asm, macro_table):
"""
Returns a matching macro, or None/False.
"""
# macros are determined by the first symbol on the line
token = extract_token(asm)
# skip db and dw since rgbasm handles those and they aren't macros
if token is not None and token not in ["db", "dw"] and token in macro_table:
return (macro_table[token], token)
else:
return (None, None)
def is_based_on(something, base):
"""
Checks whether or not 'something' is a class that is a subclass of a class
by name. This is a terrible hack but it removes a direct dependency on
existing macros.
Used by macro_translator.
"""
options = [str(klass.__name__) for klass in something.__bases__]
options += [something.__name__]
return (base in options)
def check_macro_sanity(params, macro, original_line):
"""
Checks whether or not the correct number of arguments are being passed to a
certain macro. There are a number of possibilities based on the types of
parameters that define the macro.
@param params: a list of parameters given to the macro
@param macro: macro klass
@param original_line: the line being preprocessed
"""
allowed_length = 0
for (index, param_type) in macro.param_types.items():
param_klass = param_type["class"]
if param_klass.byte_type == "db":
allowed_length += 1 # just one value
elif param_klass.byte_type == "dw":
if param_klass.size == 2:
allowed_length += 1 # just label
elif param_klass.size == 3:
allowed_length += 2 # bank and label
else:
raise MacroException(
"dunno what to do with a macro param with a size > 3 (size={size})"
.format(size=param_klass.size)
)
else:
raise MacroException(
"dunno what to do with this non db/dw macro param: {klass} in line {line}"
.format(klass=param_klass, line=original_line)
)
# sometimes the allowed length can vary
if hasattr(macro, "allowed_lengths"):
allowed_lengths = macro.allowed_lengths + [allowed_length]
else:
allowed_lengths = [allowed_length]
# used twice, so precompute once
params_len = len(params)
if params_len not in allowed_lengths:
raise PreprocessorException(
"mismatched number of parameters ({count}, instead of any of {allowed}) on this line: {line}"
.format(
count=params_len,
allowed=allowed_lengths,
line=original_line,
)
)
return True
def macro_translator(macro, token, line, show_original_lines=False, do_macro_sanity_check=False):
"""
Converts a line with a macro into a rgbasm-compatible line.
@param show_original_lines: show lines before preprocessing in stdout
@param do_macro_sanity_check: helpful for debugging macros
"""
if macro.macro_name != token:
raise MacroException("macro/token mismatch")
original_line = line
# remove trailing newline
if line[-1] == "\n":
line = line[:-1]
else:
original_line += "\n"
# remove first tab
has_tab = False
if line[0] == "\t":
has_tab = True
line = line[1:]
# remove duplicate whitespace (also trailing)
line = " ".join(line.split())
params = []
# check if the line has params
if " " in line:
# split the line into separate parameters
params = line.replace(token, "").split(",")
# check if there are no params (redundant)
if len(params) == 1 and params[0] == "":
raise MacroException("macro has no params?")
# write out a comment showing the original line
if show_original_lines:
sys.stdout.write("; original_line: " + original_line)
# rgbasm can handle "db" so no preprocessing is required, plus this wont be
# reached because of earlier checks in macro_test.
if macro.macro_name in ["db", "dw"]:
sys.stdout.write(original_line)
return
# certain macros don't need an initial byte written
# do: all scripting macros
# don't: signpost, warp_def, person_event, xy_trigger
if not macro.override_byte_check:
sys.stdout.write("db ${0:02X}\n".format(macro.id))
# Does the number of parameters on this line match any allowed number of
# parameters that the macro expects?
if do_macro_sanity_check:
check_macro_sanity(params, macro, original_line)
# used for storetext
correction = 0
output = ""
index = 0
while index < len(params):
param_type = macro.param_types[index - correction]
description = param_type["name"]
param_klass = param_type["class"]
byte_type = param_klass.byte_type # db or dw
size = param_klass.size
param = params[index].strip()
# param_klass.to_asm() won't work here because it doesn't
# include db/dw.
# some parameters are really multiple types of bytes
if (byte_type == "dw" and size != 2) or \
(byte_type == "db" and size != 1):
output += ("; " + description + "\n")
if size == 3 and is_based_on(param_klass, "PointerLabelBeforeBank"):
# write the bank first
output += ("db " + param + "\n")
# write the pointer second
output += ("dw " + params[index+1].strip() + "\n")
index += 2
correction += 1
elif size == 3 and is_based_on(param_klass, "PointerLabelAfterBank"):
# write the pointer first
output += ("dw " + param + "\n")
# write the bank second
output += ("db " + params[index+1].strip() + "\n")
index += 2
correction += 1
elif size == 3 and "from_asm" in dir(param_klass):
output += ("db " + param_klass.from_asm(param) + "\n")
index += 1
else:
raise MacroException(
"dunno what to do with this macro param ({klass}) in line: {line}"
.format(
klass=param_klass,
line=original_line,
)
)
# or just print out the byte
else:
output += (byte_type + " " + param + " ; " + description + "\n")
index += 1
sys.stdout.write(output)
def read_line(l, macro_table):
"""Preprocesses a given line of asm."""
if l in ["\n", ""] or l[0] == ";":
sys.stdout.write(l)
return # jump out early
# strip comments from asm
asm, comment = separate_comment(l)
# export all labels
if ':' in asm[:asm.find('"')]:
sys.stdout.write('GLOBAL ' + asm.split(':')[0] + '\n')
# expect preprocessed .asm files
if "INCLUDE" in asm:
asm = asm.replace('.asm','.tx')
sys.stdout.write(asm)
# ascii string macro preserves the bytes as ascii (skip the translator)
elif len(asm) > 6 and ("ascii " == asm[:6] or "\tascii " == asm[:7]):
asm = asm.replace("ascii", "db", 1)
sys.stdout.write(asm)
# convert text to bytes when a quote appears (not in a comment)
elif "\"" in asm:
sys.stdout.write(quote_translator(asm))
# check against other preprocessor features
else:
macro, token = macro_test(asm, macro_table)
if macro:
macro_translator(macro, token, asm)
else:
sys.stdout.write(asm)
if comment:
sys.stdout.write(comment)
def preprocess(macro_table, lines=None):
"""Main entry point for the preprocessor."""
if not lines:
# read each line from stdin
lines = (sys.stdin.readlines())
elif not isinstance(lines, list):
# split up the input into individual lines
lines = lines.split("\n")
for l in lines:
read_line(l, macro_table)
"""
Entry point for the preprocessor.
"""
return preprocessor.preprocess(macro_table, lines=lines)
def main():
macros = load_pokecrystal_macros()
macro_table = make_macro_table(macros)
macro_table = preprocessor.make_macro_table(macros)
preprocess(macro_table)
# only run against stdin when not included as a module

View File

@ -11,7 +11,7 @@ import preprocessor
def main():
macros = preprocessor.load_pokecrystal_macros()
macro_table = preprocessor.make_macro_table(macros)
macro_table = preprocessor.preprocessor.make_macro_table(macros)
stdout = sys.stdout