diff --git a/source/src/client.cpp b/source/src/client.cpp index 54c93798..d60c0448 100644 --- a/source/src/client.cpp +++ b/source/src/client.cpp @@ -71,8 +71,7 @@ void changeteam(int team) // force team and respawn c2sinit = false; if(m_ctf) tryflagdrop(); s_strncpy(player1->team, team_string(team), MAXTEAMLEN+1); - player1->lastaction = lastmillis; - player1->state = CS_DEAD; + playerdeath(player1); }; void newteam(char *name) @@ -81,23 +80,20 @@ void newteam(char *name) { if(m_teammode) { - bool checkteamsize = autoteambalance && players.length() >= 1; + bool checkteamsize = autoteambalance && players.length() >= 1; int freeteam = smallerteam(); - if(!strcmp(name, "RVSF") || !strcmp(name, "CLA")) - { - if(!strcmp(name, player1->team)) return; // same team - int team = team_int(name); - if(checkteamsize && team != freeteam) - { - conoutf("\f3the %s team is already full", name); - return; - }; - changeteam(team); - } - else changeteam(checkteamsize ? (uint)freeteam : rnd(2)); // random assignement - } - else return; + if(!team_valid(name)) changeteam(checkteamsize ? (uint)freeteam : rnd(2)); // random assignement + if(!strcmp(name, player1->team)) return; // same team + + int team = team_int(name); + if(checkteamsize && team != freeteam) + { + conoutf("\f3the %s team is already full", name); + return; + }; + changeteam(team); + }; } else conoutf("your team is: %s", player1->team); }; diff --git a/source/src/clientgame.cpp b/source/src/clientgame.cpp index d9696042..a550b6c3 100644 --- a/source/src/clientgame.cpp +++ b/source/src/clientgame.cpp @@ -42,6 +42,17 @@ void setskin(playerent *pl, int skin) pl->skin = max(0, skin % (maxskin+1)); }; +void playerdeath(playerent *pl) +{ + pl->lastaction = lastmillis; + pl->lifesequence++; + pl->attacking = false; + pl->state = CS_DEAD; + pl->oldpitch = pl->pitch; + pl->pitch = 0; + pl->roll = 60; +}; + void spawnstate(playerent *d) // reset player state not persistent accross spawns { d->respawn(); @@ -477,17 +488,11 @@ void selfdamage(int damage, int actor, playerent *act, bool gib, playerent *pl) setscope(false); addmsg(gib ? SV_GIBDIED : SV_DIED, "ri", actor); }; - pl->lifesequence++; - pl->attacking = false; - pl->state = CS_DEAD; - pl->oldpitch = pl->pitch; - pl->pitch = 0; - pl->roll = 60; - playsound(S_DIE1+rnd(2), pl!=player1 ? &pl->o : NULL); - if(gib) addgib(pl); + playerdeath(pl); spawnstate(pl); - pl->lastaction = lastmillis; - if (pl!=player1 || act->type==ENT_BOT) act->frags++; + playsound(S_DIE1+rnd(2), pl!=player1 ? &pl->o : NULL); + if(gib) addgib(pl); + if(pl!=player1 || act->type==ENT_BOT) act->frags++; } else { @@ -549,6 +554,7 @@ void preparectf(bool cleanonly=false) e.spawned = true; if(e.attr2>2) { conoutf("\f3invalid ctf-flag entity (%i)", i); e.attr2 = 0; }; flaginfo &f = flaginfos[e.attr2]; + f.team = e.attr2; f.flag = &e; f.state = CTFF_INBASE; f.originalpos.x = (float) e.x; @@ -602,144 +608,34 @@ void suicide() COMMAND(suicide, ARG_NONE); -// ctf flag actions done by the local player - -void flagpickup() -{ - int flag = team_opposite(team_int(player1->team)); - flaginfo &f = flaginfos[flag]; - if(f.flag) - { - f.flag->spawned = false; - f.state = CTFF_STOLEN; - f.actor = player1; // do this although we don't know if we picked the flag to avoid getting it after a possible respawn - f.ack = false; - addmsg(SV_FLAGPICKUP, "ri", flag); - }; -}; - -void tryflagdrop() -{ - int flag = team_opposite(team_int(player1->team)); - flaginfo &f = flaginfos[flag]; - if(f.state==CTFF_STOLEN && f.actor==player1) - { - f.flag->spawned = false; - f.state = CTFF_DROPPED; - f.ack = false; - addmsg(SV_FLAGDROP, "ri", flag); - }; -}; - -void flagreturn() -{ - int flag = team_int(player1->team); - flaginfo &f = flaginfos[flag]; - if(f.flag) - { - f.flag->spawned = false; - f.ack = false; - addmsg(SV_FLAGRETURN, "ri", flag); - }; -}; - -void flagscore() -{ - int flag = team_opposite(team_int(player1->team)); - flaginfo &f = flaginfos[flag]; - f.ack = false; - addmsg(SV_FLAGSCORE, "ri", flag); -}; - -void flagreset() -{ - int flag = team_opposite(team_int(player1->team)); - flaginfo &f = flaginfos[flag]; - if(f.state==CTFF_STOLEN && f.actor==player1) - { - f.flag->spawned = false; - f.state = CTFF_INBASE; - f.ack = false; - addmsg(SV_FLAGRESET, "ri", flag); - }; -}; - -// flag actions from the net - -void flagstolen(int flag, int action, playerent *actor) -{ - if(actor) - { - flaginfo &f = flaginfos[flag]; - f.actor = actor; - f.flag->spawned = false; - f.ack = true; - flagmsg(flag, action); - }; -}; - -void flagdropped(int flag, int action, short x, short y, short z) -{ - flaginfo &f = flaginfos[flag]; - sqr *dropplace = S_SECURE(x, y); - if(!dropplace) return; - - z -= 4; - float floor = (float) dropplace->floor; - if(z > hdr.waterlevel) // above water - { - if(floor < hdr.waterlevel) z = hdr.waterlevel; // avoid dropping into water - else z = (short) floor; - }; - - f.flag->x = x; - f.flag->y = y; - f.flag->z = z; - f.flag->spawned = true; - f.ack = true; - flagmsg(flag, action); -}; - -void flaginbase(int flag, int action, playerent *actor) -{ - flaginfo &f = flaginfos[flag]; - if(actor) f.actor = actor; - f.flag->x = (ushort) f.originalpos.x; - f.flag->y = (ushort) f.originalpos.y; - f.flag->z = (ushort) f.originalpos.z; - f.flag->spawned = true; - f.ack = true; - flagmsg(flag, action); -}; - // console and audio feedback void flagmsg(int flag, int action) { flaginfo &f = flaginfos[flag]; if(!f.actor || !f.ack) return; - bool ownflag = flag == team_int(player1->team); + bool own = flag == team_int(player1->team); switch(action) { case SV_FLAGPICKUP: { playsound(S_FLAGPICKUP); if(f.actor==player1) conoutf("\f2you got the enemy flag"); - else conoutf("\f2%s got %s flag", f.actor->name, (ownflag ? "your": "the enemy")); + else conoutf("\f2%s got %s flag", f.actor->name, (own ? "your": "the enemy")); break; }; case SV_FLAGDROP: { playsound(S_FLAGDROP); if(f.actor==player1) conoutf("you lost the flag"); - else conoutf("\f2%s lost %s flag", f.actor->name, (ownflag ? "your" : "the enemy")); + else conoutf("\f2%s lost %s flag", f.actor->name, (own ? "your" : "the enemy")); break; }; case SV_FLAGRETURN: { playsound(S_FLAGRETURN); if(f.actor==player1) conoutf("you returned your flag"); - else conoutf("\f2%s returned %s flag", f.actor->name, (ownflag ? "your" : "the enemy")); + else conoutf("\f2%s returned %s flag", f.actor->name, (own ? "your" : "the enemy")); break; }; case SV_FLAGSCORE: @@ -750,7 +646,7 @@ void flagmsg(int flag, int action) conoutf("\f2you scored"); addmsg(SV_FLAGS, "ri", ++player1->flagscore); } - else conoutf("\f2%s scored for %s team", f.actor->name, (ownflag ? "the enemy" : "your")); + else conoutf("\f2%s scored for %s team", f.actor->name, (own ? "the enemy" : "your")); break; }; case SV_FLAGRESET: @@ -763,6 +659,8 @@ void flagmsg(int flag, int action) }; }; +// server administration + void setmaster(char *claim, char *password) { int c = atoi(claim); @@ -786,14 +684,12 @@ void kick(int player) { mastercommand(MCMD_KICK, player); }; void ban(int player) { mastercommand(MCMD_BAN, player); }; void removebans() { mastercommand(MCMD_REMBANS, 0); }; void autoteam(int enable) { mastercommand(MCMD_AUTOTEAM, enable); }; -void shuffle() { mastercommand(MCMD_SHUFFLETEAMS, 0); }; COMMAND(setmaster, ARG_2STR); COMMAND(kick, ARG_1INT); COMMAND(ban, ARG_1INT); COMMAND(removebans, ARG_NONE); COMMAND(autoteam, ARG_1INT); -COMMAND(shuffle, ARG_NONE); struct mline { string cmd; }; static vector mlines; diff --git a/source/src/clients2c.cpp b/source/src/clients2c.cpp index bfc0c0f1..f21e8bcc 100644 --- a/source/src/clients2c.cpp +++ b/source/src/clients2c.cpp @@ -146,8 +146,10 @@ void parsemessages(int cn, playerent *d, ucharbuf &p) changemapserv(text, getint(p)); if(joining && m_arena) { - player1->state = CS_DEAD; - showscores(true); + /* TESTME + player1->state = CS_DEAD; + showscores(true);*/ + playerdeath(player1); }; mapchanged = true; break; @@ -261,6 +263,11 @@ void parsemessages(int cn, playerent *d, ucharbuf &p) { frags = -1; conoutf("you fragged a teammate (%s)", d->name); + if(m_ctf) + { + flaginfo &flag = flaginfos[team_opposite(team_int(d->team))]; + if(flag.state == CTFF_STOLEN && flag.actor == d) playerdeath(player1); // punish for ctf TK + }; } else { @@ -459,9 +466,9 @@ void parsemessages(int cn, playerent *d, ucharbuf &p) case SV_MASTERINFO: { + loopv(players) { players[i]->ismaster = false; } int m = getint(p); - if(m == -1) loopv(players) { players[i]->ismaster = false; } - else + if(m != -1) { playerent *pl = (m == getclientnum() ? player1 : getclient(m)); if(pl) @@ -473,6 +480,29 @@ void parsemessages(int cn, playerent *d, ucharbuf &p) break; }; + case SV_MASTERCMD: + { + int cmd = getint(p), arg = getint(p); + switch(cmd) + { + case MCMD_KICK: + case MCMD_BAN: + { + playerent *pl = (arg == getclientnum() ? NULL : getclient(arg)); + if(pl) conoutf("%s has been %s", pl->name, cmd == MCMD_KICK ? "kicked" : "banned"); + break; + } + case MCMD_REMBANS: + conoutf("bans removed"); + break; + + case MCMD_MASTERMODE: + conoutf("mastermode set to %i", arg); + break; + }; + break; + }; + case SV_FORCETEAM: { changeteam(getint(p)); @@ -481,8 +511,7 @@ void parsemessages(int cn, playerent *d, ucharbuf &p) case SV_AUTOTEAM: { - autoteambalance = getint(p) == 1; - conoutf("autoteam is %s", autoteambalance ? "enabled" : "disabled"); + conoutf("autoteam is %s", (autoteambalance = getint(p) == 1) ? "enabled" : "disabled"); break; }; diff --git a/source/src/editing.cpp b/source/src/editing.cpp index fac22759..daed9dfd 100644 --- a/source/src/editing.cpp +++ b/source/src/editing.cpp @@ -45,8 +45,9 @@ void toggleedit() { resettagareas(); // clear trigger areas to allow them to be edited player1->health = 100; - //put call to clear/restar gamemode + //put call to clear/restart gamemode projreset(); + player1->attacking = false; }; keyrepeat(editmode); selset = false; diff --git a/source/src/entities.cpp b/source/src/entities.cpp index f0fb9328..59950202 100644 --- a/source/src/entities.cpp +++ b/source/src/entities.cpp @@ -38,12 +38,11 @@ void renderentities() if(!&mmi) continue; rendermodel(mmi.name, ANIM_MAPMODEL|ANIM_LOOP, e.attr4, mmi.rad ? (float)mmi.rad : 1.1f, e.x, (float)S(e.x, e.y)->floor+mmi.zoff+e.attr3, e.y, (float)((e.attr1+7)-(e.attr1+7)%15), 0, 10.0f); } - else if(e.type==CTF_FLAG && m_ctf) // EDIT: AH + else if(m_ctf && e.type==CTF_FLAG) // EDIT: AH { flaginfo &f = flaginfos[e.attr2]; - if(f.state==CTFF_STOLEN && f.actor) + if(f.state==CTFF_STOLEN && f.actor == player1) { - if(f.actor == player1) continue; s_sprintfd(path)("pickups/flags/small_%s", team_string(e.attr2)); rendermodel(path, ANIM_FLAG|ANIM_START, 0, 1.1f, f.actor->o.x, f.actor->o.z+0.3f+(sinf(lastmillis/100.0f)+1)/10, f.actor->o.y, lastmillis/2.5f, 0, 120.0f); } @@ -347,3 +346,88 @@ bool intersect(entity *e, vec &from, vec &to, vec *end) // if lineseg hits entit return false; }; // End add by Ricks + +// ctf flag actions done by the local player + +void flagpickup() +{ + flaginfo &f = flaginfos[team_opposite(team_int(player1->team))]; + f.flag->spawned = false; + f.state = CTFF_STOLEN; + f.actor = player1; // do this although we don't know if we picked the flag to avoid getting it after a possible respawn + f.ack = false; + addmsg(SV_FLAGPICKUP, "ri", f.team); +}; + +void tryflagdrop() +{ + flaginfo &f = flaginfos[team_opposite(team_int(player1->team))]; + if(f.state==CTFF_STOLEN && f.actor==player1) + { + f.flag->spawned = false; + f.state = CTFF_DROPPED; + f.ack = false; + addmsg(SV_FLAGDROP, "ri", f.team); + }; +}; + +void flagreturn() +{ + flaginfo &f = flaginfos[team_int(player1->team)]; + f.flag->spawned = false; + f.ack = false; + addmsg(SV_FLAGRETURN, "ri", f.team); +}; + +void flagscore() +{ + flaginfo &f = flaginfos[team_opposite(team_int(player1->team))]; + f.ack = false; + addmsg(SV_FLAGSCORE, "ri", f.team); +}; + +// flag actions from the net + +void flagstolen(int flag, int action, playerent *actor) +{ + if(!actor) return; + flaginfo &f = flaginfos[flag]; + f.actor = actor; + f.flag->spawned = false; + f.ack = true; + flagmsg(flag, action); +}; + +void flagdropped(int flag, int action, short x, short y, short z) +{ + flaginfo &f = flaginfos[flag]; + sqr *dropplace = S_SECURE(x, y); + if(!dropplace) return; + + z -= 4; + float floor = (float) dropplace->floor; + if(z > hdr.waterlevel) // above water + { + if(floor < hdr.waterlevel) z = hdr.waterlevel; // avoid dropping into water + else z = (short) floor; + }; + + f.flag->x = x; + f.flag->y = y; + f.flag->z = z; + f.flag->spawned = true; + f.ack = true; + flagmsg(flag, action); +}; + +void flaginbase(int flag, int action, playerent *actor) +{ + flaginfo &f = flaginfos[flag]; + if(actor) f.actor = actor; + f.flag->x = (ushort) f.originalpos.x; + f.flag->y = (ushort) f.originalpos.y; + f.flag->z = (ushort) f.originalpos.z; + f.flag->spawned = true; + f.ack = true; + flagmsg(flag, action); +}; \ No newline at end of file diff --git a/source/src/entity.h b/source/src/entity.h index 0255bfda..78dd4e98 100644 --- a/source/src/entity.h +++ b/source/src/entity.h @@ -32,9 +32,9 @@ enum { GUN_KNIFE = 0, GUN_PISTOL, GUN_SHOTGUN, GUN_SUBGUN, GUN_SNIPER, GUN_ASSAU #define isteam(a,b) (m_teammode && strcmp(a, b)==0) -#define TEAM_CLA 0 // -#define TEAM_RVSF 1 // -// rb means red/blue +#define TEAM_CLA 0 +#define TEAM_RVSF 1 +#define team_valid(t) (!strcmp(t, "RVSF") || !strcmp(t, "CLA")) #define team_string(t) ((t) ? "RVSF" : "CLA") #define team_int(t) (strcmp((t), "CLA") == 0 ? TEAM_CLA : TEAM_RVSF) #define team_opposite(o) ((o) == TEAM_CLA ? TEAM_RVSF : TEAM_CLA) @@ -224,11 +224,12 @@ enum { CTFF_INBASE = 0, CTFF_STOLEN, CTFF_DROPPED }; struct flaginfo { + int team; entity *flag; playerent *actor; vec originalpos; - int state; // one of the types above - bool ack; // is the data ack'd ? + int state; // one of CTFF_* + bool ack; // data is ackd flaginfo() : flag(0), actor(0), state(CTFF_INBASE), ack(false) {}; }; diff --git a/source/src/protocol.h b/source/src/protocol.h index 64a112ca..dfeec559 100644 --- a/source/src/protocol.h +++ b/source/src/protocol.h @@ -24,7 +24,7 @@ enum SV_CLIENT, }; -enum { MCMD_KICK = 0, MCMD_BAN, MCMD_REMBANS, MCMD_MASTERMODE, MCMD_AUTOTEAM, MCMD_SHUFFLETEAMS }; +enum { MCMD_KICK = 0, MCMD_BAN, MCMD_REMBANS, MCMD_MASTERMODE, MCMD_AUTOTEAM }; #define DMF 16.0f #define DAF 1.0f diff --git a/source/src/protos.h b/source/src/protos.h index b00bc2ea..3ac9244b 100644 --- a/source/src/protos.h +++ b/source/src/protos.h @@ -98,6 +98,7 @@ extern void updateworld(int curtime, int lastmillis); extern void startmap(char *name); extern void changemap(char *name); extern void initclient(); +extern void playerdeath(playerent *pl); extern void spawnplayer(playerent *d); extern void selfdamage(int damage, int actor, playerent *act, bool gib = false, playerent *pl = player1); extern playerent *newplayerent(); diff --git a/source/src/renderextras.cpp b/source/src/renderextras.cpp index 793c03e3..1600b052 100644 --- a/source/src/renderextras.cpp +++ b/source/src/renderextras.cpp @@ -452,7 +452,7 @@ void gl_drawhud(int w, int h, int curfps, int nquads, int curvert, bool underwat // big flag icon flaginfo &f = flaginfos[team_opposite(team_int(player1->team))]; - if(f.state==CTFF_STOLEN && f.actor == player1) + if(f.state==CTFF_STOLEN && f.actor == player1 && f.ack) { glPushMatrix(); glOrtho(0, VIRTW/2, VIRTH/2, 0, -1, 1); diff --git a/source/src/server.cpp b/source/src/server.cpp index 5499eb78..7c5596a5 100644 --- a/source/src/server.cpp +++ b/source/src/server.cpp @@ -439,8 +439,22 @@ void resetvotes() loopv(clients) clients[i]->mapvote[0] = 0; }; +void shuffleteams() +{ + int numplayers = numclients(); + int teamsize[2] = {0, 0}; + loopv(clients) if(clients[i]->type!=ST_EMPTY) + { + int team = rnd(2); + if(teamsize[team] > numplayers/2) team = team_opposite(team); + sendf(i, 1, "rii", SV_FORCETEAM, team); + teamsize[team]++; + }; +}; + void resetmap(const char *newname, int newmode, int newtime = -1, bool notify = true) { + bool lastteammode = m_teammode; smode = newmode; minremain = newtime >= 0 ? newtime : (m_teammode ? 15 : 10); s_strcpy(smapname, newname); @@ -454,6 +468,7 @@ void resetmap(const char *newname, int newmode, int newtime = -1, bool notify = resetscores(); ctfreset(); if(notify) sendf(-1, 1, "risi", SV_MAPCHANGE, smapname, smode); + if(m_teammode && !lastteammode) shuffleteams(); }; void nextcfgset(bool notify = true) // load next maprotation set @@ -514,19 +529,6 @@ bool isbanned(int cn) return false; }; -void shuffleteams() -{ - int numplayers = numclients(); - int teamsize[2] = {0, 0}; - loopv(clients) if(clients[i]->type!=ST_EMPTY) - { - int team = rnd(2); - if(teamsize[team] > numplayers/2) team = team_opposite(team); - sendf(i, 1, "rii", SV_FORCETEAM, team); - teamsize[team]++; - }; -}; - int master() { loopv(clients) if(clients[i]->type!=ST_EMPTY && clients[i]->ismaster) return i; @@ -555,57 +557,45 @@ void setmaster(int client, bool claim, char *pwd = NULL) }; }; -void mastercmd(int sender, int cmd, int a) +bool mastercmd(int sender, int cmd, int a) { - if(!isdedicated) return; - if(clients[sender]->ismaster==false) return; + if(!isdedicated || clients[sender]->ismaster==false) return false; switch(cmd) { case MCMD_KICK: { - if(!valid_client(a)) return; + if(!valid_client(a)) return false; disconnect_client(a, DISC_MKICK); - sendservmsg("player kicked"); break; }; case MCMD_BAN: { - if(!valid_client(a)) return; + if(!valid_client(a)) return false; ban b = { clients[a]->peer->address, lastsec+20*60 }; bans.add(b); disconnect_client(a, DISC_MBAN); - sendservmsg("player banned"); break; }; case MCMD_REMBANS: { if(bans.length()) bans.setsize(0); - sendservmsg("bans removed"); break; }; case MCMD_MASTERMODE: { - if(a < 0 || a >= MM_NUM) return; + if(a < 0 || a >= MM_NUM) return false; mastermode = a; - s_sprintfd(msg)("mastermode set to %i", mastermode); - sendservmsg(msg); break; }; case MCMD_AUTOTEAM: { - if(a < 0 || a > 1) return; - autoteam = a == 1; + if(a < 0 || a > 1) return false; + if((autoteam = a) == 1 && m_teammode) shuffleteams(); sendf(-1, 1, "rii", SV_AUTOTEAM, a); break; }; - case MCMD_SHUFFLETEAMS: - { - if(!m_teammode) return; - shuffleteams(); - sendservmsg("teams were shuffled"); - break; - }; }; + return true; }; int checktype(int type, client *cl) @@ -833,7 +823,7 @@ void process(ENetPacket *packet, int sender, int chan) // sender may be -1 { int cmd = getint(p); int arg = getint(p); - mastercmd(sender, cmd, arg); + if(mastercmd(sender, cmd, arg) && cmd != MCMD_AUTOTEAM) QUEUE_MSG; break; }; diff --git a/source/vcpp/cube.suo b/source/vcpp/cube.suo index dd8d12eb..09df4939 100644 Binary files a/source/vcpp/cube.suo and b/source/vcpp/cube.suo differ