Jamiras / RATools

Script interpreter for writing achievements for retroachievements.org
MIT License
49 stars 11 forks source link

[Bug] Writing comment too long on the line with code crashes the program #406

Open Visssarion opened 1 year ago

Visssarion commented 1 year ago

Ways to replicate: On line 219 (script attached below) write a comment //aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, at one point it will crash because its too long

image

My RAScript this issue happens with:

// Arkanoid
// #ID = 11980

// $0001: [8 bit] Demo bit
//        0x1 - demo
//        0x0 - not
function IsDemo() => byte(0x000001) == 0x1

// $000A: [8 bit] Screen ID.
//        0x28 - Leaderboard
//        0x2a - Game Over
//        0x2c - Main Menu / In play / Other
//        0x26 & 0x1e - Player loses all lives
ScreenId = byte(0x00000A)
function IsGameFinished() => ScreenID == 0x28 && prior(ScreenID) != 0x28

// ^ checking for leaderboards because that's the first screen after losing all lives

// $0026: [8 bit] Were continues used? 
//        0x20 not used
//        0x0 used/expirienced game over
function NoContinues()=> byte(0x0026) == 0x20

// $00A4: [8 bit] Changes its value each time you delete a block with laser upgrade
function BlockWasDestroyedWithLaser() => byte(0x0000A4) != prev(byte(0x0000A4))

// $0432: Credits [8-bit]
Credits = byte(0x000432)
// Credit amount past 19 (0x13) show incorrect characters as last digit
// 0x25 - shows as 1K

// $043D: Ball. Direction
//        [Bit 0]: 0x0 - Down; 0x1 - Up
//        [Bit 1]: 0x0 - Right 0x1 - Left
//BallDirection = byte(0x00043D)
// ^ Unused

// $043F: [8 bit] Modified Ball speed
//        Calculated based on 0x0462
//        Is =0x0 when ball rests on the paddle
ModifiedBallSpeed = byte(0x00043F)
function BallLandedOnPaddle() => ModifiedBallSpeed == 0x0 && prior(ModifiedBallSpeed!=0x0)

// $0462: [8 bit] Ball speed
BallSpeed = byte(0x000462)
function BallSlowedDown() => BallSpeed < prior(BallSpeed)

// $0464: [8 bit] Paddle state
//        0x0 - Clear
//        0x1 - Laser
//        0x2 - Expand
//        0x3 - Catch
PaddleState = byte(0x000464)

// $0476: [8 bit] Ball Paddle Hit Counter
BallPaddleHitCounter = byte(0x000476)

// $04A1: [8 bit] Capsule. Vertical Position.
CapsuleVerticalPosition = byte(0x0004A1)

// $04A2: [8 bit] Capsule. Horizontal Position.
CapsuleHorizontalPosition = byte(0x0004A2)

//Ball positions:
//  0.
// $04A5: [8 bit] Ball. Vertical Position.
BallVerticalPosition = byte(0x0004A5)
// $04A6: [8 bit] Ball. Horizontal Position.
BallHorizontalPosition = byte(0x0004A6)
//  1.
// $04A9: [8 bit] Additional Ball 1. Vertical Position.
AdditionalBall1VerticalPosition = byte(0x0004A9)
// $04AA: [8 bit] Additional Ball 1. Horizontal Position.
AdditionalBall1HorizontalPosition = byte(0x0004AA)
//  2.
// $04AD: [8 bit] Additional Ball 2. Vertical Position.
AdditionalBall2VerticalPosition = byte(0x0004AD)
// $04AE: [8 bit] Additional Ball 2. Horizontal Position.
AdditionalBall2HorizontalPosition = byte(0x0004AE)

//Does [number]th ball exist?
//Starts at 0, ends at 2
function DoesBallExist(number){
    return byte(0x0004A5+(number*4)) != 0 
}

// $04AF: [8 bit] Game Over State
//        0x1 - game over
//        0x0 - not
GameOverState = byte(0x0004AF)

//Paddles
// $04B2: [8 bit] Paddle. Right part. Horizontal Position.
PaddleRightPosition = byte(0x0004B2)
// $04B6: [8 bit] Paddle. Left part. Horizontal Position.
PaddleLeftPosition = byte(0x0004B6)
// $04BA: [8 bit] Paddle. Middle part (Extend). Horizontal Position.
PaddleMiddlePPosition = byte(0x0004BA)

// $04CE: [8 bit] Warp | Level Skip | Break
//        0x0 - off
//        0x1 - on
WarpLevelSkipBreak = byte(0x0004CE)

function IsLevelBeingSkipped(){
    return PaddleRightPosition => 0xf8
}

// $04D7: Score [8-Bit]
//        --- Upper4 | Digit 1
//        --- Lower4 | Digit 2
// $04D8: Score [8-Bit]
//        --- Upper4 | Digit 3
//        --- Lower4 | Digit 4
// $04D9: Score [8-Bit]
//        --- Upper4 | Digit 5
//        --- Lower4 | Digit 6
function Score() => bcd(tbyte(0x0004D7))

