Skip to content
Tom Sherman edited this page Mar 7, 2017 · 11 revisions

Previous Section: Teching

Overview

good

bad

The next step is adding DI. The basic logic behind this is two-fold. First, the AI will try to determine if it should combo-di or survival-di, this is based off the percent that the AI is currently at. Next, the AI will determine the angle of DI based on the character orientation.

Background Knowledge

Accessing Game Data

DI logic

The header file for DI.c will look like:

void hitDI(AI* ai);
void throwDI(AI* ai);
void stopThrowDI(AI* ai);

The first two functions are called when the cpu is hit by a move or thrown. Unfortunately, the nature of DI'ing a throw is a little strange, and so we need another function to detect once its possible to stop DI'ing for the throw. DI'ing the hit it more simple: right before hitlag ends we input a direction for a single frame.

Logic hitDiLogic = 
{
    {&hitlagFrames, .arg1.u = 2, .arg2.u = 1},
    {&hitDI, .arg1.p = &cpuPlayer}
};

hitDiLogic says to call hitDI when player 2 has one frame of hitlag remaining.

void hitDI(AI* player)
{
    float knockback = getKnockBackAngle(player->port);
    float percent = _gameState.playerData[player->port]->percent;

    float comboProb = 120.f - (percent * percent / 400.f) * 7.f;
    comboProb = fmin(comboProb, 100.f);
    comboProb = fmax(comboProb, 10.f) / 100.f;

    SET_HIT_DI_DIR(chance(comboProb) ? 
        getComboDI(player, knockback) : getSurvivalDI(player, knockback));

    addMove(player, &_mv_hitDI);
}

This is the function for DI'ing all hits. First we need to know the percent and knockback angle of the move the AI was hit with. Then we calculate the percent chance we combo DI. This is based only on the current percent of the AI. We then normalize it so it is between 0 and 1. Then the direction of DI is set based on the this probability. _mv_hitDI is one frame so it is not necessary to have any "clean up" logic. The helper functions are defined as follows:

#define SAKURAI_ANGLE 0x0169

static float getKnockBackAngle(u32 port)
{
    u32 rawAngle = _gameState.playerData[port]->knockbackAngle;
    float direction = _gameState.playerData[port]->damageDirection;

    if (rawAngle == SAKURAI_ANGLE) {rawAngle = 45;}

    return (float) rawAngle - (1.f + direction) * 90.f;
}

#define AI_X     (_gameState.playerData[player->port]->coordinates.x)
#define OPP_X    (_gameState.playerData[player->opponent]->coordinates.x)
static float getComboDI(AI* player, float knockback)
{
    return AI_X < OPP_X ? 225.f : 315.f;
}

static float getSurvivalDI(AI* player, float knockback)
{
    return AI_X < OPP_X ? 45.f : 135.f;
}

At this point, the DI decision is very simple: down and away for combo DI, up and in for survival DI. This gives decent results and the structure here allows for easy expansion.

Next we have the logic for DI'ing throws:

Logic throwDiLogic =
{
    {&actionStateEq, .arg1.u = 2, .arg2.u = _AS_CaptureWaitLw},
    {&throwDI, .arg1.p = &cpuPlayer}
};

Logic stopThrowDiLogic = 
{
    {&breakoutFrame, .arg1.u = 2, .arg2.u = 0},
    {&stopThrowDI, .arg1.p = &cpuPlayer}
};

These rules tell the AI to call throwDI when the AI is grabbed and stopThrowDI when the player is about to be released. The problem is the breakout frame hits 0 before the player is actually released so we cannot immediately release the control stick. stopThrowDI simply releases the control stick slightly delayed.

void throwDI(AI* player)
{
    SET_THROW_DI_DIR(chance(0.5f) ? 0.f : 180.f);        
    addMove(player, &_mv_throwDI);
    addLogic(player, &stopThrowDiLogic);
}

void stopThrowDI(AI* player)
{
    resetAfterFrameLogic.condition.arg1.u = CURRENT_FRAME + 10;
    addLogic(player, &resetAfterFrameLogic);
}

The AI picks right or left with a 50/50 chance when DI'ing throws. The AI resets 10 frames after the breakout counter hits 0.

Creating the Program

DI.c contains most of the new code in this program.

The full code is here. Run the standard wiimake command to build the iso.

Possible Expansions

  • Incorporate stage positioning into the combo/survival DI decision.
  • Use the knockback angle to calculate a more optimal angle of DI.

Next Section

Next Section: Recovery