UQM: probability of Orz vac-suit kills in different opponent ships

star-control-2

This article on Ultronomicon describes how the Orz "intruders" (Marines) kill enemy crew and are killed in turn. The article implies that the probabilities are the same regardless of the type of enemy ship.

To me, however, it seems that Orz intruders do better in some enemy ship types than others. Particularly, the Slylandro probes seem to be almost impervious to them. Is the article's implication correct in terms of the game source code? Is it possible that other factors, such as poor random-number generation, could cause the effective probability to be different?

Best Answer

I downloaded the source code. In the file orz.c, there is a function called intruder_preprocess that handles what happens when the intruder is on the enemy ship. Within that function is the following code:

            BYTE randval;

            ElementPtr->thrust_wait = MARINE_WAIT;

            randval = (BYTE)TFB_Random ();
            if (randval < (0x0100 / 16))
            {
                ElementPtr->life_span = 0;
                ElementPtr->state_flags |= DISAPPEARING;

                ProcessSound (SetAbsSoundIndex (
                        StarShipPtr->RaceDescPtr->ship_data.ship_sounds, 4), ElementPtr);
                goto LeftShip;
            }
            else if (randval < (0x0100 / 2 + 0x0100 / 16))
            {
                if (!DeltaCrew (ShipPtr, -1))
                    ShipPtr->life_span = 0;

                ++ElementPtr->thrust_wait;
                s.origin.x = 16 + (ElementPtr->turn_wait & 3) * 9;
                s.origin.y = 14 + (ElementPtr->turn_wait >> 2) * 11;
                s.frame = SetAbsFrameIndex (ElementPtr->next.image.farray[0],
                        GetFrameCount (ElementPtr->next.image.farray[0]) - 1);
                ModifySilhouette (ShipPtr, &s, 0);
                ProcessSound (SetAbsSoundIndex (
                        StarShipPtr->RaceDescPtr->ship_data.ship_sounds, 3), ElementPtr);
            }

As you can see, a random number is generated from the TFB_Random function (this is defined in the random.c file). If it is less than 6.25 (this comes from 100/16), the ElementPtr's life_span is set to 0. ElementPtr represents the intruder and setting life_span to 0 means he dies. This matches up with the Ultranomicon saying "6.25% chance a marine dies".

If the random number is greater than 6.25 but less than 56.25 (this comes from 50+6.25), which is a range of 50, then the DeltaCrew function is called on ShipPtr with a -1 value. DeltaCrew is defined in the status.c file, and modifies the number of crew on a ship. ShipPtr represents the enemy ship and -1 means one enemy crew member has died. This matches up with the Ultranomicon saying "50% chance one enemy crew dies".

If the random number is greater than 56.25 and less than 100, which is a range of 43.75, then nothing happens. This matches up with the Ultranomicon saying "43.75% chance nothing happens".

There is no code that checks for the type of enemy ship. That code in the intruder_preprocess function will execute for all enemy ships, so the Ultranomicon is correct.

EDIT:

As for the TFB_Random function, it is seeded by the TFB_SeedRandom function (also defined in random.c):

#define A 16807 /* a relatively prime number -- also M div Q */
#define M 2147483647L /* 0xFFFFFFFF / 2 */
#define Q 127773L /* M div A */
#define R 2836 /* M mod A */

static DWORD seed = 12345L; /* random number seed */

DWORD
TFB_Random (void)
{
    seed = A * (seed % Q) - R * (seed / Q);
    if (seed > M)
        return (seed -= M);
    else if (seed)
        return (seed);
    else
        return (seed = 1L);
}

DWORD
TFB_SeedRandom (DWORD new_seed)
{
    DWORD old_seed;

    /* coerce the seed to be in the range 1..M */
    if (new_seed == 0L) /* 0 becomes 1 */
        new_seed = 1;
    else if (new_seed > M) /* and less than M */
        new_seed -= M;

    old_seed = seed;
    seed = new_seed;
    return (old_seed);
}

I searched for all calls to TFB_SeedRandom, and every one (related to melee and ship fighting) passes in a value that is based on the current time. There is nothing that passes in a seed that is dependent on ship type. If the random number generation or the seeding is poor, then that would be true for all enemy ships, not just certain types.