1 /*
2 
3 *************************************************************************
4 
5 ArmageTron -- Just another Tron Lightcycle Game in 3D.
6 Copyright (C) 2000  Manuel Moos (manuel@moosnet.de)
7 
8 **************************************************************************
9 
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License
12 as published by the Free Software Foundation; either version 2
13 of the License, or (at your option) any later version.
14 
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 GNU General Public License for more details.
19 
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23 
24 ***************************************************************************
25 
26 */
27 
28 
29 #include "rSDL.h"
30 
31 #include "gWall.h"
32 #include "gStuff.h"
33 #include "eGrid.h"
34 #include "eWall.h"
35 #include "math.h"
36 #include "gCycle.h"
37 #include "rTexture.h"
38 #include "eTimer.h"
39 #include "gGame.h"
40 #include "rScreen.h"
41 #include "rRender.h"
42 #include "eCamera.h"
43 #include "tConfiguration.h"
44 #include "gExplosion.h"
45 #include "tMath.h"
46 #include "ePlayer.h"
47 #include "eTess2.h"
48 #include "nConfig.h"
49 
50 #include <fstream>
51 
52 /* **********************************************
53    Wall
54    ********************************************** */
55 
56 #ifndef DEDICATED
57 
58 // setting items to enable the old style semi-transparency of rim walls
59 static bool sg_bugTransparency;
60 static bool sg_bugTransparencyDemand;
61 static tSettingItem< bool > sgc_bugTransparency( "BUG_TRANSPARENCY", sg_bugTransparency );
62 static tSettingItem< bool > sgc_bugTransparencyDemand( "BUG_TRANSPARENCY_DEMAND", sg_bugTransparencyDemand );
63 
64 //texture ArmageTron_invis_eWall("eWall2.png",1,0);
65 /*
66 static tString lala_wallRim("Anonymous/original/textures/rim_wall.png");
67 static nSettingItem<tString> lalala_wallRim("TEXTURE_WALLRIM", lala_wallRim);
68 rFileTexture gWallRim_text(rTextureGroups::TEX_WALL, lala_wallRim, 1,1);
69 
70 static tString lala_mp_wallRimA("Anonymous/original/moviepack/rim_wall_a.png");
71 static nSettingItem<tString> lalala_mp_wallRimA("TEXTURE_MP_WALLRIM_A", lala_mp_wallRimA);
72 rFileTexture gWallRim_a(rTextureGroups::TEX_WALL, lala_mp_wallRimA, 0,0);
73 
74 static tString lala_mp_wallRimB("Anonymous/original/moviepack/rim_wall_b.png");
75 static nSettingItem<tString> lalala_mp_wallRimB("TEXTURE_MP_WALLRIM_B", lala_mp_wallRimB);
76 rFileTexture gWallRim_b(rTextureGroups::TEX_WALL, lala_mp_wallRimB, 0,0);
77 
78 static tString lala_mp_wallRimC("Anonymous/original/moviepack/rim_wall_c.png");
79 static nSettingItem<tString> lalala_mp_wallRimC("TEXTURE_MP_WALLRIM_C", lala_mp_wallRimC);
80 rFileTexture gWallRim_c(rTextureGroups::TEX_WALL, lala_mp_wallRimC, 0,0);
81 
82 static tString lala_mp_wallRimD("Anonymous/original/moviepack/rim_wall_d.png");
83 static nSettingItem<tString> lalala_mp_wallRimD("TEXTURE_MP_WALLRIM_D", lala_mp_wallRimD);
84 rFileTexture gWallRim_d(rTextureGroups::TEX_WALL, lala_mp_wallRimD, 0,0);
85 */
86 
87 //static rTexture gWallRim_text_moviepack(rTEX_WALL,"moviepack/gWallRim2.png",1,0);
88 static rFileTexture gWallRim_a(rTextureGroups::TEX_WALL,"moviepack/rim_wall_a.png",0,0);
89 static rFileTexture gWallRim_b(rTextureGroups::TEX_WALL,"moviepack/rim_wall_b.png",0,0);
90 static rFileTexture gWallRim_c(rTextureGroups::TEX_WALL,"moviepack/rim_wall_c.png",0,0);
91 static rFileTexture gWallRim_d(rTextureGroups::TEX_WALL,"moviepack/rim_wall_d.png",0,0);
92 
93 static rITexture *gWallRim_mp[4]={&gWallRim_a,&gWallRim_b,
94                                   &gWallRim_c,&gWallRim_d};
95 
96 /*
97 static tString lala_dir_eWall("Anonymous/original/textures/dir_wall.png");
98 static nSettingItem<tString> lalala_dir_eWall("TEXTURE_DIR_WALL", lala_dir_eWall);
99 rFileTexture dir_eWall(rTextureGroups::TEX_WALL, lala_dir_eWall, 1,0);
100 
101 static tString lala_mp_dir_eWall("Anonymous/original/moviepack/dir_wall.png");
102 static nSettingItem<tString> lalala_mp_dir_eWall("TEXTURE_MP_DIR_WALL", lala_mp_dir_eWall);
103 rFileTexture dir_eWall_moviepack(rTextureGroups::TEX_WALL, lala_mp_dir_eWall, 1,0);
104 */
105 #endif
106 
107 static REAL sg_RimStretchX=100;
108 static tSettingItem<REAL> sg_RimStretchXConf
109 ("RIM_WALL_STRETCH_X",sg_RimStretchX);
110 static REAL sg_RimStretchY=100;
111 static tSettingItem<REAL> sg_RimStretchYConf
112 ("RIM_WALL_STRETCH_Y",sg_RimStretchY);
113 
114 static REAL sg_MPRimStretchX=50;
115 static tSettingItem<REAL> sg_MPRimStretchXConf
116 ("MOVIEPACK_RIM_WALL_STRETCH_X",sg_MPRimStretchX);
117 static REAL sg_MPRimStretchY=50;
118 static tSettingItem<REAL> sg_MPRimStretchYConf
119 ("MOVIEPACK_RIM_WALL_STRETCH_Y",sg_MPRimStretchY);
120 
121 /* **********************************************
122    RimWall
123    ********************************************** */
124 
gWallRim(eGrid * grid,REAL h)125 gWallRim::gWallRim(eGrid *grid, REAL h)
126         :eWallRim(grid, false, h), renderHeight_(h), lastUpdate_(-100), tBeg_( 0 ), tEnd_( 0 )
127 {
128     // std::cout << "create " << this << "\n";
129 }
130 
gWallRim(eGrid * grid,REAL tBeg,REAL tEnd,REAL h)131 gWallRim::gWallRim(eGrid *grid, REAL tBeg, REAL tEnd, REAL h)
132         :eWallRim(grid, false, h), renderHeight_(h), lastUpdate_(-100), tBeg_( tBeg ), tEnd_( tEnd )
133 {
134     // std::cout << "create " << this << "\n";
135 }
136 
~gWallRim()137 gWallRim::~gWallRim()
138 {
139     // std::cout << "destroy " << this << "\n";
140 }
141 
Splittable() const142 bool gWallRim::Splittable() const{return 1;}
Split(eWall * & w1,eWall * & w2,REAL ratio)143 void gWallRim::Split(eWall *& w1,eWall *& w2,REAL ratio)
144 {
145     // std::cout << "split " << this << "\n";
146 
147     REAL tMid = tEnd_ * ratio + tBeg_ * ( 1 - ratio );
148     w1=tNEW(gWallRim(grid, tBeg_, tMid, height));
149     w2=tNEW(gWallRim(grid, tMid, tEnd_, height));
150 }
151 
152 // do not allow walls to run parallel
RunsParallelPassive(eWall * newWall)153 bool gWallRim::RunsParallelPassive( eWall* newWall )
154 {
155     return false;
156 }
157 
158 // from display.C
159 extern REAL lower_height,upper_height;
160 
161 #ifndef DEDICATED
162 
163 
gWallRim_helper(eCoord p1,eCoord p2,REAL tBeg,REAL tEnd,REAL h,REAL Z_SCALE,bool sw)164 static void gWallRim_helper(eCoord p1,eCoord p2,REAL tBeg,REAL tEnd,REAL h,
165                             REAL Z_SCALE,bool sw){
166 
167     // draw additional upper line
168     /*
169     sr_DepthOffset(true);
170     glPolygonOffset(-100,10000000);
171     glDisable(GL_TEXTURE_2D);
172     BeginLines();
173     Color(1,1,1);
174     Vertex(p1.x,p1.y,1);
175     Vertex(p2.x,p2.y,1);
176     RenderEnd();
177     sr_DepthOffset(false);
178     glDisable(GL_POLYGON_OFFSET_LINE);
179     glEnable(GL_TEXTURE_2D);
180     */
181 
182     if (sg_MoviePack()){
183         int t=int(floor((tBeg+tEnd)/2));
184         tBeg-=t;
185         tEnd-=t;
186         t=t%4;
187         while (t<0)
188             t+=4;
189         gWallRim_mp[t]->Select();
190     }
191 
192     if (sw){
193         Swap(p1,p2);
194         Swap(tBeg,tEnd);
195     }
196 
197 
198     if (h>lower_height){
199         if (sr_upperSky && !sg_MoviePack() && h>upper_height) h=upper_height;
200         else if (sr_lowerSky || sg_MoviePack()) h=lower_height;
201     }
202 
203     BeginQuads();
204 
205     // NOTE: display lists on nvidia cards don't like infinite points
206     if (h<9000 || !sr_infinityPlane || rDisplayList::IsRecording() ){
207         TexVertex(p1.x, p1.y, 0,
208                   tBeg      , 1);
209 
210         TexVertex(p1.x, p1.y, h,
211                   tBeg,       1-h/Z_SCALE);
212 
213         TexVertex(p2.x, p2.y, h,
214                   tEnd,       1-h/Z_SCALE);
215 
216         TexVertex(p2.x, p2.y, 0,
217                   tEnd      , 1);
218     }
219 
220     else{
221         TexVertex(p1.x, p1.y, 0,
222                   tBeg,       1);
223 
224         TexCoord(0,-1/REAL(Z_SCALE),0,0);
225 
226 #ifndef WIN32
227         Vertex(0,0,1,0);
228         Vertex(0,0,1,0);
229 #else
230         Vertex(0.001f,0.001f,1,0); // Windows OpenGL has problems with
231         // infitite points perpenticular to the viewing direction
232         Vertex(0.001f,0.001f,1,0);
233 #endif
234 
235         TexVertex(p2.x, p2.y, 0,
236                   tEnd,       1);
237     }
238 }
239 
240 // maximal size of the arena wall shadow compared to the camera height
241 static REAL sg_arenaWallShadowSize = 0.1;
242 static tSettingItem<REAL> sg_arenaWallShadowSizeConf("ARENA_WALL_SHADOW_SIZE",sg_arenaWallShadowSize);
243 
244 // shadows are drawn when the cycle gets closer to the line the wall follows than this
245 static REAL sg_arenaWallShadowSideDist = 10.0;
246 static tSettingItem<REAL> sg_arenaWallShadowSideDistConf("ARENA_WALL_SHADOW_SIDEDIST",sg_arenaWallShadowSideDist);
247 
248 // getting closer to the wall than this distance does not increase the shadow much
249 static REAL sg_arenaWallShadowNear = 1.0;
250 static tSettingItem<REAL> sg_arenaWallShadowNearConf("ARENA_WALL_SHADOW_NEAR",sg_arenaWallShadowNear);
251 
252 // shadows are drawn when the cycle gets closer to the wall than this
253 static REAL sg_arenaWallShadowDist = 100.0;
254 static tSettingItem<REAL> sg_arenaWallShadowDistConf("ARENA_WALL_SHADOW_DIST",sg_arenaWallShadowDist);
255 
RenderReal(const eCamera * cam)256 void gWallRim::RenderReal(const eCamera *cam){
257     if ( Edge() ){
258         const eCoord *p1=&EndPoint(0);
259         const eCoord *p2=&EndPoint(1);
260 
261         REAL X_SCALE=sg_RimStretchX;
262         REAL Z_SCALE=sg_RimStretchY;
263 
264         // determine height and transparency
265         bool transparency = sg_bugTransparency || ( sg_bugTransparencyDemand && renderHeight_ < height );
266         REAL h = transparency ? height : renderHeight_;
267         if ( transparency )
268             glDisable( GL_DEPTH_TEST );
269 
270       if (sg_MoviePack()){
271             X_SCALE=sg_MPRimStretchX;
272             Z_SCALE=sg_MPRimStretchY;
273         }
274 
275         if ( tBeg_ == tEnd_ )
276         {
277             tBeg_=(p1->x+p1->y);
278             tEnd_=(p2->x+p2->y);
279         }
280         REAL tBeg = tBeg_/X_SCALE;
281         REAL tEnd = tEnd_/X_SCALE;
282         eCoord P1=*p1;
283         eCoord P2=*p2;
284 
285         // draw "shadow" away from camera
286         if ( cam )
287         {
288             // determine relevant position
289             eCoord pos = cam->CenterPos();
290 
291             // alternative that does not look so good
292             // eCoord pos = cam->CameraGlancePos();
293 
294             // calculate normal on wall
295             eCoord normal = (P1 - P2).Turn(0,1);
296             normal.Normalize();
297 
298             // determine distance of the position to the wall's line
299             REAL side = -eCoord::F(normal, pos - P1);
300 
301             // length scale
302             REAL scale = pos.Norm() + 10 + (P1-P2).Norm();
303 
304             // add a tiny contribution from the direction to avoid side==zero
305             // side += (  20 * EPS * eCoord::F( normal, cam->CenterCamDir() )
306             //          +10 * EPS * eCoord::F( normal, cam->CameraDir() ) ) * scale;
307 
308             // fallback to camera position in case of doubt
309             // if ( fabs(side) < EPS*scale )
310             //    side = -eCoord::F( normal, cam->CameraGlancePos() );
311 
312             // get absolute value and sign of side
313             REAL abs = fabs(side);
314             REAL sign = side/abs;
315 
316             // if abs is low, override the sign by considering the direction
317             if ( abs < EPS*scale*10 )
318             {
319                 // the direction object and camera are facing
320                 eCoord facing = cam->CenterCamDir() * 2 + cam->CameraDir();
321 
322                 sign = eCoord::F( normal, facing );
323                 abs  = fabs( sign );
324                 if ( abs > EPS )
325                 {
326                     sign/= fabs( sign );
327                     abs  = EPS*scale;
328                 }
329                 else
330                 {
331                     abs  = 0;
332                     sign = 0;
333                 }
334             }
335 
336             // driving direction
337             eCoord dir = cam->CenterCamDir();
338 
339             // the side the camera is on
340             REAL camSide = -eCoord::F(normal, cam->CameraGlancePos() - P1);
341 
342             // no shadow if camera and vehicle are on different sides
343             if ( camSide * sign < -EPS*scale )
344                 sign = 0;
345 
346             // if the camera is closer to the wall than the vehicle, take the abs value from that
347             if ( sign * eCoord::F( normal, dir ) > -EPS )
348             {
349                 if ( camSide * sign >= 0 )
350                 {
351                     REAL camAbs = fabs( camSide );
352                     if ( camAbs < abs )
353                         abs = camAbs;
354                 }
355                 else
356                 {
357                     // wall lies between camera and cycle
358                     abs = 0;
359                 }
360             }
361 
362             // add scaled down distance of the wall and the projected path
363             {
364                 REAL d1 = dir * (pos - P1);
365                 REAL d2 = dir * (pos - P2);
366                 if ( d1 * d2 >= 0 )
367                 {
368                     REAL dist = fabs( d1 );
369                     d2 = fabs( d2 );
370                     if ( d2 < dist )
371                         dist = d2;
372 
373                     abs += dist * sg_arenaWallShadowSideDist/sg_arenaWallShadowDist;
374                 }
375             }
376 
377             // add scaled down distance along the wall's direction
378             /*
379             {
380                 REAL a1 = -(pos - P1)*normal;
381                 REAL a2 =  (pos - P2)*normal;
382                 if (a1 > 0)
383                     abs += a1 * sg_arenaWallShadowSideDist/sg_arenaWallShadowDist;
384                 if (a2 > 0)
385                     abs += a2 * sg_arenaWallShadowSideDist/sg_arenaWallShadowDist;
386             }
387             */
388 
389             if ( sign != 0 && abs < sg_arenaWallShadowSideDist )
390             {
391                 // determine height scale
392                 REAL heightForShadow = cam->CameraZ()+10;
393                 if ( this->renderHeight_*4 < heightForShadow )
394                     heightForShadow = this->renderHeight_*4;
395 
396                 // determine shadow extension
397                 REAL extension = heightForShadow*sg_arenaWallShadowSize * sign/( 1 + abs/sg_arenaWallShadowNear );
398                 extension *= ( 1 - abs/sg_arenaWallShadowSideDist );
399 
400                 // get two more vertices for teh shadow
401                 eCoord P3=P1+normal*extension;
402                 eCoord P4=P2+normal*extension;
403 
404                 // render shadow
405                 Color(0,0,0);
406                 BeginQuads();
407                 Vertex(P1.x, P1.y, 0);
408                 Vertex(P2.x, P2.y, 0);
409                 Vertex(P4.x, P4.y, 0);
410                 Vertex(P3.x, P3.y, 0);
411             }
412         }
413 
414         {
415             eCoord vec = P1-P2;
416             REAL xs = vec.x*vec.x;
417             REAL ys = vec.y*vec.y;
418             REAL intensity = .7 + .3 * xs/(xs+ys+1E-30);
419             RenderEnd( true );
420             Color(intensity, intensity, intensity);
421         }
422 
423         if (sg_MoviePack()){
424             bool sw=false;
425 
426             if (tBeg>tEnd){
427                 Swap(P1,P2);
428                 Swap(tBeg,tEnd);
429                 //sw=true;
430             }
431 
432             REAL ta=tBeg;
433             eCoord ca=P1;
434             for (int i=int(ceil(tBeg));i<tEnd;i++){
435                 eCoord cb=P1+(P2-P1)*((i-tBeg)/(tEnd-tBeg));
436                 gWallRim_helper(ca,cb,ta,i,h,Z_SCALE,sw);
437                 ca=cb;
438                 ta=i;
439             }
440             gWallRim_helper(ca,P2,ta,tEnd,h,Z_SCALE,sw);
441         }
442         else{
443             // wrap manually in y-direction, some graphics card are bad at it
444             REAL offset = 0;
445             if (tBeg>tEnd)
446                 offset = -floor(tEnd);
447             else
448                 offset = -floor(tBeg);
449 
450             tBeg += offset;
451             tEnd += offset;
452 
453             gWallRim_helper(*p1,*p2,tBeg,tEnd,h,Z_SCALE,false);
454         }
455 
456         //eWall::Render_helper(edge,(p1->x+p1->y)/SCALE,(p2->x+p2->y)/SCALE,40,height);
457 
458         if ( transparency )
459             glEnable( GL_DEPTH_TEST );
460     }
461 
462     // grow the wall again
463     if ( se_mainGameTimer )
464     {
465         REAL time = se_mainGameTimer->Time();
466         REAL ts = time - lastUpdate_;
467         if ( ts > 0 )
468         {
469             lastUpdate_ = time;
470 
471             if ( renderHeight_ < .25 )
472             {
473                 renderHeight_ = .25;
474             }
475             renderHeight_ *= 1 + 10 * ts;
476             renderHeight_ += 5 * ts;
477             if ( renderHeight_ > height )
478             {
479                 renderHeight_ = height;
480             }
481         }
482 
483         if ( renderHeight_ < height )
484         {
485             DestroyDisplayList();
486         }
487     }
488 }
489 
490 // *******************************************************************************************
491 // *
492 // *   OnBlocksCamera
493 // *
494 // *******************************************************************************************
495 //!
496 //! @param cam the camera that is blocked
497 //! @param height the maximal height the wall would be allowed to have without blocking the view
498 //!
499 // *******************************************************************************************
500 
OnBlocksCamera(eCamera * camera,REAL height) const501 void gWallRim::OnBlocksCamera( eCamera * camera, REAL height ) const
502 {
503     DestroyDisplayList();
504 
505     // lower the wall so it now longer blocks the view
506     if ( height < renderHeight_ )
507     {
508         renderHeight_ = height;
509    }
510     if ( renderHeight_ < .25 )
511         renderHeight_ = .25;
512 }
513 
514 #endif
515 
516 // *******************************************************************************************
517 // *
518 // *   Height
519 // *
520 // *******************************************************************************************
521 //!
522 //!        @return
523 //!
524 // *******************************************************************************************
525 
Height(void)526 REAL gWallRim::Height( void )
527 {
528     return renderHeight_;
529 }
530 
531 // *******************************************************************************************
532 // *
533 // *   SeeHeight
534 // *
535 // *******************************************************************************************
536 //!
537 //!        @return
538 //!
539 // *******************************************************************************************
540 
SeeHeight(void)541 REAL gWallRim::SeeHeight( void )
542 {
543     return renderHeight_ * 2;
544 }
545 
546 /* **********************************************
547    PlayerWall
548    ********************************************** */
549 
550 #ifdef DEBUG
551 #define CHECKWALL this->Check();
552 #else
553 #define CHECKWALL
554 #endif
555 
gPlayerWall(gNetPlayerWall * w,gCycle * p)556 gPlayerWall::gPlayerWall(gNetPlayerWall*w, gCycle *p)
557         :eWall(p->grid),cycle_(p),netWall_(w),begDist_(w->Pos(0)),endDist_(w->Pos(1))
558 {
559     CHECKWALL;
560 
561     if (cycle_)
562         windingNumber_ = cycle_->WindingNumber();
563 
564 #ifdef DEBUG
565     if (!cycle_)
566     {
567         //		st_Breakpoint();
568     }
569 #endif
570 }
571 
~gPlayerWall()572 gPlayerWall::~gPlayerWall(){
573     CHECKWALL;
574 }
575 
576 //ArmageTron_eWalltype gPlayerWall::type(){return ArmageTron_PLAYERWALL;}
577 
Flip()578 void gPlayerWall::Flip(){
579     CHECKWALL;
580 
581     eWall::Flip();
582     Swap( this->begDist_, this->endDist_ );
583 
584     CHECKWALL;
585 }
586 
clamp01(REAL & c)587 static void clamp01(REAL &c){
588     if (!finite(c))
589         c = 0.5;
590 
591     if (c<0)
592         c = 0;
593 
594     if (c>1)
595         c = 1;
596 }
597 
598 // execute cycles that violate the rules of topology. To hell with them!
sg_TopologyPoliceKill(gCycle * cycle)599 void sg_TopologyPoliceKill( gCycle* cycle )
600 {
601     if ( sn_GetNetState() != nCLIENT && cycle->Alive() )
602     {
603         tOutput message;
604         tString name;
605         if ( cycle->Player() )
606             name = cycle->Player()->GetName();
607         else
608             cycle->PrintName( name );
609         message.SetTemplateParameter(1, name );
610         message << "$player_topologypolice";
611         sn_ConsoleOut( message );
612 
613         cycle->Kill();
614     }
615 }
616 
617 static short sg_topologyPolice = false;
618 static tSettingItem< short > sg_topologyPoliceCofig( "TOPOLOGY_POLICE", sg_topologyPolice );
619 
620 static short sg_topologyPoliceParallel = true;
621 static tSettingItem< short > sg_topologyPoliceParallelCofig( "TOPOLOGY_POLICE_PARALLEL", sg_topologyPoliceParallel );
622 
623 class gTopologyPoliceConsoleFiler: public tConsoleFilter
624 {
DoFilterLine(tString & line)625     virtual void DoFilterLine( tString& line )
626     {
627         tString oldLine = line;
628         tOutput message;
629         message.SetTemplateParameter(1, oldLine );
630         message << "$player_topologypolice";
631         line = message;
632     }
633 };
634 
635 extern bool sg_gnuplotDebug; // from gCycle.cpp
636 
637 // called on a post-insert collision of two walls
638 // oldWall is the wall that was in place first, newWall is the wall just drawn, and point
639 // is a point of collision between the two.
sg_TopologyPoliceCheck(gCycle * cycle,eWall * oldWall,gPlayerWall * newWall,const eCoord & point,bool split)640 void sg_TopologyPoliceCheck( gCycle* cycle, eWall* oldWall, gPlayerWall* newWall, const eCoord& point, bool split )
641 {
642     // test if topology police is enabled
643     if ( !sg_topologyPolice && !sg_gnuplotDebug )
644         return;
645 
646     // locate point on both edges
647     REAL oldAlpha = oldWall->Edge()->Ratio( point );
648     REAL newAlpha = newWall->Edge()->Ratio( point );
649     clamp01( newAlpha );
650     clamp01( oldAlpha );
651 
652     // calculate time of passage
653     REAL time = newWall->Time( newAlpha );
654 
655     // if the old wall does not lie in a hole of the new wall, don't go on.
656     // this test overestimates the time ( instead of "se_GameTime()", it should
657     // read just "time" ) to test wheter the wall is dangerous NOW
658     // to avoid innocent victims. A wall never gets more dangerous with time.
659     if ( !newWall->IsDangerous( newAlpha, se_GameTime() ) )
660         return;
661 
662     // the same logic for the old wall
663     gPlayerWall* oldPlayerWall = dynamic_cast< gPlayerWall* >( oldWall );
664     if ( oldPlayerWall && !oldPlayerWall->IsDangerous( oldAlpha, se_GameTime() ) )
665         return;
666 
667     // log collision for gnuplot
668 #ifdef DEBUG
669     if ( sg_gnuplotDebug )
670     {
671         std::stringstream filename;
672         if ( cycle && cycle->Player() )
673         {
674             filename << cycle->Player()->GetUserName() << "_";
675         }
676         filename << "topology";
677         std::ofstream f( filename.str().c_str(), std::ios::app );
678         f << point.x << " " << point.y << "\n";
679     }
680 #endif
681 
682     // last chance to exit
683     if ( !sg_topologyPolice || ( !split && !sg_topologyPoliceParallel ) )
684         return;
685 
686     gTopologyPoliceConsoleFiler filter;
687 
688     // treat the crossing as if the cycle just went through the old wall.
689     try
690     {
691         cycle->PassEdge( oldWall, time, oldAlpha );
692     }
693     catch ( gCycleDeath const & death )
694     {
695         cycle->KillAt( death.pos_ );
696     }
697 }
698 
699 // collision hooks
SplitByActive(eWall * oldWall)700 void gPlayerWall::SplitByActive( eWall * oldWall )
701 {
702     if ( oldWall )
703     {
704         // pretend our cycle crossed the old wall just now
705         eCoord intersection = oldWall->Edge()->IntersectWithCareless( Edge() );
706         sg_TopologyPoliceCheck( Cycle(), oldWall, this, intersection, true );
707     }
708     else
709     {
710         sg_TopologyPoliceKill( Cycle() );
711     }
712 
713     eWall::SplitByActive( oldWall );
714 }
715 
716 // hook called when walls are really parallel on the grid
RunsParallelActive(eWall * oldWall)717 bool gPlayerWall::RunsParallelActive( eWall* oldWall )
718 {
719     if ( oldWall )
720     {
721 
722         // collision point: center of gravity
723         eCoord collision = ( oldWall->Point(.5f) + this->Point(.5f) ) *.5f;
724 
725         sg_TopologyPoliceCheck( Cycle(), oldWall, this, collision, false );
726     }
727     else
728     {
729         sg_TopologyPoliceKill( Cycle() );
730     }
731 
732     return eWall::RunsParallelPassive( oldWall );
733 }
734 
Splittable() const735 bool gPlayerWall::Splittable() const{return 1;}
736 
Deletable() const737 bool gPlayerWall::Deletable() const{
738     CHECKWALL;
739 
740     // a wall without a cycle can clearly be deleted
741     if ( !cycle_ )
742         return true;
743 
744     return !IsDangerousAnywhere( se_GameTime() - 1.0f );
745 }
746 
747 /*
748 static void S_Mix( const gPlayerWallCoord source[2], REAL alpha, gPlayerWallCoord& target )
749 {
750 	REAL diff  = ( source[1].Alpha - source[0].Alpha );
751 	REAL ralpha = 0;
752 	if ( diff > 0 )
753 		ralpha     = ( alpha - source[0].Alpha ) / diff;
754 
755 	target.Alpha = alpha;
756 	target.Pos   = source[0].Pos  + ralpha * ( source[1].Pos  - source[0].Pos  );
757 	target.Pos   = source[0].Time + ralpha * ( source[1].Time - source[0].Time );
758 }
759 */
760 
Split(eWall * & w1,eWall * & w2,REAL a)761 void gPlayerWall::Split(eWall *& w1,eWall *& w2,REAL a){
762     CHECKWALL;
763 
764     gPlayerWall *W1, *W2;
765 
766     W1=tNEW(gPlayerWall(netWall_,cycle_));
767     W2=tNEW(gPlayerWall(netWall_,cycle_));
768     W1->windingNumber_ = windingNumber_;
769     W2->windingNumber_ = windingNumber_;
770     W1->begDist_ = begDist_;
771     W2->endDist_ = endDist_;
772     W1->endDist_ = W2->begDist_ = begDist_ + ( endDist_ - begDist_ ) * a;
773 
774     /*
775     	int divindex = IndexPos( mp );
776     	int i;
777 
778     	// transfer front points
779     	W1->coords_.SetLen( divindex + 2 );
780     	for ( i = divindex+1; i>=0; --i )
781     		W1->coords_(i) = coords_(i);
782 
783     	W1->coords_(divindex+1).Pos  = mp;
784     	W1->coords_(divindex+1).Time = mt;
785 
786     	// transfer rear points
787     	W2->coords_.SetLen( coords_.Len() - divindex );
788     	for ( i = coords_.Len() - divindex - 1 ; i>=0; --i )
789     		W2->coords_(i) = coords_( divindex + i );
790 
791     	W2->coords_(0).Pos  = mp;
792     	W2->coords_(0).Time = mt;
793 
794     	if ( flipped )
795     		Swap( W1, W2 );
796     */
797 
798     // store wall pointers
799     w1 = W1;
800     w2 = W2;
801 
802 #ifdef DEBUG
803     W1->Check();
804     W2->Check();
805 #endif
806 
807     CHECKWALL;
808 }
809 
810 //#define gBEG_LEN 2
811 //#define gBEG_LEN .25
812 //#define gCYCLE_LEN .95
813 //#define gCYCLE_LEN 1.6
814 #define gCYCLE_LEN 1.5
815 #define gBEG_OFFSET .25
816 #define gBEG_LEN 2
817 //#define gCYCLE_LEN 3.8
818 //#define gBEG_OFFSET 1
819 
820 #ifndef DEDICATED
Render(const eCamera * cam)821 void gPlayerWall::Render(const eCamera *cam){
822     if (!cycle_)
823         return;
824     RenderList(true);
825 }
826 
Render(const eCamera * cam)827 void gNetPlayerWall::Render(const eCamera *cam ){
828     if (!cycle_)
829         return;
830     RenderList(true);
831 }
832 
833 /*
834 class gPerformanceCounter
835 {
836 public:
837     gPerformanceCounter(): count_(0){ tRealSysTimeFloat(); }
838     unsigned int Count(){ return count_++; }
839     ~gPerformanceCounter()
840     {
841         double time = tRealSysTimeFloat();
842         std::stringstream s;
843         s << count_ << " walls in " << time << " seconds: " << count_ / time << " wps.\n";
844 #ifdef WIN32
845         MessageBox (NULL, s.str().c_str() , "Performance", MB_OK);
846 #else
847         std::cout << s.str();
848 #endif
849     }
850 private:
851     unsigned int count_;
852 };
853 */
854 
RenderList(bool list)855 void gPlayerWall::RenderList(bool list)
856 {
857     netWall_->RenderList( list );
858 }
859 
RenderList(bool list,gWallRenderMode renderMode)860 void gNetPlayerWall::RenderList(bool list, gWallRenderMode renderMode ){
861     if ( !cycle_ )
862     {
863         return;
864     }
865 
866 #ifdef DEBUG_X
867     if ( cycle_->Player()->GetName().StartsWith("B") && dbegin < .1 )
868     {
869         int x;
870         x = 1;
871     }
872 #endif
873 
874     // clear list if walls are vanishing
875     // or if the wall end was reached
876     // or this is the cycle's first wall
877     if ( gCycleWallsDisplayListManager::CannotHaveList( dbegin, cycle_ ) ||
878          this == cycle_->currentWall )
879     {
880         ClearDisplayList(2);
881     }
882 
883     if ( !displayList_.Call() )
884     {
885         //static gPerformanceCounter counter;
886         //counter.Count();
887 
888         rDisplayListFiller filler( displayList_ );
889 
890         REAL r,g,b;
891         if (cycle_){
892             r=cycle_->trailColor_.r;
893             g=cycle_->trailColor_.g;
894             b=cycle_->trailColor_.b;
895         }
896         else
897             r=g=b=1;
898 
899         eCoord P1=EndPoint(0);
900         eCoord P2=EndPoint(1);
901 
902         {
903             eCoord vec = P2-P1;
904             REAL xs = vec.x*vec.x;
905             REAL ys = vec.y*vec.y;
906             REAL denom = xs+ys;
907             if( denom <= 0 )
908             {
909                 // zero length wall
910                 return;
911             }
912 
913             REAL intensity = .7 + .3 * xs/denom;
914             r *= intensity;
915             g *= intensity;
916             b *= intensity;
917         }
918 
919         REAL a=1;
920 
921 #define SEGLEN 2.5
922         //REAL ta=startTime*3;
923         //REAL te=endTime*3;
924         for ( int i = coords_.Len()-2; i>=0; --i )
925         {
926             const gPlayerWallCoord* coord = &coords_(i);
927 
928             if ( !coord[0].IsDangerous )
929                 continue;
930 
931             REAL pa = coord[0].Pos;
932             REAL pe = coord[1].Pos;
933 
934             REAL aa = Alpha( pa );
935             REAL ae = Alpha( pe );
936 
937             eCoord p1 = P1 + ( P2 - P1 ) * aa;
938             eCoord p2 = P1 + ( P2 - P1 ) * ae;
939 
940             REAL ta=pa/SEGLEN;
941             REAL te=pe/SEGLEN;
942             //REAL shift=REAL(floor((ta+te)/20)*10);
943 
944             //REAL time=ArmageTronTimer*3;
945             REAL time;
946             if (cycle_)
947             {
948                 if ( cycle_->currentWall )
949                     time = cycle_->currentWall->EndPos()/SEGLEN;
950                 else
951                     time=cycle_->GetDistance()/SEGLEN;
952                 if ( !cycle_->Alive() )
953                     time += se_GameTime() - cycle_->deathTime;
954             }
955             else
956                 time=0;
957 
958             //ta-=shift;
959             //te-=shift;
960             //time-=shift;
961 
962             if (ta>te){
963                 Swap(ta,te);
964                 Swap(p1,p2);
965                 Swap(pa,pe);
966             }
967 
968             // cut the end of the wall
969             if ( bool(cycle_) && gCycle::WallsLength() > 0 )
970             {
971                 REAL denom = pa - pe;
972                 if( denom >= 0 )
973                 {
974                     continue;
975                 }
976 
977                 REAL cut = (cycle_->GetDistance() - cycle_->ThisWallsLength() - pe) / denom;
978                 if ( cut < 0 )
979                     continue;
980                 if ( cut < 1 )
981                 {
982                     p1 = p2 + (p1-p2)*cut;
983                     ta = te + (ta-te)*cut;
984                 }
985             }
986 
987             if (te+gBEG_LEN<=time){
988                 RenderNormal(p1,p2,ta,te,r,g,b,a,renderMode);
989             }
990 
991             else{ // complicated
992                 // can't squeeze that into a display list
993                 ClearDisplayList();
994 
995                 if (ta+gBEG_LEN>=time){
996                     RenderBegin(p1,p2,ta,te,
997                                 1+(ta-time)/gBEG_LEN,
998                                 1+(te-time)/gBEG_LEN,
999                                 r,g,b,a);
1000                 }
1001                 else{
1002                     REAL denom = te - ta;
1003                     if( denom <= 0 )
1004                     {
1005                         continue;
1006                     }
1007 
1008                     REAL s=((time-gBEG_LEN)-ta)/denom;
1009                     eCoord pm=p1+(p2-p1)*s;
1010                     RenderBegin(pm,p2,
1011                                 ta+(te-ta)*s,te,0,
1012                                 1+(te-time)/gBEG_LEN,
1013                                 r,g,b,a);
1014                     RenderNormal(p1,pm,ta,ta+(te-ta)*s,r,g,b,a, gWallRenderMode_All );
1015                 }
1016             }
1017         }
1018     }
1019 }
1020 
1021 
upperlinecolor(REAL r,REAL g,REAL b,REAL a)1022 inline bool upperlinecolor(REAL r,REAL g,REAL b, REAL a){
1023     if (rTextureGroups::TextureMode[rTextureGroups::TEX_WALL]<0)
1024         glColor4f(1,1,1,a);
1025     else{
1026         /*
1027           REAL upperline_alpha=fabs(se_cameraRise*2);
1028           upperline_alpha-=1;
1029           if (upperline_alpha>.5)
1030           upperline_alpha=1;
1031           if (upperline_alpha<=.5)
1032           return false;
1033           glColor4f(r,g,b,upperline_alpha);
1034         */
1035         //glDisable(GL_TEXTURE);
1036         glColor4f(r,g,b,a);
1037     }
1038     return true;
1039 }
1040 
RenderNormal(const eCoord & p1,const eCoord & p2,REAL ta,REAL te,REAL r,REAL g,REAL b,REAL a,gWallRenderMode mode)1041 void gNetPlayerWall::RenderNormal(const eCoord &p1,const eCoord &p2,REAL ta,REAL te,REAL r,REAL g,REAL b,REAL a, gWallRenderMode mode ){
1042     REAL hfrac=1;
1043 
1044     if (bool(cycle_) && !cycle_->Alive() && gCycle::WallsStayUpDelay() >= 0 ){
1045         REAL dt=(se_GameTime()-cycle_->deathTime-gCycle::WallsStayUpDelay())*2;
1046 
1047         if (dt>1)
1048         {
1049             // remove from rendering lists
1050             Remove();
1051             return;
1052         }
1053 
1054         if (dt>=0)
1055         {
1056             REAL ca=REAL(.5/(dt+.5));
1057             REAL alpha=1-dt;
1058             if (alpha>1) alpha=1;
1059             hfrac=1-dt;
1060 
1061             r+=ca;
1062             b+=ca;
1063             g+=ca;
1064 
1065             a*=alpha;
1066         }
1067     }
1068     REAL h=1;
1069 
1070 
1071     if (hfrac>0){
1072         if ( ( mode & gWallRenderMode_Lines ) ){
1073 
1074             // draw additional upper line
1075             if ( mode == gWallRenderMode_All )
1076             {
1077                 sr_DepthOffset(true);
1078                 if ( rTextureGroups::TextureMode[rTextureGroups::TEX_WALL] != 0 )
1079                 {
1080                     RenderEnd();
1081                     glDisable(GL_TEXTURE_2D);
1082                 }
1083             }
1084 
1085             BeginLines();
1086             upperlinecolor(r,g,b,a);
1087             glVertex3f(p1.x,p1.y,h*hfrac);
1088             upperlinecolor(r,g,b,a);
1089             glVertex3f(p2.x,p2.y,h*hfrac);
1090 
1091             // in the other modes, the caller is responsible for
1092             // calling RenderEnd() and resetting the states.
1093             if ( mode == gWallRenderMode_All )
1094             {
1095                 RenderEnd();
1096                 sr_DepthOffset(false);
1097                 if ( rTextureGroups::TextureMode[rTextureGroups::TEX_WALL] != 0 )
1098                     glEnable(GL_TEXTURE_2D);
1099             }
1100         }
1101 
1102         //glColor4f(r,g,b,a);
1103 
1104 #ifdef XDEBUG
1105         REAL extrarise = 0;
1106         if ( this->id >= 0 )
1107         {
1108             extrarise = 1;
1109         }
1110 #else
1111         static const REAL extrarise = 0;
1112 #endif
1113         if ( mode & gWallRenderMode_Quads )
1114         {
1115             BeginQuads();
1116 
1117             glColor4f(r,g,b,1);
1118             glTexCoord2f(ta,hfrac);
1119             glVertex3f(p1.x,p1.y,extrarise);
1120 
1121             glColor4f(r,g,b,1);
1122             glTexCoord2f(ta,0);
1123             glVertex3f(p1.x,p1.y,extrarise + h*hfrac);
1124 
1125             glColor4f(r,g,b,1);
1126             glTexCoord2f(te,0);
1127             glVertex3f(p2.x,p2.y,extrarise + h*hfrac);
1128 
1129             glColor4f(r,g,b,1);
1130             glTexCoord2f(te,hfrac);
1131             glVertex3f(p2.x,p2.y,extrarise);
1132 
1133 			// in the other modes, the caller is responsible for
1134 			// calling RenderEnd().
1135 			if ( mode == gWallRenderMode_All )
1136 			{
1137 				RenderEnd();
1138 			}
1139         }
1140     }
1141 }
1142 
hfunc(REAL x)1143 static inline REAL hfunc(REAL x){return 1-(x*x)/2;}
1144 //static inline REAL hfunc(REAL x){return 1-(x*x);}
cfunc(REAL x)1145 static inline REAL cfunc(REAL x){return (x*x);}
1146 //static inline REAL afunc(REAL x){return 1-(x*x)/2;}
afunc(REAL x)1147 static inline REAL afunc(REAL x){return 1-(x*x);}
sfunc(REAL x)1148 static inline REAL sfunc(REAL x){return (x*x);}
1149 //static inline REAL xfunc(REAL x){return (x+x*x)/2;}
xfunc(REAL x)1150 static inline REAL xfunc(REAL x){return REAL((x*.2+x*x)/2);}
1151 
RenderBegin(const eCoord & p1,const eCoord & pp2,REAL ta,REAL te,REAL ra,REAL re,REAL r,REAL g,REAL b,REAL a)1152 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){
1153     if ( !cycle_ )
1154     {
1155         return;
1156     }
1157 
1158     REAL hfrac=1;
1159 
1160     eCoord p2 = pp2;
1161 
1162     if (re > 1){
1163         if (re > 2 || re <= ra )
1164             return;
1165 
1166         REAL ratio = (1-ra)/(re-ra);
1167         p2 = p1 + (pp2-p1)*ratio;
1168         te = ta + (te-ta)*ratio;
1169         re= 1;
1170     }
1171 
1172     if (bool(cycle_) && !cycle_->Alive()){
1173         REAL dt=(se_GameTime()-cycle_->deathTime-gCycle::WallsStayUpDelay())*2;
1174         if (dt>1) dt=1;
1175         if (dt>0)
1176         {
1177             REAL ca=REAL(.5/(dt+.5));
1178             REAL alpha=1-dt;
1179             if (alpha>1) alpha=1;
1180             hfrac=1-dt;
1181 
1182             r+=ca;
1183             b+=ca;
1184             g+=ca;
1185         }
1186         //a*=alpha;
1187     }
1188 
1189     REAL h=1;
1190 
1191     eCoord ppos=cycle_->PredictPosition() - cycle_->dir*REAL(gCYCLE_LEN);
1192 
1193     if ( hfrac>0 ){
1194         sr_DepthOffset(true);
1195         //REAL H=h*hfrac;
1196 #define segs 5
1197         // upperlinecolor(r,g,b,a);//a*afunc(rat));
1198 
1199         if ( rTextureGroups::TextureMode[rTextureGroups::TEX_WALL] != 0 )
1200             glDisable(GL_TEXTURE_2D);
1201 
1202         BeginLineStrip();
1203         for (int i=0;i<=segs;i++){
1204             REAL frag=i/float(segs);
1205             REAL rat=ra+frag*(re-ra);
1206             REAL x=(p1.x+frag*(p2.x-p1.x))*(1-xfunc(rat))+ppos.x*xfunc(rat);
1207             REAL y=(p1.y+frag*(p2.y-p1.y))*(1-xfunc(rat))+ppos.y*xfunc(rat);
1208 
1209             REAL H=h*hfrac*hfunc(rat);
1210             upperlinecolor(r,g,b,a*afunc(rat));
1211             glVertex3f(x+H*cycle_->skew*sfunc(rat)*cycle_->dir.y,
1212                        y-H*cycle_->skew*sfunc(rat)*cycle_->dir.x,
1213                        H);//+se_cameraZ*.005);
1214         }
1215         RenderEnd();
1216         sr_DepthOffset(false);
1217         if ( rTextureGroups::TextureMode[rTextureGroups::TEX_WALL] != 0 )
1218             glEnable(GL_TEXTURE_2D);
1219     }
1220 
1221     BeginQuadStrip();
1222 
1223     //REAL H=h*hfrac;
1224 
1225     //ppos=ePlayer->pos-ePlayer->dir*gCYCLE__LEN;
1226 
1227     for (int i=0;i<=segs;i++){
1228         REAL frag=i/float(segs);
1229         REAL rat=ra+frag*(re-ra);
1230         REAL x=(p1.x+frag*(p2.x-p1.x))*(1-xfunc(rat))+ppos.x*xfunc(rat);
1231         REAL y=(p1.y+frag*(p2.y-p1.y))*(1-xfunc(rat))+ppos.y*xfunc(rat);
1232 
1233         // bottom
1234         glColor4f(r+cfunc(rat),g+cfunc(rat),b+cfunc(rat),a*afunc(rat));
1235         glTexCoord2f(ta+(te-ta)*frag,hfrac);
1236         glVertex3f(x,y,0);
1237 
1238         // top
1239 
1240         //glTexCoord2f(ta+(te-ta)*frag,hfrac*(1-hfunc(rat)));
1241         glColor4f(r+cfunc(rat),g+cfunc(rat),b+cfunc(rat),a*afunc(rat));
1242         glTexCoord2f(ta+(te-ta)*frag,0);
1243         REAL H=h*hfrac*hfunc(rat);
1244         glVertex3f(x+H*cycle_->skew*sfunc(rat)*cycle_->dir.y,
1245                    y-H*cycle_->skew*sfunc(rat)*cycle_->dir.x,
1246                    H);
1247     }
1248     RenderEnd();
1249 }
1250 #endif
1251 
SetEndTime(REAL t)1252 void gNetPlayerWall::SetEndTime(REAL t){
1253     CHECKWALL;
1254 
1255     REAL BegTime = coords_( coords_.Len() -2 ).Time;
1256     if ( t < BegTime )
1257     {
1258         t = BegTime;
1259     }
1260 
1261     coords_(coords_.Len()-1).Time = t;
1262 
1263     CHECKWALL;
1264 
1265 }
1266 
SetEndPos(REAL ep)1267 void gNetPlayerWall::SetEndPos(REAL ep){
1268     CHECKWALL;
1269 
1270     REAL BegPos = coords_( coords_.Len() -2 ).Pos;
1271     if ( ep < BegPos )
1272     {
1273         ep = BegPos;
1274     }
1275 
1276     coords_(coords_.Len()-1).Pos = ep;
1277 
1278     CHECKWALL;
1279 }
1280 
BlockHeight() const1281 REAL gPlayerWall::BlockHeight() const{
1282     if (bool(cycle_) && cycle_->Alive()==1)
1283         return 1;
1284     else
1285         return 0;
1286 }
1287 
SeeHeight() const1288 REAL gPlayerWall::SeeHeight() const{
1289     return BlockHeight();
1290 }
1291 
1292 
Cycle() const1293 gCycle *gPlayerWall::Cycle() const {return cycle_;}
CycleMovement() const1294 gCycleMovement *gPlayerWall::CycleMovement() const {return cycle_;}
NetWall() const1295 gNetPlayerWall *gPlayerWall::NetWall() const {return netWall_;}
1296 
Insert()1297 void gPlayerWall::Insert()
1298 {
1299     CHECKWALL;
1300 
1301     eWall::Insert();
1302 }
1303 
Check() const1304 void gPlayerWall::Check() const
1305 {
1306     netWall_->Check();
1307 #ifdef DEBUG
1308     REAL range = 5 * fabs(begDist_) + fabs(endDist_) * EPS;
1309     tASSERT( begDist_ <= endDist_ + range );
1310     tASSERT( begDist_ >= netWall_->Pos( 0 ) - range );
1311     tASSERT( endDist_ <= netWall_->Pos( 1 ) + range );
1312 #endif
1313 }
1314 
LocalToGlobal(REAL a) const1315 REAL gPlayerWall::LocalToGlobal( REAL a ) const
1316 {
1317     CHECKWALL;
1318 
1319     tASSERT( good( a ) );
1320 
1321     REAL dist = begDist_ + a * ( endDist_ - begDist_ );
1322     REAL ret = netWall_->Alpha( dist );
1323 
1324     tASSERT( good( ret ) );
1325 
1326     return ret;
1327 }
1328 
ClearDisplayList(int inhibitThis,int inhibitCycle)1329 void gNetPlayerWall::ClearDisplayList( int inhibitThis, int inhibitCycle )
1330 {
1331 #ifndef DEDICATED
1332     if ( CanHaveDisplayList() && cycle_ && inhibitCycle >= 0 )
1333     {
1334         cycle_->displayList_.Clear( inhibitCycle );
1335     }
1336     displayList_.Clear( inhibitThis );
1337 #endif
1338 }
1339 
GlobalToLocal(REAL a) const1340 REAL gPlayerWall::GlobalToLocal( REAL a ) const
1341 {
1342     CHECKWALL;
1343 
1344     tASSERT( good( a ) );
1345 
1346     REAL dist = netWall_->Pos( a );
1347 
1348     REAL div = ( endDist_ - begDist_ );
1349     if ( div == 0 )
1350     {
1351         return .5f;
1352     }
1353     else
1354     {
1355         REAL ret = ( dist - begDist_ ) / div;
1356 
1357         tASSERT( good( ret ) );
1358 
1359         return ret;
1360     }
1361 }
1362 
Time(REAL a) const1363 REAL gPlayerWall::Time(REAL a) const
1364 {
1365     tASSERT( good( a ) );
1366 
1367     return netWall_->Time( LocalToGlobal( a ) );
1368 }
1369 
Pos(REAL a) const1370 REAL gPlayerWall::Pos(REAL a) const
1371 {
1372     CHECKWALL;
1373 
1374     tASSERT( good( a ) );
1375 
1376     return begDist_ + ( endDist_ - begDist_ ) * a;
1377 }
1378 
Alpha(REAL pos) const1379 REAL gPlayerWall::Alpha(REAL pos) const
1380 {
1381     CHECKWALL;
1382 
1383     REAL diff = ( endDist_  - begDist_ );
1384     REAL a = pos - begDist_;
1385 
1386     if ( diff > 0 )
1387         a /= diff;
1388 
1389     tASSERT ( -.001 < a );
1390     tASSERT ( 1.001 > a );
1391 
1392     return a;
1393 }
1394 
IsDangerousAnywhere(REAL time) const1395 bool gPlayerWall::IsDangerousAnywhere( REAL time ) const
1396 {
1397     CHECKWALL;
1398 
1399     return netWall_->IsDangerousAnywhere( time );
1400 }
1401 
IsDangerous(REAL a,REAL time) const1402 bool gPlayerWall::IsDangerous( REAL a, REAL time ) const
1403 {
1404     CHECKWALL;
1405 
1406     return netWall_->IsDangerous( LocalToGlobal( a ), time );
1407 }
1408 
1409 // returns the guy who holed here
Holer(REAL a,REAL time) const1410 gExplosion * gPlayerWall::Holer( REAL a, REAL time ) const
1411 {
1412     CHECKWALL;
1413 
1414     return netWall_->Holer( LocalToGlobal( a ), time );
1415 }
1416 
EndPos() const1417 REAL gPlayerWall::EndPos() const
1418 {
1419     CHECKWALL;
1420 
1421     return this->endDist_;
1422 }
1423 
BegPos() const1424 REAL gPlayerWall::BegPos() const
1425 {
1426     CHECKWALL;
1427 
1428     return this->begDist_;
1429 }
1430 
EndTime() const1431 REAL gPlayerWall::EndTime() const
1432 {
1433     CHECKWALL;
1434 
1435     return netWall_->Time( netWall_->Alpha( this->endDist_ ) );
1436 }
1437 
BegTime() const1438 REAL gPlayerWall::BegTime() const
1439 {
1440     CHECKWALL;
1441 
1442     return netWall_->Time( netWall_->Alpha( this->begDist_ ) );
1443 }
1444 
BlowHole(REAL beg,REAL end,gExplosion * holer)1445 void gPlayerWall::BlowHole	( REAL beg, REAL end, gExplosion * holer )
1446 {
1447     CHECKWALL;
1448 
1449     this->netWall_->BlowHole( beg, end, holer );
1450 }
1451 
1452 /*
1453 void gPlayerWall::Clamp	(  )
1454 {
1455 	tASSERT( coords.Len() >= 2 );
1456 
1457 	// clamp beginning
1458 	int begin = IndexAlpha(0.0f);
1459 	gPlayerWallCoord* bcoord = &coords[begin];
1460 	S_Mix( bcoord, 0.0f, bcoord[0] );
1461 
1462 	// clamp end
1463 	int end = IndexAlpha(1.0f);
1464 	gPlayerWallCoord* ecoord = &coords[end];
1465 	S_Mix( ecoord, 1.0f, ecoord[1] );
1466 
1467 	// useful coordinates now lie between begin and end+1
1468 
1469 	// throw away junk at the beginning
1470 	if ( begin > 0 )
1471 	{
1472 		for ( int i = 0; i <= end + 1 - begin; ++i )
1473 			coords[i] = coords[ i + begin ];
1474 	}
1475 
1476 	// throw away junk at the end
1477 	coords.SetLen( end - begin + 2 );
1478 }
1479 */
1480 
1481 // ************************************************
1482 // ************************************************
1483 
1484 
1485 tList<gNetPlayerWall> sg_netPlayerWalls;
1486 tList<gNetPlayerWall> sg_netPlayerWallsGridded;
1487 
1488 
CreateEdge()1489 void gNetPlayerWall::CreateEdge()
1490 {
1491     if ( this->edge_ )
1492         return;
1493 
1494     if (this->cycle_)
1495     {
1496         gPlayerWall* w = tNEW(gPlayerWall)(this,
1497                                            this->cycle_);
1498 
1499         this->edge_=tNEW(eTempEdge)(beg,
1500                                     end,
1501                                     w );
1502     }
1503     else
1504     {
1505         this->edge_ = NULL;
1506         return;
1507     }
1508 }
1509 
InitAfterCreation()1510 void gNetPlayerWall::InitAfterCreation()
1511 {
1512     nNetObject::InitAfterCreation();
1513     MyInitAfterCreation();
1514 }
1515 
InitArray()1516 void gNetPlayerWall::InitArray()
1517 {
1518     REAL ep = dbegin+sqrt((beg-end).NormSquared());
1519     REAL sp = dbegin;
1520 
1521     if ( ep < sp )
1522     {
1523         ep = sp;
1524     }
1525 
1526     if ( tEnd < tBeg )
1527     {
1528         tEnd = tBeg;
1529     }
1530 
1531     coords_.SetLen(2);
1532     coords_[0].Pos   		= sp;
1533     coords_[0].Time  		= tBeg;
1534     coords_[0].IsDangerous   = true;
1535     coords_[1].Pos   		= ep;
1536     coords_[1].Time  		= tEnd;
1537     coords_[1].IsDangerous   = true;
1538 }
1539 
MyInitAfterCreation()1540 void gNetPlayerWall::MyInitAfterCreation()
1541 {
1542 #ifndef DEDICATED
1543     // put yourself into rendering list
1544     if ( cycle_ )
1545     {
1546         Insert( cycle_->displayList_.wallList_ );
1547     }
1548 #endif
1549 
1550     //w=
1551 #ifdef DEBUG
1552     if (!finite(end.x) || !finite(end.y))
1553         st_Breakpoint();
1554 
1555     if (!finite(beg.x) || !finite(beg.y))
1556         st_Breakpoint();
1557 #endif
1558 
1559     if ( coords_.Len() < 2 )
1560     {
1561         InitArray();
1562     }
1563 
1564     CreateEdge();
1565 
1566     id=-1;
1567     griddedid=-1;
1568     sg_netPlayerWalls.Add(this,id);
1569 
1570     if ( !Wall() )
1571         return;
1572     tASSERT( Wall()->Splittable() );
1573 
1574     for (int i=MAX_VIEWERS-1;i>=0;i--)
1575         Wall()->SetVisHeight(i,0);
1576 
1577     Wall()->Remove();
1578 
1579     displayList_.Clear(2);
1580 }
1581 
1582 
1583 
gNetPlayerWall(gCycle * cyc,const eCoord & begi,const eCoord & d,REAL tBegi,REAL dbeg)1584 gNetPlayerWall::gNetPlayerWall(gCycle *cyc,
1585                                const eCoord &begi,const eCoord &d,
1586                                REAL tBegi, REAL dbeg)
1587         :nNetObject(cyc->Owner()),
1588         id(-1),griddedid(-1),
1589         cycle_(cyc),lastWall_(NULL),dir(d),dbegin(dbeg),
1590         beg(begi),end(begi),tBeg(tBegi),tEnd(tBegi),
1591         inGrid(false){
1592     dir=dir; // Don't normalize: *REAL(1/sqrt(dir.NormSquared()));
1593     preliminary=(sn_GetNetState()==nCLIENT);
1594     obsoleted_=-100;
1595     gridding=1E+20;
1596     MyInitAfterCreation();
1597 }
1598 
1599 /*
1600 void gNetPlayerWall::Update(REAL Tend,REAL dend){
1601 	if (!inGrid){
1602 		tEnd=Tend;
1603 		end=beg + dir*(dend-dbegin);
1604 
1605 #ifdef DEBUG
1606 		if (!finite(end.x) || !finite(end.y))
1607 			st_Breakpoint();
1608 #endif
1609 
1610 		if (e)
1611 			e->Coord(1) = end;
1612 
1613 		gPlayerWall *w = Wall();
1614 		if (w){
1615 			w->SetEndTime(tEnd);
1616 			w->SetEndPos(dend);
1617 			w->CalcLen();
1618 		}
1619 	}
1620 }
1621 */
1622 
Update(REAL Tend,const eCoord & pend)1623 void gNetPlayerWall::Update(REAL Tend,const eCoord &pend)
1624 {
1625     CHECKWALL;
1626 
1627     if (!inGrid && ( preliminary || sn_GetNetState() != nCLIENT ) )
1628     {
1629         real_Update( Tend, pend, false );
1630     }
1631 
1632     CHECKWALL;
1633 }
1634 
real_Update(REAL Tend,const eCoord & pend,bool force)1635 void gNetPlayerWall::real_Update(REAL Tend,const eCoord &pend, bool force )
1636 {
1637     // duplicate last coords entry if its dangerousness disagrees with the previous entry.
1638     if ( coords_.Len() >= 2 && coords_[ coords_.Len()-2 ].IsDangerous != coords_[ coords_.Len()-1 ].IsDangerous )
1639     {
1640         Checkpoint();
1641     }
1642 
1643     tEnd=Tend;
1644     end=pend;
1645 
1646     // make sure the wall points forward
1647     REAL forward = eCoord::F( end-beg, dir )/dir.NormSquared();
1648     if ( forward < 0 )
1649     {
1650         end = beg;
1651         tEnd = tBeg;
1652     }
1653 
1654 #ifdef DEBUG
1655     if (!finite(end.x) || !finite(end.y))
1656         st_Breakpoint();
1657 #endif
1658 
1659     eCoord odir=dir.Turn(0,1);
1660     REAL x=eCoord::F(odir,(end-beg))/dir.NormSquared();
1661     beg=beg+odir*x;
1662 
1663     if (bool( this->edge_ ) && this->edge_->Point(0) && this->edge_->Point(1)){
1664         this->edge_->Coord(1) = end;
1665         if ( !lastWall_ )
1666             this->edge_->Coord(0) = beg;
1667     }
1668 
1669     // determine the correct end position
1670     REAL endPos = 0;
1671     //if ( bool( this->cycle_ ) && !force )
1672     //{
1673     //    endPos =  this->cycle_->GetDistance();
1674     //}
1675     //else
1676     {
1677         endPos = dbegin + eCoord::F(dir, end - beg )/dir.NormSquared();
1678     }
1679 
1680     // delete coords_ entries that lie after the last one according to their distance; they're invalidated.
1681     {
1682         int len = coords_.Len();
1683         while ( len >= 3 && coords_[len-2].IsDangerous == coords_[len-1].IsDangerous && coords_[len-2].Pos > endPos )
1684         {
1685             coords_[len-2] = coords_[len-1];
1686             coords_.SetLen(len - 1);
1687             len = coords_.Len();
1688         }
1689     }
1690 
1691     // set end position and time
1692     SetEndTime(tEnd);
1693     SetEndPos(endPos);
1694 
1695 
1696     gPlayerWall *w = Wall();
1697 
1698     if ( w )
1699     {
1700         w->CalcLen();
1701         if ( !lastWall_ )
1702             w->begDist_ = dbegin;
1703         w->endDist_ = EndPos();
1704 #ifdef DEBUG
1705         w->Check();
1706 #endif
1707     }
1708 }
1709 
Checkpoint()1710 void gNetPlayerWall::Checkpoint()
1711 {
1712     CHECKWALL;
1713 
1714     // copy the last coordinate entry
1715     int len = coords_.Len();
1716 
1717 #ifdef DEBUG
1718     if ( len > 100 )
1719     {
1720         st_Breakpoint();
1721     }
1722 #endif
1723 
1724     // temporary is required to compensate for growing array nightmare
1725     coords_[len] = gPlayerWallCoord( coords_[len-1] );
1726 
1727     CHECKWALL;
1728 }
1729 
CopyIntoGrid(eGrid * grid,bool force)1730 void gNetPlayerWall::CopyIntoGrid(eGrid * grid, bool force){
1731     tJUST_CONTROLLED_PTR< gNetPlayerWall > keep( this );
1732 
1733     if (!inGrid && (force ||
1734                     (sn_GetNetState()!=nCLIENT || preliminary))){
1735         inGrid=true;
1736         gridding=REAL(se_GameTime()+1.0);
1737         if (sn_GetNetState()==nCLIENT)
1738         {
1739             // leave the wall lingering around for some time on the client
1740             gridding=se_GameTime()+40*sn_Connections[0].ping+10;
1741 
1742             // unless it is already obsoleted by a final wall or IS a final wall. Delete/grid it immediately then.
1743             if ( obsoleted_ > tEnd - .003f || !preliminary )
1744             {
1745                 if ( grid )
1746                     real_CopyIntoGrid( grid );
1747                 else
1748                     gridding=REAL(se_GameTime()+.000001);
1749             }
1750         }
1751         else
1752         {
1753             // copy it into the grid at the next opportunity for server/standalone mode
1754             RequestSync();
1755             if ( grid )
1756                 real_CopyIntoGrid( grid );
1757             else
1758                 gridding=REAL(se_GameTime()+.000001);
1759         }
1760     }
1761 }
1762 
real_CopyIntoGrid(eGrid * grid)1763 void gNetPlayerWall::real_CopyIntoGrid(eGrid *grid){
1764     //  con << "Gridding " << ID() << " : ";
1765     //con << "from " << *e->Point(0) << " to " << *e->Point(1) << '\n';
1766 
1767     tJUST_CONTROLLED_PTR< gNetPlayerWall > keep( this );
1768 
1769 #ifdef DEBUG
1770     grid->Check();
1771 #endif
1772 
1773     if (griddedid<0){
1774         if ( this->cycle_ )
1775         {
1776             tASSERT( static_cast< bool >(this->edge_) );
1777             tASSERT(Wall());
1778             tASSERT(Wall()->Splittable());
1779 
1780             if (preliminary){
1781                 //delete this; // get rid of it
1782                 tControlledPTR< nNetObject > bounce( this );
1783 
1784                 sg_netPlayerWalls.Remove(this,id);
1785                 sg_netPlayerWallsGridded.Add(this,griddedid);
1786                 Wall()->Insert();
1787                 this->ReleaseData();
1788                 ClearDisplayList();
1789             }
1790             else{
1791                 sg_netPlayerWallsGridded.Add(this,griddedid);
1792                 sg_netPlayerWalls.Remove(this,id);
1793                 if ( this->edge_ ){
1794                     Wall()->Insert();
1795                     this->edge_->CopyIntoGrid(this->cycle_->Grid());
1796                     this->edge_ = NULL;
1797                 }
1798             }
1799         }
1800     }
1801 
1802 #ifdef DEBUG
1803     grid->Check();
1804 #endif
1805 
1806 }
1807 
PartialCopyIntoGrid(eGrid * grid)1808 void gNetPlayerWall::PartialCopyIntoGrid(eGrid *grid){
1809     //  con << "Gridding " << ID() << " : ";
1810     //con << "from " << *e->Point(0) << " to " << *e->Point(1) << '\n';
1811 
1812     tJUST_CONTROLLED_PTR< gNetPlayerWall > keep( this );
1813 
1814 #ifdef DEBUG
1815     grid->Check();
1816 #endif
1817 
1818     if (griddedid<0 && bool(this->cycle_) && !preliminary ){
1819 
1820         // just copy the current edge into the grid
1821         if ( this->edge_ ){
1822             lastWall_ = Wall();
1823             Wall()->Insert();
1824             this->edge_->CopyIntoGrid(grid);
1825             this->edge_ = NULL;
1826         }
1827 
1828         // and create a new one just at the end bit
1829         gPlayerWall* w = tNEW(gPlayerWall)(this,
1830                                            this->cycle_);
1831         this->edge_=tNEW(eTempEdge)(end,
1832                                     end,
1833                                     w );
1834 
1835         // insert it into the list of not yet gridded walls
1836         w->Remove();
1837 
1838         // hack the beginning distance to be the same as the starting distance
1839         w->begDist_ = w->endDist_;
1840     }
1841 
1842     // add a new segment as a copy of the current one
1843     // int newCoord = coords_.Len();
1844     // coords_[newCoord]=coords_[newCoord-1];
1845 
1846 #ifdef DEBUG
1847     grid->Check();
1848 #endif
1849 
1850 }
1851 
s_CopyIntoGrid()1852 void gNetPlayerWall::s_CopyIntoGrid()
1853 {
1854 #ifdef DEBUG
1855     static int maxw=20;
1856     if (sg_netPlayerWalls.Len()>maxw)
1857         con << "Many walls: " << (maxw=sg_netPlayerWalls.Len()) << '\n';
1858 #endif
1859 
1860     for (int i=sg_netPlayerWalls.Len()-1;i>=0;i--){
1861         gNetPlayerWall *w=sg_netPlayerWalls(i);
1862         if (w->inGrid && w->griddedid<0 && se_GameTime()>w->gridding)
1863             w->real_CopyIntoGrid(w->cycle_->Grid());
1864     }
1865 }
1866 
RealWallReceived(gNetPlayerWall * realWall)1867 void gNetPlayerWall::RealWallReceived( gNetPlayerWall* realWall )
1868 {
1869     if (this->cycle_ )
1870     {
1871         tASSERT( realWall );
1872         tASSERT( preliminary && !realWall->preliminary );
1873 
1874         // accelerate gridding if the real wall is newer than this
1875         if ( tBeg + tEnd < 2 * realWall->tEnd )
1876         {
1877             REAL maxGridding=se_GameTime() + 2*sn_Connections[0].ping;
1878             if ( gridding > maxGridding )
1879                 gridding = maxGridding;
1880         }
1881 
1882         // calculate the overlap between the real wall and this wall
1883         REAL overlap = 0;
1884         {
1885             REAL tEndThis = tEnd;
1886             // cut from the end if we're in prediction mode and this is an enemy wall
1887             if ( sr_predictObjects && this->cycle_->currentWall == this && Owner() != sn_myNetID )
1888             {
1889                 tEndThis -= this->cycle_->Lag();
1890             }
1891 
1892             REAL tBegMin = tBeg;
1893             REAL tBegMax = realWall->tBeg;
1894             if ( tBegMin > tBegMax )
1895             {
1896                 tBegMin = realWall->tBeg;
1897                 tBegMax = tBeg;
1898             }
1899 
1900             REAL tEndMin = tEndThis;
1901 
1902             REAL tEndMax = realWall->tEnd;
1903             if ( tEndMin > tEndMax )
1904             {
1905                 tEndMin = realWall->tEnd;
1906                 tEndMax = tEndThis;
1907             }
1908 
1909             REAL denominator = tEndMax - tBegMin;
1910             if ( denominator > 0 )
1911                 overlap = ( tEndMin - tBegMax ) / denominator;
1912         }
1913 
1914         // no overlap if directions don't match
1915         if ( overlap > 0 && fabs( dir * realWall->dir ) > 10 * EPS )
1916             overlap = 0;
1917 
1918         // no good overlap? Go home.
1919         if ( overlap < .8 )
1920             return;
1921 
1922         // mark current walls as to be deleted immediately after the cycle does no longer need it
1923         obsoleted_ = realWall->tEnd;
1924 
1925         // copy non-current walls into the grid immediately
1926         if (this->cycle_->currentWall!=this )
1927         {
1928             // replace pointer in cycle
1929             if (this->cycle_->lastWall==this)
1930             {
1931                 this->cycle_->lastWall=realWall;
1932 
1933                 /*
1934                 // close seams (does not help, deactivated)
1935                 if ( this->cycle_->currentWall && this->cycle_->currentWall->preliminary )
1936                 {
1937                     this->cycle_->currentWall->tBeg   = realWall->tEnd;
1938                     this->cycle_->currentWall->coords_[0].Time   = realWall->tEnd;
1939                     this->cycle_->currentWall->dbegin = realWall->EndPos();
1940                 }
1941                 */
1942             }
1943 
1944             // delete this wall, it is no longer needed
1945             this->real_CopyIntoGrid( this->cycle_->Grid() );
1946         }
1947     }
1948 }
1949 
1950 
WriteCreate(nMessage & m)1951 void gNetPlayerWall::WriteCreate(nMessage &m)
1952 {
1953     tASSERT( this->cycle_ );
1954 
1955     nNetObject::WriteCreate(m);
1956     m.Write(this->cycle_->ID());
1957     m << beg;
1958     m << dir;
1959     m << dbegin;
1960     m << tBeg;
1961     m << static_cast<int>(preliminary);
1962 }
1963 
gNetPlayerWall(nMessage & m)1964 gNetPlayerWall::gNetPlayerWall(nMessage &m)
1965         :nNetObject(m),
1966         id(-1),griddedid(-1),
1967         cycle_(NULL),edge_(NULL), lastWall_(NULL),
1968         dir(0,0),dbegin(0),
1969         beg(0,0),end(0,0),
1970         tBeg(0),tEnd(0),
1971         inGrid(0)
1972 {
1973     unsigned short cid;
1974     gridding=1E+20;
1975     m.Read(cid);
1976     cycle_=static_cast<gCycle *>(Object(cid));
1977 
1978     m >> beg;
1979     end=beg;
1980     m >> dir;
1981     m >> dbegin;
1982 
1983     m >> tBeg;
1984     {
1985         int preliminary;
1986         m >> preliminary;
1987         this->preliminary = preliminary;
1988     }
1989 
1990     obsoleted_=-100;
1991 
1992     this->InitArray();
1993 }
1994 
Vec()1995 eCoord gNetPlayerWall::Vec()
1996 {
1997     if ( edge_ ) return edge_->Vec();
1998     else return eCoord();
1999 }
2000 
Wall()2001 gPlayerWall *gNetPlayerWall::Wall(){
2002     if (this->edge_)
2003     {
2004         eWall *w = this->edge_->Wall();
2005 
2006         return reinterpret_cast<gPlayerWall *>(w);
2007     }
2008     else
2009         return NULL;
2010 }
2011 
ReleaseData()2012 void gNetPlayerWall::ReleaseData()
2013 {
2014     if (this->cycle_){
2015         if (this->cycle_->currentWall==this)
2016             this->cycle_->currentWall=NULL;
2017         if (this->cycle_->lastWall==this)
2018             this->cycle_->lastWall=NULL;
2019         if (this->cycle_->lastNetWall==this)
2020             this->cycle_->lastNetWall=NULL;
2021     }
2022 
2023     // tDESTROY(w);
2024 
2025     if (this->edge_)
2026     {
2027         if ( this->edge_->Wall() )
2028             this->edge_->Wall()->Insert();
2029 
2030         this->edge_ = NULL;  // w will be deleted with e
2031         //    tDESTROY_PTR(p1);
2032         //    tDESTROY_PTR(p2);
2033     }
2034 
2035     this->cycle_=NULL;
2036     this->edge_=NULL;
2037     //w=NULL;
2038 
2039     sg_netPlayerWalls.Remove(this,id);
2040     sg_netPlayerWallsGridded.Remove(this,griddedid);
2041 }
2042 
~gNetPlayerWall()2043 gNetPlayerWall::~gNetPlayerWall()
2044 {
2045     ReleaseData();
2046     ClearDisplayList();
2047 }
2048 
ActionOnQuit()2049 bool gNetPlayerWall::ActionOnQuit()
2050 {
2051     if ( sn_GetNetState() == nSERVER )
2052     {
2053         TakeOwnership();
2054         return false;
2055     }
2056     else
2057     {
2058         ReleaseData();
2059 
2060         return true;
2061     }
2062 }
2063 
ClearToTransmit(int user) const2064 bool gNetPlayerWall::ClearToTransmit(int user) const{
2065 #ifdef DEBUG
2066     if (nNetObject::DoDebugPrint() && bool( this->cycle_ ) )
2067     {
2068         if (!GridIsReady(user))
2069             con << "Not transfering gNetPlayerWall " << ID()
2070             << " for user " << user << " because the grid is not ready yet.\n";
2071         else if (!this->cycle_)
2072             con << "Not transfering gNetPlayerWall " << ID()
2073             << " for user " << user << " because it has no cycle!\n";
2074         else if (!this->cycle_->HasBeenTransmitted(user))
2075         {
2076             tString s;
2077             s << "No transfering gNetPlayerWall " << ID()
2078             << " for user " << user << " because ";
2079             this->cycle_->PrintName(s);
2080             s << " has not been transmitted.\n";
2081             con << s;
2082         }
2083     }
2084 #endif
2085 
2086     return GridIsReady(user) && nNetObject::ClearToTransmit(user)
2087            && bool(this->cycle_) && this->cycle_->HasBeenTransmitted(user) && inGrid;
2088 }
2089 
WriteSync(nMessage & m)2090 void gNetPlayerWall::WriteSync(nMessage &m){
2091     nNetObject::WriteSync(m);
2092 
2093     if (inGrid){
2094         m << end; // the far end of the eWall
2095         m << tEnd; // the endTime
2096     }
2097     else{
2098         m << beg;
2099         m << tBeg;
2100     }
2101     m.Write(inGrid);
2102 
2103     if ( coords_.Len() > 2 || !coords_(0).IsDangerous || !coords_(1).IsDangerous )
2104     {
2105         unsigned short len = coords_.Len();
2106         m.Write( len );
2107         for ( int i = len-1; i>=0; --i )
2108         {
2109             const gPlayerWallCoord& coord = coords_(i);
2110             m << coord.IsDangerous;
2111             m << coord.Pos;
2112             m << coord.Time;
2113         }
2114     }
2115 }
2116 
SyncIsNew(nMessage & m)2117 bool gNetPlayerWall::SyncIsNew(nMessage &m)
2118 {
2119     //	return (nNetObject::SyncIsNew(m) && !inGrid);
2120     return nNetObject::SyncIsNew(m);
2121 }
2122 
2123 static bool sg_ServerSentHoles = false;
2124 
ReadSync(nMessage & m)2125 void gNetPlayerWall::ReadSync(nMessage &m){
2126     nNetObject::ReadSync(m);
2127 
2128     ClearDisplayList();
2129 
2130     REAL tEnd_new;
2131     eCoord end_new;
2132 
2133     m >> end_new;
2134     m >> tEnd_new;
2135 
2136     if ( tEnd_new < tBeg )
2137     {
2138         tEnd_new = tBeg;
2139     }
2140 
2141     unsigned short new_inGrid;
2142     m.Read(new_inGrid);
2143 
2144     if ( griddedid < 0 )
2145         CreateEdge();
2146 
2147     if ( ! m.End() )
2148     {
2149         unsigned short len;
2150         m.Read( len );
2151 
2152         coords_.SetLen( len );
2153 
2154         for ( int i = len-1; i>=0; --i )
2155         {
2156             gPlayerWallCoord& coord = coords_(i);
2157             m >> coord.IsDangerous;
2158             m >> coord.Pos;
2159             m >> coord.Time;
2160         }
2161 
2162         sg_ServerSentHoles = true;
2163     }
2164 
2165     real_Update(tEnd_new,end_new, true);
2166 
2167     if (Wall() && new_inGrid && !inGrid)
2168     {
2169         /*
2170         		if ( ( beg - end ).NormSquared() > 0.01f )
2171         		{
2172         			gExplosion::OnNewWall( Wall() );
2173         		}
2174         */
2175 
2176         CopyIntoGrid( NULL, true );
2177 
2178         if (!preliminary)
2179         {
2180             // inform preliminary walls
2181             for (int i=sg_netPlayerWalls.Len()-1;i>=0;i--)
2182             {
2183                 gNetPlayerWall *o=sg_netPlayerWalls[i];
2184                 if ( o != this && o->preliminary && o->cycle_ == this->cycle_ )
2185                 {
2186                     o->RealWallReceived( this );
2187                 }
2188             }
2189 
2190             // test whether this wall is newer than the last received wall in the cycle
2191             if ( ( 0 != this->cycle_ ) && ( !this->cycle_->lastNetWall || this->cycle_->lastNetWall->tBeg < this->tBeg ) )
2192             {
2193                 this->cycle_->lastNetWall = this;
2194             }
2195         }
2196     }
2197     else
2198     {
2199         //		st_Breakpoint();
2200     }
2201 
2202 #ifdef DEBUG
2203     if ( Wall() )
2204         Wall()->Check();
2205 #endif
2206 }
2207 
2208 static nNOInitialisator<gNetPlayerWall> gNetPlayerWall_init(300,"gNetPlayerWall");
2209 
CreatorDescriptor() const2210 nDescriptor &gNetPlayerWall::CreatorDescriptor() const
2211 {
2212     return gNetPlayerWall_init;
2213 }
2214 
PrintName(tString & s) const2215 void gNetPlayerWall::PrintName(tString &s) const
2216 {
2217     s << "gNetPlayerWall nr. " << id;
2218     if ( this->cycle_ )
2219     {
2220         s	<< " owned by ";
2221         this->cycle_->PrintName( s );
2222     }
2223 }
2224 
CycleMovement() const2225 gCycleMovement *gNetPlayerWall::CycleMovement() const {
2226     return cycle_;
2227 }
2228 
Clear()2229 void gNetPlayerWall::Clear()
2230 {
2231     //	if( nCLIENT == sn_GetNetState() )
2232     //	return;
2233 
2234     int i;
2235     for (i=sg_netPlayerWalls.Len()-1;i>=0;i--){
2236         // sg_netPlayerWalls(i)->owner=sn_myNetID;
2237         //delete sg_netPlayerWalls(i);
2238         gNetPlayerWall* w = sg_netPlayerWalls(i);
2239         tControlledPTR< nNetObject > bounce( w );
2240         w->ReleaseData();
2241 
2242         sg_netPlayerWalls.Remove( w, w->id );
2243 
2244         if ( w->edge_ )
2245             w->edge_->Wall()->Insert();
2246 
2247     }
2248     for (i=sg_netPlayerWallsGridded.Len()-1;i>=0;i--){
2249         // sg_netPlayerWallsGridded(i)->owner=sn_myNetID;
2250         gNetPlayerWall* w = sg_netPlayerWallsGridded(i);
2251         tControlledPTR< nNetObject > bounce( w );
2252         w->ReleaseData();
2253 
2254         sg_netPlayerWallsGridded.Remove( w, w->griddedid );
2255     }
2256 }
2257 
2258 
Check() const2259 void gNetPlayerWall::Check() const
2260 {
2261 #ifdef DEBUG
2262     int i;
2263     for ( i = coords_.Len() -2 ; i>=0; --i )
2264     {
2265         gPlayerWallCoord* coords = &( coords_( i ) );
2266         tASSERT( coords[0].Pos <= coords[1].Pos );
2267         tASSERT( coords[0].Time <= coords[1].Time );
2268     }
2269 
2270     for ( i = coords_.Len() -1 ; i>=0; --i )
2271     {
2272         gPlayerWallCoord* coords = &( coords_( i ) );
2273         tASSERT( finite( coords[0].Pos ) );
2274         tASSERT( finite( coords[0].Time ) );
2275     }
2276 #endif
2277 }
2278 
IndexPos(REAL d) const2279 int gNetPlayerWall::IndexPos(REAL d) const
2280 {
2281     CHECKWALL;
2282 
2283 
2284     // get the first coord with smaller alpha than a
2285     int i = coords_.Len() - 2;
2286     while ( i >= 1 && coords_(i).Pos >= d)
2287         --i;
2288 
2289 #ifdef DEBUG
2290     if (!( i >= 0 && i < coords_.Len() - 1 ))
2291     {
2292         st_Breakpoint();
2293     }
2294 #endif
2295 
2296     return i;
2297 }
2298 
IndexAlpha(REAL a) const2299 int gNetPlayerWall::IndexAlpha(REAL a) const
2300 {
2301     CHECKWALL;
2302 
2303     REAL d = Pos( a );
2304 
2305     return IndexPos( d );
2306 }
2307 
Time(REAL a) const2308 REAL gNetPlayerWall::Time(REAL a) const
2309 {
2310     tASSERT( good( a ) );
2311 
2312     CHECKWALL;
2313 
2314     const gPlayerWallCoord* coord = &coords_(IndexAlpha(a));
2315     REAL div = ( coord[1].Pos - coord[0].Pos );
2316     REAL alpha = 0.0f;
2317     if ( div > 0 )
2318     {
2319         alpha = ( Pos(a) - coord[0].Pos ) / div;
2320     }
2321 
2322     REAL ret = coord[0].Time + alpha*(coord[1].Time-coord[0].Time);
2323 
2324     tASSERT( good( ret ) );
2325 
2326     return ret;
2327 }
2328 
Pos(REAL a) const2329 REAL gNetPlayerWall::Pos(REAL a) const
2330 {
2331     CHECKWALL;
2332 
2333     tASSERT( good( a ) );
2334 
2335     REAL ret = BegPos() + a * ( EndPos()  - BegPos() );
2336 
2337     tASSERT( good( ret ) );
2338 
2339     return ret;
2340 }
2341 
Alpha(REAL pos) const2342 REAL gNetPlayerWall::Alpha(REAL pos) const
2343 {
2344     CHECKWALL;
2345 
2346     REAL diff = ( EndPos()  - BegPos() );
2347     REAL a = pos - BegPos();
2348 
2349     if ( diff > 0 )
2350         a /= diff;
2351 
2352     tASSERT ( -.001 < a );
2353     tASSERT ( 1.001 > a );
2354 
2355     return a;
2356 }
2357 
IsDangerousAnywhere(REAL time) const2358 bool gNetPlayerWall::IsDangerousAnywhere( REAL time ) const
2359 {
2360     CHECKWALL;
2361 
2362     if ( !cycle_ )
2363         return false;
2364 
2365     // is the player dead?
2366     if ( gCycle::WallsStayUpDelay() >= 0 )
2367     {
2368         if ( !cycle_->Alive() && time - cycle_->deathTime > .2f + gCycle::WallsStayUpDelay() )
2369             return false;
2370     }
2371 
2372     // is the wall behind the wall end?
2373     if ( gCycle::WallsLength() > 0 )
2374     {
2375         tASSERT( cycle_->MaxWallsLength() >= cycle_->ThisWallsLength() );
2376         REAL maxDist = cycle_->GetDistance() - cycle_->MaxWallsLength();
2377         if ( maxDist > EndPos()  && maxDist > BegPos() )
2378         {
2379             return false;
2380         }
2381     }
2382 
2383     return true;
2384 }
2385 
IsDangerousApartFromHoles(REAL a,REAL time) const2386 bool gNetPlayerWall::IsDangerousApartFromHoles( REAL a, REAL time ) const
2387 {
2388     CHECKWALL;
2389 
2390     // test for disappearing after death
2391     if ( gCycle::WallsStayUpDelay() >= 0.0f )
2392     {
2393         // walls disappeear after death
2394         if (!cycle_ || ( !cycle_->Alive() && cycle_->deathTime + gCycle::WallsStayUpDelay()+0.2f <= time ) )
2395             return false;
2396     }
2397 
2398     // the time from the last simulation to the time the query shall be made;
2399     // cycleDistance is valid at cycle_->lastTime, we need it at time.
2400     REAL dt = ( time - cycle_->lastTime );
2401 
2402     // the distance value at the spot we hit
2403     REAL wallDistance = Pos( a );
2404 
2405     // test for finite wall lenght
2406     if ( gCycle::WallsLength() > 0 )
2407     {
2408         // the distance the cycle traveled so far
2409         REAL cycleDistance = cycle_->GetDistance();
2410 
2411         // extrapolate it, taking rubber slowdown into account
2412         if ( cycle_->Alive() )
2413         {
2414             // cycle movement
2415             cycleDistance += cycle_->WallEndSpeed() * dt;
2416         }
2417 
2418         if ( wallDistance + cycle_->ThisWallsLength() < cycleDistance )
2419             return false;	// hit was after the wall length
2420     }
2421 
2422     // check whether it is an extrapolated bit
2423     {
2424         // the distance the cycle traveled so far
2425         REAL cycleDistance = cycle_->GetDistance();
2426 
2427         // extrapolate it if the test time lies in the cycle's future.
2428         if ( cycle_->Alive() && dt > 0 )
2429         {
2430             // cycle movement
2431             cycleDistance += cycle_->Speed() * cycle_->rubberSpeedFactor * dt;
2432         }
2433 
2434         // is the wall ahead of the cycle?
2435         if ( wallDistance > cycleDistance )
2436             return false;
2437     }
2438 
2439     return true;
2440 }
2441 
IsDangerous(REAL a,REAL time) const2442 bool gNetPlayerWall::IsDangerous( REAL a, REAL time ) const
2443 {
2444     CHECKWALL;
2445 
2446     if ( !IsDangerousApartFromHoles( a, time ) )
2447     {
2448         return false;
2449     }
2450 
2451     const gPlayerWallCoord* coord = &coords_(IndexAlpha(a));
2452     return coord->IsDangerous;
2453 }
2454 
2455 // returns the guy who holed here
Holer(REAL a,REAL time) const2456 gExplosion * gNetPlayerWall::Holer( REAL a, REAL time ) const
2457 {
2458     CHECKWALL;
2459 
2460     // it does not count as a hole if the wall has expired already
2461     // for other reasons
2462     if ( !IsDangerousApartFromHoles( a, time ) )
2463     {
2464         return NULL;
2465     }
2466 
2467     const gPlayerWallCoord* coord = &coords_(IndexAlpha(a));
2468     return coord->holer;
2469 }
2470 
EndPos() const2471 REAL gNetPlayerWall::EndPos() const
2472 {
2473     CHECKWALL;
2474 
2475     return coords_(coords_.Len()-1).Pos;
2476 }
2477 
BegPos() const2478 REAL gNetPlayerWall::BegPos() const
2479 {
2480     CHECKWALL;
2481 
2482     return coords_(0).Pos;
2483 }
2484 
EndTime() const2485 REAL gNetPlayerWall::EndTime() const
2486 {
2487     CHECKWALL;
2488 
2489     return coords_(coords_.Len()-1).Time;
2490 }
2491 
BegTime() const2492 REAL gNetPlayerWall::BegTime() const
2493 {
2494     CHECKWALL;
2495 
2496     return coords_(0).Time;
2497 }
2498 
BlowHole(REAL beg,REAL end,gExplosion * holer)2499 void gNetPlayerWall::BlowHole	( REAL beg, REAL end, gExplosion * holer )
2500 {
2501     CHECKWALL;
2502 
2503 #ifndef DEDICATED
2504     ClearDisplayList(60);
2505 #endif
2506 
2507 #ifdef DEBUG
2508     /*
2509     for ( int i = 0; i < coords_.Len(); ++i )
2510     {
2511         std::cout << "[" << coords_(i).IsDangerous << ',' << coords_(i).Pos << "]";
2512     }
2513 
2514     static int count=0;
2515     ++count;
2516 
2517     std::cout << " hole " << count << " : " << beg << ',' << end << '(' << BegPos() << ',' << EndPos() << ")\n";
2518     */
2519 #endif
2520 
2521     // don't touch anything if the server concluded it is his business
2522     if ( sn_GetNetState() != nSERVER && sg_ServerSentHoles && !preliminary )
2523     {
2524         return;
2525     }
2526 
2527 #ifdef DEBUG
2528     tASSERT (coords_.Len() < 1000 );
2529 #endif
2530 
2531     // find the last index that will stay before the hole:
2532     int begind = IndexPos( beg );
2533 
2534     // skip ahead if the holing would create redunant non-dangerous blocks
2535     while ( begind >= 1 && !coords_[begind].IsDangerous )
2536     {
2537         beg = coords_[begind].Pos;
2538         begind--;
2539     }
2540 
2541     // find the last index in the hole:
2542     int endind = IndexPos( end );
2543 
2544     // skip ahead if the holing would create redunant non-dangerous blocks
2545     while ( endind < coords_.Len() - 2 && !coords_[endind].IsDangerous )
2546     {
2547         endind++;
2548         end = coords_[endind].Pos;
2549     }
2550 
2551     if ( beg < BegPos() )
2552     {
2553         begind = -1;
2554 
2555         beg = BegPos();
2556     }
2557 
2558     if ( end > EndPos() )
2559     {
2560         if ( bool(cycle_) && ( EndPos() < cycle_->GetDistance()-10 || this != cycle_->currentWall ) )
2561             endind = coords_.Len() - 1;
2562 
2563         end = EndPos();
2564     }
2565 
2566     // out of range
2567     if ( end < beg )
2568     {
2569         return;
2570     }
2571 
2572     if ( sn_GetNetState() != nCLIENT )
2573     {
2574         this->RequestSync();
2575     }
2576 
2577     // find the alpha at the hole begin and end:
2578     REAL begalph = Alpha( beg );
2579     REAL endalph = Alpha( end );
2580 
2581     // find the time at the hole begin and end:
2582     REAL begtime = Time( begalph );
2583     REAL endtime = Time( endalph );
2584 
2585     int insert = begind + 2 - endind;
2586 
2587 #ifdef DEBUG
2588     tASSERT (insert < 40 );
2589 #endif
2590 
2591     // remove positions inside the hole:
2592     if ( insert < 0 )
2593     {
2594         for ( int i = begind+1; i - insert < coords_.Len(); ++i )
2595             coords_(i) = coords_( i - insert );
2596         coords_.SetLen( coords_.Len() + insert );
2597     }
2598 
2599     // make room for the new points of the hole:
2600     else if ( insert > 0 )
2601     {
2602         coords_.SetLen( coords_.Len() + insert );
2603 
2604         for ( int i = coords_.Len() - 1; i >= begind + insert && i >= insert ; --i )
2605             coords_( i ) = coords_( i - insert );
2606     }
2607 
2608     // clamp times
2609     {
2610         if ( begind >= 0 )
2611         {
2612             REAL beforetime = coords_(begind).Time;
2613             if ( begtime < beforetime )
2614             {
2615                 begtime = beforetime;
2616             }
2617         }
2618 
2619         if ( begind +3 < coords_.Len() )
2620         {
2621             REAL afttime = coords_(begind + 3).Time;
2622             if ( endtime > afttime )
2623             {
2624                 endtime = afttime;
2625             }
2626         }
2627     }
2628 
2629     // enter the hole
2630     coords_(begind+1).IsDangerous = false;
2631     coords_(begind+1).Time        = begtime;
2632     coords_(begind+1).holer       = holer;
2633     coords_(begind+1).Pos         = beg;
2634     coords_(begind+2).Time        = endtime;
2635     coords_(begind+2).Pos         = end;
2636 
2637 #ifdef DEBUG
2638     /*
2639     for ( int i = 0; i < coords_.Len(); ++i )
2640     {
2641         std::cout << "[" << coords_(i).IsDangerous << ',' << coords_(i).Pos << "]";
2642     }
2643     std::cout << "\n";
2644     */
2645 #endif
2646 
2647     CHECKWALL;
2648 }
2649 
login_callback()2650 static void login_callback(){
2651     sg_ServerSentHoles = false;
2652 }
2653 
2654 static nCallbackLoginLogout sg_LoginLogout(&login_callback);
2655 
2656 
2657