![]() |
|
RGSS-Scripts Postet hier die Scripts die ihr im Script-Editor selbst erstellt oder gefunden habt. Gefundene Scripts jedoch mit Quellenangabe posten! |
![]() |
|
Themen-Optionen |
![]() |
#1 |
23
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() |
![]() Fantasieloser Name, ich weiß.
Inserter versucht das Problem zu lösen, auf das viele beim Skripteinbau treffen. Wo muss das Skript hin? Wie mach ich das? Usw. Ist Inserter erst einmal installiert (als oberstes Skript im Skripteditor), muss man Skripte nur noch als *.rb-Datei in den Ordner Data/Scripts werfen, sie werden automatisch über Main eingefügt. Sollte ein Skriptautor wollen, dass Inserter sein Skript anderswo einfügt, kann er das mit einem einfachen Kommentar am Anfang der Datei erreichen, zum Beispiel: Code:
=begin script Insert_Before "Game_Character" Name "Mein Skript" =end Desweiteren kann man mit folgendem Kommentar existierende Skripte bearbeiten: Code:
=begin block Script "Game_Temp" Insert_After "34" Expect " attr_accessor :battleback_name # battleback file name" =end Sollte ein Einfügen fehlschlagen (z.B. Skript mit angegebenem Namen existiert nicht, Zeile entspricht nicht dem Erwartungswert usw.), wird das in einer Datei protokolliert (abschaltbar). Es sind mehrere Blöcke / Scripte pro Datei möglich, die dann einzeln eingefügt werden. Wird nicht irgendwo am Anfang der Datei (normale Kommentare werden ignoriert) ein Blockkommentar wie oben gefunden, so wird das Skript als ganzes direkt über Main eingefügt. Verzeichnisse unterhalb Data/Scripts werden rekursiv nach Scripten durchsucht. Ein weiterer Clou ist, dass ich meinen ErrorParser hierfür erweitert habe, sodass wenn ein Fehler auftritt selbst bei eingefügten Blöcken der richtige Dateiname und Zeile zurückgegeben wird. Und noch was: ruft man das Spiel mit der Kommandozeile "Game.exe import" auf, so begrüßt einen ein Kommandozeileninterface (das ich gleich noch separat release), mit dem man die Eingefügten Skripte permanent in das Projekt einbauen kann. Sprich, das Skript fügt zuerst die Skriptfetzen ein, und speichert es dann als Scripts.rxdata ab und löscht sich selbst aus der Liste. So kann man auch Massen-Skriptimporte machen ![]() Und das wichtigste ist, dass sich verschiedene Eintragungen nicht konkurrieren können. Wenn wir zum Beispiel dieses Skript hätten: Code:
def if condition do_something else return false end end Code:
=begin block Script "Das da oben" Insert_after "3" Expect " do_something" =end do_something_else do_something_completely_different Code:
=begin block Script "Das da oben" replace "5" Expect " return false" =end return true Genug geschwafelt, hier das Skript: Code:
#============================================================================== # ** Inserter #------------------------------------------------------------------------------ # This scripts automatically scans the folder Data/Scripts and inserts those # files into the scripts list by meta informations provided in these scripts. # It also takes care that the script error messages are formatted correctly. #============================================================================== class Range def length self.end - self.begin + (self.exclude_end? ? 0 : 1) end end module Inserter # Determines when to show a warning and log any errors. # Can be :always, :in_debug, or :never WARN_AND_LOG = :in_debug # Filename of the log file. If set to nil, no log will be written, regardless # of the setting above. A warning message might still be shown. LOG_FILE = 'inserter.log' @@scripts = Array.new($RGSS_SCRIPTS.length) def self.scripts() @@scripts; end # Gets the numeric ID for the script with the given name. If that script # doesn't exist, :invalid_script_id is returned. def self.get_script_id(id) $RGSS_SCRIPTS.each_index do |i| if id.is_a? String if not @@scripts[i] and id == $RGSS_SCRIPTS[i][1] id = i break end elsif @@scripts[i] and id >= i id += 1 end end return ((0..$RGSS_SCRIPTS.length - 1) === id) ? id : :invalid_script_id end @@mods = Hash.new do |hash, key| hash[key] = [ [1..$RGSS_SCRIPTS[get_script_id(key)][3].count('\n') + 2, [:internal, 1]] ] end def self.mods() @@mods; end # Modifies an existing script. script_id is either the name or the ID of the # Script, line the line number to modify, action one of # - :delete To delete that line. # - :replace To replace the line's contents with replacement. # - :insert_before To insert replacement before that line. # - :insert_after To insert replacement after that line. # Replacement can be left out (or == nil) if and only if action == :delete. # The modification will only be performed if the original line is the same as # expected. If expected is left out, this check will be left out and the line # is always modified. WARNING: Leaving the expected value out might easily # break other scripts. Not recommended for release versions. # File specifies a script file name. Only code from this file will be # modified. Leave this out or set it to :internal if you want to modify code # from the script editor only. # Filename and start can be supplied to display proper error messages if the # error occurred in the inserted code. # Return values: # - :invalid_script_id script_id was not found in the scripts list # - :invalid_action No valid action supplied (see above) # - :line_not_found The given line was not found in this script (either # index too large or deleted by another script) # - :unexpected_content The given line didn't contain the expected contents # - :success All went well. def self.modify script_id, line, action, replacement = nil, expected = nil, old_name = :internal, new_name = :external, start = 0 if ![:delete, :replace, :insert_before, :insert_after].include? action return :invalid_action end # Find script by name script_id = get_script_id(script_id) return :invalid_script_id if not script_id.is_a? Integer if action == :delete replacement.clear elsif not replacement.empty? # Remove trailing newlines and count lines replacement[-1].chomp! while replacement[-1].empty? replacement.pop break if replacement.empty? replacement[-1].chomp! end end length = replacement.length replacement = replacement.join '' # Find real place to insert insert_at = -1 script = @@mods[script_id] script.each_index do |i| range, place = script[i] if insert_at == -1 if place[0] == old_name and (place[1]..place[1]+range.length-1)===line insert_at = i; line += range.begin - place[1] end end end return :line_not_found if insert_at == -1 lines = $RGSS_SCRIPTS[script_id][3].split(/\r?\n/) if expected == nil or lines[line - 1] == expected case action when :delete then lines.delete_at line - 1 when :replace then lines[line - 1] = replacement when :insert_before, :insert_after line += 1 if action == :insert_after lines.insert line - 1, replacement end else return :unexpected_content end $RGSS_SCRIPTS[script_id][3] = lines.join("\n") range, place = script[insert_at] if line > range.begin script.insert(insert_at, [range.begin...line, place.dup]) insert_at += 1 end if length > 0 script.insert(insert_at, [line...line+length, [new_name, start]]) insert_at += 1 end shift = ((action == :delete or action == :replace) ? 1 : 0) place[1] += line - range.begin + shift if line + length >= range.end + length - shift script.delete_at(insert_at) insert_at -= 1 else script[insert_at][0] = Range.new( line + length, range.end + length - shift, range.exclude_end? ) end length -= shift if length != 0 (insert_at+1..script.length-1).each do |i| # Move range back range = script[i][0] script[i][0] = Range.new( range.begin + length, range.end + length, range.exclude_end? ) end end return :success end # Inserts a new script. script_id is either the name or the ID of the # Script that will be used as a reference point, action is one of # - :delete To delete that script. # - :replace To replace that script with the new one. # - :insert_before To insert new script before that one. # - :insert_after To insert new script after that one. # Script can be left out (or == nil) if and only if action == :delete. # If the name is left out, either the old name will remain (when # status == :overwrite), or else the new script's name will stay empty. # Return values: # - :invalid_script_id script_id was not found in the scripts list # - :invalid_action No valid action supplied (see above) # - :success All went well. def self.insert script_id, action, script = nil, name = nil, filename = nil, line = nil if ![:delete, :replace, :insert_before, :insert_after].include? action return :invalid_action end # Find script by name script_id = get_script_id(script_id) return :invalid_script_id if not script_id.is_a? Integer case action when :delete @@scripts.delete_at script_id $RGSS_SCRIPTS.delete_at script_id return :success when :replace then @@scripts[script_id] = [filename, line] s_array = $RGSS_SCRIPTS[script_id] when :insert_before, :insert_after script_id += 1 if action == :insert_after @@scripts.insert script_id, [filename, line] $RGSS_SCRIPTS.insert script_id, [0, (name or ''), '', (script.join '')] end return :success end end #============================================================================== # ** Insert scripts #------------------------------------------------------------------------------ # This script uses the class defined above to insert scripts into the script # list. It also creates a log file according to the log settings above. #============================================================================== # Delete this script $RGSS_SCRIPTS.shift main_id = $RGSS_SCRIPTS.length - 1 # Import mode commandline = Win32API.new('kernel32', 'GetCommandLine', ['v'], 'P').call $IMPORT = (commandline.downcase[/\bimport\b/] != nil) # Cycle scripts in Scripts folder log = ($IMPORT or ( Inserter::WARN_AND_LOG == :always or ($DEBUG and Inserter::WARN_AND_LOG == :in_debug) )) errors = [] if log k = -1 Dir["Data/Scripts/**/*.rb"].sort.each do |filename| catch :next_file do script = File.readlines filename mode = :pretext options = nil script.each_index do |i| line = script[i].dup if mode == :pretext_comment # End pretext comment blocks when =end found or go to next line mode = :pretext if line[/^=end\s+/] next end # Ignore comments and newlines in the beginning if mode == :pretext mode = :pretext_comment if m=line[/^=begin(?!\s+(?i:(script|block)))/] next if m or line[/^\s*(#.*)?$/] end # Determine if we're in the last line of the script lastline = (i == script.length - 1) # Read header line if mode == :header # Header end if line[/^=end(\s|$)/] # Add missing information options[2 + k] = [] options[0] = main_id unless options[0] options[1 + k] = :insert_before unless options[1 + k] # (+2 because i is 0-based index, and we ignore the =end line) options[5 + 2*k] = i + 2 if k == 1 # modify mode if not options[1] options[1] = case options[2] when :insert_before then 0 when :insert_after $RGSS_SCRIPTS[get_script_id(options[0])].count("\n") + 1 end # Memorize the starting line of the inserted code insert_start = i end options[5] = :internal unless options[5] end mode = :body # Start to read the next line, or insert nothing if EOF lastline ? (line = nil) : next elsif options.length == 6 line.scan(/\s* (delete|replace|insert_(?:after|before)|name)\s+ "([^"]+)"\s+ /ix) do |command, value| command.downcase! if command == 'name' options[3] = value else options[1] = command.to_sym options[0] = value.to_i end end else line.scan(/\s* (script|file|delete|replace|insert_(?:after|before)|expect)\s+ "([^"]+)"\s+ /ix) do |command, value| command.downcase! if command == 'script' options[0] = value elsif command == 'file' options[5] = value elsif command == 'expect' options[4] = value else options[2] = command.to_sym options[1] = value.to_i end end end end # If new subscript started or last line if mode != :header and (lastline or line.sub!(/^=begin\s+(?i:(script|block))/, ' ') ) # Insert old script / block if mode == :body # Append last line options[2 + k] << line if lastline and line result = (options.length == 6) ? Inserter.insert(*options) : Inserter.modify(*options) if log and result != :success errors << [result, *options] end # Continue with next file if EOF throw :next_file if lastline end mode = :header # Start new script / block options = Array.new(6 + 2*(k = ($1 == "block") ? 1 : 0)) options[4 + 2*k] = filename # Sourcecode in pretext mode means single script file elsif mode == :pretext # Insert complete script above main result = Inserter.insert(main_id, :insert_before, script, File.basename(filename, '.rb'), filename, 0 ) if log and result != :success errors << [result, *options] end throw :next_file end options[2 + k] << line if mode == :body end end end p Inserter.mods # Log errors if log if Inserter::LOG_FILE File.open Inserter::LOG_FILE, 'w' do |file| errors.each do |error, *options| error = case error when :invalid_script_id "Script '#{options[0]}' not found in script collection." when :invalid_action then "Invalid action '#{action}'." when :line_not_found "Line #{options[1]} couldn't be found in script '#{options[0]}'. "+ 'Either the line number is too large or it has been removed by a '+ 'different script.' when :unexpected_content "Unexpected content in line #{options[1]} of script "+ "'#{options[0]}'. Maybe the script has been modified manually." else "Unknown reason" end if options.length == 6 # Script insertion error file.printf("[file '%s'] Script '%s' could not be inserted: %s\n", options[4], options[3], error) else # Script modification error file.printf("[file '%s'] Script '%s' could not be modified: %s\n", options[5], options[0], error) end end end end if errors.length > 0 print 'Some scripts could not be inserted or modified.' + (Inserter::LOG_FILE ? "\nSee '#{Inserter::LOG_FILE}' for details." : '') end end #============================================================================== # ** RGSS Command line interface #------------------------------------------------------------------------------ # If you start your game with the command line parameter Import, a command # line (DOS-like) interface is shown that will help you to import scripts # permanently. #============================================================================== # Import section if $IMPORT class CommandLine def self.start font_size = 20, &block new.instance_eval &block end def initialize font_size = 20 @font_size = font_size @s = Sprite.new @s.bitmap = Bitmap.new 640, 480 + [email protected]_size @s.bitmap.font.size = @font_size @row_count = 480 / @font_size @row = 0 end def puts *texts # Prepare for transition Graphics.freeze texts = texts[[email protected]_count, @row_count] if texts.length > @row_count too_many = @row - @row_count + texts.length if too_many > 0 b = Bitmap.new 640, 480 + [email protected]_size b.font.size = @font_size b.font.color = @s.bitmap.font.color b.blt 0, [email protected]_size*too_many, @s.bitmap, @s.bitmap.rect @s.bitmap, b = b, @s.bitmap b.dispose @row = @row_count - too_many end texts.each do |text| @s.bitmap.draw_text 0, @row * @font_size - 3, 640, [email protected]_size, text @row += 1 if @row < @row_count end # Execute transition Graphics.transition(5) end def note *texts @s.bitmap.font.color.set 0, 255, 0 puts *texts @s.bitmap.font.color.set 255, 255, 255 end def warning head, *texts @s.bitmap.font.color.set 255, 140, 0 puts 'WARNING: ' + head, *texts @s.bitmap.font.color.set 255, 255, 255 end def error head, *texts @s.bitmap.font.color.set 255, 0, 0 puts 'ERROR: ' + head, *texts @s.bitmap.font.color.set 255, 255, 255 end def cls @s.bitmap.clear @row = 0 end def read puts ' (Enter = yes, Esc = no)' loop do Input.update if Input.trigger? Input::B return :no elsif Input.trigger? Input::C return :yes end Graphics.update end end def sleep time start = Graphics.frame_count loop do Graphics.update if Graphics.frame_count - start == time break end end end def pause puts ' (Press any key to continue)' loop do Input.update for i in 1..18 if Input.trigger?(i) return end end Graphics.update end end def exit puts '', 'Goodbye!' pause Graphics.freeze @s.bitmap.dispose @s.dispose Graphics.transition 20 exit! 0 end end CommandLine.start do puts 'Inserter - Import mode', '' warning 'This is beta quality software. If something goes wrong,', 'don\'t blame me!', '' puts 'Import mode can be used to permanently import the scripts from', 'the Data/Scripts directory into the project. This can be useful', 'if you want to encrypt your project.' sleep 40 puts '', 'Continue?' exit if read == :no if errors.length > 0 puts '' warning "Inserter reported #{errors.length} errors while inserting", 'the scripts. If you continue, results might be erroneous!' puts '', 'Do you really want to import a partially failed insertion?' exit if read == :no end puts '','If you press enter now, the modified scripts will be written to', 'Data/Scripts.rxdata. A backup copy will be created with the file', 'name Data/Scripts.rxdata.bakxxx, where xxx is an unused number.', 'After this process is finished, the Data/Scripts folder is no', 'longer needed (and will be ignored). Only start the import if you', 'don\'t want to add other Inserter scripts later!' sleep 40 puts '', 'Do you want the import to be performed now?' exit if read == :no puts '', 'Creating backup copy...' backupname = 'Data/Scripts.rxdata.bak000' while File.exist? backupname backupname = backupname.succ end begin File.open backupname, 'wb' do |file| file.write (File.open 'Data/Scripts.rxdata', 'rb' do |file| file.read end) end rescue error 'Failed to create the backup copy.', 'See error message for more information.' pause raise end note "Successfully created backup #{backupname}." puts '', 'Re-compressing all scripts...' begin $RGSS_SCRIPTS.collect! do |script_ary| script_ary[2] = Zlib::Deflate.deflate script_ary[3] script_ary.delete_at 3 script_ary end rescue error 'Re-compression failed.' 'See error message for more information.' pause raise end note 'Successfully re-compressed the scripts.' puts '', 'Saving scripts to Data/Scripts.rxdata...' begin File.open 'Data/Scripts.rxdata', 'wb' do |file| Marshal.dump $RGSS_SCRIPTS, file end rescue error 'Failed to save the scripts file.' 'See error message for more information.' pause raise end note 'Successfully wrote Data/Scripts.rxdata.' puts '', 'The scripts have been imported. Re-open the project in RPGXP to', 'see the changes. If all went well, the scripts should be present', 'in the Script Editor. If everything\'s there, you can delete the', "Data/Scripts folder and #{backupname}." exit end end #============================================================================== # ** ErrorParser #------------------------------------------------------------------------------ # This improves the error messages in debug mode. You can change the message # templates to your likings (for both debug and normal mode). # Supports errors in external files. #============================================================================== module ErrorParser # This is the template for the message shown in debug mode. # CLASS, FILETYPE, FILENAME, LINE, METHOD, MESSAGE and TRACE get replaced # by the relevant information about the error. TEMPLATE_DEBUG = <<STRING CLASS occurred! FILETYPE: FILENAME Line: LINE SOURCETYPE: SOURCE Message: MESSAGE Trace: TRACE STRING # This is the template for the message shown in normal mode. # You can use all of the variables from above. TEMPLATE_DEFAULT = "FILETYPE 'FILENAME' line LINE: CLASS occurred!\n\nMESSAGE" # This will be used as the template for an entry in the stack trace. # CLASS, MESSAGE, and TRACE cannot be used here. TEMPLATE_TRACE_ENTRY = "FILETYPE 'FILENAME' line LINE (SOURCETYPE SOURCE)" # This is the template for line numbers in events. TEMPLATE_EVENT_LINE = "COMMAND/LINE" # This is the FILETYPE for scripts in Scripts.rxdata FILETYPE_SCRIPT = 'Script' # This is the FILETYPE for scripts called from an event FILETYPE_EVENT = 'Event' # This is the FILETYPE for otherwise evaled scripts FILETYPE_UNKNOWN = 'Unknown source' # This is the FILETYPE for external Ruby scripts (if used). FILETYPE_FILE = 'File' # This is the SOURCETYPE for methods in a script or file SOURCETYPE_METHOD = 'Method' # This is the SOURCETYPE for script calls from events SOURCETYPE_MAP = 'Map' # This is the SOURCETYPE for code from main block or class body SOURCETYPE_MAIN = 'In' # This will be used whereever we fail to parse the error correctly. UNKNOWN = '<unknown>' # Modifies the Main script to pass any errors to ErrorParser MAIN_CODE = <<CODE rescue ErrorParser.exit_with_message CODE $RGSS_SCRIPTS[-1][3].insert( $RGSS_SCRIPTS[-1][3].rindex('rescue'), MAIN_CODE ) # Modifies the Interpreter script to output extra error information or # errors in Call Script commands INTERPRETER_CODE = <<CODE begin eval script rescue $!.message.insert(5, ":\[email protected]_id}:\[email protected]_id}:\[email protected] + 1}:\#{$!.message[7, 1]}" ) raise end CODE $RGSS_SCRIPTS.each do |a| if a[1] == "Interpreter 7" a[3].sub! 'eval(script)', INTERPRETER_CODE break end end # Perform new error handling def self.exit_with_message error_message = $DEBUG ? TEMPLATE_DEBUG : TEMPLATE_DEFAULT exit_code = if $!.message.slice! /\A\(eval((?::\d+){4})?\)(:\d+:in `[^']*')/ if $1 top = $1.split ':' top.shift else top = $2 end ErrorParser.fill_template error_message, top else ErrorParser.fill_template error_message, $!.backtrace[0].dup end error_message.sub! 'CLASS', $!.class.to_s error_message.sub! 'MESSAGE', $!.message if error_message['TRACE'] error_message.sub! 'TRACE', ( ErrorParser.parse_backtrace($!.backtrace) ).join("\n") end print error_message # Add 1 because we deleted the first script exit! exit_code + (1 << 16) end # Write the backtrace items into the template def self.parse_backtrace trace if trace trace.collect do |trace_line| line = TEMPLATE_TRACE_ENTRY.dup ErrorParser.fill_template line, trace_line line end else [] end end # Transform the entries of caller as well for Debugging module ::Kernel alias old_caller caller def caller ErrorParser.parse_backtrace old_caller end end private # Fill the error template with values from a backtrace entry def self.fill_template template, trace if trace.is_a? Array source, name, command_id, line_number = trace filetype = FILETYPE_EVENT line = TEMPLATE_EVENT_LINE line.sub! 'COMMAND', command_id line.sub! 'LINE', line_number sourcetype = SOURCETYPE_MAP else script_id = trace.slice!(/\ASection(\d+)/) ? $1.to_i : nil line = trace.slice!(/\A:(\d+)/) ? $1.to_i : nil if script_id if defined? Inserter and (s = Inserter.scripts[script_id]) filetype = FILETYPE_FILE name = s[0]; line += s[1] else exit_code = (script_id << 16) filetype = FILETYPE_SCRIPT name = $RGSS_SCRIPTS[script_id][1] if line.is_a? Integer if defined? Inserter and Inserter.mods.include?(script_id) Inserter.mods[script_id].each do |range, place| if range === line case place[0] when :external filetype = FILETYPE_UNKNOWN name = 'inserted script' when String filetype = FILETYPE_FILE name = place[0] end p line, place[1], range.begin line += place[1] - range.begin break end end end exit_code += line end end else filetype = if trace.slice!(/\A(?:\.\/)?([^:]*)/).length > 0 name = $1 FILETYPE_FILE else name = 'evaluated' FILETYPE_UNKNOWN end end if trace[/\A:in `(.+)'\z/] sourcetype = SOURCETYPE_METHOD source = $1 else sourcetype = SOURCETYPE_MAIN source = 'main' end end template.sub! 'FILETYPE', (filetype or UNKNOWN) template.sub! 'FILENAME', name template.sub! 'LINE', line.to_s template.sub! 'SOURCETYPE', sourcetype template.sub! 'SOURCE', source (filetype == FILETYPE_SCRIPT) ? exit_code : 0 end end begin i = 0 while i < $RGSS_SCRIPTS.length eval($RGSS_SCRIPTS[i][3], self, sprintf('Section%03d', i), 1) i += 1 end exit! 0 rescue ErrorParser.exit_with_message end
__________________
"So, und jetzt Schluss mit dem Lamentieren - lasst uns etwas Kunst machen!!!" - GS_Raphael Geändert von derula (18.10.2009 um 16:04 Uhr). |
![]() |
![]() |
![]() |
#2 |
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Registriert seit: 04.10.2007
Ort: Österreich/Salzburg/Pongau
Alter: 23
Beiträge: 1.183
Blog-Einträge: 1
|
![]() derula, ich muss dir wirklich mal ein Kompliment aussprechen für die vielen grandiosen und innovativen Skripte, die du im Moment "auf den Markt wirfst".
Wäre alles genau mein Ding, wenn ich mit dem RMXP makern würde! ![]() mfG Cherry
__________________
|
![]() |
![]() |
![]() |
#3 | |
23
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() |
![]() Zitat:
![]() Übrigens kommt heute noch ein Bugfix... hoffe ich. Der delete-Befehl zum Beispiel funktioniert überhaupt nicht so richtig. Edit: Habe nun oben die Bugfix-Version eingefügt. Replace und Delete sollten nun funktionieren. Zusätzlich gibt es einen neuen Parameter: File. Wie oben beschrieben, kann ein Skript nicht beliebig andere Skripte bearbeiten. Mit Angabe des Dateinamens ist das nun trotzdem möglich. Dabei bezieht sich die Zeilenangabe auf die Zeilennummer in der ursprünglichen Datei. Funktioniert nur für Blöcke, keine Skripte.
__________________
"So, und jetzt Schluss mit dem Lamentieren - lasst uns etwas Kunst machen!!!" - GS_Raphael |
|
![]() |
![]() |
![]() |
Lesezeichen |
Aktive Benutzer in diesem Thema: 1 (Registrierte Benutzer: 0, Gäste: 1) | |
Themen-Optionen | |
|
|
![]() |
||||
Thema | Autor | Forum | Antworten | Letzter Beitrag |
MGK - Magic GUI Kit - BETA | MagicMagor | RGSS-Scripts | 5 | 12.03.2007 14:23 |