code:
#include "global.h"
#include "battle.h"
#include "contest.h"
#include "random.h"
#include "contest_ai.h"
#include "contest_effect.h"
#include "constants/moves.h"

extern const u8 *gAIScriptPtr;
extern const u8 *gContestAI_ScriptsTable[];

static void ContestAICmd_score(void);
static void ContestAICmd_get_appeal_num(void);
static void ContestAICmd_if_appeal_num_less_than(void);
static void ContestAICmd_if_appeal_num_more_than(void);
static void ContestAICmd_if_appeal_num_eq(void);
static void ContestAICmd_if_appeal_num_not_eq(void);
static void ContestAICmd_get_excitement(void);
static void ContestAICmd_if_excitement_less_than(void);
static void ContestAICmd_if_excitement_more_than(void);
static void ContestAICmd_if_excitement_eq(void);
static void ContestAICmd_if_excitement_not_eq(void);
static void ContestAICmd_get_user_order(void);
static void ContestAICmd_if_user_order_less_than(void);
static void ContestAICmd_if_user_order_more_than(void);
static void ContestAICmd_if_user_order_eq(void);
static void ContestAICmd_if_user_order_not_eq(void);
static void ContestAICmd_get_user_condition(void);
static void ContestAICmd_if_user_condition_less_than(void);
static void ContestAICmd_if_user_condition_more_than(void);
static void ContestAICmd_if_user_condition_eq(void);
static void ContestAICmd_if_user_condition_not_eq(void);
static void ContestAICmd_get_points(void);
static void ContestAICmd_if_points_less_than(void);
static void ContestAICmd_if_points_more_than(void);
static void ContestAICmd_if_points_eq(void);
static void ContestAICmd_if_points_not_eq(void);
static void ContestAICmd_get_preliminary_points(void);
static void ContestAICmd_if_preliminary_points_less_than(void);
static void ContestAICmd_if_preliminary_points_more_than(void);
static void ContestAICmd_if_preliminary_points_eq(void);
static void ContestAICmd_if_preliminary_points_not_eq(void);
static void ContestAICmd_get_contest_type(void);
static void ContestAICmd_if_contest_type_eq(void);
static void ContestAICmd_if_contest_type_not_eq(void);
static void ContestAICmd_get_move_excitement(void);
static void ContestAICmd_if_move_excitement_less_than(void);
static void ContestAICmd_if_move_excitement_more_than(void);
static void ContestAICmd_if_move_excitement_eq(void);
static void ContestAICmd_if_move_excitement_not_eq(void);
static void ContestAICmd_get_move_effect(void);
static void ContestAICmd_if_move_effect_eq(void);
static void ContestAICmd_if_move_effect_not_eq(void);
static void ContestAICmd_get_move_effect_type(void);
static void ContestAICmd_if_move_effect_type_eq(void);
static void ContestAICmd_if_move_effect_type_not_eq(void);
static void ContestAICmd_check_most_appealing_move(void);
static void ContestAICmd_if_most_appealing_move(void);
static void ContestAICmd_check_most_jamming_move(void);
static void ContestAICmd_if_most_jamming_move(void);
static void ContestAICmd_get_num_move_hearts(void);
static void ContestAICmd_if_num_move_hearts_less_than(void);
static void ContestAICmd_if_num_move_hearts_more_than(void);
static void ContestAICmd_if_num_move_hearts_eq(void);
static void ContestAICmd_if_num_move_hearts_not_eq(void);
static void ContestAICmd_get_num_move_jam_hearts(void);
static void ContestAICmd_if_num_move_jam_hearts_less_than(void);
static void ContestAICmd_if_num_move_jam_hearts_more_than(void);
static void ContestAICmd_if_num_move_jam_hearts_eq(void);
static void ContestAICmd_if_num_move_jam_hearts_not_eq(void);
static void ContestAICmd_get_move_used_count(void);
static void ContestAICmd_if_most_used_count_less_than(void);
static void ContestAICmd_if_most_used_count_more_than(void);
static void ContestAICmd_if_most_used_count_eq(void);
static void ContestAICmd_if_most_used_count_not_eq(void);
static void ContestAICmd_check_combo_starter(void);
static void ContestAICmd_if_combo_starter(void);
static void ContestAICmd_if_not_combo_starter(void);
static void ContestAICmd_check_combo_finisher(void);
static void ContestAICmd_if_combo_finisher(void);
static void ContestAICmd_if_not_combo_finisher(void);
static void ContestAICmd_check_would_finish_combo(void);
static void ContestAICmd_if_would_finish_combo(void);
static void ContestAICmd_if_would_not_finish_combo(void);
static void ContestAICmd_get_condition(void);
static void ContestAICmd_if_condition_less_than(void);
static void ContestAICmd_if_condition_more_than(void);
static void ContestAICmd_if_condition_eq(void);
static void ContestAICmd_if_condition_not_eq(void);
static void ContestAICmd_get_used_combo_starter(void);
static void ContestAICmd_if_used_combo_starter_less_than(void);
static void ContestAICmd_if_used_combo_starter_more_than(void);
static void ContestAICmd_if_used_combo_starter_eq(void);
static void ContestAICmd_if_used_combo_starter_not_eq(void);
static void ContestAICmd_check_can_participate(void);
static void ContestAICmd_if_can_participate(void);
static void ContestAICmd_if_cannot_participate(void);
static void ContestAICmd_get_completed_combo(void);
static void ContestAICmd_if_completed_combo(void);
static void ContestAICmd_if_not_completed_combo(void);
static void ContestAICmd_get_points_diff(void);
static void ContestAICmd_if_points_more_than_mon(void);
static void ContestAICmd_if_points_less_than_mon(void);
static void ContestAICmd_if_points_eq_mon(void);
static void ContestAICmd_if_points_not_eq_mon(void);
static void ContestAICmd_get_preliminary_points_diff(void);
static void ContestAICmd_if_preliminary_points_more_than_mon(void);
static void ContestAICmd_if_preliminary_points_less_than_mon(void);
static void ContestAICmd_if_preliminary_points_eq_mon(void);
static void ContestAICmd_if_preliminary_points_not_eq_mon(void);
static void ContestAICmd_get_used_moves_effect(void);
static void ContestAICmd_if_used_moves_effect_less_than(void);
static void ContestAICmd_if_used_moves_effect_more_than(void);
static void ContestAICmd_if_used_moves_effect_eq(void);
static void ContestAICmd_if_used_moves_effect_not_eq(void);
static void ContestAICmd_get_used_moves_excitement(void);
static void ContestAICmd_if_used_moves_excitement_less_than(void);
static void ContestAICmd_if_used_moves_excitement_more_than(void);
static void ContestAICmd_if_used_moves_excitement_eq(void);
static void ContestAICmd_if_used_moves_excitement_not_eq(void);
static void ContestAICmd_get_used_moves_effect_type(void);
static void ContestAICmd_if_used_moves_effect_type_eq(void);
static void ContestAICmd_if_used_moves_effect_type_not_eq(void);
static void ContestAICmd_save_result(void);
static void ContestAICmd_setvar(void);
static void ContestAICmd_add(void);
static void ContestAICmd_addvar(void);
static void ContestAICmd_addvar_duplicate(void);
static void ContestAICmd_if_less_than(void);
static void ContestAICmd_if_greater_than(void);
static void ContestAICmd_if_eq(void);
static void ContestAICmd_if_not_eq(void);
static void ContestAICmd_if_less_than_var(void);
static void ContestAICmd_if_greater_than_var(void);
static void ContestAICmd_if_eq_var(void);
static void ContestAICmd_if_not_eq_var(void);
static void ContestAICmd_if_random_less_than(void);
static void ContestAICmd_if_random_greater_than(void);
static void ContestAICmd_goto(void);
static void ContestAICmd_call(void);
static void ContestAICmd_end(void);
static void ContestAICmd_check_user_has_exciting_move(void);
static void ContestAICmd_if_user_has_exciting_move(void);
static void ContestAICmd_if_user_doesnt_have_exciting_move(void);
static void ContestAICmd_check_user_has_move(void);
static void ContestAICmd_if_user_has_move(void);
static void ContestAICmd_if_user_doesnt_have_move(void);

typedef void (* ContestAICmdFunc)(void);

