commit 827fddf4824f333382bb7746b40c11abd71f2049 Author: 8nl <8nlight@disroot.org> Date: Thu May 30 23:22:23 2024 +0000 Upload files to "/" diff --git a/main.c b/main.c new file mode 100644 index 0000000..c52a78a --- /dev/null +++ b/main.c @@ -0,0 +1,359 @@ +#include +#include +#include +#include +#include +#include +#include + +#ifdef ENABLE_SSL +#include +#endif + +enum { + CREWMATE, + IMPOSTER, + DIED, + COUNT +}; + +enum { + LOBBY, + GAME, + DISCUSSION +}; + +typedef struct { + char *nick; + int num; + + int type; + int admin; + int map; + + int votes; +} CLIENT; + +CLIENT *players; +size_t now_players; +size_t size_players = 10; + +time_t timer; +time_t voting_timer; + +int current_mode; + +int GetByNick(const char *nick, size_t *ret) { + for (size_t i = 0; i < now_players; i++) + if (!strcmp(nick, players[i].nick)) { + *ret = i; + return 0; + } + + return 1; +} + +void sort(size_t ptr){ + for (size_t i = ptr; i < now_players; i++) + if (i + 1 <= now_players) + players[i] = players[i + 1]; +} + +void clear(void) { + for (size_t i = 0; i < size_players; i++) + if (players[i].nick) + free(players[i].nick); + + memset(players, 0, sizeof(CLIENT) * size_players); + + current_mode = LOBBY; + now_players = 0; +} + +void broadcast(IRCC_client *irc, const char *ign, const char *msg) { + for (size_t i = 0; i < now_players; i++) + if (strcmp(ign, players[i].nick)) + IRCC_send(irc, players[i].nick, msg); +} + +int test_player(IRCC_client *irc, const char *nick, size_t *res) { + size_t ret = 0; + if (GetByNick(nick, &ret)) { + IRCC_send(irc, nick, "Firstly join!"); + return 1; + } + + *res = ret; + return 0; +} + +void player_quit(IRCC_client *irc, char *buf, size_t size, const char *nick) { + size_t ret = 0; + if (test_player(irc, nick, &ret)) + return; + + snprintf(buf, size, "Player [%d] left", players[ret].num); + broadcast(irc, nick, buf); + + if (players[ret].admin) { + CLIENT *client; + if (ret + 1 < now_players) + client = &players[ret + 1]; + + else + client = &players[ret - 1]; + + client->admin = 1; + + snprintf(buf, size, "New admin is [%d]", client->num); + broadcast(irc, nick, buf); + } + + if (players[ret].type == IMPOSTER) { + snprintf(buf, size, "[%d] was imposter. Game over!", players[ret].num); + broadcast(irc, nick, buf); + + clear(); + return; + } + + free(players[ret].nick); + sort(ret); + + now_players--; +} + +int gameloop(IRCC_client *irc) { + int irc_ret = IRCC_recv(irc); + if (irc_ret == IRCC_DISCONNECTED) + return 1; + + irc_ret = IRCC_parse(irc); + if (irc->irc_msg == NULL || irc->irc_nick == NULL || irc->irc_channel == NULL) + return 0; + + /* Common buffer */ + char buf[512]; + char *nick = strdup(irc->irc_nick); + if (nick == NULL) + return 0; + + if (irc_ret == IRCC_PRIVMSG) { + if (!strncmp(irc->irc_msg, "!join", 5)) { + if (current_mode != LOBBY) { + IRCC_send(irc, nick, "Game started"); + goto END; + } + + /* Check player */ + if (now_players == size_players) { + IRCC_send(irc, nick, "Sorry, max players"); + goto END; + } + + size_t ret = 0; + if (!GetByNick(nick, &ret)) { + IRCC_send(irc, nick, "You already joined"); + goto END; + } + + /* Register */ + players[now_players].nick = strdup(nick); + if (players[now_players].nick == NULL) + goto END; + + /* In game nickname */ + players[now_players].num = rand(); + + /* Give admin permission */ + int admin_flag = 0; + if (now_players == 0) + admin_flag = 1; + + players[now_players].admin = admin_flag; + + /* Other */ + players[now_players].map = 0; + players[now_players].type = 0; + + /* Inform all */ + snprintf(buf, sizeof(buf), "New player [%d]! Total: %zu/%zu", players[now_players].num, now_players + 1, size_players); + broadcast(irc, nick, buf); + + snprintf(buf, sizeof(buf), "You joined with id [%d]", players[now_players].num); + IRCC_send(irc, nick, buf); + + now_players++; + } + + else if (!strncmp(irc->irc_msg, "!say", 4)) { + if (current_mode == GAME) + goto END; + + size_t ret = 0; + if (test_player(irc, nick, &ret)) + goto END; + + if (players[ret].type == DIED) { + IRCC_send(irc, nick, "You died! You cant send messages"); + goto END; + } + + snprintf(buf, sizeof(buf), "[%d]:%s", players[ret].num, irc->irc_msg + 4); + broadcast(irc, nick, buf); + } + + else if (!strncmp(irc->irc_msg, "!exit", 5)) { + IRCC_send(irc, nick, "Goodbye!"); + player_quit(irc, buf, sizeof(buf), nick); + } + + else if (!strncmp(irc->irc_msg, "!status", 7)) { + size_t ret = 0; + if (test_player(irc, nick, &ret)) + goto END; + + snprintf(buf, sizeof(buf), "Status: Your id [%d] | Players [%zu/%zu]", players[ret].num, now_players, size_players); + IRCC_send(irc, nick, buf); + } + + else if (!strncmp(irc->irc_msg, "!start", 6)) { + if (current_mode != LOBBY) { + IRCC_send(irc, nick, "Game already started"); + goto END; + } + + size_t ret = 0; + if (GetByNick(nick, &ret)) { + IRCC_send(irc, nick, "You are not admin"); + goto END; + } + + current_mode = GAME; + timer = time(NULL); + + for (size_t i = 0; i < now_players; i++) + players[i].type = CREWMATE; + + size_t im = rand() % now_players; + players[im].type = IMPOSTER; + + /* Inform all */ + broadcast(irc, players[im].nick, "You crewmate"); + IRCC_send(irc, players[im].nick, "You imposter"); + } + + else if (!strncmp(irc->irc_msg, "!emergency", 10)) { + size_t ret = 0; + if (test_player(irc, nick, &ret)) + goto END; + + current_mode = DISCUSSION; + snprintf(buf, sizeof(buf), "Player [%d] pressed emergency button! You have 60 second to vote or skip", players[ret].num); + + voting_timer = time(NULL); + } + + else if (!strncmp(irc->irc_msg, "!help", 5)) + IRCC_send(irc, nick, "[!start] [!help] [!say MSG] [!join] [!exit] [!status] InGame: [!kill] [!go NUM] [!emergency] [!vote NUM] [!skip]"); + } + + else if (irc_ret == IRCC_QUIT) + player_quit(irc, buf, sizeof(buf), nick); + +END: + free(nick); + return 0; +} + +int main(int argc, char **argv) { + char *server = "127.0.0.1"; + char *nick = "amongrass"; + unsigned int port = 6667; + int usessl = 0; + + int opt; + while ((opt = getopt(argc, argv, "h:n:p:m:s")) != -1) { + switch (opt) { + case 'm': + sscanf(optarg, "%zu", &size_players); + if (size_players < 1 || size_players > 100) { + fprintf(stderr, "amongrass: failed to set players count\n"); + return 1; + } + + break; + + case 'h': + server = optarg; + break; + + case 'p': + port = atoi(optarg); + break; + + case 'n': + nick = optarg; + break; + + case 's': + usessl = 1; + break; + + default: + printf("./amongrass [snpm]\n\t-h IP Server ip Default: %s\n\t-n NICK Bot nickname Default: %s\n\t-p PORT Server port Default: %d\n\t-m N Max players in game Default: %zu\n\t-s Use SSL Default: false\n", server, nick, port, size_players); + return 0; + } + } + + players = malloc(sizeof(CLIENT) * size_players); + if (players == NULL) { + fprintf(stderr, "amongrass: malloc failed: %s", strerror(errno)); + return 1; + } + + IRCC_client irc; + if (IRCC_connect(&irc, server, port) == IRCC_ERROR) { + fprintf(stderr, "amongrass: failed connect to %s: %s\n", server, strerror(errno)); + goto EXIT_MAIN; + } + + if (usessl) { +#ifdef ENABLE_SSL + if (IRCC_initssl(&irc) == IRCC_ERROR) { + fprintf(stderr, "amongrass: irc_ssl: %s\n", ERR_error_string(ERR_get_error(), NULL)); + goto EXIT_MAIN; + } +#endif + } + + if (IRCC_register(&irc, nick) == IRCC_DISCONNECTED) { + fprintf(stderr, "amongrass: irc: disconnected\n"); + goto EXIT_MAIN; + } + + timer = time(NULL); + current_mode = LOBBY; + srand(getpid()); + + fprintf(stderr, "amongrass: Successful connected\namongrass: Nickname: %s\n", nick); + + while (1) { + if (time(NULL) - timer >= 60) { + broadcast(&irc, "", "Time is over!"); + clear(); + } + + if (gameloop(&irc)) + break; + } + + IRCC_close(&irc); + for (size_t i = 0; i < size_players; i++) + if (players[i].nick) + free(players[i].nick); + +EXIT_MAIN: + free(players); + return 1; +}