diff options
author | ennewalker <ennewalker@c06c8d41-db1a-0410-9941-cceddc491573> | 2008-01-05 01:33:53 +0000 |
---|---|---|
committer | ennewalker <ennewalker@c06c8d41-db1a-0410-9941-cceddc491573> | 2008-01-05 01:33:53 +0000 |
commit | 62f7040f14b39e67042be98f951575fbc819e84e (patch) | |
tree | d4fa0598a1bee1d34fff81e2c150de08c2256753 /crawl-ref/source/tile2.cc | |
parent | 19155f1f85058ef9d65d11e60c63cc69c36d4e8a (diff) | |
download | crawl-ref-62f7040f14b39e67042be98f951575fbc819e84e.tar.gz crawl-ref-62f7040f14b39e67042be98f951575fbc819e84e.zip |
Tiles!
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@3194 c06c8d41-db1a-0410-9941-cceddc491573
Diffstat (limited to 'crawl-ref/source/tile2.cc')
-rw-r--r-- | crawl-ref/source/tile2.cc | 3023 |
1 files changed, 3023 insertions, 0 deletions
diff --git a/crawl-ref/source/tile2.cc b/crawl-ref/source/tile2.cc new file mode 100644 index 0000000000..92eeb6dcbb --- /dev/null +++ b/crawl-ref/source/tile2.cc @@ -0,0 +1,3023 @@ +#ifdef USE_TILE + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "AppHdr.h" +#include "describe.h" +#include "direct.h" +#include "dungeon.h" +#include "files.h" +#include "guic.h" +#include "itemprop.h" +#include "it_use2.h" +#include "stuff.h" +#include "tiles.h" +#include "tilecount-w2d.h" +#include "tiledef-p.h" +#include "transfor.h" + +// normal tile count + iso tile count +#define TILE_TOTAL2 (TILE_TOTAL) +// normal tile count +#define TILE_NORMAL TILE_TOTAL + +extern void TileDrawDungeonAux(); + +// Raw tile images +extern img_type TileImg; +extern img_type TileIsoImg; +extern img_type PlayerImg; +extern img_type WallImg; +extern img_type ScrBufImg; + +extern WinClass *win_main; +// Regions +extern TileRegionClass *region_tile; +extern TextRegionClass *region_crt; +extern TextRegionClass *region_stat; +extern TextRegionClass *region_tip; +extern TextRegionClass *region_msg; + +extern TileRegionClass *region_item; +extern TileRegionClass *region_item2; + +#define ScrBufImg (region_tile->backbuf) + +//Internal +static img_type DollCacheImg; + +static void tile_draw_grid(int kind, int xx, int yy); +static void clear_tcache(); +static void init_tcache(); +static void init_tileflag(); +static void register_tile_mask(int tile, int region, int *cp, + char *ms, bool smalltile = false); +static void tcache_compose_normal(int ix, int *fg, int *bg); + +#if 1 // TILE_MON_EQUIP +static void mcache_init(); +#endif + +//Internal variables + +bool force_redraw_tile; +bool force_redraw_inv = false; +static unsigned short int t1buf[TILE_DAT_XMAX+2][TILE_DAT_YMAX+2], + t2buf[TILE_DAT_XMAX+2][TILE_DAT_YMAX+2]; +static short unsigned int tb_bk[TILE_DAT_YMAX*TILE_DAT_XMAX*2]; + +#define MAX_ITEMLIST 200 +int itemlist[MAX_ITEMLIST]; +int itemlist_num[MAX_ITEMLIST]; +int itemlist_idx[MAX_ITEMLIST]; +char itemlist_key[MAX_ITEMLIST]; +int itemlist_iflag[MAX_ITEMLIST]; +int itemlist_flag = -1; +int itemlist_n=0; + +static int wall_flavors = 0; +static int floor_flavors = 0; +static int special_flavors = 0; +static int wall_tile_idx = 0; +static int floor_tile_idx = 0; +static int special_tile_idx = 0; + +int get_num_wall_flavors() +{ + return wall_flavors; +} + +int get_num_floor_flavors() +{ + return floor_flavors; +} + +int get_num_floor_special_flavors() +{ + return special_flavors; +} + +int get_wall_tile_idx() +{ + return wall_tile_idx; +} + +int get_floor_tile_idx() +{ + return floor_tile_idx; +} + +int get_floor_special_tile_idx() +{ + return special_tile_idx; +} + +/******** Cache buffer for transparency operation *****/ +static int tcache_kind; + +#if 1 // ISO +#define TCACHE_KIND_ISO 2 +#define TCACHE0_ISO 0 +#define TCACHE1_ISO 1 +#endif + +#define TCACHE_KIND_NORMAL 1 +#define TCACHE0_NORMAL 0 + +static int last_cursor = -1; + +//Internal cache Image buffer +static img_type *tcache_image; + +//Start of a pointer string +static int *tcache_head; + +typedef struct tile_cache +{ + unsigned int id[4]; + int idx; + tile_cache *next; + tile_cache *prev; +} tile_cache; + +// number of tile grids +static int tile_xmax; +static int tile_ymax; + +static int max_tcache; +static int tc_hash; +// [kind * tc_hash][max_tcache] +static tile_cache **tcache; +// [kind][x*y] +static int **screen_tcach_idx; + +#if 1 //ISO +/* + screen grid arrangement. (x,y,kind) + (0,0,B) (1,0,A) (2,0,B) + (0,0,A) (1,0,B) (2,0,A) ... + (0,1,B) (1,1,A) (2,1,B) + (0,1,A) (1,1,B) (2,1,A) + .... +*/ +const int tcache_wx_iso[TCACHE_KIND_ISO] = {TILE_X_EX_ISO/2, TILE_X_EX_ISO/2}; +const int tcache_wy_iso[TCACHE_KIND_ISO] = {TILE_Y_EX_ISO/4, TILE_Y_EX_ISO/4}; +const int tcache_ox_iso[TCACHE_KIND_ISO] = {0,0}; +const int tcache_oy_iso[TCACHE_KIND_ISO] = {0,TILE_Y_EX_ISO/4}; +const int tcache_nlayer_iso[TCACHE_KIND_ISO] = {4,4}; +#endif + +const int tcache_wx_normal[TCACHE_KIND_NORMAL] = {TILE_X}; +const int tcache_wy_normal[TCACHE_KIND_NORMAL] = {TILE_Y}; +const int tcache_ox_normal[TCACHE_KIND_NORMAL] = {0}; +const int tcache_oy_normal[TCACHE_KIND_NORMAL] = {0}; +const int tcache_nlayer_normal[TCACHE_KIND_NORMAL] = {1}; + +unsigned char tile_flag[TILE_TOTAL2]; +#define TFLAG_A 0x80 +#define TFLAG_B 0x40 +#define TFLAG_C 0x20 +#define TFLAG_D 0x10 +#define TFLAG_F 0x08 +#define TFLAG_G 0x04 +#define TFLAG_H 0x02 +#define TFLAG_I 0x01 + +#define tile_check_blank(tile,region) \ + if( (tile_flag[tile & TILE_FLAG_MASK]&(region))==0) (tile) &= ~TILE_FLAG_MASK; + +#if 1 //ISO +#define TREGION_A_ISO 0 +#define TREGION_B_ISO 1 +#define TREGION_C_ISO 2 +#define TREGION_D_ISO 3 +#define TREGION_E_ISO 4 +#define TREGION_F_ISO 5 +#define TREGION_G_ISO 6 +#define TREGION_H_ISO 7 +/* +<-64-> + AAEE | + BBFF 64 + CCGG | + DDHH | +*/ + +const int region_sx_iso[8]= + {0, 0, 0, 0, + TILE_X_EX_ISO/2, TILE_X_EX_ISO/2, TILE_X_EX_ISO/2, TILE_X_EX_ISO/2}; +const int region_sy_iso[8]= + {0, TILE_Y_EX_ISO/4, TILE_Y_EX_ISO/2, (TILE_Y_EX_ISO*3)/4, + 0, TILE_Y_EX_ISO/4, TILE_Y_EX_ISO/2, (TILE_Y_EX_ISO*3)/4}; +const int region_wx_iso[8]= + {TILE_X_EX_ISO/2, TILE_X_EX_ISO/2, TILE_X_EX_ISO/2, TILE_X_EX_ISO/2, + TILE_X_EX_ISO/2, TILE_X_EX_ISO/2, TILE_X_EX_ISO/2, TILE_X_EX_ISO/2}; +const int region_wy_iso[8]= + {TILE_Y_EX_ISO/4, TILE_Y_EX_ISO/4, TILE_Y_EX_ISO/4, TILE_Y_EX_ISO/4, + TILE_Y_EX_ISO/4, TILE_Y_EX_ISO/4, TILE_Y_EX_ISO/4, TILE_Y_EX_ISO/4}; + +/* 32x32 �̏ꍇ �^�C����(sx,sy)����wx*wy �̗̈��� ox,oy ���炵�ăR�s�[ */ + +#ifdef ISO48 +//�傫��BMP��48x48 �̏ꍇ +const int region_sx_small_iso[8]= + {0, 0, 0, 0, + TILE_X/2, TILE_X/2, TILE_X/2, TILE_X/2}; +const int region_sy_small_iso[8]= + {0, 2, 14, 26, 0, 2, 14, 26}; +const int region_wx_small_iso[8]= + {16,16,16,16, 16,16,16,16}; +const int region_wy_small_iso[8]= + {2, 12, 12, 6, 2, 12, 12, 6}; +const int region_ox_small_iso[8]= + {8,8,8, 8, 0, 0, 0, 0}; +const int region_oy_small_iso[8]= + {14,0,0,0, 14,0,0,0}; +#else +//�傫��BMP��64x64 �̏ꍇ +const int region_sx_small_iso[8]= + {0, 0, 0, 0, + TILE_X/2, TILE_X/2, TILE_X/2, TILE_X/2}; +const int region_sy_small_iso[8]= + {0, 0, 8,24, 0, 0, 8,24}; +const int region_wx_small_iso[8]={0,16,16,16, 0,16,16,16}; +const int region_wy_small_iso[8]={0, 8,16, 8, 0, 8,16, 8}; +const int region_ox_small_iso[8]={16,16,16, 16, 0, 0, 0, 0}; +const int region_oy_small_iso[8]={0,8,0,0,0,8,0,0}; +#endif + +#endif // ISO + +#define TREGION_0_NORMAL 0 +const int region_sx_normal[1]={0}; +const int region_sy_normal[1]={0}; +const int region_wx_normal[1]={TILE_X}; +const int region_wy_normal[1]={TILE_Y}; + +// ISO mode sink mask +static char *sink_mask; + +/* BG tile priority */ +static unsigned char tile_prio[TILE_TOTAL2]; +#define PRIO_WALL 10 +#define tile_is_wall(tile) (tile_prio[(tile)&TILE_FLAG_MASK]==PRIO_WALL) + +/********* Image manipulation subroutines ****************/ +img_type ImgLoadFileSimple(const char *name) +{ + char fname[512]; +#ifdef USE_X11 + sprintf(fname,"tiles/%s.png", name); + std::string path = datafile_path(fname, true, true); + return ImgLoadFile(path.c_str()); +#endif +#ifdef WIN32TILES + sprintf(fname,"tiles/%s.bmp", name); + std::string path = datafile_path(fname, true, true); + return ImgLoadFile(path.c_str()); +#endif +} + +// TileImg macro +void ImgCopyFromTileImg(int idx, img_type dest, int dx, int dy, int copy, + char *mask = NULL, bool hilite = false) +{ + int sx = (idx % TILE_PER_ROW)*TILE_X; + int sy = (idx / TILE_PER_ROW)*TILE_Y; + if (hilite) + { + if (mask != NULL) + ImgCopyMaskedH(TileImg, sx, sy, TILE_X, TILE_Y, + dest, dx, dy, mask); + else + ImgCopyH(TileImg, sx, sy, TILE_X, TILE_Y, dest, dx, dy, copy); + } + else + { + if (mask != NULL) + ImgCopyMasked(TileImg, sx, sy, TILE_X, TILE_Y, + dest, dx, dy, mask); + else + ImgCopy(TileImg, sx, sy, TILE_X, TILE_Y, dest, dx, dy, copy); + } +} + +void ImgCopyToTileImg(int idx, img_type src, int sx, int sy, int copy, + char *mask = NULL, bool hilite = false) +{ + int dx = (idx % TILE_PER_ROW)*TILE_X; + int dy = (idx / TILE_PER_ROW)*TILE_Y; + if (hilite) + { + if (mask != NULL) + ImgCopyMaskedH(src, sx, sy, TILE_X, TILE_Y, + TileImg, dx, dy, mask); + else + ImgCopyH(src, sx, sy, TILE_X, TILE_Y, TileImg, dx, dy, copy); + } + else + { + if (mask != NULL) + ImgCopyMasked(src, sx, sy, TILE_X, TILE_Y, + TileImg, dx, dy, mask); + else + ImgCopy(src, sx, sy, TILE_X, TILE_Y, TileImg, dx, dy, copy); + } +} + +void TileInit() +{ + int x, y, k; + textcolor(WHITE); + + TileImg = ImgLoadFileSimple("tile"); + PlayerImg = ImgLoadFileSimple("player"); + WallImg = ImgLoadFileSimple("wall2d"); + + + if (!TileImg) + { + cprintf("Main tile not initialized\n"); + getch(); + end(-1); + } + + ImgSetTransparentPix(TileImg); + + if (ImgWidth(TileImg)!= TILE_X * TILE_PER_ROW || + ImgHeight(TileImg) < TILE_Y*( (TILE_TOTAL + TILE_PER_ROW -1)/TILE_PER_ROW)) + { + cprintf("Main tile size invalid\n"); + getch(); + end(-1); + } + + if (!PlayerImg) + { + cprintf("Player tile not initialized\n"); + getch(); + end(-1); + } + + if (ImgWidth(PlayerImg)!= TILE_X * TILEP_PER_ROW) + { + cprintf("Player tile size invalid\n"); + getch(); + end(-1); + } + + if (!WallImg) + { + cprintf("wall2d tile not initialized\n"); + getch(); + end(-1); + } + + tcache_kind = TCACHE_KIND_NORMAL; + tc_hash = 1; + tile_xmax = tile_dngn_x; + tile_ymax = tile_dngn_y; + + max_tcache = 4*tile_xmax*tile_ymax; + + screen_tcach_idx = (int **)malloc(sizeof(int *) * tcache_kind); + + tcache = (tile_cache **)malloc(sizeof(tile_cache *)*tcache_kind); + + tcache_head = (int *)malloc(sizeof(int)*tcache_kind*tc_hash); + + for(k=0;k<tcache_kind;k++) + { + screen_tcach_idx[k]= (int *)malloc(sizeof(int)* tile_xmax * tile_ymax); + tcache[k] = (tile_cache *)malloc(sizeof(tile_cache)*max_tcache); + for(x=0;x<tile_xmax * tile_ymax;x++) + screen_tcach_idx[k][x] = -1; + } + + sink_mask = (char *)malloc(TILE_X*TILE_Y); + + init_tileflag(); + init_tcache(); + + DollCacheImg = ImgCreateSimple(TILE_X, TILE_Y); + + for(x=0;x<TILE_DAT_XMAX+2;x++){ + for(y=0;y<TILE_DAT_YMAX+2;y++){ + t1buf[x][y]=0; + t2buf[x][y]=simple_iso_tile(TILE_DNGN_UNSEEN)|TILE_FLAG_UNSEEN; + }} + + force_redraw_tile = false; + +#if 1 // TILE_MON_EQUIP + mcache_init(); +#endif + + for(x=0; x<MAX_ITEMLIST;x++) + { + itemlist[x]=itemlist_num[x]=itemlist_key[x]=itemlist_idx[x]=0; + } +} + +void TileResizeScreen(int x0, int y0) +{ + int k, x; + tile_xmax = x0; + tile_ymax = y0; + max_tcache = 4*tile_xmax*tile_ymax; + + for(k=0;k<tcache_kind;k++) + { + free(screen_tcach_idx[k]); + screen_tcach_idx[k]= (int *)malloc(sizeof(int)* tile_xmax * tile_ymax); + + free(tcache[k]); + tcache[k] = (tile_cache *)malloc(sizeof(tile_cache)*max_tcache); + + for(x=0;x<tile_xmax * tile_ymax;x++) + { + screen_tcach_idx[k][x] = -1; + } + } + clear_tcache(); + crawl_view.viewsz.x = tile_xmax; + crawl_view.viewsz.y = tile_ymax; + crawl_view.vbuf.size(crawl_view.viewsz); +} + +/*** Investigate a region of specific tile whether it contains any + picture, or it is blank ***/ +int init_tileflag_aux(int tile, int xs, int ys, int wx, int wy){ + int x,y, sx,sy; + img_type src=TileImg; + + ASSERT(tile<TILE_TOTAL2); + + sx = tile % TILE_PER_ROW; + sx *= TILE_X; + sy = tile / TILE_PER_ROW; + sy *= TILE_Y; + + for(x=xs;x<xs+wx;x++){ + for(y=ys;y<ys+wy;y++){ + if(!ImgIsTransparentAt(src, sx+x, sy+y)) + return 1; + }} + return 0; +} + +void init_tileflag(){ + int tile, flag; + + for(tile=0;tile<TILE_TOTAL2;tile++){ + flag = 0; + tile_flag[tile]=flag; + tile_prio[tile]=0; + } + + for(tile=0;tile<4;tile++) + { + tile_prio[simple_iso_tile(TILE_DNGN_LAVA)+tile]=2; + tile_prio[simple_iso_tile(TILE_DNGN_SHALLOW_WATER)+tile]=2; + tile_prio[simple_iso_tile(TILE_DNGN_DEEP_WATER)+tile]=3; + } + +} + +void clear_tcache(){ + int i, k, h; + + for(k=0;k<tcache_kind;k++) + { + tile_cache *tc = tcache[k]; + + // Decompose pointer string tcache[k] into tc_hash segments + for (h=0; h<tc_hash;h++) + { + int i_start = (max_tcache*h)/tc_hash; + int i_end = (max_tcache*(h+1))/tc_hash -1; + tcache_head[k*tc_hash + h] = i_start; + + for(i=i_start;i<=i_end;i++) + { + tc[i].id[3] = tc[i].id[2] = + tc[i].id[1] = tc[i].id[0] = 0; + tc[i].idx = i; + if (i==i_start) tc[i].prev = NULL; + else tc[i].prev = &tc[i-1]; + if (i==i_end) tc[i].next = NULL; + else tc[i].next = &tc[i+1]; + } + } + } +} + +void init_tcache(){ + int k; + + clear_tcache(); + + tcache_image = (img_type *)malloc(sizeof(img_type)*tcache_kind); + + for(k=0;k<tcache_kind;k++) + { + int wx = tcache_wx_normal[k]; + int wy = tcache_wy_normal[k]; + tcache_image[k] = ImgCreateSimple(wx, max_tcache*wy); + } + +} + +// Move a cache to the top of pointer string +// to shorten the search time +void lift_tcache(int ix, int kind, int hash){ + int kind_n_hash = kind * tc_hash + hash; + int head_old=tcache_head[kind_n_hash]; + tile_cache *tc = tcache[kind]; + tile_cache *p = tc[ix].prev; + tile_cache *n = tc[ix].next; + + ASSERT(ix<max_tcache); + ASSERT(head_old<max_tcache); + ASSERT(kind<tcache_kind); + ASSERT(hash<tc_hash); + + if(ix == head_old) return; + if(p!=NULL) p->next = n; + if(n!=NULL) n->prev = p; + + tcache_head[kind_n_hash] = ix; + tc[head_old].prev = &tc[ix]; + tc[ix].next = &tc[head_old]; +} + +// Find cached image of fg+bg +// If not found, compose and cache it +static int tcache_find_id_normal(int kind, int *fg, int *bg, int *is_new) +{ + unsigned int id[4]; + int i; + int hash = 0; // Don't use hash + int kind_n_hash = kind*tc_hash + hash; + int nlayer = tcache_nlayer_normal[kind]; + tile_cache *tc = tcache[kind]; + tile_cache *tc0 = &tc[tcache_head[kind_n_hash]]; +#if DEBUG + int search_count =0; +#endif + + *is_new=0; + + for(i=0;i<nlayer;i++) id[i]= (fg[i]<<16)+bg[i]+1; + + while(1){ + tile_cache *next = tc0->next; + + if(tc0->id[0] == id[0]) break; + + if(tc0->id[0]==0 || next == NULL) + { + //end of used cache + *is_new = 1; + tcache_compose_normal(tc0->idx, fg, bg); + for(i=0;i<nlayer;i++) tc0->id[i] = id[i]; + break; + } + tc0 = next; +#if DEBUG + search_count++; +#endif + } + lift_tcache(tc0->idx, kind, hash); + +#if DEBUG +//DEBUGLOG("%d\n",search_count); +#endif + + return tc0->idx; +} + + +/*** overlay a tile onto an exsisting image with transpalency operation */ +void tcache_overlay(img_type img, int idx, + int tile, int region, int *copy, char *mask) +{ + + int x0, y0; + int sx= region_sx_normal[region]; + int sy= region_sy_normal[region]; + int wx= region_wx_normal[region]; + int wy= region_wy_normal[region]; + int ox=0; + int oy=0; + img_type src = TileImg; + int uy=wy; + + tile &= TILE_FLAG_MASK; + + x0 = (tile % TILE_PER_ROW)*TILE_X; + y0 = (tile / TILE_PER_ROW)*TILE_Y; + + if (mask != NULL) + { + if(*copy ==2) + ImgCopyMaskedH(src, x0 + sx, y0 + sy, wx, wy, + img, ox, oy + idx*uy, mask); + else + ImgCopyMasked(src, x0 + sx, y0 + sy, wx, wy, + img, ox, oy + idx*uy, mask); + *copy = 0; + return; + } + // Hack: hilite rim color + else if(*copy ==2) + { + *copy=0; + ImgCopyH(src, x0 + sx, y0 + sy, wx, wy, + img, ox, oy + idx*uy, *copy); + return; + } else + { + ImgCopy(src, x0 + sx, y0 + sy, wx, wy, + img, ox, oy + idx*uy, *copy); + } + *copy = 0; +} + +void tcache_overlay_player(img_type img, int dx, int dy, + int part, int idx, int ymax, int *copy) +{ + int xs, ys; + int tidx = tilep_parts_start[part]; + int nx = tilep_parts_nx[part]; + int ny = tilep_parts_ny[part]; + int ox = tilep_parts_ox[part]; + int oy = tilep_parts_oy[part]; + int wx = TILE_X/nx; + int wy = TILE_Y/ny; + + if(!idx)return; + idx--; + + tidx += idx/(nx*ny); + + if (oy+wy > ymax) wy -= oy + wy - ymax; + if (wy<=0) return; + + xs = (tidx % TILEP_PER_ROW)*TILE_X; + ys = (tidx / TILEP_PER_ROW)*TILE_Y; + + xs += (idx % nx)*(TILE_X/nx); + ys += ((idx/nx) % ny)*(TILE_Y/ny); + + ImgCopy(PlayerImg, xs, ys, wx, wy, + img, dx+ox, dy+oy, *copy); + + *copy = 0; +} + +/** overlay a tile onto an exsisting image with transpalency operation */ +void register_tile_mask(int tile, int region, int *copy, + char *mask, bool smalltile) +{ + int x0, y0, x, y; + int sx= region_sx_normal[region]; + int sy= region_sy_normal[region]; + int wx= region_wx_normal[region]; + int wy= region_wy_normal[region]; + int ox=0; + int oy=0; + img_type src = TileImg; + int ux=wx; + int uy=wy; + + tile &= TILE_FLAG_MASK; + + x0 = (tile % TILE_PER_ROW)*TILE_X; + y0 = (tile / TILE_PER_ROW)*TILE_Y; + + if (*copy!=0) memset(mask, 0, ux*uy); + + if (*copy == 2) + { + if (smalltile) + { + ux = wx; + } + for(x=0;x<wx;x++){ + for(y=0;y<wy;y++){ + if(! ImgIsTransparentAt(src, x0+sx+x, y0+sy+y)) + mask[(y+oy)*ux+(x+ox)]=1; + }} + } + else + { + for(x=0;x<wx;x+=2){ + for(y=0;y<wy;y+=2){ + if(! ImgIsTransparentAt(src, x0+sx+x, y0+sy+y)) + mask[(y+oy)*ux+(x+ox)]=1; + }} + } + *copy = 0; + +} + +void tile_draw_grid(int kind, int xx, int yy){ + int fg[4],bg[4],ix, ix_old, is_new; + + if (xx < 0 || yy < 0 || xx >= tile_xmax || yy>= tile_ymax) return; + fg[0] = t1buf[xx+1][yy+1]; + bg[0] = t2buf[xx+1][yy+1]; + + ix_old = screen_tcach_idx[kind][xx+yy*tile_xmax]; + + ix = tcache_find_id_normal(kind, fg, bg, &is_new); + + screen_tcach_idx[kind][xx+yy*tile_xmax]=ix; + if(is_new || ix!=ix_old || force_redraw_tile) + { + int x_dest = tcache_ox_normal[kind]+xx* TILE_UX_NORMAL; + int y_dest = tcache_oy_normal[kind]+yy* TILE_UY_NORMAL; + int wx = tcache_wx_normal[kind]; + int wy = tcache_wy_normal[kind]; + + ImgCopy(tcache_image[kind], + 0, ix*wy, wx, wy, + ScrBufImg, x_dest, y_dest, 1); + } +} + +void update_single_grid(int x, int y) +{ + int sx, sy, wx, wy; + + tile_draw_grid(TCACHE0_NORMAL, x, y); + sx = x*TILE_UX_NORMAL; + sy = y*TILE_UY_NORMAL; + wx = TILE_UX_NORMAL; + wy = TILE_UY_NORMAL; + region_tile->redraw(sx, sy, sx+wx-1, sy+wy-1); +} + + +// Discard cache containing specific tile +void redraw_spx_tcache(int tile) +{ + int kind, idx, layer, redraw; + int fg[4], bg[4]; + for(kind = 0; kind < tcache_kind; kind++) + { + int nlayer = tcache_nlayer_normal[kind]; + + for(idx = 0; idx < max_tcache; idx++) + { + redraw = 0; + for(layer = 0; layer < nlayer; layer++) + { + fg[layer] = (tcache[kind][idx].id[layer]-1)>>16; + bg[layer] = (tcache[kind][idx].id[layer]-1)&0xffff; + if((fg[layer]&TILE_FLAG_MASK) == tile) redraw = 1; + if((bg[layer]&TILE_FLAG_MASK) == tile) redraw = 1; + } + if (redraw) + { + tcache_compose_normal(idx, fg, bg); + } + } + } +} + +void get_bbg(int bg, int *new_bg, int *bbg) +{ + int bg0 = bg & TILE_FLAG_MASK; + *bbg=simple_iso_tile(TILE_DNGN_FLOOR); + *new_bg= bg0; + + if(bg0 == TILE_DNGN_UNSEEN || + (bg0 >= TILE_DNGN_ROCK_WALL_OFS && bg0 < TILE_DNGN_WAX_WALL) || + bg0 == 0) + *bbg = 0; + else + if( bg0 >= TILE_DNGN_FLOOR && bg0 <= TILE_DNGN_SHALLOW_WATER) + { + *bbg = bg; + *new_bg = 0; + } +} + +int sink_mask_tile(int bg, int fg) +{ + int bg0 = bg & TILE_FLAG_MASK; + + if (fg == 0 || (fg & TILE_FLAG_FLYING)!=0) return 0; +/* + if ( bg0 == simple_iso_tile(TILE_DNGN_SHALLOW_WATER)) + return TILE_MASK_SHALLOW_WATER; + if ( bg0 == simple_iso_tile(TILE_DNGN_DEEP_WATER)) + return TILE_MASK_DEEP_WATER; + if ( bg0 >= simple_iso_tile(TILE_DNGN_LAVA) && + bg0 <= simple_iso_tile(TILE_DNGN_LAVA)+3) + return TILE_MASK_LAVA; +*/ + if ( bg0 >= simple_iso_tile(TILE_DNGN_LAVA) && + bg0 <= simple_iso_tile(TILE_DNGN_SHALLOW_WATER) + 3) + { + int result = TILE_SINK_MASK;//simple_iso_tile(TILE_SINK_MASK); + if ((fg & TILE_FLAG_MASK) >= TILE_NORMAL) + result = simple_iso_tile(TILE_SINK_MASK); + //if ((fg & TILE_FLAG_MASK) >= TILE_NORMAL) result++; + return result; + } + + return 0; +} + +//normal +void tcache_compose_normal(int ix, int *fg, int *bg){ + int bbg; + int new_bg; + int c=1; + int fg0=fg[0]; + int bg0=bg[0]; + int sink; + img_type tc_img = tcache_image[TCACHE0_NORMAL]; + + get_bbg(bg0, &new_bg, &bbg); + + if(bbg) tcache_overlay(tc_img, ix, bbg, TREGION_0_NORMAL, &c, NULL); + if(new_bg) tcache_overlay(tc_img, ix, new_bg, TREGION_0_NORMAL, &c, NULL); + + //Tile cursor + if(bg0&TILE_FLAG_CURSOR) + { + int type = ((bg0&TILE_FLAG_CURSOR) == TILE_FLAG_CURSOR1) ? + TILE_CURSOR : TILE_CURSOR2; + + if ((bg0&TILE_FLAG_CURSOR) == TILE_FLAG_CURSOR3) type = TILE_CURSOR3; + + tcache_overlay(tc_img, ix, type, TREGION_0_NORMAL, &c, NULL); + + if (type != TILE_CURSOR3) c = 2;// Hilite + } + + if (bg0 & TILE_FLAG_RAY) + tcache_overlay(tc_img, ix, TILE_RAY_MESH, TREGION_0_NORMAL, &c, NULL); + + if(fg0) + { + sink = sink_mask_tile(bg0, fg0); + if (sink) + { + int flag=2; + register_tile_mask(sink, TREGION_0_NORMAL, &flag, sink_mask); + tcache_overlay(tc_img, ix, fg0, TREGION_0_NORMAL, &c, sink_mask); + } + else + tcache_overlay(tc_img, ix, fg0, TREGION_0_NORMAL, &c, NULL); + } + + if (fg0 & TILE_FLAG_NET) + tcache_overlay(tc_img, ix, TILE_TRAP_NET, TREGION_0_NORMAL, &c, NULL); + + if(fg0 & TILE_FLAG_S_UNDER) + tcache_overlay(tc_img, ix, TILE_SOMETHING_UNDER, + TREGION_0_NORMAL, &c, NULL); + + //Pet mark + if((fg0&TILE_FLAG_MAY_STAB) == TILE_FLAG_PET) + tcache_overlay(tc_img, ix, TILE_HEART, TREGION_0_NORMAL, &c, NULL); + + if((fg0&TILE_FLAG_MAY_STAB) == TILE_FLAG_STAB) + tcache_overlay(tc_img, ix, TILE_STAB_BRAND, TREGION_0_NORMAL, &c, NULL); + else if((fg0&TILE_FLAG_MAY_STAB) == TILE_FLAG_MAY_STAB) + tcache_overlay(tc_img, ix, TILE_MAY_STAB_BRAND, TREGION_0_NORMAL, &c, + NULL); + + if(bg0&TILE_FLAG_UNSEEN) + tcache_overlay(tc_img, ix, TILE_MESH, TREGION_0_NORMAL, &c, NULL); + + if(bg0&TILE_FLAG_MM_UNSEEN) + tcache_overlay(tc_img, ix, TILE_MAGIC_MAP_MESH, TREGION_0_NORMAL, &c, NULL); +} + +// Tile cursor +int TileDrawCursor(int x, int y, int cflag) +{ + int oldc = t2buf[x+1][y+1] & TILE_FLAG_CURSOR; + t2buf[x+1][y+1] &= ~ TILE_FLAG_CURSOR; + t2buf[x+1][y+1] |= cflag; + update_single_grid(x, y); + return oldc; +} + +void TileDrawBolt(int x, int y, int fg){ + + t1buf[x+1][y+1]=fg | TILE_FLAG_FLYING; + update_single_grid(x, y); +} + +void StoreDungeonView(short unsigned int *tileb) +{ + int x, y; + int count = 0; + + if (tileb == NULL) + tileb = tb_bk; + + for(y=0;y<tile_dngn_y;y++){ + for(x=0;x<tile_dngn_x;x++){ + tileb[count] = t1buf[x+1][y+1]; + count ++; + tileb[count] = t2buf[x+1][y+1]; + count ++; + }} +} + +void LoadDungeonView(short unsigned int *tileb) +{ + int x, y; + int count = 0; + + if (tileb == NULL) + tileb = tb_bk; + + for(y=0;y<tile_dngn_y;y++) + { + for(x=0;x<tile_dngn_x;x++) + { + if(tileb[count]==tileb[count+1]) + tileb[count]=0; + t1buf[x+1][y+1] = tileb[count]; + count ++; + t2buf[x+1][y+1] = tileb[count]; + count ++; + } + } +} + +//Draw the tile screen once and for all +void TileDrawDungeon(short unsigned int *tileb) +{ + int x, y, kind; + if(!TileImg)return; + + LoadDungeonView(tileb); + + extern int tile_cursor_x; + tile_cursor_x = -1; + + for(kind=0;kind<tcache_kind;kind++) + { + for(x=0;x<tile_xmax;x++) + { + for(y=0;y<tile_ymax;y++) + { + tile_draw_grid(kind, x, y); + } + } + } + + force_redraw_tile = false; + TileDrawDungeonAux(); + region_tile->redraw(); +} + +void TileDrawFarDungeon(int cx, int cy) +{ + short unsigned int tb[TILE_DAT_YMAX*TILE_DAT_XMAX*2]; + + int count = 0; + for(int y=0; y<tile_dngn_y; y++) + { + for(int x=0; x<tile_dngn_x; x++) + { + int fg; + int bg; + + const coord_def gc( + cx + x - tile_dngn_x/2, + cy + y - tile_dngn_y/2 ); + const coord_def ep = view2show(grid2view(gc)); + + // mini "viewwindow" routine + if (!map_bounds(gc)) + { + fg = 0; + bg = TILE_DNGN_UNSEEN; + } + else if (!crawl_view.in_grid_los(gc) || !env.show(ep)) + { + fg = env.tile_bk_fg[gc.x][gc.y]; + bg = env.tile_bk_bg[gc.x][gc.y]; + if (bg == 0) + bg |= TILE_DNGN_UNSEEN; + bg |= tile_unseen_flag(gc); + } + else + { + fg = env.tile_fg[ep.x-1][ep.y-1]; + bg = env.tile_bg[ep.x-1][ep.y-1]; + } + + if (gc.x == cx && gc.y == cy) + bg |= TILE_FLAG_CURSOR1; + + tb[count++]=fg; + tb[count++]=bg; + } + } + tile_finish_dngn(tb, cx, cy); + TileDrawDungeon(tb); + region_tile->redraw(); +} + +void TileDrawMap(int gx, int gy) +{ + TileDrawFarDungeon(gx, gy); +} + +// Load optional wall tile +static void TileLoadWallAux(int idx_src, int idx_dst, img_type wall) +{ + int tile_per_row = ImgWidth(wall) / TILE_X; + + int sx = idx_src % tile_per_row; + int sy = idx_src / tile_per_row; + + sx *= TILE_X; + sy *= TILE_Y; + + ImgCopyToTileImg(idx_dst, wall, sx, sy, 1); +} + +void WallIdx(int &wall, int &floor, int &special) +{ + special = -1; + + if (you.level_type == LEVEL_PANDEMONIUM) + { + switch (mcolour[env.mons_alloc[8]]) + { + case BLUE: + case LIGHTBLUE: + wall = IDX_WALL_ZOT_BLUE; + floor = IDX_FLOOR_ZOT_BLUE; + return; + + case RED: + case LIGHTRED: + wall = IDX_WALL_ZOT_RED; + floor = IDX_FLOOR_ZOT_RED; + return; + + case MAGENTA: + case LIGHTMAGENTA: + wall = IDX_WALL_ZOT_MAGENTA; + floor = IDX_FLOOR_ZOT_MAGENTA; + return; + + case GREEN: + case LIGHTGREEN: + wall = IDX_WALL_ZOT_GREEN; + floor = IDX_FLOOR_ZOT_GREEN; + return; + + case CYAN: + case LIGHTCYAN: + wall = IDX_WALL_ZOT_CYAN; + floor = IDX_FLOOR_ZOT_CYAN; + return; + + case BROWN: + case YELLOW: + wall = IDX_WALL_ZOT_YELLOW; + floor = IDX_FLOOR_ZOT_YELLOW; + return; + + case BLACK: + case WHITE: + default: + wall = IDX_WALL_ZOT_GRAY; + floor = IDX_FLOOR_ZOT_GRAY; + return; + } + } + else if (you.level_type == LEVEL_ABYSS) + { + wall = IDX_WALL_UNDEAD; + floor = IDX_FLOOR_UNDEAD; + return; + } + else if (you.level_type == LEVEL_LABYRINTH) + { + wall = IDX_WALL_UNDEAD; + floor = IDX_FLOOR_UNDEAD; + return; + } + else if (you.level_type == LEVEL_PORTAL_VAULT) + { + if (you.level_type_name == "bazaar") + { + // Bazaar tiles here lean towards grass and dirt to emphasize + // both the non-hostile and other-wordly aspects of the + // portal vaults (i.e. they aren't in the dungeon, necessarily.) + int colour = env.floor_colour; + switch (colour) + { + case BLUE: + wall = IDX_WALL_BAZAAR_GRAY; + floor = IDX_FLOOR_BAZAAR_GRASS; + special = IDX_FLOOR_BAZAAR_GRASS1_SPECIAL; + return; + + case RED: + // Reds often have lava, which looks ridiculous + // next to grass or dirt, so we'll use existing + // floor and wall tiles here. + wall = IDX_WALL_ZOT_RED; + floor = IDX_FLOOR_VAULT; + special = IDX_FLOOR_BAZAAR_VAULT_SPECIAL; + return; + + case LIGHTBLUE: + wall = IDX_WALL_HIVE; + floor = IDX_FLOOR_BAZAAR_GRASS; + special = IDX_FLOOR_BAZAAR_GRASS2_SPECIAL; + return; + + case GREEN: + wall = IDX_WALL_BAZAAR_STONE; + floor = IDX_FLOOR_BAZAAR_GRASS; + special = IDX_FLOOR_BAZAAR_GRASS1_SPECIAL; + return; + + case MAGENTA: + wall = IDX_WALL_BAZAAR_STONE; + floor = IDX_FLOOR_BAZAAR_DIRT; + special = IDX_FLOOR_BAZAAR_DIRT_SPECIAL; + return; + + default: + wall = IDX_WALL_VAULT; + floor = IDX_FLOOR_VAULT; + special = IDX_FLOOR_BAZAAR_VAULT_SPECIAL; + return; + } + } + } + + switch (you.where_are_you) + { + case BRANCH_MAIN_DUNGEON: + wall = IDX_WALL_NORMAL; + floor = IDX_FLOOR_NORMAL; + return; + + case BRANCH_HIVE: + wall = IDX_WALL_HIVE; + floor = IDX_FLOOR_HIVE; + return; + + case BRANCH_VAULTS: + wall = IDX_WALL_VAULT; + floor = IDX_FLOOR_VAULT; + return; + + case BRANCH_ELVEN_HALLS: + case BRANCH_HALL_OF_BLADES: + case BRANCH_ECUMENICAL_TEMPLE: + wall = IDX_WALL_HALL; + floor = IDX_FLOOR_HALL; + return; + + case BRANCH_TARTARUS: + case BRANCH_CRYPT: + case BRANCH_VESTIBULE_OF_HELL: + wall = IDX_WALL_UNDEAD; + floor = IDX_FLOOR_UNDEAD; + return; + + case BRANCH_TOMB: + wall = IDX_WALL_TOMB; + floor = IDX_FLOOR_TOMB; + return; + + case BRANCH_DIS: + wall = IDX_WALL_ZOT_CYAN; + floor = IDX_FLOOR_ZOT_CYAN; + return; + + case BRANCH_GEHENNA: + case BRANCH_INFERNO: + case BRANCH_THE_PIT: + wall = IDX_WALL_ZOT_RED; + floor = IDX_FLOOR_ZOT_RED; + return; + + case BRANCH_COCYTUS: + wall = IDX_WALL_ICE; + floor = IDX_FLOOR_ICE; + return; + + case BRANCH_ORCISH_MINES: + wall = IDX_WALL_ORC; + floor = IDX_FLOOR_ORC; + return; + + case BRANCH_LAIR: + wall = IDX_WALL_LAIR; + floor = IDX_FLOOR_LAIR; + return; + + case BRANCH_SLIME_PITS: + wall = IDX_WALL_SLIME; + floor = IDX_FLOOR_SLIME; + return; + + case BRANCH_SNAKE_PIT: + wall = IDX_WALL_SNAKE; + floor = IDX_FLOOR_SNAKE; + return; + + case BRANCH_SWAMP: + wall = IDX_WALL_SWAMP; + floor = IDX_FLOOR_SWAMP; + return; + + case BRANCH_SHOALS: + wall = IDX_WALL_SWAMP; + floor = IDX_FLOOR_SWAMP; + return; + + case BRANCH_CAVERNS: + wall = IDX_WALL_ORC; + floor = IDX_FLOOR_ORC; + return; + + case BRANCH_HALL_OF_ZOT: + if (you.your_level - you.branch_stairs[7] <= 1) + { + wall = IDX_WALL_ZOT_YELLOW; + floor = IDX_FLOOR_ZOT_YELLOW; + return; + } + + switch (you.your_level - you.branch_stairs[7]) + { + case 2: + wall = IDX_WALL_ZOT_GREEN; + floor = IDX_FLOOR_ZOT_GREEN; + return; + case 3: + wall = IDX_WALL_ZOT_CYAN; + floor = IDX_WALL_ZOT_CYAN; + return; + case 4: + wall = IDX_WALL_ZOT_BLUE; + floor = IDX_FLOOR_ZOT_GREEN; + return; + case 5: + default: + wall = IDX_WALL_ZOT_MAGENTA; + floor = IDX_FLOOR_ZOT_MAGENTA; + return; + } + + case NUM_BRANCHES: + break; + + // NOTE: there is no default case in this switch statement so that + // the compiler will issue a warning when new branches are created. + } + + wall = IDX_WALL_NORMAL; + floor = IDX_FLOOR_NORMAL; +} +void TileLoadWall(bool wizard) +{ + clear_tcache(); + force_redraw_tile = true; + + int wall_idx; + int floor_idx; + int special_idx; + WallIdx(wall_idx, floor_idx, special_idx); + + // Number of flavors are generated automatically... + + floor_tile_idx = TILE_DNGN_FLOOR; + floor_flavors = tile_W2D_count[floor_idx]; + int offset = floor_tile_idx; + for (int i = 0; i < floor_flavors; i++) + { + int idx_src = tile_W2D_start[floor_idx] + i; + int idx_dst = offset++; + TileLoadWallAux(idx_src, idx_dst, WallImg); + } + + wall_tile_idx = offset; + wall_flavors = tile_W2D_count[wall_idx]; + for (int i = 0; i < wall_flavors; i++) + { + int idx_src = tile_W2D_start[wall_idx] + i; + int idx_dst = offset++; + TileLoadWallAux(idx_src, idx_dst, WallImg); + } + + if (special_idx != -1) + { + special_tile_idx = offset; + special_flavors = tile_W2D_count[special_idx]; + for (int i = 0; i < special_flavors; i++) + { + int idx_src = tile_W2D_start[special_idx] + i; + int idx_dst = offset++; + TileLoadWallAux(idx_src, idx_dst, WallImg); + } + } + else + { + special_flavors = 0; + } +} + +#define DOLLS_MAX 11 +#define PARTS_DISP_MAX 11 +#define PARTS_ITEMS 12 +#define TILEP_SELECT_DOLL 20 + +typedef struct dolls_data +{ + int parts[TILEP_PARTS_TOTAL]; +} dolls_data; +static dolls_data current_doll; +static int current_gender = 0; +static int current_parts[TILEP_PARTS_TOTAL]; + +static bool draw_doll(img_type img, dolls_data *doll, bool force_redraw = false, bool your_doll = true) +{ + const int p_order[TILEP_PARTS_TOTAL]= + { + TILEP_PART_SHADOW, + TILEP_PART_DRCWING, + TILEP_PART_CLOAK, + TILEP_PART_BASE, + TILEP_PART_BOOTS, + TILEP_PART_LEG, + TILEP_PART_BODY, + TILEP_PART_ARM, + TILEP_PART_HAND1, + TILEP_PART_HAND2, + TILEP_PART_HAIR, + TILEP_PART_BEARD, + TILEP_PART_HELM, + TILEP_PART_DRCHEAD + }; + int p_order2[TILEP_PARTS_TOTAL]; + + int i; + int flags[TILEP_PARTS_TOTAL]; + int parts2[TILEP_PARTS_TOTAL]; + int *parts = doll->parts; + int c=1; + bool changed = false; + + int default_parts[TILEP_PARTS_TOTAL]; + memset(default_parts, 0, sizeof(default_parts)); + + if (your_doll) + { + tilep_race_default(you.species, parts[TILEP_PART_BASE] % 2, + you.experience_level, default_parts); + + if (default_parts[TILEP_PART_BASE] != parts[TILEP_PART_BASE]) + force_redraw = true; + parts[TILEP_PART_BASE] = default_parts[TILEP_PART_BASE]; + + // TODO enne - make these configurable. + parts[TILEP_PART_DRCHEAD] = default_parts[TILEP_PART_DRCHEAD]; + parts[TILEP_PART_DRCWING] = default_parts[TILEP_PART_DRCWING]; + } + + // convert TILEP_SHOW_EQUIP into real parts number + for(i = 0; i < TILEP_PARTS_TOTAL; i++) + { + parts2[i] = parts[i]; + if (parts2[i] == TILEP_SHOW_EQUIP) + { + switch (i) + { + int item; + case TILEP_PART_HAND1: + item = you.equip[EQ_WEAPON]; + if (you.attribute[ATTR_TRANSFORMATION] == + TRAN_BLADE_HANDS) + { + parts2[i] = TILEP_HAND1_BLADEHAND; + } + else if (item == -1) + { + parts2[i] = 0; + } + else + { + parts2[i] = tilep_equ_weapon(you.inv[item]); + } + break; + + case TILEP_PART_HAND2: + item = you.equip[EQ_SHIELD]; + if (you.attribute[ATTR_TRANSFORMATION] == + TRAN_BLADE_HANDS) + { + parts2[i] = TILEP_HAND2_BLADEHAND; + } + else if (item == -1) + { + parts2[i] = 0; + } + else + { + parts2[i] = tilep_equ_shield(you.inv[item]); + } + break; + + case TILEP_PART_BODY: + item = you.equip[EQ_BODY_ARMOUR]; + if (item == -1) + parts2[i] = 0; + else + parts2[i] = tilep_equ_armour(you.inv[item]); + break; + + case TILEP_PART_CLOAK: + item = you.equip[EQ_CLOAK]; + if (item == -1) + parts2[i] = 0; + else + parts2[i] = tilep_equ_cloak(you.inv[item]); + break; + + case TILEP_PART_HELM: + item = you.equip[EQ_HELMET]; + if (item == -1) + parts2[i] = 0; + else + parts2[i] = tilep_equ_helm(you.inv[item]); + + if (parts2[i] == 0 && you.mutation[MUT_HORNS] > 0) + { + switch (you.mutation[MUT_HORNS]) + { + case 1: + parts2[i] = TILEP_HELM_HORNS1; + break; + case 2: + parts2[i] = TILEP_HELM_HORNS2; + break; + case 3: + parts2[i] = TILEP_HELM_HORNS3; + break; + } + } + + break; + + case TILEP_PART_BOOTS: + item = you.equip[EQ_BOOTS]; + if (item == -1) + parts2[i] = 0; + else + parts2[i] = tilep_equ_boots(you.inv[item]); + + if (parts2[i] == 0 && you.mutation[MUT_HOOVES]) + parts2[i] = TILEP_BOOTS_HOOVES; + break; + + case TILEP_PART_ARM: + item = you.equip[EQ_GLOVES]; + if (item == -1) + parts2[i] = 0; + else + parts2[i] = tilep_equ_gloves(you.inv[item]); + + // There is player_has_claws() but it is not equivalent. + // Claws appear if they're big enough to not wear gloves + // or on races that have claws. + if (parts2[i] == 0 && (you.mutation[MUT_CLAWS] >= 3 || + you.species == SP_TROLL || you.species == SP_GHOUL)) + { + parts2[i] = TILEP_ARM_CLAWS; + } + break; + + case TILEP_PART_HAIR: + case TILEP_PART_BEARD: + parts2[i] = default_parts[i]; + break; + + case TILEP_PART_LEG: + default: + parts2[i] = 0; + } + } + + if (parts2[i] != current_parts[i]) + changed = true; + current_parts[i] = parts2[i]; + } + + + if (!changed && !force_redraw) + { + return false; + } + + tilep_calc_flags(parts2, flags); + ImgClear(img); + + // Hack: change overlay order of boots/skirts + for(i = 0; i < TILEP_PARTS_TOTAL; i++) + p_order2[i]=p_order[i]; + + // swap boot and leg-armor + if (parts2[TILEP_PART_LEG] < TILEP_LEG_SKIRT_OFS) + { + p_order2[5] = TILEP_PART_LEG; + p_order2[4] = TILEP_PART_BOOTS; + } + + for(i = 0; i < TILEP_PARTS_TOTAL; i++) + { + int p = p_order2[i]; + int ymax = TILE_Y; + if (flags[p]==TILEP_FLAG_CUT_CENTAUR) ymax=18; + if (flags[p]==TILEP_FLAG_CUT_NAGA) ymax=18; + + if (parts2[p] && p == TILEP_PART_BOOTS && + (parts2[p] == TILEP_BOOTS_NAGA_BARDING || + parts2[p] == TILEP_BOOTS_CENTAUR_BARDING)) + { + // Special case for barding. They should be in "boots" but because + // they're double-wide, they're stored in a different part. We just + // intercept it here before drawing. + char tile = parts2[p] == TILEP_BOOTS_NAGA_BARDING ? + TILEP_SHADOW_NAGA_BARDING : TILEP_SHADOW_CENTAUR_BARDING; + tcache_overlay_player(img, 0, 0, TILEP_PART_SHADOW, tile, + TILE_Y, &c); + } + else if(parts2[p] && flags[p]) + { + tcache_overlay_player(img, 0, 0, p, parts2[p], ymax, &c); + } + } + return true; +} + +static void load_doll_data(const char *fn, dolls_data *dolls, int max, + int *mode, int *cur) +{ + char fbuf[1024]; + int cur0 = 0; + int mode0 = TILEP_M_DEFAULT; + FILE *fp = NULL; + + std::string dollsTxtString = datafile_path(fn, false, true); + const char *dollsTxt = dollsTxtString.c_str()[0] == 0 ? + "dolls.txt" : dollsTxtString.c_str(); + + if ( (fp = fopen(dollsTxt, "r")) == NULL ) + { + // File doesn't exist. By default, use show equipment defaults. + // This will be saved out (if possible.) + + for (int i = 0; i < max; i++) + { + // Don't take gender too seriously. -- Enne + tilep_race_default(you.species, coinflip() ? 1 : 0, + you.experience_level, dolls[i].parts); + + dolls[i].parts[TILEP_PART_SHADOW] = 1; + dolls[i].parts[TILEP_PART_CLOAK] = TILEP_SHOW_EQUIP; + dolls[i].parts[TILEP_PART_BOOTS] = TILEP_SHOW_EQUIP; + dolls[i].parts[TILEP_PART_LEG] = TILEP_SHOW_EQUIP; + dolls[i].parts[TILEP_PART_BODY] = TILEP_SHOW_EQUIP; + dolls[i].parts[TILEP_PART_ARM] = TILEP_SHOW_EQUIP; + dolls[i].parts[TILEP_PART_HAND1] = TILEP_SHOW_EQUIP; + dolls[i].parts[TILEP_PART_HAND2] = TILEP_SHOW_EQUIP; + dolls[i].parts[TILEP_PART_HAIR] = TILEP_SHOW_EQUIP; + dolls[i].parts[TILEP_PART_BEARD] = TILEP_SHOW_EQUIP; + dolls[i].parts[TILEP_PART_HELM] = TILEP_SHOW_EQUIP; + } + + } + else + { + memset(fbuf, 0, sizeof(fbuf)); + if (fscanf(fp, "%s", fbuf) != EOF) + { + if (strcmp(fbuf, "MODE=LOADING") == 0) + mode0 = TILEP_M_LOADING; + } + if (fscanf(fp, "%s", fbuf) != EOF) + { + if (strncmp(fbuf, "NUM=", 4) == 0) + { + sscanf(fbuf, "NUM=%d",&cur0); + if ( (cur0 < 0)||(cur0 > 10) ) + cur0 = 0; + } + } + if (max == 1) + { + for(int j = 0; j <= cur0; j++) + { + if (fscanf(fp, "%s", fbuf) != EOF) + { + tilep_scan_parts(fbuf, dolls[0].parts); + } + else + { + break; + } + } + } + else + { + for(int j = 0; j < max; j++) + { + if (fscanf(fp, "%s", fbuf) != EOF) + { + tilep_scan_parts(fbuf, dolls[j].parts); + } + else + { + break; + } + } + } + + fclose(fp); + } + *mode = mode0; + *cur = cur0; + + current_gender = dolls[cur0].parts[TILEP_PART_BASE] % 2; +} + +void TilePlayerEdit() +{ + const int p_lines[PARTS_ITEMS]= + { + TILEP_SELECT_DOLL, + TILEP_PART_BASE, + TILEP_PART_HELM, + TILEP_PART_HAIR, + TILEP_PART_BEARD, + TILEP_PART_HAND1, + TILEP_PART_HAND2, + TILEP_PART_ARM, + TILEP_PART_BODY, + TILEP_PART_LEG, + TILEP_PART_BOOTS, + TILEP_PART_CLOAK + }; + + const char *p_names[PARTS_ITEMS]= + { + " Index:", + " Gendr:", + " Helm :", + " Hair :", + " Beard:", + " Weapn:", + " Shild:", + " Glove:", + " Armor:", + " Legs :", + " Boots:", + " Cloak:" + }; + + const char *gender_name[2] ={ + "Male", + "Fem " + }; + +#define display_parts_idx(part) \ +{ \ + gotoxy(10 , part + 1, GOTO_STAT); \ + tilep_part_to_str(dolls[cur_doll].parts[ p_lines[part] ], ibuf);\ + cprintf(ibuf);\ +} + + dolls_data dolls[DOLLS_MAX], undo_dolls[DOLLS_MAX]; + int copy_doll[TILEP_PARTS_TOTAL]; + + //int parts[TILEP_PARTS_TOTAL]; + int i, j, k, x, y, kin, done = 0; + int cur_doll = 0; + int pre_part = 0; + int cur_part = 0; + int mode = TILEP_M_DEFAULT; + int d = 0; + FILE *fp; + char fbuf[80], ibuf[8]; + int tile_str, sx, sy; + + img_type PartsImg = ImgCreateSimple(TILE_X * PARTS_DISP_MAX, TILE_Y * 1); + + img_type DollsListImg = ImgCreateSimple( TILE_X * DOLLS_MAX, TILE_Y * 1); + + ImgClear(ScrBufImg); + + memset( copy_doll, 0, sizeof(dolls_data) ); + tilep_race_default(you.species, current_gender, + you.experience_level, copy_doll); + + for(j = 0; j < DOLLS_MAX; j++) + { + memset( dolls[j].parts, 0, sizeof(dolls_data) ); + memset( undo_dolls[j].parts, 0, sizeof(dolls_data) ); + tilep_race_default(you.species, current_gender, you.experience_level, + dolls[j].parts); + tilep_race_default(you.species, current_gender, you.experience_level, + undo_dolls[j].parts); + } + + // load settings + load_doll_data("dolls.txt", dolls, DOLLS_MAX, &mode, &cur_doll); + for(j = 0; j < DOLLS_MAX; j++) + { + undo_dolls[j] = dolls[j]; + } + clrscr(); + gotoxy(1,1, GOTO_MSG); + mpr("Select Part : [j][k]or[up][down]"); + mpr("Change Part/Page : [h][l]or[left][right]/[H][L]"); + mpr("Class-Default : [CTRL]+[D]"); + mpr("Toggle Equipment Mode : [*]"); + mpr("Take off/Take off All : [t]/[CTRL]+[T]"); + mpr("Copy/Paste/Undo : [CTRL]+[C]/[CTRL]+[V]/[CTRL]+[Z]"); + mpr("Randomize : [CTRL]+[R]"); + + gotoxy(1, 8, GOTO_MSG); + cprintf("Toggle Startup mode : [m] (Current mode:%s)", + ( (mode == TILEP_M_LOADING) ? "Load User's Settings":"Class Default" )); + for (j=0; j < PARTS_ITEMS; j++) + { + gotoxy(1, 1+j, GOTO_STAT); + cprintf(p_names[j]); + } + +#define PARTS_Y (TILE_Y*11) + +// draw strings "Dolls/Parts" into backbuffer + tile_str = TILE_TEXT_PARTS_E; + sx = (tile_str % TILE_PER_ROW)*TILE_X; + sy = (tile_str / TILE_PER_ROW)*TILE_Y; + + ImgCopy(TileImg, sx, sy, TILE_X, TILE_Y/2, + ScrBufImg, (TILE_X * 3) - 8,(TILE_Y * 4) - 8-24, 0); + ImgCopy(TileImg, sx, sy+ TILE_Y/2, TILE_X, TILE_Y/2, + ScrBufImg, (TILE_X * 4) - 8,(TILE_Y * 4) - 8-24, 0); + + tile_str = TILE_TEXT_DOLLS_E; + sx = (tile_str % TILE_PER_ROW)*TILE_X; + sy = (tile_str / TILE_PER_ROW)*TILE_Y; + ImgCopy(TileImg, sx, sy, TILE_X, TILE_Y/2, + ScrBufImg, (TILE_X * 3) - 8,PARTS_Y - 8 -24, 0); + ImgCopy(TileImg, sx, sy+ TILE_Y/2, TILE_X, TILE_Y/2, + ScrBufImg, (TILE_X * 4) - 8,PARTS_Y - 8 -24, 0); + + ImgClear(DollsListImg); + for(j = 0; j < DOLLS_MAX; j++) + { + draw_doll(DollCacheImg, &dolls[j], true); + ImgCopy(DollCacheImg, 0, 0, + ImgWidth(DollCacheImg), ImgHeight(DollCacheImg), + DollsListImg, j * TILE_X, 0, 1); + } + + done = 0; + + while (!done) + { + static int inc = 1; + static int cur_inc = 1; + + ImgClear(PartsImg); + + region_tile->DrawPanel((TILE_X * 3) - 8, (TILE_Y * 4) - 8, + ImgWidth(PartsImg) + 16, ImgHeight(PartsImg) + 16); + region_tile->DrawPanel((TILE_X * 3) - 8, PARTS_Y - 8, + ImgWidth(DollsListImg) + 16, ImgHeight(DollsListImg) + 16); + region_tile->DrawPanel(8*TILE_X - 8, 8*TILE_Y - 8, + TILE_X + 16, TILE_Y + 16); + + if (cur_part == 0) + { + // now selecting doll index + gotoxy(10 , 1, GOTO_STAT); + cprintf("%02d", cur_doll); + gotoxy(10 , 2, GOTO_STAT); + current_gender = dolls[cur_doll].parts[TILEP_PART_BASE] % 2; + cprintf("%s", gender_name[ current_gender ]); + + for (i = 2; i<PARTS_ITEMS; i++) + { + gotoxy(10 , i + 1, GOTO_STAT); + tilep_part_to_str(dolls[cur_doll].parts[ p_lines[i] ], ibuf); + cprintf("%s / %03d", ibuf, tilep_parts_total[ p_lines[i] ]); + } + } + else + { + for(i = 0; i < PARTS_DISP_MAX; i++) + { + int index; + if (dolls[cur_doll].parts[ p_lines[cur_part] ] + == TILEP_SHOW_EQUIP) + index = 0; + else + index = i + dolls[cur_doll].parts[ p_lines[cur_part] ] + - (PARTS_DISP_MAX / 2); + if (index < 0) + index = index + tilep_parts_total[ p_lines[cur_part] ] + 1; + if (index > tilep_parts_total[ p_lines[cur_part] ]) + index = index - tilep_parts_total[ p_lines[cur_part] ] - 1; + tcache_overlay_player(PartsImg, i * TILE_X, 0, + p_lines[cur_part], index, TILE_Y, &d); + } + ImgCopy(PartsImg, 0, 0, ImgWidth(PartsImg), ImgHeight(PartsImg), + ScrBufImg, 3 * TILE_X, 4 * TILE_Y, 0); + ImgCopyFromTileImg( TILE_CURSOR, ScrBufImg, + (3 + PARTS_DISP_MAX / 2) * TILE_X, 4 * TILE_Y, 0); + } + draw_doll(DollCacheImg, &dolls[cur_doll], true); + + ImgCopy(DollCacheImg, 0, 0, TILE_X, TILE_Y, + DollsListImg, cur_doll*TILE_X, 0, 1); + + ImgCopyToTileImg(TILE_PLAYER, DollCacheImg, 0, 0, 1); + ImgCopyFromTileImg(TILE_PLAYER, ScrBufImg, 8*TILE_X, 8*TILE_Y, 0); + ImgCopy(DollsListImg, 0, 0, + ImgWidth(DollsListImg), ImgHeight(DollsListImg), + ScrBufImg, 3 * TILE_X, PARTS_Y, 0); + ImgCopyFromTileImg( TILE_CURSOR, ScrBufImg, + (3 + cur_doll) * TILE_X, PARTS_Y, 0); + region_tile->redraw(); + + gotoxy(10 , cur_part + 1, GOTO_STAT); + + if (cur_part == 1) + { + current_gender = dolls[cur_doll].parts[p_lines[cur_part] ]%2; + cprintf("%s", gender_name[ current_gender ]); + } + else if (cur_part != 0) + { + tilep_part_to_str(dolls[cur_doll].parts[ p_lines[cur_part] ], ibuf); + cprintf("%s", ibuf); + } + + gotoxy(1, pre_part + 1, GOTO_STAT);cprintf(" "); + gotoxy(1, cur_part + 1, GOTO_STAT);cprintf("->"); + pre_part = cur_part; + + /* Get a key */ + kin = getch(); + + inc = cur_inc = 0; + + /* Analyze the key */ + switch (kin) + { + case 0x1B: //ESC + done = 1; + break; + + case 'h': + inc = -1; + break; + case 'l': + inc = +1; + break; + case 'H': + inc = -PARTS_DISP_MAX; + break; + case 'L': + inc = +PARTS_DISP_MAX; + break; + case 'j': + { + if (cur_part < (PARTS_ITEMS-1) ) + cur_part += 1; + else + cur_part = 0; + break; + } + case 'k': + { + if (cur_part > 0) + cur_part -= 1; + else + cur_part = (PARTS_ITEMS-1); + break; + } + case 'm': + { + if (mode == TILEP_M_LOADING) + mode = TILEP_M_DEFAULT; + else + mode = TILEP_M_LOADING; + + gotoxy(1, 8, GOTO_MSG); + cprintf("Toggle Startup mode : [m] (Current mode:%s)", + ( (mode == TILEP_M_LOADING) ? "Load User's Settings":"Class Default" )); + break; + } + + case 't': + { + if (cur_part >= 2) + { + dolls[cur_doll].parts[ p_lines[cur_part] ] = 0; + display_parts_idx(cur_part); + } + break; + } + + case CONTROL('D'): + { + tilep_job_default(you.char_class, current_gender, + dolls[cur_doll].parts); + for(i = 2; i < PARTS_ITEMS; i++) + { + display_parts_idx(i); + } + break; + } + + case CONTROL('T'): + { + for(i = 2; i < PARTS_ITEMS; i++) + { + undo_dolls[cur_doll].parts[ p_lines[i] ] = dolls[cur_doll].parts[ p_lines[i] ]; + dolls[cur_doll].parts[ p_lines[i] ] = 0; + display_parts_idx(i); + } + break; + } + + case CONTROL('C'): + { + for(i = 2; i < PARTS_ITEMS; i++) + { + copy_doll[ p_lines[i] ] = dolls[cur_doll].parts[ p_lines[i] ]; + } + break; + } + + case CONTROL('V'): + { + for(i = 2; i < PARTS_ITEMS; i++) + { + undo_dolls[cur_doll].parts[ p_lines[i] ] = dolls[cur_doll].parts[ p_lines[i] ]; + dolls[cur_doll].parts[ p_lines[i] ] = copy_doll[ p_lines[i] ]; + display_parts_idx(i); + } + break; + } + + case CONTROL('Z'): + { + for(i = 2; i < PARTS_ITEMS; i++) + { + dolls[cur_doll].parts[ p_lines[i] ] = undo_dolls[cur_doll].parts[ p_lines[i] ]; + display_parts_idx(i); + } + break; + } + + case CONTROL('R'): + { + for(i = 2; i < PARTS_ITEMS; i++) + { + undo_dolls[cur_doll].parts[ p_lines[i] ] = dolls[cur_doll].parts[ p_lines[i] ]; + } + dolls[cur_doll].parts[TILEP_PART_CLOAK] = + one_chance_in(2) * ( random2(tilep_parts_total[ TILEP_PART_CLOAK ]) + 1); + dolls[cur_doll].parts[TILEP_PART_BOOTS] = + ( random2(tilep_parts_total[ TILEP_PART_BOOTS ] + 1) ); + dolls[cur_doll].parts[TILEP_PART_LEG] = + ( random2(tilep_parts_total[ TILEP_PART_LEG ] + 1) ); + dolls[cur_doll].parts[TILEP_PART_BODY] = + ( random2(tilep_parts_total[ TILEP_PART_BODY ] + 1) ); + dolls[cur_doll].parts[TILEP_PART_ARM] = + one_chance_in(2) * ( random2(tilep_parts_total[ TILEP_PART_ARM ]) + 1); + dolls[cur_doll].parts[TILEP_PART_HAND1] = + ( random2(tilep_parts_total[ TILEP_PART_HAND1 ] + 1) ); + dolls[cur_doll].parts[TILEP_PART_HAND2] = + one_chance_in(2) * ( random2(tilep_parts_total[ TILEP_PART_HAND2 ]) + 1); + dolls[cur_doll].parts[TILEP_PART_HAIR] = + ( random2(tilep_parts_total[ TILEP_PART_HAIR ] + 1) ); + dolls[cur_doll].parts[TILEP_PART_BEARD] = + ( (dolls[cur_doll].parts[TILEP_PART_BASE] + 1) % 2) * + one_chance_in(4) * ( random2(tilep_parts_total[ TILEP_PART_BEARD ]) + 1 ); + dolls[cur_doll].parts[TILEP_PART_HELM] = + one_chance_in(2) * ( random2(tilep_parts_total[ TILEP_PART_HELM ]) + 1 ); + for(i = 2; i < PARTS_ITEMS; i++) + { + display_parts_idx(i); + } + break; + } + case '*': + { + int part = p_lines[cur_part]; + int *target = &dolls[cur_doll].parts[part]; + + if (part == TILEP_PART_BASE) + continue; + if (*target == TILEP_SHOW_EQUIP) + *target = 0; + else + *target = TILEP_SHOW_EQUIP; + + display_parts_idx(cur_part); + break; + } +#ifdef WIZARD + case '1': + dolls[cur_doll].parts[TILEP_PART_DRCHEAD]++; + dolls[cur_doll].parts[TILEP_PART_DRCHEAD] %= + tilep_parts_total[TILEP_PART_DRCHEAD] -1; + break; + case '2': + dolls[cur_doll].parts[TILEP_PART_DRCWING]++; + dolls[cur_doll].parts[TILEP_PART_DRCWING] %= + tilep_parts_total[TILEP_PART_DRCWING] -1; + break; +#endif + default: + { + } + } + + if (inc != 0) + { + int *target = &dolls[cur_doll].parts[ p_lines[cur_part] ]; + + if (cur_part == 0) + { + if (inc > 0) + cur_doll++; + else + cur_doll--; + if (cur_doll < 0) + cur_doll = DOLLS_MAX -1; + else if (cur_doll == DOLLS_MAX) + cur_doll = 0; + } + else if (cur_part == 1) + { + if (*target % 2) + (*target)++; + else + (*target)--; + } + else + { + if (*target == TILEP_SHOW_EQUIP) continue; + (*target) += inc; + (*target) += tilep_parts_total[ p_lines[cur_part] ]+1; + (*target) %= tilep_parts_total[ p_lines[cur_part] ]+1; + } + } + + delay(20); + } + + current_doll = dolls[cur_doll]; + draw_doll(DollCacheImg, ¤t_doll); + ImgCopyToTileImg(TILE_PLAYER, DollCacheImg, 0, 0, 1); + + std::string dollsTxtString = datafile_path("dolls.txt", false, true); + const char *dollsTxt = dollsTxtString.c_str()[0] == 0 ? + "dolls.txt" : dollsTxtString.c_str(); + + if ( (fp = fopen(dollsTxt, "w+")) == NULL ) + { + } + else + { + fprintf(fp, "MODE=%s\n", ( (mode == TILEP_M_LOADING) ? "LOADING":"DEFAULT" ) ); + fprintf(fp, "NUM=%02d\n", cur_doll); + for(j = 0; j < DOLLS_MAX; j++) + { + tilep_print_parts(fbuf, dolls[j].parts); + fprintf(fp, "%s\n", fbuf); + } + fclose(fp); + } + + ImgDestroy(PartsImg); + ImgDestroy(DollsListImg); + + ImgClear(ScrBufImg); + redraw_spx_tcache(TILE_PLAYER); + + for(x=0;x<TILE_DAT_XMAX+2;x++){ + for(y=0;y<TILE_DAT_YMAX+2;y++){ + t1buf[x][y]=0; + t2buf[x][y]=simple_iso_tile(TILE_DNGN_UNSEEN)|TILE_FLAG_UNSEEN; + }} + + for(k=0;k<tcache_kind;k++) + for(x=0;x<tile_xmax*tile_ymax;x++) + screen_tcach_idx[k][x] = -1; + + clrscr(); + redraw_screen(); +} + +void TilePlayerRefresh() +{ + if (!draw_doll(DollCacheImg, ¤t_doll)) + return; // Not changed + + ImgCopyToTileImg(TILE_PLAYER, DollCacheImg, 0, 0, 1); + + redraw_spx_tcache(TILE_PLAYER); + force_redraw_tile = true; + + const coord_def ep = grid2view(you.pos()); + update_single_grid(ep.x-1, ep.y-1); +} + +void TilePlayerInit() +{ + int i; + int cur_doll = 0; + int mode = TILEP_M_DEFAULT; + dolls_data doll; + int gender = 0; + + for(i = 0; i < TILEP_PARTS_TOTAL; i++) + doll.parts[i] = 0; + tilep_race_default(you.species, gender, you.experience_level, doll.parts); + tilep_job_default(you.char_class, gender, doll.parts); + + load_doll_data("dolls.txt", &doll, 1, &mode, &cur_doll); + current_doll = doll; + draw_doll(DollCacheImg, &doll); + + ImgCopyToTileImg(TILE_PLAYER, DollCacheImg, 0, 0, 1); + +} + +void TileGhostInit(struct ghost_demon &ghost) +{ + dolls_data doll; + int x, y; + unsigned int pseudo_rand = ghost.values[GVAL_MAX_HP]*54321*54321; + char mask[TILE_X*TILE_Y]; + int g_gender = (pseudo_rand >>8)&1; + + for (x=0; x<TILE_X; x++) + for (y=0; y<TILE_X; y++) + mask[x+y*TILE_X] = (x+y)&1; + + for(x = 0; x < TILEP_PARTS_TOTAL; x++) + { + doll.parts[x] = 0; + current_parts[x] = 0; + } + tilep_race_default(ghost.values[GVAL_SPECIES], g_gender, + ghost.values[GVAL_EXP_LEVEL], doll.parts); + tilep_job_default (ghost.values[GVAL_CLASS], g_gender, doll.parts); + + for(x = TILEP_PART_CLOAK; x < TILEP_PARTS_TOTAL; x++) + { + if (doll.parts[x] == TILEP_SHOW_EQUIP) + { + doll.parts[x] = 1 + (pseudo_rand % tilep_parts_total[x]); + + if (x == TILEP_PART_BODY) + { + int p = 0; + int ac = ghost.values[GVAL_AC]; + ac *= (5 + (pseudo_rand/11) % 11); + ac /= 10; + + if (ac > 25) p= TILEP_BODY_PLATE_BLACK; + else + if (ac > 20) p= TILEP_BODY_BANDED; + else + if (ac > 15) p= TILEP_BODY_SCALEMAIL; + else + if (ac > 10) p= TILEP_BODY_CHAINMAIL; + else + if (ac > 5 ) p= TILEP_BODY_LEATHER_HEAVY; + else + p= TILEP_BODY_ROBE_BLUE; + doll.parts[x] = p; + } + } + } + + int sk = ghost.values[GVAL_BEST_SKILL]; + int dam = ghost.values[GVAL_DAMAGE]; + int p = 0; + + dam *= (5 + pseudo_rand % 11); + dam /= 10; + + if (sk == SK_MACES_FLAILS) + { + if (dam>30) p = TILEP_HAND1_GREAT_FRAIL; + else + if (dam>25) p = TILEP_HAND1_GREAT_MACE; + else + if (dam>20) p = TILEP_HAND1_SPIKED_FRAIL; + else + if (dam>15) p = TILEP_HAND1_MORNINGSTAR; + else + if (dam>10) p = TILEP_HAND1_FRAIL; + else + if (dam>5) p = TILEP_HAND1_MACE; + else + p = TILEP_HAND1_CLUB_SLANT; + + doll.parts[TILEP_PART_HAND1] = p; + } + else + if (sk == SK_SHORT_BLADES) + { + if (dam>20) p = TILEP_HAND1_SABRE; + else + if (dam>10) p = TILEP_HAND1_SHORT_SWORD_SLANT; + else + p = TILEP_HAND1_DAGGER_SLANT; + + doll.parts[TILEP_PART_HAND1] = p; + } + else + if (sk == SK_LONG_SWORDS) + { + if (dam>25) p = TILEP_HAND1_GREAT_SWORD_SLANT; + else + if (dam>20) p = TILEP_HAND1_KATANA_SLANT; + else + if (dam>15) p = TILEP_HAND1_SCIMITAR; + else + if (dam>10) p = TILEP_HAND1_LONG_SWORD_SLANT; + else + p = TILEP_HAND1_FALCHION; + + doll.parts[TILEP_PART_HAND1] = p; + } + else + if (sk == SK_AXES) + { + if (dam>30) p = TILEP_HAND1_EXECUTIONERS_AXE; + else + if (dam>20) p = TILEP_HAND1_BATTLEAXE; + else + if (dam>15) p = TILEP_HAND1_BROAD_AXE; + else + if (dam>10) p = TILEP_HAND1_WAR_AXE; + else + p = TILEP_HAND1_HAND_AXE; + + doll.parts[TILEP_PART_HAND1] = p; + } + else + if (sk == SK_POLEARMS) + { + if (dam>30) p = TILEP_HAND1_GLAIVE; + else + if (dam>20) p = TILEP_HAND1_SCYTHE; + else + if (dam>15) p = TILEP_HAND1_HALBERD; + else + if (dam>10) p = TILEP_HAND1_TRIDENT2; + else + if (dam>10) p = TILEP_HAND1_HAMMER; + else + p = TILEP_HAND1_SPEAR; + + doll.parts[TILEP_PART_HAND1] = p; + } + else + if (sk == SK_BOWS) + doll.parts[TILEP_PART_HAND1] = TILEP_HAND1_BOW2; + else + if (sk == SK_CROSSBOWS) + doll.parts[TILEP_PART_HAND1] = TILEP_HAND1_CROSSBOW; + else + if (sk == SK_SLINGS) + doll.parts[TILEP_PART_HAND1] = TILEP_HAND1_SLING; + else + if (sk == SK_UNARMED_COMBAT) + doll.parts[TILEP_PART_HAND1] = doll.parts[TILEP_PART_HAND2] = 0; + + ImgClear(DollCacheImg); + // Clear + ImgCopyToTileImg(TILE_MONS_PLAYER_GHOST, DollCacheImg, 0, 0, 1); + + draw_doll(DollCacheImg, &doll); + ImgCopyToTileImg(TILE_MONS_PLAYER_GHOST, DollCacheImg, 0, 0, 1, mask, false); + redraw_spx_tcache(TILE_MONS_PLAYER_GHOST); +} + +void TileInitItems() +{ + for(int i=0; i<NUM_POTIONS; i++) + { + int special = you.item_description[IDESC_POTIONS][i]; + int tile0 = TILE_POTION_OFFSET + special % 14; + int tile1 = TILE_POT_HEALING + i; + + ImgCopyFromTileImg(tile0, DollCacheImg, 0, 0, 1); + ImgCopyFromTileImg(tile1, DollCacheImg, 0, 0, 0); + ImgCopyToTileImg (tile1, DollCacheImg, 0, 0, 1); + } + + for(int i=0; i<NUM_WANDS; i++) + { + int special = you.item_description[IDESC_WANDS][i]; + int tile0 = TILE_WAND_OFFSET + special % 12; + int tile1 = TILE_WAND_FLAME + i; + + ImgCopyFromTileImg(tile0, DollCacheImg, 0, 0, 1); + ImgCopyFromTileImg(tile1, DollCacheImg, 0, 0, 0); + ImgCopyToTileImg (tile1, DollCacheImg, 0, 0, 1); + } + + //Hack: call it again + init_tileflag(); +} + +// Monster weapon tile +#define N_MCACHE (TILE_MCACHE_END - TILE_MCACHE_START +1) + +typedef struct mcache mcache; +struct mcache +{ + bool lock_flag; + mcache *next; + int mon_tile; + int equ_tile; + int draco; + int idx; +}; + +mcache mc_data[N_MCACHE]; + +mcache *mc_head = NULL; + +static void ImgCopyDoll(int equ_tile, int hand, int ofs_x, int ofs_y) +{ + int handidx = hand == 1 ? TILEP_PART_HAND1 : TILEP_PART_HAND2; + + int nx = tilep_parts_nx[handidx]; + int ny = tilep_parts_ny[handidx]; + int ox = tilep_parts_ox[handidx]; + int oy = tilep_parts_oy[handidx]; + int wx = std::min(TILE_X/nx + ofs_x, TILE_X/nx); + int wy = std::min(TILE_Y/ny + ofs_y, TILE_Y/ny); + int idx = equ_tile -1; + int tidx = tilep_parts_start[handidx] + + idx/(nx*ny); + + //Source pos + int xs = (tidx % TILEP_PER_ROW)*TILE_X + + (idx % nx)*(TILE_X/nx) - ofs_x; + int ys = (tidx / TILEP_PER_ROW)*TILE_Y + + ((idx/nx) % ny)*(TILE_Y/ny) - ofs_y; + + ImgCopy(PlayerImg, xs, ys, wx, wy, + DollCacheImg, ox, oy, 0); +} + +static void mcache_compose(int tile_idx, int mon_tile, int equ_tile) +{ + int ofs_x=0; + int ofs_y=0; + + switch(mon_tile) + { + case TILE_MONS_ORC: + case TILE_MONS_URUG: + case TILE_MONS_BLORK_THE_ORC: + case TILE_MONS_ORC_WARRIOR: + case TILE_MONS_ORC_KNIGHT: + case TILE_MONS_ORC_WARLORD: + ofs_y = 2; + break; + case TILE_MONS_GOBLIN: + case TILE_MONS_IJYB: + ofs_y = 4; + break; + case TILE_MONS_GNOLL: + ofs_x = -1; + break; + case TILE_MONS_BOGGART: + ofs_y = 2; + break; + case TILE_MONS_DEEP_ELF_FIGHTER: + case TILE_MONS_DEEP_ELF_SOLDIER: + ofs_y = 2; + break; + case TILE_MONS_DEEP_ELF_KNIGHT: + ofs_y = 1; + break; + case TILE_MONS_KOBOLD: + ofs_x = 3; + ofs_y = 4; + break; + case TILE_MONS_KOBOLD_DEMONOLOGIST: + ofs_y = -10; + break; + case TILE_MONS_BIG_KOBOLD: + ofs_x = 2; + ofs_y = 3; + break; + case TILE_MONS_MIDGE: + ofs_y = -2; + break; + case TILE_MONS_NAGA: + case TILE_MONS_GREATER_NAGA: + case TILE_MONS_NAGA_WARRIOR: + case TILE_MONS_GUARDIAN_NAGA: + case TILE_MONS_NAGA_MAGE: + ofs_y = 1; + break; + case TILE_MONS_HELL_KNIGHT: + ofs_x = -1; + ofs_y = 3; + break; + case TILE_MONS_RED_DEVIL: + ofs_x = 2; + ofs_y = -3; + break; + case TILE_MONS_WIZARD: + ofs_x = 2; + ofs_y = -2; + break; + case TILE_MONS_HUMAN: + ofs_x = 5; + ofs_y = 2; + break; + case TILE_MONS_ELF: + ofs_y = 1; + ofs_x = 4; + break; + case TILE_MONS_OGRE_MAGE: + ofs_y = -2; + ofs_x = -4; + break; + case TILE_MONS_DEEP_ELF_MAGE: + case TILE_MONS_DEEP_ELF_SUMMONER: + case TILE_MONS_DEEP_ELF_CONJURER: + case TILE_MONS_DEEP_ELF_PRIEST: + case TILE_MONS_DEEP_ELF_HIGH_PRIEST: + case TILE_MONS_DEEP_ELF_DEMONOLOGIST: + case TILE_MONS_DEEP_ELF_ANNIHILATOR: + case TILE_MONS_DEEP_ELF_SORCERER: + ofs_x = -1; + ofs_y = -2; + break; + case TILE_MONS_DEEP_ELF_DEATH_MAGE: + ofs_x = -1; + break; + } + + // Copy monster tile + ImgCopyFromTileImg(mon_tile, DollCacheImg, 0, 0, 1); + + // Overlay weapon tile + ImgCopyDoll(equ_tile, 1, ofs_x, ofs_y); + + // In some cases, overlay a second weapon tile... + if (mon_tile == TILE_MONS_DEEP_ELF_BLADEMASTER) + { + int eq2; + switch (equ_tile) + { + case TILEP_HAND1_DAGGER: + eq2 = TILEP_HAND2_DAGGER; + break; + case TILEP_HAND1_SABRE: + eq2 = TILEP_HAND2_SABRE; + break; + default: + case TILEP_HAND1_SHORT_SWORD_SLANT: + eq2 = TILEP_HAND2_SHORT_SWORD_SLANT; + break; + }; + ImgCopyDoll(eq2, 2, -ofs_x, ofs_y); + } + + // Copy to the buffer + ImgCopyToTileImg(tile_idx, DollCacheImg, 0, 0, 1); + + redraw_spx_tcache(tile_idx); +} + +static void mcache_compose_draco(int tile_idx, int race, int cls, int w) +{ + extern int draconian_color(int race, int level); + + dolls_data doll; + int x; + + int color = draconian_color(race, -1); + int armour = 0; + int armour2 = 0; + int weapon = 0; + int weapon2 = 0; + int arm = 0; + + for(x = 0; x < TILEP_PARTS_TOTAL; x++) + { + doll.parts[x] = 0; + current_parts[x] = 0; + } + doll.parts[TILEP_PART_SHADOW] = 1; + + doll.parts[TILEP_PART_BASE] = TILEP_BASE_DRACONIAN + color *2; + doll.parts[TILEP_PART_DRCWING] = 1 + color; + doll.parts[TILEP_PART_DRCHEAD] = 1 + color; + + switch(cls) + { + case MONS_DRACONIAN_CALLER: + weapon = TILEP_HAND1_STAFF_EVIL; + weapon2 = TILEP_HAND2_BOOK_YELLOW; + armour = TILEP_BODY_ROBE_BROWN; + break; + + case MONS_DRACONIAN_MONK: + arm = TILEP_ARM_GLOVE_SHORT_BLUE; + armour = TILEP_BODY_KARATE2; + break; + + case MONS_DRACONIAN_ZEALOT: + weapon = TILEP_HAND1_MACE; + weapon2 = TILEP_HAND2_BOOK_CYAN; + armour = TILEP_BODY_MONK_BLUE; + break; + + case MONS_DRACONIAN_SHIFTER: + weapon = TILEP_HAND1_STAFF_LARGE; + armour = TILEP_BODY_ROBE_CYAN; + weapon2 = TILEP_HAND2_BOOK_GREEN; + break; + + case MONS_DRACONIAN_ANNIHILATOR: + weapon = TILEP_HAND1_STAFF_RUBY; + weapon2 = TILEP_HAND2_FIRE_CYAN; + armour = TILEP_BODY_ROBE_GREEN_GOLD; + break; + + case MONS_DRACONIAN_KNIGHT: + weapon = w; + weapon2 = TILEP_HAND2_SHIELD_KNIGHT_GRAY; + armour = TILEP_BODY_BPLATE_METAL1; + armour2 = TILEP_LEG_BELT_GRAY; + break; + + case MONS_DRACONIAN_SCORCHER: + weapon = TILEP_HAND1_FIRE_RED; + weapon2 = TILEP_HAND2_BOOK_RED; + armour = TILEP_BODY_ROBE_RED; + break; + + default: + weapon = w; + armour = TILEP_BODY_BELT2; + armour2 = TILEP_LEG_LOINCLOTH_RED; + break; + } + + doll.parts[TILEP_PART_HAND1] = weapon; + doll.parts[TILEP_PART_HAND2] = weapon2; + doll.parts[TILEP_PART_BODY] = armour; + doll.parts[TILEP_PART_LEG] = armour2; + doll.parts[TILEP_PART_ARM] = arm; + + ImgClear(DollCacheImg); + draw_doll(DollCacheImg, &doll, true, false); + // Copy to the buffer + ImgCopyToTileImg(tile_idx, DollCacheImg, 0, 0, 1); + redraw_spx_tcache(tile_idx); +} + +static void mcache_init() +{ + int i; + + for(i=0;i<N_MCACHE;i++) + { + mc_data[i].lock_flag = false; + mc_data[i].next = NULL; + if (i!=N_MCACHE-1) + mc_data[i].next = &mc_data[i+1]; + mc_data[i].idx = TILE_MCACHE_START + i; + mc_data[i].mon_tile = 0; + mc_data[i].equ_tile = 0; + mc_data[i].draco = 0; + } + mc_head = &mc_data[0]; +} + +int get_base_idx_from_mcache(int tile_idx) +{ + for (mcache *mc = mc_head; mc != NULL; mc = mc->next) + { + if (mc->idx == tile_idx) + return mc->mon_tile; + } + + return tile_idx; +} + +int get_clean_map_idx(int tile_idx) +{ + int idx = tile_idx & TILE_FLAG_MASK; + if (idx >= TILE_CLOUD_FIRE_0 && idx <= TILE_CLOUD_PURP_SMOKE || + idx >= TILE_MONS_SHADOW && idx <= TILE_MONS_WATER_ELEMENTAL || + idx >= TILE_MCACHE_START && idx <= TILE_MCACHE_END) + { + return 0; + } + else + { + return tile_idx; + } +} + +void TileMcacheUnlock() +{ + int i; + + for(i=0;i<N_MCACHE;i++) + { + mc_data[i].lock_flag = false; + } +} + +int TileMcacheFind(int mon_tile, int equ_tile, int draco) +{ + mcache *mc = mc_head; + mcache *prev = NULL; + mcache *empty = NULL; +#ifdef DEBUG_DIAGNOSTICS + int count = 0; + char cache_info[40]; +#endif + int best2 = -1; + int best3 = -1; + + while(1){ + if(mon_tile == mc->mon_tile && equ_tile == mc->equ_tile + && draco == mc->draco) + { + // match found + // move cache to the head to reduce future search time + if (prev != NULL) prev->next = mc->next; + if (mc != mc_head) mc->next = mc_head; + mc_head = mc; + + // lock it + mc->lock_flag=true; + // return cache index + return mc->idx; + } + else if(draco != 0 && mon_tile == mc->mon_tile && draco == mc->draco) + // second best for draconian: only weapon differ + best2 = mc->idx; + else if(draco != 0 && mon_tile == mc->mon_tile) + // third best for draconian: only class matches + best3 = mc->idx; + + if (!mc->lock_flag) + empty = mc; + if (mc->next == NULL) + break; + prev = mc; + mc = mc->next; + +#ifdef DEBUG_DIAGNOSTICS + count++; +#endif + + }//while + + // cache image not found and no room do draw it + if(empty == NULL) + { +#ifdef DEBUG_DIAGNOSTICS + snprintf( cache_info, 39, "mcache (M %d, E %d) cache full", + mon_tile, equ_tile); + mpr(cache_info, MSGCH_DIAGNOSTICS ); +#endif + if (best2 != -1) + return best2; + if (best3 != -1) + return best3; + if (draco != 0) + return TILE_ERROR; + else + return mon_tile; + } + mc = empty; + +#ifdef DEBUG_DIAGNOSTICS + snprintf( cache_info, 39, "mcache (M %d, E %d) newly composed", + mon_tile, equ_tile); + mpr(cache_info, MSGCH_DIAGNOSTICS ); +#endif + + // compose new image + if (draco != 0) + // race, class, weapon + mcache_compose_draco(mc->idx, draco, mon_tile, equ_tile); + else + mcache_compose(mc->idx, mon_tile, equ_tile); + mc->mon_tile = mon_tile; + mc->equ_tile = equ_tile; + mc->draco = draco; + // move cache to the head to reduce future search time + if (prev) + prev->next = mc->next; + if(mc != mc_head) + mc->next = mc_head; + mc_head = mc; + mc->lock_flag=true; + return mc->idx; +} + +void TileDrawTitle() +{ + int winx, winy, tx, ty, x, y; + img_type TitleImg = ImgLoadFileSimple("title"); + img_type pBuf = region_tile->backbuf; + if (!TitleImg || !pBuf) return; + + tx = ImgWidth(TitleImg); + ty = ImgHeight(TitleImg); + winx = ImgWidth(pBuf); + winy = ImgHeight(pBuf); + + if (tx > winx) + { + x = 0; + tx = winx; + } + else + { + x = (winx - tx)/2; + } + + if (ty > winy) + { + y = 0; + ty = winy; + } + else + { + y = (winy - ty)/2; + } + + ImgCopy(TitleImg, 0, 0, tx, ty, pBuf, x, y, 1); + region_tile->make_active(); + region_tile->redraw(); + ImgDestroy(TitleImg); +} + +static void TilePutch(int c, img_type Dest, int dx, int dy) +{ + int tidx = TILE_CHAR00 + (c-32)/8; + int tidx2 = c & 7; + + int sx = (tidx % TILE_PER_ROW)*TILE_X + (tidx2 % 4)*(TILE_X/4); + int sy = (tidx / TILE_PER_ROW)*TILE_Y + (tidx2 / 4)*(TILE_Y/2);; + + ImgCopy(TileImg, sx, sy, TILE_X/4, TILE_Y/2, + Dest, dx, dy, 0); +} + +void TileRedrawInv(int region) +{ + TileRegionClass *r = (region == REGION_INV1) ? region_item:region_item2; + r->flag = true; + r->make_active(); + r->redraw(); +} + +void TileClearInv(int region) +{ + TileRegionClass *r = (region == REGION_INV1) ? region_item:region_item2; + + for (int i = 0; i < r->mx * r->my; i++) + { + TileDrawOneItem(region, i, 0, -1, -1, -1, false, false, false, false, false); + } + last_cursor = -1; + itemlist_n = 0; +} + +void TileDrawOneItem(int region, int i, char key, int idx, + int tile, int num, bool floor, + bool select, bool equip, bool tried, bool cursed) +{ + ASSERT(idx >= -1 && idx < MAX_ITEMS); + TileRegionClass *r = (region == REGION_INV1) ? region_item:region_item2; + + int item_x = r->mx; + int dx = (i % item_x)*TILE_X; + int dy = (i / item_x)*TILE_Y; + + if (tile == -1) + { + ImgCopyFromTileImg(TILE_DNGN_UNSEEN, r->backbuf, dx, dy, 1); + return; + } + + if (floor) + ImgCopyFromTileImg(TILE_DNGN_FLOOR, r->backbuf, dx, dy, 1); + else + ImgCopyFromTileImg(TILE_ITEM_SLOT, r->backbuf, dx, dy, 1); + + if (equip) + { + if (cursed) + ImgCopyFromTileImg(TILE_ITEM_SLOT_EQUIP_CURSED, r->backbuf, + dx, dy, 0); + else + ImgCopyFromTileImg(TILE_ITEM_SLOT_EQUIP, r->backbuf, dx, dy, 0); + } + else if (cursed) + { + ImgCopyFromTileImg(TILE_ITEM_SLOT_CURSED, r->backbuf, dx, dy, 0); + } + if (select) + ImgCopyFromTileImg(TILE_RAY_MESH, r->backbuf, dx, dy, 0); + + if (itemlist_iflag[i] & TILEI_FLAG_CURSOR) + ImgCopyFromTileImg(TILE_CURSOR, r->backbuf, dx, dy, 0); + + // Item tile + ImgCopyFromTileImg(tile, r->backbuf, dx, dy, 0); + + // quantity/charge + if (num != -1) + { + // If you have that many, who cares. + if (num > 999) + num = 999; + + const int offset_amount = TILE_X/4; + int offset = 0; + + int c100 = num/100; + num -= c100*100; + if (c100) + { + TilePutch('0'+ c100, r->backbuf, dx+offset, dy); + offset += offset_amount; + } + int c10 = num/10; + if (c10 || c100) + { + TilePutch('0'+ c10, r->backbuf, dx+offset, dy); + offset += offset_amount; + } + int c1 = num % 10; + TilePutch('0'+ c1, r->backbuf, dx+offset, dy); + } + + // '?' mark + if (tried) + { + TilePutch('?', r->backbuf, dx, dy + TILE_Y/2); + } + + // record tile information as we draw it so that we can re-draw it at will + itemlist[i] = tile; + itemlist_num[i] = num; + itemlist_key[i] = key; + itemlist_idx[i] = idx; + itemlist_iflag[i] = 0; + if (floor) + itemlist_iflag[i] |= TILEI_FLAG_FLOOR; + if (tried) + itemlist_iflag[i] |= TILEI_FLAG_TRIED; + if (equip) + itemlist_iflag[i] |= TILEI_FLAG_EQUIP; + if (cursed) + itemlist_iflag[i] |= TILEI_FLAG_CURSE; + if (select) + itemlist_iflag[i] |= TILEI_FLAG_SELECT; + + if (i >= itemlist_n) + itemlist_n = i+1; +} + +void TileDrawInvData(int n, int flag, int *tiles, int *num, int *idx, + int *iflags) +{ + int i; + TileRegionClass *r = (flag == REGION_INV1) ? region_item:region_item2; + + r->flag = true; + + last_cursor = -1; + int old_itemlist_n = itemlist_n; + itemlist_n = n; + + int item_x = r->mx; + int item_y = r->my; + + for (i=0;i<item_x*item_y;i++) + { + if (i==MAX_ITEMLIST) break; + + int tile0 = (i>=n) ? -1 : tiles[i]; + int idx0 = (i>=n) ? -1 : idx[i]; + char key = (iflags[i]&TILEI_FLAG_FLOOR) ? 0 : index_to_letter(idx[i]); + + if ( flag == itemlist_flag + && tile0 == itemlist[i] + && num[i] == itemlist_num[i] + && key == itemlist_key[i] + && idx0 == itemlist_idx[i] + && iflags[i] == itemlist_iflag[i] + && !force_redraw_inv + && i < old_itemlist_n) + { + continue; + } + + TileDrawOneItem(flag, i, key, idx0, tile0, num[i], + ((iflags[i]&TILEI_FLAG_FLOOR) != 0), + ((iflags[i]&TILEI_FLAG_SELECT) != 0), + ((iflags[i]&TILEI_FLAG_EQUIP) != 0), + ((iflags[i]&TILEI_FLAG_TRIED) != 0), + ((iflags[i]&TILEI_FLAG_CURSE) != 0)); + } + + r->make_active(); + r->redraw(); + itemlist_flag = flag; + force_redraw_inv = false; +} + +void TileDrawInvCursor(int ix, bool flag) +{ + TileRegionClass *r = + (itemlist_flag == REGION_INV1) ? region_item:region_item2; + + int tile0 = itemlist[ix]; + int num0 = itemlist_num[ix]; + + if (flag) + itemlist_iflag[ix] |= TILEI_FLAG_CURSOR; + else + itemlist_iflag[ix] &= ~TILEI_FLAG_CURSOR; + + TileDrawOneItem(itemlist_flag, ix, itemlist_key[ix], itemlist_idx[ix], tile0, num0, + ((itemlist_iflag[ix]&TILEI_FLAG_FLOOR) != 0), + ((itemlist_iflag[ix]&TILEI_FLAG_SELECT) != 0), + ((itemlist_iflag[ix]&TILEI_FLAG_EQUIP) != 0), + ((itemlist_iflag[ix]&TILEI_FLAG_TRIED) != 0), + ((itemlist_iflag[ix]&TILEI_FLAG_CURSE) != 0) + ); + + r->redraw(); +} + +void TileMoveInvCursor(int ix) +{ + if (last_cursor != -1) + TileDrawInvCursor(last_cursor, false); + + if (ix != -1) TileDrawInvCursor(ix, true); + last_cursor = ix; +} + +int TileInvIdx(int i) +{ + if (i >= itemlist_n) + return -1; + else + return itemlist_idx[i]; +} + +#endif |