mirror of
https://github.com/pret/pokeyellow.git
synced 2026-09-08 10:35:22 -05:00
pokemon: Stage 5b — _AddPartyMon (player gift path), validated
Wrote _AddPartyMon fresh (src/engine/pokemon/add_party_mon.asm) for the player, non-battle gift path rather than reusing the broken swarm draft in add_mon.asm (which references the not-yet-ported Moves table and the same flat-table-via-EBP pattern). Faithful translation of engine/pokemon/add_mon.asm:_AddPartyMon: appends the party-list entry + 0xFF terminator, copies the OT name, then writes the 44-byte party_struct — species, random DVs, current HP = max HP (CalcStat), box level/status, types + catch rate, level-1 moves, OT id, experience (CalcExperience), EVs zeroed, level, and a fresh CalcStats stat block. Validated natively (ELF32 harness): adding a level-5 Bulbasaur to an empty party yields count=1, species list 0x99/0xFF, struct species 0x99, level 5, exp 135 (= CalcExperience(5), Medium Slow), curHP==maxHP=19, stats 19/9/9/9/11 (exact for DV=0, cross-checked against the formula with the read-back DVs), types 22/3 (Grass/Poison), moves 33/45 (Tackle/Growl). Documented stubs (TODO): move PP written as 0 (needs the Moves table, Stage 6); OT id 0 (needs pokeyellow.sym for wPlayerID); WriteMonMoves level-up learnset (keeps level-1 base moves — correct for low levels); Pokédex flags / AskName; enemy-party and wild-caught (wIsInBattle) paths. Also wired src/home/array.asm (AddNTimes/SkipFixedLengthTextEntries) into the build and fixed its `extern NAME_LENGTH` to include gb_constants.inc instead. Full project + DEBUG_CALCSTATS gate both build and link. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GcHpAsg8pwsVATD6LWPsoR
This commit is contained in:
@@ -68,10 +68,15 @@ in UPPERCASE (`W_PARTY_COUNT`).
|
||||
1000000/1059860/800000/1250000). The draft had THREE bugs: systematic `hli`
|
||||
inversion (read wrong GrowthRateTable bytes), flat-table double-`ebp`
|
||||
(segfault), and reliance on the broken `_Divide`/`Multiply` (fixed Stage 3).
|
||||
- [ ] `_AddPartyMon` (the core creation routine — next).
|
||||
- [ ] wire/audit `load_mon_data`, `set_types`, `remove_mon`. `_AddPartyMon`
|
||||
from `engine/pokemon/add_mon.asm:1` (stub `AskName`/Pokédex); verify by adding
|
||||
a known mon and dumping its party_struct.
|
||||
- [x] `_AddPartyMon` — written fresh (`src/engine/pokemon/add_party_mon.asm`,
|
||||
player non-battle gift path) rather than reusing the broken draft. Validated
|
||||
natively: adds L5 Bulbasaur → count 1, species list correct, struct species
|
||||
0x99, level 5, exp 135 (`CalcExperience(5)`), curHP==maxHP, stats `19/9/9/9/11`
|
||||
(exact for DV=0), types Grass/Poison, moves Tackle/Growl. Wired into Makefile
|
||||
(also wired `array.asm`, fixed its `NAME_LENGTH` extern → `gb_constants.inc`).
|
||||
Stubs (TODO): PP=0 (needs Moves table), OT id=0 (needs sym), WriteMonMoves/
|
||||
Pokédex/AskName/enemy+wild paths.
|
||||
- [ ] wire/audit `load_mon_data`, `set_types`, `remove_mon` (Stage 5 tail).
|
||||
|
||||
- [ ] **Stage 6 — Evolution / learnset / PC.** Generate `EvosMovesPointerTable` +
|
||||
`MonsterNames`; wire `evos_moves.asm` (`WriteMonMoves`/`GetMonLearnset` needed by
|
||||
|
||||
@@ -110,9 +110,11 @@ POKEMON_SRCS := \
|
||||
src/data/pokemon_data.asm \
|
||||
src/home/math.asm \
|
||||
src/engine/math/multiply_divide.asm \
|
||||
src/home/array.asm \
|
||||
src/home/pokemon.asm \
|
||||
src/home/move_mon.asm \
|
||||
src/engine/pokemon/experience.asm
|
||||
src/engine/pokemon/experience.asm \
|
||||
src/engine/pokemon/add_party_mon.asm
|
||||
|
||||
# Debug-only sources (linked only when the corresponding flag is set).
|
||||
# Any debug flag implies SKIP_TITLE — debug harnesses boot straight to the overworld.
|
||||
|
||||
@@ -142,6 +142,7 @@ wPartySpecies equ 0xD163 ; wPartyCount+1; 6 species + $FF sentinel
|
||||
wPartyMons equ 0xD16A
|
||||
wPartyMonOT equ 0xD272
|
||||
wPartyMonNicks equ 0xD2B4
|
||||
wPlayerName equ 0xD157 ; = W_PLAYER_NAME (OT name source)
|
||||
|
||||
; Sprite state data — 16 slots × $10 bytes each, two parallel arrays.
|
||||
; wSpriteStateData1 ($C100) and wSpriteStateData2 ($C200) — sym-verified.
|
||||
|
||||
198
dos_port/src/engine/pokemon/add_party_mon.asm
Normal file
198
dos_port/src/engine/pokemon/add_party_mon.asm
Normal file
@@ -0,0 +1,198 @@
|
||||
; add_party_mon.asm — _AddPartyMon (Pokémon data/stats plan, Stage 5).
|
||||
;
|
||||
; Source: engine/pokemon/add_mon.asm:_AddPartyMon (player, non-battle path).
|
||||
;
|
||||
; Adds a new mon to the PLAYER's party (wMonDataLocation low nibble = 0), the
|
||||
; non-battle gift/normal path. Caller sets wCurPartySpecies and wCurEnemyLevel.
|
||||
; Writes the party-list entry + the 44-byte party_struct (species, random DVs,
|
||||
; current HP = max HP, box level/status, types, level-1 moves, OT, experience,
|
||||
; level, fresh stats). Returns CF set on success, CF clear if the party is full.
|
||||
;
|
||||
; DEFERRED (TODO):
|
||||
; - Enemy party + wild-caught (wIsInBattle) paths — need wEnemyParty*/wIsInBattle
|
||||
; addresses (pending pokeyellow.sym).
|
||||
; - WriteMonMoves (level-up learnset): the level-1 base moves are kept (correct
|
||||
; for low-level mons); needs the evos_moves audit (Stage 6).
|
||||
; - Move PP: written as 0 (needs the Moves table, Stage 6); de still advances 4.
|
||||
; - Pokédex owned/seen flags and AskName naming — skipped (no effect on stats).
|
||||
; - OT id written as 0 (wPlayerID address pending the sym).
|
||||
;
|
||||
; Register map: a=AL, b=BH, c=BL, d=DH, hl=ESI, de=EDX, bc=EBX.
|
||||
|
||||
bits 32
|
||||
|
||||
%include "gb_memmap.inc"
|
||||
%include "gb_constants.inc"
|
||||
|
||||
extern GetMonHeader
|
||||
extern CalcStat
|
||||
extern CalcStats
|
||||
extern CalcExperience
|
||||
extern Random_
|
||||
extern SkipFixedLengthTextEntries
|
||||
extern CopyData
|
||||
extern AddNTimes
|
||||
|
||||
global _AddPartyMon
|
||||
|
||||
section .text
|
||||
|
||||
_AddPartyMon:
|
||||
mov al, [ebp + wPartyCount]
|
||||
inc al
|
||||
cmp al, PARTY_LENGTH + 1
|
||||
jc .notFull
|
||||
ret ; party full (ret nc): CF clear
|
||||
.notFull:
|
||||
mov [ebp + wPartyCount], al ; new count (doubles as hNewPartyLength)
|
||||
|
||||
; append species: edx = wPartyCount + count -> &wPartySpecies[count-1]
|
||||
movzx ecx, al
|
||||
lea edx, [wPartyCount + ecx]
|
||||
mov al, [ebp + wCurPartySpecies]
|
||||
mov [ebp + edx], al
|
||||
inc edx
|
||||
mov byte [ebp + edx], 0xFF ; list terminator
|
||||
|
||||
; OT name slot: esi = wPartyMonOT + (count-1)*NAME_LENGTH
|
||||
mov esi, wPartyMonOT
|
||||
mov al, [ebp + wPartyCount]
|
||||
dec al
|
||||
call SkipFixedLengthTextEntries
|
||||
mov edx, esi ; de = OT dest
|
||||
mov esi, wPlayerName
|
||||
mov bx, NAME_LENGTH
|
||||
call CopyData
|
||||
|
||||
; esi = wPartyMons + (count-1)*PARTYMON_STRUCT_LENGTH
|
||||
mov esi, wPartyMons
|
||||
mov al, [ebp + wPartyCount]
|
||||
dec al
|
||||
mov bx, PARTYMON_STRUCT_LENGTH
|
||||
call AddNTimes
|
||||
mov edx, esi ; de = struct start (write cursor)
|
||||
push esi ; [S1] struct ptr (for final CalcStats)
|
||||
|
||||
; species byte (internal index)
|
||||
mov al, [ebp + wCurPartySpecies]
|
||||
mov [ebp + wCurSpecies], al
|
||||
call GetMonHeader
|
||||
mov al, [ebp + wMonHeader]
|
||||
mov [ebp + edx], al
|
||||
inc edx ; de = struct+1
|
||||
|
||||
; random DVs (non-battle): bh = 1st byte, al = 2nd byte
|
||||
call Random_
|
||||
mov bh, al
|
||||
call Random_
|
||||
mov esi, [esp] ; struct ptr
|
||||
add esi, MON_DVS
|
||||
mov [ebp + esi], al ; DV byte 0
|
||||
inc esi
|
||||
mov [ebp + esi], bh ; DV byte 1
|
||||
|
||||
; current HP = max HP: CalcStat(c=1 HP, b=0)
|
||||
mov esi, [esp]
|
||||
add esi, MON_HP_EXP - 1
|
||||
mov bl, 1
|
||||
mov bh, 0
|
||||
call CalcStat
|
||||
mov al, [ebp + H_MULTIPLICAND + 1]
|
||||
mov [ebp + edx], al
|
||||
inc edx
|
||||
mov al, [ebp + H_MULTIPLICAND + 2]
|
||||
mov [ebp + edx], al
|
||||
inc edx ; de = struct+3
|
||||
xor al, al
|
||||
mov [ebp + edx], al ; box level 0
|
||||
inc edx
|
||||
mov [ebp + edx], al ; status 0
|
||||
inc edx ; de = struct+5
|
||||
|
||||
; types + catch rate from wMonHTypes
|
||||
mov esi, wMonHTypes
|
||||
mov al, [ebp + esi]
|
||||
inc esi
|
||||
mov [ebp + edx], al ; type1
|
||||
inc edx
|
||||
mov al, [ebp + esi]
|
||||
inc esi
|
||||
mov [ebp + edx], al ; type2
|
||||
inc edx
|
||||
mov al, [ebp + esi]
|
||||
mov [ebp + edx], al ; catch rate (de not yet incremented)
|
||||
|
||||
; level-1 moves from wMonHMoves
|
||||
mov esi, wMonHMoves
|
||||
mov al, [ebp + esi]
|
||||
inc esi
|
||||
inc edx ; de = struct+8 (MON_MOVES)
|
||||
push edx ; [S2] moves ptr (for PP)
|
||||
mov [ebp + edx], al
|
||||
mov al, [ebp + esi]
|
||||
inc esi
|
||||
inc edx
|
||||
mov [ebp + edx], al
|
||||
mov al, [ebp + esi]
|
||||
inc esi
|
||||
inc edx
|
||||
mov [ebp + edx], al
|
||||
mov al, [ebp + esi]
|
||||
inc esi
|
||||
inc edx
|
||||
mov [ebp + edx], al ; de = struct+11
|
||||
|
||||
; OT id (stub 0)
|
||||
inc edx
|
||||
mov byte [ebp + edx], 0 ; OTID hi (struct+12)
|
||||
inc edx
|
||||
mov byte [ebp + edx], 0 ; OTID lo (struct+13)
|
||||
|
||||
; experience = CalcExperience(level)
|
||||
push edx ; [S3]
|
||||
mov al, [ebp + wCurEnemyLevel]
|
||||
mov dh, al
|
||||
call CalcExperience
|
||||
pop edx ; [S3]
|
||||
inc edx
|
||||
mov al, [ebp + H_EXPERIENCE]
|
||||
mov [ebp + edx], al ; exp hi (struct+14)
|
||||
inc edx
|
||||
mov al, [ebp + H_EXPERIENCE + 1]
|
||||
mov [ebp + edx], al
|
||||
inc edx
|
||||
mov al, [ebp + H_EXPERIENCE + 2]
|
||||
mov [ebp + edx], al ; de = struct+16
|
||||
|
||||
; zero EVs (NUM_STATS*2 bytes)
|
||||
mov bh, NUM_STATS * 2
|
||||
.evLoop:
|
||||
inc edx
|
||||
mov byte [ebp + edx], 0
|
||||
dec bh
|
||||
jnz .evLoop ; de = struct+0x1A
|
||||
|
||||
inc edx
|
||||
inc edx ; de = struct+0x1C
|
||||
pop esi ; [S2] moves ptr (PP stub doesn't use it; balances)
|
||||
; PP stub: advance de by NUM_MOVES, writing 0 (TODO real PP — Moves table)
|
||||
mov bh, NUM_MOVES
|
||||
.ppStub:
|
||||
inc edx
|
||||
mov byte [ebp + edx], 0
|
||||
dec bh
|
||||
jnz .ppStub ; de = struct+0x20
|
||||
|
||||
; level
|
||||
inc edx
|
||||
mov al, [ebp + wCurEnemyLevel]
|
||||
mov [ebp + edx], al ; struct+MON_LEVEL (0x21)
|
||||
inc edx ; de = struct+MON_STATS (0x22)
|
||||
|
||||
; fresh stats
|
||||
pop esi ; [S1] struct ptr
|
||||
add esi, MON_HP_EXP - 1
|
||||
mov bh, 0
|
||||
call CalcStats
|
||||
stc ; success
|
||||
ret
|
||||
@@ -1,9 +1,10 @@
|
||||
; dos_port/home/array.asm
|
||||
bits 32
|
||||
%include "gb_constants.inc" ; NAME_LENGTH
|
||||
|
||||
global SkipFixedLengthTextEntries
|
||||
global AddNTimes
|
||||
|
||||
extern NAME_LENGTH
|
||||
|
||||
section .text
|
||||
|
||||
; skips AL (A) text entries, each of size NAME_LENGTH
|
||||
|
||||
Reference in New Issue
Block a user