/*
 * tngp/hud.c
 *
 * Copyright (C) 2022 bzt
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * @brief Game HUD
 *
 */

#include "tngp.h"
#include "SDL2_mixer/src/music.h"                       /* MIX_MAX_VOLUME */

/* drag'n'drop sources */
enum { DND_NONE, DND_ITEMBAR, DND_EQUIP, DND_INV, DND_SKILLS, DND_MARKET, DND_CRAFT };

int hud_tab, hud_tabx[5], hud_npc = -1, hud_cft = -1;
int hud_w, hud_h, hud_navsiz, hud_enemyhp, hud_btn = 0, hud_navx = 0, hud_navy = 0;
static int *hud_vp = NULL, hud_dt, hud_fo, hud_p, hud_invtab, hud_sel1, hud_sel2, hud_max1, hud_max2, hud_line1, hud_line2;
static int hud_scr1, hud_scr2, hud_focus, *hud_attrs = NULL, hud_numattrs, hud_rem, hud_clk = 0;
static SDL_Texture *hud_win1 = NULL, *hud_win2 = NULL, *hud_win3 = NULL, *hud_frm1 = NULL, *hud_frm2 = NULL, *hud_frm3 = NULL;
static SDL_Texture *hud_pbars = NULL, *hud_title = NULL;
static SDL_Rect hud_dst1, hud_dst2, hud_dst3;       /* window positions */
static SDL_Rect hud_itemb, hud_statb, hud_titleb;   /* itembar (bottom), statusbar (top), titlebar (bottom) */
static SDL_Rect hud_items1, hud_items2;             /* item list boxes (inventory and market) */
static SDL_Rect hud_equip, hud_prt1, hud_prt2;      /* equipment "portrait" and character, npc portraits */
static uint8_t *hud_sell_bc = NULL, *hud_buy_bc = NULL;
static int hud_sell_bclen = 0, hud_buy_bclen = 0, hud_sell_tng = 0, hud_buy_tng = 0;
static int hud_dnd_src = DND_NONE, hud_dnd_idx = -1, hud_dnd_w, hud_dnd_h, hud_dnd_i;
static world_sprite_t *hud_dnd = NULL;
uint32_t hud_titlefade;
char hud_chat[516];

/**
 * Redraw hud windows
 */
void hud_redraw()
{
    world_sprite_t *spr;
    ssfn_t *font;
    char *str, tmp[256];
    int i, j, k, l, p, q, w, h, x, hb;
    int bx = world.inv_w + world.inv_l, by = world.inv_h + world.inv_t;
    uint32_t *dst, *src, c;

    if(!hud_frm1 || hud_tab == HUD_NONE) return;
    SDL_LockTexture(hud_frm1, NULL, (void**)&dst, &p);
    memset(dst, 0, p * hud_dst1.h);
    memset(&hud_items1, 0, sizeof(hud_items1));
    memset(&hud_items2, 0, sizeof(hud_items2));
    memset(&hud_equip, 0, sizeof(hud_equip));
    memset(&hud_prt1, 0, sizeof(hud_prt1));
    memset(&hud_prt2, 0, sizeof(hud_prt2));
    switch(hud_tab) {
        case HUD_MENU:
            SDL_LockTexture(logo, NULL, (void**)&src, &q);
            i = ui_wt + world.padtop[PAD_V];
            ui_blit(dst, 16, 16, p, ui_wl + world.padtop[PAD_H], i + (ui_lineh - 16) / 2, src, 320, 176, 16, 16, q,
                hud_sel1 == 0 ? 2 : 3);
            ui_slider(dst, hud_dst1.w, hud_dst1.h, p, ui_wl + 2 * world.padtop[PAD_H] + 16, i, 255,
                main_musvol, MIX_MAX_VOLUME);
            i += world.padtop[PAD_V] + ui_lineh;
            ui_blit(dst, 16, 16, p, ui_wl + world.padtop[PAD_H], i + (ui_lineh - 16) / 2, src, 336, 176, 16, 16, q,
                hud_sel1 == 1 ? 2 : 3);
            ui_slider(dst, hud_dst1.w, hud_dst1.h, p, ui_wl + 2 * world.padtop[PAD_H] + 16, i, 255,
                main_sfxvol, MIX_MAX_VOLUME);
            i += world.padtop[PAD_V] + ui_lineh;
            ui_blit(dst, 16, 16, p, ui_wl + world.padtop[PAD_H], i + (ui_lineh - 16) / 2, src, 352, 176, 16, 16, q,
                hud_sel1 == 2 ? 2 : 3);
            ui_slider(dst, hud_dst1.w, hud_dst1.h, p, ui_wl + 2 * world.padtop[PAD_H] + 16, i, 255,
                main_spcvol, MIX_MAX_VOLUME);
            i += world.padtop[PAD_V] + ui_lineh;
            str = (world.hdr.magic[0] == '#' ?
                (world.text && world.text[GAME_SAVE][0] ? world.text[GAME_SAVE] : "Save Game") :
                (world.text && world.text[GAME_CHAT][0] ? world.text[GAME_CHAT] : "Chat")
            );
            ui_button(dst, hud_dst1.w, hud_dst1.h, p, ui_wl, i, hud_dst1.w - ui_wl - ui_wr,
#ifdef __EMSCRIPTEN__
                3
#else
                hud_sel1 == 3 ? (hud_p ? 2 : 1) : 0
#endif
                , str);
            i += world.padtop[PAD_V] + ui_btnh;
            str = world.text && world.text[GAME_MENU][0] ? world.text[GAME_MENU] : "Back to Title";
            ui_button(dst, hud_dst1.w, hud_dst1.h, p, ui_wl, i, hud_dst1.w - ui_wl - ui_wr,
                hud_sel1 == 4 ? (hud_p ? 2 : 1) : 0, str);
            SDL_UnlockTexture(logo);
        break;
        case HUD_CHAT:
            ui_textinp(dst, hud_dst1.w, hud_dst1.h, p, ui_chatw, 0, hud_dst1.w - 2 * ui_chatw, 4, hud_chat + 4);
        break;
        default:
            switch(hud_invtab) {
                case 0:
                    hud_items1.x = ui_wl + world.padtop[PAD_H]; hud_items1.y = ui_wt + world.padtop[PAD_V];
                    hud_items1.w = hud_dst1.w - ui_wl - ui_wr - 2 * world.padtop[PAD_H] - ui_vbw;
                    spr = spr_get(world.equipimg.cat, world.equipimg.idx, 0);
                    if(spr) {
                        l = hud_dst1.h - ui_wt - ui_wb - 2 * ui_slots - 2 - 3 * world.padtop[PAD_V];
                        if(l > spr->h) l = spr->h;
                        ui_fit(hud_dst1.w - ui_wl - ui_wr - 2 * world.padtop[PAD_H], l, spr->w, spr->h, &hud_equip.w, &hud_equip.h);
                        hud_equip.y = hud_dst1.y + ui_wt + world.padtop[PAD_V];
                        hud_equip.x = hud_dst1.x + (hud_dst1.w - hud_equip.w) / 2;
                        hud_items1.y += l + world.padtop[PAD_V];
                    }
                    if(hud_items1.y + ui_slots < hud_dst1.h - ui_wb) {
                        hud_items1.h = ((hud_dst1.h - ui_wb - hud_items1.y) / (ui_slots + 2)) * (ui_slots + 2) - 2;
                        if(world.players && world.players[0].data.inv && world.players[0].data.numinv > 0) {
                            font = font_get(FNT_INV);
                            if(!font) font = font_get(FNT_TXT);
                            if(font) {
                                font->style &= ~SSFN_STYLE_A;
                                for(j = 0, k = hud_scr1 * hud_line1; j < hud_items1.h && k < world.players[0].data.numinv; j += ui_slots + 2)
                                    for(i = 0; i < hud_line1 && k < world.players[0].data.numinv; i++, k++)
                                        if(world.players[0].data.inv[k].qty > 1) {
                                            c = world.colors[hud_sel1 == k ? COLOR_SEL : COLOR_FG];
                                            sprintf(tmp, "%u", world.players[0].data.inv[k].qty);
                                            if(ssfn_bbox(font, tmp, &w, &h, &x, &hb) == SSFN_OK)
                                                ui_text(dst, hud_dst1.w, hud_dst1.h, p, hud_items1.x + i * (ui_slots + 2) + bx - w,
                                                    hud_items1.y + j + by - h + hb, font, c, tmp);
                                        }
                            }
                        }
                        hud_max1 = ((hud_items1.h + 2) / (ui_slots + 2)) * hud_line1 - 1;
                        if(world.players && world.players[0].data.numinv > hud_max1)
                            hud_max1 = ((world.players[0].data.numinv + hud_line1 - 1) / hud_line1) * hud_line1 - 1;
                        ui_vscr(dst, hud_dst1.w, hud_dst1.h, p, hud_items1.x + hud_items1.w, hud_items1.y, hud_items1.h,
                            hud_sel1, hud_max1);
                    }
                    hud_items1.x += hud_dst1.x;
                    hud_items1.y += hud_dst1.y;
                break;
                case 1:
                    /* get remaining level up points */
                    hud_rem = world.engattr[ENG_LVLUP] >= 0 && world.engattr[ENG_LVLUP] < world.numattrs ?
                        world.players[0].data.attrs[world.attrs[world.engattr[ENG_LVLUP]].idx] : 0;
                    if(hud_rem < 0) hud_rem = 0;
                    hud_items1.x = ui_wl + world.padtop[PAD_H]; hud_items1.y = ui_wt + world.padtop[PAD_V];
                    hud_items1.w = hud_dst1.w - ui_wl - ui_wr - 2 * world.padtop[PAD_H] - ui_vbw;
                    /* user portrait */
                    spr = spr_get(world.equipimg.cat, world.equipimg.idx, 0);
                    if(spr) {
                        l = hud_dst1.h - ui_wt - ui_wb - 2 * ui_slots - 2 - ((hud_rem ? 1 : 0) + hud_numattrs) * ui_lineh -
                            4 * world.padtop[PAD_V];
                        if(l > hud_dst1.h / 3) l = hud_dst1.h / 3;
                        if(l > spr->h) l = spr->h;
                        ui_fit(hud_dst1.w - ui_wl - ui_wr - 2 * world.padtop[PAD_H], l, spr->w, spr->h, &hud_prt1.w, &hud_prt1.h);
                        hud_prt1.y = hud_dst1.y + ui_wt + world.padtop[PAD_V];
                        hud_prt1.x = hud_dst1.x + (hud_dst1.w - hud_prt1.w) / 2;
                        hud_items1.y += l + world.padtop[PAD_V];
                    }
                    if(hud_attrs && hud_numattrs > 0) {
                        /* draw primary attributes */
                        for(j = 0; j < hud_numattrs && hud_items1.y + ui_lineh < hud_dst1.h - ui_wb; j++) {
                            l = hud_tab == HUD_INV && hud_focus == -1 && hud_sel1 == j; i = hud_attrs[j];
                            font = font_get(l ? FNT_SEL : FNT_TXT); c = world.colors[l ? COLOR_SEL : COLOR_FG];
                            str = world.text && world.attrs[i].trname != -1 && world.attrs[i].trname < world.numtext &&
                                world.text[world.attrs[i].trname][0] ? world.text[world.attrs[i].trname] : world.attrs[i].name;
                            if(str && font && ssfn_bbox(font, str, &w, &h, &x, &hb) == SSFN_OK) {
                                font->style &= ~SSFN_STYLE_A;
                                ui_text(dst, hud_dst1.w, hud_dst1.h, p, ui_wl + world.padtop[PAD_H],
                                    hud_items1.y + (ui_lineh - world.fonts[l ? FNT_SEL : FNT_TXT].size) / 2 + hb, font, c, str);
                            }
                            sprintf(tmp, "%d", world.players[0].data.attrs[world.attrs[i].idx]);
                            if(font && ssfn_bbox(font, tmp, &w, &h, &x, &hb) == SSFN_OK) {
                                ui_text(dst, hud_dst1.w, hud_dst1.h, p, hud_dst1.w - ui_wr - world.padtop[PAD_H] -
                                    (hud_tab == HUD_INV && hud_rem ? world.padtop[PAD_H] + ui_or : 0) - w,
                                    hud_items1.y + (ui_lineh - world.fonts[l ? FNT_SEL : FNT_TXT].size) / 2 + hb, font, c, tmp);
                            }
                            if(hud_tab == HUD_INV && hud_rem && world.attrs[i].type == ATTR_PRI) {
                                spr = spr_get(world.uispr[hud_p ? E_OPTNEXTPRESS : E_OPTNEXT].cat,
                                    world.uispr[hud_p ? E_OPTNEXTPRESS : E_OPTNEXT].idx, 0);
                                if(spr)
                                    spr_blit(dst, hud_dst1.w, hud_dst1.h, p, hud_dst1.w - ui_wr - world.padtop[PAD_H] - spr->w,
                                        hud_items1.y + (ui_lineh - spr->h) / 2, spr->w, spr->h, spr, 0, NULL);
                            }
                            hud_items1.y += ui_lineh;
                        }
                        if(hud_rem && hud_items1.y + ui_lineh < hud_dst1.h - ui_wb) {
                            sprintf(tmp, "%s: %u", world.text && world.text[GAME_REMAIN][0] ? world.text[GAME_REMAIN] : "Remaining",
                                hud_rem);
                            font = font_get(FNT_TXT);
                            if(font && ssfn_bbox(font, tmp, &w, &h, &x, &hb) == SSFN_OK) {
                                font->style &= ~SSFN_STYLE_A;
                                ui_text(dst, hud_dst1.w, hud_dst1.h, p, hud_items1.x + (hud_items1.w - w) / 2,
                                    hud_items1.y + (ui_lineh - world.fonts[FNT_TXT].size) / 2 + hb, font,
                                    world.colors[COLOR_FG], tmp);
                            }
                            hud_items1.y += ui_lineh;
                        }
                        hud_items1.y += world.padtop[PAD_V];
                    }
                    if(hud_items1.y + ui_slots < hud_dst1.h - ui_wb) {
                        hud_items1.h = ((hud_dst1.h - ui_wb - hud_items1.y) / (ui_slots + 2)) * (ui_slots + 2) - 2;
                        if(world.players && world.players[0].data.skills && world.players[0].data.numskl > 0) {
                            font = font_get(FNT_INV);
                            if(!font) font = font_get(FNT_TXT);
                            if(font) {
                                font->style &= ~SSFN_STYLE_A;
                                for(j = 0, k = hud_scr1 * hud_line1; j < hud_items1.h && k < world.players[0].data.numskl; j += ui_slots + 2)
                                    for(i = 0; i < hud_line1 * (ui_slots + 2) && k < world.players[0].data.numskl; i += ui_slots + 2, k++) {
                                        c = world.colors[hud_sel1 == k ? COLOR_SEL : COLOR_FG];
                                        sprintf(tmp, "%u", world.players[0].data.skills[k].qty);
                                        if(ssfn_bbox(font, tmp, &w, &h, &x, &hb) == SSFN_OK)
                                            ui_text(dst, hud_dst1.w, hud_dst1.h, p, hud_items1.x + i * (ui_slots + 2) + bx - w,
                                                hud_items1.y + j + by - h + hb, font, c, tmp);
                                    }
                            }
                        }
                        hud_max1 = ((hud_items1.h + 2) / (ui_slots + 2)) * hud_line1 - 1;
                        if(world.players && world.players[0].data.numskl > hud_max1)
                            hud_max1 = ((world.players[0].data.numskl + hud_line1 - 1) / hud_line1) * hud_line1 - 1;
                        ui_vscr(dst, hud_dst1.w, hud_dst1.h, p, hud_items1.x + hud_items1.w, hud_items1.y, hud_items1.h,
                            hud_sel1, hud_max1);
                    }
                    hud_items1.x += hud_dst1.x;
                    hud_items1.y += hud_dst1.y;
                break;
                case 2:
                    hud_items1.x = ui_wl + world.padtop[PAD_H]; hud_items1.y = ui_wt + world.padtop[PAD_V];
                    hud_items1.w = hud_dst1.w - ui_wl - ui_wr - 2 * world.padtop[PAD_H] - ui_vbw;
                    hud_items1.h = hud_dst1.h - ui_wb -  world.padtop[PAD_V] - hud_items1.y;
                    if(world.players && world.players[0].data.quests && world.players[0].data.numqst > 0) {
                        for(j = 0, k = hud_scr1; j < hud_items1.h && k < world.players[0].data.numqst; j += ui_lineh + 2, k++) {
                            font = font_get(hud_sel1 == k ? FNT_SEL : FNT_TXT);
                            c = world.colors[hud_sel1 == k ? COLOR_SEL : COLOR_FG];
                            l = world.players[0].data.quests[k * 2 + 1];
                            if(l < 0 || l >= world.numqst) break;
                            str = world.text && world.quests[l].trname >= 0 && world.quests[l].trname < world.numtext &&
                                world.text[world.quests[l].trname][0] ? world.text[world.quests[l].trname] : world.quests[l].name;
                            hb = ui_lineh;
                            if(str && font && ssfn_bbox(font, str, &w, &h, &x, &hb) == SSFN_OK) {
                                font->style &= ~SSFN_STYLE_A;
                                ui_text(dst, hud_dst1.w - ui_wr - ui_vbw - 2 * world.padtop[PAD_H], hud_dst1.h, p,
                                    hud_items1.x + ui_lineh, hud_items1.y + j + (ui_lineh - h) / 2 + hb, font, c, str);
                            }
                            spr = spr_get(world.uispr[E_CHK0 + (world.players[0].data.quests[k * 2] & 1)].cat,
                                world.uispr[E_CHK0 + (world.players[0].data.quests[k * 2] & 1)].idx, 0);
                            if(spr) spr_blit(dst, hud_dst1.w, hud_dst1.h, p,
                                hud_items1.x, hud_items1.y + j + (ui_lineh - h) / 2 + hb - spr->h, spr->w, spr->h, spr, 0, NULL);
                        }
                    }
                    hud_max1 = (world.players && world.players[0].data.numqst > 0 ? world.players[0].data.numqst - 1 : 0);
                    ui_vscr(dst, hud_dst1.w, hud_dst1.h, p, hud_items1.x + hud_items1.w, hud_items1.y, hud_items1.h,
                        hud_sel1, hud_max1);
                    hud_items1.x += hud_dst1.x;
                    hud_items1.y += hud_dst1.y;
                break;
            }
        break;
    }
    switch(hud_tab) {
        case HUD_MARKET:
            SDL_LockTexture(hud_frm2, NULL, (void**)&dst, &p);
            memset(dst, 0, p * hud_dst2.h);
            hud_items2.x = ui_wl + world.padtop[PAD_H]; hud_items2.y = ui_wt + world.padtop[PAD_V];
            hud_items2.w = hud_dst2.w - ui_wl - ui_wr - 2 * world.padtop[PAD_H] - ui_vbw;
            /* npc portrait */
            spr = spr_get(world.equipimg.cat, world.equipimg.idx, 0);
            if(spr) {
                l = hud_dst2.h - ui_wt - ui_wb - 2 * ui_slots - 2 - 3 * world.padtop[PAD_V];
                if(l > hud_dst2.h / 3) l = hud_dst2.h / 3;
                if(l > spr->h) l = spr->h;
                ui_fit(hud_dst2.w - ui_wl - ui_wr - 2 * world.padtop[PAD_H], l, spr->w, spr->h, &hud_prt2.w, &hud_prt2.h);
                hud_prt2.y = hud_dst2.y + ui_wt + world.padtop[PAD_V];
                hud_prt2.x = hud_dst2.x + (hud_dst2.w - hud_prt2.w) / 2;
                hud_items2.y += l + world.padtop[PAD_V];
            }
            if(hud_items2.y + ui_slots < hud_dst2.h - ui_wb) {
                hud_items2.h = ((hud_dst2.h - ui_wb - hud_items2.y) / (ui_slots + 2)) * (ui_slots + 2) - 2;
                hud_max2 = ((hud_items2.h + 2) / (ui_slots + 2)) * hud_line2 - 1;
                ui_vscr(dst, hud_dst2.w, hud_dst2.h, p, hud_items2.x + hud_items2.w, hud_items2.y, hud_items2.h,
                    hud_sel2, hud_max2);
            }
            hud_items2.x += hud_dst2.x;
            hud_items2.y += hud_dst2.y;
            SDL_UnlockTexture(hud_frm2);
        break;
        case HUD_CRAFT:
            SDL_LockTexture(hud_frm2, NULL, (void**)&dst, &p);
            memset(dst, 0, p * hud_dst2.h);
            SDL_UnlockTexture(hud_frm2);
        break;
    }
    SDL_UnlockTexture(hud_frm1);
}

