From bebef4e338963d1e6e3c7e606f1cf986cc44dc10 Mon Sep 17 00:00:00 2001 From: q66 Date: Fri, 17 Apr 2020 20:19:42 +0200 Subject: [PATCH] remove yet another massive chunk of game/network code --- src/client/meson.build | 1 - src/engine/animmodel.hh | 5 +- src/engine/dynlight.cc | 4 +- src/engine/physics.cc | 2 +- src/engine/rendermodel.cc | 2 +- src/engine/renderparticles.cc | 2 +- src/engine/skelmodel.hh | 2 +- src/engine/ui.cc | 4 +- src/engine/vertmodel.hh | 2 +- src/game/client.cc | 187 +------- src/game/entities.cc | 290 +------------ src/game/game.cc | 240 +---------- src/game/game.hh | 257 +---------- src/game/render.cc | 472 +-------------------- src/game/server.cc | 642 +--------------------------- src/game/weapon.cc | 775 ---------------------------------- src/shared/igame.hh | 2 +- 17 files changed, 72 insertions(+), 2817 deletions(-) delete mode 100644 src/game/weapon.cc diff --git a/src/client/meson.build b/src/client/meson.build index aab799d..da3e018 100644 --- a/src/client/meson.build +++ b/src/client/meson.build @@ -45,7 +45,6 @@ client_src = [ '../game/game.cc', '../game/render.cc', '../game/server.cc', - '../game/weapon.cc' ] threads_dep = dependency('threads') diff --git a/src/engine/animmodel.hh b/src/engine/animmodel.hh index cbbdb07..9d72ded 100644 --- a/src/engine/animmodel.hh +++ b/src/engine/animmodel.hh @@ -1056,13 +1056,14 @@ struct animmodel : model void setanim(int animpart, int num, int frame, int range, float speed, int priority = 0) { - if(animpart<0 || animpart>=MAXANIMPARTS || num<0 || num>=game::numanims()) return; + const int NUM_ANIMS = 0; // FIXME + if(animpart<0 || animpart>=MAXANIMPARTS || num<0 || num>=NUM_ANIMS) return; if(frame<0 || range<=0 || !meshes || !meshes->hasframes(frame, range)) { conoutf("invalid frame %d, range %d in model %s", frame, range, model->name); return; } - if(!anims[animpart]) anims[animpart] = new vector[game::numanims()]; + if(!anims[animpart]) anims[animpart] = new vector[NUM_ANIMS]; animspec &spec = anims[animpart][num].add(); spec.frame = frame; spec.range = range; diff --git a/src/engine/dynlight.cc b/src/engine/dynlight.cc index ab10b9b..2d25acc 100644 --- a/src/engine/dynlight.cc +++ b/src/engine/dynlight.cc @@ -91,12 +91,12 @@ void removetrackeddynlights(physent *owner) void updatedynlights() { cleardynlights(); - game::adddynlights(); + //game::adddynlights(); loopv(dynlights) { dynlight &d = dynlights[i]; - if(d.owner) game::dynlighttrack(d.owner, d.o, d.hud); + //if(d.owner) game::dynlighttrack(d.owner, d.o, d.hud); d.calcradius(); d.calccolor(); } diff --git a/src/engine/physics.cc b/src/engine/physics.cc index b869286..7030b41 100644 --- a/src/engine/physics.cc +++ b/src/engine/physics.cc @@ -1579,7 +1579,7 @@ bool bounce(physent *d, float secs, float elasticity, float waterfric, float gra } else if(collideplayer) break; d->o = old; - game::bounced(d, collidewall); + //game::bounced(d, collidewall); float c = collidewall.dot(d->vel), k = 1.0f + (1.0f-elasticity)*c/d->vel.magnitude(); d->vel.mul(k); diff --git a/src/engine/rendermodel.cc b/src/engine/rendermodel.cc index 4a6927e..fd995d6 100644 --- a/src/engine/rendermodel.cc +++ b/src/engine/rendermodel.cc @@ -1076,7 +1076,7 @@ bool matchanim(const char *name, const char *pattern) ICOMMAND(findanims, "s", (char *name), { vector anims; - game::findanims(name, anims); + //game::findanims(name, anims); vector buf; string num; loopv(anims) diff --git a/src/engine/renderparticles.cc b/src/engine/renderparticles.cc index d9cb29b..a93bc15 100644 --- a/src/engine/renderparticles.cc +++ b/src/engine/renderparticles.cc @@ -199,7 +199,7 @@ struct partrenderer { o = p->o; d = p->d; - if(type&PT_TRACK && p->owner) game::particletrack(p->owner, o, d); + //if(type&PT_TRACK && p->owner) game::particletrack(p->owner, o, d); if(p->fade <= 5) { ts = 1; diff --git a/src/engine/skelmodel.hh b/src/engine/skelmodel.hh index 9ee08aa..89ba91f 100644 --- a/src/engine/skelmodel.hh +++ b/src/engine/skelmodel.hh @@ -1790,7 +1790,7 @@ template struct skelcommands : modelcommandsparts.empty()) { conoutf("not loading an %s", MDL::formatname()); return; } vector anims; - game::findanims(anim, anims); + //game::findanims(anim, anims); if(anims.empty()) conoutf("could not find animation %s", anim); else { diff --git a/src/engine/ui.cc b/src/engine/ui.cc index 576aad5..81c5481 100644 --- a/src/engine/ui.cc +++ b/src/engine/ui.cc @@ -2878,7 +2878,7 @@ namespace UI else { vector anims; - game::findanims(animspec, anims); + //game::findanims(animspec, anims); if(anims.length()) anim = anims[0]; } } @@ -2936,7 +2936,7 @@ namespace UI int sx1, sy1, sx2, sy2; window->calcscissor(sx, sy, sx+w, sy+h, sx1, sy1, sx2, sy2, false); modelpreview::start(sx1, sy1, sx2-sx1, sy2-sy1, false, clipstack.length() > 0); - game::renderplayerpreview(model, color, team, weapon); + game::renderplayerpreview(model, color, weapon); if(clipstack.length()) clipstack.last().scissor(); modelpreview::end(); } diff --git a/src/engine/vertmodel.hh b/src/engine/vertmodel.hh index 1de8d22..bd381d8 100644 --- a/src/engine/vertmodel.hh +++ b/src/engine/vertmodel.hh @@ -501,7 +501,7 @@ template struct vertcommands : modelcommandsparts.empty()) { conoutf("not loading an %s", MDL::formatname()); return; } vector anims; - game::findanims(anim, anims); + //game::findanims(anim, anims); if(anims.empty()) conoutf("could not find animation %s", anim); else loopv(anims) { diff --git a/src/game/client.cc b/src/game/client.cc index 1912741..10bbd40 100644 --- a/src/game/client.cc +++ b/src/game/client.cc @@ -35,93 +35,6 @@ namespace game settexture("media/interface/radar/radar.png", 3); } - void drawradar(float x, float y, float s) - { - gle::defvertex(2); - gle::deftexcoord0(); - gle::begin(GL_TRIANGLE_STRIP); - gle::attribf(x, y); gle::attribf(0, 0); - gle::attribf(x+s, y); gle::attribf(1, 0); - gle::attribf(x, y+s); gle::attribf(0, 1); - gle::attribf(x+s, y+s); gle::attribf(1, 1); - gle::end(); - } - - void drawteammate(gameent *d, float x, float y, float s, gameent *o, float scale, float blipsize = 1) - { - vec dir = d->o; - dir.sub(o->o).div(scale); - float dist = dir.magnitude2(), maxdist = 1 - 0.05f - 0.05f; - if(dist >= maxdist) dir.mul(maxdist/dist); - dir.rotate_around_z(-camera1->yaw*RAD); - float bs = 0.06f*blipsize*s, - bx = x + s*0.5f*(1.0f + dir.x), - by = y + s*0.5f*(1.0f + dir.y); - vec v(-0.5f, -0.5f, 0); - v.rotate_around_z((90+o->yaw-camera1->yaw)*RAD); - gle::attribf(bx + bs*v.x, by + bs*v.y); gle::attribf(0, 0); - gle::attribf(bx + bs*v.y, by - bs*v.x); gle::attribf(1, 0); - gle::attribf(bx - bs*v.x, by - bs*v.y); gle::attribf(1, 1); - gle::attribf(bx - bs*v.y, by + bs*v.x); gle::attribf(0, 1); - } - - void setbliptex(int team, const char *type = "") - { - defformatstring(blipname, "media/interface/radar/blip%s%s.png", teamblipcolor[validteam(team) ? team : 0], type); - settexture(blipname, 3); - } - - void drawplayerblip(gameent *d, float x, float y, float s, float blipsize = 1) - { - if(d->state != CS_ALIVE && d->state != CS_DEAD) return; - float scale = calcradarscale(); - setbliptex(d->team, d->state == CS_DEAD ? "_dead" : "_alive"); - gle::defvertex(2); - gle::deftexcoord0(); - gle::begin(GL_QUADS); - drawteammate(d, x, y, s, d, scale, blipsize); - gle::end(); - } - - void drawteammates(gameent *d, float x, float y, float s) - { - if(!radarteammates) return; - float scale = calcradarscale(); - int alive = 0, dead = 0; - loopv(players) - { - gameent *o = players[i]; - if(o != d && o->state == CS_ALIVE && o->team == d->team) - { - if(!alive++) - { - setbliptex(d->team, "_alive"); - gle::defvertex(2); - gle::deftexcoord0(); - gle::begin(GL_QUADS); - } - drawteammate(d, x, y, s, o, scale); - } - } - if(alive) gle::end(); - loopv(players) - { - gameent *o = players[i]; - if(o != d && o->state == CS_DEAD && o->team == d->team) - { - if(!dead++) - { - setbliptex(d->team, "_dead"); - gle::defvertex(2); - gle::deftexcoord0(); - gle::begin(GL_QUADS); - } - drawteammate(d, x, y, s, o, scale); - } - } - if(dead) gle::end(); - } - clientmode *cmode = NULL; void setclientmode() @@ -166,7 +79,7 @@ namespace game addmsg(N_EDITMODE, "ri", on ? 1 : 0); if(player1->state==CS_DEAD) deathstate(player1, true); disablezoom(); - player1->suicided = player1->respawned = -2; + player1->respawned = -2; checkfollow(); } @@ -508,15 +421,11 @@ namespace game } } - VARP(teamcolorchat, 0, 1, 1); - const char *chatcolorname(gameent *d) { return teamcolorchat ? teamcolorname(d, NULL) : colorname(d); } + const char *chatcolorname(gameent *d) { return colorname(d); } - void toserver(char *text) { conoutf(CON_CHAT, "%s:%s %s", chatcolorname(player1), teamtextcode[0], text); addmsg(N_TEXT, "rcs", player1, text); } + void toserver(char *text) { conoutf(CON_CHAT, "%s: %s", chatcolorname(player1), text); addmsg(N_TEXT, "rcs", player1, text); } COMMANDN(say, toserver, "C"); - void sayteam(char *text) { if(!m_teammode || !validteam(player1->team)) return; conoutf(CON_TEAMCHAT, "%s:%s %s", chatcolorname(player1), teamtextcode[player1->team], text); addmsg(N_SAYTEAM, "rcs", player1, text); } - COMMAND(sayteam, "C"); - ICOMMAND(servcmd, "C", (char *cmd), addmsg(N_SERVCMD, "rs", cmd)); static void sendposition(gameent *d, packetbuf &q) @@ -761,24 +670,6 @@ namespace game break; } - case N_TELEPORT: - { - int cn = getint(p), tp = getint(p), td = getint(p); - gameent *d = getclient(cn); - if(!d || d->lifesequence < 0 || d->state==CS_DEAD) continue; - entities::teleporteffects(d, tp, td, false); - break; - } - - case N_JUMPPAD: - { - int cn = getint(p), jp = getint(p); - gameent *d = getclient(cn); - if(!d || d->lifesequence < 0 || d->state==CS_DEAD) continue; - entities::jumppadeffects(d, jp, false); - break; - } - default: neterr("type"); return; @@ -792,24 +683,8 @@ namespace game { if(d==player1) getint(p); else d->state = getint(p); - d->frags = getint(p); - d->flags = getint(p); - d->deaths = getint(p); } d->lifesequence = getint(p); - d->health = getint(p); - d->maxhealth = getint(p); - if(resume && d==player1) - { - getint(p); - loopi(NUMGUNS) getint(p); - } - else - { - int gun = getint(p); - d->gunselect = clamp(gun, 0, NUMGUNS-1); - loopi(NUMGUNS) d->ammo[i] = getint(p); - } } void parsemessages(int cn, gameent *d, ucharbuf &p) @@ -847,7 +722,6 @@ namespace game int cn = getint(p); gameent *a = cn >= 0 ? getclient(cn) : NULL; gamepaused = val; - player1->attacking = ACT_IDLE; if(a) conoutf("%s %s the game", colorname(a), val ? "paused" : "resumed"); else conoutf("game is %s", val ? "paused" : "resumed"); break; @@ -883,21 +757,7 @@ namespace game filtertext(text, text, true, true); if(d->state!=CS_DEAD && d->state!=CS_SPECTATOR) particle_textcopy(d->abovehead(), text, PART_TEXT, 2000, 0x32FF64, 4.0f, -8); - conoutf(CON_CHAT, "%s:%s %s", chatcolorname(d), teamtextcode[0], text); - break; - } - - case N_SAYTEAM: - { - int tcn = getint(p); - gameent *t = getclient(tcn); - getstring(text, p); - filtertext(text, text, true, true); - if(!t) break; - int team = validteam(t->team) ? t->team : 0; - if(t->state!=CS_DEAD && t->state!=CS_SPECTATOR) - particle_textcopy(t->abovehead(), text, PART_TEXT, 2000, teamtextcolor[team], 4.0f, -8); - conoutf(CON_TEAMCHAT, "%s:%s %s", chatcolorname(t), teamtextcode[team], text); + conoutf(CON_CHAT, "%s: %s", chatcolorname(d), text); break; } @@ -934,10 +794,8 @@ namespace game if(needclipboard >= 0) needclipboard++; } copystring(d->name, text, MAXNAMELEN+1); - d->team = getint(p); - if(!validteam(d->team)) d->team = 0; - d->playermodel = getint(p); - d->playercolor = getint(p); + d->playermodel = 0; + d->playercolor = 0; break; } @@ -963,7 +821,6 @@ namespace game { if(d) { - if(d->state==CS_DEAD && d->lastpain) saveragdoll(d); d->respawn(); } parsestate(d, p); @@ -979,7 +836,6 @@ namespace game int scn = getint(p); gameent *s = getclient(scn); if(!s) { parsestate(NULL, p); break; } - if(s->state==CS_DEAD && s->lastpain) saveragdoll(s); if(s==player1) { if(editmode) toggleedit(); @@ -988,37 +844,14 @@ namespace game parsestate(s, p); s->state = CS_ALIVE; if(cmode) cmode->pickspawn(s); - else findplayerspawn(s, -1, m_teammode ? s->team : 0); + else findplayerspawn(s, -1, 0); if(s == player1) { lasthit = 0; } if(cmode) cmode->respawned(s); checkfollow(); - addmsg(N_SPAWN, "rcii", s, s->lifesequence, s->gunselect); - break; - } - - case N_HITPUSH: - { - int tcn = getint(p), atk = getint(p), damage = getint(p); - gameent *target = getclient(tcn); - vec dir; - loopk(3) dir[k] = getint(p)/DNF; - if(!target || !validatk(atk)) break; - target->hitpush(damage * (target->health<=0 ? deadpush : 1), dir, NULL, atk); - break; - } - - case N_DIED: - { - int vcn = getint(p), acn = getint(p), frags = getint(p), tfrags = getint(p); - gameent *victim = getclient(vcn), - *actor = getclient(acn); - if(!actor) break; - actor->frags = frags; - if(!victim) break; - killed(victim, actor); + addmsg(N_SPAWN, "rci", s, s->lifesequence); break; } @@ -1179,10 +1012,6 @@ namespace game d->ping = getint(p); break; - case N_TIMEUP: - timeupdate(getint(p)); - break; - case N_SERVMSG: getstring(text, p); conoutf("%s", text); diff --git a/src/game/entities.cc b/src/game/entities.cc index 0751109..0bb4709 100644 --- a/src/game/entities.cc +++ b/src/game/entities.cc @@ -25,294 +25,47 @@ namespace entities const char *itemname(int i) { return NULL; -#if 0 - int t = ents[i]->type; - if(!validitem(t)) return NULL; - return itemstats[t-I_FIRST].name; -#endif } int itemicon(int i) { return -1; -#if 0 - int t = ents[i]->type; - if(!validitem(t)) return -1; - return itemstats[t-I_FIRST].icon; -#endif } const char *entmdlname(int type) { - static const char * const entmdlnames[MAXENTTYPES] = - { - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - "game/teleport", NULL, NULL, - NULL - }; - return entmdlnames[type]; + return NULL; } const char *entmodel(const entity &e) { - if(e.type == TELEPORT) - { - if(e.attr2 > 0) return mapmodelname(e.attr2); - if(e.attr2 < 0) return NULL; - } - return e.type < MAXENTTYPES ? entmdlname(e.type) : NULL; + return NULL; } void preloadentities() { - loopi(MAXENTTYPES) - { - const char *mdl = entmdlname(i); - if(!mdl) continue; - preloadmodel(mdl); - } - loopv(ents) - { - extentity &e = *ents[i]; - switch(e.type) - { - case TELEPORT: - if(e.attr2 > 0) preloadmodel(mapmodelname(e.attr2)); - case JUMPPAD: - //if(e.attr4 > 0) preloadmapsound(e.attr4); - break; - } - } } void renderentities() { - loopv(ents) - { - extentity &e = *ents[i]; - int revs = 10; - switch(e.type) - { - case TELEPORT: - if(e.attr2 < 0) continue; - break; - default: - if(!e.spawned() || !validitem(e.type)) continue; - break; - } - const char *mdlname = entmodel(e); - if(mdlname) - { - vec p = e.o; - p.z += 1+sinf(lastmillis/100.0+e.o.x+e.o.y)/20; - rendermodel(mdlname, ANIM_MAPMODEL|ANIM_LOOP, p, lastmillis/(float)revs, 0, 0, MDL_CULL_VFC | MDL_CULL_DIST | MDL_CULL_OCCLUDED); - } - } } - void addammo(int type, int &v, bool local) - { -#if 0 - itemstat &is = itemstats[type-I_FIRST]; - v += is.add; - if(v>is.max) v = is.max; - //if(local) msgsound(is.sound); -#endif - } - - // these two functions are called when the server acknowledges that you really - // picked up the item (in multiplayer someone may grab it before you). - - void pickupeffects(int n, gameent *d) - { -#if 0 - if(!ents.inrange(n)) return; - extentity *e = ents[n]; - int type = e->type; - if(!validitem(type)) return; - e->clearspawned(); - e->clearnopickup(); - if(!d) return; - itemstat &is = itemstats[type-I_FIRST]; - gameent *h = followingplayer(player1); - if(d!=h || isthirdperson()) - { - //particle_text(d->abovehead(), is.name, PART_TEXT, 2000, 0xFFC864, 4.0f, -8); - particle_icon(d->abovehead(), is.icon%4, is.icon/4, PART_HUD_ICON_GREY, 2000, 0xFFFFFF, 2.0f, -8); - } - playsound(itemstats[type-I_FIRST].sound, d!=h ? &d->o : NULL, NULL, 0, 0, 0, -1, 0, 1500); - d->pickup(type); - if(d==h) switch(type) - { - } -#endif - } - - // these functions are called when the client touches the item - - void teleporteffects(gameent *d, int tp, int td, bool local) - { - if(ents.inrange(tp) && ents[tp]->type == TELEPORT) - { - extentity &e = *ents[tp]; - if(e.attr4 >= 0) - { - int snd = S_TELEPORT, flags = 0; - if(e.attr4 > 0) { snd = e.attr4; flags = SND_MAP; } - gameent *h = followingplayer(player1); - playsound(snd, d==h ? NULL : &e.o, NULL, flags); - if(d!=h && ents.inrange(td) && ents[td]->type == TELEDEST) playsound(snd, &ents[td]->o, NULL, flags); - } - } - if(local && d->clientnum >= 0) - { - sendposition(d); - packetbuf p(32, ENET_PACKET_FLAG_RELIABLE); - putint(p, N_TELEPORT); - putint(p, d->clientnum); - putint(p, tp); - putint(p, td); - sendclientpacket(p.finalize(), 0); - flushclient(); - } - } - - void jumppadeffects(gameent *d, int jp, bool local) - { - if(ents.inrange(jp) && ents[jp]->type == JUMPPAD) - { - extentity &e = *ents[jp]; - if(e.attr4 >= 0) - { - int snd = S_JUMPPAD, flags = 0; - if(e.attr4 > 0) { snd = e.attr4; flags = SND_MAP; } - playsound(snd, d == followingplayer(player1) ? NULL : &e.o, NULL, flags); - } - } - if(local && d->clientnum >= 0) - { - sendposition(d); - packetbuf p(16, ENET_PACKET_FLAG_RELIABLE); - putint(p, N_JUMPPAD); - putint(p, d->clientnum); - putint(p, jp); - sendclientpacket(p.finalize(), 0); - flushclient(); - } - } - - void teleport(int n, gameent *d) // also used by monsters - { - int e = -1, tag = ents[n]->attr1, beenhere = -1; - for(;;) - { - e = findentity(TELEDEST, e+1); - if(e==beenhere || e<0) { conoutf(CON_WARN, "no teleport destination for tag %d", tag); return; } - if(beenhere<0) beenhere = e; - if(ents[e]->attr2==tag) - { - teleporteffects(d, n, e, true); - d->o = ents[e]->o; - d->yaw = ents[e]->attr1; - if(ents[e]->attr3 > 0) - { - vec dir; - vecfromyawpitch(d->yaw, 0, 1, 0, dir); - float speed = d->vel.magnitude2(); - d->vel.x = dir.x*speed; - d->vel.y = dir.y*speed; - } - else d->vel = vec(0, 0, 0); - entinmap(d); - updatedynentcache(d); - break; - } - } - } - - VARR(teleteam, 0, 1, 1); - void trypickup(int n, gameent *d) { - extentity *e = ents[n]; - switch(e->type) - { - default: - if(d->canpickup(e->type)) - { - addmsg(N_ITEMPICKUP, "rci", d, n); - e->setnopickup(); // even if someone else gets it first - } - break; - - case TELEPORT: - { - if(d->lastpickup==e->type && lastmillis-d->lastpickupmillis<500) break; - if(!teleteam && m_teammode) break; - if(e->attr3 > 0) - { - defformatstring(hookname, "can_teleport_%d", e->attr3); - if(!execidentbool(hookname, true)) break; - } - d->lastpickup = e->type; - d->lastpickupmillis = lastmillis; - teleport(n, d); - break; - } - - case JUMPPAD: - { - if(d->lastpickup==e->type && lastmillis-d->lastpickupmillis<300) break; - d->lastpickup = e->type; - d->lastpickupmillis = lastmillis; - jumppadeffects(d, n, true); - d->falling = vec(0, 0, 0); - d->physstate = PHYS_FALL; - d->timeinair = 1; - d->vel = vec(e->attr3*10.0f, e->attr2*10.0f, e->attr1*12.5f); - break; - } - } } void checkitems(gameent *d) { - if(d->state!=CS_ALIVE) return; - vec o = d->feetpos(); - loopv(ents) - { - extentity &e = *ents[i]; - if(e.type==NOTUSED) continue; - if((!e.spawned() || e.nopickup()) && e.type!=TELEPORT && e.type!=JUMPPAD) continue; - float dist = e.o.dist(o); - if(dist<(e.type==TELEPORT ? 16 : 12)) trypickup(i, d); - } } void putitems(packetbuf &p) // puts items in network stream and also spawns them locally { - putint(p, N_ITEMLIST); - loopv(ents) if(validitem(ents[i]->type)) - { - putint(p, i); - putint(p, ents[i]->type); - } - putint(p, -1); } - void resetspawns() { loopv(ents) { extentity *e = ents[i]; e->clearspawned(); e->clearnopickup(); } } + void resetspawns() { } void spawnitems(bool force) { - loopv(ents) - { - extentity *e = ents[i]; - if(validitem(e->type)) - { - e->setspawned(force || !server::delayspawn(e->type)); - e->clearnopickup(); - } - } } void setspawn(int i, bool on) { if(ents.inrange(i)) { extentity *e = ents[i]; e->setspawned(on); e->clearnopickup(); } } @@ -331,44 +84,10 @@ namespace entities void fixentity(extentity &e) { - switch(e.type) - { - case FLAG: - e.attr5 = e.attr4; - e.attr4 = e.attr3; - case TELEDEST: - e.attr3 = e.attr2; - e.attr2 = e.attr1; - e.attr1 = (int)player1->yaw; - break; - } } void entradius(extentity &e, bool color) { - switch(e.type) - { - case TELEPORT: - loopv(ents) if(ents[i]->type == TELEDEST && e.attr1==ents[i]->attr2) - { - renderentarrow(e, vec(ents[i]->o).sub(e.o).normalize(), e.o.dist(ents[i]->o)); - break; - } - break; - - case JUMPPAD: - renderentarrow(e, vec((int)(char)e.attr3*10.0f, (int)(char)e.attr2*10.0f, e.attr1*12.5f).normalize(), 4); - break; - - case FLAG: - case TELEDEST: - { - vec dir; - vecfromyawpitch(e.attr1, 0, 1, 0, dir); - renderentarrow(e, dir, 4); - break; - } - } } bool printent(extentity &e, char *buf, int len) @@ -382,8 +101,6 @@ namespace entities static const char * const entnames[MAXENTTYPES] = { "none?", "light", "mapmodel", "playerstart", "envmap", "particles", "sound", "spotlight", "decal", - "teleport", "teledest", "jumppad", - "flag" }; return i>=0 && size_t(i)o, worldpos)) return players[i]; return NULL; } @@ -173,32 +169,6 @@ namespace game void otherplayers(int curtime) { - loopv(players) - { - gameent *d = players[i]; - if(d == player1) continue; - - if(d->state==CS_DEAD && d->ragdoll) moveragdoll(d); - else if(!intermission) - { - if(lastmillis - d->lastaction >= d->gunwait) d->gunwait = 0; - } - - const int lagtime = totalmillis-d->lastupdate; - if(!lagtime || intermission) continue; - else if(lagtime>1000 && d->state==CS_ALIVE) - { - d->state = CS_LAGGED; - continue; - } - if(d->state==CS_ALIVE || d->state==CS_EDITING) - { - crouchplayer(d, 10, false); - if(smoothmove && d->smoothmillis>0) predictplayer(d, true); - else moveplayer(d, 1, false); - } - else if(d->state==CS_DEAD && !d->ragdoll && lastmillis-d->lastpain<2000) moveplayer(d, 1, true); - } } void updateworld() // main game update loop @@ -207,30 +177,15 @@ namespace game if(!curtime) { gets2c(); if(player1->clientnum>=0) c2sinfo(); return; } physicsframe(); - updateweapons(curtime); otherplayers(curtime); moveragdolls(); gets2c(); if(connected) { - if(player1->state == CS_DEAD) - { - if(player1->ragdoll) moveragdoll(player1); - else if(lastmillis-player1->lastpain<2000) - { - player1->move = player1->strafe = 0; - moveplayer(player1, 10, true); - } - } - else if(!intermission) - { - if(player1->ragdoll) cleanragdoll(player1); - crouchplayer(player1, 10, true); - moveplayer(player1, 10, true); - swayhudgun(curtime); - entities::checkitems(player1); - if(cmode) cmode->checkitems(player1); - } + crouchplayer(player1, 10, true); + moveplayer(player1, 10, true); + entities::checkitems(player1); + if(cmode) cmode->checkitems(player1); } if(player1->clientnum>=0) c2sinfo(); // do this last, to reduce the effective frame lag } @@ -238,7 +193,7 @@ namespace game void spawnplayer(gameent *d) // place at random spawn { if(cmode) cmode->pickspawn(d); - else findplayerspawn(d, -1, m_teammode ? d->team : 0); + else findplayerspawn(d, -1, 0); spawnstate(d); if(d==player1) { @@ -255,15 +210,6 @@ namespace game { if(player1->state==CS_DEAD) { - player1->attacking = ACT_IDLE; - int wait = cmode ? cmode->respawnwait(player1) : 0; - if(wait>0) - { - lastspawnattempt = lastmillis; - //conoutf(CON_GAMEINFO, "\f2you must wait %d second%s before respawn!", wait, wait!=1 ? "s" : ""); - return; - } - if(lastmillis < player1->lastpain + spawnwait) return; respawnself(); } } @@ -271,87 +217,36 @@ namespace game // inputs - VARP(attackspawn, 0, 1, 1); - - void doaction(int act) - { - if(!connected || intermission) return; - if((player1->attacking = act) && attackspawn) respawn(); - } - - ICOMMAND(shoot, "D", (int *down), doaction(*down ? ACT_SHOOT : ACT_IDLE)); - ICOMMAND(melee, "D", (int *down), doaction(*down ? ACT_MELEE : ACT_IDLE)); - VARP(jumpspawn, 0, 1, 1); bool canjump() { - if(!connected || intermission) return false; + if(!connected) return false; if(jumpspawn) respawn(); return player1->state!=CS_DEAD; } bool cancrouch() { - if(!connected || intermission) return false; + if(!connected) return false; return player1->state!=CS_DEAD; } bool allowmove(physent *d) { - if(d->type!=ENT_PLAYER) return true; - return !((gameent *)d)->lasttaunt || lastmillis-((gameent *)d)->lasttaunt>=1000; + return true; } - void taunt() - { - if(player1->state!=CS_ALIVE || player1->physstatelasttaunt<1000) return; - player1->lasttaunt = lastmillis; - addmsg(N_TAUNT, "rc", player1); - } - COMMAND(taunt, ""); - - VARP(hitsound, 0, 0, 1); - void damaged(int damage, gameent *d, gameent *actor, bool local) { - if((d->state!=CS_ALIVE && d->state != CS_LAGGED && d->state != CS_SPAWNING) || intermission) return; - - if(local) damage = d->dodamage(damage); - else if(actor==player1) return; - - gameent *h = hudplayer(); - if(h!=player1 && actor==h && d!=actor) - { - if(hitsound && lasthit != lastmillis) playsound(S_HIT); - lasthit = lastmillis; - } - if(d==h) - { - damageblend(damage); - damagecompass(damage, actor->o); - } - damageeffect(damage, d, d!=h); - - if(d->health<=0) { if(local) killed(d, actor); } - else if(d==h) playsound(S_PAIN2); - else playsound(S_PAIN1, &d->o); } void deathstate(gameent *d, bool restore) { d->state = CS_DEAD; - d->lastpain = lastmillis; - if(!restore) - { - gibeffect(max(-d->health, 0), d->vel, d); - d->deaths++; - } if(d==player1) { disablezoom(); - d->attacking = ACT_IDLE; //d->pitch = 0; d->roll = 0; playsound(S_DIE2); @@ -372,39 +267,11 @@ namespace game if(d->state==CS_EDITING) { d->editstate = CS_DEAD; - d->deaths++; if(d!=player1) d->resetinterp(); return; } - else if((d->state!=CS_ALIVE && d->state != CS_LAGGED && d->state != CS_SPAWNING) || intermission) return; + else if(d->state!=CS_ALIVE && d->state != CS_LAGGED && d->state != CS_SPAWNING) return; - gameent *h = followingplayer(player1); - int contype = d==h || actor==h ? CON_FRAG_SELF : CON_FRAG_OTHER; - const char *dname = "", *aname = ""; - if(m_teammode && teamcolorfrags) - { - dname = teamcolorname(d, "you"); - aname = teamcolorname(actor, "you"); - } - else - { - dname = colorname(d, NULL, "you"); - aname = colorname(actor, NULL, "you"); - } - if(d==actor) - conoutf(contype, "\f2%s suicided%s", dname, d==player1 ? "!" : ""); - else if(isteam(d->team, actor->team)) - { - contype |= CON_TEAMKILL; - if(actor==player1) conoutf(contype, "\f6%s fragged a teammate (%s)", aname, dname); - else if(d==player1) conoutf(contype, "\f6%s got fragged by a teammate (%s)", dname, aname); - else conoutf(contype, "\f2%s fragged a teammate (%s)", aname, dname); - } - else - { - if(d==player1) conoutf(contype, "\f2%s got fragged by %s", dname, aname); - else conoutf(contype, "\f2%s fragged %s", aname, dname); - } deathstate(d); } @@ -414,30 +281,8 @@ namespace game { maplimit = lastmillis + secs*1000; } - else - { - intermission = true; - player1->attacking = ACT_IDLE; - if(cmode) cmode->gameover(); - conoutf(CON_GAMEINFO, "\f2intermission:"); - conoutf(CON_GAMEINFO, "\f2game has ended!"); - conoutf(CON_GAMEINFO, "\f2player frags: %d, deaths: %d", player1->frags, player1->deaths); - int accuracy = (player1->totaldamage*100)/max(player1->totalshots, 1); - conoutf(CON_GAMEINFO, "\f2player total damage dealt: %d, damage wasted: %d, accuracy(%%): %d", player1->totaldamage, player1->totalshots-player1->totaldamage, accuracy); - - disablezoom(); - - execident("intermission"); - } } - ICOMMAND(getfrags, "", (), intret(player1->frags)); - ICOMMAND(getflags, "", (), intret(player1->flags)); - ICOMMAND(getdeaths, "", (), intret(player1->deaths)); - ICOMMAND(getaccuracy, "", (), intret((player1->totaldamage*100)/max(player1->totalshots, 1))); - ICOMMAND(gettotaldamage, "", (), intret(player1->totaldamage)); - ICOMMAND(gettotalshots, "", (), intret(player1->totalshots)); - vector clients; gameent *newclient(int cn) // ensure valid entity @@ -474,7 +319,6 @@ namespace game if(d) { if(notify && d->name[0]) conoutf("\f4leave:\f7 %s", colorname(d)); - removeweapons(d); removetrackedparticles(d); removetrackeddynlights(d); if(cmode) cmode->removeplayer(d); @@ -505,16 +349,11 @@ namespace game void startgame() { - clearprojectiles(); - clearbouncers(); - clearragdolls(); - // reset perma-state loopv(players) players[i]->startgame(); setclientmode(); - intermission = false; maptime = maprealtime = 0; maplimit = -1; @@ -595,67 +434,18 @@ namespace game const char *colorname(gameent *d, const char *name, const char * alt, const char *color) { if(!name) name = alt && d == player1 ? alt : d->name; - bool dup = !name[0] || duplicatename(d, name, alt); - if(dup || color[0]) - { - if(dup) return tempformatstring("\fs%s%s \f5(%d)\fr", color, name, d->clientnum); - return tempformatstring("\fs%s%s\fr", color, name); - } return name; } - VARP(teamcolortext, 0, 1, 1); - - const char *teamcolorname(gameent *d, const char *alt) - { - if(!teamcolortext || !m_teammode || !validteam(d->team) || d->state == CS_SPECTATOR) return colorname(d, NULL, alt); - return colorname(d, NULL, alt, teamtextcode[d->team]); - } - - const char *teamcolor(const char *prefix, const char *suffix, int team, const char *alt) - { - if(!teamcolortext || !m_teammode || !validteam(team)) return alt; - return tempformatstring("\fs%s%s%s%s\fr", teamtextcode[team], prefix, teamnames[team], suffix); - } - - VARP(teamsounds, 0, 1, 1); - - void teamsound(bool sameteam, int n, const vec *loc) - { - playsound(n, loc, NULL, teamsounds ? (m_teammode && sameteam ? SND_USE_ALT : SND_NO_ALT) : 0); - } - - void teamsound(gameent *d, int n, const vec *loc) - { - teamsound(isteam(d->team, player1->team), n, loc); - } - bool needminimap() { return false; } void drawicon(int icon, float x, float y, float sz) { - settexture("media/interface/hud/items.png"); - float tsz = 0.25f, tx = tsz*(icon%4), ty = tsz*(icon/4); - gle::defvertex(2); - gle::deftexcoord0(); - gle::begin(GL_TRIANGLE_STRIP); - gle::attribf(x, y); gle::attribf(tx, ty); - gle::attribf(x+sz, y); gle::attribf(tx+tsz, ty); - gle::attribf(x, y+sz); gle::attribf(tx, ty+tsz); - gle::attribf(x+sz, y+sz); gle::attribf(tx+tsz, ty+tsz); - gle::end(); } float abovegameplayhud(int w, int h) { - switch(hudplayer()->state) - { - case CS_EDITING: - case CS_SPECTATOR: - return 1; - default: - return 1650.0f/1800.0f; - } + return 1; } void drawhudicons(gameent *d) @@ -682,17 +472,9 @@ namespace game return 0; } - VARP(teamcrosshair, 0, 1, 1); - VARP(hitcrosshair, 0, 425, 1000); - const char *defaultcrosshair(int index) { - switch(index) - { - case 2: return "media/interface/crosshair/default_hit.png"; - case 1: return "media/interface/crosshair/teammate.png"; - default: return "media/interface/crosshair/default.png"; - } + return "media/interface/crosshair/default.png"; } int selectcrosshair(vec &) diff --git a/src/game/game.hh b/src/game/game.hh index 046ee2d..7ecf3d4 100644 --- a/src/game/game.hh +++ b/src/game/game.hh @@ -67,10 +67,6 @@ enum // static entity types MAPSOUND = ET_SOUND, SPOTLIGHT = ET_SPOTLIGHT, DECAL = ET_DECAL, - TELEPORT, // attr1 = idx, attr2 = model, attr3 = tag - TELEDEST, // attr1 = angle, attr2 = idx - JUMPPAD, // attr1 = zpush, attr2 = ypush, attr3 = xpush - FLAG, // attr1 = angle, attr2 = team MAXENTTYPES, I_FIRST = 0, @@ -81,67 +77,12 @@ struct gameentity : extentity { }; -enum { GUN_RAIL = 0, GUN_PULSE, NUMGUNS }; -enum { ACT_IDLE = 0, ACT_SHOOT, ACT_MELEE, NUMACTS }; -enum { ATK_RAIL_SHOOT = 0, ATK_RAIL_MELEE, ATK_PULSE_SHOOT, ATK_PULSE_MELEE, NUMATKS }; - -#define validgun(n) ((n) >= 0 && (n) < NUMGUNS) -#define validact(n) ((n) >= 0 && (n) < NUMACTS) -#define validatk(n) ((n) >= 0 && (n) < NUMATKS) - enum { - M_TEAM = 1<<0, - M_OVERTIME = 1<<1, - M_EDIT = 1<<2, - M_DEMO = 1<<3, - M_LOCAL = 1<<4, - M_LOBBY = 1<<5, - M_RAIL = 1<<6, - M_PULSE = 1<<7 + M_EDIT = 1<<0 }; -static struct gamemodeinfo -{ - const char *name, *prettyname; - int flags; - const char *info; -} gamemodes[] = -{ - { "demo", "Demo", M_DEMO | M_LOCAL, NULL}, - { "edit", "Edit", M_EDIT, "Cooperative Editing:\nEdit maps with multiple players simultaneously." }, - { "rdm", "rDM", M_LOBBY | M_RAIL, "Railgun Deathmatch:\nFrag everyone with railguns to score points." }, - { "pdm", "pDM", M_LOBBY | M_PULSE, "Pulse Rifle Deathmatch:\nFrag everyone with pulse rifles to score points." }, - { "rtdm", "rTDM", M_TEAM | M_RAIL, "Railgun Team Deathmatch:\nFrag \fs\f3the enemy team\fr with railguns to score points for \fs\f1your team\fr." }, - { "ptdm", "pTDM", M_TEAM | M_PULSE, "Pulse Rifle Team Deathmatch:\nFrag \fs\f3the enemy team\fr with pulse rifles to score points for \fs\f1your team\fr." }, -}; - -#define STARTGAMEMODE (-1) -#define NUMGAMEMODES ((int)(sizeof(gamemodes)/sizeof(gamemodes[0]))) - -#define m_valid(mode) ((mode) >= STARTGAMEMODE && (mode) < STARTGAMEMODE + NUMGAMEMODES) -#define m_check(mode, flag) (m_valid(mode) && gamemodes[(mode) - STARTGAMEMODE].flags&(flag)) -#define m_checknot(mode, flag) (m_valid(mode) && !(gamemodes[(mode) - STARTGAMEMODE].flags&(flag))) -#define m_checkall(mode, flag) (m_valid(mode) && (gamemodes[(mode) - STARTGAMEMODE].flags&(flag)) == (flag)) - -#define m_teammode false -#define m_overtime false -#define isteam(a,b) false -#define m_rail false -#define m_pulse false - -#define m_demo false #define m_edit true -#define m_lobby false -#define m_timed false -#define m_botmode false -#define m_mp(mode) false - -enum { MM_AUTH = -1, MM_OPEN = 0, MM_VETO, MM_LOCKED, MM_PRIVATE, MM_PASSWORD, MM_START = MM_AUTH, MM_INVALID = MM_START - 1 }; - -static const char * const mastermodenames[] = { "auth", "open", "veto", "locked", "private", "password" }; -static const char * const mastermodecolors[] = { "", "\f0", "\f2", "\f2", "\f3", "\f3" }; -static const char * const mastermodeicons[] = { "server", "server", "serverlock", "serverlock", "serverpriv", "serverpriv" }; // hardcoded sounds, defined in sounds.cfg enum @@ -156,22 +97,16 @@ enum // network messages codes, c2s, c2c, s2c -enum { PRIV_NONE = 0, PRIV_MASTER, PRIV_AUTH, PRIV_ADMIN }; - enum { N_CONNECT = 0, N_SERVINFO, N_WELCOME, N_INITCLIENT, N_POS, N_TEXT, N_SOUND, N_CDIS, - N_SHOOT, N_EXPLODE, N_SUICIDE, N_DIED, N_DAMAGE, N_HITPUSH, N_SHOTFX, N_EXPLODEFX, N_TRYSPAWN, N_SPAWNSTATE, N_SPAWN, N_FORCEDEATH, - N_GUNSELECT, N_TAUNT, - N_MAPCHANGE, N_MAPVOTE, N_TEAMINFO, N_ITEMSPAWN, N_ITEMPICKUP, N_ITEMACC, N_TELEPORT, N_JUMPPAD, + N_MAPCHANGE, N_PING, N_PONG, N_CLIENTPING, - N_TIMEUP, N_FORCEINTERMISSION, N_SERVMSG, N_ITEMLIST, N_RESUME, N_EDITMODE, N_EDITENT, N_EDITF, N_EDITT, N_EDITM, N_FLIP, N_COPY, N_PASTE, N_ROTATE, N_REPLACE, N_DELCUBE, N_CALCLIGHT, N_REMIP, N_EDITVSLOT, N_UNDO, N_REDO, N_NEWMAP, N_GETMAP, N_SENDMAP, N_CLIPBOARD, N_EDITVAR, N_SPECTATOR, N_SETTEAM, - N_SAYTEAM, N_CLIENT, N_PAUSEGAME, N_GAMESPEED, N_MAPCRC, N_CHECKMAPS, @@ -183,17 +118,13 @@ enum static const int msgsizes[] = // size inclusive message token, 0 for variable or not-checked sizes { N_CONNECT, 0, N_SERVINFO, 0, N_WELCOME, 1, N_INITCLIENT, 0, N_POS, 0, N_TEXT, 0, N_SOUND, 2, N_CDIS, 2, - N_SHOOT, 0, N_EXPLODE, 0, N_SUICIDE, 1, N_DIED, 5, N_DAMAGE, 5, N_HITPUSH, 7, N_SHOTFX, 10, N_EXPLODEFX, 4, N_TRYSPAWN, 1, N_SPAWNSTATE, 8, N_SPAWN, 3, N_FORCEDEATH, 2, - N_GUNSELECT, 2, N_TAUNT, 1, - N_MAPCHANGE, 0, N_MAPVOTE, 0, N_TEAMINFO, 0, N_ITEMSPAWN, 2, N_ITEMPICKUP, 2, N_ITEMACC, 3, + N_MAPCHANGE, 0, N_PING, 2, N_PONG, 2, N_CLIENTPING, 2, - N_TIMEUP, 2, N_FORCEINTERMISSION, 1, N_SERVMSG, 0, N_ITEMLIST, 0, N_RESUME, 0, N_EDITMODE, 2, N_EDITENT, 11, N_EDITF, 16, N_EDITT, 16, N_EDITM, 16, N_FLIP, 14, N_COPY, 14, N_PASTE, 14, N_ROTATE, 15, N_REPLACE, 17, N_DELCUBE, 14, N_CALCLIGHT, 1, N_REMIP, 1, N_EDITVSLOT, 16, N_UNDO, 0, N_REDO, 0, N_NEWMAP, 2, N_GETMAP, 1, N_SENDMAP, 0, N_EDITVAR, 0, N_SPECTATOR, 3, N_SETTEAM, 0, - N_SAYTEAM, 0, N_CLIENT, 0, N_PAUSEGAME, 0, N_GAMESPEED, 0, N_MAPCRC, 0, N_CHECKMAPS, 1, @@ -206,65 +137,15 @@ static const int msgsizes[] = // size inclusive message token, 0 f #define TESSERACT_LANINFO_PORT 41998 #define TESSERACT_MASTER_PORT 41999 #define PROTOCOL_VERSION 2 // bump when protocol changes -#define DEMO_VERSION 1 // bump when demo format changes -#define DEMO_MAGIC "TESSERACT_DEMO\0\0" - -struct demoheader -{ - char magic[16]; - int version, protocol; -}; #define MAXNAMELEN 15 -enum -{ - HICON_RED_FLAG = 0, - HICON_BLUE_FLAG, - - HICON_X = 20, - HICON_Y = 1650, - HICON_TEXTY = 1644, - HICON_STEP = 490, - HICON_SIZE = 120, - HICON_SPACE = 40 -}; - -#if 0 -static struct itemstat { int add, max, sound; const char *name; int icon, info; } itemstats[] = -{ -}; -#endif - #define validitem(n) false -#define MAXRAYS 1 -#define EXP_SELFDAMDIV 2 -#define EXP_SELFPUSH 2.5f -#define EXP_DISTSCALE 0.5f - -static const struct attackinfo { int gun, action, anim, vwepanim, hudanim, sound, hudsound, attackdelay, damage, spread, margin, projspeed, kickamount, range, rays, hitpush, exprad, ttl, use; } attacks[NUMATKS] = -{ - { GUN_RAIL, ACT_SHOOT, ANIM_SHOOT, ANIM_VWEP_SHOOT, ANIM_GUN_SHOOT, S_RAIL1, S_RAIL2, 1300, 1, 0, 0, 0, 30, 2048, 1, 5000, 0, 0, 0 }, - { GUN_RAIL, ACT_MELEE, ANIM_MELEE, ANIM_VWEP_MELEE, ANIM_GUN_MELEE, S_MELEE, S_MELEE, 500, 1, 0, 2, 0, 0, 14, 1, 0, 0, 0, 0 }, - { GUN_PULSE, ACT_SHOOT, ANIM_SHOOT, ANIM_VWEP_SHOOT, ANIM_GUN_SHOOT, S_PULSE1, S_PULSE2, 700, 1, 0, 1, 1000, 30, 1024, 1, 5000, 15, 0, 0 }, - { GUN_PULSE, ACT_MELEE, ANIM_MELEE, ANIM_VWEP_MELEE, ANIM_GUN_MELEE, S_MELEE, S_MELEE, 500, 1, 0, 2, 0, 0, 14, 1, 0, 0, 0, 0 } -}; - -static const struct guninfo { const char *name, *file, *vwep; int attacks[NUMACTS]; } guns[NUMGUNS] = -{ - { "railgun", "railgun", "worldgun/railgun", { -1, ATK_RAIL_SHOOT, ATK_RAIL_MELEE }, }, - { "pulse rifle", "pulserifle", "worldgun/pulserifle", { -1, ATK_PULSE_SHOOT, ATK_PULSE_MELEE } } -}; - // inherited by gameent and server clients struct gamestate { - int health, maxhealth; - int gunselect, gunwait; - int ammo[NUMGUNS]; - - gamestate() : maxhealth(1) {} + gamestate() {} bool canpickup(int type) { @@ -277,65 +158,20 @@ struct gamestate void respawn() { - health = maxhealth; - gunselect = GUN_RAIL; - gunwait = 0; - loopi(NUMGUNS) ammo[i] = 0; } void spawnstate(int gamemode) { - if(m_rail) - { - gunselect = GUN_RAIL; - ammo[GUN_RAIL] = 1; - } - else if(m_pulse) - { - gunselect = GUN_PULSE; - ammo[GUN_PULSE] = 1; - } - else if(m_edit) - { - gunselect = GUN_RAIL; - loopi(NUMGUNS) ammo[i] = 1; - } - } - - // just subtract damage here, can set death, etc. later in code calling this - int dodamage(int damage) - { - health -= damage; - return damage; - } - - int hasammo(int gun, int exclude = -1) - { - return validgun(gun) && gun != exclude && ammo[gun] > 0; } }; -#define MAXTEAMS 2 -static const char * const teamnames[1+MAXTEAMS] = { "", "azul", "rojo" }; -static const char * const teamtextcode[1+MAXTEAMS] = { "\f0", "\f1", "\f3" }; -static const int teamtextcolor[1+MAXTEAMS] = { 0x1EC850, 0x6496FF, 0xFF4B19 }; -static const char * const teamblipcolor[1+MAXTEAMS] = { "_neutral", "_blue", "_red" }; -static inline int teamnumber(const char *name) { loopi(MAXTEAMS) if(!strcmp(teamnames[1+i], name)) return 1+i; return 0; } -#define validteam(n) ((n) >= 1 && (n) <= MAXTEAMS) -#define teamname(n) (teamnames[validteam(n) ? (n) : 0]) - struct gameent : dynent, gamestate { int weight; // affects the effectiveness of hitpush int clientnum, lastupdate, plag, ping; int lifesequence; // sequence id for each respawn, used in damage test - int respawned, suicided; - int lastpain; - int lastaction, lastattack; - int attacking; - int lasttaunt; - int lastpickup, lastpickupmillis, flagpickup; - int frags, flags, deaths, totaldamage, totalshots; + int respawned; + int lastaction; editinfo *edit; float deltayaw, deltapitch, deltaroll, newyaw, newpitch, newroll; int smoothmillis; @@ -346,7 +182,7 @@ struct gameent : dynent, gamestate vec muzzle; - gameent() : weight(100), clientnum(-1), lastupdate(0), plag(0), ping(0), lifesequence(0), respawned(-1), suicided(-1), lastpain(0), frags(0), flags(0), deaths(0), totaldamage(0), totalshots(0), edit(NULL), smoothmillis(-1), team(0), playermodel(-1), playercolor(0), ownernum(-1), muzzle(-1, -1, -1) + gameent() : weight(100), clientnum(-1), lastupdate(0), plag(0), ping(0), lifesequence(0), respawned(-1), edit(NULL), smoothmillis(-1), team(0), playermodel(-1), playercolor(0), ownernum(-1), muzzle(-1, -1, -1) { name[0] = info[0] = 0; respawn(); @@ -356,40 +192,24 @@ struct gameent : dynent, gamestate freeeditinfo(edit); } - void hitpush(int damage, const vec &dir, gameent *actor, int atk) - { - vec push(dir); - push.mul((actor==this && attacks[atk].exprad ? EXP_SELFPUSH : 1.0f)*attacks[atk].hitpush*damage/weight); - vel.add(push); - } - void respawn() { dynent::reset(); gamestate::respawn(); - respawned = suicided = -1; + respawned = -1; lastaction = 0; - lastattack = -1; - attacking = ACT_IDLE; - lasttaunt = 0; - lastpickup = -1; - lastpickupmillis = 0; - flagpickup = 0; lastnode = -1; } int respawnwait(int secs, int delay = 0) { - return max(0, secs - (::lastmillis - lastpain - delay)/1000); + return 0; } void startgame() { - frags = flags = deaths = 0; - totaldamage = totalshots = 0; - maxhealth = 1; lifesequence = -1; - respawned = suicided = -2; + respawned = -2; } }; @@ -417,10 +237,6 @@ namespace entities extern void spawnitems(bool force = false); extern void putitems(packetbuf &p); extern void setspawn(int i, bool on); - extern void teleport(int n, gameent *d); - extern void pickupeffects(int n, gameent *d); - extern void teleporteffects(gameent *d, int tp, int td, bool local = true); - extern void jumppadeffects(gameent *d, int jp, bool local = true); } namespace game @@ -437,7 +253,7 @@ namespace game virtual void setup() {} virtual void checkitems(gameent *d) {} virtual int respawnwait(gameent *d, int delay = 0) { return 0; } - virtual void pickspawn(gameent *d) { findplayerspawn(d, -1, m_teammode ? d->team : 0); } + virtual void pickspawn(gameent *d) { findplayerspawn(d, -1, 0); } virtual void senditems(packetbuf &p) {} virtual void removeplayer(gameent *d) {} virtual void gameover() {} @@ -449,7 +265,6 @@ namespace game // game extern string clientmap; - extern bool intermission; extern int maptime, maprealtime, maplimit; extern gameent *player1; extern vector players, clients; @@ -462,10 +277,6 @@ namespace game extern gameent *getclient(int cn); extern gameent *newclient(int cn); extern const char *colorname(gameent *d, const char *name = NULL, const char *alt = NULL, const char *color = ""); - extern const char *teamcolorname(gameent *d, const char *alt = "you"); - extern const char *teamcolor(const char *prefix, const char *suffix, int team, const char *alt); - extern void teamsound(bool sameteam, int n, const vec *loc = NULL); - extern void teamsound(gameent *d, int n, const vec *loc = NULL); extern gameent *pointatplayer(); extern gameent *hudplayer(); extern gameent *followingplayer(gameent *fallback = NULL); @@ -477,13 +288,8 @@ namespace game extern void startgame(); extern void spawnplayer(gameent *); extern void deathstate(gameent *d, bool restore = false); - extern void damaged(int damage, gameent *d, gameent *actor, bool local = true); - extern void killed(gameent *d, gameent *actor); extern void timeupdate(int timeremain); extern void msgsound(int n, physent *d = NULL); - extern void drawicon(int icon, float x, float y, float sz = 120); - const char *mastermodecolor(int n, const char *unknown); - const char *mastermodeicon(int n, const char *unknown); // client extern bool connected, remote, demoplayback; @@ -492,45 +298,16 @@ namespace game extern int parseplayer(const char *arg); extern bool addmsg(int type, const char *fmt = NULL, ...); - extern void switchname(const char *name); - extern void switchteam(const char *name); - extern void switchplayermodel(int playermodel); - extern void switchplayercolor(int playercolor); extern void sendmapinfo(); extern void changemap(const char *name, int mode); extern void c2sinfo(bool force = false); extern void sendposition(gameent *d, bool reliable = false); - // weapon - extern int getweapon(const char *name); - extern void shoot(gameent *d, const vec &targ); - extern void shoteffects(int atk, const vec &from, const vec &to, gameent *d, bool local, int id, int prevaction); - extern void explode(bool local, gameent *owner, const vec &v, const vec &vel, dynent *safe, int dam, int atk); - extern void explodeeffects(int atk, gameent *d, bool local, int id = 0); - extern void damageeffect(int damage, gameent *d, bool thirdperson = true); - extern void gibeffect(int damage, const vec &vel, gameent *d); - extern float intersectdist; - extern bool intersect(dynent *d, const vec &from, const vec &to, float margin = 0, float &dist = intersectdist); - extern dynent *intersectclosest(const vec &from, const vec &to, gameent *at, float margin = 0, float &dist = intersectdist); - extern void clearbouncers(); - extern void updatebouncers(int curtime); - extern void removebouncers(gameent *owner); - extern void renderbouncers(); - extern void clearprojectiles(); - extern void updateprojectiles(int curtime); - extern void removeprojectiles(gameent *owner); - extern void renderprojectiles(); - extern void preloadbouncers(); - extern void removeweapons(gameent *owner); - extern void updateweapons(int curtime); - extern void gunselect(int gun, gameent *d); - extern void weaponswitch(gameent *d); - // render struct playermodelinfo { - const char *model[1+MAXTEAMS], *hudguns[1+MAXTEAMS], - *icon[1+MAXTEAMS]; + const char *model[1], *hudguns[1], + *icon[1]; bool ragdoll; }; @@ -541,21 +318,13 @@ namespace game extern int getplayercolor(gameent *d, int team); extern int chooserandomplayermodel(int seed); extern void syncplayer(); - extern void swayhudgun(int curtime); - extern vec hudgunorigin(int gun, const vec &from, const vec &to, gameent *d); } namespace server { - extern const char *modename(int n, const char *unknown = "unknown"); - extern const char *modeprettyname(int n, const char *unknown = "unknown"); - extern const char *mastermodename(int n, const char *unknown = "unknown"); - extern void startintermission(); - extern void stopdemo(); extern void forcemap(const char *map, int mode); extern void forcepaused(bool paused); extern void forcegamespeed(int speed); - extern void hashpassword(int cn, int sessionid, const char *pwd, char *result, int maxlen = MAXSTRLEN); extern int msgsizelookup(int msg); extern bool serveroption(const char *arg); extern bool delayspawn(int type); diff --git a/src/game/render.cc b/src/game/render.cc index 0d7f738..22cf5e1 100644 --- a/src/game/render.cc +++ b/src/game/render.cc @@ -2,528 +2,60 @@ namespace game { - vector bestplayers; - vector bestteams; - - VARP(ragdoll, 0, 1, 1); - VARP(ragdollmillis, 0, 10000, 300000); - VARP(ragdollfade, 0, 100, 5000); - VARP(forceplayermodels, 0, 0, 1); - VARP(hidedead, 0, 0, 1); - - extern int playermodel; - - vector ragdolls; - void saveragdoll(gameent *d) { - if(!d->ragdoll || !ragdollmillis || (!ragdollfade && lastmillis > d->lastpain + ragdollmillis)) return; - gameent *r = new gameent(*d); - r->lastupdate = ragdollfade && lastmillis > d->lastpain + max(ragdollmillis - ragdollfade, 0) ? lastmillis - max(ragdollmillis - ragdollfade, 0) : d->lastpain; - r->edit = NULL; - if(d==player1) r->playermodel = playermodel; - ragdolls.add(r); - d->ragdoll = NULL; } void clearragdolls() { - ragdolls.deletecontents(); } void moveragdolls() { - loopv(ragdolls) - { - gameent *d = ragdolls[i]; - if(lastmillis > d->lastupdate + ragdollmillis) - { - delete ragdolls.remove(i--); - continue; - } - moveragdoll(d); - } - } - - static const int playercolors[] = - { - 0xA12020, - 0xA15B28, - 0xB39D52, - 0x3E752F, - 0x3F748C, - 0x214C85, - 0xB3668C, - 0x523678, - 0xB3ADA3 - }; - - static const int playercolorsazul[] = - { - 0x27508A, - 0x3F748C, - 0x3B3B80, - 0x5364B5 - }; - - static const int playercolorsrojo[] = - { - 0xAC2C2A, - 0x992417, - 0x802438, - 0xA3435B - }; - - extern void changedplayercolor(); - VARFP(playercolor, 0, 4, sizeof(playercolors)/sizeof(playercolors[0])-1, changedplayercolor()); - VARFP(playercolorazul, 0, 0, sizeof(playercolorsazul)/sizeof(playercolorsazul[0])-1, changedplayercolor()); - VARFP(playercolorrojo, 0, 0, sizeof(playercolorsrojo)/sizeof(playercolorsrojo[0])-1, changedplayercolor()); - - static const playermodelinfo playermodels[] = - { - { { "player/bones", "player/bones", "player/bones" }, { "hudgun", "hudgun", "hudgun" }, { "player", "player_azul", "player_rojo" }, true } - }; - - extern void changedplayermodel(); - VARFP(playermodel, 0, 0, sizeof(playermodels)/sizeof(playermodels[0])-1, changedplayermodel()); - - int chooserandomplayermodel(int seed) - { - return (seed&0xFFFF)%(sizeof(playermodels)/sizeof(playermodels[0])); - } - - const playermodelinfo *getplayermodelinfo(int n) - { - if(size_t(n) >= sizeof(playermodels)/sizeof(playermodels[0])) return NULL; - return &playermodels[n]; - } - - const playermodelinfo &getplayermodelinfo(gameent *d) - { - const playermodelinfo *mdl = getplayermodelinfo(d==player1 || forceplayermodels ? playermodel : d->playermodel); - if(!mdl) mdl = getplayermodelinfo(playermodel); - return *mdl; - } - - int getplayercolor(int team, int color) - { - #define GETPLAYERCOLOR(playercolors) \ - return playercolors[color%(sizeof(playercolors)/sizeof(playercolors[0]))]; - switch(team) - { - case 1: GETPLAYERCOLOR(playercolorsazul) - case 2: GETPLAYERCOLOR(playercolorsrojo) - default: GETPLAYERCOLOR(playercolors) - } - } - - ICOMMAND(getplayercolor, "ii", (int *color, int *team), intret(getplayercolor(*team, *color))); - - int getplayercolor(gameent *d, int team) - { - if(d==player1) switch(team) - { - case 1: return getplayercolor(1, playercolorazul); - case 2: return getplayercolor(2, playercolorrojo); - default: return getplayercolor(0, playercolor); - } - else return getplayercolor(team, (d->playercolor>>(5*team))&0x1F); } void changedplayermodel() { - if(player1->clientnum < 0) player1->playermodel = playermodel; - if(player1->ragdoll) cleanragdoll(player1); - loopv(ragdolls) - { - gameent *d = ragdolls[i]; - if(!d->ragdoll) continue; - if(!forceplayermodels) - { - const playermodelinfo *mdl = getplayermodelinfo(d->playermodel); - if(mdl) continue; - } - cleanragdoll(d); - } - loopv(players) - { - gameent *d = players[i]; - if(d == player1 || !d->ragdoll) continue; - if(!forceplayermodels) - { - const playermodelinfo *mdl = getplayermodelinfo(d->playermodel); - if(mdl) continue; - } - cleanragdoll(d); - } - } - - void changedplayercolor() - { - if(player1->clientnum < 0) player1->playercolor = playercolor | (playercolorazul<<5) | (playercolorrojo<<10); } void syncplayer() { - if(player1->playermodel != playermodel) - { - player1->playermodel = playermodel; - addmsg(N_SWITCHMODEL, "ri", player1->playermodel); - } - - int col = playercolor | (playercolorazul<<5) | (playercolorrojo<<10); - if(player1->playercolor != col) - { - player1->playercolor = col; - addmsg(N_SWITCHCOLOR, "ri", player1->playercolor); - } } void preloadplayermodel() { - loopi(sizeof(playermodels)/sizeof(playermodels[0])) - { - const playermodelinfo *mdl = getplayermodelinfo(i); - if(!mdl) break; - if(i != playermodel && (!multiplayer(false) || forceplayermodels)) continue; - if(m_teammode) - { - loopj(MAXTEAMS) preloadmodel(mdl->model[1+j]); - } - else preloadmodel(mdl->model[0]); - } } - int numanims() { return NUMANIMS; } - - void findanims(const char *pattern, vector &anims) + void renderplayer(gameent *d, const playermodelinfo &mdl, int color, float fade, int flags = 0, bool mainpass = true) { - loopi(sizeof(animnames)/sizeof(animnames[0])) if(matchanim(animnames[i], pattern)) anims.add(i); - } - - VAR(animoverride, -1, 0, NUMANIMS-1); - VAR(testanims, 0, 0, 1); - VAR(testpitch, -90, 0, 90); - - void renderplayer(gameent *d, const playermodelinfo &mdl, int color, int team, float fade, int flags = 0, bool mainpass = true) - { - int lastaction = d->lastaction, anim = ANIM_IDLE|ANIM_LOOP, attack = 0, delay = 0; - if(d->lastattack >= 0) - { - attack = attacks[d->lastattack].anim; - delay = attacks[d->lastattack].attackdelay+50; - } - if(intermission && d->state!=CS_DEAD) - { - anim = attack = ANIM_LOSE|ANIM_LOOP; - if(validteam(team) ? bestteams.htfind(team)>=0 : bestplayers.find(d)>=0) anim = attack = ANIM_WIN|ANIM_LOOP; - } - else if(d->state==CS_ALIVE && d->lasttaunt && lastmillis-d->lasttaunt<1000 && lastmillis-d->lastaction>delay) - { - lastaction = d->lasttaunt; - anim = attack = ANIM_TAUNT; - delay = 1000; - } - modelattach a[5]; - int ai = 0; - if(guns[d->gunselect].vwep) - { - int vanim = ANIM_VWEP_IDLE|ANIM_LOOP, vtime = 0; - if(lastaction && d->lastattack >= 0 && attacks[d->lastattack].gun==d->gunselect && lastmillis < lastaction + delay) - { - vanim = attacks[d->lastattack].vwepanim; - vtime = lastaction; - } - a[ai++] = modelattach("tag_weapon", guns[d->gunselect].vwep, vanim, vtime); - } - if(mainpass && !(flags&MDL_ONLYSHADOW)) - { - d->muzzle = vec(-1, -1, -1); - if(guns[d->gunselect].vwep) a[ai++] = modelattach("tag_muzzle", &d->muzzle); - } - const char *mdlname = mdl.model[validteam(team) ? team : 0]; - float yaw = testanims && d==player1 ? 0 : d->yaw, - pitch = testpitch && d==player1 ? testpitch : d->pitch; - vec o = d->feetpos(); - int basetime = 0; - if(animoverride) anim = (animoverride<0 ? ANIM_ALL : animoverride)|ANIM_LOOP; - else if(d->state==CS_DEAD) - { - anim = ANIM_DYING|ANIM_NOPITCH; - basetime = d->lastpain; - if(ragdoll && mdl.ragdoll) anim |= ANIM_RAGDOLL; - else if(lastmillis-basetime>1000) anim = ANIM_DEAD|ANIM_LOOP|ANIM_NOPITCH; - } - else if(d->state==CS_EDITING || d->state==CS_SPECTATOR) anim = ANIM_EDIT|ANIM_LOOP; - else if(d->state==CS_LAGGED) anim = ANIM_LAG|ANIM_LOOP; - else if(!intermission) - { - if(lastmillis-d->lastpain < 300) - { - anim = ANIM_PAIN; - basetime = d->lastpain; - } - else if(d->lastpain < lastaction && lastmillis-lastaction < delay) - { - anim = attack; - basetime = lastaction; - } - - if(d->inwater && d->physstate<=PHYS_FALL) anim |= (((game::allowmove(d) && (d->move || d->strafe)) || d->vel.z+d->falling.z>0 ? ANIM_SWIM : ANIM_SINK)|ANIM_LOOP)<move+1)*3 + (d->strafe+1)]; - if(d->timeinair>100) anim |= ((dir ? dir+ANIM_JUMP_N-ANIM_RUN_N : ANIM_JUMP) | ANIM_END) << ANIM_SECONDARY; - else if(dir && game::allowmove(d)) anim |= (dir | ANIM_LOOP) << ANIM_SECONDARY; - } - - if(d->crouching) switch((anim>>ANIM_SECONDARY)&ANIM_INDEX) - { - case ANIM_IDLE: anim &= ~(ANIM_INDEX<>ANIM_SECONDARY)&ANIM_INDEX) anim >>= ANIM_SECONDARY; - } - if(!((anim>>ANIM_SECONDARY)&ANIM_INDEX)) anim |= (ANIM_IDLE|ANIM_LOOP)<type==ENT_PLAYER) flags |= MDL_FULLBRIGHT; - else flags |= MDL_CULL_DIST; - if(!mainpass) flags &= ~(MDL_FULLBRIGHT | MDL_CULL_VFC | MDL_CULL_OCCLUDED | MDL_CULL_QUERY | MDL_CULL_DIST); - float trans = d->state == CS_LAGGED ? 0.5f : 1.0f; - rendermodel(mdlname, anim, o, yaw, pitch, 0, flags, d, a[0].tag ? a : NULL, basetime, 0, fade, vec4(vec::hexcolor(color), trans)); } static inline void renderplayer(gameent *d, float fade = 1, int flags = 0) { - int team = m_teammode && validteam(d->team) ? d->team : 0; - renderplayer(d, getplayermodelinfo(d), getplayercolor(d, team), team, fade, flags); } void rendergame() { - if(intermission) - { - bestteams.shrink(0); - bestplayers.shrink(0); - } - - bool third = isthirdperson(); - gameent *f = followingplayer(), *exclude = third ? NULL : f; - loopv(players) - { - gameent *d = players[i]; - if(d == player1 || d->state==CS_SPECTATOR || d->state==CS_SPAWNING || d->lifesequence < 0 || d == exclude || (d->state==CS_DEAD && hidedead)) continue; - renderplayer(d); - copystring(d->info, colorname(d)); - if(d->state!=CS_DEAD) - { - int team = m_teammode && validteam(d->team) ? d->team : 0; - particle_text(d->abovehead(), d->info, PART_TEXT, 1, teamtextcolor[team], 2.0f); - } - } - loopv(ragdolls) - { - gameent *d = ragdolls[i]; - float fade = 1.0f; - if(ragdollmillis && ragdollfade) - fade -= clamp(float(lastmillis - (d->lastupdate + max(ragdollmillis - ragdollfade, 0)))/min(ragdollmillis, ragdollfade), 0.0f, 1.0f); - renderplayer(d, fade); - } - if(exclude) - renderplayer(exclude, 1, MDL_ONLYSHADOW); - else if(!f && (player1->state==CS_ALIVE || (player1->state==CS_EDITING && third) || (player1->state==CS_DEAD && !hidedead))) - renderplayer(player1, 1, third ? 0 : MDL_ONLYSHADOW); - entities::renderentities(); - renderbouncers(); - renderprojectiles(); - if(cmode) cmode->rendergame(); - } - - VARP(hudgun, 0, 1, 1); - VARP(hudgunsway, 0, 1, 1); - - FVAR(swaystep, 1, 35.0f, 100); - FVAR(swayside, 0, 0.10f, 1); - FVAR(swayup, -1, 0.15f, 1); - - float swayfade = 0, swayspeed = 0, swaydist = 0; - vec swaydir(0, 0, 0); - - void swayhudgun(int curtime) - { - gameent *d = hudplayer(); - if(d->state != CS_SPECTATOR) - { - if(d->physstate >= PHYS_SLOPE) - { - swayspeed = min(sqrtf(d->vel.x*d->vel.x + d->vel.y*d->vel.y), d->maxspeed); - swaydist += swayspeed*curtime/1000.0f; - swaydist = fmod(swaydist, 2*swaystep); - swayfade = 1; - } - else if(swayfade > 0) - { - swaydist += swayspeed*swayfade*curtime/1000.0f; - swaydist = fmod(swaydist, 2*swaystep); - swayfade -= 0.5f*(curtime*d->maxspeed)/(swaystep*1000.0f); - } - - float k = pow(0.7f, curtime/10.0f); - swaydir.mul(k); - vec vel(d->vel); - vel.add(d->falling); - swaydir.add(vec(vel).mul((1-k)/(15*max(vel.magnitude(), d->maxspeed)))); - } - } - - struct hudent : dynent - { - hudent() { type = ENT_CAMERA; } - } guninterp; - - void drawhudmodel(gameent *d, int anim, int basetime) - { - const char *file = guns[d->gunselect].file; - if(!file) return; - - vec sway; - vecfromyawpitch(d->yaw, 0, 0, 1, sway); - float steps = swaydist/swaystep*M_PI; - sway.mul(swayside*cosf(steps)); - sway.z = swayup*(fabs(sinf(steps)) - 1); - sway.add(swaydir).add(d->o); - if(!hudgunsway) sway = d->o; - - const playermodelinfo &mdl = getplayermodelinfo(d); - int team = m_teammode && validteam(d->team) ? d->team : 0, - color = getplayercolor(d, team); - defformatstring(gunname, "%s/%s", mdl.hudguns[team], file); - modelattach a[2]; - d->muzzle = vec(-1, -1, -1); - a[0] = modelattach("tag_muzzle", &d->muzzle); - rendermodel(gunname, anim, sway, d->yaw, d->pitch, 0, MDL_NOBATCH, NULL, a, basetime, 0, 1, vec4(vec::hexcolor(color), 1)); - if(d->muzzle.x >= 0) d->muzzle = calcavatarpos(d->muzzle, 12); - } - - void drawhudgun() - { - gameent *d = hudplayer(); - if(d->state==CS_SPECTATOR || d->state==CS_EDITING || !hudgun || editmode) - { - d->muzzle = player1->muzzle = vec(-1, -1, -1); - return; - } - - int anim = ANIM_GUN_IDLE|ANIM_LOOP, basetime = 0; - if(d->lastaction && d->lastattack >= 0 && attacks[d->lastattack].gun==d->gunselect && lastmillis-d->lastactionlastattack].attackdelay) - { - anim = attacks[d->lastattack].hudanim; - basetime = d->lastaction; - } - drawhudmodel(d, anim, basetime); } void renderavatar() { - drawhudgun(); } - void renderplayerpreview(int model, int color, int team, int weap) + void renderplayerpreview(int model, int color, int weap) { - static gameent *previewent = NULL; - if(!previewent) - { - previewent = new gameent; - loopi(NUMGUNS) previewent->ammo[i] = 1; - } - float height = previewent->eyeheight + previewent->aboveeye, - zrad = height/2; - vec2 xyrad = vec2(previewent->xradius, previewent->yradius).max(height/4); - previewent->o = calcmodelpreviewpos(vec(xyrad, zrad), previewent->yaw).addz(previewent->eyeheight - zrad); - previewent->gunselect = validgun(weap) ? weap : GUN_RAIL; - const playermodelinfo *mdlinfo = getplayermodelinfo(model); - if(!mdlinfo) return; - renderplayer(previewent, *mdlinfo, getplayercolor(team, color), team, 1, 0, false); - } - - vec hudgunorigin(int gun, const vec &from, const vec &to, gameent *d) - { - if(d->muzzle.x >= 0) return d->muzzle; - vec offset(from); - if(d!=hudplayer() || isthirdperson()) - { - vec front, right; - vecfromyawpitch(d->yaw, d->pitch, 1, 0, front); - offset.add(front.mul(d->radius)); - offset.z += (d->aboveeye + d->eyeheight)*0.75f - d->eyeheight; - vecfromyawpitch(d->yaw, 0, 0, -1, right); - offset.add(right.mul(0.5f*d->radius)); - offset.add(front); - return offset; - } - offset.add(vec(to).sub(from).normalize().mul(2)); - if(hudgun) - { - offset.sub(vec(camup).mul(1.0f)); - offset.add(vec(camright).mul(0.8f)); - } - else offset.sub(vec(camup).mul(0.8f)); - return offset; } void preloadweapons() { - const playermodelinfo &mdl = getplayermodelinfo(player1); - loopi(NUMGUNS) - { - const char *file = guns[i].file; - if(!file) continue; - string fname; - if(m_teammode) - { - loopj(MAXTEAMS) - { - formatstring(fname, "%s/%s", mdl.hudguns[1+j], file); - preloadmodel(fname); - } - } - else - { - formatstring(fname, "%s/%s", mdl.hudguns[0], file); - preloadmodel(fname); - } - formatstring(fname, "worldgun/%s", file); - preloadmodel(fname); - } } void preloadsounds() { - //for(int i = S_JUMP; i <= S_DIE2; i++) preloadsound(i); } void preload() { - if(hudgun) preloadweapons(); - preloadbouncers(); - preloadplayermodel(); - preloadsounds(); entities::preloadentities(); } diff --git a/src/game/server.cc b/src/game/server.cc index ea86be6..c57ca62 100644 --- a/src/game/server.cc +++ b/src/game/server.cc @@ -47,81 +47,12 @@ namespace server bool flush(clientinfo *ci, int fmillis); }; - struct hitinfo - { - int target; - int lifesequence; - int rays; - float dist; - vec dir; - }; - - struct shotevent : timedevent - { - int id, atk; - vec from, to; - vector hits; - - void process(clientinfo *ci); - }; - - struct explodeevent : timedevent - { - int id, atk; - vector hits; - - bool keepable() const { return true; } - - void process(clientinfo *ci); - }; - - struct suicideevent : gameevent - { - void process(clientinfo *ci); - }; - - struct pickupevent : gameevent - { - int ent; - - void process(clientinfo *ci); - }; - - template - struct projectilestate - { - int projs[N]; - int numprojs; - - projectilestate() : numprojs(0) {} - - void reset() { numprojs = 0; } - - void add(int val) - { - if(numprojs>=N) numprojs = 0; - projs[numprojs++] = val; - } - - bool remove(int val) - { - loopi(numprojs) if(projs[i]==val) - { - projs[i] = projs[--numprojs]; - return true; - } - return false; - } - }; struct servstate : gamestate { vec o; int state, editstate; int lastdeath, deadflush, lastspawn, lifesequence; - int lastshot; - projectilestate<8> projs; - int frags, flags, deaths, shotdamage, damage; int lasttimeplayed, timeplayed; float effectiveness; @@ -134,18 +65,15 @@ namespace server bool waitexpired(int gamemillis) { - return gamemillis - lastshot >= gunwait; + return true; } void reset() { if(state!=CS_SPECTATOR) state = editstate = CS_DEAD; - maxhealth = 1; - projs.reset(); timeplayed = 0; effectiveness = 0; - frags = flags = deaths = shotdamage = damage = 0; lastdeath = 0; @@ -158,13 +86,11 @@ namespace server o = vec(-1e10f, -1e10f, -1e10f); deadflush = 0; lastspawn = -1; - lastshot = 0; } void reassign() { respawn(); - projs.reset(); } }; @@ -295,18 +221,6 @@ namespace server } }; - struct ban - { - int time, expire; - uint ip; - }; - - #define MM_MODE 0xF - #define MM_AUTOAPPROVE 0x1000 - #define MM_PRIVSERV (MM_MODE | MM_AUTOAPPROVE) - #define MM_PUBSERV ((1< allowedips; - vector bannedips; - - void addban(uint ip, int expire) - { - allowedips.removeobj(ip); - ban b; - b.time = totalmillis; - b.expire = totalmillis + expire; - b.ip = ip; - loopv(bannedips) if(bannedips[i].expire - b.expire > 0) { bannedips.insert(i, b); return; } - bannedips.add(b); - } - vector connects, clients; - bool searchmodename(const char *haystack, const char *needle) - { - if(!needle[0]) return true; - do - { - if(needle[0] != '.') - { - haystack = strchr(haystack, needle[0]); - if(!haystack) break; - haystack++; - } - const char *h = haystack, *n = needle+1; - for(; *h && *n; h++) - { - if(*h == *n) n++; - else if(*h != ' ') break; - } - if(!*n) return true; - if(*n == '.') return !*h; - } while(needle[0] != '.'); - return false; - } - - int genmodemask(vector &modes) - { - int modemask = 0; - loopv(modes) - { - const char *mode = modes[i]; - int op = mode[0]; - switch(mode[0]) - { - case '*': - modemask |= 1<= 0 && msg < NUMMSG ? sizetable[msg] : -1; } - const char *modename(int n, const char *unknown) - { - if(m_valid(n)) return gamemodes[n - STARTGAMEMODE].name; - return unknown; - } - - const char *modeprettyname(int n, const char *unknown) - { - if(m_valid(n)) return gamemodes[n - STARTGAMEMODE].prettyname; - return unknown; - } - - const char *mastermodename(int n, const char *unknown) - { - return (n>=MM_START && size_t(n-MM_START)team, actor->team)) return -1; + if(victim==actor) return -1; return 1; } virtual void died(clientinfo *victim, clientinfo *actor) {} @@ -521,7 +337,6 @@ namespace server virtual void cleanup() {} virtual void setup() {} virtual void newmap() {} - virtual void intermission() {} virtual bool hidefrags() { return false; } }; @@ -551,108 +366,7 @@ namespace server bool pickup(int i, int sender) // server side item pickup, acknowledge first client that gets it { - if((m_timed && gamemillis>=gamelimit) || !sents.inrange(i) || !sents[i].spawned) return false; - clientinfo *ci = getinfo(sender); - if(!ci) return false; - if(!ci->local && !ci->state.canpickup(sents[i].type)) - { - sendf(sender, 1, "ri3", N_ITEMACC, i, -1); - return false; - } - sents[i].spawned = false; - sents[i].spawntime = spawntime(sents[i].type); - sendf(-1, 1, "ri3", N_ITEMACC, i, sender); - ci->state.pickup(sents[i].type); - return true; - } - - static teaminfo teaminfos[MAXTEAMS]; - - void clearteaminfo() - { - loopi(MAXTEAMS) teaminfos[i].reset(); - } - - clientinfo *choosebestclient(float &bestrank) - { - clientinfo *best = NULL; - bestrank = -1; - loopv(clients) - { - clientinfo *ci = clients[i]; - if(ci->state.timeplayed<0) continue; - float rank = ci->state.state!=CS_SPECTATOR ? ci->state.effectiveness/max(ci->state.timeplayed, 1) : -1; - if(!best || rank > bestrank) { best = ci; bestrank = rank; } - } - return best; - } - - void autoteam() - { - vector team[MAXTEAMS]; - float teamrank[MAXTEAMS] = {0}; - for(int round = 0, remaining = clients.length(); remaining>=0; round++) - { - int first = round&1, second = (round+1)&1, selected = 0; - while(teamrank[first] <= teamrank[second]) - { - float rank; - clientinfo *ci = choosebestclient(rank); - if(!ci) break; - if(smode && smode->hidefrags()) rank = 1; - else if(selected && rank<=0) break; - ci->state.timeplayed = -1; - team[first].add(ci); - if(rank>0) teamrank[first] += rank; - selected++; - if(rank<=0) break; - } - if(!selected) break; - remaining -= selected; - } - loopi(MAXTEAMS) loopvj(team[i]) - { - clientinfo *ci = team[i][j]; - if(ci->team == 1+i) continue; - ci->team = 1+i; - sendf(-1, 1, "riiii", N_SETTEAM, ci->clientnum, ci->team, -1); - } - } - - struct teamrank - { - float rank; - int clients; - - teamrank() : rank(0), clients(0) {} - }; - - int chooseworstteam(clientinfo *exclude = NULL) - { - teamrank teamranks[MAXTEAMS]; - loopv(clients) - { - clientinfo *ci = clients[i]; - if(ci==exclude || ci->state.state==CS_SPECTATOR || !validteam(ci->team)) continue; - - ci->state.timeplayed += lastmillis - ci->state.lasttimeplayed; - ci->state.lasttimeplayed = lastmillis; - - teamrank &ts = teamranks[ci->team-1]; - ts.rank += ci->state.effectiveness/max(ci->state.timeplayed, 1); - ts.clients++; - } - teamrank *worst = &teamranks[0]; - for(int i = 1; i < MAXTEAMS; i++) - { - teamrank &ts = teamranks[i]; - if(smode && smode->hidefrags()) - { - if(ts.clients < worst->clients || (ts.clients == worst->clients && ts.rank < worst->rank)) worst = &ts; - } - else if(ts.rank < worst->rank || (ts.rank == worst->rank && ts.clients < worst->clients)) worst = &ts; - } - return 1+int(worst-teamranks); + return false; } int welcomepacket(packetbuf &p, clientinfo *ci); @@ -709,7 +423,7 @@ namespace server } uchar operator[](int msg) const { return msg >= 0 && msg < NUMMSG ? msgmask[msg] : 0; } - } msgfilter(-1, N_CONNECT, N_SERVINFO, N_INITCLIENT, N_WELCOME, N_MAPCHANGE, N_SERVMSG, N_DAMAGE, N_HITPUSH, N_SHOTFX, N_EXPLODEFX, N_DIED, N_SPAWNSTATE, N_FORCEDEATH, N_TEAMINFO, N_ITEMACC, N_ITEMSPAWN, N_TIMEUP, N_CDIS, N_PONG, N_RESUME, N_SENDMAP, N_CLIENT, -2, N_CALCLIGHT, N_REMIP, N_NEWMAP, N_GETMAP, N_SENDMAP, N_CLIPBOARD, -3, N_EDITENT, N_EDITF, N_EDITT, N_EDITM, N_FLIP, N_COPY, N_PASTE, N_ROTATE, N_REPLACE, N_DELCUBE, N_EDITVAR, N_EDITVSLOT, N_UNDO, N_REDO, -4, N_POS, NUMMSG); + } msgfilter(-1, N_CONNECT, N_SERVINFO, N_INITCLIENT, N_WELCOME, N_MAPCHANGE, N_SERVMSG, N_DAMAGE, N_HITPUSH, N_SHOTFX, N_EXPLODEFX, N_DIED, N_SPAWNSTATE, N_FORCEDEATH, N_CDIS, N_PONG, N_RESUME, N_SENDMAP, N_CLIENT, -2, N_CALCLIGHT, N_REMIP, N_NEWMAP, N_GETMAP, N_SENDMAP, N_CLIPBOARD, -3, N_EDITENT, N_EDITF, N_EDITT, N_EDITM, N_FLIP, N_COPY, N_PASTE, N_ROTATE, N_REPLACE, N_DELCUBE, N_EDITVAR, N_EDITVSLOT, N_UNDO, N_REDO, -4, N_POS, NUMMSG); int checktype(int type, clientinfo *ci) { @@ -892,10 +606,6 @@ namespace server void sendstate(servstate &gs, T &p) { putint(p, gs.lifesequence); - putint(p, gs.health); - putint(p, gs.maxhealth); - putint(p, gs.gunselect); - loopi(NUMGUNS) putint(p, gs.ammo[i]); } void spawnstate(clientinfo *ci) @@ -909,9 +619,8 @@ namespace server { servstate &gs = ci->state; spawnstate(ci); - sendf(ci->ownernum, 1, "rii5v", N_SPAWNSTATE, ci->clientnum, gs.lifesequence, - gs.health, gs.maxhealth, - gs.gunselect, NUMGUNS, gs.ammo); + sendf(ci->ownernum, 1, "rii4", N_SPAWNSTATE, ci->clientnum, gs.lifesequence, + 1, 1); gs.lastspawn = gamemillis; } @@ -927,9 +636,6 @@ namespace server putint(p, N_INITCLIENT); putint(p, ci->clientnum); sendstring(ci->name, p); - putint(p, ci->team); - putint(p, ci->playermodel); - putint(p, ci->playercolor); } void welcomeinitclient(packetbuf &p, int exclude = -1) @@ -945,8 +651,7 @@ namespace server bool hasmap(clientinfo *ci) { - return (m_edit && (clients.length() > 0 || ci->local)) || - (smapname[0] && (!m_timed || gamemillis < gamelimit || (ci->state.state==CS_SPECTATOR && !ci->local) || numclients(ci->clientnum, true, true, true))); + return true; } int welcomepacket(packetbuf &p, clientinfo *ci) @@ -956,11 +661,6 @@ namespace server sendstring(smapname, p); putint(p, gamemode); putint(p, notgotitems ? 1 : 0); - if(!ci || (m_timed && smapname[0])) - { - putint(p, N_TIMEUP); - putint(p, gamemillis < gamelimit && !interm ? max((gamelimit - gamemillis)/1000, 1) : 0); - } if(!notgotitems) { putint(p, N_ITEMLIST); @@ -983,15 +683,6 @@ namespace server putint(p, gamespeed); putint(p, -1); } - if(m_teammode) - { - putint(p, N_TEAMINFO); - loopi(MAXTEAMS) - { - teaminfo &t = teaminfos[i]; - putint(p, t.frags); - } - } if(ci) { putint(p, N_SETTEAM); @@ -999,25 +690,6 @@ namespace server putint(p, ci->team); putint(p, -1); } - if(ci && m_mp(gamemode) && ci->state.state!=CS_SPECTATOR) - { - if(smode && !smode->canspawn(ci, true)) - { - ci->state.state = CS_DEAD; - putint(p, N_FORCEDEATH); - putint(p, ci->clientnum); - sendf(-1, 1, "ri2x", N_FORCEDEATH, ci->clientnum, ci->clientnum); - } - else - { - servstate &gs = ci->state; - spawnstate(ci); - putint(p, N_SPAWNSTATE); - putint(p, ci->clientnum); - sendstate(gs, p); - gs.lastspawn = gamemillis; - } - } if(ci && ci->state.state==CS_SPECTATOR) { putint(p, N_SPECTATOR); @@ -1034,9 +706,6 @@ namespace server if(ci && oi->clientnum==ci->clientnum) continue; putint(p, oi->clientnum); putint(p, oi->state.state); - putint(p, oi->state.frags); - putint(p, oi->state.flags); - putint(p, oi->state.deaths); sendstate(oi->state, p); } putint(p, -1); @@ -1049,11 +718,9 @@ namespace server void sendresume(clientinfo *ci) { servstate &gs = ci->state; - sendf(-1, 1, "ri3i7vi", N_RESUME, ci->clientnum, gs.state, - gs.frags, gs.flags, gs.deaths, + sendf(-1, 1, "ri3ii", N_RESUME, ci->clientnum, gs.state, gs.lifesequence, - gs.health, gs.maxhealth, - gs.gunselect, NUMGUNS, gs.ammo, -1); + -1); } void sendinitclient(clientinfo *ci) @@ -1074,8 +741,7 @@ namespace server server_entity se = { NOTUSED, 0, false }; while(sents.length()<=i) sents.add(se); sents[i].type = ments[i].type; - if(m_mp(gamemode) && delayspawn(sents[i].type)) sents[i].spawntime = spawntime(sents[i].type); - else sents[i].spawned = true; + sents[i].spawned = true; } notgotitems = false; } @@ -1088,7 +754,7 @@ namespace server gamemode = mode; gamemillis = 0; - gamelimit = (m_overtime ? 15 : 10)*60000; + gamelimit = 600000; interm = 0; nextexceeded = 0; copystring(smapname, s); @@ -1099,22 +765,17 @@ namespace server ci->state.timeplayed += lastmillis - ci->state.lasttimeplayed; } - if(!m_mp(gamemode)) kicknonlocalclients(DISC_LOCAL); + kicknonlocalclients(DISC_LOCAL); sendf(-1, 1, "risii", N_MAPCHANGE, smapname, gamemode, 1); - clearteaminfo(); - if(m_teammode) autoteam(); - smode = NULL; - if(m_timed && smapname[0]) sendf(-1, 1, "ri2", N_TIMEUP, gamemillis < gamelimit && !interm ? max((gamelimit - gamemillis)/1000, 1) : 0); loopv(clients) { clientinfo *ci = clients[i]; ci->mapchange(); ci->state.lasttimeplayed = lastmillis; - if(m_mp(gamemode) && ci->state.state!=CS_SPECTATOR) sendspawn(ci); } if(smode) smode->setup(); @@ -1125,156 +786,6 @@ namespace server changemap(map, mode); } - void checkintermission() - { - if(gamemillis >= gamelimit && !interm) - { - sendf(-1, 1, "ri2", N_TIMEUP, 0); - if(smode) smode->intermission(); - changegamespeed(100); - interm = gamemillis + 10000; - } - } - - void startintermission() { gamelimit = min(gamelimit, gamemillis); checkintermission(); } - - void dodamage(clientinfo *target, clientinfo *actor, int damage, int atk, const vec &hitpush = vec(0, 0, 0)) - { - servstate &ts = target->state; - ts.dodamage(damage); - if(target!=actor && !isteam(target->team, actor->team)) actor->state.damage += damage; - sendf(-1, 1, "ri5", N_DAMAGE, target->clientnum, actor->clientnum, damage, ts.health); - if(target==actor) target->setpushed(); - else if(!hitpush.iszero()) - { - ivec v(vec(hitpush).rescale(DNF)); - sendf(ts.health<=0 ? -1 : target->ownernum, 1, "ri7", N_HITPUSH, target->clientnum, atk, damage, v.x, v.y, v.z); - target->setpushed(); - } - if(ts.health<=0) - { - target->state.deaths++; - int fragvalue = smode ? smode->fragvalue(target, actor) : (target==actor || isteam(target->team, actor->team) ? -1 : 1); - actor->state.frags += fragvalue; - if(fragvalue>0) - { - int friends = 0, enemies = 0; // note: friends also includes the fragger - if(m_teammode) loopv(clients) if(clients[i]->team != actor->team) enemies++; else friends++; - else { friends = 1; enemies = clients.length()-1; } - actor->state.effectiveness += fragvalue*friends/float(max(enemies, 1)); - } - teaminfo *t = m_teammode && validteam(actor->team) ? &teaminfos[actor->team-1] : NULL; - if(t) t->frags += fragvalue; - sendf(-1, 1, "ri5", N_DIED, target->clientnum, actor->clientnum, actor->state.frags, t ? t->frags : 0); - target->position.setsize(0); - if(smode) smode->died(target, actor); - ts.state = CS_DEAD; - ts.lastdeath = gamemillis; - ts.deadflush = ts.lastdeath + DEATHMILLIS; - // don't issue respawn yet until DEATHMILLIS has elapsed - // ts.respawn(); - } - } - - void suicide(clientinfo *ci) - { - servstate &gs = ci->state; - if(gs.state!=CS_ALIVE) return; - int fragvalue = smode ? smode->fragvalue(ci, ci) : -1; - ci->state.frags += fragvalue; - ci->state.deaths++; - teaminfo *t = m_teammode && validteam(ci->team) ? &teaminfos[ci->team-1] : NULL; - if(t) t->frags += fragvalue; - sendf(-1, 1, "ri5", N_DIED, ci->clientnum, ci->clientnum, gs.frags, t ? t->frags : 0); - ci->position.setsize(0); - if(smode) smode->died(ci, NULL); - gs.state = CS_DEAD; - gs.lastdeath = gamemillis; - gs.respawn(); - } - - void suicideevent::process(clientinfo *ci) - { - suicide(ci); - } - - void explodeevent::process(clientinfo *ci) - { - servstate &gs = ci->state; - switch(atk) - { - case ATK_PULSE_SHOOT: - if(!gs.projs.remove(id)) return; - break; - - default: - return; - } - sendf(-1, 1, "ri4x", N_EXPLODEFX, ci->clientnum, atk, id, ci->ownernum); - loopv(hits) - { - hitinfo &h = hits[i]; - clientinfo *target = getinfo(h.target); - if(!target || target->state.state!=CS_ALIVE || h.lifesequence!=target->state.lifesequence || h.dist<0 || h.dist>attacks[atk].exprad) continue; - - bool dup = false; - loopj(i) if(hits[j].target==h.target) { dup = true; break; } - if(dup) continue; - - float damage = attacks[atk].damage*(1-h.dist/EXP_DISTSCALE/attacks[atk].exprad); - if(target==ci) damage /= EXP_SELFDAMDIV; - if(damage > 0) dodamage(target, ci, max(int(damage), 1), atk, h.dir); - } - } - - void shotevent::process(clientinfo *ci) - { - servstate &gs = ci->state; - int wait = millis - gs.lastshot; - if(!gs.isalive(gamemillis) || - wait attacks[atk].range + 1)) - return; - gs.ammo[gun] -= attacks[atk].use; - gs.lastshot = millis; - gs.gunwait = attacks[atk].attackdelay; - sendf(-1, 1, "rii9x", N_SHOTFX, ci->clientnum, atk, id, - int(from.x*DMF), int(from.y*DMF), int(from.z*DMF), - int(to.x*DMF), int(to.y*DMF), int(to.z*DMF), - ci->ownernum); - gs.shotdamage += attacks[atk].damage*attacks[atk].rays; - switch(atk) - { - case ATK_PULSE_SHOOT: gs.projs.add(id); break; - default: - { - int totalrays = 0, maxrays = attacks[atk].rays; - loopv(hits) - { - hitinfo &h = hits[i]; - clientinfo *target = getinfo(h.target); - if(!target || target->state.state!=CS_ALIVE || h.lifesequence!=target->state.lifesequence || h.rays<1 || h.dist > attacks[atk].range + 1) continue; - - totalrays += h.rays; - if(totalrays>maxrays) continue; - int damage = h.rays*attacks[atk].damage; - dodamage(target, ci, damage, atk, h.dir); - } - break; - } - } - } - - void pickupevent::process(clientinfo *ci) - { - servstate &gs = ci->state; - if(m_mp(gamemode) && !gs.isalive(gamemillis)) return; - pickup(ent, ci->clientnum); - } - bool gameevent::flush(clientinfo *ci, int fmillis) { process(ci); @@ -1343,30 +854,13 @@ namespace server { gamemillis += curtime; - if(!m_timed || gamemillis < gamelimit) - { - processevents(); - if(curtime) - { - loopv(sents) if(sents[i].spawntime) // spawn entities when timer reached - { - sents[i].spawntime -= curtime; - if(sents[i].spawntime<=0) - { - sents[i].spawntime = 0; - sents[i].spawned = true; - sendf(-1, 1, "ri2", N_ITEMSPAWN, i); - } - } - } - if(smode) smode->update(); - } + processevents(); + if(smode) smode->update(); } - while(bannedips.length() && bannedips[0].expire-totalmillis <= 0) bannedips.remove(0); loopv(connects) if(totalmillis-connects[i]->connectmillis>15000) disconnect_client(connects[i]->clientnum, DISC_TIMEOUT); - if(nextexceeded && gamemillis > nextexceeded && (!m_timed || gamemillis < gamelimit)) + if(nextexceeded && gamemillis > nextexceeded) { nextexceeded = 0; loopvrev(clients) @@ -1379,7 +873,6 @@ namespace server if(shouldstep && !gamepaused) { - if(m_timed && smapname[0] && gamemillis-curtime>0) checkintermission(); if(interm > 0 && gamemillis>interm) { interm = -1; @@ -1389,15 +882,6 @@ namespace server shouldstep = clients.length() > 0; } - void forcespectator(clientinfo *ci) - { - if(ci->state.state==CS_ALIVE) suicide(ci); - if(smode) smode->leavegame(ci); - ci->state.state = CS_SPECTATOR; - ci->state.timeplayed += lastmillis - ci->state.lasttimeplayed; - sendf(-1, 1, "ri3", N_SPECTATOR, ci->clientnum, 1); - } - struct crcinfo { int crc, matches; @@ -1407,66 +891,14 @@ namespace server static bool compare(const crcinfo &x, const crcinfo &y) { return x.matches > y.matches; } }; - - VAR(modifiedmapspectator, 0, 1, 2); void checkmaps(int req = -1) { - if(m_edit || !smapname[0]) return; - vector crcs; - int total = 0, unsent = 0, invalid = 0; - if(mcrc) crcs.add(crcinfo(mcrc, clients.length() + 1)); - loopv(clients) - { - clientinfo *ci = clients[i]; - if(ci->state.state==CS_SPECTATOR) continue; - total++; - if(!ci->clientmap[0]) - { - if(ci->mapcrc < 0) invalid++; - else if(!ci->mapcrc) unsent++; - } - else - { - crcinfo *match = NULL; - loopvj(crcs) if(crcs[j].crc == ci->mapcrc) { match = &crcs[j]; break; } - if(!match) crcs.add(crcinfo(ci->mapcrc, 1)); - else match->matches++; - } - } - if(!mcrc && total - unsent < min(total, 4)) return; - crcs.sort(crcinfo::compare); - string msg; - loopv(clients) - { - clientinfo *ci = clients[i]; - if(ci->state.state==CS_SPECTATOR || ci->clientmap[0] || ci->mapcrc >= 0 || (req < 0 && ci->warned)) continue; - formatstring(msg, "%s has modified map \"%s\"", colorname(ci), smapname); - sendf(req, 1, "ris", N_SERVMSG, msg); - if(req < 0) ci->warned = true; - } - if(crcs.length() >= 2) loopv(crcs) - { - crcinfo &info = crcs[i]; - if(i || info.matches <= crcs[i+1].matches) loopvj(clients) - { - clientinfo *ci = clients[j]; - if(ci->state.state==CS_SPECTATOR || !ci->clientmap[0] || ci->mapcrc != info.crc || (req < 0 && ci->warned)) continue; - formatstring(msg, "%s has modified map \"%s\"", colorname(ci), smapname); - sendf(req, 1, "ris", N_SERVMSG, msg); - if(req < 0) ci->warned = true; - } - } - if(req < 0 && modifiedmapspectator && (mcrc || modifiedmapspectator > 1)) loopv(clients) - { - clientinfo *ci = clients[i]; - if(!ci->local && ci->warned && ci->state.state != CS_SPECTATOR) forcespectator(ci); - } } bool shouldspectate(clientinfo *ci) { - return !ci->local && ci->warned && modifiedmapspectator && (mcrc || modifiedmapspectator > 1); + return false; } void unspectate(clientinfo *ci) @@ -1486,7 +918,6 @@ namespace server void noclients() { - bannedips.shrink(0); } void localconnect(int n) @@ -1514,9 +945,7 @@ namespace server ci->sessionid = (rnd(0x1000000)*((totalmillis%10000)+1))&0xFFFFFF; connects.add(ci); - if(!m_mp(gamemode)) return DISC_LOCAL; - sendservinfo(ci); - return DISC_NONE; + return DISC_LOCAL; } void clientdisconnect(int n) @@ -1556,7 +985,6 @@ namespace server void receivefile(int sender, uchar *data, int len) { - if(!m_edit || len <= 0 || len > 4*1024*1024) return; clientinfo *ci = getinfo(sender); if(ci->state.state==CS_SPECTATOR && !ci->local) return; if(mapdata) DELETEP(mapdata); @@ -1590,10 +1018,9 @@ namespace server ci->connected = true; ci->needclipboard = totalmillis ? totalmillis : 1; - if(mastermode>=MM_LOCKED) ci->state.state = CS_SPECTATOR; ci->state.lasttimeplayed = lastmillis; - ci->team = m_teammode ? chooseworstteam(ci) : 0; + ci->team = 0; sendwelcome(ci); sendinitclient(ci); @@ -1708,7 +1135,6 @@ namespace server ci->state.editstate = ci->state.state; ci->state.state = CS_EDITING; ci->events.setsize(0); - ci->state.projs.reset(); } else ci->state.state = ci->state.editstate; QUEUE_MSG; @@ -1737,10 +1163,6 @@ namespace server break; } - case N_CHECKMAPS: - checkmaps(sender); - break; - case N_TRYSPAWN: if(!ci || !cq || cq->state.state!=CS_DEAD || cq->state.lastspawn>=0 || (smode && !smode->canspawn(cq))) break; if(!ci->clientmap[0] && !ci->mapcrc) @@ -1761,11 +1183,10 @@ namespace server case N_SPAWN: { - int ls = getint(p), gunselect = getint(p); - if(!cq || (cq->state.state!=CS_ALIVE && cq->state.state!=CS_DEAD && cq->state.state!=CS_EDITING) || ls!=cq->state.lifesequence || cq->state.lastspawn<0 || !validgun(gunselect)) break; + int ls = getint(p); + if(!cq || (cq->state.state!=CS_ALIVE && cq->state.state!=CS_DEAD && cq->state.state!=CS_EDITING) || ls!=cq->state.lifesequence || cq->state.lastspawn<0) break; cq->state.lastspawn = -1; cq->state.state = CS_ALIVE; - cq->state.gunselect = gunselect; cq->exceeded = 0; if(smode) smode->spawned(cq); QUEUE_AI; @@ -1787,21 +1208,6 @@ namespace server break; } - case N_SAYTEAM: - { - getstring(text, p); - if(!ci || !cq || (ci->state.state==CS_SPECTATOR && !ci->local) || !m_teammode || !validteam(cq->team)) break; - filtertext(text, text, true, true); - loopv(clients) - { - clientinfo *t = clients[i]; - if(t==cq || t->state.state==CS_SPECTATOR || cq->team != t->team) continue; - sendf(t->clientnum, 1, "riis", N_SAYTEAM, cq->clientnum, text); - } - if(isdedicatedserver() && cq) logoutf("%s <%s>: %s", colorname(cq), teamnames[cq->team], text); - break; - } - case N_SWITCHNAME: { QUEUE_MSG; @@ -1864,10 +1270,6 @@ namespace server break; } - case N_FORCEINTERMISSION: - if(ci->local && !hasnonlocalclients()) startintermission(); - break; - case N_NEWMAP: { int size = getint(p); @@ -2006,8 +1408,8 @@ namespace server putint(p, maxclients); putint(p, gamepaused || gamespeed != 100 ? 5 : 3); // number of attrs following putint(p, gamemode); - putint(p, m_timed ? max((gamelimit - gamemillis)/1000, 0) : 0); - putint(p, MM_PRIVATE); + putint(p, 0); + putint(p, 0); if(gamepaused || gamespeed != 100) { putint(p, gamepaused ? 1 : 0); diff --git a/src/game/weapon.cc b/src/game/weapon.cc deleted file mode 100644 index 9fb1dd8..0000000 --- a/src/game/weapon.cc +++ /dev/null @@ -1,775 +0,0 @@ -// weapon.cpp: all shooting and effects code, projectile management -#include "game.hh" - -namespace game -{ - static const int OFFSETMILLIS = 500; - vec rays[MAXRAYS]; - - struct hitmsg - { - int target, lifesequence, info1, info2; - ivec dir; - }; - vector hits; - -#if 0 - #define MINDEBRIS 3 - VARP(maxdebris, MINDEBRIS, 10, 100); - VARP(maxgibs, 0, 4, 100); -#endif - - ICOMMAND(getweapon, "", (), intret(player1->gunselect)); - - void gunselect(int gun, gameent *d) - { - if(gun!=d->gunselect) - { - addmsg(N_GUNSELECT, "rci", d, gun); - playsound(S_WEAPLOAD, d == player1 ? NULL : &d->o); - } - d->gunselect = gun; - } - - void nextweapon(int dir, bool force = false) - { - if(player1->state!=CS_ALIVE) return; - dir = (dir < 0 ? NUMGUNS-1 : 1); - int gun = player1->gunselect; - loopi(NUMGUNS) - { - gun = (gun + dir)%NUMGUNS; - if(force || player1->ammo[gun]) break; - } - if(gun != player1->gunselect) gunselect(gun, player1); - else playsound(S_NOAMMO); - } - ICOMMAND(nextweapon, "ii", (int *dir, int *force), nextweapon(*dir, *force!=0)); - - int getweapon(const char *name) - { - if(isdigit(name[0])) return parseint(name); - else - { - int len = strlen(name); - loopi(sizeof(guns)/sizeof(guns[0])) if(!strncasecmp(guns[i].name, name, len)) return i; - } - return -1; - } - - void setweapon(const char *name, bool force = false) - { - int gun = getweapon(name); - if(player1->state!=CS_ALIVE || !validgun(gun)) return; - if(force || player1->ammo[gun]) gunselect(gun, player1); - else playsound(S_NOAMMO); - } - ICOMMAND(setweapon, "si", (char *name, int *force), setweapon(name, *force!=0)); - - void cycleweapon(int numguns, int *guns, bool force = false) - { - if(numguns<=0 || player1->state!=CS_ALIVE) return; - int offset = 0; - loopi(numguns) if(guns[i] == player1->gunselect) { offset = i+1; break; } - loopi(numguns) - { - int gun = guns[(i+offset)%numguns]; - if(gun>=0 && gunammo[gun])) - { - gunselect(gun, player1); - return; - } - } - playsound(S_NOAMMO); - } - ICOMMAND(cycleweapon, "V", (tagval *args, int numargs), - { - int numguns = min(numargs, 3); - int guns[3]; - loopi(numguns) guns[i] = getweapon(args[i].getstr()); - cycleweapon(numguns, guns); - }); - - void weaponswitch(gameent *d) - { - if(d->state!=CS_ALIVE) return; - int s = d->gunselect; - if(s!=GUN_PULSE && d->ammo[GUN_PULSE]) s = GUN_PULSE; - else if(s!=GUN_RAIL && d->ammo[GUN_RAIL]) s = GUN_RAIL; - gunselect(s, d); - } - - ICOMMAND(weapon, "V", (tagval *args, int numargs), - { - if(player1->state!=CS_ALIVE) return; - loopi(3) - { - const char *name = i < numargs ? args[i].getstr() : ""; - if(name[0]) - { - int gun = getweapon(name); - if(validgun(gun) && gun != player1->gunselect && player1->ammo[gun]) { gunselect(gun, player1); return; } - } else { weaponswitch(player1); return; } - } - playsound(S_NOAMMO); - }); - - void offsetray(const vec &from, const vec &to, int spread, float range, vec &dest) - { - vec offset; - do offset = vec(rndscale(1), rndscale(1), rndscale(1)).sub(0.5f); - while(offset.squaredlen() > 0.5f*0.5f); - offset.mul((to.dist(from)/1024)*spread); - offset.z /= 2; - dest = vec(offset).add(to); - if(dest != from) - { - vec dir = vec(dest).sub(from).normalize(); - raycubepos(from, dir, dest, range, RAY_CLIPMAT|RAY_ALPHAPOLY); - } - } - - void createrays(int atk, const vec &from, const vec &to) // create random spread of rays - { - loopi(attacks[atk].rays) offsetray(from, to, attacks[atk].spread, attacks[atk].range, rays[i]); - } - - enum { BNC_GIBS, BNC_DEBRIS }; - - struct bouncer : physent - { - int lifetime, bounces; - float lastyaw, roll; - bool local; - gameent *owner; - int bouncetype, variant; - vec offset; - int offsetmillis; - int id; - - bouncer() : bounces(0), roll(0), variant(0) - { - type = ENT_BOUNCE; - } - }; - - vector bouncers; - - void newbouncer(const vec &from, const vec &to, bool local, int id, gameent *owner, int type, int lifetime, int speed) - { - bouncer &bnc = *bouncers.add(new bouncer); - bnc.o = from; - bnc.radius = bnc.xradius = bnc.yradius = type==BNC_DEBRIS ? 0.5f : 1.5f; - bnc.eyeheight = bnc.radius; - bnc.aboveeye = bnc.radius; - bnc.lifetime = lifetime; - bnc.local = local; - bnc.owner = owner; - bnc.bouncetype = type; - bnc.id = local ? lastmillis : id; - - switch(type) - { - case BNC_DEBRIS: bnc.variant = rnd(4); break; - case BNC_GIBS: bnc.variant = rnd(3); break; - } - - vec dir(to); - dir.sub(from).safenormalize(); - bnc.vel = dir; - bnc.vel.mul(speed); - - avoidcollision(&bnc, dir, owner, 0.1f); - - bnc.offset = from; - bnc.offset.sub(bnc.o); - bnc.offsetmillis = OFFSETMILLIS; - - bnc.resetinterp(); - } - - void bounced(physent *d, const vec &surface) - { - if(d->type != ENT_BOUNCE) return; - bouncer *b = (bouncer *)d; - if(b->bouncetype != BNC_GIBS || b->bounces >= 2) return; - b->bounces++; - addstain(STAIN_BLOOD, vec(b->o).sub(vec(surface).mul(b->radius)), surface, 2.96f/b->bounces, bvec(0x60, 0xFF, 0xFF), rnd(4)); - } - - void updatebouncers(int time) - { - loopv(bouncers) - { - bouncer &bnc = *bouncers[i]; - vec old(bnc.o); - bool stopped = false; - // cheaper variable rate physics for debris, gibs, etc. - for(int rtime = time; rtime > 0;) - { - int qtime = min(30, rtime); - rtime -= qtime; - if((bnc.lifetime -= qtime)<0 || bounce(&bnc, qtime/1000.0f, 0.6f, 0.5f, 1)) { stopped = true; break; } - } - if(stopped) - { - delete bouncers.remove(i--); - } - else - { - bnc.roll += old.sub(bnc.o).magnitude()/(4*RAD); - bnc.offsetmillis = max(bnc.offsetmillis-time, 0); - } - } - } - - void removebouncers(gameent *owner) - { - loopv(bouncers) if(bouncers[i]->owner==owner) { delete bouncers[i]; bouncers.remove(i--); } - } - - void clearbouncers() { bouncers.deletecontents(); } - - struct projectile - { - vec dir, o, from, to, offset; - float speed; - gameent *owner; - int atk; - bool local; - int offsetmillis; - int id; - }; - vector projs; - - void clearprojectiles() { projs.shrink(0); } - - void newprojectile(const vec &from, const vec &to, float speed, bool local, int id, gameent *owner, int atk) - { - projectile &p = projs.add(); - p.dir = vec(to).sub(from).safenormalize(); - p.o = from; - p.from = from; - p.to = to; - p.offset = hudgunorigin(attacks[atk].gun, from, to, owner); - p.offset.sub(from); - p.speed = speed; - p.local = local; - p.owner = owner; - p.atk = atk; - p.offsetmillis = OFFSETMILLIS; - p.id = local ? lastmillis : id; - } - - void removeprojectiles(gameent *owner) - { - // can't use loopv here due to strange GCC optimizer bug - int len = projs.length(); - loopi(len) if(projs[i].owner==owner) { projs.remove(i--); len--; } - } - - VARP(blood, 0, 1, 1); - - void damageeffect(int damage, gameent *d, bool thirdperson) - { - vec p = d->o; - p.z += 0.6f*(d->eyeheight + d->aboveeye) - d->eyeheight; - if(blood) particle_splash(PART_BLOOD, max(damage/10, rnd(3)+1), 1000, p, 0x60FFFF, 2.96f); -#if 0 - if(thirdperson) particle_textcopy(d->abovehead(), tempformatstring("%d", damage), PART_TEXT, 2000, 0xFF4B19, 4.0f, -8); -#endif - } - - void spawnbouncer(const vec &p, const vec &vel, gameent *d, int type) - { - vec to(rnd(100)-50, rnd(100)-50, rnd(100)-50); - if(to.iszero()) to.z += 1; - to.normalize(); - to.add(p); - newbouncer(p, to, true, 0, d, type, rnd(1000)+1000, rnd(100)+20); - } - - void gibeffect(int damage, const vec &vel, gameent *d) - { -#if 0 - if(!blood || !maxgibs || damage < 0) return; - vec from = d->abovehead(); - loopi(rnd(maxgibs)+1) spawnbouncer(from, vel, d, BNC_GIBS); -#endif - } - - void hit(int damage, dynent *d, gameent *at, const vec &vel, int atk, float info1, int info2 = 1) - { - if(at==player1 && d!=at) - { - extern int hitsound; - if(hitsound && lasthit != lastmillis) playsound(S_HIT); - lasthit = lastmillis; - } - - gameent *f = (gameent *)d; - - f->lastpain = lastmillis; - if(at->type==ENT_PLAYER && !isteam(at->team, f->team)) at->totaldamage += damage; - - if(!m_mp(gamemode) || f==at) f->hitpush(damage, vel, at, atk); - - if(!m_mp(gamemode)) damaged(damage, f, at); - else - { - hitmsg &h = hits.add(); - h.target = f->clientnum; - h.lifesequence = f->lifesequence; - h.info1 = int(info1*DMF); - h.info2 = info2; - h.dir = f==at ? ivec(0, 0, 0) : ivec(vec(vel).mul(DNF)); - if(at==player1) - { - damageeffect(damage, f); - if(f==player1) - { - damageblend(damage); - damagecompass(damage, at ? at->o : f->o); - playsound(S_PAIN2); - } - else playsound(S_PAIN1, &f->o); - } - } - } - - void hitpush(int damage, dynent *d, gameent *at, vec &from, vec &to, int atk, int rays) - { - hit(damage, d, at, vec(to).sub(from).safenormalize(), atk, from.dist(to), rays); - } - - float projdist(dynent *o, vec &dir, const vec &v, const vec &vel) - { - vec middle = o->o; - middle.z += (o->aboveeye-o->eyeheight)/2; - dir = vec(middle).sub(v).add(vec(vel).mul(5)).safenormalize(); - - float low = min(o->o.z - o->eyeheight + o->radius, middle.z), - high = max(o->o.z + o->aboveeye - o->radius, middle.z); - vec closest(o->o.x, o->o.y, clamp(v.z, low, high)); - return max(closest.dist(v) - o->radius, 0.0f); - } - - void radialeffect(dynent *o, const vec &v, const vec &vel, int qdam, gameent *at, int atk) - { - if(o->state!=CS_ALIVE) return; - vec dir; - float dist = projdist(o, dir, v, vel); - if(dist 0) hit(max(int(damage), 1), o, at, dir, atk, dist); - } - } - - void explode(bool local, gameent *owner, const vec &v, const vec &vel, dynent *safe, int damage, int atk) - { - particle_splash(PART_SPARK, 200, 300, v, 0x50CFE5, 0.45f); - playsound(S_PULSEEXPLODE, &v); - particle_fireball(v, 1.15f*attacks[atk].exprad, PART_PULSE_BURST, int(attacks[atk].exprad*20), 0x50CFE5, 4.0f); - vec debrisorigin = vec(v).sub(vec(vel).mul(5)); - adddynlight(safe ? v : debrisorigin, 2*attacks[atk].exprad, vec(1.0f, 3.0f, 4.0f), 350, 40, 0, attacks[atk].exprad/2, vec(0.5f, 1.5f, 2.0f)); -#if 0 - int numdebris = maxdebris > MINDEBRIS ? rnd(maxdebris-MINDEBRIS)+MINDEBRIS : min(maxdebris, MINDEBRIS); - if(numdebris) - { - vec debrisvel = vec(vel).neg(); - loopi(numdebris) - spawnbouncer(debrisorigin, debrisvel, owner, BNC_DEBRIS); - } -#endif - if(!local) return; - int numdyn = numdynents(); - loopi(numdyn) - { - dynent *o = iterdynents(i); - if(o->o.reject(v, o->radius + attacks[atk].exprad) || o==safe) continue; - radialeffect(o, v, vel, damage, owner, atk); - } - } - - void pulsestain(const projectile &p, const vec &pos) - { - vec dir = vec(p.dir).neg(); - float rad = attacks[p.atk].exprad*0.75f; - addstain(STAIN_PULSE_SCORCH, pos, dir, rad); - addstain(STAIN_PULSE_GLOW, pos, dir, rad, 0x50CFE5); - } - - void projsplash(projectile &p, const vec &v, dynent *safe) - { - explode(p.local, p.owner, v, p.dir, safe, attacks[p.atk].damage, p.atk); - pulsestain(p, v); - } - - void explodeeffects(int atk, gameent *d, bool local, int id) - { - if(local) return; - switch(atk) - { - case ATK_PULSE_SHOOT: - loopv(projs) - { - projectile &p = projs[i]; - if(p.atk == atk && p.owner == d && p.id == id && !p.local) - { - vec pos = vec(p.offset).mul(p.offsetmillis/float(OFFSETMILLIS)).add(p.o); - explode(p.local, p.owner, pos, p.dir, NULL, 0, atk); - pulsestain(p, pos); - projs.remove(i); - break; - } - } - break; - default: - break; - } - } - - bool projdamage(dynent *o, projectile &p, const vec &v) - { - if(o->state!=CS_ALIVE) return false; - if(!intersect(o, p.o, v, attacks[p.atk].margin)) return false; - projsplash(p, v, o); - vec dir; - projdist(o, dir, v, p.dir); - hit(attacks[p.atk].damage, o, p.owner, dir, p.atk, 0); - return true; - } - - void updateprojectiles(int time) - { - if(projs.empty()) return; - gameent *noside = followingplayer(player1); - loopv(projs) - { - projectile &p = projs[i]; - p.offsetmillis = max(p.offsetmillis-time, 0); - vec dv; - float dist = p.to.dist(p.o, dv); - dv.mul(time/max(dist*1000/p.speed, float(time))); - vec v = vec(p.o).add(dv); - bool exploded = false; - hits.setsize(0); - if(p.local) - { - vec halfdv = vec(dv).mul(0.5f), bo = vec(p.o).add(halfdv); - float br = max(fabs(halfdv.x), fabs(halfdv.y)) + 1 + attacks[p.atk].margin; - loopj(numdynents()) - { - dynent *o = iterdynents(j); - if(p.owner==o || o->o.reject(bo, o->radius + br)) continue; - if(projdamage(o, p, v)) { exploded = true; break; } - } - } - if(!exploded) - { - if(dist<4) - { - if(p.o!=p.to) // if original target was moving, reevaluate endpoint - { - if(raycubepos(p.o, p.dir, p.to, 0, RAY_CLIPMAT|RAY_ALPHAPOLY)>=4) continue; - } - projsplash(p, v, NULL); - exploded = true; - } - else - { - vec pos = vec(p.offset).mul(p.offsetmillis/float(OFFSETMILLIS)).add(v); - particle_splash(PART_PULSE_FRONT, 1, 1, pos, 0x50CFE5, 2.4f, 150, 20); - if(p.owner != noside) - { - float len = min(20.0f, vec(p.offset).add(p.from).dist(pos)); - vec dir = vec(dv).normalize(), - tail = vec(dir).mul(-len).add(pos), - head = vec(dir).mul(2.4f).add(pos); - particle_flare(tail, head, 1, PART_PULSE_SIDE, 0x50CFE5, 2.5f); - } - } - } - if(exploded) - { - if(p.local) - addmsg(N_EXPLODE, "rci3iv", p.owner, lastmillis-maptime, p.atk, p.id-maptime, - hits.length(), hits.length()*sizeof(hitmsg)/sizeof(int), hits.getbuf()); - projs.remove(i--); - } - else p.o = v; - } - } - - void railhit(const vec &from, const vec &to, bool stain = true) - { - vec dir = vec(from).sub(to).safenormalize(); - if(stain) - { - addstain(STAIN_RAIL_HOLE, to, dir, 2.0f); - addstain(STAIN_RAIL_GLOW, to, dir, 2.5f, 0x50CFE5); - } - adddynlight(vec(to).madd(dir, 4), 10, vec(0.25f, 0.75f, 1.0f), 225, 75); - } - - void shoteffects(int atk, const vec &from, const vec &to, gameent *d, bool local, int id, int prevaction) // create visual effect from a shot - { - int gun = attacks[atk].gun; - switch(atk) - { - case ATK_PULSE_SHOOT: - if(d->muzzle.x >= 0) - particle_flare(d->muzzle, d->muzzle, 140, PART_PULSE_MUZZLE_FLASH, 0x50CFE5, 3.50f, d); - newprojectile(from, to, attacks[atk].projspeed, local, id, d, atk); - break; - - case ATK_RAIL_SHOOT: - particle_splash(PART_SPARK, 200, 250, to, 0x50CFE5, 0.45f); - particle_flare(hudgunorigin(gun, from, to, d), to, 500, PART_RAIL_TRAIL, 0x50CFE5, 0.5f); - if(d->muzzle.x >= 0) - particle_flare(d->muzzle, d->muzzle, 140, PART_RAIL_MUZZLE_FLASH, 0x50CFE5, 2.75f, d); - adddynlight(hudgunorigin(gun, d->o, to, d), 35, vec(0.25f, 0.75f, 1.0f), 75, 75, DL_FLASH, 0, vec(0, 0, 0), d); - if(!local) railhit(from, to); - break; - - default: - break; - } - - if(d == followingplayer(player1)) playsound(attacks[atk].hudsound, NULL); - else playsound(attacks[atk].sound, &d->o); - } - - void particletrack(physent *owner, vec &o, vec &d) - { - if(owner->type!=ENT_PLAYER) return; - gameent *pl = (gameent *)owner; - if(pl->muzzle.x < 0 || pl->lastattack < 0 || attacks[pl->lastattack].gun != pl->gunselect) return; - float dist = o.dist(d); - o = pl->muzzle; - if(dist <= 0) d = o; - else - { - vecfromyawpitch(owner->yaw, owner->pitch, 1, 0, d); - float newdist = raycube(owner->o, d, dist, RAY_CLIPMAT|RAY_ALPHAPOLY); - d.mul(min(newdist, dist)).add(owner->o); - } - } - - void dynlighttrack(physent *owner, vec &o, vec &hud) - { - if(owner->type!=ENT_PLAYER) return; - gameent *pl = (gameent *)owner; - if(pl->muzzle.x < 0 || pl->lastattack < 0 || attacks[pl->lastattack].gun != pl->gunselect) return; - o = pl->muzzle; - hud = owner == followingplayer(player1) ? vec(pl->o).add(vec(0, 0, 2)) : pl->muzzle; - } - - float intersectdist = 1e16f; - - bool intersect(dynent *d, const vec &from, const vec &to, float margin, float &dist) // if lineseg hits entity bounding box - { - vec bottom(d->o), top(d->o); - bottom.z -= d->eyeheight + margin; - top.z += d->aboveeye + margin; - return linecylinderintersect(from, to, bottom, top, d->radius + margin, dist); - } - - dynent *intersectclosest(const vec &from, const vec &to, gameent *at, float margin, float &bestdist) - { - dynent *best = NULL; - bestdist = 1e16f; - loopi(numdynents()) - { - dynent *o = iterdynents(i); - if(o==at || o->state!=CS_ALIVE) continue; - float dist; - if(!intersect(o, from, to, margin, dist)) continue; - if(dist 1) - { - dynent *hits[MAXRAYS]; - loopi(maxrays) - { - if((hits[i] = intersectclosest(from, rays[i], d, margin, dist))) - { - shorten(from, rays[i], dist); - railhit(from, rays[i], false); - } - else railhit(from, rays[i]); - } - loopi(maxrays) if(hits[i]) - { - o = hits[i]; - hits[i] = NULL; - int numhits = 1; - for(int j = i+1; j < maxrays; j++) if(hits[j] == o) - { - hits[j] = NULL; - numhits++; - } - hitpush(numhits*attacks[atk].damage, o, d, from, to, atk, numhits); - } - } - else if((o = intersectclosest(from, to, d, margin, dist))) - { - shorten(from, to, dist); - railhit(from, to, false); - hitpush(attacks[atk].damage, o, d, from, to, atk, 1); - } - else if(attacks[atk].action!=ACT_MELEE) railhit(from, to); - } - - void shoot(gameent *d, const vec &targ) - { - int prevaction = d->lastaction, attacktime = lastmillis-prevaction; - if(attacktimegunwait) return; - d->gunwait = 0; - if(!d->attacking) return; - int gun = d->gunselect, act = d->attacking, atk = guns[gun].attacks[act]; - d->lastaction = lastmillis; - d->lastattack = atk; - if(!d->ammo[gun]) - { - if(d==player1) - { - msgsound(S_NOAMMO, d); - d->gunwait = 600; - d->lastattack = -1; - weaponswitch(d); - } - return; - } - d->ammo[gun] -= attacks[atk].use; - - vec from = d->o, to = targ, dir = vec(to).sub(from).safenormalize(); - float dist = to.dist(from); - if(!(d->physstate >= PHYS_SLOPE && d->crouching && d->crouched())) - { - vec kickback = vec(dir).mul(attacks[atk].kickamount*-2.5f); - d->vel.add(kickback); - } - float shorten = attacks[atk].range && dist > attacks[atk].range ? attacks[atk].range : 0, - barrier = raycube(d->o, dir, dist, RAY_CLIPMAT|RAY_ALPHAPOLY); - if(barrier > 0 && barrier < dist && (!shorten || barrier < shorten)) - shorten = barrier; - if(shorten) to = vec(dir).mul(shorten).add(from); - - if(attacks[atk].rays > 1) createrays(atk, from, to); - else if(attacks[atk].spread) offsetray(from, to, attacks[atk].spread, attacks[atk].range, to); - - hits.setsize(0); - - if(!attacks[atk].projspeed) raydamage(from, to, d, atk); - - shoteffects(atk, from, to, d, true, 0, prevaction); - - if(d==player1) - { - addmsg(N_SHOOT, "rci2i6iv", d, lastmillis-maptime, atk, - (int)(from.x*DMF), (int)(from.y*DMF), (int)(from.z*DMF), - (int)(to.x*DMF), (int)(to.y*DMF), (int)(to.z*DMF), - hits.length(), hits.length()*sizeof(hitmsg)/sizeof(int), hits.getbuf()); - } - - d->gunwait = attacks[atk].attackdelay; - if(attacks[atk].action != ACT_MELEE) d->gunwait += int(d->gunwait*((101+rnd(111))/100.f)); - d->totalshots += attacks[atk].damage*attacks[atk].rays; - } - - void adddynlights() - { - loopv(projs) - { - projectile &p = projs[i]; - if(p.atk!=ATK_PULSE_SHOOT) continue; - vec pos(p.o); - pos.add(vec(p.offset).mul(p.offsetmillis/float(OFFSETMILLIS))); - adddynlight(pos, 20, vec(0.25f, 0.75f, 1.0f)); - } - } - -#if 0 - static const char * const gibnames[3] = { "gibs/gib01", "gibs/gib02", "gibs/gib03" }; - static const char * const debrisnames[4] = { "debris/debris01", "debris/debris02", "debris/debris03", "debris/debris04" }; -#endif - - void preloadbouncers() - { -#if 0 - loopi(sizeof(gibnames)/sizeof(gibnames[0])) preloadmodel(gibnames[i]); - loopi(sizeof(debrisnames)/sizeof(debrisnames[0])) preloadmodel(debrisnames[i]); -#endif - } - - void renderbouncers() - { - float yaw, pitch; - loopv(bouncers) - { - bouncer &bnc = *bouncers[i]; - vec pos(bnc.o); - pos.add(vec(bnc.offset).mul(bnc.offsetmillis/float(OFFSETMILLIS))); - vec vel(bnc.vel); - if(vel.magnitude() <= 25.0f) yaw = bnc.lastyaw; - else - { - vectoyawpitch(vel, yaw, pitch); - yaw += 90; - bnc.lastyaw = yaw; - } - pitch = -bnc.roll; - const char *mdl = NULL; - int cull = MDL_CULL_VFC|MDL_CULL_DIST|MDL_CULL_OCCLUDED; - float fade = 1; - if(bnc.lifetime < 250) fade = bnc.lifetime/250.0f; - switch(bnc.bouncetype) - { -#if 0 - case BNC_GIBS: mdl = gibnames[bnc.variant]; break; - case BNC_DEBRIS: mdl = debrisnames[bnc.variant]; break; -#endif - default: continue; - } - rendermodel(mdl, ANIM_MAPMODEL|ANIM_LOOP, pos, yaw, pitch, 0, cull, NULL, NULL, 0, 0, fade); - } - } - - void renderprojectiles() - { - } - - void removeweapons(gameent *d) - { - removebouncers(d); - removeprojectiles(d); - } - - void updateweapons(int curtime) - { - updateprojectiles(curtime); - if(player1->clientnum>=0 && player1->state==CS_ALIVE) shoot(player1, worldpos); // only shoot when connected to server - updatebouncers(curtime); // need to do this after the player shoots so bouncers don't end up inside player's BB next frame - } -}; - diff --git a/src/shared/igame.hh b/src/shared/igame.hh index 1d626d6..073bebd 100644 --- a/src/shared/igame.hh +++ b/src/shared/igame.hh @@ -74,7 +74,7 @@ namespace game extern int numdynents(); extern void rendergame(); extern void renderavatar(); - extern void renderplayerpreview(int model, int color, int team, int weap); + extern void renderplayerpreview(int model, int color, int weap); extern int numanims(); extern void findanims(const char *pattern, vector &anims); extern void writegamedata(vector &extras);