Subject: Re: bugs in speed system?

From: Michael Hedera <[email-masked]>
Date: 22 Nov 2000 14:02:10 -0000

Jason Short <[email-masked]> wrote:
> Michael Hedera wrote:
> > 
> > Even in the modified speed system, a fast air elemental has speed
                ^^^^^^^^^^^^^^^^^^^^^
> > 48 = 36*4/3; a very fast player has speed 20 = 12*5/3, which is
> > less than half of 48, so it seems the fast air elemental should
> > sometimes get three moves in a row. As the movement is somewhat
> > randomized to make ineffective the hit - step dance, even a normal
> > air elemental (speed 36 - just a little below 2*20) might get
> > lucky.
> 
> A fast air elemental with speed 48 will get a flat 4 moves per round.  A
> player with an *average* speed of 20 will get 1 move 1/3 of the time and
> 2 moves 2/3 of the time.  Obviously, when the player gets one move the
> air elemental will get *4* in a row (@ E E E E) - and even if it wasn't
> fast it would get three in a row (@ E E E).  This is expected (although
> unfortunate for the player).

In the vanilla speed system, yes. That's one of the reasons to try
to change it. A patch follows. The (@ E E E E) is still possible for
a fast air elmental, and (@ E E E) for a normal one, but both are
rare; eliminating such possibilities altogether would, as a side
effect, make the monster movements too predictable.

--- allmain.ori	Wed Nov 22 13:37:29 2000
+++ allmain.c	Wed Nov 22 13:39:21 2000
@@ -25,6 +25,7 @@
 #endif
     int moveamt = 0, wtcap = 0, change = 0;
     boolean didmove = FALSE, monscanmove = FALSE;