/**
 * Switch huds
 */
void hud_switch(int tab, int invtab)
{
    world_sprite_t *spr;
    int p;
    uint32_t *dst;
    int tabs[4] = { GAME_INV, GAME_SKILLS, GAME_QUESTS, 0 };

    if(hud_win1) { SDL_DestroyTexture(hud_win1); hud_win1 = NULL; }
    if(hud_win2) { SDL_DestroyTexture(hud_win2); hud_win2 = NULL; }
    if(hud_win3) { SDL_DestroyTexture(hud_win3); hud_win3 = NULL; }
    if(hud_frm1) { SDL_DestroyTexture(hud_frm1); hud_frm1 = NULL; }
    if(hud_frm2) { SDL_DestroyTexture(hud_frm2); hud_frm2 = NULL; }
    if(hud_frm3) { SDL_DestroyTexture(hud_frm3); hud_frm3 = NULL; }
    hud_dnd = NULL; hud_dnd_src = DND_NONE; hud_dnd_idx = -1;
    memset(&hud_dst1, 0, sizeof(hud_dst1));
    memset(&hud_dst2, 0, sizeof(hud_dst2));
    memset(&hud_dst3, 0, sizeof(hud_dst3));
    memset(&hud_tabx, 0, sizeof(hud_tabx));
    if(invtab > 2) invtab = 0;
    if(invtab < 0) invtab = 2;
    if((tab == HUD_MARKET && hud_npc == -1) || (tab == HUD_CRAFT && hud_cft == -1)) tab = HUD_NONE;
    if(hud_tab == HUD_MARKET || tab == HUD_NONE) {
        hud_sell_bc = hud_buy_bc = NULL;
        hud_sell_bclen = hud_buy_bclen = hud_sell_tng = hud_buy_tng = 0;
    }
    hud_invtab = (tab != HUD_MENU && tab != HUD_NONE && tab == hud_tab) ? invtab : 0;
    hud_tab = tab; hud_sel1 = hud_sel2 = hud_max1 = hud_max2 = hud_p = hud_scr1 = hud_scr2 = hud_line1 = hud_line2 = hud_focus = 0;
    switch(hud_tab) {
        case HUD_NONE: client_eqchange = 1; break;
        case HUD_MENU:
            main_takescrshot = 1;
            hud_win1 = ui_window(3 * world.padtop[PAD_H] + 16 + 256, 6 * world.padtop[PAD_V] + 3 * ui_lineh + 2 * ui_btnh,
                NULL, 0, NULL, &hud_dst1, NULL, 0, 0);
            hud_dst1.x = (win_w - hud_dst1.w) / 2; hud_dst1.y = (win_h - hud_dst1.h) / 2;
            hud_frm1 = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STREAMING, hud_dst1.w, hud_dst1.h);
            hud_max1 = 4;
        break;
        case HUD_CHAT:
            hud_dst1.w = win_w - 2 * (ui_chatw + hud_navsiz); hud_dst1.h = ui_chath;
            hud_dst1.x = (win_w - hud_dst1.w) / 2; hud_dst1.y = hud_itemb.y - hud_dst1.h - 4;
            hud_win1 = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STREAMING, hud_dst1.w, hud_dst1.h);
            if(hud_win1) {
                SDL_SetTextureBlendMode(hud_win1, SDL_BLENDMODE_BLEND);
                SDL_LockTexture(hud_win1, NULL, (void**)&dst, &p);
                memset(dst, 0, p * hud_dst1.h);
                spr = spr_get(world.uispr[E_INPL].cat, world.uispr[E_INPL].idx, 0);
                if(spr) spr_blit(dst, hud_dst1.w, hud_dst1.h, p, ui_chatw - spr->w, (ui_chath - spr->h) / 2, spr->w, spr->h, spr, 0, NULL);
                spr = spr_get(world.uispr[E_INPBG].cat, world.uispr[E_INPBG].idx, 0);
                if(spr) spr_blit(dst, hud_dst1.w, hud_dst1.h, p, ui_chatw, (ui_chath - spr->h) / 2, hud_dst1.w - 2 * ui_chatw, spr->h, spr, 0, NULL);
                spr = spr_get(world.uispr[E_INPR].cat, world.uispr[E_INPR].idx, 0);
                if(spr) spr_blit(dst, hud_dst1.w, hud_dst1.h, p, hud_dst1.w - ui_chatw, (ui_chath - spr->h) / 2, spr->w, spr->h, spr, 0, NULL);
                SDL_UnlockTexture(hud_win1);
            }
            hud_frm1 = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STREAMING, hud_dst1.w, hud_dst1.h);
            ui_input_start(hud_dst1.x + ui_chatw, hud_dst1.y, hud_dst1.w - 2 * ui_chatw, ui_chath, NULL, hud_chat + 4, sizeof(hud_chat) - 5, 2);
        break;
        default:
            hud_win1 = ui_window(hud_w, hud_h, tabs, hud_invtab, NULL, &hud_dst1, hud_tabx, ui_slots + 2, ui_vbw + 2 * world.padtop[PAD_H]);
            hud_dst1.x = win_w - hud_dst1.w - 5; hud_dst1.y = 36;
            hud_line1 = (hud_dst1.w - ui_wl - ui_wr - 2 * world.padtop[PAD_H] - ui_vbw) / (ui_slots + 2);
            hud_frm1 = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STREAMING, hud_dst1.w, hud_dst1.h);
            if(hud_tab == HUD_INV && hud_invtab == 1 && world.engattr[ENG_LVLUP] >= 0 && world.engattr[ENG_LVLUP] < world.numattrs &&
              world.players[0].data.attrs[world.attrs[world.engattr[ENG_LVLUP]].idx] > 0) {
                hud_focus = -1;
            }
        break;
    }
    switch(hud_tab) {
        case HUD_MARKET:
            hud_win2 = ui_window(hud_w, hud_h, NULL, 0, NULL, &hud_dst2, NULL, ui_slots + 2, ui_vbw + 2 * world.padtop[PAD_H]);
            hud_dst2.x = 5; hud_dst2.y = 36;
            hud_line2 = (hud_dst2.w - ui_wl - ui_wr - 2 * world.padtop[PAD_H] - ui_vbw) / (ui_slots + 2);
            hud_frm2 = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STREAMING, hud_dst2.w, hud_dst2.h);
        break;
        case HUD_CRAFT:
            hud_win2 = ui_window(hud_w, hud_h, NULL, 0, NULL, &hud_dst2, NULL, 0, 0);
            hud_dst2.x = 5; hud_dst2.y = 36;
            hud_frm2 = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STREAMING, hud_dst2.w, hud_dst2.h);
        break;
    }
    if(hud_frm1) SDL_SetTextureBlendMode(hud_frm1, SDL_BLENDMODE_BLEND);
    if(hud_frm2) SDL_SetTextureBlendMode(hud_frm2, SDL_BLENDMODE_BLEND);
    hud_redraw();
}

