#include "game.hh" namespace game { VARP(minradarscale, 0, 384, 10000); VARP(maxradarscale, 1, 1024, 10000); VARP(radarteammates, 0, 1, 1); FVARP(minimapalpha, 0, 1, 1); float calcradarscale() { return clamp(max(minimapradius.x, minimapradius.y)/3, float(minradarscale), float(maxradarscale)); } void drawminimap(gameent *d, float x, float y, float s) { vec pos = vec(d->o).sub(minimapcenter).mul(minimapscale).add(0.5f), dir; vecfromyawpitch(camera1->yaw, 0, 1, 0, dir); float scale = calcradarscale(); gle::defvertex(2); gle::deftexcoord0(); gle::begin(GL_TRIANGLE_FAN); loopi(16) { vec v = vec(0, -1, 0).rotate_around_z(i/16.0f*2*M_PI); gle::attribf(x + 0.5f*s*(1.0f + v.x), y + 0.5f*s*(1.0f + v.y)); vec tc = vec(dir).rotate_around_z(i/16.0f*2*M_PI); gle::attribf(1.0f - (pos.x + tc.x*scale*minimapscale.x), pos.y + tc.y*scale*minimapscale.y); } gle::end(); } void setradartex() { settexture("media/interface/radar/radar.png", 3); } bool connected = false, remote = false; int sessionid = 0; string servdesc = "", servauth = ""; VARP(deadpush, 1, 2, 20); void sendmapinfo() { } void writeclientinfo(stream *f) { } bool allowedittoggle() { return true; } void edittoggled(bool on) { disablezoom(); player1->respawned = -2; } string clientmap = ""; void changemapserv(const char *name, int mode) // forced map change from the server { if(editmode) toggleedit(); if(!name[0] || !load_world(name)) { emptymap(0, true, name); } startgame(); } void changemap(const char *name, int mode) // request map change, server may ignore { server::forcemap(name, mode); if(!isconnected()) localconnect(); } void changemap(const char *name) { changemap(name, 0); } ICOMMAND(map, "s", (char *name), changemap(name)); void forceedit(const char *name) { changemap(name, 0); } void newmap(int size) { addmsg(N_NEWMAP, "ri", size); } void edittrigger(const selinfo &sel, int op, int arg1, int arg2, int arg3, const VSlot *vs) { } void vartrigger(ident *id) { } bool ispaused() { return false; } bool allowmouselook() { return true; } int scaletime(int t) { return t*100; } // collect c2s messages conveniently vector messages; int messagecn = -1, messagereliable = false; bool addmsg(int type, const char *fmt, ...) { if(!connected) return false; static uchar buf[MAXTRANS]; ucharbuf p(buf, sizeof(buf)); putint(p, type); int numi = 1, numf = 0, nums = 0; bool reliable = false; if(fmt) { va_list args; va_start(args, fmt); while(*fmt) switch(*fmt++) { case 'r': reliable = true; break; case 'c': { break; } case 'v': { int n = va_arg(args, int); int *v = va_arg(args, int *); loopi(n) putint(p, v[i]); numi += n; break; } case 'i': { int n = isdigit(*fmt) ? *fmt++-'0' : 1; loopi(n) putint(p, va_arg(args, int)); numi += n; break; } case 'f': { int n = isdigit(*fmt) ? *fmt++-'0' : 1; loopi(n) putfloat(p, (float)va_arg(args, double)); numf += n; break; } case 's': sendstring(va_arg(args, const char *), p); nums++; break; } va_end(args); } int num = nums || numf ? 0 : numi, msgsize = server::msgsizelookup(type); if(msgsize && num!=msgsize) { fatal("inconsistent msg size for %d (%d != %d)", type, num, msgsize); } if(reliable) messagereliable = true; messages.put(buf, p.length()); return true; } void connectattempt(const char *name, const char *password, const ENetAddress &address) { } void connectfail() { } void gameconnect(bool _remote) { remote = _remote; } void gamedisconnect(bool cleanup) { connected = remote = false; player1->clientnum = -1; if(editmode) toggleedit(); sessionid = 0; messages.setsize(0); messagereliable = false; messagecn = -1; player1->respawn(); player1->lifesequence = 0; player1->state = CS_ALIVE; if(cleanup) { clientmap[0] = '\0'; } } void toserver(char *text) { conoutf(CON_CHAT, "%s", text); } void sendmessages() { packetbuf p(MAXTRANS); if(messages.length()) { p.put(messages.getbuf(), messages.length()); messages.setsize(0); if(messagereliable) p.reliable(); messagereliable = false; messagecn = -1; } sendclientpacket(p.finalize(), 1); } void c2sinfo(bool force) // send update to the server { static int lastupdate = -1000; if(totalmillis - lastupdate < 40 && !force) return; // don't update faster than 30fps lastupdate = totalmillis; sendmessages(); } void sendintro() { packetbuf p(MAXTRANS, ENET_PACKET_FLAG_RELIABLE); putint(p, N_CONNECT); sendstring(player1->name, p); sendclientpacket(p.finalize(), 1); } void parsestate(gameent *d, ucharbuf &p, bool resume = false) { if(!d) { static gameent dummy; d = &dummy; } if(resume) { if(d==player1) getint(p); else d->state = getint(p); } d->lifesequence = getint(p); } void parsemessages(int cn, gameent *d, ucharbuf &p) { static char text[MAXTRANS]; int type; while(p.remaining()) switch((type = getint(p))) { case N_SERVINFO: // welcome messsage from the server { int mycn = getint(p); sessionid = getint(p); player1->clientnum = mycn; // we are now connected sendintro(); break; } case N_WELCOME: { connected = true; notifywelcome(); break; } case N_MAPCHANGE: getstring(text, p); changemapserv(text, 0); break; case N_SPAWN: { printf("spawn\n"); if(d) { d->respawn(); } parsestate(d, p); if(!d) break; d->state = CS_SPAWNING; break; } case N_NEWMAP: { int size = getint(p); if(size>=0) emptymap(size, true, NULL); else enlargemap(true); break; } default: return; } } void parsepacketclient(int chan, packetbuf &p) // processes any updates from the server { if(p.packet->flags&ENET_PACKET_FLAG_UNSEQUENCED) return; switch(chan) { case 1: parsemessages(-1, NULL, p); break; } } }