+    long mainclock;
 
     flags.moonphase = phase_of_the_moon();
     if(flags.moonphase == FULL_MOON) {
@@ -57,8 +58,9 @@
     (void) encumber_msg(); /* in case they auto-picked up something */
 
     u.uz0.dlevel = u.uz.dlevel;
-    youmonst.movement = NORMAL_SPEED;	/* give the hero some movement points */
-
+    youmonst.movement = 0;	/* the hero has the first move */
+    
+    mainclock = 0;
     for(;;) {
 #ifdef CLIPPING
 	cliparound(u.ux, u.uy);
@@ -71,81 +73,78 @@
 	didmove = flags.move;
 	if(didmove) {
 	    /* actual time passed */
-	    youmonst.movement -= NORMAL_SPEED;
+	    int duration;
+
+#ifdef STEED	    
+	    if (u.usteed && flags.mv) {
+		/* your speed doesn't augment steed's speed */
+		duration = mcalcmove(u.usteed);   /*  FIXME? */
+	    } else 
+#endif	    
+	    {
+		if (youmonst.data->mmove > 0)
+		    duration = 1440/youmonst.data->mmove;
+		
+		if (Very_fast) {
+		/* speed boots or potion */
+		/* average movement is 1.67 times normal */
+		duration = (duration*3)/5;
+		} else if (Fast) {
+		/* average movement is 1.33 times normal */
+		duration = (duration*3)/4;
+		}
+	    }
+
+	    switch (wtcap) {
+	    case UNENCUMBERED: break;
+		case SLT_ENCUMBER: duration += duration/3; break;
+		case MOD_ENCUMBER: duration += duration; break;
+		case HVY_ENCUMBER: duration += duration*3; break;
+		case EXT_ENCUMBER: duration += duration*7; break;
+		default: break;
+	    }
+     
+	    if (youmonst.data->mmove > 0) youmonst.movement += duration;
+	    else youmonst.movement = 10;   /* arbitrary, but > 0 */
+
+	    settrack();
 
 	    do { /* hero can't move this turn loop */
+		struct monst *mtmp;
 		wtcap = encumber_msg();
-
+		
+		mainclock++;		
+		if (youmonst.data->mmove > 0) youmonst.movement -= 10;
+		
 		flags.mon_moving = TRUE;
-		do {
-		    monscanmove = movemon();
-		    if (youmonst.movement > NORMAL_SPEED)
-			break;	/* it's now your turn */
-		} while (monscanmove);
+		movemon();
 		flags.mon_moving = FALSE;
 
-		if (!monscanmove && youmonst.movement < NORMAL_SPEED) {
-		    /* both you and the monsters are out of steam this round */
-		    /* set up for a new turn */
-		    struct monst *mtmp;
-		    mcalcdistress();	/* adjust monsters' trap, blind, etc */
-
-		    /* reallocate movement rations to monsters */
-		    for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
-			mtmp->movement += mcalcmove(mtmp);
+		for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
+		    if (mcalcmove(mtmp) > 0) mtmp->movement -= 10;
+		}
+
+		if ( !(mainclock % NORMAL_SPEED) ) {
+		    /**********************************/
+		    /* once per "turn" things go here */
+		    /**********************************/
 
+		    mcalcdistress();   /* adjust monsters' trap, blind, etc */
 		    if(!rn2(u.uevent.udemigod ? 25 :
 			    (depth(&u.uz) > depth(&stronghold_level)) ? 50 : 70))
 			(void) makemon((struct permonst *)0, 0, 0, NO_MM_FLAGS);
 
-		    /* calculate how much time passed. */
-#ifdef STEED
-		    if (u.usteed && flags.mv) {
-			/* your speed doesn't augment steed's speed */
-			moveamt = mcalcmove(u.usteed);
-		    } else
-#endif
-		    {
-			moveamt = youmonst.data->mmove;
-
-			if (Very_fast) {	/* speed boots or potion */
-			    /* average movement is 1.67 times normal */
-			    moveamt += NORMAL_SPEED / 2;
-			    if (rn2(3) == 0) moveamt += NORMAL_SPEED / 2;
-			} else if (Fast) {
-			    /* average movement is 1.33 times normal */
-			    if (rn2(3) != 0) moveamt += NORMAL_SPEED / 2;
-			}
-		    }
-
-		    switch (wtcap) {
-			case UNENCUMBERED: break;
-			case SLT_ENCUMBER: moveamt -= (moveamt / 4); break;
-			case MOD_ENCUMBER: moveamt -= (moveamt / 2); break;
-			case HVY_ENCUMBER: moveamt -= ((moveamt * 3) / 4); break;
-			case EXT_ENCUMBER: moveamt -= ((moveamt * 7) / 8); break;
-			default: break;
-		    }
-
-		    youmonst.movement += moveamt;
-		    if (youmonst.movement < 0) youmonst.movement = 0;
-		    settrack();
-
 		    monstermoves++;
 		    moves++;
 
-		    /********************************/
-		    /* once-per-turn things go here */
-		    /********************************/
-
 		    if(Glib) glibr();
 		    nh_timeout();
 		    run_regions();
-
+	
 		    if (u.ublesscnt)  u.ublesscnt--;
 		    if(flags.time && !flags.run)
 			flags.botl = 1;
-
+	
 		    /* One possible result of prayer is healing.  Whether or
 		     * not you get healed depends on your current hit points.
 		     * If you are allowed to regenerate during the prayer, the
@@ -274,7 +273,7 @@
 			    unmul((char *)0);
 		    }
 		}			
-	    } while (youmonst.movement<NORMAL_SPEED); /* hero can't move loop */
+	    } while (youmonst.movement > 0); /* hero can't move loop */
 
 	    /******************************************/
 	    /* once-per-hero-took-time things go here */
--- mon.ori	Wed Nov 22 13:37:44 2000
+++ mon.c	Wed Nov 22 13:39:21 2000
@@ -401,7 +401,8 @@
     }
 #endif
 
-    return mmove;
+    if (mmove > 0) return 1440/mmove;
+    else return 0;   /* immobile */
 }
 
 /* actions that happen once per ``turn'', regardless of each
@@ -439,7 +440,7 @@
 movemon()
 {
     register struct monst *mtmp, *nmtmp;
-    register boolean somebody_can_move = FALSE;
+    int mduration;
 #if 0
     /* part of the original warning code which was replaced in 3.3.1 */
     warnlevel = 0;
@@ -470,12 +471,13 @@
 	/* Find a monster that we have not treated yet.	 */
 	if(DEADMONSTER(mtmp))
 	    continue;
-	if(mtmp->movement < NORMAL_SPEED)
+	if(mtmp->movement > 0)    /* not mtmp's time yet */
 	    continue;
 
-	mtmp->movement -= NORMAL_SPEED;
-	if (mtmp->movement >= NORMAL_SPEED)
-	    somebody_can_move = TRUE;
+	mduration = mcalcmove(mtmp); /* 0 means immobile */
+
+	if (mduration > 0)
+	    mtmp->movement += 2*mduration/3 + rn2(1+2*mduration/3);
 
 	if (minwater(mtmp)) continue;
 
@@ -520,10 +522,9 @@
     if (u.utotype) {
 	deferred_goto();
 	/* changed levels, so these monsters are dormant */
-	somebody_can_move = FALSE;
     }
 
-    return somebody_can_move;
+    return 0;
 }
 
 #endif /* OVL1 */

-- 
Michael Hedera

Truth? I'm not looking for truth. I'm looking for a hammer.