/**
 * Redraw quantity popup window
 */
void hud_qtyredraw()
{
    int p;
    uint32_t *dst;

    if(!hud_frm3) return;
    SDL_LockTexture(hud_frm3, NULL, (void**)&dst, &p);
    memset(dst, 0, p * hud_dst3.h);
    SDL_UnlockTexture(hud_frm3);
}

/**
 * Close the popup
 */
void hud_popupclose()
{
    if(hud_win3) { SDL_DestroyTexture(hud_win3); hud_win3 = NULL; }
    if(hud_frm3) { SDL_DestroyTexture(hud_frm3); hud_frm3 = NULL; }
    memset(&hud_dst3, 0, sizeof(hud_dst3));
}

/**
 * Quantity popup window
 */
void hud_qty(int sell)
{
    int tabs[2] = { 0, 0 };

    hud_popupclose();
printf("qty %d\n",sell);
    if(hud_tab != HUD_MARKET && hud_tab != HUD_CRAFT) return;
    tabs[0] = sell ? GAME_SELL : GAME_BUY;
    hud_win3 = ui_window(200, 100, tabs, 0, NULL, &hud_dst3, NULL, 0, 0);
    hud_dst3.x = (win_w - hud_dst3.w) / 2; hud_dst3.y = (win_h - hud_dst3.h) / 2;
    hud_frm3 = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STREAMING, hud_dst3.w, hud_dst3.h);
    if(hud_frm3) {
        SDL_SetTextureBlendMode(hud_frm3, SDL_BLENDMODE_BLEND);
        hud_qtyredraw();
    }
}

/**
 * Quest description popup window
 */
void hud_quest(int idx)
{
    ssfn_t *font;
    int l, p, w, h, t;
    char *str;
    uint32_t *dst;

    hud_popupclose();
    if(!world.quests || idx < 0 || idx >= world.numqst || !world.text || world.quests[idx].desc < 0 ||
        world.quests[idx].desc >= world.numtext) return;
    font = font_get(FNT_TXT); if(!font) return;
    str = ui_fitstr(world.text[world.quests[idx].desc], win_w / 2, FNT_TXT, &l, world.players ? world.players[0].name : NULL,
        world.players ? world.players[0].data.attrs : NULL);
    if(!str) return;
    if(l < 1) l = 1;
    hud_win3 = ui_dlgwin(win_w / 2 + 2 * world.padtop[PAD_H], l * font->size + 2 * world.padtop[PAD_V],
        world.quests[idx].trname >= 0 && world.quests[idx].trname < world.numtext ? world.text[world.quests[idx].trname] : "",
        &hud_dst3);
    hud_dst3.x = (win_w - hud_dst3.w) / 2; hud_dst3.y = hud_itemb.y - hud_dst3.h - 4;
    hud_frm3 = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STREAMING, hud_dst3.w, hud_dst3.h);
    if(hud_frm3) {
        SDL_SetTextureBlendMode(hud_frm3, SDL_BLENDMODE_BLEND);
        SDL_LockTexture(hud_frm3, NULL, (void**)&dst, &p);
        memset(dst, 0, p * hud_dst3.h);
        ssfn_bbox(font, "A", &w, &h, &l, &t);
        ui_text(dst, hud_dst3.w, hud_dst3.h, p, ui_dl + world.padtop[PAD_H], ui_dt + world.padtop[PAD_V] + t, font, world.colors[COLOR_FG], str);
        SDL_UnlockTexture(hud_frm3);
    }
    free(str);
}

/**
 * Object description popup window
 */
void hud_object(int idx)
{
    const char *rel_types[] = { "=", "!=", ">=", ">", "<=", "<" };
    char tmp[32];
    world_sprite_t *spr;
    ssfn_t *font;
    int i, j, p, x, y, w = 0, h, t, l, r = 0, m = 0;
    uint32_t *dst;

    hud_popupclose();
    if(!world.objects || !world.attrs || !world.text || idx < 0 || idx >= world.numspr[SPR_TILE] || !world.objects[idx]) return;
    font = font_get(FNT_TXT); if(!font) return;
    if(world.objects[idx]->ammo.idx >= 0 && world.objects[idx]->ammo.idx < world.numspr[SPR_TILE]) {
        if(ssfn_bbox(font, world.text[GAME_AMMO], &p, &h, &l, &t) == SSFN_OK && w < p) w = p;
        r++;
    }
    if(world.objects[idx]->req)
        for(i = 0; i < world.objects[idx]->numreq; i++) {
            j = world.objects[idx]->req[i].attr;
            if(j >= 0 && j < world.numattrs && world.objects[idx]->req[i].type < 6 && world.attrs[j].trname >= 0 && world.attrs[j].trname < world.numtext) {
                if(ssfn_bbox(font, world.text[world.attrs[j].trname], &p, &h, &l, &t) == SSFN_OK && w < p) w = p;
                r++;
            }
        }
    if(world.objects[idx]->mod)
        for(i = 0; i < world.objects[idx]->nummod; i++) {
            j = world.objects[idx]->req[i].attr;
            if(j >= 0 && j < world.numattrs && world.attrs[j].trname >= 0 && world.attrs[j].trname < world.numtext) {
                if(ssfn_bbox(font, world.text[world.attrs[j].trname], &p, &h, &l, &t) == SSFN_OK && w < p) w = p;
                m++;
            }
        }
    if(r || m) {
        ssfn_bbox(font, ">= 000000", &p, &h, &l, &t); w += p + ui_dl + 2 * world.padtop[PAD_H] + 8;
        if(ssfn_bbox(font, world.text[GAME_REQUIRES], &p, &h, &l, &t) == SSFN_OK && w < p) w = p;
        if(ssfn_bbox(font, world.text[GAME_PROVIDES], &p, &h, &l, &t) == SSFN_OK && w < p) w = p;
    } else
        if(ssfn_bbox(font, world.text[GAME_NOMODIFY], &p, &h, &l, &t) == SSFN_OK && w < p) w = p;
    i = (r + 1 + (m ? m + 1 : 0)) * font->size + (r && m ? 3 : 2) * world.padtop[PAD_V];
    hud_win3 = ui_dlgwin(p, i, world.objects[idx]->trname >= 0 && world.objects[idx]->trname < world.numtext ?
        world.text[world.objects[idx]->trname] : "", &hud_dst3);
    hud_dst3.x = (win_w - hud_dst3.w) / 2; hud_dst3.y = hud_itemb.y - hud_dst3.h - 4;
    hud_frm3 = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STREAMING, hud_dst3.w, hud_dst3.h);
    if(hud_frm3) {
        SDL_SetTextureBlendMode(hud_frm3, SDL_BLENDMODE_BLEND);
        SDL_LockTexture(hud_frm3, NULL, (void**)&dst, &p);
        memset(dst, 0, p * hud_dst3.h);
        y = ui_dt + world.padtop[PAD_V]; x = ui_dl + 2 * world.padtop[PAD_H] + 8;
        if(!r && !m)
            ui_text(dst, hud_dst3.w, hud_dst3.h, p, (hud_dst3.w - w) / 2, y + t, font, world.colors[COLOR_FG], world.text[GAME_NOMODIFY]);
        if(r) {
            i = font->style; font->style |= SSFN_STYLE_UNDERLINE;
            ui_text(dst, hud_dst3.w, hud_dst3.h, p, ui_dl + world.padtop[PAD_H], y + t, font, world.colors[COLOR_FG], world.text[GAME_REQUIRES]);
            font->style = i;
            y += font->size;
            if(world.objects[idx]->ammo.idx >= 0 && world.objects[idx]->ammo.idx < world.numspr[SPR_TILE]) {
                ui_text(dst, hud_dst3.w, hud_dst3.h, p, x, y + t, font, world.colors[COLOR_FG], world.text[GAME_AMMO]);
                spr = world.objects[world.objects[idx]->ammo.idx] && world.objects[world.objects[idx]->ammo.idx]->invspr.idx >= 0 ?
                    spr_get(world.objects[world.objects[idx]->ammo.idx]->invspr.cat,
                        world.objects[world.objects[idx]->ammo.idx]->invspr.idx, 0) : NULL;
                spr = spr_get(world.objects[idx]->ammo.cat, world.objects[idx]->ammo.idx, 0);
                if(spr) {
                    ui_fit(2 * t, t, spr->w, spr->h, &w, &h);
                    spr_blit(dst, hud_dst3.w, hud_dst3.h, p, hud_dst3.w - ui_dr - world.padtop[PAD_H] - w, y, w, h, spr, 0, NULL);
                }
                y += font->size;
            }
            if(world.objects[idx]->req)
                for(i = 0; i < world.objects[idx]->numreq; i++) {
                    j = world.objects[idx]->req[i].attr;
                    if(world.attrs[j].trname >= 0 && world.attrs[j].trname < world.numtext) {
                        ui_text(dst, hud_dst3.w, hud_dst3.h, p, x, y + t, font, world.colors[COLOR_FG], world.text[world.attrs[j].trname]);
                        sprintf(tmp, "%s %d", rel_types[world.objects[idx]->req[i].type], world.objects[idx]->req[i].value);
                        if(ssfn_bbox(font, tmp, &w, &h, &l, &t) == SSFN_OK)
                            ui_text(dst, hud_dst3.w, hud_dst3.h, p, hud_dst3.w - ui_dr - world.padtop[PAD_H] - w, y + t, font, world.colors[COLOR_FG], tmp);
                        y += font->size;
                    }
                }
        }
        if(r && m) y += world.padtop[PAD_V];
        if(m) {
            i = font->style; font->style |= SSFN_STYLE_UNDERLINE;
            ui_text(dst, hud_dst3.w, hud_dst3.h, p, ui_dl + world.padtop[PAD_H], y + t, font, world.colors[COLOR_FG], world.text[GAME_PROVIDES]);
            font->style = i;
            y += font->size;
            for(i = 0; i < world.objects[idx]->nummod; i++) {
                j = world.objects[idx]->mod[i].attr;
                if(j >= 0 && j < world.numattrs && world.attrs[j].trname >= 0 && world.attrs[j].trname < world.numtext) {
                    ui_text(dst, hud_dst3.w, hud_dst3.h, p, x, y + t, font, world.colors[COLOR_FG], world.text[world.attrs[j].trname]);
                    sprintf(tmp, "%s%d%s", world.objects[idx]->mod[i].value >= 0 ? "+" : "", world.objects[idx]->mod[i].value, world.objects[idx]->mod[i].type  & 1 ? "%" : "");
                    if(ssfn_bbox(font, tmp, &w, &h, &l, &t) == SSFN_OK)
                        ui_text(dst, hud_dst3.w, hud_dst3.h, p, hud_dst3.w - ui_dr - world.padtop[PAD_H] - w, y + t, font, world.colors[COLOR_FG], tmp);
                    y += font->size;
                }
            }
        }
        SDL_UnlockTexture(hud_frm3);
    }
}

/**
 * Initialize HUD
 */
void hud_init()
{
    world_sprite_t *spr;
    uint32_t *dst;
    int i, j, w, h, p;

    hud_free();
    hud_w = win_w / 3;
    hud_h = win_h * 3 / 4 - 36;
    hud_navsiz = win_h - hud_h - 36 - ui_wt - ui_wb;
    memset(&hud_itemb, 0, sizeof(hud_itemb));
    memset(&hud_statb, 0, sizeof(hud_statb));
    memset(&hud_chat, 0, sizeof(hud_chat));
    spr = spr_get(world.itembarbg.cat, world.itembarbg.idx, 0);
    if(spr) { hud_itemb.w = spr->w; hud_itemb.h = spr->h; hud_itemb.x = (win_w - spr->w) / 2; hud_itemb.y = win_h - spr->h; }
    spr = spr_get(world.statusbarbg.cat, world.statusbarbg.idx, 0);
    if(!world.item_c && spr) { hud_statb.w = spr->w; hud_statb.h = spr->h; hud_statb.x = (win_w - spr->w) / 2; hud_statb.y = 0; }
    else { hud_statb.x = hud_itemb.x; hud_statb.y = hud_itemb.y; }
    /* create texture with progressbars */
    hud_enemyhp = -1;
    if(world.pbars && world.attrs && world.players && world.players[0].data.attrs) {
        for(i = w = h = 0; i < world.numpbar; i++) {
            world.pbars[i].w = 0;
            spr = spr_get(world.pbars[i].fg.cat, world.pbars[i].fg.idx, 0);
            if(spr) { h += spr->h; if(spr->w > w) w = spr->w; }
        }
        if(w > 0 && h > 0) {
            hud_pbars = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STREAMING, w, h);
            if(hud_pbars) {
                SDL_SetTextureBlendMode(hud_pbars, SDL_BLENDMODE_BLEND);
                SDL_LockTexture(hud_pbars, NULL, (void**)&dst, &p);
                memset(dst, 0, p * h);
                for(i = j = 0; i < world.numpbar; i++) {
                    spr = spr_get(world.pbars[i].fg.cat, world.pbars[i].fg.idx, 0);
                    if(spr && world.pbars[i].valueattr >= 0 && world.pbars[i].valueattr < world.numattrs &&
                      world.pbars[i].maxattr >= 0 && world.pbars[i].maxattr < world.numattrs) {
                        if(world.pbars[i].type == 3 && hud_enemyhp == -1) hud_enemyhp = i;
                        spr_blit(dst, w, h, p, 0, j, spr->w, spr->h, spr, 0, NULL);
                        world.pbars[i].y = j;
                        world.pbars[i].w = spr->w;
                        world.pbars[i].h = spr->h;
                        j += spr->h;
                    }
                }
                SDL_UnlockTexture(hud_pbars);
            }
        }
    }
    /* collect attributes which are either primary or have a translation (displayed on skills inventory tab) */
    hud_numattrs = 0;
    if(world.numattrs > 0 && world.attrs && world.players && world.numplayers > 0 && world.players[0].data.attrs) {
        hud_attrs = (int*)main_alloc(world.numattrs * sizeof(int));
        for(i = 0; i < world.numattrs; i++)
            if(world.attrs[i].type < ATTR_GLOBVAR && ((world.attrs[i].trname != -1 && world.attrs[i].trname < world.numtext &&
              world.text && world.text[world.attrs[i].trname][0]) || world.attrs[i].type == ATTR_PRI))
                hud_attrs[hud_numattrs++] = i;
    } else hud_attrs = NULL;
}

