0 of 0

File information

Last updated

Original upload

Created by

STUNTS Community

Uploaded by

daniel3d

Virus scan

Some suspicious files

About this mod

To make the color of the needle for the tachometer and speedometer, editable changes to the source code had to be made.
The rebuild executable loads faster and supports different color needles if they are set in the car file.

This Package includes the original 11 and 27 additional cars (max 32 are accepted at once) and support file

Requirements
Permissions and credits
Mirrors
Donations
The Stunts Forum contains a lot more information.

For the configurable needle colour, the initial implementation was very simple. Near the middle of seg005.asm, there's the label loc_23456. At this point, the game engine calculates how the needle is to be drawn by passing the needle axis coordinates as one point and the corresponding spoke for the current speed as the second point and then calling a function that draws a line between them. This functions also requests a line colour as a parameter, so Stunts was originally passing a variable that, reaching this point, was always valued at 15 (white). The same thing is later done for the tachometer:
https://bitbucket.org/dreadnaut/restunts/src/master/src/restunts/asmorig/seg005.asm#lines-2710
loc_23456:
    cmp     [bp+var_6], 0
    jnz     short loc_23485
    mov     ax, si
    shl     ax, 1
    mov     [bp+var_20], ax
    
    pushmeter_needle_color    ; This variable in Stunts original code always ended up with a value of 15
    
    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
    
    pushmeter_needle_color    ; Again, same colour is passed for the tachometer
    
    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

I noticed that there exists a structure called simd_player, which contains the car information from the "simd" chunk in the corresponding CAR*.RES file for the current player car. Individual fields from this structure could be used as variables, so I found the reference name for an unused car configuration that's known in CarWorks as "Red #5". I picked this one because all original cars have this value set to 16, which is the closest to a perfect white (15) in Stunts palette. It's actually just slightly darker. This way, after the patch, old cars would continue to display white needles. So all we had to do was replace meter_needle_color with simd_player.field_A6+8, which is a pointer to Red #5. The resulting code goes as follows:
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:
    ;pushmeter_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:
    ;pushmeter_needle_color
    
    push    simd_player.field_A6+8
    
    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

Notice how this change only replaces a pointer with another, thus resulting in the same code length, guaranteed to be perfectly stable. Only drawback is that both needles have to be the same colour.

To achieve a separately configurable second needle, more complex changes had to be made. The first needle (speedometer) works exactly the same way as before, but now, for the tachometer needle, we needed a procedure that guaranteed the default would also result in white-white, but that could also allow for two different colours being represented. Because the colour parameter accepted by the line function in Stunts is a word, yet only the lower byte is read (since Stunts uses 8 bit colour), the most efficient way of achieving this was by using the higher byte of Red #5 to define the tachometer colour. But the default for this high byte is zero. So I had to make it so that when this byte is zero, both needles will be the colour defined by the lower byte, while, when non-zero, this value would give the tachometer needle colour and the lower byte would give the one for the speedometer. Implementation resulted in the following 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:
    ;pushmeter_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:
    ;pushmeter_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

Because this change required additional bytes in the code, Stunts quickly complained about the alignment. We solved this by testing how many bytes we needed to add. We correctly guessed that an alignment to 16 bytes would be enough because it's the real mode paragraph length. It turned out that four bytes did the trick to align to 16 bytes. Note that these four nops actually take processor time, which is negligible, but it'd be better to move these bytes to non-executable space, like after the db 144, for example. That'd also make the code cleaner.
Even with this alignment, it's impossible to be sure that Stunts doesn't make any assumption that could make it unstable. After quite some testing, it appears that it is indeed stable, but the more we test, the better. While having different colour needles isn't a very useful feature, implementing this is important as it shows how Stunts is accepting inserted code and complex mods can be made.