summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile21
-rw-r--r--battle/effect_commands.asm220
m---------extras0
-rw-r--r--main.asm128
-rw-r--r--preprocessor.py631
-rw-r--r--prequeue.py2
6 files changed, 244 insertions, 758 deletions
diff --git a/Makefile b/Makefile
index b8ded2274..1fe1789ad 100644
--- a/Makefile
+++ b/Makefile
@@ -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 $<
diff --git a/battle/effect_commands.asm b/battle/effect_commands.asm
index 94b54c0bd..5ac336ed9 100644
--- a/battle/effect_commands.asm
+++ b/battle/effect_commands.asm
@@ -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
diff --git a/extras b/extras
-Subproject 016f0206b5029fc83a6200be29b0f980c76dfd9
+Subproject 276111f04dcc3e937f1a16f4b7066934409f8ad
diff --git a/main.asm b/main.asm
index d642284dd..9f87c49d0 100644
--- a/main.asm
+++ b/main.asm
@@ -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"
diff --git a/preprocessor.py b/preprocessor.py
index 59850729a..188db81a6 100644
--- a/preprocessor.py
+++ b/preprocessor.py
@@ -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):
+def preprocess(macro_table, lines=None):
"""
- 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
+ Entry point for the preprocessor.
"""
- 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)
+ 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
diff --git a/prequeue.py b/prequeue.py
index 6efc519d1..5c1a9f161 100644
--- a/prequeue.py
+++ b/prequeue.py
@@ -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