Dutchy3010 Posted March 21, 2009 Share Posted March 21, 2009 (edited) Mission Coding for Dummies! Lots of people want to learn coding, but when they see the code, they give up. This is a big tutorial that will walk through the basic options of SCM-coding. I can promise that you are able to create a simple mission when you worked through this tutorial. The best way to learn it with this tutorial, is to try every complete script, so you will see what happens ingame. This way you will learn it faster and better, because you can visualize it in your mind. The difference between this tutorial and most others, is that this tutorial is written from another point of view. It contains (at this moment) 12 short tutorials, which you can follow separately. In every tutorial, you will learn another aspect of coding. The first 3 tutorials aren't about things ingame, it is about coding itself and about the structures. You have to learn it first, but this won't be as pleasant as the tutorials that follow. Then you will learn things like creating actors and cars, the basics of a mission. Almost every tutorial will end with a stripped file and the code, so that you can use it in SannyBuilder to see what you did learn. You can also use this as a base for your own experiments to see what other opcodes do. We will use SannyBuilder, because learning to code is easier with this tool. For these tutorials you need: SannyBuilder (Download) A "stripped" code (SannyBuilder folder > Data > SA > Stripped) Grand Theft Auto: San Andreas Ped Editor (Download) San Andreas Place Manager (Download) Content:Introduction Before you begin Basics of coding (coding structures) Actors Give weapons (and other properties) to actors Cars Spheres, icons and markers A simple mission A mission Rockstar Style Status bar Menus MPACKs Actor animations and Animation paths Pickups Texts Custom Save Point Cutscenes Links: Reactiontopic - for all responses to this tutorial. Mission Coding for Pro's SCM Coding FAQ Mission Coding subforum CLEO Script Tutorial Coding Bible Part I Coding Bible Part II Please do not post in this topic (so I can extend it later)! Thanks to PatrickW for his help! Edited June 15, 2009 by Dutchy3010 maoffense01, RyanDri3957V, Louaie575 and 9 others 12 DYOM - Create, play, share! Link to comment Share on other sites More sharing options...
Dutchy3010 Posted March 21, 2009 Author Share Posted March 21, 2009 (edited) Introduction Content: Introduction What do I need? The programs SCM CodingStructures most important! Coding CLEOIntroduction to CLEO Finally IntroductionThis tutorial is only for people who want to learn coding. When you want to learn coding, where do you have to start? You can't see the wood for the trees. In this tutorial, I will help you with these first steps. Steps which most people think are to difficult, so they quit. Everyone who puts effort in it, can learn coding! But don't think: I want to learn coding, so tomorrow I will make my first mission. This is of course not the proper way to do it. Learning to code takes time, just like when you want to learn to use other programs, like Photoshop or 3dsmax. What do I need? Some people wonders what is needed to code: A program to edit main.scm A GXT editor (SA GXT Editor) San Andreas Place Manager (not for coords, but for teleport) Map Editor Ped Editor Time/Effort Programs Function MissionBuilder SannyBuilder Notepad Editing yes yes yes (when already decompiled) Compile yes yes no Decompile yes yes no Updates no yes no Extras Little Yes No Creator Barton Waterduck Seemann Microsoft Download Klik Klik - Extra's in SannyBuilder mean things such as: CLEO3, Built-in coords-tool, opcode search tool, lot of hot-keys, colored texts, etcetera. I advise everybody who starts learning to code, to use SannyBuilder. SCM Coding Structures most important! Of course everybody wants to write code immediately, making missions or other things. I will advise against this, because when you first learn the structures of SCM-coding, it will be easier to script afterwards. You can compare this to school: first you have to learn things (which is less pleasant) so you will get a better job in the future. This is the reason why we will start with structures after the two introduction tutorials. Coding After learning the structures, you shouldn't try to make a total mission yet. A better start is to spawn some pickups. Then you can try to spawn a car or an actor, which we will explain in further tutorials. So you will learn inch by inch to make a small mission, which we also will do in further tutorials. So, if you want to learn to make a small mission, you have to follow all of these tutorials and you will learn it. After you made a small mission, you can extend it, bit by bit, so you will learn more advanced coding. CLEO CLEO is an extension to SCM scripting. It mainly adds two things: CLEO-scripts and new opcodes. I advise to start with SCM first. When you can code SCM, you can also wrote code with CLEO. The other way round it is more difficult, because of some structures within SCM, which you don't have in CLEO. But what are the advantages of CLEO?. With a CLEO-scripts you don't have start new game, which is very handy for most of the small mods. There are also some great opcodes added. You can also use the new opcodes in your SCM mods, but users of your mod will than also need to have CLEO installed. You can find all the differences between CLEO and SCM in the SannyBuilder help files: Help > Contents > CLEO 3 Library. Finally.. When you have questions, you can always ask it in the Coding Help Forum, and you will get an answer as fast and as good as possible! Good luck in the following tutorials! Edited March 21, 2009 by Dutchy3010 Mann56, Pranjit Das, st_4rb00y and 4 others 7 DYOM - Create, play, share! Link to comment Share on other sites More sharing options...
Dutchy3010 Posted March 21, 2009 Author Share Posted March 21, 2009 (edited) Before you begin Decompile What is it? Before you can edit the main.scm file, you first have to decompile. This means that it will become humanly readable, you transform the extension from .scm to .txt. You can do this in programs as MisionBuilder and SannyBuilder, but not in notepad. Once you have the txt file, you can also open it in notepad or any other text editor. This isn't very handy, because there aren't any extras in notepad (which makes it a lot more difficult). How to decompile Because these tutorials are about SannyBuilder, I will explain it for SannyBilder. Press F5, or the icon "Decompile" or "run" > "Decompile". Go to the folder: Program Files > GTA San Andreas > Data > Script and select "main" (a .scm file). Open it. When you are doing it for the first time, you will get a screen like below. Select the folder "GTA San Andreas". Then you have to do the previous step again. Now you will get the text, which you can edit. When you save it, you will get a txt file. Compile What is it? This is the opposite of decompile. When you want to test your code, you have to transform it back to the language which GTA SA can read. So you have to make it a .scm again. You can do it by pressing F6, press the icon of "compile" or by "Run" > "compile". What is the difference between compile and compile + copy? You can choose to save your txt file is at another folder on your pc than the original Data folder. Compile means that the SCM file will be created in the folder where your .txt file is saved. Compile + Copy means that the SCM file is copied into the Data folder after compilation. So the main.scm in the data folder will be replaced. There is no difference when you are editing the main.txt that is located in the "data" folder itself. SannyBuilder Colours In SannyBuilder are some words marked: Black: these are often used commands, like jump, wait, create_thread, fade, repeat, jf, etcetera. You don't have to put the code before it. Green: these are labels, for example ":label" or "@label". Blue: the variables have a blue colour. Red: names of for example objects, texts and threads are red. Yellow and blue: Yellow is the "object", the blue is what is said about the object. It is difficult to explain, but when you look at it, I'm sure you will understand it. Brown: names of the models. Blue/Grey (light): this are comments, they are not read by the game and are handy as a note. They are proceeded with //. FunctionsThere are a few functions in SannyBuilder, which are very handy to use. Of course there are more functions, but these are the most important ones. Coords manager. You can find it in Tools > Ide Tools > Coords Manager (hot key: CTRL+ALT+1). You can find the X, Y and Z coordinate of the place where you are in San Andreas. You can also find your angle. You can't use this when SA isn't running of course. Opcode search. You can find it: Tools > Ide Tools > Opcode Search (hot key: CTRL+ALT+2). With this tool you can find opcodes very easily. F1 key: when you typ a little part of a command, sannybuilder will try to find a command as it was used in the original main.scm. SCM documentation. You can find it under the help-menu (hot key: F12). You will find a usefull database. You can find here for example the icon-numbers. Start SA: you can start SA by pressing F8 or the icon "Run San Andreas". Missionbuilder > Sannybuilder converter: it doesn't work perfect, but you can find it under Tools-menu > Code Converter > MB -> SB. Edited March 21, 2009 by Dutchy3010 maoffense01, Mann56 and Kubrickian 3 DYOM - Create, play, share! Link to comment Share on other sites More sharing options...
Dutchy3010 Posted March 21, 2009 Author Share Posted March 21, 2009 (edited) Coding Structures Threads The main.scm file is processed by multiple threads.This might be one of the most difficult concepts to grasp for someone not familiar with multi-threading programming. So don't despair if you don't get it right away, you're not alone. Up till now, we described the code as being executed opcode after opcode, sometimes jumping to a different location and continuing. Imagine this process being executed by a little guy inside your computer. He spends all day reading an opcode, executing it, determining the next opcode to execute, read it and execute it, day-in day-out. Lets call this little guy "thread". Now image that this guys has a brother, who does exactly the same thing. Off course they're not looking at the same opcodes at the same time, his brother is working on another part of the code. Both are working independently of each other, reading opcodes, executing them, determining next opcode, ... Can you image that ?? Now image that there's a whole family of those little guys, all doing the same thing on different parts of the code. ~~~~~Welcome to the world of multi-threading. ~~~~ Now how do we manage these threads ? At the beginning there's only one thread that starts to execute at the beginning of the main.scm file, called the main-thread. Through a serie of jump's it will skip the first three sections and arrive at the beginning of the code-section. There it will perform some initialisation, until it encounters a series of "create_thread" opcodes. That opcode creates a new "little guy" (thread) that starts executing opcodes below the given label. In this way, the main-thread creates a whole army of threads, each working on a specific part of the code, to perform a dedicated task. Some of the threads live indefinitely, just looping around the same code. Other threads only have to perform a single task once and kill them self upon encountering an "end_thread" opcode. A thread can also kill another thread, by supplying name of its victim as a parameter to the end_thread opcode. Threads are given a name, when they execute a "name_thread" opcode, which is normally one of the first opcodes they encounter. Create_thread may be executed from both the MAIN part as well as the MISSIONS part. The code that the thread will execute however, must be located in the MAIN part. Missions are also executed as threads, but they are started with "start mission". This will create a special kind of thread oif which only one can exist at the same time. Furthermore, during this thread the engine continually checks whether the player is busted or wasted. In that case the "little guy" is instructed to perform a "return" opcode, which causes him to jump back to the last "gosub". This is why missions should have a special structure, in which this will lead to a failed mission. This structure will be described in one of the tutorials to come. Labels/jump/gosub Labels are marked with a ":". These are names that are assigned to some locations in the code. It is used jump to a location in your code. You can do this with "gosub" and "jump". :MAIN_405901B7: release_weather jump @MAIN_4075 You can see a label, named "MAIN_4059". Then you can see a command, with a code (01B7) called opcode. In the third line you can see another command: "jump". With the "@..." after that you indicate where the code has to jump to. So you are jumping to ":MAIN_4075". Gosub works different, it also jumps to another label, but it goes back to the location just after the "gosub" when he reaches a "return"-command. For example: :MS_GAME_BEEFYBARON$ONMISSION = 1 // integer values 00BA: text_styled 'BEEFY' 1000 ms 2 // Beefy Barongosub @SUB_FADE_500MS start_mission 10 // Beefy Baronjump @END_CASE_VIDEO_GAME :SUB_FADE_500MS0169: set_fade_color 0 0 0 fade 0 500 :LITCAS_282if fading else_jump @LITCAS_306 wait 0 jump @LITCAS_282 :LITCAS_306Return So it jumps with a "gosub" to ":SUB_FADE_500MS". When it reaches the "return" command (under ":LITCAS_306"), it goes back to the gosub. After the return, the code will continue with "start_mission 10"). Gosub is used when you want to use a piece of code from multiple places in your code. Conditional jump When you use a "Conditional jump", the code will do or not do the jump depending on some condition. You can use three notations for this, which all have the same result: “else_jump @boe” “jf @boe” “004D: jump_if_false @boe” :SWEET4_103if Model.Available(#GREENWOO)else_jump @SWEET4_152 In this example we check if the model is available (the model of the Greenwood, in this case). When this isn't true, it jumps to label ":SWEET4_152". When this is true, the code goes further. With the conditional jump, you can make a loop. Then the code waits until the condition is true. Be Aware! You have to put a wait in every loop! When you forget it, the game will crash, and, when you don't run SA in a window, you even can't go back to your desktop. The only solution is to restart your PC. So, my advise is to run SA in a window when testing your new code! An example of a loop is: :SWEET4_103Wait 0 msif Model.Available(#GREENWOO)else_jump @SWEET4_103 As you can see, the code stays in this loop, until the model is available. If-then-end structure There are other structures which you can use to check conditions. For example the if-then-end structure. For example: if $choice == 0then$money = 10End When the variable $choice equal is to 0, then the variable $money will become 10. If $choice isn't equal to 0, nothing will happen. You have to put an "end" to indicate where the code should continue when the condition is not true. You can add more things between "then" and "end" that will only be executed when the condition is true. Repeat-wait-until structure repeat wait 0 msuntil 03D0: wav 3 loaded This is an example of a repeat-wait-until structure. This is a loop, so there has to be a wait in it. This code means: do everything between repeat and until, until the condition is true. Between repeat and until there can be also other things, that will be executed over and over again until the condition is true. Instead of using repeat-wait-until, you can also write it as a conditional jump (this will behave exactly the same!): :labelwait 0 msif03D0: wav 3 loadedelse_jump @label Numbers There are two kinds of numbers: Integer values: 1 2 3 Floating-point values: 1.5345 3.4 Floating-point values will be used as coordinates, angles or things like speed. Integer values are used for most other things. The advantage of Integer values, is that computer can easy calculate with these. These numbers are for example used for waiting periods. The Integer Values and Floating-Point values can't be mixed up, because then the code won't work. 0004: $abc = 5000;; integer values0084: $def = $abc;; integer values and handles The difference is that the first a assigns a value to a global variable. In this case 5000 to global variable $abc. Then you say, that $def has to get the same value as $abc. So this code means: $def = $abc = 5000 (But you may not use this in the main.scm, there you have to split it up) Variables There are two kinds of variables: global and local. Global variables are indicated with a $ (for example: $abc), local are indicated with a @ at the end (for example: [email protected]). Local variable-names only consists of numbers, a global variable has to consist of characters and digts. When a Global Variable only consists of numbers, it will be handles differently by the compiler. This can lead to unexpected results, so you shoudl make sure that your variablenambles contain at least one character. The difference between local and global variable is that you use a global through the whole script. A local variable is applies only within one thread. When you assign a value to [email protected], and you want to use that number in another thread again, it won't be avaiable, you have to assign it that value again. The value of the other thread doesn't apply any more. Calculate with variables Sometimes you have to calculate with variable. There are some opcodes for this. Caution: there are different opcodes for integer-values and floating-point-values, and there are different opcodes for global or local variables. You can add, subtract, multiply and divide. Some examples: 0008: $variable += 1 000A: [email protected] += 3000 000B: [email protected] += 0.1 0009: $variable += 1.741 0058: $variable += $variable23 // (int) Beware not to confuse these two opcodes: 0038: $variable == 1 With this opcode, you will check if $672 is equal to 1. 0004: $var = 0 With this opcode you will set the global variable $var to 1. Edited March 25, 2009 by Dutchy3010 maoffense01, Sweet Bellic, Kubrickian and 1 other 4 DYOM - Create, play, share! Link to comment Share on other sites More sharing options...
Dutchy3010 Posted March 21, 2009 Author Share Posted March 21, 2009 Actors There are 2 types of actors: 'normal' actors and 'special' actors. The normal actors are easier to make, because they have to be loaded just like normal models (like weapons). The special actors are a bit more difficult, but I will explain it later. We will begin with a "stripped" code, that is a code which is clean. The only thing you can do, is walk/drive around. It is perfect for a new mod. An actor is a character in the game, like Sweet, but also random pedestrians. First we are going to spawn a normal actor. You have to do it in three steps: - Load actor models (and check if it is loaded) - Spawn actors - Unload models Load actor models (and check if it is loaded): // Load models0247: load_model #BFYST038B: load_requested_models I think this part of the code speaks for itself, but I will explain it shortly. When you typ //, it is a comment, like it was told in previous tutorials. This is only a note for the coder. In the line "load_model", you have to say which model you want to use. If you are looking for a specific ped, you can find the name by using the ped editor. I chose for BFYST, but there are also other possibilities. You have to write the third line because then the previous models will actually be loaded. Then you have to check if the model is loaded: :MODEL_LOADwait 0 msif 8248: not model #BFYST available else_jump @MODEL_SPAWN jump @MODEL_LOAD :MODEL_SPAWN You have to make a new label, because you are creating a loop. Then you know where you can jump to. It doesn't matter which name you give to the label, I called it "MODEL_LOAD". I advise you to give it a clear name, because it is easier to find it when you have a big mod. When you followed the previous tutorials, you know what the jump-if-false (or else_jump) structure is. This is a example of its usage. If the model " BFYST" isn't available, then jump to MODEL_LOAD. If it is available, jump to :MODEL_SPAWN. The following code is the same: :MODEL_LOADwait 0 msif0248: model [email protected] available else_jump @MODEL_LOAD Spawn Actor :[email protected] = Actor.Create(CIVFEMALE, #BFYST, 0.0, 0.0, 0.0)Actor.Angle([email protected]) = 318.9705 The [email protected] is a local variable, it doesn't matter which number you are using. It has to be under the 32, because that is the maximum within a thread (when you are using an "official" mission structure, it can be more then 33). Then we are going to assign the variable a value, in this case an actor. So we give the actor, in this case, the name "[email protected]". Actor.Create is the command, I think it speaks for itself. After that, you will see 5 parameters. First the type of the ped, CIVFEMALE. Then the model name and after that there are 3 coords: x, y and z. Like I already told in previous tutorials, there is a built-in coords tool in SannyBuilder, you can use that to determine coordinates like these. The Actor Angle is the direction of the ped. 0.0 is to the west. So if you want him to stand to the east, you have to give it an angle of 180.0. You can also use the coords tool for this. Model unload Finally you have to unload the model: 0249: release_model #BFYST Caution! Release_model doesn't mean that he actor will disappear! Just like loading the actor doesn't mean that you spawn the actor. You have to use another opcode to delete the actor (e.g. 009B: destroy_actor [email protected]) So the complete code for an actor spawn is: // Load models0247: load_model #BFYST038B: load_requested_models:MODEL_LOAD00D6: if 8248: not model #BFYST available 004D: jump_if_false @MODEL_SPAWN 0001: wait 0 ms 0002: jump @MODEL_LOAD :[email protected] = Actor.Create(CIVFEMALE, #BFYST, 0.0, 0.0, 0.0)//Here you do what you want to do with the actor.0249: release_model #BFYST With the Ped Editor you can find your ped-model, you will also get a view of the ped (how he looks ingame). You will see the name of the ped and the group/type. So for making an actor spawn, you need SannyBuilder (to edit the file), coords tool (in SannyBuilder) and Ped Editor to look up the names of the actor-models. Special Actors Special Actors are a bit more difficult. You have 10 "slots" for special actors models. You can compare this to the 8 slots in which you can save you savegame: you can only have 8 at one time, and if you want another savegame, you have to delete one first. To see a list of all special actors, you can look in the helpfile: Help > Contents > SCM Documentation > GTA SA > Special Actors. When you understand the normal actors, you can also understand special actors. It looks a similar, but with slightly different code. Again, you have to load the model, check if the model is available, spawn the actor and unload the model. Loading the model We take Catalina for example. You will see, when you look to the SCM Documentation, that she has the name 'CAT'. First we are going to load the model: // Load models023C: load_special_actor 'CAT' as 1 // models 290-299038B: load_requested_models So in this code, you load special actor Catalina (CAT), at slot 1. Next to this one, you can load upto 9 others. Check if it is loaded: :MODEL_LOADif823D: not special_actor 1 loaded else_jump @MODEL_SPAWN wait 0 ms jump @MODEL_LOAD :MODEL_SPAWN This is almost the same as the "normal" actor. Only the second line is a different, the structure is the same: when the model of the special actor isn't loaded, jump to the label MODEL_LOAD. If it is loaded, jump to MODEL_SPAWN. The 1 is in this case the number of the slot, in which you loaded it. Spawning the actor :MODEL_SPAWN009A: [email protected] = create_actor_pedtype CIVFEMALE model #SPECIAL01 at 0.0 0.0 0.00173: set_actor #SPECIAL01 Z_angle_to 0.0 It is exactly the same as for 'normal' actors, except that the models are named #SPECIALxx. XX depends on which slot you used. In this case, it is 01, because it was slot 1. If it was slot 2, you have to use: #SPECIAL02. CIVFEMALE is the pedtype, the angle is just like normal actors. Unload the actor Finally you have to unload it: 0296: unload_special_actor 1 So we unload the model of the special actor, which is in slot 1. The whole code to spawn a special actor: // Load models023C: load_special_actor 'CAT' as 1 // models 290-299038B: load_requested_models :MODEL_LOAD00D6: if or 823D: not special_actor 1 loaded 004D: jump_if_false @MODEL_SPAWN 0001: wait 0 ms 0002: jump @MODEL_LOAD :MODEL_SPAWN009A: [email protected] = create_actor_pedtype CIVMALE model #SPECIAL01 at 0.0 0.0 0.00173: set_actor [email protected] Z_angle_to 0.0//Here you do what you want to do with the actor.0296: unload_special_actor 1 When you include a normal actor to a stripped file! You can let the actor do many things, like get in a car, or shoot at someone. But first you have to spawn them, then you can add other things. That is why it is essential to know this. I hope you learned something from this tutorial, and if you have any questions, just let me know! maoffense01, RyanDri3957V and Kubrickian 3 DYOM - Create, play, share! Link to comment Share on other sites More sharing options...
Dutchy3010 Posted March 21, 2009 Author Share Posted March 21, 2009 Give weapons to actors Introduction In the second part of this tutorial, we will extend the code of part 1. We will give the actor a weapon, and will set some other properties. The player itself gets a weapon too. To make it more fun, the player and the actor needs to kill each other. If you kill the actor, you will get music, a mission passed text and 25000 dollar. We will start with giving the actor a weapon. Before giving a weapon to an actor (the player is also an actor!), we first have to load the weapon-model. Just like we did in part 1 for the actors. It is exactly the same as loading the model for a "normal"-actor. This was the code for loading an "normal" actor: // Load models0247: load_model #BFYST038B: load_requested_models:MODEL_LOADwait 0 msif 8248: not model #BFYST available else_jump @MODEL_SPAWN jump @MODEL_LOAD :MODEL_SPAWN We will extend this part of the code by loading the right models of 3 weapons: the desert-eagle, the rocket-launcher and the M4. In the help-files of SannyBuilder we look up the model names and the numbers of the three weapons: Help > SCM Documentation > GTA SA > Weapon Numbers. There we find the following data: desert-eagle 24 #DESERT_EAGLE rocket-launcher 35 #ROCKETLA M4 31 #M4 We extend the code above with the model names of the weapons: // Load models0247: load_model #BFYST0247: load_model #rocketla0247: load_model #desert_eagle 0247: load_model #m4 038B: load_requested_models:MODEL_LOADwait 0 msif or 8248: not model #BFYST available 8248: not model #rocketla available 8248: not model #desert_eagle available 8248: not model #m4 available else_jump @MODEL_SPAWN jump @MODEL_LOAD :MODEL_SPAWN Now the code will stay in the loop as long as any of the model isn't loaded yet. You have to make "if" a "if or", because their is more then one condition. "if or" means that one of the conditions has to be true, "if and" means that all of the conditions have to be true. So in this case, the code waits until all 4 models are loaded. Now we are going to give the weapons. We will start with giving the player a rocket-launcher and a desert-eagle: 01B2: give_actor $PLAYER_ACTOR weapon 35 ammo 10 // Load the weapon model before using this01B2: give_actor $PLAYER_ACTOR weapon 24 ammo 30000 // Load the weapon model before using this01B9: set_actor $PLAYER_ACTOR armed_weapon_to 24 Here you will need the numbers of the weapons which we found in the help-files. We will give the player a rocketlauncher (number 35) with 10 rockets and a desert-eagle (number 24) with 30,000 bullets. The player has two weapons, but can only use one at the same time. To define which is in his hand, you have to use the "01B9" opcode. In this case the player has the desert-eagle in his hands. Now we will give an actor a weapon: 01B2: give_actor [email protected] weapon 31 ammo 30000 // Load the weapon model before using this01B9: set_actor [email protected] armed_weapon_to 31 So the actor gets a M4 (number 31) with 30,000 bullets. It will also be in his hands. Both actors (Player and other) have weapons. Now we will give the actor an assignment: kill the player. We will also set some other properties of the actor. 05E2: AS_actor [email protected] kill_actor $PLAYER_ACTOR The actor ([email protected]) has to kill the player. actor.WeaponAccuracy([email protected])= 90 The weapon accuracy of the actor is 90, so the actor will shoot more accurate then when you don't use this opcode. actor.Health([email protected]) = 2000 The actor has a lot of health, so it is more difficult to kill him. 0350: toggle_actor [email protected] maintain_position_when_attacked 1 The actor maintain his position when it's attacked. Otherwise it is possible that he runs away. Now we have to code the end of the fight. We have to check if the actor is dead: repeatwait 0 ms until actor.Dead([email protected]) Finally we have to set a sound, a text and a reward: 0394: play_music 1 01E3: show_text_1number_styled GXT 'M_PASS' number 10000 time 5000 style 1 // MISSION PASSED!~n~~w~$~1~Player.Money($PLAYER_CHAR) += 25000 The first line is for the sound, the second is for the text. This will display after the actor is dead. We will give a reward of $250000. Then we have to unload the models, just like we learned in previous tutorials: 0249: release_model #BFYST0249: release_model #rocketla0249: release_model #desert_eagle0249: release_model #m4 All together (with a stripped file) Kubrickian and RyanDri3957V 2 DYOM - Create, play, share! Link to comment Share on other sites More sharing options...
Dutchy3010 Posted March 21, 2009 Author Share Posted March 21, 2009 (edited) Cars Introduction This tutorial is about an essential part of the game: cars. There are two ways of spawning cars: cargenerators, which spawn multiple times or just cars that spawn once. I will explain both. Cars that spawn multiple times Cargenerators are more easy to spawn then cars that spawn once, because you don't have to load and unload the models of the cars. This way the permanent cars in the game are spawned. The lines for the cargenerator: 014B: $PARKED_RHINO = init_parked_car_generator #RHINO -1 -1 1 alarm 0 door_lock 0 0 10000 at 2435.302 -1671.848 12.8007 angle 90.0 014C: set_parked_car_generator $PARKED_RHINO cars_to_generate_to 101 We will analyse this code. The first line: $PARKED_RHINO: a variable to which the car is assigned. #RHINO: model name of the car that you want to spawn. First -1: first color of the car. ( -1 = random color ) Second -1: secondary color of the car. ( -1 = random color ) The 1: the police thinks that it is your car. If it's a 0, then the police knows that you stole it. Alarm 0: the chance that the alarm will sound is 0%. If you make it 50, the chance is 50%. Door_Lock 0: the door isn't locked. Make it 1 and the car is locked. At the end are the x, y and z coords, and the angle of the car. Second line:$PARKED_RHINO: the variable holding the car that the opcode is meant for. 101: the car will spawn. If you make it a 0, the car won't spawn. You have to do this line always when you are making a cargenerator! Example in the stripped file There is another variant, which you can use to give the car a numberplate: 09E2: $grove = parked_car_generator_w_numberplate #GREENWOO 59 34 0 alarm 0 door_lock 0 0 10000 plate "GROVE4L_" at 2508.4824 -1670.6813 13.3812 angle 0.0014C: set_parked_car_generator $grove cars_to_generate_to 101 The only differences are the code (09E2 instead of 014B), init_parked_car_generator instead of parked_car_generator_w_numberplate (it doesn't even matter!) and of course the "Plate...". After plate you can write what you want to have on the numberplate.(8 characters) Cars that spawn once This looks a lot like spawning an actor: //Load models0247: load_model #GREENWOO 038B: load_requested_models :MODEL_LOADif 8248: not model #GREENWOO available else_jump @MODEL_SPAWNwait 0 ms jump @MODEL_LOAD When you read the other tutorials, I think you don't need any explanation. :MODEL_SPAWN$greenwood = Car.Create(#GREENWOO, 2458.2483, -1659.0264, 13.3047)Car.Angle($greenwood)= 270.0 With this code you will spawn a Greenwood. The variable ("handle") of the car is "$greenwood". The model name is #GREENWOO (you can look it up in the vehicles.ide). After that are the x, y and z coord. The second line is angle of the vehicle. 0249: release_model #GREENWOO Of course we have to release the model. There are all kind of codes for cars that spawn only once. A few examples: 0674: set_car_model #GREENWOO numberplate "ABCDEFG" You can set a special numberplate. You have to use this opcode right before you create the car. 0119: car $greenwood wrecked You can ask if the car is wrecked, most used in a if-structure. With the $ you have to use the variable (handle) of the car. 0224: set_car $greenwood health_to 10000 When the number is higher, the car can take more damage. Of course you can vary with this. The greenwood is smoking when the number is 500. When it is 250, one small crash is enough to blow up the car (black smoke). When it is less then 250, the car explode without doing anything. 1000 is a realistic number for the car. The $greenwood is the variable of the car, defined by spawning the car. 00A6: destroy_car $greenwood With this car you can remove the car from the game. Just like with actors, a release model doesn't delete the car. For that, you have to use this opcode. Of course there are many more commands that's got to do with cars, because it is an essential part of the game. So when you want to do something with a car that isn't explained here, and that you don't know how to use it, feel free to ask! Edited March 25, 2009 by Dutchy3010 RyanDri3957V and Kubrickian 2 DYOM - Create, play, share! Link to comment Share on other sites More sharing options...
Dutchy3010 Posted March 21, 2009 Author Share Posted March 21, 2009 (edited) Spheres, icons and markers First: what are spheres, icons and markers? Icons are the graphics on the radar, markers are the arrows above the heads of the actors or cars. Spheres are the small, red rounds, which for example occur when you are starting the mission. Create a sphere/icon? You can create a icon and sphere with 1 command, you can also only create a sphere or an icon. There are icons you will see always, like mission letters, and icons which only occur when you are in the neighbourhood, like ammu-nations. I will explain all of them. Spheres 03BC: [email protected] = create_sphere_at 2488.5601 -1666.84 13.38 radius 5.0 This is the code for only a sphere. The [email protected] is the variable (handle) of the sphere, which you can use later on when you want to do something with the sphere (like destroy it). Then there are x, y and z coords. Finally there is a radius. 1.0 is small, 10.0 is big. Spheres in which you can start a mission, are about size 1.0. Icon and Sphere that are always visible 02A7: $ICON_SPHERE_CJ = create_icon_marker_and_sphere 15 at 2488.5601 -1666.84 13.38 15 is the number of the icon you want to display. You can find it in Help > Contents > SCM Documentation > GTA SA > Radar icons. Then you have the 3 coords: x, y and z. $ICON_SPHERE_CJ is the variable which you can use to delete the sphere and the marker Icon (without sphere) that is always visible 02A8: $marker03 = create_marker 23 at 658.0068 -1866.3127 4.4537 This is the code for a icon marker without sphere, so you will see it on the radar, but you won't see a red round on that place. First the handle of the marker, the 23 says which icon it has to be. You can look it up in the help files, like said above. In this case, 23 is the Loco Syndicate icon. Finally you have to add the coords. Icon and Sphere that are only visible when you are in the neighbourhood 0570: $icon_en_sphere = create_asset_radar_marker_with_icon 36 at 1837.3643 -1974.4963 12.5469 Like you can see, there are only 2 things changed. The code of the opcode (02A7 > 0570), and the command itself. But the idea is the same: 36 is the number of the icon which you can look up in the help-file list and the coords. Icon that is only visible when you are in the neighbourhood 04CE: $icon = create_icon_marker_without_sphere 12 at 2447.3643 -1974.4963 12.5469 I don't think explanation is necessary anymore, by now. Markers Markers are arrows above an object, an actor or a car. They are also marked (with a square) on the radar. There are all kind of markers. You have to use one of the following opcodes: 0187: $m1 = create_marker_above_actor [email protected] 0186: $m2 = create_marker_above_car $greenwood03DC: $m3 = create_marker_above_pickup $weapon0188: $m4 = create_marker_above_object $object The first one is to create a marker above an actor, the second one above a car, the third above a pickup and the fourth above an object. These are different opcodes! Look at the code of the opcode (like 0187), it is different than the others! The first variable is the handle/name of the marker, the second is the handle of the actor/car/pickup or object. You can do all kind of things with the marker, like make it in different colors: 0165: set_marker $m1 color_to 1 List of colors: 0= red 1= green 2= light blue 3= white 4= light yellow Destroy Finally you have to de destroy the marker/sphere/icon, so that you can't see it any more. You can use the following opcodes for that: 0164: disable_marker $m1 03BD: destroy_sphere [email protected] For example: an arrow on a Greenwood: //Load models0247: load_model #GREENWOO 038B: load_requested_models :MODEL_LOAD00D6: if 8248: not model #GREENWOO available 004D: jump_if_false @MODEL_SPAWN 0001: wait 0 ms 0002: jump @MODEL_LOAD:MODEL_SPAWN00A5: $greenwood = create_car #GREENWOO at 2458.2483 -1659.0264 13.3047 Car.Angle($greenwood)= 270.00186: $m1 = create_marker_above_car $greenwoodwait 5000 msMarker.Disable($m1)0249: release_model #GREENWOO So there spawns a Greenwood, with an arrow. After 5000 ms (5 seconds), the arrow will disappear. The full code in a stripped file When you worked through all of these tutorials sofar, you can make a short, easy mission! We will do that in the next tutorial! Edited July 7, 2009 by PatrickW Kubrickian, RyanDri3957V and simanto48 3 DYOM - Create, play, share! Link to comment Share on other sites More sharing options...
Dutchy3010 Posted March 21, 2009 Author Share Posted March 21, 2009 (edited) A simple mission Like I promised, we are going to make a simple mission. First you have to make a good plan for the mission. In our example, we will spawn a car with an arrow above it. When the player gets in the car, the arrow will disappear, and the sphere where you have to drive to will appear. The player will have a baseball bat. The car is almost wrecked, and with the slightest touch it will explode. When the player is in the sphere, there have to spawn an actor, also with a baseball bat. When he sees the player, he will attack. When the actor is killed, the mission is passed, and you will get a text and $10,000. The marker will also disappear. Of course this isn't a very difficult mission, but you can make it more amusing. For example, when you add a timelimit: you have to drive fast, but may not hit anything! Or that when you get out of the car, there will be another marker on the car. Or that mission failed is when you are dead. But we will start small, with this mission! We have an idea, so we will begin coding. Like usual, we will start with a stripped file: Click First we will load everything and check if it is loaded. The actor (enemy) doesn't have to spawn, the car does. The bat has toi be given to the player, lateron also to the actor. Loading the models and spawning the car: :MODELthread 'MODEL'//Load models0247: load_model #GREENWOO0247: load_model #bat0247: load_model #BFYST038B: load_requested_models :MODEL_LOADif or 8248: not model #GREENWOO available8248: not model #bat available8248: not model #BFYST availableelse_jump @MODEL_SPAWN wait 0 ms jump @MODEL_LOAD:MODEL_SPAWN0674: set_car_model #GREENWOO numberplate "ABCDEFGH" 00A5: $greenwood = create_car #GREENWOO at 2458.2483 -1659.0264 13.3047 Car.Angle($greenwood)= 270.00224: set_car $greenwood health_to 250 What are we missing before player has to drive? The player has to get a baseball bat and there has to be a marker above the car: 0186: $m1 = create_marker_above_car $greenwood01B2: give_actor $PLAYER_ACTOR weapon 5 ammo 10 // Load the weapon model before using this01B9: set_actor $PLAYER_ACTOR armed_weapon_to 5 NOw we have to wait for the player to enter the car. What happens next? You have to go to the marked place, where there should be a sphere. The marker of the car has to disappear. repeatwait 0until Actor.InCar($PLAYER_ACTOR, $greenwood)Marker.Disable($m1)0004: $coordinate_x = 2100.96040004: $coordinate_y = -1366.83690004: $coordinate_z = 23.9844 $coordinate = Marker.CreateIconAndSphere(0, $coordinate_x, $coordinate_y, $coordinate_z) What can happen while the player is driving to the sphere? The car can be wrecked! When the car is wrecked, there has to spawn a new car in the beginning and the player has to go back to get it. The check has to continu until the player has reached the sphere. This is perhaps a bit more complex code, but when you give it a good look, I'm sure you can make it next time by yourself! :MODEL_WRECKEDwait 0 ms if 0119: car $greenwood wrecked else_jump @MODEL_END jump @MODEL_SPAWN:MODEL_ENDwait 0 msif01AE: car $greenwood sphere 0 near_point $coordinate_x $coordinate_y radius 5.0 5.0 stopped else_jump @MODEL_WRECKED This means: When the car is wrecked, jump @MODEL_SPAWN. Then you will start all over, by spawning a new car with a new arrow. When the car isn't wrecked, it will jump to MODEL_END, the second label. There it will check if the car is in the sphere. You have to make this a loop, because when you are doing it only once, the car won't be at the sphere yet. So when the car is in the neighbourhood of the sphere (radius 5.0), and the car stopped, then the code may continue. When it isn't, the code goes back to MODEL_WRECKED and check again if the car is wrecked. This continues until the car is in the sphere. When the player is in the car in the sphere, the sphere and the marker have to disappear. Also you have to spawn an actor with baseball bat, which had to attack the player. Marker.Disable($coordinate)[email protected] = Actor.Create(CIVFEMALE, #BFYST, 2094.3499, -1342.9515, 23.9844)Actor.Angle([email protected]) = 88.440187: $marker = create_marker_above_actor [email protected] actor.WeaponAccuracy([email protected])= 100actor.Health([email protected]) = 25001B2: give_actor [email protected] weapon 5 ammo 1000 // Load the weapon model before using this01B9: set_actor [email protected] armed_weapon_to 505E2: AS_actor [email protected] kill_actor $PLAYER_ACTOR Every part of this code has been explained already in previous tutorials, if it's unclear you can look it up there. Finally, when the actor is dead, the mission is passed. You have to play a sound, put a text on the screen and add some money. The marker on the actor has to be destroyed and the models have to be unloaded: repeatwait 0 msuntil actor.Dead([email protected])0394: play_music 101E3: show_text_1number_styled GXT 'M_PASS' number 10000 time 5000 style 1 // MISSION PASSED!~n~~w~$~1~Player.Money($PLAYER_CHAR) += 100000249: release_model #GREENWOO0249: release_model #BAT0249: release_model #BFYSTMarker.Disable($marker) Every part of this code has also been explained in previous tutorials. Don't forget to add the "end_thread" to stop the thread. Then you are finished. end_thread When you put this all together: Click. Now you can try your mission! Perhaps it isn't the most difficult mission, but who cares? You have to start small! So it shows, that with some simple codes, you can already make a nice mission. The limitions of the posibilities are not your coding-skills, but your creativity. Edited March 25, 2009 by Dutchy3010 RyanDri3957V and Kubrickian 2 DYOM - Create, play, share! Link to comment Share on other sites More sharing options...
Dutchy3010 Posted March 21, 2009 Author Share Posted March 21, 2009 (edited) You have now learned the basics of SCM-coding. The following tutorials will each explain more advanced aspects of SCM-modding. After working through all tutorials you should be able to combine those building blocks into rather advanced missions. When you have wishes for a tutorial, you can always send me a PM! Good luck and above all: have fun! Edited March 25, 2009 by Dutchy3010 Kubrickian and RyanDri3957V 2 DYOM - Create, play, share! Link to comment Share on other sites More sharing options...
Dutchy3010 Posted March 21, 2009 Author Share Posted March 21, 2009 (edited) A complete mission ( Rockstar Style ) In this tutorial, I will explain you how to make a real mission, just like Rockstar. So it will not be in a simple thread like the previous tutorials. First we will show the structure and specifics, then we will give templates for the different parts and explain these. Finally we will show you a mission based on this templates. Structure Missions like they are made by Rockstar have other behaviours then normal threads. First the code is only read when the mission starts, so there is only 1 mission at the same time active. Another big difference is how the code react when a player is Busted or Wasted. In a normal thread, you always have to check if the player is defined, but this isn't necessary in a mission-structure. When the player is Wasted or Busted, the SCM-engine will generate a "return"-opcode. So you don't have to check it during the mission. The framework which you should use to create a reak mission, will be explained later on in this mission. You will need two parts to make a mission: The mission itself The so called "sniffer"-thread, which checks the starting conditions of the mission and whether the player triggers a mission (like walk into a sphere). For both parts we will give you a template, which you can use for your own project. Sniffer-thread template The sniffer-thread will be started, when the missions are available. This can be directly from the start of the game, or when you passed other missions. This template contains the code for a sniffer-thread with two missions, but you can easily extend this with many more missions, which can be played after each other. // $TUT_MISSION_PASSED has to be cleared (0).// When you pass the mission, you have to raise $TUT_MISSIONS_PASSED.:TUT_MISSIONS_SNIFFERthread "TUT_SNIFF"$MARKER_SWEET_HOUSE = Marker.CreateIconAndSphere(42, <<xcoord>>, <<ycoord>>, <<zcoord>>)repeat wait $DEFAULT_WAIT_TIME if and player.Defined($PLAYER_CHAR) $ONMISSION == 0 then if and 00FF: actor $PLAYER_ACTOR sphere 0 in_sphere <<xcoord>>, <<ycoord>>, <<zcoord>> radius 1.0 1.0 2.0 on_foot Player.Controllable($PLAYER_CHAR) $TUT_MISSIONS_PASSED == 0 then $ONMISSION = 1 00BA: show_text_styled GXT 'INTRO_1' time 1000 style 2 start_mission 1 end if and 00FF: actor $PLAYER_ACTOR sphere 0 in_sphere <<xcoord>>, <<ycoord>>, <<zcoord>> radius 1.0 1.0 2.0 on_foot Player.Controllable($PLAYER_CHAR) $TUT_MISSIONS_PASSED == 1 then $ONMISSION = 1 00BA: show_text_styled GXT 'INTRO_2' time 1000 style 2 start_mission 2 end end until $TUT_MISSIONS_PASSED == 2marker.Disable($MARKER_SWEET_HOUSE)end_thread This thread will make a sphere on the specified location, where you have to start the missions. It will wait until the player walks into the sphere and stop running when both missions are passed. While $TUT_MISSIONS_PASSED is 0, none of the missions is passed. When the player walks into the sphere, it will start the first mission. After the player passed the first mission, $TUT_MISSIONS_PASSED will be 1. Then the sniffer-thread will wait until the player walks into the sphere. After the player passed the second mission, $TUT_MISSIONS_PASSED will be 2, so the loop will be ended, the sphere will be destroyed and the thread will end. Mission template //-------------Mission 1---------------// Mission wrapper:TUT_MISSION_1thread 'TUT 1' gosub @TUT_MISSION_1_MAIN if wasted_or_busted then gosub @TUT_MISSION_1_FAIL endgosub @TUT_MISSION_1_CLEANUP end_thread //-------------------------------------:TUT_MISSION_1_MAIN//-------------------------------------:TUT_MISSION_1_PASSEDPlayer.Money($PLAYER_CHAR) += 1000001E3: show_text_1number_styled GXT 'M_PASS' number 10000 time 5000 style 1 // MISSION PASSED!~n~~w~$~1~// This subroutine is executed when the mission is passed. // Give the rewards, and make new missions available if needed.return//-------------------------------------:TUT_MISSION_1_FAIL00BA: show_text_styled GXT 'M_FAIL' time 5000 style 1 // ~r~MISSION FAILED!// This subroutine is executed when the mission fails. return //-------------------------------------:TUT_MISSION_1_CLEANUP$ONMISSION = 0 // This subroutine is always executed at the end of the mission, regardless the outcome.// This is the place to unload models etc. mission_cleanup return The first part of the code is called the mission-wrapper, which calls the various parts of the mission with the help of a "gosub". This way there can be an automatic "return" after the player is WASTED or BUSTED. First he calls the main part of the mission. When it comes back, there can be two possible scenarios: •An automatic "return", because the player is Wasted or Busted. In this case the mission failed will be called, and after that the "cleanup" routine, which cleans everything up. •The mission is Passed or Failed for other reasons. In this case the mission_passed or mission_failed routine has already been called, so only the clean up has to happen. Below TUT_MISSION_1_MAIN will follow al the code for the gamneplay of the mission. In the complete example below, you will see how you can call the mission_passed and the mission_failed routines from within the main part, in certain situations. Example Mission Based on the above templates we made a simple mission. We will use the things we learned in the earlier tutorials. The purpose of the mission, which you can start in front of Sweet's house, is to kill an actor. There are two actors, a man and a woman. The woman is an enemy, the man is a friend. When you kill the woman, the mission is passed, but if you kill the man, the mission is failed. When the player is wasted or busted before the woman is killed, the mission will fail too. Click here to view the complete code The first part of the code, is the standard part of the stripped SCM file. The only thing you have to add, is for the start of the sniffer-thread: 00D7: create_thread @TUT_MISSIONS_SNIFFER Finally we will make a loop in the main-thread (:MAIN_LOOP). Then there is the sniffer thread, based on the template, but reduced to one mission. You will see that we defined two missions, the fist (mission 0), we will use, just like Rockstar, for initialising many things. Here you can add cargenerators or, for example, weapon pickups. We will set $TUT_MISSIONS_PASSED to 0, and we will define 3 variables for the mission trigger. The second mission (mission 1) is set up just like the template. In the main part, the models are loaded, the actors spawned, the weapons assigned and the car spawned, just like in previous tutorials. After that, the code waits in a loop, until $VICTIM is dead. In this case the code will go through the mission_passed routine, and the mission is finished. During the loop it will be checked whether the innocent man is still alive. When that isn't the case, we will jump to the mission_failed routine and the mission will end. In the mission passed routine, we will set a message on the screen, we will award the player some money and we will raise $TUT_MISSIONS_PASSED. In the mission failed routine, we will set a message on the screen and we will take away the weapon which we gave to him for this mission. In the cleanup routine, we clean up every used model, and we will set the wanted-level back to 0. Edited March 25, 2009 by Dutchy3010 RyanDri3957V and Kubrickian 2 DYOM - Create, play, share! Link to comment Share on other sites More sharing options...
Dutchy3010 Posted March 21, 2009 Author Share Posted March 21, 2009 (edited) Status Bars This tutorial is about Status Texts, or "bars". You can find them in SA missions like "Drive-By" and "supply-lines". :SWEET4_47Model.Load(#GREENWOO)038B: load_requested_models :SWEET4_103if not Model.Available(#GREENWOO)else_jump @SWEET4_152 wait 0 jump @SWEET4_103 :[email protected] = [email protected] = -1666.47 [email protected] = [email protected] = 16.0 0395: clear_area 1 at [email protected] [email protected] [email protected] range 6.0 [email protected] = Car.Create(#GREENWOO, [email protected], [email protected], [email protected])0229: set_car [email protected] color_to 59 34 Car.Angle([email protected]) = [email protected]([email protected]) = 1450$health = Car.Health([email protected]) This code is just spawning a vehicle, the Greenwood. In addition the health of the car is stored in variable $health. First I will explain the principle. The bar goes from 0 to 100, it are percentages. The initial health of the car is 1450. Under the 250, the car will be destroyed. So 250 will be the 0 of the bar. When 250 is in the bar 0, then the 1450 is 1200 (1450 - 250). Because you have only from 0 to 100, you have to divide it by 12. You have to code it like this: 0084: $health2 = $health // integer values and handlesif $health2 > 250 // integer valueselse_jump @SWEET4_11472$health2 -= 250 // integer values:SWEET4_11472$health2 /= 12 // integer values Before you can subtract 250, you have to check if it is more then 250. Otherwise it will be a negative number, which can't be in the bar. If the number is beneath the 250, you have to go to the next label (with the jump). If the number is above the 250, you have to subtract the 250. Then you have to divide the number by 12, so it is a number between the 0 and the 100. 0151: remove_status_text $health2 03C4: set_status_text_to $health2 1 'SWE4_08' // CAR HEALTH This is the code of the "bar". You won't see the "car health" text, because the GXT is not correct, but we will ignore that here. You can place a 0 instead of the 1, but then it will be displayed as number ingame, and it won't be a bar. repeatwait 0 ms$health = Car.Health([email protected])0084: $health2 = $health // integer values and handles if $health2 > 250 // integer values else_jump @SWEET4_11472 $health2 -= 250 // integer values :SWEET4_11472$health2 /= 12 // integer valuesuntil $health < 2500151: remove_status_text $health2end_thread We want to make a bar until the car is wrecked, so when the variable is 0, the bar has to disappear. This is a repeat-wait-until structure, so it has to repeat everything from the repeat-command until the condition is true. The condition is that $health has to be below the 250. He has to check the car health every time, and has to make it a number between 0 and 100. That's why it has to be between the repeat and until. When you don't do that, it will be the same number, because the variable $health2 won't be changed. So you have to wait until the health of the car is below the 250, then the car will be wrecked. After that you have to let the bar disappear with the 0151 opcode. After that you have to use the end_thread opcode, because else the game will crash if you don't properly end tha thread. When you add the code in a stripped SCM file, you will see the bar. Edited March 25, 2009 by Dutchy3010 Kubrickian 1 DYOM - Create, play, share! Link to comment Share on other sites More sharing options...
Dutchy3010 Posted March 21, 2009 Author Share Posted March 21, 2009 (edited) Menus In this tutorial we will use a screen, to illustrate the text. It is the "Main Panel" of the Design Your Own Mission mod. 0512: show_permanent_text_box 'CLOTHA' This is de text at the top on the left, for example "press space to continue". It is the red outlined part of the screen. 08D4: $MENU = create_panel_with_title 'DUMMY' position 29.0 145.0 width 220.0 columns 1 interactive 1 background 1 alignment 1 With this code you create the menu. You have to give the menu a name (variable/handle), so you can do things with it later on. Further, you have to give it a title. DUMMY means that you don't want text on that place ingame. If you want that the menu has a title, you have to place a text-id instead of 'DUMMY'. This is the blue outlined part of the screen. 08DB: set_panel $MENU column 0 header 'DUMMY' data 'DUMMY' 'DUMMY' 'DUMMY' 'DUMMY' 'DUMMY' 'DUMMY' 'DUMMY' 'DUMMY' 'DUMMY' 'DUMMY' 'DUMMY' 'DUMMY' First you have to give it a header, the yellow outlined part. Then, you can add things that the player can choose. One of those things is the pink outlined part of the screen. There are two ways to go on from here, but I will explain the easiest. I have to admit that I use this way most of the time. repeatwait 0 msif 00E1: player 0 pressed_key 15 then 08DA: remove_panel $MENU 03E6: remove text box jump @ENDenduntil 00E1: player 0 pressed_key 16 This is a repeat-wait-until structure, so the game repeats everything between repeat and until until the the condition is true. In this case, the code will repeat it until the player pressed key 16 (SPACE). When the player presses 15 (ENTER/F) before the player presses SPACE, you want to remove th menu, so you have to remove the panel and the text box. After that, you have to jump to the end (or the beginning, just wat you want). 08D7: $choice = panel $MENU active_row08DA: remove_panel $MENU03E6: remove text box After the player pressed SPACE, the panel and text box has to be removed. Apart from that, you have to look what the player has chosen. You can do that with the 08D7 opcode, where you check which was the latest active row before you remove the panel. Finally you have to say what happens when a player chooses. Be aware: it starts with 0, not 1! if $choice == 0then...endif $choice == 1then... end You have to do the if-then-end structure as many times as you have choices. For example, if you have 5 choices, the code has to be from 0 to 4. So the total code for a menu: 08D4: $MENU = create_panel_with_title 'DUMMY' position 29.0 145.0 width 220.0 columns 1 interactive 1 background 1 alignment 108DB: set_panel $MENU column 0 header 'DUMMY' data 'DUMMY' 'DUMMY' 'DUMMY' 'DUMMY' 'DUMMY' 'DUMMY' 'DUMMY' 'DUMMY' 'DUMMY' 'DUMMY' 'DUMMY' 'DUMMY'repeatwait 0 msif 00E1: player 0 pressed_key 15 then 08DA: remove_panel $MENU 03E6: remove text box jump @ENDenduntil 00E1: player 0 pressed_key 16 08D7: $choice = panel $MENU active_row08DA: remove_panel $MENU03E6: remove text boxif $choice == 0then...endif $choice == 1then... end:ENDwait 1000jump @END Edited March 25, 2009 by Dutchy3010 Kubrickian 1 DYOM - Create, play, share! Link to comment Share on other sites More sharing options...
Dutchy3010 Posted March 24, 2009 Author Share Posted March 24, 2009 (edited) MPACK This is a handy "tool" for scm-coders, that's why I will explain how it works. First notice that this isn't made by modders, but is added by Rockstar. When you use this, you can choose between more then 1 SCM-file at once. This way you don't have to edit the main.scm in "Program Files > Rockstar Games > GTA San Andreas > Data > Script" everytime, so you can play your own savegames in the original game whenever you want. Like you probably know, you have to start New Game when you make a SCM script, and it is annoying to switch between SCM-files. That is the biggest advantage of MPACKs. Another advantage is that you don't have to start San Andreas everytime you make a change in your code, you can simply start new game. In an MPACK there are 4 files: scr.scm (a file in the same format as the normal main.scm) text.gxt (a normal gxt file) MPACK.dat (Setting the title for this MPACK) scr.txt (The source of scr.scm, only needed during development, not when releasing In this tutorial I will explain how to make a MPACK. First, the MPACK has to be in the "GTA San Andreas User Files" folder, in "My Documents". The first thing you have to do, is make a folder called "MPACK" in User Files folder. You can make up to a maximum of 9 MPACKS, which have there own folder in the MPACK folder. You can compare it to the slots of the savegames. The number behind "MPACK" says which "slot" the MPACK uses. So in the "MPACKx" folder (x is a number between 1 and 9) have to be 4 files: scr.scm, scr.txt, text.gxt and mpack.dat. The first three will speak for themselves, but the fourth needs some explanation. You have to make a notepad file, in which you have type (for example): "7#Test#". The 7 has to correspond with the "slot" of the MPACK. So when you are using "MPACK7", there has to be a 7. Between the # has to be the name of the MPACK, which you will see in the list ingame. In my case it will be "Test". You have to save this file as "mpack.dat". Now you are ready to go ingame. Run San Andreas, and choose for "New Game". Here you will find a list of your MPACKs, and you can choose the name of the MPACK you need. As you can see, there is "Test" in slot 7. Have fun with coding! Edited March 25, 2009 by Dutchy3010 Kubrickian and Springfield 2 DYOM - Create, play, share! Link to comment Share on other sites More sharing options...
Dutchy3010 Posted March 24, 2009 Author Share Posted March 24, 2009 (edited) Actor Animations and Animation Paths Introduction You can assign all kind of animations to actors, just to make the mission more amusing. You have to know two things about the animations: the name of the animation and the name of de IFP-file that contains the animation. You can find a list of it here. The bold and large words are the names of the IFP-file, then the animation names inside that IFP-file will follow. For example, if you want that your actor dances, you have to look in the list and you will find the IFP-file "DANCING". That file contains all kind of animations, in this tutorial we will use "dnce_M_a". Of course you can give the actor also other animations, but please note: I can't guarantee that all of these animations will work! First we will create an actor, which has to perform the animation. When you worked through the other tutorials of this topic, this won't need any explanation. If you don't understand it, please go back to the tutorial about actors. 0247: load_model #BFYST038B: load_requested_models:MODEL_LOADif8248: not model #BFYST availableelse_jump @MODEL_SPAWNwait 0 msjump @MODEL_LOAD:[email protected] = Actor.Create(CIVFEMALE, #BFYST, 2491.3635, -1661.4694, 13.3359)Actor.Angle([email protected]) = 182.96510249: release_model #BFYST We will first have to load the IFP file, then we have to check if the animation is loaded. After that you have to give her an animation. You can do this with the following opcodes: 04ED: load_animation "DANCING"repeatwait 0until 04EE: animation "DANCING" loaded 0605: actor [email protected] perform_animation_sequence "DNCE_M_A" IFP_file "DANCING" 10.0 loop 1 0 0 0 time -1 // versionA Sometimes you don't have to load the animation, but I have to admit that I don't know when. I've seen many bugged scripts because they didn't load the animation, so my advice is to load it always. What do you have to lose? Better a few lines to much, than a bugged script! Opcode 0605 is exactly the same as opcode 0A1A and 0812. So it doesn't matter which opcode you choose. I will only explain the most important parts of this opcode. Feel free to experiment by changing the other parameters. First you have to say which actor you will give an animation, in our case that will be [email protected], which we just created. The first integer number, the only 1 in the opcode above, will indicate how many times the animation has to repeat itself. When you make it a 0, the animation will only be done once. When you make it a 1, it will repeated. After time you will see "-1". This means that the actor will perform the animation until there is an opcode that says that it has to stop. You can change it into a number like 4000, which means that the animation had to continue for 4 seconds. There is also a variant on the opcode: 0829: actor [email protected] perform_animation "DNCE_M_A" IFP_file "DANCING" 4.0 time 4000 and_dies In my opinion this is a bit stupid, but you can give it a try. After the actor performed it for 4 seconds, it will die. But it doesn't die like you would espect, it only freezes. There will be blood on the ground, but the actor is still standing, frozen. You can walk through it, and only if you kick the actor it will lay down. Funny to see, though. 0804: AS_actor [email protected] walk_to 2498.1187 -1671.9563 13.3427 angle 0.0 radius 0.2 animation "GRLFRD_KISS_03" IFP_file "BD_FIRE" 4.0 LA 0 LX 0 LY 0 LF 0 LT -1 0804: AS_actor [email protected] walk_to 2498.1187 -1671.9563 13.3427 angle 0.0 radius 0.2 animation "DNCE_M_A" IFP_file "DANCING" 4.0 LA 0 LX 0 LY 0 LF 0 LT -1 Two examples of one opcode, try it to see the result (you can edit it into the code at the end, if you find it difficult to create something from a stripped file). The actor walks to the supplied coordinates, and then perform the animation. In the first the actor will walk to the point and then give a kiss. To nobody in this case, but of course, you can add another actor next to it. The second will let the actor dance when he is at the location. 0611: actor [email protected] performing_animation "LRGIRL_IDLE_TO_L0" 8611: not actor [email protected] performing_animation "LRGIRL_BDBNCE" This opcode is a condition, so you have to use with for example an if-structure. This can be handy if you want to check if the animation is stopped, or if the actor is doing an animation. Here is an example of a code that checks if the animation is stopped: 0605: actor [email protected] perform_animation_sequence "DNCE_M_A" IFP_file "DANCING" 10.0 loop 1 0 0 0 time 3000 // versionA repeat wait 0until 8611: not actor [email protected] performing_animation "DNCE_M_A" Yet another opcode for an animation: 0612: set_actor [email protected] animation "DNCE_M_A" paused 1 With this code you can pause an animation. 1 means that it has to start, 0 means that it has to pause. For example we will make an actor with an animation, that has to do it for 1 second, then has to stop for 1 second, and then has to continue. 0605: actor [email protected] perform_animation_sequence "DNCE_M_A" IFP_file "DANCING" 10.0 loop 1 0 0 0 time -1wait 10000612: set_actor [email protected] animation "DNCE_M_A" paused 0 wait 10000612: set_actor [email protected] animation "DNCE_M_A" paused 1 0605: actor [email protected] perform_animation_sequence "DNCE_M_A" IFP_file "DANCING" 10.0 loop 1 0 0 0 time -1wait 30000614: set_actor [email protected] animation "DNCE_M_A" progress_to 0.5 // 0.0 to 1.0 This is another opcode, of course we are talking about the 0614 opcode. You can split up every animation. The whole animation is 1.0, it starts at 0.0. So you can say: I want that the actor perform the animation for 3 seconds, and then it has to start over from 0.5. Of course you can also say it has to start from the beginning after some time, then you have to write 0.0. Release animation Of course you have to release the animation when you loaded it: 04EF: release_animation "DANCING" Animation Paths 0754: define_new_animation_path 0755: add_animation_path_3D_coord 2496.5234 -1671.363 13.3359 animation "ROADCROSS" IFP_file "PED" 0755: add_animation_path_3D_coord 2499.4873 -1661.1962 13.3587 animation "ROADCROSS" IFP_file "PED" 0755: add_animation_path_3D_coord 2490.1294 -1661.246 13.3359 animation "ROADCROSS" IFP_file "PED" You first have to define the animation path. You have to start with define new animation path. Then you have to add coordinates. In this example, we will add three coordinates. The Animation and the IFP-file is just like the animations explained at the beginning of the tutorial. You can also use "NONE" instead of "ROADCROSS" and "PED", but then they won't do an animation. The animation will be performed at the coord, so it won't be during the time that the actor walks to the coord. Then you have to add an actor to the animation path: 0817: assign_actor [email protected] to_animation_path_with_walk_mode 4 route_mode 3 You can just expriment with this opcode. The route-mode: 0-normal order of waypoints, once (ABCD) 1-normal order of waypoints and reverse, once (ABCDCBA) 2-normal order of waypoints plus reversed, looped (ABCDDCBAABCD...) 3-normal order of waypoints, looped (ABCDABCDABCD...) (Source: this topic) Finally I will give you the code of a stripped file with an actor that performs an animation: click. Edited June 23, 2009 by Dutchy3010 Kubrickian and Sweet Bellic 2 DYOM - Create, play, share! Link to comment Share on other sites More sharing options...
Dutchy3010 Posted March 25, 2009 Author Share Posted March 25, 2009 (edited) Pickups What does this topic really miss! Indeed, a tutorial about pickups. So that is what this tutorial is all about. General Pickups 0213: $HEALTH = create_pickup #HEALTH type 3 at 2490.5598 -1658.3495 13.3528 This is the opcode to create a pickup. First the handle, so you can give it properties (like a marker) later on. Then you have to give a model for the pickups: Health: #HEALTH Armor: #BODYARMOUR Bribe: #BRIBE Info: #INFO Keycard: #KEYCARD Save pickup: #PICKUPSAVE Rhymesbook: #RMB_RHYMESBOOK Briefcase: #BRIEFCASE Clothes: #CLOTHESP Jetpack: #JETPACK Parachute Pack: #PARA_PACK Parachute: #PARACHUTE After type, you have to say if it is never available (1), once available (3) or multiple times available (15). There are other types, but these are the most common. If you want to see a full list of the types, you can look at this page. In this case, you can only pick up the HEALTH pickup once. The final three parameters are the coordinates. Weapon Pickups 0213: $BAT= create_pickup #BAT type 3 at 2490.5598 -1658.3495 13.3528 This opcode, which is the same as the opcode above, can also be used for weapons. But you can't give it ammo, so most of the times it is only used for melee weapons. When you create other weapon pickups, like a minigun, the ammo will be a standard value standard. For a minigun it is 500, for a rocket launcher it is only 4. So you can make all weapon pickups with this opcode, but it is more common to use the following: 032B: $M4 = create_weapon_pickup #M4 group 15 ammo 150 at 2490.5598 -1658.3495 13.3528 This is almost the same as 0213, but now you have to give it some ammo. So when you are using this opcode, it will spawn a M4 multiple times, with an ammo of 150 at 2490.5598 -1658.3495 13.3528. Money Pickups It is also possible to create money pickups, with the following opcode: 02E1: $MONEY = create_cash_pickup 500 at 2490.5598 -1658.3495 13.3528 permanence_flag 1 $MONEY is, of course, the handle. 500 is the amount of money which the player gets when he picked up the money. After that there are the coordinates. When the flag is 1, the money is permanently. It won't disappear until the player gets it. When the flag is 0, it will disappear after 30 seconds. Asset Pickups There are two kind of asset pickups: available and unavailable assets. The available can be bought by the player, the unavailable not yet. 0517: $asset = create_unavailable_asset_pickup 'PROP_4' at 2490.5598 -1658.3495 13.3528 0518: $asset2 = create_available_asset_pickup 'PROP_3' at 2489.5598 -1658.3495 13.3528 price 1 The first is the unavailable asset. When the player is near the pickup, the text 'PROP_4" will be displayed (You cannot buy this property yet.). The second is the available asset. Behind price you have to fill in the price of the property. Collectables Pickups You can create a horseshoe, a photo opportunity or a oyster with the following opcodes. I added a weapon pickup for the camera, because otherwise you can't see the photo opportunity when you are checking it ingame. 032B: $camera = create_weapon_pickup #CAMERA 15 ammo 50 at 2488.5598 -1663.3495 13.3528 0959: $horse = create_horseshoe_at 2490.5598 -1658.3495 13.35280958: $photo = create_photo_at 2489.5598 -1658.3495 13.3528095A: $oyster = create_oyster_at 2488.5598 -1658.3495 13.3528 Other opcodes concerning pickups 0213: $BAT = create_pickup #BAT type 3 at 2490.5598 -1658.3495 13.352803DC: [email protected] = create_marker_above_pickup $BAT With this opcode you can create a marker above the pickup, just like we did in the tutorial about markers and spheres. 0214: pickup $BAT picked_up 8214: not pickup $BAT picked_up These opcodes are conditions. You can use it to check if the player picked up the pickup. For example: 0213: $BAT = create_pickup #BAT type 3 at 2490.5598 -1658.3495 13.3528repeatwait 0until 0214: pickup $BAT picked_up Sometimes you want to destroy the pickup. You can do it like this: 0213: $BAT = create_pickup #BAT type 3 at 2490.5598 -1658.3495 13.3528wait 20000215: destroy_pickup $BAT So the pickup will be created, and after 2 seconds, it will disappear. Now we will make a small script. First we will spawn three pickups: An asset for 100 dollar, a health and a minigun weapon pickup. Above the minigun weapon pickup, there has to be a marker. After the player picked up the minigun, the marker has to disappear, and there has to spawn an actor. The actor also holds a minigun, and we will set her health and accuracy. The actor will try to kill the player, and the player has to kill the actor. When the player kills the actor, he will get 100 dollar, and he can buy the asset. Then we will display a text. First we are going to spawn three pickups and a marker above the minigun: 0518: $ASSET = create_available_asset_pickup 'PROP_3' at 2487.5598 -1658.3495 13.3528 price 1000213: $HEALTH = create_pickup #HEALTH type 3 at 2484.5598 -1658.3495 13.3528032B: $MINIGUN = create_weapon_pickup #MINIGUN group 15 ammo 5000 at 2490.5598 -1658.3495 13.3528 03DC: [email protected] = create_marker_above_pickup $MINIGUN Now we have to wait until the player picked up the minigun, and then we have to let the marker disappear and create the actor (with some properties): repeatwait 0until 0214: pickup $MINIGUN picked_up0164: disable_marker [email protected]: load_model #BFYST0247: load_model #MINIGUN038B: load_requested_models:MODEL_LOADif and8248: not model #BFYST available8248: not model #MINIGUN availableelse_jump @MODEL_SPAWNwait 0 msjump @MODEL_LOAD:[email protected] = Actor.Create(CIVFEMALE, #BFYST, 2488.5601, -1680.84, 13.3438 )01B2: give_actor [email protected] weapon 38 ammo 500 // Load the weapon model before using this 02E2: set_actor [email protected] weapon_accuracy_to 90 0223: set_actor [email protected] health_to 1000 The actor has to attack the player. After that, the code has to wait until the player kills the actor. As a reward, the player will get 100 dollar. 05E2: AS_actor [email protected] kill_actor $PLAYER_ACTORrepeatwait 100until 0118: actor [email protected] dead 0109: player $PLAYER_CHAR money += 100 Finally we will check if the asset is picked up, and we will display a text. repeatwait 100until 0214: pickup $ASSET picked_up00BC: show_text_highpriority GXT 'MCAT07E' time 3000 flag 1 The complete code in a stripped main.scm! Edited June 20, 2009 by Dutchy3010 Kubrickian 1 DYOM - Create, play, share! Link to comment Share on other sites More sharing options...
Dutchy3010 Posted March 25, 2009 Author Share Posted March 25, 2009 (edited) Texts In this tutorial we will look into texts. There are all sort of texts: big, small, bold, colored... Display Text 00BA: show_text_styled GXT 'BEEFY' time 3000 style 1 You have to use the name of the GXT entry between the ''. Behind time you have to put the amount of time which the text needs to be displayed. There are 7 styles, which you can fill in behind style: 1: In the middle, just like when you passed a mission or won a race. 2: At the bottomright, just like when you start a mission. 3: White text in the middle, just like when you are wasted or busted. 4: Style 1, but then smaller. 5: Same as style 4, but a bit higher on the screen. 6: Small white text in the middle of the screen. 7: Light blue text on top of the screen. Beware, 0 isn't a style, and the game will crash! White text along the bottom of the screen is displayed using other opcodes. There is a difference between highpriority and lowpriority opcodes. The highpriority will replace the lowpriority. For example: 00BB: show_text_lowpriority GXT 'IE23' time 3000 flag 1 wait 100000BC: show_text_highpriority GXT 'MTIME3' time 3000 flag 1 So here 'IE23' will first be displayed, but after 1 second it will be replaced by 'MTIME3'. You can clear the texts with the following opcodes: 00BE: text_clear_all 03D5: remove_text 'MTIME3' Display texts with number 01E3: show_text_1number_styled GXT 'BB_15' number 500 time 5000 style 1 With this opcode you can add a number to the text. In this case, your new high score will be 500. The styles are exactly the same as mentioned above. But be ware: you have to use gxt entries that are compatible with numbers! I will get back on this in the following tutorial, when we are going to add new texts. There are more opcodes about this. I think they will speak for itself: 01E4: show_text_1number_lowpriority GXT 'HJ_IS' number $var time 2000 flag 1 036D: show_text_2numbers_styled GXT 'TX_SEQ' numbers $var $var2 time 5000 style 5 02FD: show_text_2numbers_lowpriority GXT 'BB_05' numbers $var $var2 time 5000 flag 1 02FF: show_text_3numbers GXT 'WHEEL02' numbers $var $var2 $var3 time 3000 flag 1 0302: show_text_4numbers GXT 'WHEEL01' numbers $var $var2 $var3 $var4 time 3000 flag 1 0303: show_text_4numbers_highpriority GXT 'QUAR_P6' numbers $var $var2 $var3 $var4 time 10000 flag 1 0308: show_text_6numbers GXT 'HJSTAT' numbers $var $var2 $var3 $var4 $var5 time 5000 flag 5 Display text boxes 03E5: show_text_box 'HELP101' This is the 'normal' textbox. It will disappear after some time. A textbox is a black square in the left upper corner with white letters. 0512: show_permanent_text_box 'HOSP_1' This is a permanent text box, so it will be displayed until an opcode is executed which removes it. That is the following opcode: 03E6: remove_text_box For example: 0512: show_permanent_text_box 'HOSP_1' wait 100003E6: remove_text_box With this opcode you will display a text box, and will remove it after 1 second. 0513: show_text_box_1number 'SLOT_02' number 2 This is an opcode for a text box with a number in the text, in this case the value 2. There are three opcodes which check if the text box exist: 0A2A: text_box 'SGPUNT' displayed08FE: text_box_displayed 88FE: not text_box_displayed 0989: set_text_boxes_width 500 With this opcode, you can edit the width of the textbox. To see the difference, you can use the code below: 0512: show_permanent_text_box 'HOSP_1' wait 10000989: set_text_boxes_width 500 Drawn Textes 033E: set_draw_text_position 300.0 200.0 GXT 'BJ_PUSH' This is an example of a drawn text. You can give it the position you want, by editing the 300.0 and the 200.0. The 300.0 is horizontal, the 200.0 is vertical. A drawn text is normally a small white text. But you can change this with the opcodes 133F and 1340. You can only remove it with the following code: 03F0: enable_text_draw 0 You can also make a drawn text with numbers: 045A: draw_text_1number 320.0 155.333 GXT 'WINNER' number 1000045B: draw_text_2numbers 320.0 390.0 GXT 'TIME' numbers 20 30 I think these codes speak for itself. Other text opcodes 0A19: display_zone_text 'MARKS' With this opcode you can display a text just like the ones when you enter a zone. For example Saint Mark's. 09C1: add_next_text_to_brief_history 1 With this opcode you can add a text to "brief" in main menu, so a player can look back. A 1 means that it has to be stored in the brief option, 0 means that it doesn't have to. You have to put this code before the opcode which you are using to display texts. For example: 09C1: add_next_text_to_brief_history 1 00BB: show_text_lowpriority GXT 'IE23' time 3000 flag 1 When you want to see an example of a text in a short mission, you can look to the previous tutorial, which contains an application of the texts. Edited May 15, 2009 by Dutchy3010 Kubrickian 1 DYOM - Create, play, share! Link to comment Share on other sites More sharing options...
Dutchy3010 Posted May 15, 2009 Author Share Posted May 15, 2009 (edited) Custom Save Point In this tutorial, we are going to make an easy custom save point. Be aware, that it doesn't work that well in MPACK. So if you want to make use of the custom save point in scm, then use the main.scm and no MPACK. Action Plan: 1) Create pickup and check if the player picked it up. 2) Show save screen and wait until the save is done 3) Clean up 1) Create pickup and check if the player picked it up This isn't too hard. If you followed the other tutorials in this topic too, you will be able to make it yourself. You can make it as follow: $save_x = 2488.6506$save_y = -1660.9884$save_z = 13.33590395: clear_area 1 at $save_x $save_y $save_z range 1.0 $SAVE_PICKUP = Pickup.Create(#PICKUPSAVE, 3, $save_x, $save_y, $save_z)repeat wait 100until 0214: pickup $SAVE_PICKUP picked_up If you don't know what I'm doing here, I suggest that you take another look at this tutorial. 2) Show save screen and wait until the save is done You can show the save screen with one single opcode: 03D8: show_save_screen However, we have to do some other things before using this opcode, though. First, we have to set the $ONMISSION variable on 1, so the player doesn't get phonecalls and things like that. Second, we have to make sure that the player can't move, it would look strange when the actor is at a total different place when the save is done. $ONMISSION = 1 // integer values Player.CanMove($PLAYER_CHAR) = False We have to wait until the save is done. Although you can't find a "save_done" in the opcode search tool or in the main.scm (you can find 83D9 (not save_done) though), it is possible and easy to use. repeat wait 100until 03D9: save_done Combining these fragments, the second part of the code becomes: $ONMISSION = 1 // integer values Player.CanMove($PLAYER_CHAR) = False03D8: show_save_screen repeat wait 100until 03D9: save_done 3) Clean up What do we have now? We have the pickup which has to be picked up. Then a save screen will show up, and the code has to wait until the player finished the saving. You don't have to do anything about that saving, that is hardcoded. In this last part, we will fix the camera, and check if the player isn't near the save pickup anymore. Next to that, we have to destroy the pickup. Pickup.Destroy($SAVE_PICKUP)repeat wait 100until Player.Defined($PLAYER_CHAR) Camera.Restore_WithJumpCutCamera.SetBehindPlayerPlayer.CanMove($PLAYER_CHAR) = True$ONMISSION = 0 repeatwait 0until 80EC: not actor $PLAYER_ACTOR 0 near_point 2488.6506 -1660.9884 radius 2.0 2.0 jump @SAVE_LOOP The first line is to destroy the pickup. At the end, we will jump to the beginning (after waiting until the player isn't on that place any more), so the pickup will be created again. Then we restore the camera. The player has to be able to move again. Finally, we have to put the $ONMISSION variable back to 0, else it isn't possible to do another mission or get calls. The full code of a custom save point thread: :SAVEthread "SAVE"// location of the save pickup$save_x = 2488.6506$save_y = -1660.9884$save_z = 13.3359:SAVE_LOOP0395: clear_area 1 at $save_x $save_y $save_z range 1.0 $SAVE_PICKUP = Pickup.Create(#PICKUPSAVE, 3, $save_x, $save_y, $save_z)repeat wait 100until 0214: pickup $SAVE_PICKUP picked_up $ONMISSION = 1 // integer values Player.CanMove($PLAYER_CHAR) = False03D8: show_save_screen repeat wait 100until 03D9: save_done Pickup.Destroy($SAVE_PICKUP)repeat wait 100until Player.Defined($PLAYER_CHAR) Camera.Restore_WithJumpCutCamera.SetBehindPlayerPlayer.CanMove($PLAYER_CHAR) = True$ONMISSION = 0 repeat wait 0until 80EC: not actor $PLAYER_ACTOR 0 near_point $save_x $save_y radius 2.0 2.0 jump @SAVE_LOOPend_thread Click here to view the code in a stripped main.scm. Edited June 21, 2009 by Dutchy3010 Kubrickian 1 DYOM - Create, play, share! Link to comment Share on other sites More sharing options...
Dutchy3010 Posted June 15, 2009 Author Share Posted June 15, 2009 Cutscenes In this tutorial, I'm going to explain a basic cutscene. It is pretty difficult to tell you how to do it, because every single cutscene is different. However, I think you would be able to learn it when I explain a simple cutscene. So I coded a simple cutscene myself, and I will show you what it means. Keep in mind that you have to test almost every code you are doing. You have to put waits between it to make it a better story, you have to test for the camera, etcetera. Example cutscene Basically, a cutscene is a lot of opcodes which don't need input from the player. If the player can't do anything, and just have to watch something, it's a cutscene. Keep this in mind in the tutorial. We will start with the full code of the cutscene I scripted: //---------------------//Start Cutscene//---------------------:CUTSCENE03BC: $begin = create_sphere_at 2489.0088 -1658.4554 13.3519 radius 1.0 repeatwait 0until 00FE: actor $PLAYER_ACTOR sphere 0 in_sphere 2489.0088 -1658.4554 13.3519 radius 1.0 1.0 1.0 Player.CanMove($PLAYER_CHAR, false)//---------------------//Load Models//---------------------model.Load(#army)model.Load(#patriot)model.load(#m4)023C: load_special_actor 'SWEET' as 1 // models 290-299 023C: load_special_actor 'KENDL' as 2 // models 290-299 023C: load_special_actor 'CESAR' as 3 // models 290-299 038B: load_requested_models :load_checkwait 0if andmodel.available(#army)model.available(#patriot)model.available(#m4)023D: special_actor 1 loaded 023D: special_actor 2 loaded 023D: special_actor 3 loaded else_jump @load_check //---------------------//Spawn everything in fade//---------------------fade 0 500repeatwait 0until 816B: not fading 02A3: enable_widescreen 1 03BD: destroy_sphere $beginCar.Create($car, #patriot, 2503.0217, -1672.2841, 13.3594) Car.Angle($car) = 82.38440129: [email protected] = create_actor_pedtype 23 model #army in_car $car driverseat 01C8: [email protected] = create_actor_pedtype 23 model #army in_car $car passenger_seat 0 01C8: [email protected] = create_actor_pedtype 23 model #army in_car $car passenger_seat 101C8: [email protected] = create_actor_pedtype 23 model #army in_car $car passenger_seat 201B2: give_actor [email protected] weapon 31 ammo 60 // Load the weapon model before using this 01B2: give_actor [email protected] weapon 31 ammo 60 // Load the weapon model before using this 01B2: give_actor [email protected] weapon 31 ammo 60 // Load the weapon model before using this 01B2: give_actor [email protected] weapon 31 ammo 60 // Load the weapon model before using this 009A: [email protected] = create_actor_pedtype 4 model #SPECIAL01 at 2479.1279 -1680.2635 13.338Actor.Angle([email protected]) = 359.6866009A: [email protected] = create_actor_pedtype 4 model #SPECIAL02 at 2477.7996 -1678.5049 13.3386Actor.Angle([email protected]) = 266.6259009A: [email protected] = create_actor_pedtype 4 model #SPECIAL03 at 2479.3577 -1676.2166 13.337Actor.Angle([email protected]) = 176.385200A1: put_actor $PLAYER_ACTOR at 2480.9185 -1678.2045 13.3404Actor.Angle($PLAYER_ACTOR) = 98.7008 04ED: load_animation "GANGS"repeatwait 0until 04EE: animation "GANGS" loaded 0605: actor [email protected] perform_animation_sequence "PRTIAL_GNGTLKA" IFP_file "GANGS" 4.0 loop 1 0 0 0 time -10605: actor [email protected] perform_animation_sequence "PRTIAL_GNGTLKB" IFP_file "GANGS" 4.0 loop 1 0 0 0 time -10605: actor [email protected] perform_animation_sequence "PRTIAL_GNGTLKC" IFP_file "GANGS" 4.0 loop 1 0 0 0 time -10605: actor $PLAYER_ACTOR perform_animation_sequence "PRTIAL_GNGTLKC" IFP_file "GANGS" 4.0 loop 1 0 0 0 time -1Camera.SetPosition(2472.7151, -1681.5944, 16.9041, 0.0, 0.0, 0.0)Camera.PointAt(2494.2827, -1669.9541, 13.3359, 2)wait 200000A7: car $car drive_to 2487.1799 -1670.8324 13.3359fade 1 500repeatwait 0until 816B: not fading //---------------------//Behaviour after fade//---------------------repeatwait 10until 01AE: car $car sphere 0 near_point 2487.1799 -1670.8324 radius 3.0 3.0 stopped 0160: set_camera_point_at 2494.2827 -1669.9541 9.3359 mode 2 05CD: AS_actor [email protected] exit_car $car 05CD: AS_actor [email protected] exit_car $car 05CD: AS_actor [email protected] exit_car $car 05CD: AS_actor [email protected] exit_car $car0635: AS_actor [email protected] aim_at_actor $PLAYER_ACTOR -1 ms 0635: AS_actor [email protected] aim_at_actor $PLAYER_ACTOR -1 ms 0635: AS_actor [email protected] aim_at_actor $PLAYER_ACTOR -1 ms 0635: AS_actor [email protected] aim_at_actor $PLAYER_ACTOR -1 ms 074D: AS_actor $PLAYER_ACTOR turns_to_and_look_at_actor [email protected] timelimit -1 074D: AS_actor [email protected] turns_to_and_look_at_actor [email protected] timelimit -1 074D: AS_actor [email protected] turns_to_and_look_at_actor [email protected] timelimit -1 074D: AS_actor [email protected] turns_to_and_look_at_actor [email protected] timelimit -1 wait 250005C4: AS_actor $PLAYER_ACTOR hands_up -1 ms 05C4: AS_actor [email protected] hands_up -1 ms 05C4: AS_actor [email protected] hands_up -1 ms 05C4: AS_actor [email protected] hands_up -1 ms wait 5000//---------------------//Cleanup//---------------------fade 0 500repeatwait 0until 816B: not fading 00A6: destroy_car $car009B: destroy_actor [email protected]: destroy_actor [email protected]: destroy_actor [email protected]: destroy_actor [email protected]: destroy_actor [email protected]: destroy_actor [email protected]: destroy_actor [email protected]: clear_actor $PLAYER_ACTOR task Player.CanMove($PLAYER_CHAR, true)0373: set_camera_directly_behind_player 02EB: restore_camera_with_jumpcut 02A3: enable_widescreen 0wait 2000fade 1 500repeatwait 0until 816B: not fading Story and start The story of this small cutscene is: there is a Patriot with 4 army actors in it. There are also 4 special actors: Sweet, Kendl, Cesar and CJ. Those special actors are talking to each other (with an animation). The Patriot has to drive towards the 4 special actors, and the army guys have to exit the car. Then the 4 special actors have to turn towards the army guys. Those army guys have all a M4, and aim at the group of 4 special actors. Finally the 4 special actors have to surrender. We will make a sphere in which the player has to walk before the cutscene starts. It would be strange if the player can move CJ during the cutscene, that is why we make sure he can't move. After that we will load everything we need in the cutscene itself. I think I don't have to explain any of this. //---------------------//Start Cutscene//---------------------:CUTSCENE03BC: $begin = create_sphere_at 2489.0088 -1658.4554 13.3519 radius 1.0 repeatwait 0until 00FE: actor $PLAYER_ACTOR sphere 0 in_sphere 2489.0088 -1658.4554 13.3519 radius 1.0 1.0 1.0 Player.CanMove($PLAYER_CHAR, false)//---------------------//Load Models//---------------------model.Load(#army)model.Load(#patriot)model.load(#m4)023C: load_special_actor 'SWEET' as 1 // models 290-299 023C: load_special_actor 'KENDL' as 2 // models 290-299 023C: load_special_actor 'CESAR' as 3 // models 290-299 038B: load_requested_models :load_checkwait 0if andmodel.available(#army)model.available(#patriot)model.available(#m4)023D: special_actor 1 loaded 023D: special_actor 2 loaded 023D: special_actor 3 loaded else_jump @load_check Fade and spawns To start, you have to use some fade, because else you would see everything spawn and that isn't nice. So first you have to give a fade, and wait until it isn't fading any more (else you will see things spawn because the screen isn't black yet). After that loop, you have to spawn everything you want. //---------------------//Spawn in fade//---------------------fade 0 500repeatwait 0until 816B: not fading 02A3: enable_widescreen 1 03BD: destroy_sphere $beginCar.Create($car, #patriot, 2503.0217, -1672.2841, 13.3594) Car.Angle($car) = 82.38440129: [email protected] = create_actor_pedtype 23 model #army in_car $car driverseat 01C8: [email protected] = create_actor_pedtype 23 model #army in_car $car passenger_seat 0 01C8: [email protected] = create_actor_pedtype 23 model #army in_car $car passenger_seat 101C8: [email protected] = create_actor_pedtype 23 model #army in_car $car passenger_seat 201B2: give_actor [email protected] weapon 31 ammo 60 // Load the weapon model before using this 01B2: give_actor [email protected] weapon 31 ammo 60 // Load the weapon model before using this 01B2: give_actor [email protected] weapon 31 ammo 60 // Load the weapon model before using this 01B2: give_actor [email protected] weapon 31 ammo 60 // Load the weapon model before using this 009A: [email protected] = create_actor_pedtype 4 model #SPECIAL01 at 2479.1279 -1680.2635 13.338Actor.Angle([email protected]) = 359.6866009A: [email protected] = create_actor_pedtype 4 model #SPECIAL02 at 2477.7996 -1678.5049 13.3386Actor.Angle([email protected]) = 266.6259009A: [email protected] = create_actor_pedtype 4 model #SPECIAL03 at 2479.3577 -1676.2166 13.337Actor.Angle([email protected]) = 176.385200A1: put_actor $PLAYER_ACTOR at 2480.9185 -1678.2045 13.3404Actor.Angle($PLAYER_ACTOR) = 98.7008 04ED: load_animation "GANGS"repeatwait 0until 04EE: animation "GANGS" loaded 0605: actor [email protected] perform_animation_sequence "PRTIAL_GNGTLKA" IFP_file "GANGS" 4.0 loop 1 0 0 0 time -10605: actor [email protected] perform_animation_sequence "PRTIAL_GNGTLKB" IFP_file "GANGS" 4.0 loop 1 0 0 0 time -10605: actor [email protected] perform_animation_sequence "PRTIAL_GNGTLKC" IFP_file "GANGS" 4.0 loop 1 0 0 0 time -10605: actor $PLAYER_ACTOR perform_animation_sequence "PRTIAL_GNGTLKC" IFP_file "GANGS" 4.0 loop 1 0 0 0 time -1Camera.SetPosition(2472.7151, -1681.5944, 16.9041, 0.0, 0.0, 0.0)Camera.PointAt(2494.2827, -1669.9541, 13.3359, 2)wait 200000A7: car $car drive_to 2487.1799 -1670.8324 13.3359fade 1 500repeatwait 0until 816B: not fading We also have to give the actors an animation, because it has to look like they are having a conversation. Then perhaps the most difficult about cutscenes: the camera. There isn't an easy way to get the camera the way you want it. I just used a jetpack and then the coords tool in Sanny Builder. You have to test it a lot, so it will become the way you want it. It is recommended to have a "longer" wait in the fade, so you won't see anything spawn after the fade. But the car drive to has to be behind that wait, because else the car will be on his destination before the player can see something again! Of course we have to lift the fade at the end. Behaviour after fade //---------------------//Behaviour after fade//---------------------repeatwait 10until 01AE: car $car sphere 0 near_point 2487.1799 -1670.8324 radius 3.0 3.0 stopped 0160: set_camera_point_at 2494.2827 -1669.9541 9.3359 mode 2 05CD: AS_actor [email protected] exit_car $car 05CD: AS_actor [email protected] exit_car $car 05CD: AS_actor [email protected] exit_car $car 05CD: AS_actor [email protected] exit_car $car0635: AS_actor [email protected] aim_at_actor $PLAYER_ACTOR -1 ms 0635: AS_actor [email protected] aim_at_actor $PLAYER_ACTOR -1 ms 0635: AS_actor [email protected] aim_at_actor $PLAYER_ACTOR -1 ms 0635: AS_actor [email protected] aim_at_actor $PLAYER_ACTOR -1 ms 074D: AS_actor $PLAYER_ACTOR turns_to_and_look_at_actor [email protected] timelimit -1 074D: AS_actor [email protected] turns_to_and_look_at_actor [email protected] timelimit -1 074D: AS_actor [email protected] turns_to_and_look_at_actor [email protected] timelimit -1 074D: AS_actor [email protected] turns_to_and_look_at_actor [email protected] timelimit -1 wait 250005C4: AS_actor $PLAYER_ACTOR hands_up -1 ms 05C4: AS_actor [email protected] hands_up -1 ms 05C4: AS_actor [email protected] hands_up -1 ms 05C4: AS_actor [email protected] hands_up -1 ms wait 5000 In this code we basically say what the actors have to do after the fade. First we have to wait until the car arrives at his destination. Then we want to change the camera, so it shows what happens better. We want that the army guys exit the car, and that they aim at the player (or someone else of the 4 special actors). We want that the special actors look at the army guys. But we have to wait some time (the wait of 2500 ms), else the special actors will put their hands up before the army guys aim at them. That looks a bit strange. So after the 2500, we want them to put their hands up and the cutscene is finished. Clean up Of course we have to clean things up after the cutscene. To make sure nobody will see it, we will first do a fade again. Then we have to destroy the car and the actors. The clear task opcode is because else the Player will keep his hands up after the cutscene. The player also have to be able to move again after the cutscene, so we have to make this opcode true again. The camera has to be behind the player and the the widescreen must be lifted. //---------------------//Cleanup//---------------------fade 0 500repeatwait 0until 816B: not fading 00A6: destroy_car $car009B: destroy_actor [email protected]: destroy_actor [email protected]: destroy_actor [email protected]: destroy_actor [email protected]: destroy_actor [email protected]: destroy_actor [email protected]: destroy_actor [email protected]: clear_actor $PLAYER_ACTOR task Player.CanMove($PLAYER_CHAR, true)0373: set_camera_directly_behind_player 02EB: restore_camera_with_jumpcut 02A3: enable_widescreen 0wait 2000fade 1 500repeatwait 0until 816B: not fading Complete code in a stripped main.scm Other opcodes There are many other things you can do in a cutscene. You can also use other sort of opcodes, like changing the weather: 01B6: set_weather 1 Or just use the wanted level opcodes: 010D: set_player $PLAYER_CHAR wanted_level_to 0 010E: set_player $PLAYER_CHAR minimum_wanted_level_to 2 01F0: set_max_wanted_level_to 6 Another thing you can use in a cutscene, is the "skip cutscene" opcode. If you make a mission, and the player has to redo it, he probably don't want to view the cutscenes again. There is a solution for that. An example of the mission "General Dilemma" (coded by PatrickW and me): 0707: start_scene_skip_to @GENDIL_3502 :GENDIL_35020701: end_scene_skip if 08D0: cutscene_skipped jf @GENDIL_3523 fade 0 100 :GENDIL_3523 So when the player wants to skip the cutscene, he will go to GENDIL_3502. Apparently in the code the player skipped was a fade, so it need to be done, but only when the cutscene is skipped. You can use objects, other animations, pickups, texts... As long as you keep in mind that it has to be created and destroyed in the fades, you can do everything! Especially look at the AS opcodes, for example: 05CD: AS_actor -1 exit_car [email protected] These opcodes are all non-playable opcodes, so very useful for cutscenes! I hope you learned a bit more about cutscenes, if you have any questions or comments about the tutorials or requests for another tutorial, you can post in the reaction topic. Kubrickian 1 DYOM - Create, play, share! Link to comment Share on other sites More sharing options...
Dutchy3010 Posted September 7, 2013 Author Share Posted September 7, 2013 It has been a while since the last tutorial in this topic. However, I expect that modding GTA San Andreas on the PC will get a boost after the release of GTA V, so that PC gamers will have some of the possibilities of GTA V in San Andreas. I don't know what kind of tutorial you guys would like to see. Please inform me about which subject you would like to learn. Please keep in mind that this is a mission coding for dummies thread, not mission coding for pro's, so that the tutorials shouldn't be too difficult. If you have any idea's, please reply in the reaction topic. Thanks a lot. cyrilaeshell, becks7, Kubrickian and 4 others 7 DYOM - Create, play, share! Link to comment Share on other sites More sharing options...