• Just a reminder that providing specifics on, sharing links to, or naming websites where ROMs can be accessed is against the rules. If your post has any of this information it will be removed.
  • Ever thought it'd be cool to have your art, writing, or challenge runs featured on PokéCommunity? Click here for info - we'd love to spotlight your work!
  • Which Pokémon Masters protagonist do you like most? Let us know by casting a vote in our Masters favorite protagonist poll here!
  • Red, Hilda, Paxton, or Kellyn - which Pokémon protagonist is your favorite? Let us know by voting in our poll!
  • Welcome to PokéCommunity! Register now and join one of the best fan communities on the 'net to talk Pokémon and more! We are not affiliated with The Pokémon Company or Nintendo.

Trading Pokemon From Fanmade Game To ROM

davidthefat

I Love C++
  • 437
    Posts
    15
    Years
    • Seen Mar 3, 2012
    This just dawned onto me, it IS possible to make a game that allowed trading and battling of pokemon from a fanmade game and a legit game (not totally, since its a rom...). Let me explain, we can look into the VBA link's source code and see how the GBA handles the connectivity. Then we can observe how the game it self handles the connections. Like during a battle, does it send the ID #s of the pokemon and and the move or does it send a string (a word, I guess thats the way to say it in plain english) containing the trainer's name and pokemon's name every time it attacks, or does it do it before the battle. Im saying its TOTALLY 100% accomplishable. If you are aware, OdinMS (first successful Maplestory Private Server (currently getting sued or something)) was developed this way, by observing the packets of data being transferred. I my self will not attempt to do (at least not yet) since I already have a project to do... But Im just putting the Idea out there that it is possible. Just won't be easy at all. I think it won't be hard modifying VBA Link to create a dump of everything that it transfers, just figuring it out is hard.


    This will be my next big project after my current one. I WILL attempt it, just not now.

    These codes are https://www.vbalink.info/ 's source codes for teh linking part of the emulator only
    Server's main.cpp

    Code:
    #define WIN32_LEAN_AND_MEAN
    
    #include<windows.h>
    #include<winsock.h>
    #include<stdio.h>
    
    #define BACKLOG 4
    
    SOCKET soocket[3];
    HANDLE threaad;
    HANDLE eveent;
    int errror = false;
    bool terminate = false;
    
    DWORD WINAPI ServerThread1(LPVOID);
    DWORD WINAPI ServerThread2(LPVOID);
    DWORD WINAPI ServerThread3(LPVOID);
    
    LPTHREAD_START_ROUTINE ServerThread[3] = {ServerThread1, ServerThread2, ServerThread3};
    
    int main(void){
        WSADATA wsadata;
        int i, players;
        SOCKADDR_IN serverinfo;
        LPHOSTENT kjh;
        IN_ADDR nji;
        char nameppp[100];
    
        printf("Select number of players (2-4): ");
        do {
            players = getchar() - '2';
        } while(players<0||players>2);
        
        if(WSAStartup(MAKEWORD(1, 1), &wsadata)!=0){
            printf("Winsock couldn't be initialized.\n");
            return 1;
        }
        
        for(i=0;i<3;i++){
            if((soocket[i]=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP))==INVALID_SOCKET){
                printf("Couldn't create socket (Error %d).\n", WSAGetLastError());
                WSACleanup();
                return 1;
            }
        }
    
        serverinfo.sin_family = AF_INET;
        serverinfo.sin_addr.S_un.S_addr = INADDR_ANY;
    
        for(i=0;i<3;i++){
            serverinfo.sin_port = htons(6478+i);
            if(bind(soocket[i], (SOCKADDR*)&serverinfo, sizeof(SOCKADDR_IN))==SOCKET_ERROR){
                for(i=0;i<3;i++)
                    closesocket(soocket[i]);
                printf("Error during bind(). Error code: %d\n", WSAGetLastError());
                WSACleanup();
                return 1;
            }
        }
    
        for(i=0;i<3;i++){
            if(listen(soocket[i], BACKLOG)==SOCKET_ERROR){
                printf("Error during listen(). Error code: %d\n", WSAGetLastError());
                for(i=0;i<3;i++)
                    closesocket(soocket[i]);
                WSACleanup();
                return 1;
            }
        }
    
        gethostname(nameppp, 100);
        kjh = gethostbyname(nameppp);
        memcpy(&nji, kjh->h_addr_list[0], sizeof(IN_ADDR));
        printf("Server address: %s\n", inet_ntoa(nji));
    
        if((threaad=CreateThread(NULL, 0, ServerThread[players], &i, 0, 0))==NULL){
            printf("Couldn't create server thread.\n");
                for(i=0;i<3;i++)
                    closesocket(soocket[i]);
                WSACleanup();
                return 1;
        }
        
        if((eveent=CreateEvent(NULL, true, false, NULL))==NULL){
            printf("Couldn't create event.\n");
            for(i=0;i<3;i++)
                    closesocket(soocket[i]);
            WSACleanup();
            return 1;
        }
    
        printf("VBALink server running...\n");
        
        WaitForSingleObject(eveent, INFINITE);
        if(errror){
            printf("Errrrrrrrrrrroooooooooooor!!!!!!!!!!!!!");
        }
        printf("Press enter.\n");
        getchar();
        
        for(i=0;i<3;i++){
            closesocket(soocket[i]);
        }
        terminate = true;
        CloseHandle(threaad);
        WSACleanup();
        return 0;
    }
    
    DWORD WINAPI ServerThread1(LPVOID number){
        SOCKET clientsocket[2];
        char buffer[32];
        int numbytes = 0;
        SOCKADDR_IN clientinfo;
        int sizee = sizeof(SOCKADDR_IN);
        if((clientsocket[0]=accept(soocket[0], (LPSOCKADDR)&clientinfo, &sizee))==INVALID_SOCKET){
            errror =true;
            ExitThread(0);
        }
    
        printf("Player #1 connected from %s\n", inet_ntoa(clientinfo.sin_addr));
    
        if((clientsocket[1]=accept(soocket[0], (LPSOCKADDR)&clientinfo, &sizee))==INVALID_SOCKET){
            errror =true;
            ExitThread(0);
        }
    
        printf("Player #2 connected from %s\n", inet_ntoa(clientinfo.sin_addr));
    
        buffer[0] = 0;
        send(clientsocket[0], buffer, 4, 0);
        buffer[0] = 1;
        send(clientsocket[1], buffer, 4, 0);
        printf("OK.\n");
        while(true){
            if(terminate){
                ExitThread(0);
            }
            numbytes = 0;
            while(numbytes<8){
                numbytes += recv(clientsocket[0], buffer+numbytes, 8, 0);
            }
            //putchar('k');
            if(buffer[0]=='S'||buffer[4]=='S'){
                send(clientsocket[1], buffer, 8, 0);
                closesocket(clientsocket[0]);
                closesocket(clientsocket[1]);
                SetEvent(eveent);
                ExitThread(0);
            }
            send(clientsocket[1], buffer, 8, 0);
            numbytes = 0;
            while(numbytes<4){
                numbytes += recv(clientsocket[1], buffer+numbytes, 4, 0);
            }
            if(buffer[0]=='S'){
                send(clientsocket[0], buffer, 8, 0);
                closesocket(clientsocket[0]);
                closesocket(clientsocket[1]);
                SetEvent(eveent);
                ExitThread(0);
            }
            send(clientsocket[0], buffer, 4, 0);
        }
        return 0;
    }
    
    DWORD WINAPI ServerThread2(LPVOID number){
        SOCKET clientsocket[3];
        char buffer[32];
        DWORD data[3] = {0, 0xffff434d, 0xffff834d};
        int numbytes = 0, linktime;
        SOCKADDR_IN clientinfo;
        int sizee = sizeof(SOCKADDR_IN);
        if((clientsocket[0]=accept(soocket[1], (LPSOCKADDR)&clientinfo, &sizee))==INVALID_SOCKET){
            errror =true;
            ExitThread(0);
        }
    
        printf("Player #1 connected from %s\n", inet_ntoa(clientinfo.sin_addr));
    
        if((clientsocket[1]=accept(soocket[1], (LPSOCKADDR)&clientinfo, &sizee))==INVALID_SOCKET){
            errror =true;
            ExitThread(0);
        }
    
        printf("Player #2 connected from %s\n", inet_ntoa(clientinfo.sin_addr));
    
        if((clientsocket[2]=accept(soocket[1], (LPSOCKADDR)&clientinfo, &sizee))==INVALID_SOCKET){
            errror =true;
            ExitThread(0);
        }
    
        printf("Player #3 connected from %s\n", inet_ntoa(clientinfo.sin_addr));
    
        buffer[0] = 0;
        send(clientsocket[0], buffer, 4, 0);
        buffer[0] = 1;
        send(clientsocket[1], buffer, 4, 0);
        buffer[0] = 2;
        send(clientsocket[2], buffer, 4, 0);
    
        printf("OK.\n");
    
        while(true){
            if(terminate){
                ExitThread(0);
            }
            numbytes = 0;
            while(numbytes<8){
                numbytes += recv(clientsocket[0], buffer+numbytes, 8, 0);
            }
            if(buffer[0]=='S'){
                send(clientsocket[1], buffer, 12, 0);
                send(clientsocket[2], buffer, 12, 0);
                closesocket(clientsocket[0]);
                closesocket(clientsocket[1]);
                closesocket(clientsocket[2]);
                SetEvent(eveent);
                ExitThread(0);
            }
    
            data[0] = *(DWORD*)buffer;
            linktime = *((int*)buffer+1);
            *((DWORD*)buffer+2) = data[2];
            send(clientsocket[1], buffer, 12, 0);
            
            *((DWORD*)buffer+2) = data[1];
            send(clientsocket[2], buffer, 12, 0);
    
            numbytes = 0;
            while(numbytes<4){
                numbytes += recv(clientsocket[1], buffer+numbytes, 4, 0);
            }
            if(buffer[0]=='S'){
                send(clientsocket[0], buffer, 8, 0);
                send(clientsocket[2], buffer, 12, 0);
                closesocket(clientsocket[0]);
                closesocket(clientsocket[1]);
                closesocket(clientsocket[2]);
                SetEvent(eveent);
                ExitThread(0);
            }
    
            data[1] = *(DWORD*)buffer;
            
            numbytes = 4;
            while(numbytes<8){
                numbytes += recv(clientsocket[2], buffer+numbytes, 4, 0);
            }
            if(buffer[0]=='S'){
                send(clientsocket[0], buffer, 8, 0);
                send(clientsocket[1], buffer, 12, 0);
                closesocket(clientsocket[0]);
                closesocket(clientsocket[1]);
                closesocket(clientsocket[2]);
                SetEvent(eveent);
                ExitThread(0);
            }
            data[2] = *((DWORD*)buffer+1);
            send(clientsocket[0], buffer, 8, 0);
    
        }
        return 0;
    }
    
    DWORD WINAPI ServerThread3(LPVOID number){
    SOCKET clientsocket[4];
        char buffer[32];
        DWORD data[4] = {0, 0xffff434d, 0xffff834d, 0xffffc34d};
        int numbytes = 0, linktime;
        SOCKADDR_IN clientinfo;
        int sizee = sizeof(SOCKADDR_IN);
        if((clientsocket[0]=accept(soocket[2], (LPSOCKADDR)&clientinfo, &sizee))==INVALID_SOCKET){
            errror =true;
            ExitThread(0);
        }
    
        printf("Player #1 connected from %s\n", inet_ntoa(clientinfo.sin_addr));
    
        if((clientsocket[1]=accept(soocket[2], (LPSOCKADDR)&clientinfo, &sizee))==INVALID_SOCKET){
            errror =true;
            ExitThread(0);
        }
    
        printf("Player #2 connected from %s\n", inet_ntoa(clientinfo.sin_addr));
    
        if((clientsocket[2]=accept(soocket[2], (LPSOCKADDR)&clientinfo, &sizee))==INVALID_SOCKET){
            errror =true;
            ExitThread(0);
        }
    
        printf("Player #3 connected from %s\n", inet_ntoa(clientinfo.sin_addr));
    
        if((clientsocket[3]=accept(soocket[2], (LPSOCKADDR)&clientinfo, &sizee))==INVALID_SOCKET){
            errror =true;
            ExitThread(0);
        }
    
        printf("Player #4 connected from %s\n", inet_ntoa(clientinfo.sin_addr));
    
        buffer[0] = 0;
        send(clientsocket[0], buffer, 4, 0);
        buffer[0] = 1;
        send(clientsocket[1], buffer, 4, 0);
        buffer[0] = 2;
        send(clientsocket[2], buffer, 4, 0);
        buffer[0] = 3;
        send(clientsocket[3], buffer, 4, 0);
    
        printf("OK.\n");
    
        while(true){
            if(terminate){
                ExitThread(0);
            }
            numbytes = 0;
            while(numbytes<8){
                numbytes += recv(clientsocket[0], buffer+numbytes, 8, 0);
            }
            if(buffer[0]=='S'){
                send(clientsocket[1], buffer, 16, 0);
                send(clientsocket[2], buffer, 16, 0);
                send(clientsocket[3], buffer, 16, 0);
                closesocket(clientsocket[0]);
                closesocket(clientsocket[1]);
                closesocket(clientsocket[2]);
                closesocket(clientsocket[3]);
                SetEvent(eveent);
                ExitThread(0);
            }
    
            data[0] = *(DWORD*)buffer;
            linktime = *((int*)buffer+1);
            *((DWORD*)buffer+2) = data[2];
            *((DWORD*)buffer+3) = data[3];
            send(clientsocket[1], buffer, 16, 0);
            
            *((DWORD*)buffer+2) = data[1];
            send(clientsocket[2], buffer, 16, 0);
    
            *((DWORD*)buffer+2) = data[2];
            *((DWORD*)buffer+3) = data[1];
            send(clientsocket[3], buffer, 16, 0);
    
            numbytes = 0;
            while(numbytes<4){
                numbytes += recv(clientsocket[1], buffer+numbytes, 4, 0);
            }
            if(buffer[0]=='S'){
                send(clientsocket[0], buffer, 12, 0);
                send(clientsocket[2], buffer, 16, 0);
                send(clientsocket[3], buffer, 16, 0);
                closesocket(clientsocket[0]);
                closesocket(clientsocket[1]);
                closesocket(clientsocket[2]);
                closesocket(clientsocket[3]);
                SetEvent(eveent);
                ExitThread(0);
            }
    
            data[1] = *(DWORD*)buffer;
            
            numbytes = 4;
            while(numbytes<8){
                numbytes += recv(clientsocket[2], buffer+numbytes, 4, 0);
            }
            if(buffer[0]=='S'){
                send(clientsocket[0], buffer, 12, 0);
                send(clientsocket[1], buffer, 16, 0);
                send(clientsocket[3], buffer, 16, 0);
                closesocket(clientsocket[0]);
                closesocket(clientsocket[1]);
                closesocket(clientsocket[2]);
                closesocket(clientsocket[3]);
                SetEvent(eveent);
                ExitThread(0);
            }
            
            data[2] = *((DWORD*)buffer+1);
    
            numbytes = 8;
            while(numbytes<12){
                numbytes += recv(clientsocket[3], buffer+numbytes, 4, 0);
            }
            if(buffer[0]=='S'){
                send(clientsocket[0], buffer, 12, 0);
                send(clientsocket[1], buffer, 16, 0);
                send(clientsocket[2], buffer, 16, 0);
                closesocket(clientsocket[0]);
                closesocket(clientsocket[1]);
                closesocket(clientsocket[2]);
                closesocket(clientsocket[3]);
                SetEvent(eveent);
                ExitThread(0);
            }
    
            data[3] = *((DWORD*)buffer+2);
            send(clientsocket[0], buffer, 12, 0);
    
        }
        return 0;
    }


    Link.cpp

    Code:
    // VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator.
    // Copyright (C) 1999-2003 Forgotten
    // Copyright (C) 2004 Forgotten and the VBA development team
    // This file was written by denopqrihg
    
    // This program is free software; you can redistribute it and/or modify
    // it under the terms of the GNU General Public License as published by
    // the Free Software Foundation; either version 2, or(at your option)
    // any later version.
    //
    // This program is distributed in the hope that it will be useful,
    // but WITHOUT ANY WARRANTY; without even the implied warranty of
    // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    // GNU General Public License for more details.
    //
    // You should have received a copy of the GNU General Public License
    // along with this program; if not, write to the Free Software Foundation,
    // Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
    
    // Link.cpp : Emulation of GBA link cable
    //
    
    #include "GBA.h"
    #include<stdio.h>
    #include<afxwin.h>
    #include "port.h"
    #include "Link.h"
    #include "win32/vba.h"
    #include "win32/MainWnd.h"
    
    #define UPDATE_REG(address, value) WRITE16LE(((u16 *)&ioMem[address]),value)
    #define LINK_ID1FINISH 2
    #define LINK_ID2FINISH 4
    #define GBLINK_READY 8
    
    int linktime = 0;
    u8 tspeed=3;
    u8 transfer=0;
    LINKDATA *linkmem=NULL;
    int linkid = 1;
    HANDLE linksync[4];
    extern int *extTicks;
    int savedlinktime=0;
    char inifile[] = "vba1.ini";
    HANDLE mmf=NULL;
    char linkevent[] = "VBA link event  ";
    static int i, j;
    int linktimeout = 500;
    int linklog = 0;
    FILE *jjj = NULL;
    LANLINKDATA lanlink;
    
    
    extern unsigned char *gbMemory;
    extern int gbInterrupt;
    
    int trspeed1[4] = {34080, 8520, 5680, 2840};
    int trspeed2[4] = {65536, 16384, 10923, 5461};
    int trspeed2_5[4] = {72527, 18132, 12088, 6044};
    int trspeed3[4] = {99609, 24903, 16602, 8301};
    int trspeed3_5[4] = {106608, 26652, 17768, 8884};
    int trspeed4[4] = {133692, 33423, 22282, 11141};
    int gbtime = 1024;
    
    DWORD WINAPI LanLinkThread(void *);
    
    void StartLink(WORD value){
        if(ioMem==NULL)
            return;
        if(!(READ16LE(&ioMem[0x134])&0x8000)){
                switch(value & 0x3000){
                case 0x2000: // Multiplayer
                    if(value & 0x80){
                        if(!linkid){  
                            if(!transfer&&linkmem->numgbas>1){
                                linkmem->linkflags &= !(LINK_ID1FINISH | LINK_ID2FINISH);
                                ResetEvent(linksync[0]);
                                linkmem->linkcmd[0] = ('M'<<8)+(value&3);
                                linkmem->linkdata[0] = READ16LE(&ioMem[0x12a]);
                                transfer = 1;
                                if(linkmem->numtransfers!=0)
                                    savedlinktime = linktime;
                                else
                                    savedlinktime = 0;
                                linktime = 0;
                                tspeed = value & 3;
                                _asm{
                                    mov eax, ioMem;
                                    mov dword ptr [eax+0x120], 0xffffffff;
                                    mov dword ptr [eax+0x124], 0xffffffff;
                                }
                            }
                        } else {
                            value &= 0xff7f;
                            value |= (transfer!=0)<<7;
                        }
                    }
                    value &= 0xffbb;
                    value |= (linkid ? 0xc : 8);
    
                    UPDATE_REG(0x128, value);
                break;
                
                case 0:    // Normal 8-bit
                    value |= 4;
                    UPDATE_REG(0x128, value);
                    if(linklog) fprintf(jjj, "Attempt to use 8-bit Normal mode %04x\n", value);
                    break;
    
                case 0x1000: // Normal 32-bit
                    value |= 4;
                    UPDATE_REG(0x128, value);
                    if(linklog) fprintf(jjj, "Attempt to use 32-bit Normal mode %04x %x%x\n", value, READ16LE(&ioMem[0x122]), READ16LE(&ioMem[0x120]));
                    break;
    
                case 0x3000:    // UART
                    if(linklog&&!linkid) fprintf(jjj, "Attempt to use UART mode %04x\n", value);
                    UPDATE_REG(0x128, value);
                    break;
                }
        }
    }
    
    void StartGPLink(u16 value){
        if(!value){
            UPDATE_REG(0x134, 0);
            return;
        }
        switch(value&0xC000){
        case 0:
        case 0x4000:
            switch(READ16LE(&ioMem[0x128])&0x3000){
            case 0x2000:
                value = READ16LE(&ioMem[0x128]);
                value &= 0xffbb;
                value |= (linkid ? 0xc : 8);
                UPDATE_REG(0x128, value);
                return;
                break;
            }
            break;
        case 0x8000:
            if(linklog) 
                if(value==0x8000)
                    fprintf(jjj, "Circuit reset\n");
                else
                    fprintf(jjj, "Attempt to use General-purpose mode %04x\n", value);
            UPDATE_REG(0x134, value);
            break;
        case 0xC000:
            UPDATE_REG(0x134, value);
            break;
        }
        return;
    }
    
    void StartJOYLink(u16 value){
        if(!value){
            UPDATE_REG(0x140, 0);
            return;
        }
        if(READ16LE(&ioMem[0x134])&0xC000==0xC000){
            if(linklog) fprintf(jjj, "Attempt to use JOY-BUS mode %04x\n", value);
        }
        return;
    }
    
    void LinkUpdate(void){
        if(linkid){    
            savedlinktime = linkmem->lastlinktime;
            if(linkid==1||(linkid==2&&(linkmem->linkflags&LINK_ID1FINISH))||(linkid==3&&(linkmem->linkflags&LINK_ID2FINISH))){
                if(!transfer&&linktime>=savedlinktime&&linkmem->numtransfers){
                    if(linkid==1){
                        linkmem->linkdata[1] = READ16LE(&ioMem[0x12a]);
                    }
                    else 
                    if(linkid==2){
                        linkmem->linkflags &= !LINK_ID1FINISH;
                        linkmem->linkdata[2] = READ16LE(&ioMem[0x12a]);
                    }
                    else if(linkid==3){
                        linkmem->linkflags &= !LINK_ID2FINISH;
                        linkmem->linkdata[3] = READ16LE(&ioMem[0x12a]);
                    }
    
                    if(linkmem->numtransfers!=1)
                        linktime -= savedlinktime;
                    else
                        linktime = 0;
    
                    if(linkmem->numtransfers==1&&lanlink.active)
                        linkmem->numtransfers = 2;
    
                    switch((linkmem->linkcmd[0])>>8){
                    case 'M':
                        tspeed = (linkmem->linkcmd[0]) & 3;
                        transfer = 1;
                        _asm{
                            mov eax, ioMem;
                            mov dword ptr [eax+0x120], 0xffffffff;
                            mov dword ptr [eax+0x124], 0xffffffff;
                            or byte ptr [eax+0x128], 0x80;
                        }
                        break;
                    }
                }
            }
        }
        
        if(!transfer) return;
    
        if(transfer == 1 && linktime >= trspeed1[tspeed]){
            UPDATE_REG(0x120, linkmem->linkdata[0]);
            transfer++;
        }
        
        if(transfer == 2 && linktime >= trspeed2[tspeed]){
            if(!linkid){
                linkmem->numtransfers++;
                if(linkmem->numtransfers==0)
                    linkmem->numtransfers=2;
                linkmem->lastlinktime=savedlinktime;
                    SetEvent(linksync[1]);
                WaitForSingleObject(linksync[0], linktimeout);
                ResetEvent(linksync[0]);
            }
            if(linklog)
                fprintf(jjj, "%04x %04x %04x %04x %10u\n", 
                    linkmem->linkdata[0], linkmem->linkdata[1], linkmem->linkdata[2], linkmem->linkdata[3], linkmem->lastlinktime);
            UPDATE_REG(0x122, linkmem->linkdata[1]);
            transfer++;
        }
    
        if(transfer == 3 && linktime >= trspeed2_5[tspeed] && linkmem->numgbas==2){
            if(linkid){
                SetEvent(linksync[0]);
                if(WaitForSingleObject(linksync[1], linktimeout)==WAIT_TIMEOUT){
                    linkmem->numtransfers=0;
                }
                ResetEvent(linksync[1]);
            }
            transfer = 0;
            linktime -= trspeed2_5[tspeed];
            if((*(u16*)&ioMem[0x128]) & 0x4000){
                IF |= 0x80;
                UPDATE_REG(0x202, IF);
            }
            UPDATE_REG(0x128, (*(u16 *)&ioMem[0x128] & 0xff0f) | (linkid << 4));
            linkmem->linkdata[linkid] = 0xffff;
        }
        
        if(transfer == 3 && linktime >= trspeed3[tspeed]){
            if(linkid==1){
                linkmem->linkflags |= LINK_ID1FINISH;
                if(linkmem->numtransfers!=1)
                    SetEvent(linksync[2]);
                if(WaitForSingleObject(linksync[1], linktimeout)==WAIT_TIMEOUT){
                    linkmem->numtransfers=0;
                }
                ResetEvent(linksync[1]);
            }
            UPDATE_REG(0x124, linkmem->linkdata[2]);
            transfer++;
        }
    
        if(transfer == 4 && linktime >= trspeed3_5[tspeed] && linkmem->numgbas==3){
            if(linkid==2){
                SetEvent(linksync[0]);
                if(WaitForSingleObject(linksync[2], linktimeout)==WAIT_TIMEOUT){
                    linkmem->numtransfers=0;
                }
            ResetEvent(linksync[2]);
            }
            transfer = 0;
            linktime -= trspeed3_5[tspeed];
            if((*(u16*)&ioMem[0x128]) & 0x4000){
                IF |= 0x80;
                UPDATE_REG(0x202, IF);
            }
            UPDATE_REG(0x128, (*(u16 *)&ioMem[0x128] & 0xff0f) | (linkid << 4));
            linkmem->linkdata[linkid] = 0xffff;
        }
    
        if(transfer == 4 && linktime >= trspeed4[tspeed]){
            if(linkid==2){
                linkmem->linkflags |= LINK_ID2FINISH;
                if(linkmem->numtransfers!=1)
                    SetEvent(linksync[3]);
                if(WaitForSingleObject(linksync[2], linktimeout)==WAIT_TIMEOUT){
                    linkmem->numtransfers=0;
                }
                ResetEvent(linksync[2]);
            }
            UPDATE_REG(0x126, linkmem->linkdata[3]);
            if(linkid==3){
                SetEvent(linksync[0]);
                if(WaitForSingleObject(linksync[3], linktimeout)==WAIT_TIMEOUT){
                    linkmem->numtransfers=0;
                }
            ResetEvent(linksync[3]);
            }
            transfer = 0;
            linktime -= trspeed4[tspeed];
            if((*(u16*)&ioMem[0x128]) & 0x4000){
                IF |= 0x80;
                UPDATE_REG(0x202, IF);
            }
            UPDATE_REG(0x128, (*(u16 *)&ioMem[0x128] & 0xff0f) | (linkid << 4));
            linkmem->linkdata[linkid] = 0xffff;
        }
    
    return;
    }
    
    void gbLinkStart(u8 value){
    // Not in this version :-)
    }
    
    
    void gbLinkUpdate(void){
    }
    
    int InitLink(void){
        if(lanlink.active){
            WSADATA wsadata;
            WORD version;
            if((linkmem=(LINKDATA*)malloc(sizeof(LINKDATA)))==NULL){
                MessageBox(NULL, "Not enough memory.", "Error!", MB_OK);
                return 0;
            }
            linkid = 0;
            inifile[3]='1';
            lanlink.linkthread = NULL;
            
            version=MAKEWORD(1,1);
            if(WSAStartup(version, &wsadata)!=0){
                WSACleanup();
                return -1;
            }
            
            if((lanlink.serversocket=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP))==INVALID_SOCKET){
                MessageBox(NULL, "Couldn't create socket.", "Error!", MB_OK);
                WSACleanup();
                return -1;
            }
    
            for(i=0;i<4;i++){
                if((linksync[i]=CreateEvent(NULL, true, false, NULL))==NULL){
                    closesocket(lanlink.serversocket);
                    WSACleanup();
                    return -1;
                }
            }
    
            lanlink.numgbas = 1;
        } else {
    
            if((mmf=CreateFileMapping((HANDLE)0xffffffff, NULL, PAGE_READWRITE, 0, sizeof(LINKDATA), "VBA link memory"))==NULL){      
                MessageBox(NULL, "Error creating file mapping", "Error", MB_OK|MB_ICONEXCLAMATION);
              return 0;
          }
            
          if(GetLastError() == ERROR_ALREADY_EXISTS)
              linkid = 1;
            else
               linkid = 0;
              
          if((linkmem=(LINKDATA *)MapViewOfFile(mmf, FILE_MAP_WRITE, 0, 0, sizeof(LINKDATA)))==NULL){
              CloseHandle(mmf);
              MessageBox(NULL, "Error mapping file", "Error", MB_OK|MB_ICONEXCLAMATION);
              return 0;
          }
    
          if(linkmem->linkflags&LINK_PARENTLOST)
              linkid = 0;
    
            if(linkid==0){
                inifile[3]='1';
                if(linkmem->linkflags&LINK_PARENTLOST){
                    linkmem->numgbas++;
                    linkmem->linkflags &= !LINK_PARENTLOST;
                }
                else
                    linkmem->numgbas=1;
    
                for(i=0;i<4;i++){
                    linkevent[15]=(char)i+'1';
                    if((linksync[i]=CreateEvent(NULL, true, false, linkevent))==NULL){
                        UnmapViewOfFile(linkmem);
                        CloseHandle(mmf);
                        for(j=0;j<i;j++){
                            CloseHandle(linksync[j]);
                        }
                        MessageBox(NULL, "Error opening event", "Error", MB_OK|MB_ICONEXCLAMATION);
                        return 0;
                    }
                }
            } else {
                linkid=linkmem->numgbas;
                linkmem->numgbas++;
                linklog = 0;
                if(linkmem->numgbas>4){
                    linkmem->numgbas=4;
                    MessageBox(NULL, "5 or more GBAs not supported.", "Error!", MB_OK|MB_ICONEXCLAMATION);
                    UnmapViewOfFile(linkmem);
                    CloseHandle(mmf);
                    return 0;
                }
                inifile[3]=(char)linkmem->numgbas+'0';
                for(i=0;i<4;i++){
                    linkevent[15]=(char)i+'1';
                    if((linksync[i]=OpenEvent(EVENT_ALL_ACCESS, false, linkevent))==NULL){
                        CloseHandle(mmf);
                        UnmapViewOfFile(linkmem);
                        for(j=0;j<i;j++){
                            CloseHandle(linksync[j]);
                        }
                        MessageBox(NULL, "Error opening event", "Error", MB_OK|MB_ICONEXCLAMATION);
                        return 0;
                    }
                }
            }
        }  
        linkmem->lastlinktime=0xffffffff;
        linkmem->numtransfers=0;
        linkmem->linkflags=0;
        for(i=0;i<4;i++)
            linkmem->linkdata[i] = 0xffff;
    
        
    
    return 1;
    }
    
    void CloseLanLink(void){
        char buffer[8];
        buffer[0] = 'S';
        send(lanlink.serversocket, buffer, 8, 0);
        closesocket(lanlink.serversocket);
        free(linkmem);
        WSACleanup();
        for(i=0;i<4;i++)
            CloseHandle(linksync[i]);
        if(lanlink.linkthread!=NULL) CloseHandle(lanlink.linkthread);
        if(linklog) fclose(jjj);
    }
    
    void CloseLink(void){
        if(lanlink.active){
            CloseLanLink();
            return;
        }
        linkmem->numgbas--;
        if(!linkid&&linkmem->numgbas!=0)
            linkmem->linkflags|=LINK_PARENTLOST;
        CloseHandle(mmf);
        UnmapViewOfFile(linkmem);
    
        for(i=0;i<4;i++){
            if(linksync[i]!=NULL){
                PulseEvent(linksync[i]);
                CloseHandle(linksync[i]);
            }
        }
        if(linklog&&!linkid) fclose(jjj);
    return;
    }
    
    int LanConnect(void){
        DWORD ehh;
        LPHOSTENT hostentry;
        SOCKADDR_IN serverinfo;
        if(lanlink.linkthread!=NULL){
            CloseHandle(lanlink.linkthread);
            lanlink.linkthread = NULL;
        }
        
        hostentry = gethostbyaddr((const char *)&lanlink.serveraddress, sizeof(IN_ADDR), AF_INET);
        if(hostentry==NULL){
            return WSAGetLastError();
        }
    
        ZeroMemory(&serverinfo, sizeof(SOCKADDR_IN));
        serverinfo.sin_family = AF_INET;
        serverinfo.sin_port = htons(6477 + lanlink.numgbas);
        serverinfo.sin_addr = *((LPIN_ADDR)*hostentry->h_addr_list);
    
        if(connect(lanlink.serversocket, (LPSOCKADDR)&serverinfo, sizeof(SOCKADDR))==SOCKET_ERROR){
            return WSAGetLastError();
        }
    
        ResetEvent(linksync[1]);
        ResetEvent(linksync[0]);
    
        if((lanlink.linkthread=CreateThread(NULL, 0, LanLinkThread, NULL, 0, &ehh))==NULL){
            return -1;
        }
        
        return 0;
    }
    
    DWORD WINAPI LanLinkThread(void *number){
        SOCKET mysocket = lanlink.serversocket;
        int numbytes = 0, howmuch, whatwait;
        char *inbuffer, outbuffer[32], *oldbuffer;
    
        inbuffer = (char*)malloc(32);
    
        oldbuffer = inbuffer;
        
        while(numbytes<4){
            numbytes += recv(mysocket, inbuffer+numbytes, 4, 0);
        }
    
        numbytes = 0;
        
        MessageBox(NULL, "Connected.", "Link", MB_OK);
        
        linkid = inbuffer[0];
    
        linkmem->numgbas = lanlink.numgbas + 1;
        
        howmuch = (lanlink.numgbas)<<2;
        if(linkid) howmuch += 4;
    
        if(linkid == lanlink.numgbas)
            whatwait = 0;
        else
            whatwait = linkid + 1;
    
        linkmem->numtransfers = 0;
    
        if(!linkid) goto firstloop;
        
        while(true){
            
            numbytes = 0;
    
            while(numbytes<howmuch)
                numbytes += recv(mysocket, inbuffer+numbytes, 32, 0);
            
            while(numbytes){
                switch((inbuffer[0])&0x80){
                case 0:
                    switch(inbuffer[0]){
                    case 'M':
                        linkmem->linkdata[((inbuffer[1])&0xc0)>>6] = *((u16*)inbuffer+1);
                        linkmem->linkcmd[0] = ntohs(*(u16*)inbuffer);
                        if(linkid==2)
                            linkmem->linkflags |= LINK_ID1FINISH;
                        if(linkid==3){
                            linkmem->linkflags |= LINK_ID1FINISH;
                            linkmem->linkflags |= LINK_ID2FINISH;
                        }
                        break;
                    case 'S':
                        MessageBox(NULL, "Remote player disconnected.", "Link", MB_OK);
                        linkmem->numgbas = 1;
                        CloseHandle(lanlink.linkthread);
                        lanlink.linkthread = NULL;
                        ExitThread(0);
                        break;
                    default:
                        MessageBox(NULL, "Unknown transfer mode", "Error!", MB_OK);
                        break;
                    }
                    break;
                case 0x80:
                    inbuffer[0] &= 0x7f;
                    linkmem->lastlinktime = ntohl(*(int*)inbuffer);
                    break;
                }
                numbytes -= 4;
                inbuffer += 4;
            }
            
            inbuffer = oldbuffer;
    
            if(linkid&&(++linkmem->numtransfers)==0){
                linkmem->numtransfers = 2;
            }
            
            SetEvent(linksync[linkid]);
    firstloop:
            WaitForSingleObject(linksync[whatwait], INFINITE);
            ResetEvent(linksync[whatwait]);
            
            outbuffer[0] = (linkmem->linkcmd[0])>>8;
            outbuffer[1] = tspeed | (linkid << 6);
            *((u16*)outbuffer+1) = linkmem->linkdata[linkid];
    
            if(linkid){
                send(mysocket, outbuffer, 4, 0);
            }
            else {
                *((int*)outbuffer+1) = htonl(linkmem->lastlinktime);
                outbuffer[4] |= 0x80;
                send(mysocket, outbuffer, 8, 0);
            }
            
        }
        return 0;
    }


    Link.h


    Code:
    // VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator.
    // Copyright (C) 1999-2003 Forgotten
    // Copyright (C) 2004 Forgotten and the VBA development team
    
    // This program is free software; you can redistribute it and/or modify
    // it under the terms of the GNU General Public License as published by
    // the Free Software Foundation; either version 2, or(at your option)
    // any later version.
    //
    // This program is distributed in the hope that it will be useful,
    // but WITHOUT ANY WARRANTY; without even the implied warranty of
    // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    // GNU General Public License for more details.
    //
    // You should have received a copy of the GNU General Public License
    // along with this program; if not, write to the Free Software Foundation,
    // Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
    
    #include<winsock.h>
    
    #define LINK_PARENTLOST 0x80
    
    typedef struct {
        WORD linkdata[4];
        WORD linkcmd[4];
        WORD numtransfers;
        int lastlinktime;
        unsigned char numgbas;
        unsigned char linkflags;
    } LINKDATA;
    
    typedef struct {
        SOCKET serversocket;
        IN_ADDR serveraddress;
        int numgbas;
        bool active, wasactive;
        HANDLE linkthread;
    } LANLINKDATA;
     
    Last edited:
    This just dawned onto me, it IS possible to make a game that allowed trading and battling of pokemon from a fanmade game and a legit game (not totally, since its a rom...). Let me explain, we can look into the VBA link's source code and see how the GBA handles the connectivity. Then we can observe how the game it self handles the connections. Like during a battle, does it send the ID #s of the pokemon and and the move or does it send a string (a word, I guess thats the way to say it in plain english) containing the trainer's name and pokemon's name every time it attacks, or does it do it before the battle. Im saying its TOTALLY 100% accomplishable. If you are aware, OdinMS (first successful Maplestory Private Server (currently getting sued or something)) was developed this way, by observing the packets of data being transferred. I my self will not attempt to do (at least not yet) since I already have a project to do... But Im just putting the Idea out there that it is possible. Just won't be easy at all. I think it won't be hard modifying VBA Link to create a dump of everything that it transfers, just figuring it out is hard.


    This will be my next big project after my current one. I WILL attempt it, just not now.

    I'm not a mega scripter or anything, but it might not be possible to transfer from a fangame to a rom, but a rom to a fangame.

    There already is a debug feature in Essentials that allows you to transfer the pokemon you have in a ruby.sav file to the game your working on.
     
    I'm not a mega scripter or anything, but it might not be possible to transfer from a fangame to a rom, but a rom to a fangame.

    There already is a debug feature in Essentials that allows you to transfer the pokemon you have in a ruby.sav file to the game your working on.
    Im saying to both, like behaving as a real pokemon game. If the game check for the version of the game before linking, you can send a bogus version to make them compatible



    edit: Since pokemon stores the pokemons as an ID (might be simple as 001 for bulbasaur or has an equation to find the pokemon from it's secret ID or something) we can just make a program that sends the packets of data that makes it trade. that means you CAN'T put fakemon into the game
     
    Last edited:
    Im saying to both, like behaving as a real pokemon game. If the game check for the version of the game before linking, you can send a bogus version to make them compatible



    edit: Since pokemon stores the pokemons as an ID (might be simple as 001 for bulbasaur or has an equation to find the pokemon from it's secret ID or something) we can just make a program that sends the packets of data that makes it trade.

    Like I said hehe I'm not a coder so I can't really get into details with this.
     
    I think this will be easier than I thought (still pretty hard) since the intensive hacking Pokemon allows, we can find out Pokemon ID's and stuff
     
    We could ask Wichu as he can find some values for us and if we could manipulate the data and we could even make a Pal Park using the Pokemon Essentials ruby.sav to game as a base and coding from there. Then again we could make a new programming language for use with ruby that is called Ruby ++ or something. Which would turn Ruby code in C++.
     
    We could ask Wichu as he can find some values for us and if we could manipulate the data and we could even make a Pal Park using the Pokemon Essentials ruby.sav to game as a base and coding from there. Then again we could make a new programming language for use with ruby that is called Ruby ++ or something. Which would turn Ruby code in C++.

    Let me just say that this made no sense to me whatsoever :\

    I know the GBA Pokémon data format, but that's about it. There are already utilities in Essentials that allow you to read Pokémon data from a Ruby save file, as VarietyVidsnet stated.

    Anyway, wouldn't it be better to find how the NDS Wi-Fi system works? Then, you can trade with real games as well...
     
    I gotta admit I see what your trying to achieve and yes it can be done but is it worth your time? I mean I think this pointless. Maybe a better use of this idea is to make a fan game run on emulators all together, then perhaps this goal could be accomplished aswell.
     
    The only problem with what wichu is suggesting with the wifi idea is:
    A: Make a perfect Pokemon from the of no effort involved.
    B: What's really the point.
    C: Life is easy enough as it is in pokemon why even easier?
    D: Trading would become redundant no need for it as you could get everything you want.
    F: Nintendo would not be impressed.
     
    A, C, D, and F: Pokésav already exists.
    B. It would be awesome if we could use our Pokémon from the DS games in homebrew games, and vice-versa.

    And where did E go? :P
     
    Whoops my biggy on E but still. Ok with pokesav that exists but to great difficulty to the average person. But still i didn't know it existed till 5 seconds ago. Another point is based on what you said pokesav could be made usless as instead of fumbling around with very clumpy interface ( In my opinion ) there would be a simple common interface people could associate with and know how to use at the click of your fingers.
     
    Not really; it's much easier to make a Pokémon with Pokésav than it would be in an RPG Maker game. More people have access to a flashcart or cheat cartridge than are interested in fangames (much less know how to create a Pokémon with one), anyway... With Wi-Fi trading, it's easy for anyone who cannot use Pokésav to request a Pokémon from someone who can. The advantages of being able to trade between fangames and official games greatly outweighs the small benefit it gives to cheaters.
     
    IDK if it would have much of a purpose, but I personally thought it would be cool to allow interaction between the homebrew and official games, to show the real roots, pokemon
     
    Well, this would've gotten more tl;dr's, but my original post was deleted before being posted thanks to taking too long to write while I get signed out. I don't wanaa bother again, so here's what I typed in a shorter fashion:

    I'm using Flash via ActionScript 3 for my fangame, instead of RMXP. Pokemon are on keyframes linked by coding that when you use a control on one keyframe it goes to another. This looks like it can be optimized as a motion tween variable. Unfortunately, only the dev can do this, but you can export those kinds of varaibles as a .xml. Here's an example of this with one keyframe of a Shiny Bulbasaur sprite:

    https://www.4shared.com/file/177294692/f807713e/Shiny_Bulbasaur_export.html

    All of the following looks like it's only for text variables, but here's what looks to be...

    1: User export as a .txt:

    https://www.flash-db.com/Tutorials/savingAS3/savingData.php?page=2

    2: User import from .txt:

    https://www.flash-db.com/Tutorials/loadingAS3/loadingData.php?page=2

    3: User import from .xml:

    https://www.flash-db.com/Tutorials/loadingAS3/loadingData.php?page=3

    ...Can my fangmae be added to this connectivity?

    Thanks,
    PM260
     
    Well, this would've gotten more tl;dr's, but my original post was deleted before being posted thanks to taking too long to write while I get signed out. I don't wanaa bother again, so here's what I typed in a shorter fashion:

    I'm using Flash via ActionScript 3 for my fangame, instead of RMXP. Pokemon are on keyframes linked by coding that when you use a control on one keyframe it goes to another. This looks like it can be optimized as a motion tween variable. Unfortunately, only the dev can do this, but you can export those kinds of varaibles as a .xml. Here's an example of this with one keyframe of a Shiny Bulbasaur sprite:

    https://www.4shared.com/file/177294692/f807713e/Shiny_Bulbasaur_export.html

    All of the following looks like it's only for text variables, but here's what looks to be...

    1: User export as a .txt:

    https://www.flash-db.com/Tutorials/savingAS3/savingData.php?page=2

    2: User import from .txt:

    https://www.flash-db.com/Tutorials/loadingAS3/loadingData.php?page=2

    3: User import from .xml:

    https://www.flash-db.com/Tutorials/loadingAS3/loadingData.php?page=3

    ...Can my fangmae be added to this connectivity?

    Thanks,
    PM260
    I would Assume if I will store the data, it would be in XML, so yea I guess you can import the xml and transfer it over, but I didnt even start on it yet

    Well, this would've gotten more tl;dr's, but my original post was deleted before being posted thanks to taking too long to write while I get signed out. I don't wanaa bother again, so here's what I typed in a shorter fashion:

    I'm using Flash via ActionScript 3 for my fangame, instead of RMXP. Pokemon are on keyframes linked by coding that when you use a control on one keyframe it goes to another. This looks like it can be optimized as a motion tween variable. Unfortunately, only the dev can do this, but you can export those kinds of varaibles as a .xml. Here's an example of this with one keyframe of a Shiny Bulbasaur sprite:

    https://www.4shared.com/file/177294692/f807713e/Shiny_Bulbasaur_export.html

    All of the following looks like it's only for text variables, but here's what looks to be...

    1: User export as a .txt:

    https://www.flash-db.com/Tutorials/savingAS3/savingData.php?page=2

    2: User import from .txt:

    https://www.flash-db.com/Tutorials/loadingAS3/loadingData.php?page=2

    3: User import from .xml:

    https://www.flash-db.com/Tutorials/loadingAS3/loadingData.php?page=3

    ...Can my fangmae be added to this connectivity?

    Thanks,
    PM260
    I would Assume if I will store the data, it would be in XML, so yea I guess you can import the xml and transfer it over, but I didnt even start on it yet
     
    Last edited:
    This project isn't to enable compatibility between games using files; it's to understand the link functions of the official games and link directly with them through an emulator (or Wi-Fi).

    Importing/exporting Pokémon between fangames using files is easy. It's more useful to scramble the data in some way than to export it directly as text, though (that way, it will be harder for someone to modify the data during a trade).

    Hint: this is the system used by the Communications Center in Raptor EX :P
     
    Wichu are you suggesting you have this working in Raptor EX?!
     
    This project isn't to enable compatibility between games using files; it's to understand the link functions of the official games and link directly with them through an emulator (or Wi-Fi).

    Importing/exporting Pokémon between fangames using files is easy. It's more useful to scramble the data in some way than to export it directly as text, though (that way, it will be harder for someone to modify the data during a trade).

    Hint: this is the system used by the Communications Center in Raptor EX :P
    i mean direct, the program makes the game think its an official game, so eventually we can find out how to battle and stuff
     
    Back
    Top