1 (edited by scosu 2008-06-22 15:56:09)

Topic: [MOD] for vanilla servers with spamprotection and kickvotes

This mod gives normal servers some improvements against spammer. It combines a slightly different version from Rajh's voting and ban commands with my spamprotection. Also it provides reserved slots, joining messages and end of round messages.

Commands
sv_startmessage     (message that appears at the beginning of a round, normal there is no message)
sv_endroundmessage     (message that appears at the end of a round, normal there is no message)

sv_teamchanges 0    (allowed teamchanges in 30 seconds, '0' = disabled)
sv_teamchangeskick 0    (allowed teamchanges, after the user tried to change team more often, before the player will be kicked, '0' = disabled)
sv_time_blocked 180    (how much seconds the player can't change team)

sv_messagesnum 0    (allowed messages in 30 seconds, '0' = disabled)
sv_messageskick 0    (allowed messages, after the user tried to send messages more often, before the player will be kicked, '0' = disabled)
sv_time_muted 180    (how much seconds the player is muted)

sv_handle_mapvotes 0    (should '/++' and '/--' doesn't appear in global chat. then a confirmation is sent to the player. this option does not activate any displaying of voting results. it's only to let the player know that they voted successfully. the votes will be used by the statistics program i am working on)


Commands included from Race MOD

sv_reserved_slots (0<x<12) => number of reserved slots
sv_reserved_slots_pass     =>Pass to connect a reserved slot

sv_allow_votes (0|1]       =>Allow vote thing "/kick name"
sv_all_vote (0|1)          =>if enable the vote is YES only if "vote for yes > total of the player in the server /2"

ban id time               
banlist
unban id

vote time question         =>Start a custom vote

.info                      =>gives the player information about all commands


Download
Linux x86 binary
Linux x86_64 binary
Patch

Thanks to
Rajh for his Racemod

Please post feedback, bugs and everything else smile

2

Re: [MOD] for vanilla servers with spamprotection and kickvotes

nice smile But wtf means /++ and /--? i don't get it

Antoine de Saint Exupéry: It seems that perfection is reached not when there is nothing left to add, but when there is nothing left to take away.
Besides -  I am the gfx guy!

3 (edited by scosu 2008-06-22 15:59:04)

Re: [MOD] for vanilla servers with spamprotection and kickvotes

you can vote for maps with these two expressions. '/++' is a positive voting for the current map and '/--' a negative one. Like the track-votings you can do with aseco in trackmanianations.
At the moment this mod gives the player only the feeling that the vote was successfull. when the next version of my statistics is ready, these votings will appear on the site with all statistics, so server-admins can decide what map they wnat to replace.

EDIT:
it produces a debug-message:

[483f4002][game]: map-voting /++

4

Re: [MOD] for vanilla servers with spamprotection and kickvotes

Thanks scosu. I hope EVERY server hoster will upgrade to this..

There are so many without spam/crash protection sad

*** JUSTICE ALWAYS WINS ***

5

Re: [MOD] for vanilla servers with spamprotection and kickvotes

Nice, was about time someone added this to the vanilla server, not to the homing mod or something else. ^^

bam: WARNING:'src/game/server/gamemodes/mod.cpp' comes from the future

6

Re: [MOD] for vanilla servers with spamprotection and kickvotes

I improved this mod. Now you can let spammer kick and ban.
Also you can specify how many exactly same messages a player can write.
more info about all options: http://scosu.de/index.php?site=15&language=en

7

Re: [MOD] for vanilla servers with spamprotection and kickvotes

hi,

i have a request. last time i played on my server a player named "lol" joined the game and changed his nick to "adolf hitler". i banned him because i don't want such players on my server. he reconnected with a new ip and his first nick "lol". then i left the server and watched in the server browser until he changed his nick back to "adolf hitler". i reconnected also to my server to ban him again but he left the server...

so my request is something like a configurable blacklist for nicks or better for part of nicks. for instances "hitler" will match the nick "adolf hitler". i know player could use combinations like "h1tler" or "h1tl3r" but it is better than nothing and with enough blacklisted nicks people will maybe stop using such nicks. players whose nicks match the blacklist should be not allowed to connect to the server and on a nick change to a blacklisted nick the player should be kicked instantly.

regards

8

Re: [MOD] for vanilla servers with spamprotection and kickvotes

yes, made that. You have to create a file 'name_blacklist' in the teeworlds directory with at least one name in it. No new line at the end of the file. in the config you have to insert sv_name_blacklist 1.

if there is someone on the server with a name you doesn't want, you can use the admin command add_blacklist <id>. the id is the players id. you can find it with 'status'. Then kick the player and he can't join again.

Everyone who tries to join or rename to a name on the blacklist, will be banned for 30 minutes (i don't think anyone want those people on the server)

you can download it at the link i posted.

9 (edited by Roanoke 2008-07-04 03:23:44)

Re: [MOD] for vanilla servers with spamprotection and kickvotes

Really nice job with all this. It would be really interesting to see your map statistics program, but this stuff alone is a nice improvement, and a nice way for me to see how some advanced modding is done big_smile

if($poster["intelligence"] == $intelligence["idiot"])
        deny_post($poster);

10

Re: [MOD] for vanilla servers with spamprotection and kickvotes

awesome!
thank you very much scosu. i will try it tomorrow

11

Re: [MOD] for vanilla servers with spamprotection and kickvotes

thanks smile

nope statistics need some more time wink

another small change, because i didn't read your post carefully wink 'blacklist for nicks or better for part of nicks'.
so now it searches case-insensitive for a contained string from name_blacklist in the players_name. so be careful with the names you add.
the command changed to add_blacklist <name>. so you can add ingame parts of names.

12

Re: [MOD] for vanilla servers with spamprotection and kickvotes

hi,

i want to run your patch together with the ctfbroad patch [1] and the killingspree instagib spawnprotect patch [2] but the patchfiles are overlapping each other. maybe you could create a patchfile in which all three patches are already integrated? i could do it on my own but i think you will be faster than me smile

thx

[1] thread: http://www.teeworlds.com/forum/viewtopic.php?id=1467
[1] dl: http://seezat.com/ctfbroad.patch
[2] thread: http://www.teeworlds.com/forum/viewtopic.php?id=1210
[2] dl: http://spl0k.unreal-design.com/teeworld … .4.2.patch

13

Re: [MOD] for vanilla servers with spamprotection and kickvotes

Hey, about the name blacklist, is it possible to use this with regexp? If not, is it possible to implement regexp? Most people have no clue what that is, but for the power users it might be nice. wink

if($poster["intelligence"] == $intelligence["idiot"])
        deny_post($poster);

14 (edited by lol 2008-07-05 09:53:02)

Re: [MOD] for vanilla servers with spamprotection and kickvotes

martin.9 wrote:

hi,

i have a request. last time i played on my server a player named "lol" joined the game and changed his nick to "adolf hitler". i banned him because i don't want such players on my server. he reconnected with a new ip and his first nick "lol". then i left the server and watched in the server browser until he changed his nick back to "adolf hitler". i reconnected also to my server to ban him again but he left the server...

so my request is something like a configurable blacklist for nicks or better for part of nicks. for instances "hitler" will match the nick "adolf hitler". i know player could use combinations like "h1tler" or "h1tl3r" but it is better than nothing and with enough blacklisted nicks people will maybe stop using such nicks. players whose nicks match the blacklist should be not allowed to connect to the server and on a nick change to a blacklisted nick the player should be kicked instantly.

regards

... I don't use "lol" on teeworlds. And I don't use "Adolf Hitler" either. It must have been someone else.'

EDIT: Why would anyone use adolf hitler as their username?

Hiding in the Alps.

15

Re: [MOD] for vanilla servers with spamprotection and kickvotes

lol wrote:

EDIT: Why would anyone use adolf hitler as their username?

Script-kiddies, wannabes, noobs and spammers. smile

Official Teeworlds map developer and community moderator
Administrator for the Teeworlds community Teesites

16 (edited by FireArrow 2008-07-05 15:27:50)

Re: [MOD] for vanilla servers with spamprotection and kickvotes

Chi11y wrote:
lol wrote:

EDIT: Why would anyone use adolf hitler as their username?

Script-kiddies, wannabes, noobs and spammers. smile

and spamming n00b wannabe script-kiddies!

Edit: +1 for regexp

Used to be very active waay back

17

Re: [MOD] for vanilla servers with spamprotection and kickvotes

Tell me one reason why u really NEED the regexp. I dont wanna say its not useful, its fucking practical etc etc, but it might be an overkill if all u wanna do is filter some bad names. Bigger name-list vs. Bigger code + more libs + more pain. Also the whole name-filtering is a bad idea imho. Being able to vote to kick someone is more than enough.

We will meet again when the flowers spread their glorious scent of victory and the birds sing us the melody of justice...

18

Re: [MOD] for vanilla servers with spamprotection and kickvotes

You don't need to load more libraries than are already loaded. You can already use regexp functions in the source. The amount of code added should not top 100 lines. Why would this lead to more pain?

if($poster["intelligence"] == $intelligence["idiot"])
        deny_post($poster);

19

Re: [MOD] for vanilla servers with spamprotection and kickvotes

Ok, then do it. No I mean really. You always know the answer to everything... ( still awaiting the reason tho )

We will meet again when the flowers spread their glorious scent of victory and the birds sing us the melody of justice...

20

Re: [MOD] for vanilla servers with spamprotection and kickvotes

@martin.9
no sorry, try it yourself, its not too difficult. and if you have trouble with something you can ask.


@roanoke
what function you can use for regex?
i don't think a regex engine could be done with about 100 lines. and its much pane because it is much more comparing strings. sure it's not in the class of np-problems, but i don't think you need reg-exp and i won't program it, make it yourself if you want it.

21

Re: [MOD] for vanilla servers with spamprotection and kickvotes

Hm, I guess I just assumed they were there. Well, you guys are right, you'd need a separate library. I got used to them being there in php.

if($poster["intelligence"] == $intelligence["idiot"])
        deny_post($poster);

22

Re: [MOD] for vanilla servers with spamprotection and kickvotes

ok i merged the patches and here it is

- spamvote patch
- ctfbroad patch
- killingspree instagib spawnprotect patch

diff -Naur teeworlds-0.4.2-src/src/engine/e_if_server.h patched/src/engine/e_if_server.h
--- teeworlds-0.4.2-src/src/engine/e_if_server.h    2008-04-05 15:13:02.000000000 +0200
+++ patched/src/engine/e_if_server.h    2008-07-06 12:40:02.000000000 +0200
@@ -106,7 +106,7 @@
         <other_func>
 */
 void server_kick(int client_id, const char *reason);
-
+void server_ban(int client_id, int time, char *ban_message);
 /*
     Function: server_tick
         TODO
diff -Naur teeworlds-0.4.2-src/src/engine/server/es_server.c patched/src/engine/server/es_server.c
--- teeworlds-0.4.2-src/src/engine/server/es_server.c    2008-04-05 15:13:02.000000000 +0200
+++ patched/src/engine/server/es_server.c    2008-07-06 12:40:02.000000000 +0200
@@ -2,6 +2,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
+#include <ctype.h>
 
 #include <engine/e_system.h>
 #include <engine/e_config.h>
@@ -38,6 +39,9 @@
 static int current_map_crc;
 static unsigned char *current_map_data = 0;
 static int current_map_size = 0;
+int *banlist;
+int *bantime;
+int bans=0;
 
 void *snap_new_item(int type, int id, int size)
 {
@@ -107,6 +111,22 @@
 static CLIENT clients[MAX_CLIENTS];
 NETSERVER *net;
 
+struct blacklist
+{
+    char *name;
+    struct blacklist *next;
+};
+static struct blacklist *start, *end;
+
+static void str_lower(char *str)
+{
+    int i = 0;
+    for(;str[i];i++)
+    {
+        str[i] = tolower(str[i]);
+    }
+}
+
 static void snap_init_id()
 {
     int i;
@@ -222,10 +242,30 @@
 void server_setclientname(int client_id, const char *name)
 {
     char nametry[MAX_NAME_LENGTH];
+    char name_lower[MAX_NAME_LENGTH];
     int i;
+    struct blacklist *act;
+    act = start;
     if(client_id < 0 || client_id > MAX_CLIENTS || clients[client_id].state < SRVCLIENT_STATE_READY)
         return;
-        
+    if(config.sv_name_blacklist)
+    {
+        strcpy(name_lower, name);
+        str_lower(name_lower);
+        dbg_msg("blacklist", "name:%s", name_lower);
+        while(1)
+        {
+            dbg_msg("blacklist", "diff:%s", (*act).name);
+            if(strstr(name_lower, (*act).name) != NULL)
+            {
+                server_ban(client_id, 30, "Forbidden name");
+                return;
+            }
+            if(act == end)
+                break;
+            act = (*act).next;
+        }
+    }
     str_copy(nametry, name, MAX_NAME_LENGTH);
     if(server_try_setclientname(client_id, nametry))
     {
@@ -265,6 +305,33 @@
         netserver_drop(net, client_id, reason);
 }
 
+void server_ban(int client_id, int time, char *ban_message) {
+        NETADDR4 addr;
+        int clientip;
+    char reason[256];
+    if (clients[client_id].authed != 1)
+    {        
+        netserver_client_addr(net, client_id, &addr);
+
+        clientip=(addr.ip[0]<<24)+(addr.ip[1]<<16)+(addr.ip[2]<<8)+addr.ip[3];
+        dbg_msg("server", "the ip %d.%d.%d.%d is now banned",addr.ip[0],addr.ip[1],addr.ip[2],addr.ip[3]);
+
+        bans++;
+        if (bans==1) {banlist=malloc(sizeof(long));bantime=malloc(sizeof(long));}
+        else {banlist=realloc(banlist,sizeof(long)*bans);bantime=realloc(bantime,sizeof(long)*bans);}
+        banlist[bans-1]=clientip;
+        if(time > 0)bantime[bans-1]=server_tick()+server_tickspeed()*time *60;
+        else bantime[bans-1]=0;
+        
+        if(time > 0)str_format(reason, sizeof(reason), "Banned by console for %d minutes",time);
+        else str_format(reason, sizeof(reason), "Banned by console permanently.");
+        if(strlen(ban_message) > 0)
+            server_kick(client_id, ban_message);
+        else
+            server_kick(client_id, reason);
+    }
+}
+
 int server_tick()
 {
     return current_tick;
@@ -602,6 +669,9 @@
     int cid = packet->client_id;
     int sys;
     int msg = msg_unpack_start(packet->data, packet->data_size, &sys);
+    int i;
+    int clientip;
+    NETADDR4 addr;
     if(sys)
     {
         /* system message */
@@ -610,7 +680,7 @@
             char version[64];
             const char *password;
             str_copy(version, msg_unpack_string(), 64);
-            if(strcmp(version, mods_net_version()) != 0)
+            if(strcmp(version, "0.4 1bd7780b0f76307c") != 0)
             {
                 /* OH FUCK! wrong version, drop him */
                 char reason[256];
@@ -629,7 +699,21 @@
                 netserver_drop(net, cid, "wrong password");
                 return;
             }
-            
+            if(cid >= (config.sv_max_clients-config.sv_reserved_slots) && config.sv_reserved_slots_pass[0] != 0 && strcmp(config.sv_reserved_slots_pass, password) != 0)
+            {
+                /* wrong password */
+                netserver_drop(net, cid, "Dropped due reserved slot");
+                return;
+            }    
+
+            netserver_client_addr(net, cid, &addr);
+            clientip=(addr.ip[0]<<24)+(addr.ip[1]<<16)+(addr.ip[2]<<8)+addr.ip[3];
+            for (i=0; i<bans; i++) {
+                if (banlist[i]==clientip) {
+                    dbg_msg("server", "a banned player (ip=%d.%d.%d.%d) is trying to enter",addr.ip[0],addr.ip[1],addr.ip[2],addr.ip[3]);
+                    netserver_drop(net, cid, "You are banned");
+                }
+            }
             server_send_map(cid);
         }
         else if(msg == NETMSG_REQUEST_MAP_DATA)
@@ -926,7 +1010,38 @@
         mem_zero(&bindaddr, sizeof(bindaddr));
         bindaddr.port = config.sv_port;
     }
