diff options
-rw-r--r-- | INSTALL.md | 41 | ||||
-rw-r--r-- | README.md | 2 | ||||
-rw-r--r-- | constants.asm | 17 | ||||
-rw-r--r-- | constants/battle_constants.asm (renamed from battle_constants.asm) | 0 | ||||
-rw-r--r-- | constants/item_constants.asm (renamed from item_constants.asm) | 0 | ||||
-rw-r--r-- | constants/map_constants.asm (renamed from map_constants.asm) | 0 | ||||
-rw-r--r-- | constants/move_constants.asm (renamed from move_constants.asm) | 0 | ||||
-rw-r--r-- | constants/music_constants.asm (renamed from music_constants.asm) | 0 | ||||
-rw-r--r-- | constants/pokemon_constants.asm (renamed from pokemon_constants.asm) | 0 | ||||
-rw-r--r-- | constants/script_constants.asm (renamed from script_constants.asm) | 0 | ||||
-rw-r--r-- | constants/trainer_constants.asm (renamed from trainer_constants.asm) | 0 | ||||
-rw-r--r-- | engine/bittable2.asm (renamed from bittable2.asm) | 0 | ||||
-rw-r--r-- | engine/credits.asm (renamed from credits.asm) | 0 | ||||
-rw-r--r-- | engine/joypad.asm (renamed from joypad.asm) | 0 | ||||
-rw-r--r-- | engine/landmarks.asm (renamed from landmarks.asm) | 0 | ||||
-rw-r--r-- | engine/scripting.asm (renamed from scripting.asm) | 0 | ||||
-rw-r--r-- | engine/vblank.asm (renamed from vblank.asm) | 0 | ||||
-rw-r--r-- | extras/vba.py | 41 | ||||
-rw-r--r-- | extras/vba_autoplayer.py | 464 | ||||
-rw-r--r-- | main.asm | 12 | ||||
-rw-r--r-- | preprocessor.py | 11 | ||||
-rw-r--r-- | prequeue.py | 17 |
22 files changed, 561 insertions, 44 deletions
diff --git a/INSTALL.md b/INSTALL.md index 83ad97564..68d5c09b8 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -10,7 +10,7 @@ md5: 9f2922b235a5eeb78d65594e82ef5dde Save it as **baserom.gbc** in the repository. -Feel free to ask us on **[nucleus.kafuka.org #skeetendo](http://chat.mibbit.com/?server=nucleus.kafuka.org&channel=#skeetendo)** if something goes wrong! +Feel free to ask us on **[nucleus.kafuka.org #skeetendo](https://kiwiirc.com/client/irc.nolimitzone.com/?#skeetendo)** if something goes wrong! # Windows @@ -46,15 +46,20 @@ cd /away/we/go ## Getting up and running -We need a couple more things. +We need a couple more things to be able to compile. + +If you're feeling lazy, just paste these commands into your terminal. ```bash -apt-cyg install python make git wget +apt-cyg install make git wget python python-setuptools +easy_install pip ``` **rgbds** will let you compile Game Boy roms. ```bash +cd ~ + # download rgbds binaries wget http://diyhpl.us/~bryan/irc/pokered/rgbds/rgbds.zip unzip rgbds.zip @@ -68,27 +73,37 @@ echo "export PATH=$PATH" >> ~/.bashrc Set up the **pokecrystal** repository: ```bash -cd ~ git clone https://github.com/kanzure/pokecrystal cd pokecrystal # install python requirements pip install -r requirements.txt +``` -# use hexdump to diff binary files -git config diff.hex.textconv hexdump +## Don't forget baserom.gbc!! -# download the base rom -``` +Make sure you downloaded a base rom. Name it **baserom.gbc**. Now you should be able to build **pokecrystal.gbc** for the first time. + +This compiles a new rom from the source code, with any patches filled in from the base rom. ```bash make ``` -This ought to take between **3 and 15 seconds**, depending on your computer. +This ought to take **between 3 and 15 seconds**, depending on your computer. + +If you see `cmp baserom.gbc pokecrystal.gbc` as the last line, the build was successful! + +Your first compile processes every source file at once. After that, **only modified source files have to be reprocessed**, so compiling again should be a few seconds faster. + +Other **make targets** that may come in handy: -If you see `cmp baserom.gbc pokecrystal.gbc` as the last line, the build was successful! Rejoice! +`make clean` deletes any preprocessed source files (.tx), rgbds object files and pokecrystal.gbc, in case something goes wrong. + +`make pngs` decompresses any **lz** files in gfx/ and then exports any graphics files to **png**. + +`make lzs` does the reverse. This is already part of the build process, so **modified pngs will automatically be converted to 2bpp and lz-compressed** without any additional work. # Linux @@ -132,9 +147,11 @@ That will take between 3 and 15 seconds, depending on your computer. If you see # Now what? -* **Can't find something?** Contribute! +**main.asm** is a good starting point. The structure of the source is laid out here. + +* **Can't find something?** Anyone can add to the source. There's lots to be uncovered. * **Do your own thing!** The asm source is hack-friendly, and the supplementary scripts in extras/ can be used for other projects. -* We'll be happy to answer any **questions** at **[nucleus.kafuka.org #skeetendo](http://chat.mibbit.com/?server=nucleus.kafuka.org&channel=#skeetendo)** +* We'll be happy to answer any **questions** on **[nucleus.kafuka.org #skeetendo](https://kiwiirc.com/client/irc.nolimitzone.com/?#skeetendo)**. @@ -28,7 +28,7 @@ Eventually this will not be necessary. ## See also -* Hang out with us on IRC: **[nucleus.kafuka.org #skeetendo](http://chat.mibbit.com/?server=nucleus.kafuka.org&channel=#skeetendo)** +* Hang out with us on irc: **[nucleus.kafuka.org #skeetendo](https://kiwiirc.com/client/irc.nolimitzone.com/?#skeetendo)** * Disassembly of **[Pokémon Red](http://bitbucket.org/iimarckus/pokered)**. diff --git a/constants.asm b/constants.asm index e3d1ddf95..9c7348e9b 100644 --- a/constants.asm +++ b/constants.asm @@ -1,14 +1,13 @@ _CRYSTAL EQU 1 - -INCLUDE "pokemon_constants.asm" -INCLUDE "move_constants.asm" -INCLUDE "battle_constants.asm" -INCLUDE "map_constants.asm" -INCLUDE "item_constants.asm" -INCLUDE "trainer_constants.asm" -INCLUDE "script_constants.asm" -INCLUDE "music_constants.asm" +INCLUDE "constants/pokemon_constants.asm" +INCLUDE "constants/move_constants.asm" +INCLUDE "constants/battle_constants.asm" +INCLUDE "constants/map_constants.asm" +INCLUDE "constants/item_constants.asm" +INCLUDE "constants/trainer_constants.asm" +INCLUDE "constants/script_constants.asm" +INCLUDE "constants/music_constants.asm" ; rst vectors diff --git a/battle_constants.asm b/constants/battle_constants.asm index a1858da1f..a1858da1f 100644 --- a/battle_constants.asm +++ b/constants/battle_constants.asm diff --git a/item_constants.asm b/constants/item_constants.asm index 7fc132378..7fc132378 100644 --- a/item_constants.asm +++ b/constants/item_constants.asm diff --git a/map_constants.asm b/constants/map_constants.asm index 7861a7d44..7861a7d44 100644 --- a/map_constants.asm +++ b/constants/map_constants.asm diff --git a/move_constants.asm b/constants/move_constants.asm index 302255a57..302255a57 100644 --- a/move_constants.asm +++ b/constants/move_constants.asm diff --git a/music_constants.asm b/constants/music_constants.asm index b4e65b5c5..b4e65b5c5 100644 --- a/music_constants.asm +++ b/constants/music_constants.asm diff --git a/pokemon_constants.asm b/constants/pokemon_constants.asm index 40b450b85..40b450b85 100644 --- a/pokemon_constants.asm +++ b/constants/pokemon_constants.asm diff --git a/script_constants.asm b/constants/script_constants.asm index 30fdff8bc..30fdff8bc 100644 --- a/script_constants.asm +++ b/constants/script_constants.asm diff --git a/trainer_constants.asm b/constants/trainer_constants.asm index cfc0e26f0..cfc0e26f0 100644 --- a/trainer_constants.asm +++ b/constants/trainer_constants.asm diff --git a/bittable2.asm b/engine/bittable2.asm index 5527226e4..5527226e4 100644 --- a/bittable2.asm +++ b/engine/bittable2.asm diff --git a/credits.asm b/engine/credits.asm index d5e4399b9..d5e4399b9 100644 --- a/credits.asm +++ b/engine/credits.asm diff --git a/joypad.asm b/engine/joypad.asm index b9702d33a..b9702d33a 100644 --- a/joypad.asm +++ b/engine/joypad.asm diff --git a/landmarks.asm b/engine/landmarks.asm index 2109bd556..2109bd556 100644 --- a/landmarks.asm +++ b/engine/landmarks.asm diff --git a/scripting.asm b/engine/scripting.asm index 2875781f0..2875781f0 100644 --- a/scripting.asm +++ b/engine/scripting.asm diff --git a/vblank.asm b/engine/vblank.asm index 5080a56ad..5080a56ad 100644 --- a/vblank.asm +++ b/engine/vblank.asm diff --git a/extras/vba.py b/extras/vba.py index 317f70540..f85f838b4 100644 --- a/extras/vba.py +++ b/extras/vba.py @@ -159,15 +159,21 @@ def button_combiner(buttons): # recognized as "s" and "t" etc.. if isinstance(buttons, str): if "restart" in buttons: - buttons.replace("restart", "") + buttons = buttons.replace("restart", "") result |= button_masks["restart"] if "start" in buttons: - buttons.replace("start", "") + buttons = buttons.replace("start", "") result |= button_masks["start"] if "select" in buttons: - buttons.replace("select", "") + buttons = buttons.replace("select", "") result |= button_masks["select"] + # allow for the "a, b" and "a b" formats + if ", " in buttons: + buttons = buttons.split(", ") + elif " " in buttons: + buttons = buttons.split(" ") + if isinstance(buttons, list): if len(buttons) > 9: raise Exception("can't combine more than 9 buttons at a time") @@ -429,7 +435,7 @@ def set_memory_at(address, value): """ Gb.setMemoryAt(address, value) -def press(buttons, steplimit=1): +def press(buttons, holdsteps=1, aftersteps=1): """ Press a button. Use steplimit to say for how many steps you want to press the button (try leaving it at the default, 1). @@ -440,9 +446,14 @@ def press(buttons, steplimit=1): number = buttons else: number = buttons - for step_counter in range(0, steplimit): + for step_counter in range(0, holdsteps): Gb.step(number) + # clear the button press + if aftersteps > 0: + for step_counter in range(0, aftersteps): + Gb.step(0) + def get_buttons(): """ Returns the currentButtons[0] value (an integer with bits set for which @@ -702,6 +713,26 @@ class crystal: """ @staticmethod + def text_wait(step_size=10, max_wait=500): + """ + Watches for a sign that text is done being drawn to screen, then + presses the "A" button. + + :param step_size: number of steps per wait loop + :param max_wait: number of wait loops to perform + """ + for x in range(0, max_wait): + hi = get_memory_at(registers.sp + 1) + lo = get_memory_at(registers.sp) + address = ((hi << 8) | lo) + if address == 0xaef: + break + else: + nstep(step_size) + + press("a", holdsteps=50, aftersteps=1) + + @staticmethod def walk_through_walls_slow(): memory = get_memory() memory[0xC2FA] = 0 diff --git a/extras/vba_autoplayer.py b/extras/vba_autoplayer.py new file mode 100644 index 000000000..eafbff134 --- /dev/null +++ b/extras/vba_autoplayer.py @@ -0,0 +1,464 @@ +# -*- coding: utf-8 -*- +""" +Programmatic speedrun of Pokémon Crystal +""" +import os + +# bring in the emulator and basic tools +import vba + +def main(): + """ + Start the game. + """ + vba.load_rom() + + # get past the opening sequence + skip_intro() + + # walk to mom and handle her text + handle_mom() + + # walk to elm and do whatever he wants + handle_elm("totodile") + + new_bark_level_grind(10, skip=False) + +def skippable(func): + """ + Makes a function skippable by saving the state before and after the + function runs. Pass "skip=True" to the function to load the previous save + state from when the function finished. + """ + def wrapped_function(*args, **kwargs): + skip = True + + if "skip" in kwargs.keys(): + skip = kwargs["skip"] + del kwargs["skip"] + + # override skip if there's no save + if skip: + full_name = func.__name__ + "-end.sav" + if not os.path.exists(os.path.join(vba.save_state_path, full_name)): + skip = False + + return_value = None + + if not skip: + vba.save_state(func.__name__ + "-start", override=True) + return_value = func(*args, **kwargs) + vba.save_state(func.__name__ + "-end", override=True) + elif skip: + vba.set_state(vba.load_state(func.__name__ + "-end")) + + return return_value + return wrapped_function + +@skippable +def skip_intro(): + """ + Skip the game boot intro sequence. + """ + # copyright sequence + vba.nstep(400) + + # skip the ditto sequence + vba.press("a") + vba.nstep(100) + + # skip the start screen + vba.press("start") + vba.nstep(100) + + # click "new game" + vba.press("a", holdsteps=50, aftersteps=1) + + # Are you a boy? Or are you a girl? + vba.nstep(145) + + # pick "boy" + vba.press("a", holdsteps=50, aftersteps=1) + + # .... + vba.crystal.text_wait() + + vba.crystal.text_wait() + + # What time is it? + vba.crystal.text_wait() + + # DAY 10 o'clock + vba.press("a", holdsteps=50, aftersteps=1) + + # WHAT? DAY 10 o'clock? YES/NO. + vba.press("a", holdsteps=50, aftersteps=1) + + # How many minutes? 0 min. + vba.press("a", holdsteps=50, aftersteps=1) + + # Whoa! 0 min.? YES/NO. + vba.press("a", holdsteps=50, aftersteps=1) + + vba.crystal.text_wait() + vba.crystal.text_wait() + + # People call me + vba.crystal.text_wait() + vba.crystal.text_wait() + + # tures that we call + vba.crystal.text_wait() + + vba.crystal.text_wait() + vba.crystal.text_wait() + + vba.crystal.text_wait() + vba.crystal.text_wait() + + vba.crystal.text_wait() + + # everything about pokemon yet. + vba.crystal.text_wait() + vba.crystal.text_wait() + + vba.crystal.text_wait() + vba.crystal.text_wait() + vba.crystal.text_wait() + vba.crystal.text_wait() + + # Now, what did you say your name was? + vba.crystal.text_wait() + + # move down to "CHRIS" + vba.press("d") + vba.nstep(50) + + vba.press("a", holdsteps=50, aftersteps=1) + + vba.crystal.text_wait() + vba.crystal.text_wait() + vba.crystal.text_wait() + vba.crystal.text_wait() + vba.crystal.text_wait() + vba.crystal.text_wait() + vba.crystal.text_wait() + + # wait until playable + # could be 150, but it sometimes takes longer?? + vba.nstep(200) + + return + +@skippable +def handle_mom(): + """ + Walk to mom. Handle her speech and questions. + """ + vba.press("r"); vba.nstep(50) + vba.press("r"); vba.nstep(50) + vba.press("r"); vba.nstep(50) + vba.press("r"); vba.nstep(50) + vba.press("r"); vba.nstep(50) + vba.press("u"); vba.nstep(50) + vba.press("u"); vba.nstep(50) + vba.press("u"); vba.nstep(50) + vba.press("u"); vba.nstep(50) + + # wait for next map to load + vba.nstep(50) + + vba.press("d"); vba.nstep(50) + vba.press("d"); vba.nstep(50) + vba.press("d"); vba.nstep(50) + + # walk into mom's line of sight + vba.press("d"); vba.nstep(50) + + vba.nstep(50) + vba.crystal.text_wait() + vba.crystal.text_wait() + vba.crystal.text_wait() + vba.crystal.text_wait() + vba.crystal.text_wait() + vba.crystal.text_wait() + vba.crystal.text_wait() + vba.crystal.text_wait() + vba.crystal.text_wait() + vba.crystal.text_wait() + vba.crystal.text_wait() + vba.crystal.text_wait() + + # What day is it? SUNDAY. + vba.press("a", holdsteps=50, aftersteps=1) + + # SUNDAY, is it? YES/NO + vba.press("a", holdsteps=50, aftersteps=1) + + vba.nstep(200) + + # is it DST now? YES/NO. + vba.press("a", holdsteps=50, aftersteps=1) + + # 10:06 AM DST, is that OK? YES/NO. + vba.press("a", holdsteps=50, aftersteps=1) + + vba.crystal.text_wait() + vba.crystal.text_wait() + vba.crystal.text_wait() + + # know how to use the PHONE? YES/NO. + vba.press("a", holdsteps=50, aftersteps=1) + + vba.crystal.text_wait() + vba.crystal.text_wait() + vba.crystal.text_wait() + vba.crystal.text_wait() + + vba.press("a", holdsteps=50, aftersteps=1) + + # have to wait for her to move back :( + vba.nstep(50) + + # face down + vba.press("d"); vba.nstep(50) + + return + +@skippable +def handle_elm(starter_choice): + """ + Walk to Elm's Lab and get a starter. + """ + + # walk down + vba.press("d"); vba.nstep(50) + vba.press("d"); vba.nstep(50) + + # face left + vba.press("l"); vba.nstep(50) + + # walk left + vba.press("l"); vba.nstep(50) + vba.press("l"); vba.nstep(50) + + # face down + vba.press("d"); vba.nstep(50) + + # walk down + vba.press("d"); vba.nstep(50) + + # walk down to warp to outside + vba.press("d"); vba.nstep(50) + vba.nstep(10) + + vba.press("l", holdsteps=10, aftersteps=50) + vba.press("l", holdsteps=10, aftersteps=50) + vba.press("l", holdsteps=10, aftersteps=50) + + vba.press("l", holdsteps=10, aftersteps=50) + vba.press("l", holdsteps=10, aftersteps=50) + vba.press("l", holdsteps=10, aftersteps=50) + vba.press("l", holdsteps=10, aftersteps=50) + + vba.press("u", holdsteps=10, aftersteps=50) + vba.press("u", holdsteps=10, aftersteps=50) + + # warp into elm's lab (bottom left warp) + vba.press("u", holdsteps=5, aftersteps=50) + + # let the script play + vba.nstep(200) + + vba.crystal.text_wait() + # I needed to ask you a fa + + vba.crystal.text_wait() + vba.crystal.text_wait() + vba.crystal.text_wait() + vba.crystal.text_wait() + vba.crystal.text_wait() + vba.crystal.text_wait() + vba.crystal.text_wait() + vba.crystal.text_wait() + vba.crystal.text_wait() + vba.crystal.text_wait() + vba.crystal.text_wait() + + vba.nstep(50) + + # YES/NO. + vba.press("a") + + vba.crystal.text_wait() + vba.crystal.text_wait() + vba.crystal.text_wait() + vba.crystal.text_wait() + vba.crystal.text_wait() + + vba.press("a") + + vba.crystal.text_wait() + vba.crystal.text_wait() + vba.press("a") + vba.crystal.text_wait() + vba.crystal.text_wait() + + vba.crystal.text_wait() + + for x in range(0, 8): # was 15 + vba.crystal.text_wait() + + vba.nstep(50) + vba.press("a") + vba.nstep(100) + + vba.crystal.text_wait() + vba.crystal.text_wait() + vba.crystal.text_wait() + vba.crystal.text_wait() + + # Go on! Pick one. + vba.nstep(100) + vba.press("a"); vba.nstep(50) + + vba.press("r"); vba.nstep(50) + vba.press("r"); vba.nstep(50) + + right = 0 + if starter_choice in [1, "cyndaquil"]: + right = 0 + elif starter_choice in [2, "totodile"]: + right = 1 + elif starter_choice in [3, "chikorita"]: + right = 2 + else: + raise Exception("bad starter") + + for each in range(0, right): + vba.press("r"); vba.nstep(50) + + # look up + vba.press("u", holdsteps=5, aftersteps=50) + + # get menu + vba.press("a", holdsteps=5, aftersteps=50) + + # let the image show + vba.nstep(100) + + vba.crystal.text_wait() + vba.crystal.text_wait() + + # YES/NO. + vba.press("a") + + vba.crystal.text_wait() + vba.crystal.text_wait() + + # received.. music is playing. + vba.press("a") + vba.crystal.text_wait() + + # YES/NO (nickname) + vba.crystal.text_wait() + + vba.press("b") + + # get back to elm + vba.nstep(100) + vba.nstep(100) + + vba.crystal.text_wait() + vba.crystal.text_wait() + vba.crystal.text_wait() + vba.crystal.text_wait() + vba.crystal.text_wait() + + # phone number.. + vba.press("a") + vba.crystal.text_wait() + vba.nstep(100) + vba.press("a") + vba.nstep(300) + vba.press("a") + vba.nstep(100) + + vba.crystal.text_wait() + vba.crystal.text_wait() + vba.crystal.text_wait() + + # I'm counting on you! + vba.nstep(200) + vba.press("a") + vba.nstep(50) + + # look down + vba.press("d", holdsteps=5, aftersteps=50) + + # walk down + vba.press("d", holdsteps=10, aftersteps=50) + + vba.press("d", holdsteps=10, aftersteps=50) + vba.press("d", holdsteps=10, aftersteps=50) + vba.press("d", holdsteps=10, aftersteps=50) + vba.press("d", holdsteps=10, aftersteps=50) + + vba.crystal.text_wait() + vba.crystal.text_wait() + + vba.press("a") + vba.nstep(50) + vba.press("a") + + vba.crystal.text_wait() + vba.crystal.text_wait() + + vba.press("a") + vba.nstep(50) + + vba.crystal.text_wait() + vba.press("a") + + vba.nstep(100) + + vba.press("d", holdsteps=10, aftersteps=50) + vba.press("d", holdsteps=10, aftersteps=50) + vba.press("d", holdsteps=10, aftersteps=50) + vba.press("d", holdsteps=10, aftersteps=50) + + # step outside + vba.nstep(40) + +@skippable +def new_bark_level_grind(level): + """ + Starting just outside of Elm's Lab, do some level grinding until the first + partymon level is equal to the given value.. + """ + + # walk to the grass area + new_bark_level_grind_walk_to_grass(skip=False) + + # TODO: walk around in grass, handle battles + # TODO: heal at the lab, then repeat entire function + +@skippable +def new_bark_level_grind_travel_to_grass(): + """ + Move to just above the grass. + """ + vba.press("d", holdsteps=10, aftersteps=50) + vba.press("d", holdsteps=10, aftersteps=50) + vba.press("d", holdsteps=10, aftersteps=50) + + vba.press("l", holdsteps=10, aftersteps=50) + vba.press("l", holdsteps=10, aftersteps=50) + vba.press("l", holdsteps=10, aftersteps=50) + vba.press("l", holdsteps=10, aftersteps=50) + + vba.press("d", holdsteps=10, aftersteps=50) + vba.press("d", holdsteps=10, aftersteps=50) + +if __name__ == "__main__": + main() @@ -60,7 +60,7 @@ INCBIN "baserom.gbc", $150, $283 - $150 VBlank: ; 283 -INCLUDE "vblank.asm" +INCLUDE "engine/vblank.asm" DelayFrame: ; 45a @@ -437,7 +437,7 @@ SetClock: ; 691 INCBIN "baserom.gbc", $6c4, $92e - $6c4 -INCLUDE "joypad.asm" +INCLUDE "engine/joypad.asm" INCBIN "baserom.gbc", $a1b, $b40 - $a1b @@ -12984,7 +12984,7 @@ GetFlag2: ; 80430 BitTable2: ; 80462 -INCLUDE "bittable2.asm" +INCLUDE "engine/bittable2.asm" ; 80648 @@ -14938,7 +14938,7 @@ INCLUDE "maps/second_map_headers.asm" INCBIN "baserom.gbc", $966b0, $96cb1 - $966b0 -INCLUDE "scripting.asm" +INCLUDE "engine/scripting.asm" INCBIN "baserom.gbc", $97c20, $35e @@ -19353,7 +19353,7 @@ INCBIN "gfx/intro/logo.lz" INCBIN "baserom.gbc", $10983f, $1099aa - $10983f ; Credits -INCLUDE "credits.asm" +INCLUDE "engine/credits.asm" SECTION "bank43",DATA,BANK[$43] @@ -21354,7 +21354,7 @@ MoveNames: INCLUDE "battle/move_names.asm" -INCLUDE "landmarks.asm" +INCLUDE "engine/landmarks.asm" RegionCheck: ; 0x1caea1 diff --git a/preprocessor.py b/preprocessor.py index bf9220a83..242732094 100644 --- a/preprocessor.py +++ b/preprocessor.py @@ -317,7 +317,7 @@ def separate_comment(l): break if l[i] == "\"": in_quotes = not in_quotes - return i + return l[:i], l[i:] or None def quote_translator(asm): """ @@ -574,12 +574,12 @@ def macro_translator(macro, token, line): def read_line(l): """Preprocesses a given line of asm.""" - # strip comments - asm, comment = l[:separate_comment(l)], l[separate_comment(l):] + # 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') + sys.stdout.write('GLOBAL ' + asm.split(':')[0] + '\n') # expect preprocessed .asm files if "INCLUDE" in asm: @@ -602,7 +602,8 @@ def read_line(l): macro_translator(macro, token, asm) else: sys.stdout.write(asm) - sys.stdout.write(comment) + + if comment: sys.stdout.write(comment) def preprocess(lines=None): """Main entry point for the preprocessor.""" diff --git a/prequeue.py b/prequeue.py index 991db7eb8..c90d133ea 100644 --- a/prequeue.py +++ b/prequeue.py @@ -1,11 +1,16 @@ +# coding: utf-8 + +# Starting a new python process to preprocess each source file +# creates too much overhead. Instead, a list of files to preprocess +# is fed into a script run from a single process. + import os import sys import preprocessor if __name__ == '__main__': - for source in sys.argv[1:]: - dest = os.path.splitext(source)[0] + '.tx' - sys.stdin = open(source, 'r') - sys.stdout = open(dest, 'w') - preprocessor.preprocess() - + for source in sys.argv[1:]: + dest = os.path.splitext(source)[0] + '.tx' + sys.stdin = open(source, 'r') + sys.stdout = open(dest, 'w') + preprocessor.preprocess() |