Quantcast
Jump to content
Search In
  • More options...
Find results that contain...
Find results in...
    1. Welcome to GTAForums!   (84,804 visits to this link)

    2. News

    1. GTA Online

      1. Find Lobbies & Players
      2. Guides & Strategies
      3. Vehicles
      4. Content Creator
      5. Help & Support
    2. Crews

      1. Events
      2. Recruitment
    1. Grand Theft Auto Series

    2. GTA Next

    3. GTA V

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

      1. Episodes from Liberty City
      2. Multiplayer
      3. Guides & Strategies
      4. Help & Support
      5. GTA Mods
    5. GTA Chinatown Wars

    6. GTA Vice City Stories

    7. GTA Liberty City Stories

    8. GTA San Andreas

      1. Guides & Strategies
      2. Help & Support
      3. GTA Mods
    9. GTA Vice City

      1. Guides & Strategies
      2. Help & Support
      3. GTA Mods
    10. GTA III

      1. Guides & Strategies
      2. Help & Support
      3. GTA Mods
    11. Top Down Games

      1. GTA Advance
      2. GTA 2
      3. GTA
    12. Wiki

      1. Merchandising
    1. GTA Modding

      1. GTA V
      2. GTA IV
      3. GTA III, VC & SA
      4. Tutorials
    2. Mod Showroom

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

      1. DYOM
      2. OpenIV
      3. GTA: Underground
      4. GTA: Liberty City
      5. GTA: State of Liberty
    1. Red Dead Redemption 2

    2. Red Dead Redemption

    3. Rockstar Games

    1. Off-Topic

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

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

    2. Site Suggestions

LINK/2012

Learn GTA3script in Y minutes

Recommended Posts

LINK/2012

This is a finished serie of tutorials based off the Learn X in Y Minutes website, which quickly guides you thought programming language.

And that's exactly what is going to happen here, I'll quickly guide you thought the GTA3script language, which was the language used by Rockstar North to script the missions and other behaviors of the III-era games. As such, basic programming knowledge is assumed, be it with the Sanny Builder Language, or with any other programming language.

You can get the full tutorial directories here, so you can compile them yourself. In fact, I highly recommend reading those series from the editor with proper highlighting. You can get the compiler and editor extension here.

 

The serie is divided in three parts, where the first is obligatory and the other two are independent from each other.

Tip: Do notice how the important parts are all near comment blocks, so you should watch for those.

Edited by LINK/2012

Share this post


Link to post
Share on other sites
LINK/2012

The Basics

 

