#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include <time.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <avl.h>
#include <postgresql/libpq-fe.h>
#include "f00f.h"
#define GALGJE_TIMEOUT 900
#define GALGJE_MAXFOUT 5
#define LUKAS_TIMEOUT 90
static void f00f_ROULETTE(presence_t p, char *arg) {
pg_trans_t *pg;
PGresult *res = NULL;
s64 kamer;
if(arg) {
appreciate(p, arg, "russisch");
return;
}
pg = pg_begin();
if(!pg)
return;
res = pg_query(pg, "SELECT getsimple('roulette', '%?')", target(p));
if(!res)
goto rollback;
kamer = pg_getint(res, 0, 0);
if(kamer == ~0) /* nieuwe kogel in revolver stoppen */
kamer = mt_genrand32_bounded(0, 6);
if(kamer > 0) {
if(!pg_query(pg, "SELECT setsimple('roulette', '%?', '%Ld')", target(p), kamer-1))
goto rollback;
appreciate(p, arg, "roulette:klik");
} else {
if(!pg_query(pg, "SELECT delsimple('roulette', '%?')", target(p)))
goto rollback;
mdk(p, "PANG!");
}
pg_commit(pg);
return;
rollback:
pg_rollback(pg);
}
/* totdat die hoop schroot herschreven wordt... */
static pthread_mutex_t lukas_mutex = PTHREAD_MUTEX_INITIALIZER;
typedef struct lukas_ini {
time_t start;
char *spelers[2];
int result[2];
char *winnaar;
char *loser;
} lukas_ini_t;
static lukas_ini_t lukas_ini = {0};
static char *galgjewoord(void) {
char buf[1024];
struct stat s;
int fd;
const char *woord = NULL;
fd = open("dutch.utf8", O_RDONLY);
if(fd < 0)
return strdup(strerror(errno));
memset(buf, '0', sizeof(buf));
if(fstat(fd, &s) < 0) {
close(fd);
return strdup(strerror(errno));
}
if(lseek(fd, mt_genrand32_bounded(0, s.st_size), SEEK_SET) < 0) {
close(fd);
return strdup(strerror(errno));
}
if(read(fd, buf, sizeof(buf) - 1) <= 0) {
close(fd);
return strdup(strerror(errno));
}
close(fd);
if((woord = strchr(buf, '\n'))) {
woord++;
if(strchr(woord + 1, '\n'))
*strchr(woord + 1, '\n') = '\0';
else
woord = _("hottentottententententoonstelling");
}
return strdup(woord);
}
static void mep(presence_t p, char *arg) {
appreciate(p, arg, "mep");
}
static void f00f_MEP(presence_t p, char *arg) {
if(!p.chan)
return;
if(!arg)
arg = p.nick->name;
pthread_mutex_lock(&lukas_mutex);
if(lukas_ini.winnaar && lukas_ini.loser) {
if(strcasecmp(p.nick->name, lukas_ini.winnaar) != 0) {
appreciate(p, arg, "lukas:valsspeler");
mep(p, p.nick->name);
} else if(strcasecmp(arg, lukas_ini.loser) != 0) {
appreciate(p, arg, "lukas:geenspeler");
} else {
mep(p, arg);
}
} else {
appreciate(p, arg, "lukas:geenlukas");
}
pthread_mutex_unlock(&lukas_mutex);
}
static void f00f_LUKASSTAT(presence_t p, char *arg) {
pthread_mutex_lock(&lukas_mutex);
if(lukas_ini.winnaar && lukas_ini.loser) {
feedback_str(p, arg, "lukas:stat",
'W', lukas_ini.winnaar,
'L', lukas_ini.winnaar,
0);
} else {
appreciate(p, arg, "lukas:geenlukas");
}
pthread_mutex_unlock(&lukas_mutex);
}
static bool guess(pg_trans_t *pg, presence_t p, char *str) {
PGresult *res = NULL, *gok = NULL;
char *woord, *goed, *fout, *balk, *s, *t;
bool klaar;
int poging;
format_t fmt = format_0;
if(!pg)
return false;
if(str) {
if(!*str)
return false;
strlower(str);
format_add_str(&fmt, 'g', str, 0);
gok = pg_query(pg, "SELECT raadgalgje('%?', '%?', '%?')", target(p), f00finstance, str);
if(!gok || !PQntuples(gok))
return false;
if(PQgetisnull(gok, 0, 0)) {
if(p.chan)
appreciate(p, NULL, "galgje:geengalgje");
else
appreciate(p, NULL, "galgje:geengalgje:priv");
return false;
}
}
res = pg_query(pg, "SELECT woord, geraden, fout FROM galgje"
" WHERE channel = zoekgalgje('%?', '%?') FOR UPDATE", target(p), f00finstance);
if(!res || !PQntuples(res))
return false;
woord = PQgetvalue(res, 0, 0);
goed = PQgetvalue(res, 0, 1);
fout = PQgetvalue(res, 0, 2);
if(!woord || !goed || !fout)
return false;
balk = alloca(strlen(woord)+1);
if(!balk)
return false;
poging = strlen(fout);
format_add_i(&fmt,
'p', poging,
'o', GALGJE_MAXFOUT - poging,
0);
for(s = woord, t = balk, klaar = true; *s; s++) {
if(!strchr(goed, *s) && isalpha(*s)) {
klaar = false;
*t++ = '_';
} else {
*t++ = *s;
}
}
*t = '\0';
format_add_str(&fmt,
'w', balk,
'W', woord,
'F', fout,
0);
if(gok) {
if(strcmp(PQgetvalue(gok, 0, 0), "t")) {
if(str[1]) {
if(p.chan)
feedback(p, NULL, "galgje:helemaal:fout", &fmt);
else
feedback(p, NULL, "galgje:helemaal:fout:priv", &fmt);
} else {
if(p.chan)
feedback(p, NULL, "galgje:algeraden", &fmt);
else
feedback(p, NULL, "galgje:algeraden:priv", &fmt);
}
} else {
if(str[1]) {
if(p.chan)
feedback(p, NULL, "galgje:helemaal:goed", &fmt);
else
feedback(p, NULL, "galgje:helemaal:goed:priv", &fmt);
} else {
if(strchr(goed, *str)) {
if(p.chan)
feedback(p, NULL, "galgje:goed", &fmt);
else
feedback(p, NULL, "galgje:goed:priv", &fmt);
} else {
if(p.chan)
feedback(p, NULL, "galgje:fout", &fmt);
else
feedback(p, NULL, "galgje:fout:priv", &fmt);
}
}
}
}
if(poging > GALGJE_MAXFOUT || klaar) {
feedback(p, NULL, "galgje:klaar", &fmt);
pg_query(pg, "SELECT stopgalgje('%?', '%?')", target(p), f00finstance);
} else {
switch(poging) {
case 0:
feedback(p, NULL, "galgje:status:begin", &fmt);
break;
case GALGJE_MAXFOUT:
feedback(p, NULL, "galgje:status:eind", &fmt);
break;
default:
feedback(p, NULL, "galgje:status", &fmt);
break;
}
}
return true;
}
static void f00f_GUESS(presence_t p, char *arg) {
pg_trans_t *pg = NULL;
pg = pg_begin();
if(!pg)
return;
if(guess(pg, p, arg)) {
pg_commit(pg);
return;
}
pg_rollback(pg);
}
static bool hangman(presence_t p, char *bedenker, char *woord) {
pg_trans_t *pg = NULL;
PGresult *res = NULL;
if(!p.nick->user || !woord)
return false;
if(!checkperms(p, "galgje"))
return false;
strlower(woord);
pg = pg_begin();
if(!pg)
return false;
if(f00f_debug > 10)
eprintf("Galgje: %s %s %s\n", target(p), p.nick->user->name, woord);
res = pg_query(pg, "SELECT startgalgje('%?', '%?', '%?', '%?')",
target(p), f00finstance, p.nick->user->name, woord);
if(!res)
goto rollback;
if(!PQntuples(res) || !strtoul(PQgetvalue(res, 0, 0), NULL, 10)) {
/* ging niet goed. maar waarom? */
res = pg_query(pg, "SELECT zoekgalgje('%?', '%?')", target(p), f00finstance);
if(PQntuples(res) && strtoul(PQgetvalue(res, 0, 0), NULL, 10))
say(p, _("Er is nog een galgje bezig!"));
goto rollback;
}
if(bedenker)
say(p, _("%s heeft een galgjewoord bedacht!\n"), bedenker);
if(guess(pg, p, NULL))
return pg_commit(pg);
rollback:
return pg_rollback(pg), false;
}
static void f00f_HANGMAN(presence_t p, char *arg) {
nick_t *n;
chan_t *c;
char *woord = NULL;
if(!p.nick->user)
return;
if(!p.chan) {
woord = match(arg);
if(woord) {
c = getchan(arg);
n = getnick(f00fnick);
if(c && n && avl_search(&c->nicks, p.nick) && avl_search(&c->nicks, n)) {
p.chan = c;
hangman(p, p.nick->name, woord);
} else {
say(p, _("Wie? Wat? Waar?\n"));
}
} else {
woord = galgjewoord();
if(woord) {
hangman(p, NULL, woord);
free(woord);
}
}
} else {
woord = galgjewoord();
if(woord) {
hangman(p, NULL, woord);
free(woord);
}
}
}
static void f00f_LUKAS(presence_t p, char *arg) {
time_t nu_tijd;
bool kwijt;
if(!p.chan)
return;
if(!arg) {
say(p, _("Lukas wie?"));
return;
}
time(&nu_tijd);
if((nu_tijd - lukas_ini.start) < LUKAS_TIMEOUT) {
say(p, _("Sorry, %s. %s en %s zijn nog aan het lukassen."), p.nick->name, lukas_ini.spelers[0], lukas_ini.spelers[1]);
} else if(strcasecmp(p.nick->name, arg) == 0) {
say(p, _("We weten al wie dat gaat verliezen, %s.\n"), p.nick->name);
mep(p, p.nick->name);
rate(p, p.nick->name, -1);
} else if(!strcasecmp(arg, f00fnick)) {
say(p, _("Aha! Ik neem je uitdaging aan!"));
time(&lukas_ini.start);
lukas_ini.spelers[0] = xstrdup(p.nick->name);
lukas_ini.spelers[1] = xstrdup(f00fnick);
lukas_ini.result[0] = -1;
lukas_ini.result[1] = dice(10, 1);
say(p, _("%s rolt... en gooit %d!"), f00fnick, lukas_ini.result[1]);
if(lukas_ini.result[1] < 4)
say(p, _("Ha, zie me nu maar eens te verslaan!"));
else if(lukas_ini.result[1] > 7)
say(p, _("Ai ai, dat is geen al te beste worp..."));
} else {
kwijt = !avl_search(&p.chan->nicks, getnick(arg));
if(0 && kwijt) {
say(p, _("Ik zie hier helemaal geen %s, %s!"), arg, p.nick->name);
return;
}
say(p, _("%s geeft een d10 aan %s. Rol maar om ini."), f00fnick, arg);
time(&lukas_ini.start);
lukas_ini.spelers[0] = xstrdup(p.nick->name);
lukas_ini.spelers[1] = xstrdup(arg);
if(!lukas_ini.spelers[0] || !lukas_ini.spelers[1])
lukas_ini.start = 0; /* "Errorhandling" */
lukas_ini.result[0] = lukas_ini.result[1] = -1;
if(kwijt) {
ventriloquate(arg, p, "!rol");
lukas_ini.result[1] = dice(10, 1);
say(p, _("%s gooit %d!"), arg, lukas_ini.result[1]);
}
}
}
static void f00f_ROL(presence_t p, char *arg) {
time_t nu_tijd;
char *winnaar = NULL, *loser = NULL;
time(&nu_tijd);
if(!p.chan)
return;
pthread_mutex_lock(&lukas_mutex);
/* Er is een Lukas gaande. Of niet... */
if((nu_tijd - lukas_ini.start) < LUKAS_TIMEOUT) {
if(strcasecmp(lukas_ini.spelers[0], p.nick->name) == 0) {
if(lukas_ini.result[0] > 0) {
say(p, _("Probeer je vals te spelen, %s?"), p.nick->name);
} else {
lukas_ini.result[0] = dice(10, 1);
say(p, _("%s gooit %d!"), p.nick->name, lukas_ini.result[0]);
if(lukas_ini.result[1] > 0) {
if(lukas_ini.result[0] < lukas_ini.result[1]) {
winnaar = lukas_ini.spelers[0];
loser = lukas_ini.spelers[1];
} else {
winnaar = lukas_ini.spelers[1];
loser = lukas_ini.spelers[0];
}
}
}
} else if (strcasecmp(lukas_ini.spelers[1], p.nick->name) == 0) {
if(lukas_ini.result[1] > 0) {
say(p, _("Probeer je vals te spelen, %s?"), p.nick->name);
} else {
lukas_ini.result[1] = dice(10, 1);
say(p, _("%s gooit %d!"), p.nick->name, lukas_ini.result[1]);
if(lukas_ini.result[0] > 0) {
if(lukas_ini.result[1] < lukas_ini.result[0]) {
winnaar = lukas_ini.spelers[1];
loser = lukas_ini.spelers[0];
} else {
winnaar = lukas_ini.spelers[0];
loser = lukas_ini.spelers[1];
}
}
}
} else {
say(p, _("Jij bent niet uitgedaagd voor een lukas, %s!"), p.nick->name);
}
if (winnaar) {
if(!strcasecmp(winnaar, f00fnick)) {
say(p, _("Ha! Ik heb lekker ini!"));
mep(p, loser);
rate(presence(f00fnick, NULL), loser, -1);
} else if (!strcasecmp(loser, f00fnick)) {
say(p, _("Hmz, jij krijgt ini %s..."), winnaar);
} else {
say(p, _("%s krijgt ini!"), winnaar);
}
lukas_ini.start = 0;
lukas_ini.result[0] = lukas_ini.result[1] = -1;
xreplace(&lukas_ini.winnaar, winnaar);
xreplace(&lukas_ini.loser, loser);
free(lukas_ini.spelers[0]);
free(lukas_ini.spelers[1]);
} else if(lukas_ini.result[0] > 0 && lukas_ini.result[1] > 0) {
say(p, _("%s slaat %s en %s bont en blauw. Gelijk spel."), f00fnick, lukas_ini.spelers[0], lukas_ini.spelers[1]);
lukas_ini.start = 0;
lukas_ini.result[0] = lukas_ini.result[1] = -1;
xreplace(&lukas_ini.winnaar, NULL);
xreplace(&lukas_ini.loser, NULL);
free(lukas_ini.spelers[0]);
free(lukas_ini.spelers[1]);
}
} else {
say(p, _("%s rolt op zijn rug? ofzo?"), f00fnick);
}
pthread_mutex_unlock(&lukas_mutex);
}
static tab_entry_t command_tab_entries[] = {
{"ROUL", f00f_ROULETTE},
{"ROULETTE", f00f_ROULETTE},
{"MEP", f00f_MEP},
{"LUKASSTAT", f00f_LUKASSTAT},
{"GUESS", f00f_GUESS},
{"RAAD", f00f_GUESS},
{"GALG", f00f_HANGMAN},
{"GALGJE", f00f_HANGMAN},
{"HANG", f00f_HANGMAN},
{"HANGMAN", f00f_HANGMAN},
{"LUKAS", f00f_LUKAS},
{"ROL", f00f_ROL}
};
TAB_REGISTER(command);