static void server_socket_tx_map_updates (void) { { static uint32_t ts; if (time_have_x_hundredths_passed_since( DELAY_HUNDREDTHS_SERVER_TO_CLIENT_MAP_UPDATE_FAST, ts)) { ts = time_get_time_ms(); socket_server_tx_map_update(0, server_active_things, "rx client join active things"); } } { static uint32_t ts; if (time_have_x_hundredths_passed_since( DELAY_HUNDREDTHS_SERVER_TO_CLIENT_MAP_UPDATE_SLOW, ts)) { socket_server_tx_map_update(0, server_boring_things, "rx client join boring things"); ts = time_get_time_ms(); } } }
static void server_socket_tx_ping (void) { gsocketp s; TREE_WALK(sockets, s) { if (socket_get_client(s)) { continue; } /* * Don't ping thyself if both server and client. */ if (socket_get_server(s)) { continue; } socket_tx_ping(s, &s->tx_ping_seq, time_get_time_ms()); } static uint32_t ts; if (time_have_x_tenths_passed_since(10, ts)) { ts = time_get_time_ms(); server_alive_check(); } }
static uint8_t wid_game_map_key_event (widp w, const SDL_KEYSYM *key) { int action = PLAYER_ACTION_USE; int change_selection_only = false; if (wid_menu_visible) { return (false); } tpp tp; if (!player) { wid_player_info_hide(true /* fast */); wid_player_inventory_hide(true /* fast */); return (true); } int redraw_action_bar = 0; int action_bar_index = thing_stats_get_action_bar_index(player); if (key->mod & KMOD_SHIFT) { int weapon_switch_delta = 0; switch (key->sym) { case SDLK_LEFT: weapon_switch_delta = -1; break; case SDLK_RIGHT: weapon_switch_delta = 1; break; default: break; } /* * Weapon switch? */ if (!weapon_switch_delta) { return (true); } /* * Only switch between weapons */ int tries = THING_ACTION_BAR_MAX; while (tries-- > 0) { action_bar_index += weapon_switch_delta; if (action_bar_index < 0) { action_bar_index = THING_ACTION_BAR_MAX - 1; } if (action_bar_index >= THING_ACTION_BAR_MAX) { action_bar_index = 0; } uint32_t id = player->stats.action_bar[action_bar_index].id; if (!id) { continue; } tp = id_to_tp(id); if (!tp) { continue; } /* * Found a weapon, switch to it. */ change_selection_only = true; break; } if (tries <= 0) { return (true); } redraw_action_bar = 1; } else { switch (key->sym) { case SDLK_1: action_bar_index = 0; redraw_action_bar = 1; break; case SDLK_2: action_bar_index = 1; redraw_action_bar = 1; break; case SDLK_3: action_bar_index = 2; redraw_action_bar = 1; break; case SDLK_4: action_bar_index = 3; redraw_action_bar = 1; break; case SDLK_5: action_bar_index = 4; redraw_action_bar = 1; break; case SDLK_6: action_bar_index = 5; redraw_action_bar = 1; break; case SDLK_7: action_bar_index = 6; redraw_action_bar = 1; break; case SDLK_8: action_bar_index = 7; redraw_action_bar = 1; break; case SDLK_9: action_bar_index = 8; redraw_action_bar = 1; break; case SDLK_0: action_bar_index = 9; redraw_action_bar = 1; break; case 'z': debug = !debug; CON("debug %d", debug); return (true); case 'd': action = PLAYER_ACTION_DROP; break; case 'p': action = PLAYER_ACTION_PAY; break; case '\t': { /* * Show the inventory. */ thing_statsp s; s = &player->stats; if (!wid_player_info_is_visible()) { /* * Show stats window. */ wid_player_stats_visible(s); wid_player_info_visible(s, false /* fast */); wid_player_inventory_visible(s, false /* fast */); socket_tx_player_action(client_joined_server, player, PLAYER_ACTION_PAUSE_GAME, 0 /* action_bar_index */, false /* change_selection_only */); } else { /* * Hide stats window. */ wid_player_stats_hide(s); wid_player_info_hide(false /* fast */); wid_player_inventory_hide(false /* fast */); socket_tx_player_action(client_joined_server, player, PLAYER_ACTION_RESUME_GAME, 0 /* action_bar_index */, false /* change_selection_only */); } return (true); } case 's': wid_choose_stats_visible(); socket_tx_player_action(client_joined_server, player, PLAYER_ACTION_PAUSE_GAME, 0 /* action_bar_index */, false /* change_selection_only */); return (true); case 'q': if (client_level->is_test_level) { wid_game_map_go_back_to_editor(); return (true); } wid_game_quit_visible(); return (true); case SDLK_RETURN: case ' ': return (false); default: return (false); } } uint32_t id = player->stats.action_bar[action_bar_index].id; if (!id) { MESG(WARNING, "Nothing in that slot"); return (true); } tp = id_to_tp(id); if (!tp) { MESG(WARNING, "No carried item is using that key"); return (true); } if (!client_joined_server) { MESG(WARNING, "Not connected to server"); return (true); } if (redraw_action_bar) { /* * Assume the server will accept the change and update locally else it * looks laggy. */ player_action_bar_changed_at = time_get_time_ms(); thing_stats_set_action_bar_index(player, action_bar_index); wid_player_action_hide(true /* fast */, false /* player quit */); wid_player_action_visible(&player->stats, true /* fast */); wid_player_stats_redraw(true /* fast */); } socket_tx_player_action(client_joined_server, player, action, action_bar_index, change_selection_only); return (true); }
uint8_t wid_game_map_client_player_move (void) { uint8_t right = 0; uint8_t left = 0; uint8_t up = 0; uint8_t down = 0; uint8_t fire = 0; uint8_t magic = 0; if (!sdl_shift_held) { #if SDL_MAJOR_VERSION == 1 && SDL_MINOR_VERSION == 2 /* { */ { uint8_t *state = SDL_GetKeyState(0); right = state[SDLK_RIGHT] ? 1 : 0; left = state[SDLK_LEFT] ? 1 : 0; up = state[SDLK_UP] ? 1 : 0; down = state[SDLK_DOWN] ? 1 : 0; fire = state[SDLK_SPACE] ? 1 : 0; magic = state[SDLK_m] ? 1 : 0; } #else /* } { */ { const uint8_t *state = SDL_GetKeyboardState(0); right = state[SDL_SCANCODE_RIGHT] ? 1 : 0; left = state[SDL_SCANCODE_LEFT] ? 1 : 0; up = state[SDL_SCANCODE_UP] ? 1 : 0; down = state[SDL_SCANCODE_DOWN] ? 1 : 0; fire = state[SDL_SCANCODE_SPACE] ? 1 : 0; magic = state[SDL_SCANCODE_M] ? 1 : 0; } #endif /* } */ } if (sdl_joy_buttons[SDL_JOY_BUTTON_UP]) { up = true; } if (sdl_joy_buttons[SDL_JOY_BUTTON_DOWN]) { down = true; } if (sdl_joy_buttons[SDL_JOY_BUTTON_LEFT]) { left = true; } if (sdl_joy_buttons[SDL_JOY_BUTTON_RIGHT]) { right = true; } if (sdl_joy_buttons[SDL_JOY_BUTTON_LEFT_FIRE]) { fire = true; } else if (sdl_joy_buttons[SDL_JOY_BUTTON_RIGHT_FIRE]) { fire = true; } else if (sdl_joy_buttons[SDL_JOY_BUTTON_A]) { fire = true; } else if (sdl_joy_buttons[SDL_JOY_BUTTON_X]) { magic = true; } if (sdl_joy_axes) { if (sdl_joy_axes[3] > sdl_joy_deadzone) { right = true; } if (sdl_joy_axes[3] < -sdl_joy_deadzone) { left = true; } if (sdl_joy_axes[4] > sdl_joy_deadzone) { down = true; } if (sdl_joy_axes[4] < -sdl_joy_deadzone) { up = true; } if (wid_player_inventory_is_visible()) { wid_mouse_hide(1); } else { wid_mouse_hide(0); if (sdl_joy_axes[0] > sdl_joy_deadzone) { right = true; } if (sdl_joy_axes[0] < -sdl_joy_deadzone) { left = true; } if (sdl_joy_axes[1] > sdl_joy_deadzone) { down = true; } if (sdl_joy_axes[1] < -sdl_joy_deadzone) { up = true; } } } if (!player) { LOG("Client: No player, cannot move"); return (false); } if (wid_menu_visible) { /* * Noisy * LOG("Menu present, ignore moves"); */ return (false); } if (!client_joined_server) { LOG("Client: Have not joined server, cannot move"); return (false); } if (!up && !down && !left && !right && !fire && !magic) { return (false); } if (thing_is_dead_or_dying(player)) { return (true); } /* * If no longer visible it may mean we have finished the level and are * waiting for others to finish. */ if (!thing_is_visible(player)) { LOG("Client: Player is not visible, cannot move"); return (false); } /* * Check if we are allowed to fire our gun again so soon. */ if (fire) { tpp weapon = thing_weapon(player); if (!weapon) { THING_LOG(player, "tried to fire but no weapon"); fire = 0; } if (fire) { static uint32_t last_fired = 0; uint32_t delay = tp_get_weapon_fire_delay_hundredths(weapon); if (tp_is_melee_weapon(weapon)) { if (thing_has_ability_double_speed_swing(player)) { delay /= 2; } else if (thing_has_ability_triple_speed_swing(player)) { delay /= 3; } else if (thing_has_ability_double_damage_swing(player)) { delay = 0; } } if (!time_have_x_hundredths_passed_since(delay, last_fired)) { fire = 0; if (!up && !down && !left && !right && !magic) { return (false); } } if (fire) { last_fired = time_get_time_ms(); } } } /* * If not able to fire any more magic, stop. */ if (!player->stats.magic) { magic = 0; } /* * Check we don't send magic events too often to the server. */ if (magic) { static uint32_t last_fired = 0; if (!time_have_x_hundredths_passed_since(2, last_fired)) { magic = 0; if (!up && !down && !left && !right && !fire) { return (false); } } if (magic) { last_fired = time_get_time_ms(); } } /* * Check for not moving too fast. Yep, this needs to be done on the * server. If the clients want to cheat, so be it! */ static uint32_t last_moved = 0; double speed = thing_stats_get_total_speed(player); int delay = (60 - speed) / 2; if (delay < 0) { delay = 0; } if (!time_have_x_thousandths_passed_since(delay, last_moved)) { double x = player->x; double y = player->y; thing_client_move(player, x, y, false, false, false, false, fire, magic); return (false); } last_moved = time_get_time_ms(); double x = player->x; double y = player->y; double delta = 0.10; x += (double)right * delta; x -= (double)left * delta; y -= (double)up * delta; y += (double)down * delta; thing_client_move(player, x, y, up, down, left, right, fire, magic); /* * If no key then we allow the console. */ return (up || down || left || right || fire || magic); }
void thing_reached_teleport (levelp level, thingp t, thingp teleport) { int tx[MAP_WIDTH*MAP_HEIGHT]; int ty[MAP_WIDTH*MAP_HEIGHT]; int poss = 0; int x, y; int delay = 20; if (!thing_is_player(t)) { /* * Only move other things sometimes. */ if ((myrand() % 100) < 95) { return; } } if (!time_have_x_tenths_passed_since(delay, t->timestamp_last_teleport)) { return; } for (x = 0; x < MAP_WIDTH; x++) { for (y = 0; y < MAP_HEIGHT; y++) { level_map_tile *tile = &level->map_grid.tile[x][y][MAP_DEPTH_EXPLOSION]; tpp it = tile->tp; if (!it) { continue; } if (!tp_is_teleport(it)) { continue; } if (DISTANCE(t->x, t->y, x, y) < 2.0) { continue; } color tcol; color col; tcol = teleport->data.col; col = tile->data.col; if (color_none(col) || color_none(tcol)) { tx[poss] = x; ty[poss] = y; poss++; continue; } if (color_cmp(col, tcol)) { tx[poss] = x; ty[poss] = y; poss++; continue; } } } if (!poss) { return; } t->timestamp_last_teleport = time_get_time_ms(); poss = myrand() % poss; double nx = tx[poss]; double ny = ty[poss]; /* * Don't let lava spawn continually on top of itself. */ if (thing_is_lava(t) && map_is_lava_at(level, nx, ny)) { return; } /* * Don't let water spawn continually on top of itself. */ if (thing_is_water(t) && map_is_water_at(level, nx, ny)) { return; } /* * Don't let acid spawn continually on top of itself. */ if (thing_is_acid(t) && map_is_acid_at(level, nx, ny)) { return; } /* * Don't let water spawn continually on top of itself. */ if (thing_is_water(t) && map_is_water_at(level, nx, ny)) { return; } /* * Don't let monsters spawn continually on top of themselves. */ if (thing_is_monst(t) && map_is_monst_at(level, nx, ny)) { return; } THING_LOG(t, "Teleport"); wid_move_end(t->wid); thing_wid_update(level, t, nx, ny, false /* smooth */, true /* is_new */); /* * Make sure the client sees the jump */ thing_handle_collisions(level, t); MSG_SHOUT_AT(SOUND, t, t->x, t->y, "teleport"); }
void thing_reached_teleport (thingp t, thingp teleport) { int tx[MAP_WIDTH*MAP_HEIGHT]; int ty[MAP_WIDTH*MAP_HEIGHT]; int poss = 0; int x, y; int delay = 20; if (!thing_is_player(t)) { /* * Only move other things sometimes. */ if ((myrand() % 100) < 95) { return; } } if (!time_have_x_tenths_passed_since(delay, t->timestamp_last_teleport)) { return; } for (x = 0; x < MAP_WIDTH; x++) { for (y = 0; y < MAP_HEIGHT; y++) { level_map_tile *tile = &server_level->map_grid.tile[x][y][MAP_DEPTH_EXPLOSION]; tpp it = tile->tp; if (!it) { continue; } if (!tp_is_teleport(it)) { continue; } if (DISTANCE(t->x, t->y, x, y) < 2.0) { continue; } const char *tcol; const char *col; if (teleport->data) { tcol = teleport->data->col_name; } else { tcol = 0; } col = tile->data.col_name; if (!col || !tcol) { tx[poss] = x; ty[poss] = y; poss++; continue; } if (!strcmp(col, tcol)) { tx[poss] = x; ty[poss] = y; poss++; continue; } } } if (!poss) { return; } t->timestamp_last_teleport = time_get_time_ms(); poss = myrand() % poss; double nx = tx[poss]; double ny = ty[poss]; /* * Don't let lava spawn continually on top of itself. */ if (thing_is_lava(t) && map_is_lava_at(server_level, nx, ny)) { return; } /* * Don't let acid spawn continually on top of itself. */ if (thing_is_acid(t) && map_is_acid_at(server_level, nx, ny)) { return; } /* * Don't let water spawn continually on top of itself. */ if (thing_is_water(t) && map_is_water_at(server_level, nx, ny)) { return; } /* * Don't let monsters spawn continually on top of themselves. */ if (thing_is_monst(t) && map_is_monst_at(server_level, nx, ny)) { return; } THING_LOG(t, "teleport"); wid_move_end(t->wid); thing_server_wid_update(t, nx, ny, true /* is_new */); thing_update(t); /* * Make sure the client sees the jump */ t->needs_tx_refresh_xy_and_template_id = 1; thing_handle_collisions(wid_game_map_server_grid_container, t); MSG_SERVER_SHOUT_AT_ALL_PLAYERS(SOUND, t->x, t->y, "teleport"); }
/* * Blit the font to the screen */ void ttf_putc (font *f, int32_t c, double x, double y, double scaling) { double texMinX = f->glyphs[c].texMinX; double texMaxX = f->glyphs[c].texMaxX; double texMinY = f->glyphs[c].texMinY; double texMaxY = f->glyphs[c].texMaxY; if (c == TTF_CURSOR_CHAR) { c = TTF_FIXED_WIDTH_CHAR; GLfloat left = (GLfloat)(x); GLfloat right = (GLfloat)(x + f->glyphs[c].width * scaling); GLfloat top = (GLfloat)(y); GLfloat bottom = (GLfloat)(y + f->glyphs[c].height * (scaling)); #ifdef CURSOR_FLASH static uint32_t last; static uint8_t first = true; glBindTexture(GL_TEXTURE_2D, 0); if (first) { first = false; last = time_get_time_ms(); } glcolor_save(); if (time_have_x_tenths_passed_since(10, last)) { glcolor(CONSOLE_CURSOR_COLOR); last = time_get_time_ms(); } else if (time_have_x_tenths_passed_since(5, last)) { glcolor(CONSOLE_CURSOR_COLOR); } else { glcolor(CONSOLE_CURSOR_OTHER_COLOR); gl_blitsquare(left, top, right, bottom); left += 1; right -= 1; top += 1; bottom -= 1; gl_blitquad(left, top, right, bottom); glcolor_restore(); return; } gl_blitquad(left, top, right, bottom); glcolor(BLACK); left += 1; right -= 1; top += 1; bottom -= 1; gl_blitquad(left, top, right, bottom); glcolor_restore(); return; #else glBindTexture(GL_TEXTURE_2D, 0); { color c = CONSOLE_CURSOR_COLOR; c.a = 200; glcolor(c); gl_blitsquare(left, top, right, bottom); glcolor_restore(); return; } #endif } GLfloat left = (GLfloat)(x); GLfloat right = (GLfloat)(x + f->glyphs[c].width * scaling); GLfloat top = (GLfloat)(y); GLfloat bottom = (GLfloat)(y + f->glyphs[c].height * (scaling)); blit(f->tex[c].tex, texMinX, texMinY, texMaxX, texMaxY, left, top, right, bottom); }