// This is a comment line./*    This is a multiline comment    /* It may be nested        /* as many times */       as you want.    */*/// This script is only meant as an way of understanding the basics of the GTA3script language.// Don't try running it. It makes no logical sense, and is likely to crash the game.//////////////////////////// 1. Variables ///////////////////////////// Global variables are declared like this:VAR_INT my_global_int other_global_intVAR_FLOAT my_global_floatVAR_TEXT_LABEL my_global_text8      // GTASA onlyVAR_TEXT_LABEL16 my_global_text16   // GTASA only// You may use arrays as well (GTASA only)VAR_INT my_global_array[32]my_global_array[0] = 11my_global_array[3] = 22// To declare local variables you use LVAR_ instead of VAR_// Local variables must be declared inside scopes{    LVAR_INT my_local   }// Naturally, you may use the same name between scopes{    LVAR_FLOAT my_local}// Do note branching from scope to scope is dangerous, it uses the same variable space as the other scope.{    scope1:    LVAR_INT test_var     test_var = 99    GOSUB scope2    GOTO scope1}{    scope2:    LVAR_INT not_another_var    // the value of not_another_var is likely to be 99 as it uses the same space as test_var    not_another_var = 3    RETURN    // the value of test_var after returning to scope1 is likely 3.    // do not rely on this behaviour though.}/////////////////////////////// 2. Commands //////////////////////////////////// Mostly everything is a command on GTA3script, including the variable declaration seen above.VAR_INT player scplayer// Commands gives instructions to the script engine. Such as to create the player.// The CREATE_PLAYER command takes the player id, the coordinates to create the player at, and outputs the player reference into a variable.// (http://www.gtamodding.com/wiki/0053)CREATE_PLAYER 0 9.5 5.0 -100.0 player// Most commands takes character references, as such we need the players character.// Do note how the output values of commands are always the last parameters.GET_PLAYER_CHAR player scplayer// A very important command is WAIT (http://www.gtamodding.com/wiki/0001).// The game is single-threaded, and as such it has to stop updating the game to process scripts, including this one.// To signal the game we're done with the script on this tick, we should use WAIT.WAIT 0    // stops execution and returns on the next tick.WAIT 1000 // stops execution for at least 1000ms.// Arguments of commands are usually of the following types:DO_FADE 100 0        // integersDO_FADE 100 FADE_OUT // constants, in this particular case produces the same result as above.SET_TIME_SCALE 1.0   // floatsGOSUB scope2         // labelsPRINT_HELP M_FAIL    // text labels, you may think of this as strings in other languages.// A interesting remark: The characters '(', ')' and ',' are treated as spaces, so those lines are valid:PRINT_BIG (M_FAIL) 1000 1PRINT_BIG(M_FAIL, 1000, 1)PRINT_BIG M_FAIL, (1000), 1// Another remark: **Everything** is case-insensitive, so:print_big m_FaIL 1000 1 // is exactly the same as above // SAVE_STRING_TO_DEBUG_FILE is a special command, the **only** one which accepts a string literal.SAVE_STRING_TO_DEBUG_FILE "The quick brown fox jumps over the lazy dog"// Nevertheless, the string will be compiled into a uppercase string.// Since variables and text labels may collide, to give a variable to a text label argument// you should prefix the variable name with an $, like so:VAR_INT m_failm_fail = M_PASSDPRINT_BIG $m_fail 2000 1    // Prints M_PASSD text labelPRINT_BIG m_fail 2000 1     // Prints M_FAIL text label/////////////////////////////// 3. Constants /////////////////////////////////// Since GTASA you may define your own string constants.CONST_INT   int_max 2147483647CONST_FLOAT math_pi 3.1415927PRINT_BIG M_FAIL int_max 1      // same as PRINT_BIG M_FAIL 2147483647 1my_global_float = math_pi * 2   // same as my_global_float = 3.1415927 * 2/////////////////////////////// 4. Control-Flow //////////////////////////////VAR_INT i j kGENERATE_RANDOM_INT iGENERATE_RANDOM_INT j// If statementIF i = 100    k = 0ELSE    k = 1ENDIF// Logical disjunctionIF j < -100OR i >= -100    ++kENDIF// Logical conjunctionIF IS_CHAR_ON_FOOT scplayerAND NOT IS_CHAR_DEAD scplayer   // Logical negationAND NOT k = 2    SET_CHAR_COORDINATES scplayer 0.0 0.0 0.0ENDIF// Something to be aware of as well is that all conditions checks will happen no matter the result of the previous ones.// So, if you're doing a conjunction and the first condition failed, the second one will run anyway!// This also applies to disjunction. If the first condition is true, the second condition will run anyway.// You cannot mix disjunction and conjuntion! The following is invalid:// IF i = 0// OR i = 1// AND i = 2//     NOP// ENDIF// Switch statement (since GTASA)SWITCH k    CASE 1        // This runs if k = 1        FREEZE_CHAR_POSITION scplayer TRUE        BREAK    CASE 2    CASE 3        // This runs if k = 2 or k = 3        SET_CHAR_HEALTH scplayer 0        BREAK    DEFAULT // Optional        // This runs if k is none of the above        ADD_ARMOUR_TO_CHAR scplayer 100        BREAKENDSWITCH// While loopWHILE NOT IS_CHAR_DEAD scplayerAND NOT IS_CHAR_IN_MODEL scplayer CHEETAH    // It is very important to use WAIT on long-running loops, otherwise the will do nothing    // but keep running your script, thus freezing the game.    WAIT 0ENDWHILE// Repeat loop (since GTAVC)REPEAT 5 i    PRINT_WITH_NUMBER (NUMBER) i 1000 TRUE    WAIT 1000ENDREPEAT// Prints 0, then 1, then 2, then 3, then 4.// Do note the REPEAT runs at least once, so (REPEAT 0 i) would, in fact, print 0.// Additionally, there is IFNOT and WHILENOT, which negates every condition.// However, those are only supported in GTA3 and were never used.IFNOT IS_CHAR_HEALTH_GREATER scplayer 30AND NOT IS_CHAR_IN_ANY_CAR scplayer    // This runs if the player health **IS NOT** greater than 30, and if the char **IS** in a vehicle.ENDIF/////////////////////////////// 5. Timers       //////////////////////////////// Within every scope there are two timer local variables: timera and timerb// Those timers are in miliseconds and are updated on every game update tick.{    timera = 0    timerb = 10000    WHILE timera < 3000        WAIT 0    ENDWHILE    // this made the script wait for around 3000 miliseconds (similarly to WAIT 3000).    // also, TIMERB equals around 13000 at this point.}/////////////////////////////// 6. Arithmetic   ////////////////////////////////VAR_INT i j k -- already declared beforeVAR_FLOAT x y z// You may perform assignment/arithmetic like this:x = 1.0y = x + 3.5i += 90i = i - kk *= kj /= 2my_global_text8  = TEXT // maximum of 7 charactersmy_global_text16 = TEXT // maximum of 15 characters// But you cannot do more than binary operations, so the following is invalid:// x = x + y + z// And, you cannot mix different types in a expression, the following is also invalid:// x = j * 2// x = 2       correct would be   x = 2.0// In addition to the usual operations we know (addition, substraction, multiplication and division), we also have// timed addition and timed substraction.//// They are essentially a shortcut to the delta time constant of the current frame.// You may learn more about delta time in the animation present in this video: https://www.youtube.com/watch?v=a-w7w8x_moE// // You should usually use this when moving objects in a loop, making the movement frame-rate independent.//x = y [email protected] 3.0    // x = y + 3.0 * delta_timey [email protected] 3.0       // y += 3.0 * delta_timez [email protected] y         // z -= y * delta_time// You may perform a cast from integer to float, or float to integer, by using the =# operator.x =# ii =# x// You may also use the increment/decrement operators.// Do note there's no difference between pre and post incrementing.++i     // same as i += 1i++     // same as i += 1--i     // same as i -= 1i--     // same as i -= 1// And, finally, you can use the comparision operators in conditional contexts:IF i = 0OR i < 0OR i > 0OR i >= 0OR i <= 0    NOPENDIF//////////////////////////////////// 7. Entities          ///////////////////////////////////VAR_INT car char object1 object2 empty_var sanity// The language also checks the type of the entity assigned to a variable, in such a way// that you cannot use the variable in a different context from which it was inteded to be used at.CREATE_CAR (CHEETAH) 0.0 0.0 0.0 carCREATE_CHAR (PEDTYPE_CIVMALE MALE01) 0.0 0.0 0.0 char// IS_CHAR_DEAD car        // will not compile// IS_CAR_ENGINE_ON char   // will not compile// char = car              // will not compileempty_var = car            // compiles fine, empty_var is of type CAR now// As such, if you intend to use an certain variables as a entity type before creating it,// you need to include some unreachable code that assigns the entity type to the variable.//// There are two ways to do this:// The first, by using a impossible condition:sanity = 0IF sanity = 1    CREATE_OBJECT (BRIEFCASE) 0.0 0.0 0.0 object1ENDIF// The second, by using a GOTO before the creation code.GOTO entity_mainCREATE_OBJECT (DRUGS) 0.0 0.0 0.0 object2entity_main:GOSUB actually_create_objectsWHILE NOT IS_OBJECT_ON_SCREEN object1AND NOT IS_OBJECT_ON_SCREEN object2    WAIT 0ENDWHILEEXPLODE_CAR carEXPLODE_CHAR_HEAD charGOTO entity_cleanup// this code is after the actual object usage, but runs before it.actually_create_objects:    CREATE_OBJECT (BRIEFCASE) 0.0 0.0 0.0 object1    CREATE_OBJECT (DRUGS) 0.0 0.0 0.0 object2RETURNentity_cleanup:// After you're done with your entities, you should probably delete or mark them as no longer needed.//// Deleting removes the entity from the world immediately, invalidating all references to it.// Marking as no longer needed gives the control of the entity back to the game logic instead of the script engine.MARK_OBJECT_AS_NO_LONGER_NEEDED object1DELETE_OBJECT object2DELETE_CHAR charMARK_CAR_AS_NO_LONGER_NEEDED car//////////////////////////////////// 8. Farewell          ///////////////////////////////////// Oh well, I think we are done here.// To kill your script, use the TERMINATE_THIS_SCRIPT command.TERMINATE_THIS_SCRIPT
Edited by LINK/2012