-    
+    if(config.sv_name_blacklist)
+    {
+        
+        FILE *name_file = fopen("name_blacklist", "r");
+        if(name_file != NULL)
+        {
+            char tmp_names[MAX_NAME_LENGTH];
+            if(fgets(tmp_names, MAX_NAME_LENGTH, name_file) != NULL)
+            {
+                tmp_names[strlen(tmp_names)-1] = 0;
+                start = malloc(sizeof(struct blacklist));
+                end = start;
+                (*start).name = malloc(MAX_NAME_LENGTH);
+                strcpy((*start).name, tmp_names);
+                str_lower((*start).name);
+            }
+            while(fgets(tmp_names, MAX_NAME_LENGTH, name_file) != NULL)
+            {
+                tmp_names[strlen(tmp_names)-1] = 0;
+                (*end).next = malloc(sizeof(struct blacklist));
+                end = (*end).next;
+                (*end).name = malloc(MAX_NAME_LENGTH);
+                strcpy((*end).name, tmp_names);
+                str_lower((*end).name);
+            }
+            fclose(name_file);
+        }
+        else
+        {
+            config.sv_name_blacklist = 0;
+        }
+    }
     net = netserver_open(bindaddr, config.sv_max_clients, 0);
     if(!net)
     {
@@ -1044,6 +1159,22 @@
                     server_do_snap();
                     perf_end();
                 }
