Jump to content
NHL'94 Forums

HOW TO: Fix The Weight Bug (Gens)


smozoma

Recommended Posts

(v1.2 - update June 29 2009)

Here is a program that applies the Weight Bug Fix to your ROM. It has a few options:

1. Apply the Weight Bug Fix hack + another hack that makes the game record Checks-For and Checks-Against for each player

2. Apply just the weight bug fix hack, or

3. Apply just the record Checks-For and Checks-Against hack.

NHL94WeightBugFix1.2.zip

(There is a side-effect with the "Checks-For and Checks-Against" hack: it overwrites the PIM stat with CkF (checks for), so if you have a stat system like GDL/Blitz, then you need to manually count PIM for each player using the penalty summary.)

------------------------------------------------------------

For those interested, here are my notes on how to do the weight bug fix. There is the 'simple' weight bug fix, and the 'improved weight bug fix' which combines a player's weight and checking attributes to decide whether a check will work. The program above only does the 'improved weight bug fix'.

a line of code in my notes might look like this:

52 28 01 1C -- ADDQ.B #1,$011C(A0) -- increment check value

52 28 01 1C is the actual code that you put in the ROM using a hex editor

ADDQ.B #1,$011C(A0) is what the hex code translates to in assembly code

increment check value is my description of what the code/instruction does

If you open an NHL94 ROM in a hex editor and go to the end, you'll see a bunch 
of "FFFFFF...".  This is empty space in the ROM.  I use this empty space to add
new code to the ROM.  When I want to change the behaviour of the original code,
I overwrite the original code with code that tells the ROM to look at my code
at the end of the ROM (using a "JSR" instruction).  My code then does what I 
want to do (like add 1 check to a player who did a check).  Then at the end of 
my code, I jump back to place after my "JSR" instruction, to keep doing whatever
the game was doing before.

When a fix adds code at the end of the ROM, let "gggggggg" or "gg:gggg" be the 
location of the unused code section of the ROM (the "FF" bytes, 
so gggggggg is where those FFs start. For example, 00fffac2 for a 
28-team ROM and 01E2af2 for a 30-team ROM).  The last number should always be 
even (0,2,4,6,8,A,C,E).

================================================================================
SIMPLE WEIGHT BUG FIX - CHECKING BASED ONLY ON WEIGHT
--------------------------------------------------------------------------------
This hack doesn't involve using the empty space at the end of the ROM.  You 
just need to change 2 values in the original ROM (switch 2a and 2b).  
Easiest hack ever!
(A2) is the info array of the player getting checked
(A3) is the info array of the player trying to check

@ 01:3D72 (NHL '94) or 00:FF40 (NHLPA '93)
::Old::
   90 2b 00 67         - SUB.B #$0067(A3),D0 - sub guy checking's (wgt*8)
   d0 2a 00 67         - ADD.B #$0067(A2),D0 - add guy getting checked (wgt*8)
::New::
   90 2a 00 67         - SUB.B #$0067(A2),D0 - sub guy getting checked (wgt*8)
   d0 2b 00 67         - ADD.B #$0067(A3),D0 - add guy checking's (wgt*8)

================================================================================
IMPROVED WEIGHT BUG FIX - CHECKING BASED ON WEIGHT AND CHECKING ATTRIBUTE
--------------------------------------------------------------------------------
(A2) is the info array of the player getting checked
(A3) is the info array of the player trying to check

Make sure the bytes at 01:3D70 are E3 40

@ 01:3D72
::Old::
   90 2b 00 67     -- SUB.B #$0067(A3),D0      -- sub guy checking's (wgt*8)
   d0 2a 00 67     -- ADD.B #$0067(A2),D0      -- add guy getting checked (wgt*8)
::New::
   4e b9 gggg gggg -- JSR $(empty code)
   4e 71           -- NOP

@ gg:gggg
::Old::
   FF FF FF FF ...