/**
 * Free resources
 */
void hud_free()
{
    if(hud_win1) { SDL_DestroyTexture(hud_win1); hud_win1 = NULL; }
    if(hud_win2) { SDL_DestroyTexture(hud_win2); hud_win2 = NULL; }
    if(hud_win3) { SDL_DestroyTexture(hud_win3); hud_win3 = NULL; }
    if(hud_frm1) { SDL_DestroyTexture(hud_frm1); hud_frm1 = NULL; }
    if(hud_frm2) { SDL_DestroyTexture(hud_frm2); hud_frm2 = NULL; }
    if(hud_frm3) { SDL_DestroyTexture(hud_frm3); hud_frm3 = NULL; }
    if(hud_pbars) { SDL_DestroyTexture(hud_pbars); hud_pbars = NULL; }
    if(hud_title) { SDL_DestroyTexture(hud_title); hud_title = NULL; }
    if(hud_attrs) { free(hud_attrs); hud_attrs = NULL; }
    if(main_scrshot) { free(main_scrshot); main_scrshot = NULL; }
    main_takescrshot = hud_numattrs = 0;
    hud_tab = HUD_NONE;
    hud_npc = hud_cft = -1;
    hud_dnd = NULL; hud_dnd_src = DND_NONE; hud_dnd_idx = -1;
}

/**
 * Display a title
 */
void hud_showtitle(char *str)
{
    ssfn_t *font;
    uint32_t *dst, a;
    int p, l, t, i, j;

    if(!str || !*str) return;
    if(hud_title) { SDL_DestroyTexture(hud_title); hud_title = NULL; }
    memset(&hud_titleb, 0, sizeof(hud_titleb));
    font = font_get(FNT_TABN);
    if(font && ssfn_bbox(font, str, &hud_titleb.w, &hud_titleb.h, &l, &t) == SSFN_OK) {
        hud_titleb.w += l + 2 * font->size; hud_titleb.h += 4; font->style &= ~SSFN_STYLE_A;
        hud_title = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STREAMING, hud_titleb.w, hud_titleb.h);
        if(hud_title) {
            SDL_SetTextureBlendMode(hud_title, SDL_BLENDMODE_BLEND);
            SDL_LockTexture(hud_title, NULL, (void**)&dst, &p);
            for(i = 0; i <= hud_titleb.w / 2; i++) {
                a = (i * 3 < 0xcf ? i * 3 : 0xcf) << 24;
                for(j = 0; j < hud_titleb.h; j++)
                    dst[j * hud_titleb.w + i] = dst[j * hud_titleb.w + hud_titleb.w - 1 - i] = a;
            }
            ui_text(dst, hud_titleb.w, hud_titleb.h, p, font->size, t + 2, font, 0xFFC0C0C0, str);
            /* show twice as long as normal alerts */
            hud_dt = world.alert_dt * 20; hud_fo = hud_dt - ((world.alert_dt - world.alert_fo) * 10);
            SDL_UnlockTexture(hud_title);
            hud_titlefade = main_tick;
        }
    }
}

/**
 * Open an NPC's inventory for exchange
 */
void hud_market(int npc)
{
    int i, t;

    if(npc >= 0 && npc < game_scene.numnpc && game_scene.npc) {
        hud_npc = npc; t = game_scene.npc[npc].type;
        hud_sell_bc = hud_buy_bc = NULL;
        hud_sell_bclen = hud_buy_bclen = hud_sell_tng = hud_buy_tng = 0;
        hud_switch(HUD_MARKET, 0);
        if(world.npctypes && t >= 0 && t < world.numnpc && world.npctypes[t].evt)
            for(i = 0; i < world.npctypes[t].numevt; i++) {
                if(world.npctypes[t].evt[i].type == EVT_ONSELL) {
                    hud_sell_bc = world.npctypes[t].evt[i].bc;
                    hud_sell_bclen = world.npctypes[t].evt[i].bclen;
                    hud_sell_tng = world.npctypes[t].evt[i].tng;
                }
                if(world.npctypes[t].evt[i].type == EVT_ONBUY) {
                    hud_buy_bc = world.npctypes[t].evt[i].bc;
                    hud_buy_bclen = world.npctypes[t].evt[i].bclen;
                    hud_buy_tng = world.npctypes[t].evt[i].tng;
                }
            }
    }
}

/**
 * Open a crafting dialog
 */
void hud_craft(int craft)
{
    if(craft >= 0 && craft < world.numcft) {
        hud_cft = craft;
        hud_switch(HUD_CRAFT, 0);
    }
}

/**
 * Controller
 * Return values:
 * 1: event parsed
 * 0: quit game
 * -1: pass event to game_ctrl()
 */