+                if (bans>0) {
+                    int i=0,j=0;
+                    for (i=0; i<bans; i++) {
+                        if(bantime[i] != 0 && server_tick()-bantime[i] > server_tickspeed())
+                        {
+                            dbg_msg("server","the IP=%d:%d:%d:%d is no longer banned",i,((banlist[i]>>24)&0xFF),((banlist[i]>>16)&0xFF),((banlist[i]>>8)&0xFF),(banlist[i]&0xFF));
+                            for (j=i; j<bans; j++) {
+                                banlist[j]=banlist[j+1];
+                                bantime[j]=bantime[j+1];
+                            }
+                            bans--;
+                            realloc(banlist,sizeof(long)*bans);
+                            realloc(bantime,sizeof(long)*bans);
+                        }
+                    }
+                }
             }
             
             /* master server stuff */
@@ -1100,6 +1231,56 @@
     server_kick(console_arg_int(result, 0), "kicked by console");
 }
 
+static void con_ban(void *result, void *user_data) {
+        NETADDR4 addr;
+        int clientip;
+    char reason[256];
+        netserver_client_addr(net, console_arg_int(result, 0), &addr);
+
+        clientip=(addr.ip[0]<<24)+(addr.ip[1]<<16)+(addr.ip[2]<<8)+addr.ip[3];
+        dbg_msg("server", "the ip %d.%d.%d.%d is now banned",addr.ip[0],addr.ip[1],addr.ip[2],addr.ip[3]);
+
+        bans++;
+        if (bans==1) {banlist=malloc(sizeof(long));bantime=malloc(sizeof(long));}
+        else {banlist=realloc(banlist,sizeof(long)*bans);bantime=realloc(bantime,sizeof(long)*bans);}
+        banlist[bans-1]=clientip;
+    if(console_arg_int(result, 1) > 0)bantime[bans-1]=server_tick()+server_tickspeed()*console_arg_int(result, 1)*60;
+    else bantime[bans-1]=0;
+
+    if(console_arg_int(result, 1) > 0)str_format(reason, sizeof(reason), "Banned by console for %d minutes",console_arg_int(result, 1));
+    else str_format(reason, sizeof(reason), "Banned by console permanently.");
+    server_kick(console_arg_int(result, 0), reason);
+}
+
+static void con_banlist(void *result, void *user_data) {
+        int i;
+        if (bans>0) {
+                for (i=0; i<bans; i++) {
+                        dbg_msg("server","banid=%d, IP=%d:%d:%d:%d, time:%d min",i,((banlist[i]>>24)&0xFF),((banlist[i]>>16)&0xFF),((banlist[i]>>8)&0xFF),(banlist[i]&0xFF),(bantime[i]-server_tick())/(server_tickspeed()*60));
+                }
+        } else {
+                dbg_msg("server","there is no ban");
+        }
+}
+
+static void con_unban(void *result, void *user_data) {
+        int i=0;
+        int d=console_arg_int(result, 0);
+
+        if (d<0 || d>=bans) dbg_msg("server","no such banid: %d, type banlist to see banids",d);
+        else 
+    {
+        dbg_msg("server","the IP=%d:%d:%d:%d is no longer banned",d,((banlist[d]>>24)&0xFF),((banlist[d]>>16)&0xFF),((banlist[d]>>8)&0xFF),(banlist[d]&0xFF));
+                for (i=d; i<bans; i++) {
+                        banlist[i]=banlist[i+1];
+            bantime[i]=bantime[i+1];
+                }
+                bans--;
+                realloc(banlist,sizeof(long)*bans);
+        realloc(bantime,sizeof(long)*bans);
+    }
+}
+
 static void con_status(void *result, void *user_data)
 {
     int i;
@@ -1122,11 +1303,33 @@
     /*server_kick(console_arg_int(result, 0), "kicked by console");*/
 }
 