Share this post


Link to post
Share on other sites
LINK/2012

Multifiles

 

This tutorial is very long, so if you are not interested in the way multifiles scripting work (i.e. main.scm and script.img), simply skip this and go to custom scripts.

 

main.sc

 

// This is a tutorial about multifile scripts.// It assume you know the basics of the GTA3script language from the previous tutorial.// This multifile is for GTA SA since it contains more features than GTA III/VC, thus// we can explain more things than it would be possible by using III/VC as base.// The code in this tutorial should not really be used in a real world multifile!// This time, the code makes logical sense and **actually works**. But the variables are misplaced, which is bad for custom scripts.// Please check the stripped multifiles in the other thread (which?) for an actual base multifile source code.//// What in the world is a multifile after all?//// It's a big compiled script containing multiple source scripts. Such big script is used by the game to// conduct missions, submissions and other behaviours, as we'll see later on.//// This is what we previously knew simply as 'the SCM file'.//VAR_INT player scplayer player_groupVAR_INT flag_player_on_mission// Each script in a multifile should have a unique name.// This unique name may be used later on in a TERMINATE_ALL_SCRIPTS_WITH_THIS_NAME to kill the script.SCRIPT_NAME main// We'll learn more about this command later.SET_DEATHARREST_STATE OFF// The following commands should be used exactly as follow, with the first parameter as 0.// The compiler will, during the compilation process, replace the zeros with the correct values found during the compilation process.SET_TOTAL_NUMBER_OF_MISSIONS 0SET_PROGRESS_TOTAL 0SET_MISSION_RESPECT_TOTAL 0// In III/VC there is additionally (SET_COLLECTABLE1_TOTAL 0).// Creating the player is one of the fundamental tasks of a multifile.CREATE_PLAYER 0 0.0 0.0 5.0 player// A multifile must as well tell the game logic which variable to lookup when testing// whether the player is in a mission.flag_player_on_mission = 0DECLARE_MISSION_FLAG flag_player_on_mission// The multifile also needs to give the player some initial clothes.// Tip: Try removing those lines and running the game GIVE_PLAYER_CLOTHES_OUTSIDE_SHOP player VEST VEST 0GIVE_PLAYER_CLOTHES_OUTSIDE_SHOP player PLAYER_FACE HEAD 1 GIVE_PLAYER_CLOTHES_OUTSIDE_SHOP player JEANSDENIM JEANS 2 GIVE_PLAYER_CLOTHES_OUTSIDE_SHOP player SNEAKERBINCBLK SNEAKER 3 BUILD_PLAYER_MODEL player// And respawning points.// Tip: Try removing those lines and dying / getting arrested.ADD_HOSPITAL_RESTART (0.0 0.0 5.0) (0.0) 0 ADD_POLICE_RESTART (0.0 0.0 5.0) (0.0) 0// The game starts faded out, so let's fade in.// Tip: Try a new game, then a new game again, without the following lines.SET_PLAYER_CONTROL player ONDO_FADE 0 FADE_IN// This is the absolutely minimal initialization a multifile should do. The game works now.// The following variable inits are also useful:GET_PLAYER_CHAR player scplayerGET_PLAYER_GROUP player player_group// Now let's learn the true meaning of **multi**.// Rockstar usually puts much of the initialization in a mission script.//// You see, all the code in a multifile is loaded into memory, except for missions and streamed scripts.// So, this is not only convenient, but it saves memory.//// Do note two mission scripts **cannot** run at the same time, that's why we should// keep track of flag_player_on_mission.LOAD_AND_LAUNCH_MISSION initial.scWAIT 0 // wait for the initialization script to run/finish// Let's start some scripts!//// Those scripts will run cooperatively, when one WAITs, the other gets// to run, as we explained already in the basics tutorial. START_NEW_SCRIPT psaveSTART_NEW_SCRIPT money 5000 8000 3.0 // you may send values to be received in the script label local variables// Now let's start some subscripts.//// Despite the command name, this does not create missions per se.// Just think of this as a version of START_NEW_SCRIPT but within a new file.LAUNCH_MISSION import.scLAUNCH_MISSION other_scripts.sc// III additionally have GOSUB_FILE which does the same as GOSUB, but including a file as well.// GOSUB_FILE label file.sc// Now for a very interesting script type introduced in GTASA: streamed scripts.//// Streamed scripts are scripts which are streamed into memory only when neeeded,// and there can be multiple of those running cooperatively at the same time.//// This has the memory benefit of missions with the coding freedom of normal scripts.//// To use streamed scripts we should, first of all, assign streamed scripts to string constants:REGISTER_STREAMED_SCRIPT CARMOD1 carmod1.scREGISTER_STREAMED_SCRIPT FOOD_VENDOR food_vendor.sc// Streamed scripts can be streamed in manually or by a script trigger.// We'll see how to stream it manually at the main_loop, but for now let's focus on triggers.//// The triggers may be registered using://   + REGISTER_SCRIPT_BRAIN_FOR_CODE_USE//   + REGISTER_ATTRACTOR_SCRIPT_BRAIN_FOR_CODE_USE//   + ALLOCATE_STREAMED_SCRIPT_TO_RANDOM_PED//   + ALLOCATE_STREAMED_SCRIPT_TO_OBJECT//// Each of those triggers are very delicate and requires a tutorial by themselves, which I'm// not up to write, and gets out of the scope of this tutorial, which is quick learning.//// Instead, let's pick ALLOCATE_STREAMED_SCRIPT_TO_OBJECT and play with it.//ALLOCATE_STREAMED_SCRIPT_TO_OBJECT FOOD_VENDOR CHILLIDOGCART 100 70.0 -1ALLOCATE_STREAMED_SCRIPT_TO_OBJECT FOOD_VENDOR NOODLECART_PROP 100 70.0 -1// So, we just told the script engine we want to run FOOD_VENDOR once we're at a 70.0 radius// of the the CHILLIDOGCART or NOODLECART_PROP objects.// Unfortunately, objects spawned by script (CREATE_OBJECT) do not trigger streamed scripts, so we'll// make a teleporter to that have a cart spawned by level files.// Tip: Look away from the carts if the vendor character is not spawned.START_NEW_SCRIPT cart_teleportmain_loop:WAIT 250// This is basically how you'd stream a streamed script manually:IF IS_GARAGE_OPEN (BODLAWN)OR IS_GARAGE_OPEN (MODLAST)OR IS_GARAGE_OPEN (MDSSFSE)OR IS_GARAGE_OPEN (MDS1SFS)OR IS_GARAGE_OPEN (VECMOD)    GET_NUMBER_OF_INSTANCES_OF_STREAMED_SCRIPT CARMOD1 num_carmod_instances    IF num_carmod_instances = 0        STREAM_SCRIPT CARMOD1        IF HAS_STREAMED_SCRIPT_LOADED CARMOD1            START_NEW_STREAMED_SCRIPT CARMOD1   // Tip: You can send values just like START_NEW_SCRIPT        ENDIF    ENDIFELSE    MARK_STREAMED_SCRIPT_AS_NO_LONGER_NEEDED CARMOD1ENDIFGOTO main_loop// Let's declare a few more variables.// Usually this should be at the very top of the script, but to avoid poluting the 'minimal multifile' sample,// we'll declare them here.VAR_INT mistery_blip flag_mistery1_passed flag_mistery2_passed VAR_FLOAT mistery_xpos mistery_ypos mistery_zposVAR_INT num_carmod_instances dogcart1// This is a simple script that gives player money when he's in a small sphere near the spawning point.// Pretty straightforward, no comments needed.{    money:    SCRIPT_NAME money    // Remember the values we passed to START_NEW_SCRIPT?    LVAR_INT amount wait_time // 5000 and 8000 will be received here.    LVAR_FLOAT unused_but_example // 3.0 will be received here    money_loop:    WAIT 0    IF IS_PLAYER_PLAYING player        IF IS_CHAR_IN_AREA_ON_FOOT_3D scplayer (-8.0, 0.0 4.0) (-7.0 2.0 0.0) TRUE // Tip: Try FALSE            ADD_SCORE player amount            PLAY_MISSION_PASSED_TUNE 1            WAIT wait_time        ENDIF    ENDIF    GOTO money_loop}// This is a simple save game script.// After spawning, turn around and look for a save pickup and play with it.// Again, no comments needed.{    psave:    SCRIPT_NAME psave    LVAR_INT save_pickup pickup_created    pickup_created = 0    // Remeber the entities tutorial? Try compiling without those lines:    IF pickup_created = 1        CREATE_PICKUP 0 0 .0 .0 .0 save_pickup    ENDIF    psave_loop:    WAIT 0    IF flag_player_on_mission = 0        GOSUB psave_create_pickup        IF IS_PLAYER_PLAYING player        AND HAS_PICKUP_BEEN_COLLECTED save_pickup            GOSUB psave_do_save            GOSUB psave_destroy_pickup            GOSUB psave_create_pickup            GOSUB psave_respawn_player        ENDIF    ELSE        GOSUB psave_destroy_pickup        WAIT 1000    ENDIF    GOTO psave_loop    psave_do_save:        SET_PLAYER_CONTROL player OFF        ACTIVATE_SAVE_MENU        WHILE NOT HAS_SAVE_GAME_FINISHED            WAIT 0        ENDWHILE        SET_FADING_COLOUR 0 0 0        DO_FADE 1000 FADE_OUT        SET_PLAYER_CONTROL player OFF    RETURN    psave_respawn_player:        IF IS_PLAYER_PLAYING player            CLEAR_AREA (15.0 0.0 4.0) (1.0) TRUE            SET_CHAR_COORDINATES scplayer (15.0 0.0 4.0)        ENDIF        WAIT 0        DO_FADE 1000 FADE_IN        RESTORE_CAMERA_JUMPCUT        SET_CAMERA_BEHIND_PLAYER        WAIT 500        IF IS_PLAYER_PLAYING player            SET_PLAYER_CONTROL player ON        ENDIF    RETURN    psave_create_pickup:        IF pickup_created = 0            pickup_created = 1            CREATE_PICKUP PICKUPSAVE PICKUP_ONCE 10.0 0.0 3.0 save_pickup        ENDIF    RETURN    psave_destroy_pickup:        IF pickup_created = 1            pickup_created = 0            REMOVE_PICKUP save_pickup        ENDIF    RETURN}{    mistery1_loop:    // Well, yeah, we may refrain from using SCRIPT_NAME, but in such case the script    // cannot be terminated by another script.    WAIT 250    IF flag_mistery1_passed = 1        TERMINATE_THIS_SCRIPT    ENDIF    IF IS_PLAYER_PLAYING player        IF flag_player_on_mission = 0            IF LOCATE_CHAR_ON_FOOT_3D scplayer (mistery_xpos mistery_ypos mistery_zpos) (1.2 1.2 2.0) FALSE                IF CAN_PLAYER_START_MISSION player                    flag_player_on_mission = 1                    PRINT_BIG (SMOKE_4) 1000 2                    GOSUB fade_for_mission                    LOAD_AND_LAUNCH_MISSION mistery1.sc                ENDIF            ENDIF        ENDIF    ENDIF    GOTO mistery1_loop}{    mistery2_loop:    // So, since San Andreas they started grouping mission loops for each contact in a single loop.    // So we would have only mistery_loop. But let's build up on START_NEW_SCRIPT examples.    WAIT 250    IF flag_mistery2_passed = 1        TERMINATE_THIS_SCRIPT    ENDIF    IF IS_PLAYER_PLAYING player        IF flag_player_on_mission = 0            IF LOCATE_CHAR_ON_FOOT_3D scplayer (mistery_xpos mistery_ypos mistery_zpos) (1.2 1.2 2.0) FALSE                IF CAN_PLAYER_START_MISSION player                    flag_player_on_mission = 1                    PRINT_BIG (BCES4_2) 1000 2                    GOSUB fade_for_mission                    LOAD_AND_LAUNCH_MISSION mistery2.sc                ENDIF            ENDIF        ENDIF    ENDIF    GOTO mistery2_loop}fade_for_mission:    IF IS_PLAYER_PLAYING player        SET_PLAYER_CONTROL player OFF // Tip: turning player control off makes the player safe                                      // (i.e. cannot die or get arrested)        SET_FADING_COLOUR 0 0 0        DO_FADE 500 FADE_OUT        WHILE GET_FADING_STATUS            WAIT 0        ENDWHILE        CLEAR_PRINTS        CLEAR_HELP        CLEAR_CHAR_TASKS scplayer    ENDIFRETURN
main/import.sc

 

