void thing_shield_sheath (thingp t) { tpp shield = thing_shield(t); if (!shield) { return; } THING_LOG(t, "sheathing %s", tp_short_name(shield)); /* * If this shield has its own thing id for animations then destroy that. */ thingp shield_carry_anim = thing_shield_carry_anim(t); if (shield_carry_anim) { THING_LOG(t, "unwield, carry anim %s", thing_logname(shield_carry_anim)); thing_dead(shield_carry_anim, 0, "owner shield"); thing_set_shield_carry_anim(t, 0); } /* * Else if vanishes on level changes. */ if (!t->on_server) { t->shield = 0; } }
void thing_set_shield_carry_anim (thingp t, thingp shield_carry_anim) { if (shield_carry_anim) { verify(shield_carry_anim); } thingp old_shield_carry_anim = thing_shield_carry_anim(t); if (old_shield_carry_anim) { if (old_shield_carry_anim == shield_carry_anim) { return; } if (shield_carry_anim) { THING_LOG(t, "shield carry changed, %s->%s", thing_logname(old_shield_carry_anim), thing_logname(shield_carry_anim)); } else { THING_LOG(t, "remove shield carry animation, %s", thing_logname(old_shield_carry_anim)); } } else { if (shield_carry_anim) { THING_LOG(t, "shield carry anim now, %s", thing_logname(shield_carry_anim)); } } if (shield_carry_anim) { t->shield_carry_anim_thing_id = shield_carry_anim->thing_id; } else { t->shield_carry_anim_thing_id = 0; } }
/* * Hit the ground hard? */ static int thing_hit_ground (levelp level, thingp t, thingp it) { if (t->fall_speed > THING_FALL_SPEED_HIT_MONST) { if (thing_is_monst(it)) { THING_LOG(t, "fell (%f) and landed on monst", t->fall_speed); (void) thing_hit(level, it, t, 1); } } if (t->falling_too_fast) { t->falling_too_fast = 0; if (thing_is_player(t) || thing_is_monst(t) || thing_is_bomb(t)) { THING_LOG(t, "fell too fast (%f) and hit the ground", t->fall_speed); (void) thing_hit(level, t, it, 1); } } t->fall_speed = 0; return (true); }
void thing_unwield_shield (thingp t) { tpp shield = thing_shield(t); if (!shield) { return; } THING_LOG(t, "unwielding shield %s", tp_short_name(shield)); thing_shield_sheath(t); t->shield = 0; }
static void thing_dead_ (levelp level, thingp t, char *reason) { /* * Detach from the owner */ thing_remove_hooks(level, t); if (!reason) { ERR("thing %s dead for no reason? why? why? why?!", thing_logname(t)); } if (thing_is_dungeon_floor(t) || thing_is_ladder(t) || thing_is_door(t) || thing_is_cloud_effect(t) || thing_is_explosion(t) || thing_is_projectile(t) || thing_is_rock(t) || thing_is_wall(t)) { /* * Too boring to log. */ } else { THING_LOG(t, "Dead, why(%s)", reason); } if (thing_is_player(t)) { /* * Tell the poor player they've croaked it. */ hiscore_try_to_add("Happless human", reason, t->score); } const char *sound = tp_sound_on_death(thing_tp(t)); if (sound) { MSG_SHOUT_AT(SOUND, t, t->x, t->y, "%s", sound); } /* * Move the weapon behind the poor thing. */ thing_set_weapon_placement(level, t); myfree(reason); }
void thing_wield_shield (thingp t, tpp shield) { thingp existing_shield = thing_shield_carry_anim(t); if (existing_shield) { THING_LOG(t, "wield with existing shield %s", thing_logname(existing_shield)); } if (!shield) { THING_ERR(t, "could not wield null pointer!"); return; } const char *carry_as = tp_shield_carry_anim(shield); if (!carry_as) { THING_ERR(t, "could not wield shield %s", tp_short_name(shield)); return; } tpp what = tp_find(carry_as); if (!what) { THING_ERR(t, "Could not find %s to wield", carry_as); return; } if (t->shield == shield) { if (t->on_server) { if (thing_wid(existing_shield)) { /* * Add onto existing shield. */ thing_stats_modify_hp(existing_shield, tp_get_stats_max_hp(what)); return; } } else { return; } } if (thing_is_player(t)) { THING_LOG(t, "wield shield %s", tp_short_name(shield)); } t->shield = shield; widp shield_carry_anim_wid; if (t->on_server) { shield_carry_anim_wid = wid_game_map_server_replace_tile( wid_game_map_server_grid_container, t->x, t->y, existing_shield, /* thing */ what, 0, /* tpp data */ 0 /* item */, 0 /* stats */); } else { shield_carry_anim_wid = wid_game_map_client_replace_tile( wid_game_map_client_grid_container, t->x, t->y, 0, what); } if (!shield_carry_anim_wid) { THING_ERR(t, "failed wield shield %s", tp_short_name(shield)); return; } /* * Save the thing id so the client wid can keep track of the shield. */ thingp child = wid_get_thing(shield_carry_anim_wid); thing_set_shield_carry_anim(t, child); child->dir = t->dir; /* * Attach to the thing. */ thing_set_owner(child, t); if (t->on_server) { thing_update(t); } }
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"); }
/* * Try to fall down */ int thing_fall (levelp level, thingp t) { double x = t->x; double y = t->y + 0.015; thingp it; if (thing_is_monst(t) || thing_is_ladder(t) || thing_is_player(t)) { it = thing_overlaps(level, t, t->x, t->y, thing_is_ladder); if (it) { thing_hit_ground(level, t, it); return (false); } } if (t->jump_speed) { t->fall_speed = 0; return (false); } if (thing_is_monst(t) || thing_is_player(t)) { if (t->fall_speed > THING_FALL_SPEED_HIT_SPIKES) { it = thing_overlaps(level, t, t->x, t->y, thing_is_spikes); if (it) { THING_LOG(t, "fell onto spikes (%f)", t->fall_speed); (void) thing_hit(level, t, it, 1); } } } it = thing_hit_fall_obstacle(level, t, x, y); if (it) { thing_hit_ground(level, t, it); return (false); } t->fall_speed += THING_FALL_SPEED_GRAVITY; t->falling_too_fast = false; if (t->fall_speed - t->jump_speed > THING_FALL_SPEED_TOO_FAST) { t->falling_too_fast = true; } if (t->fall_speed > 1) { t->fall_speed = 1; } y = t->y + t->fall_speed; it = thing_hit_fall_obstacle(level, t, x, y); if (it) { y = t->y + t->fall_speed / 2; it = thing_hit_fall_obstacle(level, t, x, y); if (it) { y = t->y + t->fall_speed / 4; it = thing_hit_fall_obstacle(level, t, x, y); if (it) { y = t->y + t->fall_speed / 4; it = thing_hit_fall_obstacle(level, t, x, y); if (it) { thing_hit_ground(level, t, it); return (false); } } } } thing_wid_update(level, t, x, y, true, false /* is new */); thing_handle_collisions(level, t); return (true); }