+static void con_add_name_blacklist(void *result, void *user_data)
+{
+    FILE *names_blacklist = fopen("name_blacklist", "a");
+    (*end).next = malloc(sizeof(struct blacklist));
+    end = (*end).next;
+    (*end).name = malloc(MAX_NAME_LENGTH);
+    
+    strcpy((*end).name, console_arg_string(result, 0));
+    str_lower((*end).name);
+    if(names_blacklist != NULL)
+    {
+        
+        fputs((*end).name, names_blacklist);
+        fputs("\n", names_blacklist);
+        fclose(names_blacklist);
+    }
+}
+
 static void server_register_commands()
 {
     MACRO_REGISTER_COMMAND("kick", "i", con_kick, 0);
     MACRO_REGISTER_COMMAND("status", "", con_status, 0);
     MACRO_REGISTER_COMMAND("shutdown", "", con_shutdown, 0);
+    MACRO_REGISTER_COMMAND("ban", "ii", con_ban, 0);
+    MACRO_REGISTER_COMMAND("banlist", "", con_banlist, 0);
+    MACRO_REGISTER_COMMAND("unban", "i", con_unban, 0);
+    MACRO_REGISTER_COMMAND("add_blacklist", "s", con_add_name_blacklist, 0);
 }
 
 int main(int argc, char **argv)
diff -Naur teeworlds-0.4.2-src/src/game/g_variables.h patched/src/game/g_variables.h
--- teeworlds-0.4.2-src/src/game/g_variables.h    2008-04-05 15:13:02.000000000 +0200
+++ patched/src/game/g_variables.h    2008-07-06 13:15:23.000000000 +0200
@@ -57,3 +57,28 @@
 MACRO_CONFIG_INT(sv_spamprotection, 1, 0, 1)
 
 MACRO_CONFIG_INT(sv_spectator_slots, 0, 0, 12)
+
+MACRO_CONFIG_INT(sv_ctfbroad, 1, 0, 1)
+MACRO_CONFIG_STR(sv_ctfmsg, 512, " captured the flag!")
+
+MACRO_CONFIG_INT(sv_teamchanges, 0, 0, 100)
+MACRO_CONFIG_INT(sv_time_blocked, 180, 1, 1000)
+MACRO_CONFIG_INT(sv_teamchangeskick, 0, 0, 100)
+MACRO_CONFIG_INT(sv_teamchangesban, 0, 0, 100)
+MACRO_CONFIG_INT(sv_messagesnum, 0, 0, 100)
+MACRO_CONFIG_INT(sv_same_messages, 0, 0, 100)
+MACRO_CONFIG_INT(sv_time_muted, 180, 1, 1000)
+MACRO_CONFIG_INT(sv_messageskick, 0, 0, 100)
+MACRO_CONFIG_INT(sv_messagesban, 0, 0, 100)
+MACRO_CONFIG_STR(sv_startmessage, 1000, "")
+MACRO_CONFIG_STR(sv_endroundmessage, 1000, "")
+MACRO_CONFIG_INT(sv_handle_mapvotes, 0, 0, 1)
+MACRO_CONFIG_INT(sv_kick_teamkiller, 0, 0, 100)
+MACRO_CONFIG_INT(sv_name_blacklist, 0, 0, 1)
+MACRO_CONFIG_INT(sv_reserved_slots, 0, 0, 12)
+MACRO_CONFIG_STR(sv_reserved_slots_pass, 32, "")
+MACRO_CONFIG_INT(sv_allow_votes, 1, 0, 1)
+MACRO_CONFIG_INT(sv_all_vote, 0, 0, 1)
+MACRO_CONFIG_INT(sv_votetime, 60, 0, 500)
+MACRO_CONFIG_INT(sv_ban_time, 10, 0, 1000)
+
diff -Naur teeworlds-0.4.2-src/src/game/server/gs_common.h patched/src/game/server/gs_common.h
--- teeworlds-0.4.2-src/src/game/server/gs_common.h    2008-04-05 15:13:02.000000000 +0200
+++ patched/src/game/server/gs_common.h    2008-07-06 13:00:32.000000000 +0200
@@ -131,8 +131,10 @@
     int round_count;
     
     bool is_teamplay;