// main/import.sc//--------------------// Subscript files must be specialized with the MISSION_START / MISSION_END directives.// But once again, remember, this is not a mission per se!MISSION_STARTSCRIPT_NAME import// We'll learn more about this command later.// But it's most likely you want to turn off this on subscripts.SET_DEATHARREST_STATE OFF// I'll stop here because whatever you would use START_NEW_SCRIPT for, you can also use subscript for.// Here are some of the uses of subscripts in the trilogy: Unique Stunt Jumps, Rampages, Car Import Submissions...MISSION_END     // Terminates the script.
main/other_scripts.sc

 

// main/other_scripts.scMISSION_STARTSET_DEATHARREST_STATE OFFMISSION_END// Another use for subscripts is including labels in another file,// like labels for GOSUBs or for START_NEW_SCRIPTs.{some_random_script:TERMINATE_THIS_SCRIPT// you can use START_NEW_SCRIPT some_random_script from anywhere now.}some_random_gosub:RETURN// you can use GOSUB some_random_gosub from anywhere now.{    cart_teleport:    WAIT 0    IF IS_PLAYER_PLAYING player        IF IS_CHAR_IN_AREA_ON_FOOT_3D scplayer (-15.0, 5.0 4.0) (-14.0 2.0 0.0) TRUE            REQUEST_COLLISION -2157.6257 -425.5779            LOAD_ALL_MODELS_NOW            SET_CHAR_COORDINATES scplayer -2157.6257 -425.5779 -100.0            ADD_SCORE player 100 // some money to buy food        ENDIF    ENDIF    GOTO cart_teleport}
main/initial.sc

 

