bool targetable(fpsent *d, fpsent *e, bool anyone) { if(d == e || !canmove(d)) return false; aistate &b = d->ai->getstate(); if(b.type != AI_S_WAIT) return e->state == CS_ALIVE && (!anyone || !isteam(d->team, e->team)); return false; }
void renderclients() { Sprite *d; for (int i = 0; i < players.size(); ++i) { if ((d = players[i]) && (!demoplayback || i != democlientnum)) renderclient(d, isteam(player1->team, d->team), "monster/ogro", false, 1.0f); } }
void renderclients() { dynent *d; loopv(players) { if((d = players[i]) && (!demoplayback || i!=democlientnum)) renderclient(d, isteam(player1->team, d->team), "monster/ogro", false, 1.0f, selected_player(i)); } };
bool checkothers(vector<int> &targets, fpsent *d, int state, int targtype, int target, bool teams) { // checks the states of other ai for a match targets.setsizenodelete(0); loopv(players) { fpsent *e = players[i]; if(e == d || !e->ai || e->state != CS_ALIVE) continue; if(targets.find(e->clientnum) >= 0) continue; if(teams && d && !isteam(d->team, e->team)) continue; aistate &b = e->ai->getstate(); if(state >= 0 && b.type != state) continue; if(target >= 0 && b.target != target) continue; if(targtype >=0 && b.targtype != targtype) continue; targets.add(e->clientnum); } return !targets.empty(); }
void renderscoreboard(g3d_gui &g, bool firstpass) { const ENetAddress *address = connectedpeer(); if(showservinfo && address) { string hostname; if(enet_address_get_host_ip(address, hostname, sizeof(hostname)) >= 0) { if(servinfo[0]) g.titlef("%.25s", 0xFFFF80, NULL, servinfo); else g.titlef("%s:%d", 0xFFFF80, NULL, hostname, address->port); } } g.pushlist(0); g.text(server::modename(gamemode), 0xFFFF80); g.separator(); const char *mname = getclientmap(); g.text(mname[0] ? mname : "[new map]", 0xFFFF80); if(m_timed && mname[0] && (maplimit >= 0 || intermission)) { g.separator(); if(intermission) g.text("intermission", 0xFFFF80); else { int secs = max(maplimit-lastmillis, 0)/1000, mins = secs/60; secs %= 60; g.pushlist(); g.strut(mins >= 10 ? 4.5f : 3.5f); g.textf("%d:%02d", 0xFFFF80, NULL, mins, secs); g.poplist(); } } if(paused || ispaused()) { g.separator(); g.text("paused", 0xFFFF80); } g.poplist(); g.separator(); int numgroups = groupplayers(); loopk(numgroups) { if((k%2)==0) g.pushlist(); // horizontal scoregroup &sg = *groups[k]; int bgcolor = sg.team && m_teammode ? (isteam(player1->team, sg.team) ? 0x3030C0 : 0xC03030) : 0, fgcolor = 0xFFFF80; g.pushlist(); // vertical g.pushlist(); // horizontal #define loopscoregroup(o, b) \ loopv(sg.players) \ { \ fpsent *o = sg.players[i]; \ b; \ } g.pushlist(); if(sg.team && m_teammode) { g.pushlist(); g.background(bgcolor, numgroups>1 ? 3 : 5); g.strut(1); g.poplist(); } g.text("", 0, " "); loopscoregroup(o, { if(o==player1 && highlightscore && (multiplayer(false) || demoplayback || players.length() > 1)) { g.pushlist(); g.background(0x808080, numgroups>1 ? 3 : 5); } const playermodelinfo &mdl = getplayermodelinfo(o); const char *icon = sg.team && m_teammode ? (isteam(player1->team, sg.team) ? mdl.blueicon : mdl.redicon) : mdl.ffaicon; g.text("", 0, icon); if(o==player1 && highlightscore && (multiplayer(false) || demoplayback || players.length() > 1)) g.poplist(); }); g.poplist(); if(sg.team && m_teammode) { g.pushlist(); // vertical if(sg.score>=10000) g.textf("%s: WIN", fgcolor, NULL, sg.team); else g.textf("%s: %d", fgcolor, NULL, sg.team, sg.score); g.pushlist(); // horizontal } if(!cmode || !cmode->hidefrags()) { g.pushlist(); g.strut(7); g.text("frags", fgcolor); loopscoregroup(o, g.textf("%d", 0xFFFFDD, NULL, o->frags)); g.poplist(); } if(multiplayer(false) || demoplayback) { if(showpj) { g.pushlist(); g.strut(6); g.text("pj", fgcolor); loopscoregroup(o, { if(o->state==CS_LAGGED) g.text("LAG", 0xFFFFDD); else g.textf("%d", 0xFFFFDD, NULL, o->plag); }); g.poplist(); } if(showping) { g.pushlist(); g.text("ping", fgcolor); g.strut(6); loopscoregroup(o, { fpsent *p = o->ownernum >= 0 ? getclient(o->ownernum) : o; if(!p) p = o; if(!showpj && p->state==CS_LAGGED) g.text("LAG", 0xFFFFDD); else g.textf("%d", 0xFFFFDD, NULL, p->ping); }); g.poplist(); }
bool targetable(fpsent *d, fpsent *e) { if(d == e || !canmove(d)) return false; return e->state == CS_ALIVE && !isteam(d->team, e->team); }
void localservertoclient(uchar *buf, int len) // processes any updates from the server { if(ENET_NET_TO_HOST_16(*(ushort *)buf)!=len) neterr("packet length"); incomingdemodata(buf, len); uchar *end = buf+len; uchar *p = buf+2; char text[MAXTRANS]; int cn = -1, type; dynent *d = NULL; bool mapchanged = false; while(p<end) switch(type = getint(p)) { case SV_INITS2C: // welcome messsage from the server { cn = getint(p); int prot = getint(p); if(prot!=PROTOCOL_VERSION) { conoutf("you are using a different game protocol (you: %d, server: %d)", PROTOCOL_VERSION, prot); disconnect(); return; }; toservermap[0] = 0; clientnum = cn; // we are now fully connected if(!getint(p)) strcpy_s(toservermap, getclientmap()); // we are the first client on this server, set map sgetstr(); if(text[0] && strcmp(text, clientpassword)) { conoutf("you need to set the correct password to join this server!"); disconnect(); return; }; if(getint(p)==1) { conoutf("server is FULL, disconnecting.."); }; break; }; case SV_POS: // position of another client { cn = getint(p); d = getclient(cn); if(!d) return; d->o.x = getint(p)/DMF; d->o.y = getint(p)/DMF; d->o.z = getint(p)/DMF; d->yaw = getint(p)/DAF; d->pitch = getint(p)/DAF; d->roll = getint(p)/DAF; d->vel.x = getint(p)/DVF; d->vel.y = getint(p)/DVF; d->vel.z = getint(p)/DVF; int f = getint(p); d->strafe = (f&3)==3 ? -1 : f&3; f >>= 2; d->move = (f&3)==3 ? -1 : f&3; d->onfloor = (f>>2)&1; int state = f>>3; if(state==CS_DEAD && d->state!=CS_DEAD) d->lastaction = lastmillis; d->state = state; if(!demoplayback) updatepos(d); break; }; case SV_SOUND: playsound(getint(p), &d->o); break; case SV_TEXT: sgetstr(); conoutf("%s:\f %s", d->name, text); break; case SV_MAPCHANGE: sgetstr(); changemapserv(text, getint(p)); mapchanged = true; break; case SV_ITEMLIST: { int n; if(mapchanged) { senditemstoserver = false; resetspawns(); }; while((n = getint(p))!=-1) if(mapchanged) setspawn(n, true); break; }; case SV_MAPRELOAD: // server requests next map { getint(p); sprintf_sd(nextmapalias)("nextmap_%s", getclientmap()); char *map = getalias(nextmapalias); // look up map in the cycle changemap(map ? map : getclientmap()); break; }; case SV_INITC2S: // another client either connected or changed name/team { sgetstr(); if(d->name[0]) // already connected { if(strcmp(d->name, text)) conoutf("%s is now known as %s", d->name, text); } else // new client { c2sinit = false; // send new players my info again conoutf("connected: %s", text); }; strcpy_s(d->name, text); sgetstr(); strcpy_s(d->team, text); d->lifesequence = getint(p); break; }; case SV_CDIS: cn = getint(p); if(!(d = getclient(cn))) break; conoutf("player %s disconnected", d->name[0] ? d->name : "[incompatible client]"); zapdynent(players[cn]); break; case SV_SHOT: { int gun = getint(p); vec s, e; s.x = getint(p)/DMF; s.y = getint(p)/DMF; s.z = getint(p)/DMF; e.x = getint(p)/DMF; e.y = getint(p)/DMF; e.z = getint(p)/DMF; if(gun==GUN_SG) createrays(s, e); shootv(gun, s, e, d); break; }; case SV_DAMAGE: { int target = getint(p); int damage = getint(p); int ls = getint(p); if(target==clientnum) { if(ls==player1->lifesequence) selfdamage(damage, cn, d); } else playsound(S_PAIN1+rnd(5), &getclient(target)->o); break; }; case SV_DIED: { int actor = getint(p); if(actor==cn) { conoutf("%s suicided", d->name); } else if(actor==clientnum) { int frags; if(isteam(player1->team, d->team)) { frags = -1; conoutf("you fragged a teammate (%s)", d->name); } else { frags = 1; conoutf("you fragged %s", d->name); }; addmsg(1, 2, SV_FRAGS, player1->frags += frags); } else { dynent *a = getclient(actor); if(a) { if(isteam(a->team, d->name)) { conoutf("%s fragged his teammate (%s)", a->name, d->name); } else { conoutf("%s fragged %s", a->name, d->name); }; }; }; playsound(S_DIE1+rnd(2), &d->o); d->lifesequence++; break; }; case SV_FRAGS: players[cn]->frags = getint(p); break; case SV_ITEMPICKUP: setspawn(getint(p), false); getint(p); break; case SV_ITEMSPAWN: { uint i = getint(p); setspawn(i, true); if(i>=(uint)ents.length()) break; vec v = { ents[i].x, ents[i].y, ents[i].z }; playsound(S_ITEMSPAWN, &v); break; }; case SV_ITEMACC: // server acknowledges that I picked up this item realpickup(getint(p), player1); break; case SV_PING: getint(p); break; case SV_PONG: addmsg(0, 2, SV_CLIENTPING, player1->ping = (player1->ping*5+lastmillis-getint(p))/6); break; case SV_CLIENTPING: players[cn]->ping = getint(p); break; case SV_GAMEMODE: nextmode = getint(p); break; case SV_TIMEUP: timeupdate(getint(p)); break; case SV_RECVMAP: { sgetstr(); conoutf("received map \"%s\" from server, reloading..", text); int mapsize = getint(p); writemap(text, mapsize, p); p += mapsize; changemapserv(text, gamemode); break; }; case SV_SERVMSG: sgetstr(); conoutf("%s", text); break; case SV_EXT: // so we can messages without breaking previous clients/servers, if necessary { for(int n = getint(p); n; n--) getint(p); break; }; default: neterr("type"); return; }; };
void localservertoclient(uchar *buf, int len) // processes any updates from the server { if (ENET_NET_TO_HOST_16(*(ushort *)buf) != len) neterr("packet length"); incomingdemodata(buf, len); uchar *end = buf + len; uchar *p = buf + 2; char text[MAXTRANS]; int cn = -1, type; Sprite *spr = NULL; bool mapchanged = false; while (p < end) switch (type = getint(p)) { case SV_INITS2C: // welcome messsage from the server { cn = getint(p); int prot = getint(p); if (prot != PROTOCOL_VERSION) { conoutf( "you are using a different game protocol (you: %d, server: %d)", PROTOCOL_VERSION, prot); disconnect(); return; }; toservermap = ""; clientnum = cn; // we are now fully connected if (!getint(p)) { toservermap = getclientmap(); // we are the first client on this server, set map } sgetstr(); if (text[0] && strcmp(text, clientpassword)) { conoutf( "you need to set the correct password to join this server!"); disconnect(); return; }; if (getint(p) == 1) { conoutf("server is FULL, disconnecting.."); }; break; } case SV_POS: // position of another client { cn = getint(p); spr = getclient(cn); if (!spr) return; spr->o.x = getint(p) / DMF; spr->o.y = getint(p) / DMF; spr->o.z = getint(p) / DMF; spr->yaw = getint(p) / DAF; spr->pitch = getint(p) / DAF; spr->roll = getint(p) / DAF; spr->vel.x = getint(p) / DVF; spr->vel.y = getint(p) / DVF; spr->vel.z = getint(p) / DVF; int f = getint(p); spr->strafe = (f & 3) == 3 ? -1 : f & 3; f >>= 2; spr->move = (f & 3) == 3 ? -1 : f & 3; spr->onfloor = (f >> 2) & 1; int state = f >> 3; if (state == CS_DEAD && spr->state != CS_DEAD) spr->lastaction = lastmillis; spr->state = state; if (!demoplayback) updatepos(spr); break; } case SV_SOUND: playsound(getint(p), &spr->o); break; case SV_TEXT: sgetstr(); conoutf("%s:\f %s", spr->name, text); break; case SV_MAPCHANGE: sgetstr(); changemapserv(text, getint(p)); mapchanged = true; break; case SV_ITEMLIST: { int n; if (mapchanged) { senditemstoserver = false; resetspawns(); }; while ((n = getint(p)) != -1) { if (mapchanged) setspawn(n, true); } break; } case SV_MAPRELOAD: // server requests next map { getint(p); std::string nextmapalias = std::string("nextmap_") + getclientmap(); std::string map = getalias(nextmapalias); // look up map in the cycle changemap(map.empty() ? getclientmap() : map); break; } case SV_INITC2S: // another client either connected or changed name/team { sgetstr(); if (spr->name[0]) { // already connected if (strcmp(spr->name, text)) conoutf("%s is now known as %s", spr->name, text); } else { // new client c2sinit = false; // send new players my info again conoutf("connected: %s", text); }; strcpy_s(spr->name, text); sgetstr(); strcpy_s(spr->team, text); spr->lifesequence = getint(p); break; } case SV_CDIS: cn = getint(p); if (!(spr = getclient(cn))) break; conoutf("player %s disconnected", spr->name[0] ? spr->name : "[incompatible client]"); zapSprite(players[cn]); break; case SV_SHOT: { int gun = getint(p); Vec3 s, e; s.x = getint(p) / DMF; s.y = getint(p) / DMF; s.z = getint(p) / DMF; e.x = getint(p) / DMF; e.y = getint(p) / DMF; e.z = getint(p) / DMF; if (gun == GUN_SG) createrays(s, e); shootv(gun, s, e, spr); break; } case SV_DAMAGE: { int target = getint(p); int damage = getint(p); int ls = getint(p); if (target == clientnum) { if (ls == player1->lifesequence) selfdamage(damage, cn, spr); } else playsound(S_PAIN1 + rnd(5), &getclient(target)->o); break; } case SV_DIED: { int actor = getint(p); if (actor == cn) { conoutf("%s suicided", spr->name); } else if (actor == clientnum) { int frags; if (isteam(player1->team, spr->team)) { frags = -1; conoutf("you fragged a teammate (%s)", spr->name); } else { frags = 1; conoutf("you fragged %s", spr->name); }; addmsg(1, 2, SV_FRAGS, player1->frags += frags); } else { Sprite *a = getclient(actor); if (a) { if (isteam(a->team, spr->name)) { conoutf("%s fragged his teammate (%s)", a->name, spr->name); } else { conoutf("%s fragged %s", a->name, spr->name); }; }; }; playsound(S_DIE1 + rnd(2), &spr->o); spr->lifesequence++; break; } case SV_FRAGS: players[cn]->frags = getint(p); break; case SV_ITEMPICKUP: setspawn(getint(p), false); getint(p); break; case SV_ITEMSPAWN: { int i = getint(p); setspawn(i, true); if (i >= entityList.size()) break; Vec3 v = { entityList[i].x, entityList[i].y, entityList[i].z }; playsound(S_ITEMSPAWN, &v); break; } case SV_ITEMACC: // server acknowledges that I picked up this item realpickup(getint(p), player1); break; case SV_EDITH: // coop editing messages, should be extended to include all possible editing ops case SV_EDITT: case SV_EDITS: case SV_EDITD: case SV_EDITE: { int x = getint(p); int y = getint(p); int xs = getint(p); int ys = getint(p); int v = getint(p); Rect b = { x, y, xs, ys }; switch (type) { case SV_EDITH: editheightxy(v != 0, getint(p), b); break; case SV_EDITT: edittexxy(v, getint(p), b); break; case SV_EDITS: edittypexy(v, b); break; case SV_EDITD: setvdeltaxy(v, b); break; case SV_EDITE: editequalisexy(v != 0, b); break; }; break; } case SV_EDITENT: // coop edit of ent { int i = getint(p); while (entityList.size() <= i) { entityList.emplace_back(Entity()); entityList.back().type = NOTUSED; } int to = entityList[i].type; entityList[i].type = getint(p); entityList[i].x = getint(p); entityList[i].y = getint(p); entityList[i].z = getint(p); entityList[i].attr1 = getint(p); entityList[i].attr2 = getint(p); entityList[i].attr3 = getint(p); entityList[i].attr4 = getint(p); entityList[i].spawned = false; if (entityList[i].type == LIGHT || to == LIGHT) calclight(); break; } case SV_PING: getint(p); break; case SV_PONG: addmsg(0, 2, SV_CLIENTPING, player1->ping = (player1->ping * 5 + lastmillis - getint(p)) / 6); break; case SV_CLIENTPING: players[cn]->ping = getint(p); break; case SV_GAMEMODE: nextmode = getint(p); break; case SV_TIMEUP: timeupdate(getint(p)); break; case SV_RECVMAP: { sgetstr(); conoutf("received map \"%s\" from server, reloading..", text); int mapsize = getint(p); writemap(text, mapsize, p); p += mapsize; changemapserv(text, gamemode); break; } case SV_SERVMSG: sgetstr(); conoutf("%s", text); break; case SV_EXT: // so we can messages without breaking previous clients/servers, if necessary { for (int n = getint(p); n; n--) getint(p); break; } default: neterr("type"); return; } }