cc65-Chess/src/term/platTerm.c

402 lines
8.8 KiB
C

/*
* platTerm.c
* cc65 Chess
*
* Created by Stefan Wessels, February 2014.
*
*/
#include <curses.h>
#include <string.h>
#include <sys/time.h>
#include "types.h"
#include "globals.h"
#include "undo.h"
#include "frontend.h"
#include "plat.h"
/*-----------------------------------------------------------------------*/
// Internal function Prototype
char plat_TimeExpired(unsigned int aTime);
/*-----------------------------------------------------------------------*/
// These are read from the curses library but I assume at least 24 rows
// and 55 cols
int SCREEN_HEIGHT, SCREEN_WIDTH;
int LOG_WINDOW_HEIGHT;
/*-----------------------------------------------------------------------*/
#define SCROLL_SPEED 150000
#define BOARD_PIECE_WIDTH 6
#define BOARD_PIECE_HEIGHT 3
/*-----------------------------------------------------------------------*/
// Names of the pieces NONE, Rook, knight, Bishop, Queen, King, pawn
static const char sc_pieces[] = {'\0','R','k','B','Q','K','p'};
/*-----------------------------------------------------------------------*/
void plat_Init()
{
// Curses init
initscr();
intrflush(stdscr, FALSE);
keypad(stdscr, TRUE);
nonl();
cbreak();
noecho();
timeout(0);
curs_set(0);
getmaxyx(stdscr, SCREEN_HEIGHT, SCREEN_WIDTH) ;
LOG_WINDOW_HEIGHT = SCREEN_HEIGHT - 2;
if(has_colors() != FALSE)
{
start_color();
assume_default_colors(COLOR_WHITE, COLOR_BLACK);
init_pair(1, COLOR_BLACK, COLOR_YELLOW);
init_pair(2, COLOR_WHITE, COLOR_BLACK);
init_pair(3, COLOR_GREEN, COLOR_BLACK);
init_pair(4, COLOR_RED, COLOR_BLACK);
init_pair(5, COLOR_CYAN, COLOR_BLACK);
init_pair(6, COLOR_BLUE, COLOR_BLACK);
init_pair(7, COLOR_WHITE, COLOR_WHITE);
init_pair(8, COLOR_BLACK, COLOR_BLACK);
}
// Setting this to 0 will not show the "Quit" option in the main menu
gReturnToOS = 1;
}
/*-----------------------------------------------------------------------*/
void plat_UpdateScreen()
{
refresh();
}
/*-----------------------------------------------------------------------*/
// Very simple menu with a heading and a scrolling banner as a footer
char plat_Menu(char **menuItems, char height, char *scroller)
{
static char *prevScroller, *pScroller;
char *pEnd;
int keyMask;
char i, j, sx, sy, numMenuItems, maxLen = 0;
if(prevScroller != scroller)
{
prevScroller = scroller;
pScroller = scroller;
}
pEnd = scroller + strlen(scroller);
for(numMenuItems=0; menuItems[numMenuItems]; ++numMenuItems)
{
char len = strlen(menuItems[numMenuItems]);
if(len > maxLen)
maxLen = len;
}
sy = MAX_SIZE(0, ((8*BOARD_PIECE_HEIGHT) / 2) - (height / 2) - 1);
sx = MAX_SIZE(0, ((8*BOARD_PIECE_WIDTH) / 2) - (maxLen / 2) - 1);
maxLen = MIN_SIZE((8*BOARD_PIECE_WIDTH)-2, maxLen);
color_set(3,0);
move(sy,sx);
printw(" %.*s ",maxLen, menuItems[0]);
color_set(1,0);
move(++sy, sx);
for(j=0; j<maxLen+2; ++j)
printw(" ");
for(i=1; i<numMenuItems; ++i)
{
move(sy+i, sx);
printw(" %.*s ",maxLen, menuItems[i]);
}
for(;i<height;++i)
{
move(sy+i, sx);
for(j=0; j<maxLen+2; ++j)
printw(" ");
}
i = 1;
do
{
move(sy+i,sx);
attron(WA_REVERSE);
color_set(2,0);
printw(">%.*s<",maxLen, menuItems[i]);
attroff(WA_REVERSE);
color_set(1,0);
keyMask = plat_ReadKeys(0);
if(keyMask & INPUT_MOTION)
{
move(sy+i,sx);
printw(" %.*s ",maxLen, menuItems[i]);
switch(keyMask & INPUT_MOTION)
{
case INPUT_UP:
if(!--i)
i = numMenuItems-1;
break;
case INPUT_DOWN:
if(numMenuItems == ++i)
i = 1;
break;
}
}
keyMask &= (INPUT_SELECT | INPUT_BACKUP);
move(sy+height,sx);
color_set(5,0);
printw(" %.*s ",maxLen, pScroller);
if((pEnd - pScroller) < maxLen-1)
{
move(sy+height,sx+(pEnd-pScroller)+1);
printw(" %.*s ",maxLen-(pEnd - pScroller)-1, scroller);
}
if(plat_TimeExpired(SCROLL_SPEED))
{
++pScroller;
if(!*pScroller)
pScroller = scroller;
}
} while(keyMask != INPUT_SELECT && keyMask != INPUT_BACKUP);
if(keyMask & INPUT_BACKUP)
return 0;
return i;
}
/*-----------------------------------------------------------------------*/
void plat_DrawBoard(char clearLog)
{
char i;
if(clearLog)
erase();
for(i=0; i<64; ++i)
plat_DrawSquare(i);
}
/*-----------------------------------------------------------------------*/
void plat_DrawSquare(char position)
{
char piece, color, dx, dy;
char y = position / 8, x = position & 7;
char blackWhite = !((x & 1) ^ (y & 1));
if(blackWhite)
color = 7;
else
color = 8;
for(dy=0; dy<BOARD_PIECE_HEIGHT; ++dy)
{
for(dx=0; dx<BOARD_PIECE_WIDTH; ++dx)
{
move(dy+y*BOARD_PIECE_HEIGHT,dx+x*BOARD_PIECE_WIDTH);
color_set(color,0);
printw(" ");
}
}
// Show the attack numbers
if(gShowAttackBoard)
{
color_set(1, 0);
move(y*BOARD_PIECE_HEIGHT+2, x*BOARD_PIECE_WIDTH);
printw("%d",(gpAttackBoard[giAttackBoardOffset[position][0]]));
color_set(2,0);
move(y*BOARD_PIECE_HEIGHT+2, x*BOARD_PIECE_WIDTH+5);
printw("%d",(gpAttackBoard[giAttackBoardOffset[position][1]]));
move(y*BOARD_PIECE_HEIGHT, x*BOARD_PIECE_WIDTH);
printw("%02X",gChessBoard[y][x]);
move(y*BOARD_PIECE_HEIGHT, x*BOARD_PIECE_WIDTH+5);
printw("%d",(gChessBoard[y][x]&PIECE_WHITE)>>7);
}
piece = gChessBoard[y][x];
color = piece & PIECE_WHITE;
piece &= PIECE_DATA;
if(piece)
{
move(y*BOARD_PIECE_HEIGHT+(BOARD_PIECE_HEIGHT/2),x*BOARD_PIECE_WIDTH+(BOARD_PIECE_WIDTH/2));
color_set(color?2:1,0);
printw("%c",sc_pieces[piece]);
}
}
/*-----------------------------------------------------------------------*/
void plat_ShowSideToGoLabel(char side)
{
move(0, 2+8*BOARD_PIECE_WIDTH);
color_set(side?2:1, 0);
printw("%s",gszSideLabel[side]);
}
/*-----------------------------------------------------------------------*/
void plat_Highlight(char position, char color, char cursor)
{
char y = (BOARD_PIECE_HEIGHT/2)+1+BOARD_PIECE_HEIGHT*((position / 8)), x = (BOARD_PIECE_WIDTH/2)+BOARD_PIECE_WIDTH*((position & 7));
move(y,x);
color_set(color,0);
printw(cursor?"*":"!");
}
/*-----------------------------------------------------------------------*/
void plat_ShowMessage(char *str, char color)
{
move((8*BOARD_PIECE_HEIGHT)-1, 1+(8*BOARD_PIECE_WIDTH));
color_set(color,0);
printw("%.*s",SCREEN_WIDTH-1-(8*BOARD_PIECE_WIDTH),str);
clrtoeol();
}
/*-----------------------------------------------------------------------*/
void plat_ClearMessage()
{
move((8*BOARD_PIECE_HEIGHT)-1, 1+(8*BOARD_PIECE_WIDTH));
clrtoeol();
}
/*-----------------------------------------------------------------------*/
// This function can/will change the gTile and related global variables so
// caution is needed
void plat_AddToLogWin()
{
char bot = (8*BOARD_PIECE_HEIGHT)-2, y = 1, x = 1+(8*BOARD_PIECE_WIDTH);
for(; y<=bot; ++y)
{
move(y, x);
if(undo_FindUndoLine(bot-y))
{
frontend_FormatLogString();
color_set(gColor[0]+1,0);
printw("%.*s",SCREEN_WIDTH-1-x,gLogStrBuffer);
}
clrtoeol();
}
}
/*-----------------------------------------------------------------------*/
void plat_AddToLogWinTop()
{
plat_AddToLogWin();
}
/*-----------------------------------------------------------------------*/
char plat_TimeExpired(unsigned int aTime)
{
static struct timeval sst_store;
static int si_init = 0;
struct timeval now;
gettimeofday(&now, NULL);
if(!si_init || (MAX_SIZE(now.tv_usec,sst_store.tv_usec) - MIN_SIZE(now.tv_usec,sst_store.tv_usec) > SCROLL_SPEED))
{
si_init = 1;
sst_store = now;
return 1;
}
return 0;
}
/*-----------------------------------------------------------------------*/
int plat_ReadKeys(char blocking)
{
char key = 0;
int keyMask = 0;
if(blocking)
{
timeout(-1) ;
key = getch();
timeout(0);
}
else
{
key = getch();
}
switch(key)
{
case 3: // Up
keyMask |= INPUT_UP;
break;
case 5: // Right
keyMask |= INPUT_RIGHT;
break;
case 2: // Down
keyMask |= INPUT_DOWN;
break;
case 4: // Left
keyMask |= INPUT_LEFT;
break;
case 27: // Esc
keyMask |= INPUT_BACKUP;
break;
case 'a': // 'a' - Show Attackers
keyMask |= INPUT_TOGGLE_A;
break;
case 'b': // 'b' - Board attacks - Show all attacks
keyMask |= INPUT_TOGGLE_B;
break;
case 'd': // 'd' - Show Defenders
keyMask |= INPUT_TOGGLE_D;
break;
case 'm': // 'm' - Menu
keyMask |= INPUT_MENU;
break;
case 13: // Enter
keyMask |= INPUT_SELECT;
break;
case 'r':
keyMask |= INPUT_REDO;
break;
case 'u':
keyMask |= INPUT_UNDO;
break;
// default: // Debug - show key code
// {
// char s[] = "Key:000";
// if(key != 255)
// {
// s[4] = (key/100)+'0';
// key -= (s[4] - '0') * 100;
// s[5] = (key/10)+'0';
// s[6] = (key%10)+'0';
// plat_ShowMessage(s,COLOR_RED);
// }
// refresh();
// }
// break;
}
return keyMask;
}
/*-----------------------------------------------------------------------*/
void plat_Shutdown()
{
endwin();
}