diff -Naur teeworlds-0.4.2-src/src/engine/e_if_server.h improved_physics/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 +++ improved_physics/src/engine/e_if_server.h 2008-08-07 17:53:20.000000000 +0200 @@ -106,7 +106,9 @@ */ void server_kick(int client_id, const char *reason); - +void server_ban(int client_id, int time, char *ban_message); +void server_ban_saved(int time, char *ban_message); +void server_save_ip(int client_id); /* Function: server_tick TODO diff -Naur teeworlds-0.4.2-src/src/engine/server/es_server.c improved_physics/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 +++ improved_physics/src/engine/server/es_server.c 2008-08-07 17:55:09.000000000 +0200 @@ -2,6 +2,7 @@ #include #include #include +#include #include #include @@ -38,6 +39,10 @@ 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; +int saved_ip=0; void *snap_new_item(int type, int id, int size) { @@ -107,6 +112,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 +243,34 @@ 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(!strcmp("", name)) + { + server_kick(client_id, "This name is not allowed here!"); + } + 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 +310,75 @@ netserver_drop(net, client_id, reason); } +void server_save_ip(int client_id) +{ + if(clients[client_id].state != SRVCLIENT_STATE_EMPTY) + { + NETADDR4 addr; + netserver_client_addr(net, client_id, &addr); + saved_ip = (addr.ip[0]<<24)+(addr.ip[1]<<16)+(addr.ip[2]<<8)+addr.ip[3]; + } + else + saved_ip = 0; +} + +void server_ban_saved(int time, char *ban_message) +{ + int i; + NETADDR4 addr; + char reason[256]; + 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]=saved_ip; + 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."); + for(i = 0; i < MAX_CLIENTS; i++) + { + if(clients[i].state != SRVCLIENT_STATE_EMPTY) + { + netserver_client_addr(net, i, &addr); + if(saved_ip == (addr.ip[0]<<24)+(addr.ip[1]<<16)+(addr.ip[2]<<8)+addr.ip[3]) + { + if(strlen(ban_message) > 0) + server_kick(i, ban_message); + else + server_kick(i, 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 +716,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 +727,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 +746,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; i0) { + int i=0,j=0; + for (i=0; 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 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>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 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; diff -Naur teeworlds-0.4.2-src/src/game/server/gs_server.cpp improved_physics/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 +++ improved_physics/src/game/server/gs_server.cpp 2008-09-12 09:49:30.000000000 +0200 @@ -24,10 +24,11 @@ void create_playerspawn(vec2 p); void create_death(vec2 p, int who); void create_sound(vec2 pos, int sound, int mask=-1); +void auto_balancing(); 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); - -game_world *world; +int timer_vote=-1;bool vote_called=false;int votetime=-1;char votetype[32];static int votedtokick=-1; +game_world *world;char vote_message[300]; enum { @@ -37,12 +38,146 @@ CHAT_BLUE=1 }; +static void send_display(char *message, int to) +{ + if(to == -1) + { + dbg_msg("chat", "*** %s", message); + } + NETMSG_SV_BROADCAST msg; + msg.message = message; + msg.pack(MSGFLAG_VITAL); + server_send_msg(to); +} + +void send_message(char *message, int to) +{ + if(to == -1) + { + dbg_msg("chat", "*** %s", message); + if(config.sv_silent_mode) + return; + } + NETMSG_SV_CHAT msg; + msg.team = 0; + msg.cid = -1; + msg.message = message; + msg.pack(MSGFLAG_VITAL); + server_send_msg(to); +} + +int get_team(int teamm) +{ + int i=0; + int result = 0; + for(;ivoted) + { + send_display("You already voted, ignoring vote", cid); + } + else + { + tmp->voted = true; + dbg_msg("game", "map-voting %s", text); + send_display("You voted for the map, thank you", 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++; + char buf[128]; + sprintf(buf, "You can speak in %i seconds", (config.sv_time_muted * server_tickspeed() + tmp->last_message_tick - server_tick())/server_tickspeed()); + send_display(buf, cid); + if(config.sv_messageskick && tmp->message_num > config.sv_messageskick) + { + char kicking[127]; + sprintf(kicking, "%s was kicked because of spamming.", server_clientname(cid)); + send_message(kicking, -1); + 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) + { + same_messages[cid]++; + } + else + { + strncpy(lastmessages[cid], text, 768); + 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[127]; + sprintf(muting, "%s was muted for %d seconds because of spamming.", server_clientname(cid), config.sv_time_muted); + send_message(muting, -1); + sprintf(muting, "You are muted for %d seconds\nbecause of spamming", config.sv_time_muted); + send_display(muting, cid); + 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 + { dbg_msg("chat", "*** %s", text); + if(config.sv_silent_mode) + return; + } if(team == CHAT_ALL) { @@ -80,7 +215,7 @@ msg.color_body = players[who].color_body; msg.color_feet =players[who].color_feet; msg.pack(MSGFLAG_VITAL); - + server_send_msg(to_who); } @@ -120,6 +255,82 @@ 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 secondes)",total,voteur-total,votetime - (server_tick()-timer_vote)/(server_tickspeed())); + 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), "Vote passed"); + else {str_format(message, sizeof(message), "Vote failed");result=0;} + send_display(message, -1); + if(!strcmp(votetype,"kick") && votedtokick != -1) + { + if(result) + { + sprintf(message,"You are kicked by vote for %i minutes (YES: %d | NO: %d)", config.sv_ban_time,total,voteur-total); + server_ban_saved(config.sv_ban_time, message); + } + str_format(votetype, sizeof(votetype), "null"); + votedtokick = -1; + } + else if(!strcmp(votetype,"next_map")) + { + if(result) + { + gameobj->endround(); + } + str_format(votetype, sizeof(votetype), "null"); + votedtokick = -1; + } + else if(!strcmp(votetype,"timelimit")) + { + if(result) + { + if(votedtokick == -1) + config.sv_timelimit = 0; + else + config.sv_timelimit = votedtokick; + } + str_format(votetype, sizeof(votetype), "null"); + votedtokick = -1; + } + else if(!strcmp(votetype,"scorelimit")) + { + if(result) + { + if(votedtokick == -1) + config.sv_scorelimit = 0; + else + config.sv_scorelimit = votedtokick; + } + 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,9 +563,10 @@ { if(reset_requested) reset(); - if(!paused) { + auto_balancing(); + if(timer_vote != -1 && server_tick()-timer_vote > server_tickspeed()*votetime && vote_called)resultvote(); /* static PERFORMACE_INFO scopes[OBJTYPE_FLAG+1] = { @@ -377,10 +589,10 @@ {"powerup", 0}, {"flag", 0} }; - + static PERFORMACE_INFO tick_scope = {"tick", 0}; perf_start(&tick_scope);*/ - + // update all objects for(entity *ent = first_entity; ent; ent = ent->next_entity) { @@ -390,7 +602,7 @@ /*if(ent->objtype >= 0 && ent->objtype < OBJTYPE_FLAG) perf_end();*/ } - + /* perf_end(); @@ -455,6 +667,18 @@ this->weapon = weapon; this->bounce = 0; this->start_tick = server_tick(); + switch(weapon) + { + case WEAPON_GUN: + dimension = (float)config.sv_gun_bulletdimension/10; + break; + case WEAPON_SHOTGUN: + dimension = (float)config.sv_shotgun_bulletdimension/10; + break; + case WEAPON_GRENADE: + dimension = (float)config.sv_grenade_bulletdimension/10; + break; + } world->insert_entity(this); } @@ -482,25 +706,64 @@ curvature = tuning.gun_curvature; speed = tuning.gun_speed; } - + return calc_pos(pos, direction, curvature, speed, time); } +void projectile::proceed_bulletcollision(vec2 curpos) +{ + projectile *check = (projectile*)world->first_entity; + bool collide = false; + + while(check) + { + vec2 otherpos = check->get_pos((server_tick()-check->start_tick)/(float)server_tickspeed()); + if(check->objtype == NETOBJTYPE_PROJECTILE && check != this && + ((curpos.x - dimension < otherpos.x + check->dimension && curpos.x + dimension > otherpos.x + check->dimension) + || (curpos.x + dimension > otherpos.x - dimension && curpos.x - dimension < otherpos.x - dimension)) + && ((curpos.y - dimension < otherpos.y + check->dimension && curpos.y + dimension > otherpos.y + check->dimension) + ||(curpos.y + dimension > otherpos.y - dimension && curpos.y - dimension < otherpos.y - dimension))) + { + collide = true; + if (check->lifespan >= 0 || check->weapon == WEAPON_GRENADE) + create_sound(otherpos, sound_impact); + if (check->flags & check->PROJECTILE_FLAGS_EXPLODE) + create_explosion(otherpos, check->owner, check->weapon, false); + world->destroy_entity(check); + } + check = (projectile*)check->next_entity; + } + if(collide) + { + if (lifespan >= 0 || weapon == WEAPON_GRENADE) + create_sound(curpos, sound_impact); + if (flags & PROJECTILE_FLAGS_EXPLODE) + create_explosion(curpos, owner, weapon, false); + world->destroy_entity(this); + } +} void projectile::tick() { - + float pt = (server_tick()-start_tick-1)/(float)server_tickspeed(); float ct = (server_tick()-start_tick)/(float)server_tickspeed(); vec2 prevpos = get_pos(pt); vec2 curpos = get_pos(ct); lifespan--; - + int collide = col_intersect_line(prevpos, curpos, &curpos); //int collide = col_check_point((int)curpos.x, (int)curpos.y); - - entity *targetplayer = (entity*)intersect_player(prevpos, curpos, 6.0f, curpos, powner); + entity *targetplayer = NULL; + if(config.sv_correct_selfdamage && ct > 0.06) + { + targetplayer = (entity*)intersect_player(prevpos, curpos, 6.0f, curpos, NULL); + } + else + { + targetplayer = (entity*)intersect_player(prevpos, curpos, 6.0f, curpos, powner); + } if(targetplayer || collide || lifespan < 0) { if (lifespan >= 0 || weapon == WEAPON_GRENADE) @@ -514,7 +777,9 @@ } world->destroy_entity(this); + return; } + proceed_bulletcollision(curpos); } void projectile::fill_info(NETOBJ_PROJECTILE *proj) @@ -530,7 +795,7 @@ void projectile::snap(int snapping_client) { float ct = (server_tick()-start_tick)/(float)server_tickspeed(); - + if(distance(players[snapping_client].pos, get_pos(ct)) > 1000.0f) return; @@ -551,7 +816,7 @@ dir = direction; bounces = 0; do_bounce(); - + world->insert_entity(this); } @@ -565,7 +830,7 @@ this->from = from; pos = at; - energy = -1; + energy = -1; hit->take_damage(vec2(0,0), tuning.laser_damage, owner->client_id, WEAPON_RIFLE); return true; } @@ -573,16 +838,16 @@ void laser::do_bounce() { eval_tick = server_tick(); - + if(energy < 0) { //dbg_msg("laser", "%d removed", server_tick()); world->destroy_entity(this); return; } - + vec2 to = pos + dir*energy; - + if(col_intersect_line(pos, to, &to)) { if(!hit_player(pos, to)) @@ -592,17 +857,17 @@ pos = to - dir*2; vec2 temp_pos = pos; vec2 temp_dir = dir*4.0f; - + move_point(&temp_pos, &temp_dir, 1.0f, 0); pos = temp_pos; dir = normalize(temp_dir); - + energy -= distance(from, pos) + tuning.laser_bounce_cost; bounces++; - + if(bounces > tuning.laser_bounce_num) energy = -1; - + create_sound(pos, SOUND_RIFLE_BOUNCE); } } @@ -615,10 +880,10 @@ energy = -1; } } - + //dbg_msg("laser", "%d done %f %f %f %f", server_tick(), from.x, from.y, pos.x, pos.y); } - + void laser::reset() { world->destroy_entity(this); @@ -659,6 +924,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 @@ -677,10 +946,10 @@ { pos = vec2(0.0f, 0.0f); core.reset(); - + emote_type = 0; emote_stop = -1; - + //direction = vec2(0.0f, 1.0f); score = 0; dead = true; @@ -703,7 +972,7 @@ attack_tick = 0; mem_zero(&ninja, sizeof(ninja)); - + active_weapon = WEAPON_GUN; last_weapon = WEAPON_HAMMER; queued_weapon = -1; @@ -715,13 +984,13 @@ { if(w == active_weapon) return; - + last_weapon = active_weapon; queued_weapon = -1; active_weapon = w; if(active_weapon < 0 || active_weapon >= NUM_WEAPONS) active_weapon = 0; - + create_sound(pos, SOUND_WEAPON_SWITCH); } @@ -744,26 +1013,190 @@ else if(team == 1) return "blue team"; } - + return "spectators"; } +void auto_balancing() +{ + static int last_warning_tick = 0; + static int start_unbalance = 0; + if((config.sv_team_balance || config.sv_balance_warning) && gameobj->gametype != GAMETYPE_DM) + { + int team0 = get_team(0); + int team1 = get_team(1); + if(!start_unbalance) + start_unbalance = server_tick(); + if((config.sv_team_balance && (team0-team1 > config.sv_team_balance || team1-team0 > config.sv_team_balance)) || (!config.sv_team_balance && config.sv_balance_warning && (team0-team1 > config.sv_balance_warning || team1-team0 > config.sv_balance_warning))) + { + if(((config.sv_balance_warning && config.sv_team_balance && start_unbalance + config.sv_balance_warning*server_tickspeed() > server_tick()) || !config.sv_team_balance) && last_warning_tick + 20*server_tickspeed() < server_tick()) + { + send_display("Teams are are not balanced", -1); + last_warning_tick = server_tick(); + } + else if((config.sv_team_balance && config.sv_balance_warning && start_unbalance + config.sv_balance_warning*server_tickspeed() < server_tick()) || !config.sv_balance_warning) + { + send_display("Auto balancing teams...", -1); + while(team0-team1 > config.sv_team_balance) + { + int i = rand() % MAX_CLIENTS; + int steps = rand() % MAX_CLIENTS; + int now = 0; + while(1) + { + if(players[i].team == 0 && steps == now++) + { + int tmp_points = players[i].score; + players[i].team_changes--; + send_display("You have been assigned to the blue team", i); + players[i].set_team(1); + team0--; + players[i].score = tmp_points; + break; + } + if(++i == MAX_CLIENTS) + { + i = 0; + } + } + } + while(team1-team0 > config.sv_team_balance) + { + int i = rand() % MAX_CLIENTS; + int steps = rand() % MAX_CLIENTS; + int now = 0; + while(1) + { + if(players[i].team == 1 && steps == now++) + { + int tmp_points = players[i].score; + players[i].team_changes--; + send_display("You have been assigned to the red team", i); + players[i].set_team(0); + team1--; + players[i].score = tmp_points; + break; + } + if(++i == MAX_CLIENTS) + { + i = 0; + } + } + } + } + } + else + { + start_unbalance = 0; + last_warning_tick = 0; + } + } +} + 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++; + char buf[128]; + sprintf(buf, "You can change team in %i seconds", (config.sv_time_blocked * server_tickspeed() + last_team_set - server_tick())/server_tickspeed()); + send_display(buf, client_id); + if(config.sv_teamchangeskick && team_changes > config.sv_teamchangeskick) + { + + char kicking[127]; + sprintf(kicking, "%s was kicked because of fast teamchanging.", server_clientname(client_id)); + send_message(kicking, -1); + 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[127]; + sprintf(blocking, "%s can't change team for %d seconds", server_clientname(client_id), config.sv_time_blocked); + send_message(blocking, -1); + sprintf(blocking, "You can't change team for %d seconds", config.sv_time_blocked); + send_display(blocking, client_id); + return; + } + + } + else + { + last_team_set = server_tick(); + team_changes = 0; + } + } + } + if(config.sv_team_balance && !config.sv_balance_warning && gameobj->gametype != GAMETYPE_DM) + { + int team0 = get_team(0); + int team1 = get_team(1); + if(team == -1) + { + if(new_team == 1 && team1-team0 + 1 > config.sv_team_balance) + { + send_display("You can't join blue because of team-balance", client_id); + new_team = 0; + } + else if(new_team == 0 && team0-team1 + 1 > config.sv_team_balance) + { + send_display("You can't join red because of team-balance", client_id); + new_team = 1; + } + } + else if(new_team == 1 && team1-team0 + 2 > config.sv_team_balance) + { + send_display("You can't join blue because of team-balance", client_id); + return; + } + else if(new_team == 0 && team0-team1 + 2 > config.sv_team_balance) + { + send_display("You can't join red because of team-balance", client_id); + return; + } + } + teamkills = 0; // clamp the team new_team = gameobj->clampteam(new_team); if(team == new_team) return; - + char buf[512]; str_format(buf, sizeof(buf), "%s joined the %s", server_clientname(client_id), get_team_name(new_team)); - send_chat(-1, CHAT_ALL, buf); - + send_chat(-1, CHAT_ALL, buf); + teamkills --; die(client_id, -1); team = new_team; score = 0; dbg_msg("game", "team_join player='%d:%s' team=%d", client_id, server_clientname(client_id), team); - + gameobj->on_player_info_change(&players[client_id]); // send all info to this client @@ -786,7 +1219,7 @@ die_pos = vec2(0,0); pos = vec2(100,100); } - + vec2 pos; bool got; int friendly_team; @@ -797,35 +1230,35 @@ static float evaluate_spawn(spawneval *eval, vec2 pos) { float score = 0.0f; - + for(int c = 0; c < MAX_CLIENTS; c++) { if(players[c].client_id == -1) continue; - + // don't count dead people if(!(players[c].flags&entity::FLAG_PHYSICS)) continue; - + // team mates are not as dangerous as enemies float scoremod = 1.0f; if(eval->friendly_team != -1 && players[c].team == eval->friendly_team) scoremod = 0.5f; - + float d = distance(pos, players[c].pos); if(d == 0) score += 1000000000.0f; else score += 1.0f/d; } - + // weight in the die posititon float d = distance(pos, eval->die_pos); if(d == 0) score += 1000000000.0f; else score += 1.0f/d; - + return score; } @@ -856,17 +1289,17 @@ void player::try_respawn() { vec2 spawnpos = vec2(100.0f, -60.0f); - + // get spawn point spawneval eval; eval.die_pos = die_pos; - + eval.pos = vec2(100, 100); - + if(gameobj->gametype == GAMETYPE_CTF) { eval.friendly_team = team; - + // try first try own team spawn, then normal spawn and then enemy evaluate_spawn_type(&eval, 1+(team&1)); if(!eval.got) @@ -880,12 +1313,12 @@ { if(gameobj->gametype == GAMETYPE_TDM) eval.friendly_team = team; - + evaluate_spawn_type(&eval, 0); evaluate_spawn_type(&eval, 1); evaluate_spawn_type(&eval, 2); } - + spawnpos = eval.pos; // check if the position is occupado @@ -897,7 +1330,7 @@ if(ents[i] != this) return; } - + spawning = false; pos = spawnpos; @@ -908,9 +1341,9 @@ health = 10; armor = 0; jumped = 0; - + mem_zero(&ninja, sizeof(ninja)); - + dead = false; set_flag(entity::FLAG_PHYSICS); player_state = PLAYERSTATE_PLAYING; @@ -928,7 +1361,7 @@ /*weapons[WEAPON_RIFLE].got = true; weapons[WEAPON_RIFLE].ammo = -1;*/ - + active_weapon = WEAPON_GUN; last_weapon = WEAPON_HAMMER; queued_weapon = 0; @@ -966,7 +1399,7 @@ set_weapon(active_weapon); return 0; } - + // force ninja weapon set_weapon(WEAPON_NINJA); @@ -978,7 +1411,7 @@ ninja.activationdir = direction; ninja.currentmovetime = data->weapons[WEAPON_NINJA].movetime * server_tickspeed() / 1000; ninja.currentcooldown = data->weapons[WEAPON_NINJA].firedelay * server_tickspeed() / 1000 + server_tick(); - + // reset hit objects numobjectshit = 0; @@ -1058,7 +1491,7 @@ { if(reload_timer != 0) // make sure we have reloaded return; - + if(queued_weapon == -1) // check for a queued weapon return; @@ -1074,7 +1507,7 @@ int wanted_weapon = active_weapon; if(queued_weapon != -1) wanted_weapon = queued_weapon; - + // select weapon int next = count_input(latest_previnput.next_weapon, latest_input.next_weapon).presses; int prev = count_input(latest_previnput.prev_weapon, latest_input.prev_weapon).presses; @@ -1106,7 +1539,7 @@ // check for insane values if(wanted_weapon >= 0 && wanted_weapon < NUM_WEAPONS && wanted_weapon != active_weapon && weapons[wanted_weapon].got) queued_weapon = wanted_weapon; - + do_weaponswitch(); } @@ -1114,11 +1547,11 @@ { if(reload_timer != 0 || active_weapon == WEAPON_NINJA) return; - + do_weaponswitch(); - + vec2 direction = normalize(vec2(latest_input.target_x, latest_input.target_y)); - + bool fullauto = false; if(active_weapon == WEAPON_GRENADE || active_weapon == WEAPON_SHOTGUN || active_weapon == WEAPON_RIFLE) fullauto = true; @@ -1130,16 +1563,16 @@ if(fullauto && (latest_input.fire&1) && weapons[active_weapon].ammo) will_fire = true; if(!will_fire) return; - + // check for ammo if(!weapons[active_weapon].ammo) { create_sound(pos, SOUND_WEAPON_NOAMMO); return; } - + vec2 projectile_startpos = pos+direction*phys_size*0.75f; - + switch(active_weapon) { case WEAPON_HAMMER: @@ -1147,17 +1580,17 @@ // reset objects hit numobjectshit = 0; create_sound(pos, SOUND_HAMMER_FIRE); - + int type = NETOBJTYPE_PLAYER_CHARACTER; entity *ents[64]; - int num = world->find_entities(pos+direction*phys_size*0.75f, phys_size*0.5f, ents, 64, &type, 1); + int num = world->find_entities(pos+direction*phys_size*0.75f, phys_size*0.5f, ents, 64, &type, 1); for (int i = 0; i < num; i++) { player *target = (player*)ents[i]; if (target == this) continue; - + // hit a player, give him damage and stuffs... vec2 fdir = normalize(ents[i]->pos - pos); @@ -1169,14 +1602,16 @@ dir = normalize(target->pos - pos); else dir = vec2(0,-1); - + target->core.vel += normalize(dir + vec2(0,-1.1f)) * 10.0f; } - + } break; case WEAPON_GUN: { + direction.x += core.vel.x*((float)config.sv_gun_startvelocity/10000); + direction.y += core.vel.y*((float)config.sv_gun_startvelocity/10000); projectile *proj = new projectile(WEAPON_GUN, client_id, projectile_startpos, @@ -1184,28 +1619,30 @@ (int)(server_tickspeed()*tuning.gun_lifetime), this, 1, 0, 0, -1, WEAPON_GUN); - + // pack the projectile and send it to the client directly NETOBJ_PROJECTILE p; proj->fill_info(&p); - + msg_pack_start(NETMSGTYPE_SV_EXTRA_PROJECTILE, 0); msg_pack_int(1); for(unsigned i = 0; i < sizeof(NETOBJ_PROJECTILE)/sizeof(int); i++) msg_pack_int(((int *)&p)[i]); msg_pack_end(); server_send_msg(client_id); - + create_sound(pos, SOUND_GUN_FIRE); } break; - + case WEAPON_SHOTGUN: { + direction.x += core.vel.x*((float)config.sv_shotgun_startvelocity/10000); + direction.y += core.vel.y*((float)config.sv_shotgun_startvelocity/10000); int shotspread = 2; msg_pack_start(NETMSGTYPE_SV_EXTRA_PROJECTILE, 0); msg_pack_int(shotspread*2+1); - + for(int i = -shotspread; i <= shotspread; i++) { float spreading[] = {-0.185f, -0.070f, 0, 0.070f, 0.185f}; @@ -1220,23 +1657,25 @@ (int)(server_tickspeed()*tuning.shotgun_lifetime), this, 1, 0, 0, -1, WEAPON_SHOTGUN); - + // pack the projectile and send it to the client directly NETOBJ_PROJECTILE p; proj->fill_info(&p); - + for(unsigned i = 0; i < sizeof(NETOBJ_PROJECTILE)/sizeof(int); i++) msg_pack_int(((int *)&p)[i]); } msg_pack_end(); - server_send_msg(client_id); - + server_send_msg(client_id); + create_sound(pos, SOUND_SHOTGUN_FIRE); } break; case WEAPON_GRENADE: { + direction.x += core.vel.x*((float)config.sv_grenadelauncher_startvelocity/10000); + direction.y += core.vel.y*((float)config.sv_grenadelauncher_startvelocity/10000); projectile *proj = new projectile(WEAPON_GRENADE, client_id, projectile_startpos, @@ -1248,7 +1687,7 @@ // pack the projectile and send it to the client directly NETOBJ_PROJECTILE p; proj->fill_info(&p); - + msg_pack_start(NETMSGTYPE_SV_EXTRA_PROJECTILE, 0); msg_pack_int(1); for(unsigned i = 0; i < sizeof(NETOBJ_PROJECTILE)/sizeof(int); i++) @@ -1258,13 +1697,13 @@ create_sound(pos, SOUND_GRENADE_FIRE); } break; - + case WEAPON_RIFLE: { new laser(pos, direction, tuning.laser_reach, this); create_sound(pos, SOUND_RIFLE_FIRE); } break; - + } if(weapons[active_weapon].ammo > 0) // -1 == unlimited @@ -1295,7 +1734,7 @@ reload_timer--; return 0; } - + if (active_weapon == WEAPON_NINJA) { // don't update other weapons while ninja is active @@ -1326,7 +1765,7 @@ weapons[active_weapon].ammoregenstart = -1; } } - + return 0; } @@ -1356,7 +1795,7 @@ mem_copy(&latest_input, input, sizeof(latest_input)); } }*/ - + // check if we have enough input // this is to prevent initial weird clicks if(num_inputs < 2) @@ -1364,7 +1803,7 @@ latest_previnput = latest_input; previnput = input; } - + // do latency stuff { CLIENT_INFO info; @@ -1422,7 +1861,18 @@ //core.jumped = jumped; core.input = input; core.tick(); - + if(config.sv_activate_stopdamage) + { + if(fabs(core.old_vel.x - core.vel.x) > config.sv_activate_stopdamage) + { + take_damage(vec2(0,0), (int)((fabs(core.old_vel.x - core.vel.x) - config.sv_activate_stopdamage)/(float)10*config.sv_stopdamage), client_id, WEAPON_HAMMER); + } + if(fabs(core.old_vel.y - core.vel.y) > config.sv_activate_stopdamage) + { + take_damage(vec2(0,0), (int)((fabs(core.old_vel.y - core.vel.y) - config.sv_activate_stopdamage)/(float)10*config.sv_stopdamage), client_id, WEAPON_HAMMER); + } + core.old_vel = core.vel; + } // handle weapons handle_weapons(); @@ -1440,16 +1890,16 @@ vec2 start_pos = core.pos; vec2 start_vel = core.vel; bool stuck_before = test_box(core.pos, vec2(28.0f, 28.0f)); - + core.move(); bool stuck_after_move = test_box(core.pos, vec2(28.0f, 28.0f)); core.quantize(); bool stuck_after_quant = test_box(core.pos, vec2(28.0f, 28.0f)); pos = core.pos; - + if(!stuck_before && (stuck_after_move || stuck_after_quant)) { - dbg_msg("player", "STUCK!!! %d %d %d %f %f %f %f %x %x %x %x", + dbg_msg("player", "STUCK!!! %d %d %d %f %f %f %f %x %x %x %x", stuck_before, stuck_after_move, stuck_after_quant, @@ -1461,7 +1911,7 @@ int events = core.triggered_events; int mask = cmask_all_except_one(client_id); - + if(events&COREEVENT_GROUND_JUMP) create_sound(pos, SOUND_PLAYER_JUMP, mask); if(events&COREEVENT_AIR_JUMP) { @@ -1473,14 +1923,14 @@ c->y = (int)pos.y; } } - + //if(events&COREEVENT_HOOK_LAUNCH) snd_play_random(CHN_WORLD, SOUND_HOOK_LOOP, 1.0f, pos); if(events&COREEVENT_HOOK_ATTACH_PLAYER) create_sound(pos, SOUND_HOOK_ATTACH_PLAYER, cmask_all()); if(events&COREEVENT_HOOK_ATTACH_GROUND) create_sound(pos, SOUND_HOOK_ATTACH_GROUND, mask); //if(events&COREEVENT_HOOK_RETRACT) snd_play_random(CHN_WORLD, SOUND_PLAYER_JUMP, 1.0f, pos); - + } - + if(team == -1) { pos.x = input.target_x; @@ -1517,17 +1967,29 @@ die_tick = server_tick(); clear_flag(FLAG_PHYSICS); create_death(pos, client_id); + if(killer != client_id && players[killer].team != team && players[killer].teamkills > 0) + players[killer].teamkills --; + if(config.sv_kick_teamkiller && (killer == client_id || players[killer].team == team) && players[killer].teamkills++ >= config.sv_kick_teamkiller) + { + char kickmessage[256]; + sprintf(kickmessage, "%s was kicked because of teamkilling/selfkillng.", server_clientname(killer)); + send_message(kickmessage, -1); + if(config.sv_ban_teamkiller) + server_ban(killer, config.sv_ban_teamkiller, "You were banned because of teamkilling/selfkilling"); + else + server_kick(killer, "You were kicked because of teamkilling/selfkilling"); + } } bool player::take_damage(vec2 force, int dmg, int from, int weapon) { core.vel += force; - + if(gameobj->is_friendly_fire(client_id, from) && !config.sv_teamdamage) return false; // player only inflicts half damage on self - if(from == client_id) + if(!config.sv_correct_selfdamage && from == client_id) dmg = max(1, dmg/2); // CTF and TDM (TODO: check for FF) @@ -1557,7 +2019,7 @@ health--; dmg--; } - + if(dmg > armor) { dmg -= armor; @@ -1569,7 +2031,7 @@ dmg = 0; } } - + health -= dmg; } @@ -1649,7 +2111,7 @@ character->ammocount = 0; character->health = 0; character->armor = 0; - + character->weapon = active_weapon; character->attacktick = attack_tick; @@ -1795,7 +2257,7 @@ pplayer->emote_type = EMOTE_ANGRY; pplayer->emote_stop = server_tick() + 1200 * server_tickspeed() / 1000; - + break; } default: @@ -1950,12 +2412,12 @@ float closest_len = distance(pos0, pos1) * 100.0f; vec2 line_dir = normalize(pos1-pos0); player *closest = 0; - + for(int i = 0; i < MAX_CLIENTS; i++) { - if(players[i].client_id < 0 || (entity *)&players[i] == notthis) + if(players[i].client_id < 0 || (notthis != NULL && (entity *)&players[i] == notthis)) continue; - + if(!(players[i].flags&entity::FLAG_PHYSICS)) continue; @@ -1971,7 +2433,7 @@ } } } - + return closest; } @@ -1981,12 +2443,12 @@ // Find other players float closest_range = radius*2; player *closest = 0; - + for(int i = 0; i < MAX_CLIENTS; i++) { if(players[i].client_id < 0 || (entity *)&players[i] == notthis) continue; - + if(!(players[i].flags&entity::FLAG_PHYSICS)) continue; @@ -2000,7 +2462,7 @@ } } } - + return closest; } @@ -2024,7 +2486,7 @@ { if(!world->paused) players[client_id].on_direct_input((NETOBJ_PLAYER_INPUT *)input); - + /* if(i->fire) { @@ -2044,7 +2506,7 @@ //players[client_id].previnput = players[client_id].input; players[client_id].input = *(NETOBJ_PLAYER_INPUT*)input; players[client_id].num_inputs++; - + if(players[client_id].input.target_x == 0 && players[client_id].input.target_y == 0) players[client_id].input.target_y = -1; } @@ -2056,12 +2518,22 @@ world->insert_entity(&players[client_id]); players[client_id].respawn(); dbg_msg("game", "join player='%d:%s'", client_id, server_clientname(client_id)); - + players[client_id].voted=false; + players[client_id].votedfor=-1; + players[client_id].teamkills = 0; 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); - + 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); } @@ -2069,7 +2541,7 @@ { players[client_id].init(); players[client_id].client_id = client_id; - + // Check which team the player should be on if(config.sv_tournament_mode) players[client_id].team = -1; @@ -2088,7 +2560,6 @@ char buf[512]; str_format(buf, sizeof(buf), "%s has left the game", server_clientname(client_id)); send_chat(-1, CHAT_ALL, buf); - dbg_msg("game", "leave player='%d:%s'", client_id, server_clientname(client_id)); gameobj->on_player_death(&players[client_id], 0, -1); @@ -2105,7 +2576,7 @@ dbg_msg("server", "dropped weird message '%s' (%d), failed on '%s'", netmsg_get_name(msgtype), msgtype, netmsg_failed_on()); return; } - + if(msgtype == NETMSGTYPE_CL_SAY) { NETMSG_CL_SAY *msg = (NETMSG_CL_SAY *)rawmsg; @@ -2114,15 +2585,234 @@ team = players[client_id].team; else team = CHAT_ALL; - + if(config.sv_spamprotection && players[client_id].last_chat+time_freq() > time_get()) { // consider this as spam } else { - players[client_id].last_chat = time_get(); - send_chat(client_id, team, msg->message); + if(!strcasecmp(msg->message, ".info")) + { + char commands[768]="Mod from scosu (http://scosu.de). Available commands:\n"; + if(config.sv_handle_mapvotes) + { + strcat(commands, "Positive map-voting: /++\n"); + strcat(commands, "Negative map-voting: /--\n"); + } + strcat(commands, "Current vote: /currentvote\n"); + strcat(commands, "List of player-ids: /players\n"); + if(config.sv_allow_votes) + { + strcat(commands, "Kick player by name: /kick \n"); + strcat(commands, "Kick player by id: /kick_id \n"); + } + if(config.sv_allow_next_map) + { + strcat(commands, "Start vote for change to next map: /next_map\n"); + } + if(config.sv_allow_timelimit) + { + strcat(commands, "Start vote for set timelimit: /timelimit \n"); + } + if(config.sv_allow_scorelimit) + { + strcat(commands, "Start vote for set scorelimit: /scorelimit \n"); + } + send_message(commands, client_id); + //players[client_id].last_chat = time_get()+time_freq()*10; + } + else if (!strncasecmp(msg->message, "/kick ",6) && !vote_called && config.sv_allow_votes) + { + if(config.sv_vote_pause && players[client_id].lastvote != 0 && (server_tick() - players[client_id].lastvote)/server_tickspeed() < config.sv_vote_pause) + { + char novote[90]; + sprintf(novote, "You can start votings in %i seconds", config.sv_vote_pause-(server_tick() - players[client_id].lastvote)/server_tickspeed()); + send_display(novote, client_id); + return; + } + 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; + str_format(vote_message, sizeof(vote_message), "Vote for: kick %s\nsay \"/yes\" or \"/no\" (%s)", server_clientname(playerstokick),server_clientname(client_id)); + send_display(vote_message,-1); + vote_called=true; + timer_vote = server_tick(); + players[client_id].votedfor = 1; + players[client_id].lastvote = server_tick(); + server_save_ip(votedtokick); + } + else if(playersnumber > 1) + { + send_display("Several players possible", client_id); + } + else + { + send_display("There is no player with this name", client_id); + } + } + else if (!strncasecmp(msg->message, "/kick_id ",9) && !vote_called && config.sv_allow_votes) + { + if(config.sv_vote_pause && players[client_id].lastvote != 0 && (server_tick() - players[client_id].lastvote)/server_tickspeed() < config.sv_vote_pause) + { + char novote[90]; + sprintf(novote, "You can start votings in %i seconds", config.sv_vote_pause-(server_tick() - players[client_id].lastvote)/server_tickspeed()); + send_display(novote, client_id); + return; + } + votedtokick = atoi(&msg->message[9]); + if(votedtokick > 0 && votedtokick-- <= MAX_CLIENTS && players[votedtokick].client_id != -1) + { + votetime = config.sv_votetime; + str_format(votetype, sizeof(votetype), "kick"); + str_format(vote_message, sizeof(vote_message), "Vote for: kick %s\nsay \"/yes\" or \"/no\" (%s)",server_clientname(votedtokick), server_clientname(client_id)); + send_display(vote_message,-1); + vote_called=true; + timer_vote = server_tick(); + players[client_id].votedfor = 1; + players[client_id].lastvote = server_tick(); + server_save_ip(votedtokick); + } + else + { + votedtokick = -1; + send_display("That was no valid integer", client_id); + } + } + else if (!strncasecmp(msg->message, "/next_map",9) && !vote_called && config.sv_allow_next_map) + { + if(config.sv_vote_pause && players[client_id].lastvote != 0 && (server_tick() - players[client_id].lastvote)/server_tickspeed() < config.sv_vote_pause) + { + char novote[90]; + sprintf(novote, "You can start votings in %i seconds", config.sv_vote_pause-(server_tick() - players[client_id].lastvote)/server_tickspeed()); + send_display(novote, client_id); + return; + } + votetime = config.sv_votetime; + str_format(votetype, sizeof(votetype), "next_map"); + str_format(vote_message, sizeof(vote_message), "Vote for: changing to next map\nsay \"/yes\" or \"/no\" (%s)",server_clientname(client_id)); + send_display(vote_message,-1); + vote_called=true; + timer_vote = server_tick(); + players[client_id].votedfor = 1; + players[client_id].lastvote = server_tick(); + } + else if (!strncasecmp(msg->message, "/timelimit ",11) && !vote_called && config.sv_allow_timelimit) + { + if(config.sv_vote_pause && players[client_id].lastvote != 0 && (server_tick() - players[client_id].lastvote)/server_tickspeed() < config.sv_vote_pause) + { + char novote[90]; + sprintf(novote, "You can start votings in %i seconds", config.sv_vote_pause-(server_tick() - players[client_id].lastvote)/server_tickspeed()); + send_display(novote, client_id); + return; + } + votedtokick = atoi(&msg->message[11]); + if(votedtokick == -1 || (votedtokick>0 && votedtokick < 1000)) + { + votetime = config.sv_votetime; + str_format(votetype, sizeof(votetype), "timelimit"); + str_format(vote_message, sizeof(vote_message), "Vote for: set timelimit to %i\nsay \"/yes\" or \"/no\" (%s)",votedtokick, server_clientname(client_id)); + send_display(vote_message,-1); + vote_called=true; + timer_vote = server_tick(); + players[client_id].votedfor = 1; + players[client_id].lastvote = server_tick(); + } + else + { + votedtokick = -1; + send_display("That was no valid integer", client_id); + } + } + else if (!strncasecmp(msg->message, "/scorelimit ",12) && !vote_called && config.sv_allow_scorelimit) + { + if(config.sv_vote_pause && players[client_id].lastvote != 0 && (server_tick() - players[client_id].lastvote)/server_tickspeed() < config.sv_vote_pause) + { + char novote[90]; + sprintf(novote, "You can start votings in %i seconds", config.sv_vote_pause-(server_tick() - players[client_id].lastvote)/server_tickspeed()); + send_display(novote, client_id); + return; + } + votedtokick = atoi(&msg->message[12]); + if(votedtokick == -1 || (votedtokick>0 && votedtokick < 1000)) + { + votetime = config.sv_votetime; + str_format(votetype, sizeof(votetype), "scorelimit"); + str_format(vote_message, sizeof(vote_message), "Vote for: set scorelimit to %i\nsay \"/yes\" or \"/no\" (%s)",votedtokick, server_clientname(client_id)); + send_display(vote_message,-1); + vote_called=true; + timer_vote = server_tick(); + players[client_id].votedfor = 1; + players[client_id].lastvote = server_tick(); + } + else + { + votedtokick = -1; + send_display("That was no valid integer", client_id); + } + } + 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 buf[256]; + str_format(buf, sizeof(buf), "%s voted for no",server_clientname(client_id)); + send_message(buf, -1); + players[client_id].votedfor = 0; + //resultvote(); + } + else if (!strncasecmp(msg->message, "/currentvote",12) && vote_called) + { + send_display(vote_message, client_id); + resultvote(); + } + else if (!strncasecmp(msg->message, "/players",2)) + { + char all_players[512] = "Players:\n"; + int i = 0; + for(;i < MAX_CLIENTS;i++) + { + if(players[i].client_id != -1) + { + char player[5]; + sprintf(player, "%i", i+1); + strcat(all_players, player); + strcat(all_players, ": \""); + strcat(all_players, server_clientname(i)); + strcat(all_players, "\"\n"); + } + } + send_message(all_players, client_id); + } + else + { + players[client_id].last_chat = time_get(); + send_chat(client_id, team, msg->message); + } } } else if (msgtype == NETMSGTYPE_CL_SETTEAM) @@ -2159,7 +2849,7 @@ // copy old name char oldname[MAX_NAME_LENGTH]; str_copy(oldname, server_clientname(client_id), MAX_NAME_LENGTH); - + server_setclientname(client_id, msg->name); if(msgtype == NETMSGTYPE_CL_CHANGEINFO && strcmp(oldname, server_clientname(client_id)) != 0) { @@ -2167,16 +2857,16 @@ str_format(chattext, sizeof(chattext), "%s changed name to %s", oldname, server_clientname(client_id)); send_chat(-1, CHAT_ALL, chattext); } - + // set skin str_copy(players[client_id].skin_name, msg->skin, sizeof(players[client_id].skin_name)); - + gameobj->on_player_info_change(&players[client_id]); - + if(msgtype == NETMSGTYPE_CL_STARTINFO) { // a client that connected! - + // send all info to this client for(int i = 0; i < MAX_CLIENTS; i++) { @@ -2186,13 +2876,13 @@ // send tuning parameters to client send_tuning_params(client_id); - + // NETMSG_SV_READY_TO_ENTER m; m.pack(MSGFLAG_VITAL); - server_send_msg(client_id); + server_send_msg(client_id); } - + send_info(client_id, -1); } else if (msgtype == NETMSGTYPE_CL_EMOTICON) @@ -2265,25 +2955,59 @@ { int client_id = clamp(console_arg_int(result, 0), 0, (int)MAX_CLIENTS); int team = clamp(console_arg_int(result, 1), -1, 1); - + dbg_msg("", "%d %d", client_id, team); - + if(players[client_id].client_id != client_id) return; - + 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; +} + +static void con_next_map(void *result, void *user_data) +{ + gameobj->endround(); +} + +static void con_cancel_vote(void *result, void *user_data) +{ + 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; + } + } + vote_called = false; + send_display("Vote canceled by admin", -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); MACRO_REGISTER_COMMAND("set_team", "ii", con_set_team, 0); + MACRO_REGISTER_COMMAND("next_map", "", con_next_map, 0); + MACRO_REGISTER_COMMAND("cancel_vote", "", con_cancel_vote, 0); } void mods_init() @@ -2312,11 +3036,11 @@ // create all entities from the game layer MAPITEM_LAYER_TILEMAP *tmap = layers_game_layer(); TILE *tiles = (TILE *)map_get_data(tmap->data); - + num_spawn_points[0] = 0; num_spawn_points[1] = 0; num_spawn_points[2] = 0; - + for(int y = 0; y < tmap->height; y++) { for(int x = 0; x < tmap->width; x++)