int hud_ctrl()
{
    world_sprite_t *spr;
    SDL_Rect src;
    int i, j, k, w, h;

    if(hud_tab == HUD_CHAT) {
        if(ui_input_ctrl() == 2 && hud_chat[4] && hud_chat[5]) {
            if(hud_chat[4] == '/') {
                if(verbose > 2) printf("tngp: chat command '%s'\n", hud_chat + 4);
                /* TODO: maybe parse special chat commands */
            } else
            if(world.hdr.magic[0] != '#') {
                i = strlen(hud_chat + 4);
                if(hud_chat[3 + i] == '"') { hud_chat[3 + i] = 0; i--; }
                if(verbose > 2) printf("tngp: chat message '%s'\n", hud_chat + (hud_chat[4] == '"' ? 5 : 4));
                client_send(12, (uint8_t*)hud_chat, 4 + i);
            }
        }
        if(!ui_input_str) { hud_switch(HUD_NONE, 0); memset(&hud_chat, 0, sizeof(hud_chat)); }
        return 1;
    }
    switch(event.type) {
        case SDL_TEXTINPUT:
            if(hud_tab == HUD_NONE && (event.text.text[0] < '0' || event.text.text[0] > '9') && world.hdr.magic[0] != '#') {
                hud_switch(HUD_CHAT, 0);
                if(event.text.text[0] != ' ') ui_input_addkey((char*)&event.text.text);
            }
            return 1;
        break;
        case SDL_KEYDOWN:
            ui_input_gp &= ~1;
            if(hud_win3 && (hud_tab == HUD_INV || (hud_tab > HUD_INV && hud_invtab == 2))) { hud_popupclose(); return 1; }
            switch(event.key.keysym.sym) {
                case SDLK_AC_BACK:
                case SDLK_F10:
                case SDLK_BACKSPACE:
                case SDLK_ESCAPE:
hudmenu:            if(hud_tab != HUD_NONE && hud_win3) hud_popupclose();
                    else hud_switch(hud_tab != HUD_NONE ? HUD_NONE : HUD_MENU, 0);
                    return 1;
                break;
                case SDLK_TAB:
hudinv:             if(hud_tab >= HUD_INV) {
                        if(hud_tab > HUD_INV && !hud_invtab && !hud_focus) { hud_focus = 1; hud_redraw(); }
                        else if(hud_tab == HUD_INV && hud_focus == -1) { hud_focus = 0; hud_sel1 = hud_scr1; hud_redraw(); }
                        else { hud_focus = 0; hud_switch(hud_tab, hud_invtab + 1); }
                        return 1;
                    }
                    if(hud_tab == HUD_NONE) { hud_switch(HUD_INV, 0); return 1; }
                break;
                case SDLK_0: hud_npc = 0; hud_switch(HUD_MARKET, 0); break;
                case SDLK_UP:
up:                 switch(hud_tab) {
                        case HUD_NONE: break;
                        case HUD_MENU:
                            if(hud_sel1 > 0) hud_sel1--; else hud_sel1 = hud_max1;
#ifdef __EMSCRIPTEN__
                            if(hud_sel1 == 3) hud_sel1--;
#endif
                            media_playsel();
                            hud_redraw();
                            return 1;
                        break;
                        default:
                            if(hud_focus == 1) {
                                if(hud_sel2 > 0) { hud_sel2 -= hud_line2; media_playsel(); }
                                if(hud_sel2 < 0) hud_sel2 = 0;
                                if(hud_scr2 > hud_sel2) hud_scr2 = (hud_sel2 / hud_line2) * hud_line2;
                            } else
                            if(hud_invtab == 0 || (hud_invtab == 1 && hud_focus == 0)) {
                                if(hud_sel1 > 0) { hud_sel1 -= hud_line1; media_playsel(); }
                                if(hud_sel1 < 0) hud_sel1 = 0;
                                if(hud_scr1 > hud_sel1) hud_scr1 = (hud_sel1 / hud_line1) * hud_line1;
                            } else {
                                if(hud_sel1 > 0) { hud_sel1--; media_playsel(); }
                                if(hud_scr1 > hud_sel1) hud_scr1 = hud_sel1;
                            }
                            hud_redraw();
                            return 1;
                        break;
                    }
                break;
                case SDLK_DOWN:
down:               switch(hud_tab) {
                        case HUD_NONE: break;
                        case HUD_MENU:
                            if(hud_sel1 < hud_max1) hud_sel1++; else hud_sel1 = 0;
#ifdef __EMSCRIPTEN__
                            if(hud_sel1 == 3) hud_sel1++;
#endif
                            media_playsel();
                            hud_redraw();
                            return 1;
                        break;
                        default:
                            if(hud_focus == 1) {
                                i = (hud_items2.h / (ui_slots + 2)) * hud_line2;
                                if(hud_sel2 < hud_max2) { hud_sel2 += hud_line2; media_playsel(); }
                                if(hud_sel2 > hud_max2) hud_sel2 = hud_max2;
                                if(hud_scr2 < hud_sel2 - i) hud_scr2 = (hud_sel2 / hud_line2) * hud_line2 - i;
                            } else
                            if(hud_invtab == 0 || (hud_invtab == 1 && hud_focus == 0)) {
                                i = (hud_items1.h / (ui_slots + 2)) * hud_line1;
                                if(hud_sel1 < hud_max1) { hud_sel1 += hud_line1; media_playsel(); }
                                if(hud_sel1 > hud_max1) hud_sel1 = hud_max1;
                                if(hud_scr1 < hud_sel1 - i) hud_scr1 = (hud_sel1 / hud_line1) * hud_line1 - i;
                            } else {
                                i = (hud_items1.h / (ui_slots + 2));
                                if(hud_sel1 < hud_max1) { hud_sel1++; media_playsel(); }
                                if(hud_scr1 < hud_sel1 - i) hud_scr1 = hud_sel1 - i;
                            }
                            hud_redraw();
                            return 1;
                        break;
                    }
                break;
                case SDLK_LEFT:
left:               switch(hud_tab) {
                        case HUD_NONE: break;
                        case HUD_MENU:
                            switch(hud_sel1) {
                                case 0: if(main_musvol > 0) { main_musvol--; } media_chime(main_musvol); break;
                                case 1: if(main_sfxvol > 0) { main_sfxvol--; } media_chime(main_sfxvol); break;
                                case 2: if(main_spcvol > 0) { main_spcvol--; } media_chime(main_spcvol); break;
                            }
                            hud_redraw();
                            return 1;
                        break;
                        default:
                            if(hud_focus == 1) {
                                if(hud_sel2 > 0) { hud_sel2--; media_playsel(); }
                                if(hud_scr2 > hud_sel2) hud_scr2 = (hud_sel2 / hud_line2) * hud_line2;
                            } else
                            if(hud_invtab == 0 || (hud_invtab == 1 && hud_focus == 0)) {
                                if(hud_sel1 > 0) { hud_sel1--; media_playsel(); }
                                if(hud_scr1 > hud_sel1) hud_scr1 = (hud_sel1 / hud_line1) * hud_line1;
                            }
                            hud_redraw();
                            return 1;
                        break;
                    }
                break;
                case SDLK_RIGHT:
right:              switch(hud_tab) {
                        case HUD_NONE: break;
                        case HUD_MENU:
                            switch(hud_sel1) {
                                case 0: if(main_musvol < MIX_MAX_VOLUME) { main_musvol++; } media_chime(main_musvol); break;
                                case 1: if(main_sfxvol < MIX_MAX_VOLUME) { main_sfxvol++; } media_chime(main_sfxvol); break;
                                case 2: if(main_spcvol < MIX_MAX_VOLUME) { main_spcvol++; } media_chime(main_spcvol); break;
                            }
                            hud_redraw();
                            return 1;
                        break;
                        default:
                            if(hud_focus == 1) {
                                i = (hud_items2.h / (ui_slots + 2)) * hud_line2;
                                if(hud_sel2 < hud_max2) { hud_sel2++; media_playsel(); }
                                if(hud_scr2 < hud_sel2 - i) hud_scr2 = (hud_sel2 / hud_line2) * hud_line2 - i;
                            } else
                            if(hud_invtab == 0 || (hud_invtab == 1 && hud_focus == 0)) {
                                i = (hud_items1.h / (ui_slots + 2)) * hud_line1;
                                if(hud_sel1 < hud_max1) { hud_sel1++; media_playsel(); }
                                if(hud_scr1 < hud_sel1 - i) hud_scr1 = (hud_sel1 / hud_line1) * hud_line1 - i;
                            }
                            hud_redraw();
                            return 1;
                        break;
                    }
                break;
                case SDLK_SPACE:
guide:              if(hud_tab == HUD_INV) {
                        switch(hud_invtab) {
                            case 0:
                                if(world.players && world.players[0].data.inv && world.objects &&
                                  hud_sel1 >= 0 && hud_sel1 < world.players[0].data.numinv &&
                                  world.players[0].data.inv[hud_sel1].obj.idx >= 0 &&
                                  world.players[0].data.inv[hud_sel1].obj.idx < world.numspr[SPR_TILE] &&
                                  world.objects[world.players[0].data.inv[hud_sel1].obj.idx]) {
                                    media_playclk();
                                    hud_object(world.players[0].data.inv[hud_sel1].obj.idx);
                                }
                            break;
                            case 1:
                                if(!hud_focus && world.players && world.players[0].data.skills && world.objects &&
                                  hud_sel1 >= 0 && hud_sel1 < world.players[0].data.numskl &&
                                  world.players[0].data.skills[hud_sel1].obj.idx >= 0 &&
                                  world.players[0].data.skills[hud_sel1].obj.idx < world.numspr[SPR_TILE] &&
                                  world.objects[world.players[0].data.skills[hud_sel1].obj.idx]) {
                                    media_playclk();
                                    hud_object(world.players[0].data.skills[hud_sel1].obj.idx);
                                }
                            break;
                            case 2:
                                if(world.players && world.players[0].data.quests && world.quests &&
                                  hud_sel1 >= 0 && hud_sel1 < world.players[0].data.numqst) {
                                    media_playclk();
                                    hud_quest(world.players[0].data.quests[hud_sel1 * 2 + 1]);
                                }
                            break;
                        }
                        hud_redraw();
                        return 1;
                    }
                break;
                case SDLK_RCTRL:
                case SDLK_RETURN:
selpress:           switch(hud_tab) {
                        case HUD_NONE:
                            if(world.players && world.players[0].equip[0] < world.numspr[SPR_TILE]) {
                                game_useitem(world.players[0].equip[0], -1);
                                return 1;
                            }
                        break;
                        case HUD_MENU:
#ifdef __EMSCRIPTEN__
                            if(hud_sel1 != 3)
#endif
                            {
                                if(hud_sel1 > 2) { hud_p = 1; media_playclk(); }
                                hud_redraw();
                            }
                            return 1;
                        break;
                        default:
itemclk:                    switch(hud_invtab) {
                                case 0:
                                    if(world.players && world.players[0].data.inv && world.objects &&
                                      hud_sel1 >= 0 && hud_sel1 < world.players[0].data.numinv &&
                                      world.players[0].data.inv[hud_sel1].obj.idx >= 0 &&
                                      world.players[0].data.inv[hud_sel1].obj.idx < world.numspr[SPR_TILE] &&
                                      world.objects[world.players[0].data.inv[hud_sel1].obj.idx]) {
                                        i = world.players[0].data.inv[hud_sel1].obj.idx;
                                        switch(hud_tab) {
                                            case HUD_INV:
equip:                                          if(i >= 0 && i < world.numspr[SPR_TILE] &&
                                                  world.objects[i]->eqmask > 0 && world.objects[i]->eqmask != 0xffffffff) {
                                                    for(j = 0, k = 1; j < 31 && !(world.objects[i]->eqmask & k); j++, k <<= 1);
                                                    if(world.players[0].equip[j] == i) {
                                                        /* unequip */
                                                        for(j = 0; j < 32; j++)
                                                            if(world.players[0].equip[j] == i)
                                                                world.players[0].equip[j] = -1;
                                                        media_playinv(i);
                                                    } else {
                                                        /* check if player can equip this item */
                                                        w = 1;
                                                        if(world.objects[i]->req)
                                                            for(k = 0; w && k < world.objects[i]->numreq; k++) {
                                                                j = world.objects[i]->req[k].attr;
                                                                if(j >= 0 && j < world.numattrs)
                                                                    switch(world.objects[i]->req[k].type) {
                                                                        case REL_EQ: w &= (world.players[0].data.attrs[world.attrs[j].idx] == world.objects[i]->req[k].value); break;
                                                                        case REL_NE: w &= (world.players[0].data.attrs[world.attrs[j].idx] != world.objects[i]->req[k].value); break;
                                                                        case REL_GE: w &= (world.players[0].data.attrs[world.attrs[j].idx] >= world.objects[i]->req[k].value); break;
                                                                        case REL_GT: w &= (world.players[0].data.attrs[world.attrs[j].idx] > world.objects[i]->req[k].value); break;
                                                                        case REL_LE: w &= (world.players[0].data.attrs[world.attrs[j].idx] <= world.objects[i]->req[k].value); break;
                                                                        case REL_LT: w &= (world.players[0].data.attrs[world.attrs[j].idx] < world.objects[i]->req[k].value); break;
                                                                    }
                                                            }
                                                        if(w) {
                                                            /* make room */
                                                            for(j = 0, k = 1; j < 32; j++, k <<= 1)
                                                                if(world.objects[i]->eqmask & k) {
                                                                    w = world.players[0].equip[j];
                                                                    for(h = 0; h < 32; h++)
                                                                        if(world.players[0].equip[h] == w)
                                                                            world.players[0].equip[h] = -1;
                                                                }
                                                            /* equip */
                                                            for(j = 0, k = 1; j < 32; j++, k <<= 1)
                                                                if(world.objects[i]->eqmask & k)
                                                                    world.players[0].equip[j] = i;
                                                            media_playinv(i);
                                                        } else
                                                            media_playerr();
                                                    }
                                                } else
                                                    media_playerr();
                                            break;
                                            case HUD_MARKET:
                                                if(hud_focus == 1 && hud_sell_bc && hud_sell_bclen > 0) {
                                                    media_playclk();
                                                    printf("buy\n");
                                                    hud_qty(0);
                                                } else
                                                if(hud_buy_bc && hud_buy_bclen > 0 && world.objects[i]->price != 0 &&
                                                  world.objects[i]->unit.idx >= 0 && world.objects[i]->unit.idx < world.numspr[SPR_TILE]) {
                                                    media_playclk();
                                                    i = script_load(SCRIPT_CALLERFUNC(SCRIPT_OBJ, i, EVT_ONSELL),
                                                        hud_buy_bc, hud_buy_bclen, hud_buy_tng, &game_scene.npc[hud_npc].data,
                                                        &world.players[0].data);
                                                    if(i > SCRIPT_AGAIN && i) {
                                                        printf("sell\n");
                                                        hud_qty(1);
                                                    } else
                                                        media_playerr();
                                                } else
                                                    media_playerr();
                                            break;
                                            case HUD_CRAFT:
                                            break;
                                        }
                                    }
                                break;
                                case 1:
                                    if(hud_tab == HUD_INV && hud_focus == -1 && hud_rem > 0 && hud_sel1 >= 0 && hud_sel1 < hud_numattrs &&
                                      world.attrs[hud_attrs[hud_sel1]].type == ATTR_PRI) {
                                        hud_p = 1; media_playclk();
                                    }
                                break;
                                case 2:
                                    if(world.players && world.players[0].data.quests && world.quests &&
                                      hud_sel1 >= 0 && hud_sel1 < world.players[0].data.numqst) {
                                        media_playclk();
                                        hud_quest(world.players[0].data.quests[hud_sel1 * 2 + 1]);
                                    }
                                break;
                            }
                            hud_redraw();
                            return 1;
                        break;
                    }
                break;
                case SDLK_1: case SDLK_2: case SDLK_3: case SDLK_4: case SDLK_5: case SDLK_6: case SDLK_7: case SDLK_8: case SDLK_9:
                    i = event.key.keysym.sym - SDLK_1;
itembar:            if(i >= 0 && i < 32 && i < world.item_n) {
                        if(hud_tab == HUD_INV) {
                            /* assign objects to belt */
                            k = -1;
                            switch(hud_invtab) {
                                case 0:
                                    if(world.players && world.players[0].data.inv && world.objects &&
                                      hud_sel1 >= 0 && hud_sel1 < world.players[0].data.numinv &&
                                      world.players[0].data.inv[hud_sel1].obj.idx >= 0 &&
                                      world.players[0].data.inv[hud_sel1].obj.idx < world.numspr[SPR_TILE] &&
                                      world.objects[world.players[0].data.inv[hud_sel1].obj.idx]) {
                                        k = hud_sel1;
                                        media_playinv(world.players[0].data.inv[hud_sel1].obj.idx);
                                    }
                                break;
                                case 1:
                                    if(world.players && world.players[0].data.skills && world.objects &&
                                      hud_sel1 >= 0 && hud_sel1 < world.players[0].data.numskl &&
                                      world.players[0].data.skills[hud_sel1].obj.idx >= 0 &&
                                      world.players[0].data.skills[hud_sel1].obj.idx < world.numspr[SPR_TILE] &&
                                      world.objects[world.players[0].data.skills[hud_sel1].obj.idx]) {
                                        k = 0xffffff + hud_sel1;
                                        media_playinv(world.players[0].data.skills[hud_sel1].obj.idx);
                                    }
                                break;
                            }
                            for(j = 0; j < 32; j++)
                                if(world.players[0].belt[j] == (uint16_t)k) world.players[0].belt[j] = 0xffff;
                            world.players[0].belt[i] = k;
                        } else {
                            if(world.players[0].belt[i] != 0xffff) {
                                game_useitem(world.players[0].belt[i] < 0x8000 ? world.players[0].data.inv[world.players[0].belt[i]].obj.idx :
                                    world.players[0].data.skills[world.players[0].belt[i] & 0x7fff].obj.idx, i);
                            }
                        }
                        hud_redraw();
                        return 1;
                    }
                break;
                case SDLK_LGUI: if(hud_tab == HUD_NONE) { media_mic_start(); } return 1;
                default:
                    /* should not get here normally, as we should get an SDL_TEXTINPUT event instead */
                    if(hud_tab == HUD_NONE && !ui_input_cnt && event.key.keysym.sym >= 32 && event.key.keysym.sym < 127 &&
                      world.hdr.magic[0] != '#') {
                        SDL_StartTextInput(); ui_input_cnt++;
                        hud_switch(HUD_CHAT, 0);
                        return 1;
                    }
                break;
            }
        break;
        case SDL_KEYUP:
            ui_input_gp &= ~1;
            switch(event.key.keysym.sym) {
                case SDLK_RETURN:
dosel:              hud_dnd = NULL; hud_dnd_src = DND_NONE; hud_dnd_idx = -1;
                    switch(hud_tab) {
                        case HUD_MENU:
                            switch(hud_sel1) {
#ifndef __EMSCRIPTEN__
                                case 3:
                                    if(world.hdr.magic[0] == '#') {
                                        main_savegame(); hud_switch(HUD_NONE, 0);
                                    } else hud_switch(HUD_CHAT, 0);
                                break;
#endif
                                case 4: hud_p = 0; hud_redraw(); game_fadeout(); break;
                            }
                            return 1;
                        break;
                        case HUD_INV:
                            if(hud_focus == -1 && hud_rem > 0 && hud_sel1 >= 0 && hud_sel1 < hud_numattrs &&
                              world.attrs[hud_attrs[hud_sel1]].type == ATTR_PRI) {
                                hud_p = 0;
                                script_setattr(&world.players[0].data, world.engattr[ENG_LVLUP],
                                    world.players[0].data.attrs[world.attrs[world.engattr[ENG_LVLUP]].idx] - 1);
                                script_setattr(&world.players[0].data, hud_attrs[hud_sel1],
                                    world.players[0].data.attrs[world.attrs[hud_attrs[hud_sel1]].idx] + 1);
                                hud_redraw();
                                return 1;
                            }
                        break;
                    }
                break;
                case SDLK_LGUI: media_mic_stop(); return 1;
            }
        break;
        case SDL_MOUSEMOTION:
            ui_input_gp &= ~1; hud_clk = 0;
            if(hud_win1) {
                if(hud_tab == HUD_MENU) {
                    if(hud_vp) {
                        i = hud_dst1.x + ui_wl + 2 * world.padtop[PAD_H] + 16;
                        *hud_vp = (event.motion.x - i - ui_sldb / 2) * MIX_MAX_VOLUME / (255 - ui_sldb);
                        if(*hud_vp < 0) *hud_vp = 0;
                        if(*hud_vp > MIX_MAX_VOLUME) *hud_vp = MIX_MAX_VOLUME;
                        hud_redraw();
                    } else
                    if(!hud_p && event.button.x >= hud_dst1.x && event.button.x < hud_dst1.x + hud_dst1.w &&
                      event.button.y >= hud_dst1.y + ui_wt + world.padtop[PAD_V] && event.button.y < hud_dst1.y + hud_dst1.h) {
                        if(event.button.y < hud_dst1.y + ui_wt + world.padtop[PAD_V] + 3 * (world.padtop[PAD_V] + ui_lineh))
                            i = (event.button.y - hud_dst1.y - ui_wt - world.padtop[PAD_V]) / (world.padtop[PAD_V] + ui_lineh);
                        else
                            i = (event.button.y - hud_dst1.y - ui_wt - world.padtop[PAD_V] - 3 * (world.padtop[PAD_V] + ui_lineh)) /
                                (world.padtop[PAD_V] + ui_btnh) + 3;
                        if(i != hud_sel1 && i <= hud_max1) { media_playsel(); hud_sel1 = i; hud_redraw(); }
                    }
                }
            }
            if(hud_btn && !hud_dnd && hud_dnd_src != DND_NONE && hud_dnd_idx >= 0 && hud_dnd_idx < world.numspr[SPR_TILE]) {
                hud_dnd = world.objects && world.objects[hud_dnd_idx] && world.objects[hud_dnd_idx]->invspr.idx >= 0 ?
                    spr_get(world.objects[hud_dnd_idx]->invspr.cat, world.objects[hud_dnd_idx]->invspr.idx, 0) : NULL;
                if(!hud_dnd) hud_dnd = spr_get(SPR_TILE, hud_dnd_idx, 0);
                if(hud_dnd) ui_fit(world.inv_w, world.inv_h, hud_dnd->w, hud_dnd->h, &hud_dnd_w, &hud_dnd_h);
                else { hud_dnd_src = DND_NONE; hud_dnd_idx = -1; }
            } else
            if(!hud_btn) { hud_dnd = NULL; hud_dnd_src = DND_NONE; hud_dnd_idx = -1; }
        break;
        case SDL_MOUSEBUTTONDOWN:
            ui_input_gp &= ~1; hud_btn = 1; hud_navx = hud_navy = 0;
            if(hud_win3 && (hud_tab == HUD_INV || (hud_tab > HUD_INV && hud_invtab == 2))) { hud_popupclose(); return 1; }
            if(event.button.x < 32 && event.button.y < 32) {
                if(hud_tab != HUD_MENU) hud_switch(HUD_MENU, 0); else hud_switch(HUD_NONE, 0);
                return 1;
            } else
            if(event.button.x > win_w - 32 && event.button.y < 32) {
                if(hud_tab != HUD_INV) hud_switch(HUD_INV, 0); else hud_switch(HUD_NONE, 0);
                return 1;
            } else
            if(hud_win3) {
                if(event.button.x >= hud_dst3.x && event.button.x < hud_dst3.x + hud_dst3.w &&
                  event.button.y >= hud_dst3.y + ui_wt && event.button.y < hud_dst3.y + hud_dst3.h) {
                    printf("qty window\n");
                } else
                    hud_popupclose();
                return 1;
            } else
            if(hud_win1 && hud_tab == HUD_MENU) {
                if(event.button.x >= hud_dst1.x && event.button.x < hud_dst1.x + hud_dst1.w &&
                  event.button.y >= hud_dst1.y + ui_wt && event.button.y < hud_dst1.y + hud_dst1.h) {
                    i = hud_dst1.x + ui_wl + 2 * world.padtop[PAD_H] + 16; hud_vp = NULL;
                    switch(hud_sel1) {
                        case 0: if(event.button.x >= i && event.button.x <= i + 255) hud_vp = &main_musvol; break;
                        case 1: if(event.button.x >= i && event.button.x <= i + 255) hud_vp = &main_sfxvol; break;
                        case 2: if(event.button.x >= i && event.button.x <= i + 255) hud_vp = &main_spcvol; break;
#ifndef __EMSCRIPTEN__
                        case 3:
#endif
                        case 4: media_playclk(); hud_p = 1; hud_redraw(); break;
                    }
                    if(hud_vp) {
                        *hud_vp = (event.motion.x - i - ui_sldb / 2) * MIX_MAX_VOLUME / (255 - ui_sldb);
                        if(*hud_vp < 0) *hud_vp = 0;
                        if(*hud_vp > MIX_MAX_VOLUME) *hud_vp = MIX_MAX_VOLUME;
                        hud_redraw();
                    }
                } else
                    hud_switch(HUD_NONE, 0);
                return 1;
            } else
            if(hud_win1 && hud_tab >= HUD_INV) {
                if(event.button.x >= hud_itemb.x && event.button.x < hud_itemb.x + hud_itemb.w &&
                  event.button.y >= hud_itemb.y && event.button.y < hud_itemb.y + hud_itemb.h && world.players) {
                    src.x = hud_itemb.x + world.item_l; src.y = hud_itemb.y + world.item_t;
                    for(i = 0; i < world.item_n; i++) {
                        if(event.button.x >= src.x && event.button.x < src.x + world.item_w &&
                          event.button.y >= src.y && event.button.y < src.y + world.item_h && world.players[0].belt[i] != 0xffff) {
                            hud_dnd_src = DND_ITEMBAR;
                            hud_dnd_idx = world.players[0].belt[i] < 0x8000 && world.players[0].data.inv ?
                                world.players[0].data.inv[world.players[0].belt[i]].obj.idx : (
                                world.players[0].belt[i] != 0xffff && world.players[0].data.skills ?
                                world.players[0].data.skills[world.players[0].belt[i] & 0x7fff].obj.idx : -1);
                            hud_dnd_i = i;
                            break;
                        }
                        src.x += world.item_w + world.item_g;
                    }
                    src.x += world.item_p;
                    if(event.button.x >= src.x && event.button.x < src.x + world.item_w &&
                      event.button.y >= src.y && event.button.y < src.y + world.item_h) {
                        hud_dnd_src = DND_EQUIP; hud_dnd_idx = world.players[0].equip[0]; hud_dnd_i = 0;
                    }
                } else
                if(event.button.x >= hud_dst1.x && event.button.x < hud_dst1.x + hud_dst1.w &&
                  event.button.y >= hud_dst1.y && event.button.y < hud_dst1.y + hud_dst1.h) {
                    if(hud_focus == 1) hud_focus = 0;
                    if(event.button.y < hud_dst1.y + ui_wt) {
                        for(i = 0; i < 3; i++)
                            if(event.button.x >= hud_dst1.x + hud_tabx[i] && event.button.x < hud_dst1.x + hud_tabx[i + 1]) {
                                hud_switch(hud_tab, i);
                                return 1;
                            }
                        hud_switch(HUD_NONE, 0);
                        return 1;
                    } else {
                        switch(hud_invtab) {
                            case 0:
                                if(event.button.x >= hud_equip.x && event.button.x < hud_equip.x + hud_equip.w &&
                                  event.button.y >= hud_equip.y && event.button.y < hud_equip.y + hud_equip.h && hud_equip.h > 0) {
                                    spr = spr_get(world.equipimg.cat, world.equipimg.idx, 0);
                                    if(spr) { src.w = spr->w; src.h = spr->h; } else { src.w = hud_equip.w; src.h = hud_equip.h; }
                                    w = world.inv_w * hud_equip.w / src.w; h = world.inv_h * hud_equip.h / src.h;
                                    for(i = 0; i < 32; i++)
                                        if(world.players[0].equip[i] < world.numspr[SPR_TILE]) {
                                            src.x = hud_equip.x + world.equippos[i * 2 + 0] * hud_equip.w / src.w;
                                            src.y = hud_equip.y + world.equippos[i * 2 + 1] * hud_equip.h / src.h;
                                            if(event.button.x >= src.x && event.button.x < src.x + w &&
                                              event.button.y >= src.y && event.button.y < src.y + h) {
                                                if(event.button.button == SDL_BUTTON_RIGHT) {
                                                    media_playclk();
                                                    hud_object(world.players[0].data.inv[world.players[0].equip[i]].obj.idx);
                                                } else {
                                                    hud_dnd_src = DND_EQUIP; hud_dnd_idx = world.players[0].equip[i]; hud_dnd_i = i;
                                                }
                                                break;
                                            }
                                        }
                                }
                                if(event.button.x >= hud_items1.x && event.button.x < hud_items1.x + hud_items1.w &&
                                  event.button.y >= hud_items1.y && event.button.y < hud_items1.y + hud_items1.h && world.players &&
                                  world.players[0].data.inv) {
                                    i = (hud_scr1 + (event.button.y - hud_items1.y) / (ui_slots + 2)) * hud_line1 +
                                        (event.button.x - hud_items1.x) / (ui_slots + 2);
                                    if(i < world.players[0].data.numinv) {
                                        if(event.button.button == SDL_BUTTON_RIGHT) {
                                            media_playclk();
                                            hud_object(world.players[0].data.inv[i].obj.idx);
                                        } else {
                                            if(hud_clk == 1) {
                                                hud_sel1 = i;
                                                hud_dnd = NULL; hud_dnd_src = DND_NONE; hud_dnd_idx = hud_clk = -1;
                                                goto itemclk;
                                            } else {
                                                media_playclk();
                                                hud_dnd_idx = world.players[0].data.inv[i].obj.idx;
                                                hud_dnd_src = DND_INV; hud_dnd_i = hud_sel1 = i;
                                                hud_redraw();
                                            }
                                        }
                                    }
                                }
                            break;
                            case 1:
                                if(event.button.x >= hud_items1.x && event.button.x < hud_items1.x + hud_items1.w &&
                                  event.button.y >= hud_items1.y && event.button.y < hud_items1.y + hud_items1.h && world.players &&
                                  world.players[0].data.skills) {
                                    i = (hud_scr1 + (event.button.y - hud_items1.y) / (ui_slots + 2)) * hud_line1 +
                                        (event.button.x - hud_items1.x) / (ui_slots + 2);
                                    if(i < world.players[0].data.numskl) {
                                        media_playclk();
                                        if(event.button.button == SDL_BUTTON_RIGHT) {
                                            hud_object(world.players[0].data.skills[i].obj.idx);
                                        } else {
                                            hud_dnd_idx = world.players[0].data.skills[i].obj.idx;
                                            hud_dnd_src = DND_INV; hud_dnd_i = hud_sel1 = i;
                                            hud_redraw();
                                        }
                                    }
                                }
                            break;
                            case 2:
                                if(event.button.x >= hud_items1.x && event.button.x < hud_items1.x + hud_items1.w &&
                                  event.button.y >= hud_items1.y && event.button.y < hud_items1.y + hud_items1.h && world.players &&
                                  world.players[0].data.quests) {
                                    i = (hud_scr1 + (event.button.y - hud_items1.y) / (ui_lineh + 2));
                                    if(i < world.players[0].data.numqst) {
                                        media_playclk();
                                        hud_quest(world.players[0].data.quests[i * 2 + 1]);
                                    }
                                }
                            break;
                        }
                    }
                } else
                if(hud_win2 && event.button.x >= hud_dst2.x && event.button.x < hud_dst2.x + hud_dst2.w &&
                  event.button.y >= hud_dst2.y + ui_wt && event.button.y < hud_dst2.y + hud_dst2.h) {
                    hud_focus = 1;
                    printf("other win click\n");
                } else
                    hud_switch(HUD_NONE, 0);
                return 1;
            } else
            if(hud_tab == HUD_NONE && world.players && event.button.x >= hud_itemb.x && event.button.x < hud_itemb.x + hud_itemb.w &&
              event.button.y >= hud_itemb.y && event.button.y < hud_itemb.y + hud_itemb.h) {
                src.x = hud_itemb.x + world.item_l; src.y = hud_itemb.y + world.item_t;
                for(i = 0; i < world.item_n; i++) {
                    if(event.button.x >= src.x && event.button.x < src.x + world.item_w &&
                      event.button.y >= src.y && event.button.y < src.y + world.item_h) {
                        if(world.players[0].belt[i] != 0xffff) {
                            game_useitem(world.players[0].belt[i] < 0x8000 ? world.players[0].data.inv[world.players[0].belt[i]].obj.idx :
                                world.players[0].data.skills[world.players[0].belt[i] & 0x7fff].obj.idx, i);
                        }
                        src.x = win_w;
                        break;
                    }
                    src.x += world.item_w + world.item_g;
                }
                src.x += world.item_p;
                if(event.button.x >= src.x && event.button.x < src.x + world.item_w &&
                  event.button.y >= src.y && event.button.y < src.y + world.item_h &&
                  world.players[0].equip[0] < world.numspr[SPR_TILE]) {
                    game_useitem(world.players[0].equip[0], -1);
                }
            }
            if(touch) {
                i = hud_navsiz / 3;
                if(event.button.x >= win_w - i - i && event.button.x < win_w - i &&
                  event.button.y >= win_h - hud_navsiz && event.button.y < win_h - i - i) {
                    i = 2; goto itembar;
                } else
                if(event.button.x >= win_w - hud_navsiz && event.button.x < win_w - i - i &&
                  event.button.y >= win_h - i - i && event.button.y < win_h - i) {
                    i = 1; goto itembar;
                } else
                if(event.button.x >= win_w - i && event.button.x < win_w &&
                  event.button.y >= win_h - i - i && event.button.y < win_h - i) {
                    goto selpress;
                } else
                if(event.button.x >= win_w - i - i && event.button.x < win_w - i &&
                  event.button.y >= win_h - i && event.button.y < win_h) {
                    i = 0; goto itembar;
                }
            }
        break;
        case SDL_MOUSEBUTTONUP:
            ui_input_gp &= ~1; hud_btn = 0; hud_clk++;
            if(hud_dnd && hud_dnd_idx >= 0 && hud_dnd_idx < world.numspr[SPR_TILE]) {
                if(event.button.x >= hud_itemb.x && event.button.x < hud_itemb.x + hud_itemb.w &&
                  event.button.y >= hud_itemb.y && event.button.y < hud_itemb.y + hud_itemb.h) {
                    src.x = hud_itemb.x + world.item_l; src.y = hud_itemb.y + world.item_t;
                    for(i = 0; i < world.item_n; i++) {
                        if(event.button.x >= src.x && event.button.x < src.x + world.item_w &&
                          event.button.y >= src.y && event.button.y < src.y + world.item_h) {
                            k = -1;
                            switch(hud_dnd_src) {
                                case DND_INV: k = hud_dnd_i; break;
                                case DND_SKILLS: k = 0x8000 + hud_dnd_i; break;
                                case DND_ITEMBAR: k = world.players[0].belt[hud_dnd_i]; break;
                                case DND_EQUIP:
                                    for(k = 0; k < world.players[0].data.numinv && world.players[0].data.inv[k].obj.idx != hud_dnd_idx; k++);
                                    if(k >= world.players[0].data.numinv) k = -1;
                                break;
                            }
                            for(j = 0; j < 32; j++)
                                if(world.players[0].belt[j] == (uint16_t)k) world.players[0].belt[j] = 0xffff;
                            world.players[0].belt[i] = k;
                            media_playinv(hud_dnd_idx);
                            hud_dnd = NULL; hud_dnd_src = DND_NONE; hud_dnd_idx = -1;
                            src.x = win_w;
                            break;
                        }
                        src.x += world.item_w + world.item_g;
                    }
                    src.x += world.item_p;
                    if(event.button.x >= src.x && event.button.x < src.x + world.item_w &&
                      event.button.y >= src.y && event.button.y < src.y + world.item_h) {
                        i = hud_dnd_idx;
                        hud_dnd = NULL; hud_dnd_src = DND_NONE; hud_dnd_idx = -1;
                        goto equip;
                    }
                }
                if(hud_dnd_src == DND_ITEMBAR) world.players[0].belt[hud_dnd_i] = -1;
                if(hud_win1 && hud_tab >= HUD_INV) {
                    if(hud_dnd_src == DND_EQUIP || ((hud_dnd_src == DND_INV || hud_dnd_src == DND_ITEMBAR) &&
                      event.button.x >= hud_equip.x && event.button.x < hud_equip.x + hud_equip.w &&
                      event.button.y >= hud_equip.y && event.button.y < hud_equip.y + hud_equip.h)) {
                        i = hud_dnd_idx;
                        hud_dnd = NULL; hud_dnd_src = DND_NONE; hud_dnd_idx = -1;
                        goto equip;
                    }
                }
            }
            hud_dnd = NULL; hud_dnd_src = DND_NONE; hud_dnd_idx = -1;
            if(hud_win1 && hud_tab == HUD_MENU) {
                hud_p = 0; hud_redraw();
                if(hud_vp) { media_chime(*hud_vp); hud_vp = NULL; } else
                if(event.button.x >= hud_dst1.x && event.button.x < hud_dst1.x + hud_dst1.w &&
                  event.button.y >= hud_dst1.y + ui_wt + world.padtop[PAD_V] && event.button.y < hud_dst1.y + hud_dst1.h) {
                    if(event.button.y < hud_dst1.y + ui_wt + world.padtop[PAD_V] + 3 * (world.padtop[PAD_V] + ui_lineh))
                        i = (event.button.y - hud_dst1.y - ui_wt - world.padtop[PAD_V]) / (world.padtop[PAD_V] + ui_lineh);
                    else
                        i = (event.button.y - hud_dst1.y - ui_wt - world.padtop[PAD_V] - 3 * (world.padtop[PAD_V] + ui_lineh)) /
                            (world.padtop[PAD_V] + ui_btnh) + 3;
                    if(i == hud_sel1) goto dosel;
                }
            } /*else
            if(hud_win3) {
                hud_p = 0; hud_qtyredraw();
                if(event.button.x >= hud_dst3.x && event.button.x < hud_dst3.x + hud_dst3.w &&
                  event.button.y >= hud_dst3.y + ui_wt && event.button.y < hud_dst3.y + hud_dst3.h) {
                    printf("qty window\n");
                }
            }*/
        break;
        case SDL_CONTROLLERBUTTONDOWN:
            ui_input_gp |= 1;
            if(hud_win3 && (hud_tab == HUD_INV || (hud_tab > HUD_INV && hud_invtab == 2))) { hud_popupclose(); return 1; }
            switch(event.cbutton.button) {
                case SDL_CONTROLLER_BUTTON_A: goto selpress;
                case SDL_CONTROLLER_BUTTON_B:
                case SDL_CONTROLLER_BUTTON_X:
                case SDL_CONTROLLER_BUTTON_Y: i = event.cbutton.button - SDL_CONTROLLER_BUTTON_A; goto itembar;
                case SDL_CONTROLLER_BUTTON_DPAD_UP: goto up;
                case SDL_CONTROLLER_BUTTON_DPAD_DOWN: goto down;
                case SDL_CONTROLLER_BUTTON_DPAD_LEFT: goto left;
                case SDL_CONTROLLER_BUTTON_DPAD_RIGHT: goto right;
                case SDL_CONTROLLER_BUTTON_START:
                case SDL_CONTROLLER_BUTTON_MISC1: if(hud_tab == HUD_NONE) { media_mic_start(); } return 1;
            }
        break;
        case SDL_CONTROLLERBUTTONUP:
            ui_input_gp |= 1;
            hud_p = 0;
            switch(event.cbutton.button) {
                case SDL_CONTROLLER_BUTTON_LEFTSHOULDER:
                case SDL_CONTROLLER_BUTTON_BACK: goto hudmenu;
                case SDL_CONTROLLER_BUTTON_GUIDE:
#ifndef __EMSCRIPTEN__
                    if(hud_tab == HUD_NONE && world.hdr.magic[0] != '#') { hud_switch(HUD_CHAT, 0); return 1; }
#endif
                    goto guide;
                case SDL_CONTROLLER_BUTTON_START:
                case SDL_CONTROLLER_BUTTON_MISC1: media_mic_stop(); return 1;
                case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER: goto hudinv;
                case SDL_CONTROLLER_BUTTON_A: goto dosel;
            }
        break;
        case SDL_CONTROLLERAXISMOTION:
            ui_input_gp |= 1;
            if(hud_tab >= HUD_INV) {
                if(event.caxis.axis == SDL_CONTROLLER_AXIS_RIGHTY) {
                    if(event.caxis.value < -main_gptres) { hud_focus = 0; goto up; }
                    if(event.caxis.value > main_gptres) { hud_focus = 0; goto down; }
                }
                if(event.caxis.axis == SDL_CONTROLLER_AXIS_RIGHTX) {
                    if(event.caxis.value < -main_gptres) { hud_focus = 0; goto left; }
                    if(event.caxis.value > main_gptres) { hud_focus = 0; goto right; }
                }
                if(hud_tab > HUD_INV) {
                    if(event.caxis.axis == SDL_CONTROLLER_AXIS_LEFTY) {
                        if(event.caxis.value < -main_gptres) { hud_focus = 1; goto up; }
                        if(event.caxis.value > main_gptres) { hud_focus = 1; goto down; }
                    }
                    if(event.caxis.axis == SDL_CONTROLLER_AXIS_LEFTX) {
                        if(event.caxis.value < -main_gptres) { hud_focus = 1; goto left; }
                        if(event.caxis.value > main_gptres) { hud_focus = 1; goto right; }
                    }
                }
            }
        break;
    }
    return hud_tab == HUD_NONE ? -1 : 1;
}