::New::
   3F 01           -- MOVE.W   D1,-(A7)        -- push d1
   90 2a 00 67     -- SUB.B    #$0067(A2),D0   -- sub guy getting checked (wgt*8)
                                               -- (let x = current value of d0, which is $78 or $F0)
   12 2B 00 67     -- MOV.B    #$0067(A3),D1   -- d1 = ckr wgt     -- d1 = wgt*8
   E2 01           -- ASR.B    #1,D1           -- d1 /= 2          -- d1 = wgt*4
   D0 01           -- ADD.B    D1, D0          -- d0 += d1         -- d0 = x + wgt*4
   E2 01           -- ASR.B    #1,D1           -- d1 /= 2          -- d1 = wgt*2
   D0 01           -- ADD.B    D1, D0          -- d0 += d1         -- d0 = x + wgt*6
   12 2B 00 75     -- MOV.B    #$0075(A3),D1   -- d1 = ckr chk     -- d1 = chk*5+0.5 (the bonus averages about 0.5)
   E3 01           -- ASL.B    #1,D1           -- d1 *= 2          -- d1 = chk*10+1
   D0 01           -- ADD.B    D1, D0          -- d0 += d1         -- d0 = x + wgt*6 + chk*10+1
   04 00 00 0E     -- SUBI.B   #$0E, D0        -- d0 -= 14         -- d0 = x + wgt*6 + chk*10+1 - 14
   32 1F           -- MOVE.W   (A7)+,D1        -- pop d1
   4e 75           -- RTS

   You can change the value subtracted with the SUBI.B to make it harder or 
   easier to check, overall.  Subtract less to make it easier to check, 
   subtract more to make it harder.  I chose 14 because it made the average of 
   the formula equal to the average wgt*8.  wgt*8 is the check resistance of 
   the players.

================================================================================
CHECK STATS
--------------------------------------------------------------------------------
This replaces the PIM stat in the Player Stats screen with CHK (checks) per player.
It also adds a Checks Against stat per player (overwriting the original hidden check stat).
(A0) is $C6CE or $CA32, the start of the home or away team stats, respectively.
(A2) is the info array of the player getting checked
(A3) is the info array of the player giving the check

Replace "PIM" text with "CHK" in Player Stats screen.
@ 00:993F
::Old::
   50 49 4D        -- PIM   -- ASCII text "PIM"
::New::
   43 48 4B        -- CHK   -- ASCII text "CHK"