static const ContestAICmdFunc sContestAICmdTable[] =
{
    ContestAICmd_score,                               // 0x00
    ContestAICmd_get_appeal_num,                      // 0x01
    ContestAICmd_if_appeal_num_less_than,             // 0x02
    ContestAICmd_if_appeal_num_more_than,             // 0x03
    ContestAICmd_if_appeal_num_eq,                    // 0x04
    ContestAICmd_if_appeal_num_not_eq,                // 0x05
    ContestAICmd_get_excitement,                      // 0x06
    ContestAICmd_if_excitement_less_than,             // 0x07
    ContestAICmd_if_excitement_more_than,             // 0x08
    ContestAICmd_if_excitement_eq,                    // 0x09
    ContestAICmd_if_excitement_not_eq,                // 0x0A
    ContestAICmd_get_user_order,                      // 0x0B
    ContestAICmd_if_user_order_less_than,             // 0x0C
    ContestAICmd_if_user_order_more_than,             // 0x0D
    ContestAICmd_if_user_order_eq,                    // 0x0E
    ContestAICmd_if_user_order_not_eq,                // 0x0F
    ContestAICmd_get_user_condition,                  // 0x10
    ContestAICmd_if_user_condition_less_than,         // 0x11
    ContestAICmd_if_user_condition_more_than,         // 0x12
    ContestAICmd_if_user_condition_eq,                // 0x13
    ContestAICmd_if_user_condition_not_eq,            // 0x14
    ContestAICmd_get_points,                          // 0x15
    ContestAICmd_if_points_less_than,                 // 0x16
    ContestAICmd_if_points_more_than,                 // 0x17
    ContestAICmd_if_points_eq,                        // 0x18
    ContestAICmd_if_points_not_eq,                    // 0x19
    ContestAICmd_get_preliminary_points,              // 0x1A
    ContestAICmd_if_preliminary_points_less_than,     // 0x1B
    ContestAICmd_if_preliminary_points_more_than,     // 0x1C
    ContestAICmd_if_preliminary_points_eq,            // 0x1D
    ContestAICmd_if_preliminary_points_not_eq,        // 0x1E
    ContestAICmd_get_contest_type,                    // 0x1F
    ContestAICmd_if_contest_type_eq,                  // 0x20
    ContestAICmd_if_contest_type_not_eq,              // 0x21
    ContestAICmd_get_move_excitement,                 // 0x22
    ContestAICmd_if_move_excitement_less_than,        // 0x23
    ContestAICmd_if_move_excitement_more_than,        // 0x24
    ContestAICmd_if_move_excitement_eq,               // 0x25
    ContestAICmd_if_move_excitement_not_eq,           // 0x26
    ContestAICmd_get_move_effect,                     // 0x27
    ContestAICmd_if_move_effect_eq,                   // 0x28
    ContestAICmd_if_move_effect_not_eq,               // 0x29
    ContestAICmd_get_move_effect_type,                // 0x2A
    ContestAICmd_if_move_effect_type_eq,              // 0x2B
    ContestAICmd_if_move_effect_type_not_eq,          // 0x2C
    ContestAICmd_check_most_appealing_move,           // 0x2D
    ContestAICmd_if_most_appealing_move,              // 0x2E
    ContestAICmd_check_most_jamming_move,             // 0x2F
    ContestAICmd_if_most_jamming_move,                // 0x30
    ContestAICmd_get_num_move_hearts,                 // 0x31
    ContestAICmd_if_num_move_hearts_less_than,        // 0x32
    ContestAICmd_if_num_move_hearts_more_than,        // 0x33
    ContestAICmd_if_num_move_hearts_eq,               // 0x34
    ContestAICmd_if_num_move_hearts_not_eq,           // 0x35
    ContestAICmd_get_num_move_jam_hearts,             // 0x36
    ContestAICmd_if_num_move_jam_hearts_less_than,    // 0x37
    ContestAICmd_if_num_move_jam_hearts_more_than,    // 0x38
    ContestAICmd_if_num_move_jam_hearts_eq,           // 0x39
    ContestAICmd_if_num_move_jam_hearts_not_eq,       // 0x3A
    ContestAICmd_get_move_used_count,                 // 0x3B
    ContestAICmd_if_most_used_count_less_than,        // 0x3C
    ContestAICmd_if_most_used_count_more_than,        // 0x3D
    ContestAICmd_if_most_used_count_eq,               // 0x3E
    ContestAICmd_if_most_used_count_not_eq,           // 0x3F
    ContestAICmd_check_combo_starter,                 // 0x40
    ContestAICmd_if_combo_starter,                    // 0x41
    ContestAICmd_if_not_combo_starter,                // 0x42
    ContestAICmd_check_combo_finisher,                // 0x43
    ContestAICmd_if_combo_finisher,                   // 0x44
    ContestAICmd_if_not_combo_finisher,               // 0x45
    ContestAICmd_check_would_finish_combo,            // 0x46
    ContestAICmd_if_would_finish_combo,               // 0x47
    ContestAICmd_if_would_not_finish_combo,           // 0x48
    ContestAICmd_get_condition,                       // 0x49
    ContestAICmd_if_condition_less_than,              // 0x4A
    ContestAICmd_if_condition_more_than,              // 0x4B
    ContestAICmd_if_condition_eq,                     // 0x4C
    ContestAICmd_if_condition_not_eq,                 // 0x4D
    ContestAICmd_get_used_combo_starter,              // 0x4E
    ContestAICmd_if_used_combo_starter_less_than,     // 0x4F
    ContestAICmd_if_used_combo_starter_more_than,     // 0x50
    ContestAICmd_if_used_combo_starter_eq,            // 0x51
    ContestAICmd_if_used_combo_starter_not_eq,        // 0x52
    ContestAICmd_check_can_participate,               // 0x53
    ContestAICmd_if_can_participate,                  // 0x54
    ContestAICmd_if_cannot_participate,               // 0x55
    ContestAICmd_get_completed_combo,                 // 0x56
    ContestAICmd_if_completed_combo,                  // 0x57
    ContestAICmd_if_not_completed_combo,              // 0x58
    ContestAICmd_get_points_diff,                     // 0x59
    ContestAICmd_if_points_more_than_mon,             // 0x5A
    ContestAICmd_if_points_less_than_mon,             // 0x5B
    ContestAICmd_if_points_eq_mon,                    // 0x5C
    ContestAICmd_if_points_not_eq_mon,                // 0x5D
    ContestAICmd_get_preliminary_points_diff,         // 0x5E
    ContestAICmd_if_preliminary_points_more_than_mon, // 0x5F
    ContestAICmd_if_preliminary_points_less_than_mon, // 0x60
    ContestAICmd_if_preliminary_points_eq_mon,        // 0x61
    ContestAICmd_if_preliminary_points_not_eq_mon,    // 0x62
    ContestAICmd_get_used_moves_effect,               // 0x63
    ContestAICmd_if_used_moves_effect_less_than,      // 0x64
    ContestAICmd_if_used_moves_effect_more_than,      // 0x65
    ContestAICmd_if_used_moves_effect_eq,             // 0x66
    ContestAICmd_if_used_moves_effect_not_eq,         // 0x67
    ContestAICmd_get_used_moves_excitement,           // 0x68
    ContestAICmd_if_used_moves_excitement_less_than,  // 0x69
    ContestAICmd_if_used_moves_excitement_more_than,  // 0x6A
    ContestAICmd_if_used_moves_excitement_eq,         // 0x6B
    ContestAICmd_if_used_moves_excitement_not_eq,     // 0x6C
    ContestAICmd_get_used_moves_effect_type,          // 0x6D
    ContestAICmd_if_used_moves_effect_type_eq,        // 0x6E
    ContestAICmd_if_used_moves_effect_type_not_eq,    // 0x6F
    ContestAICmd_save_result,                         // 0x70
    ContestAICmd_setvar,                              // 0x71
    ContestAICmd_add,                                 // 0x72
    ContestAICmd_addvar,                              // 0x73
    ContestAICmd_addvar_duplicate,                    // 0x74
    ContestAICmd_if_less_than,                        // 0x75
    ContestAICmd_if_greater_than,                     // 0x76
    ContestAICmd_if_eq,                               // 0x77
    ContestAICmd_if_not_eq,                           // 0x78
    ContestAICmd_if_less_than_var,                    // 0x79
    ContestAICmd_if_greater_than_var,                 // 0x7A
    ContestAICmd_if_eq_var,                           // 0x7B
    ContestAICmd_if_not_eq_var,                       // 0x7C
    ContestAICmd_if_random_less_than,                 // 0x7D
    ContestAICmd_if_random_greater_than,              // 0x7E
    ContestAICmd_goto,                                // 0x7F
    ContestAICmd_call,                                // 0x80
    ContestAICmd_end,                                 // 0x81
    ContestAICmd_check_user_has_exciting_move,        // 0x82
    ContestAICmd_if_user_has_exciting_move,           // 0x83
    ContestAICmd_if_user_doesnt_have_exciting_move,   // 0x84
    ContestAICmd_check_user_has_move,                 // 0x85
    ContestAICmd_if_user_has_move,                    // 0x86
    ContestAICmd_if_user_doesnt_have_move,            // 0x87
};

static void ContestAI_DoAIProcessing(void);
static bool8 GetContestantIdByTurn(u8);
static void AIStackPushVar(const u8 *);
static u8 AIStackPop(void);

void ContestAI_ResetAI(u8 contestantAI)
{
    int i;
    memset(&eContestAI, 0, sizeof(struct ContestAIInfo));

    for (i = 0; i < MAX_MON_MOVES; i++)
        eContestAI.moveScores[i] = 100;

    eContestAI.contestantId = contestantAI;
    eContestAI.stackSize = 0;
    eContestAI.aiFlags = gContestMons[eContestAI.contestantId].aiFlags;
}

u8 ContestAI_GetActionToUse(void)
{
    while (eContestAI.aiFlags != 0)
    {
        if (eContestAI.aiFlags & 1)
        {
            eContestAI.aiState = CONTESTAI_SETTING_UP;
            ContestAI_DoAIProcessing();
        }
        eContestAI.aiFlags >>= 1;
        eContestAI.currentAIFlag++;
        eContestAI.nextMoveIndex = 0;
    }

    while (1)
    {
        // Randomly choose a move index. If it's the move
        // with the highest (or tied highest) score, return
        u8 moveIdx = Random() & (MAX_MON_MOVES - 1); // % MAX_MON_MOVES doesn't match
        u8 score = eContestAI.moveScores[moveIdx];
        int i;
        for (i = 0; i < MAX_MON_MOVES; i++)
        {
            if (score < eContestAI.moveScores[i])
                break;
        }
        if (i == MAX_MON_MOVES)
            return moveIdx;
    }
}

static void ContestAI_DoAIProcessing(void)
{
    while (eContestAI.aiState != CONTESTAI_FINISHED)
    {
        switch(eContestAI.aiState)
        {
            case CONTESTAI_DO_NOT_PROCESS:
                break;
            case CONTESTAI_SETTING_UP:
                gAIScriptPtr = gContestAI_ScriptsTable[eContestAI.currentAIFlag];

                if (gContestMons[eContestAI.contestantId].moves[eContestAI.nextMoveIndex] == MOVE_NONE)
                    eContestAI.nextMove = MOVE_NONE; // don't process a move that doesn't exist.
                else
                    eContestAI.nextMove = gContestMons[eContestAI.contestantId].moves[eContestAI.nextMoveIndex];
                eContestAI.aiState++;
                break;
            case CONTESTAI_PROCESSING:
                if (eContestAI.nextMove != MOVE_NONE)
                {
                    sContestAICmdTable[*gAIScriptPtr](); // run the command.
                }
                else
                {
                    eContestAI.moveScores[eContestAI.nextMoveIndex] = 0; // don't consider a move that doesn't exist.
                    eContestAI.aiAction |= 1;
                }
                if (eContestAI.aiAction & 1)
                {
                    eContestAI.nextMoveIndex++;
                    if (eContestAI.nextMoveIndex < MAX_MON_MOVES)
                        eContestAI.aiState = 0;
                    else
                        // aiState = CONTESTAI_FINISHED
                        eContestAI.aiState++;
                    eContestAI.aiAction &= 0xFE; // TODO: Define action flags
                }
                break;
        }
    }
}

static u8 GetContestantIdByTurn(u8 turn)
{
    int i;

    for (i = 0; i < CONTESTANT_COUNT; i++)
        if (eContestAppealResults.turnOrder[i] == turn)
            break;

    return i;
}

static void ContestAICmd_score(void)
{
    s16 score = eContestAI.moveScores[eContestAI.nextMoveIndex] + (s8)gAIScriptPtr[1];

    if (score > 255)
        score = 255;
    else if (score < 0)
        score = 0;

    eContestAI.moveScores[eContestAI.nextMoveIndex] = score;

    gAIScriptPtr += 2;
}

static void ContestAICmd_get_appeal_num(void)
{
    eContestAI.scriptResult = eContest.appealNumber;
    gAIScriptPtr += 1;
}

static void ContestAICmd_if_appeal_num_less_than(void)
{
    ContestAICmd_get_appeal_num();

    if (eContestAI.scriptResult < gAIScriptPtr[0])
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1);
    else
        gAIScriptPtr += 5;
}

static void ContestAICmd_if_appeal_num_more_than(void)
{
    ContestAICmd_get_appeal_num();

    if (eContestAI.scriptResult > gAIScriptPtr[0])
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1);
    else
        gAIScriptPtr += 5;
}

static void ContestAICmd_if_appeal_num_eq(void)
{
    ContestAICmd_get_appeal_num();

    if (eContestAI.scriptResult == gAIScriptPtr[0])
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1);
    else
        gAIScriptPtr += 5;
}

static void ContestAICmd_if_appeal_num_not_eq(void)
{
    ContestAICmd_get_appeal_num();

    if (eContestAI.scriptResult != gAIScriptPtr[0])
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1);
    else
        gAIScriptPtr += 5;
}

static void ContestAICmd_get_excitement(void)
{
    eContestAI.scriptResult = eContest.applauseLevel;
    gAIScriptPtr += 1;
}

static void ContestAICmd_if_excitement_less_than(void)
{
    ContestAICmd_get_excitement();

    if (eContestAI.scriptResult < gAIScriptPtr[0])
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1);
    else
        gAIScriptPtr += 5;
}

static void ContestAICmd_if_excitement_more_than(void)
{
    ContestAICmd_get_excitement();

    if (eContestAI.scriptResult > gAIScriptPtr[0])
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1);
    else
        gAIScriptPtr += 5;
}

static void ContestAICmd_if_excitement_eq(void)
{
    ContestAICmd_get_excitement();

    if (eContestAI.scriptResult == gAIScriptPtr[0])
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1);
    else
        gAIScriptPtr += 5;
}

static void ContestAICmd_if_excitement_not_eq(void)
{
    ContestAICmd_get_excitement();

    if (eContestAI.scriptResult != gAIScriptPtr[0])
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1);
    else
        gAIScriptPtr += 5;
}

static void ContestAICmd_get_user_order(void)
{
    eContestAI.scriptResult = eContestAppealResults.turnOrder[eContestAI.contestantId];
    gAIScriptPtr += 1;
}

static void ContestAICmd_if_user_order_less_than(void)
{
    ContestAICmd_get_user_order();

    if (eContestAI.scriptResult < gAIScriptPtr[0])
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1);
    else
        gAIScriptPtr += 5;
}

static void ContestAICmd_if_user_order_more_than(void)
{
    ContestAICmd_get_user_order();

    if (eContestAI.scriptResult > gAIScriptPtr[0])
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1);
    else
        gAIScriptPtr += 5;
}

static void ContestAICmd_if_user_order_eq(void)
{
    ContestAICmd_get_user_order();

    if (eContestAI.scriptResult == gAIScriptPtr[0])
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1);
    else
        gAIScriptPtr += 5;
}

static void ContestAICmd_if_user_order_not_eq(void)
{
    ContestAICmd_get_user_order();

    if (eContestAI.scriptResult != gAIScriptPtr[0])
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1);
    else
        gAIScriptPtr += 5;
}

static void ContestAICmd_get_user_condition(void)
{
    eContestAI.scriptResult = eContestantStatus[eContestAI.contestantId].condition / 10;
    gAIScriptPtr += 1;
}

static void ContestAICmd_if_user_condition_less_than(void)
{
    ContestAICmd_get_user_condition();

    if (eContestAI.scriptResult < gAIScriptPtr[0])
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1);
    else
        gAIScriptPtr += 5;
}

