Jump to content
Search In
  • More options...
Find results that contain...
Find results in...
    1. Welcome to GTAForums!

    1. GTANet.com

    1. GTA Online

      1. The Cayo Perico Heist
      2. The Diamond Casino Heist
      3. Find Lobbies & Players
      4. Guides & Strategies
      5. Vehicles
      6. Content Creator
      7. Help & Support
    2. Red Dead Online

      1. Frontier Pursuits
      2. Find Lobbies & Outlaws
      3. Help & Support
    3. Crews

    1. Red Dead Redemption 2

      1. PC
      2. Help & Support
    2. Red Dead Redemption

    1. Grand Theft Auto Series

    2. GTA VI

      1. St. Andrews Cathedral
    3. GTA V

      1. Guides & Strategies
      2. Help & Support
    4. GTA IV

      1. The Lost and Damned
      2. The Ballad of Gay Tony
      3. Guides & Strategies
      4. Help & Support
    5. GTA San Andreas

      1. Guides & Strategies
      2. Help & Support
    6. GTA Vice City

      1. Guides & Strategies
      2. Help & Support
    7. GTA III

      1. Guides & Strategies
      2. Help & Support
    8. Portable Games

      1. GTA Chinatown Wars
      2. GTA Vice City Stories
      3. GTA Liberty City Stories
    9. Top-Down Games

      1. GTA Advance
      2. GTA 2
      3. GTA
    1. GTA Mods

      1. GTA V
      2. GTA IV
      3. GTA III, VC & SA
      4. Tutorials
    2. Red Dead Mods

      1. Documentation
    3. Mod Showroom

      1. Scripts & Plugins
      2. Maps
      3. Total Conversions
      4. Vehicles
      5. Textures
      6. Characters
      7. Tools
      8. Other
      9. Workshop
    4. Featured Mods

      1. Design Your Own Mission
      2. OpenIV
      3. GTA: Underground
      4. GTA: Liberty City
      5. GTA: State of Liberty
    1. Rockstar Games

    2. Rockstar Collectors

    1. Off-Topic

      1. General Chat
      2. Gaming
      3. Technology
      4. Movies & TV
      5. Music
      6. Sports
      7. Vehicles
    2. Expression

      1. Graphics / Visual Arts
      2. GFX Requests & Tutorials
      3. Writers' Discussion
      4. Debates & Discussion
    3. Gangs

    1. Announcements

    2. Support

    3. Suggestions

Sign in to follow this  

[Intro] How To Fix Missions with Variables Corrupted by Bad Cleo Scripts

Recommended Posts


Introduction: (San Andreas PC specific, but the same general principles apply to GTA3 era games)

This question (paraphrased) came up in PM and I wanted to move the discussion to the open forums for others to use as reference. This is intended as an introductions to saved data and game scripts, and I won't answer the current question right away.

This topic will cover the basics of getting started with decompiling the main script file (main.scm) using Sanny Builder 3 and figuring out what the mess of bizarre codes might mean.

SASE 1.00 will be used to view and modify save information. This isn't exactly a perfect editing tool, but it's a powerful save viewer and much easier to use than a hex editor or learning to write custom cleo scripts.

I'll fill in the blanks later if necessary but I'll trust that readers won't have too much trouble searching for official links to Sanny or finding specific files in their data folders.

Decompiling with Sanny

If you are working with a decompiled main.scm in Sanny you run the risk of accidentally hitting Compile and Copy or otherwise overwriting your original main.scm, so make a backup, and zip up your backup for safe keeping. script.img is paired with main.scm, so keep them together in the same archives. Then make a another copy of your backup folder in your user files and decompile those.

Rename your decompiled main scripts to keep track of their purpose and decompile settings. unmoddified.GTASA.v1.default.main.scm, for whatever you get out of the box.

Decompiled scripts will look much different depending on the settings. It won't make much sense if my examples look different than yours so I'll cover some specific settings. However, I've made many adjustments to Sanny over the years and sometimes lose track of why I set what. Hopefully I haven't mess things up too much.

