示例#1
0
int real_main() {
    srand48(time(NULL));

    if (!al_init()) {
        puts("Could not initialise allegro");
        return 1;
    }
    if (!al_install_keyboard()) {
        puts("Could not initialise allegro keyboard subsystem");
        return 1;
    }
    keys = malloc(sizeof(ALLEGRO_KEYBOARD_STATE));
    if (!init_font()) {
        puts("Could not initialise allegro font subsystem");
        return 1;
    }

    al_set_new_display_flags(ALLEGRO_FULLSCREEN_WINDOW);

    ALLEGRO_DISPLAY* display = al_create_display(1, 1);
    if (!display) {
        puts("Could not initialise allegro display");
        return 1;
    }

    Vector size = new_vector();
    size.x = al_get_display_width(display);
    size.y = al_get_display_height(display);

    Game* game = new_game(size);
    int i;
    for (i = 0; i < ASTEROIDN; i++)
        spawn_asteroid(game);

    ALLEGRO_TIMER* timer = al_create_timer(1.0/FPS);

    ALLEGRO_EVENT_QUEUE *timereq = al_create_event_queue();
    ALLEGRO_EVENT_QUEUE *genericeq = al_create_event_queue();
    if (!timereq || !genericeq) {
        puts("Could not create allegro event queue");
        return 1;
    }
    al_register_event_source(timereq, al_get_timer_event_source(timer));

    al_register_event_source(genericeq, al_get_keyboard_event_source());
    al_register_event_source(genericeq, al_get_display_event_source(display));

    al_start_timer(timer); // Start generating timer events
    ALLEGRO_EVENT *timerevent = malloc(sizeof(ALLEGRO_EVENT));
    ALLEGRO_EVENT *genericevent = malloc(sizeof(ALLEGRO_EVENT));

    float last_drawn, now;
    last_drawn = now = al_get_time();
    while (game->status != Quit) {
        al_get_keyboard_state(keys);

        al_wait_for_event(timereq, NULL);
        al_get_next_event(timereq, timerevent);
        // No need to fill up the queue if we are late drawing frames
        al_flush_event_queue(timereq);

        handle_key_status(game, keys);

        while(al_get_next_event(genericeq, genericevent))
            switch(genericevent->type) {
            case ALLEGRO_EVENT_KEY_DOWN:
                handle_key_event(game, genericevent->keyboard.keycode);
                break;

            case ALLEGRO_EVENT_DISPLAY_RESIZE:
                game->size.x = genericevent->display.x;
                game->size.y = genericevent->display.y;
                al_acknowledge_resize(display);
                break;

            case ALLEGRO_EVENT_DISPLAY_CLOSE:
                game->status = Quit;
                break;
            }

        now = al_get_time();
        update_game(game, now - last_drawn);
        last_drawn = now;

        draw_game(game, game->status == Playing ? 1 : 0.2);
        switch(game->status) {
        case Playing:
            break;
        case Paused:
            draw_paused(game);
            break;
        case Won:
            draw_won(game);
            break;
        case Lost:
            draw_lost(game);
            break;
        default:
            break;
        }

        al_flip_display();
    }

    free(timerevent);
    free(genericevent);
    delete_game(game);
    return 0;
}
示例#2
0
/* run the state driven loop until game is broken up or finished */
void client_game_run( void )
{
	int ms, frame_delay = config.fps?10:1;
	int button_clicked, key_pressed;
	SDL_Event event;
	int abort = 0, i, j, penalty;
	/* frame rate */
	int frames = 0;
	int frame_time = SDL_GetTicks();

	event_clear_sdl_queue();
	
	stk_display_fade( STK_FADE_IN, STK_FADE_DEFAULT_TIME );
	
	stats_received = 0;
	stk_timer_reset(); ms = 1;
	while ( !abort && !stk_quit_request ) {
		/* check wether an event occured */
		button_clicked = key_pressed = 0;
		if ( SDL_PollEvent( &event ) ) {
			if ( client_state == CS_PAUSE && game->game_type == GT_NETWORK )
				gui_dispatch_event( &event, ms );
			else
			if ( event.type == SDL_MOUSEBUTTONDOWN )
				button_clicked = event.button.button;
			else
			if ( event.type == SDL_KEYDOWN ) {
				key_pressed = event.key.keysym.sym;
				if ( handle_default_key( key_pressed, &abort ) )
					key_pressed = 0;
			}
			else
			if (event.type == SDL_ACTIVEEVENT)
		          {
			    if (event.active.state == SDL_APPINPUTFOCUS ||
				event.active.state == SDL_APPACTIVE )
                            if (event.active.gain == 0 )
			      client_set_pause(1);
			  }
		}
		else if ( client_state == CS_PAUSE && game->game_type == GT_NETWORK )
			gui_dispatch_event( 0, ms );

		/* check whether Shift is pressed to switch between own and highest score */
		if (game->game_type == GT_LOCAL)
		  handle_display_switch();

		/* let server know we're still alive except
		 * in CS_PLAY as we send paddle updates there */
		if ( game->game_type == GT_NETWORK )
			comm_send_heartbeat();

		/* handle client */
		switch ( client_state ) {

		case CS_FINAL_STATS:
			if ( key_pressed==SDLK_SPACE ) abort = 1;
			break;
			
		case CS_FATAL_ERROR:
			/* after game was violently broken up the server
			 * may still send the stats of the game so far */
			if ( button_clicked || key_pressed ) {
				SDL_Delay(250); /* give time to release button */
				set_state( CS_RECV_STATS );
				display_text( font, "Receiving final stats..." );
			}
			break;
			
		case CS_FINAL_TABLE:
			if ( button_clicked || key_pressed ) {
				check_highscores();
				select_chart( game_set->name, 0 );
                                /* remove saved game */
                                slot_delete( 0 );
                                slot_update_hint( 0, item_resume_0->hint );
				/* quit local game */
				abort = 1;
			}
			break;

		case CS_SCORE_TABLE:
			/* show who's next player and scores in local game */
			display_score_table( "Next Player: %s", cur_player->name );
			set_state( CS_GET_READY );
			break;
        
        case CS_BONUS_LEVEL_SCORE:
            /* display total score from this level for player */
            display_bonus_level_score();
			set_state( CS_GET_READY_FOR_NEXT_LEVEL );
            break;
			
		case CS_FINAL_PLAYER_INFO:
			if ( button_clicked || key_pressed ) {
				SDL_Delay(250); /* give time to release button */
				set_state( CS_NEXT_PLAYER );
			}
			break;

		case CS_RECV_LEVEL:
			comm_recv();
			if ( cur_player->next_level_received ) {
				cur_player->next_level_received = 0;
				cur_player->paddle_id = cur_player->next_paddle_id;
				init_next_round();
			}
			break;

		case CS_RECV_STATS:
			comm_recv();
			if ( stats_received ) {
				set_state( CS_FINAL_STATS );
				display_final_stats();
			}
			break;
			
		case CS_ROUND_RESULT:
			if ( button_clicked || key_pressed ) {
				SDL_Delay(250); /* give time to release button */
				if ( game_over ) {
					set_state( CS_RECV_STATS );
					display_text( font, "Receiving final stats..." );
				} else {
					set_state( CS_RECV_LEVEL );
					display_text( font, "Receiving level data..." );
 				}
			}
			break;
			
		case CS_GET_READY:
			if ( button_clicked || key_pressed ) {
				SDL_Delay(250); /* give time to release button */
				comm_send_short( MSG_READY );
				set_state( CS_PLAY );
			}
			break;

		case CS_GET_READY_FOR_NEXT_LEVEL:
			if ( button_clicked || key_pressed ) {
				SDL_Delay(250); /* give time to release button */
				set_state( CS_NEXT_LEVEL );
			}
			break;

		case CS_PAUSE:
			if ( game->game_type == GT_LOCAL ) break;

			/* check wether pause chatroom has been closed
			 * either by client or remote */
			comm_recv();
			break;
			
		case CS_PLAY:
			/* hide objects */
			begin_frame();
			
			/* apply events to local paddle */
			paddle_handle_events( l_paddle, ms );

			/* update local objects and communicate if
			 * comm_delay ms have passed */
			update_game( ms );
			
			/* show objects */
			end_frame();

			/* handle local level over */
			if ( game->level_over ) {
				if ( game->game_type == GT_LOCAL ) {
					if ( game_set == 0 ) {
						abort = 1; /* was a test level */
						grab_input(0);
						break;
					}
					if ( game->winner == PADDLE_BOTTOM )
                    {
                        if (local_game->isBonusLevel)
                            set_state( CS_BONUS_LEVEL_SCORE );
                        else
                            set_state( CS_NEXT_LEVEL );
                    }
					else
						set_state( CS_LOOSE_LIFE );
				} else {
					finalize_round();
				}
			}
			break;

		case CS_NEXT_LEVEL:
			/* apply paddle stats to player */
			game_set_current( local_game );
			game_update_stats( PADDLE_BOTTOM, &cur_player->stats );
			game_set_current( game );
			/* init next level for player in local game */
			cur_player->level_id++;
			if ( cur_player->level_id >= game_set->count ) {
				/* deactivate player */
				cur_player->lives = 0;
				display_text( font, 
					"You've cleared all levels...#Congratulations!!!" );
				set_state( CS_FINAL_PLAYER_INFO );
				break;
			}
			/* get snapshot for next init */
			cur_player->snapshot = *game_set->levels[cur_player->level_id];
			/* cycle players */
			set_state( CS_NEXT_PLAYER );
			break;

		case CS_RESTART_LEVEL:
			/* apply paddle stats to player */
			game_set_current( local_game );
			game_update_stats( PADDLE_BOTTOM, &cur_player->stats );
			game_set_current( game );
			/* reset level for next turn */
			cur_player->snapshot = *game_set->levels[cur_player->level_id];
			/* decrease lives (is checked that this wasn't the last one) */
			cur_player->lives--;
			/* cycle players */
			set_state( CS_NEXT_PLAYER );
			break;
			
		case CS_LOOSE_LIFE:
			/* apply paddle stats to player */
			game_set_current( local_game );
			game_update_stats( PADDLE_BOTTOM, &cur_player->stats );
			game_set_current( game );

			/* remember level for next turn */
			game_get_level_snapshot( &cur_player->snapshot );

			/* decrease lives */
			cur_player->lives--;
			if ( cur_player->lives == 0 ) {
				display_text( font, 
					"You've lost all lives...#Do you want to buy a continue#for 100%% of your score? y/n" );
                                set_state( CS_CONFIRM_CONTINUE );
				//set_state( CS_FINAL_PLAYER_INFO );
				break;
			}
			set_state( CS_NEXT_PLAYER );
			break;

		case CS_NEXT_PLAYER:
			/* game over? */
			if ( players_count() == 0 ) {
				display_score_table( "Game Over!" );
				set_state( CS_FINAL_TABLE );
				break;
			}
			/* speak and fade */
			play_speech();
			fade_anims();
			/* finalize current game context */
			finalize_level();
			/* set next player */
			cur_player = players_get_next();
			init_level( cur_player, PADDLE_BOTTOM );
			if ( player_count > 1 )
				set_state( CS_SCORE_TABLE );
			else {
				set_state( CS_PLAY ); /* one player starts immediately */
				stk_display_update( STK_UPDATE_ALL );
			}
			break;
		
                case CS_CONFIRM_CONTINUE:
		case CS_CONFIRM_QUIT:
		case CS_CONFIRM_WARP:
		case CS_CONFIRM_RESTART:
			if ( key_pressed == 0 ) break;
			if ( key_pressed==SDLK_n||key_pressed==SDLK_ESCAPE ) {
                            /* if denying continue... DIE!!! */
                            if ( client_state == CS_CONFIRM_CONTINUE )
                            {
				SDL_Delay(250); /* give time to release button */
				set_state( CS_NEXT_PLAYER );
                                //set_state( CS_FINAL_PLAYER_INFO );
                            }
                            else
				set_state( CS_PLAY );
			    break;
			}
			if ( key_pressed != SDLK_y && key_pressed != SDLK_z ) break;
			/* handle confirmed action */
			SDL_Delay(250); /* give time to release button */
			switch( client_state ) {
                                case CS_CONFIRM_CONTINUE:
                                    /* clear score and give full lives again */
                                    cur_player->lives = game->diff->lives;
                                    cur_player->stats.total_score = 0;
                                    set_state( CS_NEXT_PLAYER );
                                    break;
				case CS_CONFIRM_QUIT:
					comm_send_short( MSG_QUIT_GAME );
					if ( game->game_type == GT_LOCAL ) {
						/* apply paddle stats to player */
						game_set_current( local_game );
						game_update_stats( PADDLE_BOTTOM, &cur_player->stats );
						game_set_current( game );
                                                /* no higscore check anymore as game is supposed to
                                                 * be resumed until normal game over */
						/* testing levels don't got for
						 * high scores ***
						if ( game_set ) {
							check_highscores();
							select_chart( game_set->name, 0 );
						}*/
                                                /* save local game */
                                                if ( game_set != 0 /*not testing a level*/ )
                                                    save_local_game( 0 );
						
                                                abort = 1;
					}
					else {
						/* await game stats */
						set_state( CS_RECV_STATS );
						display_text( font, "Receiving final stats..." );
					}
					break;
				case CS_CONFIRM_WARP:
					game->winner = -1; /* no speech */
					local_game->winner = -1; /* not counted as win */
                                        /* substract doubled score of remaining bricks */
                                        penalty = 0;
                                        for ( i = 0; i < MAP_WIDTH; i++ )
                                            for ( j = 0; j < MAP_HEIGHT; j++ )
                                                if ( local_game->bricks[i][j].dur != -1 )
                                                    penalty += local_game->bricks[i][j].score;
                                        printf( "warp penalty: -%d\n", penalty );
                                        local_game->paddles[0]->score -= penalty;
					set_state( CS_NEXT_LEVEL );
					break;
				case CS_CONFIRM_RESTART:
					game->winner = -1; /* no speech */
					local_game->winner = -1; /* not counted as win */
					local_game->level_over = 1;
					set_state( CS_RESTART_LEVEL );
					break;
			}
			break;

		}

		/* update anything that was changed */
		stk_display_update( STK_UPDATE_RECTS );

		/* get time since last call and delay if below frame_delay */
		ms = stk_timer_get_time();
		if ( ms < frame_delay ) {
			SDL_Delay( frame_delay - ms );
			ms += stk_timer_get_time();
		}
		frames++;
	}
	finalize_level();
	client_state = CLIENT_NONE;

	stk_display_fade( STK_FADE_OUT, STK_FADE_DEFAULT_TIME );
	if ( stk_quit_request )
		comm_send_short( MSG_DISCONNECT );
	else
		comm_send_short( MSG_UNHIDE );

	/* frame rate */
	frame_time = SDL_GetTicks() - frame_time;
	printf( "Time: %.2f, Frames: %i -> FPS: %.2f\n", 
		(double)frame_time / 1000, frames, 1000.0*frames/frame_time );

	event_clear_sdl_queue();

	/* update the selected user and the user list in network as 
	 * we received ADD/REMOVE_USER messages */
	gui_list_update( list_users, client_users->count );
	/* re-select current entry */
	if ( client_user ) {
		i = list_check( client_users, client_user );
		if ( i != -1 )
			gui_list_select( list_users, 0, i, 1 );
	}
}
示例#3
0
文件: main.c 项目: needs/anko
int main(int argc, char **argv)
{
	world_t world;
	game_t game;
	double last_time = 0;
	double current_time = 0;
	float deltatime = 0;
	float sleep_time;

	if (config_from_file("anko.cfg", 1) == 2)
		return EXIT_FAILURE;
	if (config_from_args(argc, argv))
		return EXIT_FAILURE;

	if (!init())
		goto err_init;
	if (!new_game(&game, config.board_width, config.board_height, &config.gen_params, config.sim_speed * 1000))
		goto err_game;
	if (!create_world(&world, &game))
		goto err_world;
	if ((current_ui = init_ui_game(&world)) == NULL)
		goto err_ui;

	world_set_active_player(&world, add_player(&game, TEAM_BURNER));
	events_link_frame(&current_ui); // link window event to game ui frame
	glClearColor(0, 0, 0, 1);

	last_time = 0;
	while(!glfwWindowShouldClose(window)) {
	    current_time = glfwGetTime();
		deltatime = current_time - last_time;
		update_speed(deltatime);
		glfwPollEvents();

		// Update
		update_ui(current_ui, deltatime);
		update_world(&world);
		if (update_game(&game, deltatime * 1000))
			refresh_world(&world);
		if(should_quit)
			glfwSetWindowShouldClose(window, GL_TRUE);

		// Rendering
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
		draw_ui(current_ui);
		font_swap_buffers();
		glfwSwapBuffers(window);

		// Update speed and sleep if necessary
		last_time = current_time;
		sleep_time = (current_time + MAX_MSPF - glfwGetTime()) * 1000 * 1000;
		if(sleep_time > 0)
			usleep(sleep_time);
	}

	destroy_ui(current_ui);
	game_over(&game);
	end_of_the_world(&world); // Tin tin tin
	terminate();

	return EXIT_SUCCESS;
err_ui:
	end_of_the_world(&world);
err_world:
	game_over(&game);
err_game:
	terminate();
err_init:
	return EXIT_FAILURE;
}
示例#4
0
int main(int argc, char* argv[])
{
	// init allegro and add keyboard and optional mouse support
	allegro_init();
	install_timer();
	install_keyboard();
	if (ENABLE_MOUSE_SUPPORT)
	{
		install_mouse();
	}

	// set the video mode
	set_color_depth(WINDOW_COLOR_DEPTH);
	set_gfx_mode(
		(WINDOW_USE_FULLSCREEN) ?
			GFX_AUTODETECT_FULLSCREEN :
			GFX_AUTODETECT_WINDOWED,
		WINDOW_WIDTH, WINDOW_HEIGHT, 0, 0);
	// set the window caption text
	set_window_title(WINDOW_CAPTION);

	// create the back buffer bitmap
	backbuffer = create_bitmap(SCREEN_W, SCREEN_H);

	// seed the random number generator
	srand(time(0));

	// lock the static functions and variables we need for handling timing and closing the window via the [X] button
	LOCK_FUNCTION(my_allegro_close_button_handler);
	LOCK_FUNCTION(my_allegro_timer_speed_controller);
	LOCK_VARIABLE(allegrotimerspeedcounter);

	// set the callback function for the close-button to our global handler function
	set_close_button_callback(my_allegro_close_button_handler);

	// set our FPS lock timing global function
	install_int_ex(my_allegro_timer_speed_controller, BPS_TO_TIMER(FRAME_LOCK_RATE));

	// setup the game
	if (!setup_game())
	{
		fprintf(stderr, "The game initialization has failed. Cannot continue!\n");
		exit(1);
	}

	// main loop
	bool gameover = false;
	while(!gameover)
	{
		// if our global is ever false
		if (!mainthreadisrunning)
		{
			gameover = true;
		}

		// we only draw when the FPS should be locked
		if (allegrotimerspeedcounter > 0)
		{
			// we only update during our FPS lock time
			while (allegrotimerspeedcounter > 0)
			{
				// ensure the keyboard data is current
				if (keyboard_needs_poll())
				{
					poll_keyboard();
				}

				// ensure the mosue data is current
				if (ENABLE_MOUSE_SUPPORT)
				{
					if (mouse_needs_poll())
					{
						poll_mouse();
					}
				}

				// update
				update_game();

				// decrement the global timing var so that we can leave the update loop!
				allegrotimerspeedcounter--;
			}

			// start rendering the scene
			render_game();

			if (ENABLE_MOUSE_SUPPORT)
			{
				show_mouse(backbuffer);
			}

			// make it all visible
			blit(backbuffer, screen, 0, 0, 0, 0, backbuffer->w, backbuffer->h);
		}
		else
		{
			// a little rest to keep CPU usage down ^-^
			rest(1);
		}
	}

	// shutdown the game
	shutdown_game();

	// clean up the back buffer
	if (backbuffer)
	{
		if (ENABLE_MOUSE_SUPPORT)
		{
			show_mouse(0);
		}
		destroy_bitmap(backbuffer);
	}

	return 0;
}
示例#5
0
void Game::run()
{	

	//_________________________________________________________________
	//										V I D E O   S E T T I N G S
	screen_x_res = 640;
	screen_y_res = 480;

	CL_DisplayWindowDescription desc;
	desc.set_title("Roadgeddon");
	desc.set_size(CL_Size(screen_x_res, screen_y_res), true);
	desc.set_allow_resize(false);

	CL_DisplayWindow window(desc);
	
	CL_Slot slot_quit				= window.sig_window_close()							.connect(this,&Game::on_quit);
	CL_Slot slot_keyboard_key_down	= (window.get_ic().get_keyboard()).sig_key_down()	.connect(this,&Game::on_key_down);
	CL_Slot slot_keyboard_key_up	= (window.get_ic().get_keyboard()).sig_key_up()		.connect(this,&Game::on_key_up);
	CL_Slot slot_mouse_moved		= (window.get_ic().get_mouse()).sig_pointer_move()	.connect(this,&Game::on_pointer_move);
	CL_Slot slot_mouse_down			= (window.get_ic().get_mouse()).sig_key_down()		.connect(this,&Game::on_pointer_down);
	CL_Slot slot_mouse_up			= (window.get_ic().get_mouse()).sig_key_up()		.connect(this,&Game::on_pointer_up);
	
	gc = window.get_gc();

	CL_ResourceManager resources("resources.xml");
	resources_=&resources;

	int time_elapsed_ms = 0;
	int lastTime = 0;
	int currentTime = 0;
	currentTime = CL_System::get_time();
	lastTime = CL_System::get_time();

	//________________________________________________________________
	//											           S O U N D S

	total_channels=3;
	current_channel=1;
	CL_SoundBuffer music("Music1",&resources);
	music.set_volume(0.3f);

	sound_session1.play();
	sound_session2.play();
	sound_session3.play();

	total_samples = 6;
	samples.resize(total_samples);
	samples[0] = CL_SoundBuffer("Explosion1",&resources);
	samples[1] = CL_SoundBuffer("Explosion2",&resources);
	samples[2] = CL_SoundBuffer("Hurt1",&resources);
	samples[3] = CL_SoundBuffer("Hurt2",&resources);
	samples[4] = CL_SoundBuffer("Powerup1",&resources);
	samples[5] = CL_SoundBuffer("Shoot1",&resources);
	
	for(int i = 0; i<total_samples; i++)
	{
		samples[i].set_volume(0.3f);
	}
	
	CL_SoundBuffer_Session music_session = music.prepare();
	music_session_ = &music_session;

	music_session.set_looping(true);
	music_session.play();
	is_music_muted = false;

	//________________________________________________________________
	//											     G A M E   P R E P
	
	Map map(*this);
	Player player(*this);

	mapP = &map;
	playerP = &player;

	time_elapsed_since_last_enemy=0;
	
	//________________________________________________________________
	//														 O T H E R 
	srand(CL_System::get_time());

	while (!quit)
	{
		currentTime = CL_System::get_time();
		time_elapsed_ms = currentTime - lastTime; 
		lastTime = currentTime;
	
		update_game(time_elapsed_ms);
		update_signal.invoke(time_elapsed_ms);

		map.drawBackground();
		draw_signal.invoke();

		// Flip the display, showing on the screen what we have drawed since last call to flip()
		window.flip(1);

		// This call processes user input and other events
		CL_KeepAlive::process(0);

		// Sleep for a little while to avoid using too much of the CPU.
		CL_System::sleep(5);

		if(objects_for_deletion.size()>0)
		{
			std::list<Gameobject *>::iterator it;
			for(it=objects_for_deletion.begin(); it!= objects_for_deletion.end(); ++it)
			{
				delete (*it);
			}

			objects_for_deletion.clear();
		}
	}
}
示例#6
0
void game_wait(int created_game) {
    int key = 0;

    dispmultiframe();

    // this prints out current users in this game
    int i = created_game; // (which also needs to be integrated with server)
    // int onlinelistoffset = 0    ;

    int p_id;
    int foxes;
    int command;
    char* buffer;

    while (1) {
        int useroffset = 1;

        if (receive(sockfd, &command, &buffer) < 0) {
            if (errno != EWOULDBLOCK && errno != EAGAIN)
                return;
        }
        else {
            switch (command) {
                case CMD_NEW_REQUEST:
                    if (confirm_request(buffer))
                        transmit(sockfd, CMD_ACCEPT_REQ, buffer);
                    else
                        transmit(sockfd, CMD_REJECT_REQ, buffer);
                    dispmultiframe();
                    break;
                case CMD_CANCEL_REQ:
                    // TODO: implement
                    break;
                case CMD_PLAYER_JOIN:
                    sscanf(buffer, "%d", &p_id);
                    for (foxes = 0; foxes < games[i].slots_total; foxes++) {
                        if (games[i].players[foxes] == EMPTY_SLOT) {
                            games[i].players[foxes] = p_id;
                            break;
                        }
                    }
                    break;
                case CMD_PLAYER_PART:
                    sscanf(buffer, "%d", &p_id);
                    for (foxes = 0; foxes < games[i].slots_total; foxes++) {
                        if (games[i].players[foxes] == p_id) {
                            games[i].players[foxes] = EMPTY_SLOT;
                            break;
                        }
                    }
                    break;
                case CMD_GAME_START: {
                    game_t game;
                    setup_game(&game);
                    setup_multiplayer(&game, games[i].slots_total, atoi(buffer), sockfd);
                    while (game.running) {
                        update_game(&game);
                        usleep(1000000 / FPS);
                    }
                    return;
                }
                case CMD_QUIT:
                case CMD_ERROR:
                    return;
            }
            free(buffer);
        }

        switch ((key = getkey())) {
            case 'q':
            case 'Q':
            case 27: // esc
                transmit(sockfd, CMD_PLAYER_PART, NULL);
                xt_par0(XT_CLEAR_SCREEN);
                return;
        }

        for (foxes = 0; foxes < games[i].slots_total; foxes++) {
            SETPOS(6 + 2 * i + useroffset, 8);
            if (games[i].players[foxes] != EMPTY_SLOT) {
                printf("%d", games[i].players[foxes]);
                useroffset++;
            }
        }

        SETPOS(2,3);
        printf("%s", games[created_game].name);
        SETPOS(ROWS, COLS);

        fflush(stdout);
        usleep(1000000 / 20);
    }
}