static void ContestAICmd_if_user_condition_more_than(void)
{
    ContestAICmd_get_user_condition();

    if (eContestAI.scriptResult > gAIScriptPtr[0])
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1);
    else
        gAIScriptPtr += 5;
}

static void ContestAICmd_if_user_condition_eq(void)
{
    ContestAICmd_get_user_condition();

    if (eContestAI.scriptResult == gAIScriptPtr[0])
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1);
    else
        gAIScriptPtr += 5;
}

static void ContestAICmd_if_user_condition_not_eq(void)
{
    ContestAICmd_get_user_condition();

    if (eContestAI.scriptResult != gAIScriptPtr[0])
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1);
    else
        gAIScriptPtr += 5;
}

static void ContestAICmd_get_points(void)
{
    eContestAI.scriptResult = eContestantStatus[eContestAI.contestantId].pointTotal;
    gAIScriptPtr += 1;
}

static void ContestAICmd_if_points_less_than(void)
{
    ContestAICmd_get_points();

    if (eContestAI.scriptResult < (s16)T1_READ_16(gAIScriptPtr + 0))
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 2);
    else
        gAIScriptPtr += 6;
}

static void ContestAICmd_if_points_more_than(void)
{
    ContestAICmd_get_points();

    if (eContestAI.scriptResult > (s16)T1_READ_16(gAIScriptPtr + 0))
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 2);
    else
        gAIScriptPtr += 6;
}

static void ContestAICmd_if_points_eq(void)
{
    ContestAICmd_get_points();

    if (eContestAI.scriptResult == (s16)T1_READ_16(gAIScriptPtr + 0))
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 2);
    else
        gAIScriptPtr += 6;
}

static void ContestAICmd_if_points_not_eq(void)
{
    ContestAICmd_get_points();

    if (eContestAI.scriptResult != (s16)T1_READ_16(gAIScriptPtr + 0))
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 2);
    else
        gAIScriptPtr += 6;
}

static void ContestAICmd_get_preliminary_points(void)
{
    eContestAI.scriptResult = gContestMonRound1Points[eContestAI.contestantId];
    gAIScriptPtr += 1;
}

static void ContestAICmd_if_preliminary_points_less_than(void)
{
    ContestAICmd_get_preliminary_points();

    if (eContestAI.scriptResult < (s16)T1_READ_16(gAIScriptPtr + 0))
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 2);
    else
        gAIScriptPtr += 6;
}

static void ContestAICmd_if_preliminary_points_more_than(void)
{
    ContestAICmd_get_preliminary_points();

    if (eContestAI.scriptResult > (s16)T1_READ_16(gAIScriptPtr + 0))
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 2);
    else
        gAIScriptPtr += 6;
}

static void ContestAICmd_if_preliminary_points_eq(void)
{
    ContestAICmd_get_preliminary_points();

    if (eContestAI.scriptResult == (s16)T1_READ_16(gAIScriptPtr + 0))
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 2);
    else
        gAIScriptPtr += 6;
}

static void ContestAICmd_if_preliminary_points_not_eq(void)
{
    ContestAICmd_get_preliminary_points();

    if (eContestAI.scriptResult != (s16)T1_READ_16(gAIScriptPtr + 0))
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 2);
    else
        gAIScriptPtr += 6;
}

static void ContestAICmd_get_contest_type(void)
{
    eContestAI.scriptResult = gSpecialVar_ContestCategory;
    gAIScriptPtr += 1;
}

static void ContestAICmd_if_contest_type_eq(void)
{
    ContestAICmd_get_contest_type();

    if (eContestAI.scriptResult == gAIScriptPtr[0])
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1);
    else
        gAIScriptPtr += 5;
}

static void ContestAICmd_if_contest_type_not_eq(void)
{
    ContestAICmd_get_contest_type();

    if (eContestAI.scriptResult != gAIScriptPtr[0])
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1);
    else
        gAIScriptPtr += 5;
}

static void ContestAICmd_get_move_excitement(void)
{
    eContestAI.scriptResult = Contest_GetMoveExcitement(gContestMons[eContestAI.contestantId].moves[eContestAI.nextMoveIndex]);
    gAIScriptPtr += 1;
}

static void ContestAICmd_if_move_excitement_less_than(void)
{
    ContestAICmd_get_move_excitement();

    if (eContestAI.scriptResult < (s8)gAIScriptPtr[0])
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1);
    else
        gAIScriptPtr += 5;
}

static void ContestAICmd_if_move_excitement_more_than(void)
{
    ContestAICmd_get_move_excitement();

    if (eContestAI.scriptResult > (s8)gAIScriptPtr[0])
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1);
    else
        gAIScriptPtr += 5;
}

static void ContestAICmd_if_move_excitement_eq(void)
{
    ContestAICmd_get_move_excitement();

    if (eContestAI.scriptResult == (s8)gAIScriptPtr[0])
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1);
    else
        gAIScriptPtr += 5;
}

static void ContestAICmd_if_move_excitement_not_eq(void)
{
    ContestAICmd_get_move_excitement();

    if (eContestAI.scriptResult != (s8)gAIScriptPtr[0])
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1);
    else
        gAIScriptPtr += 5;
}

static void ContestAICmd_get_move_effect(void)
{
    u16 move = gContestMons[eContestAI.contestantId].moves[eContestAI.nextMoveIndex];

    eContestAI.scriptResult = gContestMoves[move].effect;
    gAIScriptPtr += 1;
}

static void ContestAICmd_if_move_effect_eq(void)
{
    ContestAICmd_get_move_effect();

    if (eContestAI.scriptResult == gAIScriptPtr[0])
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1);
    else
        gAIScriptPtr += 5;
}

static void ContestAICmd_if_move_effect_not_eq(void)
{
    ContestAICmd_get_move_effect();

    if (eContestAI.scriptResult != gAIScriptPtr[0])
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1);
    else
        gAIScriptPtr += 5;
}

static void ContestAICmd_get_move_effect_type(void)
{
    u16 move = gContestMons[eContestAI.contestantId].moves[eContestAI.nextMoveIndex];

    eContestAI.scriptResult = gContestEffects[gContestMoves[move].effect].effectType;
    gAIScriptPtr += 1;
}

static void ContestAICmd_if_move_effect_type_eq(void)
{
    ContestAICmd_get_move_effect_type();

    if (eContestAI.scriptResult == gAIScriptPtr[0])
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1);
    else
        gAIScriptPtr += 5;
}

static void ContestAICmd_if_move_effect_type_not_eq(void)
{
    ContestAICmd_get_move_effect_type();

    if (eContestAI.scriptResult != gAIScriptPtr[0])
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1);
    else
        gAIScriptPtr += 5;
}

static void ContestAICmd_check_most_appealing_move(void)
{
    int i;
    u16 move = gContestMons[eContestAI.contestantId].moves[eContestAI.nextMoveIndex];
    u8 appeal = gContestEffects[gContestMoves[move].effect].appeal;

    for (i = 0; i < MAX_MON_MOVES; i++)
    {
        u16 newMove = gContestMons[eContestAI.contestantId].moves[i];
        if (newMove != 0 && appeal < gContestEffects[gContestMoves[newMove].effect].appeal)
            break;
    }

    if (i == MAX_MON_MOVES)
        eContestAI.scriptResult = TRUE;
    else
        eContestAI.scriptResult = FALSE;

    gAIScriptPtr += 1;
}

static void ContestAICmd_if_most_appealing_move(void)
{
    ContestAICmd_check_most_appealing_move();

    if (eContestAI.scriptResult != FALSE)
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 0);
    else
        gAIScriptPtr += 4;
}

static void ContestAICmd_check_most_jamming_move(void)
{
    int i;
    u16 move = gContestMons[eContestAI.contestantId].moves[eContestAI.nextMoveIndex];
    u8 jam = gContestEffects[gContestMoves[move].effect].jam;

    for (i = 0; i < MAX_MON_MOVES; i++)
    {
        u16 newMove = gContestMons[eContestAI.contestantId].moves[i];
        if (newMove != MOVE_NONE && jam < gContestEffects[gContestMoves[newMove].effect].jam)
            break;
    }

    if (i == MAX_MON_MOVES)
        eContestAI.scriptResult = TRUE;
    else
        eContestAI.scriptResult = FALSE;

    gAIScriptPtr += 1;
}

static void ContestAICmd_if_most_jamming_move(void)
{
    ContestAICmd_check_most_jamming_move();

    if (eContestAI.scriptResult != FALSE)
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1);
    else
        gAIScriptPtr += 5;
}

static void ContestAICmd_get_num_move_hearts(void)
{
    u16 move = gContestMons[eContestAI.contestantId].moves[eContestAI.nextMoveIndex];

    eContestAI.scriptResult = gContestEffects[gContestMoves[move].effect].appeal / 10;
    gAIScriptPtr += 1;
}

static void ContestAICmd_if_num_move_hearts_less_than(void)
{
    ContestAICmd_get_num_move_hearts();

    if (eContestAI.scriptResult < gAIScriptPtr[0])
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1);
    else
        gAIScriptPtr += 5;
}

static void ContestAICmd_if_num_move_hearts_more_than(void)
{
    ContestAICmd_get_num_move_hearts();

    if (eContestAI.scriptResult > gAIScriptPtr[0])
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1);
    else
        gAIScriptPtr += 5;
}

static void ContestAICmd_if_num_move_hearts_eq(void)
{
    ContestAICmd_get_num_move_hearts();

    if (eContestAI.scriptResult == gAIScriptPtr[0])
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1);
    else
        gAIScriptPtr += 5;
}

static void ContestAICmd_if_num_move_hearts_not_eq(void)
{
    ContestAICmd_get_num_move_hearts();

    if (eContestAI.scriptResult != gAIScriptPtr[0])
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1);
    else
        gAIScriptPtr += 5;
}

static void ContestAICmd_get_num_move_jam_hearts(void)
{
    u16 move = gContestMons[eContestAI.contestantId].moves[eContestAI.nextMoveIndex];

    eContestAI.scriptResult = gContestEffects[gContestMoves[move].effect].jam / 10;
    gAIScriptPtr += 1;
}

static void ContestAICmd_if_num_move_jam_hearts_less_than(void)
{
    ContestAICmd_get_num_move_jam_hearts();

    if (eContestAI.scriptResult < gAIScriptPtr[0])
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1);
    else
        gAIScriptPtr += 5;
}

static void ContestAICmd_if_num_move_jam_hearts_more_than(void)
{
    ContestAICmd_get_num_move_jam_hearts();

    if (eContestAI.scriptResult > gAIScriptPtr[0])
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1);
    else
        gAIScriptPtr += 5;
}

static void ContestAICmd_if_num_move_jam_hearts_eq(void)
{
    ContestAICmd_get_num_move_jam_hearts();

    if (eContestAI.scriptResult == gAIScriptPtr[0])
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1);
    else
        gAIScriptPtr += 5;
}

static void ContestAICmd_if_num_move_jam_hearts_not_eq(void)
{
    ContestAICmd_get_num_move_jam_hearts();

    if (eContestAI.scriptResult != gAIScriptPtr[0])
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1);
    else
        gAIScriptPtr += 5;
}

static void ContestAICmd_get_move_used_count(void)
{
    s16 result;
    u16 move = gContestMons[eContestAI.contestantId].moves[eContestAI.nextMoveIndex];

    if (move != eContestantStatus[eContestAI.contestantId].prevMove)
        result = 0; // move is unique and not reused.
    else
        result = eContestantStatus[eContestAI.contestantId].moveRepeatCount + 1;

    eContestAI.scriptResult = result;
    gAIScriptPtr += 1;
}

static void ContestAICmd_if_most_used_count_less_than(void)
{
    ContestAICmd_get_move_used_count();

    if (eContestAI.scriptResult < gAIScriptPtr[0])
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1);
    else
        gAIScriptPtr += 5;
}

static void ContestAICmd_if_most_used_count_more_than(void)
{
    ContestAICmd_get_move_used_count();

    if (eContestAI.scriptResult > gAIScriptPtr[0])
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1);
    else
        gAIScriptPtr += 5;
}

static void ContestAICmd_if_most_used_count_eq(void)
{
    ContestAICmd_get_move_used_count();

    if (eContestAI.scriptResult == gAIScriptPtr[0])
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1);
    else
        gAIScriptPtr += 5;
}

