burn 0.1.3 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. data/README.md +56 -569
  2. data/lib/burn.rb +5 -3
  3. data/lib/burn/cli.rb +160 -199
  4. data/lib/burn/config.rb +4 -0
  5. data/lib/burn/config/app.rb +15 -0
  6. data/lib/burn/config/config_base.rb +16 -0
  7. data/lib/burn/config/loader.rb +23 -0
  8. data/lib/burn/config/server.rb +11 -0
  9. data/lib/burn/fuel.rb +11 -0
  10. data/lib/burn/{dsl → fuel}/dsl_base.rb +1 -1
  11. data/lib/burn/fuel/rom/channel_stream.rb +106 -0
  12. data/lib/burn/fuel/rom/declare.rb +43 -0
  13. data/lib/burn/fuel/rom/music.rb +37 -0
  14. data/lib/burn/fuel/rom/note.rb +126 -0
  15. data/lib/burn/fuel/rom/scene.rb +279 -0
  16. data/lib/burn/fuel/rom/sound.rb +31 -0
  17. data/lib/burn/fuel/rom/sound_effect.rb +92 -0
  18. data/lib/burn/fuel/telnet/declare.rb +26 -0
  19. data/lib/burn/fuel/telnet/scene.rb +112 -0
  20. data/lib/burn/generator.rb +10 -3
  21. data/lib/burn/generator/rom/assembly_music.rb +49 -0
  22. data/lib/burn/generator/rom/assembly_sound_effect.rb +35 -0
  23. data/lib/burn/generator/rom/c_source.rb +55 -0
  24. data/lib/burn/generator/{template → rom/template}/mus_template.s +0 -0
  25. data/lib/burn/generator/{template → rom/template}/template.c +0 -0
  26. data/lib/burn/generator/rom_builder.rb +67 -0
  27. data/lib/burn/generator/telnet/jit_compiler.rb +41 -0
  28. data/lib/burn/generator/telnet/screen.rb +86 -0
  29. data/lib/burn/generator/telnet/sprite.rb +16 -0
  30. data/lib/burn/generator/telnet/user_input.rb +25 -0
  31. data/lib/burn/generator/telnet_vm.rb +50 -0
  32. data/lib/burn/pxes.rb +3 -0
  33. data/lib/burn/{util/pxes.rb → pxes/cc65_transpiler.rb} +8 -14
  34. data/lib/burn/pxes/cruby_transpiler.rb +189 -0
  35. data/lib/burn/pxes/transpiler_base.rb +14 -0
  36. data/lib/burn/server.rb +2 -0
  37. data/lib/burn/server/rom.rb +24 -0
  38. data/lib/burn/server/telnet.rb +120 -0
  39. data/lib/burn/util.rb +1 -2
  40. data/lib/burn/util/logo.rb +68 -0
  41. data/lib/burn/util/os.rb +1 -1
  42. data/lib/burn/version.rb +1 -1
  43. metadata +53 -19
  44. data/lib/burn/builder.rb +0 -65
  45. data/lib/burn/dsl.rb +0 -8
  46. data/lib/burn/dsl/channel_stream.rb +0 -105
  47. data/lib/burn/dsl/declare.rb +0 -42
  48. data/lib/burn/dsl/music.rb +0 -36
  49. data/lib/burn/dsl/note.rb +0 -125
  50. data/lib/burn/dsl/scene.rb +0 -278
  51. data/lib/burn/dsl/sound.rb +0 -30
  52. data/lib/burn/dsl/sound_effect.rb +0 -91
  53. data/lib/burn/generator/assembly_music.rb +0 -47
  54. data/lib/burn/generator/assembly_sound_effect.rb +0 -33
  55. data/lib/burn/generator/c_source.rb +0 -54
  56. data/lib/burn/util/server.rb +0 -21