// main/initial.sc//---------------------// Initialization mission, as explained already in main.sc!MISSION_STARTSCRIPT_NAME initialflag_mistery1_passed = 0flag_mistery2_passed = 0mistery_xpos = 0.0mistery_ypos = 4.0mistery_zpos = 4.0START_NEW_SCRIPT mistery1_loopADD_SPRITE_BLIP_FOR_CONTACT_POINT (mistery_xpos mistery_ypos mistery_zpos) RADAR_SPRITE_MYSTERY mistery_blipMISSION_END
main/mistery1.sc

 

// main/mistery1.sc// // This is a mission script. It has the following basic structure:MISSION_STARTGOSUB mission_start_mistery1IF HAS_DEATHARREST_BEEN_EXECUTED     GOSUB mission_mistery1_failedENDIFGOSUB mission_cleanup_mistery1MISSION_END//// Here, in mission scripts, is where the the deatharrest state shines (remember SET_DEATHARREST_STATE?).// The deatharrest state is the scripting engine constantly checking if the player is dead or arrested,// if so, the engine will make the script return from all its GOSUBs immediately!//// Do you see the relationship in the basic mission structure? Nice, eh?//// Another interesting features of mission scripts are the mission cleanup list and the cleanup gosub.// The cleanup gosub serves as a disposal method for all the resources used by the mission.// The cleanup list is a script engine internal list that keeps track of some, but not all, of the entities created// by the mission, in such a way that once the mission is ended, the control of those entities are given back to the// game logic (just like by calling MARK_THING_AS_NO_LONGER_NEEDED). The most notable entities tracked by the cleanup// list are chars and cars.//// It reminds a bit of RAII. Request your stuff on mission startup and cleanup them on the cleanup sub.//// Let's write a simple 'GO FROM POINT A TO POINT B' mission.{// Variables for mission// For III/VC you'll probably declare globals, but SA has an abundant amount of local variables in a mission.LVAR_INT mistery1_delivery_car mistery1_delivery_blipLVAR_FLOAT x y zmission_start_mistery1:flag_player_on_mission = 1REGISTER_MISSION_GIVENWAIT 0 // let other scripts know a mission has been startedSCRIPT_NAME mister1LOAD_MISSION_TEXT (BCESAR4)REQUEST_MODEL ZR350LOAD_ALL_MODELS_NOW // Tip: This freezes the game, use only while faded out (which we are).                    // Otherwise use HAS_MODEL_LOADED in a while loop.GET_CHAR_COORDINATES scplayer (x y z)CREATE_CAR ZR350 (x y z) mistery1_delivery_carWARP_CHAR_INTO_CAR scplayer mistery1_delivery_carADD_BLIP_FOR_COORD (40.0 0.0 4.0) mistery1_delivery_blip DO_FADE 1000 FADE_INWHILE GET_FADING_STATUS    WAIT 0ENDWHILEPRINT_NOW (BCE5W10) 5000 1SET_PLAYER_CONTROL player ONWHILE NOT LOCATE_CHAR_ANY_MEANS_3D scplayer (40.0 0.0 4.0) (5.0 5.0 3.0) TRUE    WAIT 0    IF IS_CAR_DEAD mistery1_delivery_car        PRINT_NOW ([email protected]) 5000 1        GOTO mission_mistery1_failed    ENDIFENDWHILEGOTO mission_mistery1_passedmission_mistery1_failed:PRINT_BIG (M_FAIL) 5000 1RETURNmission_mistery1_passed:PRINT_WITH_NUMBER_BIG (M_PASSS 25000) 5000 1 // MISSION PASSED!~n~~w~$~1~~n~~w~RESPECT +ADD_SCORE player (25000)                                            // Remember the counters at the top of main.sc?REGISTER_MISSION_PASSED	(SMOKE_4)           // This builds up to the SET_TOTAL_NUMBER_OF_MISSIONS counterPLAYER_MADE_PROGRESS 1                      // This builds up to the SET_PROGRESS_TOTAL counter. AWARD_PLAYER_MISSION_RESPECT 3              // This builds up to the SET_MISSION_RESPECT_TOTAL counter.CLEAR_WANTED_LEVEL playerPLAY_MISSION_PASSED_TUNE 1flag_mistery1_passed = 1START_NEW_SCRIPT mistery2_loopRETURNmission_cleanup_mistery1:MARK_MODEL_AS_NO_LONGER_NEEDED ZR350//MARK_CAR_AS_NO_LONGER_NEEDED mistery1_delivery_car  // Not necessary, mission cleanup list does that for us!REMOVE_BLIP mistery1_delivery_blipflag_player_on_mission = 0MISSION_HAS_FINISHED // runs the mission cleanup listRETURN}// IMPORTANT NOTICE:// Don't START_NEW_SCRIPT into a label inside a mission script.// Remember, the mission scripts do not persist in memory!
main/mistery2.sc

 

// main/mistery2.scMISSION_STARTGOSUB mission_start_mistery2IF HAS_DEATHARREST_BEEN_EXECUTED     GOSUB mission_mistery2_failedENDIFGOSUB mission_cleanup_mistery2MISSION_END// One last mission, let's see a feature introduced in GTASA: SKIP_CUTSCENE.{mission_start_mistery2:flag_player_on_mission = 1REGISTER_MISSION_GIVENWAIT 0SCRIPT_NAME mister2SWITCH_WIDESCREEN TRUE// Everthing enclosed in a SKIP_CUTSCENE_START...SKIP_CUTSCENE_END may be skipped if the player// presses the skip key (usually ENTER). This makes it easy to work with cutscenes.SKIP_CUTSCENE_START    SET_FIXED_CAMERA_POSITION (0.0 -10.0 20.0) (0.0 0.0 0.0)    POINT_CAMERA_AT_CHAR scplayer FIXED JUMP_CUT    DO_FADE 1000 FADE_IN    WHILE GET_FADING_STATUS        WAIT 0    ENDWHILE    PRINT_NOW (GYMHELP) 10000 1    WAIT 5000    SET_FIXED_CAMERA_POSITION (10.0 0.0 20.0) (0.0 0.0 0.0)    POINT_CAMERA_AT_CHAR scplayer FIXED JUMP_CUT    PRINT_NOW (AMUHLP) 10000 1    WAIT 5000    SET_FIXED_CAMERA_POSITION (0.0 20.0 20.0) (0.0 0.0 0.0)    POINT_CAMERA_AT_CHAR scplayer FIXED JUMP_CUT    PRINT_NOW (BURG_10) 10000 1    WAIT 5000SKIP_CUTSCENE_ENDCLEAR_PRINTSDO_FADE 500 FADE_OUTWHILE GET_FADING_STATUS    WAIT 0ENDWHILESWITCH_WIDESCREEN FALSERESTORE_CAMERA_JUMPCUTDO_FADE 500 FADE_INWHILE GET_FADING_STATUS    WAIT 0ENDWHILESET_PLAYER_CONTROL player ONGOTO mission_mistery2_passedmission_mistery2_failed:PRINT_BIG (M_FAIL) 5000 1RETURNmission_mistery2_passed:PRINT_WITH_NUMBER_BIG (M_PASSS 100000) 5000 1ADD_SCORE player (100000)REGISTER_MISSION_PASSED	(BCES4_2)PLAYER_MADE_PROGRESS 1AWARD_PLAYER_MISSION_RESPECT 10CLEAR_WANTED_LEVEL playerPLAY_MISSION_PASSED_TUNE 2REMOVE_BLIP mistery_blipflag_mistery2_passed = 1RETURNmission_cleanup_mistery2:flag_player_on_mission = 0MISSION_HAS_FINISHEDRETURN}
main/streams/carmod1.sc

 

// main/stream/carmod1.sc//----------------------------// Streamed scripts are enclosed by the SCRIPT_START...SCRIPT_END directive.// A scope must appear right after it as well.SCRIPT_START{// Now we would code the tunning garage script, which is very complicated,// so let's just imagine it's here }SCRIPT_END
main/streams/food_vendor.sc

 