Debug Options - gear icon on right of menu bar

  • ON = CONSTANT_INDEXES (don't know why)
  • all others off

Edit Mode - game icon in lower right corners

  • use GTA SA mode - this is the format everyone has been using for many years
  • GTA SA SCR - original Rockstar command names and format (not always compatible)
  • SA Mobile - mobile versions have different commands and variable names

Tools > Options (F10)

  • General
    • off = Always overwrite output file
    • on = Show progress
    • on = Show report
    • on = Show warning
    • off = Manual IMG opening
    • on = Quick game loading
    • on = Conditions check
    • on = Ranges check
    • on = Write opcodes (this will force the display of all opcodes)
    • on = Insert original mission names
    • off = Add extra info to SCM
  • Formats
    • use Thread+Local Offset (most common setting)
    • off = hex offsets
    • on = Custom label names (MS_Riot_Missions)
    • on = Custom variable names ($Riot_Total_Passed_Missions)
    • off = Custom array names
    • Case conversion: As is

The specific issue is that the Riot mission won't start even though all the mission requirements have been unlocked. First I want to show a few examples from the RIOT sniffer thread. This is the thread that is supposed to loop in memory and start the RIOT1 mission when CJ is inside the marker. But before I show the full snippet I want to show a few examples of how the code vary depending on the setting.

Decompile main.scm using the settings above, then make the changes below:

:MS_Riot_Missions03A4: name_thread 'RIOT' :RIOT_110001: wait $DEFAULT_WAIT_TIME ms 00D6: if 0038:   $Riot_Total_Passed_Missions == 5 004D: jump_if_false @RIOT_36 004E: end_thread 

Write Opcodes OFF (close to default, I think)

:MS_Riot_Missionsthread 'RIOT' :RIOT_11wait $DEFAULT_WAIT_TIME if   $Riot_Total_Passed_Missions == 5 jf @RIOT_36 end_thread 

Hex Offsets, Custom label names OFF, UPPER case conversion (upper might be default)

:RIOTthread 'RIOT' :RIOT_Bwait $DEFAULT_WAIT_TIME if   $RIOT_TOTAL_PASSED_MISSIONS == 5 jf @RIOT_24 end_thread 

Thread+Global Offset, Custom variable names OFF, lower case conversion

:riot_12257thread 'RIOT' :riot_12262wait $14 if   $629 == 5 jf @riot_1227B end_thread 

Reset to the suggested settings at the top.
Change to the GTA SA SCR edit mode.

:MS_Riot_Missions03A4: script_name 'RIOT' :RIOT_110001: wait $DEFAULT_WAIT_TIME 00D6: if 0038:   $Riot_Total_Passed_Missions == 5 004D: goto_if_false @RIOT_36 004E: terminate_this_script 

Up until we started SCR mode, Sanny would work with any of the format setting. Sanny can figure out which opcodes belong where during compile. An import difference in SCR mode, besides it not being setup to find vehicles.ide, is that SCR uses a handle first format which makes these codes incompatible. The text changes don't matter, but the change in the sequence of the variables ($7997) makes a huge difference.

00A5: $7997 = create_car #CAMPER at 1242.9 -805.4 82.9     // GTA SA00A5: create_car 483 at 1242.9 -805.4 82.9 store_to $7997  // GTA SA SCR
Edited by OrionSR
  • Like 2

Share this post

Link to post
Share on other sites

Back to the main question, why doesn't the riot mission start? If you know the answer please keep it to yourself for a while.


This this the start of the RIOT sniffer thread, and the part that launches the Riot mission. Similar segments follow for the rest of the missions in this final strand. The last line is where the mission is started.

:MS_Riot_Missions03A4: name_thread 'RIOT' :RIOT_110001: wait $DEFAULT_WAIT_TIME ms 00D6: if 0038:   $Riot_Total_Passed_Missions == 5 004D: jump_if_false @RIOT_36 004E: end_thread :RIOT_3600D6: if 0256:   player $PLAYER_CHAR defined 004D: jump_if_false @RIOT_673 00D6: if 0038:   $ONMISSION == 0 004D: jump_if_false @RIOT_673 00D6: if 00FF:   actor $PLAYER_ACTOR sphere 0 in_sphere $X_Madd_Dogg_Crib $Y_Madd_Dogg_Crib $Z_Madd_Dogg_Crib radius 1.2 1.2 2.0 on_foot 004D: jump_if_false @RIOT_180 00D6: if 03EE:   player $PLAYER_CHAR controllable 004D: jump_if_false @RIOT_180 00D6: if 0038:   $Riot_Total_Passed_Missions == 0 004D: jump_if_false @RIOT_180 0004: $ONMISSION = 1 00BA: show_text_styled GXT 'RIOT_1' time 1000 style 2  // Riot0050: gosub @sub_CJ_goto_Madd_Doggs_Crib 0417: start_mission 108  // Riot

But how did I find this segment? Near the beginning of script is a definition list for mission start address labels. A search for "riot" found this.

DEFINE MISSION 108 AT @RIOT1           // RiotDEFINE MISSION 109 AT @RIOT2           // Los DesperadosDEFINE MISSION 110 AT @FINALEA         // End Of The Line (1)DEFINE MISSION 111 AT @FINALEB         // End Of The Line (2)DEFINE MISSION 112 AT @FINALEC         // End Of The Line (3)

A search for "mission 108" brought me to the end of the segment above.


To clarify, RIOT is the sniffer thread that controls RIOT1 - Riot, RIOT2 - Los Desperados, and what could be referred to as Riot 3, 4 and 5, the End of the Line missions. When all 5 are completed ($Riot_Total_Passed_Missions == 5) the RIOT thread should end.


So what's gone wrong in this save?


Generally, problems with corruption to global variables is caused by cleo scripts that use custom global variables. These undeclared variables usually get assigned to the first unnamed variable available. Sometimes this doesn't matter, other times it can break missions. But all of the global variables in this segment are named. I've seen problems with bad cleo scripts converted to Android stomping on the default wait time, but PC is probably immune from issues.


I looked up the values of the globals anyway. Nothing is wrong. If you check the script that you decompiled without the custom variable names you can get the global numbers for the global names. $409 for $ONMISSION, for example. The Script tab of SASE shows the Global Variable numbers in the left panel. The interfaces allows you to set the number format to Hex, Integer, or Float (numbers with decimal values) since each global may hold a different type of data - switch as needed.


Again, what's gone wrong? SASE's center Script panel has a list of running threads. And RIOT isn't on it. A better question then, is why isn't the riot thread running when all requirements have been met. What is supposed launch the riot thread?


Thread are launched differently than missions. And this thread is a bit different because it has a custom label name, :MS_Riot_Missions. The colon indicates it's a label to be used by a jump @ address. So search for something that is using a launch code with a @MS_Riot_Missions label address.


Is This It? - hench the clarification of Sanny settings

//-------------Mission 108---------------// Originally: Riot:RIOT103A4: name_thread 'RIOT1' 0050: gosub @RIOT1_47 00D6: if 0112:   wasted_or_busted // mission only 004D: jump_if_false @RIOT1_38 0050: gosub @RIOT1_2979 :RIOT1_380050: gosub @RIOT1_3082 004E: end_thread 

Nope, that's the actual mission, and has labels that start with RIOT1. It comes later in the chain. Something should start RIOT; RIOT should start RIOT1, but what is the something not launching RIOT?

Edited by OrionSR
  • Like 1

Share this post

Link to post
Share on other sites

Coding Language Clues


Learning a new language can be confusing. It's perfectly normal for people to be overwhelmed with all the new information. It will start to make sense with practice. Here are a few clues about the formats and protocols.

// A comment line. These are usually comments but may also be disabled codes in a working script./* Commented segment */ common C style format{  Sanny will also take comments between brackets}

$ONMISSION, $5653 - variable preceded by a $ indicate a global variable either by name or by number.

Global variables are saved and accessible by any thread or mission. This is how the game remembers stuff associated with the scripts.


@RIOT1_222 - the @ symbol in the front indicates a :label address.

[email protected] - a @ symbol at the end is a local variable.


Local variables are limited to 32 in threads,1022? in missions, and can be remembered by running threads, but locals in missions are usually lost when the mission ends.


:StartMyLoop - Labels start with a colon and can be called by @StartMyLoop style commands. With global offsets, the numbers describe the exact byte location within the script. The labels don't actually exist in the script. Sanny just makes those up when it finds an address. That address won't be the same if you make a change and recompile. Sanny doesn't care. It'll just put in the new address as it compiles. Labels can be anything, Sanny just organizes them based on the rules set.

0001: wait $DEFAULT_WAIT_TIME mswait [email protected] // first set [email protected] = 2500001: pickyournose 250 times0001: 250 

If there is no opcode Sanny can figure it out for common commands. And if you use an opcode the text doesn't matter as long as you don't chose a keyword. You can change it to suit your needs or omit it entirely.

00D6: if 0038:   $Riot_Total_Passed_Missions == 5 004D: jump_if_false @RIOT_36 004E: end_thread 

Conditional commands are indented two spaces by convention. These are the types of checks that can be made for IF commands. In this sequence the game will check IF all of the riot strand missions are complete ( $Riot_Total_Passed_Missions == 5). If this statement if true because the value is exactly (==) 5 then it will end the thread. Otherwise, (jump_if_false) it will continue on with whatever exists at label #RIOT_36.


== is used as a conditional check. = is used to make an assignment.

0004: $ONMISSION = 1 

Integers are indicated as numbers without a decimal. Floating point values are indicated with a decimal point and trailing 0 if necessary. Each type of value has it's own type of operator command. [email protected] = 1 and [email protected] = 1.0 will need different commands to work properly, Sanny can usually figure it out. += Add, -= subtract. But the primitive language doesn't inherently do things like [email protected] = 1 + 4. It needs to be broken down to [email protected] = 1 and then [email protected] += 4. Something like 1.0 + 4 gets even weirder.


It takes a bit of time to get familiar with the odd rules of a basic script language. That's why I like to start with the primitive opcode format.


#KEYCARD - # indicates a constant. These can be defined in SCM scripts but Sanny can determine the ID numbers associated with many pickups, vehicles and other items, which makes the script easier to read and write. Sanny knows the values associated with these keywords and will apply them at compile time. Numbers can be hard coded, or use constant or variables.

Edited by OrionSR
  • Like 1

Share this post

Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this  

  • 2 Users Currently Viewing
    0 members, 0 Anonymous, 2 Guests

  • Create New...

Important Information

By using GTAForums.com, you agree to our Terms of Use and Privacy Policy.