Esempio n. 1
0
void Tournament::add_npc_remove_animation(SpawnableNPC *npc) {
    const std::string& animation_name = npc->npc->get_value("kill_animation");
    const std::string& sound_name = npc->npc->get_value("kill_sound");
    if (animation_name.length()) {
        try {
            Animation *ani = resources.get_animation(animation_name);
            TileGraphic *tg = npc->npc->get_tile(DirectionLeft, NPCAnimationStanding)->get_tilegraphic();
            int width = tg->get_width();
            int height = tg->get_height();
            GAnimation *sgani = new GAnimation;
            memset(sgani, 0, GAnimationLen);
            strncpy(sgani->animation_name, ani->get_name().c_str(), NameLength - 1);
            strncpy(sgani->sound_name, sound_name.c_str(), NameLength - 1);
            sgani->id = npc->state.id;
            sgani->duration = ani->get_duration();
            TileGraphic *anitg = ani->get_tile()->get_tilegraphic();

            sgani->x = npc->state.x + width / 2 - anitg->get_width() / 2;
            sgani->y = npc->state.y - height / 2 - anitg->get_height() / 2;
            sgani->accel_x = 0.0f;
            sgani->accel_y = 0.0f;
            sgani->to_net();
            add_state_response(GPCAddAnimation, GAnimationLen, sgani);
        } catch (const Exception& e) {
            subsystem << e.what() << std::endl;
        }
    }
}
Esempio n. 2
0
void Tournament::player_dies(Player *p, const std::string& die_message) {
    player_died(p);
    p->state.server_state.health = 0;
    p->state.server_state.flags |= PlayerServerFlagDead;
    p->state.server_state.kills++;
    if (die_message.length()) {
        add_msg_response(die_message.c_str());
    }

    try {
        Animation *tempani = resources.get_animation(properties.get_value("die_animation"));

        GAnimation *ani = new GAnimation;
        memset(ani, 0, sizeof(GAnimation));
        strncpy(ani->animation_name, tempani->get_name().c_str(), NameLength - 1);
        strncpy(ani->sound_name, properties.get_value("die_sound").c_str(), NameLength - 1);

        TileGraphic *tg = p->get_characterset()->get_tile(DirectionLeft, CharacterAnimationStanding)->get_tilegraphic();
        TileGraphic *tga = tempani->get_tile()->get_tilegraphic();

        int x = static_cast<int>(p->state.client_server_state.x) + tg->get_width() / 2 - tga->get_width() / 2;
        int y = static_cast<int>(p->state.client_server_state.y) - tg->get_height() / 2 - tga->get_height() / 2;

        ani->id = ++animation_id;
        ani->x = x;
        ani->y = y;
        ani->to_net();
        add_state_response(GPCAddAnimation, sizeof(GAnimation), ani);
    } catch (const Exception& e) {
        subsystem << e.what() << std::endl;
    }
}
Esempio n. 3
0
void Tournament::player_npc_collision(Player *p, SpawnableNPC *npc) {
    if (npc->init_owner != p->state.id) {
        const std::string& explosion_animation = npc->npc->get_value("explosion_animation");
        if (explosion_animation.length()) {
            Animation *ani = resources.get_animation(explosion_animation);
            GAnimation *sgani = new GAnimation;
            memset(sgani, 0, GAnimationLen);
            strncpy(sgani->animation_name, ani->get_name().c_str(), NameLength - 1);
            strncpy(sgani->sound_name, ani->get_value("sound_name").c_str(), NameLength - 1);
            sgani->id = npc->state.id;
            sgani->duration = ani->get_duration();
            sgani->x = npc->state.x + ani->get_x_offset();
            sgani->y = npc->state.y + ani->get_y_offset();
            sgani->accel_x = 0.0f;
            sgani->accel_y = 0.0f;
            sgani->to_net();
            add_state_response(GPCAddAnimation, GAnimationLen, sgani);
            check_killing_animation(static_cast<int>(npc->state.x),
                static_cast<int>(npc->state.y), ani, npc->state.owner, true, npc->npc);
        }
    }
}
Esempio n. 4
0
void Tournament::integrate(ns_t ns) {
    double period_f = ns / static_cast<double>(ns_fc);

    /* show stats, if game is over? */
    if (!game_state.seconds_remaining) {
        if (!warmup) {
            game_over = true;
            show_statistics = true;
        }
        return;
    }

    /* update time counter */
    if (server) {
        second_counter += ns;
        if (second_counter >= ns_sec) {
            second_counter -= ns_sec;
            if (game_state.seconds_remaining) {
                game_state.seconds_remaining--;
                if (!game_state.seconds_remaining) {
                    if (!warmup) {
                        add_state_response(GPCGameOver, 0, 0);
                        if (logger) {
                            logger->log(ServerLogger::LogTypeGameOver, "game over");
                            write_stats_in_server_log();
                            logger->log(ServerLogger::LogTypeEndOfStats, "end of stats");
                        }
                    }
                }
            }
        }
    }

    /* update game objects -> respawning */
    if (server) {
        for (GameObjects::iterator it = game_objects.begin();
            it != game_objects.end(); it++)
        {
            GameObject *obj = *it;
            int spawn_time = obj->object->get_spawning_time();
            if (obj->picked && spawn_time) {
                obj->spawn_counter += period_f;
                if (obj->spawn_counter >= spawn_time) {
                    obj->picked = false;
                    obj->spawn_counter = 0.0f;
                    GPlaceObject *gpo = new GPlaceObject;
                    gpo->id = obj->state.id;
                    gpo->flags = PlaceObjectWithAnimation | PlaceObjectWithSpawnSound;
                    gpo->x = static_cast<pos_t>(obj->state.x);
                    gpo->y = static_cast<pos_t>(obj->state.y);
                    gpo->to_net();
                    add_state_response(GPCPlaceObject, GPlaceObjectLen, gpo);
                }
            }
        }
    }

    /* update typing animation */
    player_afk_counter += period_f * AnimationMultiplier;
    if (player_afk_counter > player_afk->get_animation_speed()) {
        player_afk_counter = 0.0f;
        player_afk_index = player_afk_index + 1;
        if (player_afk_index >= player_afk->get_tile()->get_tilegraphic()->get_tile_count()) {
            player_afk_index = 0;
        }
    }

    /* update animation states and its physics */
    for (GameAnimations::iterator it = game_animations.begin();
        it != game_animations.end(); it++)
    {
        GameAnimation *gani = *it;

        gani->animation_counter += period_f * AnimationMultiplier;
        double speed = static_cast<double>(gani->animation->get_animation_speed());
        bool finished = false;

        if (gani->animation_counter > speed) {
            TileGraphic *tg = gani->animation->get_tile()->get_tilegraphic();
            gani->animation_counter = 0.0f;
            gani->index++;
            if (gani->index >= static_cast<int>(tg->get_tile_count())) {
                if (gani->state.duration) {
                    gani->state.duration--;
                    if (!gani->state.duration) {
                        finished = true;
                    }
                } else {
                    finished = true;
                }
            }
        }

        if (gani->animation->get_physics()) {
            TileGraphic *tg = gani->animation->get_tile()->get_tilegraphic();
            int width = tg->get_width();
            int height = tg->get_height();
            double springiness = gani->animation->get_springiness();
            bool projectile = gani->animation->is_projectile();
            double recoil = gani->animation->get_recoil();
            int damage = gani->animation->get_damage();

            const CollisionBox& colbox = gani->animation->get_physics_colbox();
            bool col = render_physics(period_f, projectile, damage, recoil,
                gani->state.owner, springiness, springiness, colbox,
                gani->state.x, gani->state.y, gani->state.accel_x,
                gani->state.accel_y, width, height, 1.0f, true, gani->falling,
                gani->last_falling_y_pos, 0, gani->animation->get_name());

            if (col && projectile) {
                finished = true;
            }
        }

        if (finished) {
            gani->delete_me = true;
            if (server) {
                const std::string& finished_animation = gani->animation->get_value("finished_animation");
                if (finished_animation.length()) {
                    Animation *ani = resources.get_animation(finished_animation);
                    GAnimation *sgani = new GAnimation;
                    memset(sgani, 0, GAnimationLen);
                    strncpy(sgani->animation_name, ani->get_name().c_str(), NameLength - 1);
                    strncpy(sgani->sound_name, ani->get_value("sound_name").c_str(), NameLength - 1);
                    sgani->id = gani->state.id;
                    sgani->duration = ani->get_duration();
                    sgani->x = gani->state.x + ani->get_x_offset();
                    sgani->y = gani->state.y + ani->get_y_offset();
                    sgani->accel_x = 0.0f;
                    sgani->accel_y = 0.0f;
                    sgani->to_net();
                    add_state_response(GPCAddAnimation, GAnimationLen, sgani);
                    check_killing_animation(
                        static_cast<int>(gani->state.x + gani->animation->get_tile()->get_tilegraphic()->get_width() / 2),
                        static_cast<int>(gani->state.y + gani->animation->get_tile()->get_tilegraphic()->get_height() / 2),
                        ani, gani->state.owner,
                        false, 0
                    );
                }
            }
        }
    }

    game_animations.erase(std::remove_if(game_animations.begin(),
        game_animations.end(), erase_element<GameAnimation>),
        game_animations.end());

    /* update text animations */
    for (GameTextAnimations::iterator it = game_text_animations.begin();
        it != game_text_animations.end(); it++)
    {
        GameTextAnimation *gani = *it;
        gani->animation_counter += period_f * AnimationMultiplier;
        if (gani->animation_counter > TextAnimationSpeed) {
            gani->animation_counter = 0.0f;
            gani->y--;
            gani->rise_counter++;
            if (gani->rise_counter > gani->max_rise_counter) {
                gani->delete_me = true;
            }
        }
    }

    game_text_animations.erase(std::remove_if(game_text_animations.begin(),
        game_text_animations.end(), erase_element<GameTextAnimation>),
        game_text_animations.end());

    /* update frog respawns */
    if (server && has_frogs) {
        frog_respawn_counter -= period_f;
        if (frog_respawn_counter <= 0.0f) {
            reset_frog_spawn_counter();
            spawn_frog();
        }
    }

    /* update npcs */
    update_npc_states(period_f);

    /* update tile states */
    if (!server) {
        resources.update_tile_index(period_f * AnimationMultiplier, tileset);
    }

    /* update object physics */
    for (GameObjects::iterator it = game_objects.begin();
        it != game_objects.end(); it++)
    {
        GameObject *obj = *it;
        if (!obj->picked) {
            if (obj->object->get_physics()) {
                TileGraphic *tg = obj->object->get_tile()->get_tilegraphic();
                int width = tg->get_width();
                int height = tg->get_height();
                double springiness = obj->object->get_springiness();

                const CollisionBox& colbox = (obj->object->has_physics_colbox() ?
                    obj->object->get_physics_colbox() : obj->object->get_colbox());

                render_physics(period_f, false, 0, 0.0f, 0, springiness,
                    springiness, colbox, obj->state.x, obj->state.y, obj->state.accel_x,
                    obj->state.accel_y, width, height, 1.0f, true, obj->falling,
                    obj->last_falling_y_pos, 0, obj->object->get_name());
            }
        }
    }

    /* subclassed integration */
    subintegrate(ns);

    /* player update cycle */
    Player *following_player = 0;
    Player *me = get_me();

    /* player wants to join or to respawn */
    if (!server && me) {
        bool button_state = ((me->state.client_server_state.key_states & PlayerKeyStateJump) != 0);
        if (button_state != last_button_a_state) {
            last_button_a_state = button_state;
            if (me->state.server_state.flags & PlayerServerFlagSpectating) {
                if (!me->joining && button_state) {
                    player_join_request(me);
                }
            } else if (!me->is_alive_and_playing()) {
                if (!me->respawning && button_state) {
                    this->spawn_player(me);
                    me->respawning = true;
                    add_state_response(GPSRespawnRequest, 0, 0);
                    me->state.client_state.flags &= ~PlayerClientFlagJumpReleased;
                }
            }
        }
    }

    /* control spectator */
    control_spectator(me, period_f);

    /* update all player states */
    for (Players::iterator it = players.begin(); it != players.end(); it++) {
        Player *p = *it;

        if (p->is_alive_and_playing()) {
            const CollisionBox& colbox = p->get_characterset()->get_colbox();

            /* check player name width */
            if (!p->font) {
                p->font = resources.get_font("normal");
                p->player_name_width = p->font->get_text_width(p->get_player_name());
            }

            /* set following player */
            if (p->state.id == following_id) {
                following_player = p;
            }

            /* action key triggers */
            bool move_left = ((p->state.client_server_state.key_states & PlayerKeyStateLeft) != 0) |
                ((p->state.client_server_state.jaxis & PlayerKeyStateLeft) != 0);

            bool move_right = ((p->state.client_server_state.key_states & PlayerKeyStateRight) != 0) |
                ((p->state.client_server_state.jaxis & PlayerKeyStateRight) != 0);

            bool move_up = ((p->state.client_server_state.key_states & PlayerKeyStateUp) != 0) |
                ((p->state.client_server_state.jaxis & PlayerKeyStateUp) != 0);

            bool move_down = ((p->state.client_server_state.key_states & PlayerKeyStateDown) != 0) |
                ((p->state.client_server_state.jaxis & PlayerKeyStateDown) != 0);

            bool move_jump = ((p->state.client_server_state.key_states & PlayerKeyStateJump) != 0);

            /* prevent locking slidings */
            if (move_left && move_right) {
                move_left = move_right = false;
            }

            if (move_up && move_down) {
                move_up = move_down = false;
            }

            /* horizontal acceleration */
            if (move_left) {
                p->state.client_server_state.accel_x -= (XAccel * period_f);
            }

            if (move_right) {
                p->state.client_server_state.accel_x += (XAccel * period_f);
            }

            if (p->state.client_server_state.accel_x < -XMaxAccel) {
                p->state.client_server_state.accel_x = -XMaxAccel;
            }

            if (p->state.client_server_state.accel_x > XMaxAccel) {
                p->state.client_server_state.accel_x = XMaxAccel;
            }

            /* horizontal deceleration */
            if (!move_left && !move_right) {
                if (p->state.client_server_state.accel_x > -Epsilon && p->state.client_server_state.accel_x < Epsilon) {
                    p->state.client_server_state.accel_x = 0.0f;
                } else if (p->state.client_server_state.accel_x < -Epsilon) {
                    p->state.client_server_state.accel_x += (XDecel * period_f);
                    if (p->state.client_server_state.accel_x > -Epsilon) {
                        p->state.client_server_state.accel_x = 0.0f;
                    }
                } else if (p->state.client_server_state.accel_x > Epsilon) {
                    p->state.client_server_state.accel_x -= (XDecel * period_f);
                    if (p->state.client_server_state.accel_x < Epsilon) {
                        p->state.client_server_state.accel_x = 0.0f;
                    }
                }
            }

            /* jump */
            if (move_jump && p->state.client_state.flags & PlayerClientFlagJumpReleased) {
                p->state.client_state.flags &= ~PlayerClientFlagJumpReleased;
                if (!(p->state.client_state.flags & PlayerClientFlagFalling) &&
                    p->state.client_server_state.jump_accel_y > -Epsilon &&
                    p->state.client_server_state.jump_accel_y < Epsilon)
                {
                    if (p == me) {
                        p->state.client_server_state.jump_accel_y = -YInitialJumpImpulse;
                        if (!server) {
                            p->force_broadcast = true;
                            const std::string& jump_sound = p->get_characterset()->get_value("jump_sound");
                            if (jump_sound.length()) {
                                subsystem.play_sound(resources.get_sound(jump_sound), 0);
                            }
                        }
                    }
                }
            } else if (!move_jump) {
                p->state.client_state.flags |= PlayerClientFlagJumpReleased;
            }

            /* gravity */
            p->state.client_server_state.accel_y += YAccelGravity * period_f;
            if (p->state.client_server_state.accel_y > YMaxAccel) {
                p->state.client_server_state.accel_y = YMaxAccel;
            }

            if (p->state.client_server_state.accel_y + p->state.client_server_state.jump_accel_y < -Epsilon) {
                p->state.client_server_state.jump_accel_y += (move_jump ? YDecelJump : YDecelJumpNormal) * period_f;
            } else {
                p->state.client_server_state.jump_accel_y += YDecelJumpNormal * period_f;
            }

            if (p->state.client_server_state.jump_accel_y > -Epsilon) {
                p->state.client_server_state.jump_accel_y = 0.0f;
            }

            /* new movement vector */
            double movy = p->state.client_server_state.accel_y + p->state.client_server_state.jump_accel_y;

            /* new position */
            double newx = p->state.client_server_state.x + (p->state.client_server_state.accel_x * period_f);
            double newy = p->state.client_server_state.y + (movy * period_f);

            /* map boundary checks */
            if (newx < -colbox.x) {
                newx = -colbox.x;
                p->state.client_server_state.accel_x = 0.0f;
            }
            if (newx + colbox.x + colbox.width > map_width * tile_width) {
                newx = map_width * tile_width - (colbox.x + colbox.width);
                p->state.client_server_state.accel_x = 0.0f;
            }

            /* tile collision detection */
            bool bailout;
            int colmax;

            /* AABB tile collision detection in x direction */
            do {
                /* left side */
                if (p->state.client_server_state.accel_x < 0.0f) {
                    /* left upper stepped down */
                    bailout = false;
                    colmax = ((colbox.height - 1) / tile_height) + 1;
                    for (int i = 0; i < colmax; i++) {
                        if (collide_with_tile(TestTypeNormal, p, p->last_falling_y_pos, newx + colbox.x, p->state.client_server_state.y - colbox.y - colbox.height + (i * tile_height), 0, 0)) {
                            newx = (tilex + 1) * tile_width - colbox.x;
                            p->state.client_server_state.accel_x = 0.0f;
                            bailout = true;
                            break;
                        }
                    }
                    if (bailout) {
                        break;
                    }

                    /* left lower */
                    if (collide_with_tile(TestTypeNormal, p, p->last_falling_y_pos, newx + colbox.x, p->state.client_server_state.y - colbox.y - 1.0f, 0, 0)) {
                        newx = (tilex + 1) * tile_width - colbox.x;
                        p->state.client_server_state.accel_x = 0.0f;
                        break;
                    }
                }

                if (p->state.client_server_state.accel_x > 0.0f) {
                    /* right upper stepped down */
                    bailout = false;
                    colmax = ((colbox.height - 1) / tile_height) + 1;
                    for (int i = 0; i < colmax; i++) {
                        if (collide_with_tile(TestTypeNormal, p, p->last_falling_y_pos, newx + colbox.width + colbox.x, p->state.client_server_state.y - colbox.height - colbox.y + (i * tile_height), 0, 0)) {
                            newx = tilex * tile_width - colbox.width - colbox.x;
                            p->state.client_server_state.accel_x = 0.0f;
                            bailout = true;
                            break;
                        }
                    }
                    if (bailout) {
                        break;
                    }

                    /* right lower */
                    if (collide_with_tile(TestTypeNormal, p, p->last_falling_y_pos, newx + colbox.width + colbox.x, p->state.client_server_state.y - colbox.y - 1.0f, 0, 0)) {
                        newx = tilex * tile_width - colbox.width - colbox.x;
                        p->state.client_server_state.accel_x = 0.0f;
                    }
                }
            } while (false);

            /* set player's falling flag */
            p->state.client_state.flags |= PlayerClientFlagFalling;

            /* save last falling y before y correction for falling tile collision tests */
            if (static_cast<int>(newy) < p->last_falling_y_pos) {
                p->last_falling_y_pos = static_cast<int>(newy);
            }

            /* AABB tile collision detection in y direction */
            double ground_friction = 0.0f;

            do {
                /* test if jumping only */
                if (movy < 0.0f) {
                    /* reset after jump */
                    p->last_falling_y_pos = Player::PlayerFallingTestMaxY;
                    /* top edge */
                    bailout = false;
                    colmax = ((colbox.width - 1) / tile_width) + 1;
                    for (int i = 0; i < colmax; i++) {
                        if (collide_with_tile(TestTypeNormal, p, p->last_falling_y_pos, p->state.client_server_state.x + colbox.x + (i * tile_width), newy - colbox.y - colbox.height, 0, 0)) {
                            newy = (tiley + 1) * tile_height + colbox.y + colbox.height;
                            p->state.client_server_state.jump_accel_y = 0.0f;
                            p->state.client_server_state.accel_y = 0.0f;
                            p->state.client_state.flags &= ~PlayerClientFlagFalling;
                            bailout = true;
                            break;
                        }
                    }
                    if (bailout) {
                        break;
                    }

                    /* top edge right point */
                    if (collide_with_tile(TestTypeNormal, p, p->last_falling_y_pos, p->state.client_server_state.x + colbox.x + colbox.width - 1.0f, newy - colbox.y - colbox.height, 0, 0)) {
                        newy = (tiley + 1) * tile_height + colbox.y + colbox.height;
                        p->state.client_server_state.jump_accel_y = 0.0f;
                        p->state.client_server_state.accel_y = 0.0f;
                        p->state.client_state.flags &= ~PlayerClientFlagFalling;
                        break;
                    }
                }

                /* test if falling only */
                TestType test_type;
                if (move_down) {
                    p->last_falling_y_pos = Player::PlayerFallingTestMaxY;
                    test_type = TestTypeFallingThrough;
                } else {
                    test_type = TestTypeFalling;
                }
                if (movy > 0.0f) {
                    /* bottom edge */
                    bool found = false;
                    colmax = ((colbox.width - 1) / tile_width) + 1;
                    for (int i = 0; i < colmax; i++) {
                        double tile_friction = 0.0f;
                        if (collide_with_tile(test_type, p, p->last_falling_y_pos, p->state.client_server_state.x + colbox.x + (i * tile_width), newy - colbox.y, &tile_friction, 0)) {
                            if (!found) {
                                if (p->state.client_server_state.accel_y > YVeloLanding) {
                                    p->state.client_state.flags |= PlayerClientFlagLanded;
                                }
                                newy = tiley * tile_height + colbox.y;
                                p->state.client_server_state.jump_accel_y = 0.0f;
                                p->state.client_server_state.accel_y = 0.0f;
                                p->state.client_state.flags &= ~PlayerClientFlagFalling;
                                found = true;
                            }
                        }
                        if (tile_friction > ground_friction) {
                            ground_friction = tile_friction;
                        }
                    }

                    /* bottom edge right point */
                    double tile_friction = 0.0f;
                    if (collide_with_tile(test_type, p, p->last_falling_y_pos, p->state.client_server_state.x + colbox.x + colbox.width - 1.0f, newy - colbox.y, &tile_friction, 0)) {
                        if (!found) {
                            if (p->state.client_server_state.accel_y > YVeloLanding) {
                                p->state.client_state.flags |= PlayerClientFlagLanded;
                            }
                            newy = tiley * tile_height + colbox.y;
                            p->state.client_server_state.jump_accel_y = 0.0f;
                            p->state.client_server_state.accel_y = 0.0f;
                            p->state.client_state.flags &= ~PlayerClientFlagFalling;
                        }
                    }
                    if (tile_friction > ground_friction) {
                        ground_friction = tile_friction;
                    }
                }
            } while (false);

            /* save last falling y after y correction for falling tile collision tests */
            if (static_cast<int>(newy) > p->last_falling_y_pos) {
                p->last_falling_y_pos = static_cast<int>(newy);
            }

            /* if player was killed by tile, continue to next player here */
            if (p->state.server_state.flags & PlayerServerFlagDead) {
                continue;
            }

            /* collision with object and NPC */
            if (server) {
                CollisionBox p_colbox = colbox;
                p_colbox.x += static_cast<int>(newx);
                p_colbox.y = static_cast<int>(newy) - p_colbox.height - p_colbox.y;

                /* object collision? */
                for (GameObjects::iterator oit = game_objects.begin();
                    oit != game_objects.end(); oit++)
                {
                    GameObject *obj = *oit;
                    if (!obj->picked) {
                        TileGraphic *tg = obj->object->get_tile()->get_tilegraphic();

                        CollisionBox obj_colbox = obj->object->get_colbox();
                        obj_colbox.x += static_cast<int>(obj->state.x);
                        obj_colbox.y = static_cast<int>(obj->state.y) + tg->get_height() - obj_colbox.height - obj_colbox.y;

                        /* intersection? */
                        if (p_colbox.intersects(obj_colbox)) {
                            bool proceed = false;
                            if (!pick_item(p, obj)) {
                                proceed = Tournament::pick_item(p, obj);
                            } else {
                                proceed = true;
                            }
                            if (proceed) {
                                GPickObject *po = new GPickObject;
                                po->id = obj->state.id;
                                po->to_net();
                                add_state_response(GPCPickObject, sizeof(GPickObject), po);
                                obj->picked = true;
                                obj->delete_me = obj->object->is_spawnable();
                            }
                        }
                    }
                }

                /* delete marked objects */
                game_objects.erase(std::remove_if(game_objects.begin(),
                    game_objects.end(), erase_element<GameObject>),
                    game_objects.end());

                /* NPC collision */
                for (SpawnableNPCs::iterator nit = spawnable_npcs.begin();
                    nit != spawnable_npcs.end(); nit++)
                {
                    SpawnableNPC *npc = *nit;

                    CollisionBox npc_colbox = npc->npc->get_colbox();
                    npc_colbox.x += static_cast<int>(npc->state.x);
                    npc_colbox.y = static_cast<int>(npc->state.y) -
                        npc_colbox.height - npc_colbox.y;

                    /* intersection? */
                    if (p_colbox.intersects(npc_colbox)) {
                        player_npc_collision(p, npc);
                    }
                }

                /* delete marked objects */
                remove_marked_npcs();
            }

            /* if player is sliding -> more friction */
            if (!move_left && !move_right && !(p->state.client_state.flags & PlayerClientFlagFalling)) {
                if (p->state.client_server_state.accel_x > -Epsilon && p->state.client_server_state.accel_x < Epsilon) {
                    p->state.client_server_state.accel_x = 0.0f;
                } else if (p->state.client_server_state.accel_x < -Epsilon) {
                    p->state.client_server_state.accel_x += (ground_friction * period_f);
                    if (p->state.client_server_state.accel_x > -Epsilon) {
                        p->state.client_server_state.accel_x = 0.0f;
                    }
                } else if (p->state.client_server_state.accel_x > Epsilon) {
                    p->state.client_server_state.accel_x -= (ground_friction * period_f);
                    if (p->state.client_server_state.accel_x < Epsilon) {
                        p->state.client_server_state.accel_x = 0.0f;
                    }
                }
            }

            /* fell off the screen */
            if (server) {
                if (newy - 100 > map_height * tile_height) {
                    std::string msg(p->get_player_name() + " fell off the stage");
                    player_dies(p, msg);
                    if (logger) {
                        logger->log(ServerLogger::LogTypeKill, msg, p, p, "void");
                    }
                }
            }

            /* update player position */
            p->state.client_server_state.x = newx;
            p->state.client_server_state.y = newy;

            /* setup character icon and its animation */
            unsigned char icon = p->state.client_state.icon;
            p->animation_counter += period_f * AnimationMultiplier;
            if (p->state.client_state.flags & PlayerClientFlagDoShotAnimation) {
                if (p->state.client_state.flags & PlayerClientFlagOneShotFinished) {
                    p->state.client_state.flags &= ~PlayerClientFlagDoShotAnimation;
                }
                icon = static_cast<unsigned char>(CharacterAnimationShooting);
                if (icon != p->state.client_state.icon) {
                    p->state.client_state.flags &= ~PlayerClientFlagOneShotFinished;
                    p->animation_counter = 0.0f;
                }
                p->state.client_state.icon = icon;
                if (move_right && !move_left) {
                    p->state.client_server_state.direction = DirectionRight;
                }
                if (move_left && !move_right) {
                    p->state.client_server_state.direction = DirectionLeft;
                }
            } else if (p->state.client_server_state.jump_accel_y < -YVeloJumpToLanding) {
                icon = static_cast<unsigned char>(CharacterAnimationJumping);
                if (icon != p->state.client_state.icon) {
                    p->state.client_state.flags &= ~PlayerClientFlagOneShotFinished;
                    p->animation_counter = 0.0f;
                }
                p->state.client_state.icon = icon;
                if (move_right && !move_left) {
                    p->state.client_server_state.direction = DirectionRight;
                }
                if (move_left && !move_right) {
                    p->state.client_server_state.direction = DirectionLeft;
                }
            } else if (p->state.client_state.flags & PlayerClientFlagFalling) {
                icon = static_cast<unsigned char>(CharacterAnimationFalling);
                if (icon != p->state.client_state.icon) {
                    p->state.client_state.flags &= ~PlayerClientFlagOneShotFinished;
                    p->animation_counter = 0.0f;
                }
                p->state.client_state.icon = icon;
                if (move_right && !move_left) {
                    p->state.client_server_state.direction = DirectionRight;
                }
                if (move_left && !move_right) {
                    p->state.client_server_state.direction = DirectionLeft;
                }
            } else if (move_right && p->state.client_server_state.accel_x < Epsilon) {
                icon = static_cast<unsigned char>(CharacterAnimationSliding);
                if (icon != p->state.client_state.icon) {
                    p->state.client_state.flags &= ~PlayerClientFlagOneShotFinished;
                    p->animation_counter = 0.0f;
                }
                p->state.client_state.icon = icon;
            } else if (move_left && p->state.client_server_state.accel_x > -Epsilon) {
                icon = static_cast<unsigned char>(CharacterAnimationSliding);
                if (icon != p->state.client_state.icon) {
                    p->state.client_state.flags &= ~PlayerClientFlagOneShotFinished;
                    p->animation_counter = 0.0f;
                }
                p->state.client_state.icon = icon;
            } else if (move_right || move_left) {
                icon = static_cast<unsigned char>(CharacterAnimationRunning);
                if (icon != p->state.client_state.icon) {
                    p->state.client_state.flags &= ~PlayerClientFlagOneShotFinished;
                    p->animation_counter = 0.0f;
                }
                p->state.client_state.icon = icon;
                if (move_right && !move_left) {
                    p->state.client_server_state.direction = DirectionRight;
                }
                if (move_left && !move_right) {
                    p->state.client_server_state.direction = DirectionLeft;
                }
            } else {
                if (p->state.client_state.flags & PlayerClientFlagLanded) {
                    if (p->state.client_state.flags & PlayerClientFlagOneShotFinished) {
                        p->state.client_state.flags &= ~PlayerClientFlagLanded;
                    }
                    icon = static_cast<unsigned char>(CharacterAnimationLanding);
                    if (icon != p->state.client_state.icon) {
                        p->state.client_state.flags &= ~PlayerClientFlagOneShotFinished;
                        p->animation_counter = 0.0f;
                    }
                    p->state.client_state.icon = icon;
                } else if (p->state.client_server_state.accel_x < -Epsilon || p->state.client_server_state.accel_x > Epsilon) {
                    icon = static_cast<unsigned char>(CharacterAnimationSliding);
                    if (icon != p->state.client_state.icon) {
                        p->state.client_state.flags &= ~PlayerClientFlagOneShotFinished;
                        p->animation_counter = 0.0f;
                    }
                    p->state.client_state.icon = icon;
                } else {
                    icon = static_cast<unsigned char>(CharacterAnimationStanding);
                    if (icon != p->state.client_state.icon) {
                        p->state.client_state.flags &= ~PlayerClientFlagOneShotFinished;
                        p->animation_counter = 0.0f;
                    }
                    p->state.client_state.icon = icon;
                    if (move_right && !move_left) {
                        p->state.client_server_state.direction = DirectionRight;
                    }
                    if (move_left && !move_right) {
                        p->state.client_server_state.direction = DirectionLeft;
                    }
                }
            }

            Tile *t = p->get_characterset()->get_tile(DirectionLeft,
                static_cast<CharacterAnimation>(p->state.client_state.icon));

            if (p->animation_counter >= static_cast<double>(t->get_animation_speed())) {
                p->animation_counter = 0.0f;
                int index = p->state.client_state.iconindex + 1;
                int sz = static_cast<int>(t->get_tilegraphic()->get_tile_count());
                if (index >= sz) {
                    if (t->is_one_shot()) {
                        index = sz - 1;
                        p->state.client_state.flags |= PlayerClientFlagOneShotFinished;
                    } else {
                        index = 0;
                    }
                }
                p->state.client_state.iconindex = static_cast<unsigned char>(index);
            }

            /* check attacks */
            if (p == me) {
                check_attack(p, colbox, move_up, move_down, following_player);
            }
        }
    }

    /* post actions */
    players_post_actions();

    /* set top/left */
    if (following_player) {
        const CollisionBox& colbox = following_player->get_characterset()->get_colbox();
        spectator_x = following_player->state.client_server_state.x + colbox.x + colbox.width / 2;
        spectator_y = following_player->state.client_server_state.y;
    }

    int view_width = subsystem.get_view_width();
    int view_height = subsystem.get_view_height();
    int origin_x = static_cast<int>(spectator_x);
    int origin_y = static_cast<int>(spectator_y);

    if (map_width * tile_width < view_width) {
        left = (view_width / 2) - (map_width * tile_width / 2);
    } else {
        left = -(origin_x - (view_width / 2));
        if (left > 0) left = 0;
        if (left < -((map_width * tile_width) - view_width)) {
            left = -((map_width * tile_width) - view_width);
        }
    }

    if (map_height * tile_height < view_height) {
        top = (view_height / 2) - (map_height * tile_height / 2);
    } else {
        top = -(origin_y - (view_height / 2));
        if (top > 0) top = 0;
        if (top < -((map_height * tile_height) - view_height)) {
            top = -((map_height * tile_height) - view_height);
        }
    }
}
Esempio n. 5
0
void Client::sevt_data(ServerEvent& evt) {
    GTransport *t = reinterpret_cast<GTransport *>(evt.data);

    while (true) {
        t->from_net();
        switch (t->cmd) {
            case GPCServerMessage:
            {
                size_t sz = 0;
                std::string msg(reinterpret_cast<char *>(t->data), t->len);
                std::vector<std::string> lines;
                while (true) {
                    sz++;
                    size_t pos = msg.find("|");
                    if (pos == std::string::npos) {
                        lines.push_back(msg);
                        break;
                    }
                    lines.push_back(msg.substr(0, pos));
                    msg = msg.substr(pos + 1);
                }
                int vw = subsystem.get_view_width();
                int vh = subsystem.get_view_height();
                int ww = 200;
                int wh = 130;
                int x = 10;
                int y = 10;
                GuiWindow *window = push_window(x, y, ww, wh, "Server Message");

                Font *f = get_font();
                int text_height = 0;
                int ly = Spc;
                int maxw = 0;
                for (size_t i = 0; i < sz; i++) {
                    create_label(window, Spc, ly, lines[i]);
                    ly += f->get_font_height();
                    text_height += f->get_font_height();
                    int tw = f->get_text_width(lines[i]) + 2 * Spc;
                    maxw = (tw > maxw ? tw : maxw);
                }
                int maxh = text_height + 2 * Spc;
                int bw = 46;
                int bh = 18;
                create_button(window, maxw / 2 - bw / 2, maxh, bw, bh, "Okay", static_window_close_click, this);
                maxh += bh + Spc;
                window->set_width(window->get_width() - window->get_client_width() + maxw);
                window->set_height(window->get_height() - window->get_client_height() + maxh);
                window->set_x(vw / 2 - window->get_width() / 2);
                window->set_y(vh / 2 - window->get_height() / 2);
                break;
            }

            case GPCMapState:
            {
                GTournament *tour = reinterpret_cast<GTournament *>(t->data);
                tour->from_net();
                if (tournament) {
                    delete tournament;
                }

                /* reload resources? */
                if (reload_resources) {
                    resources.reload_resources();
                    load_resources();
                    reload_resources = false;
                }

                /* setup tournament */
                bool warmup = ((tour->flags & TournamentFlagWarmup) != 0);
                GamePlayType type = static_cast<GamePlayType>(tour->gametype);
                MapConfiguration config(type, tour->map_name, tour->duration, tour->warmup);
                tournament = factory.create_tournament(config, false, warmup, players, 0);
                factory.set_tournament_id(tour->tournament_id);
                tournament->set_following_id(my_id);
                tournament->set_player_configuration(&player_config);
                tournament->set_team_names(team_red_name, team_blue_name);

                /* reopen, if join request window is already open */
                if (me && me->joining) {
                    tournament->reopen_join_window(me);
                }

                break;
            }

            case GPCIdentifyPlayer:
            {
                player_id_t *nid = reinterpret_cast<player_id_t *>(t->data);
                my_id = ntohs(*nid);
                if (tournament) {
                    tournament->set_following_id(my_id);
                }
                break;
            }

            case GPCReady:
            {
                if (tournament) {
                    tournament->set_ready();
                }
                if (me) {
                    me->state.client_server_state.key_states = 0;
                }
                break;
            }

            case GPCAddPlayer:
            {
                GPlayerInfo *info = reinterpret_cast<GPlayerInfo *>(t->data);
                info->from_net();

                Player *p = new Player(resources, 0, info->id,
                    info->desc.player_name, info->desc.characterset_name);
                players.push_back(p);

                p->state.server_state = info->server_state;
                p->state.client_server_state = info->client_server_state;
                p->state.client_state = info->client_state;

                if (p->state.id == my_id) {
                    me = p;
                    p->mark_as_me();
                }

                if (tournament) {
                    tournament->player_added(p);
                }

                break;
            }

            case GPCResetPlayer:
            {
                GPlayerInfo *info = reinterpret_cast<GPlayerInfo *>(t->data);
                info->from_net();

                for (Players::iterator it = players.begin();
                    it != players.end(); it++)
                {
                    Player *p = *it;
                    if (p->state.id == info->id) {
                        p->state.server_state = info->server_state;
                        p->state.client_server_state = info->client_server_state;
                        p->state.client_state = info->client_state;
                        if (tournament) {
                            tournament->reset_player(p);
                        }
                        break;
                    }
                }
                break;
            }

            case GPCRemovePlayer:
            {
                player_id_t *nid = reinterpret_cast<player_id_t *>(t->data);
                player_id_t id = ntohs(*nid);
                for (Players::iterator it = players.begin();
                    it != players.end(); it++)
                {
                    Player *p = *it;
                    if (p->state.id == id) {
                        if (id == my_id) {
                            me = 0;
                        }

                        if (tournament) {
                            tournament->player_removed(p);
                        }

                        players.erase(it);
                        delete p;
                        break;
                    }
                }
                break;
            }

            case GPCSpawnPlayer:
            {
                GPlayerState *state = reinterpret_cast<GPlayerState *>(t->data);
                state->from_net();
                for (Players::iterator it = players.begin();
                    it != players.end(); it++)
                {
                    Player *p = *it;
                    if (p->state.id == state->id) {
                        if (p == me) {
                            p->state.server_state = state->server_state;
                        } else {
                            p->state = *state;
                        }
                        p->respawning = false;
                        if (tournament) {
                            tournament->add_player_spawn_animation(p);
                        }
                        break;
                    }
                }
                break;
            }

            case GPCUpdateGameState:
            {
                if (t->tournament_id == factory.get_tournament_id()) {
                    GGameState *state = reinterpret_cast<GGameState *>(t->data);
                    state->from_net();
                    if (tournament) {
                        tournament->get_game_state() = *state;
                    }
                }
                break;
            }

            case GPCUpdatePlayerState:
            {
                if (t->tournament_id== factory.get_tournament_id()) {
                    GPTAllStates *state = reinterpret_cast<GPTAllStates *>(t->data);
                    state->from_net();

                    for (Players::iterator it = players.begin();
                        it != players.end(); it++)
                    {
                        Player *p = *it;
                        if (p->state.id == state->id) {
                            p->state.server_state = state->server_state;
                            if (p != me) {
                                p->state.client_server_state = state->client_server_state;
                            }
                            break;
                        }
                    }
                }
                break;
            }

            case GPCUpdateObject:
            {
                if (tournament) {
                    if (t->tournament_id == factory.get_tournament_id()) {
                        GObjectState *state = reinterpret_cast<GObjectState *>(t->data);
                        state->from_net();
                        Tournament::GameObjects& objects = tournament->get_game_objects();
                        for (Tournament::GameObjects::iterator it = objects.begin();
                            it != objects.end(); it++)
                        {
                            GameObject *obj = *it;
                            if (obj->state.id == state->id) {
                                obj->state = *state;
                                break;
                            }
                        }
                    }
                }
                break;
            }

            case GPCUpdateAnimation:
            {
                if (tournament) {
                    if (t->tournament_id == factory.get_tournament_id()) {
                        GAnimationState *state = reinterpret_cast<GAnimationState *>(t->data);
                        state->from_net();
                        Tournament::GameAnimations& animations = tournament->get_game_animations();
                        for (Tournament::GameAnimations::iterator it = animations.begin();
                            it != animations.end(); it++)
                        {
                            GameAnimation *ani = *it;
                            if (ani->state.id == state->id) {
                                ani->state = *state;
                                break;
                            }
                        }
                    }
                }
                break;
            }

            case GPCUpdateSpawnableNPC:
            {
                if (tournament) {
                    if (t->tournament_id == factory.get_tournament_id()) {
                        GNPCState *state = reinterpret_cast<GNPCState *>(t->data);
                        state->from_net();
                        Tournament::SpawnableNPCs& spawnable_npcs = tournament->get_spawnable_npcs();
                        for (Tournament::SpawnableNPCs::iterator it = spawnable_npcs.begin();
                            it != spawnable_npcs.end(); it++)
                        {
                            SpawnableNPC *npc = *it;
                            if (npc->state.id == state->id) {
                                npc->state = *state;
                                break;
                            }
                        }
                    }
                }
                break;
            }

            case GPCSpawnNPC:
            {
                if (tournament) {
                    if (t->tournament_id == factory.get_tournament_id()) {
                        GSpawnNPC *state = reinterpret_cast<GSpawnNPC *>(t->data);
                        state->from_net();
                        tournament->add_spawnable_npc(state);
                    }
                }
                break;
            }

            case GPCRemoveNPC:
            {
                if (tournament) {
                    if (t->tournament_id == factory.get_tournament_id()) {
                        GRemoveNPC *rnpc = reinterpret_cast<GRemoveNPC *>(t->data);
                        rnpc->from_net();
                        tournament->remove_spawnable_npc(rnpc);
                    }
                }
                break;
            }

            case GPCTextMessage:
            {
                std::string msg(reinterpret_cast<char *>(t->data), t->len);
                ClientTextMessage *cmsg = new ClientTextMessage;
                cmsg->text = msg;
                client_text_messages.push_back(cmsg);
                break;
            }

            case GPCPlaySound:
            {
                GGenericName *name = reinterpret_cast<GGenericName *>(t->data);
                try {
                    subsystem.play_sound(resources.get_sound(name->name), 0);
                } catch (...) {
                    /* chomp */
                }
                break;
            }

            case GPCChatMessage:
            {
                std::string msg(reinterpret_cast<char *>(t->data), t->len);
                ClientTextMessage *cmsg = new ClientTextMessage;
                cmsg->text = msg;
                client_text_messages.push_back(cmsg);
                subsystem.play_sound(resources.get_sound("chat"), 0);
                break;
            }

            case GPCAddAnimation:
            {
                GAnimation *ani = reinterpret_cast<GAnimation *>(t->data);
                ani->from_net();
                if (tournament) {
                    tournament->add_animation(ani);
                }
                break;
            }

            case GPCAddTextAnimation:
            {
                GTextAnimation *ani = reinterpret_cast<GTextAnimation *>(t->data);
                ani->from_net();
                if (tournament) {
                    tournament->add_text_animation(ani);
                }
                break;
            }

            case GPCPlayerRecoil:
            {
                GPlayerRecoil *prec = reinterpret_cast<GPlayerRecoil *>(t->data);
                prec->from_net();
                for (Players::iterator it = players.begin(); it != players.end(); it++) {
                    Player *p = *it;
                    if (p->state.id == prec->id) {
                        p->state.client_server_state.accel_x += prec->x_recoil;
                        break;
                    }
                }
                break;
            }

            case GPCPlayerHurt:
            {
                if (tournament) {
                    if (t->tournament_id == factory.get_tournament_id()) {
                        subsystem.play_sound(resources.get_sound("hurt"), 0);
                    }
                }
                break;
            }

            case GPCPickObject:
            {
                GPickObject *po = reinterpret_cast<GPickObject *>(t->data);
                po->from_net();
                if (tournament) {
                    tournament->add_pick_object(po);
                }
                break;
            }

            case GPCPlaceObject:
            {
                GPlaceObject *po = reinterpret_cast<GPlaceObject *>(t->data);
                po->from_net();
                if (tournament) {
                    tournament->add_place_object(po);
                }
                break;
            }

            case GPCSpawnObject:
            {
                GSpawnObject *so = reinterpret_cast<GSpawnObject *>(t->data);
                so->from_net();
                if (tournament) {
                    tournament->spawn_object(so);
                }
                break;
            }

            case GPCJoinAccepted:
            {
                if (tournament) {
                    tournament->join_accepted();
                }
                break;
            }

            case GPCJoinRefused:
            {
                if (tournament) {
                    tournament->join_refused();
                    ClientTextMessage *cmsg = new ClientTextMessage;
                    cmsg->text = "YOUR JOIN REQUEST WAS REFUSED";
                    client_text_messages.push_back(cmsg);
                    subsystem.play_sound(resources.get_sound("error"), 0);
                }
                break;
            }

            case GPCTeamScore:
            {
                GTeamScore *ts = reinterpret_cast<GTeamScore *>(t->data);
                ts->from_net();
                if (tournament) {
                    tournament->add_team_score(ts);
                }
                break;
            }

            case GPCTimeRemaining:
            {
                GTimeRemaining *remain = reinterpret_cast<GTimeRemaining *>(t->data);
                remain->from_net();
                if (tournament) {
                    tournament->update_wearable_remaining(remain);
                }
                break;
            }

            case GPCFriendlyFire:
            {
                GFriendyFireAlarm *alarm = reinterpret_cast<GFriendyFireAlarm *>(t->data);
                alarm->from_net();
                if (tournament) {
                    if (tournament->friendly_fire_alarm(alarm)) {
                        subsystem.play_controlled_sound(resources.get_sound("friendly_fire"), 0);
                        ClientTextMessage *cmsg = new ClientTextMessage;
                        cmsg->text = "FRIENDLY FIRE: WATCH OUT!!!";
                        client_text_messages.push_back(cmsg);
                    }
                }
                break;
            }

            case GPCGamePlayUnbalanced:
            {
                if (tournament) {
                    subsystem.play_controlled_sound(resources.get_sound("unbalanced"), 0);
                    ClientTextMessage *cmsg = new ClientTextMessage;
                    cmsg->text = "GAMEPLAY IS UNBALANCED";
                    client_text_messages.push_back(cmsg);
                }
                break;
            }

            case GPCWarmUp:
            {
                if (tournament) {
                    subsystem.play_system_sound(resources.get_sound("warm_up"));
                    ClientTextMessage *cmsg = new ClientTextMessage;
                    cmsg->text = "please warm up";
                    client_text_messages.push_back(cmsg);
                }
                break;
            }

            case GPCGameBegins:
            {
                if (tournament) {
                    subsystem.play_system_sound(resources.get_sound("ready"));
                    ClientTextMessage *cmsg = new ClientTextMessage;
                    cmsg->text = "game begins";
                    client_text_messages.push_back(cmsg);
                }
                break;
            }

            case GPCGameOver:
            {
                if (tournament) {
                    subsystem.play_system_sound(resources.get_sound("game_over"));
                    ClientTextMessage *cmsg = new ClientTextMessage;
                    cmsg->text = "GAME IS OVER";
                    client_text_messages.push_back(cmsg);
                }
                break;
            }

            case GPCPlayerChanged:
            {
                GPlayerDescription *pdesc = reinterpret_cast<GPlayerDescription *>(t->data);
                pdesc->from_net();
                for (Players::iterator it = players.begin(); it != players.end(); it++) {
                    Player *p = *it;
                    if (p->state.id == pdesc->id) {
                        std::string old_name = p->get_player_name();
                        std::string new_name(pdesc->player_name);
                        std::string old_skin(p->get_characterset()->get_name());
                        std::string new_skin(pdesc->characterset_name);

                        /* change player name */
                        if (old_name != new_name) {
                            p->set_player_name(new_name);
                            p->font = 0;
                            ClientTextMessage *cmsg = new ClientTextMessage;
                            cmsg->text = old_name + " is now known as " + new_name;
                            client_text_messages.push_back(cmsg);
                        }

                        /* change skin */
                        if (old_skin != new_skin) {
                            try {
                                p->set_characterset(new_skin);
                                ClientTextMessage *cmsg = new ClientTextMessage;
                                cmsg->text = p->get_player_name() + " changed the skin to " + new_skin;
                                client_text_messages.push_back(cmsg);
                            } catch (const Exception& e) {
                                subsystem << e.what() << std::endl;
                            }
                        }
                        break;
                    }
                }
                break;
            }

            case GPCScoreTransportRaw:
            {
                if (tournament) {
                    tournament->score_transport_raw(t->data);
                }
                break;
            }

            case GPCClanNames:
            {
                GClanNames *names = reinterpret_cast<GClanNames *>(t->data);
                names->from_net();
                team_red_name = names->red_name;
                team_blue_name = names->blue_name;
                if (tournament) {
                    tournament->set_team_names(team_red_name, team_blue_name);
                }
                break;
            }

            case GPCXferHeader:
            {
                reload_resources = true;
                GXferHeader *header = reinterpret_cast<GXferHeader *>(t->data);
                header->from_net();
                if (!fhnd) {
                    xfer_filename = header->filename;
                    current_download_filename = get_home_directory() + dir_separator + UserDirectory + dir_separator + header->filename;
                    fhnd = fopen(current_download_filename.c_str(), "wb");
                    if (fhnd) {
                        total_xfer_sz = remaining_xfer_sz = header->filesize;
                    } else {
                        subsystem << "WARNING: cannot open file " << strerror(errno) << std::endl;
                    }
                } else {
                    subsystem << "WARNING: cannot receive " << xfer_filename << ". a file is already opened." << std::endl;
                }
                break;
            }

            case GPCXferDataChunk:
            {
                GXferDataChunk *chunk = reinterpret_cast<GXferDataChunk *>(t->data);
                chunk->from_net();
                if (fhnd) {
                    fwrite(chunk->data, chunk->chunksize, 1, fhnd);
                    remaining_xfer_sz -= chunk->chunksize;
                    if (remaining_xfer_sz < 1) {
                        fclose(fhnd);
                        fhnd = 0;
                        current_download_filename = "";
                    }
                }
                {
                    ScopeMutex lock(mtx);
                    send_data(evt.c, 0, GPSPakSyncAck, NetFlagsReliable, 0, 0);
                }
                break;
            }

            case GPCGenericData:
            {
                if (tournament) {
                    tournament->generic_data_delivery(t->data);
                }
                break;
            }

            case GPCServerQuit:
            {
                exception_msg.assign(reinterpret_cast<char *>(t->data), t->len);
                throw_exception = true;
                return;
                /* not necessary */
                break;
            }
        }

        /* advance to next element */
        if (t->flags & TransportFlagMorePackets) {
            unsigned char *tpb = reinterpret_cast<unsigned char *>(t);
            tpb += GTransportLen;
            tpb += t->len;
            t = reinterpret_cast<GTransport *>(tpb);
        } else {
            break;
        }
    }
}