// main/stream/food_vendor.sc//----------------------------------// For the good of the nation the food vendor script from the original multifile has been decompiled// and improved a bit, there's nothing very special to learn here except for the fact the triggerer// is passed to the first local variable of the streamed script.//----------------------------------SCRIPT_START{LVAR_INT prop_cart      // The object which triggered this script is passed to the first variable.LVAR_INT script_stateLVAR_INT vendorLVAR_INT next_state_timeLVAR_INT game_timer temp_healthLVAR_FLOAT temp_x temp_y temp_z temp_headingLVAR_FLOAT area_lower_x area_lower_y area_lower_zLVAR_FLOAT area_upper_x area_upper_y area_upper_zSCRIPT_NAME fodvendscript_state = 0IF script_state = 1    CREATE_OBJECT_NO_OFFSET ICESCART_PROP 0.0 0.0 0.0 prop_cartENDIFfood_vendor_loop:WAIT 0GET_GAME_TIMER game_timerIF DOES_OBJECT_EXIST prop_cart    IF IS_OBJECT_WITHIN_BRAIN_ACTIVATION_RANGE prop_cart        IF IS_PLAYER_PLAYING player            IF NOT HAS_OBJECT_BEEN_UPROOTED prop_cart                IF script_state = 0 // still needs to create vendor                    GET_OFFSET_FROM_OBJECT_IN_WORLD_COORDS prop_cart -1.0 0.0 -1.0 temp_x temp_y temp_z                    area_lower_x = temp_x - 0.5                    area_lower_y = temp_y - 0.5                    area_lower_z = temp_z                    area_upper_x = temp_x + 0.5                    area_upper_y = temp_y + 0.5                    area_upper_z = temp_z + 2.0                    IF NOT IS_AREA_OCCUPIED (area_lower_x area_lower_y area_lower_z) (area_upper_x area_upper_y area_upper_z) FALSE FALSE TRUE FALSE FALSE                        IF NOT IS_POINT_ON_SCREEN temp_x temp_y temp_z 1.0                            REQUEST_MODEL BMOCHIL                            IF HAS_MODEL_LOADED BMOCHIL                                CREATE_CHAR (PEDTYPE_CIVMALE BMOCHIL) (temp_x temp_y temp_z) vendor                                GET_OFFSET_FROM_OBJECT_IN_WORLD_COORDS prop_cart (1.0 0.0 0.0) (area_lower_x area_lower_y area_lower_z)                                area_lower_x = area_lower_x - temp_x                                area_lower_y = area_lower_y - temp_y                                GET_HEADING_FROM_VECTOR_2D (area_lower_x area_lower_y) temp_heading                                SET_CHAR_HEADING vendor temp_heading                                ++script_state                            ENDIF                        ENDIF                    ELSE                        GOTO terminate_vendor_script                    ENDIF                ENDIF                IF script_state = 1 // may buy food                    IF LOCATE_CHAR_ON_FOOT_OBJECT_2D scplayer prop_cart 8.0 8.0 FALSE                        REQUEST_ANIMATION VENDING                        IF HAS_ANIMATION_LOADED VENDING                            IF IS_SCORE_GREATER player 0                                GET_OFFSET_FROM_OBJECT_IN_WORLD_COORDS prop_cart (1.0 0.0 0.0) (temp_x temp_y temp_z)                                IF LOCATE_CHAR_ON_FOOT_3D scplayer (temp_x temp_y temp_z) (0.6 0.6 1.0) TRUE                                    GET_CHAR_HEALTH scplayer temp_health                                    temp_health += 50                                    SET_CHAR_HEALTH scplayer temp_health                                    TASK_PLAY_ANIM_SECONDARY scplayer VEND_EAT1_P VENDING 4.0 FALSE FALSE FALSE FALSE -1                                    INCREMENT_INT_STAT 245 10                                    next_state_time = game_timer + 3000                                    ADD_SCORE player -1                                    ++script_state                                ENDIF                            ENDIF                        ENDIF                    ENDIF                ENDIF                IF script_state = 2 // waiting for animation to end                    IF game_timer > next_state_time                        next_state_time = game_timer + 27000                        ++script_state                    ENDIF                ENDIF                IF script_state = 3 // waiting for next buy time and player get out of cart activation sphere                    IF game_timer > next_state_time                        GET_OFFSET_FROM_OBJECT_IN_WORLD_COORDS prop_cart 1.0 0.0 0.0 temp_x temp_y temp_z                        IF NOT LOCATE_CHAR_ON_FOOT_3D scplayer temp_x temp_y temp_z 0.6 0.6 1.0 FALSE                            script_state = 1                        ENDIF                    ENDIF                ENDIF            ELSE // HAS_OBJECT_BEEN_UPROOTED                IF script_state > 0                    IF IS_PLAYER_PLAYING player                        IF NOT IS_CHAR_DEAD vendor                            TASK_KILL_CHAR_ON_FOOT_TIMED vendor scplayer 10000                        ENDIF                    ENDIF                ENDIF                GOTO terminate_vendor_script            ENDIF        ELSE            GOSUB mark_vendor_as_no_longer_needed            MARK_MODEL_AS_NO_LONGER_NEEDED BMOCHIL        ENDIF    ELSE        GOTO terminate_vendor_script    ENDIFELSE    GOTO terminate_vendor_scriptENDIFGOTO food_vendor_loopterminate_vendor_script:    GOSUB mark_vendor_as_no_longer_needed    MARK_MODEL_AS_NO_LONGER_NEEDED BMOCHILTERMINATE_THIS_SCRIPTmark_vendor_as_no_longer_needed:    IF script_state > 0        MARK_CHAR_AS_NO_LONGER_NEEDED vendor        REMOVE_ANIMATION VENDING        script_state = 0    ENDIFRETURN}SCRIPT_END
Edited by LINK/2012

Share this post


Link to post
Share on other sites
LINK/2012

Custom Scripts

move_around.sc

 

