added 4wins game
authorpk910 <philipp@zoelle1.de>
Thu, 22 Mar 2012 16:11:25 +0000 (17:11 +0100)
committerpk910 <philipp@zoelle1.de>
Thu, 22 Mar 2012 16:38:04 +0000 (17:38 +0100)
Makefile.am
src/modules/NeonFun.mod/bot_NeonFun.c
src/modules/NeonFun.mod/bot_NeonFun.h
src/modules/NeonFun.mod/cmd_neonfun.c
src/modules/NeonFun.mod/cmd_neonfun.h
src/modules/NeonFun.mod/cmd_neonfun_4stone.c [new file with mode: 0644]
src/modules/NeonFun.mod/cmd_neonfun_4view.c [new file with mode: 0644]
src/modules/NeonFun.mod/cmd_neonfun_4wins.c [new file with mode: 0644]
src/modules/NeonFun.mod/game_4wins.c [new file with mode: 0644]
src/modules/NeonFun.mod/game_4wins.h [new file with mode: 0644]
src/modules/NeonFun.mod/game_uno.c

index aba1bf4da2bc41e359f66236725b5b803c3677ed..6daebad4e2cc7966bd0bcc1114e84eb0a01de9ea 100644 (file)
@@ -155,6 +155,10 @@ libNeonFun_la_SOURCES = src/modules/NeonFun.mod/bot_NeonFun.c \
       src/modules/NeonFun.mod/cmd_neonfun_unoplay.c \
       src/modules/NeonFun.mod/cmd_neonfun_unotake.c \
       src/modules/NeonFun.mod/game_uno.c \
+      src/modules/NeonFun.mod/cmd_neonfun_4wins.c \
+      src/modules/NeonFun.mod/cmd_neonfun_4stone.c \
+      src/modules/NeonFun.mod/cmd_neonfun_4view.c \
+      src/modules/NeonFun.mod/game_4wins.c \
       src/modules/NeonFun.mod/module.c
 libNeonFun_la_LDFLAGS = -module -rpath /nowhere -avoid-version -no-undefined
 libNeonFun_la_LIBADD = $(MYSQL_LIBS)
index f203f9114eb99e99f4f949a50a967d467a2750af..ebb0cc58dc4ac17d7d2cdffcb060d41b468a874f 100644 (file)
@@ -38,6 +38,7 @@
 #include "../../EventLogger.h"
 #include "../../bots.h"
 #include "game_uno.h"
+#include "game_4wins.h"
 
 #define BOTID NEONFUN_BOTID
 #define BOTALIAS "NeonFun"
