Difference between revisions of "Needle colour mod"
Line 136: | Line 136: | ||
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 [https://forum.stunts.hu/index.php?topic=3872.0 this forum post]. | 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 [https://forum.stunts.hu/index.php?topic=3872.0 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 == |
Revision as of 19:18, 15 April 2024
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.