static void ContestAICmd_if_most_used_count_not_eq(void)
{
    ContestAICmd_get_move_used_count();

    if (eContestAI.scriptResult != gAIScriptPtr[0])
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1);
    else
        gAIScriptPtr += 5;
}

static void ContestAICmd_check_combo_starter(void)
{
    u8 result = 0;
    int i;
    u16 move = gContestMons[eContestAI.contestantId].moves[eContestAI.nextMoveIndex];

    for (i = 0; i < MAX_MON_MOVES; i++)
    {
        if (gContestMons[eContestAI.contestantId].moves[i])
        {
            result = AreMovesContestCombo(move, gContestMons[eContestAI.contestantId].moves[i]);
            if (result)
            {
                result = 1;
                break;
            }
        }
    }

    if (result)
        result = 1;

    eContestAI.scriptResult = result;
    gAIScriptPtr += 1;
}

static void ContestAICmd_if_combo_starter(void)
{
    ContestAICmd_check_combo_starter();

    if (eContestAI.scriptResult)
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 0);
    else
        gAIScriptPtr += 4;
}

static void ContestAICmd_if_not_combo_starter(void)
{
    ContestAICmd_check_combo_starter();

    if (!eContestAI.scriptResult)
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 0);
    else
        gAIScriptPtr += 4;
}

static void ContestAICmd_check_combo_finisher(void)
{
    u8 result = 0;
    int i;
    u16 move = gContestMons[eContestAI.contestantId].moves[eContestAI.nextMoveIndex];

    for (i = 0; i < MAX_MON_MOVES; i++)
    {
        if (gContestMons[eContestAI.contestantId].moves[i])
        {
            result = AreMovesContestCombo(gContestMons[eContestAI.contestantId].moves[i], move);
            if (result)
            {
                result = 1;
                break;
            }
        }
    }

    if (result)
        result = 1;

    eContestAI.scriptResult = result;
    gAIScriptPtr += 1;
}

static void ContestAICmd_if_combo_finisher(void)
{
    ContestAICmd_check_combo_finisher();

    if (eContestAI.scriptResult)
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 0);
    else
        gAIScriptPtr += 4;
}

static void ContestAICmd_if_not_combo_finisher(void)
{
    ContestAICmd_check_combo_finisher();

    if (!eContestAI.scriptResult)
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 0);
    else
        gAIScriptPtr += 4;
}

static void ContestAICmd_check_would_finish_combo(void)
{
    u8 result = 0;
    u16 move = gContestMons[eContestAI.contestantId].moves[eContestAI.nextMoveIndex];

    if (eContestantStatus[eContestAI.contestantId].prevMove)
        result = AreMovesContestCombo(eContestantStatus[eContestAI.contestantId].prevMove, move);

    if (result)
        result = 1;

    eContestAI.scriptResult = result;
    gAIScriptPtr += 1;
}

static void ContestAICmd_if_would_finish_combo(void)
{
    ContestAICmd_check_would_finish_combo();

    if (eContestAI.scriptResult)
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 0);
    else
        gAIScriptPtr += 4;
}

static void ContestAICmd_if_would_not_finish_combo(void)
{
    ContestAICmd_check_would_finish_combo();

    if (!eContestAI.scriptResult)
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 0);
    else
        gAIScriptPtr += 4;
}

static void ContestAICmd_get_condition(void)
{
    u8 contestant = GetContestantIdByTurn(gAIScriptPtr[1]);

    eContestAI.scriptResult = eContestantStatus[contestant].condition / 10;
    gAIScriptPtr += 2;
}

static void ContestAICmd_if_condition_less_than(void)
{
    ContestAICmd_get_condition();

    if (eContestAI.scriptResult < gAIScriptPtr[0])
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1);
    else
        gAIScriptPtr += 5;
}

static void ContestAICmd_if_condition_more_than(void)
{
    ContestAICmd_get_condition();

    if (eContestAI.scriptResult > gAIScriptPtr[0])
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1);
    else
        gAIScriptPtr += 5;
}

static void ContestAICmd_if_condition_eq(void)
{
    ContestAICmd_get_condition();

    if (eContestAI.scriptResult == gAIScriptPtr[0])
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1);
    else
        gAIScriptPtr += 5;
}

static void ContestAICmd_if_condition_not_eq(void)
{
    ContestAICmd_get_condition();

    if (eContestAI.scriptResult != gAIScriptPtr[0])
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1);
    else
        gAIScriptPtr += 5;
}

static void ContestAICmd_get_used_combo_starter(void)
{
    u16 result = FALSE;
    u8 contestant = GetContestantIdByTurn(gAIScriptPtr[1]);

    if (IsContestantAllowedToCombo(contestant))
        result = gContestMoves[eContestantStatus[contestant].prevMove].comboStarterId ? TRUE : FALSE;

    eContestAI.scriptResult = result;
    gAIScriptPtr += 2;
}

static void ContestAICmd_if_used_combo_starter_less_than(void)
{
    ContestAICmd_get_used_combo_starter();

    if (eContestAI.scriptResult < gAIScriptPtr[0])
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1);
    else
        gAIScriptPtr += 5;
}

static void ContestAICmd_if_used_combo_starter_more_than(void)
{
    ContestAICmd_get_used_combo_starter();

    if (eContestAI.scriptResult > gAIScriptPtr[0])
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1);
    else
        gAIScriptPtr += 5;
}

static void ContestAICmd_if_used_combo_starter_eq(void)
{
    ContestAICmd_get_used_combo_starter();

    if (eContestAI.scriptResult == gAIScriptPtr[0])
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1);
    else
        gAIScriptPtr += 5;
}

static void ContestAICmd_if_used_combo_starter_not_eq(void)
{
    ContestAICmd_get_used_combo_starter();

    if (eContestAI.scriptResult != gAIScriptPtr[0])
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1);
    else
        gAIScriptPtr += 5;
}

static void ContestAICmd_check_can_participate(void)
{
    if (Contest_IsMonsTurnDisabled(GetContestantIdByTurn(gAIScriptPtr[1])))
        eContestAI.scriptResult = FALSE;
    else
        eContestAI.scriptResult = TRUE;

    gAIScriptPtr += 2;
}

static void ContestAICmd_if_can_participate(void)
{
    ContestAICmd_check_can_participate();

    if (eContestAI.scriptResult)
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 0);
    else
        gAIScriptPtr += 4;
}

static void ContestAICmd_if_cannot_participate(void)
{
    ContestAICmd_check_can_participate();

    if (!eContestAI.scriptResult)
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 0);
    else
        gAIScriptPtr += 4;
}

static void ContestAICmd_get_completed_combo(void)
{
    u8 contestant = GetContestantIdByTurn(gAIScriptPtr[1]);

    eContestAI.scriptResult = eContestantStatus[contestant].completedComboFlag;
    gAIScriptPtr += 2;
}

static void ContestAICmd_if_completed_combo(void)
{
    ContestAICmd_get_completed_combo();

    if (eContestAI.scriptResult)
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 0);
    else
        gAIScriptPtr += 4;
}

static void ContestAICmd_if_not_completed_combo(void)
{
    ContestAICmd_get_completed_combo();

    if (!eContestAI.scriptResult)
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 0);
    else
        gAIScriptPtr += 4;
}

static void ContestAICmd_get_points_diff(void)
{
    u8 contestant = GetContestantIdByTurn(gAIScriptPtr[1]);

    eContestAI.scriptResult = eContestantStatus[contestant].pointTotal - eContestantStatus[eContestAI.contestantId].pointTotal;
    gAIScriptPtr += 2;
}

static void ContestAICmd_if_points_more_than_mon(void)
{
    ContestAICmd_get_points_diff();

    if (eContestAI.scriptResult < 0)
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 0);
    else
        gAIScriptPtr += 4;
}

static void ContestAICmd_if_points_less_than_mon(void)
{
    ContestAICmd_get_points_diff();

    if (eContestAI.scriptResult > 0)
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 0);
    else
        gAIScriptPtr += 4;
}

static void ContestAICmd_if_points_eq_mon(void)
{
    ContestAICmd_get_points_diff();

    if (eContestAI.scriptResult == 0)
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 0);
    else
        gAIScriptPtr += 4;
}

static void ContestAICmd_if_points_not_eq_mon(void)
{
    ContestAICmd_get_points_diff();

    if (eContestAI.scriptResult != 0)
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 0);
    else
        gAIScriptPtr += 4;
}

static void ContestAICmd_get_preliminary_points_diff(void)
{
    u8 contestant = GetContestantIdByTurn(gAIScriptPtr[1]);

    eContestAI.scriptResult = gContestMonRound1Points[contestant] - gContestMonRound1Points[eContestAI.contestantId];
    gAIScriptPtr += 2;
}

static void ContestAICmd_if_preliminary_points_more_than_mon(void)
{
    ContestAICmd_get_preliminary_points_diff();

    if (eContestAI.scriptResult < 0)
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 0);
    else
        gAIScriptPtr += 4;
}

static void ContestAICmd_if_preliminary_points_less_than_mon(void)
{
    ContestAICmd_get_preliminary_points_diff();

    if (eContestAI.scriptResult > 0)
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 0);
    else
        gAIScriptPtr += 4;
}

static void ContestAICmd_if_preliminary_points_eq_mon(void)
{
    ContestAICmd_get_preliminary_points_diff();

    if (eContestAI.scriptResult == 0)
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 0);
    else
        gAIScriptPtr += 4;
}

static void ContestAICmd_if_preliminary_points_not_eq_mon(void)
{
    ContestAICmd_get_preliminary_points_diff();

    if (eContestAI.scriptResult != 0)
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 0);
    else
        gAIScriptPtr += 4;
}

static void ContestAICmd_get_used_moves_effect(void)
{
    u8 contestant = GetContestantIdByTurn(gAIScriptPtr[1]);
    u8 round = gAIScriptPtr[2];
    u16 move = eContest.moveHistory[round][contestant];

    eContestAI.scriptResult = gContestMoves[move].effect;
    gAIScriptPtr += 3;
}

static void ContestAICmd_if_used_moves_effect_less_than(void)
{
    ContestAICmd_get_used_moves_effect();

    if (eContestAI.scriptResult < gAIScriptPtr[0])
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1);
    else
        gAIScriptPtr += 5;
}

static void ContestAICmd_if_used_moves_effect_more_than(void)
{
    ContestAICmd_get_used_moves_effect();

    if (eContestAI.scriptResult > gAIScriptPtr[0])
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1);
    else
        gAIScriptPtr += 5;
}

static void ContestAICmd_if_used_moves_effect_eq(void)
{
    ContestAICmd_get_used_moves_effect();

    if (eContestAI.scriptResult == gAIScriptPtr[0])
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1);
    else
        gAIScriptPtr += 5;
}

static void ContestAICmd_if_used_moves_effect_not_eq(void)
{
    ContestAICmd_get_used_moves_effect();

    if (eContestAI.scriptResult != gAIScriptPtr[0])
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1);
    else
        gAIScriptPtr += 5;
}

static void ContestAICmd_get_used_moves_excitement(void)
{
    u8 contestant = GetContestantIdByTurn(gAIScriptPtr[1]);
    u8 round = gAIScriptPtr[2];
    s8 result = eContest.excitementHistory[round][contestant];

    eContestAI.scriptResult = result;
    gAIScriptPtr += 3;
}

static void ContestAICmd_if_used_moves_excitement_less_than(void)
{
    ContestAICmd_get_used_moves_excitement();

    if (eContestAI.scriptResult < gAIScriptPtr[0])
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1);
    else
        gAIScriptPtr += 5;
}

static void ContestAICmd_if_used_moves_excitement_more_than(void)
{
    ContestAICmd_get_used_moves_excitement();

    if (eContestAI.scriptResult > gAIScriptPtr[0])
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1);
    else
        gAIScriptPtr += 5;
}

static void ContestAICmd_if_used_moves_excitement_eq(void)
{
    ContestAICmd_get_used_moves_excitement();

    if (eContestAI.scriptResult == gAIScriptPtr[0])
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1);
    else
        gAIScriptPtr += 5;
}

static void ContestAICmd_if_used_moves_excitement_not_eq(void)
{
    ContestAICmd_get_used_moves_excitement();

    if (eContestAI.scriptResult != gAIScriptPtr[0])
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1);
    else
        gAIScriptPtr += 5;
}