Replace the "increment team and player check count" with a jump to custom code:
@ 01:4130
::Old::
   52 68 00 10         -- ADDQ.W    #1,$0010(A0)
   42 40               -- CLR.W     D0
   10 2B 00 66         -- MOVE.b    $0066(A3),D0   -- d0 = player index/offset in team     
   D0 C0               -- ADDA.W    D0,A0          -- a0 += player index/offset
   52 28 01 1C         -- ADDQ.B    #1,$011C(A0)   -- increment check value
   (we can change the value of A0 because it isn't used later until reset to another value)

::New::
   4e b9 gggg gggg     -- JSR       $gggggggg
   4e 71 4e 71         -- NOP, NOP
   4e 71 4e 71         -- NOP, NOP
   4e 71

Here is our custom code:
@ hh:hhhh
::Old::
   FF FF FF FF ...
::New::

   1. Increment team check count
   52 68 00 10             -- ADDQ.W   #1,$0010(A0)    -- inc team check count for the Game Stats 
                                                       -- screen (checks after the whistle count)

   2. If the game is halted (whistle blown), branch to skip recording individual checks
   08 39 00 00 00 ff c2 ea -- BTST     #0,($00FFC2EA)  -- if the bit not 0, we will branch
   66 00 00 2A             -- BNE      $002A           -- branch to the RTS to skip checks after whistle

   (NOTE: if you want to also not count checks after the whistle in the Game 
   Stats screen, then move the "1." code below "2." and change "66 00 00 2A" 
   to "66 00 00 2E")

   3. Increment check (for) count for individual players
   42 40                   -- CLR.W    D0
   10 2B 00 66             -- MOVE.b   $0066(A3),D0    -- d0 = player index (offset in team)
   D0 C0                   -- ADDA.W   D0,A0           -- a0 += player index
   52 28 01 02             -- ADDQ.B   #1,$0102(A0)    -- increment check value

   4. Increment check (against) count for individual players
   90 C0                   -- SUBA.W   D0, A0          -- undo the ADDA.W above
   90 FC 03 64             -- SUBA.W   #$0364,A0       -- back up A0 to Home Players stat array
   B7 CA                   -- CMPA.L   a2,a3           -- cmp a3-a2  (cmp checker-checkee)
   6E 00 00 06             -- BGT      #$0006          -- if a3-a2 is positive, it's a check against
                                                       -- a home player, so skip next instruction
   D0 FC 06 C8             -- ADDA.W   #$06C8,A0       -- go to Away Players stat array
   42 40                   -- CLR.W    D0              -- set D0 to zero
   10 2A 00 66             -- MOV.B    #$0066(A2),D0   -- set D0 = player index of checked player
   D0 C0                   -- ADDA.W   D0,A0           -- a0 += player index
   52 28 01 1C             -- ADDQ.B   #1,$011C(A0)    -- increment check against value

   5. return
   4e 75                   -- RTS


Don't write PIM stat -- we're using that memory for check stats!
@ 01:2302
::Old::
   D5 32 00 00             -- ADD.B    D2,$00(A2,D0)
::New::
   4E 71 4E 71             -- NOP NOP       

================================================================================

--

Explanation:

In the "Simple" version of the weight bug fix, the 2 lines of code being edited are below (SUB.B and ADD.B instructions).

When the game first starts, it takes each player's weight, multiplies it by 8, and stores it somewhere, then it uses that value when doing checking.

This code retrieves those values and does a calculation with them to decide if the check succeeds or not. Here, I have Gretzky (weight=4, so 8*4=32) trying to check Muller (weight=9, so 8*9=72)

(note: D0 is a register(like a variable) with an initial value of 240)

90 2B 00 67 :: SUB.B $0067(A3),D0

-- D0 = D0-8*(gretz's wgt)

-- D0 = 240 - 32 = 208

-- (for mcsorley it would be D0 = 240 - 112 = 128)

-- (A3) points to information about Gretzky and $0067 means to get his wgt*8 value

D0 2A 00 67 :: ADD.B $0067(A2),D0

-- D0 = D0+8*(muller's wgt)

-- D0 = 208 + 72 = 280

-- but since 280 is too big (this is a Byte command, so max 255), it becomes:

-- D0 = 208 + 72 = 24

-- (had it been mcsorley trying to check: D0 = 128 + 8*9 = 200)

-- (A2) points to information about Muller and $0067 means to get his wgt*8 value

After this, it divides the result by 2, then does some stuff I don't understand!

The fix just swiches (A2) and (A3) in the instructions.

--

I played gr8199kings a few games with a ROM with this fix, and it works. Guys like McSorley and Lemieux are tough to knock down. Guys like Gretzky are easy to knock down, but because low weight makes guys turn and accelerate better, it's very hard to catch him to check him with a big, lumbering, slow guy who can check well.

Whether this actually improves the fun factor of the game or not is another matter..

You can download a ROM with the fix in it here

Edited by smozoma
  • Thanks 1
Link to comment
Share on other sites

could this maybe mean that there's a chance that the CHK ability has a purpose in life?

Nah, checking just affects how often they check (the AI) -- watch Ray Bourque play under AI control, he's hilarious.

Link to comment
Share on other sites

I've tried making teams that are all the same , except one team's players all have '6' for checking and the other team's players all have '1'. Playing as both teams, I didn't feel like either team checked better than the other (though the team with 6 did a lot more AI checking). So, I'm pretty sure now that the checking really has no bearing on a player's actual ability to check.

So, I found a way to factor the players' checking rating into their actual ability to check. I did it by adding (10*(chk-3)) into the checking code (but then i had to subtract an extra 2 due to some random bonus the game gives...)

A bit of background:

When a player takes to the ice, the game calculates:

  • weight = 8*(weight in rom (1-15)) --- so this is 32 for roenick(4*8) and 80 for bourque(10*8)
  • checking = 5*(checking in rom (0-6)) + (some random bonus between -1 and 2 that is constant for the game for that player for checking)

The original (bug-fixed) algorithm is

  1. checkvalue = 120 or 240 depending on something i don't understand (EDIT: I think this ended up being the C/B check bug - the value depends on whether you control the player or not)
  2. checkvalue = checkvalue - (weight of guy getting checked)
  3. checkvalue = checkvalue + (weight of guy checking)
  4. checkvalue = checkvalue / 2
  5. magic (???)

To factor in the checking rating:

  1. checkvalue = 120 or 240 depending on something i don't understand
  2. redirect execution of code to an empty area of the ROM where i added new instructions (instructions 3-8)
  3. checkvalue = checkvalue - (weight of guy getting checked)
  4. checkvalue = checkvalue + (weight of guy checking)
  5. checkvalue = checkvalue + (checking of guy checking)
  6. checkvalue = checkvalue + (checking of guy checking) --- add again.. adding twice is faster than multiplying
  7. checkvalue = checkvalue - 32
  8. return to original code execution place.
  9. (empty instruction)
  10. checkvalue = checkvalue / 2
  11. magic (???)

Where does the 32 come from?

I didn't want to just add checking into the formula, because then even a guy with 1 checking would suddenly be able to check better. so i wanted to use something like +(chk - average chk).

  • the average checking rating in the game is around 3 (a bit less for forwards, a bit more for defensemen).
  • 3*5=15. --- because the game multiplies the players' chk ratings by 5
  • 15*2 = 30. --- because i added the 5*chk rating twice
  • that random bonus between -1 and 2 will have an average value of +1, so to counter that, i subtract an extra 2 (because i multiplied the weight value by 2 when putting it in the formula)

In the compressed ROMs, you can add code at address $0f:fb10.

In the uncompressed ROMS, you can add code at address $1f:2b00

Here is the assembly code to insert (overwriting the old code):

At ROM address $01:3D72:

4e b9 00 0f fb 10 - JSR $000ffb10 (use 001e2b00 instead for uncompressed ROM)

4e 71 - NOP

At ROM address $0f:fb10 (use 1e:2b00 for uncompressed ROM). You should be overwriting a bunch of "FF" bytes.

90 2a 00 67 - SUB.B #$0067(A2),D0 - sub guy getting checked (wgt*8)

d0 2b 00 67 - ADD.B #$0067(A3),D0 - add guy checking's (wgt*8)

d0 2b 00 75 - ADD.B #$0075(A3),D0 - add guy checking's (chk*5)

d0 2b 00 75 - ADD.B #$0075(A3),D0 - add guy checking's (chk*5)

04 00 00 20 - SUBI.B #20, D0 - subtract 32 (to bias checking so a chk of 3 is no modifier)

4e 75 - RTS

uhh.. hope that makes some sense to someone

Link to comment
Share on other sites

In the above hack, when a player has a checking rating of 3, they get no checking advantage (the -32 counters it). 3 is about the average checking rating.

If a player has a checking rating of 4 (that's 1 above average), they get +10 overall to the calculation that decides if the check works or not. In comparison, a single weight point counts for +8. So, a 4 in checking is roughly equivalent to a whole extra weight point (1.25 actually). So, a player with a checking of 4 can check a player who weighs 1 more than him.

If a player has 2 checking, he gets -10 in the calculation, so he will check like a player who weighs 1 weight point less than him.

No bonus (wgt=3):

McSorley: wgt=14, chk=3 => wgt=14*8=112, chk=(3-3)*10=0 => actual checking ability = 112 + 0 = 112

Lemieux: wgt=10, chk=3 => wgt=10*8=80, chk=(3-3)*10=0 => actual checking ability = 80+ 0 = 80

Lafontaine: wgt=5, chk=3 => wgt=5*8=40, chk=(3-3)*10=0 => actual checking ability = 40+ 0 = 40

Positive Bonus (wgt>3):

Bourque: wgt=10, chk=6 => wgt=10*8=80, chk=(6-3)*10=30 => actual checking ability = 80 + 30 = 110

Lindros: wgt=12, chk=5 => wgt=12*8=96, chk=(5-3)*10=20 => actual checking ability = 96 + 20 = 116

Mike Eagles: wgt=7, chk=5 => wgt=7*8=56, chk=(5-3)*10=20 => actual checking ability = 56 + 20 = 76

Fleury: wgt=3, chk=4 => wgt=3*8=24, chk=(4-3)*10=10=> actual checking ability = 24 + 10 = 34

Negative Bonus (wgt<3)

Coffey: wgt=9, chk=2 => wgt=9*8=72, chk=(2-3)*10=-10=> actual checking ability = 72 + -10 = 62

Roenick: wgt=4, chk=2 => wgt=4*8=32, chk=(2-3)*10=-10=> actual checking ability = 32 + -10 = 22

Yzerman: wgt=6, chk=1 => 48 - 20 = 28

I've attached a spreadsheet you can look at to see all the players

NHL94_players___wgtchkfix.zip

Link to comment
Share on other sites

So what does the checking rating actually do, smomoza?

Does it only determine frequency of AI checks?

Is player checking all about weight? Or weight-speed combo?

I dunno for sure : )

I don't think Chk affects ability to check, since I tried teams of equal players with unequal Chk ratings, and though the AI was a lot different, my own ability to check seemed the same (really bad).

I think they actually have code about if the player is "ready" for a check.. have you ever noticed that when a guy gets knocked out, he usually just received a pass, or was in the process of turning around, so didn't "see" the player coming?

Link to comment
Share on other sites

Maybe it's just how often the players will try to bodycheck?

Yeah, it definitely does that. Ray Bourque attacks everyone; it's hilarious (99 checking)

Link to comment
Share on other sites

Have you found a way to SNES-ify the checking?

i.e. checks, when lined up properly, and the players are good enough, always seem to nail guys flat on their asses (and I'm talking C-button checks more than B-button, here)

Link to comment
Share on other sites

Have you found a way to SNES-ify the checking?

i.e. checks, when lined up properly, and the players are good enough, always seem to nail guys flat on their asses (and I'm talking C-button checks more than B-button, here)

well.. it's kinda like that anyway already..

Link to comment
Share on other sites

Nice work! I think I could get used to 94 this way. I like the way you've preserved the value of being a light-weight while giving heavier players back their value too.

Is there an updated rom with checking factored in? Maybe you could post it in the other thread as well?

Link to comment
Share on other sites

Do you know what determines if a player gets injured when hes hit? and if its for the period or the game?

Ive always wondered what would happen if say you had more then 2 defensive injuries in a draft league. (you only have 4 defense total)

Link to comment
Share on other sites

Guest Wags13
The fact that a major bug like this exists in gens makes it inferior to snes!

I'd rather have the weight bug than have the "entire gameplay" bug that SNES has....

;)

Link to comment
Share on other sites

Nice work! I think I could get used to 94 this way. I like the way you've preserved the value of being a light-weight while giving heavier players back their value too.

Is there an updated rom with checking factored in? Maybe you could post it in the other thread as well?

I'm writing a little program that will let you apply the weight bug fix to any nhl94-based ROM.. and it'll let you decide whether or not to include the checking rating in the calculation.

Link to comment
Share on other sites

I'm writing a little program that will let you apply the weight bug fix to any nhl94-based ROM.. and it'll let you decide whether or not to include the checking rating in the calculation.

Outstanding. :D

Link to comment
Share on other sites

Outstanding. :D

was about to upload it, but then noticed, whoops, i'm not setting the checksum so the rom doesn't load if you apply the checking fix. i'll fix it tomorrow..

Link to comment
Share on other sites

I can't get this program to work unfortunately. When I try to drag the bin onto it, windows says the program is configured incorrectly or something to that effect. I've tried this on both XP and Vista.

Link to comment
Share on other sites

I can't get this program to work unfortunately. When I try to drag the bin onto it, windows says the program is configured incorrectly or something to that effect. I've tried this on both XP and Vista.

can you get me the actual error message?

thanks

(sighh i think this has to do with the new versions of microsoft visual studio.. they have some dumb new 'feature' that makes it hard to share programs..)

Link to comment
Share on other sites

can you get me the actual error message?

thanks

(sighh i think this has to do with the new versions of microsoft visual studio.. they have some dumb new 'feature' that makes it hard to share programs..)

"This application has failed to start because the application configuration is incorrect. Reinstalling the application may fix this problem"

Link to comment
Share on other sites

"This application has failed to start because the application configuration is incorrect. Reinstalling the application may fix this problem"

:) dumb microsoft.

i'll recompile it next week with something non-microsoft! no time right now

anyway, i've been working on an even better checking algorithm.. no time to get it done this weekend, though.

Link to comment
Share on other sites

This is a momentous discovery for NHL'94, the obese, rotund, and all around heavy setters.

It really swings the pendulum back to where it once belonged (if it ever did).

Having the Hatcher's, and Neely's of the world be formidable checking machines, get's the game that much closer to perfection - killing two stones with one bird, neutralizing all of the light weight man crushes that are created by this glitch.

And it's good logic - fat guy hit light guy, light guy fall down. Plus the Tim Kerr's, and Lindros's should be harder to knock off the puck - giving some of the slower players and bangers higher stock - and this makes them much more valuable down low.

The actual bug is still at large, but this really remedies the ailment.

Some of you purists might think the stick tape, new rosters, or Tony's finds are superfluous. But this should be mandatory.

To me, it's as important, if not more important than all the other game play or cosmetic tweaks.

Great job, can't say it enough.

Link to comment
Share on other sites

This is a momentous discovery for NHL'94, the obese, rotund, and all around heavy setters.

It really swings the pendulum back to where it once belonged (if it ever did).

Having the Hatcher's, and Neely's of the world be formidable checking machines, get's the game that much closer to perfection - killing two stones with one bird, neutralizing all of the light weight man crushes that are created by this glitch.

And it's good logic - fat guy hit light guy, light guy fall down. Plus the Tim Kerr's, and Lindros's should be harder to knock off the puck - giving some of the slower players and bangers higher stock - and this makes them much more valuable down low.

The actual bug is still at large, but this really remedies the ailment.

Some of you purists might think the stick tape, new rosters, or Tony's finds are superfluous. But this should be mandatory.

To me, it's as important, if not more important than all the other game play or cosmetic tweaks.

Great job, can't say it enough.

Completely agreed. And light players will still accelerate faster and possess more agility so it would seem to strike a better balance overall. Checking out the player spreadsheet that Smozoma posted, I noticed some players who will definitely be happy with the return of their mojo.

Smozoma, wondering if your program will work with all roms?

Link to comment
Share on other sites

Completely agreed. And light players will still accelerate faster and possess more agility so it would seem to strike a better balance overall. Checking out the player spreadsheet that Smozoma posted, I noticed some players who will definitely be happy with the return of their mojo.

Smozoma, wondering if your program will work with all roms?

The 93s etc? Nope, I haven't looked at them at all. Maybe some day...

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Who's Online   0 Members, 0 Anonymous, 69 Guests (See full list)

    • There are no registered users currently online
×
×
  • Create New...