src/tron/gWall.cpp

Go to the documentation of this file.
00001 /*
00002 
00003 *************************************************************************
00004 
00005 ArmageTron -- Just another Tron Lightcycle Game in 3D.
00006 Copyright (C) 2000  Manuel Moos (manuel@moosnet.de)
00007 
00008 **************************************************************************
00009 
00010 This program is free software; you can redistribute it and/or
00011 modify it under the terms of the GNU General Public License
00012 as published by the Free Software Foundation; either version 2
00013 of the License, or (at your option) any later version.
00014 
00015 This program is distributed in the hope that it will be useful,
00016 but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018 GNU General Public License for more details.
00019 
00020 You should have received a copy of the GNU General Public License
00021 along with this program; if not, write to the Free Software
00022 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00023 
00024 ***************************************************************************
00025 
00026 */
00027 
00028 
00029 #include "rSDL.h"
00030 
00031 #include "gWall.h"
00032 #include "gStuff.h"
00033 #include "eGrid.h"
00034 #include "eWall.h"
00035 #include "math.h"
00036 #include "gCycle.h"
00037 #include "rTexture.h"
00038 #include "eTimer.h"
00039 #include "gGame.h"
00040 #include "rScreen.h"
00041 #include "rRender.h"
00042 #include "eCamera.h"
00043 #include "tConfiguration.h"
00044 #include "gExplosion.h"
00045 #include "tMath.h"
00046 #include "ePlayer.h"
00047 #include "eTess2.h"
00048 #include "nConfig.h"
00049 
00050 #include <fstream>
00051 
00052 /* **********************************************
00053    Wall
00054    ********************************************** */
00055 
00056 #ifndef DEDICATED
00057 
00058 // setting items to enable the old style semi-transparency of rim walls
00059 static bool sg_bugTransparency;
00060 static bool sg_bugTransparencyDemand;
00061 static tSettingItem< bool > sgc_bugTransparency( "BUG_TRANSPARENCY", sg_bugTransparency );
00062 static tSettingItem< bool > sgc_bugTransparencyDemand( "BUG_TRANSPARENCY_DEMAND", sg_bugTransparencyDemand );
00063 
00064 //texture ArmageTron_invis_eWall("eWall2.png",1,0);
00065 /*
00066 static tString lala_wallRim("Anonymous/original/textures/rim_wall.png");
00067 static nSettingItem<tString> lalala_wallRim("TEXTURE_WALLRIM", lala_wallRim);
00068 rFileTexture gWallRim_text(rTextureGroups::TEX_WALL, lala_wallRim, 1,1);
00069 
00070 static tString lala_mp_wallRimA("Anonymous/original/moviepack/rim_wall_a.png");
00071 static nSettingItem<tString> lalala_mp_wallRimA("TEXTURE_MP_WALLRIM_A", lala_mp_wallRimA);
00072 rFileTexture gWallRim_a(rTextureGroups::TEX_WALL, lala_mp_wallRimA, 0,0);
00073 
00074 static tString lala_mp_wallRimB("Anonymous/original/moviepack/rim_wall_b.png");
00075 static nSettingItem<tString> lalala_mp_wallRimB("TEXTURE_MP_WALLRIM_B", lala_mp_wallRimB);
00076 rFileTexture gWallRim_b(rTextureGroups::TEX_WALL, lala_mp_wallRimB, 0,0);
00077 
00078 static tString lala_mp_wallRimC("Anonymous/original/moviepack/rim_wall_c.png");
00079 static nSettingItem<tString> lalala_mp_wallRimC("TEXTURE_MP_WALLRIM_C", lala_mp_wallRimC);
00080 rFileTexture gWallRim_c(rTextureGroups::TEX_WALL, lala_mp_wallRimC, 0,0);
00081 
00082 static tString lala_mp_wallRimD("Anonymous/original/moviepack/rim_wall_d.png");
00083 static nSettingItem<tString> lalala_mp_wallRimD("TEXTURE_MP_WALLRIM_D", lala_mp_wallRimD);
00084 rFileTexture gWallRim_d(rTextureGroups::TEX_WALL, lala_mp_wallRimD, 0,0);
00085 */
00086 
00087 //static rTexture gWallRim_text_moviepack(rTEX_WALL,"moviepack/gWallRim2.png",1,0);
00088 static rFileTexture gWallRim_a(rTextureGroups::TEX_WALL,"moviepack/rim_wall_a.png",0,0);
00089 static rFileTexture gWallRim_b(rTextureGroups::TEX_WALL,"moviepack/rim_wall_b.png",0,0);
00090 static rFileTexture gWallRim_c(rTextureGroups::TEX_WALL,"moviepack/rim_wall_c.png",0,0);
00091 static rFileTexture gWallRim_d(rTextureGroups::TEX_WALL,"moviepack/rim_wall_d.png",0,0);
00092 
00093 static rITexture *gWallRim_mp[4]={&gWallRim_a,&gWallRim_b,
00094                                   &gWallRim_c,&gWallRim_d};
00095 
00096 /*
00097 static tString lala_dir_eWall("Anonymous/original/textures/dir_wall.png");
00098 static nSettingItem<tString> lalala_dir_eWall("TEXTURE_DIR_WALL", lala_dir_eWall);
00099 rFileTexture dir_eWall(rTextureGroups::TEX_WALL, lala_dir_eWall, 1,0);
00100 
00101 static tString lala_mp_dir_eWall("Anonymous/original/moviepack/dir_wall.png");
00102 static nSettingItem<tString> lalala_mp_dir_eWall("TEXTURE_MP_DIR_WALL", lala_mp_dir_eWall);
00103 rFileTexture dir_eWall_moviepack(rTextureGroups::TEX_WALL, lala_mp_dir_eWall, 1,0);
00104 */
00105 #endif
00106 
00107 static REAL sg_RimStretchX=100;
00108 static tSettingItem<REAL> sg_RimStretchXConf
00109 ("RIM_WALL_STRETCH_X",sg_RimStretchX);
00110 static REAL sg_RimStretchY=100;
00111 static tSettingItem<REAL> sg_RimStretchYConf
00112 ("RIM_WALL_STRETCH_Y",sg_RimStretchY);
00113 
00114 static REAL sg_MPRimStretchX=50;
00115 static tSettingItem<REAL> sg_MPRimStretchXConf
00116 ("MOVIEPACK_RIM_WALL_STRETCH_X",sg_MPRimStretchX);
00117 static REAL sg_MPRimStretchY=50;
00118 static tSettingItem<REAL> sg_MPRimStretchYConf
00119 ("MOVIEPACK_RIM_WALL_STRETCH_Y",sg_MPRimStretchY);
00120 
00121 /* **********************************************
00122    RimWall
00123    ********************************************** */
00124 
00125 gWallRim::gWallRim(eGrid *grid, REAL h)
00126         :eWallRim(grid, false, h), renderHeight_(h), lastUpdate_(-100), tBeg_( 0 ), tEnd_( 0 )
00127 {
00128     // std::cout << "create " << this << "\n";
00129 }
00130 
00131 gWallRim::gWallRim(eGrid *grid, REAL tBeg, REAL tEnd, REAL h)
00132         :eWallRim(grid, false, h), renderHeight_(h), lastUpdate_(-100), tBeg_( tBeg ), tEnd_( tEnd )
00133 {
00134     // std::cout << "create " << this << "\n";
00135 }
00136 
00137 gWallRim::~gWallRim()
00138 {
00139     // std::cout << "destroy " << this << "\n";
00140 }
00141 
00142 bool gWallRim::Splittable() const{return 1;}
00143 void gWallRim::Split(eWall *& w1,eWall *& w2,REAL ratio)
00144 {
00145     // std::cout << "split " << this << "\n";
00146 
00147     REAL tMid = tEnd_ * ratio + tBeg_ * ( 1 - ratio );
00148     w1=tNEW(gWallRim(grid, tBeg_, tMid, height));
00149     w2=tNEW(gWallRim(grid, tMid, tEnd_, height));
00150 }
00151 
00152 // do not allow walls to run parallel
00153 bool gWallRim::RunsParallelPassive( eWall* newWall )
00154 {
00155     return false;
00156 }
00157 
00158 // from display.C
00159 extern REAL lower_height,upper_height;
00160 
00161 #ifndef DEDICATED
00162 
00163 
00164 static void gWallRim_helper(eCoord p1,eCoord p2,REAL tBeg,REAL tEnd,REAL h,
00165                             REAL Z_SCALE,bool sw){
00166 
00167     // draw additional upper line
00168     /*
00169     sr_DepthOffset(true);
00170     glPolygonOffset(-100,10000000);
00171     glDisable(GL_TEXTURE_2D);
00172     BeginLines();
00173     Color(1,1,1);
00174     Vertex(p1.x,p1.y,1);
00175     Vertex(p2.x,p2.y,1);
00176     RenderEnd();
00177     sr_DepthOffset(false);
00178     glDisable(GL_POLYGON_OFFSET_LINE);
00179     glEnable(GL_TEXTURE_2D);
00180     */
00181 
00182     if (sg_MoviePack()){
00183         int t=int(floor((tBeg+tEnd)/2));
00184         tBeg-=t;
00185         tEnd-=t;
00186         t=t%4;
00187         while (t<0)
00188             t+=4;
00189         gWallRim_mp[t]->Select();
00190     }
00191 
00192     if (sw){
00193         Swap(p1,p2);
00194         Swap(tBeg,tEnd);
00195     }
00196 
00197 
00198     if (h>9000){
00199         if (sr_lowerSky || sg_MoviePack()) h=lower_height;
00200         if (sr_upperSky && !sg_MoviePack()) h=upper_height;
00201     }
00202 
00203     BeginQuads();
00204 
00205     // NOTE: display lists on nvidia cards don't like infinite points
00206     if (h<9000 || !sr_infinityPlane || rDisplayList::IsRecording() ){
00207         TexVertex(p1.x, p1.y, 0,
00208                   tBeg      , 1);
00209 
00210         TexVertex(p1.x, p1.y, h,
00211                   tBeg,       1-h/Z_SCALE);
00212 
00213         TexVertex(p2.x, p2.y, h,
00214                   tEnd,       1-h/Z_SCALE);
00215 
00216         TexVertex(p2.x, p2.y, 0,
00217                   tEnd      , 1);
00218     }
00219 
00220     else{
00221         TexVertex(p1.x, p1.y, 0,
00222                   tBeg,       1);
00223 
00224         TexCoord(0,-1/REAL(Z_SCALE),0,0);
00225 
00226 #ifndef WIN32
00227         Vertex(0,0,1,0);
00228         Vertex(0,0,1,0);
00229 #else
00230         Vertex(0.001f,0.001f,1,0); // Windows OpenGL has problems with
00231         // infitite points perpenticular to the viewing direction
00232         Vertex(0.001f,0.001f,1,0);
00233 #endif
00234 
00235         TexVertex(p2.x, p2.y, 0,
00236                   tEnd,       1);
00237     }
00238 }
00239 
00240 // maximal size of the arena wall shadow compared to the camera height
00241 static REAL sg_arenaWallShadowSize = 0.1;
00242 static tSettingItem<REAL> sg_arenaWallShadowSizeConf("ARENA_WALL_SHADOW_SIZE",sg_arenaWallShadowSize);
00243 
00244 // shadows are drawn when the cycle gets closer to the line the wall follows than this
00245 static REAL sg_arenaWallShadowSideDist = 10.0;
00246 static tSettingItem<REAL> sg_arenaWallShadowSideDistConf("ARENA_WALL_SHADOW_SIDEDIST",sg_arenaWallShadowSideDist);
00247 
00248 // getting closer to the wall than this distance does not increase the shadow much
00249 static REAL sg_arenaWallShadowNear = 1.0;
00250 static tSettingItem<REAL> sg_arenaWallShadowNearConf("ARENA_WALL_SHADOW_NEAR",sg_arenaWallShadowNear);
00251 
00252 // shadows are drawn when the cycle gets closer to the wall than this
00253 static REAL sg_arenaWallShadowDist = 100.0;
00254 static tSettingItem<REAL> sg_arenaWallShadowDistConf("ARENA_WALL_SHADOW_DIST",sg_arenaWallShadowDist);
00255 
00256 void gWallRim::RenderReal(const eCamera *cam){
00257     if ( Edge() ){
00258         const eCoord *p1=&EndPoint(0);
00259         const eCoord *p2=&EndPoint(1);
00260 
00261         REAL X_SCALE=sg_RimStretchX;
00262         REAL Z_SCALE=sg_RimStretchY;
00263 
00264         // determine height and transparency
00265         bool transparency = sg_bugTransparency || ( sg_bugTransparencyDemand && renderHeight_ < height );
00266         REAL h = transparency ? height : renderHeight_;
00267         if ( transparency )
00268             glDisable( GL_DEPTH_TEST );
00269 
00270       if (sg_MoviePack()){
00271             X_SCALE=sg_MPRimStretchX;
00272             Z_SCALE=sg_MPRimStretchY;
00273         }
00274 
00275         if ( tBeg_ == tEnd_ )
00276         {
00277             tBeg_=(p1->x+p1->y);
00278             tEnd_=(p2->x+p2->y);
00279         }
00280         REAL tBeg = tBeg_/X_SCALE;
00281         REAL tEnd = tEnd_/X_SCALE;
00282         eCoord P1=*p1;
00283         eCoord P2=*p2;
00284 
00285         // draw "shadow" away from camera
00286         if ( cam )
00287         {
00288             // determine relevant position
00289             eCoord pos = cam->CenterPos();
00290 
00291             // alternative that does not look so good
00292             // eCoord pos = cam->CameraGlancePos();
00293 
00294             // calculate normal on wall
00295             eCoord normal = (P1 - P2).Turn(0,1);
00296             normal.Normalize();
00297 
00298             // determine distance of the position to the wall's line
00299             REAL side = -eCoord::F(normal, pos - P1);
00300 
00301             // length scale
00302             REAL scale = pos.Norm() + 10 + (P1-P2).Norm();
00303 
00304             // add a tiny contribution from the direction to avoid side==zero
00305             // side += (  20 * EPS * eCoord::F( normal, cam->CenterCamDir() )
00306             //          +10 * EPS * eCoord::F( normal, cam->CameraDir() ) ) * scale;
00307 
00308             // fallback to camera position in case of doubt
00309             // if ( fabs(side) < EPS*scale )
00310             //    side = -eCoord::F( normal, cam->CameraGlancePos() );
00311 
00312             // get absolute value and sign of side
00313             REAL abs = fabs(side);
00314             REAL sign = side/abs;
00315 
00316             // if abs is low, override the sign by considering the direction
00317             if ( abs < EPS*scale*10 )
00318             {
00319                 // the direction object and camera are facing
00320                 eCoord facing = cam->CenterCamDir() * 2 + cam->CameraDir();
00321 
00322                 sign = eCoord::F( normal, facing );
00323                 abs  = fabs( sign );
00324                 if ( abs > EPS )
00325                 {
00326                     sign/= fabs( sign );
00327                     abs  = EPS*scale;
00328                 }
00329                 else
00330                 {
00331                     abs  = 0;
00332                     sign = 0;
00333                 }
00334             }
00335 
00336             // driving direction
00337             eCoord dir = cam->CenterCamDir();
00338 
00339             // the side the camera is on
00340             REAL camSide = -eCoord::F(normal, cam->CameraGlancePos() - P1);
00341 
00342             // no shadow if camera and vehicle are on different sides
00343             if ( camSide * sign < -EPS*scale )
00344                 sign = 0;
00345 
00346             // if the camera is closer to the wall than the vehicle, take the abs value from that
00347             if ( sign * eCoord::F( normal, dir ) > -EPS )
00348             {
00349                 if ( camSide * sign >= 0 )
00350                 {
00351                     REAL camAbs = fabs( camSide );
00352                     if ( camAbs < abs )
00353                         abs = camAbs;
00354                 }
00355                 else
00356                 {
00357                     // wall lies between camera and cycle
00358                     abs = 0;
00359                 }
00360             }
00361 
00362             // add scaled down distance of the wall and the projected path
00363             {
00364                 REAL d1 = dir * (pos - P1);
00365                 REAL d2 = dir * (pos - P2);
00366                 if ( d1 * d2 >= 0 )
00367                 {
00368                     REAL dist = fabs( d1 );
00369                     d2 = fabs( d2 );
00370                     if ( d2 < dist )
00371                         dist = d2;
00372 
00373                     abs += dist * sg_arenaWallShadowSideDist/sg_arenaWallShadowDist;
00374                 }
00375             }
00376 
00377             // add scaled down distance along the wall's direction
00378             /*
00379             {
00380                 REAL a1 = -(pos - P1)*normal;
00381                 REAL a2 =  (pos - P2)*normal;
00382                 if (a1 > 0)
00383                     abs += a1 * sg_arenaWallShadowSideDist/sg_arenaWallShadowDist;
00384                 if (a2 > 0)
00385                     abs += a2 * sg_arenaWallShadowSideDist/sg_arenaWallShadowDist;
00386             }
00387             */
00388 
00389             if ( sign != 0 && abs < sg_arenaWallShadowSideDist )
00390             {
00391                 // determine height scale
00392                 REAL heightForShadow = cam->CameraZ()+10;
00393                 if ( this->renderHeight_*4 < heightForShadow )
00394                     heightForShadow = this->renderHeight_*4;
00395 
00396                 // determine shadow extension
00397                 REAL extension = heightForShadow*sg_arenaWallShadowSize * sign/( 1 + abs/sg_arenaWallShadowNear );
00398                 extension *= ( 1 - abs/sg_arenaWallShadowSideDist );
00399 
00400                 // get two more vertices for teh shadow
00401                 eCoord P3=P1+normal*extension;
00402                 eCoord P4=P2+normal*extension;
00403 
00404                 // render shadow
00405                 Color(0,0,0);
00406                 BeginQuads();
00407                 Vertex(P1.x, P1.y, 0);
00408                 Vertex(P2.x, P2.y, 0);
00409                 Vertex(P4.x, P4.y, 0);
00410                 Vertex(P3.x, P3.y, 0);
00411             }
00412         }
00413 
00414         {
00415             eCoord vec = P1-P2;
00416             REAL xs = vec.x*vec.x;
00417             REAL ys = vec.y*vec.y;
00418             REAL intensity = .7 + .3 * xs/(xs+ys);
00419             RenderEnd( true );
00420             Color(intensity, intensity, intensity);
00421         }
00422 
00423         if (sg_MoviePack()){
00424             bool sw=false;
00425 
00426             if (tBeg>tEnd){
00427                 Swap(P1,P2);
00428                 Swap(tBeg,tEnd);
00429                 //sw=true;
00430             }
00431 
00432             REAL ta=tBeg;
00433             eCoord ca=P1;
00434             for (int i=int(ceil(tBeg));i<tEnd;i++){
00435                 eCoord cb=P1+(P2-P1)*((i-tBeg)/(tEnd-tBeg));
00436                 gWallRim_helper(ca,cb,ta,i,h,Z_SCALE,sw);
00437                 ca=cb;
00438                 ta=i;
00439             }
00440             gWallRim_helper(ca,P2,ta,tEnd,h,Z_SCALE,sw);
00441         }
00442         else{
00443             // wrap manually in y-direction, some graphics card are bad at it
00444             REAL offset = 0;
00445             if (tBeg>tEnd)
00446                 offset = -floor(tEnd);
00447             else
00448                 offset = -floor(tBeg);
00449 
00450             tBeg += offset;
00451             tEnd += offset;
00452 
00453             gWallRim_helper(*p1,*p2,tBeg,tEnd,h,Z_SCALE,false);
00454         }
00455 
00456         //eWall::Render_helper(edge,(p1->x+p1->y)/SCALE,(p2->x+p2->y)/SCALE,40,height);
00457             
00458         if ( transparency )
00459             glEnable( GL_DEPTH_TEST );
00460     }
00461 
00462     // grow the wall again
00463     if ( se_mainGameTimer )
00464     {
00465         REAL time = se_mainGameTimer->Time();
00466         REAL ts = time - lastUpdate_;
00467         if ( ts > 0 )
00468         {
00469             lastUpdate_ = time;
00470 
00471             if ( renderHeight_ < .25 )
00472             {
00473                 renderHeight_ = .25;
00474             }
00475             renderHeight_ *= 1 + 10 * ts;
00476             renderHeight_ += 5 * ts;
00477             if ( renderHeight_ > height )
00478             {
00479                 renderHeight_ = height;
00480             }
00481         }
00482 
00483         if ( renderHeight_ < height )
00484         {
00485             DestroyDisplayList();
00486         }
00487     }
00488 }
00489 
00490 // *******************************************************************************************
00491 // *
00492 // *   OnBlocksCamera
00493 // *
00494 // *******************************************************************************************
00499 // *******************************************************************************************
00500 
00501 void gWallRim::OnBlocksCamera( eCamera * camera, REAL height ) const
00502 {
00503     DestroyDisplayList();
00504 
00505     // lower the wall so it now longer blocks the view
00506     if ( height < renderHeight_ )
00507     {
00508         renderHeight_ = height;
00509    }
00510     if ( renderHeight_ < .25 )
00511         renderHeight_ = .25;
00512 }
00513 
00514 #endif
00515 
00516 // *******************************************************************************************
00517 // *
00518 // *   Height
00519 // *
00520 // *******************************************************************************************
00524 // *******************************************************************************************
00525 
00526 REAL gWallRim::Height( void )
00527 {
00528     return renderHeight_;
00529 }
00530 
00531 // *******************************************************************************************
00532 // *
00533 // *   SeeHeight
00534 // *
00535 // *******************************************************************************************
00539 // *******************************************************************************************
00540 
00541 REAL gWallRim::SeeHeight( void )
00542 {
00543     return renderHeight_ * 2;
00544 }
00545 
00546 /* **********************************************
00547    PlayerWall
00548    ********************************************** */
00549 
00550 #ifdef DEBUG
00551 #define CHECKWALL this->Check();
00552 #else
00553 #define CHECKWALL
00554 #endif
00555 
00556 gPlayerWall::gPlayerWall(gNetPlayerWall*w, gCycle *p)
00557         :eWall(p->grid),cycle_(p),netWall_(w),begDist_(w->Pos(0)),endDist_(w->Pos(1))
00558 {
00559     CHECKWALL;
00560 
00561     if (cycle_)
00562         windingNumber_ = cycle_->WindingNumber();
00563 
00564 #ifdef DEBUG
00565     if (!cycle_)
00566     {
00567         //              st_Breakpoint();
00568     }
00569 #endif
00570 }
00571 
00572 gPlayerWall::~gPlayerWall(){
00573     CHECKWALL;
00574 }
00575 
00576 //ArmageTron_eWalltype gPlayerWall::type(){return ArmageTron_PLAYERWALL;}
00577 
00578 void gPlayerWall::Flip(){
00579     CHECKWALL;
00580 
00581     eWall::Flip();
00582     Swap( this->begDist_, this->endDist_ );
00583 
00584     CHECKWALL;
00585 }
00586 
00587 static void clamp01(REAL &c){
00588     if (!finite(c))
00589         c = 0.5;
00590 
00591     if (c<0)
00592         c = 0;
00593 
00594     if (c>1)
00595         c = 1;
00596 }
00597 
00598 // execute cycles that violate the rules of topology. To hell with them!
00599 void sg_TopologyPoliceKill( gCycle* cycle )
00600 {
00601     if ( sn_GetNetState() != nCLIENT && cycle->Alive() )
00602     {
00603         tOutput message;
00604         tString name;
00605         if ( cycle->Player() )
00606             name = cycle->Player()->GetName();
00607         else
00608             cycle->PrintName( name );
00609         message.SetTemplateParameter(1, name );
00610         message << "$player_topologypolice";
00611         sn_ConsoleOut( message );
00612 
00613         cycle->Kill();
00614     }
00615 }
00616 
00617 static short sg_topologyPolice = false;
00618 static tSettingItem< short > sg_topologyPoliceCofig( "TOPOLOGY_POLICE", sg_topologyPolice );
00619 
00620 static short sg_topologyPoliceParallel = true;
00621 static tSettingItem< short > sg_topologyPoliceParallelCofig( "TOPOLOGY_POLICE_PARALLEL", sg_topologyPoliceParallel );
00622 
00623 class gTopologyPoliceConsoleFiler: public tConsoleFilter
00624 {
00625     virtual void DoFilterLine( tString& line )
00626     {
00627         tString oldLine = line;
00628         tOutput message;
00629         message.SetTemplateParameter(1, oldLine );
00630         message << "$player_topologypolice";
00631         line = message;
00632     }
00633 };
00634 
00635 extern bool sg_gnuplotDebug; // from gCycle.cpp
00636 
00637 // called on a post-insert collision of two walls
00638 // oldWall is the wall that was in place first, newWall is the wall just drawn, and point
00639 // is a point of collision between the two.
00640 void sg_TopologyPoliceCheck( gCycle* cycle, eWall* oldWall, gPlayerWall* newWall, const eCoord& point, bool split )
00641 {
00642     // test if topology police is enabled
00643     if ( !sg_topologyPolice && !sg_gnuplotDebug )
00644         return;
00645 
00646     // locate point on both edges
00647     REAL oldAlpha = oldWall->Edge()->Ratio( point );
00648     REAL newAlpha = newWall->Edge()->Ratio( point );
00649     clamp01( newAlpha );
00650     clamp01( oldAlpha );
00651 
00652     // calculate time of passage
00653     REAL time = newWall->Time( newAlpha );
00654 
00655     // if the old wall does not lie in a hole of the new wall, don't go on.
00656     // this test overestimates the time ( instead of "se_GameTime()", it should
00657     // read just "time" ) to test wheter the wall is dangerous NOW
00658     // to avoid innocent victims. A wall never gets more dangerous with time.
00659     if ( !newWall->IsDangerous( newAlpha, se_GameTime() ) )
00660         return;
00661 
00662     // the same logic for the old wall
00663     gPlayerWall* oldPlayerWall = dynamic_cast< gPlayerWall* >( oldWall );
00664     if ( oldPlayerWall && !oldPlayerWall->IsDangerous( oldAlpha, se_GameTime() ) )
00665         return;
00666 
00667     // log collision for gnuplot
00668 #ifdef DEBUG
00669     if ( sg_gnuplotDebug )
00670     {
00671         std::stringstream filename;
00672         if ( cycle && cycle->Player() )
00673         {
00674             filename << cycle->Player()->GetUserName() << "_";
00675         }
00676         filename << "topology";
00677         std::ofstream f( filename.str().c_str(), std::ios::app );
00678         f << point.x << " " << point.y << "\n";
00679     }
00680 #endif
00681 
00682     // last chance to exit
00683     if ( !sg_topologyPolice || ( !split && !sg_topologyPoliceParallel ) )
00684         return;
00685 
00686     gTopologyPoliceConsoleFiler filter;
00687 
00688     // treat the crossing as if the cycle just went through the old wall.
00689     try
00690     {
00691         cycle->PassEdge( oldWall, time, oldAlpha );
00692     }
00693     catch ( gCycleDeath const & death )
00694     {
00695         cycle->KillAt( death.pos_ );
00696     }
00697 }
00698 
00699 // collision hooks
00700 void gPlayerWall::SplitByActive( eWall * oldWall )
00701 {
00702     if ( oldWall )
00703     {
00704         // pretend our cycle crossed the old wall just now
00705         eCoord intersection = oldWall->Edge()->IntersectWithCareless( Edge() );
00706         sg_TopologyPoliceCheck( Cycle(), oldWall, this, intersection, true );
00707     }
00708     else
00709     {
00710         sg_TopologyPoliceKill( Cycle() );
00711     }
00712 
00713     eWall::SplitByActive( oldWall );
00714 }
00715 
00716 // hook called when walls are really parallel on the grid
00717 bool gPlayerWall::RunsParallelActive( eWall* oldWall )
00718 {
00719     if ( oldWall )
00720     {
00721 
00722         // collision point: center of gravity
00723         eCoord collision = ( oldWall->Point(.5f) + this->Point(.5f) ) *.5f;
00724 
00725         sg_TopologyPoliceCheck( Cycle(), oldWall, this, collision, false );
00726     }
00727     else
00728     {
00729         sg_TopologyPoliceKill( Cycle() );
00730     }
00731 
00732     return eWall::RunsParallelPassive( oldWall );
00733 }
00734 
00735 bool gPlayerWall::Splittable() const{return 1;}
00736 
00737 bool gPlayerWall::Deletable() const{
00738     CHECKWALL;
00739 
00740     // a wall without a cycle can clearly be deleted
00741     if ( !cycle_ )
00742         return true;
00743 
00744     return !IsDangerousAnywhere( se_GameTime() - 1.0f );
00745 }
00746 
00747 /*
00748 static void S_Mix( const gPlayerWallCoord source[2], REAL alpha, gPlayerWallCoord& target )
00749 {
00750         REAL diff  = ( source[1].Alpha - source[0].Alpha );
00751         REAL ralpha = 0;
00752         if ( diff > 0 )
00753                 ralpha     = ( alpha - source[0].Alpha ) / diff;
00754 
00755         target.Alpha = alpha;
00756         target.Pos   = source[0].Pos  + ralpha * ( source[1].Pos  - source[0].Pos  );
00757         target.Pos   = source[0].Time + ralpha * ( source[1].Time - source[0].Time );
00758 }
00759 */
00760 
00761 void gPlayerWall::Split(eWall *& w1,eWall *& w2,REAL a){
00762     CHECKWALL;
00763 
00764     gPlayerWall *W1, *W2;
00765 
00766     W1=tNEW(gPlayerWall(netWall_,cycle_));
00767     W2=tNEW(gPlayerWall(netWall_,cycle_));
00768     W1->windingNumber_ = windingNumber_;
00769     W2->windingNumber_ = windingNumber_;
00770     W1->begDist_ = begDist_;
00771     W2->endDist_ = endDist_;
00772     W1->endDist_ = W2->begDist_ = begDist_ + ( endDist_ - begDist_ ) * a;
00773 
00774     /*
00775         int divindex = IndexPos( mp );
00776         int i;
00777 
00778         // transfer front points
00779         W1->coords_.SetLen( divindex + 2 );
00780         for ( i = divindex+1; i>=0; --i )
00781                 W1->coords_(i) = coords_(i);
00782 
00783         W1->coords_(divindex+1).Pos  = mp;
00784         W1->coords_(divindex+1).Time = mt;
00785 
00786         // transfer rear points
00787         W2->coords_.SetLen( coords_.Len() - divindex );
00788         for ( i = coords_.Len() - divindex - 1 ; i>=0; --i )
00789                 W2->coords_(i) = coords_( divindex + i );
00790 
00791         W2->coords_(0).Pos  = mp;
00792         W2->coords_(0).Time = mt;
00793 
00794         if ( flipped )
00795                 Swap( W1, W2 );
00796     */
00797 
00798     // store wall pointers
00799     w1 = W1;
00800     w2 = W2;
00801 
00802 #ifdef DEBUG
00803     W1->Check();
00804     W2->Check();
00805 #endif
00806 
00807     CHECKWALL;
00808 }
00809 
00810 //#define gBEG_LEN 2
00811 //#define gBEG_LEN .25
00812 //#define gCYCLE_LEN .95
00813 //#define gCYCLE_LEN 1.6
00814 #define gCYCLE_LEN 1.5
00815 #define gBEG_OFFSET .25
00816 #define gBEG_LEN 2
00817 //#define gCYCLE_LEN 3.8
00818 //#define gBEG_OFFSET 1
00819 
00820 #ifndef DEDICATED
00821 void gPlayerWall::Render(const eCamera *cam){
00822     if (!cycle_)
00823         return;
00824     RenderList(true);
00825 }
00826 
00827 void gNetPlayerWall::Render(const eCamera *cam ){
00828     if (!cycle_)
00829         return;
00830     RenderList(true);
00831 }
00832 
00833 /*
00834 class gPerformanceCounter
00835 {
00836 public:
00837     gPerformanceCounter(): count_(0){ tRealSysTimeFloat(); }
00838     unsigned int Count(){ return count_++; }
00839     ~gPerformanceCounter()
00840     {
00841         double time = tRealSysTimeFloat();
00842         std::stringstream s;
00843         s << count_ << " walls in " << time << " seconds: " << count_ / time << " wps.\n";
00844 #ifdef WIN32
00845         MessageBox (NULL, s.str().c_str() , "Performance", MB_OK);
00846 #else
00847         std::cout << s.str();
00848 #endif
00849     }
00850 private:
00851     unsigned int count_;
00852 };
00853 */
00854 
00855 void gPlayerWall::RenderList(bool list)
00856 {
00857     netWall_->RenderList( list );
00858 }
00859 
00860 void gNetPlayerWall::RenderList(bool list, gWallRenderMode renderMode ){
00861     if ( !cycle_ )
00862     {
00863         return;
00864     }
00865 
00866 #ifdef DEBUG_X
00867     if ( cycle_->Player()->GetName().StartsWith("B") && dbegin < .1 )
00868     {
00869         int x;
00870         x = 1;
00871     }
00872 #endif
00873     // clear list if walls are vanishing
00874     // or if the wall end was reached
00875     // or this is the cycle's first wall
00876     if ( gCycleWallsDisplayListManager::CannotHaveList( dbegin, cycle_ ) ||
00877          this == cycle_->currentWall )
00878     {
00879         ClearDisplayList(2);
00880     }
00881 
00882     if ( !displayList_.Call() )
00883     {   
00884         //static gPerformanceCounter counter;
00885         //counter.Count();
00886 
00887         rDisplayListFiller filler( displayList_ );
00888 
00889         REAL r,g,b;
00890         if (cycle_){
00891             r=cycle_->trailColor_.r;
00892             g=cycle_->trailColor_.g;
00893             b=cycle_->trailColor_.b;
00894         }
00895         else
00896             r=g=b=1;
00897 
00898         eCoord P1=EndPoint(0);
00899         eCoord P2=EndPoint(1);
00900 
00901         {
00902             eCoord vec = P2-P1;
00903             REAL xs = vec.x*vec.x;
00904             REAL ys = vec.y*vec.y;
00905             REAL intensity = .7 + .3 * xs/(xs+ys);
00906             r *= intensity;
00907             g *= intensity;
00908             b *= intensity;
00909         }
00910 
00911         REAL a=1;
00912 
00913 #define SEGLEN 2.5
00914         //REAL ta=startTime*3;
00915         //REAL te=endTime*3;
00916         for ( int i = coords_.Len()-2; i>=0; --i )
00917         {
00918             const gPlayerWallCoord* coord = &coords_(i);
00919 
00920             if ( !coord[0].IsDangerous )
00921                 continue;
00922 
00923             REAL pa = coord[0].Pos;
00924             REAL pe = coord[1].Pos;
00925 
00926             REAL aa = Alpha( pa );
00927             REAL ae = Alpha( pe );
00928 
00929             eCoord p1 = P1 + ( P2 - P1 ) * aa;
00930             eCoord p2 = P1 + ( P2 - P1 ) * ae;
00931 
00932             REAL ta=pa/SEGLEN;
00933             REAL te=pe/SEGLEN;
00934             //REAL shift=REAL(floor((ta+te)/20)*10);
00935 
00936             //REAL time=ArmageTronTimer*3;
00937             REAL time;
00938             if (cycle_)
00939             {
00940                 if ( cycle_->currentWall )
00941                     time = cycle_->currentWall->EndPos()/SEGLEN;
00942                 else
00943                     time=cycle_->GetDistance()/SEGLEN;
00944                 if ( !cycle_->Alive() )
00945                     time += se_GameTime() - cycle_->deathTime;
00946             }
00947             else
00948                 time=0;
00949 
00950             //ta-=shift;
00951             //te-=shift;
00952             //time-=shift;
00953 
00954             if (ta>te){
00955                 Swap(ta,te);
00956                 Swap(p1,p2);
00957                 Swap(pa,pe);
00958             }
00959 
00960             // cut the end of the wall
00961             if ( bool(cycle_) && gCycle::WallsLength() > 0 )
00962             {
00963                 REAL cut = (cycle_->GetDistance() - cycle_->ThisWallsLength() - pe) / ( pa - pe );
00964                 if ( cut < 0 )
00965                     continue;
00966                 if ( cut < 1 )
00967                 {
00968                     p1 = p2 + (p1-p2)*cut;
00969                     ta = te + (ta-te)*cut;
00970                 }
00971             }
00972 
00973             if (te+gBEG_LEN<=time){
00974                 RenderNormal(p1,p2,ta,te,r,g,b,a,renderMode);
00975                 sr_CheckGLError();
00976             }
00977 
00978             else{ // complicated
00979                 // can't squeeze that into a display list
00980                 ClearDisplayList();
00981 
00982                 if (ta+gBEG_LEN>=time){
00983                     sr_CheckGLError();
00984                     RenderBegin(p1,p2,ta,te,
00985                                 1+(ta-time)/gBEG_LEN,
00986                                 1+(te-time)/gBEG_LEN,
00987                                 r,g,b,a);
00988                     sr_CheckGLError();
00989                 }
00990                 else{
00991                     sr_CheckGLError();
00992                     REAL s=((time-gBEG_LEN)-ta)/(te-ta);
00993                     eCoord pm=p1+(p2-p1)*s;
00994                     RenderBegin(pm,p2,
00995                                 ta+(te-ta)*s,te,0,
00996                                 1+(te-time)/gBEG_LEN,
00997                                 r,g,b,a);
00998                     RenderNormal(p1,pm,ta,ta+(te-ta)*s,r,g,b,a, gWallRenderMode_All );
00999                     sr_CheckGLError();
01000                 }
01001             }
01002         }
01003     }
01004 }
01005 
01006 
01007 inline bool upperlinecolor(REAL r,REAL g,REAL b, REAL a){
01008     if (rTextureGroups::TextureMode[rTextureGroups::TEX_WALL]<0)
01009         glColor4f(1,1,1,a);
01010     else{
01011         /*
01012           REAL upperline_alpha=fabs(se_cameraRise*2);
01013           upperline_alpha-=1;
01014           if (upperline_alpha>.5)
01015           upperline_alpha=1;
01016           if (upperline_alpha<=.5)
01017           return false;
01018           glColor4f(r,g,b,upperline_alpha);
01019         */
01020         //glDisable(GL_TEXTURE);
01021         glColor4f(r,g,b,a);
01022     }
01023 
01024     return true;
01025 }
01026 
01027 void gNetPlayerWall::RenderNormal(const eCoord &p1,const eCoord &p2,REAL ta,REAL te,REAL r,REAL g,REAL b,REAL a, gWallRenderMode mode ){
01028     REAL hfrac=1;
01029 
01030     if (bool(cycle_) && !cycle_->Alive() && gCycle::WallsStayUpDelay() >= 0 ){
01031         REAL dt=(se_GameTime()-cycle_->deathTime-gCycle::WallsStayUpDelay())*2;
01032 
01033         if (dt>1)
01034         {
01035             // remove from rendering lists
01036             Remove();
01037             return;
01038         }
01039 
01040         if (dt>=0)
01041         {
01042             REAL ca=REAL(.5/(dt+.5));
01043             REAL alpha=1-dt;
01044             if (alpha>1) alpha=1;
01045             hfrac=1-dt;
01046 
01047             r+=ca;
01048             b+=ca;
01049             g+=ca;
01050 
01051             a*=alpha;
01052         }
01053     }
01054     REAL h=1;
01055 
01056 
01057     if (hfrac>0){
01058         if ( ( mode & gWallRenderMode_Lines ) ){
01059 
01060             // draw additional upper line
01061             if ( mode == gWallRenderMode_All )
01062             {
01063                 sr_DepthOffset(true);
01064                 if ( rTextureGroups::TextureMode[rTextureGroups::TEX_WALL] != 0 )
01065                 {
01066                     RenderEnd();
01067                     glDisable(GL_TEXTURE_2D);
01068                 }
01069             }
01070 
01071             BeginLines();
01072             upperlinecolor(r,g,b,a);
01073             glVertex3f(p1.x,p1.y,h*hfrac);
01074             upperlinecolor(r,g,b,a);
01075             glVertex3f(p2.x,p2.y,h*hfrac);
01076 
01077             // in the other modes, the caller is responsible for
01078             // calling RenderEnd() and resetting the states.
01079             if ( mode == gWallRenderMode_All )
01080             {
01081                 RenderEnd();
01082                 sr_DepthOffset(false);
01083                 if ( rTextureGroups::TextureMode[rTextureGroups::TEX_WALL] != 0 )
01084                     glEnable(GL_TEXTURE_2D);
01085             }
01086         }
01087 
01088         //glColor4f(r,g,b,a);
01089 
01090 #ifdef XDEBUG
01091         REAL extrarise = 0;
01092         if ( this->id >= 0 )
01093         {
01094             extrarise = 1;
01095         }
01096 #else
01097         static const REAL extrarise = 0;
01098 #endif
01099         if ( mode & gWallRenderMode_Quads )
01100         {
01101             BeginQuads();
01102 
01103             glColor3f(r,g,b);
01104             glTexCoord2f(ta,hfrac);
01105             glVertex3f(p1.x,p1.y,extrarise);
01106             
01107             glColor3f(r,g,b);
01108             glTexCoord2f(ta,0);
01109             glVertex3f(p1.x,p1.y,extrarise + h*hfrac);
01110             
01111             glColor3f(r,g,b);
01112             glTexCoord2f(te,0);
01113             glVertex3f(p2.x,p2.y,extrarise + h*hfrac);
01114             
01115             glColor3f(r,g,b);
01116             glTexCoord2f(te,hfrac);
01117             glVertex3f(p2.x,p2.y,extrarise);
01118 
01119                         // in the other modes, the caller is responsible for
01120                         // calling RenderEnd().
01121                         if ( mode == gWallRenderMode_All )
01122                         {
01123                                 RenderEnd();
01124                         }
01125         }
01126     }
01127 }
01128 
01129 static inline REAL hfunc(REAL x){return 1-(x*x)/2;}
01130 //static inline REAL hfunc(REAL x){return 1-(x*x);}
01131 static inline REAL cfunc(REAL x){return (x*x);}
01132 //static inline REAL afunc(REAL x){return 1-(x*x)/2;}
01133 static inline REAL afunc(REAL x){return 1-(x*x);}
01134 static inline REAL sfunc(REAL x){return (x*x);}
01135 //static inline REAL xfunc(REAL x){return (x+x*x)/2;}
01136 static inline REAL xfunc(REAL x){return REAL((x*.2+x*x)/2);}
01137 
01138 void gNetPlayerWall::RenderBegin(const eCoord &p1,const eCoord &pp2,REAL ta,REAL te,REAL ra,REAL re,REAL r,REAL g,REAL b,REAL a){
01139     if ( !cycle_ )
01140     {
01141         return;
01142     }
01143 
01144     REAL hfrac=1;
01145 
01146     eCoord p2 = pp2;
01147 
01148     if (re > 1){
01149         if (re > 2)
01150             return;
01151 
01152         REAL ratio = (1-ra)/(re-ra);
01153         p2 = p1 + (pp2-p1)*ratio;
01154         te = ta + (te-ta)*ratio;
01155         re= 1;
01156     }
01157 
01158     if (bool(cycle_) && !cycle_->Alive()){
01159         REAL dt=(se_GameTime()-cycle_->deathTime-gCycle::WallsStayUpDelay())*2;
01160         if (dt>1) dt=1;
01161         if (dt>0)
01162         {
01163             REAL ca=REAL(.5/(dt+.5));
01164             REAL alpha=1-dt;
01165             if (alpha>1) alpha=1;
01166             hfrac=1-dt;
01167 
01168             r+=ca;
01169             b+=ca;
01170             g+=ca;
01171         }
01172         //a*=alpha;
01173     }
01174 
01175     REAL h=1;
01176 
01177     eCoord ppos=cycle_->PredictPosition() - cycle_->dir*REAL(gCYCLE_LEN);
01178 
01179     if ( hfrac>0 ){
01180         sr_DepthOffset(true);  
01181         //REAL H=h*hfrac;
01182 #define segs 5
01183         upperlinecolor(r,g,b,a);//a*afunc(rat));
01184 
01185         if ( rTextureGroups::TextureMode[rTextureGroups::TEX_WALL] != 0 )
01186             glDisable(GL_TEXTURE_2D);
01187         
01188         BeginLineStrip();
01189 
01190         for (int i=0;i<=segs;i++){
01191             REAL frag=i/float(segs);
01192             REAL rat=ra+frag*(re-ra);
01193             REAL x=(p1.x+frag*(p2.x-p1.x))*(1-xfunc(rat))+ppos.x*xfunc(rat);
01194             REAL y=(p1.y+frag*(p2.y-p1.y))*(1-xfunc(rat))+ppos.y*xfunc(rat);
01195 
01196             REAL H=h*hfrac*hfunc(rat);
01197             upperlinecolor(r,g,b,a*afunc(rat));
01198             glVertex3f(x+H*cycle_->skew*sfunc(rat)*cycle_->dir.y,
01199                        y-H*cycle_->skew*sfunc(rat)*cycle_->dir.x,
01200                        H);//+se_cameraZ*.005);
01201         }
01202         RenderEnd();
01203 
01204         sr_DepthOffset(false);
01205         if ( rTextureGroups::TextureMode[rTextureGroups::TEX_WALL] != 0 )
01206             glEnable(GL_TEXTURE_2D);
01207     }
01208 
01209     sr_CheckGLError();
01210     BeginQuadStrip();
01211 
01212     //REAL H=h*hfrac;
01213 
01214     //ppos=ePlayer->pos-ePlayer->dir*gCYCLE__LEN;
01215 
01216     for (int i=0;i<=segs;i++){
01217         REAL frag=i/float(segs);
01218         REAL rat=ra+frag*(re-ra);
01219         REAL x=(p1.x+frag*(p2.x-p1.x))*(1-xfunc(rat))+ppos.x*xfunc(rat);
01220         REAL y=(p1.y+frag*(p2.y-p1.y))*(1-xfunc(rat))+ppos.y*xfunc(rat);
01221 
01222         // bottom
01223         glColor4f(r+cfunc(rat),g+cfunc(rat),b+cfunc(rat),a*afunc(rat));
01224         glTexCoord2f(ta+(te-ta)*frag,hfrac);
01225         glVertex3f(x,y,0);
01226 
01227         // top
01228 
01229         //glTexCoord2f(ta+(te-ta)*frag,hfrac*(1-hfunc(rat)));
01230         glTexCoord2f(ta+(te-ta)*frag,0);
01231         REAL H=h*hfrac*hfunc(rat);
01232         glVertex3f(x+H*cycle_->skew*sfunc(rat)*cycle_->dir.y,
01233                    y-H*cycle_->skew*sfunc(rat)*cycle_->dir.x,
01234                    H);
01235     }
01236     RenderEnd();
01237     sr_CheckGLError();
01238 }
01239 #endif
01240 
01241 void gNetPlayerWall::SetEndTime(REAL t){
01242     CHECKWALL;
01243 
01244     REAL BegTime = coords_( coords_.Len() -2 ).Time;
01245     if ( t < BegTime )
01246     {
01247         t = BegTime;
01248     }
01249 
01250     coords_(coords_.Len()-1).Time = t;
01251 
01252     CHECKWALL;
01253 
01254 }
01255 
01256 void gNetPlayerWall::SetEndPos(REAL ep){
01257     CHECKWALL;
01258 
01259     REAL BegPos = coords_( coords_.Len() -2 ).Pos;
01260     if ( ep < BegPos )
01261     {
01262         ep = BegPos;
01263     }
01264 
01265     coords_(coords_.Len()-1).Pos = ep;
01266 
01267     CHECKWALL;
01268 }
01269 
01270 REAL gPlayerWall::BlockHeight() const{
01271     if (bool(cycle_) && cycle_->Alive()==1)
01272         return 1;
01273     else
01274         return 0;
01275 }
01276 
01277 REAL gPlayerWall::SeeHeight() const{
01278     return BlockHeight();
01279 }
01280 
01281 
01282 gCycle *gPlayerWall::Cycle() const {return cycle_;}
01283 gCycleMovement *gPlayerWall::CycleMovement() const {return cycle_;}
01284 gNetPlayerWall *gPlayerWall::NetWall() const {return netWall_;}
01285 
01286 void gPlayerWall::Insert()
01287 {
01288     CHECKWALL;
01289 
01290     eWall::Insert();
01291 }
01292 
01293 void gPlayerWall::Check() const
01294 {
01295     netWall_->Check();
01296 #ifdef DEBUG
01297     REAL range = 5 * fabs(begDist_) + fabs(endDist_) * EPS;
01298     tASSERT( begDist_ <= endDist_ + range );
01299     tASSERT( begDist_ >= netWall_->Pos( 0 ) - range );
01300     tASSERT( endDist_ <= netWall_->Pos( 1 ) + range );
01301 #endif
01302 }
01303 
01304 REAL gPlayerWall::LocalToGlobal( REAL a ) const
01305 {
01306     CHECKWALL;
01307 
01308     tASSERT( good( a ) );
01309 
01310     REAL dist = begDist_ + a * ( endDist_ - begDist_ );
01311     REAL ret = netWall_->Alpha( dist );
01312 
01313     tASSERT( good( ret ) );
01314 
01315     return ret;
01316 }
01317 
01318 void gNetPlayerWall::ClearDisplayList( int inhibitThis, int inhibitCycle )
01319 {
01320 #ifndef DEDICATED
01321     if ( CanHaveDisplayList() && cycle_ && inhibitCycle >= 0 )
01322     {
01323         cycle_->displayList_.Clear( inhibitCycle );
01324     }
01325     displayList_.Clear( inhibitThis );
01326 #endif
01327 }
01328 
01329 REAL gPlayerWall::GlobalToLocal( REAL a ) const
01330 {
01331     CHECKWALL;
01332 
01333     tASSERT( good( a ) );
01334 
01335     REAL dist = netWall_->Pos( a );
01336 
01337     REAL div = ( endDist_ - begDist_ );
01338     if ( div == 0 )
01339     {
01340         return .5f;
01341     }
01342     else
01343     {
01344         REAL ret = ( dist - begDist_ ) / div;
01345 
01346         tASSERT( good( ret ) );
01347 
01348         return ret;
01349     }
01350 }
01351 
01352 REAL gPlayerWall::Time(REAL a) const
01353 {
01354     tASSERT( good( a ) );
01355 
01356     return netWall_->Time( LocalToGlobal( a ) );
01357 }
01358 
01359 REAL gPlayerWall::Pos(REAL a) const
01360 {
01361     CHECKWALL;
01362 
01363     tASSERT( good( a ) );
01364 
01365     return begDist_ + ( endDist_ - begDist_ ) * a;
01366 }
01367 
01368 REAL gPlayerWall::Alpha(REAL pos) const
01369 {
01370     CHECKWALL;
01371 
01372     REAL diff = ( endDist_  - begDist_ );
01373     REAL a = pos - begDist_;
01374 
01375     if ( diff > 0 )
01376         a /= diff;
01377 
01378     tASSERT ( -.001 < a );
01379     tASSERT ( 1.001 > a );
01380 
01381     return a;
01382 }
01383 
01384 bool gPlayerWall::IsDangerousAnywhere( REAL time ) const
01385 {
01386     CHECKWALL;
01387 
01388     return netWall_->IsDangerousAnywhere( time );
01389 }
01390 
01391 bool gPlayerWall::IsDangerous( REAL a, REAL time ) const
01392 {
01393     CHECKWALL;
01394 
01395     return netWall_->IsDangerous( LocalToGlobal( a ), time );
01396 }
01397 
01398 // returns the guy who holed here
01399 gExplosion * gPlayerWall::Holer( REAL a, REAL time ) const
01400 {
01401     CHECKWALL;
01402 
01403     return netWall_->Holer( LocalToGlobal( a ), time );
01404 }
01405 
01406 REAL gPlayerWall::EndPos() const
01407 {
01408     CHECKWALL;
01409 
01410     return this->endDist_;
01411 }
01412 
01413 REAL gPlayerWall::BegPos() const
01414 {
01415     CHECKWALL;
01416 
01417     return this->begDist_;
01418 }
01419 
01420 REAL gPlayerWall::EndTime() const
01421 {
01422     CHECKWALL;
01423 
01424     return netWall_->Time( netWall_->Alpha( this->endDist_ ) );
01425 }
01426 
01427 REAL gPlayerWall::BegTime() const
01428 {
01429     CHECKWALL;
01430 
01431     return netWall_->Time( netWall_->Alpha( this->begDist_ ) );
01432 }
01433 
01434 void gPlayerWall::BlowHole      ( REAL beg, REAL end, gExplosion * holer )
01435 {
01436     CHECKWALL;
01437 
01438     this->netWall_->BlowHole( beg, end, holer );
01439 }
01440 
01441 /*
01442 void gPlayerWall::Clamp (  )
01443 {
01444         tASSERT( coords.Len() >= 2 );
01445 
01446         // clamp beginning
01447         int begin = IndexAlpha(0.0f);
01448         gPlayerWallCoord* bcoord = &coords[begin];
01449         S_Mix( bcoord, 0.0f, bcoord[0] );
01450 
01451         // clamp end
01452         int end = IndexAlpha(1.0f);
01453         gPlayerWallCoord* ecoord = &coords[end];
01454         S_Mix( ecoord, 1.0f, ecoord[1] );
01455 
01456         // useful coordinates now lie between begin and end+1
01457 
01458         // throw away junk at the beginning
01459         if ( begin > 0 )
01460         {
01461                 for ( int i = 0; i <= end + 1 - begin; ++i )
01462                         coords[i] = coords[ i + begin ];
01463         }
01464 
01465         // throw away junk at the end
01466         coords.SetLen( end - begin + 2 );
01467 }
01468 */
01469 
01470 // ************************************************
01471 // ************************************************
01472 
01473 
01474 tList<gNetPlayerWall> sg_netPlayerWalls;
01475 tList<gNetPlayerWall> sg_netPlayerWallsGridded;
01476 
01477 
01478 void gNetPlayerWall::CreateEdge()
01479 {
01480     if ( this->edge_ )
01481         return;
01482 
01483     if (this->cycle_)
01484     {
01485         gPlayerWall* w = tNEW(gPlayerWall)(this,
01486                                            this->cycle_);
01487 
01488         this->edge_=tNEW(eTempEdge)(beg,
01489                                     end,
01490                                     w );
01491     }
01492     else
01493     {
01494         this->edge_ = NULL;
01495         return;
01496     }
01497 }
01498 
01499 void gNetPlayerWall::InitAfterCreation()
01500 {
01501     nNetObject::InitAfterCreation();
01502     MyInitAfterCreation();
01503 }
01504 
01505 void gNetPlayerWall::InitArray()
01506 {
01507     REAL ep = dbegin+sqrt((beg-end).NormSquared());
01508     REAL sp = dbegin;
01509 
01510     if ( ep < sp )
01511     {
01512         ep = sp;
01513     }
01514 
01515     if ( tEnd < tBeg )
01516     {
01517         tEnd = tBeg;
01518     }
01519 
01520     coords_.SetLen(2);
01521     coords_[0].Pos              = sp;
01522     coords_[0].Time             = tBeg;
01523     coords_[0].IsDangerous   = true;
01524     coords_[1].Pos              = ep;
01525     coords_[1].Time             = tEnd;
01526     coords_[1].IsDangerous   = true;
01527 }
01528 
01529 void gNetPlayerWall::MyInitAfterCreation()
01530 {
01531 #ifndef DEDICATED
01532     // put yourself into rendering list
01533     if ( cycle_ )
01534     {
01535         Insert( cycle_->displayList_.wallList_ );
01536     }
01537 #endif
01538 
01539     //w=
01540 #ifdef DEBUG
01541     if (!finite(end.x) || !finite(end.y))
01542         st_Breakpoint();
01543 
01544     if (!finite(beg.x) || !finite(beg.y))
01545         st_Breakpoint();
01546 #endif
01547 
01548     if ( coords_.Len() < 2 )
01549     {
01550         InitArray();
01551     }
01552 
01553     CreateEdge();
01554 
01555     id=-1;
01556     griddedid=-1;
01557     sg_netPlayerWalls.Add(this,id);
01558 
01559     if ( !Wall() )
01560         return;
01561     tASSERT( Wall()->Splittable() );
01562 
01563     for (int i=MAX_VIEWERS-1;i>=0;i--)
01564         Wall()->SetVisHeight(i,0);
01565 
01566     Wall()->Remove();
01567 
01568     displayList_.Clear(2);
01569 }
01570 
01571 
01572 
01573 gNetPlayerWall::gNetPlayerWall(gCycle *cyc,
01574                                const eCoord &begi,const eCoord &d,
01575                                REAL tBegi, REAL dbeg)
01576         :nNetObject(cyc->Owner()),
01577         id(-1),griddedid(-1),
01578         cycle_(cyc),lastWall_(NULL),dir(d),dbegin(dbeg),
01579         beg(begi),end(begi),tBeg(tBegi),tEnd(tBegi),
01580         inGrid(false){
01581     dir=dir; // Don't normalize: *REAL(1/sqrt(dir.NormSquared()));
01582     preliminary=(sn_GetNetState()==nCLIENT);
01583     obsoleted_=-100;
01584     gridding=1E+20;
01585     MyInitAfterCreation();
01586 }
01587 
01588 /*
01589 void gNetPlayerWall::Update(REAL Tend,REAL dend){
01590         if (!inGrid){
01591                 tEnd=Tend;
01592                 end=beg + dir*(dend-dbegin);
01593 
01594 #ifdef DEBUG
01595                 if (!finite(end.x) || !finite(end.y))
01596                         st_Breakpoint();
01597 #endif
01598 
01599                 if (e)
01600                         e->Coord(1) = end;
01601 
01602                 gPlayerWall *w = Wall();
01603                 if (w){
01604                         w->SetEndTime(tEnd);
01605                         w->SetEndPos(dend);
01606                         w->CalcLen();
01607                 }
01608         }
01609 }
01610 */
01611 
01612 void gNetPlayerWall::Update(REAL Tend,const eCoord &pend)
01613 {
01614     CHECKWALL;
01615 
01616     if (!inGrid && ( preliminary || sn_GetNetState() != nCLIENT ) )
01617     {
01618         real_Update( Tend, pend, false );
01619     }
01620 
01621     CHECKWALL;
01622 }
01623 
01624 void gNetPlayerWall::real_Update(REAL Tend,const eCoord &pend, bool force )
01625 {
01626     // duplicate last coords entry if its dangerousness disagrees with the previous entry.
01627     if ( coords_.Len() >= 2 && coords_[ coords_.Len()-2 ].IsDangerous != coords_[ coords_.Len()-1 ].IsDangerous )
01628     {
01629         Checkpoint();
01630     }
01631 
01632     tEnd=Tend;
01633     end=pend;
01634 
01635     // make sure the wall points forward
01636     REAL forward = eCoord::F( end-beg, dir )/dir.NormSquared();
01637     if ( forward < 0 )
01638     {
01639         end = beg;
01640         tEnd = tBeg;
01641     }
01642 
01643 #ifdef DEBUG
01644     if (!finite(end.x) || !finite(end.y))
01645         st_Breakpoint();
01646 #endif
01647 
01648     eCoord odir=dir.Turn(0,1);
01649     REAL x=eCoord::F(odir,(end-beg))/dir.NormSquared();
01650     beg=beg+odir*x;
01651 
01652     if (bool( this->edge_ ) && this->edge_->Point(0) && this->edge_->Point(1)){
01653         this->edge_->Coord(1) = end;
01654         if ( !lastWall_ )
01655             this->edge_->Coord(0) = beg;
01656     }
01657 
01658     // determine the correct end position
01659     REAL endPos = 0;
01660     //if ( bool( this->cycle_ ) && !force )
01661     //{
01662     //    endPos =  this->cycle_->GetDistance();
01663     //}
01664     //else
01665     {
01666         endPos = dbegin + eCoord::F(dir, end - beg )/dir.NormSquared();
01667     }
01668 
01669     // delete coords_ entries that lie after the last one according to their distance; they're invalidated.
01670     {
01671         int len = coords_.Len();
01672         while ( len >= 3 && coords_[len-2].IsDangerous == coords_[len-1].IsDangerous && coords_[len-2].Pos > endPos )
01673         {
01674             coords_[len-2] = coords_[len-1];
01675             coords_.SetLen(len - 1);
01676             len = coords_.Len();
01677         }
01678     }
01679 
01680     // set end position and time
01681     SetEndTime(tEnd);
01682     SetEndPos(endPos);
01683 
01684 
01685     gPlayerWall *w = Wall();
01686 
01687     if ( w )
01688     {
01689         w->CalcLen();
01690         if ( !lastWall_ )
01691             w->begDist_ = dbegin;
01692         w->endDist_ = EndPos();
01693 #ifdef DEBUG
01694         w->Check();
01695 #endif
01696     }
01697 }
01698 
01699 void gNetPlayerWall::Checkpoint()
01700 {
01701     CHECKWALL;
01702 
01703     // copy the last coordinate entry
01704     int len = coords_.Len();
01705 
01706     // temporary is required to compensate for growing array nightmare
01707     coords_[len] = gPlayerWallCoord( coords_[len-1] );
01708 
01709     CHECKWALL;
01710 }
01711 
01712 void gNetPlayerWall::CopyIntoGrid(eGrid * grid, bool force){
01713     tJUST_CONTROLLED_PTR< gNetPlayerWall > keep( this );
01714 
01715     if (!inGrid && (force ||
01716                     (sn_GetNetState()!=nCLIENT || preliminary))){
01717         inGrid=true;
01718         gridding=REAL(se_GameTime()+1.0);
01719         if (sn_GetNetState()==nCLIENT)
01720         {
01721             // leave the wall lingering around for some time on the client
01722             gridding=se_GameTime()+40*sn_Connections[0].ping+10;
01723 
01724             // unless it is already obsoleted by a final wall or IS a final wall. Delete/grid it immediately then.
01725             if ( obsoleted_ > tEnd - .003f || !preliminary )
01726             {
01727                 if ( grid )
01728                     real_CopyIntoGrid( grid );
01729                 else
01730                     gridding=REAL(se_GameTime()+.000001);
01731             }
01732         }
01733         else
01734         {
01735             // copy it into the grid at the next opportunity for server/standalone mode
01736             RequestSync();
01737             if ( grid )
01738                 real_CopyIntoGrid( grid );
01739             else
01740                 gridding=REAL(se_GameTime()+.000001);
01741         }
01742     }
01743 }
01744 
01745 void gNetPlayerWall::real_CopyIntoGrid(eGrid *grid){
01746     //  con << "Gridding " << ID() << " : ";
01747     //con << "from " << *e->Point(0) << " to " << *e->Point(1) << '\n';
01748 
01749     tJUST_CONTROLLED_PTR< gNetPlayerWall > keep( this );
01750 
01751 #ifdef DEBUG
01752     grid->Check();
01753 #endif
01754 
01755     if (griddedid<0){
01756         if ( this->cycle_ )
01757         {
01758             tASSERT( static_cast< bool >(this->edge_) );
01759             tASSERT(Wall());
01760             tASSERT(Wall()->Splittable());
01761 
01762             if (preliminary){
01763                 //delete this; // get rid of it
01764                 tControlledPTR< nNetObject > bounce( this );
01765 
01766                 sg_netPlayerWalls.Remove(this,id);
01767                 sg_netPlayerWallsGridded.Add(this,griddedid);
01768                 Wall()->Insert();
01769                 this->ReleaseData();
01770                 ClearDisplayList();
01771             }
01772             else{
01773                 sg_netPlayerWallsGridded.Add(this,griddedid);
01774                 sg_netPlayerWalls.Remove(this,id);
01775                 if ( this->edge_ ){
01776                     Wall()->Insert();
01777                     this->edge_->CopyIntoGrid(this->cycle_->Grid());
01778                     this->edge_ = NULL;
01779                 }
01780             }
01781         }
01782     }
01783 
01784 #ifdef DEBUG
01785     grid->Check();
01786 #endif
01787 
01788 }
01789 
01790 void gNetPlayerWall::PartialCopyIntoGrid(eGrid *grid){
01791     //  con << "Gridding " << ID() << " : ";
01792     //con << "from " << *e->Point(0) << " to " << *e->Point(1) << '\n';
01793 
01794     tJUST_CONTROLLED_PTR< gNetPlayerWall > keep( this );
01795 
01796 #ifdef DEBUG
01797     grid->Check();
01798 #endif
01799 
01800     if (griddedid<0 && bool(this->cycle_) && !preliminary ){
01801 
01802         // just copy the current edge into the grid
01803         if ( this->edge_ ){
01804             lastWall_ = Wall();
01805             Wall()->Insert();
01806             this->edge_->CopyIntoGrid(grid);
01807             this->edge_ = NULL;
01808         }
01809 
01810         // and create a new one just at the end bit
01811         gPlayerWall* w = tNEW(gPlayerWall)(this,
01812                                            this->cycle_);
01813         this->edge_=tNEW(eTempEdge)(end,
01814                                     end,
01815                                     w );
01816 
01817         // insert it into the list of not yet gridded walls
01818         w->Remove();
01819 
01820         // hack the beginning distance to be the same as the starting distance
01821         w->begDist_ = w->endDist_;
01822     }
01823 
01824     // add a new segment as a copy of the current one
01825     // int newCoord = coords_.Len();
01826     // coords_[newCoord]=coords_[newCoord-1];
01827 
01828 #ifdef DEBUG
01829     grid->Check();
01830 #endif
01831 
01832 }
01833 
01834 void gNetPlayerWall::s_CopyIntoGrid()
01835 {
01836 #ifdef DEBUG
01837     static int maxw=20;
01838     if (sg_netPlayerWalls.Len()>maxw)
01839         con << "Many walls: " << (maxw=sg_netPlayerWalls.Len()) << '\n';
01840 #endif
01841 
01842     for (int i=sg_netPlayerWalls.Len()-1;i>=0;i--){
01843         gNetPlayerWall *w=sg_netPlayerWalls(i);
01844         if (w->inGrid && w->griddedid<0 && se_GameTime()>w->gridding)
01845             w->real_CopyIntoGrid(w->cycle_->Grid());
01846     }
01847 }
01848 
01849 void gNetPlayerWall::RealWallReceived( gNetPlayerWall* realWall )
01850 {
01851     if (this->cycle_ )
01852     {
01853         tASSERT( realWall );
01854         tASSERT( preliminary && !realWall->preliminary );
01855 
01856         // accelerate gridding if the real wall is newer than this
01857         if ( tBeg + tEnd < 2 * realWall->tEnd )
01858         {
01859             REAL maxGridding=se_GameTime() + 2*sn_Connections[0].ping;
01860             if ( gridding > maxGridding )
01861                 gridding = maxGridding;
01862         }
01863 
01864         // calculate the overlap between the real wall and this wall
01865         REAL overlap = 0;
01866         {
01867             REAL tEndThis = tEnd;
01868             // cut from the end if we're in prediction mode and this is an enemy wall
01869             if ( sr_predictObjects && this->cycle_->currentWall == this && Owner() != sn_myNetID )
01870             {
01871                 tEndThis -= this->cycle_->Lag();
01872             }
01873 
01874             REAL tBegMin = tBeg;
01875             REAL tBegMax = realWall->tBeg;
01876             if ( tBegMin > tBegMax )
01877             {
01878                 tBegMin = realWall->tBeg;
01879                 tBegMax = tBeg;
01880             }
01881 
01882             REAL tEndMin = tEndThis;
01883 
01884             REAL tEndMax = realWall->tEnd;
01885             if ( tEndMin > tEndMax )
01886             {
01887                 tEndMin = realWall->tEnd;
01888                 tEndMax = tEndThis;
01889             }
01890 
01891             REAL denominator = tEndMax - tBegMin;
01892             if ( denominator > 0 )
01893                 overlap = ( tEndMin - tBegMax ) / denominator;
01894         }
01895 
01896         // no overlap if directions don't match
01897         if ( overlap > 0 && fabs( dir * realWall->dir ) > 10 * EPS )
01898             overlap = 0;
01899 
01900         // no good overlap? Go home.
01901         if ( overlap < .8 )
01902             return;
01903 
01904         // mark current walls as to be deleted immediately after the cycle does no longer need it
01905         obsoleted_ = realWall->tEnd;
01906 
01907         // copy non-current walls into the grid immediately
01908         if (this->cycle_->currentWall!=this )
01909         {
01910             // replace pointer in cycle
01911             if (this->cycle_->lastWall==this)
01912             {
01913                 this->cycle_->lastWall=realWall;
01914 
01915                 /*
01916                 // close seams (does not help, deactivated)
01917                 if ( this->cycle_->currentWall && this->cycle_->currentWall->preliminary )
01918                 {
01919                     this->cycle_->currentWall->tBeg   = realWall->tEnd;
01920                     this->cycle_->currentWall->coords_[0].Time   = realWall->tEnd;
01921                     this->cycle_->currentWall->dbegin = realWall->EndPos();
01922                 }
01923                 */
01924             }
01925 
01926             // delete this wall, it is no longer needed
01927             this->real_CopyIntoGrid( this->cycle_->Grid() );
01928         }
01929     }
01930 }
01931 
01932 
01933 void gNetPlayerWall::WriteCreate(nMessage &m)
01934 {
01935     tASSERT( this->cycle_ );
01936 
01937     nNetObject::WriteCreate(m);
01938     m.Write(this->cycle_->ID());
01939     m << beg;
01940     m << dir;
01941     m << dbegin;
01942     m << tBeg;
01943     m << static_cast<int>(preliminary);
01944 }
01945 
01946 gNetPlayerWall::gNetPlayerWall(nMessage &m)
01947         :nNetObject(m),
01948         id(-1),griddedid(-1),
01949         cycle_(NULL),edge_(NULL), lastWall_(NULL),
01950         dir(0,0),dbegin(0),
01951         beg(0,0),end(0,0),
01952         tBeg(0),tEnd(0),
01953         inGrid(0)
01954 {
01955     unsigned short cid;
01956     gridding=1E+20;
01957     m.Read(cid);
01958     cycle_=static_cast<gCycle *>(Object(cid));
01959 
01960     m >> beg;
01961     end=beg;
01962     m >> dir;
01963     m >> dbegin;
01964 
01965     m >> tBeg;
01966     {
01967         int preliminary;
01968         m >> preliminary;
01969         this->preliminary = preliminary;
01970     }
01971 
01972     obsoleted_=-100;
01973 
01974     this->InitArray();
01975 }
01976 
01977 eCoord gNetPlayerWall::Vec()
01978 {
01979     if ( edge_ ) return edge_->Vec();
01980     else return eCoord();
01981 }
01982 
01983 gPlayerWall *gNetPlayerWall::Wall(){
01984     if (this->edge_)
01985     {
01986         eWall *w = this->edge_->Wall();
01987 
01988         return reinterpret_cast<gPlayerWall *>(w);
01989     }
01990     else
01991         return NULL;
01992 }
01993 
01994 void gNetPlayerWall::ReleaseData()
01995 {
01996     if (this->cycle_){
01997         if (this->cycle_->currentWall==this)
01998             this->cycle_->currentWall=NULL;
01999         if (this->cycle_->lastWall==this)
02000             this->cycle_->lastWall=NULL;
02001         if (this->cycle_->lastNetWall==this)
02002             this->cycle_->lastNetWall=NULL;
02003     }
02004 
02005     // tDESTROY(w);
02006 
02007     if (this->edge_)
02008     {
02009         if ( this->edge_->Wall() )
02010             this->edge_->Wall()->Insert();
02011 
02012         this->edge_ = NULL;  // w will be deleted with e
02013         //    tDESTROY_PTR(p1);
02014         //    tDESTROY_PTR(p2);
02015     }
02016 
02017     this->cycle_=NULL;
02018     this->edge_=NULL;
02019     //w=NULL;
02020 
02021     sg_netPlayerWalls.Remove(this,id);
02022     sg_netPlayerWallsGridded.Remove(this,griddedid);
02023 }
02024 
02025 gNetPlayerWall::~gNetPlayerWall()
02026 {
02027     ReleaseData();
02028     ClearDisplayList();
02029 }
02030 
02031 bool gNetPlayerWall::ActionOnQuit()
02032 {
02033     if ( sn_GetNetState() == nSERVER )
02034     {
02035         TakeOwnership();
02036         return false;
02037     }
02038     else
02039     {
02040         ReleaseData();
02041 
02042         return true;
02043     }
02044 }
02045 
02046 bool gNetPlayerWall::ClearToTransmit(int user) const{
02047 #ifdef DEBUG
02048     if (nNetObject::DoDebugPrint() && bool( this->cycle_ ) )
02049     {
02050         if (!GridIsReady(user))
02051             con << "Not transfering gNetPlayerWall " << ID()
02052             << " for user " << user << " because the grid is not ready yet.\n";
02053         else if (!this->cycle_)
02054             con << "Not transfering gNetPlayerWall " << ID()
02055             << " for user " << user << " because it has no cycle!\n";
02056         else if (!this->cycle_->HasBeenTransmitted(user))
02057         {
02058             tString s;
02059             s << "No transfering gNetPlayerWall " << ID()
02060             << " for user " << user << " because ";
02061             this->cycle_->PrintName(s);
02062             s << " has not been transmitted.\n";
02063             con << s;
02064         }
02065     }
02066 #endif
02067 
02068     return GridIsReady(user) && nNetObject::ClearToTransmit(user)
02069            && bool(this->cycle_) && this->cycle_->HasBeenTransmitted(user) && inGrid;
02070 }
02071 
02072 void gNetPlayerWall::WriteSync(nMessage &m){
02073     nNetObject::WriteSync(m);
02074 
02075     if (inGrid){
02076         m << end; // the far end of the eWall
02077         m << tEnd; // the endTime
02078     }
02079     else{
02080         m << beg;
02081         m << tBeg;
02082     }
02083     m.Write(inGrid);
02084 
02085     if ( coords_.Len() > 2 || !coords_(0).IsDangerous || !coords_(1).IsDangerous )
02086     {
02087         unsigned short len = coords_.Len();
02088         m.Write( len );
02089         for ( int i = len-1; i>=0; --i )
02090         {
02091             const gPlayerWallCoord& coord = coords_(i);
02092             m << coord.IsDangerous;
02093             m << coord.Pos;
02094             m << coord.Time;
02095         }
02096     }
02097 }
02098 
02099 bool gNetPlayerWall::SyncIsNew(nMessage &m)
02100 {
02101     //  return (nNetObject::SyncIsNew(m) && !inGrid);
02102     return nNetObject::SyncIsNew(m);
02103 }
02104 
02105 static bool sg_ServerSentHoles = false;
02106 
02107 void gNetPlayerWall::ReadSync(nMessage &m){
02108     nNetObject::ReadSync(m);
02109 
02110     ClearDisplayList();
02111 
02112     REAL tEnd_new;
02113     eCoord end_new;
02114 
02115     m >> end_new;
02116     m >> tEnd_new;
02117 
02118     if ( tEnd_new < tBeg )
02119     {
02120         tEnd_new = tBeg;
02121     }
02122 
02123     unsigned short new_inGrid;
02124     m.Read(new_inGrid);
02125 
02126     if ( griddedid < 0 )
02127         CreateEdge();
02128 
02129     if ( ! m.End() )
02130     {
02131         unsigned short len;
02132         m.Read( len );
02133 
02134         coords_.SetLen( len );
02135 
02136         for ( int i = len-1; i>=0; --i )
02137         {
02138             gPlayerWallCoord& coord = coords_(i);
02139             m >> coord.IsDangerous;
02140             m >> coord.Pos;
02141             m >> coord.Time;
02142         }
02143 
02144         sg_ServerSentHoles = true;
02145     }
02146 
02147     real_Update(tEnd_new,end_new, true);
02148 
02149     if (Wall() && new_inGrid && !inGrid)
02150     {
02151         /*
02152                         if ( ( beg - end ).NormSquared() > 0.01f )
02153                         {
02154                                 gExplosion::OnNewWall( Wall() );
02155                         }
02156         */
02157 
02158         CopyIntoGrid( NULL, true );
02159 
02160         if (!preliminary)
02161         {
02162             // inform preliminary walls
02163             for (int i=sg_netPlayerWalls.Len()-1;i>=0;i--)
02164             {
02165                 gNetPlayerWall *o=sg_netPlayerWalls[i];
02166                 if ( o != this && o->preliminary && o->cycle_ == this->cycle_ )
02167                 {
02168                     o->RealWallReceived( this );
02169                 }
02170             }
02171 
02172             // test whether this wall is newer than the last received wall in the cycle
02173             if ( ( 0 != this->cycle_ ) && ( !this->cycle_->lastNetWall || this->cycle_->lastNetWall->tBeg < this->tBeg ) )
02174             {
02175                 this->cycle_->lastNetWall = this;
02176             }
02177         }
02178     }
02179     else
02180     {
02181         //              st_Breakpoint();
02182     }
02183 
02184 #ifdef DEBUG
02185     if ( Wall() )
02186         Wall()->Check();
02187 #endif
02188 }
02189 
02190 static nNOInitialisator<gNetPlayerWall> gNetPlayerWall_init(300,"gNetPlayerWall");
02191 
02192 nDescriptor &gNetPlayerWall::CreatorDescriptor() const
02193 {
02194     return gNetPlayerWall_init;
02195 }
02196 
02197 void gNetPlayerWall::PrintName(tString &s) const
02198 {
02199     s << "gNetPlayerWall nr. " << id;
02200     if ( this->cycle_ )
02201     {
02202         s       << " owned by ";
02203         this->cycle_->PrintName( s );
02204     }
02205 }
02206 
02207 gCycleMovement *gNetPlayerWall::CycleMovement() const {
02208     return cycle_;
02209 }
02210 
02211 void gNetPlayerWall::Clear()
02212 {
02213     //  if( nCLIENT == sn_GetNetState() )
02214     //  return;
02215 
02216     int i;
02217     for (i=sg_netPlayerWalls.Len()-1;i>=0;i--){
02218         // sg_netPlayerWalls(i)->owner=sn_myNetID;
02219         //delete sg_netPlayerWalls(i);
02220         gNetPlayerWall* w = sg_netPlayerWalls(i);
02221         tControlledPTR< nNetObject > bounce( w );
02222         w->ReleaseData();
02223 
02224         sg_netPlayerWalls.Remove( w, w->id );
02225 
02226         if ( w->edge_ )
02227             w->edge_->Wall()->Insert();
02228 
02229     }
02230     for (i=sg_netPlayerWallsGridded.Len()-1;i>=0;i--){
02231         // sg_netPlayerWallsGridded(i)->owner=sn_myNetID;
02232         gNetPlayerWall* w = sg_netPlayerWallsGridded(i);
02233         tControlledPTR< nNetObject > bounce( w );
02234         w->ReleaseData();
02235 
02236         sg_netPlayerWallsGridded.Remove( w, w->griddedid );
02237     }
02238 }
02239 
02240 
02241 void gNetPlayerWall::Check() const
02242 {
02243 #ifdef DEBUG
02244     int i;
02245     for ( i = coords_.Len() -2 ; i>=0; --i )
02246     {
02247         gPlayerWallCoord* coords = &( coords_( i ) );
02248         tASSERT( coords[0].Pos <= coords[1].Pos );
02249         tASSERT( coords[0].Time <= coords[1].Time );
02250     }
02251 
02252     for ( i = coords_.Len() -1 ; i>=0; --i )
02253     {
02254         gPlayerWallCoord* coords = &( coords_( i ) );
02255         tASSERT( finite( coords[0].Pos ) );
02256         tASSERT( finite( coords[0].Time ) );
02257     }
02258 #endif
02259 }
02260 
02261 int gNetPlayerWall::IndexPos(REAL d) const
02262 {
02263     CHECKWALL;
02264 
02265 
02266     // get the first coord with smaller alpha than a
02267     int i = coords_.Len() - 2;
02268     while ( i >= 1 && coords_(i).Pos >= d)
02269         --i;
02270 
02271 #ifdef DEBUG
02272     if (!( i >= 0 && i < coords_.Len() - 1 ))
02273     {
02274         st_Breakpoint();
02275     }
02276 #endif
02277 
02278     return i;
02279 }
02280 
02281 int gNetPlayerWall::IndexAlpha(REAL a) const
02282 {
02283     CHECKWALL;
02284 
02285     REAL d = Pos( a );
02286 
02287     return IndexPos( d );
02288 }
02289 
02290 REAL gNetPlayerWall::Time(REAL a) const
02291 {
02292     tASSERT( good( a ) );
02293 
02294     CHECKWALL;
02295 
02296     const gPlayerWallCoord* coord = &coords_(IndexAlpha(a));
02297     REAL div = ( coord[1].Pos - coord[0].Pos );
02298     REAL alpha = 0.0f;
02299     if ( div > 0 )
02300     {
02301         alpha = ( Pos(a) - coord[0].Pos ) / div;
02302     }
02303 
02304     REAL ret = coord[0].Time + alpha*(coord[1].Time-coord[0].Time);
02305 
02306     tASSERT( good( ret ) );
02307 
02308     return ret;
02309 }
02310 
02311 REAL gNetPlayerWall::Pos(REAL a) const
02312 {
02313     CHECKWALL;
02314 
02315     tASSERT( good( a ) );
02316 
02317     REAL ret = BegPos() + a * ( EndPos()  - BegPos() );
02318 
02319     tASSERT( good( ret ) );
02320 
02321     return ret;
02322 }
02323 
02324 REAL gNetPlayerWall::Alpha(REAL pos) const
02325 {
02326     CHECKWALL;
02327 
02328     REAL diff = ( EndPos()  - BegPos() );
02329     REAL a = pos - BegPos();
02330 
02331     if ( diff > 0 )
02332         a /= diff;
02333 
02334     tASSERT ( -.001 < a );
02335     tASSERT ( 1.001 > a );
02336 
02337     return a;
02338 }
02339 
02340 bool gNetPlayerWall::IsDangerousAnywhere( REAL time ) const
02341 {
02342     CHECKWALL;
02343 
02344     if ( !cycle_ )
02345         return false;
02346 
02347     // is the player dead?
02348     if ( gCycle::WallsStayUpDelay() >= 0 )
02349     {
02350         if ( !cycle_->Alive() && time - cycle_->deathTime > .2f + gCycle::WallsStayUpDelay() )
02351             return false;
02352     }
02353 
02354     // is the wall behind the wall end?
02355     if ( gCycle::WallsLength() > 0 )
02356     {
02357         tASSERT( cycle_->MaxWallsLength() >= cycle_->ThisWallsLength() );
02358         REAL maxDist = cycle_->GetDistance() - cycle_->MaxWallsLength();
02359         if ( maxDist > EndPos()  && maxDist > BegPos() )
02360         {
02361             return false;
02362         }
02363     }
02364 
02365     return true;
02366 }
02367 
02368 bool gNetPlayerWall::IsDangerousApartFromHoles( REAL a, REAL time ) const
02369 {
02370     CHECKWALL;
02371 
02372     // test for disappearing after death
02373     if ( gCycle::WallsStayUpDelay() >= 0.0f )
02374     {
02375         // walls disappeear after death
02376         if (!cycle_ || !cycle_->Alive() && cycle_->deathTime+ gCycle::WallsStayUpDelay()+0.2f<=time)
02377             return false;
02378     }
02379 
02380     // the time from the last simulation to the time the query shall be made;
02381     // cycleDistance is valid at cycle_->lastTime, we need it at time.
02382     REAL dt = ( time - cycle_->lastTime );
02383 
02384     // the distance value at the spot we hit
02385     REAL wallDistance = Pos( a );
02386 
02387     // test for finite wall lenght
02388     if ( gCycle::WallsLength() > 0 )
02389     {
02390         // the distance the cycle traveled so far
02391         REAL cycleDistance = cycle_->GetDistance();
02392 
02393         // extrapolate it, taking rubber slowdown into account
02394         if ( cycle_->Alive() )
02395         {
02396             // cycle movement
02397             cycleDistance += cycle_->WallEndSpeed() * dt;
02398         }
02399 
02400         if ( wallDistance + cycle_->ThisWallsLength() < cycleDistance )
02401             return false;       // hit was after the wall length
02402     }
02403 
02404     // check whether it is an extrapolated bit
02405     {
02406         // the distance the cycle traveled so far
02407         REAL cycleDistance = cycle_->GetDistance();
02408 
02409         // extrapolate it if the test time lies in the cycle's future.
02410         if ( cycle_->Alive() && dt > 0 )
02411         {
02412             // cycle movement
02413             cycleDistance += cycle_->Speed() * cycle_->rubberSpeedFactor * dt;
02414         }
02415 
02416         // is the wall ahead of the cycle?
02417         if ( wallDistance > cycleDistance )
02418             return false;
02419     }
02420 
02421     return true;
02422 }
02423 
02424 bool gNetPlayerWall::IsDangerous( REAL a, REAL time ) const
02425 {
02426     CHECKWALL;
02427 
02428     if ( !IsDangerousApartFromHoles( a, time ) )
02429     {
02430         return false;
02431     }
02432 
02433     const gPlayerWallCoord* coord = &coords_(IndexAlpha(a));
02434     return coord->IsDangerous;
02435 }
02436 
02437 // returns the guy who holed here
02438 gExplosion * gNetPlayerWall::Holer( REAL a, REAL time ) const
02439 {
02440     CHECKWALL;
02441 
02442     // it does not count as a hole if the wall has expired already
02443     // for other reasons
02444     if ( !IsDangerousApartFromHoles( a, time ) )
02445     {
02446         return false;
02447     }
02448 
02449     const gPlayerWallCoord* coord = &coords_(IndexAlpha(a));
02450     return coord->holer;
02451 }
02452 
02453 REAL gNetPlayerWall::EndPos() const
02454 {
02455     CHECKWALL;
02456 
02457     return coords_(coords_.Len()-1).Pos;
02458 }
02459 
02460 REAL gNetPlayerWall::BegPos() const
02461 {
02462     CHECKWALL;
02463 
02464     return coords_(0).Pos;
02465 }
02466 
02467 REAL gNetPlayerWall::EndTime() const
02468 {
02469     CHECKWALL;
02470 
02471     return coords_(coords_.Len()-1).Time;
02472 }
02473 
02474 REAL gNetPlayerWall::BegTime() const
02475 {
02476     CHECKWALL;
02477 
02478     return coords_(0).Time;
02479 }
02480 
02481 void gNetPlayerWall::BlowHole   ( REAL beg, REAL end, gExplosion * holer )
02482 {
02483     CHECKWALL;
02484 
02485 #ifndef DEDICATED
02486     ClearDisplayList(60);
02487 #endif
02488 
02489 #ifdef DEBUG
02490     /*
02491     for ( int i = 0; i < coords_.Len(); ++i )
02492     {
02493         std::cout << "[" << coords_(i).IsDangerous << ',' << coords_(i).Pos << "]";
02494     }
02495 
02496     static int count=0;
02497     ++count;
02498 
02499     std::cout << " hole " << count << " : " << beg << ',' << end << '(' << BegPos() << ',' << EndPos() << ")\n";
02500     */
02501 #endif
02502 
02503     // don't touch anything if the server concluded it is his business
02504     if ( sn_GetNetState() != nSERVER && sg_ServerSentHoles && !preliminary )
02505     {
02506         return;
02507     }
02508 
02509 #ifdef DEBUG
02510     tASSERT (coords_.Len() < 1000 );
02511 #endif
02512 
02513     // find the last index that will stay before the hole:
02514     int begind = IndexPos( beg );
02515 
02516     // skip ahead if the holing would create redunant non-dangerous blocks
02517     while ( begind >= 1 && !coords_[begind].IsDangerous )
02518     {
02519         beg = coords_[begind].Pos;
02520         begind--;
02521     }
02522 
02523     // find the last index in the hole:
02524     int endind = IndexPos( end );
02525 
02526     // skip ahead if the holing would create redunant non-dangerous blocks
02527     while ( endind < coords_.Len() - 2 && !coords_[endind].IsDangerous )
02528     {
02529         endind++;
02530         end = coords_[endind].Pos;
02531     }
02532 
02533     if ( beg < BegPos() )
02534     {
02535         begind = -1;
02536 
02537         beg = BegPos();
02538     }
02539 
02540     if ( end > EndPos() )
02541     {
02542         if ( bool(cycle_) && ( EndPos() < cycle_->GetDistance()-10 || this != cycle_->currentWall ) )
02543             endind = coords_.Len() - 1;
02544 
02545         end = EndPos();
02546     }
02547 
02548     // out of range
02549     if ( end < beg )
02550     {
02551         return;
02552     }
02553 
02554     if ( sn_GetNetState() != nCLIENT )
02555     {
02556         this->RequestSync();
02557     }
02558 
02559     // find the alpha at the hole begin and end:
02560     REAL begalph = Alpha( beg );
02561     REAL endalph = Alpha( end );
02562 
02563     // find the time at the hole begin and end:
02564     REAL begtime = Time( begalph );
02565     REAL endtime = Time( endalph );
02566 
02567     int insert = begind + 2 - endind;
02568 
02569 #ifdef DEBUG
02570     tASSERT (insert < 40 );
02571 #endif
02572 
02573     // remove positions inside the hole:
02574     if ( insert < 0 )
02575     {
02576         for ( int i = begind+1; i - insert < coords_.Len(); ++i )
02577             coords_(i) = coords_( i - insert );
02578         coords_.SetLen( coords_.Len() + insert );
02579     }
02580 
02581     // make room for the new points of the hole:
02582     else if ( insert > 0 )
02583     {
02584         coords_.SetLen( coords_.Len() + insert );
02585 
02586         for ( int i = coords_.Len() - 1; i >= begind + insert && i >= insert ; --i )
02587             coords_( i ) = coords_( i - insert );
02588     }
02589 
02590     // clamp times
02591     {
02592         if ( begind >= 0 )
02593         {
02594             REAL beforetime = coords_(begind).Time;
02595             if ( begtime < beforetime )
02596             {
02597                 begtime = beforetime;
02598             }
02599         }
02600 
02601         if ( begind +3 < coords_.Len() )
02602         {
02603             REAL afttime = coords_(begind + 3).Time;
02604             if ( endtime > afttime )
02605             {
02606                 endtime = afttime;
02607             }
02608         }
02609     }
02610 
02611     // enter the hole
02612     coords_(begind+1).IsDangerous = false;
02613     coords_(begind+1).Time        = begtime;
02614     coords_(begind+1).holer       = holer;
02615     coords_(begind+1).Pos         = beg;
02616     coords_(begind+2).Time        = endtime;
02617     coords_(begind+2).Pos         = end;
02618 
02619 #ifdef DEBUG
02620     /*
02621     for ( int i = 0; i < coords_.Len(); ++i )
02622     {
02623         std::cout << "[" << coords_(i).IsDangerous << ',' << coords_(i).Pos << "]";
02624     }
02625     std::cout << "\n";
02626     */
02627 #endif
02628 
02629     CHECKWALL;
02630 }
02631 
02632 static void login_callback(){
02633     sg_ServerSentHoles = false;
02634 }
02635 
02636 static nCallbackLoginLogout sg_LoginLogout(&login_callback);
02637 
02638 

Generated on Sat Mar 15 22:56:11 2008 for Armagetron Advanced by  doxygen 1.5.4