ascii-game/main.c

201 lines
4.4 KiB
C

/*
* Copyright(c) 2017 Daniel Knüttel
*/
/* This program is free software.
* Anyways if you think this program is worth it
* and we meet shout a drink for me.
*/
/* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Dieses Programm ist Freie Software: Sie können es unter den Bedingungen
* der GNU Affero General Public License, wie von der Free Software Foundation,
* Version 3 der Lizenz oder (nach Ihrer Wahl) jeder neueren
* veröffentlichten Version, weiterverbreiten und/oder modifizieren.
*
* Dieses Programm wird in der Hoffnung, dass es nützlich sein wird, aber
* OHNE JEDE GEWÄHRLEISTUNG, bereitgestellt; sogar ohne die implizite
* Gewährleistung der MARKTFÄHIGKEIT oder EIGNUNG FÜR EINEN BESTIMMTEN ZWECK.
* Siehe die GNU Affero General Public License für weitere Details.
*
* Sie sollten eine Kopie der GNU Affero General Public License zusammen mit diesem
* Programm erhalten haben. Wenn nicht, siehe <http://www.gnu.org/licenses/>.
*/
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<termios.h>
#include <sys/select.h>
#include<signal.h>
#include"input_output.h"
#include"playfield.h"
int difficulty = 200;
static struct termios oldt, newt;
char * playfield;
char ** horizon;
// break the mainloop, if there was a SIGINT
static volatile char sigint_received = 0;
static struct termios oldt, newt;
int main(void)
{
// set up the terminal for our hacky game....
tcgetattr(STDIN_FILENO, &oldt);
newt = oldt;
newt.c_lflag &= ~(ICANON | ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
// ok done
int pos = 0;
unsigned long long int score = 0;
char input = KEY_DEFAULT;
int to_place = 0;
printf("q: end; d: right; a: left\n\n\n");
while(input != KEY_EXIT && !(EOF_received || sigint_received))
{
horizon_drop_one_line(horizon);
// clear both the cursor and
// the last enemy
playfield[pos] = ' ';
horizon[0][to_place] = ' ';
// actually if...else produces
// smaller objectcode than switch
if(input == KEY_RIGHT)
{
pos++;
if(pos >= WIDTH)
{
pos = 0;
}
}
if(input == KEY_LEFT)
{
pos--;
if(pos < 0)
{
pos = WIDTH - 1;
}
}
if(input == KEY_EXIT)
{
break;
}
clear_screen();
print_horizon(horizon);
// set the player cursor
playfield[pos] = CHAR_ME;
// add the next enemy
to_place = (random() & 0xff) % WIDTH;
horizon[0][to_place] = CHAR_ENEMY;
put_line(playfield);
// player got hit.
if(horizon[LINES - 1][pos] == CHAR_ENEMY)
{
printf("GAME OVER!\nYour score was: %llu\n", score);
break;
}
usleep(difficulty * 1000);
score++;
if(!(score % 50))
{
difficulty--;
}
if(score == 0)
{
printf("Congrats. You won the game.\n");
break;
}
printf("SCORE: %llu\n", score);
// check this to prevent blocking
if(EOF_received || sigint_received)
{
break;
}
input = get_last_key_or_default();
}
return 0;
}
// We need those signal handlers to
// free the memory properly.
// If they do not get caught the
// destructors will be skipped.
// should not happen.
void __attribute__((cold)) handle_sigint(int signum)
{
sigint_received = 1;
}
// should not happen.
void __attribute__((cold)) handle_sigterm(int signum)
{
printf("\n\nTERMINATED!\n");
exit(1);
}
/*
Constructor: Add a sighandler for SIGINT and SIGTERM
*/
void __attribute__((constructor)) add_signal_handlers(void)
{
signal(SIGINT, handle_sigint);
signal(SIGTERM, handle_sigterm);
}
/*
Destructor: Free memory
*/
void __attribute__((destructor)) clean(void)
{
free(playfield);
delete_horizon(horizon);
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
printf("\n");
}
/*
Constructor: create all the data we need
*/
void __attribute__((constructor)) build_playfield(void)
{
playfield = allocate_playfield(WIDTH);
build_horizon(&horizon);
}