• Our software update is now concluded. You will need to reset your password to log in. In order to do this, you will have to click "Log in" in the top right corner and then "Forgot your password?".
  • Welcome to PokéCommunity! Register now and join one of the best fan communities on the 'net to talk Pokémon and more! We are not affiliated with The Pokémon Company or Nintendo.

Tool: Python Pokemon Scripting

Full Metal

C(++) Developer.
810
Posts
16
Years
  • This is just a fun experiment on my part. Something that troubled me when I was more active in the ROM hacking scene was that scripting many practical things involved annoying practices (re: loops, and similar.)

    My solution for this is fairly simple: create a pre-processor / compiler. Obviously I didn't want to put effort into writing a lexer or anything; others exist and are far better than one I could make. So I made a super simple library in python that would allow you to use python to make pokemon scripts (though it could easily be modified to make something like brainfuck or other vm based languages.)

    The github repository can be found here.

    Here's the code from my sample script which displays a text box at some arbitrary location:

    Code:
    import frlg
    from scripting import script_section
    
    @script_section
    def sample_text_display(text_location):
    	yield frlg.lock()
    	yield frlg.faceplayer()
    	yield frlg.preparemsg(text_location)
    	yield frlg.closeonkeypress()
    	yield frlg.release()
    	yield frlg.end()
    
    if __name__=="__main__":
    	import sys
    	# I don't actually know of any text locations off the top of my head lol
    	TEXT_LOCATION = 0x08123456
    	if len(sys.argv) > 1:
    		TEXT_LOCATION = int(sys.argv[1])
    	sys.stdout.buffer.write(sample_text_display(TEXT_LOCATION))

    I created the frlg module using data provided here. that I extracted using this javascript in the browser console window:

    Code:
    function translate_command_entry(entry_element) {
    	arg_els = entry_element.querySelectorAll(".args > ul > li");
    	r = {args:[],structure:"<B",cmd:0,doc_string:"",name:''}
    	for(var i=0;i<arg_els.length;i++) {
    		a = {}
    		a['kind'] = arg_els[i].querySelector("span:first-child").textContent;
    		a['name'] = arg_els[i].lastChild.nodeValue;
    		r.args.push(a)
        }
    	h = entry_element.querySelector("h3").textContent
    	r['cmd'] = parseInt('0x' +h);
    	name_start = h.indexOf(' ') + 1;
    	name_end = h.indexOf(' ',name_start);
    	if(name_end < 0) {
    		r['name'] = h.slice(name_start);
        } else {
    		r['name'] = h.slice(name_start,name_end);
        }
    	doc_els = entry_element.querySelectorAll("p");
    	for(var i =0;i<doc_els.length;i++) {
    		r['doc_string'] += doc_els[i].textContent;
    		r['doc_string'] += '\n\n';
        }
    	kind_to_struct_tbl = {
    		word: "H",
    		byte: 'B',
    		dword: 'I',
    		pointer: 'I',
    		variable: 'H',
    		flag: 'H',
    		bank: 'B',
    		buffer: 'B',
    		'hidden-variable': 'B',
    		'pointer-or-bank': 'I',
    		'pointer-or-bank-0': 'I',
    		'flag-or-variable': "H",
    		'word-or-variable': "H",
    		'byte-or-variable': 'H'
    	}
    	for(var i=0;i<r['args'].length;i++) {
    		r['structure'] += kind_to_struct_tbl[r['args'][i]['kind']];
    		r['doc_string'] += r['args'][i]['kind'] + ':\t' + r['args'][i]['name'] + '\n';
        }
    	r['doc_string'] = r['doc_string'].trim();
    	return r;
    }
    
    var all_cmds = [];
    for(var i=0;i<e_list.length;i++) {
    	all_cmds.push(translate_command_entry(e_list[i]));
    }
    
    clear();
    console.log(JSON.stringify(all_cmds))

    Usage is simple enough:
    Code:
    sample.py >script.bin

    Which will (currently) give you a compiled bytecode that you can paste in a hex editor. Plans for the future involve a free space searcher which will allow you to reference other script blocks that are dynamically allocated and output this as an IPS patch, or Darthatrons patch format which is easily undone, which allows for simpler debugging.

    If I really want to make this thing cool, I will add memory inspection for VBA to modify the ROMS runtime memory, but I would not hold my breath as that's a lot of effort and time I don't have really.

    If you would like to contribute, making a json file similar to the one I made for fr/lg for other games would be appreciated. I believe many of the commands are shared, but I don't know for sure which ones are and are not.
     
    Back
    Top