示例#1
0
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;
    }
}
示例#2
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;
    }
}
示例#3
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);
}
示例#4
0
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;
}
示例#5
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);
}
示例#6
0
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);
    }
}
示例#7
0
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);
}
示例#8
0
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");
}
示例#9
0
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");
}
示例#10
0
/*
 * 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);
}