123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552 |
- # Main eruta script.
- #
- # This will be executed on start up, and certain well-known functions will be
- # called on input events, on timer ticks, or on screen updates.
- # Note that, due to muby's syntax, everythg that is defined in this
- # file at file scope, will actually be defined at the scope of Object.
- # then, though inheritance, every other object will inherit it.
- # This may or may not be what you want!!!
- # Therefore, it's probably a a good idea to include everything
- # except the well-known functions into the module Main below.
- #
- # The well-known functions that will be called are as follows:
- # "on_bump" when a physics collision takes place
- # "on_poll" when input events or timer events are received
- # "on_start" when the script is loaded the first time
- # "on_reload" when the script is reloaded (using the F5 key)
- # "on_update" whenever the screen redraw is about to take place
- # All these functions should execute quickly so they don't block the Eruta
- # engine. They should set the Eruta engine state and let the C side do the
- # heavy work.
- # Set this to true to start a test map in stead of the normal main menu on startup.
- START_TEST_MAP = false
- # Play music at startup
- PLAY_MUSIC = false
- # Show main background
- MAIN_BACKGROUND = true
- # Helpers
- script 'forwardable.rb'
- # Registry module
- script 'registry.rb'
- # Game state
- script 'state.rb'
- # Load keycodes
- script 'keycode.rb'
- # Load OO wrappers
- script 'timer.rb'
- script 'thing.rb'
- script 'sprite.rb'
- script 'graph.rb'
- script 'store.rb'
- script 'bitmap.rb'
- script 'font.rb'
- script 'music.rb'
- script 'sound.rb'
- script 'tilemap.rb'
- # Load UI subsystem
- script 'zori.rb'
- # Attacks
- script 'attack.rb'
- # Main menu
- script 'mainmenu.rb'
- script 'helpers.rb'
- puts "Hi from ruby!"
- module Main
- def ulpcss_load(sprite, layer, name)
- full_name = "image/ulpcss/#{name}"
- sprite_loadulpcss sprite, layer, full_name
- end
- def torso_tint(sprite, r, g, b, a = 255)
- sprite_tint_rgba sprite, SPRITELAYER_TORSO, r, g, b, a
- end
- def hair_tint(sprite, r, g, b, a = 255)
- sprite_tint_rgba sprite, SPRITELAYER_HAIR, r, g, b, a
- end
- def start_load_sprites
- Timer.make(1.0) do | timer |
- puts "In timer tick_tock, total run time: #{timer.total}."
- timer.total > 10.0
- end
-
- puts "Loading some things and sprites"
- player_1 = Thing.make(:player_1, Thing::Kind::PLAYER, 300, 400, 1, 32, 32)
- player_1.load_ulpcss(Sprite::Layer::BODY , "body/female/light.png")
- player_1.load_ulpcss(Sprite::Layer::TORSO, "torso/dress_female/underdress.png")
- player_1.load_ulpcss(Sprite::Layer::HAIR , "hair/female/bangslong.png")
- player_1.load_ulpcss(Sprite::Layer::STAFF, "weapons/steelwand_female.png")
- player_1.load_ulpcss_slash(Sprite::Layer::BLADE, "weapons/oversize/longsword_female.png")
- player_1.load_ulpcss_stab(Sprite::Layer::POLEARM, "weapons/oversize/spear.png")
- player_1.load_ulpcss(Sprite::Layer::BOW, "weapons/greatbow.png")
- player_1.one_shot_default
- player_1.tint_hair(0, 255, 0)
- player_1.tint_torso(255, 64, 64)
- player_1.direction = Sprite::SOUTH
- player_1.pose = Sprite::STAND
- player_1.hide_layer(Sprite::Layer::STAFF)
- player_1.group = Thing::Kind::PLAYER
-
- # hf = Thing[100].hull_flags= Thing::Flag::DISABLED
- # p "set hull flag", hf, Thing[100].hull_flags
-
- Thing.make(:player_2, Thing::Kind::FOE, 400, 400, 1, 32, 32)
- Sprite.make(:s101)
- Sprite[:s101].load_ulpcss(Sprite::Layer::BODY , "body/female/orc.png")
- Sprite[:s101].load_ulpcss(Sprite::Layer::TORSO, "torso/dress_w_sash_female.png")
- # Sprite[:s101].load_ulpcss(Sprite::Layer::HAIR , "hair/female/bangsshort.png")
- Thing[:player_2].sprite = Sprite[:s101]
- Thing[:player_2].tint_hair(255, 255, 0)
- Thing[:player_2].tint_torso(128, 128, 255)
- Thing[:player_2].pose = Sprite::STAND
- Thing[:player_2].direction = Sprite::SOUTH
- player_1.group = Thing::Kind::FOE
- puts "Things and sprites loaded."
- end
- def start_load_stuff
- end
- def start_load_tilemap
- tilemap_fn = 'map/map_0001_tiled11.tmx'
- tilemap = Tilemap.load(:map_0001, tilemap_fn)
- State.tilemap_name = :map_0001
- tilemap.activate!()
- end
- def reload_tilemap
- Tilemap.reload
- end
- def do_start_test_map
- start_load_tilemap
- start_load_sprites
- start_load_stuff
- # start_setup_ui
- actor_switch(Thing[:player_1])
- end
- #
- # def load_main_menu
- # $main_music = Store.load_audio_stream('/music/hiver_com64.ogg')
- # $main_back = Store.load_bitmap('/image/background/eruta_mainmenu.png')
- # $main_graph = Graph.make_image(0, 0, $main_back.id)
- # Eruta::Audio.music_id = $main_music.id
- # res = Eruta::Audio.play_music
- # puts "play_music #{res} #{$main_music.id}"
- # end
- POEM_TEXT = "After mankind's summer, winter suddenly came" +
- "Most reached for the stars, but some remained" +
- "The earth scarred by the Ancients unhostpitable" +
- "The hopes low, and so much wisdom forgotten" +
- "Yet when it seemed the last hour struck" +
- "Our hope returned, a savior arose" +
- "Lord Kei, who by Creator's grace" +
- "Restored the Trees that guard us all from harm" +
- "Thus ushered in a new millennial spring" +
- "Lord Kei, watch over us and protect us" +
- "Until the Travellers return with bounty of the stars"
- INTRO_TEXT = "Millennia have passed since mankind first traveled to the moon. "+
- "Civilizations rose as never before, yet to fall again. " +
- "When all hope seemed lost, the 21 trees sprouted from the earth. " +
- "They brought mysterious powers that protected and strengthened mankind. "+
- "Hi!\n\n" +
- "Hello µ world, this is me, 無 life should be\nfun for everyone!"
- INTRO_TEXT2 = "Something happened, and I was changed!"
- def make_sub_menu(parent, x, y, w, h, bh)
- sub_menu = parent.make_menu(x, y, w, h, nil)
- sub_menu.make_button(x, y + 20, w - 20, bh, "Sub choice 1") do
- puts "choice 1"
- end
- sub_menu.make_button(x, y + 30 + bh, w - 20, bh, "Sub choice 2") do
- puts "choice 2"
- end
- sub_menu.make_button(x, y + 40 + 2* bh, w - 20, bh, "Sub choice 3") do
- puts "choice 3"
- end
- sub_menu.fit_children
- sub_menu.hide
- return sub_menu
- end
- def do_main_menu
- main_music = Music.load(:main, '/music/nethis-the_writer.ogg')
- $lote = nil
- $lobe = nil
- if PLAY_MUSIC
- res = main_music.play!
- end
- # res = nil
- # $main_menu = MainMenu.new
- # $main_menu.active = true
- Zori.make_page(:default) do |m|
- State.talk_box = m.make_longtext(10, 310, 620, 160, "Testing 1 2 3")
- State.talk_box.graph.each { |g| g.font = Eruta::Zori.font.id }
- State.talk_box.delay = 0.1
- State.talk_box.page_lines = 5
- State.talk_box.page = 0
- State.talk_box.hide
- end
-
- Zori.make_page(:main_menu) do |m|
- if MAIN_BACKGROUND
- main_back = Bitmap.load(:main_back,
- '/image/background/eruta_mainmenu.png')
- p main_back, main_back.width, main_back.height, main_back.name, main_back.id
-
- main_back = Bitmap.load(:main_back,
- '/image/background/eruta_mainmenu.png')
- p main_back, main_back.width, main_back.height, main_back.name, main_back.id
- p Bitmap[:main_back]
- p Store[:bitmap_main_back]
- m.graph_image(0, 0, main_back.id)
- end
- main_menu = m.make_menu(250, 190, 120, 440, nil)
- ma = main_menu
- main_button_1 = ma.make_button(260, 200, 100, 30, "Continue")
- sub_menu = make_sub_menu(main_button_1, 50, 190, 120, 440, 30)
- sub_menu.hide
-
- main_button_2 = ma.make_button(260, 240, 100, 30, "New") do
- do_start_test_map
- Zori.go(:default)
- end
-
- main_button_3 = ma.make_button(260, 280, 100, 30, "Settings") do
- Zori.go(:settings)
- end
-
- main_button_4 = ma.make_button(260, 320, 100, 30, "Instructions")
- main_button_5 = ma.make_button(260, 360, 100, 30, "µ£éè")
- main_button_5 << sub_menu
-
- main_button_5= ma.make_button(260, 400, 100, 30, "Quit") do
- Eruta.quit
- end
-
- main_menu.fit_children
- end
- Zori.make_page(:settings) do |se|
- lote2 = se.make_longtext(100, 10, 160, 100, INTRO_TEXT)
- lote2.delay = 1
- lote2.page = 0
- lote2.page_lines = 3
- # $lote2.line_stop = 999990
-
- settings_menu = se.make_menu(480, 380, 120, 440, nil)
- sm = settings_menu
- settings_ok_button = sm.make_button(500, 300, 100, 30, "Font 1") do
- if lote2
- lote2.graph.each { |g| g.font = 0 }
- end
- end
- settings_ok_button = sm.make_button(500, 350, 100, 30, "Font 2") do
- if lote2
- lote2.graph.each { |g| g.font = Eruta::Zori.font.id }
- end
- lote2.text = INTRO_TEXT2
- end
- settings_ok_button = sm.make_button(500, 400, 100, 30, "OK") do
- Zori.go(:main_menu)
- if lote
- lote.close
- lote = nil
- end
- end
- sm.fit_children
- end
- Zori[:main_menu].hide
- Zori[:settings].hide
- Zori.go(:main_menu)
- end
- def ok!
- log "OK, it works!"
- end
- def actor_switch(new_actor)
- # Ensure the old actor stops walking.
- new_actor.v = [ 0.0, 0.0 ]
- Thing.actor = new_actor
- new_actor.track
- return new_actor
- end
- def actor_continue_talk
- if State.talk_box.at_end?
- State.talk_box.hide
- State.talk_with = nil
- p "Talk ended."
- elsif State.talk_box.paused
- res = (State.talk_box.next_page)
- p "Continue_talk", res
- else
- State.talk_box.delay = 0.05
- p "Talking speed up"
- # speed up talk here?
- end
- end
- def actor_start_search
- p "starting search"
- found = Thing.actor.find_in_front(60, 60)
- unless found.empty?
- first = found.first
- State.talk_box.delay = 0.05
- State.talk_box.show
- State.talk_box.text = "Let's make this text a bit longer\n
- Hi there, I'm #{first.id}!"
- State.talk_with = first
- end
- end
- # Searches and interacts with things in front of the actor.
- # Or if already talking/reading, continue with it.
- def actor_search_or_talk
- return if !Thing.actor
- if State.talk_with
- actor_continue_talk
- else
- actor_start_search
- end
- end
- # Searches and interacts with things in front of the actor.
- # Or if already talking/reading, continue with it.
- def actor_attack
- return if !Thing.actor
- Thing.actor.v = [ 0, 0 ]
- pose = Thing.actor.pose
- Thing.actor.one_shot_action(Sprite::SLASH)
- Thing.actor.pose = Sprite::SLASH
- Attack.make(Thing.actor, 64, 64)
- end
- # Show a reminder of the key bindings on stdout
- def show_keybindings
- puts "Keybindings:"
- puts "A: Switch to actor A."
- puts "B: Switch to actor B."
- puts "E: REload currently active tile map."
- puts "F: Toggle the visibility of the FPS counter"
- puts "G: Toggle the visibility of the 2D scene Graph"
- puts "H: Hide 2D scene graph GUI"
- puts "N: Disable tile map."
- puts "P: Toggle the visibility of the area/physics bounds boxes."
- puts "R: Toggle the visibility of the area spRites."
- puts "S: Show 2D scene graph GUI"
- puts "Arrow keys: Move active actor."
- puts "Shift keys: use weapon."
- puts "Space: search in front of active actor or continue talking."
- end
- # Handle key down
- def on_key_down(time, key)
- State.last_key_time = time
- State.last_key = key
-
- p "on_key_down #{time} #{key}"
- actor = Thing.actor
- return nil unless actor
- vx, vy = * actor.v
- case key
- when KEY_A
- actor_switch(Thing[:player_1])
- when KEY_B
- actor_switch(Thing[:player_2])
- when KEY_E
- reload_tilemap()
- when KEY_H
- Eruta::Graph.visible_(52, 0)
- when KEY_M
- active_map_($tilemap_id)
- when KEY_N
- active_map_(-1)
- when KEY_S
- Eruta::Graph.visible_(52, 1)
- when KEY_F
- Eruta.show_fps= !Eruta.show_fps
- when KEY_R
- Eruta.show_area= !Eruta.show_area
- when KEY_G
- Eruta.show_graph= !Eruta.show_graph
- when KEY_P
- Eruta.show_physics= !Eruta.show_physics
- when KEY_UP
- vy -= 100.0
- actor.v = [ vx, vy ]
- when KEY_DOWN
- vy += 100.0
- actor.v = [ vx, vy ]
- when KEY_LEFT
- vx -= 100.0
- actor.v = [ vx, vy ]
- when KEY_RIGHT
- vx += 100.0
- actor.v = [ vx, vy ]
- when KEY_D
- Thing.actor.pose = Sprite::DOWN
- when KEY_SPACE
- puts "Searching..."
- actor_search_or_talk
- when KEY_LSHIFT, KEY_RSHIFT
- puts "attacking"
- actor_attack
- actor.v = [ 0, 0 ]
- when KEY_COMMA
- show_keybindings
- else
- end
- return nil
- end
- # Handle key up. XXX: maybe refactor this to a game class or module???
- def on_key_up(time, key)
- actor = Thing.actor
- return nil unless actor
- vx, vy = * actor.v
- case key
- when KEY_UP
- vy = 0.0
- actor.v = [vx, vy]
- when KEY_DOWN
- vy = 0.0
- actor.v = [vx, vy]
- when KEY_LEFT
- vx = 0.0
- actor.v = [vx, vy]
- when KEY_RIGHT
- vx = 0.0
- actor.v = [vx, vy]
- when KEY_SPACE
- State.talk_box.delay = 0.1 if State.talk_with
- else
- end
- return nil
- end
- # Make all methods and constants are available as Main.XXX
- extend self
- end # module Main
- ####################################
- # Below are the entry point functions that will be called by the Eruta engine
- # at certain events or times.
- ####################################
- # Called when the main.rb script is loaded for the first time.
- def eruta_on_start(*args)
- puts "on_start #{args}"
- State.time_start = Eruta.time
- Zori.open
- Main.do_main_menu()
- return :ok
- end
- # Called when the main.rb script is reloaded (through the F5 key).
- def eruta_on_reload(*args)
- puts "on_reload #{args}"
- puts "load thing ok: #{Thing.methods - Object.methods}"
- puts "load thing ok: #{Eruta::Thing.methods - Object.methods}"
- return :ok
- end
- # Called on a physics collision.
- def eruta_on_bump(t1, t2, h1, h2, kind = nil)
- if kind == 1 # Begin of collision
- # puts "Begin collision!"
- elsif kind == 2 # Collision active
- thing1 = Thing[t1]
- thing2 = Thing[t2]
- if thing1 && thing2
- thing1.on_bump(thing2, h1, h2)
- else
- puts "Colliding! #{t1}<->#{t2} (#{h1}<->#{h2})"
- end
- elsif kind == 3 # Collision done
- puts "Collision done!"
- else
- puts "Unknown collision type shouldn't happen!"
- end
- return true
- end
- # Called on certain sprite events (end of one shot animation)
- def eruta_on_sprite(spriteid, thingid, pose, direction, kind = nil)
- thing = Thing[thingid]
- if thing
- thing.on_sprite(spriteid, pose, direction, kind)
- end
- puts "Sprite event: #{spriteid} #{thingid} #{pose} #{direction} #{kind}."
- end
- # Called on an update tick, just before drawing to the screen.
- def eruta_on_update(dt)
- # Update the timers
- Timer.update
- end
- # Called when an input event occurs.
- def eruta_on_poll(*args)
- # Send to Zori ui first. If it returns non-nil the event is handled,
- # otherwise, pass on to key handler.
- res = Zori.on_event(*args)
- if res
- return nil
- else
- type = args.shift
- meth = "on_#{type}".to_sym
- if Main.respond_to?(meth)
- Main.send(meth, *args)
- else
- # ignore
- log_to "input", "#{__FILE__.split('/').last}:#{__LINE__}: input: #{type} #{meth} #{args}"
- # puts "input #{type} #{meth} #{args}"
- end
- end
- end
|