static void ContestAICmd_get_used_moves_effect_type(void)
{
    u8 contestant = GetContestantIdByTurn(gAIScriptPtr[1]);
    u8 round = gAIScriptPtr[2];
    u16 move = eContest.moveHistory[round][contestant];

    eContestAI.scriptResult = gContestEffects[gContestMoves[move].effect].effectType;
    gAIScriptPtr += 3;
}

static void ContestAICmd_if_used_moves_effect_type_eq(void)
{
    ContestAICmd_get_used_moves_effect_type();

    if (eContestAI.scriptResult == gAIScriptPtr[0])
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1);
    else
        gAIScriptPtr += 5;
}

static void ContestAICmd_if_used_moves_effect_type_not_eq(void)
{
    ContestAICmd_get_used_moves_effect_type();

    if (eContestAI.scriptResult != gAIScriptPtr[0])
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1);
    else
        gAIScriptPtr += 5;
}

static void ContestAICmd_save_result(void)
{
    eContestAI.vars[gAIScriptPtr[1]] = eContestAI.scriptResult;
    gAIScriptPtr += 2;
}

static void ContestAICmd_setvar(void)
{
    eContestAI.vars[gAIScriptPtr[1]] = T1_READ_16(gAIScriptPtr + 2);
    gAIScriptPtr += 4;
}

static void ContestAICmd_add(void)
{
    // wtf? shouldn't T1_READ_16 work here? why the signed 8 load by gAIScriptPtr[2]?
    eContestAI.vars[gAIScriptPtr[1]] += ((s8)gAIScriptPtr[2] | gAIScriptPtr[3] << 8);
    gAIScriptPtr += 4;
}

static void ContestAICmd_addvar(void)
{
    eContestAI.vars[gAIScriptPtr[1]] += eContestAI.vars[gAIScriptPtr[2]];
    gAIScriptPtr += 3;
}

static void ContestAICmd_addvar_duplicate(void)
{
    eContestAI.vars[gAIScriptPtr[1]] += eContestAI.vars[gAIScriptPtr[2]];
    gAIScriptPtr += 3;
}

static void ContestAICmd_if_less_than(void)
{
    if (eContestAI.vars[gAIScriptPtr[1]] < T1_READ_16(gAIScriptPtr + 2))
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 4);
    else
        gAIScriptPtr += 8;
}

static void ContestAICmd_if_greater_than(void)
{
    if (eContestAI.vars[gAIScriptPtr[1]] > T1_READ_16(gAIScriptPtr + 2))
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 4);
    else
        gAIScriptPtr += 8;
}

static void ContestAICmd_if_eq(void)
{
    if (eContestAI.vars[gAIScriptPtr[1]] == T1_READ_16(gAIScriptPtr + 2))
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 4);
    else
        gAIScriptPtr += 8;
}

static void ContestAICmd_if_not_eq(void)
{
    if (eContestAI.vars[gAIScriptPtr[1]] != T1_READ_16(gAIScriptPtr + 2))
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 4);
    else
        gAIScriptPtr += 8;
}

static void ContestAICmd_if_less_than_var(void)
{
    if (eContestAI.vars[gAIScriptPtr[1]] < (eContestAI.vars[gAIScriptPtr[2]]))
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 3);
    else
        gAIScriptPtr += 7;
}

static void ContestAICmd_if_greater_than_var(void)
{
    if (eContestAI.vars[gAIScriptPtr[1]] > (eContestAI.vars[gAIScriptPtr[2]]))
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 3);
    else
        gAIScriptPtr += 7;
}

static void ContestAICmd_if_eq_var(void)
{
    if (eContestAI.vars[gAIScriptPtr[1]] == (eContestAI.vars[gAIScriptPtr[2]]))
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 3);
    else
        gAIScriptPtr += 7;
}

static void ContestAICmd_if_not_eq_var(void)
{
    if (eContestAI.vars[gAIScriptPtr[1]] != (eContestAI.vars[gAIScriptPtr[2]]))
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 3);
    else
        gAIScriptPtr += 7;
}

// UB: Should just be comparing to gAIScriptPtr[1] in the functions below
// The values passed via gAIScriptPtr[1] range from 0-255
// and vars is an s16[3], so this goes way out of bounds
static void ContestAICmd_if_random_less_than(void)
{
#ifndef UBFIX
    if ((Random() & 0xFF) < eContestAI.vars[gAIScriptPtr[1]])
#else
    if ((Random() & 0xFF) < gAIScriptPtr[1])
#endif
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 2);
    else
        gAIScriptPtr += 6;
}

static void ContestAICmd_if_random_greater_than(void)
{
#ifndef UBFIX
    if (((Random()) & 0xFF) > eContestAI.vars[gAIScriptPtr[1]])
#else
    if (((Random()) & 0xFF) > gAIScriptPtr[1])
#endif
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 2);
    else
        gAIScriptPtr += 6;
}

static void ContestAICmd_goto(void)
{
    gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1);
}

static void ContestAICmd_call(void)
{
    AIStackPushVar(gAIScriptPtr + 5);
    gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1);
}

static void ContestAICmd_end(void)
{
    if (!AIStackPop())
        eContestAI.aiAction |= 1;
}

static void AIStackPushVar(const u8 *ptr)
{
    eContestAI.stack[eContestAI.stackSize++] = ptr;
}

static bool8 AIStackPop(void)
{
    if (eContestAI.stackSize != 0)
    {
        --eContestAI.stackSize;
        gAIScriptPtr = eContestAI.stack[eContestAI.stackSize];
        return TRUE;
    }
    else
    {
        return FALSE;
    }
}

static void ContestAICmd_check_user_has_exciting_move(void)
{
    int result = 0;
    int i;

    for (i = 0; i < MAX_MON_MOVES; i++)
    {
        if (gContestMons[eContestAI.contestantId].moves[i])
        {
            if (Contest_GetMoveExcitement(gContestMons[eContestAI.contestantId].moves[i]) == 1)
            {
                result = 1;
                break;
            }
        }
    }

    eContestAI.scriptResult = result;
    gAIScriptPtr += 1;
}

static void ContestAICmd_if_user_has_exciting_move(void)
{
    ContestAICmd_check_user_has_exciting_move();

    if (eContestAI.scriptResult)
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 0);
    else
        gAIScriptPtr += 4;
}

static void ContestAICmd_if_user_doesnt_have_exciting_move(void)
{
    ContestAICmd_check_user_has_exciting_move();

    if (!eContestAI.scriptResult)
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 0);
    else
        gAIScriptPtr += 4;
}

// BUG: This is checking if the user has a specific move, but when it's used in the AI script
//      they're checking for an effect. Checking for a specific effect would make more sense,
//      but given that effects are normally read as a single byte and this reads 2 bytes, it
//      seems reading a move was intended and the AI script is using it incorrectly.
//      The fix below aligns the function with how it's used by the script, rather than the apparent
//      intention of its usage

static void ContestAICmd_check_user_has_move(void)
{
    int hasMove = FALSE;
    int i;
    u16 targetMove = T1_READ_16(gAIScriptPtr + 1);

    for (i = 0; i < MAX_MON_MOVES; i++)
    {
        #ifdef BUGFIX
        u16 move = gContestMoves[gContestMons[eContestAI.contestantId].moves[i]].effect;
        #else
        u16 move = gContestMons[eContestAI.contestantId].moves[i];
        #endif

        if (move == targetMove)
        {
            hasMove = TRUE;
            break;
        }
    }

    eContestAI.scriptResult = hasMove;
    gAIScriptPtr += 3;
}

static void ContestAICmd_if_user_has_move(void)
{
    ContestAICmd_check_user_has_move();

    if (eContestAI.scriptResult)
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 0);
    else
        gAIScriptPtr += 4;
}

static void ContestAICmd_if_user_doesnt_have_move(void)
{
    ContestAICmd_check_user_has_move();

    if (!eContestAI.scriptResult)
        gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 0);
    else
        gAIScriptPtr += 4;
}

repo_name: Lunos/pokeemerald

license: mit


code:
#include "global.h"
#include "random.h"
#include "constants/moves.h"
#include "contest.h"
#include "contest_effect.h"

static void ContestEffect_HighlyAppealing(void);
static void ContestEffect_UserMoreEasilyStartled(void);
static void ContestEffect_GreatAppealButNoMoreMoves(void);
static void ContestEffect_RepetitionNotBoring(void);
static void ContestEffect_AvoidStartleOnce(void);
static void ContestEffect_AvoidStartle(void);
static void ContestEffect_AvoidStartleSlightly(void);
static void ContestEffect_UserLessEasilyStartled(void);
static void ContestEffect_StartleFrontMon(void);
static void ContestEffect_StartlePrevMons(void);
static void ContestEffect_StartlePrevMon2(void);
static void ContestEffect_StartlePrevMons2(void);
static void ContestEffect_ShiftJudgeAttention(void);
static void ContestEffect_StartleMonWithJudgesAttention(void);
static void ContestEffect_JamsOthersButMissOneTurn(void);
static void ContestEffect_StartleMonsSameTypeAppeal(void);
static void ContestEffect_StartleMonsCoolAppeal(void);
static void ContestEffect_StartleMonsBeautyAppeal(void);
static void ContestEffect_StartleMonsCuteAppeal(void);
static void ContestEffect_StartleMonsSmartAppeal(void);
static void ContestEffect_StartleMonsToughAppeal(void);
static void ContestEffect_MakeFollowingMonNervous(void);
static void ContestEffect_MakeFollowingMonsNervous(void);
static void ContestEffect_WorsenConditionOfPrevMons(void);
static void ContestEffect_BadlyStartlesMonsInGoodCondition(void);
static void ContestEffect_BetterIfFirst(void);
static void ContestEffect_BetterIfLast(void);
static void ContestEffect_AppealAsGoodAsPrevOnes(void);
static void ContestEffect_AppealAsGoodAsPrevOne(void);
static void ContestEffect_BetterWhenLater(void);
static void ContestEffect_QualityDependsOnTiming(void);
static void ContestEffect_BetterIfSameType(void);
static void ContestEffect_BetterIfDiffType(void);
static void ContestEffect_AffectedByPrevAppeal(void);
static void ContestEffect_ImproveConditionPreventNervousness(void);
static void ContestEffect_BetterWithGoodCondition(void);
static void ContestEffect_NextAppealEarlier(void);
static void ContestEffect_NextAppealLater(void);
static void ContestEffect_MakeScramblingTurnOrderEasier(void);
static void ContestEffect_ScrambleNextTurnOrder(void);
static void ContestEffect_ExciteAudienceInAnyContest(void);
static void ContestEffect_BadlyStartleMonsWithGoodAppeals(void);
static void ContestEffect_BetterWhenAudienceExcited(void);
static void ContestEffect_DontExciteAudience(void);
static void JamByMoveCategory(u8);
static bool8 CanUnnerveContestant(u8);
static u8 WasAtLeastOneOpponentJammed(void);
static void JamContestant(u8, u8);
static s16 RoundTowardsZero(s16);
static s16 RoundUp(s16);

#include "data/contest_moves.h"

bool8 AreMovesContestCombo(u16 lastMove, u16 nextMove)
{
    u8 nextMoveComboMoves[4];
    u8 lastMoveComboStarterId = gContestMoves[lastMove].comboStarterId;
    nextMoveComboMoves[0] = gContestMoves[nextMove].comboMoves[0];
    nextMoveComboMoves[1] = gContestMoves[nextMove].comboMoves[1];
    nextMoveComboMoves[2] = gContestMoves[nextMove].comboMoves[2];
    nextMoveComboMoves[3] = gContestMoves[nextMove].comboMoves[3];

    if (lastMoveComboStarterId == 0)
        return FALSE;
    else if (lastMoveComboStarterId == nextMoveComboMoves[0]
          || lastMoveComboStarterId == nextMoveComboMoves[1]
          || lastMoveComboStarterId == nextMoveComboMoves[2]
          || lastMoveComboStarterId == nextMoveComboMoves[3])
        return gComboStarterLookupTable[lastMoveComboStarterId];
    else
        return FALSE;
}

// A highly appealing move.
static void ContestEffect_HighlyAppealing(void)
{
}

// After this move, the user is more easily startled.
static void ContestEffect_UserMoreEasilyStartled(void)
{
    eContestantStatus[eContestAppealResults.contestant].moreEasilyStartled = TRUE;
    SetContestantEffectStringID(eContestAppealResults.contestant, CONTEST_STRING_MORE_CONSCIOUS);
}

