Kaphotics Posted May 4, 2013 Posted May 4, 2013 (edited) Introduction: Scripting is what coordinates and executes in-game events to create a story for the player. Gen III hacks have been able to tell new stories with custom scripts written from scratch; future hacks in more current generations are key for good hacks. This thread is to provide information in regards to how to script, what script commands do, and some example scripts. I'll try to go more in depth than pichu2001 did in his basic tutorial thread; if you are just starting off scripting, you should definitely read his thread first. Starting Information: First you need to extract the Script .narc with NitroExplorer, and unpack it into the individual files with editor.exe (kiwi.ds). Program & Lua starter kit: download here The location of the scripts is /a/0/5/6 There is currently no XSE equivalent of symbolic scripting for B2W2. We're doing this with hex. So have a hex editor ready (HxD or Hex Workshop), and get PPNFR to replace the individual scripts you edit. How do you know what script is used where? You currently need to use a Lua script while emulating. The script depicted below is in the starter kit. At the bottom right corner of the touch-screen, it tells you which Script is being used. Correlate this with the file numbers you extracted from the narc. Script Structure: As previously described by pichu2001, the script contains two parts. The pointers and the scripts that are pointed to. Pointers are 4 bytes long (32 bits); the first script in this example image points to 00 00 00 38, which is equivalent to 00000038 = 0x38. 0x38 bytes after this pointer is the start of script 1. Use this formula to find the script's location in the file: Current Read Offset + Pointer Value = Script Offset In this example image, 0x04+0x38 = 0x3C. The first script is located at 0x3C... unfortunately it starts off reading as "End", so the script ends there. Try finding the offset of Script 2; you should get 0x3E, which just so happens to start right after Script 1 ends. To tell the game to stop reading pointers, a 16 byte "STOP" = 13 FD is used (0xFD13). After the STOP, there are no more pointers and the raw script command data starts. Pointers are an important part of the file; if you insert anything between existing data, the pointers will point to improper locations. I'll cover this later. Hello World: Interpreting Existing Scripts Knowing how to script requires you to observe how commands are normally used by others. I'll show you an example script that has an NPC says a text line and ends the script when dismissed. Above is the example script file. As you can see, it contains one script, which starts at 0x06. [color="purple"]02 00 00 00[/color] [u][i]13 FD[/i][/u] [color="blue"]2E 00 A6 00 47 05 74 00 3D 00 00 04 0A 00 00 00 00 00 32 00 3F 00 30 00 2F 00 02 00 00 00[/color] First we must separate out our script data. Remove everything before the start of our script (everything before 0x06) [color="blue"]2E 00 A6 00[/color] [color="green"]47 05[/color] [color="blue"]74 00 3D 00[/color] [color="green"]00 04 0A 00 00 00 00 00[/color] [color="blue"]32 00 3F 00 30 00 2F 00 02 00[/color] 00 00 Looks decent, let's make this more easily to see: [color="blue"]2E 00[/color] -- [color="red"]LockAll[/color] [color="blue"]A6 00[/color] [color="green"]47 05[/color] -- [color="red"]PlaySound Clink[/color] [color="blue"]74 00[/color] -- [color="red"]FacePlayer[/color] [color="blue"]3D 00[/color] [color="green"]00 04 0A 00 00 00 00 00[/color] -- [color="red"]Message2, text line 0xA, default settings[/color] [color="blue"]32 00[/color] -- [color="red"]WaitKeypress[/color] [color="blue"]3F 00[/color] -- [color="red"]CloseMessage2[/color] [color="blue"]30 00[/color] -- [color="red"]WaitDelay[/color] [color="blue"]2F 00[/color] -- [color="red"]UnlockAll[/color] [color="blue"]02 00[/color] -- [color="red"]End[/color] 00 00 -- Padding to make the file's size divisible by 0x4 This is gibberish to the untrained eye, so I'll explain what each line does in 'English'. [color="red"]LockAll[/color] [color="blue"]0x002E[/color] -- Stop all movements of NPCs and Player. LOCK EVERYTHING. [color="red"]PlaySound Clink[/color] [color="blue"]0x00A6[/color] [color="green"]0x0547[/color] -- Play a sound, sound number 0x0547 - "clink" [color="red"]FacePlayer[/color] [color="blue"]0x0074[/color] -- Make the NPC that was interacted with face the player [color="red"]Message2[/color] [color="blue"]0x003D[/color] -- Pops up a speech bubble from the interacted with NPC [color="green"]0x0400[/color] -- Tells the game to use the current text file [color="green"]0x000A[/color] -- Tells the game to use text line 0xA [color="green"]0x0000[/color] -- Tells the game to place the bubble away from interaction [color="green"]0x0000[/color] -- Tells the game to use the default speech bubble [color="red"]WaitKeypress[/color] [color="blue"]0x0032[/color] -- Wait until a button is pressed before proceeding [color="red"]CloseMessage2[/color] [color="blue"]0x003F[/color] -- Close the popped up speech bubble [color="red"]WaitDelay[/color] [color="blue"]0x0030[/color] -- Waits a frame; cools down the game [color="red"]UnlockAll[/color] [color="blue"]0x002F[/color] -- Allow all NPCs and player to move [color="red"]End[/color] [color="blue"]0x0002[/color] -- Ends the script; read no further! Pretty easy to interpret when you know what each command is... Value Storage: Flags, Containers (const) and Variables The game likes to keep track of what has happened in game, and your choices that you have made. If you get an item from an NPC, the game sets a flag so that the NPC doesn't give it out again. The game also sets flags to prevent NPCs from spawning (so that progress based NPCs appear/disappear) [*]If you choose a certain starter, the game sets a Const container to know what Rival teams to face you against. Constants are stored in the save file along with flags. [*]Variables are temporary values that are used to contain values for a short time. Variables do the majority of the work in scripts. They are defined by some command, then later used as dynamic parameters. Essentially symbolic math. Variables are not saved in the save file; however if they are not cleared/set properly their values can persist into other custom scripts. When you are done with them, clear them! Conclusion: Part 1 This introduction to scripting is just touching the surface on what you can do with B2W2 scripting. With over 800 commands at your disposal (more than 3x that of Gen III), there's so much more you can do! Edited May 4, 2013 by Kaphotics
Kaphotics Posted May 4, 2013 Author Posted May 4, 2013 . Quick Script Interpretation The best way to figure out how to script an event is to observe one in game. I created a subversion of NPRE that parses B2W2 scripts. Download this NPRE svn https://www.dropbox.com/s/owrbm4fw4nh07ut/NPREzz.zip?dl=0 https://www.dropbox.com/s/kf1gi0i23yfc266/NPRE-1226.zip?dl=0 . How to use NPRE: Open the program File->Open your ROM Navigate to /a/0/5/6, right click open as Narc (script). Select Target game as B2W2 A new window will pop up. In the top left corner, enter the script number you want to open. It will then parse the script! Open spoiler for visual illustration of ^ above process ^ http://i.snag.gy/tQXj2.jpg To exhibit the parsing, here's an image of the first example script file I gave in part 1. Open script file 0 with NPRE via the dropdown in the top left corner. Open spoiler for visual illustration of ^ above process ^ http://i.snag.gy/gBahe.jpg As you can see, Script 1 (displayed as Script 0) starts at Offset 60. In hex, that's 0x3C. The next script starts at 0x3E; this is exactly the same as we mathematically solved in part one of this tutorial. Now that you can quickly see how the game does certain events in game, you can easily open up that script file to see the raw hex instructions and what they do! But... you want to script your own stuff too! ----- List of Common Commands C# reference of known commands and parameter length, from NPRE's source . Should be fairly easy to understand; although most don't have comments, it should be obvious as to how the parameters of each command are used (and how many). Here's a reduced list with some description: Logic & Meta commands: 0x0000 NOP Do nothing 0x0001 NOP Do nothing 0x0002 End End Script 0x0003 Wait Wait a given amount of time --16bit parameter : Frames to wait 0x0004 CallRoutine Point to a sub-script within the current script --32bit pointer parameter 0x0005 EndRoutine End subscript, pop back to main script -- 0x0008 CompareTo Compares the current internal number to parameter --16bit value 0x0009 StoreVar Stores Variable/Container as an internal number --16bit value of Var/Cont to store. 0x000A ClearVar Clears the variable from internal memory. --16bit value of Var/Cont to clear. -- 0x0010 StoreFlag Stores the current status of an event flag. --16bit flag number - 0~unset 1~set 0x0011 Condition Comparison Condition --16bit comparison condition =>< etc 0x0012 BitAND Bitwise AND of two parameters --16bit container --16bit value to AND 0x0013 BitXOR Bitwise XOR of two parameters --16bit container --16bit value to XOR 0x0019 CompareVar Compares Container to a parameter --16bit container --16bit compareto -- 0x001C CallStd Calls a standard function (main->external script) --16bit external script reference number 0x001D ReturnStd EndStd, pop back to main script (external->main) 0x001E Jump / Goto Goto another part of the script (pointer) --32bit pointer 0x001F If If-Then jump compare with conditional, if satisfied->jump --8bit result operator --32bit pointer 0x0023 SetFlag Toggle flag to set (1) --16bit flag number to set 0x0024 ClearFlag Toggle flag to unset (0) --16bit flag to unset 0x0025 SetVarFlagStatus Get status of flag --16bit var --16bit flag 0x0026 Add Add value to Variable/Constant --16bit container --16bit add 0x0027 Subtract Subtract value from Variable/Constant 0x0028 SetVarEqualVal Sets Variable/Constant equal to Value --16bit container --16bit value 0x0029 - 0x002A CopyVar Copy variable to new, keeping qualities (text type etc) --16bit destination var --16bit source variable NPC Interaction case 0x2E: com.Name = "LockAll"; break; case 0x2F: com.Name = "UnlockAll"; break; case 0x30: com.Name = "WaitMoment"; break; case 0x32: com.Name = "WaitButton"; break; case 0x74: com.Name = "FacePlayer"; break; case 0x3C: com.Name = "Message"; com.parameters.Add(reader.ReadByte()); //Costant com.parameters.Add(reader.ReadByte()); //Costant com.parameters.Add(reader.ReadUInt16()); //Message Id com.parameters.Add(reader.ReadUInt16()); //NPC Id com.parameters.Add(reader.ReadUInt16()); //Bottom/Top View. com.parameters.Add(reader.ReadUInt16()); //Message Type break; case 0x3D: com.Name = "Message2"; com.parameters.Add(reader.ReadByte()); //Costant com.parameters.Add(reader.ReadByte()); //Costant com.parameters.Add(reader.ReadUInt16()); //Message Id com.parameters.Add(reader.ReadUInt16()); //Bottom/Top View. com.parameters.Add(reader.ReadUInt16()); //Message Type break; case 0x3E: com.Name = "CloseMessageKeyPress"; break; case 0x3F: com.Name = "CloseMessageKeyPress2"; break; case 0x33: com.Name = "MusicalMessage"; com.parameters.Add(reader.ReadUInt16()); //Message Id break; case 0x34: com.Name = "EventGreyMessage"; com.parameters.Add(reader.ReadUInt16()); //Message Id com.parameters.Add(reader.ReadUInt16()); //Bottom/Top View. break; case 0x35: com.Name = "CloseMusicalMessage"; break; case 0x36: com.Name = "CloseEventGreyMessage"; break; case 0x38: com.Name = "BubbleMessage"; com.parameters.Add(reader.ReadUInt16()); //Message Id com.parameters.Add(reader.ReadByte()); //Bottom/Top View. break; case 0x39: com.Name = "CloseBubbleMessage"; break; Teleportation case 0xBE: com.Name = "Warp"; com.parameters.Add(reader.ReadUInt16()); //Map Id com.parameters.Add(reader.ReadUInt16()); // X coordinate com.parameters.Add(reader.ReadUInt16()); // Y coordinate break; case 0xBF: com.Name = "TeleportWarp"; com.parameters.Add(reader.ReadUInt16()); //Map Id com.parameters.Add(reader.ReadUInt16()); // X coordinate com.parameters.Add(reader.ReadUInt16()); // Y coordinate com.parameters.Add(reader.ReadUInt16()); // Z coordinate break; case 0xC1: com.Name = "FallWarp"; com.parameters.Add(reader.ReadUInt16()); //Map Id com.parameters.Add(reader.ReadUInt16()); // X coordinate com.parameters.Add(reader.ReadUInt16()); // Y coordinate break; case 0xC2: com.Name = "FastWarp"; com.parameters.Add(reader.ReadUInt16()); //Map Id com.parameters.Add(reader.ReadUInt16()); // X coordinate com.parameters.Add(reader.ReadUInt16()); // Y coordinate com.parameters.Add(reader.ReadUInt16()); // Hero's Facing break; case 0xC3: com.Name = "UnionWarp"; // warp to union room break; case 0xC4: com.Name = "TeleportWarp"; com.parameters.Add(reader.ReadUInt16()); //Map Id com.parameters.Add(reader.ReadUInt16()); // X coordinate com.parameters.Add(reader.ReadUInt16()); // Y coordinate com.parameters.Add(reader.ReadUInt16()); // Z coordinate com.parameters.Add(reader.ReadUInt16()); // Hero's Facing break; All this is pretty useless unless you know what you are doing. More advanced scripting is covered in the next post. Sound Hexes for PlaySound/Play... again, C# reference of known commands and parameter length, from NPRE's source . Biggest database of known commands.
Kaphotics Posted May 4, 2013 Author Posted May 4, 2013 (edited) . Common Use Scripts & Snippets of Large Ones Simple NPC Interaction [color="blue"]2E 00[/color] -- [color="red"]LockAll[/color] [color="blue"]A6 00[/color] [color="green"]47 05[/color] -- [color="red"]PlaySound Clink[/color] [color="blue"]74 00[/color] -- [color="red"]FacePlayer[/color] [color="blue"]3D 00[/color] [color="green"]00 04 0A 00 00 00 00 00[/color] -- [color="red"]Message2[/color][color="orange"], current text file, text line 0xA, default settings[/color] [color="blue"]32 00[/color] -- [color="red"]WaitKeypress[/color] [color="blue"]3F 00[/color] -- [color="red"]CloseMessage2[/color] [color="blue"]30 00[/color] -- [color="red"]WaitDelay[/color] [color="blue"]2F 00[/color] -- [color="red"]UnlockAll[/color] [color="blue"]02 00[/color] -- [color="red"]End[/color] NPC that you didn't interact with says a message: ... You can't use FacePlayer. [color="blue"]3C 00[/color] [color="green"]00 04 02 00 01 00 00 00 00 00[/color] [color="red"]Message[/color] [color="orange"]current text file, line 0x0002, NPC 0x0001 (from overworld #), default view/type[/color] [color="blue"]32 00[/color] [color="red"]WaitKeypress[/color] [color="blue"]3E 00[/color] [color="red"]CloseMessage[/color] ... YesNo Box - Saying No ends the conversation ... [color="blue"]47 00[/color] [color="green"]10 80[/color] [color="red"]PopYesNo[/color] [color="orange"]Store Result@Var10[/color] [color="blue"]09 00[/color] [color="green"]10 80[/color] [color="orange"]Internalize Var10[/color] [color="blue"]08 00[/color] [color="green"]00 00[/color] [color="orange"]Compare to 0 (yes=true=0)[/color] [color="blue"]11 00[/color] [color="green"]01 00[/color] [color="orange"]Condition Equal[/color] [color="blue"]1F 00[/color] [color="green"][b][u]FF[/u][/b][/color] [color="purple"]06 00 00 00[/color] [color="orange"]If False, Jump 0x00000006 to #no[/color] [color="blue"]1E 00[/color] [color="purple"]14 00 00 00[/color] [color="orange"]Jump 0x00000014 to #body[/color] [color="blue"]3D 00[/color] [color="green"]00 04 02 00 00 00 00 00[/color] [color="orange"]##no Message (line 2)[/color] [color="blue"]32 00[/color] [color="red"]WaitKeypress[/color] [color="blue"]3F 00[/color] [color="red"]CloseMessage2[/color] [color="blue"]30 00[/color] [color="red"]WaitMoment[/color] [color="blue"]2F 00[/color] [color="red"]ReleaseAll[/color] [color="blue"]02 00[/color] [color="Red"]End[/color] [color="blue"]A6 00[/color][color="green"] 47 05[/color] [color="orange"]##body Sound Clink[/color] [color="blue"]3D 00[/color][color="green"] 00 04 03 00 00 00 00 00[/color] [color="orange"]Message (line 3)[/color] [color="blue"]32 00[/color] [color="Red"]WaitKeypress[/color] [color="blue"]3F 00[/color] [color="Red"]CloseMessage2[/color] ... proceed... YesNo box script in action: [video=youtube;8tBDVstp1hM] GiveItem ... [color="blue"]09 00[/color] [color="green"]00 80[/color] [color="red"]StoreVar[/color] [color="orange"]0x8000[/color] [color="blue"]09 00[/color] [color="green"]01 80[/color] [color="red"]StoreVar[/color] [color="orange"]0x8001[/color] [color="blue"]2A 00[/color] [color="green"]00 80 32 00[/color] [color="orange"]Item # to give[/color] [color="blue"]2A 00[/color] [color="green"]01 80 01 00[/color] [color="orange"]Amount to give[/color] [color="blue"]1C 00[/color] [color="green"]F5 0A[/color] [color="red"]CallStd[/color] [color="orange"]'give item'[/color] [color="blue"]0A 00[/color] [color="green"]01 80[/color] [color="red"]ClearVar[/color] [color="orange"]0x8000[/color] [color="blue"]0A 00[/color] [color="green"]00 80[/color] [color="red"]ClearVar[/color] [color="orange"]0x8000[/color] ... Another one which says the quantity but no colored item text ... [color="blue"]09 00[/color] [color="green"]00 80 [/color] [color="red"]StoreVar[/color] [color="orange"]0x8000[/color] [color="blue"]09 00[/color] [color="green"]01 80 [/color] [color="red"]StoreVar[/color] [color="orange"]0x8000[/color] [color="blue"]2A 00[/color] [color="green"]01 80 02 00 [/color] [color="orange"]Item # to give[/color] [color="blue"]2A 00[/color] [color="green"]00 80 0F 00 [/color] [color="orange"]Amount to give[/color] [color="blue"]1C 00[/color] [color="green"]01 0B[/color] [color="red"]CallStd[/color] [color="orange"]'give item2'[/color] [color="blue"]0A 00[/color] [color="green"]01 80[/color] [color="red"]ClearVar[/color] [color="orange"]0x8001[/color] [color="blue"]0A 00[/color] [color="green"]00 80[/color] [color="red"]ClearVar[/color] [color="orange"]0x8000[/color] Edited May 9, 2013 by Kaphotics
Kaphotics Posted May 4, 2013 Author Posted May 4, 2013 (edited) . Useful Large Scripts (Trainer / Wild Battles) Trainer Battle [color="blue"]85 00[/color] [color="green"]2D 03 00 00 00 00[/color] [color="red"]SingleTrainerBattle[/color] [color="orange"](813 - Colress), trainer2 = none, params=none[/color] ---Battle Ends, script continues--- [color="blue"]8D 00[/color] [color="green"]10 80[/color] [color="orange"]StoreBattleResult to var 0x8010[/color] [color="blue"]09 00[/color] [color="green"]10 80[/color] [color="orange"]StoreVar 0x8010[/color] [color="blue"]08 00[/color] [color="green"]01 00[/color] [color="orange"]CompareTo 0x01[/color] [color="blue"]11 00[/color] [color="green"]01 00[/color] [color="orange"]Condition 0x01 (notEQ)[/color] [color="blue"]1F 00[/color] [color="green"]FF[/color] [color="purple"]08 00 00 00 [/color] [color="orange"]Incapacitation logic (return to pokecenter, etc)[/color] [color="blue"]8E 00[/color] [color="orange"]and eventually restore to Overworld if won[/color] [color="blue"]1E 00[/color] [color="purple"]02 00 00 00[/color] [color="blue"]8C 00[/color] PKM Battle [color="blue"]74 01[/color] [color="green"]7D 02 41 00 01 00 [/color] [color="red"]StartWildBattle[/color] [color="orange"]dex=0x027D @ level 0x41, parameters=0x0001[/color] ---Battle Ends, script continues--- [color="blue"]77 01[/color] [color="green"]10 80[/color] [color="orange"]Check if KO'd[/color] [color="blue"]09 00[/color] [color="green"]10 80[/color] [color="blue"]08 00[/color] [color="green"]01 00[/color] [color="blue"]11 00[/color] [color="green"]01 00[/color] [color="blue"]1F 00[/color] [color="green"]FF[/color] [color="purple"]14 00 00 00[/color] [color="orange"]Incapacitation Logic[/color] [color="blue"]23 00[/color] [color="green"]A0 03[/color] [color="orange"]Set disablespawn flag[/color] [color="blue"]23 00[/color] [color="green"]94 01[/color] [color="orange"]Set encountered at least once flag[/color] [color="blue"]6C 00[/color] [color="green"]00 00[/color] [color="orange"]Remove NPC[/color] [color="blue"]75 01[/color] [color="red"]EndWildBattle[/color] [color="blue"]1E 00[/color] [color="purple"]02 00 00 00[/color] [color="blue"]76 01[/color] [color="red"]EndWildBattle1[/color] [color="blue"]78 01[/color] [color="green"]10 80[/color] [color="blue"]19 00[/color] [color="green"]10 80 00 00[/color] [color="orange"]Check if captured[/color] [color="blue"]1F 00[/color] [color="green"]01[/color] [color="purple"]06 00 00 00[/color] [color="blue"]1E 00[/color] [color="purple"]0A 00 00 00[/color] [color="blue"]23 00[/color] [color="green"]93 01[/color] [color="orange"]Set captured flag, goto end[/color] [color="blue"]1E 00[/color] [color="purple"]30 00 00 00[/color] [color="blue"]19 00[/color] [color="green"]10 80 01 00[/color] [color="orange"]Check if player was defeated?[/color] [color="blue"]1F 00[/color] [color="green"]01[/color] [color="purple"]13 00 00 00 [color="blue"]19 00[/color] [color="green"]10 80 02 00[/color] [color="orange"]Check if defeated[/color] [color="blue"]1F 00[/color] [color="green"]01 [color="purple"]06 00 00 00[/color] [color="orange"]Goto #defeated[/color] [color="blue"]1E 00[/color] [color="purple"]10 00 00 00 [/color] [color="orange"]Goto end[/color] [color="blue"]34 00[/color] [color="green"]01 00 02 00[/color] [color="orange"]#defeated pkm, message flew away.[/color] [color="blue"]32 00[/color] [/color] [color="blue"]36 00[/color] [/color] [color="blue"]1E 00[/color] [color="purple"]00 00 00 00[/color] [color="orange"]Goto end[/color] [color="blue"]30 00 2F 00 02 00[/color] 00 00 end --- Other Useful Scripts (Trades / PokeMart) .. coming soon .. Edited May 4, 2013 by Kaphotics
Kaphotics Posted May 4, 2013 Author Posted May 4, 2013 (edited) . NPC Manipulation (Add / Remove / MOVE) NPCs are referred to with an 8 bit number, based off of their overworld data. The hero is always 0xFF (entry 255), and the map's overworld NPCs start at 0x00+ Adding and Removing an NPC: Overworld Add/Remove: You can add and remove an NPC based on its overworld ID. [color="blue"]006B[/color] [color="red"]AddNPC[/color][color="green"] - u16: NPC ID[/color] [color="blue"]6B 00[/color] [color="green"]0A 00[/color] Add NPC ID=0x0A ===== [color="blue"]006C[/color] [color="red"]RemoveNPC[/color][color="green"] - u16: NPC ID[/color] [color="blue"]6C 00[/color] [color="green"]0A 00[/color] Remove NPC ID=0x0A Adding only works for NPCs that already exist in the overworld file, but aren't on the map (previously removed, or flag prevented spawn). In order to add a new NPC from scratch, use CreateNPC [color="blue"]0069[/color] [color="red"]CreateNPC[/color][color="green"] - u16: X coordinate - u16: Y coordinate - u16: Face direction - u16: Overworld ID - u16: Sprite Number - u16: Movement Permission[/color] [color="blue"]69 00[/color] [color="green"]01 00 02 00 03 00 41 00 53 00 02 00[/color] make NPC @ (X,Y)=(1,2) facing Right, NPC ID=0x41, sprite=SuitMan, looks around randomly Moving an NPC: You have three methods to move NPCs. 0064 - Applymovement - You can tell them what movements to perform. 006D - RelocateNPC - You can instantly relocate them to new coordinates. 024F - MoveNPC - You can tell them to move coordinates (over a time period) from their current coordinates. ========== 0064 - Applymovement Applymovement has many movement types. Give the NPC a movement and how many times it does that movement. ...time to move an NPC. [color="blue"]64 00[/color] [color="green"]FF 00[/color] [color="purple"]08 00 00 00[/color] ApplyMovement 0xFF~hero (jump 0x00000008, start those movements, continue script) [color="blue"]65 00[/color] WaitMovement [color="blue"]1E 00[/color] [color="purple"]16 00 00 00[/color] Jump (0x00000016) past the movement instructions [color="gold"]01 00 00 00[/color] Face Down for 0 iterations. [color="gold"]4B 00 00 00[/color] Exclamation for 0 iterations (0 or 1 is ok) [color="gold"]17 00 01 00[/color] Shuffle right 1 step (one can always have StoreHeroPosition -> different moves) [color="gold"]14 00 01 00[/color] Shuffle up 1 step [color="gold"]01 00 00 00[/color] Face Down for 0 iterations [u]FE 00 00 00[/u] End Movement Instructions ... continue script List of movement types ========== 006D - RelocateNPC - Used mainly for off-screen relocation of NPCs or between fadeouts. [color="blue"]006D[/color] [color="red"]RelocateNPC[/color][color="green"] - u16: Overworld ID - u16: X coordinate - u16: Y coordinate - u16: Z coordinate - u16: Face direction[/color] [color="blue"]6D 00[/color] [color="green"]00 41 01 00 02 00 00 00 02 00[/color] relocate NPC=0x41 to (X,Y,Z)=(1,2,0), facing left ========== 024F - MoveNPC [color="blue"]024F[/color] [color="red"]MoveNPC[/color][color="green"] - u16: Overworld ID - u16: X coordinate - u16: Y coordinate - u16: Z coordinate - u16: Rapidity (how fast) - u16: Face Direction (not used?)[/color] [color="blue"]4F 02 [/color] [color="green"]FF 00 19 00 0F 00 02 00 0C 00 02 00[/color] relocate NPC=0xFF to (X,Y,Z)=(0x19,0x15,0x02), at speed 0x0C Edited May 4, 2013 by Kaphotics
Kaphotics Posted May 4, 2013 Author Posted May 4, 2013 (edited) . Massive Script Examples Scripted Event [video=youtube;8tBDVstp1hM] Raw Script "Chargestone Cave: HACKED" [video=youtube;z0VLebo1mnk] Raw Script "DRAYNO60S MARVELOUS TRIP THROUGH ISSHU" [video=youtube;XiHALWTQ5Tc] BBVW2 Scripts (by me, not yet in public versions) Force save before continuing the script Random Baby Egg script Edited May 4, 2013 by Kaphotics
Kaphotics Posted May 4, 2013 Author Posted May 4, 2013 . Testing custom scripts in real time Using a Lua script, you can write a script into the game in real time. Using Event Script Writer (scrins.Lua), the script writes a text string (of hex copypasted from a hex editor) directly into the memory. If an NPC were to initiate script 0, the game would read the inserted script rather than the one from the ROM. To use: Save state. Load the script. Stop it for now. Talk to the NPC once so that the default script data is loaded. Use the Overworld Editor script to force all NPCs to use Script 1 (offset 0xA = 0x1). Run the insertion script. Talk to the NPC, custom script runs. Dump of scripting related tutorial resources: pichu2001's tutorial My Video Tutorials ============ Feel free to ask questions related to scripting, whether it be how they work or how to script a certain event.
evandixon Posted May 4, 2013 Posted May 4, 2013 ?????? That's not a question. Don't understand something?
ciprian Posted May 4, 2013 Posted May 4, 2013 That's not a question. Don't understand something? No, I replied to Kaphotics he had written "reserve" and I thought he was talking to me since I was only following the discussion, that's all.
RubyCarbuncle Posted May 5, 2013 Posted May 5, 2013 Interesting, I'm going to start practicing with stuff like this. I'm sure this will be a huge help. Thanks a bunch!
Bond697 Posted June 1, 2013 Posted June 1, 2013 (edited) scrcmd.txt from my info dump in the r&d forum: http://pastebin.com/yhVVej8A the script commands are at the end, starting with cmd 0, s0000. the array at the top is super-important if you're adding commands. it's a 0x2f3 u8 array(matching the number of script commands) of bitflags for each script command that each one is verified against before executing. the verifier works because it changes for every type of script command- moves, AI, effects, and events. it's part of the virtual machine built before execution starts. see here: http://img.thundaga.com/verify.png green is the verifier that runs first then hands off to the command execution in red. 7 is for a normal script command 1 is an assembly command 0 is for non-existant script commands- there are about 90 or 95 non-existent script command numbers, more than enough to add your own. the other flags are for fine-grained stuff and aren't relevant for basically anyone besides me. ex. s0002 ends a script without jumping to the asm handler, so it's a normal script command and is a 7. s0003 pauses the entire script system for a given amount of time- a spinwait kinda thing in C#. it does it via the asm handler in the script virtual machine, so it's a 1 in the verifier array. the main script environment struct virtual machine is @ 224A140 and looks like this: struct ScriptEnvironment { u16 maxStackDepth; u16 maxVars; ScriptCall *cmdArray; u32 cmdMax; u32 unk3; u32 unk4; u32 unk5; u8 stackPointer; u8 executionState; u8 scriptCmpResult; u8 padding; AsmCall funcptr; u8 *script_pos_ptr; u8 *script_stack_ptr; u32 *vars; ScrcmdEnvironment *scrcmd_ptr; ScriptCall script_callback_verifier; void *sys_info; Arc_Tool *script_arc_file_ptr; }; or this if you like it in excel: (see info dump download here for the spreadsheet) Offset Member Size Use 224A140 2257248 224738C 224A004 0x0 Stack size 2 Max size of the script stack- 4 bytes each 0x2 Global/Environment var size 2 Max number of global/script environment vars- 4 bytes each 0x4 Command ptr array 4 Ptr to command array to fetch script functions from 0x8 Command max 4 Total number of commands 0xC 0x10 0x14 0x18 Stack position 1 sp++ every time a value is added to the stack, sp-- when removed 0x19 Environment state 1 Script environment current running state- 0/1/2 end/script/asm 0x1A Compare result 1 Used for loading from compare mode array for conditionals 0x1B Padding 1 Empty, 00 0x1C Asm ptr 4 Ptr to asm routine for script state asm 0x20 Script pos 4 Ptr to current script position to read from 0x24 Stack 4 ptr to stack 0x28 Global/Environment var 4 Global/Environment var ptr 0x2C Scrcmd environment 4 Ptr to info container 0x30 Script callback 4 Ptr to script callback verifier function 0x34 Gamesys 4 Ptr to main gamesystem 0x38 Script file 4 Ptr to beginning of loaded script file via Arc_Tool* the entire core of the script system: (see scriptHandler_main for the actual script handler with notes) http://pastebin.com/zk31sJYg and last, there are up to 4 virtual machines running at once in a struct that looks like this: struct ScriptSystem { u16 vmMax; u16 vmCount; ScriptEnvironment *vmachines[4]; }; vmMax is always 4 and the first element of vmachine struct ptrs will always be 224A140. there's a script command that adds to this and creates submachines off the main one: s001B. (for anyone who hasn't realized it by now, the entire(literally entire) game hinges on a series of structs within structs within structs with structs that are nothing but pointers to other structs. gamefreak is obsessive about it. it also happens to be good practice for an embedded ARM system- reducing literal pools via relative offsetting, etc.) Edited June 2, 2013 by Bond697
Bond697 Posted June 15, 2013 Posted June 15, 2013 (edited) it turns out that the 3 unknowns in my script environment: struct ScriptEnvironment { u16 maxStackDepth; u16 maxVars; ScriptCall *cmdArray; u32 cmdMax; [b]u32 unk3; u32 unk4; u32 unk5;[/b] u8 stackPointer; u8 executionState; u8 scriptCmpResult; u8 padding; AsmCall funcptr; u8 *script_pos_ptr; u8 *script_stack_ptr; u32 *vars; ScrcmdEnvironment *scrcmd_ptr; ScriptCall script_callback_verifier; void *sys_info; Arc_Tool *script_arc_file_ptr; }; are actually the components of a scripting plugin system that gamefreak uses for commands that are very specific to certain contexts in the game. they're plugins that can be switched in when new sub-script environments are started and are "unloaded" when the environment memory is freed. the environment actually looks like this: struct ScriptEnvironment { u16 maxStackDepth; u16 maxVars; ScriptCall *cmdArray; u32 cmdMax; ScriptPlugin plugin; u8 stackPointer; u8 executionState; u8 scriptCmpResult; u8 padding; AsmCall funcptr; u8 *script_pos_ptr; u8 *script_stack_ptr; u32 *vars; ScrcmdEnvironment *scrcmd_ptr; ScriptCall script_callback_verifier; void *sys_info; Arc_Tool *script_arc_file_ptr; }; ScriptPlugin being this: struct ScriptPlugin { ScriptCall *plugin_lut; int plugin_cmd_count; int plugin_min_cmd; // seems to always be 0x3E8(1000d) }; at 0x216C1EC there's a set of 17 registered script plugins. each info set is 0x14 bytes. basically, there's a word in the player data(0x223B370 + 0x2F8) that gets updated when a plugin is needed. that byte is read while the script environment is being built and the right plugin pointer is loaded from the array. that plugin ptr is written to the script virtual machine. then the plugin ptr is run through a verifier function that verifies the plugin and counts the number of commands in it. that number of commands is written to the virtual machine and so is 0x3E8, which is always the minimum script command value. after it's loaded, the script handler and virtual machine run as usual. when they hit a special command from a plugin, it activates an exception handler kind of thing that handles the very high script number and points the handler to the plugin to pull data from. after that command runs, it returns to the main script handler and continues execution commands back and forth between the main script command set and the plugin. Edited June 15, 2013 by Bond697
Bond697 Posted June 15, 2013 Posted June 15, 2013 figuring out which script file a callstd call will use: -take the argument supplied with the callstd and look here: http://pastebin.com/q98R6YfN. -this is a 60 element array of 5 member 16-bit structs. -go down the array of structs looking at the first member of each struct until you find the one where the callstd argument is finally bigger than the first member of the struct. -take the third member of that struct and turn it to decimal. there's your script file number.
na81096 Posted June 19, 2013 Posted June 19, 2013 (edited) Can anyone help me with this script ? In the end of the event, NPCs are not unlocked but if i use bicycle then they are unlocked. I've tried to fix it a lot but it doesn't work Here is the whole script( it is based on Scripted event Kaphotics - Thanks) 2E 00 74 00 A6 00 47 05 4C 00 00 3D 00 00 04 00 00 00 00 00 00 47 00 10 80 09 00 10 80 08 00 00 00 11 00 01 00 1F 00 FF 23 04 00 00 03 00 06 00 98 00 B4 04 3D 00 00 04 01 00 00 00 00 00 32 00 3F 00 1E 00 00 00 00 00 A6 00 47 05 3D 00 00 04 03 00 00 00 00 00 32 00 3F 00 30 00 09 00 00 80 09 00 01 80 2A 00 00 80 01 00 2A 00 01 80 02 00 1C 00 F5 0A 0A 00 01 80 0A 00 00 80 03 00 0F 00 30 00 A6 00 47 05 3D 00 00 04 04 00 00 00 00 00 32 00 3F 00 03 00 04 00 98 00 F3 04 9B 01 6D 00 6C 00 02 00 6C 00 03 00 6C 00 05 00 6C 00 06 00 6C 00 08 00 6D 00 0A 00 74 00 01 00 A8 02 00 00 6D 00 0B 00 76 00 01 00 A8 02 00 00 6D 00 0C 00 78 00 01 00 A8 02 00 00 6D 00 0D 00 7A 00 01 00 A8 02 00 00 AD 01 03 00 0A 00 64 00 FF 00 08 00 00 00 65 00 1E 00 18 00 00 00 01 00 00 00 4B 00 00 00 17 00 01 00 14 00 01 00 01 00 00 00 FE 00 00 00 30 00 3D 00 00 04 06 00 00 00 00 00 32 00 3F 00 64 00 09 00 06 00 00 00 1E 00 10 00 00 00 02 00 00 00 16 00 06 00 15 00 0C 00 FE 00 00 00 03 00 10 00 6C 00 09 00 64 00 0B 00 06 00 00 00 1E 00 0C 00 00 00 9F 00 01 00 4C 00 02 00 FE 00 00 00 03 00 24 00 64 00 0C 00 06 00 00 00 1E 00 08 00 00 00 4C 00 02 00 FE 00 00 00 A6 00 47 05 3C 00 00 04 07 00 0C 00 00 00 00 00 32 00 3F 00 AB 00 7E 01 00 00 64 00 0D 00 06 00 00 00 1E 00 10 00 00 00 4C 00 02 00 4E 00 01 00 00 00 01 00 FE 00 00 00 64 00 0C 00 06 00 00 00 1E 00 10 00 00 00 4D 00 02 00 4F 00 01 00 00 00 01 00 FE 00 00 00 A6 00 47 05 3C 00 00 04 08 00 0B 00 00 00 00 00 32 00 3F 00 AB 00 7F 01 00 00 64 00 0A 00 06 00 00 00 1E 00 10 00 00 00 4C 00 02 00 4F 00 03 00 00 00 01 00 FE 00 00 00 64 00 0B 00 06 00 00 00 1E 00 10 00 00 00 4D 00 02 00 4F 00 01 00 00 00 01 00 FE 00 00 00 6D 00 0E 00 72 00 01 00 9A 02 00 00 6D 00 0F 00 70 00 01 00 9A 02 00 00 03 00 08 00 3C 00 00 04 09 00 0E 00 00 00 01 00 32 00 3F 00 98 00 4D 04 64 00 0E 00 06 00 00 00 1E 00 14 00 00 00 4D 00 0B 00 4F 00 07 00 4C 00 01 00 01 00 01 00 FE 00 00 00 64 00 0F 00 06 00 00 00 1E 00 14 00 00 00 4D 00 0B 00 4F 00 07 00 4C 00 01 00 01 00 01 00 FE 00 00 00 03 00 4C 00 64 00 0A 00 06 00 00 00 1E 00 0C 00 00 00 4D 00 01 00 00 00 01 00 FE 00 00 00 03 00 08 00 64 00 0D 00 06 00 00 00 1E 00 0C 00 00 00 4D 00 01 00 00 00 01 00 FE 00 00 00 03 00 1A 00 64 00 0E 00 06 00 00 00 1E 00 08 00 00 00 02 00 01 00 FE 00 00 00 A6 00 47 05 3C 00 00 04 0A 00 0E 00 00 00 00 00 32 00 3F 00 03 00 0C 00 64 00 0E 00 06 00 00 00 1E 00 0C 00 00 00 01 00 00 00 9C 00 01 00 FE 00 00 00 64 00 0F 00 06 00 00 00 1E 00 08 00 00 00 9C 00 01 00 FE 00 00 00 AC 01 03 00 24 00 A6 00 00 08 98 00 00 00 03 00 4C 00 A9 00 76 05 A7 00 03 00 08 00 AB 00 80 01 00 00 03 00 10 00 AC 00 03 00 2C 00 A6 00 91 05 03 00 1F 00 AB 01 03 00 0C 00 64 00 0E 00 06 00 00 00 1E 00 0C 00 00 00 9B 00 01 00 01 00 00 00 FE 00 00 00 64 00 0F 00 06 00 00 00 1E 00 0C 00 00 00 9B 00 01 00 01 00 00 00 FE 00 00 00 3C 00 00 04 0B 00 0E 00 00 00 00 00 32 00 3F 00 3C 00 00 04 0C 00 0C 00 00 00 00 00 32 00 3F 00 85 00 01 00 00 00 00 00 28 00 20 80 00 00 8D 00 10 80 09 00 10 80 08 00 01 00 11 00 01 00 1F 00 FF 08 00 00 00 8E 00 1E 00 02 00 00 00 8C 00 3C 00 00 04 0E 00 0C 00 00 00 00 00 32 00 3F 00 03 00 0F 00 AC 01 6C 00 0A 00 6C 00 0B 00 6C 00 0C 00 6C 00 0D 00 6B 00 02 00 6B 00 03 00 6B 00 05 00 6B 00 06 00 6B 00 08 00 6C 00 0E 00 6C 00 0F 00 AB 01 03 00 0A 00 34 00 0F 00 02 00 32 00 36 00 1E 00 10 00 00 00 3D 00 00 04 02 00 00 00 00 00 32 00 3F 00 30 00 2F 00 02 00 00 00 BTW, i don't know how to use "Wait command" - 0x03. Sometimes it's 03 00 2A 00 and sometimes it's 03 00 0F 00 What is the diference? I'm confused. Edited June 21, 2013 by na81096
Kaphotics Posted June 19, 2013 Author Posted June 19, 2013 the parameter for 'wait' is essentially like in-game frames. the larger the number, the longer the wait you need to make sure that the script finishes properly. if something isn't done right than the game error handles -> premature quit or bad termination.
na81096 Posted June 19, 2013 Posted June 19, 2013 How can i check that the script doesn't finish and how to correct it? About 'wait', what does it wait for?
evandixon Posted June 19, 2013 Posted June 19, 2013 It sounds like it waits for the specified number of frames to pass. (Frames being each individual picture that compose video.)
evandixon Posted June 20, 2013 Posted June 20, 2013 I don't know, but there's probably 30 frames per second in this game. No more than 60. Possibly slightly less than 30. Unless Kaphotics or someone saves the day with a specific answer, pick a number and see if that's long enough for you.
Kaphotics Posted June 20, 2013 Author Posted June 20, 2013 you can have 0030's any number so long as it's 16 bit. you can have 2 'wait's consecutively too. it's just a way to tune events to feel smoother
na81096 Posted June 20, 2013 Posted June 20, 2013 (edited) Oh thks now I know how to use it. But still having trouble with the script ... I use NPRE to check it and it's OK but in the game at the end it still not unlock everything Can you help me plz ? Edited June 21, 2013 by na81096
Bond697 Posted July 19, 2013 Posted July 19, 2013 0x8011 is the variable that holds the map npc number for the speaking npc - this is usually 0224742A
Andarkvolt Posted September 11, 2013 Posted September 11, 2013 Kaphotics, how to I make the pokemon change the pokemon form with the script that u given me. I edited ur script and I have a keldeo but i dont know how to change it into resolute form... Here is the script 74 01 87 02 32 00 01 10 77 01 00 80 09 00 10 80 08 00 01 00 11 00 01 00 1F 00 FF 14 00 00 00 23 00 A0 03 23 00 94 01 6C 00 00 00 75 01 1E 00 02 00 00 00 76 01 78 01 10 80 19 00 10 80 00 00 1F 00 01 06 00 00 00 1E 00 0A 00 00 00 23 00 93 01 1E 00 30 00 00 00 19 00 10 80 01 00 1F 00 01 13 00 00 00 19 00 10 80 02 00 1F 00 01 06 00 00 00 1E 00 10 00 00 00 32 00 36 00 1E 00 00 00 00 00 30 00 2F 00 02 00 00 00 .
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now