Advertisement
lucasgautheron

onpickup fix

Aug 20th, 2011
108
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 20.50 KB | None | 0 0
  1. // entities.cpp: map entity related functions (pickup etc.)
  2.  
  3. #include "cube.h"
  4.  
  5. vector<entity> ents;
  6. vector<int> eh_ents; // edithide entities
  7. const char *entmdlnames[] =
  8. {
  9.     "pickups/pistolclips", "pickups/ammobox", "pickups/nade", "pickups/health", "pickups/helmet", "pickups/kevlar", "pickups/akimbo", "pickups/nades", //FIXME
  10. };
  11.  
  12. void renderent(entity &e)
  13. {
  14.     /* FIXME: if the item list change, this hack will be messed */
  15.     const char *mdlname = entmdlnames[e.type-I_CLIPS+(m_lss && e.type==I_GRENADE ? 5:0)];
  16.     float z = (float)(1+sinf(lastmillis/100.0f+e.x+e.y)/20),
  17.           yaw = lastmillis/10.0f;
  18.     rendermodel(mdlname, ANIM_MAPMODEL|ANIM_LOOP|ANIM_DYNALLOC, 0, 0, vec(e.x, e.y, z+S(e.x, e.y)->floor+e.attr1), yaw, 0);
  19. }
  20.  
  21. void renderclip(entity &e)
  22. {
  23.     float xradius = max(float(e.attr2), 0.1f), yradius = max(float(e.attr3), 0.1f);
  24.     vec bbmin(e.x - xradius, e.y - yradius, float(S(e.x, e.y)->floor+e.attr1)),
  25.         bbmax(e.x + xradius, e.y + yradius, bbmin.z + max(float(e.attr4), 0.1f));
  26.  
  27.     glDisable(GL_TEXTURE_2D);
  28.     switch(e.type)
  29.     {
  30.         case CLIP:     linestyle(1, 0xFF, 0xFF, 0); break;  // yellow
  31.         case MAPMODEL: linestyle(1, 0, 0xFF, 0);    break;  // green
  32.         case PLCLIP:   linestyle(1, 0xFF, 0, 0xFF); break;  // magenta
  33.     }
  34.     glBegin(GL_LINES);
  35.  
  36.     glVertex3f(bbmin.x, bbmin.y, bbmin.z);
  37.     loopi(2) glVertex3f(bbmax.x, bbmin.y, bbmin.z);
  38.     loopi(2) glVertex3f(bbmax.x, bbmax.y, bbmin.z);
  39.     loopi(2) glVertex3f(bbmin.x, bbmax.y, bbmin.z);
  40.     glVertex3f(bbmin.x, bbmin.y, bbmin.z);
  41.  
  42.     glVertex3f(bbmin.x, bbmin.y, bbmax.z);
  43.     loopi(2) glVertex3f(bbmax.x, bbmin.y, bbmax.z);
  44.     loopi(2) glVertex3f(bbmax.x, bbmax.y, bbmax.z);
  45.     loopi(2) glVertex3f(bbmin.x, bbmax.y, bbmax.z);
  46.     glVertex3f(bbmin.x, bbmin.y, bbmax.z);
  47.  
  48.     loopi(8) glVertex3f(i&2 ? bbmax.x : bbmin.x, i&4 ? bbmax.y : bbmin.y, i&1 ? bbmax.z : bbmin.z);
  49.  
  50.     glEnd();
  51.     glEnable(GL_TEXTURE_2D);
  52. }
  53.  
  54. void rendermapmodels()
  55. {
  56.     loopv(ents)
  57.     {
  58.         entity &e = ents[i];
  59.         if(e.type==MAPMODEL)
  60.         {
  61.             mapmodelinfo &mmi = getmminfo(e.attr2);
  62.             if(!&mmi) continue;
  63.             rendermodel(mmi.name, ANIM_MAPMODEL|ANIM_LOOP, e.attr4, 0, vec(e.x, e.y, (float)S(e.x, e.y)->floor+mmi.zoff+e.attr3), (float)((e.attr1+7)-(e.attr1+7)%15), 0, 10.0f);
  64.         }
  65.     }
  66. }
  67.  
  68. VAR(showmodelclipping, 0, 0, 1);
  69.  
  70. void showedithide()
  71. {
  72.     loopv(eh_ents)
  73.     {
  74.         if(eh_ents[i]>0 && eh_ents[i]<MAXENTTYPES) { conoutf("#%02d: %d : %s", i, eh_ents[i], entnames[eh_ents[i]]); }
  75.         else { conoutf("#%02d: %d : -n/a-", i, eh_ents[i]);  }
  76.     }
  77. }
  78. COMMAND(showedithide, ARG_NONE);
  79.  
  80. void setedithide(char *text) // FIXME: human indexing inside
  81. {
  82.     eh_ents.setsize(0);
  83.     if(text && text[0] != '\0')
  84.     {
  85.         const char *s = strtok(text, " ");
  86.         do
  87.         {
  88.             bool k = false;
  89.             int sn = -1;
  90.             int tn = atoi(s);
  91.             loopi(MAXENTTYPES) if(!strcmp(entnames[i], s)) sn = i;
  92.             if(sn!=-1) { loopv(eh_ents) { if(eh_ents[i]==sn) { k = true; } } }
  93.             else sn = tn;
  94.             if(!k) { if(sn>0 && sn<MAXENTTYPES) eh_ents.add(sn); }
  95.             s = strtok(NULL, " ");
  96.         }
  97.         while(s);
  98.     }
  99. }
  100. COMMAND(setedithide, ARG_CONC);
  101.  
  102. void seteditshow(char *just)
  103. {
  104.     eh_ents.setsize(0);
  105.     if(just && just[0] != '\0')
  106.     {
  107.         const char *s = strtok(just, " ");
  108.         int sn = -1;
  109.         int tn = atoi(s);
  110.         loopi(MAXENTTYPES) if(!strcmp(entnames[i], s)) sn = i;
  111.         if(sn==-1) sn = tn;
  112.         loopi(MAXENTTYPES-1)
  113.         {
  114.             int j = i+1;
  115.             if(j!=sn) eh_ents.add(j);
  116.         }
  117.     }
  118. }
  119. COMMAND(seteditshow, ARG_1STR);
  120.  
  121. void renderentarrow(const entity &e, const vec &dir, float radius)
  122. {
  123.     if(radius <= 0) return;
  124.     float arrowsize = min(radius/8, 0.5f);
  125.     vec epos(e.x, e.y, e.z);
  126.     vec target = vec(dir).mul(radius).add(epos), arrowbase = vec(dir).mul(radius - arrowsize).add(epos), spoke;
  127.     spoke.orthogonal(dir);
  128.     spoke.normalize();
  129.     spoke.mul(arrowsize);
  130.     glDisable(GL_TEXTURE_2D); // this disables reaction to light, but also emphasizes shadows .. a nice effect, but should be independent
  131.     glDisable(GL_CULL_FACE);
  132.     glLineWidth(3);
  133.     glBegin(GL_LINES);
  134.     glVertex3fv(epos.v);
  135.     glVertex3fv(target.v);
  136.     glEnd();
  137.     glBegin(GL_TRIANGLE_FAN);
  138.     glVertex3fv(target.v);
  139.     loopi(5)
  140.     {
  141.         vec p(spoke);
  142.         p.rotate(2*M_PI*i/4.0f, dir);
  143.         p.add(arrowbase);
  144.         glVertex3fv(p.v);
  145.     }
  146.     glEnd();
  147.     glLineWidth(1);
  148.     glEnable(GL_CULL_FACE);
  149.     glEnable(GL_TEXTURE_2D);
  150. }
  151.  
  152. void renderentities()
  153. {
  154.     int closest = editmode ? closestent() : -1;
  155.     if(editmode && !reflecting && !refracting && !stenciling)
  156.     {
  157.         static int lastsparkle = 0;
  158.         if(lastmillis - lastsparkle >= 20)
  159.         {
  160.             lastsparkle = lastmillis - (lastmillis%20);
  161.             // closest see above
  162.             loopv(ents)
  163.             {
  164.                 entity &e = ents[i];
  165.                 if(e.type==NOTUSED) continue;
  166.                 bool ice = false;
  167.                 loopk(eh_ents.length()) if(eh_ents[k]==e.type) ice = true;
  168.                 if(ice) continue;
  169.                 vec v(e.x, e.y, e.z);
  170.                 if(vec(v).sub(camera1->o).dot(camdir) < 0) continue;
  171.                 //particle_splash(i == closest ? 12 : 2, 2, 40, v);
  172.                 int sc = 17; // "carrot" (orange) - entity slot currently unused, possibly "reserved"
  173.                 if(i==closest)
  174.                 {
  175.                     sc = 2; // blue
  176.                 }
  177.                 else switch(e.type)
  178.                 {
  179.                     case LIGHT : sc = 12; break; // white
  180.                     case PLAYERSTART: sc = 13; break; // green
  181.                     case I_CLIPS:
  182.                     case I_AMMO:
  183.                     case I_GRENADE: sc = 14; break; // red
  184.                     case I_HEALTH:
  185.                     case I_HELMET:
  186.                     case I_ARMOUR:
  187.                     case I_AKIMBO: sc = 15; break; // yellow
  188.                     case MAPMODEL:
  189.                     case SOUND: sc = 16; break; // magenta
  190.                     case LADDER:
  191.                     case CLIP:
  192.                     case PLCLIP: sc = 18; break; // grey
  193.                     case CTF_FLAG: sc = 19; break; // turquoise
  194.                     default: break;
  195.                 }
  196.                 //particle_splash(sc, i==closest?6:2, i==closest?120:40, v);
  197.                 particle_splash(sc, 2, 40, v);
  198.             }
  199.         }
  200.     }
  201.     loopv(ents)
  202.     {
  203.         entity &e = ents[i];
  204.         if(isitem(e.type))
  205.         {
  206.             if((!OUTBORD(e.x, e.y) && e.spawned) || editmode)
  207.             {
  208.                 renderent(e);
  209.             }
  210.         }
  211.         else if(editmode)
  212.         {
  213.             if(e.type==CTF_FLAG)
  214.             {
  215.                 defformatstring(path)("pickups/flags/%s", team_basestring(e.attr2));
  216.                 rendermodel(path, ANIM_FLAG|ANIM_LOOP, 0, 0, vec(e.x, e.y, (float)S(e.x, e.y)->floor), (float)((e.attr1+7)-(e.attr1+7)%15), 0, 120.0f);
  217.             }
  218.             else if((e.type == CLIP || e.type == PLCLIP) && !stenciling) renderclip(e);
  219.             else if(showmodelclipping && e.type == MAPMODEL && !stenciling)
  220.             {
  221.                 mapmodelinfo &mmi = getmminfo(e.attr2);
  222.                 if(&mmi && mmi.h)
  223.                 {
  224.                     entity ce = e;
  225.                     ce.type = MAPMODEL;
  226.                     ce.attr1 = mmi.zoff+e.attr3;
  227.                     ce.attr2 = ce.attr3 = mmi.rad;
  228.                     ce.attr4 = mmi.h;
  229.                     renderclip(ce);
  230.                 }
  231.             }
  232.         }
  233.         if(editmode && i==closest && !stenciling)//closest see above
  234.         {
  235.             switch(e.type)
  236.             {
  237.                 case PLAYERSTART:
  238.                 {
  239.                     glColor3f(0, 1, 1);
  240.                     vec dir;
  241.                     vecfromyawpitch(e.attr1, 0, -1, 0, dir);
  242.                     renderentarrow(e, dir, 4);
  243.                     glColor3f(1, 1, 1);
  244.                 }
  245.                 default: break;
  246.             }
  247.         }
  248.     }
  249.     if(m_flags) loopi(2)
  250.     {
  251.         flaginfo &f = flaginfos[i];
  252.         switch(f.state)
  253.         {
  254.             case CTFF_STOLEN:
  255.                 if(f.actor && f.actor != player1)
  256.                 {
  257.                     if(OUTBORD(f.actor->o.x, f.actor->o.y)) break;
  258.                     defformatstring(path)("pickups/flags/small_%s%s", m_ktf ? "" : team_basestring(i), m_htf ? "_htf" : m_ktf ? "ktf" : "");
  259.                     rendermodel(path, ANIM_FLAG|ANIM_START|ANIM_DYNALLOC, 0, 0, vec(f.actor->o).add(vec(0, 0, 0.3f+(sinf(lastmillis/100.0f)+1)/10)), lastmillis/2.5f, 0, 120.0f);
  260.                 }
  261.                 break;
  262.             case CTFF_INBASE:
  263.                 if(!numflagspawn[i]) break;
  264.             case CTFF_DROPPED:
  265.             {
  266.                 if(OUTBORD(f.pos.x, f.pos.y)) break;
  267.                 entity &e = *f.flagent;
  268.                 defformatstring(path)("pickups/flags/%s%s", m_ktf ? "" : team_basestring(i),  m_htf ? "_htf" : m_ktf ? "ktf" : "");
  269.                 if(f.flagent->spawned) rendermodel(path, ANIM_FLAG|ANIM_LOOP, 0, 0, vec(f.pos.x, f.pos.y, f.state==CTFF_INBASE ? (float)S(int(f.pos.x), int(f.pos.y))->floor : f.pos.z), (float)((e.attr1+7)-(e.attr1+7)%15), 0, 120.0f);
  270.                 break;
  271.             }
  272.             case CTFF_IDLE:
  273.                 break;
  274.         }
  275.     }
  276. }
  277.  
  278. // these two functions are called when the server acknowledges that you really
  279. // picked up the item (in multiplayer someone may grab it before you).
  280.  
  281. void pickupeffects(int n, playerent *d)
  282. {
  283.     if(!ents.inrange(n)) return;
  284.     entity &e = ents[n];
  285.     e.spawned = false;
  286.     if(!d) return;
  287.     d->pickup(e.type);
  288.     if (m_lss && e.type == I_GRENADE) d->pickup(e.type); // get 2
  289.     itemstat &is = d->itemstats(e.type);
  290.     if(d!=player1 && d->type!=ENT_BOT) return;
  291.     if(&is)
  292.     {
  293.         if(d==player1)
  294.         {
  295.             audiomgr.playsoundc(is.sound);
  296.  
  297.             /*
  298.                 onPickup arg1 legend:
  299.                   0 = pistol clips
  300.                   1 = ammo box
  301.                   2 = grenade
  302.                   3 = health pack
  303.                   4 = helmet
  304.                   5 = armour
  305.                   6 = akimbo
  306.             */
  307.             if(identexists("onPickup"))
  308.             {
  309.                 string o;
  310.                 itemstat *tmp = NULL;
  311.                 switch(e.type)
  312.                 {
  313.                     case I_CLIPS:   tmp = &ammostats[GUN_PISTOL]; break;
  314.                     case I_AMMO:    tmp = &ammostats[player1->primary]; break;
  315.                     case I_GRENADE: tmp = &ammostats[GUN_GRENADE]; break;
  316.                     case I_AKIMBO:  tmp = &ammostats[GUN_AKIMBO]; break;
  317.                     case I_HEALTH:
  318.                     case I_HELMET:
  319.                     case I_ARMOUR:  tmp = &powerupstats[e.type-I_HEALTH]; break;
  320.                     default: break;
  321.                 }
  322.                 if(tmp)
  323.                 {
  324.                     formatstring(o)("onPickup %d %d", e.type - 3, m_lss && e.type == I_GRENADE ? 2 : tmp->add);
  325.                     execute(o);
  326.                 }
  327.             }
  328.         }
  329.         else audiomgr.playsound(is.sound, d);
  330.     }
  331.  
  332.     weapon *w = NULL;
  333.     switch(e.type)
  334.     {
  335.         case I_AKIMBO: w = d->weapons[GUN_AKIMBO]; break;
  336.         case I_CLIPS: w = d->weapons[GUN_PISTOL]; break;
  337.         case I_AMMO: w = d->primweap; break;
  338.         case I_GRENADE: w = d->weapons[GUN_GRENADE]; break;
  339.     }
  340.     if(w) w->onammopicked();
  341. }
  342.  
  343. // these functions are called when the client touches the item
  344.  
  345. extern int lastspawn;
  346.  
  347. void trypickup(int n, playerent *d)
  348. {
  349.     entity &e = ents[n];
  350.     switch(e.type)
  351.     {
  352.         default:
  353.             if( d->canpickup(e.type) && lastmillis > e.lastmillis + 250 && lastmillis > lastspawn + 500 )
  354.             {
  355.                 if(d->type==ENT_PLAYER) addmsg(SV_ITEMPICKUP, "ri", n);
  356.                 else if(d->type==ENT_BOT && serverpickup(n, -1)) pickupeffects(n, d);
  357.                 e.lastmillis = lastmillis;
  358.             }
  359.             break;
  360.  
  361.         case LADDER:
  362.             if(!d->crouching) d->onladder = true;
  363.             break;
  364.     }
  365. }
  366.  
  367. void trypickupflag(int flag, playerent *d)
  368. {
  369.     if(d==player1)
  370.     {
  371.         flaginfo &f = flaginfos[flag];
  372.         flaginfo &of = flaginfos[team_opposite(flag)];
  373.         if(f.state == CTFF_STOLEN) return;
  374.         bool own = flag == team_base(d->team);
  375.  
  376.         if(m_ctf)
  377.         {
  378.             if(own) // it's the own flag
  379.             {
  380.                 if(f.state == CTFF_DROPPED) flagreturn(flag);
  381.                 else if(f.state == CTFF_INBASE && of.state == CTFF_STOLEN && of.actor == d && of.ack) flagscore(of.team);
  382.             }
  383.             else flagpickup(flag);
  384.         }
  385.         else if(m_htf)
  386.         {
  387.             if(own)
  388.             {
  389.                 flagpickup(flag);
  390.             }
  391.             else
  392.             {
  393.                 if(f.state == CTFF_DROPPED) flagscore(f.team); // may not count!
  394.             }
  395.         }
  396.         else if(m_ktf)
  397.         {
  398.             if(f.state != CTFF_INBASE) return;
  399.             flagpickup(flag);
  400.         }
  401.     }
  402. }
  403.  
  404. void checkitems(playerent *d)
  405. {
  406.     if(editmode || d->state!=CS_ALIVE) return;
  407.     d->onladder = false;
  408.     float eyeheight = d->eyeheight;
  409.     loopv(ents)
  410.     {
  411.         entity &e = ents[i];
  412.         if(e.type==NOTUSED) continue;
  413.         if(e.type==LADDER)
  414.         {
  415.             if(OUTBORD(e.x, e.y)) continue;
  416.             vec v(e.x, e.y, d->o.z);
  417.             float dist1 = d->o.dist(v);
  418.             float dist2 = d->o.z - (S(e.x, e.y)->floor+eyeheight);
  419.             if(dist1<1.5f && dist2<e.attr1) trypickup(i, d);
  420.             continue;
  421.         }
  422.  
  423.         if(!e.spawned) continue;
  424.         if(OUTBORD(e.x, e.y)) continue;
  425.  
  426.         if(e.type==CTF_FLAG) continue;
  427.         // simple 2d collision
  428.         vec v(e.x, e.y, S(e.x, e.y)->floor+eyeheight);
  429.         if(isitem(e.type)) v.z += e.attr1;
  430.         if(d->o.dist(v)<2.5f) trypickup(i, d);
  431.     }
  432.     if(m_flags) loopi(2)
  433.     {
  434.         flaginfo &f = flaginfos[i];
  435.         entity &e = *f.flagent;
  436.         if(!e.spawned || !f.ack || (f.state == CTFF_INBASE && !numflagspawn[i])) continue;
  437.         if(OUTBORD(f.pos.x, f.pos.y)) continue;
  438.         if(f.state==CTFF_DROPPED) // 3d collision for dropped ctf flags
  439.         {
  440.             if(objcollide(d, f.pos, 2.5f, 4.0f)) trypickupflag(i, d);
  441.         }
  442.         else // simple 2d collision
  443.         {
  444.             vec v = f.pos;
  445.             v.z = S(int(v.x), int(v.y))->floor + eyeheight;
  446.             if(d->o.dist(v)<2.5f) trypickupflag(i, d);
  447.         }
  448.     }
  449. }
  450.  
  451. void spawnallitems()            // spawns items locally
  452. {
  453.     loopv(ents) if(ents[i].fitsmode(gamemode) || (multiplayer(false) && gamespeed!=100 && (i=-1)))
  454.     {
  455.         ents[i].spawned = true;
  456.         ents[i].lastmillis = lastmillis;
  457.     }
  458. }
  459.  
  460. void resetspawns(int type)
  461. {
  462.     loopv(ents) if(type < 0 || type == ents[i].type) ents[i].spawned = false;
  463.     if(m_noitemsnade || m_pistol)
  464.     {
  465.         loopv(ents) ents[i].transformtype(gamemode);
  466.     }
  467. }
  468.  
  469. void setspawn(int i, bool on)
  470. {
  471.     if(ents.inrange(i))
  472.     {
  473.         ents[i].spawned = on;
  474.         if (on) ents[i].lastmillis = lastmillis; // to control trypickup spam
  475.     }
  476. }
  477.  
  478. bool selectnextprimary(int num)
  479. {
  480.     switch(num)
  481.     {
  482. //         case GUN_CPISTOL:
  483.         case GUN_CARBINE:
  484.         case GUN_SHOTGUN:
  485.         case GUN_SUBGUN:
  486.         case GUN_SNIPER:
  487.         case GUN_ASSAULT:
  488.             player1->setnextprimary(num);
  489.             addmsg(SV_PRIMARYWEAP, "ri", player1->nextprimweap->type);
  490.             return true;
  491.  
  492.         default:
  493.             conoutf("this is not a valid primary weapon");
  494.             return false;
  495.     }
  496. }
  497.  
  498. VARFP(nextprimary, 0, GUN_ASSAULT, NUMGUNS,
  499. {
  500.     if(!selectnextprimary(nextprimary)) selectnextprimary((nextprimary = GUN_ASSAULT));
  501. });
  502.  
  503. // flag ent actions done by the local player
  504.  
  505. int flagdropmillis = 0;
  506.  
  507. void flagpickup(int fln)
  508. {
  509.     if(flagdropmillis && flagdropmillis>lastmillis) return;
  510.     flaginfo &f = flaginfos[fln];
  511.     int action = f.state == CTFF_INBASE ? FA_STEAL : FA_PICKUP;
  512.     f.flagent->spawned = false;
  513.     f.state = CTFF_STOLEN;
  514.     f.actor = player1; // do this although we don't know if we picked the flag to avoid getting it after a possible respawn
  515.     f.actor_cn = getclientnum();
  516.     f.ack = false;
  517.     addmsg(SV_FLAGACTION, "rii", action, f.team);
  518. }
  519.  
  520. void tryflagdrop(bool manual)
  521. {
  522.     loopi(2)
  523.     {
  524.         flaginfo &f = flaginfos[i];
  525.         if(f.state==CTFF_STOLEN && f.actor==player1)
  526.         {
  527.             f.flagent->spawned = false;
  528.             f.state = CTFF_DROPPED;
  529.             f.ack = false;
  530.             flagdropmillis = lastmillis+3000;
  531.             addmsg(SV_FLAGACTION, "rii", manual ? FA_DROP : FA_LOST, f.team);
  532.         }
  533.     }
  534. }
  535.  
  536. void flagreturn(int fln)
  537. {
  538.     flaginfo &f = flaginfos[fln];
  539.     f.flagent->spawned = false;
  540.     f.ack = false;
  541.     addmsg(SV_FLAGACTION, "rii", FA_RETURN, f.team);
  542. }
  543.  
  544. void flagscore(int fln)
  545. {
  546.     flaginfo &f = flaginfos[fln];
  547.     f.ack = false;
  548.     addmsg(SV_FLAGACTION, "rii", FA_SCORE, f.team);
  549. }
  550.  
  551. // flag ent actions from the net
  552.  
  553. void flagstolen(int flag, int act)
  554. {
  555.     playerent *actor = act == getclientnum() ? player1 : getclient(act);
  556.     flaginfo &f = flaginfos[flag];
  557.     f.actor = actor; // could be NULL if we just connected
  558.     f.actor_cn = act;
  559.     f.flagent->spawned = false;
  560.     f.ack = true;
  561. }
  562.  
  563. void flagdropped(int flag, float x, float y, float z)
  564. {
  565.     flaginfo &f = flaginfos[flag];
  566.     if(OUTBORD(x, y)) return; // valid pos
  567.     bounceent p;
  568.     p.rotspeed = 0.0f;
  569.     p.o.x = x;
  570.     p.o.y = y;
  571.     p.o.z = z;
  572.     p.vel.z = -0.8f;
  573.     p.aboveeye = p.eyeheight = p.maxeyeheight = 0.4f;
  574.     p.radius = 0.1f;
  575.  
  576.     bool oldcancollide = false;
  577.     if(f.actor)
  578.     {
  579.         oldcancollide = f.actor->cancollide;
  580.         f.actor->cancollide = false; // avoid collision with owner
  581.     }
  582.     loopi(100) // perform physics steps
  583.     {
  584.         moveplayer(&p, 10, true, 50);
  585.         if(p.stuck) break;
  586.     }
  587.     if(f.actor) f.actor->cancollide = oldcancollide; // restore settings
  588.  
  589.     f.pos.x = round(p.o.x);
  590.     f.pos.y = round(p.o.y);
  591.     f.pos.z = round(p.o.z);
  592.     if(f.pos.z < hdr.waterlevel) f.pos.z = (short) hdr.waterlevel;
  593.     f.flagent->spawned = true;
  594.     f.ack = true;
  595. }
  596.  
  597. void flaginbase(int flag)
  598. {
  599.     flaginfo &f = flaginfos[flag];
  600.     f.actor = NULL; f.actor_cn = -1;
  601.     f.pos = vec(f.flagent->x, f.flagent->y, f.flagent->z);
  602.     f.flagent->spawned = true;
  603.     f.ack = true;
  604. }
  605.  
  606. void flagidle(int flag)
  607. {
  608.     flaginbase(flag);
  609.     flaginfos[flag].flagent->spawned = false;
  610. }
  611.  
  612. void entstats(void)
  613. {
  614.     int entcnt[MAXENTTYPES] = {0}, clipents = 0, spawncnt[5] = {0};
  615.     loopv(ents)
  616.     {
  617.         entity &e = ents[i];
  618.         if(e.type >= MAXENTTYPES) continue;
  619.         entcnt[e.type]++;
  620.         switch(e.type)
  621.         {
  622.             case MAPMODEL:
  623.             {
  624.                 mapmodelinfo &mmi = getmminfo(e.attr2);
  625.                 if(&mmi && mmi.h) clipents++;
  626.                 break;
  627.             }
  628.             case PLAYERSTART:
  629.                 if(e.attr2 < 2) spawncnt[e.attr2]++;
  630.                 if(e.attr2 == 100) spawncnt[2]++;
  631.                 break;
  632.             case CTF_FLAG:
  633.                 if(e.attr2 < 2) spawncnt[e.attr2 + 3]++;
  634.                 break;
  635.         }
  636.     }
  637.     loopi(MAXENTTYPES)
  638.     {
  639.         if(entcnt[i]) switch(i)
  640.         {
  641.             case MAPMODEL:      conoutf(" %d %s, %d clipped", entcnt[i], entnames[i], clipents); break;
  642.             case PLAYERSTART:   conoutf(" %d %s, %d CLA, %d RVSF, %d FFA", entcnt[i], entnames[i], spawncnt[0], spawncnt[1], spawncnt[2]); break;
  643.             case CTF_FLAG:      conoutf(" %d %s, %d CLA, %d RVSF", entcnt[i], entnames[i], spawncnt[3], spawncnt[4]); break;
  644.             default:            conoutf(" %d %s", entcnt[i], entnames[i]); break;
  645.         }
  646.     }
  647.     conoutf("total entities: %d", ents.length());
  648. }
  649.  
  650. COMMAND(entstats, ARG_NONE);
  651.  
  652. vector<int> changedents;
  653. int lastentsync = 0;
  654.  
  655. void syncentchanges(bool force)
  656. {
  657.     if(lastmillis - lastentsync < 1000 && !force) return;
  658.     loopv(changedents) if(ents.inrange(changedents[i]))
  659.     {
  660.         entity &e = ents[changedents[i]];
  661.         addmsg(SV_EDITENT, "ri9", changedents[i], e.type, e.x, e.y, e.z, e.attr1, e.attr2, e.attr3, e.attr4);
  662.     }
  663.     changedents.setsize(0);
  664.     lastentsync = lastmillis;
  665. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement