summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--INSTALL.md41
-rw-r--r--README.md2
-rw-r--r--constants.asm17
-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.py41
-rw-r--r--extras/vba_autoplayer.py464
-rw-r--r--main.asm12
-rw-r--r--preprocessor.py11
-rw-r--r--prequeue.py17
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)**.
diff --git a/README.md b/README.md
index d55a5a7b5..6adb65625 100644
--- a/README.md
+++ b/README.md
@@ -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()
diff --git a/main.asm b/main.asm
index 3dd69c930..df7433011 100644
--- a/main.asm
+++ b/main.asm
@@ -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()