00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "rSDL.h"
00029
00030
00031 #ifndef ARMAGETRONAD_SRC_TRON_GCYCLEMOVEMENT_H_INCLUDED
00032 #include "gCycleMovement.h"
00033 #endif
00034
00035 #include "tMath.h"
00036
00037 #include "nConfig.h"
00038
00039 #include "ePlayer.h"
00040 #include "eDebugLine.h"
00041 #include "eGrid.h"
00042 #include "eLagCompensation.h"
00043 #include "eTeam.h"
00044
00045 #include "eTimer.h"
00046
00047 #include "gWall.h"
00048 #include "gSensor.h"
00049 #include "gAIBase.h"
00050
00051 #include "tRecorder.h"
00052
00053
00054
00055 #ifdef DEBUG_RUBBER
00056 #include <fstream>
00057 #endif
00058
00059 #undef INLINE_DEF
00060 #define INLINE_DEF
00061
00062 #ifndef DEDICATED
00063 #define MAXRUBBER 1
00064 #else
00065 #define MAXRUBBER 3
00066 #endif
00067
00068 #ifdef DEBUG
00069 #define DEBUGOUTPUT
00070 #endif
00071
00072 #ifdef DEBUGOUTPUT
00073 #include "tSysTime.h"
00074 static int sg_cycleDebugPrintLevel = 0;
00075 #endif
00076
00077
00078 void sg_RubberValues( ePlayerNetID const * player, REAL speed, REAL & max, REAL & effectiveness );
00079
00080
00081
00082 static void sg_ArchiveCoord( eCoord & coord, int level )
00083 {
00084 static char const * section = "_COORD";
00085 tRecorderSync< eCoord >::Archive( section, level, coord );
00086 }
00087
00088 static void sg_ArchiveReal( REAL & real, int level )
00089 {
00090 static char const * section = "_REAL";
00091 tRecorderSync< REAL >::Archive( section, level, real );
00092 }
00093
00094
00095
00096 static nVersionFeature sg_verletIntegration( 7 );
00097
00098
00099 REAL sg_brakeCycle=30;
00100 static nSettingItem<REAL> c_ab("CYCLE_BRAKE",
00101 sg_brakeCycle);
00102
00103 REAL sg_cycleBrakeRefill = 0.0;
00104 REAL sg_cycleBrakeDeplete = 0.0;
00105
00106
00107
00108 static nSettingItemWatched<REAL> sg_cycleBrakeRefillConf("CYCLE_BRAKE_REFILL",sg_cycleBrakeRefill, nConfItemVersionWatcher::Group_Annoying, 2 );
00109 static nSettingItemWatched<REAL> sg_cycleBrakeDepleteConf("CYCLE_BRAKE_DEPLETE",sg_cycleBrakeDeplete, nConfItemVersionWatcher::Group_Annoying, 2 );
00110
00111
00112
00113
00114
00115 REAL sg_cycleWidth = 0;
00116 static nSettingItemWatched<REAL> c_cw("CYCLE_WIDTH",
00117 sg_cycleWidth, nConfItemVersionWatcher::Group_Bumpy, 14 );
00118
00119 REAL sg_cycleWidthSide = 0;
00120 static nSettingItemWatched<REAL> c_cws("CYCLE_WIDTH_SIDE",
00121 sg_cycleWidthSide, nConfItemVersionWatcher::Group_Bumpy, 14 );
00122
00123 REAL sg_GetSparksDistance()
00124 {
00125 if ( sg_cycleWidth < 2 * sg_cycleWidthSide )
00126 return sg_cycleWidth;
00127 else if ( sg_cycleWidthSide > 0 )
00128 return sg_cycleWidthSide * 2;
00129 else
00130 return .25;
00131 }
00132
00133
00134
00135 REAL sg_cycleWidthRubberMin = 1;
00136 static nSettingItemWatched<REAL> c_cwrmax("CYCLE_WIDTH_RUBBER_MIN",
00137 sg_cycleWidthRubberMin, nConfItemVersionWatcher::Group_Bumpy, 14 );
00138
00139 REAL sg_cycleWidthRubberMax = 1;
00140 static nSettingItemWatched<REAL> c_cwrmin("CYCLE_WIDTH_RUBBER_MAX",
00141 sg_cycleWidthRubberMax, nConfItemVersionWatcher::Group_Bumpy, 14 );
00142
00143
00144 static REAL sg_speedCycle=10;
00145 static nSettingItem<REAL> c_s("CYCLE_SPEED",sg_speedCycle);
00146
00147
00148 static REAL sg_speedCycleMin=.25;
00149 static nSettingItemWatched<REAL> c_smin("CYCLE_SPEED_MIN",
00150 sg_speedCycleMin,
00151 nConfItemVersionWatcher::Group_Bumpy,
00152 9);
00153
00154
00155 static REAL sg_speedCycleMax=0;
00156 static nSettingItemWatched<REAL> c_smax("CYCLE_SPEED_MAX",
00157 sg_speedCycleMax,
00158 nConfItemVersionWatcher::Group_Bumpy,
00159 14);
00160
00161 REAL sg_speedCycleDecayBelow = 5;
00162 static nSettingItemWatched<REAL> c_sdb("CYCLE_SPEED_DECAY_BELOW",
00163 sg_speedCycleDecayBelow,
00164 nConfItemVersionWatcher::Group_Bumpy,
00165 8);
00166
00167 REAL sg_speedCycleDecayAbove = .1;
00168 static nSettingItemWatched<REAL> c_sda("CYCLE_SPEED_DECAY_ABOVE",
00169 sg_speedCycleDecayAbove,
00170 nConfItemVersionWatcher::Group_Bumpy,
00171 8);
00172
00173
00174 static REAL sg_speedCycleStart=20;
00175 static tSettingItem<REAL> c_st("CYCLE_START_SPEED",
00176 sg_speedCycleStart);
00177
00178
00179 REAL sg_delayCycle = .1;
00180 static nSettingItem<REAL> c_d("CYCLE_DELAY",
00181 sg_delayCycle);
00182
00183 REAL sg_delayCycleDoublebindBonus = 1.;
00184 static nSettingItemWatched<REAL> c_d_d_b("CYCLE_DELAY_DOUBLEBIND_BONUS",
00185 sg_delayCycleDoublebindBonus, nConfItemVersionWatcher::Group_Bumpy, 14 );
00186
00187
00188 int sg_cycleTurnMemory = 3;
00189 static tSettingItem<int> c_tm("CYCLE_TURN_MEMORY",
00190 sg_cycleTurnMemory);
00191
00192 REAL sg_delayCycleTimeBased = 1;
00193 static nSettingItemWatched<REAL> c_dt("CYCLE_DELAY_TIMEBASED",
00194 sg_delayCycleTimeBased,
00195 nConfItemVersionWatcher::Group_Bumpy,
00196 7);
00197
00198
00199 #ifdef DEDICATED
00200 REAL sg_delayCycleBonus=.95;
00201 static tSettingItem<REAL> c_db("CYCLE_DELAY_BONUS",
00202 sg_delayCycleBonus);
00203 #else
00204 REAL sg_delayCycleBonus=1;
00205 #endif
00206
00207 REAL sg_cycleTurnSpeedFactor=.95;
00208 static nSettingItemWatched<REAL> c_ctf("CYCLE_TURN_SPEED_FACTOR",
00209 sg_cycleTurnSpeedFactor,
00210 nConfItemVersionWatcher::Group_Bumpy,
00211 7);
00212
00213
00214 static REAL sg_accelerationCycle=10;
00215 static nSettingItem<REAL> c_a("CYCLE_ACCEL",
00216 sg_accelerationCycle);
00217
00218
00219 REAL sg_accelerationCycleSelf = 1;
00220 static nSettingItemWatched<REAL> c_aco("CYCLE_ACCEL_SELF",
00221 sg_accelerationCycleSelf,
00222 nConfItemVersionWatcher::Group_Bumpy,
00223 8);
00224
00225 REAL sg_accelerationCycleTeam = 1;
00226 static nSettingItemWatched<REAL> c_act("CYCLE_ACCEL_TEAM",
00227 sg_accelerationCycleTeam,
00228 nConfItemVersionWatcher::Group_Bumpy,
00229 14);
00230
00231 REAL sg_accelerationCycleEnemy = 1;
00232 static nSettingItemWatched<REAL> c_ace("CYCLE_ACCEL_ENEMY",
00233 sg_accelerationCycleEnemy,
00234 nConfItemVersionWatcher::Group_Bumpy,
00235 14);
00236
00237 REAL sg_accelerationCycleRim = 0;
00238 static nSettingItemWatched<REAL> c_acr("CYCLE_ACCEL_RIM",
00239 sg_accelerationCycleRim,
00240 nConfItemVersionWatcher::Group_Bumpy,
00241 8);
00242
00243 REAL sg_accelerationCycleSlingshot = 1;
00244 static nSettingItemWatched<REAL> c_acs("CYCLE_ACCEL_SLINGSHOT",
00245 sg_accelerationCycleSlingshot,
00246 nConfItemVersionWatcher::Group_Bumpy,
00247 8);
00248
00249 REAL sg_accelerationCycleTunnel = 1;
00250 static nSettingItemWatched<REAL> c_acu("CYCLE_ACCEL_TUNNEL",
00251 sg_accelerationCycleTunnel,
00252 nConfItemVersionWatcher::Group_Bumpy,
00253 14);
00254
00255
00256 static REAL sg_accelerationCycleOffs=2;
00257 static nSettingItem<REAL> c_ao("CYCLE_ACCEL_OFFSET",
00258 sg_accelerationCycleOffs);
00259
00260
00261
00262 static REAL sg_nearCycle=6;
00263 static nSettingItem<REAL> c_n("CYCLE_WALL_NEAR",
00264 sg_nearCycle);
00265
00266
00267 REAL sg_boostCycleSelf = 0;
00268 static nSettingItemWatched<REAL> c_bco("CYCLE_BOOST_SELF",
00269 sg_boostCycleSelf,
00270 nConfItemVersionWatcher::Group_Bumpy,
00271 14);
00272
00273 REAL sg_boostCycleTeam = 0;
00274 static nSettingItemWatched<REAL> c_bct("CYCLE_BOOST_TEAM",
00275 sg_boostCycleTeam,
00276 nConfItemVersionWatcher::Group_Bumpy,
00277 14);
00278
00279 REAL sg_boostCycleEnemy = 0;
00280 static nSettingItemWatched<REAL> c_bce("CYCLE_BOOST_ENEMY",
00281 sg_boostCycleEnemy,
00282 nConfItemVersionWatcher::Group_Bumpy,
00283 14);
00284
00285 REAL sg_boostCycleRim = 0;
00286 static nSettingItemWatched<REAL> c_bcr("CYCLE_BOOST_RIM",
00287 sg_boostCycleRim,
00288 nConfItemVersionWatcher::Group_Bumpy,
00289 14);
00290
00291
00292 REAL sg_boostFactorCycleSelf = 1;
00293 static nSettingItemWatched<REAL> c_bfco("CYCLE_BOOSTFACTOR_SELF",
00294 sg_boostFactorCycleSelf,
00295 nConfItemVersionWatcher::Group_Bumpy,
00296 14);
00297
00298 REAL sg_boostFactorCycleTeam = 1;
00299 static nSettingItemWatched<REAL> c_bfct("CYCLE_BOOSTFACTOR_TEAM",
00300 sg_boostFactorCycleTeam,
00301 nConfItemVersionWatcher::Group_Bumpy,
00302 14);
00303
00304 REAL sg_boostFactorCycleEnemy = 1;
00305 static nSettingItemWatched<REAL> c_bfce("CYCLE_BOOSTFACTOR_ENEMY",
00306 sg_boostFactorCycleEnemy,
00307 nConfItemVersionWatcher::Group_Bumpy,
00308 14);
00309
00310 REAL sg_boostFactorCycleRim = 1;
00311 static nSettingItemWatched<REAL> c_bfcr("CYCLE_BOOSTFACTOR_RIM",
00312 sg_boostFactorCycleRim,
00313 nConfItemVersionWatcher::Group_Bumpy,
00314 14);
00315
00316
00317 static REAL sg_packetLossTolerance = 0;
00318 static tSettingItem<REAL> conf_packetLossTolerance ("CYCLE_PACKETLOSS_TOLERANCE", sg_packetLossTolerance);
00319
00320
00321 static REAL sg_packetMissTolerance = 3;
00322 static tSettingItem<REAL> conf_packetMissTolerance ("CYCLE_PACKETMISS_TOLERANCE", sg_packetMissTolerance);
00323
00324
00325 REAL sg_rubberCycle=MAXRUBBER;
00326 static nSettingItem<REAL> c_r("CYCLE_RUBBER",
00327 sg_rubberCycle);
00328
00329 REAL sg_rubberCycleTimeBased = 0;
00330 static nSettingItemWatched<REAL> c_rtb("CYCLE_RUBBER_TIMEBASED",
00331 sg_rubberCycleTimeBased,
00332 nConfItemVersionWatcher::Group_Visual,
00333 7);
00334
00335
00336 bool sg_rubberCycleLegacy=true;
00337 static nSettingItem<bool> c_rl("CYCLE_RUBBER_LEGACY",
00338 sg_rubberCycleLegacy);
00339
00340
00341 static REAL sg_rubberCyclePing=3;
00342 static nSettingItem<REAL> c_rp("CYCLE_PING_RUBBER",
00343 sg_rubberCyclePing);
00344
00345
00346 REAL sg_rubberCycleTime=10;
00347 static nSettingItemWatched<REAL> c_rt("CYCLE_RUBBER_TIME",
00348 sg_rubberCycleTime,
00349 nConfItemVersionWatcher::Group_Visual,
00350 7);
00351
00352
00353 static REAL sg_rubberCycleSpeed=40;
00354 static nSettingItemWatched<REAL> c_rs("CYCLE_RUBBER_SPEED",
00355 sg_rubberCycleSpeed,
00356 nConfItemVersionWatcher::Group_Cheating,
00357 4);
00358
00359 #ifdef DEDICATED
00360 #define MINDISTANCE_FACTOR 1
00361 #else
00362 #define MINDISTANCE_FACTOR 0
00363 #endif
00364
00365
00366 static REAL sg_rubberCycleMinDistance=.001 * MINDISTANCE_FACTOR;
00367 static nSettingItemWatched<REAL> c_rmd("CYCLE_RUBBER_MINDISTANCE",
00368 sg_rubberCycleMinDistance,
00369 nConfItemVersionWatcher::Group_Annoying,
00370 4);
00371
00372
00373 static REAL sg_rubberCycleMinDistanceRatio=.0001 * MINDISTANCE_FACTOR;
00374 static nSettingItemWatched<REAL> c_rmdr("CYCLE_RUBBER_MINDISTANCE_RATIO",
00375 sg_rubberCycleMinDistanceRatio,
00376 nConfItemVersionWatcher::Group_Annoying,
00377 4);
00378
00379
00380 static REAL sg_rubberCycleMinDistanceReservoir=0.005 * MINDISTANCE_FACTOR;
00381 static nSettingItemWatched<REAL> c_rmdres("CYCLE_RUBBER_MINDISTANCE_RESERVOIR",
00382 sg_rubberCycleMinDistanceReservoir,
00383 nConfItemVersionWatcher::Group_Annoying,
00384 7);
00385
00386
00387 static REAL sg_rubberCycleMinDistanceUnprepared=0.005 * MINDISTANCE_FACTOR;
00388 static nSettingItemWatched<REAL> c_rmdup("CYCLE_RUBBER_MINDISTANCE_UNPREPARED",
00389 sg_rubberCycleMinDistanceUnprepared ,
00390 nConfItemVersionWatcher::Group_Annoying,
00391 7);
00392
00393
00394 static REAL sg_rubberCycleMinDistancePreparation=0.2;
00395 static nSettingItemWatched<REAL> c_rmdp("CYCLE_RUBBER_MINDISTANCE_PREPARATION",
00396 sg_rubberCycleMinDistancePreparation,
00397 nConfItemVersionWatcher::Group_Annoying,
00398 7);
00399
00400
00401
00402 static REAL sg_rubberCycleMinDistanceLegacy=1;
00403 static nSettingItem<REAL> c_rmdl("CYCLE_RUBBER_MINDISTANCE_LEGACY",
00404 sg_rubberCycleMinDistanceLegacy);
00405
00406
00407 static nVersionFeature sg_nonRippable(4);
00408
00409
00410 static REAL sg_rubberCycleMinAdjust=.05;
00411 static nSettingItemWatched<REAL> c_rma("CYCLE_RUBBER_MINADJUST",
00412 sg_rubberCycleMinAdjust,
00413 nConfItemVersionWatcher::Group_Annoying,
00414 4);
00415
00416
00417 static REAL sg_rubberCycleDelay=0;
00418 static nSettingItemWatched<REAL> c_rcd("CYCLE_RUBBER_DELAY",
00419 sg_rubberCycleDelay,
00420 nConfItemVersionWatcher::Group_Visual,
00421 6);
00422
00423
00424 static REAL sg_rubberCycleDelayBonus=.5;
00425 static nSettingItemWatched<REAL> c_rcdb("CYCLE_RUBBER_DELAY_BONUS",
00426 sg_rubberCycleDelayBonus,
00427 nConfItemVersionWatcher::Group_Visual,
00428 6);
00429
00430
00431 static REAL sg_rubberCycleMalusTurn=0;
00432 static nSettingItemWatched<REAL> c_rctm("CYCLE_RUBBER_MALUS_TURN",
00433 sg_rubberCycleMalusTurn,
00434 nConfItemVersionWatcher::Group_Visual,
00435 6);
00436
00437
00438 static REAL sg_rubberCycleMalusTime=5;
00439 static nSettingItem<REAL> c_rcmd("CYCLE_RUBBER_MALUS_TIME",
00440 sg_rubberCycleMalusTime);
00441
00442
00443 static REAL sg_timeTolerance=.1;
00444 static nSettingItemWatched<REAL> c_tt( "CYCLE_TIME_TOLERANCE",
00445 sg_timeTolerance,
00446 nConfItemVersionWatcher::Group_Visual,
00447 6 );
00448
00449 static int sg_cycleMaxRefCount = 30000;
00450 static tSettingItem<int> conf_sgCycleMaxRefCount ("CYCLE_MAX_REFCOUNT", sg_cycleMaxRefCount );
00451
00452 static void blocks(const gSensor &s, const gCycleMovement *c, int lr)
00453 {
00454 if ( nCLIENT == sn_GetNetState() )
00455 return;
00456
00457 if (s.type == gSENSOR_RIM)
00458 gAIPlayer::CycleBlocksRim(c, lr);
00459 else if (s.type == gSENSOR_TEAMMATE || s.type == gSENSOR_ENEMY && s.ehit)
00460 {
00461 gPlayerWall *w = dynamic_cast<gPlayerWall*>(s.ehit->GetWall());
00462 if (w)
00463 {
00464
00465
00466
00467
00468 int windingBefore = c->WindingNumber();
00469
00470
00471
00472
00473
00474 int windingAfter = w->WindingNumber();
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490 if (((windingBefore - windingAfter) & 1) == 0)
00491 gAIPlayer::CycleBlocksWay(c, w->Cycle(),
00492 lr, s.lr,
00493 w->Pos(s.ehit->Ratio(s.before_hit)),
00494 - windingAfter + windingBefore);
00495 }
00496 }
00497 }
00498
00499
00500 static REAL sg_enemyFriendTimePenalty = 2500.0f;
00501
00502 static REAL sg_enemyDeadTimePenalty = 0.0f;
00503 REAL sg_suicideTimeout = 10000.0f;
00504 static REAL sg_enemyCurrentTimeInfluence = 0.0f;
00505
00506 static tSettingItem<REAL> sg_enemyFriendTimePenaltyConf( "ENEMY_TEAMMATE_PENALTY", sg_enemyFriendTimePenalty );
00507 static tSettingItem<REAL> sg_enemyDeadTimePenaltyConf( "ENEMY_DEAD_PENALTY", sg_enemyDeadTimePenalty );
00508 static tSettingItem<REAL> sg_suicideTimeoutConf( "ENEMY_SUICIDE_TIMEOUT", sg_suicideTimeout );
00509 static tSettingItem<REAL> sg_enemyCurrentTimeInfluenceConf( "ENEMY_CURRENTTIME_INFLUENCE", sg_enemyCurrentTimeInfluence );
00510
00511
00512 const ePlayerNetID* gEnemyInfluence::GetEnemy() const
00513 {
00514 return lastEnemyInfluence.GetPointer();
00515 }
00516
00517 REAL gEnemyInfluence::GetTime() const
00518 {
00519 return lastTime;
00520 }
00521
00522 gEnemyInfluence::gEnemyInfluence()
00523 {
00524 lastTime = -sg_suicideTimeout;
00525 }
00526
00527
00528 void gEnemyInfluence::AddSensor( const gSensor& sensor, REAL timePenalty, gCycleMovement * thisCycle )
00529 {
00530
00531 if ( sn_GetNetState() == nCLIENT )
00532 return;
00533
00534
00535
00536
00537
00538
00539 if ( !sensor.ehit )
00540 return;
00541
00542 eWall* wall = sensor.ehit->GetWall();
00543 if ( !wall )
00544 return;
00545
00546 AddWall( wall, sensor.before_hit, timePenalty, thisCycle );
00547 }
00548
00549
00550 void gEnemyInfluence::AddWall( const eWall * wall, eCoord const & pos, REAL timePenalty, gCycleMovement * thisCycle )
00551 {
00552
00553 if ( sn_GetNetState() == nCLIENT )
00554 return;
00555
00556
00557 gPlayerWall const * playerWall = dynamic_cast<gPlayerWall const *>( wall );
00558 if ( !playerWall )
00559 return;
00560
00561
00562 REAL alpha = .5f;
00563
00564 if ( playerWall->Edge() )
00565 {
00566
00567 alpha = playerWall->Edge()->Ratio( pos );
00568 }
00569 REAL timeBuilt = playerWall->Time( 0.5f );
00570
00571 AddWall( playerWall, timeBuilt - timePenalty, thisCycle );
00572 }
00573
00574
00575 void gEnemyInfluence::AddWall( const gPlayerWall * wall, REAL timeBuilt, gCycleMovement * thisCycle )
00576 {
00577
00578 if ( sn_GetNetState() == nCLIENT )
00579 return;
00580
00581 if ( !wall )
00582 return;
00583
00584
00585 gCycle *cycle = wall->Cycle();
00586 if ( !cycle )
00587 return;
00588
00589
00590 if ( thisCycle == cycle )
00591 return;
00592
00593 REAL time = timeBuilt;
00594 if ( thisCycle )
00595 {
00596 REAL currentTime = thisCycle->LastTime();
00597 time += ( currentTime - time ) * sg_enemyCurrentTimeInfluence;
00598 }
00599
00600
00601 ePlayerNetID* player = cycle->Player();
00602 if ( !player )
00603 return;
00604
00605
00606 if ( thisCycle && !ePlayerNetID::Enemies( thisCycle->Player(), player ) )
00607 {
00608 return;
00609 }
00610
00611
00612 if ( thisCycle->Player() && player->CurrentTeam() == thisCycle->Player()->CurrentTeam() )
00613 {
00614
00615
00616 if ( time > cycle->GetLastTurnTime() )
00617 time = cycle->GetLastTurnTime();
00618 time -= sg_enemyFriendTimePenalty;
00619 }
00620 const ePlayerNetID* pInfluence = this->lastEnemyInfluence.GetPointer();
00621
00622
00623 REAL lastEffectiveTime = lastTime;
00624 if ( !pInfluence || !pInfluence->Object() || !pInfluence->Object()->Alive() )
00625 {
00626 lastEffectiveTime -= sg_enemyDeadTimePenalty;
00627 }
00628
00629
00630 REAL effectiveTime = time;
00631 if ( !cycle->Alive() )
00632 {
00633 effectiveTime -= sg_enemyDeadTimePenalty;
00634 }
00635
00636
00637 if ( effectiveTime > lastEffectiveTime || !bool(lastEnemyInfluence) )
00638 {
00639 lastEnemyInfluence = player;
00640 lastTime = time;
00641 }
00642 }
00643
00644
00645
00646
00647
00648
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661
00662
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675
00676
00677
00678
00683
00684
00685 gCycleMovement & gCycleMovement::operator= ( gCycleMovement const & other )
00686 {
00687 this->CopyFrom( other );
00688 return *this;
00689 }
00690
00691
00692
00693
00694
00695
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709
00712
00713
00714
00715
00716
00717
00718
00719
00720
00721 static float sg_speedMultiplier = 1.0f;
00722 static nSettingItem<float> conf_mult ("REAL_CYCLE_SPEED_FACTOR", sg_speedMultiplier);
00723
00724
00725
00726
00727
00728
00732
00733
00734 float gCycleMovement::RubberSpeed()
00735 {
00736 return sg_rubberCycleSpeed;
00737 }
00738
00739
00740
00741
00742
00743
00747
00748
00749 float gCycleMovement::SpeedMultiplier( void )
00750 {
00751 return sg_speedMultiplier;
00752 }
00753
00754
00755
00756
00757
00758
00762
00763
00764 void gCycleMovement::SetSpeedMultiplier( REAL mul )
00765 {
00766 conf_mult.Set( mul );
00767 }
00768
00769
00770 static REAL sg_MaxSpeed( REAL maxAcceleration )
00771 {
00772 if ( sg_speedCycleDecayAbove > 0 )
00773 return sg_speedCycle + maxAcceleration / sg_speedCycleDecayAbove;
00774 else
00775 return sg_speedCycle * 100;
00776 }
00777
00778
00779
00780
00781
00782
00786
00787
00788 float gCycleMovement::MaximalSpeed( void )
00789 {
00790
00791 REAL maxWallAcceleration = 0;
00792 REAL wallAcceleration = sg_accelerationCycleTeam * sg_accelerationCycle;
00793 if ( wallAcceleration > maxWallAcceleration )
00794 maxWallAcceleration = wallAcceleration;
00795 wallAcceleration = sg_accelerationCycleEnemy * sg_accelerationCycle;
00796 if ( wallAcceleration > maxWallAcceleration )
00797 maxWallAcceleration = wallAcceleration;
00798 wallAcceleration = sg_accelerationCycleRim * sg_accelerationCycle;
00799 if ( wallAcceleration > maxWallAcceleration )
00800 maxWallAcceleration = wallAcceleration;
00801
00802
00803 REAL wallAccelerationSelf = sg_accelerationCycleSelf * sg_accelerationCycle;
00804
00805 {
00806
00807 REAL wallAccelerationSingle = maxWallAcceleration;
00808 if ( wallAccelerationSingle < wallAccelerationSelf )
00809 wallAccelerationSingle = wallAccelerationSelf;
00810
00811
00812 REAL wallAccelerationSlingshot = ( wallAccelerationSingle + wallAccelerationSelf ) * sg_accelerationCycleSlingshot;
00813
00814
00815 REAL wallAccelerationTunnel = ( maxWallAcceleration ) * sg_accelerationCycleTunnel;
00816
00817
00818
00819 if ( maxWallAcceleration < wallAccelerationSlingshot )
00820 maxWallAcceleration = wallAccelerationSlingshot;
00821 if ( maxWallAcceleration < wallAccelerationTunnel )
00822 maxWallAcceleration = wallAccelerationTunnel;
00823 }
00824
00825
00826 maxWallAcceleration *= ( 1/sg_accelerationCycleOffs - 1/(sg_accelerationCycleOffs+sg_nearCycle ) );
00827
00828
00829 REAL maxSpeed = sg_MaxSpeed( maxWallAcceleration );
00830
00831
00832 if ( sg_brakeCycle < 0 )
00833 {
00834
00835 REAL maxSpeedBoost = sg_MaxSpeed( maxWallAcceleration - sg_brakeCycle );
00836
00837
00838 REAL efficiency = 1;
00839 if ( sg_cycleBrakeRefill + sg_cycleBrakeDeplete > 0 )
00840 efficiency = sg_cycleBrakeRefill/(sg_cycleBrakeRefill + sg_cycleBrakeDeplete);
00841
00842
00843 REAL maxSpeedPermanent = sg_MaxSpeed( maxWallAcceleration - sg_brakeCycle*efficiency );
00844
00845
00846
00847 if ( sg_cycleBrakeDeplete > 0 )
00848 {
00849 REAL boostTime = 1/sg_cycleBrakeDeplete;
00850 REAL maxSpeedBoost2 = maxSpeedPermanent - boostTime * sg_brakeCycle;
00851 if ( maxSpeedBoost2 < maxSpeedBoost )
00852 maxSpeedBoost = maxSpeedBoost2;
00853 }
00854
00855
00856 maxSpeed = maxSpeedBoost;
00857 }
00858
00859
00860 if ( sg_speedCycleStart > maxSpeed )
00861 maxSpeed = sg_speedCycleStart;
00862
00863
00864 return sg_speedMultiplier * maxSpeed;
00865 }
00866
00867
00868
00869
00870
00871
00872
00873
00877
00878
00879 int gCycleMovement::WindingNumber( void ) const
00880 {
00881 return windingNumber_;
00882 }
00883
00884
00885
00886
00887
00888
00892
00893
00894 void gCycleMovement::SetWindingNumberWrapped ( int newWindingNumberWrapped )
00895 {
00896
00897 int difference = newWindingNumberWrapped - windingNumberWrapped_;
00898
00899
00900 if (2 * difference <= -Grid()->WindingNumber())
00901 difference += Grid()->WindingNumber();
00902 if (2 * difference >= Grid()->WindingNumber())
00903 difference -= Grid()->WindingNumber();
00904
00905
00906 windingNumberWrapped_ = newWindingNumberWrapped;
00907 windingNumber_ += difference;
00908 }
00909
00910
00911
00912
00913
00914
00918
00919
00920 eCoord gCycleMovement::Direction( void ) const
00921 {
00922 return dirDrive;
00923 }
00924
00926
00927 eCoord gCycleMovement::SpawnDirection() const {
00928 return dirSpawn;
00929 }
00930
00931
00932
00933
00934
00935
00939
00940
00941 eCoord gCycleMovement::LastDirection( void ) const
00942 {
00943 return lastDirDrive;
00944 }
00945
00946
00947
00948
00949
00950
00954
00955
00956 REAL gCycleMovement::Speed( void ) const
00957 {
00958 REAL ret = verletSpeed_ + .5f * lastTimestep_ * acceleration;
00959 return ret > 0 ? ret : 0;
00960 }
00961
00962
00963
00964
00965
00966
00970
00971
00972 bool gCycleMovement::Alive() const
00973 {
00974 return alive_ > 0;
00975 }
00976
00977
00978
00979
00980
00981
00985
00986
00987 bool gCycleMovement::Vulnerable() const
00988 {
00989 return true;
00990 }
00991
00992
00993
00994
00995
00996
01001
01002
01003 bool gCycleMovement::CanMakeTurn( int direction ) const
01004 {
01005 return pendingTurns.empty() && CanMakeTurn( lastTime, direction );
01006 }
01007
01008
01009
01010
01011
01012
01018
01019
01020 bool gCycleMovement::CanMakeTurn( REAL time, int direction ) const
01021 {
01022 return time >= GetNextTurn(direction);
01023 }
01024
01025
01026
01027
01028
01029
01033
01034
01035 REAL gCycleMovement::GetTurnDelay( void ) const
01036 {
01037
01038 REAL baseDelay = sg_delayCycle*sg_delayCycleBonus/SpeedMultiplier();
01039
01040
01041 REAL speedFactor = verletSpeed_/(sg_speedCycle*SpeedMultiplier());
01042
01043 return baseDelay * pow( speedFactor, sg_delayCycleTimeBased-1 );
01044 }
01045
01047 REAL gCycleMovement::GetTurnDelayDb( void ) const
01048 {
01049
01050 REAL baseDelay = sg_delayCycle*sg_delayCycleBonus/SpeedMultiplier()*sg_delayCycleDoublebindBonus;
01051
01052
01053 REAL speedFactor = verletSpeed_/(sg_speedCycle*SpeedMultiplier());
01054
01055 return baseDelay * pow( speedFactor, sg_delayCycleTimeBased-1 );
01056 }
01057
01058
01059
01060
01061
01062
01066
01067
01068 REAL gCycleMovement::GetNextTurn( int direction ) const
01069 {
01070 float right,left;
01071 #ifdef DEBUG_X
01072 std::cerr << "GetNextTurn: " << direction << std::endl;
01073 #endif
01074 if(direction == 1) {
01075 right = lastTurnTimeRight_ + GetTurnDelayDb();
01076 left = lastTurnTimeLeft_ + GetTurnDelay();
01077 } else {
01078 right = lastTurnTimeLeft_ + GetTurnDelayDb();
01079 left = lastTurnTimeRight_ + GetTurnDelay();
01080 }
01081 #ifdef DEBUG_X
01082 std::cerr << "GetTurnDelay: " << GetTurnDelay() << std::endl;
01083 std::cerr << "GetTurnDelayDb: " << GetTurnDelayDb() << std::endl;
01084 std::cerr << "lastTurnTimeRight_: " << lastTurnTimeRight_ << std::endl;
01085 std::cerr << "lastTurnTimeLeft_: " << lastTurnTimeLeft_ << std::endl;
01086 std::cerr << "right: " << right << std::endl;
01087 std::cerr << "left: " << left << std::endl;
01088 #endif
01089 return left > right ? left : right;
01090 }
01091
01092
01093
01094
01095
01096
01099
01100
01101 void gCycleMovement::AddDestination( void )
01102 {
01103 if ( sn_GetNetState() == nCLIENT )
01104 {
01105 gDestination* dest = tNEW(gDestination)(*this);
01106
01107 AddDestination( dest );
01108 }
01109 }
01110
01111
01112
01113
01114
01115
01119
01120
01121 void gCycleMovement::AddDestination( gDestination * dest )
01122 {
01123
01124
01125
01126 dest->InsertIntoList(&destinationList);
01127
01128
01129 if (dest->next && dest->next->hasBeenUsed){
01130 delete dest;
01131 return;
01132 }
01133
01134 this->NotifyNewDestination( dest );
01135
01136
01137 dest->InsertIntoList(&destinationList);
01138 }
01139
01140
01141
01142
01143
01144
01148
01149
01150 gDestination * gCycleMovement::GetCurrentDestination( void ) const
01151 {
01152 return currentDestination;
01153 }
01154
01155
01156
01157
01158
01159
01162
01163
01164 void gCycleMovement::AdvanceDestination( void )
01165 {
01166
01167 tASSERT(0);
01168 }
01169
01170
01171
01172
01173
01174
01178
01179
01180 void gCycleMovement::NotifyNewDestination( gDestination * dest )
01181 {
01182 this->OnNotifyNewDestination( dest );
01183 }
01184
01185
01186
01187
01188
01189
01194
01195
01196 bool gCycleMovement::DoIsDestinationUsed( const gDestination * dest ) const
01197 {
01198 return ( destinationList == currentDestination || destinationList == lastDestination );
01199 }
01200
01201
01202
01203
01204
01205
01210
01211
01212 REAL gCycleMovement::DistanceToDestination( gDestination & dest ) const
01213 {
01214
01215 eCoord dirTurned = dest.direction;
01216
01217 REAL divisor = ( dirDrive * dirTurned );
01218 if ( divisor < EPS && divisor > -EPS )
01219 {
01220 REAL F = eCoord::F( dirTurned, dirDrive );
01221 if ( F > 0 )
01222 {
01223
01224
01225
01226
01227 if ( ( braking != 0 ) != dest.braking )
01228 {
01229 return eCoord::F( dest.position - pos, dirDrive )/dirDrive.NormSquared();
01230 }
01231
01232
01233 int side = (dest.position - pos) * dirDrive > 0 ? -1 : 1;
01234
01235
01236 int w = windingNumberWrapped_;
01237 Grid()->Turn(w, side);
01238 dirTurned = Grid()->GetDirection( w );
01239
01240
01241 divisor = ( dirDrive * dirTurned );
01242 tASSERT( fabs( divisor ) > EPS );
01243 }
01244 else
01245 {
01246
01247
01248 return eCoord::F( dest.position - pos, dirDrive )/dirDrive.NormSquared();
01249 }
01250 }
01251
01252
01253
01254 return ( ( dest.position - pos ) * dirTurned ) / divisor;
01255 }
01256
01257
01258
01259
01260
01261
01265
01266
01267 void gCycleMovement::OnNotifyNewDestination( gDestination * dest )
01268 {
01269
01270 if ((!currentDestination || currentDestination == dest->next ) &&
01271 sn_GetNetState()!=nSTANDALONE && ( Owner() != ::sn_myNetID || !destinationList ) )
01272 {
01273 currentDestination=dest;
01274
01275 }
01276 }
01277
01278
01279
01280
01281
01282
01288
01289
01290 void gCycleMovement::OnDropTempWall( gPlayerWall * wall, eCoord const & pos, eCoord const & dir )
01291 {
01292 }
01293
01294
01295
01296
01297
01298
01304
01305
01306 gDestination * gCycleMovement::GetDestinationBefore( const SyncData & sync, gDestination * first )
01307 {
01308
01309 if ( sync.messageID != 1 )
01310 {
01311 gDestination * ret = first;
01312
01313
01314 while ( ret && ret->messageID != sync.messageID )
01315 ret = ret->next;
01316
01317
01318 return ret;
01319 }
01320 else
01321 {
01322
01323 REAL syncLastTurnDistance = sync.distance - ( sync.pos - sync.lastTurn ).Norm();
01324
01325
01326 gDestination * run = first;
01327 gDestination * bestMatch = NULL;
01328 REAL bestMatchDistance = 1E+20;
01329 bool braking = false;
01330 while ( run )
01331 {
01332
01333 REAL distanceBefore = syncLastTurnDistance - run->distance;
01334 REAL distanceAfter = run->distance - sync.distance;
01335
01336
01337
01338
01339
01340 REAL distance = distanceBefore < distanceAfter ? distanceBefore : distanceAfter;
01341
01342
01343 if ( distance < 0 && ( run->braking || sync.braking ) )
01344 {
01345
01346 if ( !braking )
01347 bestMatchDistance += 1;
01348 braking = true;
01349 }
01350
01351
01352
01353 if ( distance < 0 )
01354 distance = 0;
01355
01356
01357 if ( braking )
01358 {
01359 distance += fabs( distanceAfter + .01 * distanceBefore ) * .0001;
01360 }
01361 else
01362 {
01363 distance += fabs( distanceBefore ) * .1;
01364 }
01365
01366
01367 if ( eCoord::F( run->direction, sync.dir ) > .9*sync.dir.NormSquared() && run->braking == ( sync.braking != 0 ) )
01368 {
01369 if ( !bestMatch || distance < bestMatchDistance )
01370 {
01371 bestMatch = run;
01372 bestMatchDistance = distance;
01373 }
01374 }
01375 run = run->next;
01376 }
01377
01378
01379
01380
01381 return bestMatch;
01382 }
01383 }
01384
01385
01386
01387
01388
01389
01396
01397
01398 bool gCycleMovement::EdgeIsDangerous( const eWall * wall, REAL time, REAL alpha ) const
01399 {
01400 if (!wall)
01401 return false;
01402
01403 const gPlayerWall *w = dynamic_cast<const gPlayerWall*>(wall);
01404 if (w)
01405 {
01406
01407 if ( !w->IsDangerous( alpha, time ) )
01408 return false;
01409
01410
01411
01412
01413
01414
01415
01416
01417 }
01418
01419 return true;
01420 }
01421
01422
01423
01424
01425
01426
01431
01432
01433 bool gCycleMovement::Turn( REAL dir )
01434 {
01435 if (dir>0)
01436 return Turn(1);
01437 else if (dir<0)
01438 return Turn(-1);
01439 else
01440 return false;
01441 }
01442
01443
01444
01445
01446
01447
01452
01453
01454 bool gCycleMovement::Turn( int dir )
01455 {
01456 return DoTurn( dir );
01457 }
01458
01459 static void sg_DropTempWall( eCoord const & dir, gSensor const & sensor )
01460 {
01461 tASSERT( sensor.ehit );
01462
01463 if (sn_GetNetState() != nCLIENT )
01464 {
01465
01466
01467
01468 eCoord vec = sensor.ehit->Vec();
01469 if ( fabs( dir * vec ) < vec.Norm() * .5 )
01470 return;
01471
01472
01473 eWall * ew = sensor.ehit->GetWall();
01474 tASSERT( ew );
01475 gPlayerWall* w = dynamic_cast< gPlayerWall * >( ew );
01476
01477
01478 if ( w )
01479 {
01480
01481 gCycleMovement* other = w->CycleMovement();
01482
01483
01484 if ( other )
01485 other->DropTempWall( w, sensor.before_hit, dir );
01486 }
01487 }
01488 }
01489
01491 struct gMaxSpaceAheadHitInfo
01492 {
01493 eCoord pos;
01494 REAL offset;
01495
01496 tJUST_CONTROLLED_PTR< eHalfEdge const > edge;
01497 tJUST_CONTROLLED_PTR< gPlayerWall > playerWall;
01498 REAL wallAlpha;
01499
01500 gMaxSpaceAheadHitInfo()
01501 : offset(0), wallAlpha(.5)
01502 {}
01503 };
01504
01505
01506 gMaxSpaceAheadHitInfoClearer::gMaxSpaceAheadHitInfoClearer( gMaxSpaceAheadHitInfo * & info )
01507 : info_( info ){}
01508
01509 gMaxSpaceAheadHitInfoClearer::~gMaxSpaceAheadHitInfoClearer()
01510 {
01511 gMaxSpaceAheadHitInfo * info = info_;
01512 if ( info )
01513 {
01514
01515 info->edge = NULL;
01516 info->playerWall = NULL;
01517 }
01518 }
01519
01520 static REAL sg_Gap( gSensor const & front, gSensor const & side, eCoord const & dir, REAL norm, REAL def, REAL & tolerance )
01521 {
01522 if ( side.ehit && side.ehit->Other() )
01523 {
01524
01525
01526 REAL gap1 = ( front.ehit->Vec()*( *side.ehit->Point() - *front.ehit->Point() ) )/norm;
01527 REAL gap2 = ( front.ehit->Vec()*( *side.ehit->Other()->Point() - *front.ehit->Point() ) )/norm;
01528
01529
01530 REAL sign = (dir * front.ehit->Vec())/norm;
01531 if ( sign != 0 )
01532 {
01533 sign = 1/sign;
01534 gap1 *= sign;
01535 gap2 *= sign;
01536 }
01537
01538
01539 tolerance = ( fabs(gap1) + fabs(gap2) ) * EPS * 10;
01540 REAL minGap = gap1 < gap2 ? gap1 : gap2;
01541
01542 return minGap;
01543 }
01544 else
01545 {
01546
01547 tolerance = EPS * 10 * front.hit;
01548 return def;
01549 }
01550 }
01551
01552 static REAL sg_rubberCycleMinDistanceGap = .0f;
01553 static REAL sg_rubberCycleMinDistanceGapSide = .5f;
01554
01555 static nSettingItemWatched<REAL> c_rcmdg("CYCLE_RUBBER_MINDISTANCE_GAP",
01556 sg_rubberCycleMinDistanceGap, nConfItemVersionWatcher::Group_Bumpy, 14 );
01557 static nSettingItem<REAL> c_rcmdgs("CYCLE_RUBBER_MINDISTANCE_GAP_SIDE",
01558 sg_rubberCycleMinDistanceGapSide);
01559
01560
01561
01562
01563
01564
01573
01574
01575
01576
01577
01578
01579
01585
01586
01587 REAL gCycleMovement::GetMaxSpaceAhead( REAL maxReport ) const
01588 {
01589
01590 if ( refreshSpaceAhead_ )
01591 {
01592 refreshSpaceAhead_ = false;
01593
01594
01595 REAL lookAhead = maxSpaceMaxCast_;
01596 if ( maxReport > lookAhead )
01597 {
01598 lookAhead = maxReport;
01599 }
01600
01601 sg_ArchiveReal( lookAhead, 9 );
01602
01603
01604 gMaxSpaceAheadHitInfo info;
01605
01606
01607 REAL mindistance = sg_rubberCycleMinDistance;
01608 {
01609
01610 REAL rubber_granted, rubberEffectiveness;
01611 sg_RubberValues( player, verletSpeed_, rubber_granted, rubberEffectiveness );
01612
01613
01614 if ( rubber_granted > 0 )
01615 {
01616
01617 REAL rubberUsageSpeed = verletSpeed_ * ( 1 - rubberSpeedFactor ) / rubberEffectiveness;
01618
01619 REAL rubberUsed = rubberUsageSpeed * lastTimestep_;
01620
01621
01622 REAL filling = ( GetRubber() + rubberUsed )/rubber_granted;
01623 if ( filling > 1 )
01624 filling = 1;
01625 mindistance += sg_rubberCycleMinDistanceReservoir * (1-filling);
01626 }
01627
01628
01629 if ( sg_rubberCycleMinDistancePreparation > 0 )
01630 {
01631 REAL badPreparation = sg_rubberCycleMinDistancePreparation/( sg_rubberCycleMinDistancePreparation + ( this->LastTime() - this->GetLastTurnTime() ) );
01632 mindistance += sg_rubberCycleMinDistanceUnprepared * badPreparation;
01633 }
01634 }
01635 sg_ArchiveReal( mindistance, 9 );
01636
01637
01638 lookAhead += mindistance * sg_rubberCycleMinDistanceLegacy * 2;
01639
01640
01641 gSensor fr( const_cast< gCycleMovement* >(this), this->Position(), this->Direction() );
01642 {
01643 REAL speed = this->Speed();
01644 if ( speed > 0 )
01645 fr.SetInverseSpeed( 1 / speed );
01646 }
01647 fr.detect( lookAhead );
01648
01649 info.edge = fr.ehit;
01650 info.pos = fr.before_hit;
01651
01652 if ( fr.ehit )
01653 {
01654 {
01655
01656 eWall * w = info.edge->GetWall();
01657 if ( !w && info.edge->Other() )
01658 {
01659 info.edge = info.edge->Other();
01660 w = info.edge->GetWall();
01661 }
01662
01663 gPlayerWall * wall = dynamic_cast< gPlayerWall * >( w );
01664 if ( wall && wall->Cycle() )
01665 {
01666
01667 info.wallAlpha = info.edge->Ratio( info.pos );
01668 info.playerWall = wall;
01669 }
01670 }
01671
01672 #ifdef DEBUG
01673 {
01674 gSensor fr2( const_cast< gCycleMovement* >( this ), this->Position(), this->Direction() );
01675 fr2.detect( lookAhead );
01676 }
01677 #endif
01678
01679 REAL stopDistance = 0.1;
01680 if ( fr.ehit )
01681 {
01682 REAL norm = fr.ehit->Vec().Norm();
01683 stopDistance = mindistance + sg_rubberCycleMinDistanceRatio * norm;
01684
01685 ::sg_DropTempWall( this->Direction(), fr );
01686
01687
01688
01689 REAL rubberCycleMinDistanceGapDistance = sg_rubberCycleMinDistanceGapSide * Speed();
01690
01691
01692 if ( sg_rubberCycleMinDistanceGap > 0 )
01693 {
01694
01695 for ( int dir = -1; dir < 2; dir += 2 )
01696 {
01697
01698 REAL & gapCache = gap_[(dir+1)/2];
01699 bool & keepLooking = keepLookingForGap_[(dir+1)/2];
01700
01701 if ( gapCache > fr.hit && keepLooking )
01702 {
01703
01704 int wn = windingNumberWrapped_;
01705 Grid()->Turn(wn, dir);
01706 eCoord dirCast = Grid()->GetDirection(wn);
01707
01708 bool gapFound = false;
01709 for ( int back = -1; back <= 2; ++back )
01710 {
01711
01712 int wn2 = wn;
01713 Grid()->Turn(wn2, back);
01714 eCoord dirCast2 = Grid()->GetDirection(wn2);
01715
01716
01717 gSensor side( const_cast< gCycleMovement * >( this ),
01718 this->Position(),
01719 ( dirCast + dirCast2 ) * .5 );
01720
01721 side.detect( rubberCycleMinDistanceGapDistance );
01722
01723
01724 if ( back != 0 && !side.ehit )
01725 continue;
01726
01727 REAL tolerance;
01728 REAL minGap = sg_Gap( fr, side, dirDrive, norm, fr.hit * .5, tolerance );
01729
01730 while ( minGap > tolerance )
01731 {
01732
01733 gSensor side2( const_cast< gCycleMovement * >( this ),
01734 this->Position() + this->Direction() * ( fr.hit - minGap * .9 ),
01735 dirCast );
01736 side2.detect( rubberCycleMinDistanceGapDistance );
01737
01738
01739 if ( fabs(side2.hit - side.hit) < tolerance )
01740 {
01741
01742 REAL dumpTolerance;
01743 REAL lastMinGap = minGap;
01744 minGap = sg_Gap( fr, side2, dirDrive, norm, minGap * .5, dumpTolerance );
01745
01746 if ( minGap >= lastMinGap * .9 )
01747 break;
01748 }
01749 else
01750 {
01751 gapFound = true;
01752
01753
01754 if ( minGap < gapCache )
01755 {
01756 gapCache = minGap;
01757
01758
01759 back = 100;
01760 }
01761
01762
01763 break;
01764 }
01765 }
01766 }
01767
01768
01769 if ( ! gapFound )
01770 {
01771
01772 keepLooking = false;
01773
01774
01775 if ( gapCache > 5E+19 )
01776 gapCache = 0;
01777 }
01778 }
01779 }
01780
01781
01782 REAL gap = ( ( gap_[0] > 0 ? gap_[0] : 1E+30 ) < ( gap_[1] > 0 ? gap_[1] : 1E+30 ) ) ? gap_[0] : gap_[1];
01783 if ( gap > 0 )
01784 {
01785 REAL minDistanceGap = gap * sg_rubberCycleMinDistanceGap;
01786 if ( stopDistance > minDistanceGap )
01787 stopDistance = minDistanceGap;
01788 }
01789 }
01790 }
01791 sg_ArchiveReal( stopDistance, 9 );
01792
01793
01794
01795 if ( sg_rubberCycleLegacy && !sg_nonRippable.Supported() && stopDistance > .001 )
01796 stopDistance = .001;
01797
01798
01799
01800
01801
01802 REAL space = fr.hit;
01803 sg_ArchiveReal( space, 9 );
01804
01805
01806 REAL distSinceLastTurn = this->GetDistanceSinceLastTurn();
01807
01808
01809 REAL maxStop = ( distSinceLastTurn + space ) * ( 1 - sg_rubberCycleMinAdjust );
01810 if ( maxStop < stopDistance )
01811 {
01812 stopDistance = maxStop;
01813 }
01814
01815 sg_ArchiveReal( stopDistance, 9 );
01816
01817
01818 REAL safety = this->Position().Norm() * 2 * EPS;
01819
01820 info.offset = stopDistance + safety;
01821
01822 sg_ArchiveReal( space, 9 );
01823
01824
01825 if ( !maxSpaceHit_ )
01826 maxSpaceHit_ = tNEW( gMaxSpaceAheadHitInfo );
01827
01828
01829 *maxSpaceHit_ = info;
01830 }
01831 else
01832 {
01833
01834 delete maxSpaceHit_;
01835 maxSpaceHit_ = NULL;
01836 }
01837 }
01838
01839
01840 REAL ret = 1E+30;
01841 if ( maxSpaceHit_ )
01842 {
01843 ret = eCoord::F( dirDrive, maxSpaceHit_->pos - pos ) - maxSpaceHit_->offset;
01844 }
01845
01846
01847 if ( ret > maxReport )
01848 ret = maxReport;
01849 return ret;
01850 }
01851
01852
01853
01854
01855
01856
01858
01865
01866
01867
01868
01869
01870
01871
01872
01873
01874
01875
01876
01877
01878
01879
01880
01881
01882
01883
01884
01885
01886
01887
01888
01889 static nVersionFeature sg_CommandTime( 4 );
01890
01891
01892 static nVersionFeature sg_AntiLag( 5 );
01893
01894
01895 static bool sg_fairAntiLagSliding=true;
01896 static nSettingItem<bool> c_fals("CYCLE_FAIR_ANTILAG",sg_fairAntiLagSliding);
01897
01898
01899 static bool sg_UseAntiLagSliding( const eNetGameObject* obj )
01900 {
01901 tASSERT( obj );
01902
01903
01904 if ( !sg_CommandTime.Supported( obj->Owner() ) )
01905 return false;
01906
01907
01908 if ( sn_GetNetState() == nCLIENT && !sg_AntiLag.Supported( obj->Owner() ) )
01909 return false;
01910
01911
01912 if ( sg_fairAntiLagSliding )
01913 {
01914 return sg_CommandTime.Supported();
01915 }
01916 else
01917 {
01918
01919 return true;
01920 }
01921 }
01922
01923
01924 class gTurnDelayOverride
01925 {
01926 public:
01927 explicit gTurnDelayOverride( bool override )
01928 {
01929 delay_ = sg_delayCycle;
01930 if ( override )
01931 sg_delayCycle = 0.0f;
01932 }
01933
01934 explicit gTurnDelayOverride( REAL factor )
01935 {
01936 delay_ = sg_delayCycle;
01937 sg_delayCycle *= factor;
01938 }
01939
01940 ~gTurnDelayOverride()
01941 {
01942 sg_delayCycle = delay_;
01943 }
01944 private:
01945 REAL delay_;
01946 };
01947
01948 static nVersionFeature sg_noRedundantBrakeCommands( 13 );
01949
01950
01951
01952
01953
01954
01959
01960
01961 bool gCycleMovement::Timestep( REAL currentTime )
01962 {
01963
01964 refreshSpaceAhead_ = true;
01965
01966
01967 gMaxSpaceAheadHitInfoClearer hitInfoClearer( maxSpaceHit_ );
01968
01969
01970 clamp( rubber, 0, sg_rubberCycle );
01971
01972
01973 tJUST_CONTROLLED_PTR< gCycleMovement > keep( this->GetRefcount()>0 ? this : 0 );
01974
01975
01976 if ( currentTime < lastTime )
01977 return TimestepCore( currentTime );
01978
01979
01980
01981
01982
01983
01984
01985 while(destinationList && destinationList->hasBeenUsed && !IsDestinationUsed( destinationList ) )
01986 delete destinationList;
01987
01988
01989 REAL dt = currentTime - lastTime;
01990
01991 sg_ArchiveReal( dt, 9 );
01992
01993
01994 {
01995 int timeout=10;
01996 bool forceTurn = false;
01997 bool overrideTurnDelay=false;
01998
01999
02000 while (pendingTurns.empty() && currentDestination && timeout > 0 )
02001 {
02002 timeout --;
02003
02004
02005 REAL dist_to_dest = DistanceToDestination( *currentDestination );
02006 sg_ArchiveReal( dist_to_dest, 9 );
02007
02008 REAL ts=currentTime - lastTime;
02009 sg_ArchiveReal( ts, 9 );
02010
02011 sg_ArchiveReal( verletSpeed_, 9 );
02012 sg_ArchiveReal( acceleration, 9 );
02013
02014
02015 REAL avgspeed=verletSpeed_;
02016 CalculateAcceleration();
02017 if (acceleration > 0)
02018 avgspeed += acceleration * SpeedMultiplier() * ts * .5;
02019
02020
02021
02022 bool rubberActive = false;
02023
02024
02025 sg_ArchiveReal( rubberSpeedFactor, 9 );
02026 REAL distToWall=1E+30;
02027 if ( rubberSpeedFactor < .999 )
02028 {
02029
02030 rubberActive = true;
02031 avgspeed *= rubberSpeedFactor;
02032 if ( avgspeed < EPS )
02033 avgspeed = EPS;
02034
02035 sg_ArchiveReal( avgspeed, 9 );
02036
02037
02038 REAL lookahead = ts * avgspeed * 2;
02039
02040 REAL dist_to_wall = GetMaxSpaceAhead( lookahead );
02041
02042 if ( dist_to_dest > dist_to_wall )
02043 dist_to_dest = dist_to_wall;
02044 }
02045
02046 static bool breakp = false;
02047
02048
02049
02050
02051
02052 REAL turnTime = currentDestination->GetGameTime();
02053 REAL earliestTurnTime = turnTime - sg_timeTolerance - 100;
02054 REAL latestTurnTime = turnTime + sg_timeTolerance;
02055
02056
02057
02058 if ( sg_UseAntiLagSliding( this ) )
02059 {
02060 if ( rubberActive )
02061 {
02062
02063 earliestTurnTime = turnTime - sg_timeTolerance * rubberSpeedFactor;
02064 latestTurnTime = turnTime + sg_timeTolerance * rubberSpeedFactor;
02065
02066
02067 if ( verletSpeed_ > 0 )
02068 {
02069 REAL maxRubber, effectiveness;
02070 sg_RubberValues( Player(), verletSpeed_, maxRubber, effectiveness );
02071
02072
02073 REAL rubberLeft = (maxRubber - rubber)*.9;
02074 REAL stepLeft = rubberLeft + distToWall;
02075 REAL timeLeft = stepLeft/verletSpeed_;
02076 REAL deathTime = lastTime + timeLeft;
02077
02078
02079 if ( deathTime < turnTime )
02080 deathTime = turnTime;
02081
02082
02083 if ( latestTurnTime > deathTime )
02084 latestTurnTime = deathTime;
02085 }
02086 }
02087 else
02088 {
02089
02090 earliestTurnTime = turnTime - sg_timeTolerance;
02091 }
02092 }
02093
02094 sg_ArchiveReal( dist_to_dest, 9 );
02095
02096 REAL simulateAhead = MaxSimulateAhead();
02097
02098 if ( dist_to_dest > ( ts + simulateAhead ) * avgspeed && currentTime < latestTurnTime )
02099 break;
02100
02101 if ( currentTime < earliestTurnTime && sg_CommandTime.Supported( Owner() ) )
02102 break;
02103
02104
02105
02106
02107
02108 int turnTo=0;
02109
02110
02111 bool missed=false;
02112
02113 {
02114 REAL t = currentDestination->direction * dirDrive;
02115 bool turn = true;
02116
02117 missed = (fabs(t)<.01);
02118 if (int(braking) != int(currentDestination->braking))
02119 {
02120 turn = false;
02121 missed=!missed;
02122 }
02123
02124
02125
02126 if ( missed && lastDestination && lastDestination->messageID == currentDestination->messageID-1 )
02127 {
02128 missed = false;
02129 if ( ( dirDrive - currentDestination->direction ).NormSquared() < EPS )
02130 {
02131 turn = false;
02132 turnTo = 0;
02133 }
02134 }
02135
02136
02137 if ( missed && sn_GetNetState() == nSERVER && !sg_noRedundantBrakeCommands.Supported( Owner() ) )
02138 {
02139
02140 REAL timeToDest = currentDestination->GetGameTime() - lastTime;
02141 eCoord posDelta = pos + dirDrive * ( timeToDest * ( verletSpeed_ + .5f * acceleration * timeToDest ) ) - currentDestination->position;
02142 REAL deltaParallel = eCoord::F( posDelta, dirDrive );
02143 REAL deltaOrthogonal = posDelta * dirDrive;
02144
02145
02146 REAL tolerance = verletSpeed_ * GetTurnDelay();
02147 if ( fabs(deltaParallel) < tolerance && fabs(deltaOrthogonal) < tolerance * .5 )
02148 {
02149 missed = false;
02150 if ( ( dirDrive - currentDestination->direction ).NormSquared() < EPS )
02151 {
02152 turn = false;
02153 }
02154 }
02155 }
02156
02157
02158 if ( turns < currentDestination->turns - 1 )
02159 missed = true;
02160
02161 if ( turn )
02162 {
02163
02164
02165 int wn = windingNumberWrapped_;
02166 Grid()->Turn(wn, 1);
02167 eCoord dirPlus = Grid()->GetDirection(wn);
02168 wn = windingNumberWrapped_;
02169 Grid()->Turn(wn, -1);
02170 eCoord dirMinus = Grid()->GetDirection(wn);
02171
02172 if ( missed )
02173 {
02174 eCoord dirTurn = (currentDestination->position - pos);
02175
02176
02177 turnTo = ( ( fabs( dirMinus * dirTurn ) - .1 * eCoord::F( dirMinus, dirTurn ) )/dirTurn.NormSquared() < ( fabs( dirPlus * dirTurn ) - .1 * eCoord::F( dirPlus, dirTurn ) )/dirTurn.NormSquared() ) ? -1 : +1;
02178 }
02179 else
02180 {
02181
02182 eCoord dirTurn = currentDestination->direction;
02183
02184 turnTo = ( ( dirMinus - dirTurn ).NormSquared() < ( dirPlus - dirTurn ).NormSquared() ) ? -1 : +1;
02185
02186 }
02187 }
02188 }
02189
02190
02191 bool canTurn = ( turnTo == 0 || CanMakeTurn(turnTo) || overrideTurnDelay );
02192
02193 if ( lastTime >= earliestTurnTime && canTurn && ( forceTurn || dist_to_dest < 0.01 || timeout <= 0 || lastTime >= latestTurnTime ) ){
02194 forceTurn = false;
02195
02196 #ifdef DEBUG
02197 if ( turnTo != 0 )
02198 {
02199 static REAL checkFactor = .9f;
02200 gTurnDelayOverride check( checkFactor );
02201 if ( !CanMakeTurn( turnTo ) )
02202 {
02203 con << "Early turn!\n";
02204 st_Breakpoint();
02205 }
02206 }
02207 #endif
02208
02209
02210
02211
02212
02213
02214
02215
02216
02217
02218
02219
02220
02221
02222
02223
02224
02225
02226
02227
02228
02229
02230
02231
02232
02233
02234
02235
02236
02237
02238
02239
02240
02241
02242
02243
02244
02245
02246
02247 bool used = false;
02248
02249 if (!missed){
02250 used = true;
02251
02252 if (turnTo != 0)
02253 {
02254 #ifdef DEBUG
02255 #ifdef DEDICATED
02256 eCoord slide = this->pos - currentDestination->position;
02257 if ( Player() && slide.NormSquared() > .01 )
02258 con << "Lag slide for " << Player()->GetUserName() << ": " << slide << ", rubberSpeedFactor " << rubberSpeedFactor << "\n";
02259 #endif
02260 #endif
02261 gTurnDelayOverride override( overrideTurnDelay );
02262 Turn(turnTo);
02263 }
02264 else{
02265 AccelerationDiscontinuity();
02266 braking = currentDestination->braking;
02267 if (sn_GetNetState()!=nCLIENT)
02268 RequestSync();
02269 }
02270
02271
02272
02273
02274
02275
02276 }
02277 else
02278 {
02279
02280
02281
02282 if ( lastTime > currentTime - Lag()*sg_packetMissTolerance )
02283 return !Alive();
02284
02285 if ( turns >= currentDestination->turns - 1 )
02286 {
02287
02288
02289 REAL side = (currentDestination->position - pos) * dirDrive;
02290 if ( fabs(side)>verletSpeed_ * GetTurnDelay() * .2 )
02291 {
02292 gTurnDelayOverride override( overrideTurnDelay );
02293 Turn(turnTo);
02294 }
02295 else
02296 used = true;
02297 }
02298
02299
02300
02301
02302
02303
02304 }
02305
02306 overrideTurnDelay = false;
02307
02308 if ( used )
02309 {
02310
02311 currentDestination->hasBeenUsed = (sn_GetNetState()!=nCLIENT);
02312 lastDestination = currentDestination;
02313
02314
02315 currentDestination = currentDestination->next;
02316 }
02317
02318
02319 while (currentDestination && currentDestination->hasBeenUsed)
02320 {
02321 breakp = false;
02322 currentDestination = currentDestination->next;
02323 }
02324 }
02325 else
02326 {
02327
02328
02329
02330 sg_ArchiveReal( avgspeed, 9 );
02331 REAL tsTodo = dist_to_dest/avgspeed;
02332
02333
02334
02335
02336
02337
02338 sg_ArchiveReal( tsTodo, 9 );
02339
02340
02341 if ( !canTurn )
02342 {
02343 REAL nextTurn = GetNextTurn(turnTo);
02344 REAL turnStep = nextTurn - lastTime;
02345
02346
02347 if ( turnTime < nextTurn )
02348 turnTime = nextTurn;
02349 if ( earliestTurnTime < nextTurn )
02350 earliestTurnTime = nextTurn;
02351 if ( latestTurnTime < nextTurn )
02352 latestTurnTime = nextTurn;
02353
02354 if ( currentTime - lastTime > turnStep )
02355 {
02356 tsTodo = turnStep;
02357
02358
02359
02360 if ( tsTodo < ts + simulateAhead && tsTodo > 0 )
02361 {
02362 overrideTurnDelay = true;
02363 }
02364 }
02365 else
02366 {
02367
02368 break;
02369 }
02370 }
02371 else
02372 {
02373 sg_ArchiveReal( tsTodo, 9 );
02374
02375 REAL maxts = latestTurnTime - lastTime;
02376 sg_ArchiveReal( maxts, 9 );
02377 if ( tsTodo > maxts )
02378 {
02379
02380 forceTurn = true;
02381 tsTodo = maxts;
02382 }
02383
02384
02385 REAL mints = earliestTurnTime - lastTime;
02386
02387 if ( tsTodo < mints )
02388 {
02389 tsTodo = mints;
02390 }
02391 }
02392
02393 if ( tsTodo < 0 )
02394 {
02395
02396 st_Breakpoint();
02397 return !Alive();
02398 }
02399 if ( tsTodo > ts + simulateAhead )
02400 {
02401 tsTodo = ts + simulateAhead ;
02402 forceTurn = false;
02403
02404
02405 if ( tsTodo <= EPS )
02406 break;
02407 }
02408 #ifdef DEBUG
02409 if ( tsTodo < 0 )
02410 con << "Negative timestep!\n";
02411 #endif
02412 sg_ArchiveReal( tsTodo, 9 );
02413
02414
02415 if ( tsTodo > EPS )
02416 {
02417 REAL lastTimeBack = lastTime;
02418 bool ret = TimestepCore( lastTime + tsTodo, false );
02419 if ( lastTime <= lastTimeBack )
02420 return ret;
02421 }
02422 else
02423 {
02424
02425 forceTurn = true;
02426 }
02427 }
02428 }
02429 }
02430
02431
02432 if ( !pendingTurns.empty())
02433 {
02434 REAL nextTurn = GetNextTurn(pendingTurns.front());
02435 if(currentTime>nextTurn) {
02436 if ( nextTurn > lastTime )
02437 TimestepCore( nextTurn );
02438
02439
02440 Turn(pendingTurns.front());
02441 pendingTurns.pop_front();
02442 }
02443 }
02444
02445
02446 bool ret = false;
02447 if ( currentTime > lastTime )
02448 ret = TimestepCore( currentTime );
02449
02450 return ret;
02451 }
02452
02453
02454
02455
02456
02457
02460
02461
02462 void gCycleMovement::AddRef( void )
02463 {
02464 eNetGameObject::AddRef();
02465 if ( GetRefcount() > sg_cycleMaxRefCount && Alive() )
02466 {
02467
02468
02469 int backup = sg_cycleMaxRefCount;
02470 sg_cycleMaxRefCount += 100;
02471 Kill();
02472 sg_cycleMaxRefCount = backup;
02473 }
02474 }
02475
02476
02477
02478
02479
02480
02488
02489
02490 gCycleMovement::gCycleMovement( eGrid * grid, const eCoord & pos, const eCoord & dir, ePlayerNetID * player, bool autodelete )
02491 :eNetGameObject(grid, pos,dir,player,autodelete),
02492 destinationList(NULL),currentDestination(NULL),lastDestination(NULL),
02493 dirDrive(dir),
02494 acceleration(0),
02495 totalZoneAcceleration(0),
02496 lastTimestep_(0),
02497 verletSpeed_(sg_speedCycleStart * SpeedMultiplier()),
02498 pendingTurns()
02499 {
02500 windingNumberWrapped_ = windingNumber_ = Grid()->DirectionWinding(dir);
02501
02502 MyInitAfterCreation();
02503 }
02504
02505
02506
02507
02508
02509
02513
02514
02515 gCycleMovement::gCycleMovement( nMessage & message )
02516 :eNetGameObject(message),
02517 destinationList(NULL),currentDestination(NULL),lastDestination(NULL),
02518 dirDrive(1,0),
02519 acceleration(0),
02520 totalZoneAcceleration(0),
02521 lastTimestep_(0),
02522 verletSpeed_(5)
02523 {
02524 windingNumberWrapped_ = windingNumber_ = 2;
02525
02526
02527 }
02528
02529
02530
02531
02532
02533
02536
02537
02538 gCycleMovement::~gCycleMovement( void )
02539 {
02540 lastDestination = NULL;
02541 currentDestination = NULL;
02542
02543 while(destinationList)
02544 {
02545 gDestination* dest = destinationList;
02546 delete dest;
02547 }
02548
02549 verletSpeed_=distance=0;
02550
02551 delete maxSpaceHit_;
02552 maxSpaceHit_ = NULL;
02553 }
02554
02555 void gCycleMovement::RequestSync(bool ack)
02556 {
02557
02558 if ( !Alive() )
02559 {
02560 return;
02561 }
02562
02563
02564 eNetGameObject::RequestSync( ack );
02565 }
02566
02567 void gCycleMovement::RequestSync(int user,bool ack)
02568 {
02569
02570 if ( !Alive() )
02571 {
02572 return;
02573 }
02574
02575
02576 eNetGameObject::RequestSync( user, ack );
02577 }
02578
02579 void gCycleMovement::OnRemoveFromGame()
02580 {
02581 delete maxSpaceHit_;
02582 maxSpaceHit_ = NULL;
02583
02584 eNetGameObject::OnRemoveFromGame();
02585 }
02586
02587
02588
02589
02590
02591
02595
02596
02597 void gCycleMovement::CopyFrom( const gCycleMovement & other )
02598 {
02599
02600 eCoord posUpdate = other.Position() - this->Position();
02601
02602 #ifdef DEBUG_X
02603
02604 REAL lag = 1;
02605 if ( player )
02606 lag = player->ping;
02607
02608 REAL tol = this->speed * lag;
02609 if ( posUpdate.NormSquared() > tol*tol )
02610 {
02611 con << "Out of sync!\n";
02612
02613
02614
02615 tJUST_CONTROLLED_PTR<gCycleExtrapolator> extrapolator = tNEW( gCycleExtrapolator )(grid, pos, dir );
02616 gCycleExtrapolator& secondOpinion = *extrapolator;
02617 secondOpinion.CopyFrom( sg_usedMessage, *this );
02618 eGameObject::TimestepThis( other.lastTime, &secondOpinion );
02619 }
02620 #endif
02621
02622 dirDrive = other.dirDrive;
02623
02624
02625 currentFace = other.currentFace;
02626 pos = other.Position();
02627 lastTime = other.LastTime();
02628
02629
02630
02631
02632
02633
02634 team = other.team;
02635 distance = other.distance;
02636 lastTimestep_ = other.lastTimestep_;
02637 verletSpeed_ = other.verletSpeed_;
02638 acceleration = other.acceleration;
02639 rubber = other.rubber;
02640 rubberMalus = other.rubberMalus;
02641 brakingReservoir= other.brakingReservoir;
02642 windingNumber_ = other.windingNumber_;
02643 windingNumberWrapped_ = other.windingNumberWrapped_;
02644
02645 tASSERT(finite(distance));
02646
02647
02648
02649 #ifdef DEBUG_X
02650 if ( turns != other.turns )
02651 {
02652 con << "Client/Server turn mismatch:" << turns << " != " << other.turns << "\n";
02653 }
02654 #endif
02655
02656
02657 REAL right = GetNextTurn(1);
02658 REAL left = GetNextTurn(-1);
02659 if ( lastTime > (right > left ? right : left) + 2 * GetTurnDelay() )
02660 turns = other.turns;
02661 }
02662
02663 static nVersionFeature sg_sendCorrectLastTurn(8);
02664
02665
02666
02667
02668
02669
02674
02675
02676 void gCycleMovement::CopyFrom( const SyncData & sync, const gCycleMovement & other )
02677 {
02678
02679 dir = dirDrive = sync.dir;
02680 lastTimestep_ = 0;
02681 verletSpeed_ = sync.speed;
02682 rubber = sync.rubber;
02683 rubberMalus = sync.rubberMalus;
02684 braking = sync.braking;
02685 distance = sync.distance;
02686 turns = sync.turns;
02687 brakingReservoir= sync.brakingReservoir;
02688
02689
02690 tASSERT(finite(distance));
02691
02692
02693 this->SetWindingNumberWrapped( Grid()->DirectionWinding(dirDrive) );
02694 acceleration = 0;
02695
02696
02697
02698 SetPlayer( other.Player() );
02699 currentFace = other.currentFace;
02700
02701 {
02702
02703
02704
02705
02706
02707 this->currentDestination = GetDestinationBefore( sync, other.destinationList );
02708
02709 bool trustDestination = true;
02710 if ( currentDestination && sn_GetNetState() == nCLIENT && !sg_sendCorrectLastTurn.Supported(0) )
02711 {
02712
02713
02714
02715
02716 if ( ( currentDestination->braking != (bool)braking ) || fabs( currentDestination->direction * dirDrive ) > .01 )
02717 trustDestination = false;
02718 }
02719
02720
02721 if ( trustDestination && currentDestination )
02722 currentDestination = currentDestination->next;
02723 }
02724
02725
02726 MoveSafely( sync.pos, sync.time, sync.time );
02727
02728
02729 lastTurnTimeRight_ = lastTurnTimeLeft_ = -100;
02730 }
02731
02732
02733
02734
02735
02736
02739
02740
02741 void gCycleMovement::InitAfterCreation( void )
02742 {
02743 #ifdef DEBUG
02744 if (!finite(verletSpeed_))
02745 st_Breakpoint();
02746 #endif
02747 eNetGameObject::InitAfterCreation();
02748 #ifdef DEBUG
02749 if (!finite(verletSpeed_))
02750 st_Breakpoint();
02751 #endif
02752 MyInitAfterCreation();
02753 }
02754
02755
02756 static nVersionFeature sg_correctAccelerationScaling( 8 );
02757
02758
02759 void sg_RubberValues( ePlayerNetID const * player, REAL speed, REAL & max, REAL & effectiveness )
02760 {
02761
02762 max=sg_rubberCycle;
02763 effectiveness=1;
02764
02765
02766 if ( player )
02767 {
02768 if ( max > 0 )
02769
02770 effectiveness *= ( max + player->ping * sg_rubberCyclePing )/max;
02771 else
02772
02773 max += player->ping * sg_rubberCyclePing;
02774 }
02775
02776 {
02777
02778 REAL speedFactor = speed/(sg_speedCycle*gCycleMovement::SpeedMultiplier());
02779
02780 effectiveness *= pow( speedFactor, sg_rubberCycleTimeBased );
02781 }
02782 }
02783
02784
02785
02786
02787
02788
02791
02792
02793 void gCycleMovement::AccelerationDiscontinuity()
02794 {
02795
02796 verletSpeed_ = Speed();
02797 lastTimestep_ = 0;
02798 }
02799
02800
02801
02802
02803
02804
02807
02808
02809 void gCycleMovement::CalculateAcceleration()
02810 {
02811
02812 brakeUsage = 0.0f;
02813 rubberUsage = 0.0f;
02814
02815
02816 acceleration=0;
02817
02818
02819 static nVersionFeature brakeDepletion(2);
02820
02821
02822 static nVersionFeature brakeDepletionHandledWithConfig(10);
02823
02824
02825
02826
02827 if ( sn_GetNetState() != nCLIENT || brakeDepletion.Supported() || brakeDepletionHandledWithConfig.Supported(0) )
02828 {
02829 if(braking)
02830 {
02831 if ( brakingReservoir > 0.0 )
02832 {
02833 brakeUsage = sg_cycleBrakeDeplete;
02834 acceleration-=sg_brakeCycle * SpeedMultiplier();
02835 }
02836 else
02837 brakingReservoir = 0.0f;
02838 }
02839 else
02840 {
02841 if ( brakingReservoir < 1.0 )
02842 {
02843 brakeUsage = -sg_cycleBrakeRefill;
02844 }
02845 else
02846 brakingReservoir = 1.0f;
02847 }
02848 }
02849 else
02850 {
02851 if(braking)
02852 {
02853 acceleration-=sg_brakeCycle * SpeedMultiplier();
02854 }
02855 }
02856
02857 sg_ArchiveReal( acceleration, 9 );
02858
02859 REAL baseSpeed = sg_speedCycle * SpeedMultiplier();
02860 if ( verletSpeed_ <= ( sg_correctAccelerationScaling.Supported() ? baseSpeed : sg_speedCycle ) )
02861 acceleration+=( baseSpeed - verletSpeed_) * sg_speedCycleDecayBelow;
02862 else
02863 acceleration+=( baseSpeed - verletSpeed_) * sg_speedCycleDecayAbove;
02864
02865 tASSERT( good( acceleration ) );
02866 sg_ArchiveReal( acceleration, 9 );
02867
02868
02869 REAL totalWallAcceleration = 0;
02870 REAL tunnelWidth = 0;
02871 REAL sideWidth = sg_cycleWidthSide * 2;
02872 bool slingshot = true;
02873 bool oneOwnWall = false;
02874 for(int d=1;d>=-1;d-=2){
02875
02876 eCoord dirCast = dirDrive.Turn(-1,d);
02877 gSensor rear(this,pos,dirCast);
02878 rear.detect(sg_nearCycle);
02879
02880 enemyInfluence.AddSensor( rear, 0, this );
02881
02882 if (rear.ehit && rear.hit < sg_cycleWidth + .1f )
02883 blocks(rear, this, -d);
02884
02885 if ( 0 != rear.ehit )
02886 {
02887 sg_ArchiveReal( rear.hit, 9 );
02888
02889
02890 if ( sideWidth > rear.hit )
02891 sideWidth = rear.hit;
02892
02893
02894 if ( rear.hit < verletSpeed_ * .01 )
02895 ::sg_DropTempWall( dirCast, rear );
02896
02897
02898 eCoord wallVec = rear.ehit->Vec();
02899 if ( fabs( eCoord::F( wallVec, dirDrive ) ) > .9 * dirDrive.NormSquared() )
02900 {
02901
02902 REAL wallAcceleration=SpeedMultiplier() * sg_accelerationCycle * ((1/(rear.hit+sg_accelerationCycleOffs))
02903 -(1/(sg_nearCycle+sg_accelerationCycleOffs)));
02904
02905 tunnelWidth += rear.hit;
02906
02907
02908 switch (rear.type)
02909 {
02910 case gSENSOR_SELF:
02911 wallAcceleration *= sg_accelerationCycleSelf;
02912 oneOwnWall = true;
02913 break;
02914 case gSENSOR_TEAMMATE:
02915 wallAcceleration *= sg_accelerationCycleTeam;
02916 break;
02917 case gSENSOR_ENEMY:
02918 wallAcceleration *= sg_accelerationCycleEnemy;
02919 break;
02920 case gSENSOR_RIM:
02921 wallAcceleration *= sg_accelerationCycleRim;
02922 break;
02923 case gSENSOR_NONE:
02924 wallAcceleration = 0;
02925 slingshot = false;
02926 break;
02927
02928 }
02929
02930 sg_ArchiveReal( wallAcceleration, 9 );
02931 totalWallAcceleration += wallAcceleration;
02932 }
02933 else
02934 {
02935 slingshot = false;
02936 }
02937 }
02938 else
02939 {
02940 slingshot = false;
02941 }
02942
02943 sg_ArchiveReal( totalWallAcceleration, 9 );
02944 }
02945
02946
02947 if ( slingshot && tunnelWidth < sg_cycleWidth || sideWidth < sg_cycleWidthSide )
02948 {
02949 tunnelWidth = 0;
02950 REAL sideWidth = sg_cycleWidthSide * 2;
02951
02952
02953
02954 for(int d=1;d>=-1;d-=2)
02955 {
02956
02957 eCoord dirCast = dirDrive.Turn(1,d);
02958 gSensor front(this,pos,dirCast);
02959 front.detect(sg_nearCycle);
02960
02961 if ( front.ehit && front.ehit->Other() )
02962 {
02963 sg_ArchiveReal( front.hit, 9 );
02964
02965
02966 if ( sideWidth > front.hit )
02967 sideWidth = front.hit;
02968
02969 tunnelWidth += front.hit;
02970 }
02971 else
02972 {
02973 tunnelWidth += sg_cycleWidth;
02974 }
02975 }
02976
02977 if ( tunnelWidth < sg_cycleWidth || sideWidth < sg_cycleWidthSide )
02978 {
02979
02980 REAL available1 = 1;
02981 REAL available2 = 1;
02982 if ( sg_cycleWidth > 0 )
02983 available1 = tunnelWidth/sg_cycleWidth;
02984 if ( sg_cycleWidthSide > 0 )
02985 available2 = sideWidth/sg_cycleWidthSide;
02986 REAL available = available1 < available2 ? available1 : available2;
02987
02988
02989
02990
02991
02992
02993 rubberUsage = sg_cycleWidthRubberMax + ( sg_cycleWidthRubberMin - sg_cycleWidthRubberMax ) * available;
02994 }
02995 }
02996
02997
02998 if ( slingshot )
02999 {
03000 if ( oneOwnWall )
03001 totalWallAcceleration *= sg_accelerationCycleSlingshot;
03002 else
03003 totalWallAcceleration *= sg_accelerationCycleTunnel;
03004 }
03005
03006
03007 acceleration += totalWallAcceleration;
03008 acceleration += totalZoneAcceleration;
03009 totalZoneAcceleration = 0.0;
03010
03011 tASSERT( good( acceleration ) );
03012 sg_ArchiveReal( acceleration, 9 );
03013 }
03014
03015
03016
03017
03018
03019
03023
03024
03025 void gCycleMovement::ApplyAcceleration( REAL dt )
03026 {
03027 sg_ArchiveReal( verletSpeed_, 9 );
03028 sg_ArchiveReal( dt, 9 );
03029 sg_ArchiveReal( acceleration, 9 );
03030
03031
03032 REAL verletTimestep = sg_verletIntegration.Supported() ? .5 * ( dt + lastTimestep_ ) : dt;
03033 lastTimestep_ = dt;
03034
03035 sg_ArchiveReal( verletTimestep, 9 );
03036
03037
03038 bool properDecay = false;
03039 REAL maxTimestep = verletTimestep > dt ? verletTimestep : dt;
03040 if ( sg_speedCycleDecayBelow * maxTimestep > .1 || sg_speedCycleDecayAbove * maxTimestep > .1 )
03041 {
03042 REAL speedDecay = 0;
03043 REAL baseSpeed = sg_speedCycle * SpeedMultiplier();
03044 if ( verletSpeed_ < ( sg_correctAccelerationScaling.Supported() ? baseSpeed : sg_speedCycle ) )
03045 speedDecay = sg_speedCycleDecayBelow;
03046 else
03047 speedDecay = sg_speedCycleDecayAbove;
03048
03049 if ( speedDecay * maxTimestep > .1 && dt > EPS )
03050 {
03051
03052 properDecay = true;
03053
03054
03055 REAL decayAcceleration = ( baseSpeed - verletSpeed_) * speedDecay;
03056
03057 acceleration -= decayAcceleration;
03058
03059 tASSERT( good( acceleration ) );
03060
03061
03062 baseSpeed += acceleration/speedDecay;
03063
03064
03065 verletSpeed_ = baseSpeed + ( verletSpeed_ - baseSpeed ) * exp( -speedDecay * verletTimestep );
03066
03067
03068
03069
03070 acceleration = ( baseSpeed - verletSpeed_) * ( 1 - exp( -speedDecay * dt * .5f ) ) / ( .5f * dt );
03071
03072 tASSERT( good( acceleration ) );
03073 }
03074 }
03075
03076
03077 if ( !properDecay )
03078 verletSpeed_+=acceleration*verletTimestep;
03079
03080
03081 REAL minSpeed = sg_speedCycle*SpeedMultiplier()*sg_speedCycleMin;
03082 REAL maxSpeed = ( 100 + sg_speedCycle*SpeedMultiplier() )* 100000;
03083 if ( sg_speedCycleMax > 0 )
03084 {
03085 maxSpeed = sg_speedCycle*SpeedMultiplier()*sg_speedCycleMax;
03086 }
03087
03088 sg_ArchiveReal( minSpeed, 9 );
03089 sg_ArchiveReal( maxSpeed, 9 );
03090 sg_ArchiveReal( acceleration, 9 );
03091
03092 if ( clamp( verletSpeed_, minSpeed, maxSpeed ) )
03093 acceleration = 0;
03094
03095 sg_ArchiveReal( acceleration, 9 );
03096
03097 sg_ArchiveReal( verletSpeed_, 9 );
03098 }
03099
03100
03101
03102
03103
03104
03109
03110
03111 bool gCycleMovement::DoTurn( int dir )
03112 {
03113 if ( turns == 0 )
03114 turns = 1;
03115
03116 if (dir > 1) dir = 1;
03117 if (dir < -1) dir = -1;
03118
03119 if ( CanMakeTurn( lastTime, dir ) )
03120 {
03121
03122 refreshSpaceAhead_ = true;
03123
03124
03125
03126 rubberSpeedFactor = 1;
03127
03128
03129 lastTurnPos_ = pos;
03130
03131 turns++;
03132
03133 AccelerationDiscontinuity();
03134 verletSpeed_ *= sg_cycleTurnSpeedFactor;
03135 rubberMalus += sg_rubberCycleMalusTurn;
03136
03137 gap_[0] = gap_[1] = 1E+30;
03138 keepLookingForGap_[0] = keepLookingForGap_[1] = true;
03139
03140
03141 int wn = windingNumberWrapped_;
03142 Grid()->Turn(wn, dir);
03143 this->SetWindingNumberWrapped( wn );
03144
03145 eCoord nextDirDrive = Grid()->GetDirection(windingNumberWrapped_);
03146
03147
03148
03149 {
03150 REAL range = .1 * Speed();
03151 eCoord dirCast = nextDirDrive;
03152 gSensor gridder1( this, Position(), dirCast );
03153 gridder1.detect( range );
03154 if ( gridder1.ehit )
03155 ::sg_DropTempWall( nextDirDrive, gridder1 );
03156
03157 gSensor gridder3( this, Position() - dirCast * (range*.5), dirCast );
03158 gridder3.detect( range );
03159 if ( gridder3.ehit )
03160 ::sg_DropTempWall( nextDirDrive, gridder3 );
03161
03162
03163
03164 if ( range < sg_nearCycle )
03165 range = sg_nearCycle;
03166
03167 gSensor gridder2( this, Position(), -dirCast );
03168 gridder2.detect( range );
03169 if ( gridder2.ehit )
03170 {
03171 ::sg_DropTempWall( nextDirDrive, gridder2 );
03172
03173
03174 REAL dist = gridder2.hit;
03175
03176
03177 REAL accellerationFactorOffset = 1/(sg_nearCycle+sg_accelerationCycleOffs);
03178 REAL accelerationFactor = (1/(dist+sg_accelerationCycleOffs)) - accellerationFactorOffset;
03179
03180 REAL accelerationFactorMax = (1/sg_accelerationCycleOffs) - accellerationFactorOffset;
03181
03182
03183
03184 REAL boost = 0, boostFactor = 1;
03185 switch (gridder2.type)
03186 {
03187 case gSENSOR_SELF:
03188 boost = sg_boostCycleSelf;
03189 boostFactor = sg_boostFactorCycleSelf;
03190 break;
03191 case gSENSOR_TEAMMATE:
03192 boost = sg_boostCycleTeam;
03193 boostFactor = sg_boostFactorCycleTeam;
03194 break;
03195 case gSENSOR_ENEMY:
03196 boost = sg_boostCycleEnemy;
03197 boostFactor = sg_boostFactorCycleEnemy;
03198 break;
03199 case gSENSOR_RIM:
03200 boost = sg_boostCycleRim;
03201 boostFactor = sg_boostFactorCycleRim;
03202 break;
03203 case gSENSOR_NONE:
03204 break;
03205 }
03206
03207
03208 boostFactor = 1 + ( boostFactor - 1 ) * accelerationFactor / accelerationFactorMax;
03209 boost *= SpeedMultiplier() * accelerationFactor / accelerationFactorMax;
03210
03211
03212 verletSpeed_ = verletSpeed_ * boostFactor + boost;
03213 }
03214
03215
03216 FindCurrentFace();
03217 }
03218
03219
03220 lastDirDrive = dirDrive;
03221
03222 if(dir == 1)
03223 lastTurnTimeRight_ = lastTime;
03224 else
03225 lastTurnTimeLeft_ = lastTime;
03226
03227 dirDrive = nextDirDrive;
03228
03229 #ifdef DEBUGOUTPUT
03230 if ( sg_cycleDebugPrintLevel > 0 )
03231 con << Player()->GetName() << " turned " << pos << "," << dirDrive << " " << tSysTimeFloat() << "\n";
03232 #endif
03233
03234 return true;
03235 }
03236 else {
03237 int maxPendingTurns=sg_cycleTurnMemory;
03238 int size = pendingTurns.size();
03239
03240 if (size <= maxPendingTurns)
03241 pendingTurns.push_back(dir);
03242 else {
03243 if(pendingTurns.empty()) return false;
03244 if(pendingTurns.back() != dir) {
03245 pendingTurns.pop_back();
03246 }
03247 else {
03248 pendingTurns.push_back(dir);
03249 }
03250 }
03251 }
03252
03253 return false;
03254 }
03255
03256
03257
03258
03259
03260
03264
03265
03266 void gCycleMovement::RightBeforeDeath( int numTries )
03267 {
03268 }
03269
03270
03271
03272
03273
03274
03278
03279
03280 void gCycleMovement::Die( REAL time )
03281 {
03282
03283 if ( alive_ == 1 )
03284 {
03285 alive_ = -1;
03286 deathTime = time;
03287 }
03288
03289
03290 if ( alive_ == -1 )
03291 {
03292 alive_ = 0;
03293 }
03294 }
03295
03296 class gRecursionGuard
03297 {
03298 public:
03299 gRecursionGuard( bool & guard )
03300 : guard_( guard )
03301 {
03302 guard_ = false;
03303 }
03304 ~gRecursionGuard()
03305 {
03306 guard_ = true;
03307 }
03308 private:
03309 bool & guard_;
03310 };
03311
03312
03313
03314
03315
03316
03321
03322
03323 bool gCycleMovement::TimestepCore( REAL currentTime, bool calculateAcceleration )
03324 {
03325 eCoord oldpos=pos;
03326 REAL lastSpeed=verletSpeed_;
03327
03328 REAL ts=(currentTime-lastTime);
03329
03330
03331 if ( calculateAcceleration )
03332 this->CalculateAcceleration();
03333
03334
03335 REAL lastAcceleration=acceleration;
03336
03337
03338 {
03339 static bool recurse = true;
03340 if (recurse && brakingReservoir > 0 && brakeUsage > 0 && brakingReservoir - ts * brakeUsage < 0 )
03341 {
03342 gRecursionGuard guard( recurse );
03343
03344
03345 REAL brakeTime = lastTime + brakingReservoir/brakeUsage;
03346 if ( TimestepCore( brakeTime, false ) )
03347 return true;
03348 AccelerationDiscontinuity();
03349 brakingReservoir = -EPS;
03350 return TimestepCore( currentTime );
03351 }
03352 }
03353
03354
03355 if ( sg_verletIntegration.Supported() )
03356 this->ApplyAcceleration( ts );
03357
03358
03359
03360
03361
03362 sg_ArchiveCoord( pos, 9 );
03363 sg_ArchiveReal( ts, 9 );
03364 sg_ArchiveReal( verletSpeed_, 9 );
03365
03366 #ifdef DEBUG
03367 if ( ts > 2.0f )
03368 {
03369 int x;
03370 x = 0;
03371 }
03372
03373 if ( verletSpeed_ > 30.0f )
03374 {
03375 int x;
03376 x = 0;
03377 }
03378
03379 if ( acceleration > 100.0f )
03380 {
03381 int x;
03382 x = 0;
03383 }
03384 #endif
03385
03386 clamp(ts, -10, 10);
03387
03388 REAL step=verletSpeed_*ts;
03389 tASSERT(finite(step));
03390
03391 int numTries = 0;
03392 bool emergency = false;
03393
03394 rubberSpeedFactor = 1;
03395
03396
03397 REAL rubber_granted, rubberEffectiveness;
03398
03399
03400 sg_RubberValues( player, verletSpeed_, rubber_granted, rubberEffectiveness );
03401
03402
03403 rubberEffectiveness /= (1 + rubberMalus );
03404
03405
03406 {
03407 REAL delayTime = (lastTurnTimeRight_ > lastTurnTimeLeft_ ? lastTurnTimeRight_ : lastTurnTimeLeft_) + GetTurnDelay() * sg_rubberCycleDelay;
03408 if ( lastTime < delayTime )
03409 {
03410 rubberEffectiveness *= sg_rubberCycleDelayBonus;
03411
03412
03413 if( currentTime > delayTime )
03414 {
03415 static bool recurse = true;
03416 if (recurse)
03417 {
03418 gRecursionGuard guard( recurse );
03419
03420 verletSpeed_=lastSpeed;
03421 acceleration=lastAcceleration;
03422
03423 return TimestepCore( delayTime, false ) || TimestepCore( currentTime );
03424 }
03425 }
03426 }
03427 }
03428
03429 sg_ArchiveReal( rubberEffectiveness, 9 );
03430
03431 tASSERT( rubber >= 0 );
03432
03433
03434 if ( player && ( rubber_granted > rubber || sn_GetNetState() == nCLIENT || !Vulnerable() ) && sg_rubberCycleSpeed > 0 && step > -EPS && ( sn_GetNetState() == nCLIENT || rubberEffectiveness > 0 ) )
03435 {
03436
03437 if ( rubberEffectiveness <= 0 )
03438 rubberEffectiveness = 1E+20;
03439
03440
03441 REAL beta = ts * sg_rubberCycleSpeed;
03442 REAL neededSpace = 0;
03443 REAL rubberFactor;
03444 if ( beta > .001 )
03445 {
03446 rubberFactor = 1 - exp( -beta );
03447 neededSpace = step/rubberFactor;
03448 }
03449 else
03450 {
03451 rubberFactor = beta;
03452
03453
03454 neededSpace = verletSpeed_/sg_rubberCycleSpeed;
03455 }
03456
03457
03458 if ( rubberFactor > .999 )
03459 rubberFactor = .999;
03460
03461
03462 if ( sg_rubberCycleLegacy && !sg_nonRippable.Supported() && rubberFactor < .5f )
03463 rubberFactor = .5f;
03464
03465
03466 if ( neededSpace < step*3 || ts < -EPS )
03467 neededSpace = step*3;
03468
03469
03470
03471 REAL space = GetMaxSpaceAhead( neededSpace );
03472
03473 #ifdef DEBUG_RUBBER
03474 if ( Player() && space < 1E+15)
03475 {
03476 std::ofstream f( Player()->GetUserName() + "_rubber", std::ios::app );
03477 f << lastTime << " " << space << "\n";
03478 }
03479 #endif
03480
03481
03482
03483 if ( space < neededSpace )
03484 {
03485
03486 REAL rubberStartSpace = verletSpeed_/sg_rubberCycleSpeed;
03487 static bool recurse = true;
03488 if ( space > rubberStartSpace && recurse )
03489 {
03490
03491 gRecursionGuard guard( recurse );
03492
03493
03494 REAL ratio = ( space - rubberStartSpace )/step;
03495 if ( ratio > EPS && ratio < 1 - EPS )
03496 {
03497 REAL rubberGetsActiveTime = lastTime + ( currentTime - lastTime ) * ratio;
03498
03499 verletSpeed_=lastSpeed;
03500 acceleration=lastAcceleration;
03501 return TimestepCore( rubberGetsActiveTime, false ) || TimestepCore( currentTime );
03502 }
03503 }
03504 #ifdef DEDICATED
03505 else
03506 {
03507
03508
03509
03510 if ( maxSpaceHit_ && maxSpaceHit_->playerWall )
03511 {
03512 gPlayerWall * wall = maxSpaceHit_->playerWall;
03513
03514
03515 REAL alpha = maxSpaceHit_->wallAlpha;
03516
03517
03518 REAL wallDist = wall->Pos( alpha );
03519
03520 REAL cycleDist = wall->CycleMovement()->distance;
03521
03522
03523 REAL minLag = se_GameTime() - lastTime - LagThreshold();
03524 if ( cycleDist < wallDist && ( minLag < Lag() || minLag < wall->CycleMovement()->Lag() ) )
03525 {
03526
03527
03528 verletSpeed_=lastSpeed;
03529 acceleration=lastAcceleration;
03530
03531 return false;
03532 }
03533 }
03534 }
03535 #endif
03536
03537
03538
03539 {
03540
03541 if ( maxSpaceHit_ && maxSpaceHit_->playerWall )
03542 {
03543 gPlayerWall * wall = maxSpaceHit_->playerWall;
03544
03545
03546 REAL alpha = maxSpaceHit_->wallAlpha;
03547
03548
03549
03550
03551 REAL tolerance = 0.001;
03552 if ( !wall->IsDangerous( alpha, currentTime ) && currentTime > lastTime + tolerance )
03553 {
03554
03555
03556 REAL distanceOffset = 0;
03557 {
03558 REAL speed = Speed();
03559 if ( speed > 0 )
03560 distanceOffset = space/speed;
03561 }
03562
03563 REAL minTime = lastTime + distanceOffset;
03564 REAL maxTime = currentTime + distanceOffset;
03565 while ( minTime + tolerance < maxTime )
03566 {
03567 REAL midTime = .5 * ( minTime + maxTime );
03568 if ( wall->IsDangerous( alpha, midTime ) )
03569 minTime = midTime;
03570 else
03571 maxTime = midTime;
03572 }
03573
03574 maxTime -= distanceOffset;
03575
03576
03577
03578 {
03579 static bool recurse = true;
03580 if (recurse)
03581 {
03582 gRecursionGuard guard( recurse );
03583
03584 verletSpeed_=lastSpeed;
03585 acceleration=lastAcceleration;
03586 return TimestepCore( maxTime, false ) || TimestepCore( currentTime );
03587 }
03588 }
03589 }
03590 }
03591 }
03592
03593
03594
03595
03596
03597
03598
03599
03600
03601
03602
03603
03604
03605 emergency = true;
03606
03607
03608
03609 REAL rubberStep = space * rubberFactor;
03610 if ( rubberStep > step )
03611 rubberStep = step;
03612
03613
03614 if (step<0)
03615 step=0;
03616
03617
03618 REAL rubberneeded = step - rubberStep;
03619 if (rubberneeded < 0)
03620 rubberneeded = 0;
03621
03622
03623 REAL rubberAvailable = ( rubber_granted - rubber ) * rubberEffectiveness;
03624 if ( sn_GetNetState() != nCLIENT && rubberneeded > rubberAvailable && Vulnerable() )
03625 {
03626
03627
03628 {
03629 REAL ratio = rubberAvailable/rubberneeded;
03630
03631 if ( ratio > .01 && ratio < .99 && currentTime - lastTime > .001 )
03632 {
03633 REAL runOutTime = lastTime + ( currentTime - lastTime ) * ratio;
03634 static bool recurse = true;
03635 if (recurse)
03636 {
03637 gRecursionGuard guard( recurse );
03638
03639 verletSpeed_=lastSpeed;
03640 acceleration=lastAcceleration;
03641 return TimestepCore( runOutTime, false ) || TimestepCore( currentTime );
03642 }
03643 }
03644 }
03645
03646 rubberneeded = rubberAvailable;
03647 }
03648
03649
03650 rubber += rubberneeded / rubberEffectiveness;
03651
03652 numTries = int((sg_rubberCycleTime * ( rubber_granted - rubber ) - 1 )/(sg_rubberCycleTime * step*1.5 + 1));
03653 int numTriesSpace = int(space*10/verletSpeed_);
03654 if ( numTriesSpace < numTries )
03655 numTriesSpace = 0;
03656
03657 if ( step > 0 )
03658 rubberSpeedFactor = 1 - rubberneeded/step;
03659 else
03660
03661 rubberSpeedFactor = space / neededSpace;
03662
03663
03664 if ( rubberSpeedFactor < 0 )
03665 rubberSpeedFactor = 0;
03666
03667
03668 step -= rubberneeded;
03669 if (step<0)
03670 step=0;
03671
03672
03673
03674
03675
03676 }
03677 }
03678
03679 tASSERT( rubber >= 0 );
03680
03681 sg_ArchiveReal( step, 9 );
03682
03683
03684 eCoord nextpos;
03685 if ( verletSpeed_ >0 )
03686 nextpos=pos+dirDrive*step;
03687 else
03688 nextpos=pos;
03689
03690 eCoord lastPos = pos;
03691 tJUST_CONTROLLED_PTR< eFace > lastFace = currentFace;
03692 try
03693 {
03694 #ifdef DEBUG
03695 static int run = 0;
03696 run++;
03697 if ( run == -1 )
03698 {
03699 st_Breakpoint();
03700 }
03701 #endif
03702 Move(nextpos,lastTime,currentTime);
03703 #ifdef DEBUG
03704 {
03705 if ( step > 0 && ( nextpos - pos ).NormSquared() > 1 )
03706 {
03707 con << "Wrong move! run = " << run << ", nextpos = " << nextpos << ", pos = " << pos << "\n";
03708 }
03709 }
03710 #endif
03711
03712 tASSERT(finite(distance));
03713 tASSERT(finite(step));
03714 distance += step;
03715 lastTimeAlive_ = currentTime;
03716 }
03717 catch ( gCycleStop const & )
03718 {
03719
03720 pos = lastPos;
03721 verletSpeed_ = lastSpeed;
03722 acceleration = lastAcceleration;
03723 currentFace = lastFace;
03724 numTries = 0;
03725
03726
03727 return false;
03728 }
03729 catch ( gCycleDeath const & )
03730 {
03731 rubberSpeedFactor = 0;
03732
03733
03734
03735 if ( rubberEffectiveness <= 0 || step >= (rubber_granted-rubber)*rubberEffectiveness || ( sg_rubberCycleMinDistance < 0 && Player() && Player()->IsHuman() ) )
03736 {
03737
03738 bool toleratePacketLoss = false;
03739 if (!currentDestination)
03740 {
03741
03742 REAL tolerance = Lag() * sg_packetLossTolerance;
03743
03744
03745 if ( Owner() > 0 )
03746 tolerance += eLag::Credit( Owner() );
03747
03748
03749 if ( sn_GetNetState() == nSERVER && player && player->Owner() != 0 )
03750 {
03751 REAL varianceTolerance = 2 * sqrtf( sn_Connections[ player->Owner() ].ping.GetSnailAverager().GetDataVariance() );
03752
03753 if ( varianceTolerance > tolerance )
03754 varianceTolerance = tolerance;
03755 tolerance += varianceTolerance;
03756 }
03757
03758
03759 toleratePacketLoss = ( se_GameTime() - Lag() - lastTimeAlive_ < tolerance );
03760 }
03761
03762
03763 if ( toleratePacketLoss )
03764 {
03765 pos = lastPos;
03766 verletSpeed_ = lastSpeed;
03767 acceleration = lastAcceleration;
03768 currentFace = lastFace;
03769 numTries = 0;
03770 emergency = true;
03771
03772
03773 return false;
03774 }
03775 else
03776 {
03777
03778 rubber = rubber_granted;
03779
03780
03781 tASSERT(finite(distance));
03782 distance += eCoord::F( dirDrive, pos - lastPos )/dirDrive.NormSquared();
03783 tASSERT(finite(distance));
03784
03785 throw;
03786 }
03787 }
03788 else
03789 {
03790 pos = lastPos;
03791 currentFace = lastFace;
03792 rubber += step/rubberEffectiveness;
03793 if ( rubber < 0 )
03794 rubber = 0;
03795
03796 numTries = 0;
03797 emergency = true;
03798 }
03799 }
03800
03801 tASSERT( rubber >= 0 );
03802
03803
03804 if ( rubberEffectiveness > 0 )
03805 {
03806 rubber += rubberUsage * ts * verletSpeed_ / rubberEffectiveness; }
03807 else if ( rubberUsage > 0 )
03808 {
03809 rubber = rubber_granted + 10;
03810 }
03811 rubberUsage = 0;
03812
03813
03814 if ( rubber > rubber_granted || ( sg_cycleWidthRubberMax == 0 && sg_cycleWidthRubberMin == 0 ) )
03815 {
03816 if ( sn_GetNetState() != nCLIENT )
03817 {
03818 throw gCycleDeath( pos );
03819 }
03820 else
03821 rubber = rubber_granted;
03822 }
03823
03824
03825 brakingReservoir -= brakeUsage * ts;
03826 clamp( brakingReservoir, 0, 1 );
03827
03828
03829 if ( sg_rubberCycleTime > 0 )
03830 rubber /= (1+ts/sg_rubberCycleTime);
03831 else
03832 rubber = 0;
03833
03834
03835 if ( sg_rubberCycleMalusTime > 0 )
03836 rubberMalus /= (1+ts/sg_rubberCycleMalusTime);
03837 else
03838 rubberMalus = 0;
03839
03840
03841
03842 if ( rubber > rubber_granted )
03843 rubber = rubber_granted;
03844
03845
03846 lastTime=currentTime;
03847
03848
03849 if (emergency)
03850 {
03851 RightBeforeDeath(numTries);
03852 }
03853
03854 #ifdef DEBUGOUTPUT
03855 if ( sg_cycleDebugPrintLevel > 1 )
03856 con << Player()->GetName() << " moved " << pos << "," << dirDrive << " " << tSysTimeFloat() << "\n";
03857 #endif
03858
03859
03860
03861
03862
03863
03864
03865
03866
03867
03868
03869
03870
03871 if ( !sg_verletIntegration.Supported() )
03872 this->ApplyAcceleration( ts );
03873
03874 tASSERT(finite(distance));
03875
03876 tASSERT( rubber >= 0 );
03877
03878
03879 return eNetGameObject::Timestep(currentTime);
03880 }
03881
03882
03883
03884
03885
03886
03889
03890
03891 void gCycleMovement::MyInitAfterCreation( void )
03892 {
03893 #ifdef DEBUG
03894
03895 #endif
03896 brakingReservoir = 1.0f;
03897
03898 braking = false;
03899
03900 acceleration = 0;
03901
03902 refreshSpaceAhead_ = true;
03903 maxSpaceMaxCast_ = 0.0;
03904 maxSpaceHit_ = NULL;
03905
03906 dir=dirDrive;
03907 lastDirDrive=dirDrive;
03908 lastTurnPos_=pos;
03909
03910 distance=0;
03911
03912 rubber=0.0f;
03913 rubberMalus=0.0f;
03914 rubberSpeedFactor=1.0f;
03915
03916 gap_[0] = gap_[1] = 1E+30;
03917 keepLookingForGap_[0] = keepLookingForGap_[1] = true;
03918
03919 alive_ = 1;
03920
03921 z=.75;
03922
03923 turns=1;
03924
03925 pendingTurns.clear();
03926 lastTurnTimeRight_ = lastTurnTimeLeft_=lastTime-10;
03927
03928 lastTimeAlive_ = lastTime;
03929
03930 if (!finite(verletSpeed_)){
03931 st_Breakpoint();
03932 verletSpeed_ = 1;
03933 }
03934
03935 if (verletSpeed_ < .1)
03936 verletSpeed_=.1;
03937
03938 #ifdef DEBUGOUTPUT
03939 if ( sg_cycleDebugPrintLevel > 0 )
03940 con << Player()->GetName() << " created " << pos << "," << dirDrive << " " << tSysTimeFloat() << "\n";
03941 #endif
03942 }
03943
03944
03945
03946
03947
03948
03951
03952
03953
03954
03955
03956
03957
03958
03959
03960
03961
03962
03965
03966
03967
03968
03969
03970
03971
03972
03973
03974
03975
03976
03979
03980
03981
03982
03983
03984
03985
03986
03987
03988
03989
03990
03994
03995
03996
03997
03998
03999
04000
04001
04002
04003
04004
04005
04010
04011
04012
04013
04014
04015
04016
04017
04018
04019
04020
04021
04022
04026
04027
04028
04029
04030
04031
04032
04033
04034
04035
04036
04037
04041
04042
04043 REAL gCycleMovement::DoGetDistanceSinceLastTurn( void ) const
04044 {
04045 return eCoord::F( dirDrive, pos - lastTurnPos_ )/dirDrive.NormSquared();
04046 }
04047
04048
04049
04050
04051
04052
04056
04057
04058 bool gCycleMovement::RubberMalusActive( void )
04059 {
04060 return sg_rubberCycleMalusTurn > 0;
04061 }
04062
04063
04064
04065
04066
04067
04073
04074
04075 void gCycleMovement::MoveSafely( const eCoord & dest, REAL startTime, REAL endTime )
04076 {
04077 static bool recursing = false;
04078 if ( !recursing )
04079 {
04080 recursing = true;
04081 try
04082 {
04083
04084 Move( dest, startTime, endTime );
04085 }
04086 catch( eDeath & death )
04087 {
04088
04089 short lastAlive = alive_;
04090 alive_ = 0;
04091 Move( dest, startTime, endTime );
04092 alive_ = lastAlive;
04093 }
04094 }
04095 else
04096 {
04097
04098
04099
04100
04101 short lastAlive = alive_;
04102 alive_ = 0;
04103 Move( dest, startTime, endTime );
04104 alive_ = lastAlive;
04105 }
04106 }
04107
04108 REAL GetTurnSpeedFactor(void) {
04109 return sg_cycleTurnSpeedFactor;
04110 }
04111
04112
04113
04114
04115
04116
04120
04121
04122 REAL gCycleMovement::NextInterestingTime( void ) const
04123 {
04124
04125 REAL ret = LastTime();
04126
04127
04128 gDestination * run = currentDestination;
04129 while ( run )
04130 {
04131 REAL time = run->GetGameTime();
04132 if ( time > ret )
04133 ret = time;
04134 run = run->next;
04135 }
04136
04137 return ret;
04138 }
04139
04140 void gCycleMovement::AddZoneAcceleration( REAL zoneAcceleration )
04141 {
04142 totalZoneAcceleration += zoneAcceleration;
04143 }