// Makes a great appeal, but allows no more to the end.
static void ContestEffect_GreatAppealButNoMoreMoves(void)
{
    eContestantStatus[eContestAppealResults.contestant].exploded = TRUE;
    SetContestantEffectStringID(eContestAppealResults.contestant, CONTEST_STRING_NO_APPEAL);
}

// Can be used repeatedly without boring the JUDGE.
static void ContestEffect_RepetitionNotBoring(void)
{
    eContestantStatus[eContestAppealResults.contestant].usedRepeatableMove = TRUE;
    eContestantStatus[eContestAppealResults.contestant].repeatedMove = FALSE;
    eContestantStatus[eContestAppealResults.contestant].moveRepeatCount = 0;
}

// Can avoid being startled by others once.
static void ContestEffect_AvoidStartleOnce(void)
{
    eContestantStatus[eContestAppealResults.contestant].jamSafetyCount = 1;
    SetContestantEffectStringID(eContestAppealResults.contestant, CONTEST_STRING_SETTLE_DOWN);
}

// Can avoid being startled by others.
static void ContestEffect_AvoidStartle(void)
{
    eContestantStatus[eContestAppealResults.contestant].immune = TRUE;
    SetContestantEffectStringID(eContestAppealResults.contestant, CONTEST_STRING_OBLIVIOUS_TO_OTHERS);
}

// Can avoid being startled by others a little.
static void ContestEffect_AvoidStartleSlightly(void)
{
    eContestantStatus[eContestAppealResults.contestant].jamReduction = 20;
    SetContestantEffectStringID(eContestAppealResults.contestant,CONTEST_STRING_LESS_AWARE);
}

// After this move, the user is less likely to be startled.
static void ContestEffect_UserLessEasilyStartled(void)
{
    eContestantStatus[eContestAppealResults.contestant].resistant = TRUE;
    SetContestantEffectStringID(eContestAppealResults.contestant,CONTEST_STRING_STOPPED_CARING);
}

// Slightly startles the POKéMON in front.
static void ContestEffect_StartleFrontMon(void)
{
    u8 idx = 0;
    u8 a = eContestAppealResults.contestant;

    if (eContestAppealResults.turnOrder[a] != 0) {
        int i;

        for (i = 0; i < CONTESTANT_COUNT; i++)
        {
            if (eContestAppealResults.turnOrder[a] - 1 == eContestAppealResults.turnOrder[i])
                break;
        }
        eContestAppealResults.jamQueue[0] = i;
        eContestAppealResults.jamQueue[1] = 0xFF;
        idx = WasAtLeastOneOpponentJammed();
    }
    if (idx == 0)
        SetContestantEffectStringID2(eContestAppealResults.contestant, CONTEST_STRING_MESSED_UP2);
    SetContestantEffectStringID(eContestAppealResults.contestant, CONTEST_STRING_ATTEMPT_STARTLE);
}

// Slightly startles those that have made appeals.
static void ContestEffect_StartlePrevMons(void)
{
    u8 idx = 0;
    u8 contestant = eContestAppealResults.contestant;

    if (eContestAppealResults.turnOrder[contestant] != 0)
    {
        int i, j;

        for (i = 0, j = 0; i < CONTESTANT_COUNT; i++)
        {
            if (eContestAppealResults.turnOrder[contestant] > eContestAppealResults.turnOrder[i])
                eContestAppealResults.jamQueue[j++] = i;
        }

        eContestAppealResults.jamQueue[j] = 0xFF;
        idx = WasAtLeastOneOpponentJammed();
    }
    if (idx == 0)
        SetContestantEffectStringID2(eContestAppealResults.contestant, CONTEST_STRING_MESSED_UP2);
    SetContestantEffectStringID(eContestAppealResults.contestant, CONTEST_STRING_ATTEMPT_STARTLE);
}

// Startles the POKéMON that appealed before the user.
static void ContestEffect_StartlePrevMon2(void)
{
    u8 rval = Random() % 10;
    int jam;

    if (rval < 2)
        jam = 20;
    else if (rval < 8)
        jam = 40;
    else
        jam = 60;

    eContestAppealResults.jam = jam;
    ContestEffect_StartleFrontMon();
}

// Startles all POKéMON that appealed before the user.
static void ContestEffect_StartlePrevMons2(void)
{
    u8 numStartled = 0;
    u8 contestant = eContestAppealResults.contestant;
    u8 turnOrder = eContestAppealResults.turnOrder[contestant];

    if (turnOrder != 0)
    {
        int i;

        for (i = 0; i < 4; i++)
        {
            if (eContestAppealResults.turnOrder[contestant] > eContestAppealResults.turnOrder[i])
            {
                u8 rval, jam;

                eContestAppealResults.jamQueue[0] = i;
                eContestAppealResults.jamQueue[1] = 0xFF;
                rval = Random() % 10;

                if (rval == 0)
                    jam = 0;
                else if (rval <= 2)
                    jam = 10;
                else if (rval <= 4)
                    jam = 20;
                else if (rval <= 6)
                    jam = 30;
                else if (rval <= 8)
                    jam = 40;
                else
                    jam = 60;

                eContestAppealResults.jam = jam;

                if (WasAtLeastOneOpponentJammed())
                    numStartled++;
            }
        }
    }
    SetContestantEffectStringID(eContestAppealResults.contestant, CONTEST_STRING_ATTEMPT_STARTLE);
    if (numStartled == 0)
        SetContestantEffectStringID2(eContestAppealResults.contestant, CONTEST_STRING_MESSED_UP2);
}

// Shifts the JUDGE's attention from others.
static void ContestEffect_ShiftJudgeAttention(void)
{
    bool32 hitAny = FALSE;
    u8 contestant = eContestAppealResults.contestant;

    if (eContestAppealResults.turnOrder[eContestAppealResults.contestant] != 0)
    {
        int i;

        for (i = 0; i < 4; i++)
        {
            if (eContestAppealResults.turnOrder[contestant] > eContestAppealResults.turnOrder[i] &&
                eContestantStatus[i].hasJudgesAttention &&
                CanUnnerveContestant(i))
            {
                eContestantStatus[i].hasJudgesAttention = FALSE;
                eContestantStatus[i].judgesAttentionWasRemoved = TRUE;
                SetContestantEffectStringID(i, CONTEST_STRING_JUDGE_LOOK_AWAY2);
                hitAny = TRUE;
            }
        }
    }
    SetContestantEffectStringID(eContestAppealResults.contestant,CONTEST_STRING_DAZZLE_ATTEMPT);
    if (!hitAny)
    {
        SetContestantEffectStringID2(eContestAppealResults.contestant, CONTEST_STRING_MESSED_UP2);
    }
}

// Startles the POKéMON that has the JUDGE's attention.
static void ContestEffect_StartleMonWithJudgesAttention(void)
{
    u8 numStartled = 0;
    u8 contestant = eContestAppealResults.contestant;

    if (eContestAppealResults.turnOrder[eContestAppealResults.contestant] != 0)
    {
        int i;

        for (i = 0; i < 4; i++)
        {
            if (eContestAppealResults.turnOrder[contestant] > eContestAppealResults.turnOrder[i])
            {
                if (eContestantStatus[i].hasJudgesAttention)
                    eContestAppealResults.jam = 50;
                else
                    eContestAppealResults.jam = 10;
                eContestAppealResults.jamQueue[0] = i;
                eContestAppealResults.jamQueue[1] = 0xFF;
                if (WasAtLeastOneOpponentJammed())
                    numStartled++;
            }
        }
    }
    SetContestantEffectStringID(eContestAppealResults.contestant, CONTEST_STRING_ATTEMPT_STARTLE);
    if (numStartled == 0)
        SetContestantEffectStringID2(eContestAppealResults.contestant, CONTEST_STRING_MESSED_UP2);
}

// Jams the others, and misses one turn of appeals.
static void ContestEffect_JamsOthersButMissOneTurn(void)
{
    eContestantStatus[eContestAppealResults.contestant].turnSkipped = TRUE;
    ContestEffect_StartlePrevMons();
    SetContestantEffectStringID(eContestAppealResults.contestant, CONTEST_STRING_ATTEMPT_STARTLE);
}

// Startles POKéMON that made a same-type appeal.
static void ContestEffect_StartleMonsSameTypeAppeal(void)
{
    u16 move = eContestantStatus[eContestAppealResults.contestant].currMove;
    JamByMoveCategory(gContestMoves[move].contestCategory);
    SetContestantEffectStringID(eContestAppealResults.contestant, CONTEST_STRING_ATTEMPT_STARTLE);
}

// Badly startles POKéMON that made COOL appeals.
static void ContestEffect_StartleMonsCoolAppeal(void)
{
    JamByMoveCategory(CONTEST_CATEGORY_COOL);
    SetContestantEffectStringID(eContestAppealResults.contestant, CONTEST_STRING_ATTEMPT_STARTLE);
}

// Badly startles POKéMON that made BEAUTY appeals.
static void ContestEffect_StartleMonsBeautyAppeal(void)
{
    JamByMoveCategory(CONTEST_CATEGORY_BEAUTY);
    SetContestantEffectStringID(eContestAppealResults.contestant, CONTEST_STRING_ATTEMPT_STARTLE);
}

// Badly startles POKéMON that made CUTE appeals.
static void ContestEffect_StartleMonsCuteAppeal(void)
{
    JamByMoveCategory(CONTEST_CATEGORY_CUTE);
    SetContestantEffectStringID(eContestAppealResults.contestant, CONTEST_STRING_ATTEMPT_STARTLE);
}

// Badly startles POKéMON that made SMART appeals.
static void ContestEffect_StartleMonsSmartAppeal(void)
{
    JamByMoveCategory(CONTEST_CATEGORY_SMART);
    SetContestantEffectStringID(eContestAppealResults.contestant, CONTEST_STRING_ATTEMPT_STARTLE);
}

// Badly startles POKéMON that made TOUGH appeals.
static void ContestEffect_StartleMonsToughAppeal(void)
{
    JamByMoveCategory(CONTEST_CATEGORY_TOUGH);
    SetContestantEffectStringID(eContestAppealResults.contestant, CONTEST_STRING_ATTEMPT_STARTLE);
}

// Makes one POKéMON after the user nervous.
static void ContestEffect_MakeFollowingMonNervous(void)
{
    bool32 hitAny = FALSE;

    if (eContestAppealResults.turnOrder[eContestAppealResults.contestant] != 3)
    {
        int i;

        for (i = 0; i < 4; i++)
        {
            if (eContestAppealResults.turnOrder[eContestAppealResults.contestant] + 1 == eContestAppealResults.turnOrder[i])
            {
                if (CanUnnerveContestant(i))
                {
                    MakeContestantNervous(i);
                    SetContestantEffectStringID(i, CONTEST_STRING_NERVOUS);
                    hitAny = TRUE;
                }
                else
                {
                    SetContestantEffectStringID(i, CONTEST_STRING_UNAFFECTED);
                    hitAny = TRUE;
                }
            }
        }
    }
    SetContestantEffectStringID(eContestAppealResults.contestant, CONTEST_STRING_UNNERVE_ATTEMPT);
    if (!hitAny)
        SetContestantEffectStringID2(eContestAppealResults.contestant, CONTEST_STRING_MESSED_UP2);
}

