Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
608 lines
16 KiB
C
608 lines
16 KiB
C
// ____________________________
|
|
// ██▀▀█▀▀██▀▀▀▀▀▀▀█▀▀█ │ ▄▄▄ ▄▄
|
|
// ██ ▀ █▄ ▀██▄ ▀ ▄█ ▄▀▀ █ │ ▀█▄ ▄▀██ ▄█▄█ ██▀▄ ██ ▄███
|
|
// █ █ █ ▀▀ ▄█ █ █ ▀▄█ █▄ │ ▄▄█▀ ▀▄██ ██ █ ██▀ ▀█▄ ▀█▄▄
|
|
// ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀────────┘ ▀▀
|
|
// Hello world sample
|
|
//─────────────────────────────────────────────────────────────────────────────
|
|
#include "msxgl.h"
|
|
#include "network/obsonet.h"
|
|
|
|
//=============================================================================
|
|
// DEFINES
|
|
//=============================================================================
|
|
|
|
// Library's logo
|
|
#define MSX_GL "\x02\x03\x04\x05"
|
|
|
|
// Modes
|
|
#define MODE_SNIFFER 0
|
|
#define MODE_GAME 1
|
|
|
|
// Message ID
|
|
enum MESSAGE
|
|
{
|
|
MESSAGE_INVITATION = 0, // Sent at regular intervals by the server to inform of the existence of a game session
|
|
MESSAGE_JOIN_REQUEST, // Sent by the player who wishes to join a game session
|
|
MESSAGE_JOIN_VALID, // + PlayerID Sent by the server to accept a join request
|
|
MESSAGE_UPDATE, // + struct Player Sent by the player during the game session
|
|
};
|
|
|
|
// Message ID
|
|
enum STATE
|
|
{
|
|
STATE_MENU_INIT = 0,
|
|
STATE_MENU,
|
|
STATE_HOSTING_INIT,
|
|
STATE_HOSTING,
|
|
STATE_BROWSE_INIT,
|
|
STATE_BROWSE,
|
|
STATE_JOINING_INIT,
|
|
STATE_JOINING,
|
|
STATE_PLAYING_INIT,
|
|
STATE_PLAYING,
|
|
};
|
|
|
|
// Functions prototypes
|
|
void DisplaySniffer();
|
|
void UpdateSniffer();
|
|
void DisplayGame();
|
|
void UpdateGame();
|
|
|
|
// Process mode structure
|
|
struct Process
|
|
{
|
|
callback Display;
|
|
callback Update;
|
|
};
|
|
|
|
// Player structure
|
|
struct Player
|
|
{
|
|
u8 Y;
|
|
u8 X;
|
|
u8 Shape;
|
|
u8 Color;
|
|
//---------- End of Sprite buffer
|
|
u8 ID;
|
|
u8 Direction;
|
|
};
|
|
|
|
// Vector structure
|
|
struct Vector
|
|
{
|
|
i8 X;
|
|
i8 Y;
|
|
};
|
|
|
|
//=============================================================================
|
|
// READ-ONLY DATA
|
|
//=============================================================================
|
|
|
|
// Fonts data
|
|
#include "font/font_mgl_sample8.h"
|
|
|
|
// Character animation data
|
|
const c8 g_ChrAnim[] = { '|', '\\', '-', '/' };
|
|
|
|
// Process mode table
|
|
const struct Process g_ModeTab[2] =
|
|
{
|
|
{ DisplaySniffer, UpdateSniffer },
|
|
{ DisplayGame, UpdateGame },
|
|
};
|
|
|
|
// Broadcast MAC address
|
|
const u8 g_BroadcastMAC[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
|
|
|
|
// Vector structure
|
|
const struct Vector g_MoveTab[8] =
|
|
{
|
|
{ 0, 1 },
|
|
{ -1, 1 },
|
|
{ -1, 0 },
|
|
{ -1, -1 },
|
|
{ 0, -1 },
|
|
{ 1, -1 },
|
|
{ 1, 0 },
|
|
{ 1, 1 },
|
|
};
|
|
|
|
//=============================================================================
|
|
// MEMORY DATA
|
|
//=============================================================================
|
|
|
|
u8 g_Buffer[1514+2]; // Max Ethernet frame size + 2 bytes for size value
|
|
bool g_Pending;
|
|
u8 g_Mode;
|
|
u8 g_Server[6];
|
|
u8 g_Frame;
|
|
u8 g_State;
|
|
u8 g_PlayerNum;
|
|
u8 g_Slot;
|
|
struct Player g_Player[32];
|
|
|
|
//=============================================================================
|
|
// FUNCTIONS
|
|
//=============================================================================
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
void Erase(u8 sx, u8 sy, u16 num)
|
|
{
|
|
u16 dst = g_ScreenLayoutLow + (sy * g_PrintData.ScreenWidth) + sx;
|
|
VDP_FillVRAM(0, dst, g_ScreenLayoutHigh, num);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
const c8* GetEtherTypeName(u16 id)
|
|
{
|
|
switch (id)
|
|
{
|
|
case ETHERTYPE_IPV4 : return "IPv4";
|
|
case ETHERTYPE_ARP : return "ARP";
|
|
case ETHERTYPE_WOLAN : return "WoLAN";
|
|
case ETHERTYPE_AVTP : return "AVTP";
|
|
case ETHERTYPE_IETF : return "IETF";
|
|
case ETHERTYPE_SRP : return "SRP";
|
|
case ETHERTYPE_DEC_MOP : return "DEC MOP";
|
|
case ETHERTYPE_DECNET : return "DECnet";
|
|
case ETHERTYPE_DEC_LAT : return "DEC LAT";
|
|
case ETHERTYPE_RARP : return "RARP";
|
|
case ETHERTYPE_ETHERTALK : return "Eth Talk";
|
|
case ETHERTYPE_AARP : return "AARP";
|
|
case ETHERTYPE_VLANTF : return "VLANtf";
|
|
case ETHERTYPE_SLPP : return "SLPP";
|
|
case ETHERTYPE_VLACP : return "VLACP";
|
|
case ETHERTYPE_IPX : return "IPX";
|
|
case ETHERTYPE_QNX : return "QNX Qnet";
|
|
case ETHERTYPE_IPV6 : return "IPv6";
|
|
case ETHERTYPE_EFC : return "EFC";
|
|
case ETHERTYPE_LACP : return "LACP";
|
|
case ETHERTYPE_COBRA : return "CobraNet";
|
|
case ETHERTYPE_MPLS_UNI : return "MPLS uni";
|
|
case ETHERTYPE_MPLS_MUL : return "MPLS mul";
|
|
case ETHERTYPE_PPPOE_DISC : return "PPPoE D";
|
|
case ETHERTYPE_PPPOE_SES : return "PPPoE S";
|
|
case ETHERTYPE_HOMEPLUG_MME : return "HomePlug";
|
|
case ETHERTYPE_EAP : return "EAPoLAN";
|
|
case ETHERTYPE_PROFINET : return "PROFINET";
|
|
case ETHERTYPE_SCSI : return "H-SCSI";
|
|
case ETHERTYPE_ATA : return "ATA";
|
|
case ETHERTYPE_ETHERCAT : return "EtherCAT";
|
|
case ETHERTYPE_SVLAN : return "S-Tag";
|
|
case ETHERTYPE_POWERLINK : return "Powerlnk";
|
|
case ETHERTYPE_GOOSE : return "GOOSE";
|
|
case ETHERTYPE_GSE : return "GSE";
|
|
case ETHERTYPE_SV : return "SV";
|
|
case ETHERTYPE_MIKROTIK : return "MikroTik";
|
|
case ETHERTYPE_LLDP : return "LLDP";
|
|
case ETHERTYPE_SERCOS : return "SERCOS3";
|
|
case ETHERTYPE_HOMEPLUG_PHY : return "HP PHY";
|
|
case ETHERTYPE_MRP : return "IEC62439";
|
|
case ETHERTYPE_MACSEC : return "MACsec";
|
|
case ETHERTYPE_PBB : return "PBB";
|
|
case ETHERTYPE_PTP : return "PTP";
|
|
case ETHERTYPE_NCSI : return "NC-SI";
|
|
case ETHERTYPE_PRP : return "PRP";
|
|
case ETHERTYPE_CFM : return "CFM/OAM";
|
|
case ETHERTYPE_FCOE : return "FCoE";
|
|
case ETHERTYPE_FCOE_INI : return "FCoE Ini";
|
|
case ETHERTYPE_ROCE : return "RoCE";
|
|
case ETHERTYPE_TTE : return "TTE";
|
|
case ETHERTYPE_1905 : return "1905.1";
|
|
case ETHERTYPE_HSR : return "HSR";
|
|
case ETHERTYPE_ECTP : return "ECTP";
|
|
case ETHERTYPE_RT : return "802.1CB";
|
|
};
|
|
return "Unknown";
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
const c8* GetSendResultName(u8 val)
|
|
{
|
|
switch (val)
|
|
{
|
|
case ONET_SYNC_SUCCESS : return "Success"; // Packet successfully sent
|
|
case ONET_SYNC_ERROR_LENGTH : return "Error length"; // Invalid packet length
|
|
case ONET_SYNC_ERROR_CARRIER : return "Error carrier"; // Transmission aborted due to carrier loss
|
|
case ONET_SYNC_ERROR_COLLISION : return "Error collision"; // Transmission aborted due to excessive collisions
|
|
};
|
|
return "Unknown";
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
const c8* GetSendStatusName(u8 val)
|
|
{
|
|
switch (val)
|
|
{
|
|
case ONET_SEND_NONE : return "None"; // No packets have been sent since the last execution of RTL_RESET
|
|
case ONET_SEND_PROGRESS : return "Progress"; // Transmission in progress
|
|
case ONET_SEND_SUCESSS : return "Sucess"; // The packet has been successfully sent
|
|
case ONET_SEND_ERROR_CARRIER : return "Error carrier"; // Transmission aborted due to carrier loss
|
|
case ONET_SEND_ERROR_COLLISION : return "Error collision"; // Transmission aborted due to excessive collisions
|
|
};
|
|
return "Unknown";
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
void Print_DrawSlot(u8 slot)
|
|
{
|
|
Print_DrawInt(Sys_SlotGetPrimary(slot));
|
|
if (Sys_SlotIsExpended(slot))
|
|
{
|
|
Print_DrawChar('-');
|
|
Print_DrawInt(Sys_SlotGetSecondary(slot));
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
void Print_DrawMAC(const u8* addr)
|
|
{
|
|
Print_DrawHex8(*addr++);
|
|
Print_DrawChar('.');
|
|
Print_DrawHex8(*addr++);
|
|
Print_DrawChar('.');
|
|
Print_DrawHex8(*addr++);
|
|
Print_DrawChar('.');
|
|
Print_DrawHex8(*addr++);
|
|
Print_DrawChar('.');
|
|
Print_DrawHex8(*addr++);
|
|
Print_DrawChar('.');
|
|
Print_DrawHex8(*addr++);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
void DisplayHead()
|
|
{
|
|
Print_Clear();
|
|
Print_SetPosition(0, 0);
|
|
Print_DrawText(MSX_GL " OBSONET SAMPLE");
|
|
Print_DrawLineH(0, 1, 32);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
void DisplayFoot()
|
|
{
|
|
Print_DrawLineH(0, 22, 32);
|
|
Erase(0, 23, 32);
|
|
Print_SetPosition(0, 23);
|
|
if (g_Mode == MODE_SNIFFER)
|
|
Print_DrawFormat("F1:Game R:Reset%s", (g_Pending) ? " G:Get D:Discard" : "");
|
|
else
|
|
Print_DrawFormat("F1:Sniffer");
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
void DisplaySniffer()
|
|
{
|
|
g_Pending = false;
|
|
VDP_DisableSpritesFrom(0);
|
|
|
|
DisplayHead();
|
|
DisplayFoot();
|
|
|
|
Print_SetPosition(0, 3);
|
|
Print_DrawText("Slot :");
|
|
g_Slot = ONET_Initialize();
|
|
if (g_Slot == 0xFF)
|
|
{
|
|
Print_DrawText("Not found!");
|
|
return;
|
|
}
|
|
Print_DrawSlot(g_Slot);
|
|
Print_DrawFormat("\nBIOS :%s", ONET_HasBIOS() ? "Yes" : "No");
|
|
Print_DrawFormat("\nVer. :%i.%i.%i", g_ONET_Version[0], g_ONET_Version[1], g_ONET_Version[2]);
|
|
Print_DrawText( "\nMAC :");
|
|
Print_DrawMAC(g_ONET_MAC);
|
|
Print_DrawFormat("\nConn. :%s", ONET_GetStatus() ? "Yes" : "No");
|
|
Print_DrawFormat("\nActive :%s", ONET_IsActivate() ? "Yes" : "No");
|
|
|
|
u8 rec = ONET_GetReceptConfig();
|
|
Print_DrawFormat("\nRecept :%2xh Sm%s BC%s MC%s All%s", rec,
|
|
(rec & ONET_RECEPT_SMALL) ? "\x0C" : "\x0B",
|
|
(rec & ONET_RECEPT_BROADCAST) ? "\x0C" : "\x0B",
|
|
(rec & ONET_RECEPT_MULTICAST) ? "\x0C" : "\x0B",
|
|
(rec & ONET_RECEPT_ALL) ? "\x0C" : "\x0B");
|
|
|
|
Print_DrawText("\nPacket :");
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
void UpdateSniffer()
|
|
{
|
|
struct ONET_PacketInfo info;
|
|
|
|
if (ONET_GetSlot() == 0xFF)
|
|
return;
|
|
|
|
if (!g_Pending)
|
|
{
|
|
Erase(8, 10, 32-8);
|
|
bool bInf = ONET_GetPacketInfo(&info);
|
|
Print_SetPosition(8, 10);
|
|
if (bInf)
|
|
{
|
|
Print_DrawFormat("Yes S=%i H=%4x %s", info.Size, info.Head, GetEtherTypeName(info.Head));
|
|
g_Pending = TRUE;
|
|
DisplayFoot();
|
|
}
|
|
else
|
|
{
|
|
Print_DrawText("No");
|
|
DisplayFoot();
|
|
}
|
|
}
|
|
if (g_Pending)
|
|
{
|
|
if (Keyboard_IsKeyPressed(KEY_G)) // Get Packet
|
|
{
|
|
if (ONET_GetPacket(g_Buffer))
|
|
{
|
|
Erase(0, 11, 32*11);
|
|
Print_SetPosition(0, 11);
|
|
Print_DrawCharX(0x1C, 32);
|
|
Print_DrawFormat("\nSize %i bytes", *(i16*)g_Buffer);
|
|
Print_DrawText("\nDest. "); Print_DrawMAC(g_Buffer + 2);
|
|
Print_DrawText("\nSource "); Print_DrawMAC(g_Buffer + 8);
|
|
u8* buf;
|
|
if (info.Head > 1500)
|
|
{
|
|
buf = g_Buffer + 14;
|
|
}
|
|
else
|
|
{
|
|
Print_DrawFormat("\nLength %i", *(i16*)(g_Buffer + 14));
|
|
buf = g_Buffer + 22;
|
|
}
|
|
Print_DrawFormat("\nType %2x%2x (%s)", buf[0], buf[1], GetEtherTypeName(Math_Swap(*(u16*)buf)));
|
|
|
|
buf += 2;
|
|
Print_DrawText("\nRaw ");
|
|
u16 size = MIN(info.Size, 8*6);
|
|
for (u8 i = 0; i < size; ++i)
|
|
{
|
|
if ((i > 0) && ((i % 8) == 0))
|
|
{
|
|
g_PrintData.CursorX = 8;
|
|
g_PrintData.CursorY++;
|
|
}
|
|
Print_DrawHex8(*buf++);
|
|
if ((i % 8) != 7)
|
|
g_PrintData.CursorX++;
|
|
}
|
|
g_Pending = FALSE;
|
|
DisplayFoot();
|
|
}
|
|
}
|
|
else if (Keyboard_IsKeyPressed(KEY_D)) // Discard Packet
|
|
{
|
|
ONET_GetPacket(0);
|
|
g_Pending = FALSE;
|
|
DisplayFoot();
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
void DisplayGame()
|
|
{
|
|
VDP_DisableSpritesFrom(0);
|
|
|
|
g_State = STATE_MENU_INIT;
|
|
|
|
DisplayHead();
|
|
DisplayFoot();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
void InitPlayer()
|
|
{
|
|
struct Player* ply = &g_Player[0];
|
|
ply->ID = 0;
|
|
ply->X = Math_GetRandom8();
|
|
ply->Y = Math_GetRandom8() / 2 + 32;
|
|
ply->Direction = Math_GetRandom8() % 8;
|
|
ply->Shape = 0xB0 + ply->Direction;
|
|
ply->Color = 2 + Math_GetRandom8() % 14;
|
|
VDP_SetSpriteSM1(ply->ID, ply->X, ply->Y, ply->Shape, ply->Color);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
inline void SetMAC(u8* dest, const u8* src) { Mem_Copy(src, dest, 6); }
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
void SendBroadcast(u8 msg, const u8* data, u16 size)
|
|
{
|
|
// Prepare header
|
|
struct EtherHeader* head = (struct EtherHeader*)g_Buffer;
|
|
SetMAC(head->Dest, g_BroadcastMAC);
|
|
SetMAC(head->Source, ONET_GetMACAddress());
|
|
head->Type = Math_Swap(ETHERTYPE_IPV4);
|
|
|
|
// Prepare data
|
|
g_Buffer[14] = msg;
|
|
if (size)
|
|
Mem_Copy(data, g_Buffer + 15, size);
|
|
|
|
// Send data
|
|
ONET_SendPacketAsync(g_Buffer, size + 15);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Pseudo game FSM
|
|
void UpdateGame()
|
|
{
|
|
switch (g_State)
|
|
{
|
|
case STATE_MENU_INIT:
|
|
Erase(0, 2, 20*32);
|
|
Print_SetPosition(0, 3);
|
|
Print_DrawText("State: Menu");
|
|
Print_DrawText("\nMAC: ");
|
|
Print_DrawMAC(g_ONET_MAC);
|
|
Print_DrawText("\n\n1. Host");
|
|
Print_DrawText("\n2. Join");
|
|
InitPlayer();
|
|
g_State = STATE_MENU;
|
|
|
|
case STATE_MENU:
|
|
if (Keyboard_IsKeyPressed(KEY_1))
|
|
g_State = STATE_HOSTING_INIT;
|
|
if (Keyboard_IsKeyPressed(KEY_2))
|
|
g_State = STATE_BROWSE_INIT;
|
|
break;
|
|
|
|
case STATE_HOSTING_INIT:
|
|
Erase(0, 2, 20*32);
|
|
Print_SetPosition(0, 3);
|
|
Print_DrawText("State: Hosting");
|
|
Print_DrawText("\nLocal: ");
|
|
Print_DrawMAC(g_ONET_MAC);
|
|
Print_DrawText("\nServer: ");
|
|
Print_DrawMAC(g_ONET_MAC);
|
|
g_PlayerNum = 1;
|
|
g_State = STATE_HOSTING;
|
|
break;
|
|
|
|
case STATE_BROWSE_INIT:
|
|
Erase(0, 2, 20*32);
|
|
Print_SetPosition(0, 3);
|
|
Print_DrawText("State: Browsing");
|
|
Print_DrawText("\nMAC: ");
|
|
Print_DrawMAC(g_ONET_MAC);
|
|
break;
|
|
|
|
case STATE_BROWSE:
|
|
break;
|
|
|
|
case STATE_JOINING_INIT:
|
|
Erase(0, 2, 20*32);
|
|
Print_SetPosition(0, 3);
|
|
Print_DrawText("State: Joining");
|
|
break;
|
|
|
|
case STATE_JOINING:
|
|
break;
|
|
|
|
case STATE_PLAYING_INIT:
|
|
Erase(0, 2, 20*32);
|
|
Print_SetPosition(0, 3);
|
|
Print_DrawText("State: Playing");
|
|
g_State = STATE_PLAYING;
|
|
break;
|
|
|
|
case STATE_HOSTING:
|
|
if ((g_Frame % 32) == 0)
|
|
SendBroadcast(MESSAGE_INVITATION, NULL, 0);
|
|
|
|
// u8 res = ONET_GetSendStatus();
|
|
// Erase(0, 20, 32);
|
|
// Print_SetPosition(0, 20);
|
|
// Print_DrawText("Status: ");
|
|
// Print_DrawText(GetSendStatusName(res));
|
|
|
|
case STATE_PLAYING:
|
|
{
|
|
// Handle local player
|
|
struct Player* ply = &g_Player[0];
|
|
if (Keyboard_IsKeyPressed(KEY_RIGHT))
|
|
{
|
|
ply->Direction++;
|
|
ply->Direction %= 32;
|
|
ply->Shape = 0xB0 + (ply->Direction / 4);
|
|
}
|
|
else if (Keyboard_IsKeyPressed(KEY_LEFT))
|
|
{
|
|
ply->Direction--;
|
|
ply->Direction %= 32;
|
|
ply->Shape = 0xB0 + (ply->Direction / 4);
|
|
}
|
|
if (Keyboard_IsKeyPressed(KEY_UP))
|
|
{
|
|
const struct Vector* vec = &g_MoveTab[ply->Direction / 4];
|
|
ply->X += vec->X;
|
|
ply->Y += vec->Y;
|
|
}
|
|
|
|
// Handle local player send info
|
|
if ((g_Frame % 8) == 0)
|
|
SendBroadcast(MESSAGE_UPDATE, (const u8*)ply, sizeof(struct Player));
|
|
|
|
// u8 res = ONET_GetSendStatus();
|
|
// Erase(0, 20, 32);
|
|
// Print_SetPosition(0, 20);
|
|
// Print_DrawText("Status: ");
|
|
// Print_DrawText(GetSendStatusName(res));
|
|
|
|
// Update distant players
|
|
|
|
// Draw players
|
|
for (u8 i = 0; i < g_PlayerNum; ++i)
|
|
VDP_WriteVRAM((const u8*)&g_Player[i], g_SpriteAttributeLow + (i * 4), g_SpriteAttributeHigh, 3);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Program entry point
|
|
void main()
|
|
{
|
|
VDP_SetMode(VDP_MODE_SCREEN1);
|
|
VDP_SetColor(0);
|
|
VDP_ClearVRAM();
|
|
|
|
// Initialize font
|
|
Print_SetTextFont(g_Font_MGL_Sample8, 1);
|
|
Print_SetColor(0xF, 0x0);
|
|
|
|
// Initialize sprite
|
|
VDP_SetSpriteFlag(VDP_SPRITE_SIZE_8);
|
|
VDP_LoadSpritePattern(g_Font_MGL_Sample8 + 4, 0, sizeof(g_Font_MGL_Sample8) / 8 - 4);
|
|
|
|
g_Mode = MODE_SNIFFER;
|
|
g_ModeTab[g_Mode].Display();
|
|
|
|
g_Pending = false;
|
|
bool bPressed = FALSE;
|
|
while (!Keyboard_IsKeyPressed(KEY_ESC))
|
|
{
|
|
Halt();
|
|
|
|
Print_SetPosition(31, 0);
|
|
Print_DrawChar(g_ChrAnim[g_Frame & 0x03]);
|
|
|
|
g_ModeTab[g_Mode].Update();
|
|
|
|
if (Keyboard_IsKeyPressed(KEY_F1))
|
|
{
|
|
if ((!bPressed) && (g_Slot != 0xFF))
|
|
{
|
|
g_Mode = 1 - g_Mode;
|
|
g_ModeTab[g_Mode].Display();
|
|
bPressed = TRUE;
|
|
}
|
|
}
|
|
else
|
|
bPressed = FALSE;
|
|
|
|
if (Keyboard_IsKeyPressed(KEY_R))
|
|
g_ModeTab[g_Mode].Display();
|
|
|
|
g_Frame++;
|
|
}
|
|
} |