Date: 17 May 2001 14:33:25 -0000 Message-ID: <20010517143325.25271.qmail@nym.alias.net> From: Michael Hedera Newsgroups: rec.games.roguelike.nethack Subject: [PATCH] YA speed system [LONG] Mail-To-News-Contact: abuse@dizum.com Organization: mail2news@dizum.com Lines: 369 [This is a repost. I have never seen the original posting, even in Doogle. Apologies if you see it twice] Some time ago, I posted a patch modifying the NetHack speed system. I made some improvements to it, and fixed some bugs. Here is a new version. A few comments on how (I hope) it works: All the monsters and the player have their counters (mtmp->movement and youmonst.movement, respectively). The game goes in little steps (counted by mainclock), at each step decrementing the player's and monters' counters (if positive) by TIME_STEP, by default 10. When a monster's counter is <= 0, this monster will move: a variable (mtmp->timet) is set to the base time taken by the move, then the move happens, then mtmp->timet (randomized a bit) is added to the monster's movement counter. As I wanted to keep the patch relatively short, I left the general layout of moveloop() unchanged, so the code still looks very assymetrical; the part handling player's move is done "inside out". The mtmp->timet can in principle be modified during the "move happens". This should make it relatively straightforward to make different actions take different amounts of time: just add: mtmp->timet = 3 * mtmp->timet / 5 or somesuch in the code performing given action. The base time taken by a monster's move is NLENUNIT (default 1440) divided by monster's speed; immobile creatures get a special treatment. The patch also uses flags.step, which is true if the last player's move was... well... movement, not fight or something else. It is used in allmain.c to (hopefully) fix the bug of steeds being speeded up by the player wearing speed boots. --- include/permonst.ori Wed Jan 17 23:31:59 2001 +++ include/permonst.h Tue May 15 10:03:43 2001 @@ -72,6 +72,11 @@ #define FAST_SPEED 15 #define VERY_FAST 24 +#define TIME_STEP 10 /* smallest time an action can take */ +#define NLENUNIT 1440 /* NetHack length unit */ + /* NLENUNIT / NORMAL_SPEED is the time taken to move one step + at normal speed */ + #define NON_PM PM_PLAYERMON /* "not a monster" */ #define LOW_PM (NON_PM+1) /* first monster in mons[] */ #define SPECIAL_PM PM_LONG_WORM_TAIL /* [normal] < ~ < [special] */ --- include/monst.ori Thu Dec 7 21:47:04 2000 +++ include/monst.h Tue May 15 10:03:43 2001 @@ -41,6 +41,7 @@ unsigned m_id; short mnum; /* permanent monster index number */ short movement; /* movement points (derived from permonst definition and added effects */ + short timet; /* time taken by action */ uchar m_lev; /* adjusted difficulty level of monster */ aligntyp malign; /* alignment of this monster, relative to the player (positive = good to kill) */ --- include/flag.ori Mon Dec 11 23:59:18 2000 +++ include/flag.h Tue May 15 10:03:43 2001 @@ -53,6 +53,7 @@ boolean mon_moving; /* monsters' turn to move */ boolean move; boolean mv; + boolean step; /* last move was a(n attempted) step */ boolean nap; /* `timed_delay' option for display effects */ boolean nopick; /* do not pickup objects (as when running) */ boolean null; /* OK to send nulls to the terminal */ --- src/allmain.ori Sun Sep 10 23:59:49 2000 +++ src/allmain.c Tue May 15 10:24:08 2001 @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)allmain.c 3.3 2000/05/05 */ +/* SCCS Id: @(#allmain.c 3.3 2000/05/05 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -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,13 @@ (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 */ + if (youmonst.data->mmove > 0) + youmonst.timet = NLENUNIT / youmonst.data->mmove; + else youmonst.timet = TIME_STEP; + + mainclock = 0; for(;;) { #ifdef CLIPPING cliparound(u.ux, u.uy); @@ -71,81 +77,78 @@ didmove = flags.move; if(didmove) { /* actual time passed */ - youmonst.movement -= NORMAL_SPEED; + +#ifdef STEED + if (u.usteed && flags.step) { + /* your speed doesn't augment steed's speed */ + youmonst.timet = mcalcmove(u.usteed); /* FIXME? */ + } else +#endif + { + if (Very_fast) { + /* speed boots or potion */ + /* average movement is 1.67 times normal */ + youmonst.timet = (youmonst.timet*3)/5; + } else if (Fast) { + /* average movement is 1.33 times normal */ + youmonst.timet = (youmonst.timet*3)/4; + } + } + + /* currently encumberance slows all actions equally */ + switch (wtcap) { + case UNENCUMBERED: break; + case SLT_ENCUMBER: youmonst.timet += youmonst.timet/3; break; + case MOD_ENCUMBER: youmonst.timet += youmonst.timet; break; + case HVY_ENCUMBER: youmonst.timet += youmonst.timet*3; break; + case EXT_ENCUMBER: youmonst.timet += youmonst.timet*7; break; + default: break; + } + + if (youmonst.data->mmove > 0) + youmonst.movement += youmonst.timet; + else youmonst.movement = TIME_STEP; /* low, 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 > 0)) + youmonst.movement -= TIME_STEP; + 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 ((mtmp->data->mmove > 0) && (mtmp->movement > 0)) + mtmp->movement -= TIME_STEP; + } + + 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,12 +277,17 @@ unmul((char *)0); } } - } while (youmonst.movement 0); /* hero can't move loop */ /******************************************/ /* once-per-hero-took-time things go here */ /******************************************/ + /* set base duration for next move */ + /* youmonst.timet can be modified when moving */ + if (youmonst.data->mmove > 0) + youmonst.timet = NLENUNIT / youmonst.data->mmove; + else youmonst.timet = TIME_STEP; } /* actual time passed */ @@ -364,6 +372,7 @@ sanity_check(); #endif + flags.step = 0; u.umoved = FALSE; if (multi > 0) { --- src/mon.ori Sun Sep 10 23:59:49 2000 +++ src/mon.c Tue May 15 10:24:08 2001 @@ -401,7 +401,8 @@ } #endif - return mmove; + if (mmove > 0) return NLENUNIT / mmove; + else return TIME_STEP; /* low, but > 0 */ } /* actions that happen once per ``turn'', regardless of each @@ -439,7 +440,6 @@ movemon() { register struct monst *mtmp, *nmtmp; - register boolean somebody_can_move = FALSE; #if 0 /* part of the original warning code which was replaced in 3.3.1 */ warnlevel = 0; @@ -470,22 +470,21 @@ /* 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; + mtmp->timet = mcalcmove(mtmp); /* may be overwritten when moving */ + if (!mtmp->data->mmove) continue; /* immobile */ - if (minwater(mtmp)) continue; + if (minwater(mtmp)) goto admove; if (is_hider(mtmp->data)) { /* unwatched mimics and piercers may hide again [MRS] */ - if(restrap(mtmp)) continue; + if(restrap(mtmp)) goto admove; if(mtmp->m_ap_type == M_AP_FURNITURE || mtmp->m_ap_type == M_AP_OBJECT) - continue; - if(mtmp->mundetected) continue; + goto admove; + if(mtmp->mundetected) goto admove; } /* continue if the monster died fighting */ @@ -501,10 +500,12 @@ if (couldsee(mtmp->mx,mtmp->my) && (distu(mtmp->mx,mtmp->my) <= BOLT_LIM*BOLT_LIM) && fightm(mtmp)) - continue; /* mon might have died */ + goto admove; /* mon might have died */ } if(dochugw(mtmp)) /* otherwise just move the monster */ - continue; + continue; /* dead don't need movement */ +admove: if (mtmp->data->mmove > 0) + mtmp->movement += 2*mtmp->timet/3 + rn2(1+2*mtmp->timet/3); } #if 0 /* part of the original warning code which was replaced in 3.3.1 */ @@ -520,10 +521,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 */ --- src/monmove.ori Sat Mar 10 01:53:37 2001 +++ src/monmove.c Tue May 15 10:24:08 2001 @@ -912,8 +912,8 @@ return 2; if ((mstatus & MM_HIT) && !(mstatus & MM_DEF_DIED) && - rn2(4) && mtmp2->movement >= NORMAL_SPEED) { - mtmp2->movement -= NORMAL_SPEED; + rn2(4) && mtmp2->movement < mcalcmove(mtmp2)) { + mtmp2->movement += mcalcmove(mtmp2); notonhead = 0; mstatus = mattackm(mtmp2, mtmp); /* return attack */ if (mstatus & MM_DEF_DIED) --- src/hack.ori Tue Dec 12 00:09:26 2000 +++ src/hack.c Tue May 15 10:24:08 2001 @@ -745,7 +745,11 @@ unmap_object(x, y); newsym(x, y); } + /* not attacking an animal, so we try to move */ + + flags.step = 1; + #ifdef STEED if (u.usteed && !u.usteed->mcanmove && (u.dx || u.dy)) { pline("%s won't move!", Monnam(u.usteed));