From aab03618a5f4a2782ae123932f524fba2b198c77 Mon Sep 17 00:00:00 2001 From: ac_stef Date: Sun, 31 Aug 2008 13:07:28 +0000 Subject: [PATCH] non-overlapping player spawns in arena modes git-svn-id: svn://svn.code.sf.net/p/actiongame/code/trunk/ac@2454 e016b1c5-ed68-44aa-a2f7-31cac88cffde --- source/src/client.cpp | 9 +++-- source/src/clientgame.cpp | 6 ++- source/src/server.cpp | 84 ++++++++++++++++++++++++++++++++++----- 3 files changed, 83 insertions(+), 16 deletions(-) diff --git a/source/src/client.cpp b/source/src/client.cpp index 0aeb20fb..f0611643 100644 --- a/source/src/client.cpp +++ b/source/src/client.cpp @@ -308,9 +308,12 @@ void c2sinfo(playerent *d) // send update to the server if(senditemstoserver) { packet->flags = ENET_PACKET_FLAG_RELIABLE; - putint(p, SV_ITEMLIST); - if(!m_noitems) putitems(p); - putint(p, -1); + if(maploaded > 0) + { + putint(p, SV_ITEMLIST); + if(!m_noitems) putitems(p); + putint(p, -1); + } putint(p, SV_SPAWNLIST); putint(p, maploaded); if(maploaded > 0) loopi(3) putint(p, numspawn[i]); diff --git a/source/src/clientgame.cpp b/source/src/clientgame.cpp index f7b149fc..bcb9fb9f 100644 --- a/source/src/clientgame.cpp +++ b/source/src/clientgame.cpp @@ -340,13 +340,15 @@ void findplayerstart(playerent *d, bool mapcenter, int arenaspawn) entity *e = NULL; if(!mapcenter) { + int type = m_teammode ? team_int(d->team) : 100; if(m_arena && arenaspawn > -1) { - ; // unfinished + int x = -1; + loopi(arenaspawn) x = findentity(PLAYERSTART, x+1, type); + if(x >= 0) e = &ents[x]; } else if(m_teammode || m_arena) { - int type = m_teammode ? team_int(d->team) : 100; loopi(r) spawncycle = findentity(PLAYERSTART, spawncycle+1, type); if(spawncycle >= 0) e = &ents[spawncycle]; } diff --git a/source/src/server.cpp b/source/src/server.cpp index 52722f8c..6e0e56e6 100644 --- a/source/src/server.cpp +++ b/source/src/server.cpp @@ -220,6 +220,7 @@ struct client // server side version of "dynent" type int saychars, lastsay, spamcount; int at3_score, at3_lastforce; bool at3_dontmove; + int spawnindex; gameevent &addevent() { @@ -249,6 +250,7 @@ struct client // server side version of "dynent" type lastvotecall = 0; lastsaytext[0] = '\0'; saychars = 0; + spawnindex = -1; mapchange(); } @@ -549,7 +551,7 @@ void sendspawn(client *c) spawnstate(c); sendf(c->clientnum, 1, "ri7vv", SV_SPAWNSTATE, gs.lifesequence, gs.health, gs.armour, - gs.primary, gs.gunselect, -1, // unfinished + gs.primary, gs.gunselect, m_arena ? c->spawnindex : -1, NUMGUNS, gs.ammo, NUMGUNS, gs.mag); gs.lastspawn = gamemillis; } @@ -911,13 +913,68 @@ bool canspawn(client *c, bool connecting = false) int arenaround = 0; +struct twoint { int index, value; }; +int cmpscore(const void *a, const void * b) { return clients[*((int *)a)]->at3_score - clients[*((int *)b)]->at3_score; } +int cmptwoint(const void *a, const void * b) { return ((struct twoint *)a)->value - ((struct twoint *)b)->value; } +ivector tdistrib; +vector sdistrib; + +void distributeteam(int team) +{ + int numsp = team == 100 ? clnumspawn[2] : clnumspawn[team]; + if(!numsp) numsp = 15; // no map data yet: make a guess + twoint ti; + tdistrib.setsize(0); + loopv(clients) if(clients[i]->type!=ST_EMPTY) + { + if(team == 100 || team == team_int(clients[i]->team)) + { + tdistrib.add(i); + clients[i]->at3_score = rand(); + } + } + tdistrib.sort(cmpscore); // random player order + sdistrib.setsize(0); + loopi(numsp) + { + ti.index = i; + ti.value = rand(); + sdistrib.add(ti); + } + sdistrib.sort(cmptwoint); // random spawn order + int x = 0; + loopv(tdistrib) + { + clients[tdistrib[i]]->spawnindex = sdistrib[x++].index; + x %= sdistrib.length(); + } +} + +void distributespawns() +{ + loopv(clients) if(clients[i]->type!=ST_EMPTY) + { + clients[i]->spawnindex = -1; + } + if(m_teammode) + { + distributeteam(0); + distributeteam(1); + } + else + { + distributeteam(100); + } +} + void arenacheck() { if(!m_arena || interm || gamemillistype!=ST_EMPTY) { clients[i]->state.respawn(); @@ -1293,11 +1350,11 @@ void calcscores() loopv(clients) if (clients[i]->type!=ST_EMPTY) { clients[i]->at3_score = clients[i]->state.frags * 100 / (clients[i]->state.deaths ? clients[i]->state.deaths : 1) - + clients[i]->state.flagscore * (33 + 33 * (clients[i]->state.flagscore < 3)); + + clients[i]->state.flagscore < 3 ? 66 * clients[i]->state.flagscore : 66 + 33 * clients[i]->state.flagscore; } } -int cmpsc(const void *a, const void * b) { return clients[*((int *)a)]->at3_score - clients[*((int *)b)]->at3_score; } +ivector shuffle; void shuffleteams(bool respawn = true) { @@ -1316,12 +1373,13 @@ void shuffleteams(bool respawn = true) else { // skill sorted calcscores(); - int *list = new int[numplayers], t = rnd(2), j = 0; - loopv(clients) if(clients[i]->type!=ST_EMPTY) list[j++] = i; - qsort(list, numplayers, sizeof(int), cmpsc); - loopi(numplayers) + shuffle.setsize(0); + int t = rnd(2); + loopv(clients) if(clients[i]->type!=ST_EMPTY) shuffle.add(i); + shuffle.sort(cmpscore); + loopi(shuffle.length()) { - forceteam(list[i], t, respawn); + forceteam(shuffle[i], t, respawn); t = !t; } } @@ -1439,7 +1497,11 @@ void resetmap(const char *newname, int newmode, int newtime, bool notify) sendf(-1, 1, "risii", SV_MAPCHANGE, smapname, smode, mapavailable(smapname) ? 1 : 0); if(smode>1 || (smode==0 && numnonlocalclients()>0)) sendf(-1, 1, "ri2", SV_TIMEUP, minremain); } - if(m_arena) arenaround = 0; + if(m_arena) + { + arenaround = 0; + distributespawns(); + } if(notify) { // shuffle if previous mode wasn't a team-mode @@ -1834,7 +1896,7 @@ void welcomepacket(ucharbuf &p, int n) putint(p, gs.armour); putint(p, gs.primary); putint(p, gs.gunselect); - putint(p, -1); // unfinished + putint(p, -1); loopi(NUMGUNS) putint(p, gs.ammo[i]); loopi(NUMGUNS) putint(p, gs.mag[i]); gs.lastspawn = gamemillis;