Compare commits

..

No commits in common. "main" and "v1.0.0" have entirely different histories.
main ... v1.0.0

3 changed files with 105 additions and 80 deletions

View File

@ -1,5 +1,5 @@
# CC = /opt/gbdk/bin/lcc -Wa-l -Wl-m -Wl-j # CC = /opt/gbdk/bin/lcc -Wa-l -Wl-m -Wl-j
CC = ~/gbdk-2020/build/gbdk/bin/lcc -Wa-l -Wl-m -Wl-j CC = /Users/jasoncarpenter/gbdk-2020/build/gbdk/bin/lcc -Wa-l -Wl-m -Wl-j
BINS = comm.gb BINS = comm.gb

141
comm.c
View File

@ -40,18 +40,18 @@ unsigned char nicknames[11] = {
pokechar_E, pokechar_E,
pokechar_W, pokechar_W,
pokechar_STOP_BYTE, pokechar_STOP_BYTE,
pokechar_STOP_BYTE, pokechar_NULL_BYTE,
pokechar_STOP_BYTE, pokechar_NULL_BYTE,
pokechar_STOP_BYTE, pokechar_NULL_BYTE,
pokechar_STOP_BYTE, pokechar_NULL_BYTE,
pokechar_STOP_BYTE, pokechar_NULL_BYTE,
pokechar_STOP_BYTE, pokechar_NULL_BYTE,
pokechar_STOP_BYTE, pokechar_NULL_BYTE,
}; };
typedef struct TraderPacket { typedef struct TraderPacket {
// Name must not exceed 10 characters + 1 STOP_BYTE // Name must not exceed 10 characters + 1 STOP_BYTE
// Any leftover space must be filled with STOP_BYTE // Any leftover space after STOP_BYTE must be filled with NULL_BYTE
unsigned char name[11]; unsigned char name[11];
struct SelectedPokemon selected_pokemon; struct SelectedPokemon selected_pokemon;
struct PartyMember pokemon[6]; struct PartyMember pokemon[6];
@ -143,6 +143,12 @@ void trader_packet_to_bytes(struct TraderPacket *pTraderPacket, uint8_t *out) {
for (size_t i = 0; i < PARTY_SIZE; i++) { for (size_t i = 0; i < PARTY_SIZE; i++) {
uint8_t poke[POKE_SIZE]; uint8_t poke[POKE_SIZE];
party_member_to_bytes(&pTraderPacket->pokemon[i], poke); party_member_to_bytes(&pTraderPacket->pokemon[i], poke);
// Selected Pokemon Data (for listing and ordering without stats)
// if (poke[0] != 0x00) {
// pTraderPacket->selected_pokemon.number++;
// pTraderPacket->selected_pokemon.pokemon[i] = poke[0];
// }
// Full Party Data (all stats and such) // Full Party Data (all stats and such)
for (size_t j = 0; j < POKE_SIZE; j++) { for (size_t j = 0; j < POKE_SIZE; j++) {
@ -197,62 +203,67 @@ uint8_t handle_byte(uint8_t in, size_t *counter) {
switch (connection_state) switch (connection_state)
{ {
case NOT_CONNECTED: case NOT_CONNECTED:
switch (in) // printf("NC\n");
{ if(in == PKMN_MASTER) {
case PKMN_MASTER: out[0] = PKMN_SLAVE;
out[0] = PKMN_SLAVE; // printf("SLV\n");
break; }
case PKMN_BLANK: else if(in == PKMN_BLANK) {
out[0] = PKMN_BLANK; out[0] = PKMN_BLANK;
break; // printf("BNK\n");
case PKMN_CONNECTED: }
connection_state = CONNECTED; else if(in == PKMN_CONNECTED) {
out[0] = PKMN_CONNECTED; out[0] = PKMN_CONNECTED;
break; connection_state = CONNECTED;
// printf("CON\n");
} }
break; break;
case CONNECTED: case CONNECTED:
switch (in) //printf("Connected...\n");
{ if(in == PKMN_CONNECTED) {
case PKMN_CONNECTED: out[0] = PKMN_CONNECTED;
out[0] = PKMN_CONNECTED; // printf("CC\n");
break; }
case PKMN_TRADE_CENTRE: else if(in == PKMN_TRADE_CENTRE) {
// No byte known, just move on the next case connection_state = TRADE_CENTRE;
connection_state = TRADE_CENTRE; // printf("TC\n");
break; }
case PKMN_COLOSSEUM: else if(in == PKMN_COLOSSEUM) {
// No byte known, just move on the next case connection_state = COLOSSEUM;
// This case is not built out and I have no intention to do it // printf("COL\n");
connection_state = COLOSSEUM; }
break; else if(in == PKMN_BREAK_LINK || in == PKMN_MASTER) {
case PKMN_BREAK_LINK: connection_state = NOT_CONNECTED;
case PKMN_MASTER: out[0] = PKMN_BREAK_LINK;
connection_state = NOT_CONNECTED; // printf(in == PKMN_MASTER ? "PMR\n" : "PBL\n");
out[0] = PKMN_BREAK_LINK; } else {
break; out[0] = in;
// printf("echoing back after connected: %x\n", in);
default: // printf("EC1\n");
out[0] = in;
break;
} }
break; break;
case TRADE_CENTRE: case TRADE_CENTRE:
// printf("TCC\n");
if(trade_state == INIT && in == 0x00) { if(trade_state == INIT && in == 0x00) {
trade_state = READY; trade_state = READY;
out[0] = 0x00; out[0] = 0x00;
// printf("I\n");
} else if(trade_state == READY && in == 0xFD) { } else if(trade_state == READY && in == 0xFD) {
trade_state = DETECTED; trade_state = FIRST_DETECTED_WAIT;
out[0] = 0xFD; out[0] = 0xFD;
} else if(trade_state == DETECTED && in != 0xFD) { // printf("R\n");
} else if(trade_state == FIRST_DETECTED_WAIT && in != 0xFD) {
// random data of slave is ignored.
out[0] = in; out[0] = in;
trade_state = DATA_TX_RANDOM; trade_state = DATA_TX_RANDOM;
// printf("DRD\n");
} else if(trade_state == DATA_TX_RANDOM && in == 0xFD) { } else if(trade_state == DATA_TX_RANDOM && in == 0xFD) {
trade_state = DATA_TX_WAIT; trade_state = DATA_TX_WAIT;
out[0] = 0xFD; out[0] = 0xFD;
(*counter) = 0; (*counter) = 0;
// printf("RDS\n");
} else if (trade_state == DATA_TX_WAIT && in == 0xFD) { } else if (trade_state == DATA_TX_WAIT && in == 0xFD) {
out[0] = 0x00; out[0] = 0x00;
} else if(trade_state == DATA_TX_WAIT && in != 0xFD) { } else if(trade_state == DATA_TX_WAIT && in != 0xFD) {
@ -262,6 +273,7 @@ uint8_t handle_byte(uint8_t in, size_t *counter) {
INPUT_BLOCK[(*counter)] = in; INPUT_BLOCK[(*counter)] = in;
trade_state = DATA_TX; trade_state = DATA_TX;
(*counter)++; (*counter)++;
// printf("SD1\n");
} else if(trade_state == DATA_TX) { } else if(trade_state == DATA_TX) {
out[0] = DATA_BLOCK[(*counter)]; out[0] = DATA_BLOCK[(*counter)];
INPUT_BLOCK[(*counter)] = in; INPUT_BLOCK[(*counter)] = in;
@ -269,46 +281,63 @@ uint8_t handle_byte(uint8_t in, size_t *counter) {
if((*counter) == 418) { if((*counter) == 418) {
trade_state = DATA_TX_PATCH; trade_state = DATA_TX_PATCH;
} }
// printf("SD2\n");
} else if(trade_state == DATA_TX_PATCH && in == 0xFD) { } else if(trade_state == DATA_TX_PATCH && in == 0xFD) {
(*counter) = 0; (*counter) = 0;
out[0] = 0xFD; out[0] = 0xFD;
// printf("SP\n");
} else if(trade_state == DATA_TX_PATCH && in != 0xFD) { } else if(trade_state == DATA_TX_PATCH && in != 0xFD) {
out[0] = in; out[0] = in;
(*counter)++; (*counter)++;
if((*counter) == 197) { if((*counter) == 197) {
trade_state = TRADE_WAIT; trade_state = TRADE_WAIT;
} }
(*counter) = 0;
// printf("SPW\n");
} else if(trade_state == TRADE_WAIT && (in & 0x60) == 0x60) { } else if(trade_state == TRADE_WAIT && (in & 0x60) == 0x60) {
if (in == 0x6f) { if (in == 0x6f) {
trade_state = READY; trade_state = READY;
out[0] = 0x6f; out[0] = 0x6f;
// printf("MR\n");
} else { } else {
out[0] = 0x60; out[0] = 0x60; // first pokemon
trade_pokemon = in - 0x60; trade_pokemon = in - 0x60;
// printf("MFP\n");
} }
} else if(trade_state == TRADE_WAIT && in == 0x00) { } else if(trade_state == TRADE_WAIT && in == 0x00) {
out[0] = 0; out[0] = 0;
trade_state = TRADE_DONE; trade_state = TRADE_DONE;
// printf("TWD\n");
// printf("Sent the Gameboy:\n");
// printf("Gameboy Sent:\n");
// printf("Trade done\n");
} else if(trade_state == TRADE_DONE && (in & 0x60) == 0x60) { } else if(trade_state == TRADE_DONE && (in & 0x60) == 0x60) {
out[0] = in; out[0] = in;
if (in == 0x61) { if (in == 0x61) {
trade_pokemon = -1; trade_pokemon = -1;
trade_state = TRADE_WAIT; trade_state = TRADE_WAIT;
// printf("TDW\n");
} else { } else {
trade_state = DONE; trade_state = DONE;
// printf("TD\n");
} }
} else if(trade_state == DONE && in == 0x00) { } else if(trade_state == DONE && in == 0x00) {
out[0] = 0; out[0] = 0;
trade_state = INIT; trade_state = INIT;
// printf("DRI\n");
} else { } else {
out[0] = in; out[0] = in;
// printf("EC2\n");
} }
break; break;
default: default:
out[0] = in; out[0] = in;
// printf("EC3\n");
break; break;
} }
// printf(" %x %x\n", in, out[0]);
return out[0]; return out[0];
} }
@ -401,6 +430,8 @@ void main(void)
puts("Poke Distribution"); puts("Poke Distribution");
puts("Copyright 2023"); puts("Copyright 2023");
puts("BreadCodes"); puts("BreadCodes");
puts("");
puts("Reset: Press Button");
size_t trade_counter = 0; size_t trade_counter = 0;
while(1) { while(1) {
@ -418,19 +449,13 @@ void main(void)
__endasm; __endasm;
} }
// trade_byte_primary(); trade_byte();
// See https://github.com/gbdk-2020/gbdk-2020/pull/577
__asm
LD A,#0x02 ; .IO_RECEIVING
LD (__io_status),A ; Store status
LD A,#0x01
LDH (0x02),A ; (.SC) Use external clock
LD A,(__io_out)
LDH (0x01),A ; (.SB) Send __io_out byte
LD A,#0x81
LDH (0x02),A ; (.SC) Use external clock
__endasm;
while(_io_status == IO_RECEIVING || _io_status == IO_SENDING); while(_io_status == IO_RECEIVING || _io_status == IO_SENDING);
if (joypad() > 0) {
connection_state = NOT_CONNECTED;
trade_state = INIT;
}
} }
} }

42
gen1.h
View File

@ -195,19 +195,19 @@ enum connection_state_t {
enum trade_state_t { enum trade_state_t {
INIT = 0x00, INIT = 0x00,
READY = 0x01, READY = 0x01,
DETECTED = 0x02, FIRST_DETECTED_WAIT = 0x02,
DATA_TX = 0x03, DATA_TX = 0x03,
DATA_TX_WAIT = 0x04, DATA_TX_WAIT = 0x04,
DATA_TX_WAIT_HOLD = 0x05, DATA_TX_WAIT_HOLD = 0x0B,
DATA_TX_START = 0x06, DATA_TX_START = 0x05,
DATA_TX_RANDOM = 0x07, DATA_TX_RANDOM = 0x06,
DATA_TX_PATCH = 0x08, DATA_TX_PATCH = 0x07,
TRADE_WAIT = 0x09, TRADE_WAIT = 0x08,
TRADE_DONE = 0x0A, TRADE_DONE = 0x09,
DONE = 0x0B DONE = 0x0A
}; };
enum gen_one_dex_t { enum GenOneDex {
NULL_POKEMON = 0xFF, NULL_POKEMON = 0xFF,
RHYDON = 0x01, RHYDON = 0x01,
KANGASKHAN = 0x02, KANGASKHAN = 0x02,
@ -362,7 +362,7 @@ enum gen_one_dex_t {
VICTREEBEL = 0xBE, VICTREEBEL = 0xBE,
}; };
enum poke_move_t { enum PokemonMove {
ABSORB = 0x47, ABSORB = 0x47,
ACID = 0x33, ACID = 0x33,
ACID_ARMOR = 0x97, ACID_ARMOR = 0x97,
@ -530,7 +530,7 @@ enum poke_move_t {
WRAP = 0x23, WRAP = 0x23,
}; };
enum status_condition_t { enum StatusCondition {
NONE = 0x00, NONE = 0x00,
ASLEEP = 0x04, ASLEEP = 0x04,
BURNED = 0x10, BURNED = 0x10,
@ -539,7 +539,7 @@ enum status_condition_t {
POISONED = 0x08, POISONED = 0x08,
}; };
enum poke_type_t { enum PokemonType {
NORMAL = 0x00, NORMAL = 0x00,
FIGHTING = 0x01, FIGHTING = 0x01,
FLYING = 0x02, FLYING = 0x02,
@ -560,25 +560,25 @@ enum poke_type_t {
typedef struct SelectedPokemon { typedef struct SelectedPokemon {
// Number of pokemon in the trainer's party // Number of pokemon in the trainer's party
uint8_t number; uint8_t number;
enum gen_one_dex_t pokemon[6]; enum GenOneDex pokemon[6];
} SelectedPokemon; } SelectedPokemon;
// Luckily it follows the save file structure closely enough // Luckily it follows the save file structure closely enough
// https://bulbapedia.bulbagarden.net/wiki/Pok%C3%A9mon_data_structure_(Generation_I) // https://bulbapedia.bulbagarden.net/wiki/Pok%C3%A9mon_data_structure_(Generation_I)
typedef struct PartyMember { typedef struct PartyMember {
enum gen_one_dex_t pokemon; enum GenOneDex pokemon;
uint16_t current_hp; uint16_t current_hp;
uint16_t max_hp; uint16_t max_hp;
uint8_t level; uint8_t level;
enum status_condition_t status; enum StatusCondition status;
enum poke_type_t type1; enum PokemonType type1;
enum poke_type_t type2; // If only one type, copy the first enum PokemonType type2; // If only one type, copy the first
uint8_t catch_rate_or_held_item; // R/G/B/Y (catch rate), G/S/C (held item), and Stadium (held item) use this byte differently uint8_t catch_rate_or_held_item; // R/G/B/Y (catch rate), G/S/C (held item), and Stadium (held item) use this byte differently
enum poke_move_t move1; enum PokemonMove move1;
enum poke_move_t move2; enum PokemonMove move2;
enum poke_move_t move3; enum PokemonMove move3;
enum poke_move_t move4; enum PokemonMove move4;
uint16_t original_trainer_id; // In decimal, these are the funny numbers uint16_t original_trainer_id; // In decimal, these are the funny numbers
// - Experience is complicated. You must look up the Pokemon you are trying to trade // - Experience is complicated. You must look up the Pokemon you are trying to trade