// dx & dy indicates moving direction, useful for choosing melee attack targets
bool PlayerInst::enqueue_io_spell_and_attack_actions(GameState* gs, float dx,
        float dy) {
    GameView& view = gs->view();
    WeaponEntry& wentry = weapon().weapon_entry();

    bool mouse_within = gs->mouse_x() < gs->view().width;
    int rmx = view.x + gs->mouse_x(), rmy = view.y + gs->mouse_y();

    int level = gs->get_level()->id(), frame = gs->frame();

    bool is_moving = (dx != 0.0f || dy != 0.0f);
    IOController& io = gs->io_controller();
    bool attack_used = enqueue_io_spell_actions(gs);

    bool autotarget = io.query_event(IOEvent::AUTOTARGET_CURRENT_ACTION)
                      || io.query_event(IOEvent::ACTIVATE_SPELL_N);
    bool mousetarget = io.query_event(IOEvent::MOUSETARGET_CURRENT_ACTION);

    bool weaponuse = spell_selected() == -1;

    // choose & use weapon
    if (io.query_event(IOEvent::USE_WEAPON)) {
        queued_actions.push_back(
            game_action(gs, this, GameAction::CHOSE_SPELL, -1));
        autotarget = true;
        weaponuse = true;
    }

    if (spell_selected() >= 0
            && spells_known().get_entry(spell_selected()).mp_cost
            > core_stats().mp) {
        weaponuse = true;
    }

    // weapon use
    if (!attack_used && weaponuse && (autotarget || mousetarget)) {

        bool is_projectile = wentry.uses_projectile
                             || equipment().has_projectile();

        MonsterController& mc = gs->monster_controller();
        GameInst* curr_target = gs->get_instance(current_target);
        GameInst* target = NULL;
        Pos targ_pos;

        if (is_projectile) {
            if (mousetarget) {
                targ_pos = Pos(rmx, rmy);
            } else if (autotarget && curr_target) {
                targ_pos = curr_target->pos();
            }
        } else {
            if (mousetarget) {
                dx = rmx - x, dy = rmy - y;
            }
            target = get_weapon_autotarget(gs, this, curr_target, dx, dy);
            if (target) {
                targ_pos = Pos(target->x, target->y);

            }
            if (!is_moving && !target && !mousetarget && spell_selected() == -1
                    && curr_target && !is_projectile) {
                int vx, vy;
                GameInst* closest = get_closest_monster(gs, this);

                if (closest
                        && decide_attack_movement(pos(), closest->pos(),
                                                  TILE_SIZE / 4, vx, vy)) {
                    queued_actions.push_back(
                        game_action(gs, this, GameAction::MOVE, spellselect,
                                    round(vx), round(vy)));
                }
            }
        }
        if (target || (is_projectile && (mousetarget || curr_target))) {
            queued_actions.push_back(
                game_action(gs, this, GameAction::USE_WEAPON, spellselect,
                            targ_pos.x, targ_pos.y));
            attack_used = true;
        }
    }
    return attack_used;
}