@@ -0,0 +1,31 @@
1
+ module Burn
2
+ module Fuel
3
+ module Rom
4
+ class Sound < DslBase
5
+ def initialize(resource_name, context)
6
+ super(resource_name, context)
7
+
8
+ if resource_name.nil? then
9
+ raise Exception.new "Resource name for Sound class must be provided."
10
+ else
11
+ @resource_name = resource_name
12
+ end
13
+
14
+ @context.instance_exec resource_name, &lambda{|resource_name|
15
+ @resources["#{resource_name}"] = Array.new
16
+ }
17
+
18
+ @se = SoundEffect.new
19
+
20
+ end
21
+
22
+ def effect(&block)
23
+ @context.instance_exec(@resource_name,@se) do |resource_name,se|
24
+ se.load(&block)
25
+ @resources["#{resource_name}"] << se.generate
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,92 @@
1
+ module Burn
2
+ module Fuel
3
+ module Rom
4
+ class SoundEffect
5
+ # duty cycle: 00�F12.5%�@01�F25%�@10�F50%�@11�F75%
6
+ LOWEST = 0
7
+ LOWER = 1
8
+ HIGHER = 2
9
+ HIGHEST = 3
10
+
11
+ def initialize
12
+ @output_buffer = Array.new
13
+ end
14
+
15
+ def load(&block)
16
+ self.instance_eval &block
17
+ end
18
+
19
+ # $4000 related
20
+ def duty_cycle(ratio)
21
+ @duty_cycle = SoundEffect.const_get(ratio.upcase)
22
+ end
23
+
24
+ def velocity(level)
25
+ @velocity = level
26
+ end
27
+
28
+ def envelope_decay(flag)
29
+ @envelope_decay = flag==:enable ? 0 : 1
30
+ end
31
+
32
+ def envelope_decay_loop(flag)
33
+ @envelope_decay_loop = flag==:enable ? 1 : 0
34
+ end
35
+
36
+ def length_counter_clock(flag)
37
+ @envelope_decay_loop = flag==:enable ? 0 : 1
38
+ end
39
+
40
+ # $4001 related
41
+ def pitch(i)
42
+ @pitch = i
43
+ end
44
+
45
+ def length(i)
46
+ @length = i + 15
47
+ end
48
+
49
+ alias_method :envelope_decay_rate, :velocity
50
+ alias_method :volume, :velocity
51
+ alias_method :envelope, :envelope_decay
52
+ alias_method :envelope_loop, :envelope_decay_loop
53
+ alias_method :key_off_counter, :length_counter_clock
54
+
55
+ def generate
56
+ if !@duty_cycle.nil? || !@velocity.nil? || @envelope_decay.nil? || @envelope_decay_loop.nil? then
57
+ @duty_cycle = HIGHER if !@duty_cycle.nil?
58
+ @velocity = 7 if @velocity.nil?
59
+ @envelope_decay = 0 if @envelope_decay.nil?
60
+ @envelope_decay_loop = 0 if @envelope_decay_loop.nil?
61
+
62
+ reg = @duty_cycle*64 + @envelope_decay*32 + @envelope_decay_loop*16 + @velocity
63
+ if @reg4000 != reg then
64
+ @output_buffer << " .byte $00,$%02x" % reg
65
+ @reg4000 = reg
66
+ end
67
+ end
68
+
69
+ if !@pitch.nil? then
70
+ if @reg4001 != @pitch then
71
+ @output_buffer << " .byte $01,$%02x" % @pitch
72
+ @reg4001 = @pitch
73
+ end
74
+ end
75
+
76
+ @length = 16 if @length.nil?
77
+ @output_buffer << " .byte $%02x" % @length
78
+
79
+ # return result
80
+ @output_buffer.join("\n") + "\n"
81
+
82
+ #" .byte $00,$7f\n .byte $01,$ab\n .byte $02,$01\n .byte $13\n .byte $01,$3f\n .byte $39\n .byte $01,$1c\n .byte $13\n .byte $ff\n"
83
+ end
84
+
85
+ private
86
+ def __translate
87
+ " .byte " + @notes.map{|p| "$%02x" % p}.join(",")
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,26 @@
1
+ module Burn
2
+ module Fuel
3
+ module Telnet
4
+ class Declare < DslBase
5
+
6
+ def initialize(resource_name, context)
7
+ super(resource_name, context)
8
+ end
9
+
10
+ def method_missing(method_symbol, *args, &block)
11
+ proc = Proc.new{|args|
12
+ key=args.shift
13
+ value=args.shift
14
+ if value.is_a?(String) then
15
+ @opcodes << "@___#{key} = Sprite.new(\"#{value}\",0,0)"
16
+ else
17
+ @opcodes << "@___#{key} = #{value}"
18
+ end
19
+ }
20
+
21
+ @context.instance_exec [method_symbol.to_s, args[0]], &proc
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,112 @@
1
+ module Burn
2
+ module Fuel
3
+ module Telnet
4
+ class Scene < DslBase
5
+ # Where to draw
6
+ BG = 40 # background palette (0x00-0x0f)
7
+ TEXT = 30 # background palette (0x00-0x0f)
8
+ # SPRITE = 17 # sprite palette (0x10-0x1f)
9
+
10
+ # Color Control
11
+ WHITE = 7
12
+ LIGHTBLUE = 4
13
+ BLUE = 4
14
+ PURPLE = 5
15
+ PINK = 5
16
+ RED = 1
17
+ DEEPRED = 1
18
+ ORANGE = 3
19
+ LIGHTORANGE = 3
20
+ DARKGREEN = 2
21
+ GREEN = 2
22
+ LIGHTGREEN = 6
23
+ BLUEGREEN = 6
24
+ GRAY = 7
25
+ BLACK = 0
26
+
27
+ # Light Control
28
+ DARKEST = 60
29
+ DARKER = 60
30
+ LIGHTER = 0
31
+ LIGHTEST = 0
32
+
33
+ def initialize(resource_name, context)
34
+ super(resource_name, context)
35
+ end
36
+
37
+ def label(string, x=0, y=1)
38
+ @context.instance_exec { @opcodes << "@screen.display[#{y}][#{x},#{string.length}] = \"#{string.upcase}\"" }
39
+ end
40
+
41
+ def wait(interval)
42
+ @context.instance_exec { @opcodes << "@wait = #{interval}" }
43
+ end
44
+
45
+ def method_missing(method_symbol, *args, &block)
46
+ #TBD if needed
47
+ end
48
+
49
+ def goto(scene_name)
50
+ @context.instance_exec { @opcodes << "@screen.flush_screen && @pc = @opcodes.index(\"##{scene_name}\")" }
51
+ end
52
+
53
+ def color(palette, color, lightness=:lighter)
54
+ target = palette==:bg ? "bg" : "fg"
55
+ palette=Scene.const_get(palette.upcase)
56
+ color=Scene.const_get(color.upcase)
57
+ lightness=Scene.const_get(lightness.upcase)
58
+ @context.instance_exec { @opcodes << "@screen.#{target}_color = #{palette+color+lightness}" }
59
+ end
60
+
61
+ def main_loop(rrb_source=nil)
62
+ @context.instance_exec(@context,@resource_name) do |c, resource|
63
+ p=Pxes::CrubyTranspiler.new(Ripper.sexp(rrb_source),c,resource)
64
+ start_label = "##{resource}-main_loop:" + @opcodes.count.to_s
65
+ @opcodes << start_label
66
+ @opcodes << "@user_input.init_for_next_loop"
67
+ @opcodes.concat p.to_rb.split("\n")
68
+ @opcodes << "@pc = @opcodes.index(\"#{start_label}\")" #JUMP
69
+ end
70
+ end
71
+
72
+ def sprite(resource)
73
+ @context.instance_exec { @opcodes << "@screen.activated_sprite_objects << @___#{resource} if @screen.activated_sprite_objects.index(@___#{resource}).nil?" }
74
+ end
75
+
76
+ # def fade_in
77
+ # @context.instance_exec do
78
+ # [
79
+ # "ppu_on_all();",
80
+ # "screen_fade_in();"
81
+ # ].each {|p| @code_blocks.push p}
82
+ # end
83
+ # end
84
+ #
85
+ # def fade_out(sec=3)
86
+ # @context.instance_exec {@code_blocks.push "screen_fade_out(#{sec.to_s});"}
87
+ # end
88
+ #
89
+ # def show(string, x=0, y=0, *args)
90
+ # end
91
+ #
92
+ # def inline(code)
93
+ # end
94
+ #
95
+ # def screen(map, vars)
96
+ # end
97
+ #
98
+ # def paint(dest, palette)
99
+ # end
100
+ #
101
+ # def rand
102
+ # @context.instance_exec {@code_blocks.push "rand8()"}
103
+ # end
104
+ #
105
+ # # utility methods
106
+ # def range(x_from, y_from, x_to, y_to)
107
+ # end
108
+
109
+ end
110
+ end
111
+ end
112
+ end
@@ -1,3 +1,10 @@
1
- require 'burn/generator/assembly_sound_effect'
2
- require 'burn/generator/assembly_music'
3
- require 'burn/generator/c_source'
1
+ require 'burn/generator/rom/assembly_sound_effect'
2
+ require 'burn/generator/rom/assembly_music'
3
+ require 'burn/generator/rom/c_source'
4
+ require 'burn/generator/rom_builder'
5
+
6
+ require 'burn/generator/telnet/sprite'
7
+ require 'burn/generator/telnet/screen'
8
+ require 'burn/generator/telnet/user_input'
9
+ require 'burn/generator/telnet/jit_compiler'
10
+ require 'burn/generator/telnet_vm'
@@ -0,0 +1,49 @@
1
+ module Burn
2
+ module Generator
3
+ module Rom
4
+ class AssemblyMusic
5
+ include Debug
6
+
7
+ def initialize(workspace_root)
8
+ # Generic
9
+ @workspace_root = workspace_root
10
+
11
+ # Music related
12
+ @resources = {}
13
+
14
+ #@channels = Array.new
15
+
16
+ end
17
+
18
+ def get_context
19
+ self
20
+ end
21
+
22
+ def generate
23
+ # prepare music.s - music assembler file
24
+ File.write(
25
+ "#{@workspace_root}/tmp/burn/asset/music.s",
26
+ File.read("#{@workspace_root}/tmp/burn/asset/music.s")
27
+ .gsub(/__@__EXPORT__@__/, @resources.keys.map{|p| " .export _music_#{p}"}.join("\n"))
28
+ .gsub(/__@__INCLUDE__@__/, @resources.keys.map{|p| "_music_#{p}: .include \"mus_#{p}.s\""}.join("\n"))
29
+ )
30
+
31
+ # preparing each song file
32
+ @resources.each {|resource_name, channels|
33
+ # prepare other music resources
34
+ File.write( "#{@workspace_root}/tmp/burn/asset/mus_#{resource_name}.s",
35
+ File.read(File.dirname(__FILE__)+"/template/mus_template.s")
36
+ .gsub(/__@__NAME__@__/, resource_name)
37
+ .gsub(/__@__CHANNEL1__@__/, channels.shift || "")
38
+ .gsub(/__@__CHANNEL2__@__/, channels.shift || "")
39
+ .gsub(/__@__CHANNEL3__@__/, channels.shift || "")
40
+ .gsub(/__@__CHANNEL4__@__/, channels.shift || "")
41
+ .gsub(/__@__CHANNEL5__@__/, channels.shift || "")
42
+ )
43
+ }
44
+
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,35 @@
1
+ module Burn
2
+ module Generator
3
+ module Rom
4
+ class AssemblySoundEffect
5
+ include Debug
6
+ attr_reader :resources
7
+
8
+ def initialize(workspace_root)
9
+ # Generic
10
+ @workspace_root = workspace_root
11
+
12
+ # Music related
13
+ @resources = {}
14
+
15
+ end
16
+
17
+ def get_context
18
+ self
19
+ end
20
+
21
+ def generate
22
+ # prepare sound.s - sound effect assembler file
23
+ File.write(
24
+ "#{@workspace_root}/tmp/burn/asset/sounds.s",
25
+ "sounds:\n" \
26
+ + @resources.keys.map{|p| " .word @#{p}"}.join("\n") \
27
+ + "\n" \
28
+ + @resources.map{|key,value| "@#{key}:\n#{value.join} .byte $ff\n" }.join
29
+ )
30
+
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,55 @@
1
+ module Burn
2
+ module Generator
3
+ module Rom
4
+ class CSource
5
+ include Debug
6
+ attr_reader :global, :code_blocks
7
+
8
+ def initialize(workspace_root)
9
+ # Generic
10
+ @workspace_root = workspace_root
11
+ @global = Array.new
12
+ @code_blocks = Array.new
13
+
14
+ # Scene related
15
+ @pattern_tables = Array.new
16
+ @pattern_table_pointer = 80 #0x50 equivalent
17
+ @pattern_table_index = Hash.new
18
+ end
19
+
20
+ def get_context
21
+ self
22
+ end
23
+
24
+ def generate
25
+ # Initialization for codeblocks
26
+ @code_blocks.unshift "init();"
27
+
28
+ # generate source code
29
+ File.write(
30
+ "#{@workspace_root}/tmp/burn/main.c",
31
+ File.read(File.dirname(__FILE__) + "/template/template.c")
32
+ .gsub(/__@__MAIN__@__/, @code_blocks.join("\n"))
33
+ .gsub(/__@__GLOBAL__@__/, @global.join("\n"))
34
+ )
35
+
36
+ # save pattern tables associated with source code
37
+ pattern_header = []
38
+ File.open("#{@workspace_root}/tmp/burn/asset/tileset.chr", "rb") do |f|
39
+ pattern_header << f.read(16*80)
40
+ end
41
+ File.open("#{@workspace_root}/tmp/burn/asset/tileset.chr", "wb") do |f|
42
+ f << pattern_header[0]
43
+ @pattern_tables.each do |p|
44
+ f << p
45
+ end
46
+ (8192-16*80-@pattern_tables.count*16).times do |i|
47
+ f << ["0x00"].pack("B*")
48
+ end
49
+ end
50
+
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,67 @@
1
+ module Burn
2
+ module Generator
3
+ class RomBuilder
4
+ include Fuel::Rom
5
+ include Generator::Rom
6
+ include Debug
7
+
8
+ def initialize(workspace_root)
9
+ @workspace_root = workspace_root
10
+
11
+ @game_generator = CSource.new(@workspace_root)
12
+ @music_generator = AssemblyMusic.new(@workspace_root)
13
+ @sound_effect_generator = AssemblySoundEffect.new(@workspace_root)
14
+ end
15
+
16
+ def verbose(flag)
17
+ Debug::Logger.new.enabled flag
18
+ end
19
+
20
+ def load(dsl_raw_text)
21
+ self.instance_eval dsl_raw_text
22
+ end
23
+
24
+ def generate
25
+ @game_generator.generate
26
+ @music_generator.generate
27
+ @sound_effect_generator.generate
28
+ end
29
+
30
+ def method_missing(method_symbol, *args, &block)
31
+ log :method_symbol=>method_symbol, :args=>args, :block=>block
32
+ if method_symbol == :music then
33
+ Music.new(args[0], @music_generator.get_context).instance_eval(&block)
34
+
35
+ elsif method_symbol == :scene then
36
+ # preprocess
37
+ args[0] = "main" if args[0].nil?
38
+ @game_generator.get_context.instance_exec args[0], &lambda{|resource_name|
39
+ [
40
+ "",
41
+ "//#{resource_name} label starts",
42
+ "#{resource_name}:"
43
+ ].each {|p| @code_blocks.push p}
44
+ }
45
+
46
+ # execute dsls
47
+ Scene.new(args[0], @game_generator.get_context).instance_eval(&block)
48
+
49
+ # postprocess - To deal with the case of on_enter_frame not found, adding while loop at the end of program
50
+ @game_generator.get_context.instance_exec {@code_blocks.push "ppu_on_all();", "while(1);"}
51
+
52
+ elsif method_symbol == :declare then
53
+ Declare.new(args[0], @game_generator.get_context).instance_eval(&block)
54
+
55
+ elsif method_symbol == :sound then
56
+ Sound.new(args[0], @sound_effect_generator.get_context).instance_eval(&block)
57
+
58
+ # postprocess
59
+ @game_generator.get_context.instance_exec(@sound_effect_generator.resources.count-1) do |count|
60
+ @global.push "#define SFX_#{args[0].upcase} #{count.to_s}"
61
+ end
62
+
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end