burn 0.1.3 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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