On this page
  1. Related
  2. Mechanics
  3. References
  4. Sources

The atlas reads PaRappa the Rapper 2 through the parappadev team’s decompilation, which rebuilds a Japanese prototype dated July 12th, not a retail release. Names and comments quoted here are theirs. Nothing has been measured in the game yet.

A press isn’t graded by its distance from the teacher’s note. The game puts it in a 4-tick slot of the beat and reads a fixed pattern: the scoring runs fill 16 of every 24 ticks1, from 4 ticks before to 11 after each quarter of the beat, and a press in the gaps between them costs1. The imitation check pairs each press with each teacher’s note in the same run, of the same key outside one-button play1. The timing-window page has the grid.

After each line the player’s score is set against a target: the line’s coolup value from the stage data plus what the teacher’s own presses would score. Each line steps the rank one level, and an in-between level beside each rank means 2 lines in a row2 are needed to change the rank shown2. At Cool any of the six keys counts, the checks for following the teacher stop, and the target becomes coolup + 1503,3.

Mechanics

MechanicKindHow
Timing windowBeat grideach press falls in a 4-tick slot of a 96-tick cycle, a beat at the computed tempo scale; runs from 4 ticks before to 11 after each quarter beat score, and the 8-tick gaps between them cost
Rank meterStepped levelseach line steps the rank one level against the teacher's line plus the line's `coolup`, with an in-between level beside Cool, Good, Bad, and Awful; at Cool any key counts and following the teacher isn't checked
Every claim about this game, by concept (3)
Rank meterIn the July 12th NTSC-J prototype of PaRappa the Rapper 2, the rank is one of 14 levels (RANK_LEVEL, RLVL_COOL 0 to RLVL_END2 13), and RANK_LEVEL2DISP_LEVEL shows levels 0 and 1 as Cool, 2 to 4 as Good, 5 to 7 as Bad, 8 to 10 as Awful, and 11 to 13 as none (DLVL_MAX). The stage's score data sets each exam's type (SCRRJ_EXAM). At an exam other than hook, VS, cancel, and bonus, the player's line score (now_score) is set against a target (exam_coolP): the line's coolup from the stage data plus what the teacher's own presses score when run through the same checks (ExamScoreCheckSame, which scores a copy and returns its unhalved sum, so in one-button play or the easy table mode a halved line score meets a target whose teacher part isn't halved), a part that is a flat 150 while the rank is at level 0 or 1, and 11111 when there is no line. Under a Cool exam a score below the target steps the rank down (levelDownRank) and any other steps it up (levelUpRank). Under a Good exam a score at or above the target steps up, a score of 0 or less steps down, and a score between them moves level 2 (RLVL_GOOD_COOL) down to Good, leaves Good alone, and steps any other level up. Under a Bad or Awful exam a score above 0 steps up and any other steps down. A step moves to the next level along the tables, which put an in-between level beside each rank: up from Good (3) is level 2, still shown Good, then Cool (0); down from Good is level 4, then Bad (6); down from Awful (9) is level 10 and then RLVL_END1 (12). So a shown rank changes after two steps the same way, and a step back from an in-between level returns to the plain rank (computed from the tables). In one-button play (PLAY_TYPE_ONE) or the easy table mode (PLAY_TABLE_EASY), a Good exam that would leave the rank at level 0, 1, or 2 sets it to Good (3), so the rank can't reach Cool there.Code
In the July 12th NTSC-J prototype of PaRappa the Rapper 2, while the rank is at level 0 or 1 (RLVL_COOL, RLVL_COOL_GOOD, both shown as Cool), a line is scored three ways differently. Every key the game maps (KcAll: triangle, circle, cross, square, L1, and R1 by GetIndex2KeyCode) counts as one the teacher's line uses (otehon_all), where otherwise only the keys in the teacher's line count, so on-grid presses of any of them score and exh_nombar_sub, which takes points for keys outside the teacher's, finds none (computed); in one-button play (PLAY_TYPE_ONE) the set is triangle alone either way. Five checks score 0: the all-keys test (EXH_ALLKEY_OUT), the imitation test (EXH_MANE), and three that compare the presses with the teacher's notes (EXH_MBAR_KEY_OUT and EXH_MBAR_TIME_OUT, the first press's key and slot run against the first note's, and EXH_MBAR_NUM_OUT, the count of presses against the count of notes). And the teacher's part of the target is a flat 150 (ExamScoreCheckSame), not the teacher's notes scored. The atlas reads this as Cool's freestyle: following the teacher is no longer checked, and off-grid presses and mashing (exh_renda_out) still cost. Under a Good exam the rank gets to Cool after two lines in a row that each score at least the target, the line's coolup plus the teacher's notes scored (computed: Good to level 2, then 0), except in one-button play or the easy table mode, which hold it at Good; under a Cool exam a line below coolup + 150 steps it down, and two in a row put it back at Good (computed).Code
Timing windowIn the July 12th NTSC-J prototype of PaRappa the Rapper 2, a press is judged by which slot of a fixed grid it lands in, not by its distance from the teacher's note. The line clock converts a vsync count to ticks as count × 96 × tempo / 3600, so with 60 vsyncs a second and tempo in beats per minute a beat is 96 ticks (computed). Each press is stored with its time less the line's start time (ofs_frame); on_th_make adds that start modulo 96, plus 96, and divides by 4, which puts the press in the 4-tick slot of its own time modulo 96 (computed). thnum_get reads the slot in a 24-bit pattern that repeats every beat and numbers its runs of equal bits, so a press in a run of 1s gets an even th_num and a press in a run of 0s an odd one. For the main grid (CK_TH_NORMAL, 0x00e79e79) the 1s cover ticks 92 to 11, 20 to 35, 44 to 59, and 68 to 83 of each beat, that is from 4 ticks before to 11 ticks after each multiple of 24 (a quarter of the beat), and the 0s cover the 8 ticks from 12 to 19 after it (computed). In the first of a line's three checks, exh_normal_add counts each press in a 1-run whose key the teacher's line uses (otehon_all; while the rank is Cool, any key, and in one-button play, triangle) and exh_normal_sub takes one off for each such press in a 0-run, each weighted 48/16, that is ±3 (computed); a press anywhere in a run scores the same. The same check's imitation test (exh_mane, weight 8/16) runs over every pair of a teacher's note and a press and counts each pair with the same th_num and, outside one-button play, the same key, so one press can count once for each note in its run; it scores 2 × that count − presses; it runs again on a late grid (CK_TH_LATE, 0x00f3cf3c, with the teacher's notes moved 2 slots later) and keeps the better result. The third check uses a swing grid (CK_TH_HANE, 0x00c1cc1c). A line's score (now_score) is the sum of the three checks' totals, and in the game play step (PSTEP_GAME) it is then halved as (now_score + 1) / 2 in one-button play (PLAY_TYPE_ONE) and halved that way again in the easy table mode (PLAY_TABLE_EASY), so twice when both apply; a check's total is 0 when its all-keys test fails and −100 when the presses reach the line's length in 24-tick steps, rounded up, plus 3 (exh_renda_out). In the hook play step (PSTEP_HOOK) a line is scored by an imitation test alone (manemane_check), on the main grid.Code

References

  1. ^ abcIn the July 12th NTSC-J prototype of PaRappa the Rapper 2, a press is judged by which slot of a fixed grid it lands in, not by its distance from the teacher's note. The line clock converts a vsync count to ticks as count × 96 × tempo / 3600, so with 60 vsyncs a second and tempo in beats per minute a beat is 96 ticks (computed). Each press is stored with its time less the line's start time (ofs_frame); on_th_make adds that start modulo 96, plus 96, and divides by 4, which puts the press in the 4-tick slot of its own time modulo 96 (computed). thnum_get reads the slot in a 24-bit pattern that repeats every beat and numbers its runs of equal bits, so a press in a run of 1s gets an even th_num and a press in a run of 0s an odd one. For the main grid (CK_TH_NORMAL, 0x00e79e79) the 1s cover ticks 92 to 11, 20 to 35, 44 to 59, and 68 to 83 of each beat, that is from 4 ticks before to 11 ticks after each multiple of 24 (a quarter of the beat), and the 0s cover the 8 ticks from 12 to 19 after it (computed). In the first of a line's three checks, exh_normal_add counts each press in a 1-run whose key the teacher's line uses (otehon_all; while the rank is Cool, any key, and in one-button play, triangle) and exh_normal_sub takes one off for each such press in a 0-run, each weighted 48/16, that is ±3 (computed); a press anywhere in a run scores the same. The same check's imitation test (exh_mane, weight 8/16) runs over every pair of a teacher's note and a press and counts each pair with the same th_num and, outside one-button play, the same key, so one press can count once for each note in its run; it scores 2 × that count − presses; it runs again on a late grid (CK_TH_LATE, 0x00f3cf3c, with the teacher's notes moved 2 slots later) and keeps the better result. The third check uses a swing grid (CK_TH_HANE, 0x00c1cc1c). A line's score (now_score) is the sum of the three checks' totals, and in the game play step (PSTEP_GAME) it is then halved as (now_score + 1) / 2 in one-button play (PLAY_TYPE_ONE) and halved that way again in the easy table mode (PLAY_TABLE_EASY), so twice when both apply; a check's total is 0 when its all-keys test fails and −100 when the presses reach the line's length in 24-tick steps, rounded up, plus 3 (exh_renda_out). In the hook play step (PSTEP_HOOK) a line is scored by an imitation test alone (manemane_check), on the main grid.Codeparappadev/parappa2revised
    How we know
    3990        if (scr_main_pp->scr_ctrl_pp[i].gtime_type == GTIME_VSYNC) {
    3991            scr_main_pp->scr_ctrl_pp[i].lineTime =  ((TimeCallbackTimeGetChan(i) * 96.0f * GetLineTempo(i) + 1800.0f)  / 3600.0f);
    
    src/main/scrctrl.c lines 3990–3991 at 45694de · upstream ↗
    2141        SCR_TAP_MEMORY *mkey_pp = &sindv_pp->scr_tap_memory[sindv_pp->scr_tap_memory_cnt];
    ⋮
    2145        mkey_pp->ofs_frame = onKeyTime - tapset_pp->taptimeStart - sindv_pp->current_time;
    
    src/main/scrctrl.c lines 2141–2145 at 45694de · upstream ↗
    2765        exam_check[i].tapset_pp = IndvGetTapSetAdrs(sindv_pp);
    ⋮
    2770            exam_check[i].ofs_tick = exam_check[i].tapset_pp->taptimeStart + sindv_pp->current_time;
    ⋮
    2776            exam_check[i].otehon_all = otehon_all_make(&exam_check[i]);
    ⋮
    2785        if (global_data.play_typeL == PLAY_TYPE_ONE) {
    2786            exam_check[i].otehon_all = KcTR;
    
    src/main/scrctrl.c lines 2765–2787 at 45694de · upstream ↗
    136static u_int thnum_tbl[] = { 0x00e79e79, 0x00f3cf3c, 0x00c1cc1c, 0x00000000 };
    
    src/main/scrctrl.c line 136 at 45694de · upstream ↗
    2222static int thnum_get(int p96_num, CK_TH_ENUM ckth) {
    ⋮
    2230    thnum_data = thnum_tbl[ckth];
    ⋮
    2232    for (i = 0; i <= p96_num; i++) {
    2233        ck_dat = (thnum_data >> (23 - (i % 24))) & 1;
    ⋮
    2235        if (ck_bit < 0) {
    2236            if (ck_dat == 0) {
    2237                ret_cnt = 1;
    ⋮
    2239        } else if (ck_dat != ck_bit) {
    2240            ret_cnt++;
    
    src/main/scrctrl.c lines 2222–2247 at 45694de · upstream ↗
    2253static void on_th_make(EXAM_CHECK *ec_pp, CK_TH_ENUM ckth) {
    ⋮
    2267    ofsT = ec_pp->ofs_tick % 96;
    2268    ofsT += 96;
    ⋮
    2273        frame   = ec_pp->stm_pp[i].ofs_frame;
    2274        p96_num = (frame + ofsT) / 4;
    ⋮
    2277        ec_pp->ted[i].th_num = thnum_get(p96_num, ckth);
    ⋮
    2304            p96_num = (frame + ofsT) / 4;
    ⋮
    2306            if (ckth == CK_TH_LATE) {
    2307                p96_num += 2;
    ⋮
    2311            ec_pp->oth[i].th_num = thnum_get(p96_num, ckth);
    
    src/main/scrctrl.c lines 2253–2312 at 45694de · upstream ↗
    2317static int exh_normal_add(EXAM_CHECK *ec_pp) {
    ⋮
    2322        if (!(ec_pp->ted[i].th_num & 1)) {
    2323            if (GetIndex2KeyCode(ec_pp->ted[i].key) & ec_pp->otehon_all) {
    2324                ret++;
    ⋮
    2332static int exh_normal_sub(EXAM_CHECK *ec_pp) {
    ⋮
    2337        if (GetIndex2KeyCode(ec_pp->ted[i].key) & ec_pp->otehon_all) {
    2338            ret -= ec_pp->ted[i].th_num & 1;
    
    src/main/scrctrl.c lines 2317–2343 at 45694de · upstream ↗
    99static EXH_STR exh_str_normal[] = {
    100    { .score_prg = exh_normal_add,    .save_p = EXH_NORMAL_ADD,    .bairitu = 48 },
    101    { .score_prg = exh_normal_sub,    .save_p = EXH_NORMAL_SUB,    .bairitu = 48 },
    ⋮
    108    { .score_prg = exh_mane,          .save_p = EXH_MANE,          .bairitu = 8  },
    109    { .score_prg = exh_all_add,       .save_p = EXH_TOTAL,         .bairitu = 16 },
    
    src/main/scrctrl.c lines 99–110 at 45694de · upstream ↗
    2583static int exh_renda_out(EXAM_CHECK *ec_pp) {
    ⋮
    2586    renda_ck = ec_pp->tapset_pp->taptimeEnd - ec_pp->tapset_pp->taptimeStart;
    2587    renda_ck = ((renda_ck + 23) / 24);
    2588    renda_ck += 3;
    ⋮
    2590    if (ec_pp->ted_num >= renda_ck) {
    2591        return -1;
    ⋮
    2597static int manemane_check_sub(EXAM_CHECK *ec_pp) {
    ⋮
    2605            if (global_data.play_typeL == PLAY_TYPE_ONE) {
    2606                if (ec_pp->oth[i].th_num == ec_pp->ted[j].th_num) {
    2607                    mane_cnt++;
    ⋮
    2610                if (ec_pp->oth[i].th_num == ec_pp->ted[j].th_num) {
    2611                    if (ec_pp->oth[i].key == ec_pp->ted[j].key) {
    ⋮
    
    src/main/scrctrl.c lines 2583–2684 at 45694de · upstream ↗
    2790    if (global_data.play_step == PSTEP_HOOK) {
    ⋮
    2796        scrprgstr_pp  = scrprgstr_hook;
    ⋮
    2813            exam_check_pp->each_point[scrprgstr_pp->exh_str_pp[j].save_p] = (ret * scrprgstr_pp->exh_str_pp[j].bairitu) / 16;
    ⋮
    2816        CK_TH_ENUM  ck_th_enum_tbl[3] = { 
    2817            CK_TH_NORMAL, 
    2818            CK_TH_NORMAL, 
    2819            CK_TH_HANE
    ⋮
    2829            on_th_make(exam_check_pp, ck_th_enum_tbl[i]);
    ⋮
    2844                exam_check_pp->each_point[scrprgstr_pp->exh_str_pp[j].save_p] = (ret * scrprgstr_pp->exh_str_pp[j].bairitu) / 16;
    ⋮
    2853        sum += exam_check[i].each_point[EXH_TOTAL];
    ⋮
    2856    sindv_pp->global_ply->now_score = sum;
    
    src/main/scrctrl.c lines 2790–2856 at 45694de · upstream ↗
    3077        if (scex_pp->exam_do == EXAM_DO_NON) {
    3078            ExamScoreCheck(sindv_pp);
    ⋮
    3080            if (global_data.play_step == PSTEP_GAME) {
    3081                if (global_data.play_typeL == PLAY_TYPE_ONE) {
    3082                    sindv_pp->global_ply->now_score = (sindv_pp->global_ply->now_score + 1) / 2;
    ⋮
    3084                if (global_data.play_table_modeL == PLAY_TABLE_EASY) {
    3085                    sindv_pp->global_ply->now_score = (sindv_pp->global_ply->now_score + 1) / 2;
    
    src/main/scrctrl.c lines 3077–3087 at 45694de · upstream ↗
    131static EXH_STR exh_str_hook[] = {
    132    { .score_prg = manemane_check,    .save_p = EXH_MANE,          .bairitu = 16 },
    133    { .score_prg = exh_all_add,       .save_p = EXH_TOTAL,         .bairitu = 16 },
    
    src/main/scrctrl.c lines 131–134 at 45694de · upstream ↗

    Checked against the evidence by its author, an AI model, 2026-10-22.

    Revised after a check by a second AI model, 2026-10-22.

    In the claim ledger

  2. ^ abIn the July 12th NTSC-J prototype of PaRappa the Rapper 2, the rank is one of 14 levels (RANK_LEVEL, RLVL_COOL 0 to RLVL_END2 13), and RANK_LEVEL2DISP_LEVEL shows levels 0 and 1 as Cool, 2 to 4 as Good, 5 to 7 as Bad, 8 to 10 as Awful, and 11 to 13 as none (DLVL_MAX). The stage's score data sets each exam's type (SCRRJ_EXAM). At an exam other than hook, VS, cancel, and bonus, the player's line score (now_score) is set against a target (exam_coolP): the line's coolup from the stage data plus what the teacher's own presses score when run through the same checks (ExamScoreCheckSame, which scores a copy and returns its unhalved sum, so in one-button play or the easy table mode a halved line score meets a target whose teacher part isn't halved), a part that is a flat 150 while the rank is at level 0 or 1, and 11111 when there is no line. Under a Cool exam a score below the target steps the rank down (levelDownRank) and any other steps it up (levelUpRank). Under a Good exam a score at or above the target steps up, a score of 0 or less steps down, and a score between them moves level 2 (RLVL_GOOD_COOL) down to Good, leaves Good alone, and steps any other level up. Under a Bad or Awful exam a score above 0 steps up and any other steps down. A step moves to the next level along the tables, which put an in-between level beside each rank: up from Good (3) is level 2, still shown Good, then Cool (0); down from Good is level 4, then Bad (6); down from Awful (9) is level 10 and then RLVL_END1 (12). So a shown rank changes after two steps the same way, and a step back from an in-between level returns to the plain rank (computed from the tables). In one-button play (PLAY_TYPE_ONE) or the easy table mode (PLAY_TABLE_EASY), a Good exam that would leave the rank at level 0, 1, or 2 sets it to Good (3), so the rank can't reach Cool there.Codeparappadev/parappa2revised
    How we know
    246    RLVL_COOL = 0,
    247    RLVL_COOL_GOOD = 1,
    248    RLVL_GOOD_COOL = 2,
    249    RLVL_GOOD = 3,
    250    RLVL_GOOD_BAD = 4,
    251    RLVL_BAD_GOOD = 5,
    252    RLVL_BAD = 6,
    253    RLVL_BAD_AWFUL = 7,
    254    RLVL_AWFUL_BAD = 8,
    255    RLVL_AWFUL = 9,
    256    RLVL_AWFUL_END = 10,
    257    RLVL_END0 = 11,
    ⋮
    
    include/main/etc.h lines 246–259 at 45694de · upstream ↗
    453DISP_LEVEL RANK_LEVEL2DISP_LEVEL(RANK_LEVEL lvl) {
    454    DISP_LEVEL lvl_tbl[17] = {
    455        DLVL_COOL,  DLVL_COOL,
    456        DLVL_GOOD,  DLVL_GOOD,  DLVL_GOOD,
    457        DLVL_BAD,   DLVL_BAD,   DLVL_BAD,
    458        DLVL_AWFUL, DLVL_AWFUL, DLVL_AWFUL,
    459        DLVL_MAX,   DLVL_MAX,   DLVL_MAX,
    460        DLVL_MAX,   DLVL_MAX,   DLVL_MAX,
    
    src/main/scrctrl.c lines 453–464 at 45694de · upstream ↗
    1352        case SCRRJ_EXAM:
    1353            sindv_pp->scr_exam_str.exam_enum = Rsub;
    
    src/main/scrctrl.c lines 1352–1353 at 45694de · upstream ↗
    3067        if (scex_pp->exam_enum == EXAM_CANCEL) {
    ⋮
    3070        if (scex_pp->exam_enum == EXAM_BONUS) {
    ⋮
    3077        if (scex_pp->exam_do == EXAM_DO_NON) {
    3078            ExamScoreCheck(sindv_pp);
    ⋮
    3080            if (global_data.play_step == PSTEP_GAME) {
    3081                if (global_data.play_typeL == PLAY_TYPE_ONE) {
    3082                    sindv_pp->global_ply->now_score = (sindv_pp->global_ply->now_score + 1) / 2;
    ⋮
    3084                if (global_data.play_table_modeL == PLAY_TABLE_EASY) {
    3085                    sindv_pp->global_ply->now_score = (sindv_pp->global_ply->now_score + 1) / 2;
    
    src/main/scrctrl.c lines 3067–3087 at 45694de · upstream ↗
    2873    global_ply_tmp = *sindv_pp->global_ply;
    ⋮
    2875    sindv_tmp      = *sindv_pp;
    2876    sindv_tmp.global_ply = &global_ply_tmp;
    ⋮
    2907    ExamScoreCheck(&sindv_tmp);
    2908    return global_ply_tmp.now_score;
    
    src/main/scrctrl.c lines 2873–2908 at 45694de · upstream ↗
    2859static int ExamScoreCheckSame(SCORE_INDV_STR *sindv_pp) {
    ⋮
    2868    if (sindv_pp->global_ply->rank_level == RLVL_COOL ||
    2869        sindv_pp->global_ply->rank_level == RLVL_COOL_GOOD) {
    2870        return 150;
    
    src/main/scrctrl.c lines 2859–2871 at 45694de · upstream ↗
    3204                    scex_pp->exam_point = sindv_pp->global_ply->now_score;
    ⋮
    3206                    if (tapset_pp == NULL) {
    3207                        scex_pp->exam_coolP = 11111;
    3208                    } else {
    3209                        exp = ExamScoreCheckSame(sindv_pp);
    3210                        if (global_data.play_step != PSTEP_VS) {
    3211                            scex_pp->exam_coolP = tapset_pp->coolup + exp;
    3212                        } else {
    ⋮
    3225                    case EXAM_COOL:
    3226                        if (scex_pp->exam_point < scex_pp->exam_coolP) {
    3227                            rank_saki = levelDownRank(rank_moto);
    3228                        } else {
    ⋮
    
    src/main/scrctrl.c lines 3201–3259 at 45694de · upstream ↗
    2922static int levelUpRank(RANK_LEVEL lvl) {
    2923    RANK_LEVEL up_tbl[17] = {
    2924        /* COOL      -> COOL      */ RLVL_COOL,
    2925        /* COOL/GOOD -> COOL      */ RLVL_COOL,
    2926        /* GOOD/COOL -> COOL      */ RLVL_COOL,
    2927        /* GOOD      -> GOOD/COOL */ RLVL_GOOD_COOL,
    2928        /* GOOD/BAD  -> GOOD      */ RLVL_GOOD,
    2929        /* BAD/GOOD  -> GOOD      */ RLVL_GOOD,
    2930        /* BAD       -> BAD/GOOD  */ RLVL_BAD_GOOD,
    2931        /* BAD/AWFUL -> BAD       */ RLVL_BAD,
    2932        /* AWFUL/BAD -> BAD       */ RLVL_BAD,
    2933        /* AWFUL     -> AWFUL/BAD */ RLVL_AWFUL_BAD,
    ⋮
    
    src/main/scrctrl.c lines 2922–2968 at 45694de · upstream ↗
    3487                    if (scex_pp->exam_enum != EXAM_HOOK && scex_pp->exam_enum != EXAM_VS) {
    3488                        if (rank_saki != rank_moto) {
    3489                            int line_change;
    ⋮
    3491                            sindv_pp->global_ply->rank_level = rank_saki;
    
    src/main/scrctrl.c lines 3487–3491 at 45694de · upstream ↗

    Checked against the evidence by its author, an AI model, 2026-10-22.

    Revised after a check by a second AI model, 2026-10-22.

    In the claim ledger

  3. ^ abIn the July 12th NTSC-J prototype of PaRappa the Rapper 2, while the rank is at level 0 or 1 (RLVL_COOL, RLVL_COOL_GOOD, both shown as Cool), a line is scored three ways differently. Every key the game maps (KcAll: triangle, circle, cross, square, L1, and R1 by GetIndex2KeyCode) counts as one the teacher's line uses (otehon_all), where otherwise only the keys in the teacher's line count, so on-grid presses of any of them score and exh_nombar_sub, which takes points for keys outside the teacher's, finds none (computed); in one-button play (PLAY_TYPE_ONE) the set is triangle alone either way. Five checks score 0: the all-keys test (EXH_ALLKEY_OUT), the imitation test (EXH_MANE), and three that compare the presses with the teacher's notes (EXH_MBAR_KEY_OUT and EXH_MBAR_TIME_OUT, the first press's key and slot run against the first note's, and EXH_MBAR_NUM_OUT, the count of presses against the count of notes). And the teacher's part of the target is a flat 150 (ExamScoreCheckSame), not the teacher's notes scored. The atlas reads this as Cool's freestyle: following the teacher is no longer checked, and off-grid presses and mashing (exh_renda_out) still cost. Under a Good exam the rank gets to Cool after two lines in a row that each score at least the target, the line's coolup plus the teacher's notes scored (computed: Good to level 2, then 0), except in one-button play or the easy table mode, which hold it at Good; under a Cool exam a line below coolup + 150 steps it down, and two in a row put it back at Good (computed).Codeparappadev/parappa2
    How we know
    2773        if (sindv_pp->global_ply->rank_level == RLVL_COOL || sindv_pp->global_ply->rank_level == RLVL_COOL_GOOD) {
    2774            exam_check[i].otehon_all = KcAll;
    2775        } else {
    2776            exam_check[i].otehon_all = otehon_all_make(&exam_check[i]);
    ⋮
    2785        if (global_data.play_typeL == PLAY_TYPE_ONE) {
    2786            exam_check[i].otehon_all = KcTR;
    
    src/main/scrctrl.c lines 2773–2787 at 45694de · upstream ↗
    81typedef enum {
    82    KcTR = 16,
    83    KcCI = 32,
    84    KcXX = 64,
    85    KcSQ = 128,
    86    KcL1 = 4,
    87    KcR1 = 8,
    88    KcAll = 252,
    
    include/main/scrctrl.h lines 81–88 at 45694de · upstream ↗
    500int GetIndex2KeyCode(int index) {
    501    static int KeyCode[7] = {
    502        0, KcTR, KcCI, KcXX, KcSQ, KcL1, KcR1,
    
    src/main/etc.c lines 500–503 at 45694de · upstream ↗
    2345static int exh_nombar_sub(EXAM_CHECK *ec_pp) {
    ⋮
    2353        int keycode = GetIndex2KeyCode(ec_pp->ted[i].key);
    2354        if ((keycode & ec_pp->otehon_all) == 0) {
    2355            ret -= 1;
    
    src/main/scrctrl.c lines 2345–2357 at 45694de · upstream ↗
    2383static int exh_mbar_key_out(EXAM_CHECK *ec_pp) {
    ⋮
    2394        } else if (ec_pp->oth[0].key == ec_pp->ted[0].key) {
    ⋮
    2402static int exh_mbar_time_out(EXAM_CHECK *ec_pp) {
    ⋮
    2409        } else if (ec_pp->oth[0].th_num == ec_pp->ted[0].th_num) {
    ⋮
    2417static int exh_mbar_num_out(EXAM_CHECK *ec_pp) {
    2418    int ret = ec_pp->ted_num - ec_pp->oth_num;
    
    src/main/scrctrl.c lines 2383–2420 at 45694de · upstream ↗
    2832                ret = scrprgstr_pp->exh_str_pp[j].score_prg(exam_check_pp);
    ⋮
    2834                if (sindv_pp->global_ply->rank_level == RLVL_COOL || sindv_pp->global_ply->rank_level == RLVL_COOL_GOOD) {
    2835                    if (scrprgstr_pp->exh_str_pp[j].save_p == EXH_ALLKEY_OUT ||
    2836                        scrprgstr_pp->exh_str_pp[j].save_p == EXH_MBAR_NUM_OUT ||
    2837                        scrprgstr_pp->exh_str_pp[j].save_p == EXH_MBAR_KEY_OUT ||
    2838                        scrprgstr_pp->exh_str_pp[j].save_p == EXH_MANE ||
    2839                        scrprgstr_pp->exh_str_pp[j].save_p == EXH_MBAR_TIME_OUT) {
    2840                        ret = 0;
    
    src/main/scrctrl.c lines 2831–2844 at 45694de · upstream ↗
    2868    if (sindv_pp->global_ply->rank_level == RLVL_COOL ||
    2869        sindv_pp->global_ply->rank_level == RLVL_COOL_GOOD) {
    2870        return 150;
    
    src/main/scrctrl.c lines 2868–2871 at 45694de · upstream ↗
    3209                        exp = ExamScoreCheckSame(sindv_pp);
    3210                        if (global_data.play_step != PSTEP_VS) {
    3211                            scex_pp->exam_coolP = tapset_pp->coolup + exp;
    ⋮
    3225                    case EXAM_COOL:
    3226                        if (scex_pp->exam_point < scex_pp->exam_coolP) {
    3227                            rank_saki = levelDownRank(rank_moto);
    ⋮
    3229                            rank_saki = levelUpRank(rank_moto);
    ⋮
    3232                    case EXAM_GOOD:
    3233                        if (scex_pp->exam_point >= scex_pp->exam_coolP) {
    3234                            rank_saki = levelUpRank(rank_moto);
    ⋮
    3236                            rank_saki = levelDownRank(rank_moto);
    ⋮
    3239                                rank_saki = levelDownRank(rank_moto);
    ⋮
    
    src/main/scrctrl.c lines 3209–3247 at 45694de · upstream ↗
    2923    RANK_LEVEL up_tbl[17] = {
    2924        /* COOL      -> COOL      */ RLVL_COOL,
    2925        /* COOL/GOOD -> COOL      */ RLVL_COOL,
    2926        /* GOOD/COOL -> COOL      */ RLVL_COOL,
    2927        /* GOOD      -> GOOD/COOL */ RLVL_GOOD_COOL,
    ⋮
    2947    RANK_LEVEL down_tbl[17] = {
    2948        /* COOL      -> COOL/GOOD */ RLVL_COOL_GOOD,
    2949        /* COOL/GOOD -> GOOD      */ RLVL_GOOD,
    
    src/main/scrctrl.c lines 2922–2951 at 45694de · upstream ↗

    Checked against the evidence by its author, an AI model, 2026-10-22.

    Checked by a second AI model, 2026-10-22.

    In the claim ledger

Sources

Code