-    
+
 public:
+    char spree_msg[128];
+    
     int gametype;
     gameobject();
 
@@ -238,6 +240,9 @@
 // player entity
 class player : public entity
 {
+private:
+    int spawn_tick;
+
 public:
     static const int phys_size = 28;
 
@@ -299,8 +304,12 @@
 
     //
     int score;
+    int lastplayer;
+    int lastplayertime;
+    int votedfor;
     int team;
     int player_state; // if the client is chatting, accessing a menu or so
+    unsigned int spree;
     
     bool spawning;
     bool dead;
@@ -352,6 +361,10 @@
     
     virtual bool take_damage(vec2 force, int dmg, int from, int weapon);
     virtual void snap(int snaping_client);
+    
+    int last_message_tick; unsigned char message_num; bool muted;
+    bool teamchanging; unsigned char team_changes; int last_team_set;
+    bool voted;
 };
 
 extern player *players;
diff -Naur teeworlds-0.4.2-src/src/game/server/gs_game.cpp patched/src/game/server/gs_game.cpp
--- teeworlds-0.4.2-src/src/game/server/gs_game.cpp    2008-04-05 15:13:02.000000000 +0200
+++ patched/src/game/server/gs_game.cpp    2008-07-06 13:05:40.000000000 +0200
@@ -90,7 +90,15 @@
 {
     if(warmup) // game can't end when we are running warmup
         return;
-        
+    if(strlen(config.sv_endroundmessage) > 0)
+    {
+        NETMSG_SV_CHAT msg;
+        msg.team = 0;
+        msg.cid = -1;
+        msg.message = config.sv_endroundmessage;
+        msg.pack(MSGFLAG_VITAL);
+        server_send_msg(-1);
+    }
     world->paused = true;
     game_over_tick = server_tick();
     sudden_death = 0;
@@ -197,20 +205,58 @@
     }
 }
 
+char spree_note[6][64] = { "is on a killing spree!", "is on a rampage!", "is dominating", "is unstoppable!", "is Godlike!", "is Wicked SICK!!" };
+
+void broadcast_spree(class player *p1, class player *p2)
+{
+    NETMSG_SV_BROADCAST msg;
+
+    if(!p2)
+        str_format(gameobj->spree_msg, sizeof(gameobj->spree_msg), "%s %s", server_clientname(p1->client_id), spree_note[(p1->spree/5)-1]);
+    else
+        str_format(gameobj->spree_msg, sizeof(gameobj->spree_msg), "%s's killing spree ended by %s", server_clientname(p1->client_id), server_clientname(p2->client_id));
+
+    msg.message = gameobj->spree_msg;
+    msg.pack(MSGFLAG_VITAL);
+    server_send_msg(-1);
+}
+
+void increment_spree(class player *p)
+{
+    if(++(p->spree) < 31 && (p->spree)%5 == 0)
+        broadcast_spree(p, NULL);
+}
+
+void end_spree(class player *victim, class player *killer)
+{
+    if(victim->spree > 4)
+        broadcast_spree(victim, killer);
+    victim->spree = 0;
+}
 
 int gameobject::on_player_death(class player *victim, class player *killer, int weapon)
 {
     // do scoreing
-    if(!killer)
-        return 0;
-    if(killer == victim)
-        victim->score--; // suicide
-    else
+    if(weapon != -1)
     {
-        if(is_teamplay && victim->team == killer->team)
-            killer->score--; // teamkill
+        if(!killer)
+            return 0;
+        end_spree(victim, killer);
+        if(killer == victim)
+            victim->score--; // suicide
         else
-            killer->score++; // normal kill
+        {
+            if(is_teamplay && victim->team == killer->team)
+                killer->score--; // teamkill
+            else
+                killer->score++; // normal kill
+            increment_spree(killer);
+        }
+        if(config.sv_kick_teamkiller != 0 && killer->score <= -config.sv_kick_teamkiller && gametype == GAMETYPE_TDM)
+        {
+            if(killer->team != -1)
+                teamscore[killer->team] -= killer->score;
+        }
     }
     return 0;
 }
diff -Naur teeworlds-0.4.2-src/src/game/server/gs_game_ctf.cpp patched/src/game/server/gs_game_ctf.cpp
--- teeworlds-0.4.2-src/src/game/server/gs_game_ctf.cpp    2008-04-05 15:13:02.000000000 +0200
+++ patched/src/game/server/gs_game_ctf.cpp    2008-07-06 13:08:35.000000000 +0200
@@ -1,6 +1,9 @@
 /* copyright (c) 2007 magnus auvinen, see licence.txt for more info */
 #include <engine/e_server_interface.h>
 #include <game/g_mapitems.h>
+#include <engine/e_config.h>
+#include <stdio.h>
+#include <stdlib.h>
 #include "gs_common.h"
 #include "gs_game_ctf.h"
 
@@ -90,6 +93,16 @@
 
                     dbg_msg("game", "flag_capture player='%d:%s'", f->carrying_player->client_id, server_clientname(f->carrying_player->client_id));
 
+                                        //Captured the flag patch
+                    if (config.sv_ctfbroad) {
+                                            char bravo[256];
+                                            sprintf(bravo,"%s %s",server_clientname(f->carrying_player->client_id),config.sv_ctfmsg);
+                                            NETMSG_SV_BROADCAST msg;
+                                            msg.message = bravo;
+                                            msg.pack(MSGFLAG_VITAL);
+                                            server_send_msg(-1);
+                    }
+
                     for(int i = 0; i < 2; i++)
                         flags[i]->reset();
                     
diff -Naur teeworlds-0.4.2-src/src/game/server/gs_server.cpp patched/src/game/server/gs_server.cpp
--- teeworlds-0.4.2-src/src/game/server/gs_server.cpp    2008-04-05 15:13:02.000000000 +0200
+++ patched/src/game/server/gs_server.cpp    2008-07-06 13:00:32.000000000 +0200
@@ -26,7 +26,7 @@
 void create_sound(vec2 pos, int sound, int mask=-1);
 class player *intersect_player(vec2 pos0, vec2 pos1, float radius, vec2 &new_pos, class entity *notthis = 0);
 class player *closest_player(vec2 pos, float radius, entity *notthis);
-
+int timer_vote=-1;bool vote_called=false;int votetime=-1;char votetype[32];int votedtokick=-1;
 game_world *world;
 
 enum
@@ -36,9 +36,119 @@
     CHAT_RED=0,
     CHAT_BLUE=1
 };
-
 static void send_chat(int cid, int team, const char *text)
 {
+    static char lastmessages[12][1000];
+    static short int same_messages[12];
+    player *tmp = get_player(cid);
+    if(config.sv_handle_mapvotes && (strcmp("/++",text) == 0 || strcmp("/--", text) == 0))
+    {
+        if(tmp->voted)
+        {
+            char voted[] = "You already voted the map, ignoring vote";
+            NETMSG_SV_CHAT msg;
+            msg.team = 0;
+            msg.cid = -1;
+            msg.message = voted;
+            msg.pack(MSGFLAG_VITAL);
+            server_send_msg(cid);
+        }
+        else
+        {
+            tmp->voted = true;
+            dbg_msg("game", "map-voting %s", text);
+            char voted[] = "You voted for the map, thank you";
+            NETMSG_SV_CHAT msg;
+            msg.team = 0;
+            msg.cid = -1;
+            msg.message = voted;
+            msg.pack(MSGFLAG_VITAL);
+            server_send_msg(cid);
+        }
+        
+        
+        return;
+    }
+    
+    if(config.sv_messagesnum && cid > -1 && cid < MAX_CLIENTS)
+    {
+        
+        
+        if(tmp->muted)
+        {
+            if(tmp->last_message_tick + config.sv_time_muted*SERVER_TICK_SPEED > server_tick())
+            {
+                tmp->message_num++;
+                if(config.sv_messageskick && tmp->message_num > config.sv_messageskick)
+                {
+                    char *kicking = (char *)malloc(sizeof(char) * 200);
+                    sprintf(kicking, "%s was kicked because of spamming.", server_clientname(cid));
+                    dbg_msg("chat", "*** %s", kicking);
+                    NETMSG_SV_CHAT msg;
+                    msg.team = 0;
+                    msg.cid = -1;
+                    msg.message = kicking;
+                    msg.pack(MSGFLAG_VITAL);
+                    server_send_msg(-1);
+                    free(kicking);
+                    if(config.sv_messagesban)
+                    {
+                        char ban_message[255];
+                        sprintf(ban_message, "You were banned for %i minutes because of spamming", config.sv_messagesban);
+                        server_ban(cid, config.sv_teamchangesban, ban_message);
+                    }
+                    else
+                        server_kick(cid,"You were kicked because of spamming");
+                }
+                return;
+            }
+            else
+            {
+                tmp->muted = false;
+                tmp->message_num = 0;
+                tmp->last_message_tick = server_tick();
+            }
+        }
+        else
+        {
+            if(tmp->last_message_tick + 30*SERVER_TICK_SPEED > server_tick())
+            {
+                tmp->message_num++;
+                if(config.sv_same_messages && strcmp(lastmessages[cid], text) == 0)
+                {
+                    dbg_msg("messsages", "same message");
+                    same_messages[cid]++;
+                }
+                else
+                {
+                    strncpy(lastmessages[cid], text, 1000);
+                    same_messages[cid] = 0;
+                }
+                if(tmp->message_num >= config.sv_messagesnum || (config.sv_same_messages && config.sv_same_messages <= same_messages[cid]))
+                {
+                    tmp->muted = true;same_messages[cid] = 0;
+                    tmp->message_num = 0;
+                    char *muting = (char *)malloc(sizeof(char) * 200);
+                    sprintf(muting, "%s was muted for %d seconds because of spamming.", server_clientname(cid), config.sv_time_muted);
+                    dbg_msg("chat", "*** %s", muting);
+                    NETMSG_SV_CHAT msg;
+                    msg.team = 0;
+                    msg.cid = -1;
+                    msg.message = muting;
+                    msg.pack(MSGFLAG_VITAL);
+                    server_send_msg(-1);
+                    free(muting);
+                    return;
+                }
+                    
+            }
+            else
+            {
+                tmp->last_message_tick = server_tick();
+                tmp->message_num = 0;
+            }
+        }
+    }
     if(cid >= 0 && cid < MAX_CLIENTS)
         dbg_msg("chat", "%d:%d:%s: %s", cid, team, server_clientname(cid), text);
     else
@@ -120,6 +230,53 @@
     server_send_msg(cid);
 }
 
+void resultvote()
+{
+    int players_serv=0,total=0,voteur=0;
+    for (int i=0; i < MAX_CLIENTS;i++)
+    {
+        if(players[i].client_id !=-1)
+        {
+            if(players[i].votedfor != -1)
+            {total+=players[i].votedfor;voteur++;}
+            players_serv++;
+        }
+    }
+    char buf[256];
+    str_format(buf, sizeof(buf), "YES: %d | NO: %d (Time remaining : %d/%d secondes)",total,voteur-total,(server_tick()-timer_vote)/(server_tickspeed()),votetime);
+    send_chat(-1,CHAT_ALL,buf);
+    if (voteur==players_serv || (server_tick()-timer_vote  > server_tickspeed()*votetime && timer_vote != -1))
+    {
+        vote_called=false;
+        int result=1;
+        char message[256];
+        if((total > voteur / 2 && !config.sv_all_vote) || (total > players_serv / 2 && config.sv_all_vote))str_format(message, sizeof(message), "Result for the vote is : YES");
+        else {str_format(message, sizeof(message), "Result for the vote is : NO");result=0;}
+        send_chat(-1,CHAT_ALL,message);
+        if(!strcmp(votetype,"kick") && votedtokick != -1)
+        {    
+            if(result)
+            {
+                char reason[256];
+                //str_format(reason, sizeof(reason), "Kicked");
+                //server_kick(votedfor,reason);
+                str_format(reason, sizeof(reason), "%s has been kicked.",server_clientname(votedtokick));
+                send_chat(-1,-1, reason);
+                server_ban(votedtokick,config.sv_ban_time, "");
+            }    
+            str_format(votetype, sizeof(votetype), "null");
+            votedtokick = -1;    
+        }
+        for (int i=0; i < MAX_CLIENTS;i++)
+        {
+            if(players[i].client_id !=-1)
+            {
+                players[i].votedfor=-1;
+            }
+        }
+    }    
+}
+
 //////////////////////////////////////////////////
 // Event handler
 //////////////////////////////////////////////////
