@@ -528,25 +528,46 @@ boolean P_LookForPlayers(mobj_t * actor, boolean allaround)
528
528
player_t * player ;
529
529
angle_t an ;
530
530
fixed_t dist ;
531
+ int consecutive_missing = 0 ; // for breaking infinite loop
531
532
532
533
if (!netgame && players [0 ].health <= 0 )
533
534
{ // Single player game and player is dead, look for monsters
534
535
return (P_LookForMonsters (actor ));
535
536
}
536
537
c = 0 ;
537
538
538
- // NOTE: This behavior has been changed from the Vanilla behavior, where
539
- // an infinite loop can occur if players 0-3 all quit the game. Although
540
- // technically this is not what Vanilla does, fixing this is highly
541
- // desirable, and having the game simply lock up is not acceptable.
542
- // stop = (actor->lastlook - 1) & 3;
543
- // for (;; actor->lastlook = (actor->lastlook + 1) & 3)
539
+ // The 3 below is probably a mistake (it should be MAXPLAYERS - 1, or 7)
540
+ // and in vanilla this can potentially cause an infinite loop in
541
+ // multiplayer. Unfortunately we can't correct the mistake - doing so will
542
+ // cause desyncs. Upon spawning, each enemy's lastlook is initialized to a
543
+ // random value between 0 and 7 (i.e MAXPLAYERS - 1). There's a chance
544
+ // that the first call of this function for that enemy will return early
545
+ // courtesy of the actor->lastlook == stop condition. In a single-player
546
+ // game this occurs when (actor->lastlook - 1) & 3 equals 0, or when
547
+ // lastlook equals 1 or 5.
544
548
545
- stop = (actor -> lastlook + maxplayers - 1 ) % maxplayers ;
546
- for (;; actor -> lastlook = (actor -> lastlook + 1 ) % maxplayers )
549
+ // If you use MAXPLAYERS - 1, it has the side effect of altering which
550
+ // enemies are affected by an early actor->lastlook == stop return. Now it
551
+ // happens when (actor->lastlook - 1) & 7 equals 0, or when lastlook equals
552
+ // 1, *not* 1 and 5 as above.
553
+
554
+ stop = (actor -> lastlook - 1 ) & 3 ;
555
+ for (;; actor -> lastlook = (actor -> lastlook + 1 ) & 3 )
547
556
{
548
557
if (!playeringame [actor -> lastlook ])
558
+ {
559
+ // Break the vanilla infinite loop here. It can occur if there are
560
+ // > 4 players and players 0 - 3 all quit the game. Error out
561
+ // instead.
562
+ if (consecutive_missing == 4 )
563
+ {
564
+ I_Error ("P_LookForPlayers: No player 1 - 4.\n" );
565
+ }
566
+ consecutive_missing ++ ;
549
567
continue ;
568
+ }
569
+
570
+ consecutive_missing = 0 ;
550
571
551
572
if (c ++ == 2 || actor -> lastlook == stop )
552
573
return false; // done looking
0 commit comments