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