@@ -352,7 +509,7 @@
 {
     if(reset_requested)
         reset();
-
+    if(timer_vote != -1 && server_tick()-timer_vote  > server_tickspeed()*votetime && vote_called)resultvote();
     if(!paused)
     {
         /*
@@ -659,6 +816,10 @@
 
 void player::init()
 {
+    voted = false;
+    teamchanging = false; team_changes = 0; last_team_set = server_tick();
+    last_message_tick = server_tick(); message_num = 0; muted = false;
+    
     proximity_radius = phys_size;
     client_id = -1;
     team = -1; // -1 == spectator
@@ -683,6 +844,7 @@
     
     //direction = vec2(0.0f, 1.0f);
     score = 0;
+    spree = 0;
     dead = true;
     clear_flag(entity::FLAG_PHYSICS);
     spawning = false;
@@ -700,6 +862,7 @@
 
     emote_stop = 0;
     damage_taken_tick = 0;
+    spawn_tick = 0;
     attack_tick = 0;
 
     mem_zero(&ninja, sizeof(ninja));
@@ -750,6 +913,74 @@
 
 void player::set_team(int new_team)
 {
+    if(config.sv_teamchanges)
+    {
+        if(teamchanging)
+        {
+            if(last_team_set + config.sv_time_blocked*SERVER_TICK_SPEED > server_tick())
+            {
+                team_changes++;
+                if(config.sv_teamchangeskick && team_changes > config.sv_teamchangeskick)
+                {
+                    
+                    char *kicking = (char *)malloc(sizeof(char) * 200);
+                    sprintf(kicking, "%s was kicked because of fast teamchanging.", server_clientname(client_id));
+                    dbg_msg("chat", "*** %s", kicking);
+                    NETMSG_SV_CHAT msg;
+                    msg.team = 0;
+                    msg.cid = -1;
+                    msg.message = kicking;
+                    msg.pack(MSGFLAG_VITAL);
+                    server_send_msg(-1);
+                    free(kicking);
+                    if(config.sv_teamchangesban)
+                    {
+                        char ban_message[255];
+                        sprintf(ban_message, "You were banned for %i minutes because of fast teamchanging", config.sv_teamchangesban);
+                        server_ban(client_id, config.sv_teamchangesban, ban_message);
+                    }
+                    else
+                        server_kick(client_id,"You were kicked because of fast teamchanging");
+                }
+                return;
+            }
+            else
+            {
+                teamchanging = false;
+                team_changes = 0;
+                last_team_set = server_tick();
+            }
+        }
+        else
+        {
+            if(last_team_set + 30*SERVER_TICK_SPEED > server_tick())
+            {
+                team_changes++;
+                if(config.sv_teamchanges && team_changes >= config.sv_teamchanges)
+                {
+                    teamchanging = true;
+                    team_changes = 0;
+                    char *blocking = (char *)malloc(sizeof(char) * 200);
+                    sprintf(blocking, "%s can't change team for %d seconds", server_clientname(client_id), config.sv_time_blocked);
+                    dbg_msg("chat", "*** %s", blocking);
+                    NETMSG_SV_CHAT msg;
+                    msg.team = 0;
+                    msg.cid = -1;
+                    msg.message = blocking;
+                    msg.pack(MSGFLAG_VITAL);
+                    server_send_msg(-1);
+                    free(blocking);
+                    return;
+                }
+                    
+            }
+            else
+            {
+                last_team_set = server_tick();
+                team_changes = 0;
+            }
+        }
+    }
     // clamp the team
     new_team = gameobj->clampteam(new_team);
     if(team == new_team)
@@ -914,6 +1145,7 @@
     dead = false;
     set_flag(entity::FLAG_PHYSICS);
     player_state = PLAYERSTATE_PLAYING;
+    spree = 0;
 
     core.hook_state = HOOK_IDLE;
 
@@ -921,20 +1153,23 @@
 
     // init weapons
     mem_zero(&weapons, sizeof(weapons));
-    weapons[WEAPON_HAMMER].got = true;
+    /*weapons[WEAPON_HAMMER].got = true;
     weapons[WEAPON_HAMMER].ammo = -1;
     weapons[WEAPON_GUN].got = true;
-    weapons[WEAPON_GUN].ammo = data->weapons[WEAPON_GUN].maxammo;
+    weapons[WEAPON_GUN].ammo = data->weapons[WEAPON_GUN].maxammo;*/
 
-    /*weapons[WEAPON_RIFLE].got = true;
-    weapons[WEAPON_RIFLE].ammo = -1;*/
+    weapons[WEAPON_RIFLE].got = true;
+    weapons[WEAPON_RIFLE].ammo = -1;
     
-    active_weapon = WEAPON_GUN;
-    last_weapon = WEAPON_HAMMER;
-    queued_weapon = 0;
+    active_weapon = WEAPON_RIFLE;
+    last_weapon = WEAPON_RIFLE;
+    queued_weapon = -1;
 
     reload_timer = 0;
 
+    // Spawn protection
+    spawn_tick = server_tick();
+
     // Create sound and spawn effects
     create_sound(pos, SOUND_PLAYER_SPAWN);
     create_playerspawn(pos);
@@ -1517,12 +1752,29 @@
     die_tick = server_tick();
     clear_flag(FLAG_PHYSICS);
     create_death(pos, client_id);
+    if(config.sv_kick_teamkiller != 0 && score <= -config.sv_kick_teamkiller)
+    {
+        char *kickmessage = (char*)malloc(1000);
+        sprintf(kickmessage, "%s was kicked because of teamkilling/selfkillng.", server_clientname(client_id));
+        dbg_msg("chat", "*** %s", kickmessage);
+        NETMSG_SV_CHAT msg;
+        msg.team = 0;
+        msg.cid = -1;
+        msg.message = kickmessage;
+        msg.pack(MSGFLAG_VITAL);
+        server_send_msg(-1);
+        server_kick(client_id, "You were kicked because of teamkilling/selfkilling");
+    }
 }
 
 bool player::take_damage(vec2 force, int dmg, int from, int weapon)
 {
     core.vel += force;
-    
+
+    // Spawn protection
+    if(server_tick()-spawn_tick <= server_tickspeed())
+        return false;
+
     if(gameobj->is_friendly_fire(client_id, from) && !config.sv_teamdamage)
         return false;
 
@@ -1690,10 +1942,10 @@
     subtype = _subtype;
     proximity_radius = phys_size;
 
-    reset();
+    //reset();
 
     // TODO: should this be done here?
-    world->insert_entity(this);
+    //world->insert_entity(this);
 }
 
 void powerup::reset()
@@ -2061,7 +2313,15 @@
     char buf[512];
     str_format(buf, sizeof(buf), "%s entered and joined the %s", server_clientname(client_id), get_team_name(players[client_id].team));
     send_chat(-1, CHAT_ALL, buf); 
-
+    if(strlen(config.sv_startmessage) > 0)
+    {
+        NETMSG_SV_CHAT msg;
+        msg.team = 0;
+        msg.cid = -1;
+        msg.message = config.sv_startmessage;
+        msg.pack(MSGFLAG_VITAL);
+        server_send_msg(client_id);
+    }
     dbg_msg("game", "team_join player='%d:%s' team=%d", client_id, server_clientname(client_id), players[client_id].team);
 }
 