// $04FD: [8 Bit] Round ID mod 4
// RoundIdMod4 = byte(0x0004FD)
// Unused ^

// $0658: [8 bit] ID of a current capsule on screen
//        Laser - 0x81
//        Expand - 0x82
//        Catch - 0x83
//        Slow - 0x84
//        Bonus - 0x85
//        Disrupt - 0x86
//        Player - 0x87
//        None - 0x00-0x07 (copies value from 0x0659 after capsule disappearing)
//        [Bit 7] can be used to check if there is a capsule on screen (1 = yes; 0 = no)
IdOfACurrentCapsuleOnScreen = byte(0x000658)

// $0659: [8 bit] ID of last capsule picked up
//        None - 0x00
//        Laser - 0x01
//        Expand - 0x02
//        Catch - 0x03
//        Slow - 0x04
//        Bonus - 0x05
//        Disrupt - 0x06
//        Player - 0x07
IdOfLastCapsulePickedUp = byte(0x000659)

// $0663: [8 bit] ID of the last capsule spawned
//        None - 0x00
//        Laser - 0x90
//        Expand - 0x98
//        Catch - 0x88
//        Slow - 0x80
//        Bonus - 0xa8
//        Disrupt - 0xa0
//        Player - 0xb0
IdOfTheLastCapsuleSpawned = byte(0x000663)

// $15EB: [8 bit] Amount of damage dealt to boss.
//        Boss dies at 0x10 (16) hits
DamageDealtToBoss = byte(0x0015EB)

// $15F1: Lives [8-bit]
Lives = byte(0x0015F1)

// $15F2: Round [8-bit]
Round = byte(0x0015F2)
function LevelCompleted(id) => prior(Round) == id && Round == id+1

// $1603: [8 bit] Amount of bricks left to be destroyed.
BricksLeft = byte(0x001603)

// $17E4: [8 bit] Max amount of enemies on screen.
//MaxAmountOfEnemiesOnScreen = byte(0x0017E4)
// Unused

//              AUTO-GENERATED ACHIVEMENTS INFO ARRAY
//Easy - with continues, Hard - without
//Granted for completing level ID_in_array*4
//Description: "Complete levels [ID*4-3]-[ID*4] (Without continues)"  
LevelCompletionCheevoInfo = {
    "easy": {
        1: {"title": "Begginer", "points": 1, "id": 0, "badge": "0"},
        2: {"title": "Cooler begginer", "points": 2, "id": 0, "badge": "0"},
        3: {"title": "", "points": 2, "id": 0, "badge": "0"},
        4: {"title": "", "points": 3, "id": 0, "badge": "0"},
        5: {"title": "", "points": 3, "id": 0, "badge": "0"},
        6: {"title": "", "points": 4, "id": 0, "badge": "0"},
        7: {"title": "", "points": 4, "id": 0, "badge": "0"},
        8: {"title": "", "points": 5, "id": 0, "badge": "0"}
    },
    "hard": {
        1: {"title": "", "points": 3, "id": 0, "badge": "0"},
        2: {"title": "", "points": 5, "id": 0, "badge": "0"},
        3: {"title": "", "points": 5, "id": 0, "badge": "0"},
        4: {"title": "", "points": 10, "id": 0, "badge": "0"},
        5: {"title": "", "points": 10, "id": 0, "badge": "0"},
        6: {"title": "", "points": 10, "id": 0, "badge": "0"},
        7: {"title": "", "points": 10, "id": 0, "badge": "0"},
        8: {"title": "", "points": 5, "id": 0, "badge": "0"}
    }
}

for cheevo_id in LevelCompletionCheevoInfo["easy"]{
    achievement(
        title = LevelCompletionCheevoInfo["easy"][cheevo_id]["title"],
        description = "Complete levels " + (cheevo_id*4-3) + "-" + (cheevo_id*4) + ".",
        points = LevelCompletionCheevoInfo["easy"][cheevo_id]["points"],
        trigger = !IsDemo() && LevelCompleted(cheevo_id*4-1) 
        //                                               ^ because first = 0
    )
}

for cheevo_id in LevelCompletionCheevoInfo["hard"]{
    achievement(
        title = LevelCompletionCheevoInfo["hard"][cheevo_id]["title"],
        description = "Complete levels " + (cheevo_id*4-3) + "-" + (cheevo_id*4) + ".",
        points = LevelCompletionCheevoInfo["hard"][cheevo_id]["points"],
        trigger = !IsDemo() && LevelCompleted(cheevo_id*4-1) 
        //                                               ^ because first = 0

    )
}
Jamiras commented 1 year ago

This should have been fixed in 1.12 with a change to the Core DLL: https://github.com/Jamiras/Core/pull/31

Are you on 1.12? If so, can you verify the version of the Jamiras.Core.DLL is 1.3.1?

Visssarion commented 1 year ago

I am on 1.12 of RATools and Core is 1.3.1.

Visssarion commented 1 year ago

It also works with just code and not only with comments image

Visssarion commented 1 year ago

If i load autosaved copy of the file before crash, i can continue writing stuff on the line over the limit without a crash. but if I erase some amount of symbols and type them back, it crashes again