From 675e248a050da8f6bfd89cf83bf35f986aaf2638 Mon Sep 17 00:00:00 2001 From: ac_stef Date: Thu, 11 Sep 2008 16:28:56 +0000 Subject: [PATCH] rewritten flag modes, added non-team ktf mode git-svn-id: svn://svn.code.sf.net/p/actiongame/code/trunk/ac@2521 e016b1c5-ed68-44aa-a2f7-31cac88cffde --- config/defaults.cfg | 3 +- source/src/clientgame.cpp | 97 ++++++------ source/src/clients2c.cpp | 58 ++++---- source/src/entities.cpp | 34 +++-- source/src/entity.h | 1 - source/src/protocol.cpp | 6 +- source/src/protocol.h | 12 +- source/src/protos.h | 9 +- source/src/renderhud.cpp | 12 +- source/src/server.cpp | 301 +++++++++++++++++++++++++------------- 10 files changed, 308 insertions(+), 225 deletions(-) diff --git a/config/defaults.cfg b/config/defaults.cfg index 047bd776..b3512210 100644 --- a/config/defaults.cfg +++ b/config/defaults.cfg @@ -72,7 +72,8 @@ alias lss [ votemap 9 $arg1 ] alias osok [ votemap 10 $arg1 ] alias tosok [ votemap 11 $arg1 ] alias htf [ votemap 13 $arg1 ] -alias ktf [ votemap 14 $arg1 ] +alias tktf [ votemap 14 $arg1 ] +alias ktf [ votemap 15 $arg1 ] //--------------------- editing ------------------------------- diff --git a/source/src/clientgame.cpp b/source/src/clientgame.cpp index c6afd33c..19d85cf5 100644 --- a/source/src/clientgame.cpp +++ b/source/src/clientgame.cpp @@ -351,7 +351,7 @@ void findplayerstart(playerent *d, bool mapcenter, int arenaspawn) loopi(arenaspawn) x = findentity(PLAYERSTART, x+1, type); if(x >= 0) e = &ents[x]; } - else if((m_teammode || m_arena) && !m_ktf) // ktf uses ffa spawns + else if((m_teammode || m_arena) && !(m_ktf || m_tktf)) // ktf uses ffa spawns { loopi(r) spawncycle = findentity(PLAYERSTART, spawncycle+1, type); if(spawncycle >= 0) e = &ents[spawncycle]; @@ -362,7 +362,7 @@ void findplayerstart(playerent *d, bool mapcenter, int arenaspawn) loopi(r) { - spawncycle = m_ktf && numspawn[2] > 5 ? findentity(PLAYERSTART, spawncycle+1, 100) : findentity(PLAYERSTART, spawncycle+1); + spawncycle = (m_ktf || m_tktf) && numspawn[2] > 5 ? findentity(PLAYERSTART, spawncycle+1, 100) : findentity(PLAYERSTART, spawncycle+1); if(spawncycle < 0) continue; float dist = nearestenemy(vec(ents[spawncycle].x, ents[spawncycle].y, ents[spawncycle].z), d->team); if(!e || dist < 0 || (bestdist >= 0 && dist > bestdist)) { e = &ents[spawncycle]; bestdist = dist; } @@ -564,7 +564,7 @@ void preparectf(bool cleanonly=false) f.actor = NULL; f.actor_cn = -1; f.team = i; - f.state = m_ktf ? CTFF_IDLE : CTFF_INBASE; + f.state = m_ktf || m_tktf ? CTFF_IDLE : CTFF_INBASE; } loopv(ents) { @@ -612,7 +612,7 @@ void startmap(const char *name) // called just after a map load showscores(false); intermission = false; minutesremaining = -1; - bool noflags = (m_ctf || m_ktf) && (!numflagspawn[0] || !numflagspawn[1]); + bool noflags = (m_ctf || m_ktf || m_tktf) && (!numflagspawn[0] || !numflagspawn[1]); if(*clientmap) conoutf("game mode is \"%s\"%s", modestr(gamemode, modeacronyms > 0), noflags ? " - \f2but there are no flag bases on this map" : ""); // run once @@ -622,7 +622,7 @@ void startmap(const char *name) // called just after a map load firstrun = false; } // execute mapstart event - if(identexists("mapstartonce")) + if(identexists("mapstartonce")) { execute("mapstartonce"); alias("mapstartonce", ""); // reset after execution (once) @@ -642,88 +642,73 @@ COMMAND(suicide, ARG_NONE); // console and audio feedback -void flagmsg(int flag, int action) +void flagmsg(int flag, int message, int actor, int flagtime) { - if(m_htf && (action == SV_FLAGRETURN || action == SV_FLAGSCORE)) flag = team_opposite(flag); - flaginfo &f = flaginfos[flag]; - if(!f.actor || !f.ack) return; - bool own = flag == team_int(player1->team), firstperson = f.actor == player1; - const char *teamstr = m_ktf ? "the" : own ? "your" : "the enemy"; + playerent *act = getclient(actor); + if(actor != getclientnum() && !act && message != FM_RESET) return; + bool own = flag == team_int(player1->team); + bool firstperson = actor == getclientnum(); + bool teammate = !act ? true : team_int(player1->team) == team_int(act->team); + const char *teamstr = m_ktf || m_tktf ? "the" : own ? "your" : "the enemy"; - switch(action) + switch(message) { - case SV_FLAGPICKUP: - { + case FM_PICKUP: playsound(S_FLAGPICKUP, SP_HIGH); if(firstperson) { conoutf("\f2you got the %sflag", m_ctf ? "enemy " : ""); musicsuggest(M_FLAGGRAB, m_ctf ? 90*1000 : 900*1000, true); } - else conoutf("\f2%s got %s flag", colorname(f.actor), teamstr); + else conoutf("\f2%s got %s flag", colorname(act), teamstr); break; - } - case SV_FLAGDROP: - case SV_FLAGLOST: + case FM_LOST: + case FM_DROP: { - const char *droplost = action == SV_FLAGLOST ? "lost" : "dropped"; + const char *droplost = message == FM_LOST ? "lost" : "dropped"; playsound(S_FLAGDROP, SP_HIGH); if(firstperson) { conoutf("\f2you %s the flag", droplost); musicfadeout(M_FLAGGRAB); } - else conoutf("\f2%s %s %s flag", colorname(f.actor), droplost, teamstr); + else conoutf("\f2%s %s %s flag", colorname(act), droplost, teamstr); break; } - case SV_FLAGRETURN: - { + case FM_RETURN: playsound(S_FLAGRETURN, SP_HIGH); - if(m_ctf) - { - if(firstperson) conoutf("\f2you returned your flag"); - else conoutf("\f2%s returned %s flag", colorname(f.actor), teamstr); - } - else if(m_htf) - { - conoutf("\f2%s failed to score (own team flag not taken)", firstperson ? "you" : colorname(f.actor)); - } - else - { //ktf - conoutf("\f2%s lost the flag", firstperson ? "you" : colorname(f.actor)); - if(firstperson) musicfadeout(M_FLAGGRAB); - } + if(firstperson) conoutf("\f2you returned your flag"); + else conoutf("\f2%s returned %s flag", colorname(act), teamstr); break; - } - case SV_FLAGSCORE: - { - playsound(m_ktf ? S_VOTEPASS : S_FLAGSCORE, SP_HIGH); // need better ktf sound here - if(m_ktf) - { - const char *ta = firstperson ? "you have" : colorname(f.actor); - const char *tb = firstperson ? "" : " has"; - int m = f.stolentime / 60; - if(m) - conoutf("%s%s been keeping the flag for %d minute%s %d seconds now", ta, tb, m, m == 1 ? "" : "s", f.stolentime % 60); - else - conoutf("%s%s been keeping the flag for %d seconds now", ta, tb, f.stolentime); - } - else if(firstperson) + case FM_SCORE: + playsound(S_FLAGSCORE, SP_HIGH); + if(firstperson) { conoutf("\f2you scored"); if(m_ctf) musicfadeout(M_FLAGGRAB); } - else conoutf("\f2%s scored for %s team", colorname(f.actor), (own ? "your" : "the enemy")); + else conoutf("\f2%s scored for %s team", colorname(act), teammate ? "your" : "the enemy"); + break; + case FM_KTFSCORE: + { + playsound(S_VOTEPASS, SP_HIGH); // need better ktf sound here + const char *ta = firstperson ? "you have" : colorname(act); + const char *tb = firstperson ? "" : " has"; + int m = flagtime / 60; + if(m) + conoutf("%s%s been keeping the flag for %d minute%s %d seconds now", ta, tb, m, m == 1 ? "" : "s", flagtime % 60); + else + conoutf("%s%s been keeping the flag for %d seconds now", ta, tb, flagtime); break; } - case SV_FLAGRESET: - { + case FM_SCOREFAIL: // sound? + conoutf("\f2%s failed to score (own team flag not taken)", firstperson ? "you" : colorname(act)); + break; + case FM_RESET: playsound(S_FLAGRETURN, SP_HIGH); conoutf("the server reset the flag"); if(firstperson) musicfadeout(M_FLAGGRAB); break; - } - default: break; } } diff --git a/source/src/clients2c.cpp b/source/src/clients2c.cpp index 3efc3acb..be88f8d3 100644 --- a/source/src/clients2c.cpp +++ b/source/src/clients2c.cpp @@ -538,43 +538,43 @@ void parsemessages(int cn, playerent *d, ucharbuf &p) if(flag<0 || flag>1) return; flaginfo &f = flaginfos[flag]; f.state = getint(p); - int action = getint(p); - int actor = f.state==CTFF_STOLEN || action==SV_FLAGRETURN ? getint(p) : -1; - - switch(f.state) - { - case CTFF_STOLEN: - { - if(action==SV_FLAGSCORE) f.stolentime = getint(p); - flagstolen(flag, action, actor); - break; - } - case CTFF_DROPPED: - { - if(action != SV_FLAGRETURN) - { - short x = (ushort) (getint(p)/DMF); - short y = (ushort) (getint(p)/DMF); - short z = ((ushort) (getint(p)/DMF))-((short)player1->eyeheight); // correct z offset, assumes all players do have the same eyeheight - flagdropped(flag, action, x, y, z); - } - break; - } + switch(f.state) + { + case CTFF_STOLEN: + flagstolen(flag, getint(p)); + break; + case CTFF_DROPPED: + { + short x = (ushort) (getint(p)/DMF); + short y = (ushort) (getint(p)/DMF); + short z = ((ushort) (getint(p)/DMF))-((short)player1->eyeheight); // correct z offset, assumes all players do have the same eyeheight + flagdropped(flag, x, y, z); + break; + } case CTFF_INBASE: - flaginbase(flag, action, actor); + flaginbase(flag); break; case CTFF_IDLE: - flaginbase(flag, action, actor); - f.flagent->spawned = false; - f.ack = true; + flagidle(flag); break; - } + } break; } - case SV_FLAGS: + case SV_FLAGMSG: { - int fcn = getint(p), flags = getint(p); + int flag = getint(p); + int message = getint(p); + int actor = getint(p); + int flagtime = message == FM_KTFSCORE ? getint(p) : -1; + flagmsg(flag, message, actor, flagtime); + break; + } + + case SV_FLAGCNT: + { + int fcn = getint(p); + int flags = getint(p); playerent *p = (fcn == getclientnum() ? player1 : getclient(fcn)); if(p) p->flagscore = flags; break; diff --git a/source/src/entities.cpp b/source/src/entities.cpp index 712c4134..6d6ef607 100644 --- a/source/src/entities.cpp +++ b/source/src/entities.cpp @@ -63,7 +63,7 @@ void renderentities() case CTFF_STOLEN: if(f.actor && f.actor != player1) { - s_sprintfd(path)("pickups/flags/small_%s%s", m_ktf ? "" : team_string(i), m_htf ? "_htf" : m_ktf ? "ktf" : ""); + s_sprintfd(path)("pickups/flags/small_%s%s", m_ktf || m_tktf ? "" : team_string(i), m_htf ? "_htf" : m_ktf || m_tktf ? "ktf" : ""); rendermodel(path, ANIM_FLAG|ANIM_START, 0, 1.1f, vec(f.actor->o).add(vec(0, 0, 0.3f+(sinf(lastmillis/100.0f)+1)/10)), lastmillis/2.5f, 0, 120.0f); } break; @@ -72,7 +72,7 @@ void renderentities() case CTFF_DROPPED: { entity &e = *f.flagent; - s_sprintfd(path)("pickups/flags/%s%s", m_ktf ? "" : team_string(i), m_htf ? "_htf" : m_ktf ? "ktf" : ""); + s_sprintfd(path)("pickups/flags/%s%s", m_ktf || m_tktf ? "" : team_string(i), m_htf ? "_htf" : m_ktf || m_tktf ? "ktf" : ""); rendermodel(path, ANIM_FLAG|ANIM_LOOP, 0, 4, vec(e.x, e.y, f.state==CTFF_INBASE ? (float)S(e.x, e.y)->floor : e.z), (float)((e.attr1+7)-(e.attr1+7)%15), 0, 120.0f); break; } @@ -162,9 +162,9 @@ void trypickupflag(int flag, playerent *d) if(f.state == CTFF_DROPPED) flagscore(f.team); // may not count! } } - else if(m_ktf) + else if(m_ktf || m_tktf) { - if(f.state == CTFF_IDLE) return; + if(f.state != CTFF_INBASE) return; flagpickup(flag); } } @@ -317,7 +317,7 @@ void flagpickup(int fln) f.actor = player1; // do this although we don't know if we picked the flag to avoid getting it after a possible respawn f.actor_cn = getclientnum(); f.ack = false; - addmsg(SV_FLAGPICKUP, "ri", f.team); + addmsg(SV_FLAGACTION, "rii", FA_PICKUP, f.team); } void tryflagdrop(bool manual) @@ -331,7 +331,7 @@ void tryflagdrop(bool manual) f.state = CTFF_DROPPED; f.ack = false; flagdropmillis = lastmillis+3000; - addmsg(manual ? SV_FLAGDROP : SV_FLAGLOST, "ri", f.team); + addmsg(SV_FLAGACTION, "rii", manual ? FA_DROP : FA_LOST, f.team); } } } @@ -341,19 +341,19 @@ void flagreturn(int fln) flaginfo &f = flaginfos[fln]; f.flagent->spawned = false; f.ack = false; - addmsg(SV_FLAGRETURN, "ri", f.team); + addmsg(SV_FLAGACTION, "rii", FA_RETURN, f.team); } void flagscore(int fln) { flaginfo &f = flaginfos[fln]; f.ack = false; - addmsg(SV_FLAGSCORE, "ri", fln); + addmsg(SV_FLAGACTION, "rii", FA_SCORE, f.team); } // flag ent actions from the net -void flagstolen(int flag, int action, int act) +void flagstolen(int flag, int act) { playerent *actor = act == getclientnum() ? player1 : getclient(act); if(!actor) return; @@ -362,10 +362,9 @@ void flagstolen(int flag, int action, int act) f.actor_cn = act; f.flagent->spawned = false; f.ack = true; - flagmsg(flag, action); } -void flagdropped(int flag, int action, short x, short y, short z) +void flagdropped(int flag, short x, short y, short z) { flaginfo &f = flaginfos[flag]; if(OUTBORD(x, y)) return; // valid pos @@ -396,19 +395,22 @@ void flagdropped(int flag, int action, short x, short y, short z) if(f.flagent->z < hdr.waterlevel) f.flagent->z = (short) hdr.waterlevel; f.flagent->spawned = true; f.ack = true; - flagmsg(flag, action); } -void flaginbase(int flag, int action, int act) +void flaginbase(int flag) { flaginfo &f = flaginfos[flag]; - playerent *actor = act == getclientnum() ? player1 : getclient(act); - if(actor) { f.actor = actor; f.actor_cn = act; } + f.actor = NULL; f.actor_cn = -1; f.flagent->x = (ushort) f.originalpos.x; f.flagent->y = (ushort) f.originalpos.y; f.flagent->z = (ushort) f.originalpos.z; f.flagent->spawned = true; f.ack = true; - flagmsg(flag, action); +} + +void flagidle(int flag) +{ + flaginbase(flag); + flaginfos[flag].flagent->spawned = false; } diff --git a/source/src/entity.h b/source/src/entity.h index 93ae9c7e..52369899 100644 --- a/source/src/entity.h +++ b/source/src/entity.h @@ -476,7 +476,6 @@ struct flaginfo vec originalpos; int state; // one of CTFF_* bool ack; - int stolentime; flaginfo() : flagent(0), actor(0), state(CTFF_INBASE), ack(false) {} }; diff --git a/source/src/protocol.cpp b/source/src/protocol.cpp index 14f479a9..b97cf9ac 100644 --- a/source/src/protocol.cpp +++ b/source/src/protocol.cpp @@ -97,13 +97,13 @@ const char *modefullnames[] = { "team deathmatch", "coopedit", "deathmatch", "survivor", "team survivor", "ctf", "pistol frenzy", "bot team deathmatch", "bot deathmatch", "last swiss standing", - "one shot, one kill", "team one shot, one kill", "bot one shot, one kill", "hunt the flag", "keep the flag" + "one shot, one kill", "team one shot, one kill", "bot one shot, one kill", "hunt the flag", "team keep the flag", "keep the flag" }; const char *modeacronymnames[] = { "TDM", "coop", "DM", "SURV", "TSURV", "CTF", "PF", "BTDM", "BDM", "LSS", - "OSOK", "TOSOK", "BOSOK", "HTF", "CTF" + "OSOK", "TOSOK", "BOSOK", "HTF", "TKTF", "KTF" }; const char *voteerrors[] = { "voting is currently disabled", "there is already a vote pending", "already voted", "can't vote that often", "this vote is not allowed in the current environment (singleplayer/multiplayer)", "no permission", "invalid vote" }; @@ -125,7 +125,7 @@ char msgsizesl[] = // size inclusive message token, 0 for variable SV_EDITMODE, 2, SV_EDITH, 7, SV_EDITT, 7, SV_EDITS, 6, SV_EDITD, 6, SV_EDITE, 6, SV_SENDMAP, 0, SV_RECVMAP, 1, SV_SERVMSG, 0, SV_ITEMLIST, 0, SV_WEAPCHANGE, 2, SV_PRIMARYWEAP, 2, SV_MODELSKIN, 2, - SV_FLAGPICKUP, 2, SV_FLAGDROP, 2, SV_FLAGLOST, 2, SV_FLAGRETURN, 2, SV_FLAGSCORE, 2, SV_FLAGRESET, 2, SV_FLAGINFO, 0, SV_FLAGS, 3, + SV_FLAGACTION, 3, SV_FLAGINFO, 0, SV_FLAGMSG, 0, SV_FLAGCNT, 3, SV_ARENAWIN, 2, SV_SETADMIN, 0, SV_SERVOPINFO, 3, SV_CALLVOTE, 0, SV_CALLVOTESUC, 1, SV_CALLVOTEERR, 2, SV_VOTE, 2, SV_VOTERESULT, 2, diff --git a/source/src/protocol.h b/source/src/protocol.h index 7140c160..c9a9b2a5 100644 --- a/source/src/protocol.h +++ b/source/src/protocol.h @@ -23,7 +23,7 @@ enum SV_EDITMODE, SV_EDITH, SV_EDITT, SV_EDITS, SV_EDITD, SV_EDITE, SV_SENDMAP, SV_RECVMAP, SV_SERVMSG, SV_ITEMLIST, SV_WEAPCHANGE, SV_PRIMARYWEAP, SV_MODELSKIN, - SV_FLAGPICKUP, SV_FLAGDROP, SV_FLAGLOST, SV_FLAGRETURN, SV_FLAGSCORE, SV_FLAGRESET, SV_FLAGINFO, SV_FLAGS, + SV_FLAGACTION, SV_FLAGINFO, SV_FLAGMSG, SV_FLAGCNT, SV_ARENAWIN, SV_SETADMIN, SV_SERVOPINFO, SV_CALLVOTE, SV_CALLVOTESUC, SV_CALLVOTEERR, SV_VOTE, SV_VOTERESULT, @@ -41,6 +41,8 @@ enum { VOTE_NEUTRAL = 0, VOTE_YES, VOTE_NO, VOTE_NUM }; enum { VOTEE_DISABLED = 0, VOTEE_CUR, VOTEE_MUL, VOTEE_MAX, VOTEE_AREA, VOTEE_PERMISSION, VOTEE_INVALID, VOTEE_NUM }; enum { MM_OPEN, MM_PRIVATE, MM_NUM }; enum { AT_DISABLED = 0, AT_ENABLED, AT_SHUFFLE, AT_NUM }; +enum { FA_PICKUP = 0, FA_DROP, FA_LOST, FA_RETURN, FA_SCORE, FA_NUM, FA_RESET }; +enum { FM_PICKUP = 0, FM_DROP, FM_LOST, FM_RETURN, FM_SCORE, FM_KTFSCORE, FM_SCOREFAIL, FM_RESET, FM_NUM }; #define DMF 16.0f #define DNF 100.0f @@ -75,6 +77,7 @@ enum GMODE_TEAMONESHOTONEKILL, GMODE_BOTONESHOTONEKILL, GMODE_HUNTTHEFLAG, // 13 + GMODE_TEAMKEEPTHEFLAG, GMODE_KEEPTHEFLAG }; @@ -84,7 +87,8 @@ enum #define m_lss (gamemode==9) #define m_osok (gamemode>=10 && gamemode<=12) #define m_htf (gamemode==13) -#define m_ktf (gamemode==14) +#define m_tktf (gamemode==14) +#define m_ktf (gamemode==15) #define m_noitems (m_lms || m_osok) #define m_noitemsnade (m_lss) @@ -95,7 +99,7 @@ enum #define m_teammode (gamemode==0 || gamemode==4 || gamemode==5 || gamemode==7 || gamemode==11 || gamemode==13 || gamemode==14) #define m_tarena (m_arena && m_teammode) #define m_botmode (gamemode==7 || gamemode == 8 || gamemode==12) -#define m_valid(mode) (((mode)>=0 && (mode)<=14) || (mode) == -3) +#define m_valid(mode) (((mode)>=0 && (mode)<=15) || (mode) == -3) #define m_mp(mode) (m_valid(mode) && (mode)!=7 && (mode)!=8 && (mode)!=12) #define m_demo (gamemode==-3) -#define m_flags (m_ctf || m_htf || m_ktf) +#define m_flags (m_ctf || m_htf || m_ktf || m_tktf) diff --git a/source/src/protos.h b/source/src/protos.h index 0ab5d611..acf877f0 100644 --- a/source/src/protos.h +++ b/source/src/protos.h @@ -310,10 +310,11 @@ extern void flagpickup(int fln); extern void tryflagdrop(bool manual = false); extern void flagreturn(int fln); extern void flagscore(int fln); -extern void flagstolen(int flag, int action, int act); -extern void flagdropped(int flag, int action, short x, short y, short z); -extern void flaginbase(int flag, int action, int act); -extern void flagmsg(int flag, int action); +extern void flagstolen(int flag, int act); +extern void flagdropped(int flag, short x, short y, short z); +extern void flaginbase(int flag); +extern void flagidle(int flag); +extern void flagmsg(int flag, int message, int actor, int flagtime); extern void arenarespawn(); extern bool tryrespawn(); extern void findplayerstart(playerent *d, bool mapcenter=false, int arenaspawn=-1); diff --git a/source/src/renderhud.cpp b/source/src/renderhud.cpp index d382ad18..a0b8262d 100644 --- a/source/src/renderhud.cpp +++ b/source/src/renderhud.cpp @@ -42,7 +42,7 @@ void drawctficon(float x, float y, float s, int col, int row, float ts) { if(htftex) drawicon(htftex, x, y, s, col, row, ts); } - else if(m_ktf) + else if(m_ktf || m_tktf) { if(ktftex) drawicon(ktftex, x, y, s, col, row, ts); } @@ -355,16 +355,16 @@ void drawradar(playerent *p, int w, int h) entity *e = f.flagent; if(!e) continue; float yaw = showmap ? 0 : p->yaw; - if(m_ktf && f.state == CTFF_IDLE) continue; + if((m_ktf || m_tktf) && f.state == CTFF_IDLE) continue; if(f.state==CTFF_STOLEN) { bool tm = i != team_int(p->team); if(m_htf) tm = !tm; - else if(m_ktf) tm = true; + else if(m_ktf || m_tktf) tm = true; if(f.actor && tm && insideradar(centerpos, res/2, f.actor->o)) - drawradarent(f.actor->o.x*coordtrans+iconsize/2, f.actor->o.y*coordtrans+iconsize/2, yaw, 3, m_ktf ? 2 : f.team, iconsize, true); // draw near flag thief + drawradarent(f.actor->o.x*coordtrans+iconsize/2, f.actor->o.y*coordtrans+iconsize/2, yaw, 3, m_ktf || m_tktf ? 2 : f.team, iconsize, true); // draw near flag thief } - else if(insideradar(centerpos, res/2, vec(e->x, e->y, centerpos.z))) drawradarent(e->x*coordtrans, e->y*coordtrans, yaw, 3, m_ktf ? 2 : f.team, iconsize, false); // draw on entitiy pos + else if(insideradar(centerpos, res/2, vec(e->x, e->y, centerpos.z))) drawradarent(e->x*coordtrans, e->y*coordtrans, yaw, 3, m_ktf || m_tktf ? 2 : f.team, iconsize, false); // draw on entitiy pos } } @@ -549,7 +549,7 @@ void gl_drawhud(int w, int h, int curfps, int nquads, int curvert, bool underwat { glColor4f(1.0f, 1.0f, 1.0f, (sinf(lastmillis/100.0f)+1.0f) / 2.0f); glEnable(GL_BLEND); - drawctficon(VIRTW-225-10, VIRTH*5/8, 225, m_ktf ? team_int(p->team) : ft, 1, 1/2.0f); + drawctficon(VIRTW-225-10, VIRTH*5/8, 225, m_ktf || m_tktf ? team_int(p->team) : ft, 1, 1/2.0f); glDisable(GL_BLEND); } } diff --git a/source/src/server.cpp b/source/src/server.cpp index 3c1fc6d7..44c56a46 100644 --- a/source/src/server.cpp +++ b/source/src/server.cpp @@ -824,7 +824,7 @@ struct sflaginfo int stolentime; } sflaginfos[2]; -void sendflaginfo(int flag, int action, int cn = -1) +void sendflaginfo(int flag, int cn = -1) { sflaginfo &f = sflaginfos[flag]; ENetPacket *packet = enet_packet_create(NULL, MAXTRANS, ENET_PACKET_FLAG_RELIABLE); @@ -832,105 +832,179 @@ void sendflaginfo(int flag, int action, int cn = -1) putint(p, SV_FLAGINFO); putint(p, flag); putint(p, f.state); - putint(p, action); - if(f.state==CTFF_STOLEN || action==SV_FLAGRETURN) putint(p, f.actor_cn); - else if(f.state==CTFF_DROPPED) loopi(3) putint(p, int(f.pos[i]*DMF)); - if(f.state==CTFF_STOLEN && action==SV_FLAGSCORE) putint(p, (gamemillis - f.stolentime) / 1000); + switch(f.state) + { + case CTFF_STOLEN: + putint(p, f.actor_cn); + break; + case CTFF_DROPPED: + loopi(3) putint(p, int(f.pos[i]*DMF)); + break; + } enet_packet_resize(packet, p.length()); sendpacket(cn, 1, packet); if(packet->referenceCount==0) enet_packet_destroy(packet); } -void flagaction(int flag, int action, int sender) +void flagmessage(int flag, int message, int actor, int cn = -1) +{ + if(message == FM_KTFSCORE) + sendf(cn, 1, "riiiii", SV_FLAGMSG, flag, message, actor, (gamemillis - sflaginfos[flag].stolentime) / 1000); + else + sendf(cn, 1, "riiii", SV_FLAGMSG, flag, message, actor); +} + +void flagaction(int flag, int action, int actor) { if(!valid_flag(flag)) return; sflaginfo &f = sflaginfos[flag]; sflaginfo &of = sflaginfos[team_opposite(flag)]; - bool ktf_switch = false; - switch(action) - { - case SV_FLAGPICKUP: - { - if(f.state == CTFF_STOLEN) return; - f.state = CTFF_STOLEN; - f.actor_cn = sender; - f.stolentime = gamemillis; - logger->writeline(log::info,"[%s] %s stole the flag", clients[sender]->hostname, clients[sender]->name); - break; - } - case SV_FLAGDROP: - case SV_FLAGLOST: - { - if(f.state!=CTFF_STOLEN || (sender != -1 && f.actor_cn != sender)) return; - ktf_switch = true; - f.state = CTFF_DROPPED; - loopi(3) f.pos[i] = clients[f.actor_cn]->state.o[i]; - logger->writeline(log::info,"[%s] %s %s the flag", clients[f.actor_cn]->hostname, clients[f.actor_cn]->name, action == SV_FLAGLOST ? "lost" : "dropped"); - break; - } - case SV_FLAGRETURN: - { - if(f.state!=CTFF_DROPPED) return; - f.state = CTFF_INBASE; - f.actor_cn = sender; - logger->writeline(log::info,"[%s] %s returned the flag", clients[sender]->hostname, clients[sender]->name); - break; - } - case SV_FLAGRESET: - { - if(sender != -1 && f.actor_cn != sender) return; - ktf_switch = true; - f.state = CTFF_INBASE; - logger->writeline(log::info,"The server reset the flag"); - break; - } - case SV_FLAGSCORE: - { - bool score = true; - if(m_ctf) - { //ctf f: actor carrying, of: unstolen own - if(f.state != CTFF_STOLEN || f.actor_cn != sender || of.state != CTFF_INBASE) return; - f.state = CTFF_INBASE; - } - else if(m_htf) - { //htf of: own team carrying, f: other team dropped - if(f.state != CTFF_DROPPED) return; - f.state = CTFF_INBASE; - if(of.state != CTFF_STOLEN) - { - action = SV_FLAGRETURN; - score = false; // sry, fail - } - } - if(score) - { - clients[sender]->state.flagscore += 1; - sendf(-1, 1, "riii", SV_FLAGS, sender, clients[sender]->state.flagscore); - logger->writeline(log::info, "[%s] %s scored with the flag for %s, new score %d", clients[sender]->hostname, clients[sender]->name, clients[sender]->team, clients[sender]->state.flagscore); - } - else - { - logger->writeline(log::info, "[%s] %s failed to score", clients[sender]->hostname, clients[sender]->name); - } - break; - } - default: return; - } - if(m_ktf && ktf_switch) + bool deadactor = valid_client(actor) ? clients[actor]->state.state != CS_ALIVE : true; + bool score = false; + int message = -1; + + if(m_ctf || m_htf) { - f.state = CTFF_IDLE; - of.state = CTFF_INBASE; - sendflaginfo(team_opposite(flag), 0); - action = SV_FLAGRETURN; + switch(action) + { + case FA_PICKUP: // ctf: f = enemy team htf: f = own team + { + if(deadactor || f.state == CTFF_STOLEN) return; + int team = team_int(clients[actor]->team); + if(m_ctf) team = team_opposite(team); + if(team != flag) return; + f.state = CTFF_STOLEN; + f.actor_cn = actor; + message = FM_PICKUP; + break; + } + case FA_LOST: + if(actor == -1) actor = f.actor_cn; + case FA_DROP: + if(f.state!=CTFF_STOLEN || f.actor_cn != actor) return; + f.state = CTFF_DROPPED; + loopi(3) f.pos[i] = clients[actor]->state.o[i]; + message = action == FA_LOST ? FM_LOST : FM_DROP; + break; + case FA_RETURN: + if(f.state!=CTFF_DROPPED || m_htf) return; + f.state = CTFF_INBASE; + message = FM_RETURN; + break; + case FA_SCORE: // ctf: f = carried by actor flag, htf: f = hunted flag (run over by actor) + if(m_ctf) + { + if(f.state != CTFF_STOLEN || f.actor_cn != actor || of.state != CTFF_INBASE) return; + score = true; + message = FM_SCORE; + } + else // m_htf + { + if(f.state != CTFF_DROPPED) return; + score = of.state == CTFF_STOLEN; + message = score ? FM_SCORE : FM_SCOREFAIL; + } + f.state = CTFF_INBASE; + break; + + case FA_RESET: + f.state = CTFF_INBASE; + message = FM_RESET; + break; + } + } + else if(m_ktf || m_tktf) // f: active flag, of: idle flag + { + switch(action) + { + case FA_PICKUP: + if(deadactor || f.state != CTFF_INBASE) return; + f.state = CTFF_STOLEN; + f.actor_cn = actor; + f.stolentime = gamemillis; + message = FM_PICKUP; + break; + case FA_SCORE: // f = carried by actor flag + if(actor != -1 || f.state != CTFF_STOLEN) return; // no client msg allowed here + if(valid_client(f.actor_cn) && clients[f.actor_cn]->state.state == CS_ALIVE) + { + actor = f.actor_cn; + score = true; + message = FM_KTFSCORE; + break; + } + case FA_LOST: + if(actor == -1) actor = f.actor_cn; + case FA_DROP: + if(f.actor_cn != actor || f.state != CTFF_STOLEN) return; + case FA_RESET: + if(f.state == CTFF_STOLEN) + { + actor = f.actor_cn; + message = FM_LOST; + } + f.state = CTFF_IDLE; + of.state = CTFF_INBASE; + sendflaginfo(team_opposite(flag)); + break; + } + } + if(score) + { + clients[actor]->state.flagscore += 1; + sendf(-1, 1, "riii", SV_FLAGCNT, actor, clients[actor]->state.flagscore); + } + if(valid_client(actor)) + { + client &c = *clients[actor]; + switch(message) + { + case FM_PICKUP: + logger->writeline(log::info,"[%s] %s stole the flag", c.hostname, c.name); + break; + case FM_DROP: + case FM_LOST: + logger->writeline(log::info,"[%s] %s %s the flag", c.hostname, c.name, message == FM_LOST ? "lost" : "dropped"); + break; + case FM_RETURN: + logger->writeline(log::info,"[%s] %s returned the flag", c.hostname, c.name); + break; + case FM_SCORE: + logger->writeline(log::info, "[%s] %s scored with the flag for %s, new score %d", c.hostname, c.name, c.team, c.state.flagscore); + break; + case FM_KTFSCORE: + logger->writeline(log::info, "[%s] %s scored, carrying for %d seconds, new score %d", c.hostname, c.name, (gamemillis - f.stolentime) / 1000, c.state.flagscore); + break; + case FM_SCOREFAIL: + logger->writeline(log::info, "[%s] %s failed to score", c.hostname, c.name); + break; + default: + logger->writeline(log::info, "flagaction %d, actor %d, flag %d, message %d", action, actor, flag, message); + break; + } + } + else + { + switch(message) + { + case FM_RESET: + logger->writeline(log::info,"the server reset the flag for team %s", team_string(flag)); + break; + default: + logger->writeline(log::info, "flagaction %d with invalid actor cn %d, flag %d, message %d", action, actor, flag, message); + break; + } } f.lastupdate = gamemillis; - sendflaginfo(flag, action); + sendflaginfo(flag); + if(message >= 0) + flagmessage(flag, message, valid_client(actor) ? actor : -1); } void ctfreset() { - int idleflag = m_ktf ? rnd(2) : -1; + int idleflag = m_ktf || m_tktf ? rnd(2) : -1; loopi(2) { sflaginfos[i].actor_cn = -1; @@ -968,7 +1042,8 @@ void htf_forceflag(int flag) { f.state = CTFF_STOLEN; f.actor_cn = i; - sendflaginfo(flag, SV_FLAGPICKUP); + sendflaginfo(flag); + flagmessage(flag, FM_PICKUP, i); logger->writeline(log::info,"[%s] %s got forced to pickup the flag", clients[i]->hostname, clients[i]->name); break; } @@ -1250,10 +1325,10 @@ void serverdamage(client *target, client *actor, int damage, int gun, bool gib, suic = true; } sendf(-1, 1, "ri4", gib ? SV_GIBDIED : SV_DIED, target->clientnum, actor->clientnum, actor->state.frags); - if((suic || flagtk) && (m_htf || m_ktf) && targethasflag >= 0) + if((suic || flagtk) && (m_htf || m_ktf || m_tktf) && targethasflag >= 0) { actor->state.flagscore--; - sendf(-1, 1, "riii", SV_FLAGS, actor->clientnum, actor->state.flagscore); + sendf(-1, 1, "riii", SV_FLAGCNT, actor->clientnum, actor->state.flagscore); } target->position.setsizenodelete(0); ts.state = CS_DEAD; @@ -1262,11 +1337,11 @@ void serverdamage(client *target, client *actor, int damage, int gun, bool gib, if(m_flags && targethasflag >= 0) { if(m_ctf) - flagaction(targethasflag, flagtk ? SV_FLAGRESET : SV_FLAGLOST, -1); + flagaction(targethasflag, flagtk ? FA_RESET : FA_LOST, -1); else if(m_htf) - flagaction(targethasflag, SV_FLAGLOST, -1); - else // ktf - flagaction(targethasflag, SV_FLAGRESET, -1); + flagaction(targethasflag, FA_LOST, -1); + else // ktf || tktf + flagaction(targethasflag, FA_RESET, -1); } // don't issue respawn yet until DEATHMILLIS has elapsed // ts.respawn(); @@ -1421,7 +1496,7 @@ void readblacklist(const char *name) } delete[] buf; blacklist.sort(cmpiprange); - if(verbose) + if(verbose) { loopv(blacklist) { @@ -1730,7 +1805,7 @@ void resetmap(const char *newname, int newmode, int newtime, bool notify) demonextmatch = false; setupdemorecord(); } - if(m_ktf) { sendflaginfo(0, 0); sendflaginfo(1, 0); } + if(m_ktf || m_tktf) { sendflaginfo(0); sendflaginfo(1); } } void nextcfgset(bool notify = true) // load next maprotation set @@ -1920,7 +1995,14 @@ const char *disc_reason(int reason) void disconnect_client(int n, int reason) { if(!clients.inrange(n) || clients[n]->type!=ST_TCPIP) return; - if(m_flags) loopi(2) if(sflaginfos[i].state==CTFF_STOLEN && sflaginfos[i].actor_cn==n) flagaction(i, SV_FLAGLOST, n); + if(m_flags) + { + loopi(2) + { + if(sflaginfos[i].state==CTFF_STOLEN && sflaginfos[i].actor_cn==n) + flagaction(i, FA_LOST, n); + } + } client &c = *clients[n]; savedscore *sc = findscore(c, true); if(sc) sc->save(c.state); @@ -2176,7 +2258,12 @@ int checktype(int type, client *cl) static int edittypes[] = { SV_EDITENT, SV_EDITH, SV_EDITT, SV_EDITS, SV_EDITD, SV_EDITE }; if(cl && smode!=1) loopi(sizeof(edittypes)/sizeof(int)) if(type == edittypes[i]) return -1; // server only messages - static int servtypes[] = { SV_INITS2C, SV_MAPRELOAD, SV_SERVMSG, SV_GIBDAMAGE, SV_DAMAGE, SV_HITPUSH, SV_SHOTFX, SV_DIED, SV_SPAWNSTATE, SV_FORCEDEATH, SV_ITEMACC, SV_ITEMSPAWN, SV_TIMEUP, SV_CDIS, SV_PONG, SV_RESUME, SV_FLAGINFO, SV_ARENAWIN, SV_SENDDEMOLIST, SV_SENDDEMO, SV_DEMOPLAYBACK, SV_CLIENT, SV_CALLVOTESUC, SV_CALLVOTEERR, SV_VOTERESULT, SV_WHOISINFO, SV_FLAGS, SV_FLAGRESET }; + static int servtypes[] = { SV_INITS2C, SV_MAPRELOAD, SV_SERVMSG, SV_GIBDAMAGE, SV_DAMAGE, + SV_HITPUSH, SV_SHOTFX, SV_DIED, SV_SPAWNSTATE, SV_FORCEDEATH, SV_ITEMACC, + SV_ITEMSPAWN, SV_TIMEUP, SV_CDIS, SV_PONG, SV_RESUME, + SV_FLAGINFO, SV_FLAGMSG, SV_FLAGCNT, + SV_ARENAWIN, SV_SENDDEMOLIST, SV_SENDDEMO, SV_DEMOPLAYBACK, SV_CLIENT, + SV_CALLVOTESUC, SV_CALLVOTEERR, SV_VOTERESULT, SV_WHOISINFO }; if(cl) loopi(sizeof(servtypes)/sizeof(int)) if(type == servtypes[i]) return -1; return type; } @@ -2249,7 +2336,10 @@ void process(ENetPacket *packet, int sender, int chan) // sender may be -1 welcomepacket(p, sender); enet_packet_resize(packet, p.length()); sendpacket(sender, 1, packet); - if(smapname[0] && m_flags) loopi(2) sendflaginfo(i, -1, sender); + if(smapname[0] && m_flags) + { + loopi(2) sendflaginfo(i, sender); + } if(clientrole != CR_DEFAULT) changeclientrole(sender, clientrole, NULL, true); } @@ -2552,15 +2642,13 @@ void process(ENetPacket *packet, int sender, int chan) // sender may be -1 break; } - case SV_FLAGPICKUP: - case SV_FLAGDROP: - case SV_FLAGLOST: - case SV_FLAGRETURN: - case SV_FLAGSCORE: - case SV_FLAGRESET: + case SV_FLAGACTION: { if(!m_flags) { disconnect_client(sender, DISC_TAGT); return; } - flagaction(getint(p), type, sender); + int action = getint(p); + int flag = getint(p); + if(flag < 0 || flag > 1 || action < 0 || action > FA_NUM) return; + flagaction(flag, action, sender); break; } @@ -2791,19 +2879,22 @@ void serverslice(uint timeout) // main server update, called from cube main lo { processevents(); checkitemspawns(diff); + bool ktfflagingame = false; if(m_flags) loopi(2) { sflaginfo &f = sflaginfos[i]; - if(f.state == CTFF_DROPPED && gamemillis-f.lastupdate > (m_ctf ? 30000 : 10000)) flagaction(i, SV_FLAGRESET, -1); + if(f.state == CTFF_DROPPED && gamemillis-f.lastupdate > (m_ctf ? 30000 : 10000)) flagaction(i, FA_RESET, -1); if(m_htf && f.state == CTFF_INBASE && gamemillis-f.lastupdate > (clnumflagspawn[0] && clnumflagspawn[1] ? 10000 : 1000)) { htf_forceflag(i); } - if(m_ktf && f.state == CTFF_STOLEN && gamemillis-f.lastupdate > 15000) + if((m_ktf || m_tktf) && f.state == CTFF_STOLEN && gamemillis-f.lastupdate > 15000) { - flagaction(i, SV_FLAGSCORE, f.actor_cn); + flagaction(i, FA_SCORE, -1); } + if(f.state == CTFF_INBASE || f.state == CTFF_STOLEN) ktfflagingame = true; } + if((m_ktf || m_tktf) && !ktfflagingame) flagaction(rnd(2), FA_RESET, -1); // ktf flag watchdog if(m_arena) arenacheck(); }