// Makes all POKéMON after the user nervous.
static void ContestEffect_MakeFollowingMonsNervous(void)
{
    u8 numUnnerved = 0;
    bool32 contestantUnnerved = FALSE;
    u8 contestantIds[5];
    int i;
    int numAfter;
    s16 oddsMod[CONTESTANT_COUNT];
    s16 odds[CONTESTANT_COUNT];

    memset(contestantIds, 0xFF, ARRAY_COUNT(contestantIds));
    for (i = 0, numAfter = 0; i < CONTESTANT_COUNT; i++)
    {
        if (eContestAppealResults.turnOrder[eContestAppealResults.contestant] < eContestAppealResults.turnOrder[i] &&
            !eContestantStatus[i].nervous && !Contest_IsMonsTurnDisabled(i))
            contestantIds[numAfter++] = i;
    }

    if (numAfter == 1)
    {
        odds[0] = 60;
    }
    else if (numAfter == 2)
    {
        odds[0] = 30;
        odds[1] = 30;
    }
    else if (numAfter == 3)
    {
        odds[0] = 20;
        odds[1] = 20;
        odds[2] = 20;
    }
    else
    {
        for (i = 0; i < CONTESTANT_COUNT; i++)
            odds[i] = 0;
    }
    for (i = 0; i < CONTESTANT_COUNT; i++)
    {
        if (eContestantStatus[i].hasJudgesAttention && IsContestantAllowedToCombo(i))
            oddsMod[i] = gComboStarterLookupTable[gContestMoves[eContestantStatus[i].prevMove].comboStarterId] * 10;
        else
            oddsMod[i] = 0;
        oddsMod[i] -= (eContestantStatus[i].condition / 10) * 10;
    }
    if (odds[0] != 0)
    {
        for (i = 0; contestantIds[i] != 0xFF; i++)
        {
            if (Random() % 100 < odds[i] + oddsMod[contestantIds[i]])
            {
                if (CanUnnerveContestant(contestantIds[i]))
                {
                    MakeContestantNervous(contestantIds[i]);
                    SetContestantEffectStringID(contestantIds[i], CONTEST_STRING_NERVOUS);
                    numUnnerved++;
                }
                else
                {
                    contestantUnnerved = TRUE;
                }
            }
            else
            {
                contestantUnnerved = TRUE;
            }

            if (contestantUnnerved)
            {
                contestantUnnerved = FALSE;
                SetContestantEffectStringID(contestantIds[i], CONTEST_STRING_UNAFFECTED);
                numUnnerved++;
            }
            eContestAppealResults.unnervedPokes[contestantIds[i]] = 1;
        }
    }
    SetContestantEffectStringID(eContestAppealResults.contestant, CONTEST_STRING_UNNERVE_WAITING);
    if (numUnnerved == 0)
        SetContestantEffectStringID2(eContestAppealResults.contestant, CONTEST_STRING_MESSED_UP2);
}

// Worsens the condition of those that made appeals.
static void ContestEffect_WorsenConditionOfPrevMons(void)
{
    u8 numHit = 0;
    int i;

    for (i = 0; i < CONTESTANT_COUNT; i++)
    {
        if (eContestAppealResults.turnOrder[eContestAppealResults.contestant] > eContestAppealResults.turnOrder[i] &&
            eContestantStatus[i].condition > 0 &&
            CanUnnerveContestant(i))
        {
            eContestantStatus[i].condition = 0;
            eContestantStatus[i].conditionMod = CONDITION_LOSE;
            SetContestantEffectStringID(i, CONTEST_STRING_REGAINED_FORM);
            numHit++;
        }
    }

    SetContestantEffectStringID(eContestAppealResults.contestant, CONTEST_STRING_TAUNT_WELL);
    if (numHit == 0)
        SetContestantEffectStringID2(eContestAppealResults.contestant, CONTEST_STRING_IGNORED);
}

// Badly startles POKéMON in good condition.
static void ContestEffect_BadlyStartlesMonsInGoodCondition(void)
{
    u8 numHit = 0;
    int i;

    for (i = 0; i < CONTESTANT_COUNT; i++)
    {
        if (eContestAppealResults.turnOrder[eContestAppealResults.contestant] > eContestAppealResults.turnOrder[i])
        {
            if (eContestantStatus[i].condition > 0)
                eContestAppealResults.jam = 40;
            else
                eContestAppealResults.jam = 10;
            eContestAppealResults.jamQueue[0] = i;
            eContestAppealResults.jamQueue[1] = 0xFF;
            if (WasAtLeastOneOpponentJammed())
                numHit++;
        }
    }
    SetContestantEffectStringID(eContestAppealResults.contestant, CONTEST_STRING_JAM_WELL);
    if (numHit == 0)
        SetContestantEffectStringID2(eContestAppealResults.contestant, CONTEST_STRING_IGNORED);
}

// The appeal works great if performed first.
static void ContestEffect_BetterIfFirst(void)
{
    if (gContestantTurnOrder[eContestAppealResults.contestant] == 0)
    {
        u16 move = eContestantStatus[eContestAppealResults.contestant].currMove;
        eContestantStatus[eContestAppealResults.contestant].appeal += 2 * gContestEffects[gContestMoves[move].effect].appeal;
        SetContestantEffectStringID(eContestAppealResults.contestant, CONTEST_STRING_HUSTLE_STANDOUT);
    }
}

// The appeal works great if performed last.
static void ContestEffect_BetterIfLast(void)
{
    if (gContestantTurnOrder[eContestAppealResults.contestant] == 3)
    {
        u16 move = eContestantStatus[eContestAppealResults.contestant].currMove;
        eContestantStatus[eContestAppealResults.contestant].appeal += 2 * gContestEffects[gContestMoves[move].effect].appeal;
        SetContestantEffectStringID(eContestAppealResults.contestant, CONTEST_STRING_WORK_HARD_UNNOTICED);
    }
}

// Makes the appeal as good as those before it.
static void ContestEffect_AppealAsGoodAsPrevOnes(void)
{
    int i;
    int appealSum;

    for (i = 0, appealSum = 0; i < CONTESTANT_COUNT; i++)
    {
        if (eContestAppealResults.turnOrder[eContestAppealResults.contestant] > eContestAppealResults.turnOrder[i])
            appealSum += eContestantStatus[i].appeal;
    }
    if (appealSum < 0)
        appealSum = 0;

    if (eContestAppealResults.turnOrder[eContestAppealResults.contestant] == 0 || appealSum == 0)
    {
        SetContestantEffectStringID(eContestAppealResults.contestant, CONTEST_STRING_APPEAL_NOT_WELL);
    }
    else
    {
        eContestantStatus[eContestAppealResults.contestant].appeal += appealSum / 2;
        SetContestantEffectStringID(eContestAppealResults.contestant, CONTEST_STRING_WORK_BEFORE);
    }
    eContestantStatus[eContestAppealResults.contestant].appeal = RoundTowardsZero(eContestantStatus[eContestAppealResults.contestant].appeal);
}

// Makes the appeal as good as the one before it.
static void ContestEffect_AppealAsGoodAsPrevOne(void)
{
    s16 appeal = 0;

    if (eContestAppealResults.turnOrder[eContestAppealResults.contestant] != 0)
    {
        int i;
        for (i = 0; i < CONTESTANT_COUNT; i++)
        {
            if (eContestAppealResults.turnOrder[eContestAppealResults.contestant] - 1 == eContestAppealResults.turnOrder[i])
                appeal = eContestantStatus[i].appeal;
        }
    }
    if (eContestAppealResults.turnOrder[eContestAppealResults.contestant] == 0 || appeal <= 0)
    {
        SetContestantEffectStringID(eContestAppealResults.contestant, CONTEST_STRING_APPEAL_NOT_WELL2);
    }
    else
    {
        eContestantStatus[eContestAppealResults.contestant].appeal += appeal;
        SetContestantEffectStringID(eContestAppealResults.contestant, CONTEST_STRING_WORK_PRECEDING);
    }
}

// The appeal works better the later it is performed.
static void ContestEffect_BetterWhenLater(void)
{
    u8 whichTurn = eContestAppealResults.turnOrder[eContestAppealResults.contestant];
    if (whichTurn == 0)
        eContestantStatus[eContestAppealResults.contestant].appeal = 10;
    else
        eContestantStatus[eContestAppealResults.contestant].appeal = 20 * whichTurn;
    if (whichTurn == 0)
        SetContestantEffectStringID(eContestAppealResults.contestant, CONTEST_STRING_APPEAL_NOT_SHOWN_WELL);
    else if (whichTurn == 1)
        SetContestantEffectStringID(eContestAppealResults.contestant, CONTEST_STRING_APPEAL_SLIGHTLY_WELL);
    else if (whichTurn == 2)
        SetContestantEffectStringID(eContestAppealResults.contestant, CONTEST_STRING_APPEAL_PRETTY_WELL);
    else
        SetContestantEffectStringID(eContestAppealResults.contestant, CONTEST_STRING_APPEAL_EXCELLENTLY);
}

// The appeal's quality varies depending on its timing.
static void ContestEffect_QualityDependsOnTiming(void)
{
    u8 rval = Random() % 10;
    s16 appeal;

    if (rval < 3)
    {
        appeal = 10;
        SetContestantEffectStringID(eContestAppealResults.contestant, CONTEST_STRING_APPEAL_NOT_VERY_WELL);
    } else if (rval < 6)
    {
        appeal = 20;
        SetContestantEffectStringID(eContestAppealResults.contestant, CONTEST_STRING_APPEAL_SLIGHTLY_WELL2);
    } else if (rval < 8)
    {
        appeal = 40;
        SetContestantEffectStringID(eContestAppealResults.contestant, CONTEST_STRING_APPEAL_PRETTY_WELL2);
    } else if (rval < 9)
    {
        appeal = 60;
        SetContestantEffectStringID(eContestAppealResults.contestant, CONTEST_STRING_APPEAL_VERY_WELL);
    }
    else
    {
        appeal = 80;
        SetContestantEffectStringID(eContestAppealResults.contestant, CONTEST_STRING_APPEAL_EXCELLENTLY2);
    }
    eContestantStatus[eContestAppealResults.contestant].appeal = appeal;
}

static void ContestEffect_BetterIfSameType(void)
{
    s8 turnOrder = eContestAppealResults.turnOrder[eContestAppealResults.contestant];
    s8 i = turnOrder - 1, j;
    u16 move;

    if (turnOrder == 0)
        return;

    while (1)
    {
        for (j = 0; j < CONTESTANT_COUNT; j++)
        {
            if (eContestAppealResults.turnOrder[j] == i)
                break;
        }
        if (eContestantStatus[j].noMoreTurns || eContestantStatus[j].nervous || eContestantStatus[j].numTurnsSkipped)
        {
            if (--i < 0)
                return;
        }
        else
        {
            break;
        }
    }

    move = eContestantStatus[eContestAppealResults.contestant].currMove;
    if (gContestMoves[move].contestCategory == gContestMoves[eContestantStatus[j].currMove].contestCategory)
    {
        eContestantStatus[eContestAppealResults.contestant].appeal += gContestEffects[gContestMoves[move].effect].appeal * 2;
        SetContestantEffectStringID(eContestAppealResults.contestant, CONTEST_STRING_SAME_TYPE_GOOD);
    }
}

// Works well if different in type than the one before.
static void ContestEffect_BetterIfDiffType(void)
{
    if (eContestAppealResults.turnOrder[eContestAppealResults.contestant] != 0)
    {
        u16 move = eContestantStatus[eContestAppealResults.contestant].currMove;
        int i;

        for (i = 0; i < CONTESTANT_COUNT; i++)
        {
            if (eContestAppealResults.turnOrder[eContestAppealResults.contestant] - 1 == eContestAppealResults.turnOrder[i] &&
                gContestMoves[move].contestCategory != gContestMoves[eContestantStatus[i].currMove].contestCategory)
            {
                eContestantStatus[eContestAppealResults.contestant].appeal += gContestEffects[gContestMoves[move].effect].appeal * 2;
                SetContestantEffectStringID(eContestAppealResults.contestant, CONTEST_STRING_DIFF_TYPE_GOOD);
                break;
            }
        }
    }
}

// Affected by how well the appeal in front goes.
static void ContestEffect_AffectedByPrevAppeal(void)
{
    if (eContestAppealResults.turnOrder[eContestAppealResults.contestant] != 0)
    {
        int i;

        for (i = 0; i < CONTESTANT_COUNT; i++)
        {
            if (eContestAppealResults.turnOrder[eContestAppealResults.contestant] - 1 == eContestAppealResults.turnOrder[i])
            {
                if (eContestantStatus[eContestAppealResults.contestant].appeal > eContestantStatus[i].appeal)
                {
                    eContestantStatus[eContestAppealResults.contestant].appeal *= 2;
                    SetContestantEffectStringID(eContestAppealResults.contestant, CONTEST_STRING_STOOD_OUT_AS_MUCH);
                }
                else if (eContestantStatus[eContestAppealResults.contestant].appeal < eContestantStatus[i].appeal)
                {
                    eContestantStatus[eContestAppealResults.contestant].appeal = 0;
                    SetContestantEffectStringID(eContestAppealResults.contestant, CONTEST_STRING_NOT_AS_WELL);
                }
            }
        }
    }
}

