Needle colour mod

From Stunts Wiki

This article refers to a Stunts mod coded by Cas with quite some work from Daniel3D by editing the Restunts source and recompiling it, which allows to configure the instrument needle colour as seen from a car cockpit for each car individually.

History

On 22 August 2021, Ryoma created a thread where he mentioned he had had some success changing the instrument needle colour by creating a mask for one of his cars. Daniel3D noted that this wasn't a complete solution and decided to look into the Restunts code to find a better way to do it. He realised the instrument needle colour was actually defined by reference and not hard-coded, as there is a needle_meter_color pointer in the code.

This called the attention of Cas, who noticed that the pointer actually referenced a constant field, yet, it could be changed for a pointer to a variable. He correctly guessed that there should be a field in memory at a static offset relative to needle_meter_color that would lay within the car RES information and be currently unused, so changing this pointer to make reference to that field would allow for cars to have a configurable needle colour.

Originally, the idea was to just patch the binary by finding the pointer value and replace it, but this turned out to be challenging, so Daniel3D helped with recompilation of the source. Red #5 field was chosen because its default value is 16, which is white in Stunts. This worked flawlessly and it's the first version of the mod.

Then, Cas thought it could be possible to configure different colours for the two instrument needles, but this would require to push new code into the source. Both Cas and Daniel3D worked hard to get this done because this would produce artifacts and made the code unstable. With some padding bytes and several tries, they finally got it working. This is the new version and it has so far proved very stable, although it's impossible to confirm it can never lead to errors.

Technical details

The code Daniel3D initially identified in ReStunts is located in the seg005.asm segment source file and it looks like this:

loc_23456:

   cmp     [bp+var_6], 0
   jnz     short loc_23485
   mov     ax, si
   shl     ax, 1
   mov     [bp+var_20], ax
   push    meter_needle_color
   mov     bx, ax
   mov     al, (simd_player.spdpoints+1)[bx]
   sub     ah, ah
   push    ax
   mov     al, simd_player.spdpoints[bx]
   push    ax
   push    simd_player.spdcenter.y2
   push    simd_player.spdcenter.x2
   call    preRender_line
   add     sp, 0Ah

loc_23485:

   mov     ax, di
   shl     ax, 1
   mov     [bp+var_20], ax
   push    meter_needle_color
   mov     bx, ax
   mov     al, (simd_player.revpoints+1)[bx]
   sub     ah, ah
   push    ax
   mov     al, simd_player.revpoints[bx]
   push    ax
   push    simd_player.revcenter.y2
   push    simd_player.revcenter.x2
   call    preRender_line
   add     sp, 0Ah
   mov     al, [bp+var_2]
   cbw
   or      ax, ax
   jz      short loc_234BE
   cmp     ax, 2           ; st. whl. position flag
   jz      short loc_234EC
   jmp     short loc_234DE
   ; align 2
   db 144

Here, meter_needle_color is a pointer and at that location, there is a single fixed byte with the number 15, which is white in Stunts. Cas searched and found a region of the code where the car information was loaded and among the so-called "mysterious fields", picked one that had the value 16 on all original and old custom cars, because 16 is also white in Stunts. Then he proposed to change the push line to:

push simd_player.field_A6+4

Initially, Cas expected it'd be possible to find within the binary file the word corresponding the the meter_needle_colour pointer and change it to this other point, but this didn't work for some reason. Daniel3D aided in recompiling and testing the code. The first version worked well immediately, but caused both needles to change to that colour. To obtain independently configurable needle colours, Cas came up with this modified code:

loc_23456:

   cmp     [bp+var_6], 0
   jnz     short loc_23485
   mov     ax, si
   shl     ax, 1
   mov     [bp+var_20], ax
  
   ; Patch #1 ----*
   ; Replaced needle colour for speed-o-meter
  
   ; Original code:
   ;push	meter_needle_color
  
   push    simd_player.field_A6+8
  
   mov     bx, ax
   mov     al, (simd_player.spdpoints+1)[bx]
   sub     ah, ah
   push    ax
   mov     al, simd_player.spdpoints[bx]
   push    ax
   push    simd_player.spdcenter.y2
   push    simd_player.spdcenter.x2
   call    preRender_line
   add     sp, 0Ah

loc_23485:

   mov     ax, di
   shl     ax, 1
   mov     [bp+var_20], ax
  
   ; Replaced needle colour for RPM meter
   ; Original code:
   ;push	meter_needle_color
  
   ; This line is for the first version of the patch
   ;push    simd_player.field_A6+8
  ; This block is the new version of the patch   
   cmp     byte ptr [simd_player.field_A6+9], 0    ; Check to see if the high byte is zero
   jz      use_the_same_colour
   push    simd_player.field_A6+9                      ; It's not, so push this high byte as the colour
   jmp     needle_value_successfully_set            ; Continue with the old code

use_the_same_colour: push simd_player.field_A6+8 ; It is, so push the low byte as the colour needle_value_successfully_set: nop ; Alignment bytes nop nop

   mov     bx, ax
   mov     al, (simd_player.revpoints+1)[bx]
   sub     ah, ah
   push    ax
   mov     al, simd_player.revpoints[bx]
   push    ax
   push    simd_player.revcenter.y2
   push    simd_player.revcenter.x2
   call    preRender_line
   add     sp, 0Ah
   mov     al, [bp+var_2]
   cbw
   or      ax, ax
   jz      short loc_234BE
   cmp     ax, 2           ; st. whl. position flag
   jz      short loc_234EC
   jmp     short loc_234DE
   ; align 2
   db 144

Here, new code had to be pushed into the source, so Daniel3D and Cas had to work hard to test alignment, which gave bugs, until they found the three nops would work. This modification is explained in detail in this forum post.

Using the needle colour mod

To correctly change a car's needle colours, we modify the Red #5 "mysterious" field that appears as "needle colour" in more recent versions of CarWorks. This field is a word, so if we use a value from 0 to 255, the high byte will be left at 0. In this case, both needles will be set to the specified colour. The default value of this field is 16, so by default, both needles will be white.

If we want to use different colours for the needles, we need to change the high byte to a non-zero value. In that case, the speed-o-meter will take the colour set in the low byte and the tach-o-meter will use the high byte colour. This means the tach-o-meter can't have a 0 colour needle, but there are other values that also produce black or close to black, so that's not a problem.

Custom cars that use this mod

Since the mod was released, car makers have made extensive use of the needle colour set up. Probably the first custom car to use the mod was Zapper's Caterham Super Seven JPE, with the two of its instrument needles set to black. Ryoma also used it for his Ford Shelby Mustang GT350x, with red needles and his Ferrari 308 GT Rainbow, which features yellow instrument needles.