/**
 * View layer
 */
void hud_view()
{
    world_sprite_t *spr, *spr2, *spr3;
    SDL_Rect src, dst;
    int i, j, k, v, m, a, w;

    if(!main_draw) return;
    /* icons in the four corners */
    SDL_SetTextureAlphaMod(logo, game_a);
    if(hud_tab == HUD_MENU) {
        src.x = 224; src.y = 160; src.w = src.h = dst.w = dst.h = 32; dst.x = 0; dst.y = 1;
        SDL_RenderCopy(renderer, logo, &src, &dst);
    } else {
        src.x = 256; src.y = 160; src.w = src.h = dst.w = dst.h = 32; dst.x = 2; dst.y = 3;
        SDL_RenderCopy(renderer, logo, &src, &dst);
        src.x = 224; dst.x = dst.y = 0;
        SDL_RenderCopy(renderer, logo, &src, &dst);
    }
    src.w = src.h = dst.w = dst.h = 32; dst.x = win_w - 32; dst.y = 0;
    if(hud_tab == HUD_NONE || hud_tab == HUD_MENU) {
        spr = spr_get(world.invicon.cat, world.invicon.idx, 0);
        if(spr) spr_render(dst.x, dst.y, spr, ui_anim(spr->t, spr->f, -1), 0, 32, 32, game_a);
        else { src.x = 224; src.y = 160; SDL_RenderCopy(renderer, logo, &src, &dst); }
    } else {
        spr = spr_get(world.inviconp.cat, world.inviconp.idx, 0);
        if(!spr || world.inviconp.idx == world.invicon.idx) { spr = spr_get(world.invicon.cat, world.invicon.idx, 0); dst.y = 1; }
        if(spr) spr_render(dst.x, dst.y, spr, ui_anim(spr->t, spr->f, -1), 0, 32, 32, game_a);
        else { src.x = 224; src.y = 160; SDL_RenderCopy(renderer, logo, &src, &dst); }
    }
    if(touch) {
        dst.w = dst.h = hud_navsiz; dst.x = 0; dst.y = win_h - dst.h;
        spr = spr_get(world.navcirc.cat, world.navcirc.idx, 0);
        if(spr) spr_render(dst.x, dst.y, spr, 0, 0, dst.w, dst.w, game_a);
        else { src.x = 0; src.y = 200; src.w = src.h = 183; SDL_RenderCopy(renderer, logo, &src, &dst); }
        dst.x = win_w - dst.h;
        spr = spr_get(world.navbtns.cat, world.navbtns.idx, 0);
        if(spr) spr_render(dst.x, dst.y, spr, 0, 0, dst.w, dst.w, game_a);
        else { src.x = 183; src.y = 200; src.w = src.h = 183; SDL_RenderCopy(renderer, logo, &src, &dst); }
    }
    SDL_SetTextureAlphaMod(logo, 255);
    /* itembar and statusbar */
    spr = spr_get(world.itembarbg.cat, world.itembarbg.idx, 0);
    if(spr) {
        spr_render(hud_itemb.x, hud_itemb.y, spr, ui_anim(spr->t, spr->f, -1), 0, hud_itemb.w, hud_itemb.h, game_a);
        /* items on itembar */
        dst.x = hud_itemb.x + world.item_l; dst.y = hud_itemb.y + world.item_t;
        for(i = 0; i < world.item_n; i++) {
            if(world.players[0].belt[i] != 0xffff) {
                j = world.players[0].belt[i] < 0x8000 ? world.players[0].data.inv[world.players[0].belt[i]].obj.idx :
                    world.players[0].data.skills[world.players[0].belt[i] & 0x7fff].obj.idx;
                spr = j < world.numspr[SPR_TILE] &&
                    world.objects && world.objects[j] && world.objects[j]->invspr.idx >= 0 ?
                    spr_get(world.objects[j]->invspr.cat, world.objects[j]->invspr.idx, 0) : NULL;
                if(!spr) spr = spr_get(SPR_TILE, j, 0);
                if(spr) {
                    ui_fit(world.item_w, world.item_h, spr->w, spr->h, &dst.w, &dst.h);
                    spr_render(dst.x + (world.item_w - dst.w) / 2, dst.y + world.item_h - dst.h, spr, ui_anim(spr->t, spr->f, -1), 0,
                        dst.w, dst.h, game_a);
                }
            }
            dst.x += world.item_w + world.item_g;
        }
        dst.x += world.item_p;
        /* last item is the same as the first equipted one (primary) */
        if(world.players[0].equip[0] < world.numspr[SPR_TILE]) {
            j = world.players[0].equip[0];
            spr = world.objects && world.objects[j] && world.objects[j]->eqspr[0].idx >= 0 ?
                spr_get(world.objects[j]->eqspr[0].cat, world.objects[j]->eqspr[0].idx, 0) : NULL;
            if(!spr) spr = spr_get(SPR_TILE, j, 0);
            if(spr) {
                ui_fit(world.item_w, world.item_h, spr->w, spr->h, &dst.w, &dst.h);
                spr_render(dst.x + (world.item_w - dst.w) / 2, dst.y + world.item_h - dst.h, spr, ui_anim(spr->t, spr->f, -1), 0,
                    dst.w, dst.h, game_a);
            }
        }
    }
    if(!world.item_c) {
        spr = spr_get(world.statusbarbg.cat, world.statusbarbg.idx, 0);
        if(spr) spr_render((win_w - spr->w) / 2, 0, spr, ui_anim(spr->t, spr->f, -1), 0, spr->w, spr->h, game_a);
    }
    /* progressbars and statusbars at hud_statb */
    if(hud_pbars) {
        for(i = w = 0; i < world.numpbar; i++) {
            if(!world.pbars[i].w || world.pbars[i].type == 3) continue;
            src.x = 0; src.y = world.pbars[i].y;
            src.w = world.pbars[i].w; src.h = world.pbars[i].h;
            v = script_getattr(&world.players[0].data, world.pbars[i].valueattr);
            m = script_getattr(&world.players[0].data, world.pbars[i].maxattr);
            if(!world.pbars[i].l && !world.pbars[i].t) {
                if(v > 0 && m > 0) w += world.pbars[i].w;
                continue;
            }
            if(m < 1) m = 1;
            if(v > m) v = m;
            a = 255;
            dst.x = hud_statb.x + world.pbars[i].l; dst.y = hud_statb.y + world.pbars[i].t;
            spr = spr_get(world.pbars[i].bg.cat, world.pbars[i].bg.idx, 0);
            if(spr) spr_render(dst.x, dst.y, spr, 0, 0, spr->w, spr->h, game_a);
            switch(world.pbars[i].type) {
                case 0: src.w = src.w * v / m; break;
                case 1: src.y = src.h - (src.h * v / m); src.h -= src.y; dst.y += src.y; break;
                case 2: a = 255 * v / m; break;
            }
            SDL_SetTextureAlphaMod(hud_pbars, a < game_a ? a : game_a);
            dst.w = src.w; dst.h = src.h;
            SDL_RenderCopy(renderer, hud_pbars, &src, &dst);
        }
        /* if we have temporary status effects */
        if(w > 0) {
            dst.x = (win_w - w) / 2;
            for(i = 0; i < world.numpbar; i++) {
                if(!world.pbars[i].w || world.pbars[i].type == 3 || world.pbars[i].l || world.pbars[i].t) continue;
                src.x = 0; src.y = world.pbars[i].y; src.w = world.pbars[i].w; src.h = world.pbars[i].h;
                v = script_getattr(&world.players[0].data, world.pbars[i].valueattr);
                m = script_getattr(&world.players[0].data, world.pbars[i].maxattr);
                if(m < 1) continue;
                if(v > m) v = m;
                a = 255;
                dst.y = hud_statb.h;
                spr = spr_get(world.pbars[i].bg.cat, world.pbars[i].bg.idx, 0);
                if(spr) spr_render(dst.x, dst.y, spr, 0, 0, spr->w, spr->h, game_a);
                switch(world.pbars[i].type) {
                    case 0: src.w = src.w * v / m; break;
                    case 1: src.y = src.h - (src.h * v / m); src.h -= src.y; dst.y += src.y; break;
                    case 2: a = 255 * v / m; break;
                }
                SDL_SetTextureAlphaMod(hud_pbars, a < game_a ? a : game_a);
                dst.w = src.w; dst.h = src.h;
                SDL_RenderCopy(renderer, hud_pbars, &src, &dst);
                dst.x += world.pbars[i].w;
            }
        }
    }
    spr = spr_get(world.itembarfg.cat, world.itembarfg.idx, 0);
    if(spr) spr_render((win_w - spr->w) / 2, win_h - spr->h, spr, ui_anim(spr->t, spr->f, -1), 0, spr->w, spr->h, game_a);
    if(!world.item_c) {
        spr = spr_get(world.statusbarfg.cat, world.statusbarfg.idx, 0);
        if(spr) spr_render((win_w - spr->w) / 2, 0, spr, ui_anim(spr->t, spr->f, -1), 0, spr->w, spr->h, game_a);
    }
    /* title */
    if(hud_title) {
        i = main_tick - hud_titlefade;
        if(i > hud_dt) {
            SDL_DestroyTexture(hud_title); hud_title = NULL;
        } else {
            if(i < world.alert_fi * 10 && world.alert_fi > 0) a = i * 255 / (world.alert_fi * 10); else
            if(i >= world.alert_fi * 10 && i < hud_fo) a = 255; else
            if(i >= hud_fo && hud_dt > hud_fo)
                a = 255 - ((i - hud_fo) * 255 / (hud_dt - hud_fo));
            if(a > game_a) a = game_a;
            hud_titleb.x = (win_w - hud_titleb.w) / 2;
            hud_titleb.y = win_h - hud_titleb.h - hud_itemb.h - 4;
            SDL_SetTextureAlphaMod(hud_title, a);
            SDL_RenderCopy(renderer, hud_title, NULL, &hud_titleb);
        }

    }
    /* hud windows */
    if(!main_takescrshot) {
        if(hud_win1) {
            SDL_SetTextureAlphaMod(hud_win1, game_a);
            SDL_RenderCopy(renderer, hud_win1, NULL, &hud_dst1);
            if(hud_tab >= HUD_INV) {
                switch(hud_invtab) {
                    case 0:
                        spr = spr_get(world.equipimg.cat, world.equipimg.idx, 0);
                        src.x = src.y = 0;
                        if(spr && hud_equip.h > 0) {
                            spr_render(hud_equip.x, hud_equip.y, spr, ui_anim(spr->t, spr->f, -1), 0, hud_equip.w, hud_equip.h, game_a);
                            src.w = spr->w; src.h = spr->h;
                        } else {
                            src.w = hud_equip.w; src.h = hud_equip.h;
                        }
                        /* equipted objects */
                        if(hud_equip.w > 0 && hud_equip.h > 0 && world.players) {
                            w = world.inv_w * hud_equip.w / src.w; m = world.inv_h * hud_equip.h / src.h;
                            for(i = 0; i < 32; i++)
                                if(world.players[0].equip[i] < world.numspr[SPR_TILE]) {
                                    spr = world.objects && world.objects[world.players[0].equip[i]] &&
                                        world.objects[world.players[0].equip[i]]->eqspr[i].idx >= 0 ?
                                        spr_get(world.objects[world.players[0].equip[i]]->eqspr[i].cat,
                                            world.objects[world.players[0].equip[i]]->eqspr[i].idx, 0) : NULL;
                                    if(!spr) spr = spr_get(SPR_TILE, world.players[0].equip[i], 0);
                                    if(spr) {
                                        ui_fit(w, m, spr->w, spr->h, &dst.w, &dst.h);
                                        dst.x = hud_equip.x + world.equippos[i * 2 + 0] * hud_equip.w / src.w + (w - dst.w) / 2;
                                        dst.y = hud_equip.y + world.equippos[i * 2 + 1] * hud_equip.h / src.h + m - dst.h;
                                        spr_render(dst.x, dst.y, spr, ui_anim(spr->t, spr->f, -1), 0, dst.w, dst.h, game_a);
                                    }
                                }
                        }
                        /*SDL_RenderFillRect(renderer, &hud_items1);*/
                        spr = spr_get(world.invslot.cat, world.invslot.idx, 0);
                        spr2 = spr_get(world.invslots.cat, world.invslots.idx, 0);
                        if(!spr2) spr2 = spr;
                        w = hud_line1 * (ui_slots + 2);
                        if(spr) {
                            for(j = 0, k = hud_scr1 * hud_line1; j < hud_items1.h; j += ui_slots + 2)
                                for(i = 0; i < w; i += ui_slots + 2, k++) {
                                    if(!hud_focus && k == hud_sel1)
                                        spr_render(hud_items1.x + i + (ui_slots - spr2->w) / 2,
                                            hud_items1.y + j + (ui_slots - spr2->h) / 2, spr2,
                                            ui_anim(spr2->t, spr2->f, -1), 0, spr2->w, spr2->h, game_a);
                                    else
                                        spr_render(hud_items1.x + i + (ui_slots - spr->w) / 2,
                                            hud_items1.y + j + (ui_slots - spr->h) / 2, spr,
                                            ui_anim(spr->t, spr->f, -1), 0, spr->w, spr->h, game_a);
                                    if(world.players && world.players[0].data.inv && k < world.players[0].data.numinv) {
                                        spr3 = world.players[0].data.inv[k].obj.idx >= 0 && world.players[0].data.inv[k].obj.idx < world.numspr[SPR_TILE] &&
                                            world.objects && world.objects[world.players[0].data.inv[k].obj.idx] &&
                                            world.objects[world.players[0].data.inv[k].obj.idx]->invspr.idx >= 0 ?
                                            spr_get(world.objects[world.players[0].data.inv[k].obj.idx]->invspr.cat,
                                                world.objects[world.players[0].data.inv[k].obj.idx]->invspr.idx, 0) : NULL;
                                        if(!spr3) spr3 = spr_get(world.players[0].data.inv[k].obj.cat, world.players[0].data.inv[k].obj.idx, 0);
                                        if(spr3) {
                                            ui_fit(world.inv_w, world.inv_h, spr3->w, spr3->h, &dst.w, &dst.h);
                                            dst.x = hud_items1.x + i + world.inv_l + (world.inv_w - dst.w) / 2;
                                            dst.y = hud_items1.y + j + world.inv_t + world.inv_h - dst.h;
                                            spr_render(dst.x, dst.y, spr3, ui_anim(spr->t, spr->f, -1), 0, dst.w, dst.h, game_a);
                                        }
                                    }
                                }
                        }
                    break;
                    case 1:
                        /* FIXME: portrait */
                        spr = spr_get(world.equipimg.cat, world.equipimg.idx, 0);
                        if(spr && hud_prt1.h > 0)
                            spr_render(hud_prt1.x, hud_prt1.y, spr, ui_anim(spr->t, spr->f, -1), 0, hud_prt1.w, hud_prt1.h, game_a);
                        /* skill slots */
                        spr = spr_get(world.invslot.cat, world.invslot.idx, 0);
                        spr2 = spr_get(world.invslots.cat, world.invslots.idx, 0);
                        if(!spr2) spr2 = spr;
                        w = hud_line1 * (ui_slots + 2);
                        if(spr) {
                            for(j = 0, k = hud_scr1 * hud_line1; j < hud_items1.h; j += ui_slots + 2)
                                for(i = 0; i < w; i += ui_slots + 2, k++) {
                                    if(!hud_focus && k == hud_sel1)
                                        spr_render(hud_items1.x + i + (ui_slots - spr2->w) / 2,
                                            hud_items1.y + j + (ui_slots - spr2->h) / 2, spr2,
                                            ui_anim(spr2->t, spr2->f, -1), 0, spr2->w, spr2->h, game_a);
                                    else
                                        spr_render(hud_items1.x + i + (ui_slots - spr->w) / 2,
                                            hud_items1.y + j + (ui_slots - spr->h) / 2, spr,
                                            ui_anim(spr->t, spr->f, -1), 0, spr->w, spr->h, game_a);
                                    if(world.players && world.players[0].data.skills && k < world.players[0].data.numskl) {
                                        spr3 = world.players[0].data.skills[k].obj.idx >= 0 && world.players[0].data.skills[k].obj.idx < world.numspr[SPR_TILE] &&
                                            world.objects && world.objects[world.players[0].data.skills[k].obj.idx] &&
                                            world.objects[world.players[0].data.skills[k].obj.idx]->invspr.idx >= 0 ?
                                            spr_get(world.objects[world.players[0].data.skills[k].obj.idx]->invspr.cat,
                                                world.objects[world.players[0].data.skills[k].obj.idx]->invspr.idx, 0) : NULL;
                                        if(!spr3) spr3 = spr_get(world.players[0].data.skills[k].obj.cat, world.players[0].data.skills[k].obj.idx, 0);
                                        if(spr3) {
                                            ui_fit(world.inv_w, world.inv_h, spr3->w, spr3->h, &dst.w, &dst.h);
                                            dst.x = hud_items1.x + i + (ui_slots - spr3->w) / 2;
                                            dst.y = hud_items1.y + (ui_slots - world.inv_h) / 2 + (world.inv_h - spr3->h);
                                            spr_render(dst.x, dst.y, spr3, ui_anim(spr->t, spr->f, -1), 0, dst.w, dst.h, game_a);
                                        }
                                    }
                                }
                        }
                    break;
                }
            }
            if(hud_tab == HUD_CHAT) hud_redraw();
            if(hud_frm1) {
                SDL_SetTextureAlphaMod(hud_frm1, game_a);
                SDL_RenderCopy(renderer, hud_frm1, NULL, &hud_dst1);
            }
            if(hud_tab == HUD_CHAT) ui_input_view();
        }
        if(hud_win2) {
            SDL_SetTextureAlphaMod(hud_win2, game_a);
            SDL_RenderCopy(renderer, hud_win2, NULL, &hud_dst2);
            if(hud_frm2) {
                switch(hud_tab) {
                    case HUD_MARKET:
                        /* FIXME: opponent portrait */
                        spr = spr_get(world.equipimg.cat, world.equipimg.idx, 0);
                        if(spr && hud_prt2.h > 0)
                            spr_render(hud_prt2.x, hud_prt2.y, spr, ui_anim(spr->t, spr->f, -1), 0, hud_prt2.w, hud_prt2.h, game_a);
                        /* opponent's inventory slots */
                        spr = spr_get(world.invslot.cat, world.invslot.idx, 0);
                        spr2 = spr_get(world.invslots.cat, world.invslots.idx, 0);
                        if(!spr2) spr2 = spr;
                        w = hud_line2 * (ui_slots + 2);
                        if(spr) {
                            for(j = 0, k = hud_scr2 * hud_line2; j < hud_items2.h; j += ui_slots + 2)
                                for(i = 0; i < w; i += ui_slots + 2, k++)
                                    if(hud_focus == 1 && k == hud_sel2)
                                        spr_render(hud_items2.x + i + (ui_slots - spr2->w) / 2,
                                            hud_items2.y + j + (ui_slots - spr2->h) / 2, spr2,
                                            ui_anim(spr2->t, spr2->f, -1), 0, spr2->w, spr2->h, game_a);
                                    else
                                        spr_render(hud_items2.x + i + (ui_slots - spr->w) / 2,
                                            hud_items2.y + j + (ui_slots - spr->h) / 2, spr,
                                            ui_anim(spr->t, spr->f, -1), 0, spr->w, spr->h, game_a);
                        }
                    break;
                    case HUD_CRAFT:
                    break;
                }
                SDL_SetTextureAlphaMod(hud_frm2, game_a);
                SDL_RenderCopy(renderer, hud_frm2, NULL, &hud_dst2);
            }
        }
        if(hud_win3) {
            SDL_SetTextureAlphaMod(hud_win3, game_a);
            SDL_RenderCopy(renderer, hud_win3, NULL, &hud_dst3);
            if(hud_frm3) {
                SDL_SetTextureAlphaMod(hud_frm3, game_a);
                SDL_RenderCopy(renderer, hud_frm3, NULL, &hud_dst3);
            }
        }
    }
    /* dnd */
    if(hud_dnd)
        spr_render(main_curx, main_cury, hud_dnd, ui_anim(hud_dnd->t, hud_dnd->f, -1), 0, hud_dnd_w, hud_dnd_h, game_a);
}
