Jump to content
IGNORED

Convert a range to a BACKTAB card


Recommended Posts

In games you often need to convert a variable that keeps track of power, energy, force etc. into something more meaningful to display to the player so they don't always have to think about what the number is and exactly what it means. Lets create a contrived example:

 

Say you want to display the player's remaining fuel as a graphic and not a number. The fuel has 4 limits :-

 

2/3 to 3/3 - Green

1/3 to 2/3 - Yellow

1 to 1/3 - Red

0 - Death.

 

and is always in the range 0 to 100. So you could code something like this :-

 

    mvi thePlayerFuel, r0
    cmpi #(100*2)/3, r0
    bge @@FuelIsAllGreen
    cmpi #(100*1)/3, r0
    bge @@FuelIsAllYellow
    cmpi #1, r0
    bge @@FuleIsAllRed
; Fuel depleted - Fall through...
    ...
@@FuelIsAllGreen:
    mvii #FUEL_GREEN, r0
    mvo r0, SCREEN_POS(0,0)
    b @@FuelCommon
@@FuelIsAllYellow:
    mvii #FUEL_YELLOW, r0
    mvo r0, SCREEN_POS(0,0)
    b @@FuelCommon
@@FuelIsAllRed:
    mvii #FUEL_RED, r0
    mvo r0, SCREEN_POS(0,0)
; Fall through...

@@FuelCommon:
...
But a much neater approach is to make use of the carry flag in the compares, so I came up with this :-

 

    clrr r1
    mvi thePlayerFuel, r0
    cmpi #(100*2)/3, r0
    adcr r1
    cmpi #(100*1)/3, r0
    adcr r1
    cmpi #1, r0
    adcr r1
    beq @@FuelDepleted
    addi #@@FuelConversionTable, r1
    mvi@ r1, r1
    mvo r1, SCREEN_POS(0,0)
...

@@FuelConversionTable:
    DECLE 0  ; Dummy
    DECLE FUEL_RED
    DECLE FUEL_YELLOW
    DECLE FUEL_GREEN
  • Like 2
Link to comment
Share on other sites

If you don't mind making a small approximation, you may also consider using the lookup table directly by computing fuel / 33 ~= (fuel * 7) >> 8.

 

Something along those lines:

    mvi  thePlayerFuel, r1   ; r1 = fuel
    sll  r1                  ; r1 = fuel * 2
    beq  @@fuelDepleted      ; abort right away if zero
    sll  r1, 2               ; r1 = fuel * 8
    sub  thePlayerFuel, r1   ; r1 = fuel * 7
    swap r1                  ; r1 = (fuel * 7) >> 8
    andi #3, r1
    addi #@@FuelConversionTable, r1
    mvi@ r1, r1
    mvo  r1, SCREEN_POS(0,0)

@@FuelConversionTable:
    DECLE FUEL_RED
    DECLE FUEL_YELLOW
    DECLE FUEL_GREEN

Of course, this approach makes more sense if you happen to have -- say -- 4 intervals rather than 3 and a fuel counter going from 0 to 255:

    mvi  thePlayerFuel, r1
    sll  r1, 2
    beq  @@fuelDepleted
    swap r1
    andi #3, r1
    addi #@@FuelConversionTable, r1
    mvi@ r1, r1
    mvo  r1, SCREEN_POS(0,0)

@@FuelConversionTable:
    DECLE FUEL_RED
    DECLE FUEL_ORANGE
    DECLE FUEL_YELLOW
    DECLE FUEL_GREEN

  • Like 2
Link to comment
Share on other sites

If you don't mind making a small approximation, you may also consider using the lookup table directly by computing fuel / 33 ~= (fuel * 7) >> 8.

Yep! There are always many ways to solve a problem. This was just an example with fictional colour bands. You might have a graphical gauge with very different points at where the colour changes start/end in your own games.

Link to comment
Share on other sites

For something like this, I'm likely to throw a table at it, similar to Arnauld, but perhaps with more redundancy in the table if that allows me to keep the original ranges. For example, with the 3-color approach, something like this gets close enough:

.

    MOV     thePlayerFuel, R1     ; 0 .. 100
    SLR     R1,            2      ; \_ divide by 16; now 0 to 6
    SLR     R1,            2      ; /
    BEQ     @@fuel_depleted 
    ADDI    #@@fuel_tbl,   R1
    MVI@    R1,            R1
    MVO     R1,            wherever
;...
@@fuel_tbl:
    DECLE   FUEL_RED,    FUEL_RED                ;  0 .. 31
    DECLE   FUEL_YELLOW, FUEL_YELLOW             ; 32 .. 63
    DECLE   FUEL_GREEN,  FUEL_GREEN,  FUEL_GREEN ; 64 .. 100

.

The larger table is offset by the smaller code. This particular example retains the 0..100 range of the original.

Link to comment
Share on other sites

Another good solution to the contrived example I provided . But in both cases, if your gauge has band limits at 17, 45, 67 and 91 its not going to be so simple ;).

 

True. But just as we snap graphics to BACKTAB tile boundaries, I would probably snap my thresholds to less numerically spiteful values, such as 16, 48, 64 and 96. ;-)

 

But lacking that option, abusing the carry bit as you did does work. In one of the early versions of Space Patrol, I used a similar trick when counting the number of active sprites (for the multiplex engine), comparing each sprite's 'attribute number' (an index into a table of sprite attributes) to 0, and adding up the carries. That worked reasonably well.

 

(Later, I changed the representation of the sprite indices, and used a different trick here. To save cycles in the sprite => MOB mapping code, I scaled the sprite attribute index by 4 (since each entry in the sprite attr table was 4 words), and then added 1, to force all active sprites to have non-zero indices. When counting active sprites, I added groups of 3 sprite entries together and then masked with #3, which was even cheaper then the compare-with-zero/ADCR approach.)

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.
Note: Your post will require moderator approval before it will be visible.

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.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...