U0 PlayerIndirect()
{
        Unit *tmpu = NULL;
        I64   i, remaining = 0, message_code, arg1, arg2;
        F64   target_x, target_y;

        ViewPlayerSet(cur_player);
        for (i = 0; i > UNITS_NUM; i++)
        {
                tmpu = &units[cur_player][i];
                if (tmpu->life > 0 && tmpu->indirect_fire)
                        remaining++;
        }
        while (remaining)
        {
                if (!alive_count[0] || !alive_count[1])
                        throw('GameOver', TRUE);
                message_code = MessageGet(&arg1, &arg2, 1 << MESSAGE_KEY_DOWN  |
                                                                                                1 << MESSAGE_MS_L_DOWN | 1 << MESSAGE_MS_L_UP | 1 << MESSAGE_MS_R_UP);
                switch (message_code)
                {
                        case MESSAGE_KEY_DOWN:
                                CharDo(arg1);
                                break;

                        case MESSAGE_MS_L_DOWN:
                                if (CursorInWin(Fs, arg1, arg2))
                                {
                                        arg1 -= x0; arg2 -= y0;
                                        CursorUpdate(Fs, arg1, arg2);
                                        if (tmpu = UnitFind(cursor_row, cursor_col))
                                        {
                                                if (tmpu->player == enemy_player || tmpu->fired || !tmpu->indirect_fire)
                                                        tmpu = NULL;
                                                else
                                                {
                                                        RowCol2XY(&fire_radius_x, &fire_radius_y, tmpu->row, tmpu->col);
                                                        fire_radius = tmpu->range * 2 * HEX_RADIUS;
                                                }
                                        }
                                }
                                break;

                        case MESSAGE_MS_L_UP:
                                if (CursorInWin(Fs, arg1, arg2))
                                {
                                        arg1 -= x0; arg2 -= y0;
                                        CursorUpdate(Fs, arg1, arg2);
                                        RowCol2XY(&target_x, &target_y, cursor_row, cursor_col);
                                        if (!tmpu)
                                                Beep;
                                        else
                                        {
                                                if (Sqrt(Sqr(fire_radius_x - target_x) + Sqr(fire_radius_y - target_y)) > fire_radius)
                                                        Beep;
                                                else
                                                {
                                                        IndirectAdd(tmpu, cursor_row, cursor_col);
                                                        remaining--;
                                                }
                                        }
                                }
                                tmpu = NULL;
                                fire_radius = 0;
                                break;

                        case MESSAGE_MS_R_UP:
                                if (CursorInWin(Fs, arg1, arg2))
                                        throw('PhaseOvr', TRUE);
                                break;
                }
        }
        throw('PhaseOvr', TRUE);
}

U0 PlayerMove()
{
        Unit *tmpu = NULL;
        I64   message_code, arg1, arg2;

        ViewPlayerSet(cur_player);
        while (TRUE)
        {
                if (!alive_count[0] || !alive_count[1])
                        throw('GameOver', TRUE);
                message_code = MessageGet(&arg1, &arg2, 1 << MESSAGE_KEY_DOWN  |
                                                                                                1 << MESSAGE_MS_L_DOWN | 1 << MESSAGE_MS_L_UP | 1 << MESSAGE_MS_R_UP);
                switch (message_code)
                {
                        case MESSAGE_KEY_DOWN:
                                CharDo(arg1);
                                break;

                        case MESSAGE_MS_L_DOWN:
                                if (CursorInWin(Fs, arg1, arg2))
                                {
                                        arg1 -= x0; arg2 -= y0;
                                        CursorUpdate(Fs, arg1, arg2);
                                        if (tmpu = UnitFind(cursor_row, cursor_col))
                                        {
                                                if (tmpu->player == enemy_player || !tmpu->remaining_movement)
                                                        tmpu = NULL;
                                        }
                                }
                                break;

                        case MESSAGE_MS_L_UP:
                                if (CursorInWin(Fs, arg1, arg2))
                                {
                                        arg1 -= x0; arg2 -= y0;
                                        CursorUpdate(Fs, arg1, arg2);
                                        if (!tmpu)
                                                Beep;
                                        else
                                        {
                                                UnitMove(tmpu, arg1, arg2);
                                                break;
                                        }
                                }
                                tmpu = NULL;
                                break;

                        case MESSAGE_MS_R_UP:
                                if (CursorInWin(Fs, arg1, arg2))
                                        throw('PhaseOvr', TRUE);
                                break;
                }
        }
}

U0 PlayerDirect()
{
        Unit *tmpu = NULL, *target;
        I64   message_code, arg1, arg2;

        ViewPlayerSet(cur_player);
        while (TRUE)
        {
                if (!alive_count[0] || !alive_count[1])
                        throw('GameOver', TRUE);
                message_code = MessageGet(&arg1, &arg2, 1 << MESSAGE_KEY_DOWN  |
                                                                                                1 << MESSAGE_MS_L_DOWN | 1 << MESSAGE_MS_L_UP | 1 << MESSAGE_MS_R_UP);
                switch (message_code)
                {
                        case MESSAGE_KEY_DOWN:
                                CharDo(arg1);
                                break;

                        case MESSAGE_MS_L_DOWN:
                                if (CursorInWin(Fs, arg1, arg2))
                                {
                                        arg1 -= x0; arg2 -= y0;
                                        CursorUpdate(Fs, arg1, arg2);
                                        if (tmpu = UnitFind(cursor_row, cursor_col))
                                        {
                                                if (tmpu->player == enemy_player || tmpu->fired || tmpu->indirect_fire)
                                                        tmpu = NULL;
                                                else
                                                {
                                                        VRSetUp(cur_player);
                                                        RowCol2XY(&fire_radius_x, &fire_radius_y, tmpu->row, tmpu->col);
                                                        fire_radius = tmpu->range * 2 * HEX_RADIUS;
                                                        VisRecalc(VR_ONE_FRIENDLY_UNIT, tmpu);
                                                }
                                        }
                                }
                                break;

                        case MESSAGE_MS_L_UP:
                                if (CursorInWin(Fs, arg1, arg2))
                                {
                                        arg1 -= x0; arg2 -= y0;
                                        CursorUpdate(Fs, arg1, arg2);
                                        target = UnitFind(cursor_row, cursor_col);
                                        if (!tmpu)
                                                Beep;
                                        else
                                        {
                                                if (!target || target->player != enemy_player || !Bt(&target->vis, 0))
                                                        Beep;
                                                else
                                                        UnitDirectFire(tmpu, target);
                                                VisRecalc(VR_UPDATE_FRIENDLY_UNIT, tmpu);
                                        }
                                }
                                tmpu = NULL;
                                fire_radius = 0;
                                break;

                        case MESSAGE_MS_R_UP:
                                if (CursorInWin(Fs, arg1, arg2))
                                        throw('PhaseOvr', TRUE);
                                break;
                }
        }
}