static void Freeze() { char buffer[1024]; int i; S9xSetSoundMute(TRUE); S9xSRTCPreSaveState(); for (i = 0; i < 8; i++) { SoundData.channels [i].previous16 [0] = (int16) SoundData.channels [i].previous [0]; SoundData.channels [i].previous16 [1] = (int16) SoundData.channels [i].previous [1]; } sprintf(buffer, "%s:%04d\n", SNAPSHOT_MAGIC, SNAPSHOT_VERSION); statef_write(buffer, strlen(buffer)); sprintf(buffer, "NAM:%06d:%s%c", strlen(Memory.ROMFilename) + 1, Memory.ROMFilename, 0); statef_write(buffer, strlen(buffer) + 1); FreezeStruct("CPU", &CPU, SnapCPU, COUNT(SnapCPU)); FreezeStruct("REG", &Registers, SnapRegisters, COUNT(SnapRegisters)); FreezeStruct("PPU", &PPU, SnapPPU, COUNT(SnapPPU)); FreezeStruct("DMA", DMA, SnapDMA, COUNT(SnapDMA)); // RAM and VRAM FreezeBlock("VRA", Memory.VRAM, 0x10000); FreezeBlock("RAM", Memory.RAM, 0x20000); FreezeBlock("SRA", SRAM, 0x20000); FreezeBlock("FIL", Memory.FillRAM, 0x8000); if (Settings.APUEnabled) { // APU FreezeStruct("APU", &APU, SnapAPU, COUNT(SnapAPU)); // copy all SPC700 regs to savestate compatible struct SAPURegisters spcregs; spcregs.P = IAPU.P; spcregs.YA.W = IAPU.YA.W; spcregs.X = IAPU.X; spcregs.S = IAPU.S; spcregs.PC = IAPU.PC - IAPU.RAM; FreezeStruct("ARE", &spcregs, SnapAPURegisters, COUNT(SnapAPURegisters)); FreezeBlock("ARA", IAPU.RAM, 0x10000); FreezeStruct("SOU", &SoundData, SnapSoundData, COUNT(SnapSoundData)); } #ifdef USE_SA1 if (Settings.SA1) { SA1Registers.PC = SA1.PC - SA1.PCBase; S9xSA1PackStatus(); FreezeStruct("SA1", &SA1, SnapSA1, COUNT(SnapSA1)); FreezeStruct("SAR", &SA1Registers, SnapSA1Registers, COUNT(SnapSA1Registers)); } #endif S9xSetSoundMute(FALSE); }
void FreezeStruct(char* name, void* base, FreezeData* fields, int num_fields) { // Work out the size of the required block int len = 0; int i; int j; for (i = 0; i < num_fields; i++) { if (fields [i].offset + FreezeSize(fields [i].size, fields [i].type) > len) len = fields [i].offset + FreezeSize(fields [i].size, fields [i].type); } // uint8 *block = new uint8 [len]; uint8* block = (uint8*)malloc(len); uint8* ptr = block; uint16 word; uint32 dword; int64 qword; // Build the block ready to be streamed out for (i = 0; i < num_fields; i++) { switch (fields [i].type) { case INT_V: switch (fields [i].size) { case 1: *ptr++ = *((uint8*) base + fields [i].offset); break; case 2: word = *((uint16*)((uint8*) base + fields [i].offset)); *ptr++ = (uint8)(word >> 8); *ptr++ = (uint8) word; break; case 4: dword = *((uint32*)((uint8*) base + fields [i].offset)); *ptr++ = (uint8)(dword >> 24); *ptr++ = (uint8)(dword >> 16); *ptr++ = (uint8)(dword >> 8); *ptr++ = (uint8) dword; break; case 8: qword = *((int64*)((uint8*) base + fields [i].offset)); *ptr++ = (uint8)(qword >> 56); *ptr++ = (uint8)(qword >> 48); *ptr++ = (uint8)(qword >> 40); *ptr++ = (uint8)(qword >> 32); *ptr++ = (uint8)(qword >> 24); *ptr++ = (uint8)(qword >> 16); *ptr++ = (uint8)(qword >> 8); *ptr++ = (uint8) qword; break; } break; case uint8_ARRAY_V: memmove(ptr, (uint8*) base + fields [i].offset, fields [i].size); ptr += fields [i].size; break; case uint16_ARRAY_V: for (j = 0; j < fields [i].size; j++) { word = *((uint16*)((uint8*) base + fields [i].offset + j * 2)); *ptr++ = (uint8)(word >> 8); *ptr++ = (uint8) word; } break; case uint32_ARRAY_V: for (j = 0; j < fields [i].size; j++) { dword = *((uint32*)((uint8*) base + fields [i].offset + j * 4)); *ptr++ = (uint8)(dword >> 24); *ptr++ = (uint8)(dword >> 16); *ptr++ = (uint8)(dword >> 8); *ptr++ = (uint8) dword; } break; } } FreezeBlock(name, block, len); free(block); }
/** * 응용프로그램의 C 언어 엔트리 포인트 */ int Main( char* pcArgument ) { QWORD qwWindowID; EVENT stEvent; KEYEVENT *pstKeyEvent; QWORD qwLastTickCount; char* pcStartMessage = "Please LButton Down To Start~!"; RECT stScreenArea; int iX; int iY; BYTE bBlockKind; //-------------------------------------------------------------------------- // 윈도우를 화면 가운데에 생성 //-------------------------------------------------------------------------- GetScreenArea( &stScreenArea ); iX = ( GetRectangleWidth( &stScreenArea ) - WINDOW_WIDTH ) / 2; iY = ( GetRectangleHeight( &stScreenArea ) - WINDOW_HEIGHT ) / 2; qwWindowID = CreateWindow( iX, iY, WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_FLAGS_DEFAULT, "Hexa" ); if( qwWindowID == WINDOW_INVALIDID ) { printf( "Window create fail\n" ); return -1; } //-------------------------------------------------------------------------- // 게임에 관련된 정보를 초기화하고 사용할 버퍼를 할당 //-------------------------------------------------------------------------- // 게임 정보를 초기화 Initialize(); // 난수 초깃값(Random Seed) 설정 srand( GetTickCount() ); //-------------------------------------------------------------------------- // 게임 정보와 게임 영역을 출력하고 게임 시작 대기 메시지를 표시 //-------------------------------------------------------------------------- DrawInformation( qwWindowID ); DrawGameArea( qwWindowID ); DrawText( qwWindowID, 7, 200, RGB( 255, 255, 255 ), RGB( 0, 0, 0 ), pcStartMessage, strlen( pcStartMessage ) ); // 출력된 메시지를 화면에 표시 ShowWindow( qwWindowID, TRUE ); //-------------------------------------------------------------------------- // GUI 태스크의 이벤트와 게임 루프를 처리하는 부분 //-------------------------------------------------------------------------- qwLastTickCount = GetTickCount(); while( 1 ) { //---------------------------------------------------------------------- // 이벤트 처리 부분 //---------------------------------------------------------------------- // 이벤트 큐에서 이벤트를 수신 if( ReceiveEventFromWindowQueue( qwWindowID, &stEvent ) == TRUE ) { // 수신된 이벤트를 타입에 따라 나누어 처리 switch( stEvent.qwType ) { // 마우스 클릭 처리 case EVENT_MOUSE_LBUTTONDOWN: // 게임 시작을 원하는 클릭이면 게임을 시작 if( g_stGameInfo.bGameStart == FALSE ) { // 게임 정보를 초기화 Initialize(); // 게임 시작 플래그를 설정 g_stGameInfo.bGameStart = TRUE; break; } break; // 키보드 눌림 처리 case EVENT_KEY_DOWN: pstKeyEvent = &( stEvent.stKeyEvent ); if( g_stGameInfo.bGameStart == FALSE ) { break; } switch( pstKeyEvent->bASCIICode ) { // 왼쪽으로 이동 case KEY_LEFT: if( IsMovePossible( g_stGameInfo.iBlockX - 1, g_stGameInfo.iBlockY ) == TRUE ) { g_stGameInfo.iBlockX -= 1; DrawGameArea( qwWindowID ); } break; // 오른쪽으로 이동 case KEY_RIGHT: if( IsMovePossible( g_stGameInfo.iBlockX + 1, g_stGameInfo.iBlockY ) == TRUE ) { g_stGameInfo.iBlockX += 1; DrawGameArea( qwWindowID ); } break; // 움직이는 블록을 구성하는 작은 블록의 순서를 변경 case KEY_UP: bBlockKind = g_stGameInfo.vbBlock[ 0 ]; memcpy( &( g_stGameInfo.vbBlock ), &( g_stGameInfo.vbBlock[ 1 ] ), BLOCKCOUNT - 1 ); g_stGameInfo.vbBlock[ BLOCKCOUNT - 1 ] = bBlockKind; DrawGameArea( qwWindowID ); break; // 블록을 아래로 이동 case KEY_DOWN: if( IsMovePossible( g_stGameInfo.iBlockX, g_stGameInfo.iBlockY + 1 ) == TRUE ) { g_stGameInfo.iBlockY += 1; } DrawGameArea( qwWindowID ); break; // 블록을 아래로 끝까지 이동 case ' ': while( IsMovePossible( g_stGameInfo.iBlockX, g_stGameInfo.iBlockY + 1 ) == TRUE ) { g_stGameInfo.iBlockY += 1; } DrawGameArea( qwWindowID ); break; } // 변경된 내용을 화면에 표시 ShowWindow( qwWindowID, TRUE ); break; // 윈도우 닫기 버튼 처리 case EVENT_WINDOW_CLOSE: // 윈도우를 삭제 DeleteWindow( qwWindowID ); return 0; break; } } //---------------------------------------------------------------------- // 게임 루프 처리 부분 //---------------------------------------------------------------------- // 게임이 시작 되었다면 레벨에 따라 일정 시간 대기한 뒤에 블록을 아래로 이동 if( ( g_stGameInfo.bGameStart == TRUE ) && ( ( GetTickCount() - qwLastTickCount ) > ( 300 - ( g_stGameInfo.qwLevel * 10 ) ) ) ) { qwLastTickCount = GetTickCount(); // 블록을 한 칸 아래로 내리고 더 이상 내릴 수 없다면 블록을 고정 if( IsMovePossible( g_stGameInfo.iBlockX, g_stGameInfo.iBlockY + 1 ) == FALSE ) { // 블록 고정할 수 없으면 게임 종료 if( FreezeBlock( g_stGameInfo.iBlockX, g_stGameInfo.iBlockY ) == FALSE ) { g_stGameInfo.bGameStart = FALSE; // 게임 종료 메시지를 출력 DrawText( qwWindowID, 82, 230, RGB( 255, 255, 255 ), RGB( 0, 0, 0 ), "Game Over~!!!", 13 ); DrawText( qwWindowID, 7, 250, RGB( 255, 255, 255 ), RGB( 0, 0, 0 ), pcStartMessage, strlen( pcStartMessage ) ); } // 보드에 블록을 검사하여 3개 이상 연속된 블록을 삭제하고 화면에 표시 EraseAllContinuousBlockOnBoard( qwWindowID ); // 새로운 블록을 생성 CreateBlock(); } else { g_stGameInfo.iBlockY++; // 게임 영역을 새로 그림 DrawGameArea( qwWindowID ); } // 변경된 내용을 화면에 표시 ShowWindow( qwWindowID, TRUE ); } else { Sleep( 0 ); } } return 0; }