@@ -123,14 +124,17 @@ static void start_bots(int type) {
 
 static void neonfun_parted(struct ChanUser *chanuser, char *reason) {
     uno_event_part(chanuser);
+    fourwins_event_part(chanuser);
 }
 
 static void neonfun_quitted(struct UserNode *user, char *reason) {
     uno_event_quit(user);
+    fourwins_event_quit(user);
 }
 
 static int neonfun_freechan(struct ChanNode *chan) {
     uno_event_freechan(chan);
+    fourwins_event_freechan(chan);
     return 0;
 }
 
@@ -232,5 +236,42 @@ void uno_reply(struct uno_game *game, struct UserNode *user, const char *text, .
     write_socket(client, sendBuf, pos+1);
 }
 
+void fourwins_reply(struct fourwins_game *game, const char *text, ...) {
+    struct ClientSocket *client = game->textbot;
+    struct fourwins_guest *guest;
+    int guest_count = 0;
+    for(guest = game->guests; guest; guest = guest->next) {
+        guest_count++;
+    }
+    struct ChanUser *chanusers[guest_count + 2];
+    chanusers[0] = game->player[0];
+    chanusers[1] = game->player[1];
+    guest_count = 0;
+    for(guest = game->guests; guest; guest = guest->next) {
+        chanusers[2 + (guest_count++)] = guest->chanuser;
+    }
+    int i;
+    guest_count += 2;
+    for(i = 0; i < guest_count; i++) {
+        const char *reply_format = get_language_string(chanusers[i]->user, text);
+        if(reply_format == NULL)
+            reply_format = text;
+        char formatBuf[MAXLEN];
+        sprintf(formatBuf, "NOTICE %s :[4WINS] %s", chanusers[i]->user->nick, reply_format);
+        va_list arg_list;
+        char sendBuf[MAXLEN];
+        int pos;
+        if (!(client->flags & SOCKET_FLAG_CONNECTED)) return;
+        sendBuf[0] = '\0';
+        va_start(arg_list, text);
+        pos = vsnprintf(sendBuf, MAXLEN - 2, formatBuf, arg_list);
+        va_end(arg_list);
+        if (pos < 0 || pos > (MAXLEN - 2)) pos = MAXLEN - 2;
+        sendBuf[pos] = '\n';
+        sendBuf[pos+1] = '\0';
+        write_socket(client, sendBuf, pos+1);
+    }
+}
+
 #undef BOTID
 #undef BOTALIAS
index 6e0e0f6869c136d67fb779e2a89fb4cadd14a2fd..c2102e7a7e76d4fd3370c8ed91570316f00c217a 100644 (file)
@@ -24,11 +24,13 @@ void loop_NeonFun();
 void free_NeonFun(int type);
 
 struct uno_game;
+struct fourwins_game;
 struct ChanNode;
 struct UserNode;
 
 char* getSetting(struct UserNode *user, struct ChanNode *chan, const char *setting);
 void setSetting(struct UserNode *user, struct ChanNode *chan, const char *setting, const char *value);
 void uno_reply(struct uno_game *game, struct UserNode *user, const char *text, ...);
+void fourwins_reply(struct fourwins_game *game, const char *text, ...);
 
 #endif
\ No newline at end of file
index 4f659c96cf04204fa3976cbc94b6208384d889c8..195749885344a5ee085a35ad02b2edc02860362e 100644 (file)
@@ -48,6 +48,28 @@ static const struct default_language_entry msgtab[] = {
     {"NF_UNO_USER_SKIP", "skipped $b%s$b."}, /* {ARGS: "TestUser"} */
     {"NF_UNO_GAME_FINISHED", "The UNO Game has been finished!"},
     {"NF_UNO_ADD_CARD", "$b%s$b has to take up %d cards. There is still the possibility that he/she has another card of this type...?"},
+    {"NF_UNO_RANK", "Rank"},
+    {"NF_UNO_NAME", "Name"},
+    {"NF_UNO_WON_GAMES", "Won Games"},
+    {"NF_UNO_TOTAL_WON_GAMES", "Total won Games"},
+    
+    {"NF_4WINS_NOT_YOUR_TURN", "Wait your turn!"},
+    {"NF_4WINS_INVALID_COLUMN", "invalid column!"},
+    {"NF_4WINS_COLUMN_FULL", "This column is full!"},
+    {"NF_4WINS_USER_HURRY_UP", "$b%s$b, it's your turn! To put a stone into a column use: 4stone <colomn>"}, /* {ARGS: "TestUser"} */
+    {"NF_4WINS_USER_WON", "$b%s$b won the game!"}, /* {ARGS: "TestUser"} */
+    {"NF_4WINS_ENTER_OPPONENT", "Please enter the nick of the opponent you want to play against as a parameter of 4wins (eg. $b4wins TestUser$b)"},
+    {"NF_4WINS_OPPONENT_NOT_IN_CHAN", "$b%s$b needs to be in this channel to start a game against him/her."}, /* {ARGS: "TestUser"} */
+    {"NF_4WINS_DRAW", "Noone has won this game."},
+    {"NF_4WINS_REQUEST", "$b%s$b wants to play a game against you. use $b4wins$b to start the game."}, /* {ARGS: "TestUser"} */
+    {"NF_4WINS_REQUESTED", "waiting for $b%s$b accepting the game..."}, /* {ARGS: "TestUser"} */
+    {"NF_4WINS_START", "%s accepted the challenge! game starts:"}, /* {ARGS: "TestUser"} */
+    {"NF_4WINS_APPEND_PLAYER", "Please append the nick of a player playing the game you want to view. (eg. $b4view TestUser$b)"},
+    {"NF_4WINS_NO_GAME_FOUND", "Couldn't find a game with this user in this channel."},
+    {"NF_4WINS_VIEWING_ANOTHER_GAME", "You are already viewing another game."},
+    {"NF_4WINS_VIEWING_GAME", "You are now viewing the game."},
+    {"NF_4WINS_GAME_CLOSED", "Game aborted."},
+    {"NF_4WINS_TIMEOUT", "Game aborted (timeout)."},
     {NULL, NULL}
 };
 
@@ -62,6 +84,10 @@ void register_commands() {
     USER_COMMAND("unotake",      neonfun_cmd_unotake,  0,      NULL,     CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN);
     USER_COMMAND("unoplay",      neonfun_cmd_unoplay,  1,      NULL,     CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN);
     
+    USER_COMMAND("4wins",        neonfun_cmd_4wins,    0,      NULL,     CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN);
+    USER_COMMAND("4stone",       neonfun_cmd_4stone,   1,      NULL,     CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN);
+    USER_COMMAND("4view",        neonfun_cmd_4view,    0,      NULL,     CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN);
+    
     #undef USER_COMMAND
     
 }
index a97da59debaac63839b5f9172c430c4d3ca67941..93963da717e67e50d4aaf6b069d3d898be05fb7c 100644 (file)
@@ -46,4 +46,8 @@ CMD_BIND(neonfun_cmd_uno);
 CMD_BIND(neonfun_cmd_unotake);
 CMD_BIND(neonfun_cmd_unoplay);
 
+CMD_BIND(neonfun_cmd_4wins);
+CMD_BIND(neonfun_cmd_4stone);
+CMD_BIND(neonfun_cmd_4view);
+
 #endif
diff --git a/src/modules/NeonFun.mod/cmd_neonfun_4stone.c b/src/modules/NeonFun.mod/cmd_neonfun_4stone.c
new file mode 100644 (file)
index 0000000..96fa091
--- /dev/null
@@ -0,0 +1,107 @@
+/* cmd_neonfun_4stone.c - NeonServ v5.4
+ * Copyright (C) 2011-2012  Philipp Kreil (pk910)
+ * 
+ * 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 <http://www.gnu.org/licenses/>. 
+ */
+
+#include "cmd_neonfun.h"
+#include "game_4wins.h"
+
+CMD_BIND(neonfun_cmd_4stone) {
+    struct ChanUser *chanuser = getChanUser(user, chan);
+    if(!chanuser) return;
+    struct fourwins_game *game;
+    for(game = fourwins_active_games; game; game = game->next) {
+        if(chanuser == game->player[0] || chanuser == game->player[1]) {
+            if(game->state == FOURWINS_STATE_WAITING)
+                return;
+            else 
+                break;
+        }
+    }
+    if(game) {
+        //check if it's the player's turn
+        if(game->player[game->active_player] != chanuser) {
+            reply(getTextBot(), user, "NF_4WINS_NOT_YOUR_TURN");
+            return;
+        }
+        int x = atoi(argv[0])-1;
+        if(x < 0 || x >= FOURWINS_MATRIX_WIDTH) {
+            reply(getTextBot(), user, "NF_4WINS_INVALID_COLUMN");
+            return;
+        }
+        int y = fourwins_next_free_y(game, x);
+        if(y < 0) {
+            reply(getTextBot(), user, "NF_4WINS_COLUMN_FULL");
+            return;
+        }
+        timeq_del(game->timer);
+        game->timer = NULL;
+        game->matrix[x][y].field = game->active_player+1;
+        fourwins_show_matrix(game);
+        if(fourwins_check_win(game, x, y)) {
+            fourwins_reply(game, "NF_4WINS_USER_WON", game->player[game->active_player]->user->nick);
+            if((game->player[game->active_player]->user->flags & USERFLAG_ISAUTHED)) {
+                char *tmp;
+                int win_count = ((tmp = getSetting(game->player[game->active_player]->user, chan, "4wins_win")) ? atoi(tmp) : 0);
+                int total_win_count = ((tmp = getSetting(game->player[game->active_player]->user, NULL, "4wins_win")) ? atoi(tmp) : 0);
+                win_count++;
+                total_win_count++;
+                char buf[10];
+                sprintf(buf, "%d", win_count);
+                setSetting(game->player[game->active_player]->user, chan, "4wins_win", buf);
+                sprintf(buf, "%d", total_win_count);
+                setSetting(game->player[game->active_player]->user, NULL, "4wins_win", buf);
+            }
+            fourwins_free_game(game);
+        } else {
+            game->total_stones++;
+            if(game->total_stones == FOURWINS_MAX_STONES) {
+                fourwins_reply(game, "NF_4WINS_DRAW");
+                if((game->player[0]->user->flags & USERFLAG_ISAUTHED)) {
+                    char *tmp;
+                    int win_count = ((tmp = getSetting(game->player[0]->user, chan, "4wins_draw")) ? atoi(tmp) : 0);
+                    int total_win_count = ((tmp = getSetting(game->player[0]->user, NULL, "4wins_draw")) ? atoi(tmp) : 0);
+                    win_count++;
+                    total_win_count++;
+                    char buf[10];
+                    sprintf(buf, "%d", win_count);
+                    setSetting(game->player[0]->user, chan, "4wins_draw", buf);
+                    sprintf(buf, "%d", total_win_count);
+                    setSetting(game->player[0]->user, NULL, "4wins_draw", buf);
+                }
+                if((game->player[1]->user->flags & USERFLAG_ISAUTHED)) {
+                    char *tmp;
+                    int win_count = ((tmp = getSetting(game->player[1]->user, chan, "4wins_draw")) ? atoi(tmp) : 0);
+                    int total_win_count = ((tmp = getSetting(game->player[1]->user, NULL, "4wins_draw")) ? atoi(tmp) : 0);
+                    win_count++;
+                    total_win_count++;
+                    char buf[10];
+                    sprintf(buf, "%d", win_count);
+                    setSetting(game->player[1]->user, chan, "4wins_draw", buf);
+                    sprintf(buf, "%d", total_win_count);
+                    setSetting(game->player[1]->user, NULL, "4wins_draw", buf);
+                }
+                fourwins_free_game(game);
+                return;
+            }
+            if(game->active_player)
+                game->active_player = 0;
+            else
+                game->active_player = 1;
+            fourwins_reply(game, "NF_4WINS_USER_HURRY_UP", game->player[game->active_player]->user->nick);
+            game->timer = timeq_add(120, module_id, fourwins_timeout, game);
+        }
+    }
+}
diff --git a/src/modules/NeonFun.mod/cmd_neonfun_4view.c b/src/modules/NeonFun.mod/cmd_neonfun_4view.c
new file mode 100644 (file)
index 0000000..22aef65
--- /dev/null
@@ -0,0 +1,57 @@
+/* cmd_neonfun_4view.c - NeonServ v5.4
+ * Copyright (C) 2011-2012  Philipp Kreil (pk910)
+ * 
+ * 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 <http://www.gnu.org/licenses/>. 
+ */
+
+#include "cmd_neonfun.h"
+#include "game_4wins.h"
+
+CMD_BIND(neonfun_cmd_4view) {
+    struct UserNode *gameuser;
+    struct ChanUser *chanuser;
+    if(!argc || !(gameuser = getUserByNick(argv[0])) || !(chanuser = getChanUser(gameuser, chan))) {
+        reply(getTextBot(), user, "NF_4WINS_APPEND_PLAYER");
+        return;
+    }
+    struct fourwins_game *game, *fgame = NULL;
+    struct fourwins_guest *guest;
+    for(game = fourwins_active_games; game; game = game->next) {
+        for(guest = game->guests; guest; guest = guest->next) {
+            if(guest->chanuser->user == user) {
+                reply(getTextBot(), user, "NF_4WINS_VIEWING_ANOTHER_GAME");
+                return;
+            }
+        }
+        if(game->player[0]->user == user || game->player[1]->user == user) {
+            reply(getTextBot(), user, "NF_4WINS_VIEWING_ANOTHER_GAME");
+            return;
+        }
+        if(chanuser == game->player[0] || chanuser == game->player[1]) {
+            fgame = game;
+        }
+    }
+    game = fgame;
+    if(game) {
+        guest = malloc(sizeof(*guest));
+        chanuser = getChanUser(user, chan);
+        if(!chanuser) return;
+        guest->chanuser = chanuser;
+        guest->next = game->guests;
+        game->guests = guest;
+        reply(getTextBot(), user, "NF_4WINS_VIEWING_GAME");
+    } else {
+        reply(getTextBot(), user, "NF_4WINS_NO_GAME_FOUND");
+    }
+}
diff --git a/src/modules/NeonFun.mod/cmd_neonfun_4wins.c b/src/modules/NeonFun.mod/cmd_neonfun_4wins.c
new file mode 100644 (file)
index 0000000..a282a14
--- /dev/null
@@ -0,0 +1,93 @@
+/* cmd_neonfun_4wins.c - NeonServ v5.4
+ * Copyright (C) 2011-2012  Philipp Kreil (pk910)
+ * 
+ * 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 <http://www.gnu.org/licenses/>. 
+ */
+
+#include "cmd_neonfun.h"
+#include "game_4wins.h"
+
+CMD_BIND(neonfun_cmd_4wins) {
+    struct ChanUser *chanuser = getChanUser(user, chan);
+    if(!chanuser) return;
+    struct fourwins_game *game;
+    for(game = fourwins_active_games; game; game = game->next) {
+        if(chanuser == game->player[0]) {
+            return;
+        } else if(chanuser == game->player[1]) {
+            if(game->state == FOURWINS_STATE_WAITING)
+                break;
+            else 
+                return;
+        }
+    }
+    if(game) {
+        timeq_del(game->timer);
+        game->timer = NULL;
+        game->state = FOURWINS_STATE_RUNNING;
+        fourwins_reply(game, "NF_4WINS_START", user->nick);
+        if((game->player[0]->user->flags & USERFLAG_ISAUTHED)) {
+            char *tmp;
+            int win_count = ((tmp = getSetting(game->player[0]->user, chan, "4wins_games")) ? atoi(tmp) : 0);
+            int total_win_count = ((tmp = getSetting(game->player[0]->user, NULL, "4wins_games")) ? atoi(tmp) : 0);
+            win_count++;
+            total_win_count++;
+            char buf[10];
+            sprintf(buf, "%d", win_count);
+            setSetting(game->player[0]->user, chan, "4wins_games", buf);
+            sprintf(buf, "%d", total_win_count);
+            setSetting(game->player[0]->user, NULL, "4wins_games", buf);
+        }
+        if((game->player[1]->user->flags & USERFLAG_ISAUTHED)) {
+            char *tmp;
+            int win_count = ((tmp = getSetting(game->player[1]->user, chan, "4wins_games")) ? atoi(tmp) : 0);
+            int total_win_count = ((tmp = getSetting(game->player[1]->user, NULL, "4wins_games")) ? atoi(tmp) : 0);
+            win_count++;
+            total_win_count++;
+            char buf[10];
+            sprintf(buf, "%d", win_count);
+            setSetting(game->player[1]->user, chan, "4wins_games", buf);
+            sprintf(buf, "%d", total_win_count);
+            setSetting(game->player[1]->user, NULL, "4wins_games", buf);
+        }
+        fourwins_show_matrix(game);
+        fourwins_reply(game, "NF_4WINS_USER_HURRY_UP", game->player[game->active_player]->user->nick);
+        game->timer = timeq_add(120, module_id, fourwins_timeout, game);
+    } else {
+        if(!argc) {
+            reply(getTextBot(), user, "NF_4WINS_ENTER_OPPONENT");
+            return;
+        }
+        struct UserNode *opp_user = getUserByNick(argv[0]);
+        if(!opp_user) {
+            reply(getTextBot(), user, "NS_USER_UNKNOWN", argv[0]);
+            return;
+        }
+        struct ChanUser *opponent = getChanUser(opp_user, chan);
+        if(!opponent) {
+            reply(getTextBot(), user, "NF_4WINS_OPPONENT_NOT_IN_CHAN", opp_user->nick);
+            return;
+        }
+        game = calloc(1,sizeof(*game));
+        game->player[0] = chanuser;
+        game->player[1] = opponent;
+        game->textbot = getTextBot();
+        game->state = FOURWINS_STATE_WAITING;
+        game->timer = timeq_add(120, module_id, fourwins_timeout, game);
+        game->next = fourwins_active_games;
+        fourwins_active_games = game;
+        reply(getTextBot(), user, "NF_4WINS_REQUESTED", opp_user->nick);
+        reply(getTextBot(), opp_user, "NF_4WINS_REQUEST", user->nick);
+    }
+}
diff --git a/src/modules/NeonFun.mod/game_4wins.c b/src/modules/NeonFun.mod/game_4wins.c
new file mode 100644 (file)
index 0000000..88503a1
--- /dev/null
@@ -0,0 +1,212 @@
+/* game_4wins.c - NeonServ v5.4
+ * Copyright (C) 2011-2012  Philipp Kreil (pk910)
+ * 
+ * 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 <http://www.gnu.org/licenses/>. 
+ */
+#include "../module.h"
+#include "game_4wins.h"
+#include "bot_NeonFun.h"
+#include "../../IRCParser.h"
+#include "../../bots.h"
+#include "../../UserNode.h"
+#include "../../ChanUser.h"
+#include "../../tools.h"
+#include "../botid.h"
+
+struct fourwins_game *fourwins_active_games = NULL;
+
+int fourwins_next_free_y(struct fourwins_game *game, int x) {
+    int y;
+    for(y = 0; y < FOURWINS_MATRIX_HEIGHT; y++) {
+        if(!game->matrix[x][y].field)
+            return y;
+    }
+    return -1;
+}
+
+int fourwins_check_win(struct fourwins_game *game, int x, int y) {
+    int field = game->matrix[x][y].field;
+    if(!field) return 0;
+    //horizontal
+    {
+        int fc = 0;
+        int i;
+        for(i = x; i < FOURWINS_MATRIX_WIDTH; i++) {
+            if(game->matrix[i][y].field == field)
+                fc++;
+            else
+                break;
+        }
+        for(i = x-1; i >= 0; i--) {
+            if(game->matrix[i][y].field == field)
+                fc++;
+            else
+                break;
+        }
+        if(fc >= 4) return 1;
+    }
+    //senkrecht
+    if(y >= 3) {
+        int fc = 0;
+        int i;
+        for(i = y; i >= 0; i--) {
+            if(game->matrix[i][y].field == field)
+                fc++;
+            else
+                break;
+        }
+        if(fc >= 4) return 1;
+    }
+    //diagonal 1
+    {
+        int fc = 0;
+        int ix, iy;
+        for(ix = x, iy = y; ix < FOURWINS_MATRIX_WIDTH && iy < FOURWINS_MATRIX_HEIGHT; ix++, iy++) {
+            if(game->matrix[ix][iy].field == field)
+                fc++;
+            else
+                break;
+        }
+        for(ix = x, iy = y; ix >= 0 && iy >= 0; ix--, iy--) {
+            if(game->matrix[ix][iy].field == field)
+                fc++;
+            else
+                break;
+        }
+        if(fc >= 4) return 1;
+    }
+    //diagonal 2
+    {
+        int fc = 0;
+        int ix, iy;
+        for(ix = x, iy = y; ix < FOURWINS_MATRIX_WIDTH && iy >= 0; ix++, iy--) {
+            if(game->matrix[ix][iy].field == field)
+                fc++;
+            else
+                break;
+        }
+        for(ix = x, iy = y; ix >= 0 && iy < FOURWINS_MATRIX_HEIGHT; ix--, iy++) {
+            if(game->matrix[ix][iy].field == field)
+                fc++;
+            else
+                break;
+        }
+        if(fc >= 4) return 1;
+    }
+    return 0;
+}
+
+void fourwins_show_matrix(struct fourwins_game *game) {
+    int x,y;
+    char lineBuf[MAXLEN];
+    int linePos = 0;
+    for(x = 0; x < FOURWINS_MATRIX_WIDTH; x++) {
+        linePos += sprintf(lineBuf+linePos, (x ? "| %d " : " %d "), x+1);
+    }
+    fourwins_reply(game, lineBuf);
+    for(y = FOURWINS_MATRIX_HEIGHT-1; y >= 0; y--) {
+        linePos = 0;
+        for(x = 0; x < FOURWINS_MATRIX_WIDTH; x++) {
+            char *field = " ";
+            if(game->matrix[x][y].field == 1)
+                field = "\0034o\003";
+            if(game->matrix[x][y].field == 2)
+                field = "\00312o\003";
+            linePos += sprintf(lineBuf+linePos, (x ? " (%s)" : "(%s)"), field);
+        }
+        fourwins_reply(game, lineBuf);
+    }
+}
+
+TIMEQ_CALLBACK(fourwins_timeout) {
+    struct fourwins_game *game = data;
+    game->timer = NULL;
+    fourwins_reply(game, "NF_4WINS_TIMEOUT");
+    fourwins_free_game(game);
+}
+
+void fourwins_free_game(struct fourwins_game *game) {
+    struct fourwins_guest *guest, *next_guest;
+    for(guest = game->guests; guest; guest = next_guest) {
+        next_guest = guest->next;
+        free(guest);
+    }
+    struct fourwins_game *cgame, *prev = NULL;
+    for(cgame = fourwins_active_games; cgame; cgame = cgame->next) {
+        if(cgame == game) {
+            if(prev)
+                prev->next = game->next;
+            else
+                fourwins_active_games->next = game->next;
+        } else
+            prev = cgame;
+    }
+    free(game);
+}
+
+void fourwins_event_part(struct ChanUser *chanuser) {
+    struct fourwins_game *game;
+    for(game = fourwins_active_games; game; game = game->next) {
+        if(game->player[0] == chanuser || game->player[1] == chanuser) {
+            fourwins_reply(game, "NF_4WINS_GAME_CLOSED");
+            fourwins_free_game(game);
+            return;
+        }
+        struct fourwins_guest *guest, *prev_guest = NULL;
+        for(guest = game->guests; guest; guest = guest->next) {
+            if(guest->chanuser == chanuser) {
+                if(prev_guest)
+                    prev_guest->next = guest->next;
+                else
+                    game->guests = guest->next;
+                free(guest);
+                break;
+            } else
+                prev_guest = guest;
+        }
+    }
+}
+
+void fourwins_event_quit(struct UserNode *user) {
+    struct fourwins_game *game;
+    for(game = fourwins_active_games; game; game = game->next) {
+        if(game->player[0]->user == user || game->player[1]->user == user) {
+            fourwins_reply(game, "NF_4WINS_GAME_CLOSED");
+            fourwins_free_game(game);
+            return;
+        }
+        struct fourwins_guest *guest, *prev_guest = NULL;
+        for(guest = game->guests; guest; guest = guest->next) {
+            if(guest->chanuser->user == user) {
+                if(prev_guest)
+                    prev_guest->next = guest->next;
+                else
+                    game->guests = guest->next;
+                free(guest);
+                break;
+            } else
+                prev_guest = guest;
+        }
+    }
+}
+
+void fourwins_event_freechan(struct ChanNode *chan) {
+    struct fourwins_game *game;
+    for(game = fourwins_active_games; game; game = game->next) {
+        if(game->player[0]->chan == chan) {
+            fourwins_free_game(game);
+            return;
+        }
+    }
+}
diff --git a/src/modules/NeonFun.mod/game_4wins.h b/src/modules/NeonFun.mod/game_4wins.h
new file mode 100644 (file)
index 0000000..7e404b6
--- /dev/null
@@ -0,0 +1,63 @@
+/* game_4wins.h - NeonServ v5.4
+ * Copyright (C) 2011-2012  Philipp Kreil (pk910)
+ * 
+ * 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 <http://www.gnu.org/licenses/>. 
+ */
+#ifndef _game_4wins_h
+#define _game_4wins_h
+#include "../../timeq.h"
+
+#define FOURWINS_STATE_WAITING 1
+#define FOURWINS_STATE_RUNNING 2
+
+#define FOURWINS_MATRIX_WIDTH 7
+#define FOURWINS_MATRIX_HEIGHT 6
+
+#define FOURWINS_MAX_STONES (FOURWINS_MATRIX_WIDTH * FOURWINS_MATRIX_HEIGHT)
+
+struct UserNode;
+struct ChanNode;
+struct ChanUser;
+struct ClientSocket;
+extern struct fourwins_game *fourwins_active_games;
+
+struct fourwins_guest {
+    struct ChanUser *chanuser;
+    struct fourwins_guest *next;
+};
+
+struct fourwins_game {
+    struct ChanUser *player[2];
+    int active_player;
+    struct fourwins_guest *guests;
+    struct ClientSocket *textbot;
+    int state : 3;
+    struct {
+        unsigned int field:2; /* 0,1,2 */
+    } matrix[FOURWINS_MATRIX_WIDTH][FOURWINS_MATRIX_HEIGHT];
+    int total_stones;
+    struct timeq_entry *timer;
+    struct fourwins_game *next;
+};
+
+int fourwins_next_free_y(struct fourwins_game *game, int x);
+int fourwins_check_win(struct fourwins_game *game, int x, int y);
+void fourwins_show_matrix(struct fourwins_game *game);
+TIMEQ_CALLBACK(fourwins_timeout);
+void fourwins_free_game(struct fourwins_game *game);
+void fourwins_event_part(struct ChanUser *chanuser);
+void fourwins_event_quit(struct UserNode *user);
+void fourwins_event_freechan(struct ChanNode *chan);
+
+#endif
index 8ddd9c9d089b1097f1edc4af42055de249af2939..4f17aebe40ac4188844bab73883f51ce72d8f13d 100644 (file)
@@ -652,6 +652,7 @@ void uno_event_freechan(struct ChanNode *chan) {
     for(game = uno_active_games; game; game = game->next) {
         if(game->channel == chan) {
             uno_free_game(game);
+            return;
         }
     }
 }