@@ -2121,8 +2381,81 @@
         }
         else
         {
-            players[client_id].last_chat = time_get();
-            send_chat(client_id, team, msg->message);
+            if(!strcasecmp(msg->message, ".info"))
+            {
+                char buf[128];
+                str_format(buf, sizeof(buf), "Mod from Rajh and scosu. Available commands:");
+                send_chat(-1,CHAT_ALL,buf);
+                send_chat(-1, CHAT_ALL, "Positive map-voting: /++");
+                send_chat(-1, CHAT_ALL, "Negative map-voting: /--");
+                send_chat(-1, CHAT_ALL, "Kick player by name: /kick <player name>");
+                send_chat(-1, CHAT_ALL, "Current vote: /currentvote");
+                players[client_id].last_chat = time_get()+time_freq()*10;
+            }
+            else if (!strncasecmp(msg->message, "/kick",5) && !vote_called && config.sv_allow_votes)
+            {
+                int playersnumber=0;
+                int playerstokick=-1;
+                char message[256];
+                for (int i=0; i < MAX_CLIENTS;i++)
+                {
+                    if(players[i].client_id !=-1)
+                    {
+                        str_format(message, sizeof(message), "/kick ");
+                        strcat(message,server_clientname(i));
+                        if(!strncmp(msg->message, message,9))
+                        {
+                            playersnumber++;
+                            playerstokick=i;
+                        }
+                    }
+                }
+                if(playersnumber == 1 && playerstokick != -1)
+                {
+                    votetime = config.sv_votetime;
+                    str_format(votetype, sizeof(votetype), "kick");
+                    votedtokick=playerstokick;
+                    char buf[512];
+                    str_format(buf, sizeof(buf), "||| Vote for: kick %s (say \"/yes\" or \"/no\") |||(%s)", server_clientname(playerstokick),server_clientname(client_id));
+                    send_chat(-1, CHAT_ALL, buf);
+                    str_format(message, sizeof(message), "%s voted for yes",server_clientname(client_id));
+                    send_chat(-1,CHAT_ALL,message);
+                    vote_called=true;
+                    timer_vote = server_tick();
+                    players[client_id].votedfor = 1;
+                }
+                else if(playersnumber > 1)
+                {
+                    char buf[512];
+                    str_format(buf, sizeof(buf), "||| Several players possible |||(%s)", server_clientname(client_id));
+                    send_chat(-1, CHAT_ALL, buf);
+                }
+            }
+            else if (!strncasecmp(msg->message, "/yes",3) && players[client_id].votedfor == -1 && vote_called)
+            {
+                char message[256];
+                str_format(message, sizeof(message), "%s voted for yes",server_clientname(client_id));
+                send_chat(-1,CHAT_ALL,message);
+                players[client_id].votedfor = 1;
+                //resultvote();
+            }
+            else if (!strncasecmp(msg->message, "/no",2) && players[client_id].votedfor == -1 && vote_called)
+            {
+                char message[256];
+                str_format(message, sizeof(message), "%s voted for no",server_clientname(client_id));
+                send_chat(-1,CHAT_ALL,message);
+                players[client_id].votedfor = 0;
+                //resultvote();
+            }
+            else if (!strncasecmp(msg->message, "/currentvote",2) && vote_called)
+            {
+                resultvote();
+            }
+            else
+            {
+                players[client_id].last_chat = time_get();
+                send_chat(client_id, team, msg->message);
+            }
         }
     }
     else if (msgtype == NETMSGTYPE_CL_SETTEAM)
@@ -2274,12 +2607,24 @@
     players[client_id].set_team(team);
 }
 
+static void con_vote(void *result, void *user_data)
+{
+    votetime =console_arg_int(result, 0);
+    char buf[512];
+    str_format(buf, sizeof(buf), "||| Vote for: %s (say \"/yes\" or \"/no\") |||", console_arg_string(result, 1));
+    send_chat(-1, CHAT_ALL, buf);
+    vote_called=true;
+    //if (console_arg_int(result, 0) == 1)
+    timer_vote = server_tick();
+    //else world->timer_vote = -1;
+}
+
 void mods_console_init()
 {
     MACRO_REGISTER_COMMAND("tune", "si", con_tune_param, 0);
     MACRO_REGISTER_COMMAND("tune_reset", "", con_tune_reset, 0);
     MACRO_REGISTER_COMMAND("tune_dump", "", con_tune_dump, 0);
-
+    MACRO_REGISTER_COMMAND("vote", "ir", con_vote, 0);
     MACRO_REGISTER_COMMAND("restart", "?i", con_restart, 0);
     MACRO_REGISTER_COMMAND("broadcast", "r", con_broadcast, 0);
     MACRO_REGISTER_COMMAND("say", "r", con_say, 0);

23

Re: [MOD] for vanilla servers with spamprotection and kickvotes

I've a football mod server (it's the version from Rajh) how can I apply your patch (with the blacklist...) and the patch from Rajh, so that I've at least a server with handball/football mod and kick/ban/blacklist/Spam protection ?

Do I have to adjust the patch files? Or can I apply first the handball/football patch and then your patch?
Or do I have to change something in the patch files? Or do I have to apply your patch first?

24

Re: [MOD] for vanilla servers with spamprotection and kickvotes

How to join instagib to this mod?
I have problem with patching both mods to source.

25

Re: [MOD] for vanilla servers with spamprotection and kickvotes

@martin.9

thanks, but your patch doesn't work here. wanted to compile some binaries for linux so that everyone can download them.
for the first i made those few lines for instagib with my patch: http://scosu.de/index.php?site=17&language=en

football mod is ready but i have to test it first wink