// So, all we've learnt so far is everything Rockstar North's language offers.//// But, as curious as we modders are, we discovered ways to inject custom scripts into the game,// and even further, add more script commands.//// This is what we call custom scripts (or cleo scripts). Those scripts are independent of// the multifile and are run when they are put in the CLEO directory (http://cleo.li/).//// Most CLEO additions are useful commands, which you can learn by yourself (if you didn't already).// But, some of these additions requires languages semantics, and that's what we'll focus on here.////----------------------------------------------------------//// Custom scripts are enclosed by SCRIPT_START and SCRIPT_END, much like streamed scripts.SCRIPT_START{LVAR_INT scplayerLVAR_FLOAT player_x player_y player_z// Tip: The player reference which CREATE_PLAYER gives (see multifile guide) is simply// the player index, which is always 0 since there's no two-player mode on PC.GET_PLAYER_CHAR 0 scplayermain_loop:WAIT 0IF IS_PLAYER_PLAYING 0    GET_CHAR_COORDINATES scplayer player_x player_y player_z    // CLEO_CALL calls a label procedure. This is similar to functions in any other language.    // Unlike GOSUB, this truly creates a new local variable scope, and can receive and output values.    CLEO_CALL get_random_coords 0 (player_x player_y player_z 50.0) (player_x player_y player_z)    //                          ^ This parameter should always be 0.    //                            This was previously the amount of input variables, but now we employ    //                            automatic detection of this value, much like progress counters in multifiles.    SET_CHAR_COORDINATES scplayer (player_x player_y -100.0)    // Most CLEO commands needs to accept string literals, which GTA3script do not have*,    // as such, when CLEO support is enabled, you are given the power to use string literals within    // strings and text label parameters. Unlike the *SAVE_STRING_TO_DEBUG_FILE literal, the string literals    // in CLEO commands are compiled as-is, with no case conversion whatsover.    //    // I don't recommend using string literals in any other command other than CLEO commands.    //    PRINT_FORMATTED_NOW "Your current coordinate is %f %f %f" 5000 (player_x player_y player_z)    WAIT 200ENDIFGOTO main_loop }SCRIPT_END{// So this is the body of a CLEO procedure.get_random_coords:LVAR_FLOAT x y z radius     // The inputs will be passed to those variables,                            // pretty much like with multifile's START_NEW_SCRIPT.LVAR_FLOAT lower_x lower_y lower_zLVAR_FLOAT upper_x upper_y upper_zlower_x = x - radiuslower_y = y - radiuslower_z = z - radiusupper_x = x + radiusupper_y = y + radiusupper_z = z + radiusGENERATE_RANDOM_FLOAT_IN_RANGE (lower_x upper_x) xGENERATE_RANDOM_FLOAT_IN_RANGE (lower_y upper_y) yGENERATE_RANDOM_FLOAT_IN_RANGE (lower_z upper_z) zCLEO_RETURN 0 x y z // and those are going to be the outputs of the procedure.//          ^ should always be 0, for the same reason as explained in CLEO_CALL.}{// I couldn't find any use for conditional procedures on this sample, but let's explain those anyway:is_x_equal_to_y:LVAR_INT x yIF x = y    IS_PC_VERSION       // gives trueELSE    IS_AUSTRALIAN_GAME  // gives falseENDIFCLEO_RETURN 0//// This procedure can then be used like// IF CLEO_CALL is_x_equal_to_y 0 x y //     NOP// ENDIF//// **Note 1:** You cannot put the CLEO_CALL in a AND/OR context, it doesn't accumulate the boolean results properly.// **Note 2:** You also cannot use NOT CLEO_CALL to negate the its boolean result.}// Hexadecimal integer literals aren't present in the original language and were introduced// because of CLEO:WRITE_MEMORY 0xDEADC0DE 0 0 FALSE// We also introduced DUMP...ENDDUMP, which is the equivalent of Sanny Builder's HEX...END.DUMP    00 FF 00 7FENDDUMP// Another addition was REQUIRE. This is very much like LAUNCH_MISSION or GOSUB_FILE:// It includes a new script file into the compilation process. But unlike the former commands,// this does not spawn a cooperative script.REQUIRE example.sc// Final Note:// To kill a custom script you shall use TERMINATE_THIS_CUSTOM_SCRIPT and TERMINATE_ALL_CUSTOM_SCRIPTS_WITH_THIS_NAME// instead of TERMINATE_THIS_SCRIPT and TERMINATE_ALL_SCRIPTS_WITH_THIS_NAME.
move_around/example.sc

 

// move_around/example.sc// Whatever you want to code here.// Usually you'd fill those required files with procedures.
Edited by LINK/2012

Share this post


Link to post
Share on other sites
_Israel_

Awesome !

Share this post


Link to post
Share on other sites
Junior_Djjr

Please guys, start creating your mods using this. This can't go unnoticed. :)

Share this post


Link to post
Share on other sites
fastman92

It might be too late.
There must be a really good reason, why someone would use this instead of Sanny Builder.

When Sanny Builder already the job just fine.

 

Also, I've got a question.

How can I access the variables like:

[email protected]([email protected],30i)

[email protected]([email protected],30i)

[email protected]([email protected],30i)

[email protected]([email protected],30i)

[email protected]([email protected],30i)

[email protected]([email protected],30i)

[email protected]([email protected],30i)

[email protected]([email protected],30i)

 

[email protected] is correctly set up to point into script memory.

.....

Which is what I'm doing in my complicated scripts.

Edited by fastman92

Share this post


Link to post
Share on other sites
LINK/2012
You cannot, the correct approach is to relax the local variable limitation in the script engine which we'll be working on in the future. This is more or less a high-level language, as such this kind of trickery does not fit. Edited by LINK/2012

Share this post


Link to post
Share on other sites
thehambone

Fantastic! Great work! :)

Share this post


Link to post
Share on other sites
Silent

There must be a really good reason, why someone would use this instead of Sanny Builder.

When Sanny Builder already the job just fine.

sannylang is joke of a scripting language compared to gta3script though*.

 

*Not meant to be disrespectful, we all realize sannylang is mirroring what we knew about SCM back in the day so naturally it's nothing close to real gta3script

Share this post


Link to post
Share on other sites
goodidea82

It should be mentioned in big letters that after a "wait" statement, the existence and the state of every used object must be checked and that any global variable may have been modified and must be checked. In particular one should take care when calling subroutines which have "wait" statements inside, because one does not see the "wait" statement when calling the subroutine. There are hundreds of cleo scripts which do not follow this rule and then cause random crashes of the game.

Share this post


Link to post
Share on other sites
Junior_Djjr

There are hundreds of cleo scripts which do not follow this rule and then cause random crashes of the game.

Hundreds? You were kind :)

This is really a common problem.

 

Maybe just a note "After WAIT the game was processed, and all used global vars and objects must be checked (e.g. If your object still exists or was deleted by game etc)"

Share this post


Link to post
Share on other sites
Silent

Entities you create yourself will not be deleted by the game though unless you explicitly allow it to.

Share this post


Link to post
Share on other sites
Junior_Djjr

Entities you create yourself will not be deleted by the game though unless you explicitly allow it to.

Yep, because of this we used the word "used" and not "created".

 

For example, when you pick up some entity from world it can be deleted at any time and beginners never think about it; or think, but these guys use a lot of unnecessary WAIT at any time, and such entities ends up being deleted by the game, so crashes when you try to use it again.

 

This is actually very common, even Active Dashboard / Steering there was this error in the penultimate version.

 

Another common mistake is to mark the vehicle / ped as "no longer necessary", unnecessarily, so doing missions failed or even crashes too (related to the above problem). But this is a learning problem by looking at poor third party codes ("Oh, he used it, I think I should use it too!").

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×

Important Information

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