, or <0> drops the block immediately\n");
printf(" pauses and unpauses the game\n");
printf(" , or starts a new game\n");
printf(" or hitting escape twice, quits immediately\n");
#ifdef USE_JOYSTICK
printf(" This build also accepts joystick input.\n\n");
#endif
}
long get_msec(void)
{
struct timeval tv;
gettimeofday(&tv, 0);
return (tv.tv_sec - tv0.tv_sec) * 1000 + (tv.tv_usec - tv0.tv_usec) / 1000;
}
void sighandler(int s)
{
struct winsize winsz;
signal(s, sighandler);
switch(s) {
case SIGWINCH:
ioctl(1, TIOCGWINSZ, &winsz);
term_width = winsz.ws_col;
term_height = winsz.ws_row;
game_input('`'); /* redraw */
break;
default:
break;
}
}
#ifdef USE_JOYSTICK
static void read_joystick(void)
{
struct js_event ev;
unsigned int dir;
while(read(jsdev, &ev, sizeof ev) > 0) {
if(ev.type & JS_EVENT_AXIS) {
int axis = ev.number & 1;
int val = abs(ev.value) < 32587 ? 0 : ev.value;
if(axis == 0) {
if(val) {
dir = val > 0 ? BN_RIGHT : BN_LEFT;
} else {
dir = BN_LEFT | BN_RIGHT;
}
} else {
if(val) {
dir = val > 0 ? BN_DOWN : BN_UP;
if(dir == BN_UP) {
game_input('\n');
}
} else {
dir = BN_DOWN | BN_UP;
}
}
if(val) {
jstate |= dir;
} else {
jstate &= ~dir;
}
}
if(ev.type & JS_EVENT_BUTTON) {
if(ev.value) {
if(ev.number >= 4) {
game_input('p');
} else {
game_input('w');
}
}
}
}
autorepeat = jstate ? 1 : 0;
}
static void update_joystick(void)
{
if(jstate) autorepeat++;
if(jstate & BN_LEFT) {
game_input('a');
}
if(jstate & BN_RIGHT) {
game_input('d');
}
if(jstate & BN_DOWN) {
game_input('s');
}
if(jstate & 0x3) {
game_input('w');
}
}
#endif
termtris-1.3/src/pieces.h 0000664 0000000 0000000 00000005052 13435567761 0015461 0 ustar 00root root 0000000 0000000 /*
Termtris - a tetris game for ANSI/VT220 terminals
Copyright (C) 2019 John Tsiombikas
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, see .
*/
#ifndef PIECES_H_
#define PIECES_H_
#define BLK(x, y) ((x) | ((y) << 4))
#define BLKX(c) ((unsigned char)(c) & 0xf)
#define BLKY(c) ((unsigned char)(c) >> 4)
#define NUM_PIECES 7
static unsigned char pieces[NUM_PIECES][4][4] = {
/* L block */
{
{BLK(0, 1), BLK(0, 2), BLK(1, 1), BLK(2, 1)},
{BLK(0, 0), BLK(1, 0), BLK(1, 1), BLK(1, 2)},
{BLK(0, 1), BLK(1, 1), BLK(2, 1), BLK(2, 0)},
{BLK(1, 0), BLK(1, 1), BLK(1, 2), BLK(2, 2)}
},
/* J block */
{
{BLK(0, 1), BLK(1, 1), BLK(2, 1), BLK(2, 2)},
{BLK(1, 0), BLK(1, 1), BLK(1, 2), BLK(0, 2)},
{BLK(0, 0), BLK(0, 1), BLK(1, 1), BLK(2, 1)},
{BLK(1, 0), BLK(2, 0), BLK(1, 1), BLK(1, 2)}
},
/* I block */
{
{BLK(0, 2), BLK(1, 2), BLK(2, 2), BLK(3, 2)},
{BLK(1, 0), BLK(1, 1), BLK(1, 2), BLK(1, 3)},
{BLK(0, 2), BLK(1, 2), BLK(2, 2), BLK(3, 2)},
{BLK(1, 0), BLK(1, 1), BLK(1, 2), BLK(1, 3)}
},
/* O block */
{
{BLK(1, 1), BLK(2, 1), BLK(1, 2), BLK(2, 2)},
{BLK(1, 1), BLK(2, 1), BLK(1, 2), BLK(2, 2)},
{BLK(1, 1), BLK(2, 1), BLK(1, 2), BLK(2, 2)},
{BLK(1, 1), BLK(2, 1), BLK(1, 2), BLK(2, 2)}
},
/* Z block */
{
{BLK(0, 1), BLK(1, 1), BLK(1, 2), BLK(2, 2)},
{BLK(0, 1), BLK(1, 1), BLK(1, 0), BLK(0, 2)},
{BLK(0, 1), BLK(1, 1), BLK(1, 2), BLK(2, 2)},
{BLK(0, 1), BLK(1, 1), BLK(1, 0), BLK(0, 2)}
},
/* S block */
{
{BLK(1, 1), BLK(2, 1), BLK(0, 2), BLK(1, 2)},
{BLK(0, 0), BLK(0, 1), BLK(1, 1), BLK(1, 2)},
{BLK(1, 1), BLK(2, 1), BLK(0, 2), BLK(1, 2)},
{BLK(0, 0), BLK(0, 1), BLK(1, 1), BLK(1, 2)}
},
/* T block */
{
{BLK(0, 1), BLK(1, 1), BLK(2, 1), BLK(1, 2)},
{BLK(1, 0), BLK(1, 1), BLK(1, 2), BLK(0, 1)},
{BLK(0, 1), BLK(1, 1), BLK(2, 1), BLK(1, 0)},
{BLK(1, 0), BLK(1, 1), BLK(1, 2), BLK(2, 1)}
}
};
static int piece_spawnpos[NUM_PIECES][2] = {
{-1, -2}, {-1, -2}, {-2, -2}, {-1, -2}, {-1, -2}, {-1, -2}, {-1, -2}
};
#endif /* PIECES_H_ */
termtris-1.3/src/scoredb.c 0000664 0000000 0000000 00000011133 13435567761 0015622 0 ustar 00root root 0000000 0000000 /*
Termtris - a tetris game for ANSI/VT220 terminals
Copyright (C) 2019 John Tsiombikas
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, see .
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include "scoredb.h"
struct score_entry {
char *user;
int score, lines, level;
struct score_entry *next;
};
#define SCOREDB_PATH "/var/games/termtris/scores"
static void write_score(FILE *fp, struct score_entry *s);
static struct score_entry *read_scores(FILE *fp);
static void free_list(struct score_entry *s);
int save_score(int score, int lines, int level)
{
int fd, count;
FILE *fp;
struct passwd *pw;
struct score_entry *slist, *sptr;
struct score_entry newscore;
struct flock flk;
if(!(pw = getpwuid(getuid()))) {
perror("save_score: failed to retreive user information");
return -1;
}
newscore.user = pw->pw_name;
newscore.score = score;
newscore.lines = lines;
newscore.level = level;
if((fd = open(SCOREDB_PATH, O_RDWR | O_CREAT, 0666)) == -1 || !(fp = fdopen(fd, "r+"))) {
close(fd);
fprintf(stderr, "failed to save scores to %s: %s\n", SCOREDB_PATH, strerror(errno));
return -1;
}
/* lock the file */
flk.l_type = F_WRLCK;
flk.l_start = flk.l_len = 0;
flk.l_whence = SEEK_SET;
while(fcntl(fd, F_SETLKW, &flk) == -1);
slist = read_scores(fp);
rewind(fp);
count = 0;
sptr = slist;
while(sptr && sptr->score >= score && count++ < 100) {
write_score(fp, sptr);
sptr = sptr->next;
}
if(count++ < 100) {
write_score(fp, &newscore);
}
while(sptr && count++ < 100) {
write_score(fp, sptr);
sptr = sptr->next;
}
fflush(fp);
/* unlock the file */
flk.l_type = F_UNLCK;
flk.l_start = flk.l_len = 0;
flk.l_whence = SEEK_SET;
fcntl(fd, F_SETLK, &flk);
free_list(slist);
fclose(fp);
return 0;
}
static void write_score(FILE *fp, struct score_entry *s)
{
fprintf(fp, "%s %d/%d/%d\n", s->user, s->score, s->lines, s->level);
}
static char *skip_space(char *s)
{
if(!s) return 0;
while(*s && isspace(*s)) s++;
return *s ? s : 0;
}
static int parse_score(char *buf, struct score_entry *ent)
{
char *userptr, *scoreptr;
int scores[3];
if(!(userptr = skip_space(buf))) return -1;
scoreptr = userptr;
while(*scoreptr && !isspace(*scoreptr)) scoreptr++;
if(!*scoreptr) return -1;
*scoreptr = 0;
if(!(scoreptr = skip_space(scoreptr + 1))) return -1;
if(sscanf(scoreptr, "%d/%d/%d", scores, scores + 1, scores + 2) != 3) {
return -1;
}
ent->user = userptr;
ent->score = scores[0];
ent->lines = scores[1];
ent->level = scores[2];
return 0;
}
static struct score_entry *read_scores(FILE *fp)
{
char buf[128];
struct score_entry *node, *head = 0, *tail = 0;
while(fgets(buf, sizeof buf, fp)) {
struct score_entry ent;
if(parse_score(buf, &ent) == -1) {
continue;
}
if(!(node = malloc(sizeof *node)) || !(node->user = malloc(strlen(ent.user) + 1))) {
perror("failed to allocate scorelist");
free(node);
free_list(head);
return 0;
}
strcpy(node->user, ent.user);
node->score = ent.score;
node->lines = ent.lines;
node->level = ent.level;
node->next = 0;
if(!head) {
head = tail = node;
} else {
tail->next = node;
tail = node;
}
}
return head;
}
static void free_list(struct score_entry *s)
{
while(s) {
struct score_entry *tmp = s;
s = s->next;
free(tmp->user);
free(tmp);
}
}
int print_scores(int num)
{
int i;
FILE *fp;
struct flock flk;
char buf[128];
struct score_entry sc;
if(!(fp = fopen(SCOREDB_PATH, "r"))) {
fprintf(stderr, "no high-scores found\n");
return -1;
}
flk.l_type = F_RDLCK;
flk.l_start = flk.l_len = 0;
flk.l_whence = SEEK_SET;
while(fcntl(fileno(fp), F_SETLKW, &flk) == -1);
for(i=0; i