Allow more than 15 object_events per map - pret/pokecrystal GitHub Wiki
Map scripts in maps/*.asm declare new objects—NPCs, item balls, Berry trees, etc—with the object_event
macro. But you can't have more than 15 object_event
s in one map. (GoldenrodCity.asm reaches this limit, and four other maps nearly do with 14 object_event
s.) Turns out this is an easy limit to increase.
Edit constants/map_object_constants.asm (older versions of pokecrystal may have this bit in constants/wram_constants.asm):
MAPOBJECT_LENGTH EQU _RS
-NUM_OBJECTS EQU 16
+NUM_OBJECTS EQU 18
PLAYER_OBJECT EQU 0
And edit wram.asm:
- ds 40
+ ds 6
wMapObjects::
wPlayerObject:: map_object wPlayer ; player is map object 0
-; wMap1Object - wMap15Object
+; wMap1Object - wMap17Object
for n, 1, NUM_OBJECTS
wMap{d:n}Object:: map_object wMap{d:n}
endr
wObjectMasks:: ds NUM_OBJECTS
That's it! We just added space for maps to define 17 total object_event
s. (Plus the player object, making 18 total.) So you could, for example, add two more NPCs to make Goldenrod City feel busier.
Let's look at how it works. wMapObjects
is an array of map_object
structs, one for each possible object (including the player). You can see what data is stored for each map_object
in the macro definition in macros/wram.asm:
map_object: MACRO
\1ObjectStructID:: db
\1ObjectSprite:: db
\1ObjectYCoord:: db
\1ObjectXCoord:: db
\1ObjectMovement:: db
\1ObjectRadius:: db
\1ObjectHour:: db
\1ObjectTimeOfDay:: db
\1ObjectColor:: db
\1ObjectRange:: db
\1ObjectScript:: dw
\1ObjectEventFlag:: dw
ds 2
ENDM
This is all the same data that gets declared by the object_event
macro, defined in macros/scripts/maps.asm:
object_event: MACRO
;\1: x: left to right, starts at 0
;\2: y: top to bottom, starts at 0
;\3: sprite: a SPRITE_* constant
;\4: movement function: a SPRITEMOVEDATA_* constant
;\5, \6: movement radius: x, y
;\7, \8: hour limits: h1, h2 (0-23)
; * if h1 < h2, the object_event will only appear from h1 to h2
; * if h1 > h2, the object_event will not appear from h2 to h1
; * if h1 == h2, the object_event will always appear
; * if h1 == -1, h2 is treated as a time-of-day value:
; a combo of MORN, DAY, and/or NITE, or -1 to always appear
;\9: color: a PAL_NPC_* constant, or 0 for sprite default
;\<10>: function: a OBJECTTYPE_* constant
;\<11>: sight range: applies to OBJECTTYPE_TRAINER
;\<12>: script pointer
;\<13>: event flag: an EVENT_* constant, or -1 to always appear
db \3, \2 + 4, \1 + 4, \4
dn \6, \5
db \7, \8
dn \9, \<10>
db \<11>
dw \<12>, \<13>
; the dummy PlayerObjectTemplate object_event has no def_object_events
if DEF(_NUM_OBJECT_EVENTS)
{_NUM_OBJECT_EVENTS} += 1
endc
ENDM
wObjectMasks
is likewise an array of mask bytes, one for each possible object. If the mask is −1, the object is hidden.
Basically, the object_event
structs in the ROM get copied into the map_object
structs in RAM, so there needs to be enough space in RAM for all of them. And each new object needs 17 bytes—16 for its map_object
(count them), and one for its mask—so we had to use 34 of the unused bytes in that ds 40
.
If you wanted to allow an 18th object, you would have to find 17 bytes of unused space here and there in the same SECTION
as wMapObjects
and wObjectMasks
. Which is not difficult; if you scroll down to the "map scene ids
" and "fight counts
", they both have large chunks of unused space afterwards (ds 49
and ds 100
).