// Ups the user's condition. Helps prevent nervousness.
static void ContestEffect_ImproveConditionPreventNervousness(void)
{
    if (eContestantStatus[eContestAppealResults.contestant].condition < 30)
    {
        eContestantStatus[eContestAppealResults.contestant].condition += 10;
        eContestantStatus[eContestAppealResults.contestant].conditionMod = CONDITION_GAIN;
        SetContestantEffectStringID(eContestAppealResults.contestant, CONTEST_STRING_CONDITION_ROSE);
    }
    else
    {
        SetContestantEffectStringID(eContestAppealResults.contestant, CONTEST_STRING_NO_CONDITION_IMPROVE);
    }
}

// The appeal works well if the user's condition is good.
static void ContestEffect_BetterWithGoodCondition(void)
{
    eContestantStatus[eContestAppealResults.contestant].appealTripleCondition = TRUE;
    if (eContestantStatus[eContestAppealResults.contestant].condition != 0)
        SetContestantEffectStringID(eContestAppealResults.contestant, CONTEST_STRING_HOT_STATUS);
    else
        SetContestantEffectStringID(eContestAppealResults.contestant, CONTEST_STRING_BAD_CONDITION_WEAK_APPEAL);
}

// The next appeal can be made earlier next turn.
static void ContestEffect_NextAppealEarlier(void)
{
    s8 i;
    s8 j;
    u8 turnOrder[CONTESTANT_COUNT];

    if (eContest.appealNumber != CONTEST_LAST_APPEAL)
    {
        for (i = 0; i < CONTESTANT_COUNT; i++)
            turnOrder[i] = eContestantStatus[i].nextTurnOrder;

        turnOrder[eContestAppealResults.contestant] = 0xFF;

        for (i = 0; i < CONTESTANT_COUNT; i++)
        {
            for (j = 0; j < CONTESTANT_COUNT; j++)
            {
                if (j != eContestAppealResults.contestant &&
                    i == turnOrder[j] &&
                    turnOrder[j] == eContestantStatus[j].nextTurnOrder)
                {
                    turnOrder[j]++;
                    break;
                }
            }
            if (j == CONTESTANT_COUNT)
                break;
        }

        turnOrder[eContestAppealResults.contestant] = 0;
        eContestantStatus[eContestAppealResults.contestant].turnOrderMod = 1;

        for (i = 0; i < CONTESTANT_COUNT; i++)
        {
            eContestantStatus[i].nextTurnOrder = turnOrder[i];
        }
        eContestantStatus[eContestAppealResults.contestant].turnOrderModAction = 1;
        SetContestantEffectStringID(eContestAppealResults.contestant, CONTEST_STRING_MOVE_UP_LINE);
    }
}

// The next appeal can be made later next turn.
static void ContestEffect_NextAppealLater(void)
{
    s8 i;
    s8 j;
    u8 turnOrder[CONTESTANT_COUNT];

    if (eContest.appealNumber != CONTEST_LAST_APPEAL)
    {
        for (i = 0; i < CONTESTANT_COUNT; i++)
            turnOrder[i] = eContestantStatus[i].nextTurnOrder;

        turnOrder[eContestAppealResults.contestant] = 0xFF;

        for (i = CONTESTANT_COUNT - 1; i > -1; i--)
        {
            for (j = 0; j < CONTESTANT_COUNT; j++)
            {
                if (j != eContestAppealResults.contestant &&
                    i == turnOrder[j] &&
                    turnOrder[j] == eContestantStatus[j].nextTurnOrder)
                {
                    turnOrder[j]--;
                    break;
                }
            }
            if (j == CONTESTANT_COUNT)
                break;
        }

        turnOrder[eContestAppealResults.contestant] = CONTESTANT_COUNT - 1;
        eContestantStatus[eContestAppealResults.contestant].turnOrderMod = 1;

        for (i = 0; i < CONTESTANT_COUNT; i++)
        {
            eContestantStatus[i].nextTurnOrder = turnOrder[i];
        }
        eContestantStatus[eContestAppealResults.contestant].turnOrderModAction = 2;
        SetContestantEffectStringID(eContestAppealResults.contestant, CONTEST_STRING_MOVE_BACK_LINE);
    }
}

// Makes the next turn's order more easily scrambled.
static void ContestEffect_MakeScramblingTurnOrderEasier(void)
{
    // dummied out?
}

// Scrambles the order of appeals on the next turn.
static void ContestEffect_ScrambleNextTurnOrder(void)
{
    s8 i;
    s8 j;
    u8 turnOrder[CONTESTANT_COUNT];
    u8 unselectedContestants[CONTESTANT_COUNT];

    if (eContest.appealNumber != CONTEST_LAST_APPEAL)
    {
        for (i = 0; i < CONTESTANT_COUNT; i++)
        {
            turnOrder[i] = eContestantStatus[i].nextTurnOrder;
            unselectedContestants[i] = i;
        }

        for (i = 0; i < CONTESTANT_COUNT; i++)
        {
            u8 rval = Random() % (CONTESTANT_COUNT - i);

            for (j = 0; j < CONTESTANT_COUNT; j++)
            {
                if (unselectedContestants[j] != 0xFF)
                {
                    if (rval == 0)
                    {
                        turnOrder[j] = i;
                        unselectedContestants[j] = 0xFF;
                        break;
                    }
                    else
                        rval--;
                }
            }
        }

        for (i = 0; i < CONTESTANT_COUNT; i++)
        {
            eContestantStatus[i].nextTurnOrder = turnOrder[i];
            eContestantStatus[i].turnOrderMod = 2;
        }
        eContestantStatus[eContestAppealResults.contestant].turnOrderModAction = 3;
        SetContestantEffectStringID(eContestAppealResults.contestant, CONTEST_STRING_SCRAMBLE_ORDER);
    }
}

// An appeal that excites the audience in any CONTEST.
static void ContestEffect_ExciteAudienceInAnyContest(void)
{
    if (gContestMoves[eContestantStatus[eContestAppealResults.contestant].currMove].contestCategory != gSpecialVar_ContestCategory)
    {
        eContestantStatus[eContestAppealResults.contestant].overrideCategoryExcitementMod = TRUE;
    }
}

// Badly startles all POKéMON that made good appeals.
static void ContestEffect_BadlyStartleMonsWithGoodAppeals(void)
{
    int i;
    u8 numJammed = 0;

    for (i = 0; i < CONTESTANT_COUNT; i++)
    {
        if (eContestAppealResults.turnOrder[eContestAppealResults.contestant] > eContestAppealResults.turnOrder[i])
        {
            if (eContestantStatus[i].appeal > 0)
            {
                eContestAppealResults.jam = eContestantStatus[i].appeal / 2;
                eContestAppealResults.jam = RoundUp(eContestAppealResults.jam);
            }
            else
                eContestAppealResults.jam = 10;
            eContestAppealResults.jamQueue[0] = i;
            eContestAppealResults.jamQueue[1] = 0xFF;
            if (WasAtLeastOneOpponentJammed())
                numJammed++;
        }
    }
    if (numJammed == 0)
        SetContestantEffectStringID2(eContestAppealResults.contestant, CONTEST_STRING_MESSED_UP2);
    SetContestantEffectStringID(eContestAppealResults.contestant, CONTEST_STRING_ATTEMPT_STARTLE);
}

// The appeal works best the more the crowd is excited.
static void ContestEffect_BetterWhenAudienceExcited(void)
{
    s16 appeal;

    if (eContest.applauseLevel == 0)
    {
        appeal = 10;
        SetContestantEffectStringID(eContestAppealResults.contestant, CONTEST_STRING_APPEAL_NOT_VERY_WELL);
    }
    else if (eContest.applauseLevel == 1)
    {
        appeal = 20;
        SetContestantEffectStringID(eContestAppealResults.contestant, CONTEST_STRING_APPEAL_SLIGHTLY_WELL2);
    }
    else if (eContest.applauseLevel == 2)
    {
        appeal = 30;
        SetContestantEffectStringID(eContestAppealResults.contestant, CONTEST_STRING_APPEAL_PRETTY_WELL2);
    }
    else if (eContest.applauseLevel == 3)
    {
        appeal = 50;
        SetContestantEffectStringID(eContestAppealResults.contestant, CONTEST_STRING_APPEAL_VERY_WELL);
    }
    else
    {
        appeal = 60;
        SetContestantEffectStringID(eContestAppealResults.contestant, CONTEST_STRING_APPEAL_EXCELLENTLY2);
    }
    eContestantStatus[eContestAppealResults.contestant].appeal = appeal;
}

// Temporarily stops the crowd from growing excited.
static void ContestEffect_DontExciteAudience(void)
{
    if (!eContestExcitement.frozen)
    {
        eContestExcitement.frozen = TRUE;
        eContestExcitement.freezer = eContestAppealResults.contestant;
        SetContestantEffectStringID(eContestAppealResults.contestant, CONTEST_STRING_ATTRACTED_ATTENTION);
    }
}

static void JamByMoveCategory(u8 category)
{
    int i;
    int numJammed = 0;

    for (i = 0; i < CONTESTANT_COUNT; i++)
    {
        if (eContestAppealResults.turnOrder[eContestAppealResults.contestant] > eContestAppealResults.turnOrder[i])
        {
            if (category == gContestMoves[eContestantStatus[i].currMove].contestCategory)
                eContestAppealResults.jam = 40;
            else
                eContestAppealResults.jam = 10;
            eContestAppealResults.jamQueue[0] = i;
            eContestAppealResults.jamQueue[1] = 0xFF;
            if (WasAtLeastOneOpponentJammed())
                numJammed++;
        }
    }

    if (numJammed == 0)
        SetContestantEffectStringID2(eContestAppealResults.contestant, CONTEST_STRING_MESSED_UP2);
}

static bool8 CanUnnerveContestant(u8 i)
{
    eContestAppealResults.unnervedPokes[i] = 1;
    if (eContestantStatus[i].immune)
    {
        SetContestantEffectStringID(i, CONTEST_STRING_AVOID_SEEING);
        return FALSE;
    }
    else if (eContestantStatus[i].jamSafetyCount != 0)
    {
        eContestantStatus[i].jamSafetyCount--;
        SetContestantEffectStringID(i, CONTEST_STRING_AVERT_GAZE);
        return FALSE;
    }
    else if (!eContestantStatus[i].noMoreTurns && eContestantStatus[i].numTurnsSkipped == 0)
    {
        return TRUE;
    }
    else
    {
        return FALSE;
    }
}

static bool8 WasAtLeastOneOpponentJammed(void)
{
    s16 jamBuffer[CONTESTANT_COUNT] = {0};
    int i;

    for (i = 0; eContestAppealResults.jamQueue[i] != 0xFF; i++)
    {
        u8 contestant = eContestAppealResults.jamQueue[i];
        if (CanUnnerveContestant(contestant))
        {
            eContestAppealResults.jam2 = eContestAppealResults.jam;
            if (eContestantStatus[contestant].moreEasilyStartled)
                eContestAppealResults.jam2 *= 2;
            if (eContestantStatus[contestant].resistant)
            {
                eContestAppealResults.jam2 = 10;
                SetContestantEffectStringID(contestant, CONTEST_STRING_LITTLE_DISTRACTED);
            }
            else
            {
                eContestAppealResults.jam2 -= eContestantStatus[contestant].jamReduction;
                if (eContestAppealResults.jam2 <= 0)
                {
                    eContestAppealResults.jam2 = 0;
                    SetContestantEffectStringID(contestant, CONTEST_STRING_NOT_FAZED);
                }
                else
                {
                    JamContestant(contestant, eContestAppealResults.jam2);
                    SetStartledString(contestant, eContestAppealResults.jam2);
                    jamBuffer[contestant] = eContestAppealResults.jam2;
                }
            }
        }
    }

    for (i = 0; i < CONTESTANT_COUNT; i++)
    {
        if (jamBuffer[i] != 0)
            return TRUE;
    }
    return FALSE;
}

static void JamContestant(u8 i, u8 jam)
{
    eContestantStatus[i].appeal -= jam;
    eContestantStatus[i].jam += jam;
}

static s16 RoundTowardsZero(s16 score)
{
    s16 absScore = abs(score) % 10;
    if (score < 0)
    {
        if (absScore != 0)
            score -= 10 - absScore;
    }
    else
        score -= absScore;
    return score;
}

static s16 RoundUp(s16 score)
{
    s16 absScore = abs(score) % 10;
    if (absScore != 0)
        score += 10 - absScore;
    return score;
}