Skip to content

Courses: LR2 course IR flag (button 253, text 183) #404

Open

Description

@nulltask

LR2 marks a course for IR submission with button 253 (L11139-11152). Text 183 shows the flag (L8406), and a flagged course becomes read-only (L18080). be-music has neither the button nor the text.

The likely mapping is to beatoraja's release for made courses, or a fixed string on text 183.

Found in the LR2 / beatoraja course compatibility audit for #373 / #377.

🤖 Generated with Claude Code

Activity

  1. nulltask commented on Oct 19, 2026

    @nulltask
    OwnerAuthor

    Findings

    Sources: OpenLR2 LR2f.cpp @ 583a385, the LR2 beta3 binaries (LR2body.exe, and LR2.exe, the config program that imports course files) and LR2files/Config/optionstr.csv.

    Where the flag lives

    • The flag is not in the .lr2crs file. It is the ir column of LR2's own course tables in song.db (CREATE TABLE expert|nonstop|grade(id, title, line, hash, ir), L19281-L19283). It is read as column 4 into courseIR, and courseIR == 1 sets courseReadOnly (L18078-L18080).
    • Imported courses are always IR ON. LR2.exe reads only title, line and hash from a <courselist> (strings courselist, hash, title, line, with no ir or type tag next to them), and inserts every course with ir fixed to 1: INSERT INTO expert (title,line,hash,ir) VALUES ('%q',%d,'%q',1), and the same for nonstop / grade (LR2.exe strings at VA 0x4a9f80-0x4aa004). The release notes say course files come from the IR ranking page, to join that course's ranking (history.txt, beta3 090916).
    • Courses made in game start IR OFF. WriteCourse inserts a new course (NEW COURSE, RANDOM MIX) with ir = 0 (L17588-L17603).

    Button 253 and text 183

    • Button 253 (L11141-L11153): when the selected course's flag is 1 the button is drawn at cell 1 and does nothing. When it is 0, a click steps it in 0-1 (so 0 → 1), plays option_change and sets isCourseCreated, which saves the course with UPDATE ... SET title, hash, ir=<courseIR> (L17604-L17616). The flag is one-way in game: once ON it cannot be turned OFF.
    • Text 183 is optionstr.csv row 24, #COURSE_IR,OFF,ON (L8406). It is set for any bar, so a song bar or a non-course bar reads OFF.

    What "read-only" covers

    • WriteCourse returns at once for a read-only course (L17580-L17584), and buttons 240-248 (NONSTOP connections) are locked for an IR course (L11126-L11129). So the course's stages, connections and hash can no longer change, and the hash (which keys the score and the IR ranking) stays stable.
    • Not covered: renaming (text 170 → ChangeCourseTitle, L8686-L8691, L17625) and deleting (button 233 → DeleteCourse, L11107-L11115) still work on an IR course.

    What the flag does online

    • On the select screen, IR ranking auto-update starts for a course only when its flag is set (L8452-L8460).
    • At the course result: with the flag OFF and online, the IR rank is cleared and text 20 reads このコースはIRに対応していません。 ("this course does not support IR"). With the flag ON, the score is sent, unless a long-sound option was used (このコースはIRに登録できません) (L9686-L9710, and the early return at L9517-L9519).

    beatoraja

    • CourseData.release ("公開するかどうか", whether to publish), default true (CourseData.java L31-L34). It only gates the IR send of a course result: send = isUpdateCourseScore() && getCourseData().isRelease() (CourseResult.java L95-L96). It does not make a course read-only.
    • Courses from an IR table get release = true (BarManager.java L180); a new course in the launcher's course editor starts with release = false (CourseEditorView.java L221-L223), with a checkbox to change it (L144, L181). Drawn random courses are release = false.
    • So the defaults line up: imported / IR-table courses ranked, self-made courses not ranked until the player says so. The difference is that LR2 also freezes the course once it is flagged.

    be-music today

    • CourseDefinition.release exists (packages/player/src/course/definition.ts) and gates ranking only (packages/player/src/playlog/course-eligibility.ts, reason unreleased).
    • .lr2crs import sets release: true (packages/player/src/course/lr2crs.ts), which matches LR2.exe's ir = 1.
    • Courses made with the course maker also get release: true (packages/player/src/course/maker.ts, lr2CourseDefinition). LR2 inserts them with ir = 0 and beatoraja's editor with release = false, so both would keep them off the ranking by default.
    • Editing is already limited to the player's own courses (packages/player-web/src/session/select/select-session.ts, runCourseMaker: course.editable && maker.owns(...)), which is close to LR2's read-only rule for imported courses.
    • No button 253 or text 183 in packages/lr2-skin/src/ids/.

    Proposed behaviour

    • Map LR2's IR flag to release: text 183 reads ON when the selected course bar's course is released, else OFF (and OFF on non-course bars, as LR2).
    • Button 253 on a course the player owns: turns release from false to true and then locks, like LR2; on a released course it shows cell 1 and does nothing. While locked, keep the stages and connections fixed (buttons 240-248 disabled), but still allow renaming and deleting, as LR2 does.
    • Make course-maker courses start with release: false, as both LR2 and beatoraja do. They become rankable once the player flips button 253 (or an equivalent toggle in the demo's course maker panel).

    Open questions

    • Should be-music keep LR2's one-way flag, or allow turning it off (beatoraja's checkbox allows both ways)? One-way protects the course fingerprint that ranks it; two-way is friendlier.
    • Changing course-maker courses to release: false changes which existing runs the Leaderboard accepts. Is that wanted?
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions