static int minimap_handle_event_click(minimap_t *minimap, int x, int y) { map_pos_t pos = minimap_map_pos_from_screen_pix(minimap, x, y); viewport_move_to_map_pos(interface_get_top_viewport(minimap->interface), pos); interface_update_map_cursor_pos(minimap->interface, pos); interface_close_popup(minimap->interface); return 0; }
/* game_loop() has been turned into a SDL based loop. The code for one iteration of the original game_loop is in game_loop_iter. */ static void game_loop() { /* FPS */ int fps = 0; int fps_ema = 0; int fps_target = 25; const float ema_alpha = 0.003; int drag_button = 0; unsigned int last_down[3] = {0}; unsigned int last_click[3] = {0}; unsigned int current_ticks = SDL_GetTicks(); unsigned int accum = 0; unsigned int accum_frames = 0; SDL_Event event; gui_event_t ev; game_loop_run = 1; while (game_loop_run) { if (SDL_PollEvent(&event)) { switch (event.type) { case SDL_MOUSEBUTTONUP: if (drag_button == event.button.button) { ev.type = GUI_EVENT_TYPE_DRAG_END; ev.x = event.button.x; ev.y = event.button.y; ev.button = drag_button; gui_object_handle_event((gui_object_t *)&interface, &ev); drag_button = 0; } ev.type = GUI_EVENT_TYPE_BUTTON_UP; ev.x = event.button.x; ev.y = event.button.y; ev.button = event.button.button; gui_object_handle_event((gui_object_t *)&interface, &ev); if (event.button.button <= 3 && current_ticks - last_down[event.button.button-1] < MOUSE_SENSITIVITY) { ev.type = GUI_EVENT_TYPE_CLICK; ev.x = event.button.x; ev.y = event.button.y; ev.button = event.button.button; gui_object_handle_event((gui_object_t *)&interface, &ev); if (current_ticks - last_click[event.button.button-1] < MOUSE_SENSITIVITY) { ev.type = GUI_EVENT_TYPE_DBL_CLICK; ev.x = event.button.x; ev.y = event.button.y; ev.button = event.button.button; gui_object_handle_event((gui_object_t *)&interface, &ev); } last_click[event.button.button-1] = current_ticks; } break; case SDL_MOUSEBUTTONDOWN: ev.type = GUI_EVENT_TYPE_BUTTON_DOWN; ev.x = event.button.x; ev.y = event.button.y; ev.button = event.button.button; gui_object_handle_event((gui_object_t *)&interface, &ev); if (event.button.button <= 3) last_down[event.button.button-1] = current_ticks; break; case SDL_MOUSEMOTION: if (drag_button == 0) { /* Move pointer normally. */ interface_set_cursor(&interface, event.motion.x, event.motion.y); } for (int button = 1; button <= 3; button++) { if (event.motion.state & SDL_BUTTON(button)) { if (drag_button == 0) { drag_button = button; ev.type = GUI_EVENT_TYPE_DRAG_START; ev.x = event.motion.x; ev.y = event.motion.y; ev.button = drag_button; gui_object_handle_event((gui_object_t *)&interface, &ev); } ev.type = GUI_EVENT_TYPE_DRAG_MOVE; ev.x = event.motion.x; ev.y = event.motion.y; ev.button = drag_button; gui_object_handle_event((gui_object_t *)&interface, &ev); break; } } break; case SDL_KEYDOWN: if (event.key.keysym.sym == SDLK_q && (event.key.keysym.mod & KMOD_CTRL)) { game_loop_quit(); break; } switch (event.key.keysym.sym) { /* Map scroll */ case SDLK_UP: { viewport_t *viewport = interface_get_top_viewport(&interface); viewport_move_by_pixels(viewport, 0, -1); } break; case SDLK_DOWN: { viewport_t *viewport = interface_get_top_viewport(&interface); viewport_move_by_pixels(viewport, 0, 1); } break; case SDLK_LEFT: { viewport_t *viewport = interface_get_top_viewport(&interface); viewport_move_by_pixels(viewport, -1, 0); } break; case SDLK_RIGHT: { viewport_t *viewport = interface_get_top_viewport(&interface); viewport_move_by_pixels(viewport, 1, 0); } break; /* Panel click shortcuts */ case SDLK_1: { panel_bar_t *panel = interface_get_panel_bar(&interface); panel_bar_activate_button(panel, 0); } break; case SDLK_2: { panel_bar_t *panel = interface_get_panel_bar(&interface); panel_bar_activate_button(panel, 1); } break; case SDLK_3: { panel_bar_t *panel = interface_get_panel_bar(&interface); panel_bar_activate_button(panel, 2); } break; case SDLK_4: { panel_bar_t *panel = interface_get_panel_bar(&interface); panel_bar_activate_button(panel, 3); } break; case SDLK_5: { panel_bar_t *panel = interface_get_panel_bar(&interface); panel_bar_activate_button(panel, 4); } break; /* Game speed */ case SDLK_PLUS: case SDLK_KP_PLUS: if (game.game_speed < 40) game.game_speed += 1; LOGI("main", "Game speed: %u", game.game_speed); break; case SDLK_MINUS: case SDLK_KP_MINUS: if (game.game_speed >= 1) game.game_speed -= 1; LOGI("main", "Game speed: %u", game.game_speed); break; case SDLK_0: game.game_speed = DEFAULT_GAME_SPEED; LOGI("main", "Game speed: %u", game.game_speed); break; case SDLK_p: if (game.game_speed == 0) game_pause(0); else game_pause(1); break; /* Audio */ case SDLK_s: sfx_enable(!sfx_is_enabled()); break; case SDLK_m: midi_enable(!midi_is_enabled()); break; /* Misc */ case SDLK_ESCAPE: if (BIT_TEST(interface.click, 7)) { /* Building road */ interface_build_road_end(&interface); } else if (interface.clkmap != 0) { interface_close_popup(&interface); } break; /* Debug */ case SDLK_g: interface.viewport.layers ^= VIEWPORT_LAYER_GRID; break; case SDLK_j: { int current = 0; for (int i = 0; i < 4; i++) { if (interface.player == game.player[i]) { current = i; break; } } for (int i = (current+1) % 4; i != current; i = (i+1) % 4) { if (PLAYER_IS_ACTIVE(game.player[i])) { interface.player = game.player[i]; LOGD("main", "Switched to player %i.", i); break; } } } break; case SDLK_z: if (event.key.keysym.mod & KMOD_CTRL) { save_game(0); } break; default: break; } break; case SDL_QUIT: game_loop_quit(); break; } } unsigned int new_ticks = SDL_GetTicks(); int delta_ticks = new_ticks - current_ticks; current_ticks = new_ticks; accum += delta_ticks; while (accum >= TICK_LENGTH) { game_update(); /* Autosave periodically */ if ((game.const_tick % AUTOSAVE_INTERVAL) == 0 && game.game_speed > 0) { int r = save_game(1); if (r < 0) LOGW("main", "Autosave failed."); } /* FPS */ fps = 1000*((float)accum_frames / accum); if (fps_ema > 0) fps_ema = ema_alpha*fps + (1-ema_alpha)*fps_ema; else if (fps > 0) fps_ema = fps; if ((game.const_tick % (10*TICKS_PER_SEC)) == 0) { LOGV("main", "FPS: %i", fps_ema); } accum -= TICK_LENGTH; accum_frames = 0; } /* Update and draw interface */ interface_update(&interface); interface.flags &= ~BIT(4); interface.flags &= ~BIT(7); gui_object_redraw((gui_object_t *)&interface, game.frame); /* TODO very crude dirty marking algortihm: mark everything. */ sdl_mark_dirty(0, 0, sdl_frame_get_width(game.frame), sdl_frame_get_height(game.frame)); /* Swap video buffers */ sdl_swap_buffers(); accum_frames += 1; /* Reduce framerate to target */ if (fps_target > 0) { int delay = 0; if (fps_ema > 0) delay = (1000/fps_target) - (1000/fps_ema); if (delay > 0) SDL_Delay(delay); } } }
/* game_loop() has been turned into a SDL based loop. The code for one iteration of the original game_loop is in game_loop_iter. */ static void game_loop() { /* FPS */ int fps = 0; float fps_ema = 0; int fps_target = 25; /* TODO: compute alpha dynamically based on frametime */ const float ema_alpha = 0.07; const int frametime_target = 1000 / fps_target; /* in milliseconds */ int last_frame = SDL_GetTicks(); int drag_button = 0; unsigned int last_down[3] = {0}; unsigned int last_click[3] = {0}; unsigned int current_ticks = SDL_GetTicks(); unsigned int accum = 0; SDL_Event event; gui_event_t ev; game_loop_run = 1; while (game_loop_run) { while (SDL_PollEvent(&event)) { switch (event.type) { case SDL_MOUSEBUTTONUP: if (drag_button == event.button.button) { ev.type = GUI_EVENT_TYPE_DRAG_END; ev.x = event.button.x; ev.y = event.button.y; ev.button = drag_button; gui_object_handle_event((gui_object_t *)&interface, &ev); drag_button = 0; } ev.type = GUI_EVENT_TYPE_BUTTON_UP; ev.x = event.button.x; ev.y = event.button.y; ev.button = event.button.button; gui_object_handle_event((gui_object_t *)&interface, &ev); if (event.button.button <= 3 && current_ticks - last_down[event.button.button-1] < MOUSE_SENSITIVITY) { ev.type = GUI_EVENT_TYPE_CLICK; ev.x = event.button.x; ev.y = event.button.y; ev.button = event.button.button; gui_object_handle_event((gui_object_t *)&interface, &ev); if (current_ticks - last_click[event.button.button-1] < MOUSE_SENSITIVITY) { ev.type = GUI_EVENT_TYPE_DBL_CLICK; ev.x = event.button.x; ev.y = event.button.y; ev.button = event.button.button; gui_object_handle_event((gui_object_t *)&interface, &ev); } last_click[event.button.button-1] = current_ticks; } break; case SDL_MOUSEBUTTONDOWN: ev.type = GUI_EVENT_TYPE_BUTTON_DOWN; ev.x = event.button.x; ev.y = event.button.y; ev.button = event.button.button; gui_object_handle_event((gui_object_t *)&interface, &ev); if (event.button.button <= 3) last_down[event.button.button-1] = current_ticks; break; case SDL_MOUSEMOTION: if (drag_button == 0) { /* Move pointer normally. */ interface_set_cursor(&interface, event.motion.x, event.motion.y); } for (int button = 1; button <= 3; button++) { if (event.motion.state & SDL_BUTTON(button)) { if (drag_button == 0) { drag_button = button; ev.type = GUI_EVENT_TYPE_DRAG_START; ev.x = event.motion.x; ev.y = event.motion.y; ev.button = drag_button; gui_object_handle_event((gui_object_t *)&interface, &ev); } ev.type = GUI_EVENT_TYPE_DRAG_MOVE; ev.x = event.motion.x; ev.y = event.motion.y; ev.button = drag_button; gui_object_handle_event((gui_object_t *)&interface, &ev); break; } } break; case SDL_KEYDOWN: if (event.key.keysym.sym == SDLK_q && (event.key.keysym.mod & KMOD_CTRL)) { game_loop_quit(); break; } switch (event.key.keysym.sym) { /* Map scroll */ case SDLK_UP: { viewport_t *viewport = interface_get_top_viewport(&interface); viewport_move_by_pixels(viewport, 0, -1); } break; case SDLK_DOWN: { viewport_t *viewport = interface_get_top_viewport(&interface); viewport_move_by_pixels(viewport, 0, 1); } break; case SDLK_LEFT: { viewport_t *viewport = interface_get_top_viewport(&interface); viewport_move_by_pixels(viewport, -1, 0); } break; case SDLK_RIGHT: { viewport_t *viewport = interface_get_top_viewport(&interface); viewport_move_by_pixels(viewport, 1, 0); } break; /* Panel click shortcuts */ case SDLK_1: { panel_bar_t *panel = interface_get_panel_bar(&interface); panel_bar_activate_button(panel, 0); } break; case SDLK_2: { panel_bar_t *panel = interface_get_panel_bar(&interface); panel_bar_activate_button(panel, 1); } break; case SDLK_3: { panel_bar_t *panel = interface_get_panel_bar(&interface); panel_bar_activate_button(panel, 2); } break; case SDLK_4: { panel_bar_t *panel = interface_get_panel_bar(&interface); panel_bar_activate_button(panel, 3); } break; case SDLK_5: { panel_bar_t *panel = interface_get_panel_bar(&interface); panel_bar_activate_button(panel, 4); } break; case SDLK_TAB: if (event.key.keysym.mod & KMOD_SHIFT) { interface_return_from_message(&interface); } else { interface_open_message(&interface); } break; /* Game speed */ case SDLK_PLUS: case SDLK_KP_PLUS: if (game.game_speed < 40) game.game_speed += 1; LOGI("main", "Game speed: %u", game.game_speed); break; case SDLK_MINUS: case SDLK_KP_MINUS: if (game.game_speed >= 1) game.game_speed -= 1; LOGI("main", "Game speed: %u", game.game_speed); break; case SDLK_0: game.game_speed = DEFAULT_GAME_SPEED; LOGI("main", "Game speed: %u", game.game_speed); break; case SDLK_p: if (game.game_speed == 0) game_pause(0); else game_pause(1); break; /* Audio */ case SDLK_s: sfx_enable(!sfx_is_enabled()); break; case SDLK_m: midi_enable(!midi_is_enabled()); break; /* Video */ case SDLK_f: if (event.key.keysym.mod & KMOD_CTRL) { sdl_set_fullscreen(!sdl_is_fullscreen()); } break; /* Misc */ case SDLK_ESCAPE: if (GUI_OBJECT(&interface.popup)->displayed) { interface_close_popup(&interface); } else if (interface.building_road) { interface_build_road_end(&interface); } break; /* Debug */ case SDLK_g: interface.viewport.layers ^= VIEWPORT_LAYER_GRID; break; case SDLK_b: interface.viewport.show_possible_build = !interface.viewport.show_possible_build; break; case SDLK_j: { int current = 0; for (int i = 0; i < 4; i++) { if (interface.player == game.player[i]) { current = i; break; } } for (int i = (current+1) % 4; i != current; i = (i+1) % 4) { if (PLAYER_IS_ACTIVE(game.player[i])) { interface.player = game.player[i]; LOGD("main", "Switched to player %i.", i); break; } } } break; case SDLK_z: if (event.key.keysym.mod & KMOD_CTRL) { save_game(0); } break; case SDLK_F10: interface_open_game_init(&interface); break; default: break; } break; case SDL_VIDEORESIZE: sdl_set_resolution(event.resize.w, event.resize.h, 0); frame_t *screen = sdl_get_screen_frame(); int width = sdl_frame_get_width(screen); int height = sdl_frame_get_height(screen); screen_frame.clip.w = width; screen_frame.clip.h = height; gui_object_set_size((gui_object_t *)&interface, width, height); break; case SDL_QUIT: game_loop_quit(); break; } } unsigned int new_ticks = SDL_GetTicks(); int delta_ticks = new_ticks - current_ticks; current_ticks = new_ticks; /* Update FPS EMA per frame */ fps = 1000*(1.0 / (float)delta_ticks); if (fps_ema > 0) fps_ema = ema_alpha*fps + (1-ema_alpha)*fps_ema; else if (fps > 0) fps_ema = fps; accum += delta_ticks; while (accum >= TICK_LENGTH) { game_update(); /* Autosave periodically */ if ((game.const_tick % AUTOSAVE_INTERVAL) == 0 && game.game_speed > 0) { int r = save_game(1); if (r < 0) LOGW("main", "Autosave failed."); } /* Print FPS */ if ((game.const_tick % (10*TICKS_PER_SEC)) == 0) { LOGV("main", "FPS: %i", (int)fps_ema); } accum -= TICK_LENGTH; } /* Update and draw interface */ interface_update(&interface); gui_object_redraw(GUI_OBJECT(&interface), game.frame); /* TODO very crude dirty marking algortihm: mark everything. */ sdl_mark_dirty(0, 0, sdl_frame_get_width(game.frame), sdl_frame_get_height(game.frame)); /* Swap video buffers */ sdl_swap_buffers(); /* Reduce framerate to target if we finished too fast */ int now = SDL_GetTicks(); int frametime_spent = now - last_frame; if (frametime_spent < frametime_target) { SDL_Delay(frametime_target - frametime_spent); } last_frame = SDL_GetTicks(); } }