/** ** Exit the game. ** ** @param err Error code to pass to shell. */ void Exit(int err) { if (GameRunning) { StopGame(GameExit); return; } StopMusic(); QuitSound(); NetworkQuitGame(); ExitNetwork1(); CleanModules(); FreeBurningBuildingFrames(); FreeSounds(); FreeGraphics(); FreePlayerColors(); FreeButtonStyles(); FreeAllContainers(); freeGuichan(); DebugPrint("Frames %lu, Slow frames %d = %ld%%\n" _C_ FrameCounter _C_ SlowFrameCounter _C_ (SlowFrameCounter * 100) / (FrameCounter ? FrameCounter : 1)); lua_settop(Lua, 0); lua_close(Lua); DeInitVideo(); #ifdef USE_PHYSFS if (PHYSFS_isInit()) { PHYSFS_deinit(); } #endif fprintf(stdout, "%s", _("Thanks for playing Stratagus.\n")); exit(err); }
// called from ---GUI--- thread NetPlayClient::~NetPlayClient() { // not perfect if (m_is_running.load()) StopGame(); if (is_connected) { m_do_loop.store(false); m_thread.join(); } if (m_server) { Disconnect(); } if (g_MainNetHost.get() == m_client) { g_MainNetHost.release(); } if (m_client) { enet_host_destroy(m_client); m_client = nullptr; } if (m_traversal_client) { ReleaseTraversalClient(); } }
/** ** Exit the game. ** ** @param err Error code to pass to shell. */ void Exit(int err) { if (GameRunning) { StopGame(GameExit); return; } StopMusic(); QuitSound(); NetworkQuit(); ExitNetwork1(); #ifdef DEBUG CleanModules(); FreeBurningBuildingFrames(); FreeSounds(); FreeGraphics(); FreePlayerColors(); FreeButtonStyles(); for (size_t i = 0; i < Containers.size(); ++i) { delete Containers[i]; } freeGuichan(); DebugPrint("Frames %lu, Slow frames %d = %ld%%\n" _C_ FrameCounter _C_ SlowFrameCounter _C_ (SlowFrameCounter * 100) / (FrameCounter ? FrameCounter : 1)); lua_settop(Lua, 0); lua_close(Lua); DeInitVideo(); #endif fprintf(stdout, "%s", _("Thanks for playing Stratagus.\n")); exit(err); }
void file_cb(Widget widget, XtPointer client, XtPointer call) { int selection = (int) client; switch(selection) { case 0: /* New Game */ NewGame(); break; case 1: /* Stop Game */ StopGame(); Message("Game stopped"); break; case 2: /* Quit */ ClearBoard(); StopGame(); exit(0); } }
// called from ---GUI--- thread NetPlay::~NetPlay() { std::lock_guard<std::mutex> lk(crit_netplay_ptr); netplay_ptr = NULL; // not perfect if (m_is_running) StopGame(); }
// called from ---GUI--- thread NetPlayClient::~NetPlayClient() { // not perfect if (m_is_running) StopGame(); if (is_connected) { m_do_loop = false; m_thread.join(); } }
/************************************************************************ * 程序退出 ************************************************************************/ void GameLogic::ExitApp() { if (GetGameType() == SINGLE_GAME_TYPE) { } else { StopGame(); GetNetworkModule()->Logout(); GetNetworkModule()->Close(); } Director::getInstance()->end(); }
void CmdQuit(CORE_DATA *cd) { USER_DATA *ud = UD(cd); if (IsPlaying(ud, cd->cmd_name)) { if (ud->in_progress) { StopGame(ud, "%s cedes victory to %s!", cd->cmd_name, GetOpponentName(ud, cd->cmd_name)); } else { UnsetPlayerName(ud, cd->cmd_name); ArenaMessageFmt("%s is no longer playing", cd->cmd_name); } } else { Reply("You are not playing"); } }
int main(int argc, char **argv) { printf("Level 9 Interpreter\n\n"); if (argc != 2) { printf("Use: %s <gamefile>\n",argv[0]); return 0; } if (!LoadGame(argv[1],NULL)) { printf("Error: Unable to open game file\n"); return 0; } while (RunGame()); StopGame(); FreeMemory(); return 0; }
// called from ---NETPLAY--- thread void NetPlayClient::ThreadFunc() { while (m_do_loop.IsSet()) { ENetEvent netEvent; int net; if (m_traversal_client) m_traversal_client->HandleResends(); net = enet_host_service(m_client, &netEvent, 250); while (!m_async_queue.Empty()) { Send(*(m_async_queue.Front().get())); m_async_queue.Pop(); } if (net > 0) { sf::Packet rpac; switch (netEvent.type) { case ENET_EVENT_TYPE_RECEIVE: rpac.append(netEvent.packet->data, netEvent.packet->dataLength); OnData(rpac); enet_packet_destroy(netEvent.packet); break; case ENET_EVENT_TYPE_DISCONNECT: m_dialog->OnConnectionLost(); if (m_is_running.IsSet()) StopGame(); break; default: break; } } } Disconnect(); return; }
// Must do several things: // - Adds the current block to the pile // - checks for "game over" state and ends game if so. // - Destroys any lines that needs destroying // - Increments the score // - Moves to the next level // - Creates the next block. void cGame::NextCycle() { if (g_pBlock != NULL) { g_pPile->AddBlock(g_pBlock); int rows = 0; g_pPile->DestroyRows(&rows); // See spec for scoring equation. if (rows > 0) { g_iScore += (SCORE_INCREMENT*(rows*rows))-(SCORE_INCREMENT*rows)+SCORE_INCREMENT; g_iLevelRows += rows; g_iTotalRows += rows; } // on level up: if (g_iLevelRows >= 10) { g_iLevel++; g_iLevelRows = 0; g_dwTimeLimit -= g_dwTimeLimit/12; } g_sNextMessage = (LPSTR)GetScoreMessage(); if (g_pPile->GetTopY() >= TETRIS_AREA_HEIGHT+BLOCK_SQUARE_SIZE) { StopGame(); } else { // Create next block g_pBlock->CreateCubes((rand()%7), TETRIS_AREA_WIDTH/2, TETRIS_AREA_HEIGHT+BLOCK_SQUARE_SIZE); m_3DRenderer->Render(g_sNextMessage, g_pBlock, g_pPile); } } }
void GameEvent(CORE_DATA *cd) { USER_DATA *ud = UD(cd); switch (cd->event) { case EVENT_START: RegisterPlugin(OPENCORE_VERSION, "chess", "cycad", "1.0", __DATE__, __TIME__, "A player-vs-player chess bot", sizeof(USER_DATA), 0); ud = UD(cd); // allocate chess board ud->board = (BOARD)calloc(8, sizeof(PIECE*)); for (int i = 0; i < 8; ++i) { ud->board[i] = (PIECE*)calloc(8, sizeof(PIECE)); } BoardReset(ud, ud->board); // draw the board LvzDrawAll(ud, NULL, true); RegisterCommand(COMMAND_CHESSHELP, "!chesshelp", "Chess", 0, CMD_PUBLIC | CMD_PRIVATE, NULL, "Get basic chessbot information", NULL); RegisterCommand(COMMAND_GAMEINFO, "!gameinfo", "Chess", 0, CMD_PUBLIC | CMD_PRIVATE, NULL, "Get information about the current game", NULL); RegisterCommand(COMMAND_WHITE, "!white", "Chess", 0, CMD_PUBLIC | CMD_PRIVATE, NULL, "Play as White", NULL); RegisterCommand(COMMAND_BLACK, "!black", "Chess", 0, CMD_PUBLIC | CMD_PRIVATE, NULL, "Play as Black", NULL); RegisterCommand(COMMAND_MOVE, "!move", "Chess", 0, CMD_PUBLIC | CMD_PRIVATE, "<coord1>,<coord2>", "Move a chess piece", NULL); RegisterCommand(COMMAND_QUIT, "!quit", "Chess", 0, CMD_PUBLIC | CMD_PRIVATE, NULL, "Stop playing chess", NULL); break; case EVENT_COMMAND: switch (cd->cmd_id) { case COMMAND_CHESSHELP: CmdChessHelp(cd); break; case COMMAND_GAMEINFO: CmdGameInfo(cd); break; case COMMAND_WHITE: CmdWhite(cd); break; case COMMAND_BLACK: CmdBlack(cd); break; case COMMAND_MOVE: CmdMove(cd); break; case COMMAND_QUIT: CmdQuit(cd); break; default: assert(0); break; } break; case EVENT_MESSAGE: #if 0 // eventually handle commands in pubchat, like "b1,c3" if (cd->msg_type == MSG_PUBLIC && ud->in_progress && IsPlaying(cd->msg_name)) { } #endif break; case EVENT_ENTER: LvzActivateBoard(); LvzDrawAll(ud, cd->p1, true); LvzToMove(ud->to_move, cd->p1); if (IsPlaying(ud, cd->p1->name)) { // player rejoined ArenaMessageFmt("%s has returned to the game", cd->p1->name); KillTimer(ud->timer); ud->timer = 0; } break; case EVENT_LEAVE: // check if this player is relevant if (IsPlaying(ud, cd->p1->name)) { if (ud->in_progress && ud->timer) { // timer is only set when one player is already gone StopGame(ud, "Both players left the game"); KillTimer(ud->timer); ud->timer = 0; } else if (ud->in_progress) { // someone left a game in progress ArenaMessageFmt("%s has left the game and has 2 minutes to return", cd->p1->name); ud->timer = SetTimer(2 * 60 * 1000, 0, 0); } else { // no need to wait for someone not playing ArenaMessageFmt("%s is no longer playing", cd->p1->name); UnsetPlayerName(ud, cd->p1->name); } } break; case EVENT_TIMER: // this game needs to be stopped due to timeout if (ud->in_progress && cd->timer_id == ud->timer) { StopGame(ud, "Player did not return to game"); ud->timer = 0; } else if (cd->timer_data1) { uint32_t objid = (uint32_t)(intptr_t)cd->timer_data1; uint32_t on = (uint32_t)(intptr_t)cd->timer_data2; if (on) { PubMessageFmt("*objon %u", objid); } else { PubMessageFmt("*objoff %u", objid); } } break; case EVENT_STOP: // free chess board for (int i = 0; i < 8; ++i) { free(ud->board[i]); } free(ud->board); // free user data free(cd->user_data); break; } }
// called from ---NETPLAY--- thread unsigned int NetPlayClient::OnData(sf::Packet& packet) { MessageId mid; packet >> mid; switch (mid) { case NP_MSG_PLAYER_JOIN: { Player player; packet >> player.pid; packet >> player.name; packet >> player.revision; { std::lock_guard<std::recursive_mutex> lkp(m_crit.players); m_players[player.pid] = player; } m_dialog->Update(); } break; case NP_MSG_PLAYER_LEAVE: { PlayerId pid; packet >> pid; { std::lock_guard<std::recursive_mutex> lkp(m_crit.players); m_players.erase(m_players.find(pid)); } m_dialog->Update(); } break; case NP_MSG_CHAT_MESSAGE: { PlayerId pid; packet >> pid; std::string msg; packet >> msg; // don't need lock to read in this thread const Player& player = m_players[pid]; // add to gui std::ostringstream ss; ss << player.name << '[' << (char)(pid + '0') << "]: " << msg; m_dialog->AppendChat(ss.str()); } break; case NP_MSG_PAD_MAPPING: { for (PadMapping& mapping : m_pad_map) { packet >> mapping; } UpdateDevices(); m_dialog->Update(); } break; case NP_MSG_WIIMOTE_MAPPING: { for (PadMapping& mapping : m_wiimote_map) { packet >> mapping; } m_dialog->Update(); } break; case NP_MSG_PAD_DATA: { PadMapping map = 0; GCPadStatus pad; packet >> map >> pad.button >> pad.analogA >> pad.analogB >> pad.stickX >> pad.stickY >> pad.substickX >> pad.substickY >> pad.triggerLeft >> pad.triggerRight; // Trusting server for good map value (>=0 && <4) // add to pad buffer m_pad_buffer.at(map).Push(pad); m_gc_pad_event.Set(); } break; case NP_MSG_WIIMOTE_DATA: { PadMapping map = 0; NetWiimote nw; u8 size; packet >> map >> size; nw.resize(size); for (unsigned int i = 0; i < size; ++i) packet >> nw[i]; // Trusting server for good map value (>=0 && <4) // add to Wiimote buffer m_wiimote_buffer.at(map).Push(nw); m_wii_pad_event.Set(); } break; case NP_MSG_PAD_BUFFER: { u32 size = 0; packet >> size; m_target_buffer_size = size; m_dialog->OnPadBufferChanged(size); } break; case NP_MSG_CHANGE_GAME: { { std::lock_guard<std::recursive_mutex> lkg(m_crit.game); packet >> m_selected_game; } // update gui m_dialog->OnMsgChangeGame(m_selected_game); sf::Packet spac; spac << static_cast<MessageId>(NP_MSG_GAME_STATUS); PlayerGameStatus status = m_dialog->FindGame(m_selected_game).empty() ? PlayerGameStatus::NotFound : PlayerGameStatus::Ok; spac << static_cast<u32>(status); Send(spac); } break; case NP_MSG_GAME_STATUS: { PlayerId pid; packet >> pid; { std::lock_guard<std::recursive_mutex> lkp(m_crit.players); Player& player = m_players[pid]; u32 status; packet >> status; player.game_status = static_cast<PlayerGameStatus>(status); } m_dialog->Update(); } break; case NP_MSG_START_GAME: { { std::lock_guard<std::recursive_mutex> lkg(m_crit.game); packet >> m_current_game; packet >> g_NetPlaySettings.m_CPUthread; packet >> g_NetPlaySettings.m_CPUcore; packet >> g_NetPlaySettings.m_EnableCheats; packet >> g_NetPlaySettings.m_SelectedLanguage; packet >> g_NetPlaySettings.m_OverrideGCLanguage; packet >> g_NetPlaySettings.m_ProgressiveScan; packet >> g_NetPlaySettings.m_PAL60; packet >> g_NetPlaySettings.m_DSPEnableJIT; packet >> g_NetPlaySettings.m_DSPHLE; packet >> g_NetPlaySettings.m_WriteToMemcard; packet >> g_NetPlaySettings.m_OCEnable; packet >> g_NetPlaySettings.m_OCFactor; int tmp; packet >> tmp; g_NetPlaySettings.m_EXIDevice[0] = (TEXIDevices)tmp; packet >> tmp; g_NetPlaySettings.m_EXIDevice[1] = (TEXIDevices)tmp; u32 time_low, time_high; packet >> time_low; packet >> time_high; g_netplay_initial_rtc = time_low | ((u64)time_high << 32); } m_dialog->OnMsgStartGame(); } break; case NP_MSG_STOP_GAME: case NP_MSG_DISABLE_GAME: { StopGame(); m_dialog->OnMsgStopGame(); } break; case NP_MSG_PING: { u32 ping_key = 0; packet >> ping_key; sf::Packet spac; spac << (MessageId)NP_MSG_PONG; spac << ping_key; Send(spac); } break; case NP_MSG_PLAYER_PING_DATA: { PlayerId pid; packet >> pid; { std::lock_guard<std::recursive_mutex> lkp(m_crit.players); Player& player = m_players[pid]; packet >> player.ping; } DisplayPlayersPing(); m_dialog->Update(); } break; case NP_MSG_DESYNC_DETECTED: { int pid_to_blame; u32 frame; packet >> pid_to_blame; packet >> frame; std::string player = "??"; std::lock_guard<std::recursive_mutex> lkp(m_crit.players); { auto it = m_players.find(pid_to_blame); if (it != m_players.end()) player = it->second.name; } m_dialog->OnDesync(frame, player); } break; case NP_MSG_SYNC_GC_SRAM: { u8 sram[sizeof(g_SRAM.p_SRAM)]; for (size_t i = 0; i < sizeof(g_SRAM.p_SRAM); ++i) { packet >> sram[i]; } { std::lock_guard<std::recursive_mutex> lkg(m_crit.game); memcpy(g_SRAM.p_SRAM, sram, sizeof(g_SRAM.p_SRAM)); g_SRAM_netplay_initialized = true; } } break; case NP_MSG_COMPUTE_MD5: { std::string file_identifier; packet >> file_identifier; ComputeMD5(file_identifier); } break; case NP_MSG_MD5_PROGRESS: { PlayerId pid; int progress; packet >> pid; packet >> progress; m_dialog->SetMD5Progress(pid, progress); } break; case NP_MSG_MD5_RESULT: { PlayerId pid; std::string result; packet >> pid; packet >> result; m_dialog->SetMD5Result(pid, result); } break; case NP_MSG_MD5_ERROR: { PlayerId pid; std::string error; packet >> pid; packet >> error; m_dialog->SetMD5Result(pid, error); } break; case NP_MSG_MD5_ABORT: { m_should_compute_MD5 = false; m_dialog->AbortMD5(); } break; default: PanicAlertT("Unknown message received with id : %d", mid); break; } return 0; }
/** ** Action condition player draw. */ void ActionDraw() { StopGame(GameDraw); }
/** ** Action condition player lose. */ void ActionDefeat() { StopGame(GameDefeat); }
int main(int argc, char *argv[]) { char text[1028],temptext[1028], str[1028]; int tlen,mlen,move[12],numlegal,done; if(argc>=3) { if(!strncasecmp("-MaxDepth",argv[argc-2], strlen("-MaxDepth"))) { MaxDepth = atoi(argv[argc-1]); argc-=2; } else MaxDepth = -1; } else MaxDepth = -1; #ifndef GRAPHICS printf("No graphics\n"); if(argc != 4) Usage(argv[0]); strcpy(player1,argv[1]); strcpy(player2,argv[2]); SecPerMove = atof(argv[3]); #endif #ifdef GRAPHICS printf("Graphics\n"); InitGraphics(argc,argv); #else NewGame(); { int x,y; /* I'll wait a bit to make sure both oponents are ready to go */ printf("waiting\n"); sleep(1); for(x=0;x<1000;x++) for(y=0;y<10000;y++); } #endif ResetBoard(); for(;;) { pthread_t thread; int rc, dummy; HandleEvents(); if(playing) { sprintf(str,"Waiting for player %d",turn+1); Message(str); HumanMoved = done = 0; //start = times(&bff); rc = pthread_create(&thread, NULL, timer, (void*)&done); pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &dummy); do { HandleEvents(); /* Give humans all the time they want to move */ if(player[turn] == HUMAN) done = HumanMoved; else if(player[turn] == COMPUTER) { char *ptr; memset(temptext,0,sizeof(temptext)); tlen = read(readfd[turn],temptext,1028); if(tlen > 0) { ptr = temptext; while(*ptr == 10 && *ptr !=0) ptr++; strcpy(text,ptr); if(strlen(text)) done=1; } } } while(playing && !done); pthread_cancel(thread); if(!playing) continue; if(player[turn] == COMPUTER && tlen <= 0) { sprintf(str,"Player %d has lost the game (time limit reached).",turn+1); Message(str); StopGame(); } else { if(player[turn] == COMPUTER) { text[tlen] = '\0'; memset(move,0,12*sizeof(int)); mlen = TextToMove(text,move); } else if(player[turn] == HUMAN) { mlen = hlen; memcpy(move,hmove,12*sizeof(int)); hlen = 0; memset(hmove,0,12*sizeof(int)); MoveToText(move,text); } if(!mlen) { /* Illegal move check 1 */ /*char temp[1000]; char *ptr1, *ptr2; ptr1=text; temp[0] = 0; ptr2=temp; while(*ptr1) { sprintf(ptr2,"%i, ", *ptr1); ptr1++; ptr2 = &(ptr2[strlen(ptr2)]); }*/ //sprintf(str,"Player %d has lost the game (illegal move %s %s submitted).",turn+1,text, temp); sprintf(str,"Player %d has lost the game (illegal move %s submitted).",turn+1,text); Message(str); StopGame(); } else { if(!IsLegal(move,mlen)) { /* Illegal move check 2 */ /*char temp[1000]; char *ptr1, *ptr2; ptr1=text; temp[0] = 0; ptr2=temp; while(*ptr1) { sprintf(ptr2,"%i, ", *ptr1); ptr1++; ptr2 = &(ptr2[strlen(ptr2)]); } sprintf(str,"Player %d has lost the game (illegal move %s %s submitted).",turn+1,text, temp);*/ sprintf(str,"Player %d has lost the game (illegal move %s submitted).",turn+1,text); Message(str); StopGame(); } else { /* Legal Move */ PerformMove(move,mlen); #ifdef GRAPHICS UpdateBoard(); #else printf("Move: %s\n",text); PrintBoard(); #endif if(turn) turn=0; else turn=1; /* Check to see if other player has now lost */ numlegal = FindLegalMoves(turn+1); if(!numlegal) { sprintf(str,"Player %d has lost the game.",turn+1); Message(str); StopGame(); } else if(player[turn] == COMPUTER) { write(writefd[turn],text,strlen(text)); } } } } } } }
/* Called when the 'New Game' menu item is selected */ void NewGame(void) { char arg1[16],arg2[16], arg01[16], arg02[16]; int i; #ifdef GRAPHICS if(!NewDialog(player1,player2,&SecPerMove)) return; if(!strcmp(player1,"human")) player[0] = HUMAN; else player[0] = COMPUTER; if(!strcmp(player2,"human")) player[1] = HUMAN; else player[1] = COMPUTER; #else player[0]=COMPUTER; player[1]=COMPUTER; #endif arg01[0]=0; arg02[0]=0; player1Java=0; player2Java=0; if(!strncmp(player1,"java",4)) { player1Java=1; fprintf(stderr,"Player1 is java player\n"); strcpy(arg01,&(player1[5])); player1[4]=0; strcpy(player1,"/usr/bin/java"); fprintf(stderr,"%s %s\n", player1, arg01); } if(!strncmp(player2,"java",4)) { player2Java=1; fprintf(stderr,"Player2 is java player\n"); strcpy(arg02,&(player2[5])); //player2[4]=0; strcpy(player2,"/usr/bin/java"); fprintf(stderr,"%s %s\n", player2, arg02); } /* If 'New Game' is chosen while a game is in progress, stop the game */ if (playing) StopGame(); // Set up the pipes necessary for communication with computer players. for (i = 0; i < 2; i++) { int to_proc[2]; int from_proc[2]; if (player[i] == HUMAN) { // Pipes aren't needed for human players. continue; } pipe(to_proc); pipe(from_proc); writefd[i] = to_proc[1]; readfd[i] = from_proc[0]; if (fcntl(readfd[i],F_SETFL,(int)O_NDELAY) < 0) { printf("fcntl failed\n"); return; } /* Fork a child process. We will then overlay the computer program */ if((pid[i] = fork()) == (pid_t)0) { int temp; dup2(to_proc[0], STDIN_FILENO); close(to_proc[0]); dup2(from_proc[1], STDOUT_FILENO); close(from_proc[1]); sprintf(arg1,"%.2f",SecPerMove); if(MaxDepth >= 0) { sprintf(arg2,"%d", MaxDepth); if((i==0 && player1Java ) || (i==1 && player2Java)) temp = execl(i?player2:player1,i?player2:player1, i?arg02:arg01,arg1,arg2, NULL); else temp = execl(i?player2:player1,i?player2:player1, arg1,arg2,(char *)0); if(temp) { fprintf(stderr, "exec for %s failed\n",i?player2:player1); exit(0); } } else { if((i==0 && player1Java ) || (i==1 && player2Java)) temp = execl(i?player2:player1,i?player2:player1, i?arg02:arg01,arg1, NULL); else temp = execl(i?player2:player1,i?player2:player1, arg1,(char *)0); if(temp) { fprintf(stderr, "exec for %s failed\n",i?player2:player1); exit(0); } } } } ResetBoard(); playing = 1; turn = 0; hlen = 0; memset(hmove,0,12*sizeof(int)); FindLegalMoves(turn+1); /* Tell the computer programs which player they are */ if(player[0] == COMPUTER) { write(writefd[0],"Player1",7); fsync(writefd[0]); } if(player[1] == COMPUTER) { write(writefd[1],"Player2",7); fsync(writefd[1]); } }
void GameManager::OnStopGame() { StopGame(); }
/** ** Action condition player wins. */ void ActionVictory() { StopGame(GameVictory); }
// TODO: Handle en passant static char* TryMove(USER_DATA *ud, COLOR c, int x, int y, int dx, int dy) { BOARD b = ud->board; PIECE *p = GetPieceAt(ud->board, x, y); if (p->type == TYPE_NONE) { return "No piece at that position!"; } else if (p->color != c) { return "That piece is not yours!"; } // check if this move is a castle attempt // TODO: check for rook movements if (p->type == TYPE_KING && IsCastleMove(c, x, y, dx, dy)) { if (ColorCanCastle(ud, c) == false) { return "You can no longer castle"; } return TryCastle(ud, c, x, y, dx, dy); } // check that the piece can make this movement if (PieceCanAttack(ud->board, c, p->type, x, y, dx, dy) == false) { return "Piece can't make that movement"; } // target piece PIECE *t = GetPieceAt(ud->board, dx, dy); if (t->type != TYPE_NONE && t->color == c) { return "You already have a piece in the destination position!"; } // make the movements to check for check, but store the data // in case the board needs to be reverted PIECE old_p = *p; PIECE old_t = *t; SetPieceAt(b, dx, dy, p->color, p->type); SetPieceAt(b, x, y, COLOR_NONE, TYPE_NONE); // find the king and test for check int kingx, kingy; FindKing(b, c, &kingx, &kingy); if (IsCoordAttackedBy(b, GetOppositeColor(c), kingx, kingy) == true) { // restore saved positions SetPieceAt(b, x, y, old_p.color, old_p.type); SetPieceAt(b, dx, dy, old_t.color, old_t.type); return "That move would place your King in check!"; } // // At this point, the move was successful // // make the pieces blink // TODO: this will erroneously leave pieces on if 2 moves // are made quickly uint32_t objid = LvzGetObjId(old_p.color, old_p.type, dx, dy); SetTimer(500, (void*)objid, (void*)0); SetTimer(1000, (void*)objid, (void*)1); SetTimer(1500, (void*)objid, (void*)0); SetTimer(2000, (void*)objid, (void*)1); SetTimer(2500, (void*)objid, (void*)0); SetTimer(3000, (void*)objid, (void*)1); if (old_t.type != TYPE_NONE) { // flash the captured piece objid = LvzGetObjId(old_t.color, old_t.type, dx, dy); SetTimer(500, (void*)objid, (void*)1); SetTimer(1000, (void*)objid, (void*)0); SetTimer(1500, (void*)objid, (void*)1); SetTimer(2000, (void*)objid, (void*)0); SetTimer(2500, (void*)objid, (void*)1); SetTimer(3000, (void*)objid, (void*)0); } if (old_p.type == TYPE_KING) { // kings cant castle once theyve moved if (old_p.color == COLOR_WHITE) { ud->white_can_castle = false; } else if (old_p.color == COLOR_BLACK) { ud->black_can_castle = false; } } // set if a piece has been captured bool capture = old_t.type != TYPE_NONE; // remove drawing of the old pieces LvzActivate(ud, NULL, old_p.color, old_p.type, x, y, false); if (capture) { LvzActivate(ud, NULL, old_t.color, old_t.type, dx, dy, false); } // check for pawn promotions // TODO: handle underpromotions bool promoted = false; p = GetPieceAt(b, dx, dy); if (p->type == TYPE_PAWN) { if (p->color == COLOR_WHITE && dy == 7) { p->type = TYPE_QUEEN; promoted = true; } else if (p->color == COLOR_BLACK && dy == 0) { p->type = TYPE_QUEEN; promoted = true; } } // draw the new piece LvzActivate(ud, NULL, old_p.color, old_p.type, dx, dy, true); objid = LvzGetObjId(old_p.color, old_p.type, dx, dy); // create move notation char move[6]; move[0] = x + 'a'; move[1] = y + '1'; move[2] = ','; move[3] = dx + 'a'; move[4] = dy + '1'; move[5] = '\0'; // announce the move char line[256]; snprintf(line, 256, "%s (%s) Moves: %s", GetPlayerName(ud, c), GetColorText(ud->to_move), move); if (capture) { // add capture line char capture[64]; snprintf(capture, 64, ", capturing a %s!", GetTypeName(old_t.type)); strlcat(line, capture, 256); } if (promoted == true) { // add promition line strlcat(line, " Pawn promoted to Queen!", 256); } FindKing(b, GetOppositeColor(c), &kingx, &kingy); if (IsCoordAttackedBy(b, c, kingx, kingy) == true) { if (IsCheckmatedBy(b, c, kingx, kingy) == true) { strlcat(line, " Checkmate!", 256); ArenaMessage(line); char gametime[32]; TicksToText(gametime, 32, GetTicksMs() - ud->start_tick); StopGame(ud, "%s Wins in %s!", GetPlayerName(ud, c), gametime); } else { strlcat(line, " Check!", 256); ArenaMessage(line); } } else { ArenaMessage(line); } return NULL; }