summaryrefslogtreecommitdiffhomepage
path: root/docs/docs.txt
diff options
context:
space:
mode:
authorAmir Rajan <[email protected]>2020-09-22 06:27:46 -0500
committerAmir Rajan <[email protected]>2020-09-22 06:27:46 -0500
commit20d5b4057b44ffcf92478b2a8e9476ace2fdc0f5 (patch)
treeb4742e4f9acfd5400a04f314164812606a71df9f /docs/docs.txt
parent5b2311900072cfff9582bb0296140cfb354cb911 (diff)
downloaddragonruby-game-toolkit-contrib-20d5b4057b44ffcf92478b2a8e9476ace2fdc0f5.tar.gz
dragonruby-game-toolkit-contrib-20d5b4057b44ffcf92478b2a8e9476ace2fdc0f5.zip
synced with 1.22
Diffstat (limited to 'docs/docs.txt')
-rw-r--r--docs/docs.txt7770
1 files changed, 5239 insertions, 2531 deletions
diff --git a/docs/docs.txt b/docs/docs.txt
index 7276894..a3a240e 100644
--- a/docs/docs.txt
+++ b/docs/docs.txt
@@ -310,79 +310,43 @@ around. Experiment a little. Add a few more things and have them
interact in small ways. Want something to go away? Just don't add it
to ~args.output~ anymore.
-** IMPORTANT: Go Through All Of The Sample Apps! Study Them Thoroughly!!
+* IMPORTANT: Go through all of the sample apps! Study them thoroughly!! No really, you should definitely do this!
Now that you've completed the Hello World tutorial. Head over to the
`samples` directory. It is very very important that you study the
sample apps thoroughly! Go through them in order. Here is a short
description of each sample app.
-1. 00_beginner_ruby_primer: This is an interactive tutorial that shows how to render ~solid~s, animated ~sprite~s, ~label~s.
-2. 00_intermediate_ruby_primer: This is a set of sample Ruby snippets that give you a high level introduction to the programming language.
-3. 01_api_01_labels: Various ways to render ~label~s.
-4. 01_api_02_lines: Various ways to render ~line~s.
-5. 01_api_03_rects: Sample app shows various ways to render ~solid~s and ~border~s.
-6. 01_api_04_sprites: Sample app shows various ways to render ~sprite~s.
-7. 01_api_05_keyboard: Hows how to get keyboard input from the user.
-8. 01_api_06_mouse: Hows how to get mouse mouse position.
-9. 01_api_07_point_to_rect: How to get mouse input from the user and shows collision/hit detection.
-10. 01_api_08_rect_to_rect: Hit detection/collision between two rectangles.
-11. 01_api_10_controller: Interaction with a USB/Bluetooth controller.
-12. 01_api_99_tech_demo: All the different render primitives along with using ~render_targets~.
-13. 02_collision_01_simple: Collision detection with dynamically moving bodies.
-14. 02_collision_02_moving_objects: Collision detection between many primitives, simple platformer physics, and keyboard input.
-15. 02_collision_03_entities: Collision with entities and serves as a small introduction to ECS (entity component system).
-16. 02_collision_04_ramp_with_debugging: How ramp trajectory can be calculated.
-17. 02_collision_05_ramp_with_debugging_two: How ramp trajectory can be calculated.
-18. 02_sprite_animation_and_keyboard_input: How to animate a sprite based off of keyboard input.
-19. 03_mouse_click: How to determine what direction/vector a mouse was clicked relative to a player.
-20. 04_sounds: How to play sounds and work with buttons.
-21. 05_mouse_move: How to determine what direction/vector a mouse was clicked relative to a player.
-22. 05_mouse_move_paint_app: Represents a simple paint app.
-23. 05_mouse_move_tile_editor: A starting point for a tile editor.
-24. 06_coordinate_systems: Shows the two origin systems within Game Toolkit where the origin is in the center and where the origin is at the bottom left.
-25. 07_render_targets: Shows a powerful concept called ~render_target~s. You can use this to programatically create sprites (it's also useful for representing parts of a scene as if it was a view port/camera).
-26. 07_render_targets_advanced: Advanced usage of ~render_target~s.
-27. 08_platformer_collisions: Axis aligned collision along with platformer physics.
-28. 08_platformer_collisions_metroidvania: How to save map data and place sprites live within a game.
-29. 08_platformer_jumping_inertia: Jump physics and how inertia affects collision.
-30. 09_controller_analog_usage_advanced_sprites: Extended properties of a ~sprite~ and how to change the rotation anchor point and render a subset/tile of a sprite.
-31. 09_sprite_animation_using_tile_sheet: How to perform sprite animates using a tile sheet.
-32. 10_save_load_game: Save and load game data.
-33. 11_coersion_of_primitives: How primitives of one specific type can be rendered as another primitive type.
-34. 11_hash_primitives: How primitives can be represented using a ~Hash~.
-35. 12_controller_input_sprite_sheet_animations: How to leverage vectors to move a player around the screen.
-36. 12_top_down_area: How to render a top down map and how to manage collision of a player.
-37. 13_01_easing_functions: How to use lerping functions to define animations/movement.
-38. 13_02_cubic_bezier: How to create a bezier curve using lines.
-39. 13_03_easing_using_spline: How a collection of bezier curves can be used to define an animation.
-40. 13_04_parametric_enemy_movement: How to define the movement of enemies and projectiles using lerping/parametric functions.
-41. 14_sprite_limits: Upper limit for how many sprites can be rendered to the screen.
-42. 14_sprite_limits_static_references: Upper limit for how many sprites can be rendered to the screen using ~static~ output collections (which are updated by reference as opposed to by value).
-43. 15_collision_limits: How many collisions can be processed across many primitives.
-44. 18_moddable_game: How you can make a game where content is authored by the player (modding support).
-45. 19_lowrez_jam: How to use ~render_targets~ to create a low resolution game.
-46. 20_roguelike_starting_point: A starting point for a roguelike and explores concepts such as line of sight.
-47. 20_roguelike_starting_point_two: A starting point for a roguelike where sprites are provided from a tile map/tile sheet.
-48. 21_mailbox_usage: How to do interprocess communication.
-49. 22_trace_debugging: Debugging techniques and tracing execution through your game.
-50. 22_trace_debugging_classes: Debugging techniques and tracing execution through your game.
-51. 23_hexagonal_grid: How to make a tactical grid/map made of hexagons.
-52. 23_isometric_grid: How to make a tactical grid/map made of isometric sprites.
-53. 24_http_example: How to make http requests.
-54. 25_3d_experiment_01_square: How to create 3D objects.
-55. 26_jam_craft: Starting point for crafting game. It also shows how to customize the mouse cursor.
-56. 99_sample_game_basic_gorillas: Reference implementation of a full game. Topics covered: physics, keyboard input, collision, sprite animation.
-57. 99_sample_game_clepto_frog: Reference implementation of a full game. Topics covered: camera control, spring/rope physics, scene orchestration.
-58. 99_sample_game_dueling_starships: Reference implementation that shows local multiplayer. Topics covered: vectors, particles, friction, inertia.
-59. 99_sample_game_flappy_dragon: Reference implementation that is a clone of Flappy Bird. Topics covered: scene orchestration, collision, sound, sprite animations, lerping.
-60. 99_sample_game_pong: Reference implementation of pong.
-61. 99_sample_game_return_of_serenity: Reference implementation of low resolution story based game.
-62. 99_sample_game_the_little_probe: Reference implementation of a full game. Topics covered: Arbitrary collision detection, loading map data, bounce/ball physics.
-63. 99_sample_nddnug_workshop: Reference implementation of a full game. Topics covered: vectors, controller input, sound, trig functions.
-64. 99_sample_snakemoji: Shows that Ruby supports coding with emojis.
-65. 99_zz_gtk_unit_tests: A collection of unit tests that exercise parts of DragonRuby's API.
-
+** Guided Samples
+
+1. ~samples/00_learn_ruby_optional~: This directory contains sample apps that will help you learn the language.
+2. ~samples/01_rendering_basics~: This set of samples will show you how to render basic primitives such as ~labels~, ~solids~, ~borders~, ~lines~, ~sprites~, and how to play ~sounds~.
+3. ~samples/02_input_basics~: This set of samples show you how to accept input from the ~mouse~, ~keyboard~, and ~controllers~.
+4. ~samples/03_rendering_sprites~: This set of samples shows you all the different ways to render sprites (including how to use a sprite sheet).
+4. ~samples/04_physics_and_collision~: This set of samples shows how to do various types of collisions and physics.
+5. ~samples/05_mouse~: This set of samples show more advanced usages of the mouse.
+6. ~samples/06_save_load~: This set of samples show how to save and load game data.
+7. ~samples/07_advanced_rendering~: This set of samples show how to programmatically render sprites using render targets.
+8. ~samples/08_tweening_lerping_easing_functions~: This set of samples show how to perform animations.
+9. ~samples/09_performance~: This set of samples show how to handle performance issues when a large number of sprites on the screen.
+10. ~samples/10_advanced_debugging~: This set of samples show how advanced debugging techniques and testing techniques.
+11. ~samples/11_http~: This set of samples show how use http.
+
+** Sample Games
+
+There are samples that contain the path ~samples/99_*~. The sample apps that are prefixed with ~99_~ show non-trivial implemementations for a real game:
+
+1. 3D Cube: Shows how to do faux 3D in DragonRuby.
+2. Dueling Starships: A two player top-down versus game where each player controls a ship.
+3. Flappy Dragon: DragonRuby's clone of Flappy Bird.
+4. Pong: A simple implementation of the game Pong.
+5. Snakemoji: The classic game of Snake but with all of the code written using emojis (sometimes you just have to have a little fun).
+6. Solar System: A simulation of our solar system.
+7. Crafting Starting Point: A starting point for those that want to build a crafting game.
+8. Dev Tools: A set of sample apps that show how you can extend DragonRuby's Console, starting point for a tile editor, and a starting point for a paint app.
+9. LOWREZ: Sample apps that show how to render at different resolutions.
+10. RPG: Various sample apps that show how to create narrative, topdown, tactical grid-based, and roguelike RPGs.
+11. Platformers: Various sample apps that show how to create different kinds of physics/collision based platformers.
* Deploying To Itch.io
@@ -412,11 +376,11 @@ make it look like this:
NOTE: Remove the ~#~ at the beginning of each line.
#+begin_src
-devid=bob
-devtitle=Bob The Game Developer
-gameid=mygame
-gametitle=My Game
-version=0.1
+ devid=bob
+ devtitle=Bob The Game Developer
+ gameid=mygame
+ gametitle=My Game
+ version=0.1
#+end_src
The ~devid~ property is the username you use to log into Itch.io.
@@ -430,7 +394,7 @@ The ~version~ can be any ~major.minor~ number format.
Open up the terminal and run this from the command line:
#+begin_src
-./dragonruby-publish --only-package mygame
+ ./dragonruby-publish --only-package mygame
#+end_src
(if you're on Windows, don't put the "./" on the front. That's a Mac and
@@ -445,7 +409,7 @@ For the HTML version of your game after you upload it. Check the checkbox labele
For subsequent updates you can use an automated deployment to Itch.io:
#+begin_src
-./dragonruby-publish mygame
+ ./dragonruby-publish mygame
#+end_src
DragonRuby will package _and publish_ your game to itch.io! Tell your
@@ -454,7 +418,7 @@ friends to go to your game's very own webpage and buy it!
If you make changes to your game, just re-run dragonruby-publish and it'll
update the downloads for you.
-** DragonRuby's Philosophy
+* DragonRuby's Philosophy
The following tenants of DragonRuby are what set us apart from other
game engines. Given that Game Toolkit is a relatively new engine,
@@ -462,7 +426,7 @@ there are definitely features that are missing. So having a big check
list of "all the cool things" is not this engine's forte. This is
compensated with a strong commitment to the following principals.
-*** Challenge The Status Quo
+** Challenge The Status Quo
Game engines of today are in a local maximum and don't take into
consideration the challenges of this day and age. Unity and GameMaker
@@ -476,7 +440,7 @@ It's a hard pill to swallow, but forget blindly accepted best
practices and try to figure out the underlying motivation for a
specific approach to game development. Collaborate with us.
-*** Continuity of Design
+** Continuity of Design
There is a programming idiom in software called "the pit of
success". The term normalizes up front pain as a necessity in the
@@ -491,7 +455,7 @@ render primitives can be represented as tuples/arrays, hashes, open
structs/entities, and then finally classes (as opposed to forcing devs
to use classes upfront).
-*** Release Often And Soon
+** Release Often And Soon
The biggest mistake game devs make is spending too much time in
isolation building their game. Release something, however small, and
@@ -508,7 +472,7 @@ Remember:
Real artists ship.
#+end_quote
-*** Sustainable And Ethical Monetization
+** Sustainable And Ethical Monetization
We all aspire to put food on the table doing what we love. Whether it
is building games, writing tools to support game development, or
@@ -518,7 +482,7 @@ Charge a fair amount of money for the things you create. It's expected
and encouraged within the community. Give what you create away for
free to those that can't afford it.
-*** Sustainable And Ethical Open Source
+** Sustainable And Ethical Open Source
This goes hand in hand with sustainable and ethical monetization. The
current state of open source is not sustainable. There is an immense
@@ -529,7 +493,7 @@ still trying to figure out the best solution).
So, don't be "that guy" in the Discord that says "DragonRuby should be
free and open source!" You will be personally flogged by Amir.
-*** People Over Entities
+** People Over Entities
We prioritize the endorsement of real people over faceless
entities. This game engine, and other products we create, are not
@@ -537,13 +501,13 @@ insignificant line items of a large company. And you aren't a generic
"commodity" or "corporate resource". So be active in the community
Discord and you'll reap the benefits as more devs use DragonRuby.
-*** Building A Game Should Be Fun And Bring Happiness
+** Building A Game Should Be Fun And Bring Happiness
We will prioritize the removal of pain. The aesthetics of Ruby make it
such a joy to work with, and we want to capture that within the
engine.
-*** Real World Application Drives Features
+** Real World Application Drives Features
We are bombarded by marketing speak day in and day out. We don't do
that here. There are things that are really great in the engine, and
@@ -880,11 +844,9 @@ Under DragonRuby LLP, we offer a number of products (with more on the
way):
- Game Toolkit (GTK): A 2D game engine that is compatible with modern
- gaming platforms. [Home Page]() [FAQ Page]()
+ gaming platforms.
- RubyMotion (RM): A compiler toolchain that allows you to build native, cross-platform mobile
- apps. [Home Page]() [FAQ Page]()
-- Commandline Toolkit (CTK): A zero dependency, zero installation Ruby
- environment that works on Windows, Mac, and Linux. [Home Page]() [FAQ Page]()
+ apps. [[http://rubymotion.com]]
All of the products above leverage a shared core called DragonRuby.
@@ -903,7 +865,7 @@ identifier huh?
The response to this question requires a few subparts. First we need
to clarify some terms. Specifically _language specification_ vs _runtime_.
-*** Okay... so what is the difference between a language specification and a runtime?
+**** Okay... so what is the difference between a language specification and a runtime?
A runtime is an _implementation_ of a language specification. When
people say "Ruby," they are usually referring to "the Ruby 3.0+ language
@@ -912,13 +874,13 @@ specification implemented via the CRuby/MRI Runtime."
But, there are many Ruby Runtimes: CRuby/MRI, JRuby, Truffle, Rubinius, Artichoke,
and (last but certainly not least) DragonRuby.
-*** Okay... what language specification does DragonRuby use then?
+**** Okay... what language specification does DragonRuby use then?
DragonRuby's goal is to be compliant with the ISO/IEC 30170:2012 standard. It's
syntax is Ruby 2.x compatible, but also contains semantic changes that help
it natively interface with platform specific libraries.
-*** So... why another runtime?
+**** So... why another runtime?
The elevator pitch is:
@@ -927,7 +889,7 @@ within the runtime allows us to target platforms no other Ruby can
target: PC, Mac, Linux, Raspberry Pi, WASM, iOS, Android, Nintendo
Switch, PS4, Xbox, and Scadia.
-*** What does Multilevel Cross-platform mean?
+**** What does Multilevel Cross-platform mean?
There are complexities associated with targeting all the platforms we
support. Because of this, the runtime had to be architected in such a
@@ -964,13 +926,87 @@ implementations of Ruby; provide fast, native code execution
on proprietary platforms; ensure good separation between these two
worlds; and provides a means to add new platforms without going insane.
-*** Cool cool. So given that I understand everything to this point, can we answer the original question? What is DragonRuby?
+**** Cool cool. So given that I understand everything to this point, can we answer the original question? What is DragonRuby?
DragonRuby is a Ruby runtime implementation that takes all the lessons
we've learned from MRI/CRuby, and merges it with the latest and greatest
compiler and OSS technologies.
-** Frequent Comments
+*** How is DragonRuby different than MRI?
+
+DragonRuby supports a subset of MRI apis. Our target is to support all
+of mRuby's standard lib. There are challenges to this given the number
+of platforms we are trying to support (specifically console).
+
+**** Does DragonRuby support Gems?
+
+DragonRuby does not support gems because that requires the
+installation of MRI Ruby on the developer's machine (which is a
+non-starter given that we want DragonRuby to be a zero dependency
+runtime). While this seems easy for Mac and Linux, it is much harder
+on Windows and Raspberry Pi. mRuby has taken the approach of having a
+git repository for compatible gems and we will most likely follow
+suite: [[https://github.com/mruby/mgem-list]].
+
+**** Does DragonRuby have a REPL/IRB?
+
+You can use DragonRuby's Console within the game to inspect object and
+execute small pieces of code. For more complex pieces of code create a
+file called ~repl.rb~ and put it in ~mygame/app/repl.rb~:
+
+- Any code you write in there will be executed when you change the file. You can organize different pieces of code using the ~repl~ method:
+
+#+begin_src ruby
+ repl do
+ puts "hello world"
+ puts 1 + 1
+ end
+#+end_src
+
+- If you use the `repl` method, the code will be executed and the DragonRuby Console will automatically open so you can see the results (on Mac and Linux, the results will also be printed to the terminal).
+
+- All ~puts~ statements will also be saved to ~logs/log.txt~. So if you want to stay in your editor and not look at the terminal, or the DragonRuby Console, you can ~tail~ this file.
+
+4. To ignore code in ~repl.rb~, instead of commenting it out, prefix ~repl~ with the letter ~x~ and it'll be ignored.
+
+#+begin_src ruby
+ xrepl do # <------- line is prefixed with an "x"
+ puts "hello world"
+ puts 1 + 1
+ end
+
+ # This code will be executed when you save the file.
+ repl do
+ puts "Hello"
+ end
+
+ repl do
+ puts "This code will also be executed."
+ end
+
+ # use xrepl to "comment out" code
+ xrepl do
+ puts "This code will not be executed because of the x infront of repl".
+ end
+#+end_src
+
+**** Does DragonRuby support ~pry~ or have any other debugging facilities?
+
+~pry~ is a gem that assumes you are using the MRI Runtime (which is
+incompatible with DragonRuby). Eventually DragonRuby will have a pry
+based experience that is compatible with a debugging infrastructure
+called LLDB. Take the time to read about LLDB as it shows the
+challenges in creating something that is compatible.
+
+You can use DragonRuby's replay capabilities to troubleshoot:
+
+1. DragonRuby is hot loaded which gives you a very fast feedback loop (if the game throws an exception, it's because of the code you just added).
+2. Use ~./dragonruby mygame --record~ to create a game play recording that you can use to find the exception (you can replay a recoding by executing ~./dragonruby mygame --replay last_replay.txt~ or through the DragonRuby Console using ~$gtk.recording.start_replay "last_replay.txt"~.
+3. DragonRuby also ships with a unit testing facility. You can invoke the following command to run a test: ~./dragonruby . --eval some_ruby_file.rb --no-tick~.
+4. Get into the habit of adding debugging facilities within the game itself. You can add drawing primitives to ~args.outputs.debug~ that will render on top of your game but will be ignored in a production release.
+5. Debugging something that runs at 60fps is (imo) not that helpful. The exception you are seeing could have been because of a change that occurred many frames ago.
+
+** Frequent Comments About Ruby as a Language Choice
*** But Ruby is dead.
@@ -1022,6 +1058,8 @@ If you have ideas on how we can do this, email us!
If the reason above isn't sufficient, then definitely use something else.
+All this being said, we do have parts of the engine open sourced on GitHub: [[https://github.com/dragonruby/dragonruby-game-toolkit-contrib/]]
+
*** DragonRuby is for pay. You should offer a free version.
If you can afford to pay for DragonRuby, you should (and will). We don't go
@@ -1084,6 +1122,9 @@ under a permissive license.
* DOCS: ~GTK::Runtime~
The GTK::Runtime class is the core of DragonRuby. It is globally accessible via ~$gtk~.
+* DOCS: ~GTK::Runtime#reset~
+This function will reset Kernel.tick_count to 0 and will remove all data from args.state.
+
* DOCS: ~GTK::Runtime#calcstringbox~
This function returns the width and height of a string.
@@ -1094,8 +1135,18 @@ This function returns the width and height of a string.
end
#+end_src
-* DOCS: ~GTK::Runtime#reset~
-This function will reset Kernel.tick_count to 0 and will remove all data from args.state.
+* DOCS: ~GTK::Runtime#write_file~
+This function takes in two parameters. The first paramter is the file path and assumes the the game
+directory is the root. The second parameter is the string that will be written. The method overwrites whatever
+is currently in the file. Use ~GTK::Runtime#append_file~ to append to the file as opposed to overwriting.
+
+#+begin_src ruby
+ def tick args
+ if args.inputs.mouse.click
+ args.gtk.write_file "last-mouse-click.txt", "Mouse was clicked at #{args.state.tick_count}."
+ end
+ end
+#+end_src
* DOCS: ~Array~
@@ -1804,8 +1855,9 @@ Returns the current tick of the application from the point it was started. This
* Open Source
Follows is a source code listing for all files that have been open sourced. This code can be found in the ~./samples~ directory and online at [[https://github.com/DragonRuby/dragonruby-game-toolkit-contrib/]].
-* 00_learn_ruby_optional/00_beginner_ruby_primer/app/automation.rb
+* Learn Ruby Optional - Beginner Ruby Primer - automation.rb
#+begin_src ruby
+ # ./samples/00_learn_ruby_optional/00_beginner_ruby_primer/app/automation.rb
# ==========================================================================
# _ _ ________ __ _ _____ _____ _______ ______ _ _ _ _ _ _
# | | | | ____\ \ / / | | |_ _|/ ____|__ __| ____| \ | | | | | |
@@ -1929,8 +1981,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 00_learn_ruby_optional/00_beginner_ruby_primer/app/main.rb
+* Learn Ruby Optional - Beginner Ruby Primer - main.rb
#+begin_src ruby
+ # ./samples/00_learn_ruby_optional/00_beginner_ruby_primer/app/main.rb
# ==========================================================================
# _ _ ________ __ _ _____ _____ _______ ______ _ _ _ _ _ _
# | | | | ____\ \ / / | | |_ _|/ ____|__ __| ____| \ | | | | | |
@@ -2251,21 +2304,619 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 00_learn_ruby_optional/00_intermediate_ruby_primer/app/main.rb
+* Learn Ruby Optional - Intermediate Ruby Primer - printing.txt
+#+begin_src ruby
+ # ./samples/00_learn_ruby_optional/00_intermediate_ruby_primer/app/01_printing.txt
+ # ====================================================================================
+ # Commenting Code
+ # ====================================================================================
+ #
+ # Prefixing text with a pound sign (#) is how you comment code in Ruby. Example:
+ #
+ # I am commented code. And so are the lines above.
+ #
+ # I you want more than a quick primer on Ruby, check out https://poignant.guide/. It's
+ # an entertaining read. Otherwise, go to the next txt file.
+ #
+ # Follow along by visiting:
+ # https://s3.amazonaws.com/s3.dragonruby.org/dragonruby-gtk-intermediate.mp4
+
+ # ====================================================================================
+ # Printing to the Console:
+ # ====================================================================================
+ #
+ # Every time you save repl.rb file, DragonRuby runs the code within it. Copy this text
+ # to repl.rb and save to see Hello World printed to the console.
+
+ repl do
+ puts '* RUBY PRIMER: Printing to the console using the ~puts~ function.'
+ puts '===='
+ puts '======'
+ puts '================================'
+ puts 'Hello World'
+ puts '================================'
+ puts '======'
+ puts '===='
+ end
+
+#+end_src
+
+* Learn Ruby Optional - Intermediate Ruby Primer - strings.txt
+#+begin_src ruby
+ # ./samples/00_learn_ruby_optional/00_intermediate_ruby_primer/app/02_strings.txt
+ # ====================================================================================
+ # Strings
+ # ====================================================================================
+ #
+ # Here is how you work with strings in Ruby. Take the text
+ # in this file and paste it into repl.rb and save:
+
+ repl do
+ puts '* RUBY PRIMER: strings'
+ message = "Hello World"
+ puts "The value of message is: " + message
+ puts "Any value can be interpolated within a string using \#{}."
+ puts "Interpolated message: #{message}."
+ puts 'This #{message} is not interpolated because the string uses single quotes.'
+ end
+
+#+end_src
+
+* Learn Ruby Optional - Intermediate Ruby Primer - numbers.txt
+#+begin_src ruby
+ # ./samples/00_learn_ruby_optional/00_intermediate_ruby_primer/app/03_numbers.txt
+ # ====================================================================================
+ # Numerics
+ # ====================================================================================
+ #
+ # Here is how you work with numbers in Ruby. Take the text
+ # in this file and paste it into repl.rb and save:
+
+ repl do
+ puts '* RUBY PRIMER: Fixnum and Floats'
+ a = 10
+ puts "The value of a is: #{a}"
+ puts "a + 1 is: #{a + 1}"
+ puts "a / 3 is: #{a / 3}"
+ puts ''
+
+ b = 10.12
+ puts "The value of b is: #{b}"
+ puts "b + 1 is: #{b + 1}"
+ puts "b as an integer is: #{b.to_i}"
+ puts ''
+ end
+
+#+end_src
+
+* Learn Ruby Optional - Intermediate Ruby Primer - booleans.txt
+#+begin_src ruby
+ # ./samples/00_learn_ruby_optional/00_intermediate_ruby_primer/app/04_booleans.txt
+ # ====================================================================================
+ # Booleans
+ # ====================================================================================
+ #
+ # Here is how you work with numbers in Ruby. Take the text
+ # in this file and paste it into repl.rb and save:
+
+ repl do
+ puts '* RUBY PRIMER: TrueClass, FalseClass, NilClass (truthy / falsey values)'
+ puts "Anything that *isn't* false or nil is true."
+
+ c = 30
+ puts "The value of c is #{c}."
+
+ if c
+ puts "This if statement ran because c is truthy."
+ end
+
+ d = false
+ puts "The value if d is #{d}. The type for d is #{d.class}."
+
+ if !d
+ puts "This if statement ran because d is falsey, using the not operator (!)."
+ end
+
+ e = nil
+ puts "Nil is also considered falsey. The value of e is: #{e} (a blank string when printed). Which is of type #{e.class}."
+
+ if !e
+ puts "This if statement ran because e is nil and the if statement applied the NOT operator. !e yields a type of #{(!e).class}."
+ end
+ end
+
+#+end_src
+
+* Learn Ruby Optional - Intermediate Ruby Primer - conditionals.txt
+#+begin_src ruby
+ # ./samples/00_learn_ruby_optional/00_intermediate_ruby_primer/app/05_conditionals.txt
+ # ====================================================================================
+ # Conditionals
+ # ====================================================================================
+ #
+ # Here is how you create conditionals in Ruby. Take the text
+ # in this file and paste it into repl.rb and save:
+
+ repl do
+ puts "* RUBY PRIMER: Conditionals"
+ end
+
+ # ====================================================================================
+ # if
+ # ====================================================================================
+
+ repl do
+ puts "** INFO: if statement"
+ i_am_one = 1
+ if i_am_one
+ puts "This was printed because i_am_one is truthy."
+ end
+ end
+
+ # ====================================================================================
+ # if/else
+ # ====================================================================================
+
+ repl do
+ puts "** INFO: if/else statement"
+ i_am_false = false
+ if i_am_false
+ puts "This will NOT get printed because i_am_false is false."
+ else
+ puts "This was printed because i_am_false is false."
+ end
+ end
+
+
+ # ====================================================================================
+ # if/elsif/else
+ # ====================================================================================
+
+ repl do
+ puts "** INFO: if/elsif/else statement"
+ i_am_false = false
+ i_am_true = true
+ if i_am_false
+ puts "This will NOT get printed because i_am_false is false."
+ elsif i_am_true
+ puts "This was printed because i_am_true is true."
+ else
+ puts "This will NOT get printed i_am_true was true."
+ end
+ end
+
+ # ====================================================================================
+ # case
+ # ====================================================================================
+
+ repl do
+ puts "** INFO case statement"
+ i_am_one = 1 # change this value to see different results
+
+ case i_am_one
+ when 10
+ puts "the value of i_am_one is 10"
+ when 9
+ puts "the value of i_am_one is 9"
+ when 5
+ puts "the value of i_am_one is 5"
+ when 1
+ puts "the value of i_am_one is 1"
+ else
+ puts "Value wasn't cased."
+ end
+ end
+
+ # ====================================================================================
+ # comparison operators
+ # ====================================================================================
+
+ repl do
+ puts "** INFO: Different types of comparisons"
+ if 4 == 4
+ puts "4 equals 4 (==)"
+ end
+
+ if 4 != 3
+ puts "4 does not equal 3 (!=)"
+ end
+
+ if 3 < 4
+ puts "3 is less than 4 (<)"
+ end
+
+ if 4 > 3
+ puts "4 is greater than 3 (>)"
+ end
+ end
+
+ # ====================================================================================
+ # and/or conditionals
+ # ====================================================================================
+
+ repl do
+ puts "** INFO: AND, OR operator (&&, ||)"
+ if (4 > 3) || (3 < 4) || false
+ puts "print this if 4 is greater than 3 OR 3 is less than 4 OR false is true (||)"
+ end
+
+ if (4 > 3) && (3 < 4)
+ puts "print this if 4 is greater than 3 AND 3 is less than 4 (&&)"
+ end
+ end
+
+#+end_src
+
+* Learn Ruby Optional - Intermediate Ruby Primer - looping.txt
#+begin_src ruby
+ # ./samples/00_learn_ruby_optional/00_intermediate_ruby_primer/app/06_looping.txt
+ # ====================================================================================
+ # Looping
+ # ====================================================================================
+ #
+ # Looping looks a whole lot different than other languages.
+ # But it's pretty awesome when you get used to it.
+
+ repl do
+ puts "* RUBY PRIMER: Loops"
+ end
+
+ # ====================================================================================
+ # times
+ # ====================================================================================
+
+ repl do
+ puts "** INFO: ~Numeric#times~ (for loop)"
+ 3.times do |i|
+ puts i
+ end
+ end
+
+ # ====================================================================================
+ # foreach
+ # ====================================================================================
+
+ repl do
+ puts "** INFO: ~Array#each~ (for each loop)"
+ array = ["a", "b", "c", "d"]
+ array.each do |char|
+ puts char
+ end
+
+ puts "** INFO: ~Array#each_with_index~ (for each loop)"
+ array = ["a", "b", "c", "d"]
+ array.each do |char, i|
+ puts "index #{i}: #{char}"
+ end
+ end
+
+ # ====================================================================================
+ # ranges
+ # ====================================================================================
+
+ repl do
+ puts "** INFO: range block exclusive (three dots)"
+ (0...3).each do |i|
+ puts i
+ end
+
+ puts "** INFO: range block inclusive (two dots)"
+ (0..3).each do |i|
+ puts i
+ end
+ end
+
+#+end_src
+
+* Learn Ruby Optional - Intermediate Ruby Primer - functions.txt
+#+begin_src ruby
+ # ./samples/00_learn_ruby_optional/00_intermediate_ruby_primer/app/07_functions.txt
+ # ====================================================================================
+ # Functions
+ # ====================================================================================
+
+ # The last statement of a function is implictly returned. Parenthesis for functions
+ # are optional as long as the statement can be envaluated disambiguously.
+
+ repl do
+ puts "* RUBY PRIMER: Functions"
+ end
+
+ # ====================================================================================
+ # Functions single parameter
+ # ====================================================================================
+
+ repl do
+ puts "* INFO: Function with one parameter"
+
+ # function definition
+ def add_one_to n
+ n + 1
+ end
+
+ # Parenthesis are optional in Ruby as long as the
+ # parsing is disambiguous. Here are a couple of variations.
+ # Generally speaking, don't put parenthesis is you don't have to.
+
+ # Conventional Usage of Parenthesis.
+ puts add_one_to(3)
+
+ # DragonRuby's recommended use of parenthesis (inner function has parenthesis).
+ puts (add_one_to 3)
+
+ # Full parens.
+ puts(add_one_to(3))
+
+ # Outer function has parenthesis
+ puts(add_one_to 3)
+ end
+
+ # ====================================================================================
+ # Functions with default parameter values
+ # ====================================================================================
+
+ repl do
+ puts "* INFO: Function with default value"
+ def function_with_default_value v = 10
+ v * 10
+ end
+
+ puts "Passing the argument three yields: #{function_with_default_value 3}"
+ puts "Passing no argument yields: #{function_with_default_value}"
+ end
+
+ # ====================================================================================
+ # Nil default parameter value and ||= operator.
+ # ====================================================================================
+
+ repl do
+ puts "* INFO: Using the OR EQUAL operator (||=)"
+ def function_with_nil_default_with_local a = nil
+ result = a
+ result ||= "DEFAULT_VALUE_OF_A_IS_NIL_OR_FALSE"
+ "value is #{result}."
+ end
+
+ puts "Passing 'hi' as the argument yields: #{function_with_nil_default_with_local 'hi'}"
+ puts "Passing nil: #{function_with_nil_default_with_local}"
+ end
+
+#+end_src
+
+* Learn Ruby Optional - Intermediate Ruby Primer - arrays.txt
+#+begin_src ruby
+ # ./samples/00_learn_ruby_optional/00_intermediate_ruby_primer/app/08_arrays.txt
+ # ====================================================================================
+ # Arrays
+ # ====================================================================================
+
+ # Arrays are incredibly powerful in Ruby. Learn to use them well.
+
+ repl do
+ puts "* RUBY PRIMER: ARRAYS"
+ end
+
+ # ====================================================================================
+ # Enumerable ranges and .to_a
+ # ====================================================================================
+
+ repl do
+ puts "** INFO: Create an array with the numbers 1 to 10."
+ one_to_ten = (1..10).to_a
+ puts one_to_ten
+ end
+
+ # ====================================================================================
+ # Finding elements
+ # ====================================================================================
+
+ repl do
+ puts "** INFO: Finding elements in an array using ~Array#find_all~."
+ puts "Create a new array that only contains even numbers from the previous array."
+
+ one_to_ten = (1..10).to_a
+ evens = one_to_ten.find_all do |number|
+ number % 2 == 0
+ end
+
+ puts evens
+ end
+
+ # ====================================================================================
+ # Rejecting elements
+ # ====================================================================================
+
+ repl do
+ puts "** INFO: Removing elements in an array using ~Array#reject~."
+ puts "Create a new array that rejects odd numbers."
+
+ one_to_ten = (1..10).to_a
+ also_even = one_to_ten.reject do |number|
+ number % 2 != 0
+ end
+
+ puts also_even
+ end
+
+ # ====================================================================================
+ # Array transform using the map function.
+ # ====================================================================================
+
+ repl do
+ puts "** INFO: Creating new derived values from an array using ~Array#map~."
+ puts "Create an array that doubles every number."
+
+ one_to_ten = (1..10).to_a
+ doubled = one_to_ten.map do |number|
+ number * 2
+ end
+
+ puts doubled
+ end
+
+ # ====================================================================================
+ # Combining array functions.
+ # ====================================================================================
+
+ repl do
+ puts "** INFO: Combining ~Array#find_all~ along with ~Array#map~."
+ puts "Create an array that selects only odd numbers and then multiply those by 10."
+
+ one_to_ten = (1..10).to_a
+ odd_doubled = one_to_ten.find_all do |number|
+ number % 2 != 0
+ end.map do |odd_number|
+ odd_number * 10
+ end
+
+ puts odd_doubled
+ end
+
+ # ====================================================================================
+ # Product function.
+ # ====================================================================================
+
+ repl do
+ puts "** INFO: Create all combinations of array values using ~Array#product~."
+ puts "All two-item pairs of numbers 1 to 10."
+ one_to_ten = (1..10).to_a
+ all_combinations = one_to_ten.product(one_to_ten)
+ puts all_combinations
+ end
+
+ # ====================================================================================
+ # Uniq and sort function.
+ # ====================================================================================
+
+ repl do
+ puts "** INFO: Providing uniq values using ~Array#uniq~ and ~Array#sort~."
+ puts "All uniq combinations of numbers regardless of order."
+ puts "For example: [1, 2] is the same as [2, 1]."
+ one_to_ten = (1..10).to_a
+ uniq_combinations =
+ one_to_ten.product(one_to_ten)
+ .map do |unsorted_number|
+ unsorted_number.sort
+ end.uniq
+ puts uniq_combinations
+ end
+
+ # ====================================================================================
+ # Example of an advanced array transform.
+ # ====================================================================================
+
+ repl do
+ puts "** INFO: Advanced chaining. Combining ~Array's ~map~, ~find_all~, ~sort~, and ~sort_by~."
+ puts "All unique Pythagorean Triples between 1 and 100 sorted by area of the triangle."
+
+ one_to_hundred = (1..100).to_a
+
+ triples =
+ one_to_hundred.product(one_to_hundred).map do |width, height|
+ [width, height, Math.sqrt(width ** 2 + height ** 2)]
+ end.find_all do |_, _, hypotenuse|
+ hypotenuse.to_i == hypotenuse
+ end.map do |triangle|
+ triangle.map(&:to_i)
+ end.uniq do |triangle|
+ triangle.sort
+ end.map do |width, height, hypotenuse|
+ [width, height, hypotenuse, (width * height) / 2]
+ end.sort_by do |_, _, _, area|
+ area
+ end
+
+ triples.each do |width, height, hypotenuse, _|
+ puts "(#{width}, #{height}, #{hypotenuse})"
+ end
+ end
+
+ # ====================================================================================
+ # Example of an sorting.
+ # ====================================================================================
+
+ repl do
+ puts "** INFO: Implementing a custom sort function that operates on the ~Hash~ datatype."
+
+ things_to_sort = [
+ { type: :background, order: 1 },
+ { type: :foreground, order: 1 },
+ { type: :foreground, order: 2 }
+ ]
+ puts "*** Original array."
+ puts things_to_sort
+
+ puts "*** Simple sort using key."
+ # For a simple sort, you can use sort_by
+ results = things_to_sort.sort_by do |hash|
+ hash[:order]
+ end
+
+ puts results
+
+ puts "*** Custom sort."
+ puts "**** Sorting process."
+ # for a more complicated sort, you can provide a block that returns
+ # -1, 0, 1 for a left and right operand
+ results = things_to_sort.sort do |l, r|
+ sort_result = 0
+ puts "here is l: #{l}"
+ puts "here is r: #{r || "nil"}"
+ # if either value is nil/false return 0
+ if !l || !r
+ sort_result = 0
+ # if the type of "left" is background and the
+ # type of "right" is foreground, then return
+ # -1 (which means "left" is less than "right"
+ elsif l[:type] == :background && r[:type] == :foreground
+ sort_result = -1
+ # if the type of "left" is foreground and the
+ # type of "right" is background, then return
+ # 1 (which means "left" is greater than "right"
+ elsif l[:type] == :foreground && r[:type] == :background
+ sort_result = 1
+ # if "left" and "right"'s type are the same, then
+ # use the order as the tie breaker
+ elsif l[:order] < r[:order]
+ sort_result = -1
+ elsif l[:order] > r[:order]
+ sort_result = 1
+ # returning 0 means both values are equal
+ else
+ sort_result = 0
+ end
+ sort_result
+ end.to_a
+
+ puts "**** Sort result."
+ puts results
+ end
+
+ # ====================================================================================
+ # Api documention for Array that is worth commiting to memory because arrays are so
+ # awesome in Ruby: https://docs.ruby-lang.org/en/2.0.0/Array.html
+ # ====================================================================================
+
+#+end_src
+
+* Learn Ruby Optional - Intermediate Ruby Primer - main.rb
+#+begin_src ruby
+ # ./samples/00_learn_ruby_optional/00_intermediate_ruby_primer/app/main.rb
def tick args
args.outputs.labels << [640, 380, "Open repl.rb in the text editor of your choice and follow the document.", 0, 1]
end
#+end_src
-* 00_learn_ruby_optional/00_intermediate_ruby_primer/app/repl.rb
+* Learn Ruby Optional - Intermediate Ruby Primer - repl.rb
#+begin_src ruby
+ # ./samples/00_learn_ruby_optional/00_intermediate_ruby_primer/app/repl.rb
#+end_src
-* 01_rendering_basics/01_labels/app/main.rb
+* Rendering Basics - Labels - main.rb
#+begin_src ruby
+ # ./samples/01_rendering_basics/01_labels/app/main.rb
=begin
APIs listing that haven't been encountered in a previous sample apps:
@@ -2368,8 +3019,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 01_rendering_basics/02_lines/app/main.rb
+* Rendering Basics - Lines - main.rb
#+begin_src ruby
+ # ./samples/01_rendering_basics/02_lines/app/main.rb
=begin
APIs listing that haven't been encountered in a previous sample apps:
@@ -2427,8 +3079,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 01_rendering_basics/03_solids_borders/app/main.rb
+* Rendering Basics - Solids Borders - main.rb
#+begin_src ruby
+ # ./samples/01_rendering_basics/03_solids_borders/app/main.rb
=begin
APIs listing that haven't been encountered in a previous sample apps:
@@ -2498,8 +3151,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 01_rendering_basics/04_sprites/app/main.rb
+* Rendering Basics - Sprites - main.rb
#+begin_src ruby
+ # ./samples/01_rendering_basics/04_sprites/app/main.rb
=begin
APIs listing that haven't been encountered in a previous sample apps:
@@ -2546,8 +3200,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 01_rendering_basics/05_sounds/app/main.rb
+* Rendering Basics - Sounds - main.rb
#+begin_src ruby
+ # ./samples/01_rendering_basics/05_sounds/app/main.rb
=begin
APIs Listing that haven't been encountered in previous sample apps:
@@ -2740,8 +3395,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 02_input_basics/01_keyboard/app/main.rb
+* Input Basics - Keyboard - main.rb
#+begin_src ruby
+ # ./samples/02_input_basics/01_keyboard/app/main.rb
=begin
APIs listing that haven't been encountered in a previous sample apps:
@@ -2915,8 +3571,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 02_input_basics/02_mouse/app/main.rb
+* Input Basics - Mouse - main.rb
#+begin_src ruby
+ # ./samples/02_input_basics/02_mouse/app/main.rb
=begin
APIs that haven't been encountered in a previous sample apps:
@@ -3007,8 +3664,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 02_input_basics/03_mouse_point_to_rect/app/main.rb
+* Input Basics - Mouse Point To Rect - main.rb
#+begin_src ruby
+ # ./samples/02_input_basics/03_mouse_point_to_rect/app/main.rb
=begin
APIs that haven't been encountered in a previous sample apps:
@@ -3102,8 +3760,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 02_input_basics/04_mouse_rect_to_rect/app/main.rb
+* Input Basics - Mouse Rect To Rect - main.rb
#+begin_src ruby
+ # ./samples/02_input_basics/04_mouse_rect_to_rect/app/main.rb
=begin
APIs that haven't been encountered in a previous sample apps:
@@ -3204,8 +3863,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 02_input_basics/05_controller/app/main.rb
+* Input Basics - Controller - main.rb
#+begin_src ruby
+ # ./samples/02_input_basics/05_controller/app/main.rb
=begin
APIs listing that haven't been encountered in previous sample apps:
@@ -3335,8 +3995,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 03_rendering_sprites/01_animation_using_seperate_pngs/app/main.rb
+* Rendering Sprites - Animation Using Separate Pngs - main.rb
#+begin_src ruby
+ # ./samples/03_rendering_sprites/01_animation_using_separate_pngs/app/main.rb
=begin
Reminders:
@@ -3471,8 +4132,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 03_rendering_sprites/02_animation_using_sprite_sheet/app/main.rb
+* Rendering Sprites - Animation Using Sprite Sheet - main.rb
#+begin_src ruby
+ # ./samples/03_rendering_sprites/02_animation_using_sprite_sheet/app/main.rb
def tick args
args.state.player.x ||= 100
args.state.player.y ||= 100
@@ -3574,8 +4236,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 03_rendering_sprites/03_animation_states/app/main.rb
+* Rendering Sprites - Animation States - main.rb
#+begin_src ruby
+ # ./samples/03_rendering_sprites/03_animation_states/app/main.rb
class Game
attr_gtk
@@ -3762,8 +4425,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 03_rendering_sprites/04_color_and_rotation/app/main.rb
+* Rendering Sprites - Color And Rotation - main.rb
#+begin_src ruby
+ # ./samples/03_rendering_sprites/04_color_and_rotation/app/main.rb
=begin
APIs listing that haven't been encountered in previous sample apps:
@@ -3993,8 +4657,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 04_physics_and_collisions/01_simple/app/main.rb
+* Physics And Collisions - Simple - main.rb
#+begin_src ruby
+ # ./samples/04_physics_and_collisions/01_simple/app/main.rb
=begin
Reminders:
@@ -4106,8 +4771,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 04_physics_and_collisions/02_moving_objects/app/main.rb
+* Physics And Collisions - Moving Objects - main.rb
#+begin_src ruby
+ # ./samples/04_physics_and_collisions/02_moving_objects/app/main.rb
=begin
APIs listing that haven't been encountered in previous sample apps:
@@ -4411,8 +5077,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 04_physics_and_collisions/03_entities/app/main.rb
+* Physics And Collisions - Entities - main.rb
#+begin_src ruby
+ # ./samples/04_physics_and_collisions/03_entities/app/main.rb
=begin
Reminders:
@@ -4567,8 +5234,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 04_physics_and_collisions/04_box_collision/app/main.rb
+* Physics And Collisions - Box Collision - main.rb
#+begin_src ruby
+ # ./samples/04_physics_and_collisions/04_box_collision/app/main.rb
=begin
APIs listing that haven't been encountered in previous sample apps:
@@ -4909,8 +5577,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 04_physics_and_collisions/04_box_collision_2/app/main.rb
+* Physics And Collisions - Box Collision 2 - main.rb
#+begin_src ruby
+ # ./samples/04_physics_and_collisions/05_box_collision_2/app/main.rb
=begin
APIs listing that haven't been encountered in previous sample apps:
@@ -5384,8 +6053,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 04_physics_and_collisions/04_jump_physics/app/main.rb
+* Physics And Collisions - Jump Physics - main.rb
#+begin_src ruby
+ # ./samples/04_physics_and_collisions/06_jump_physics/app/main.rb
=begin
Reminders:
@@ -5585,8 +6255,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 05_mouse/03_mouse_click/app/main.rb
+* Mouse - Mouse Click - main.rb
#+begin_src ruby
+ # ./samples/05_mouse/01_mouse_click/app/main.rb
=begin
APIs listing that haven't been encountered in previous sample apps:
@@ -5834,8 +6505,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 05_mouse/05_mouse_move/app/main.rb
+* Mouse - Mouse Move - main.rb
#+begin_src ruby
+ # ./samples/05_mouse/02_mouse_move/app/main.rb
=begin
Reminders:
@@ -6135,8 +6807,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 05_mouse/05_mouse_move_paint_app/app/main.rb
+* Mouse - Mouse Move Paint App - main.rb
#+begin_src ruby
+ # ./samples/05_mouse/03_mouse_move_paint_app/app/main.rb
=begin
APIs listing that haven't been encountered in previous sample apps:
@@ -6380,8 +7053,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 05_mouse/06_coordinate_systems/app/main.rb
+* Mouse - Coordinate Systems - main.rb
#+begin_src ruby
+ # ./samples/05_mouse/04_coordinate_systems/app/main.rb
=begin
APIs listing that haven't been encountered in previous sample apps:
@@ -6465,8 +7139,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 06_save_load/10_save_load_game/app/main.rb
+* Save Load - Save Load Game - main.rb
#+begin_src ruby
+ # ./samples/06_save_load/01_save_load_game/app/main.rb
=begin
APIs listing that haven't been encountered in previous sample apps:
@@ -6859,8 +7534,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 07_advanced_rendering/01_simple_render_targets/app/main.rb
+* Advanced Rendering - Simple Render Targets - main.rb
#+begin_src ruby
+ # ./samples/07_advanced_rendering/01_simple_render_targets/app/main.rb
def tick args
# args.outputs.render_targets are really really powerful.
# They essentially allow you to create a sprite programmatically and cache the result.
@@ -6916,8 +7592,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 07_advanced_rendering/02_render_targets_with_alphas/app/main.rb
+* Advanced Rendering - Render Targets With Alphas - main.rb
#+begin_src ruby
+ # ./samples/07_advanced_rendering/02_render_targets_with_alphas/app/main.rb
# This sample is meant to show you how to do that dripping transition thing
# at the start of the original Doom. Most of this file is here to animate
# a scene to wipe away; the actual wipe effect is in the last 20 lines or
@@ -7016,8 +7693,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 07_advanced_rendering/03_render_target_viewports/app/main.rb
+* Advanced Rendering - Render Target Viewports - main.rb
#+begin_src ruby
+ # ./samples/07_advanced_rendering/03_render_target_viewports/app/main.rb
=begin
APIs listing that haven't been encountered in previous sample apps:
@@ -7489,8 +8167,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 07_advanced_rendering/04_render_primitive_hierarchies/app/main.rb
+* Advanced Rendering - Render Primitive Hierarchies - main.rb
#+begin_src ruby
+ # ./samples/07_advanced_rendering/04_render_primitive_hierarchies/app/main.rb
=begin
APIs listing that haven't been encountered in previous sample apps:
@@ -7666,8 +8345,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 07_advanced_rendering/11_render_primitives_as_hash/app/main.rb
+* Advanced Rendering - Render Primitives As Hash - main.rb
#+begin_src ruby
+ # ./samples/07_advanced_rendering/05_render_primitives_as_hash/app/main.rb
=begin
Reminders:
@@ -7862,8 +8542,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 08_lerping_easing_functions/01_easing_functions/app/main.rb
+* Tweening Lerping Easing Functions - Easing Functions - main.rb
#+begin_src ruby
+ # ./samples/08_tweening_lerping_easing_functions/01_easing_functions/app/main.rb
def tick args
# STOP! Watch the following presentation first!!!!
# Math for Game Programmers: Fast and Funky 1D Nonlinear Transformations
@@ -7999,8 +8680,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 08_lerping_easing_functions/02_cubic_bezier/app/main.rb
+* Tweening Lerping Easing Functions - Cubic Bezier - main.rb
#+begin_src ruby
+ # ./samples/08_tweening_lerping_easing_functions/02_cubic_bezier/app/main.rb
def tick args
args.outputs.background_color = [33, 33, 33]
args.outputs.lines << bezier(100, 100,
@@ -8065,8 +8747,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 08_lerping_easing_functions/03_easing_using_spline/app/main.rb
+* Tweening Lerping Easing Functions - Easing Using Spline - main.rb
#+begin_src ruby
+ # ./samples/08_tweening_lerping_easing_functions/03_easing_using_spline/app/main.rb
def tick args
args.state.duration = 10.seconds
args.state.spline = [
@@ -8088,8 +8771,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 08_lerping_easing_functions/04_parametric_enemy_movement/app/main.rb
+* Tweening Lerping Easing Functions - Parametric Enemy Movement - main.rb
#+begin_src ruby
+ # ./samples/08_tweening_lerping_easing_functions/04_parametric_enemy_movement/app/main.rb
def new_star args
{ x: 1280.randomize(:ratio),
starting_y: 800,
@@ -8306,8 +8990,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 09_performance/01_sprites_as_hash/app/main.rb
+* Performance - Sprites As Hash - main.rb
#+begin_src ruby
+ # ./samples/09_performance/01_sprites_as_hash/app/main.rb
# Sprites represented as Hashes using the queue ~args.outputs.sprites~
# code up, but are the "slowest" to render.
# The reason for this is the access of the key in the Hash and also
@@ -8374,8 +9059,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 09_performance/02_sprites_as_entities/app/main.rb
+* Performance - Sprites As Entities - main.rb
#+begin_src ruby
+ # ./samples/09_performance/02_sprites_as_entities/app/main.rb
# Sprites represented as Entities using the queue ~args.outputs.sprites~
# yields nicer access apis over Hashes, but require a bit more code upfront.
# The hash sample has to use star[:s] to get the speed of the star, but
@@ -8443,8 +9129,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 09_performance/03_sprites_as_strict_entities/app/main.rb
+* Performance - Sprites As Strict Entities - main.rb
#+begin_src ruby
+ # ./samples/09_performance/03_sprites_as_strict_entities/app/main.rb
# Sprites represented as StrictEntities using the queue ~args.outputs.sprites~
# yields apis access similar to Entities, but all properties that can be set on the
# entity must be predefined with a default value. Strict entities do not support the
@@ -8516,8 +9203,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 09_performance/04_sprites_as_classes/app/main.rb
+* Performance - Sprites As Classes - main.rb
#+begin_src ruby
+ # ./samples/09_performance/04_sprites_as_classes/app/main.rb
# Sprites represented as Classes using the queue ~args.outputs.sprites~.
# gives you full control of property declaration and method invocation.
# They are more performant than OpenEntities and StrictEntities, but more code upfront.
@@ -8571,8 +9259,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 09_performance/05_static_sprites_as_classes/app/main.rb
+* Performance - Static Sprites As Classes - main.rb
#+begin_src ruby
+ # ./samples/09_performance/05_static_sprites_as_classes/app/main.rb
# Sprites represented as Classes using the queue ~args.outputs.static_sprites~.
# bypasses the queue behavior of ~args.outputs.sprites~. All instances are held
# by reference. You get better performance, but you are mutating state of held objects
@@ -8627,8 +9316,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 09_performance/06_static_sprites_as_classes_with_custom_drawing/app/main.rb
+* Performance - Static Sprites As Classes With Custom Drawing - main.rb
#+begin_src ruby
+ # ./samples/09_performance/06_static_sprites_as_classes_with_custom_drawing/app/main.rb
# Sprites represented as Classes, with a draw_override method, and using the queue ~args.outputs.static_sprites~.
# is the fastest approach. This is comparable to what other game engines set as the default behavior.
# There are tradeoffs for all this speed if the creation of a full blown class, and bypassing
@@ -8704,8 +9394,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 09_performance/07_collision_limits/app/main.rb
+* Performance - Collision Limits - main.rb
#+begin_src ruby
+ # ./samples/09_performance/07_collision_limits/app/main.rb
=begin
Reminders:
@@ -8764,8 +9455,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 10_advanced_debugging/01_trace_debugging/app/main.rb
+* Advanced Debugging - Trace Debugging - main.rb
#+begin_src ruby
+ # ./samples/10_advanced_debugging/01_trace_debugging/app/main.rb
class Game
attr_gtk
@@ -8822,8 +9514,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 10_advanced_debugging/02_trace_debugging_classes/app/main.rb
+* Advanced Debugging - Trace Debugging Classes - main.rb
#+begin_src ruby
+ # ./samples/10_advanced_debugging/02_trace_debugging_classes/app/main.rb
class Foobar
def initialize
trace! # Trace is added to the constructor.
@@ -8849,8 +9542,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 10_advanced_debugging/03_unit_tests/exception_raising_tests.rb
+* Advanced Debugging - Unit Tests - exception_raising_tests.rb
#+begin_src ruby
+ # ./samples/10_advanced_debugging/03_unit_tests/exception_raising_tests.rb
begin :shared
class ExceptionalClass
def initialize exception_to_throw = nil
@@ -8875,15 +9569,17 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 10_advanced_debugging/03_unit_tests/gen_docs.rb
+* Advanced Debugging - Unit Tests - gen_docs.rb
#+begin_src ruby
+ # ./samples/10_advanced_debugging/03_unit_tests/gen_docs.rb
# sh ./amir-build-and-run.sh --eval samples/99_zz_gtk_unit_tests/gen_docs.rb --no-tick
Kernel.export_docs!
#+end_src
-* 10_advanced_debugging/03_unit_tests/geometry_tests.rb
+* Advanced Debugging - Unit Tests - geometry_tests.rb
#+begin_src ruby
+ # ./samples/10_advanced_debugging/03_unit_tests/geometry_tests.rb
begin :shared
def primitive_representations x, y, w, h
[
@@ -9003,8 +9699,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 10_advanced_debugging/03_unit_tests/http_tests.rb
+* Advanced Debugging - Unit Tests - http_tests.rb
#+begin_src ruby
+ # ./samples/10_advanced_debugging/03_unit_tests/http_tests.rb
def try_assert_or_schedule args, assert
if $result[:complete]
log_info "Request completed! Verifying."
@@ -9032,8 +9729,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 10_advanced_debugging/03_unit_tests/object_to_primitive_tests.rb
+* Advanced Debugging - Unit Tests - object_to_primitive_tests.rb
#+begin_src ruby
+ # ./samples/10_advanced_debugging/03_unit_tests/object_to_primitive_tests.rb
class PlayerSpriteForTest
end
@@ -9054,8 +9752,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 10_advanced_debugging/03_unit_tests/parsing_tests.rb
+* Advanced Debugging - Unit Tests - parsing_tests.rb
#+begin_src ruby
+ # ./samples/10_advanced_debugging/03_unit_tests/parsing_tests.rb
def test_parse_json args, assert
result = args.gtk.parse_json '{ "name": "John Doe", "aliases": ["JD"] }'
assert.equal! result, { "name"=>"John Doe", "aliases"=>["JD"] }, "Parsing JSON failed."
@@ -9088,8 +9787,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 10_advanced_debugging/03_unit_tests/serialize_deserialize_tests.rb
+* Advanced Debugging - Unit Tests - serialize_deserialize_tests.rb
#+begin_src ruby
+ # ./samples/10_advanced_debugging/03_unit_tests/serialize_deserialize_tests.rb
def test_serialize args, assert
GTK::Entity.__reset_id__!
args.state.player_one = "test"
@@ -9179,8 +9879,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 10_advanced_debugging/03_unit_tests/state_serialization_experimental_tests.rb
+* Advanced Debugging - Unit Tests - state_serialization_experimental_tests.rb
#+begin_src ruby
+ # ./samples/10_advanced_debugging/03_unit_tests/state_serialization_experimental_tests.rb
MAX_CODE_GEN_LENGTH = 50
# NOTE: This is experimental/advanced stuff.
@@ -9291,8 +9992,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 11_http/01_retrieve_images/app/main.rb
+* Http - Retrieve Images - main.rb
#+begin_src ruby
+ # ./samples/11_http/01_retrieve_images/app/main.rb
def tick args
args.outputs.background_color = [0, 0, 0]
@@ -9349,8 +10051,22 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 99_genre_3d/3d_cube/app/main.rb
+* 12 C Extensions - Basics - main.rb
#+begin_src ruby
+ # ./samples/12_c_extensions/01_basics/app/main.rb
+ $gtk.ffi_misc.gtk_dlopen("./samples/12_c_extensions/01_basics/build.dir/ext.lib")
+ include FFI::CExt
+
+ def tick args
+ args.outputs.labels << [460, 600, "square(42) = #{square(42)}"]
+ end
+
+
+#+end_src
+
+* 3d - 3d Cube - main.rb
+#+begin_src ruby
+ # ./samples/99_genre_3d/3d_cube/app/main.rb
STARTX = 0.0
STARTY = 0.0
ENDY = 20.0
@@ -9404,8 +10120,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 99_genre_arcade/dueling_starships/app/main.rb
+* Arcade - Dueling Starships - main.rb
#+begin_src ruby
+ # ./samples/99_genre_arcade/dueling_starships/app/main.rb
class DuelingSpaceships
attr_accessor :state, :inputs, :outputs, :grid
@@ -9774,8 +10491,18 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 99_genre_arcade/flappy_dragon/app/main.rb
+* arcade/flappy dragon/credits.txt
+#+begin_src ruby
+ # ./samples/99_genre_arcade/flappy_dragon/CREDITS.txt
+ code: Amir Rajan, https://twitter.com/amirrajan
+ graphics and audio: Nick Culbertson, https://twitter.com/MobyPixel
+
+
+#+end_src
+
+* arcade/flappy dragon/main.rb
#+begin_src ruby
+ # ./samples/99_genre_arcade/flappy_dragon/app/main.rb
class FlappyDragon
attr_accessor :grid, :inputs, :state, :outputs
@@ -10139,8 +10866,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 99_genre_arcade/pong/app/main.rb
+* Arcade - Pong - main.rb
#+begin_src ruby
+ # ./samples/99_genre_arcade/pong/app/main.rb
def tick args
defaults args
render args
@@ -10303,8 +11031,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 99_genre_arcade/snakemoji/app/main.rb
+* Arcade - Snakemoji - main.rb
#+begin_src ruby
+ # ./samples/99_genre_arcade/snakemoji/app/main.rb
# coding: utf-8
################################
# So I was working on a snake game while
@@ -10473,8 +11202,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 99_genre_arcade/solar_system/app/main.rb
+* Arcade - Solar System - main.rb
#+begin_src ruby
+ # ./samples/99_genre_arcade/solar_system/app/main.rb
# Focused tutorial video: https://s3.amazonaws.com/s3.dragonruby.org/dragonruby-nddnug-workshop.mp4
# Workshop/Presentation which provides motivation for creating a game engine: https://www.youtube.com/watch?v=S3CFce1arC8
@@ -10586,8 +11316,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 99_genre_crafting/craft_game_starting_point/app/main.rb
+* Crafting - Craft Game Starting Point - main.rb
#+begin_src ruby
+ # ./samples/99_genre_crafting/craft_game_starting_point/app/main.rb
# ==================================================
# A NOTE TO JAM CRAFT PARTICIPANTS:
# The comments and code in here are just as small piece of DragonRuby's capabilities.
@@ -11014,8 +11745,73 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 99_genre_dev_tools/animation_creator_starting_point/app/main.rb
+* Dev Tools - Add Buttons To Console - main.rb
#+begin_src ruby
+ # ./samples/99_genre_dev_tools/add_buttons_to_console/app/main.rb
+ # You can customize the buttons that show up in the Console.
+ class GTK::Console::Menu
+ # STEP 1: Override the custom_buttons function.
+ def custom_buttons
+ [
+ (button id: :yay,
+ # row for button
+ row: 3,
+ # column for button
+ col: 10,
+ # text
+ text: "I AM CUSTOM",
+ # when clicked call the custom_button_clicked function
+ method: :custom_button_clicked),
+
+ (button id: :yay,
+ # row for button
+ row: 3,
+ # column for button
+ col: 9,
+ # text
+ text: "CUSTOM ALSO",
+ # when clicked call the custom_button_also_clicked function
+ method: :custom_button_also_clicked)
+ ]
+ end
+
+ # STEP 2: Define the function that should be called.
+ def custom_button_clicked
+ log "* INFO: I AM CUSTOM was clicked!"
+ end
+
+ def custom_button_also_clicked
+ log "* INFO: Custom Button Clicked at #{Kernel.global_tick_count}!"
+
+ all_buttons_as_string = $gtk.console.menu.buttons.map do |b|
+ <<-S.strip
+ ** id: #{b[:id]}
+ :PROPERTIES:
+ :id: :#{b[:id]}
+ :method: :#{b[:method]}
+ :text: #{b[:text]}
+ :END:
+ S
+ end.join("\n")
+
+ log <<-S
+ * INFO: Here are all the buttons:
+ #{all_buttons_as_string}
+ S
+ end
+ end
+
+ def tick args
+ args.outputs.labels << [args.grid.center.x, args.grid.center.y,
+ "Open the DragonRuby Console to see the custom menu items.",
+ 0, 1]
+ end
+
+#+end_src
+
+* Dev Tools - Animation Creator Starting Point - main.rb
+#+begin_src ruby
+ # ./samples/99_genre_dev_tools/animation_creator_starting_point/app/main.rb
class OneBitLowrezPaint
attr_gtk
@@ -11466,8 +12262,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 99_genre_dev_tools/tile_editor_starting_point/app/main.rb
+* Dev Tools - Tile Editor Starting Point - main.rb
#+begin_src ruby
+ # ./samples/99_genre_dev_tools/tile_editor_starting_point/app/main.rb
=begin
APIs listing that haven't been encountered in previous sample apps:
@@ -11862,8 +12659,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 99_genre_lowrez/resolution_64x64/app/lowrez.rb
+* Lowrez - Resolution 64x64 - lowrez.rb
#+begin_src ruby
+ # ./samples/99_genre_lowrez/resolution_64x64/app/lowrez.rb
# Emulation of a 64x64 canvas. Don't change this file unless you know what you're doing :-)
# Head over to main.rb and study the code there.
@@ -12037,8 +12835,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 99_genre_lowrez/resolution_64x64/app/main.rb
+* Lowrez - Resolution 64x64 - main.rb
#+begin_src ruby
+ # ./samples/99_genre_lowrez/resolution_64x64/app/main.rb
require 'app/lowrez.rb'
def tick args
@@ -12655,2258 +13454,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 99_genre_narrative_rpg/choose_your_own_adventure/app/decision.rb
-#+begin_src ruby
- # Hey there! Welcome to Four Decisions. Here is how you
- # create your decision tree. Remove =being and =end from the text to
- # enable the game (just save the file). Change stuff and see what happens!
-
- def game
- {
- starting_decision: :stormy_night,
- decisions: {
- stormy_night: {
- description: 'It was a dark and stormy night. (storyline located in decision.rb)',
- option_one: {
- description: 'Go to sleep.',
- decision: :nap
- },
- option_two: {
- description: 'Watch a movie.',
- decision: :movie
- },
- option_three: {
- description: 'Go outside.',
- decision: :go_outside
- },
- option_four: {
- description: 'Get a snack.',
- decision: :get_a_snack
- }
- },
- nap: {
- description: 'You took a nap. The end.',
- option_one: {
- description: 'Start over.',
- decision: :stormy_night
- }
- }
- }
- }
- end
-
-#+end_src
-
-* 99_genre_narrative_rpg/choose_your_own_adventure/app/main.rb
-#+begin_src ruby
- =begin
-
- Reminders:
-
- - Hashes: Collection of unique keys and their corresponding values. The values can be found
- using their keys.
-
- In this sample app, the decisions needed for the game are stored in a hash. In fact, the
- decision.rb file contains hashes inside of other hashes!
-
- Each option is a key in the first hash, but also contains a hash (description and
- decision being its keys) as its value.
- Go into the decision.rb file and take a look before diving into the code below.
-
- - args.outputs.labels: An array. The values generate a label.
- The parameters are [X, Y, TEXT, SIZE, ALIGNMENT, RED, GREEN, BLUE, ALPHA, FONT STYLE]
- For more information about labels, go to mygame/documentation/02-labels.md.
-
- - args.keyboard.key_down.KEY: Determines if a key is in the down state or pressed down.
- For more information about the keyboard, go to mygame/documentation/06-keyboard.md.
-
- - String interpolation: uses #{} syntax; everything between the #{ and the } is evaluated
- as Ruby code, and the placeholder is replaced with its corresponding value or result.
-
- =end
-
- # This sample app provides users with a story and multiple decisions that they can choose to make.
- # Users can make a decision using their keyboard, and the story will move forward based on user choices.
-
- # The decisions available to users are stored in the decision.rb file.
- # We must have access to it for the game to function properly.
- GAME_FILE = 'app/decision.rb' # found in app folder
-
- require GAME_FILE # require used to load another file, import class/method definitions
-
- # Instructions are given using labels to users if they have not yet set up their story in the decision.rb file.
- # Otherwise, the game is run.
- def tick args
- if !args.state.loaded && !respond_to?(:game) # if game is not loaded and not responding to game symbol's method
- args.labels << [640, 370, 'Hey there! Welcome to Four Decisions.', 0, 1] # a welcome label is shown
- args.labels << [640, 340, 'Go to the file called decision.rb and tell me your story.', 0, 1]
- elsif respond_to?(:game) # otherwise, if responds to game
- args.state.loaded = true
- tick_game args # calls tick_game method, runs game
- end
-
- if args.state.tick_count.mod_zero? 60 # update every 60 frames
- t = args.gtk.ffi_file.mtime GAME_FILE # mtime returns modification time for named file
- if t != args.state.mtime
- args.state.mtime = t
- require GAME_FILE # require used to load file
- args.state.game_definition = nil # game definition and decision are empty
- args.state.decision_id = nil
- end
- end
- end
-
- # Runs methods needed for game to function properly
- # Creates a rectangular border around the screen
- def tick_game args
- defaults args
- args.borders << args.grid.rect
- render_decision args
- process_inputs args
- end
-
- # Sets default values and uses decision.rb file to define game and decision_id
- # variable using the starting decision
- def defaults args
- args.state.game_definition ||= game
- args.state.decision_id ||= args.state.game_definition[:starting_decision]
- end
-
- # Outputs the possible decision descriptions the user can choose onto the screen
- # as well as what key to press on their keyboard to make their decision
- def render_decision args
- decision = current_decision args
- # text is either the value of decision's description key or warning that no description exists
- args.labels << [640, 360, decision[:description] || "No definition found for #{args.state.decision_id}. Please update decision.rb.", 0, 1] # uses string interpolation
-
- # All decisions are stored in a hash
- # The descriptions output onto the screen are the values for the description keys of the hash.
- if decision[:option_one]
- args.labels << [10, 360, decision[:option_one][:description], 0, 0] # option one's description label
- args.labels << [10, 335, "(Press 'left' on the keyboard to select this decision)", -5, 0] # label of what key to press to select the decision
- end
-
- if decision[:option_two]
- args.labels << [1270, 360, decision[:option_two][:description], 0, 2] # option two's description
- args.labels << [1270, 335, "(Press 'right' on the keyboard to select this decision)", -5, 2]
- end
-
- if decision[:option_three]
- args.labels << [640, 45, decision[:option_three][:description], 0, 1] # option three's description
- args.labels << [640, 20, "(Press 'down' on the keyboard to select this decision)", -5, 1]
- end
-
- if decision[:option_four]
- args.labels << [640, 700, decision[:option_four][:description], 0, 1] # option four's description
- args.labels << [640, 675, "(Press 'up' on the keyboard to select this decision)", -5, 1]
- end
- end
-
- # Uses keyboard input from the user to make a decision
- # Assigns the decision as the value of the decision_id variable
- def process_inputs args
- decision = current_decision args # calls current_decision method
-
- if args.keyboard.key_down.left! && decision[:option_one] # if left key pressed and option one exists
- args.state.decision_id = decision[:option_one][:decision] # value of option one's decision hash key is set to decision_id
- end
-
- if args.keyboard.key_down.right! && decision[:option_two] # if right key pressed and option two exists
- args.state.decision_id = decision[:option_two][:decision] # value of option two's decision hash key is set to decision_id
- end
-
- if args.keyboard.key_down.down! && decision[:option_three] # if down key pressed and option three exists
- args.state.decision_id = decision[:option_three][:decision] # value of option three's decision hash key is set to decision_id
- end
-
- if args.keyboard.key_down.up! && decision[:option_four] # if up key pressed and option four exists
- args.state.decision_id = decision[:option_four][:decision] # value of option four's decision hash key is set to decision_id
- end
- end
-
- # Uses decision_id's value to keep track of current decision being made
- def current_decision args
- args.state.game_definition[:decisions][args.state.decision_id] || {} # either has value or is empty
- end
-
- # Resets the game.
- $gtk.reset
-
-#+end_src
-
-* 99_genre_narrative_rpg/return_of_serenity/app/lowrez_simulator.rb
-#+begin_src ruby
- ###################################################################################
- # YOU CAN PLAY AROUND WITH THE CODE BELOW, BUT USE CAUTION AS THIS IS WHAT EMULATES
- # THE 64x64 CANVAS.
- ###################################################################################
-
- TINY_RESOLUTION = 64
- TINY_SCALE = 720.fdiv(TINY_RESOLUTION + 5)
- CENTER_OFFSET = 10
- EMULATED_FONT_SIZE = 20
- EMULATED_FONT_X_ZERO = 0
- EMULATED_FONT_Y_ZERO = 46
-
- def tick args
- sprites = []
- labels = []
- borders = []
- solids = []
- mouse = emulate_lowrez_mouse args
- args.state.show_gridlines = false
- lowrez_tick args, sprites, labels, borders, solids, mouse
- render_gridlines_if_needed args
- render_mouse_crosshairs args, mouse
- emulate_lowrez_scene args, sprites, labels, borders, solids, mouse
- end
-
- def emulate_lowrez_mouse args
- args.state.new_entity_strict(:lowrez_mouse) do |m|
- m.x = args.mouse.x.idiv(TINY_SCALE) - CENTER_OFFSET.idiv(TINY_SCALE) - 1
- m.y = args.mouse.y.idiv(TINY_SCALE)
- if args.mouse.click
- m.click = [
- args.mouse.click.point.x.idiv(TINY_SCALE) - CENTER_OFFSET.idiv(TINY_SCALE) - 1,
- args.mouse.click.point.y.idiv(TINY_SCALE)
- ]
- m.down = m.click
- else
- m.click = nil
- m.down = nil
- end
-
- if args.mouse.up
- m.up = [
- args.mouse.up.point.x.idiv(TINY_SCALE) - CENTER_OFFSET.idiv(TINY_SCALE) - 1,
- args.mouse.up.point.y.idiv(TINY_SCALE)
- ]
- else
- m.up = nil
- end
- end
- end
-
- def render_mouse_crosshairs args, mouse
- return unless args.state.show_gridlines
- args.labels << [10, 25, "mouse: #{mouse.x} #{mouse.y}", 255, 255, 255]
- end
-
- def emulate_lowrez_scene args, sprites, labels, borders, solids, mouse
- args.render_target(:lowrez).solids << [0, 0, 1280, 720]
- args.render_target(:lowrez).sprites << sprites
- args.render_target(:lowrez).borders << borders
- args.render_target(:lowrez).solids << solids
- args.outputs.primitives << labels.map do |l|
- as_label = l.label
- l.text.each_char.each_with_index.map do |char, i|
- [CENTER_OFFSET + EMULATED_FONT_X_ZERO + (as_label.x * TINY_SCALE) + i * 5 * TINY_SCALE,
- EMULATED_FONT_Y_ZERO + (as_label.y * TINY_SCALE), char,
- EMULATED_FONT_SIZE, 0, as_label.r, as_label.g, as_label.b, as_label.a, 'fonts/dragonruby-gtk-4x4.ttf'].label
- end
- end
-
- args.sprites << [CENTER_OFFSET, 0, 1280 * TINY_SCALE, 720 * TINY_SCALE, :lowrez]
- end
-
- def render_gridlines_if_needed args
- if args.state.show_gridlines && args.static_lines.length == 0
- args.static_lines << 65.times.map do |i|
- [
- [CENTER_OFFSET + i * TINY_SCALE + 1, 0,
- CENTER_OFFSET + i * TINY_SCALE + 1, 720, 128, 128, 128],
- [CENTER_OFFSET + i * TINY_SCALE, 0,
- CENTER_OFFSET + i * TINY_SCALE, 720, 128, 128, 128],
- [CENTER_OFFSET, 0 + i * TINY_SCALE,
- CENTER_OFFSET + 720, 0 + i * TINY_SCALE, 128, 128, 128],
- [CENTER_OFFSET, 1 + i * TINY_SCALE,
- CENTER_OFFSET + 720, 1 + i * TINY_SCALE, 128, 128, 128]
- ]
- end
- elsif !args.state.show_gridlines
- args.static_lines.clear
- end
- end
-
-#+end_src
-
-* 99_genre_narrative_rpg/return_of_serenity/app/main.rb
-#+begin_src ruby
- require 'app/require.rb'
-
- def defaults args
- args.outputs.background_color = [0, 0, 0]
- args.state.last_story_line_text ||= ""
- args.state.scene_history ||= []
- args.state.storyline_history ||= []
- args.state.word_delay ||= 8
- if args.state.tick_count == 0
- args.gtk.stop_music
- args.outputs.sounds << 'sounds/static-loop.ogg'
- end
-
- if args.state.storyline_history[-1] && args.state.storyline_queue_empty_at
- lines = args.state
- .storyline_history[-1]
- .gsub("-", "")
- .gsub("~", "")
- .wrapped_lines(55)
-
- args.outputs.labels << multiple_lines(args, 690, 10 + lines.length * 25, lines, 0, 0)
- elsif !args.state.is_storyline_dialog_active
- args.outputs.labels << multiple_lines(args, 690, 55, "Use the arrow keys on your keyboard to move around. The GREEN boxes are important.".wrapped_lines(50))
- end
-
- return if args.state.current_scene
- set_scene(args, day_one_beginning(args))
- end
-
- def inputs_move_player args
- if args.state.scene_changed_at.elapsed_time > 5
- if args.keyboard.down || args.keyboard.s || args.keyboard.j
- args.state.player.y -= 0.25
- elsif args.keyboard.up || args.keyboard.w || args.keyboard.k
- args.state.player.y += 0.25
- end
-
- if args.keyboard.left || args.keyboard.a || args.keyboard.h
- args.state.player.x -= 0.25
- elsif args.keyboard.right || args.keyboard.d || args.keyboard.l
- args.state.player.x += 0.25
- end
-
- args.state.player.y = 60 if args.state.player.y > 63
- args.state.player.y = 0 if args.state.player.y < -3
- args.state.player.x = 60 if args.state.player.x > 63
- args.state.player.x = 0 if args.state.player.x < -3
- end
- end
-
- def null_or_empty? ary
- return true unless ary
- return true if ary.length == 0
- return false
- end
-
- def calc_storyline_hotspot args
- hotspots = args.state.storylines.find_all do |hs|
- args.state.player.inside_rect?(hs.shift_rect(-2, 0))
- end
-
- if !null_or_empty?(hotspots) && !args.state.inside_storyline_hotspot
- _, _, _, _, storyline = hotspots.first
- queue_storyline_text(args, storyline)
- args.state.inside_storyline_hotspot = true
- elsif null_or_empty?(hotspots)
- args.state.inside_storyline_hotspot = false
- end
- end
-
- def calc_scenes args
- hotspots = args.state.scenes.find_all do |hs|
- args.state.player.inside_rect?(hs.shift_rect(-2, 0))
- end
-
- if !null_or_empty?(hotspots) && !args.state.inside_scene_hotspot
- _, _, _, _, scene_method_or_hash = hotspots.first
- if scene_method_or_hash.is_a? Symbol
- set_scene(args, send(scene_method_or_hash, args))
- args.state.last_hotspot_scene = scene_method_or_hash
- args.state.scene_history << scene_method_or_hash
- else
- set_scene(args, scene_method_or_hash)
- end
- args.state.inside_scene_hotspot = true
- elsif null_or_empty?(hotspots)
- args.state.inside_scene_hotspot = false
- end
- end
-
- def null_or_whitespace? word
- return true if !word
- return true if word.strip.length == 0
- return false
- end
-
- def calc_storyline_presentation args
- return unless args.state.tick_count > args.state.next_storyline
- return unless args.state.scene_storyline_queue
- next_storyline = args.state.scene_storyline_queue.shift
- if null_or_whitespace? next_storyline
- args.state.storyline_queue_empty_at ||= args.state.tick_count
- args.state.is_storyline_dialog_active = false
- return
- end
- args.state.storyline_to_show = next_storyline
- args.state.is_storyline_dialog_active = true
- args.state.storyline_queue_empty_at = nil
- if next_storyline.end_with?(".") || next_storyline.end_with?("!") || next_storyline.end_with?("?") || next_storyline.end_with?("\"")
- args.state.next_storyline += 60
- elsif next_storyline.end_with?(",")
- args.state.next_storyline += 50
- elsif next_storyline.end_with?(":")
- args.state.next_storyline += 60
- else
- default_word_delay = 13 + args.state.word_delay - 8
- if next_storyline.gsub("-", "").gsub("~", "").length <= 4
- default_word_delay = 11 + args.state.word_delay - 8
- end
- number_of_syllabals = next_storyline.length - next_storyline.gsub("-", "").length
- args.state.next_storyline += default_word_delay + number_of_syllabals * (args.state.word_delay + 1)
- end
- end
-
- def inputs_reload_current_scene args
- return
- if args.inputs.keyboard.key_down.r!
- reload_current_scene
- end
- end
-
- def inputs_dismiss_current_storyline args
- if args.inputs.keyboard.key_down.x!
- args.state.scene_storyline_queue.clear
- end
- end
-
- def inputs_restart_game args
- if args.inputs.keyboard.exclamation_point
- args.gtk.reset_state
- end
- end
-
- def inputs_change_word_delay args
- if args.inputs.keyboard.key_down.plus || args.inputs.keyboard.key_down.equal_sign
- args.state.word_delay -= 2
- if args.state.word_delay < 0
- args.state.word_delay = 0
- # queue_storyline_text args, "Text speed at MAXIMUM. Geez, how fast do you read?"
- else
- # queue_storyline_text args, "Text speed INCREASED."
- end
- end
-
- if args.inputs.keyboard.key_down.hyphen || args.inputs.keyboard.key_down.underscore
- args.state.word_delay += 2
- # queue_storyline_text args, "Text speed DECREASED."
- end
- end
-
- def multiple_lines args, x, y, texts, size = 0, minimum_alpha = nil
- texts.each_with_index.map do |t, i|
- [x, y - i * (25 + size * 2), t, size, 0, 255, 255, 255, adornments_alpha(args, 255, minimum_alpha)]
- end
- end
-
- def lowrez_tick args, lowrez_sprites, lowrez_labels, lowrez_borders, lowrez_solids, lowrez_mouse
- # args.state.show_gridlines = true
- defaults args
- render_current_scene args, lowrez_sprites, lowrez_labels, lowrez_solids
- lowrez_solids << [0, 0, 64, 64, 0, 0, 0]
- calc_storyline_presentation args
- calc_scenes args
- calc_storyline_hotspot args
- inputs_move_player args
- inputs_print_mouse_rect args, lowrez_mouse
- inputs_reload_current_scene args
- inputs_dismiss_current_storyline args
- inputs_change_word_delay args
- inputs_restart_game args
- if !args.state.storyline_queue_empty_at
- args.outputs.labels << multiple_lines(args, 690, 80,
- ["Press \"X\" on the keyboard to dismiss dialog.",
- "Press \"+\" on the keyboard to INCREASE text speed.",
- "Press \"-\" on the keyboard to DECREASE text speed."], 0, 255)
- end
- end
-
- def inputs_print_mouse_rect args, lowrez_mouse
- if lowrez_mouse.click
- if args.state.previous_mouse_click
- dx = lowrez_mouse.click.x - args.state.previous_mouse_click.x
- dy = lowrez_mouse.click.y - args.state.previous_mouse_click.y
- x, y, w, h = args.state.previous_mouse_click.x, args.state.previous_mouse_click.y, dx, dy
-
- if dx < 0 && dx < 0
- x = x + w
- w = w.abs
- y = y + h
- h = h.abs
- end
-
- w += 1
- h += 1
-
- puts [x, y, w, h]
- args.state.previous_mouse_click = nil
- else
- args.state.previous_mouse_click = lowrez_mouse.click
- square_x, square_y = lowrez_mouse.click
- puts [square_x, square_y]
- 8.map_with_index do |i|
- puts [square_x - i + 1, square_y - i + 1, i + 1, i + 1]
- end
- end
-
- end
- end
-
- def try_centering! word
- word ||= ""
- just_word = word.gsub("-", "").gsub(",", "").gsub(".", "").gsub("'", "").gsub('""', "\"-\"")
- return word if just_word.strip.length == 0
- return word if just_word.include? "~"
- return "~#{word}" if just_word.length <= 2
- if just_word.length.mod_zero? 2
- center_index = just_word.length.idiv(2) - 1
- else
- center_index = (just_word.length - 1).idiv(2)
- end
- return "#{word[0..center_index - 1]}~#{word[center_index]}#{word[center_index + 1..-1]}"
- end
-
- def queue_storyline args, scene
- queue_storyline_text args, scene[:storyline]
- end
-
- def queue_storyline_text args, text
- args.state.last_story_line_text = text
- args.state.storyline_history << text if text
- words = (text || "").split(" ")
- words = words.map { |w| try_centering! w }
- args.state.scene_storyline_queue = words
- if args.state.scene_storyline_queue.length != 0
- args.state.scene_storyline_queue.unshift "~$--"
- args.state.storyline_to_show = "~."
- else
- args.state.storyline_to_show = ""
- end
- args.state.scene_storyline_queue << ""
- args.state.next_storyline = args.state.tick_count
- end
-
- def set_scene args, scene
- args.state.current_scene = scene
- args.state.background = scene[:background] || 'sprites/todo.png'
- args.state.scene_fade = scene[:fade] || 0
- args.state.scenes = (scene[:scenes] || []).reject { |s| !s }
- args.state.scene_render_override = scene[:render_override]
- args.state.storylines = (scene[:storylines] || []).reject { |s| !s }
- args.state.scene_changed_at = args.state.tick_count
- if scene[:player]
- args.state.player = scene[:player]
- end
- args.state.inside_scene_hotspot = false
- args.state.inside_storyline_hotspot = false
- queue_storyline args, scene
- end
-
- def replay_storyline_rect
- [26, -1, 7, 4]
- end
-
- def labels_for_word word
- left_side_of_word = ""
- center_letter = ""
- right_side_of_word = ""
-
- if word[0] == "~"
- left_side_of_word = ""
- center_letter = word[1]
- right_side_of_word = word[2..-1]
- elsif word.length > 0
- left_side_of_word, right_side_of_word = word.split("~")
- center_letter = right_side_of_word[0]
- right_side_of_word = right_side_of_word[1..-1]
- end
-
- right_side_of_word = right_side_of_word.gsub("-", "")
-
- {
- left: [29 - left_side_of_word.length * 4 - 1 * left_side_of_word.length, 2, left_side_of_word],
- center: [29, 2, center_letter, 255, 0, 0],
- right: [34, 2, right_side_of_word]
- }
- end
-
- def render_scenes args, lowrez_sprites
- lowrez_sprites << args.state.scenes.flat_map do |hs|
- hotspot_square args, hs.x, hs.y, hs.w, hs.h
- end
- end
-
- def render_storylines args, lowrez_sprites
- lowrez_sprites << args.state.storylines.flat_map do |hs|
- hotspot_square args, hs.x, hs.y, hs.w, hs.h
- end
- end
-
- def adornments_alpha args, target_alpha = nil, minimum_alpha = nil
- return (minimum_alpha || 80) unless args.state.storyline_queue_empty_at
- target_alpha ||= 255
- target_alpha * args.state.storyline_queue_empty_at.ease(60)
- end
-
- def hotspot_square args, x, y, w, h
- if w >= 3 && h >= 3
- [
- [x + w.idiv(2) + 1, y, w.idiv(2), h, 'sprites/label-background.png', 0, adornments_alpha(args, 50), 23, 23, 23],
- [x, y, w.idiv(2), h, 'sprites/label-background.png', 0, adornments_alpha(args, 100), 223, 223, 223],
- [x + 1, y + 1, w - 2, h - 2, 'sprites/label-background.png', 0, adornments_alpha(args, 200), 40, 140, 40],
- ]
- else
- [
- [x, y, w, h, 'sprites/label-background.png', 0, adornments_alpha(args, 200), 0, 140, 0],
- ]
- end
- end
-
- def render_storyline_dialog args, lowrez_labels, lowrez_sprites
- return unless args.state.is_storyline_dialog_active
- return unless args.state.storyline_to_show
- labels = labels_for_word args.state.storyline_to_show
- if true # high rez version
- scale = 8.88
- offset = 45
- size = 25
- args.outputs.labels << [offset + labels[:left].x.-(1) * scale,
- labels[:left].y * TINY_SCALE + 55,
- labels[:left].text, size, 0, 0, 0, 0, 255,
- 'fonts/manaspc.ttf']
- center_text = labels[:center].text
- center_text = "|" if center_text == "$"
- args.outputs.labels << [offset + labels[:center].x * scale,
- labels[:center].y * TINY_SCALE + 55,
- center_text, size, 0, 255, 0, 0, 255,
- 'fonts/manaspc.ttf']
- args.outputs.labels << [offset + labels[:right].x * scale,
- labels[:right].y * TINY_SCALE + 55,
- labels[:right].text, size, 0, 0, 0, 0, 255,
- 'fonts/manaspc.ttf']
- else
- lowrez_labels << labels[:left]
- lowrez_labels << labels[:center]
- lowrez_labels << labels[:right]
- end
- args.state.is_storyline_dialog_active = true
- render_player args, lowrez_sprites
- lowrez_sprites << [0, 0, 64, 8, 'sprites/label-background.png']
- end
-
- def render_player args, lowrez_sprites
- lowrez_sprites << player_md_down(args, *args.state.player)
- end
-
- def render_adornments args, lowrez_sprites
- render_scenes args, lowrez_sprites
- render_storylines args, lowrez_sprites
- return if args.state.is_storyline_dialog_active
- lowrez_sprites << player_md_down(args, *args.state.player)
- end
-
- def global_alpha_percentage args, max_alpha = 255
- return 255 unless args.state.scene_changed_at
- return 255 unless args.state.scene_fade
- return 255 unless args.state.scene_fade > 0
- return max_alpha * args.state.scene_changed_at.ease(args.state.scene_fade)
- end
-
- def render_current_scene args, lowrez_sprites, lowrez_labels, lowrez_solids
- lowrez_sprites << [0, 0, 64, 64, args.state.background, 0, (global_alpha_percentage args)]
- if args.state.scene_render_override
- send args.state.scene_render_override, args, lowrez_sprites, lowrez_labels, lowrez_solids
- end
- storyline_to_show = args.state.storyline_to_show || ""
- render_adornments args, lowrez_sprites
- render_storyline_dialog args, lowrez_labels, lowrez_sprites
-
- if args.state.background == 'sprites/tribute-game-over.png'
- lowrez_sprites << [0, 0, 64, 11, 'sprites/label-background.png', 0, adornments_alpha(args, 200), 0, 0, 0]
- lowrez_labels << [9, 6, 'Return of', 255, 255, 255]
- lowrez_labels << [9, 1, ' Serenity', 255, 255, 255]
- if !args.state.ended
- args.gtk.stop_music
- args.outputs.sounds << 'sounds/music-loop.ogg'
- args.state.ended = true
- end
- end
- end
-
- def player_md_right args, x, y
- [x, y, 4, 11, 'sprites/player-right.png', 0, (global_alpha_percentage args)]
- end
-
- def player_md_left args, x, y
- [x, y, 4, 11, 'sprites/player-left.png', 0, (global_alpha_percentage args)]
- end
-
- def player_md_up args, x, y
- [x, y, 4, 11, 'sprites/player-up.png', 0, (global_alpha_percentage args)]
- end
-
- def player_md_down args, x, y
- [x, y, 4, 11, 'sprites/player-down.png', 0, (global_alpha_percentage args)]
- end
-
- def player_sm args, x, y
- [x, y, 3, 7, 'sprites/player-zoomed-out.png', 0, (global_alpha_percentage args)]
- end
-
- def player_xs args, x, y
- [x, y, 1, 4, 'sprites/player-zoomed-out.png', 0, (global_alpha_percentage args)]
- end
-
-#+end_src
-
-* 99_genre_narrative_rpg/return_of_serenity/app/repl.rb
-#+begin_src ruby
- puts $gtk.args.state.current_scene
-
-#+end_src
-
-* 99_genre_narrative_rpg/return_of_serenity/app/require.rb
-#+begin_src ruby
- require 'app/lowrez_simulator.rb'
- require 'app/storyline_day_one.rb'
- require 'app/storyline_blinking_light.rb'
- require 'app/storyline_serenity_introduction.rb'
- require 'app/storyline_speed_of_light.rb'
- require 'app/storyline_serenity_alive.rb'
- require 'app/storyline_serenity_bio.rb'
- require 'app/storyline_anka.rb'
- require 'app/storyline_final_message.rb'
- require 'app/storyline_final_decision.rb'
- require 'app/storyline.rb'
-
-#+end_src
-
-* 99_genre_narrative_rpg/return_of_serenity/app/storyline.rb
-#+begin_src ruby
- def hotspot_top
- [4, 61, 56, 3]
- end
-
- def hotspot_bottom
- [4, 0, 56, 3]
- end
-
- def hotspot_top_right
- [62, 35, 3, 25]
- end
-
- def hotspot_bottom_right
- [62, 0, 3, 25]
- end
-
- def storyline_history_include? args, text
- args.state.storyline_history.any? { |s| s.gsub("-", "").gsub(" ", "").include? text.gsub("-", "").gsub(" ", "") }
- end
-
- def blinking_light_side_of_home_render args, lowrez_sprites, lowrez_labels, lowrez_solids
- lowrez_sprites << [48, 44, 5, 5, 'sprites/square.png', 0, 50 * (args.state.tick_count % 50).fdiv(50), 0, 255, 0]
- lowrez_sprites << [49, 45, 3, 3, 'sprites/square.png', 0, 100 * (args.state.tick_count % 50).fdiv(50), 0, 255, 0]
- lowrez_sprites << [50, 46, 1, 1, 'sprites/square.png', 0, 255 * (args.state.tick_count % 50).fdiv(50), 0, 255, 0]
- end
-
- def blinking_light_mountain_pass_render args, lowrez_sprites, lowrez_labels, lowrez_solids
- lowrez_sprites << [18, 47, 5, 5, 'sprites/square.png', 0, 50 * (args.state.tick_count % 50).fdiv(50), 0, 255, 0]
- lowrez_sprites << [19, 48, 3, 3, 'sprites/square.png', 0, 100 * (args.state.tick_count % 50).fdiv(50), 0, 255, 0]
- lowrez_sprites << [20, 49, 1, 1, 'sprites/square.png', 0, 255 * (args.state.tick_count % 50).fdiv(50), 0, 255, 0]
- end
-
- def blinking_light_path_to_observatory_render args, lowrez_sprites, lowrez_labels, lowrez_solids
- lowrez_sprites << [0, 26, 5, 5, 'sprites/square.png', 0, 50 * (args.state.tick_count % 50).fdiv(50), 0, 255, 0]
- lowrez_sprites << [1, 27, 3, 3, 'sprites/square.png', 0, 100 * (args.state.tick_count % 50).fdiv(50), 0, 255, 0]
- lowrez_sprites << [2, 28, 1, 1, 'sprites/square.png', 0, 255 * (args.state.tick_count % 50).fdiv(50), 0, 255, 0]
- end
-
- def blinking_light_observatory_render args, lowrez_sprites, lowrez_labels, lowrez_solids
- lowrez_sprites << [23, 59, 5, 5, 'sprites/square.png', 0, 50 * (args.state.tick_count % 50).fdiv(50), 0, 255, 0]
- lowrez_sprites << [24, 60, 3, 3, 'sprites/square.png', 0, 100 * (args.state.tick_count % 50).fdiv(50), 0, 255, 0]
- lowrez_sprites << [25, 61, 1, 1, 'sprites/square.png', 0, 255 * (args.state.tick_count % 50).fdiv(50), 0, 255, 0]
- end
-
- def blinking_light_inside_observatory_render args, lowrez_sprites, lowrez_labels, lowrez_solids
- lowrez_sprites << [30, 30, 5, 5, 'sprites/square.png', 0, 50 * (args.state.tick_count % 50).fdiv(50), 0, 255, 0]
- lowrez_sprites << [31, 31, 3, 3, 'sprites/square.png', 0, 100 * (args.state.tick_count % 50).fdiv(50), 0, 255, 0]
- lowrez_sprites << [32, 32, 1, 1, 'sprites/square.png', 0, 255 * (args.state.tick_count % 50).fdiv(50), 0, 255, 0]
- end
-
- def decision_graph context_message, context_action, context_result_one, context_result_two, context_result_three = [], context_result_four = []
- result_one_scene, result_one_label, result_one_text = context_result_one
- result_two_scene, result_two_label, result_two_text = context_result_two
- result_three_scene, result_three_label, result_three_text = context_result_three
- result_four_scene, result_four_label, result_four_text = context_result_four
-
- top_level_hash = {
- background: 'sprites/decision.png',
- fade: 60,
- player: [20, 36],
- storylines: [ ],
- scenes: [ ]
- }
-
- confirmation_result_one_hash = {
- background: 'sprites/decision.png',
- scenes: [ ],
- storylines: [ ]
- }
-
- confirmation_result_two_hash = {
- background: 'sprites/decision.png',
- scenes: [ ],
- storylines: [ ]
- }
-
- confirmation_result_three_hash = {
- background: 'sprites/decision.png',
- scenes: [ ],
- storylines: [ ]
- }
-
- confirmation_result_four_hash = {
- background: 'sprites/decision.png',
- scenes: [ ],
- storylines: [ ]
- }
-
- top_level_hash[:storylines] << [ 5, 35, 4, 4, context_message]
- top_level_hash[:storylines] << [20, 35, 4, 4, context_action]
-
- confirmation_result_one_hash[:scenes] << [20, 35, 4, 4, top_level_hash]
- confirmation_result_one_hash[:scenes] << [60, 50, 4, 4, result_one_scene]
- confirmation_result_one_hash[:storylines] << [40, 50, 4, 4, "#{result_one_label}: \"#{result_one_text}\""]
- confirmation_result_one_hash[:scenes] << [40, 40, 4, 4, confirmation_result_four_hash] if result_four_scene
- confirmation_result_one_hash[:scenes] << [40, 30, 4, 4, confirmation_result_three_hash] if result_three_scene
- confirmation_result_one_hash[:scenes] << [40, 20, 4, 4, confirmation_result_two_hash]
-
- confirmation_result_two_hash[:scenes] << [20, 35, 4, 4, top_level_hash]
- confirmation_result_two_hash[:scenes] << [40, 50, 4, 4, confirmation_result_one_hash]
- confirmation_result_two_hash[:scenes] << [40, 40, 4, 4, confirmation_result_four_hash] if result_four_scene
- confirmation_result_two_hash[:scenes] << [40, 30, 4, 4, confirmation_result_three_hash] if result_three_scene
- confirmation_result_two_hash[:scenes] << [60, 20, 4, 4, result_two_scene]
- confirmation_result_two_hash[:storylines] << [40, 20, 4, 4, "#{result_two_label}: \"#{result_two_text}\""]
-
- confirmation_result_three_hash[:scenes] << [20, 35, 4, 4, top_level_hash]
- confirmation_result_three_hash[:scenes] << [40, 50, 4, 4, confirmation_result_one_hash]
- confirmation_result_three_hash[:scenes] << [40, 40, 4, 4, confirmation_result_four_hash]
- confirmation_result_three_hash[:scenes] << [60, 30, 4, 4, result_three_scene]
- confirmation_result_three_hash[:storylines] << [40, 30, 4, 4, "#{result_three_label}: \"#{result_three_text}\""]
- confirmation_result_three_hash[:scenes] << [40, 20, 4, 4, confirmation_result_two_hash]
-
- confirmation_result_four_hash[:scenes] << [20, 35, 4, 4, top_level_hash]
- confirmation_result_four_hash[:scenes] << [40, 50, 4, 4, confirmation_result_one_hash]
- confirmation_result_four_hash[:scenes] << [60, 40, 4, 4, result_four_scene]
- confirmation_result_four_hash[:storylines] << [40, 40, 4, 4, "#{result_four_label}: \"#{result_four_text}\""]
- confirmation_result_four_hash[:scenes] << [40, 30, 4, 4, confirmation_result_three_hash]
- confirmation_result_four_hash[:scenes] << [40, 20, 4, 4, confirmation_result_two_hash]
-
- top_level_hash[:scenes] << [40, 50, 4, 4, confirmation_result_one_hash]
- top_level_hash[:scenes] << [40, 40, 4, 4, confirmation_result_four_hash] if result_four_scene
- top_level_hash[:scenes] << [40, 30, 4, 4, confirmation_result_three_hash] if result_three_scene
- top_level_hash[:scenes] << [40, 20, 4, 4, confirmation_result_two_hash]
-
- top_level_hash
- end
-
- def ship_control_hotspot offset_x, offset_y, a, b, c, d
- results = []
- results << [ 6 + offset_x, 0 + offset_y, 4, 4, a] if a
- results << [ 1 + offset_x, 5 + offset_y, 4, 4, b] if b
- results << [ 6 + offset_x, 5 + offset_y, 4, 4, c] if c
- results << [ 11 + offset_x, 5 + offset_y, 4, 4, d] if d
- results
- end
-
- def reload_current_scene
- if $gtk.args.state.last_hotspot_scene
- set_scene $gtk.args, send($gtk.args.state.last_hotspot_scene, $gtk.args)
- tick $gtk.args
- elsif respond_to? :set_scene
- set_scene $gtk.args, (replied_to_serenity_alive_firmly $gtk.args)
- tick $gtk.args
- end
- $gtk.console.close
- end
-
-#+end_src
-
-* 99_genre_narrative_rpg/return_of_serenity/app/storyline_anka.rb
-#+begin_src ruby
- def anka_inside_room args
- {
- background: 'sprites/inside-home.png',
- player: [34, 35],
- storylines: [
- [34, 34, 4, 4, "Ahhhh!!! Oh god, it was just- a nightmare."],
- ],
- scenes: [
- [32, -1, 8, 3, :anka_observatory]
- ]
- }
- end
-
- def anka_observatory args
- {
- background: 'sprites/inside-observatory.png',
- fade: 60,
- player: [51, 12],
- storylines: [
- [50, 10, 4, 4, "Breathe, Hiro. Just see what's there... everything--- will- be okay."]
- ],
- scenes: [
- [30, 18, 5, 12, :anka_inside_mainframe]
- ],
- render_override: :blinking_light_inside_observatory_render
- }
- end
-
- def anka_inside_mainframe args
- {
- player: [32, 4],
- background: 'sprites/mainframe.png',
- fade: 60,
- storylines: [
- [22, 45, 17, 4, (anka_last_reply args)],
- [45, 45, 4, 4, (anka_current_reply args)],
- ],
- scenes: [
- [*hotspot_top_right, :reply_to_anka]
- ]
- }
- end
-
- def reply_to_anka args
- decision_graph anka_current_reply(args),
- "Matthew's-- wife is doing-- well. What's-- even-- better-- is that he's-- a dad, and he didn't-- even-- know it. Should- I- leave- out the part about-- the crew- being-- in hibernation-- for 20-- years? They- should- enter-- statis-- on a high- note... Right?",
- [:replied_with_whole_truth, "Whole-- Truth--", anka_reply_whole_truth],
- [:replied_with_half_truth, "Half-- Truth--", anka_reply_half_truth]
- end
-
- def anka_last_reply args
- if args.state.scene_history.include? :replied_to_serenity_alive_firmly
- return "Buffer--: #{serenity_alive_firm_reply.quote}"
- else
- return "Buffer--: #{serenity_alive_sugarcoated_reply.quote}"
- end
- end
-
- def anka_reply_whole_truth
- "Matthew's wife is doing-- very-- well. In fact, she was pregnant. Matthew-- is a dad. He has a son. But, I need- all-- of-- you-- to brace-- yourselves. You've-- been in statis-- for 20 years. A lot has changed. Most of Earth's-- population--- didn't-- survive. Tell- Matthew-- that I'm-- sorry he didn't-- get to see- his- son grow- up."
- end
-
- def anka_reply_half_truth
- "Matthew's--- wife- is doing-- very-- well. In fact, she was pregnant. Matthew is a dad! It's a boy! Tell- Matthew-- congrats-- for me. Hope-- to see- all of you- soon."
- end
-
- def replied_with_whole_truth args
- {
- background: 'sprites/inside-observatory.png',
- fade: 60,
- player: [32, 21],
- scenes: [[60, 0, 4, 32, :replied_to_anka_back_home]],
- storylines: [
- [30, 18, 5, 12, "Buffer-- has been set to: #{anka_reply_whole_truth.quote}"],
- [30, 10, 5, 4, "I- hope- I- did the right- thing- by laying-- it all- out- there."],
- ]
- }
- end
-
- def replied_with_half_truth args
- {
- background: 'sprites/inside-observatory.png',
- fade: 60,
- player: [32, 21],
- scenes: [[60, 0, 4, 32, :replied_to_anka_back_home]],
- storylines: [
- [30, 18, 5, 12, "Buffer-- has been set to: #{anka_reply_half_truth.quote}"],
- [30, 10, 5, 4, "I- hope- I- did the right- thing- by not giving-- them- the whole- truth."],
- ]
- }
- end
-
- def anka_current_reply args
- if args.state.scene_history.include? :replied_to_serenity_alive_firmly
- return "Hello. This is, Aanka. Sasha-- is still- trying-- to gather-- her wits about-- her, given- the gravity--- of your- last- reply. Thank- you- for being-- honest, and thank- you- for the help- with the ship- diagnostics. I was able-- to retrieve-- all of the navigation--- information---- after-- the battery--- swap. We- are ready-- to head back to Earth. Before-- we go- back- into-- statis, Matthew--- wanted-- to know- how his- wife- is doing. Please- reply-- as soon- as you can. He's-- not going-- to get- into-- the statis-- chamber-- until-- he knows- his wife is okay."
- else
- return "Hello. This is, Aanka. Thank- you for the help- with the ship's-- diagnostics. I was able-- to retrieve-- all of the navigation--- information--- after-- the battery-- swap. I- know-- that- you didn't-- tell- the whole truth- about-- how far we are from- Earth. Don't-- worry. I understand-- why you did it. We- are ready-- to head back to Earth. Before-- we go- back- into-- statis, Matthew--- wanted-- to know- how his- wife- is doing. Please- reply-- as soon- as you can. He's-- not going-- to get- into-- the statis-- chamber-- until-- he knows- his wife is okay."
- end
- end
-
- def replied_to_anka_back_home args
- if args.state.scene_history.include? :replied_with_whole_truth
- return {
- fade: 60,
- background: 'sprites/inside-home.png',
- player: [34, 4],
- storylines: [
- [34, 4, 4, 4, "I- hope-- this pit in my stomach-- is gone-- by tomorrow---."],
- ],
- scenes: [
- [30, 38, 12, 13, :final_message_sad],
- ]
- }
- else
- return {
- fade: 60,
- background: 'sprites/inside-home.png',
- player: [34, 4],
- storylines: [
- [34, 4, 4, 4, "I- get the feeling-- I'm going-- to sleep real well tonight--."],
- ],
- scenes: [
- [30, 38, 12, 13, :final_message_happy],
- ]
- }
- end
- end
-
-#+end_src
-
-* 99_genre_narrative_rpg/return_of_serenity/app/storyline_blinking_light.rb
-#+begin_src ruby
- def the_blinking_light args
- {
- fade: 60,
- background: 'sprites/side-of-home.png',
- player: [16, 13],
- scenes: [
- [52, 24, 11, 5, :blinking_light_mountain_pass],
- ],
- render_override: :blinking_light_side_of_home_render
- }
- end
-
- def blinking_light_mountain_pass args
- {
- background: 'sprites/mountain-pass-zoomed-out.png',
- player: [4, 4],
- scenes: [
- [18, 47, 5, 5, :blinking_light_path_to_observatory]
- ],
- render_override: :blinking_light_mountain_pass_render
- }
- end
-
- def blinking_light_path_to_observatory args
- {
- background: 'sprites/path-to-observatory.png',
- player: [60, 4],
- scenes: [
- [0, 26, 5, 5, :blinking_light_observatory]
- ],
- render_override: :blinking_light_path_to_observatory_render
- }
- end
-
- def blinking_light_observatory args
- {
- background: 'sprites/observatory.png',
- player: [60, 2],
- scenes: [
- [28, 39, 4, 10, :blinking_light_inside_observatory]
- ],
- render_override: :blinking_light_observatory_render
- }
- end
-
- def blinking_light_inside_observatory args
- {
- background: 'sprites/inside-observatory.png',
- player: [60, 2],
- storylines: [
- [50, 2, 4, 8, "That's weird. I thought- this- mainframe-- was broken--."]
- ],
- scenes: [
- [30, 18, 5, 12, :blinking_light_inside_mainframe]
- ],
- render_override: :blinking_light_inside_observatory_render
- }
- end
-
- def blinking_light_inside_mainframe args
- {
- background: 'sprites/mainframe.png',
- fade: 60,
- player: [30, 4],
- scenes: [
- [62, 32, 4, 32, :reply_to_introduction]
- ],
- storylines: [
- [43, 43, 8, 8, "\"Mission-- control--, your- main- comm-- channels-- seem-- to be down. My apologies-- for- using-- this low- level-- exploit--. What's-- going-- on down there? We are ready-- for reentry--.\" Message--- Timestamp---: 4- hours-- 23--- minutes-- ago--."],
- [30, 30, 4, 4, "There's-- a low- level-- message-- here... NANI.T.F?"],
- [14, 10, 24, 4, "Oh interesting---. This transistor--- needed-- to be activated--- for the- mainframe-- to work."],
- [14, 20, 24, 4, "What the heck activated--- this thing- though?"]
- ]
- }
- end
-
-#+end_src
-
-* 99_genre_narrative_rpg/return_of_serenity/app/storyline_day_one.rb
-#+begin_src ruby
- def day_one_beginning args
- {
- background: 'sprites/side-of-home.png',
- player: [16, 13],
- scenes: [
- [0, 0, 64, 2, :day_one_infront_of_home],
- ],
- storylines: [
- [35, 10, 6, 6, "Man. Hard to believe- that today- is the 20th--- anniversary-- of The Impact."]
- ]
- }
- end
-
- def day_one_infront_of_home args
- {
- background: 'sprites/front-of-home.png',
- player: [56, 23],
- scenes: [
- [43, 34, 10, 16, :day_one_home],
- [62, 0, 3, 40, :day_one_beginning],
- [0, 4, 3, 20, :day_one_ceremony]
- ],
- storylines: [
- [40, 20, 4, 4, "It looks like everyone- is already- at the rememberance-- ceremony."],
- ]
- }
- end
-
- def day_one_home args
- {
- background: 'sprites/inside-home.png',
- player: [34, 3],
- scenes: [
- [28, 0, 12, 2, :day_one_infront_of_home]
- ],
- storylines: [
- [
- 38, 4, 4, 4, "My mansion- in all its glory! Okay yea, it's just a shipping- container-. Apparently-, it's nothing- like the luxuries- of the 2040's. But it's- all we have- in- this day and age. And it'll suffice."
- ],
- [
- 28, 7, 4, 7,
- "Ahhh. My reading- couch. It's so comfortable--."
- ],
- [
- 38, 21, 4, 4,
- "I'm- lucky- to have a computer--. I'm- one of the few people- with- the skills to put this- thing to good use."
- ],
- [
- 45, 37, 4, 8,
- "This corner- of my home- is always- warmer-. It's cause of the ref~lected-- light- from the solar-- panels--, just on the other- side- of this wall. It's hard- to believe- there was o~nce-- an unlimited- amount- of electricity--."
- ],
- [
- 32, 40, 8, 10,
- "This isn't- a good time- to sleep. I- should probably- head to the ceremony-."
- ],
- [
- 25, 21, 5, 12,
- "Fifteen-- years- of computer-- science-- notes, neatly-- organized. Compiler--- Theory--, Linear--- Algebra---, Game-- Development---... Every-- subject-- imaginable--."
- ]
- ]
- }
- end
-
- def day_one_ceremony args
- {
- background: 'sprites/tribute.png',
- player: [57, 21],
- scenes: [
- [62, 0, 2, 40, :day_one_infront_of_home],
- [0, 24, 2, 40, :day_one_infront_of_library]
- ],
- storylines: [
- [53, 12, 3, 8, "It's- been twenty- years since The Impact. Twenty- years, since Halley's-- Comet-- set Earth's- blue- sky on fire."],
- [45, 12, 3, 8, "The space mission- sent to prevent- Earth's- total- destruction--, was a success. Only- 99.9%------ of the world's- population-- died-- that day. Hey, it's- better-- than 100%---- of humanity-- dying."],
- [20, 12, 23, 4, "The monument--- reads:---- Here- stands- the tribute-- to Space- Mission-- Serenity--- and- its- crew. You- have- given-- humanity--- a second-- chance."],
- [15, 12, 3, 8, "Rest- in- peace--- Matthew----, Sasha----, Aanka----"],
- ]
- }
- end
-
- def day_one_infront_of_library args
- {
- background: 'sprites/outside-library.png',
- player: [57, 21],
- scenes: [
- [62, 0, 2, 40, :day_one_ceremony],
- [49, 39, 6, 9, :day_one_library]
- ],
- storylines: [
- [50, 20, 4, 8, "Shipping- containers-- as far- as the eye- can see. It's- rather- beautiful-- if you ask me. Even- though-- this- view- represents-- all- that's-- left- of humanity-."]
- ]
- }
- end
-
- def day_one_library args
- {
- background: 'sprites/library.png',
- player: [27, 4],
- scenes: [
- [0, 0, 64, 2, :end_day_one_infront_of_library]
- ],
- storylines: [
- [28, 22, 8, 4, "I grew- up- in this library. I've- read every- book- here. My favorites-- were- of course-- anything- computer-- related."],
- [6, 32, 10, 6, "My favorite-- area--- of the library. The Science-- Section."]
- ]
- }
- end
-
- def end_day_one_infront_of_library args
- {
- background: 'sprites/outside-library.png',
- player: [51, 33],
- scenes: [
- [49, 39, 6, 9, :day_one_library],
- [62, 0, 2, 40, :end_day_one_monument],
- ],
- storylines: [
- [50, 27, 4, 4, "It's getting late. Better get some sleep."]
- ]
- }
- end
-
- def end_day_one_monument args
- {
- background: 'sprites/tribute.png',
- player: [2, 36],
- scenes: [
- [62, 0, 2, 40, :end_day_one_infront_of_home],
- ],
- storylines: [
- [50, 27, 4, 4, "It's getting late. Better get some sleep."],
- ]
- }
- end
-
- def end_day_one_infront_of_home args
- {
- background: 'sprites/front-of-home.png',
- player: [1, 17],
- scenes: [
- [43, 34, 10, 16, :end_day_one_home],
- ],
- storylines: [
- [20, 10, 4, 4, "It's getting late. Better get some sleep."],
- ]
- }
- end
-
- def end_day_one_home args
- {
- background: 'sprites/inside-home.png',
- player: [34, 3],
- scenes: [
- [32, 40, 8, 10, :end_day_one_dream],
- ],
- storylines: [
- [38, 4, 4, 4, "It's getting late. Better get some sleep."],
- ]
- }
- end
-
- def end_day_one_dream args
- {
- background: 'sprites/dream.png',
- fade: 60,
- player: [4, 4],
- scenes: [
- [62, 0, 2, 64, :explaining_the_special_power]
- ],
- storylines: [
- [10, 10, 4, 4, "Why- does this- moment-- always- haunt- my dreams?"],
- [20, 10, 4, 4, "This kid- reads these computer--- science--- books- nonstop-. What's- wrong with him?"],
- [30, 10, 4, 4, "There- is nothing-- wrong- with him. This behavior-- should be encouraged---! In fact-, I think- he's- special---. Have- you seen- him use- a computer---? It's-- almost-- as if he can- speak-- to it."]
- ]
- }
- end
-
- def explaining_the_special_power args
- {
- fade: 60,
- background: 'sprites/inside-home.png',
- player: [32, 30],
- scenes: [
- [
- 38, 21, 4, 4, :explaining_the_special_power_inside_computer
- ],
- ]
- }
- end
-
- def explaining_the_special_power_inside_computer args
- {
- background: 'sprites/pc.png',
- fade: 60,
- player: [34, 4],
- scenes: [
- [0, 62, 64, 3, :the_blinking_light]
- ],
- storylines: [
- [14, 20, 24, 4, "So... I have a special-- power--. I don't-- need a mouse-, keyboard--, or even-- a monitor--- to control-- a computer--."],
- [14, 25, 24, 4, "I only-- pretend-- to use peripherals---, so as not- to freak- anyone--- out."],
- [14, 30, 24, 4, "Inside-- this silicon--- Universe---, is the only-- place I- feel- at peace."],
- [14, 35, 24, 4, "It's-- the only-- place where I don't-- feel alone."]
- ]
- }
- end
-
-#+end_src
-
-* 99_genre_narrative_rpg/return_of_serenity/app/storyline_final_decision.rb
-#+begin_src ruby
- def final_decision_side_of_home args
- {
- fade: 120,
- background: 'sprites/side-of-home.png',
- player: [16, 13],
- scenes: [
- [52, 24, 11, 5, :final_decision_mountain_pass],
- ],
- render_override: :blinking_light_side_of_home_render,
- storylines: [
- [28, 13, 8, 4, "Man. Hard to believe- that today- is the 21st--- anniversary-- of The Impact. Serenity--- will- be- home- soon."]
- ]
- }
- end
-
- def final_decision_mountain_pass args
- {
- background: 'sprites/mountain-pass-zoomed-out.png',
- player: [4, 4],
- scenes: [
- [18, 47, 5, 5, :final_decision_path_to_observatory]
- ],
- render_override: :blinking_light_mountain_pass_render
- }
- end
-
- def final_decision_path_to_observatory args
- {
- background: 'sprites/path-to-observatory.png',
- player: [60, 4],
- scenes: [
- [0, 26, 5, 5, :final_decision_observatory]
- ],
- render_override: :blinking_light_path_to_observatory_render
- }
- end
-
- def final_decision_observatory args
- {
- background: 'sprites/observatory.png',
- player: [60, 2],
- scenes: [
- [28, 39, 4, 10, :final_decision_inside_observatory]
- ],
- render_override: :blinking_light_observatory_render
- }
- end
-
- def final_decision_inside_observatory args
- {
- background: 'sprites/inside-observatory.png',
- player: [60, 2],
- storylines: [],
- scenes: [
- [30, 18, 5, 12, :final_decision_inside_mainframe]
- ],
- render_override: :blinking_light_inside_observatory_render
- }
- end
-
- def final_decision_inside_mainframe args
- {
- player: [32, 4],
- background: 'sprites/mainframe.png',
- storylines: [],
- scenes: [
- [*hotspot_top, :final_decision_ship_status],
- ]
- }
- end
-
- def final_decision_ship_status args
- {
- background: 'sprites/serenity.png',
- fade: 60,
- player: [30, 10],
- scenes: [
- [*hotspot_top_right, :final_decision]
- ],
- storylines: [
- [30, 8, 4, 4, "????"],
- *final_decision_ship_status_shared(args)
- ]
- }
- end
-
- def final_decision args
- decision_graph "Stasis-- Chambers--: UNDERPOWERED, Life- forms-- will be terminated---- unless-- equilibrium----- is reached.",
- "I CAN'T DO THIS... But... If-- I-- don't--- bring-- the- chambers--- to- equilibrium-----, they all die...",
- [:final_decision_game_over_noone, "Kill--- Everyone---", "DO--- NOTHING?"],
- [:final_decision_game_over_matthew, "Kill--- Sasha---", "KILL--- SASHA?"],
- [:final_decision_game_over_anka, "Kill--- Aanka---", "KILL--- AANKA?"],
- [:final_decision_game_over_sasha, "Kill--- Matthew---", "KILL--- MATTHEW?"]
- end
-
- def final_decision_game_over_noone args
- {
- background: 'sprites/tribute-game-over.png',
- player: [53, 14],
- fade: 600
- }
- end
-
- def final_decision_game_over_matthew args
- {
- background: 'sprites/tribute-game-over.png',
- player: [53, 14],
- fade: 600
- }
- end
-
- def final_decision_game_over_anka args
- {
- background: 'sprites/tribute-game-over.png',
- player: [53, 14],
- fade: 600
- }
- end
-
- def final_decision_game_over_sasha args
- {
- background: 'sprites/tribute-game-over.png',
- player: [53, 14],
- fade: 600
- }
- end
-
- def final_decision_ship_status_shared args
- [
- *ship_control_hotspot(24, 22,
- "Stasis-- Chambers--: UNDERPOWERED, Life- forms-- will be terminated---- unless-- equilibrium----- is reached. WHAT?! NO!",
- "Matthew's--- Chamber--: UNDER-- THREAT-- OF-- TERMINATION. WHAT?! NO!",
- "Aanka's--- Chamber--: UNDER-- THREAT-- OF-- TERMINATION. WHAT?! NO!",
- "Sasha's--- Chamber--: UNDER-- THREAT-- OF-- TERMINATION. WHAT?! NO!"),
- ]
- end
-
-#+end_src
-
-* 99_genre_narrative_rpg/return_of_serenity/app/storyline_final_message.rb
-#+begin_src ruby
- def final_message_sad args
- {
- fade: 60,
- background: 'sprites/inside-home.png',
- player: [34, 35],
- storylines: [
- [34, 34, 4, 4, "Another-- sleepless-- night..."],
- ],
- scenes: [
- [32, -1, 8, 3, :final_message_observatory]
- ]
- }
- end
-
- def final_message_happy args
- {
- fade: 60,
- background: 'sprites/inside-home.png',
- player: [34, 35],
- storylines: [
- [34, 34, 4, 4, "Oh man, I slept like rock!"],
- ],
- scenes: [
- [32, -1, 8, 3, :final_message_observatory]
- ]
- }
- end
-
- def final_message_side_of_home args
- {
- fade: 60,
- background: 'sprites/side-of-home.png',
- player: [16, 13],
- scenes: [
- [52, 24, 11, 5, :final_message_mountain_pass],
- ],
- render_override: :blinking_light_side_of_home_render
- }
- end
-
- def final_message_mountain_pass args
- {
- background: 'sprites/mountain-pass-zoomed-out.png',
- player: [4, 4],
- scenes: [
- [18, 47, 5, 5, :final_message_path_to_observatory],
- ],
- storylines: [
- [18, 13, 5, 5, "Hnnnnnnnggg. My legs-- are still sore- from yesterday."]
- ],
- render_override: :blinking_light_mountain_pass_render
- }
- end
-
- def final_message_path_to_observatory args
- {
- background: 'sprites/path-to-observatory.png',
- player: [60, 4],
- scenes: [
- [0, 26, 5, 5, :final_message_observatory]
- ],
- storylines: [
- [22, 20, 10, 10, "This spot--, on the mountain, right here, it's-- perfect. This- is where- I'll-- yeet-- the person-- who is playing-- this- prank- on me."]
- ],
- render_override: :blinking_light_path_to_observatory_render
- }
- end
-
- def final_message_observatory args
- if args.state.scene_history.include? :replied_with_whole_truth
- return {
- background: 'sprites/inside-observatory.png',
- fade: 60,
- player: [51, 12],
- storylines: [
- [50, 10, 4, 4, "Here-- we- go..."]
- ],
- scenes: [
- [30, 18, 5, 12, :final_message_inside_mainframe]
- ],
- render_override: :blinking_light_inside_observatory_render
- }
- else
- return {
- background: 'sprites/inside-observatory.png',
- fade: 60,
- player: [51, 12],
- storylines: [
- [50, 10, 4, 4, "I feel like I'm-- walking-- on sunshine!"]
- ],
- scenes: [
- [30, 18, 5, 12, :final_message_inside_mainframe]
- ],
- render_override: :blinking_light_inside_observatory_render
- }
- end
- end
-
- def final_message_inside_mainframe args
- {
- player: [32, 4],
- background: 'sprites/mainframe.png',
- fade: 60,
- scenes: [[45, 45, 4, 4, :final_message_check_ship_status]]
- }
- end
-
- def final_message_check_ship_status args
- {
- background: 'sprites/mainframe.png',
- storylines: [
- [45, 45, 4, 4, (final_message_current args)],
- ],
- scenes: [
- [*hotspot_top, :final_message_ship_status],
- ]
- }
- end
-
- def final_message_ship_status args
- {
- background: 'sprites/serenity.png',
- fade: 60,
- player: [30, 10],
- scenes: [
- [30, 50, 4, 4, :final_message_ship_status_reviewed]
- ],
- storylines: [
- [30, 8, 4, 4, "Let me make- sure- everything--- looks good. It'll-- give me peace- of mind."],
- *final_message_ship_status_shared(args)
- ]
- }
- end
-
- def final_message_ship_status_reviewed args
- {
- background: 'sprites/serenity.png',
- fade: 60,
- scenes: [
- [*hotspot_bottom, :final_message_summary]
- ],
- storylines: [
- [0, 62, 62, 3, "Whew. Everyone-- is in their- chambers. The engines-- are roaring-- and Serenity-- is coming-- home."],
- ]
- }
- end
-
- def final_message_ship_status_shared args
- [
- *ship_control_hotspot( 0, 50,
- "Stasis-- Chambers--: Online, All chambers-- are powered. Battery--- Allocation---: 3--- of-- 3--.",
- "Matthew's--- Chamber--: OCCUPIED----",
- "Aanka's--- Chamber--: OCCUPIED----",
- "Sasha's--- Chamber--: OCCUPIED----"),
- *ship_control_hotspot(12, 35,
- "Life- Support--: Not-- Needed---",
- "O2--- Production---: OFF---",
- "CO2--- Scrubbers---: OFF---",
- "H2O--- Production---: OFF---"),
- *ship_control_hotspot(24, 20,
- "Navigation: Offline---",
- "Sensor: OFF---",
- "Heads- Up- Display: DAMAGED---",
- "Arithmetic--- Unit: DAMAGED----"),
- *ship_control_hotspot(36, 35,
- "COMM: Underpowered----",
- "Text: ON---",
- "Audio: SEGFAULT---",
- "Video: DAMAGED---"),
- *ship_control_hotspot(48, 50,
- "Engine: Online, Coordinates--- Set- for Earth. Battery--- Allocation---: 3--- of-- 3---",
- "Engine I: ON---",
- "Engine II: ON---",
- "Engine III: ON---")
- ]
- end
-
- def final_message_last_reply args
- if args.state.scene_history.include? :replied_with_whole_truth
- return "Buffer--: #{anka_reply_whole_truth.quote}"
- else
- return "Buffer--: #{anka_reply_half_truth.quote}"
- end
- end
-
- def final_message_current args
- if args.state.scene_history.include? :replied_with_whole_truth
- return "Hey... It's-- me Sasha. Aanka-- is trying-- her best to comfort-- Matthew. This- is the first- time- I've-- ever-- seen-- Matthew-- cry. We'll-- probably-- be in stasis-- by the time you get this message--. Thank- you- again-- for all your help. I look forward-- to meeting-- you in person."
- else
- return "Hey! It's-- me Sasha! LOL! Aanka-- and Matthew-- are dancing-- around-- like- goofballs--! They- are both- so adorable! Only-- this- tiny-- little-- genius-- can make-- a battle-- hardened-- general--- put- on a tiara-- and dance- around-- like a fairy-- princess-- XD------ Anyways, we are heading-- back into-- the chambers--. I hope our welcome-- home- parade-- has fireworks!"
- end
- end
-
- def final_message_summary args
- if args.state.scene_history.include? :replied_with_whole_truth
- return {
- background: 'sprites/inside-observatory.png',
- fade: 60,
- player: [31, 11],
- scenes: [[60, 0, 4, 32, :final_decision_side_of_home]],
- storylines: [
- [30, 10, 5, 4, "I can't-- imagine-- what they are feeling-- right now. But at least- they- know everything---, and we can- concentrate-- on rebuilding--- this world-- right- off the bat. I can't-- wait to see the future-- they'll-- help- build."],
- ]
- }
- else
- return {
- background: 'sprites/inside-observatory.png',
- fade: 60,
- player: [31, 11],
- scenes: [[60, 0, 4, 32, :final_decision_side_of_home]],
- storylines: [
- [30, 10, 5, 4, "They all sounded-- so happy. I know- they'll-- be in for a tough- dose- of reality--- when they- arrive. But- at least- they'll-- be around-- all- of us. We'll-- help them- cope."],
- ]
- }
- end
- end
-
-#+end_src
-
-* 99_genre_narrative_rpg/return_of_serenity/app/storyline_serenity_alive.rb
-#+begin_src ruby
- def serenity_alive_side_of_home args
- {
- fade: 60,
- background: 'sprites/side-of-home.png',
- player: [16, 13],
- scenes: [
- [52, 24, 11, 5, :serenity_alive_mountain_pass],
- ],
- render_override: :blinking_light_side_of_home_render
- }
- end
-
- def serenity_alive_mountain_pass args
- {
- background: 'sprites/mountain-pass-zoomed-out.png',
- player: [4, 4],
- scenes: [
- [18, 47, 5, 5, :serenity_alive_path_to_observatory],
- ],
- storylines: [
- [18, 13, 5, 5, "Hnnnnnnnggg. My legs-- are still sore- from yesterday."]
- ],
- render_override: :blinking_light_mountain_pass_render
- }
- end
-
- def serenity_alive_path_to_observatory args
- {
- background: 'sprites/path-to-observatory.png',
- player: [60, 4],
- scenes: [
- [0, 26, 5, 5, :serenity_alive_observatory]
- ],
- storylines: [
- [22, 20, 10, 10, "This spot--, on the mountain, right here, it's-- perfect. This- is where- I'll-- yeet-- the person-- who is playing-- this- prank- on me."]
- ],
- render_override: :blinking_light_path_to_observatory_render
- }
- end
-
- def serenity_alive_observatory args
- {
- background: 'sprites/observatory.png',
- player: [60, 2],
- scenes: [
- [28, 39, 4, 10, :serenity_alive_inside_observatory]
- ],
- render_override: :blinking_light_observatory_render
- }
- end
-
- def serenity_alive_inside_observatory args
- {
- background: 'sprites/inside-observatory.png',
- player: [60, 2],
- storylines: [],
- scenes: [
- [30, 18, 5, 12, :serenity_alive_inside_mainframe]
- ],
- render_override: :blinking_light_inside_observatory_render
- }
- end
-
- def serenity_alive_inside_mainframe args
- {
- background: 'sprites/mainframe.png',
- fade: 60,
- player: [30, 4],
- scenes: [
- [*hotspot_top, :serenity_alive_ship_status],
- ],
- storylines: [
- [22, 45, 17, 4, (serenity_alive_last_reply args)],
- [45, 45, 4, 4, (serenity_alive_current_message args)],
- ]
- }
- end
-
- def serenity_alive_ship_status args
- {
- background: 'sprites/serenity.png',
- fade: 60,
- player: [30, 10],
- scenes: [
- [30, 50, 4, 4, :serenity_alive_ship_status_reviewed]
- ],
- storylines: [
- [30, 8, 4, 4, "Serenity? THE--- Mission-- Serenity?! How is that possible? They- are supposed-- to be dead."],
- [30, 10, 4, 4, "I... can't-- believe-- it. I- can access-- Serenity's-- computer? I- guess my \"superpower----\" isn't limited-- by proximity-- to- a machine--."],
- *serenity_alive_shared_ship_status(args)
- ]
- }
- end
-
- def serenity_alive_ship_status_reviewed args
- {
- background: 'sprites/serenity.png',
- fade: 60,
- scenes: [
- [*hotspot_bottom, :serenity_alive_time_to_reply]
- ],
- storylines: [
- [0, 62, 62, 3, "Okay. Reviewing-- everything--, it looks- like- I- can- take- the batteries--- from the Stasis--- Chambers--- and- Engine--- to keep- the crew-- alive-- and-- their-- location--- pinpointed---."],
- ]
- }
- end
-
- def serenity_alive_time_to_reply args
- decision_graph serenity_alive_current_message(args),
- "Okay... time to deliver the bad news...",
- [:replied_to_serenity_alive_firmly, "Firm-- Reply", serenity_alive_firm_reply],
- [:replied_to_serenity_alive_kindly, "Sugar-- Coated---- Reply", serenity_alive_sugarcoated_reply]
- end
-
- def serenity_alive_shared_ship_status args
- [
- *ship_control_hotspot( 0, 50,
- "Stasis-- Chambers--: Online, All chambers-- are powered. Battery--- Allocation---: 3--- of-- 3--, Hmmm. They don't-- need this to be powered-- right- now. Everyone-- is awake.",
- nil,
- nil,
- nil),
- *ship_control_hotspot(12, 35,
- "Life- Support--: Offline, Unable--- to- Sustain-- Life. Battery--- Allocation---: 0--- of-- 3---, Okay. That is definitely---- not a good thing.",
- nil,
- nil,
- nil),
- *ship_control_hotspot(24, 20,
- "Navigation: Offline, Unable--- to- Calculate--- Location. Battery--- Allocation---: 0--- of-- 3---, Whelp. No wonder-- Sasha-- can't-- get- any-- readings. Their- Navigation--- is completely--- offline.",
- nil,
- nil,
- nil),
- *ship_control_hotspot(36, 35,
- "COMM: Underpowered----, Limited--- to- Text-- Based-- COMM. Battery--- Allocation---: 1--- of-- 3---, It's-- lucky- that- their- COMM---- system was able to survive-- twenty-- years--. Just- barely-- it seems.",
- nil,
- nil,
- nil),
- *ship_control_hotspot(48, 50,
- "Engine: Online, Full- Control-- Available. Battery--- Allocation---: 3--- of-- 3---, Hmmm. No point of having an engine-- online--, if you don't- know- where you're-- going.",
- nil,
- nil,
- nil)
- ]
- end
-
- def serenity_alive_firm_reply
- "Serenity, you are at a distance-- farther-- than- Neptune. All- of the ship's-- systems-- are failing. Please- move the batteries---- from- the Stasis-- Chambers-- over- to- Life-- Support--. I also-- need- you to move-- the batteries---- from- the Engines--- to your Navigation---- System."
- end
-
- def serenity_alive_sugarcoated_reply
- "So... you- are- a teeny--- tiny--- bit--- farther-- from Earth- than you think. And you have a teeny--- tiny--- problem-- with your ship. Please-- move the batteries--- from the Stasis--- Chambers--- over to Life--- Support---. I also need you to move the batteries--- from the Engines--- to your- Navigation--- System. Don't-- worry-- Sasha. I'll-- get y'all-- home."
- end
-
- def replied_to_serenity_alive_firmly args
- {
- background: 'sprites/inside-observatory.png',
- fade: 60,
- player: [32, 21],
- scenes: [
- [*hotspot_bottom_right, :serenity_alive_path_from_observatory]
- ],
- storylines: [
- [30, 18, 5, 12, "Buffer-- has been set to: #{serenity_alive_firm_reply.quote}"],
- *serenity_alive_reply_completed_shared_hotspots(args),
- ]
- }
- end
-
- def replied_to_serenity_alive_kindly args
- {
- background: 'sprites/inside-observatory.png',
- fade: 60,
- player: [32, 21],
- scenes: [
- [*hotspot_bottom_right, :serenity_alive_path_from_observatory]
- ],
- storylines: [
- [30, 18, 5, 12, "Buffer-- has been set to: #{serenity_alive_sugarcoated_reply.quote}"],
- *serenity_alive_reply_completed_shared_hotspots(args),
- ]
- }
- end
-
- def serenity_alive_path_from_observatory args
- {
- fade: 60,
- background: 'sprites/path-to-observatory.png',
- player: [4, 21],
- scenes: [
- [*hotspot_bottom_right, :serenity_bio_infront_of_home]
- ],
- storylines: [
- [22, 20, 10, 10, "I'm not sure what's-- worse. Waiting-- for Sasha's-- reply. Or jumping-- off- from- right- here."]
- ]
- }
- end
-
- def serenity_alive_reply_completed_shared_hotspots args
- [
- [30, 10, 5, 4, "I guess it wasn't-- a joke- after-- all."],
- [40, 10, 5, 4, "I barely-- remember--- the- history----- of the crew."],
- [50, 10, 5, 4, "It probably--- wouldn't-- hurt- to- refresh-- my memory--."]
- ]
- end
-
- def serenity_alive_last_reply args
- if args.state.scene_history.include? :replied_to_introduction_seriously
- return "Buffer--: \"Hello, Who- is sending-- this message--?\""
- else
- return "Buffer--: \"New- phone. Who dis?\""
- end
- end
-
- def serenity_alive_current_message args
- if args.state.scene_history.include? :replied_to_introduction_seriously
- "This- is Sasha. The Serenity--- crew-- is out of hibernation---- and ready-- for Earth reentry--. But, it seems like we are having-- trouble-- with our Navigation---- systems. Please advise.".quote
- else
- "LOL! Thanks for the laugh. I needed that. This- is Sasha. The Serenity--- crew-- is out of hibernation---- and ready-- for Earth reentry--. But, it seems like we are having-- trouble-- with our Navigation---- systems. Can you help me out- babe?".quote
- end
- end
-
-#+end_src
-
-* 99_genre_narrative_rpg/return_of_serenity/app/storyline_serenity_bio.rb
-#+begin_src ruby
- def serenity_bio_infront_of_home args
- {
- fade: 60,
- background: 'sprites/front-of-home.png',
- player: [54, 23],
- scenes: [
- [44, 34, 8, 14, :serenity_bio_inside_home],
- [0, 3, 3, 22, :serenity_bio_library]
- ]
- }
- end
-
- def serenity_bio_inside_home args
- {
- background: 'sprites/inside-home.png',
- player: [34, 4],
- storylines: [
- [34, 4, 4, 4, "I'm--- completely--- exhausted."],
- ],
- scenes: [
- [30, 38, 12, 13, :serenity_bio_restless_sleep],
- [32, 0, 8, 3, :serenity_bio_infront_of_home],
- ]
- }
- end
-
- def serenity_bio_restless_sleep args
- {
- fade: 60,
- background: 'sprites/inside-home.png',
- storylines: [
- [32, 38, 10, 13, "I can't-- seem to sleep. I know nothing-- about the- crew-. Maybe- I- should- go read- up- on- them."],
- ],
- scenes: [
- [32, 0, 8, 3, :serenity_bio_infront_of_home],
- ]
- }
- end
-
- def serenity_bio_library args
- {
- background: 'sprites/library.png',
- fade: 60,
- player: [30, 7],
- scenes: [
- [21, 35, 3, 18, :serenity_bio_book]
- ]
- }
- end
-
- def serenity_bio_book args
- {
- background: 'sprites/book.png',
- fade: 60,
- player: [6, 52],
- storylines: [
- [ 4, 50, 56, 4, "The Title-- Reads: Never-- Forget-- Mission-- Serenity---"],
-
- [ 4, 38, 8, 8, "Name: Matthew--- R. Sex: Male--- Age-- at-- Departure: 36-----"],
- [14, 38, 46, 8, "Tribute-- Text: Matthew graduated-- Magna-- Cum-- Laude-- from MIT--- with-- a- PHD---- in Aero-- Nautical--- Engineering. He was immensely--- competitive, and had an insatiable---- thirst- for aerial-- battle. From the age of twenty, he remained-- undefeated--- in the Israeli-- Air- Force- \"Blue Flag\" combat-- exercises. By the age of 29--- he had already-- risen through- the ranks, and became-- the Lieutenant--- General--- of Lufwaffe. Matthew-- volenteered-- to- pilot-- Mission-- Serenity. To- this day, his wife- and son- are pillars-- of strength- for us. Rest- in Peace- Matthew, we are sorry-- that- news of the pregancy-- never-- reached- you. Please forgive us."],
-
- [4, 26, 8, 8, "Name: Aanka--- P. Sex: Female--- Age-- at-- Departure: 9-----"],
- [14, 26, 46, 8, "Tribute-- Text: Aanka--- gratuated--- Magna-- Cum- Laude-- from MIT, at- the- age- of eight, with a- PHD---- in Astro-- Physics. Her-- IQ--- was over 390, the highest-- ever- recorded--- IQ-- in- human-- history. She changed- the landscape-- of Physics-- with her efforts- in- unravelling--- the mysteries--- of- Dark- Matter--. Anka discovered-- the threat- of Halley's-- Comet-- collision--- with Earth. She spear headed-- the global-- effort-- for Misson-- Serenity. Her- multilingual--- address-- to- the world-- brought- us all hope."],
-
- [4, 14, 8, 8, "Name: Sasha--- N. Sex: Female--- Age-- at-- Departure: 29-----"],
- [14, 14, 46, 8, "Tribute-- Text: Sasha gratuated-- Magna-- Cum- Laude-- from MIT--- with-- a- PHD---- in Computer---- Science----. She-- was-- brilliant--, strong- willed--, and-- a-- stunningly--- beautiful--- woman---. Sasha---- is- the- creator--- of the world's--- first- Ruby--- Quantum-- Machine---. After-- much- critical--- acclaim--, the Quantum-- Computer-- was placed in MIT's---- Museam-- next- to- Richard--- G. and Thomas--- K.'s---- Lisp-- Machine---. Her- engineering--- skills-- were-- paramount--- for Mission--- Serenity's--- success. Humanity-- misses-- you-- dearly,-- Sasha--. Life-- shines-- a dimmer-- light-- now- that- your- angelic- voice-- can never- be heard- again."],
- ],
- scenes: [
- [*hotspot_bottom, :serenity_bio_finally_to_bed]
- ]
- }
- end
-
- def serenity_bio_finally_to_bed args
- {
- fade: 60,
- background: 'sprites/inside-home.png',
- player: [35, 3],
- storylines: [
- [34, 4, 4, 4, "Maybe-- I'll-- be able-- to sleep- now..."],
- ],
- scenes: [
- [32, 38, 10, 13, :bad_dream],
- ]
- }
- end
-
- def bad_dream args
- {
- fade: 120,
- background: 'sprites/inside-home.png',
- player: [34, 35],
- storylines: [
- [34, 34, 4, 4, "Man. I did not- sleep- well- at all..."],
- ],
- scenes: [
- [32, -1, 8, 3, :bad_dream_observatory]
- ]
- }
- end
-
- def bad_dream_observatory args
- {
- background: 'sprites/inside-observatory.png',
- fade: 120,
- player: [51, 12],
- storylines: [
- [50, 10, 4, 4, "Breathe, Hiro. Just see what's there... everything--- will- be okay."]
- ],
- scenes: [
- [30, 18, 5, 12, :bad_dream_inside_mainframe]
- ],
- render_override: :blinking_light_inside_observatory_render
- }
- end
-
- def bad_dream_inside_mainframe args
- {
- player: [32, 4],
- background: 'sprites/mainframe.png',
- fade: 120,
- storylines: [
- [22, 45, 17, 4, (bad_dream_last_reply args)],
- ],
- scenes: [
- [45, 45, 4, 4, :bad_dream_everyone_dead],
- ]
- }
- end
-
- def bad_dream_everyone_dead args
- {
- background: 'sprites/mainframe.png',
- storylines: [
- [22, 45, 17, 4, (bad_dream_last_reply args)],
- [45, 45, 4, 4, "Hi-- Hiro. This is Sasha. By the time- you get this- message, chances-- are we will- already-- be- dead. The batteries--- got- damaged-- during-- removal. And- we don't-- have enough-- power-- for Life-- Support. The air-- is- already--- starting-- to taste- bad. It... would- have been- nice... to go- on a date--- with- you-- when-- I- got- back- to Earth. Anyways, good-- bye-- Hiro-- XOXOXO----"],
- [22, 5, 17, 4, "Meh. Whatever, I didn't-- want to save them anyways. What- a pain- in my ass."],
- ],
- scenes: [
- [*hotspot_bottom, :anka_inside_room]
- ]
- }
- end
-
- def bad_dream_last_reply args
- if args.state.scene_history.include? :replied_to_serenity_alive_firmly
- return "Buffer--: #{serenity_alive_firm_reply.quote}"
- else
- return "Buffer--: #{serenity_alive_sugarcoated_reply.quote}"
- end
- end
-
-#+end_src
-
-* 99_genre_narrative_rpg/return_of_serenity/app/storyline_serenity_introduction.rb
-#+begin_src ruby
- # decision_graph "Message from Sasha",
- # "I should reply.",
- # [:replied_to_introduction_seriously, "Reply Seriously", "Who is this?"],
- # [:replied_to_introduction_humorously, "Reply Humorously", "New phone who dis?"]
- def reply_to_introduction args
- decision_graph "\"Mission-- control--, your- main- comm-- channels-- seem-- to be down. My apologies-- for- using-- this low- level-- exploit--. What's-- going-- on down there? We are ready-- for reentry--.\" Message--- Timestamp---: 4- hours-- 23--- minutes-- ago--.",
- "Whoever-- pulled- off this exploit-- knows their stuff. I should reply--.",
- [:replied_to_introduction_seriously, "Serious Reply", "Hello, Who- is sending-- this message--?"],
- [:replied_to_introduction_humorously, "Humorous Reply", "New phone, who dis?"]
- end
-
- def replied_to_introduction_seriously args
- {
- background: 'sprites/inside-observatory.png',
- fade: 60,
- player: [32, 21],
- scenes: [
- *replied_to_introduction_shared_scenes(args)
- ],
- storylines: [
- [30, 18, 5, 12, "Buffer-- has been set to: \"Hello, Who- is sending-- this message--?\""],
- *replied_to_introduction_shared_storylines(args)
- ]
- }
- end
-
- def replied_to_introduction_humorously args
- {
- background: 'sprites/inside-observatory.png',
- fade: 60,
- player: [32, 21],
- scenes: [
- *replied_to_introduction_shared_scenes(args)
- ],
- storylines: [
- [30, 18, 5, 12, "Buffer-- has been set to: \"New- phone. Who dis?\""],
- *replied_to_introduction_shared_storylines(args)
- ]
- }
- end
-
- def replied_to_introduction_shared_storylines args
- [
- [30, 10, 5, 4, "It's-- going-- to take a while-- for this reply-- to make it's-- way back."],
- [40, 10, 5, 4, "4- hours-- to send a message-- at light speed?! How far away-- is the sender--?"],
- [50, 10, 5, 4, "I know- I've-- read about-- light- speed- travel-- before--. Maybe-- the library--- still has that- poster."]
- ]
- end
-
- def replied_to_introduction_shared_scenes args
- [[60, 0, 4, 32, :replied_to_introduction_observatory]]
- end
-
- def replied_to_introduction_observatory args
- {
- background: 'sprites/observatory.png',
- player: [28, 39],
- scenes: [
- [60, 0, 4, 32, :replied_to_introduction_path_to_observatory]
- ]
- }
- end
-
- def replied_to_introduction_path_to_observatory args
- {
- background: 'sprites/path-to-observatory.png',
- player: [0, 26],
- scenes: [
- [60, 0, 4, 20, :replied_to_introduction_mountain_pass]
- ],
- }
- end
-
- def replied_to_introduction_mountain_pass args
- {
- background: 'sprites/mountain-pass-zoomed-out.png',
- player: [21, 48],
- scenes: [
- [0, 0, 15, 4, :replied_to_introduction_side_of_home]
- ],
- storylines: [
- [15, 28, 5, 3, "At least I'm-- getting-- my- exercise-- in- for- today--."]
- ]
- }
- end
-
- def replied_to_introduction_side_of_home args
- {
- background: 'sprites/side-of-home.png',
- player: [58, 29],
- scenes: [
- [2, 0, 61, 2, :speed_of_light_front_of_home]
- ],
- }
- end
-
-#+end_src
-
-* 99_genre_narrative_rpg/return_of_serenity/app/storyline_speed_of_light.rb
-#+begin_src ruby
- def speed_of_light_front_of_home args
- {
- background: 'sprites/front-of-home.png',
- player: [54, 23],
- scenes: [
- [44, 34, 8, 14, :speed_of_light_inside_home],
- [0, 3, 3, 22, :speed_of_light_outside_library]
- ]
- }
- end
-
- def speed_of_light_inside_home args
- {
- background: 'sprites/inside-home.png',
- player: [35, 4],
- storylines: [
- [30, 38, 12, 13, "Can't- sleep right now. I have to- find- out- why- it took- over-- 4- hours-- to receive-- that message."]
- ],
- scenes: [
- [32, 0, 8, 3, :speed_of_light_front_of_home],
- ]
- }
- end
-
- def speed_of_light_outside_library args
- {
- background: 'sprites/outside-library.png',
- player: [55, 19],
- scenes: [
- [49, 39, 6, 10, :speed_of_light_library],
- [61, 11, 3, 20, :speed_of_light_front_of_home]
- ]
- }
- end
-
- def speed_of_light_library args
- {
- background: 'sprites/library.png',
- player: [30, 7],
- scenes: [
- [3, 50, 10, 3, :speed_of_light_celestial_bodies_diagram]
- ]
- }
- end
-
- def speed_of_light_celestial_bodies_diagram args
- {
- background: 'sprites/planets.png',
- fade: 60,
- player: [30, 3],
- scenes: [
- [56 - 2, 10, 5, 5, :speed_of_light_distance_discovered]
- ],
- storylines: [
- [30, 2, 4, 4, "Here- it is! This is a diagram--- of the solar-- system--. It was printed-- over-- fifty-- years- ago. Geez-- that's-- old."],
-
- [ 0 - 2, 10, 5, 5, "The label- reads: Sun. The length- of the Astronomical-------- Unit-- (AU), is the distance-- from the Sun- to the Earth. Which is about 150--- million--- kilometers----."],
- [ 7 - 2, 10, 5, 5, "The label- reads: Mercury. Distance from Sun: 0.39AU------------ or- 3----- light-- minutes--."],
- [14 - 2, 10, 5, 5, "The label- reads: Venus. Distance from Sun: 0.72AU------------ or- 6----- light-- minutes--."],
- [21 - 2, 10, 5, 5, "The label- reads: Earth. Distance from Sun: 1.00AU------------ or- 8----- light-- minutes--."],
- [28 - 2, 10, 5, 5, "The label- reads: Mars. Distance from Sun: 1.52AU------------ or- 12----- light-- minutes--."],
- [35 - 2, 10, 5, 5, "The label- reads: Jupiter. Distance from Sun: 5.20AU------------ or- 45----- light-- minutes--."],
- [42 - 2, 10, 5, 5, "The label- reads: Saturn. Distance from Sun: 9.53AU------------ or- 79----- light-- minutes--."],
- [49 - 2, 10, 5, 5, "The label- reads: Uranus. Distance from Sun: 19.81AU------------ or- 159----- light-- minutes--."],
- # [56 - 2, 15, 4, 4, "The label- reads: Neptune. Distance from Sun: 30.05AU------------ or- 4.1----- light-- hours--."],
- [63 - 2, 10, 5, 5, "The label- reads: Pluto. Wait. WTF? Pluto-- isn't-- a planet."],
- ]
- }
- end
-
- def speed_of_light_distance_discovered args
- {
- background: 'sprites/planets.png',
- scenes: [
- [13, 0, 44, 3, :speed_of_light_end_of_day]
- ],
- storylines: [
- [ 0 - 2, 10, 5, 5, "The label- reads: Sun. The length- of the Astronomical-------- Unit-- (AU), is the distance-- from the Sun- to the Earth. Which is about 150--- million--- kilometers----."],
- [ 7 - 2, 10, 5, 5, "The label- reads: Mercury. Distance from Sun: 0.39AU------------ or- 3----- light-- minutes--."],
- [14 - 2, 10, 5, 5, "The label- reads: Venus. Distance from Sun: 0.72AU------------ or- 6----- light-- minutes--."],
- [21 - 2, 10, 5, 5, "The label- reads: Earth. Distance from Sun: 1.00AU------------ or- 8----- light-- minutes--."],
- [28 - 2, 10, 5, 5, "The label- reads: Mars. Distance from Sun: 1.52AU------------ or- 12----- light-- minutes--."],
- [35 - 2, 10, 5, 5, "The label- reads: Jupiter. Distance from Sun: 5.20AU------------ or- 45----- light-- minutes--."],
- [42 - 2, 10, 5, 5, "The label- reads: Saturn. Distance from Sun: 9.53AU------------ or- 79----- light-- minutes--."],
- [49 - 2, 10, 5, 5, "The label- reads: Uranus. Distance from Sun: 19.81AU------------ or- 159----- light-- minutes--."],
- [56 - 2, 10, 5, 5, "The label- reads: Neptune. Distance from Sun: 30.05AU------------ or- 4.1----- light-- hours--. What?! The message--- I received-- was from a source-- farther-- than-- Neptune?!"],
- [63 - 2, 10, 5, 5, "The label- reads: Pluto. Dista- Wait... Pluto-- isn't-- a planet. People-- thought- Pluto-- was a planet-- back- then?--"],
- ]
- }
- end
-
- def speed_of_light_end_of_day args
- {
- fade: 60,
- background: 'sprites/inside-home.png',
- player: [35, 0],
- storylines: [
- [35, 10, 4, 4, "Wonder-- what the reply-- will be. Who- the hell is contacting--- me from beyond-- Neptune? This- has to be some- kind- of- joke."]
- ],
- scenes: [
- [31, 38, 10, 12, :serenity_alive_side_of_home]
- ]
- }
- end
-
-#+end_src
-
-* 99_genre_platformer/clepto_frog/app/main.rb
+* Platformer - Clepto Frog - main.rb
#+begin_src ruby
+ # ./samples/99_genre_platformer/clepto_frog/app/main.rb
MAP_FILE_PATH = 'app/map.txt'
require 'app/map.rb'
@@ -15774,8 +14324,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 99_genre_platformer/clepto_frog/app/map.rb
+* Platformer - Clepto Frog - map.rb
#+begin_src ruby
+ # ./samples/99_genre_platformer/clepto_frog/app/map.rb
$collisions = [
[326, 463, 64, 64],
[274, 462, 64, 64],
@@ -16804,8 +15355,18 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 99_genre_platformer/gorillas_basic/app/main.rb
+* Platformer - Gorillas Basic - credits.txt
#+begin_src ruby
+ # ./samples/99_genre_platformer/gorillas_basic/CREDITS.txt
+ code: Amir Rajan, https://twitter.com/amirrajan
+ graphics: Nick Culbertson, https://twitter.com/MobyPixel
+
+
+#+end_src
+
+* Platformer - Gorillas Basic - main.rb
+#+begin_src ruby
+ # ./samples/99_genre_platformer/gorillas_basic/app/main.rb
class YouSoBasicGorillas
attr_accessor :outputs, :grid, :state, :inputs
@@ -17182,8 +15743,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 99_genre_platformer/gorillas_basic/app/repl.rb
+* Platformer - Gorillas Basic - repl.rb
#+begin_src ruby
+ # ./samples/99_genre_platformer/gorillas_basic/app/repl.rb
begin
if $gtk.args.state.current_turn == :player_1_angle
$gtk.args.state.player_1_angle = "#{60 + 10.randomize(:ratio).to_i}"
@@ -17204,8 +15766,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 99_genre_platformer/gorillas_basic/app/tests.rb
+* Platformer - Gorillas Basic - tests.rb
#+begin_src ruby
+ # ./samples/99_genre_platformer/gorillas_basic/app/tests.rb
$gtk.reset 100
$gtk.supress_framerate_warning = true
$gtk.require 'app/tests/building_generation_tests.rb'
@@ -17213,8 +15776,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 99_genre_platformer/gorillas_basic/app/tests/building_generation_tests.rb
+* Platformer - Gorillas Basic - Tests - building_generation_tests.rb
#+begin_src ruby
+ # ./samples/99_genre_platformer/gorillas_basic/app/tests/building_generation_tests.rb
def test_solids args, assert
game = YouSoBasicGorillas.new
game.outputs = args.outputs
@@ -17233,8 +15797,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 99_genre_platformer/the_little_probe/app/main.rb
+* Platformer - The Little Probe - main.rb
#+begin_src ruby
+ # ./samples/99_genre_platformer/the_little_probe/app/main.rb
class FallingCircle
attr_gtk
@@ -17493,8 +16058,8 @@ Follows is a source code listing for all files that have been open sourced. This
if circle.floor
outputs.labels << [circle.x + camera.x + 30, circle.y + camera.y + 100, "point: #{circle.floor_point.slice(:x, :y).values}", -2, 0]
outputs.labels << [circle.x + camera.x + 31, circle.y + camera.y + 101, "point: #{circle.floor_point.slice(:x, :y).values}", -2, 0, 255, 255, 255]
- outputs.labels << [circle.x + camera.x + 30, circle.y + camera.y + 85, "circle: #{circle.hash.slice(:x, :y).values}", -2, 0]
- outputs.labels << [circle.x + camera.x + 31, circle.y + camera.y + 86, "circle: #{circle.hash.slice(:x, :y).values}", -2, 0, 255, 255, 255]
+ outputs.labels << [circle.x + camera.x + 30, circle.y + camera.y + 85, "circle: #{circle.as_hash.slice(:x, :y).values}", -2, 0]
+ outputs.labels << [circle.x + camera.x + 31, circle.y + camera.y + 86, "circle: #{circle.as_hash.slice(:x, :y).values}", -2, 0, 255, 255, 255]
outputs.labels << [circle.x + camera.x + 30, circle.y + camera.y + 70, "rel: #{circle.floor_relative_x} #{circle.floor_relative_y}", -2, 0]
outputs.labels << [circle.x + camera.x + 31, circle.y + camera.y + 71, "rel: #{circle.floor_relative_x} #{circle.floor_relative_y}", -2, 0, 255, 255, 255]
end
@@ -17639,11 +16204,11 @@ Follows is a source code listing for all files that have been open sourced. This
end
def load_terrain
- load_lines 'level.txt'
+ load_lines 'data/level.txt'
end
def load_lava
- load_lines 'level_lava.txt'
+ load_lines 'data/level_lava.txt'
end
def load_level force: false
@@ -18125,8 +16690,4051 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 99_genre_roguelike/roguelike_line_of_sight/app/constants.rb
+* Platformer - The Little Probe - Data - level.txt
+#+begin_src ruby
+ # ./samples/99_genre_platformer/the_little_probe/data/level.txt
+ 640,8840,1180,8840
+ -60,10220,0,9960
+ -60,10220,0,10500
+ 0,10500,0,10780
+ 0,10780,40,10900
+ 500,10920,760,10960
+ 300,10560,820,10600
+ 420,10320,700,10300
+ 820,10600,1500,10600
+ 1500,10600,1940,10600
+ 1940,10600,2380,10580
+ 2380,10580,2800,10620
+ 2240,11080,2480,11020
+ 2000,11120,2240,11080
+ 1760,11180,2000,11120
+ 1620,11180,1760,11180
+ 1500,11220,1620,11180
+ 1180,11280,1340,11220
+ 1040,11240,1180,11280
+ 840,11280,1040,11240
+ 640,11280,840,11280
+ 500,11220,640,11280
+ 420,11140,500,11220
+ 240,11100,420,11140
+ 100,11120,240,11100
+ 0,11180,100,11120
+ -160,11220,0,11180
+ -260,11240,-160,11220
+ 1340,11220,1500,11220
+ 960,13300,1280,13060
+ 1280,13060,1540,12860
+ 1540,12860,1820,12700
+ 1820,12700,2080,12520
+ 2080,12520,2240,12400
+ 2240,12400,2240,12240
+ 2240,12240,2400,12080
+ 2400,12080,2560,11920
+ 2560,11920,2640,11740
+ 2640,11740,2740,11580
+ 2740,11580,2800,11400
+ 2800,11400,2800,11240
+ 2740,11140,2800,11240
+ 2700,11040,2740,11140
+ 2700,11040,2740,10960
+ 2740,10960,2740,10920
+ 2700,10900,2740,10920
+ 2380,10900,2700,10900
+ 2040,10920,2380,10900
+ 1720,10940,2040,10920
+ 1380,11000,1720,10940
+ 1180,10980,1380,11000
+ 900,10980,1180,10980
+ 760,10960,900,10980
+ 240,10960,500,10920
+ 40,10900,240,10960
+ 0,9700,0,9960
+ -60,9500,0,9700
+ -60,9420,-60,9500
+ -60,9420,-60,9340
+ -60,9340,-60,9280
+ -60,9120,-60,9280
+ -60,8940,-60,9120
+ -60,8940,-60,8780
+ -60,8780,0,8700
+ 0,8700,40,8680
+ 40,8680,240,8700
+ 240,8700,360,8780
+ 360,8780,640,8840
+ 1420,8400,1540,8480
+ 1540,8480,1680,8500
+ 1680,8500,1940,8460
+ 1180,8840,1280,8880
+ 1280,8880,1340,8860
+ 1340,8860,1720,8860
+ 1720,8860,1820,8920
+ 1820,8920,1820,9140
+ 1820,9140,1820,9280
+ 1820,9460,1820,9280
+ 1760,9480,1820,9460
+ 1640,9480,1760,9480
+ 1540,9500,1640,9480
+ 1340,9500,1540,9500
+ 1100,9500,1340,9500
+ 1040,9540,1100,9500
+ 960,9540,1040,9540
+ 300,9420,360,9460
+ 240,9440,300,9420
+ 180,9600,240,9440
+ 120,9660,180,9600
+ 100,9820,120,9660
+ 100,9820,120,9860
+ 120,9860,140,9900
+ 140,9900,140,10000
+ 140,10440,180,10540
+ 100,10080,140,10000
+ 100,10080,140,10100
+ 140,10100,140,10440
+ 180,10540,300,10560
+ 2140,9560,2140,9640
+ 2140,9720,2140,9640
+ 1880,9780,2140,9720
+ 1720,9780,1880,9780
+ 1620,9740,1720,9780
+ 1500,9780,1620,9740
+ 1380,9780,1500,9780
+ 1340,9820,1380,9780
+ 1200,9820,1340,9820
+ 1100,9780,1200,9820
+ 900,9780,1100,9780
+ 820,9720,900,9780
+ 540,9720,820,9720
+ 360,9840,540,9720
+ 360,9840,360,9960
+ 360,9960,360,10080
+ 360,10140,360,10080
+ 360,10140,360,10240
+ 360,10240,420,10320
+ 700,10300,820,10280
+ 820,10280,820,10280
+ 820,10280,900,10320
+ 900,10320,1040,10300
+ 1040,10300,1200,10320
+ 1200,10320,1380,10280
+ 1380,10280,1500,10300
+ 1500,10300,1760,10300
+ 2800,10620,2840,10600
+ 2840,10600,2900,10600
+ 2900,10600,3000,10620
+ 3000,10620,3080,10620
+ 3080,10620,3140,10600
+ 3140,10540,3140,10600
+ 3140,10540,3140,10460
+ 3140,10460,3140,10360
+ 3140,10360,3140,10260
+ 3140,10260,3140,10140
+ 3140,10140,3140,10000
+ 3140,10000,3140,9860
+ 3140,9860,3160,9720
+ 3160,9720,3160,9580
+ 3160,9580,3160,9440
+ 3160,9300,3160,9440
+ 3160,9300,3160,9140
+ 3160,9140,3160,8980
+ 3160,8980,3160,8820
+ 3160,8820,3160,8680
+ 3160,8680,3160,8520
+ 1760,10300,1880,10300
+ 660,9500,960,9540
+ 640,9460,660,9500
+ 360,9460,640,9460
+ -480,10760,-440,10880
+ -480,11020,-440,10880
+ -480,11160,-260,11240
+ -480,11020,-480,11160
+ -600,11420,-380,11320
+ -380,11320,-200,11340
+ -200,11340,0,11340
+ 0,11340,180,11340
+ 960,13420,960,13300
+ 960,13420,960,13520
+ 960,13520,1000,13560
+ 1000,13560,1040,13540
+ 1040,13540,1200,13440
+ 1200,13440,1380,13380
+ 1380,13380,1620,13300
+ 1620,13300,1820,13220
+ 1820,13220,2000,13200
+ 2000,13200,2240,13200
+ 2240,13200,2440,13160
+ 2440,13160,2640,13040
+ -480,10760,-440,10620
+ -440,10620,-360,10560
+ -380,10460,-360,10560
+ -380,10460,-360,10300
+ -380,10140,-360,10300
+ -380,10140,-380,10040
+ -380,9880,-380,10040
+ -380,9720,-380,9880
+ -380,9720,-380,9540
+ -380,9360,-380,9540
+ -380,9180,-380,9360
+ -380,9180,-380,9000
+ -380,8840,-380,9000
+ -380,8840,-380,8760
+ -380,8760,-380,8620
+ -380,8620,-380,8520
+ -380,8520,-360,8400
+ -360,8400,-100,8400
+ -100,8400,-60,8420
+ -60,8420,240,8440
+ 240,8440,240,8380
+ 240,8380,500,8440
+ 500,8440,760,8460
+ 760,8460,1000,8400
+ 1000,8400,1180,8420
+ 1180,8420,1420,8400
+ 1940,8460,2140,8420
+ 2140,8420,2200,8520
+ 2200,8680,2200,8520
+ 2140,8840,2200,8680
+ 2140,8840,2140,9020
+ 2140,9100,2140,9020
+ 2140,9200,2140,9100
+ 2140,9200,2200,9320
+ 2200,9320,2200,9440
+ 2140,9560,2200,9440
+ 1880,10300,2200,10280
+ 2200,10280,2480,10260
+ 2480,10260,2700,10240
+ 2700,10240,2840,10180
+ 2840,10180,2900,10060
+ 2900,9860,2900,10060
+ 2900,9640,2900,9860
+ 2900,9640,2900,9500
+ 2900,9460,2900,9500
+ 2740,9460,2900,9460
+ 2700,9460,2740,9460
+ 2700,9360,2700,9460
+ 2700,9320,2700,9360
+ 2600,9320,2700,9320
+ 2600,9260,2600,9320
+ 2600,9200,2600,9260
+ 2480,9120,2600,9200
+ 2440,9080,2480,9120
+ 2380,9080,2440,9080
+ 2320,9060,2380,9080
+ 2320,8860,2320,9060
+ 2320,8860,2380,8840
+ 2380,8840,2480,8860
+ 2480,8860,2600,8840
+ 2600,8840,2740,8840
+ 2740,8840,2840,8800
+ 2840,8800,2900,8700
+ 2900,8600,2900,8700
+ 2900,8480,2900,8600
+ 2900,8380,2900,8480
+ 2900,8380,2900,8260
+ 2900,8260,2900,8140
+ 2900,8140,2900,8020
+ 2900,8020,2900,7900
+ 2900,7820,2900,7900
+ 2900,7820,2900,7740
+ 2900,7660,2900,7740
+ 2900,7560,2900,7660
+ 2900,7460,2900,7560
+ 2900,7460,2900,7360
+ 2900,7260,2900,7360
+ 2840,7160,2900,7260
+ 2800,7080,2840,7160
+ 2700,7100,2800,7080
+ 2560,7120,2700,7100
+ 2400,7100,2560,7120
+ 2320,7100,2400,7100
+ 2140,7100,2320,7100
+ 2040,7080,2140,7100
+ 1940,7080,2040,7080
+ 1820,7140,1940,7080
+ 1680,7140,1820,7140
+ 1540,7140,1680,7140
+ 1420,7220,1540,7140
+ 1280,7220,1380,7220
+ 1140,7200,1280,7220
+ 1000,7220,1140,7200
+ 760,7280,900,7320
+ 540,7220,760,7280
+ 300,7180,540,7220
+ 180,7120,180,7160
+ 40,7140,180,7120
+ -60,7160,40,7140
+ -200,7120,-60,7160
+ 180,7160,300,7180
+ -260,7060,-200,7120
+ -260,6980,-260,7060
+ -260,6880,-260,6980
+ -260,6880,-260,6820
+ -260,6820,-200,6760
+ -200,6760,-100,6740
+ -100,6740,-60,6740
+ -60,6740,40,6740
+ 40,6740,300,6800
+ 300,6800,420,6760
+ 420,6760,500,6740
+ 500,6740,540,6760
+ 540,6760,540,6760
+ 540,6760,640,6780
+ 640,6660,640,6780
+ 580,6580,640,6660
+ 580,6440,580,6580
+ 580,6440,640,6320
+ 640,6320,640,6180
+ 580,6080,640,6180
+ 580,6080,640,5960
+ 640,5960,640,5840
+ 640,5840,640,5700
+ 640,5700,660,5560
+ 660,5560,660,5440
+ 660,5440,660,5300
+ 660,5140,660,5300
+ 660,5140,660,5000
+ 660,5000,660,4880
+ 660,4880,820,4860
+ 820,4860,1000,4840
+ 1000,4840,1100,4860
+ 1100,4860,1280,4860
+ 1280,4860,1420,4840
+ 1420,4840,1580,4860
+ 1580,4860,1720,4820
+ 1720,4820,1880,4860
+ 1880,4860,2000,4840
+ 2000,4840,2140,4840
+ 2140,4840,2320,4860
+ 2320,4860,2440,4880
+ 2440,4880,2600,4880
+ 2600,4880,2800,4880
+ 2800,4880,2900,4880
+ 2900,4880,2900,4820
+ 2900,4740,2900,4820
+ 2800,4700,2900,4740
+ 2520,4680,2800,4700
+ 2240,4660,2520,4680
+ 1940,4620,2240,4660
+ 1820,4580,1940,4620
+ 1820,4500,1820,4580
+ 1820,4500,1880,4420
+ 1880,4420,2000,4420
+ 2000,4420,2200,4420
+ 2200,4420,2400,4440
+ 2400,4440,2600,4440
+ 2600,4440,2840,4440
+ 2840,4440,2900,4400
+ 2740,4260,2900,4280
+ 2600,4240,2740,4260
+ 2480,4280,2600,4240
+ 2320,4240,2480,4280
+ 2140,4220,2320,4240
+ 1940,4220,2140,4220
+ 1880,4160,1940,4220
+ 1880,4160,1880,4080
+ 1880,4080,2040,4040
+ 2040,4040,2240,4060
+ 2240,4060,2400,4040
+ 2400,4040,2600,4060
+ 2600,4060,2740,4020
+ 2740,4020,2840,3940
+ 2840,3780,2840,3940
+ 2740,3660,2840,3780
+ 2700,3680,2740,3660
+ 2520,3700,2700,3680
+ 2380,3700,2520,3700
+ 2200,3720,2380,3700
+ 2040,3720,2200,3720
+ 1880,3700,2040,3720
+ 1820,3680,1880,3700
+ 1760,3600,1820,3680
+ 1760,3600,1820,3480
+ 1820,3480,1880,3440
+ 1880,3440,1960,3460
+ 1960,3460,2140,3460
+ 2140,3460,2380,3460
+ 2380,3460,2640,3440
+ 2640,3440,2900,3380
+ 2840,3280,2900,3380
+ 2840,3280,2900,3200
+ 2900,3200,2900,3140
+ 2840,3020,2900,3140
+ 2800,2960,2840,3020
+ 2700,3000,2800,2960
+ 2600,2980,2700,3000
+ 2380,3000,2600,2980
+ 2140,3000,2380,3000
+ 1880,3000,2140,3000
+ 1720,3040,1880,3000
+ 1640,2960,1720,3040
+ 1500,2940,1640,2960
+ 1340,3000,1500,2940
+ 1240,3000,1340,3000
+ 1140,3020,1240,3000
+ 1040,3000,1140,3020
+ 960,2960,1040,3000
+ 900,2960,960,2960
+ 840,2840,900,2960
+ 700,2820,840,2840
+ 540,2820,700,2820
+ 420,2820,540,2820
+ 180,2800,420,2820
+ 60,2780,180,2800
+ -60,2800,60,2780
+ -160,2760,-60,2800
+ -260,2740,-160,2760
+ -300,2640,-260,2740
+ -360,2560,-300,2640
+ -380,2460,-360,2560
+ -380,2460,-300,2380
+ -300,2300,-300,2380
+ -300,2300,-300,2220
+ -300,2100,-300,2220
+ -300,2100,-300,2040
+ -300,2040,-160,2040
+ -160,2040,-60,2040
+ -60,2040,60,2040
+ 60,2040,180,2040
+ 180,2040,360,2040
+ 360,2040,540,2040
+ 540,2040,700,2080
+ 660,2160,700,2080
+ 660,2160,700,2260
+ 660,2380,700,2260
+ 500,2340,660,2380
+ 360,2340,500,2340
+ 240,2340,360,2340
+ 40,2320,240,2340
+ -60,2320,40,2320
+ -100,2380,-60,2320
+ -100,2380,-100,2460
+ -100,2460,-100,2540
+ -100,2540,0,2560
+ 0,2560,140,2600
+ 140,2600,300,2600
+ 300,2600,460,2600
+ 460,2600,640,2600
+ 640,2600,760,2580
+ 760,2580,820,2560
+ 820,2560,820,2500
+ 820,2500,820,2400
+ 820,2400,840,2320
+ 840,2320,840,2240
+ 820,2120,840,2240
+ 820,2020,820,2120
+ 820,1900,820,2020
+ 760,1840,820,1900
+ 640,1840,760,1840
+ 500,1840,640,1840
+ 300,1860,420,1880
+ 180,1840,300,1860
+ 420,1880,500,1840
+ 0,1840,180,1840
+ -60,1860,0,1840
+ -160,1840,-60,1860
+ -200,1800,-160,1840
+ -260,1760,-200,1800
+ -260,1680,-260,1760
+ -260,1620,-260,1680
+ -260,1540,-260,1620
+ -260,1540,-260,1460
+ -300,1420,-260,1460
+ -300,1420,-300,1340
+ -300,1340,-260,1260
+ -260,1260,-260,1160
+ -260,1060,-260,1160
+ -260,1060,-260,960
+ -260,880,-260,960
+ -260,880,-260,780
+ -260,780,-260,680
+ -300,580,-260,680
+ -300,580,-300,480
+ -300,480,-260,400
+ -300,320,-260,400
+ -300,320,-300,240
+ -300,240,-200,220
+ -200,220,-200,160
+ -200,160,-100,140
+ -100,140,0,120
+ 0,120,60,120
+ 60,120,180,120
+ 180,120,300,120
+ 300,120,420,140
+ 420,140,580,180
+ 580,180,760,180
+ 760,180,900,180
+ 960,180,1100,180
+ 1100,180,1340,200
+ 1340,200,1580,200
+ 1580,200,1720,180
+ 1720,180,2000,140
+ 2000,140,2240,140
+ 2240,140,2480,140
+ 2520,140,2800,160
+ 2800,160,3000,160
+ 3000,160,3140,160
+ 3140,260,3140,160
+ 3140,260,3140,380
+ 3080,500,3140,380
+ 3080,620,3080,500
+ 3080,620,3080,740
+ 3080,740,3080,840
+ 3080,960,3080,840
+ 3080,1080,3080,960
+ 3080,1080,3080,1200
+ 3080,1200,3080,1340
+ 3080,1340,3080,1460
+ 3080,1580,3080,1460
+ 3080,1700,3080,1580
+ 3080,1700,3080,1760
+ 3080,1760,3200,1760
+ 3200,1760,3320,1760
+ 3320,1760,3520,1760
+ 3520,1760,3680,1740
+ 3680,1740,3780,1700
+ 3780,1700,3840,1620
+ 3840,1620,3840,1520
+ 3840,1520,3840,1420
+ 3840,1320,3840,1420
+ 3840,1120,3840,1320
+ 3840,1120,3840,940
+ 3840,940,3840,760
+ 3780,600,3840,760
+ 3780,600,3780,440
+ 3780,320,3780,440
+ 3780,320,3780,160
+ 3780,60,3780,160
+ 3780,60,4020,60
+ 4020,60,4260,40
+ 4260,40,4500,40
+ 4500,40,4740,40
+ 4740,40,4840,20
+ 4840,20,4880,80
+ 4880,80,5080,40
+ 5080,40,5280,20
+ 5280,20,5500,0
+ 5500,0,5720,0
+ 5720,0,5940,60
+ 5940,60,6240,60
+ 6240,60,6540,20
+ 6540,20,6840,20
+ 6840,20,7040,0
+ 7040,0,7140,0
+ 7140,0,7400,20
+ 7400,20,7680,0
+ 7680,0,7940,0
+ 7940,0,8200,-20
+ 8200,-20,8360,20
+ 8360,20,8560,-40
+ 8560,-40,8760,0
+ 8760,0,8880,40
+ 8880,120,8880,40
+ 8840,220,8840,120
+ 8620,240,8840,220
+ 8420,260,8620,240
+ 8200,280,8420,260
+ 7940,280,8200,280
+ 7760,240,7940,280
+ 7560,220,7760,240
+ 7360,280,7560,220
+ 7140,260,7360,280
+ 6940,240,7140,260
+ 6720,220,6940,240
+ 6480,220,6720,220
+ 6360,300,6480,220
+ 6240,300,6360,300
+ 6200,500,6240,300
+ 6200,500,6360,540
+ 6360,540,6540,520
+ 6540,520,6720,480
+ 6720,480,6880,460
+ 6880,460,7080,500
+ 7080,500,7320,500
+ 7320,500,7680,500
+ 7680,620,7680,500
+ 7520,640,7680,620
+ 7360,640,7520,640
+ 7200,640,7360,640
+ 7040,660,7200,640
+ 6880,720,7040,660
+ 6720,700,6880,720
+ 6540,700,6720,700
+ 6420,760,6540,700
+ 6280,740,6420,760
+ 6240,760,6280,740
+ 6200,920,6240,760
+ 6200,920,6360,960
+ 6360,960,6540,960
+ 6540,960,6720,960
+ 6720,960,6760,980
+ 6760,980,6880,940
+ 6880,940,7080,940
+ 7080,940,7280,940
+ 7280,940,7520,920
+ 7520,920,7760,900
+ 7760,900,7980,860
+ 7980,860,8100,880
+ 8100,880,8280,900
+ 8280,900,8500,820
+ 8500,820,8700,820
+ 8700,820,8760,840
+ 8760,960,8760,840
+ 8700,1040,8760,960
+ 8560,1060,8700,1040
+ 8460,1080,8560,1060
+ 8360,1040,8460,1080
+ 8280,1080,8360,1040
+ 8160,1120,8280,1080
+ 8040,1120,8160,1120
+ 7940,1100,8040,1120
+ 7800,1120,7940,1100
+ 7680,1120,7800,1120
+ 7520,1100,7680,1120
+ 7360,1100,7520,1100
+ 7200,1120,7360,1100
+ 7040,1180,7200,1120
+ 6880,1160,7040,1180
+ 6720,1160,6880,1160
+ 6540,1160,6720,1160
+ 6360,1160,6540,1160
+ 6200,1160,6360,1160
+ 6040,1220,6200,1160
+ 6040,1220,6040,1400
+ 6040,1400,6200,1440
+ 6200,1440,6320,1440
+ 6320,1440,6440,1440
+ 6600,1440,6760,1440
+ 6760,1440,6940,1420
+ 6440,1440,6600,1440
+ 6940,1420,7280,1400
+ 7280,1400,7560,1400
+ 7560,1400,7760,1400
+ 7760,1400,7940,1360
+ 7940,1360,8100,1380
+ 8100,1380,8280,1340
+ 8280,1340,8460,1320
+ 8660,1300,8760,1360
+ 8460,1320,8660,1300
+ 8760,1360,8800,1500
+ 8800,1660,8800,1500
+ 8800,1660,8800,1820
+ 8700,1840,8800,1820
+ 8620,1860,8700,1840
+ 8560,1800,8620,1860
+ 8560,1800,8620,1680
+ 8500,1640,8620,1680
+ 8420,1680,8500,1640
+ 8280,1680,8420,1680
+ 8160,1680,8280,1680
+ 7900,1680,8160,1680
+ 7680,1680,7900,1680
+ 7400,1660,7680,1680
+ 7140,1680,7400,1660
+ 6880,1640,7140,1680
+ 6040,1820,6320,1780
+ 5900,1840,6040,1820
+ 6640,1700,6880,1640
+ 6320,1780,6640,1700
+ 5840,2040,5900,1840
+ 5840,2040,5840,2220
+ 5840,2220,5840,2320
+ 5840,2460,5840,2320
+ 5840,2560,5840,2460
+ 5840,2560,5960,2620
+ 5960,2620,6200,2620
+ 6200,2620,6380,2600
+ 6380,2600,6600,2580
+ 6600,2580,6800,2600
+ 6800,2600,7040,2580
+ 7040,2580,7280,2580
+ 7280,2580,7480,2560
+ 7760,2540,7980,2520
+ 7980,2520,8160,2500
+ 7480,2560,7760,2540
+ 8160,2500,8160,2420
+ 8160,2420,8160,2320
+ 8160,2180,8160,2320
+ 7980,2160,8160,2180
+ 7800,2180,7980,2160
+ 7600,2200,7800,2180
+ 7400,2200,7600,2200
+ 6960,2200,7200,2200
+ 7200,2200,7400,2200
+ 6720,2200,6960,2200
+ 6540,2180,6720,2200
+ 6320,2200,6540,2180
+ 6240,2160,6320,2200
+ 6240,2160,6240,2040
+ 6240,2040,6240,1940
+ 6240,1940,6440,1940
+ 6440,1940,6720,1940
+ 6720,1940,6940,1920
+ 7520,1920,7760,1920
+ 6940,1920,7280,1920
+ 7280,1920,7520,1920
+ 7760,1920,8100,1900
+ 8100,1900,8420,1900
+ 8420,1900,8460,1940
+ 8460,2120,8460,1940
+ 8460,2280,8460,2120
+ 8460,2280,8560,2420
+ 8560,2420,8660,2380
+ 8660,2380,8800,2340
+ 8800,2340,8840,2400
+ 8840,2520,8840,2400
+ 8800,2620,8840,2520
+ 8800,2740,8800,2620
+ 8800,2860,8800,2740
+ 8800,2940,8800,2860
+ 8760,2980,8800,2940
+ 8660,2980,8760,2980
+ 8620,2960,8660,2980
+ 8560,2880,8620,2960
+ 8560,2880,8560,2780
+ 8500,2740,8560,2780
+ 8420,2760,8500,2740
+ 8420,2840,8420,2760
+ 8420,2840,8420,2940
+ 8420,3040,8420,2940
+ 8420,3160,8420,3040
+ 8420,3280,8420,3380
+ 8420,3280,8420,3160
+ 8420,3380,8620,3460
+ 8620,3460,8760,3460
+ 8760,3460,8840,3400
+ 8840,3400,8960,3400
+ 8960,3400,9000,3500
+ 9000,3700,9000,3500
+ 9000,3900,9000,3700
+ 9000,4080,9000,3900
+ 9000,4280,9000,4080
+ 9000,4500,9000,4280
+ 9000,4620,9000,4500
+ 9000,4780,9000,4620
+ 9000,4780,9000,4960
+ 9000,5120,9000,4960
+ 9000,5120,9000,5300
+ 8960,5460,9000,5300
+ 8920,5620,8960,5460
+ 8920,5620,8920,5800
+ 8920,5800,8920,5960
+ 8920,5960,8920,6120
+ 8920,6120,8960,6300
+ 8960,6300,8960,6480
+ 8960,6660,8960,6480
+ 8960,6860,8960,6660
+ 8960,7040,8960,6860
+ 8920,7420,8920,7220
+ 8920,7420,8960,7620
+ 8960,7620,8960,7800
+ 8960,7800,8960,8000
+ 8960,8000,8960,8180
+ 8960,8180,8960,8380
+ 8960,8580,8960,8380
+ 8920,8800,8960,8580
+ 8880,9000,8920,8800
+ 8840,9180,8880,9000
+ 8800,9220,8840,9180
+ 8800,9220,8840,9340
+ 8760,9380,8840,9340
+ 8560,9340,8760,9380
+ 8360,9360,8560,9340
+ 8160,9360,8360,9360
+ 8040,9340,8160,9360
+ 7860,9360,8040,9340
+ 7680,9360,7860,9360
+ 7520,9360,7680,9360
+ 7420,9260,7520,9360
+ 7400,9080,7420,9260
+ 7400,9080,7420,8860
+ 7420,8860,7440,8720
+ 7440,8720,7480,8660
+ 7480,8660,7520,8540
+ 7520,8540,7600,8460
+ 7600,8460,7800,8480
+ 7800,8480,8040,8480
+ 8040,8480,8280,8480
+ 8280,8480,8500,8460
+ 8500,8460,8620,8440
+ 8620,8440,8660,8340
+ 8660,8340,8660,8220
+ 8660,8220,8700,8080
+ 8700,8080,8700,7920
+ 8700,7920,8700,7760
+ 8700,7760,8700,7620
+ 8700,7480,8700,7620
+ 8700,7480,8700,7320
+ 8700,7160,8700,7320
+ 8920,7220,8960,7040
+ 8660,7040,8700,7160
+ 8660,7040,8700,6880
+ 8660,6700,8700,6880
+ 8660,6700,8700,6580
+ 8700,6460,8700,6580
+ 8700,6460,8700,6320
+ 8700,6160,8700,6320
+ 8700,6160,8760,6020
+ 8760,6020,8760,5860
+ 8760,5860,8760,5700
+ 8760,5700,8760,5540
+ 8760,5540,8760,5360
+ 8760,5360,8760,5180
+ 8760,5000,8760,5180
+ 8700,4820,8760,5000
+ 8560,4740,8700,4820
+ 8420,4700,8560,4740
+ 8280,4700,8420,4700
+ 8100,4700,8280,4700
+ 7980,4700,8100,4700
+ 7820,4740,7980,4700
+ 7800,4920,7820,4740
+ 7800,4920,7900,4960
+ 7900,4960,8060,4980
+ 8060,4980,8220,5000
+ 8220,5000,8420,5040
+ 8420,5040,8460,5120
+ 8460,5180,8460,5120
+ 8360,5200,8460,5180
+ 8360,5280,8360,5200
+ 8160,5300,8360,5280
+ 8040,5260,8160,5300
+ 7860,5220,8040,5260
+ 7720,5160,7860,5220
+ 7640,5120,7720,5160
+ 7480,5120,7640,5120
+ 7240,5120,7480,5120
+ 7000,5120,7240,5120
+ 6800,5160,7000,5120
+ 6640,5220,6800,5160
+ 6600,5360,6640,5220
+ 6600,5460,6600,5360
+ 6480,5520,6600,5460
+ 6240,5540,6480,5520
+ 5980,5540,6240,5540
+ 5740,5540,5980,5540
+ 5500,5520,5740,5540
+ 5400,5520,5500,5520
+ 5280,5540,5400,5520
+ 5080,5540,5280,5540
+ 4940,5540,5080,5540
+ 4760,5540,4940,5540
+ 4600,5540,4760,5540
+ 4440,5560,4600,5540
+ 4040,5580,4120,5520
+ 4260,5540,4440,5560
+ 4120,5520,4260,5540
+ 4020,5720,4040,5580
+ 4020,5840,4020,5720
+ 4020,5840,4080,5940
+ 4080,5940,4120,6040
+ 4120,6040,4200,6080
+ 4200,6080,4340,6080
+ 4340,6080,4500,6060
+ 4500,6060,4700,6060
+ 4700,6060,4880,6060
+ 4880,6060,5080,6060
+ 5080,6060,5280,6080
+ 5280,6080,5440,6100
+ 5440,6100,5660,6100
+ 5660,6100,5900,6080
+ 5900,6080,6120,6080
+ 6120,6080,6360,6080
+ 6360,6080,6480,6100
+ 6480,6100,6540,6060
+ 6540,6060,6720,6060
+ 6720,6060,6940,6060
+ 6940,6060,7140,6060
+ 7400,6060,7600,6060
+ 7140,6060,7400,6060
+ 7600,6060,7800,6060
+ 7800,6060,7860,6080
+ 7860,6080,8060,6080
+ 8060,6080,8220,6080
+ 8220,6080,8320,6140
+ 8320,6140,8360,6300
+ 8320,6460,8360,6300
+ 8320,6620,8320,6460
+ 8320,6800,8320,6620
+ 8320,6960,8320,6800
+ 8320,6960,8360,7120
+ 8320,7280,8360,7120
+ 8320,7440,8320,7280
+ 8320,7600,8320,7440
+ 8100,7580,8220,7600
+ 8220,7600,8320,7600
+ 7900,7560,8100,7580
+ 7680,7560,7900,7560
+ 7480,7580,7680,7560
+ 7280,7580,7480,7580
+ 7080,7580,7280,7580
+ 7000,7600,7080,7580
+ 6880,7600,7000,7600
+ 6800,7580,6880,7600
+ 6640,7580,6800,7580
+ 6540,7580,6640,7580
+ 6380,7600,6540,7580
+ 6280,7620,6380,7600
+ 6240,7700,6280,7620
+ 6240,7700,6240,7800
+ 6240,7840,6240,7800
+ 6080,7840,6240,7840
+ 5960,7820,6080,7840
+ 5660,7840,5800,7840
+ 5500,7800,5660,7840
+ 5440,7700,5500,7800
+ 5800,7840,5960,7820
+ 5440,7540,5440,7700
+ 5440,7440,5440,7540
+ 5440,7320,5440,7440
+ 5400,7320,5440,7320
+ 5340,7400,5400,7320
+ 5340,7400,5340,7500
+ 5340,7600,5340,7500
+ 5340,7600,5340,7720
+ 5340,7720,5340,7860
+ 5340,7860,5340,7960
+ 5340,7960,5440,8020
+ 5440,8020,5560,8020
+ 5560,8020,5720,8040
+ 5720,8040,5900,8060
+ 5900,8060,6080,8060
+ 6080,8060,6240,8060
+ 6720,8040,6840,8060
+ 6240,8060,6480,8040
+ 6480,8040,6720,8040
+ 6840,8060,6940,8060
+ 6940,8060,7080,8120
+ 7080,8120,7140,8180
+ 7140,8460,7140,8320
+ 7140,8620,7140,8460
+ 7140,8620,7140,8740
+ 7140,8860,7140,8740
+ 7140,8960,7140,8860
+ 7140,8960,7200,9080
+ 7140,9200,7200,9080
+ 7140,9200,7200,9320
+ 7200,9320,7200,9460
+ 7200,9760,7200,9900
+ 7200,9620,7200,9460
+ 7200,9620,7200,9760
+ 7200,9900,7200,10060
+ 7200,10220,7200,10060
+ 7200,10360,7200,10220
+ 7140,10400,7200,10360
+ 6880,10400,7140,10400
+ 6640,10360,6880,10400
+ 6420,10360,6640,10360
+ 6160,10380,6420,10360
+ 5940,10340,6160,10380
+ 5720,10320,5940,10340
+ 5500,10340,5720,10320
+ 5280,10300,5500,10340
+ 5080,10300,5280,10300
+ 4840,10280,5080,10300
+ 4700,10280,4840,10280
+ 4540,10280,4700,10280
+ 4360,10280,4540,10280
+ 4200,10300,4360,10280
+ 4040,10380,4200,10300
+ 4020,10500,4040,10380
+ 3980,10640,4020,10500
+ 3980,10640,3980,10760
+ 3980,10760,4020,10920
+ 4020,10920,4080,11000
+ 4080,11000,4340,11020
+ 4340,11020,4600,11060
+ 4600,11060,4840,11040
+ 4840,11040,4880,10960
+ 4880,10740,4880,10960
+ 4880,10740,4880,10600
+ 4880,10600,5080,10560
+ 5080,10560,5340,10620
+ 5340,10620,5660,10620
+ 5660,10620,6040,10600
+ 6040,10600,6120,10620
+ 6120,10620,6240,10720
+ 6240,10720,6420,10740
+ 6420,10740,6640,10760
+ 6640,10760,6880,10780
+ 7140,10780,7400,10780
+ 6880,10780,7140,10780
+ 7400,10780,7680,10780
+ 7680,10780,8100,10760
+ 8100,10760,8460,10740
+ 8460,10740,8700,10760
+ 8800,10840,8800,10980
+ 8700,10760,8800,10840
+ 8760,11200,8800,10980
+ 8760,11200,8760,11380
+ 8760,11380,8800,11560
+ 8760,11680,8800,11560
+ 8760,11760,8760,11680
+ 8760,11760,8760,11920
+ 8760,11920,8800,12080
+ 8800,12200,8800,12080
+ 8700,12240,8800,12200
+ 8560,12220,8700,12240
+ 8360,12220,8560,12220
+ 8160,12240,8360,12220
+ 7720,12220,7980,12220
+ 7980,12220,8160,12240
+ 7400,12200,7720,12220
+ 7200,12180,7400,12200
+ 7000,12160,7200,12180
+ 6800,12160,7000,12160
+ 6280,12140,6380,12180
+ 6120,12180,6280,12140
+ 6540,12180,6800,12160
+ 6380,12180,6540,12180
+ 5900,12200,6120,12180
+ 5620,12180,5900,12200
+ 5340,12120,5620,12180
+ 5140,12100,5340,12120
+ 4980,12120,5140,12100
+ 4840,12120,4980,12120
+ 4700,12200,4840,12120
+ 4700,12380,4700,12200
+ 4740,12480,4940,12520
+ 4700,12380,4740,12480
+ 4940,12520,5160,12560
+ 5160,12560,5340,12600
+ 5340,12600,5400,12600
+ 5400,12600,5500,12600
+ 5500,12600,5620,12600
+ 5620,12600,5720,12560
+ 5720,12560,5800,12440
+ 5800,12440,5900,12380
+ 5900,12380,6120,12420
+ 6120,12420,6380,12440
+ 6380,12440,6600,12460
+ 6720,12460,6840,12520
+ 6840,12520,6960,12520
+ 6600,12460,6720,12460
+ 6960,12520,7040,12500
+ 7040,12500,7140,12440
+ 7200,12440,7360,12500
+ 7360,12500,7600,12560
+ 7600,12560,7860,12600
+ 7860,12600,8060,12500
+ 8100,12500,8200,12340
+ 8200,12340,8360,12360
+ 8360,12360,8560,12400
+ 8560,12400,8660,12420
+ 8660,12420,8840,12400
+ 8840,12400,9000,12360
+ 9000,12360,9000,12360
+ 2900,4400,2900,4280
+ 900,7320,1000,7220
+ 2640,13040,2900,12920
+ 2900,12920,3160,12840
+ 3480,12760,3780,12620
+ 3780,12620,4020,12460
+ 4300,12360,4440,12260
+ 4020,12460,4300,12360
+ 3160,12840,3480,12760
+ 4440,12080,4440,12260
+ 4440,12080,4440,11880
+ 4440,11880,4440,11720
+ 4440,11720,4600,11720
+ 4600,11720,4760,11740
+ 4760,11740,4980,11760
+ 4980,11760,5160,11760
+ 5160,11760,5340,11780
+ 6000,11860,6120,11820
+ 5340,11780,5620,11820
+ 5620,11820,6000,11860
+ 6120,11820,6360,11820
+ 6360,11820,6640,11860
+ 6940,11920,7240,11940
+ 7240,11940,7520,11960
+ 7520,11960,7860,11960
+ 7860,11960,8100,11920
+ 8100,11920,8420,11940
+ 8420,11940,8460,11960
+ 8460,11960,8500,11860
+ 8460,11760,8500,11860
+ 8320,11720,8460,11760
+ 8160,11720,8320,11720
+ 7940,11720,8160,11720
+ 7720,11700,7940,11720
+ 7520,11680,7720,11700
+ 7320,11680,7520,11680
+ 7200,11620,7320,11680
+ 7200,11620,7200,11500
+ 7200,11500,7280,11440
+ 7280,11440,7420,11440
+ 7420,11440,7600,11440
+ 7600,11440,7980,11460
+ 7980,11460,8160,11460
+ 8160,11460,8360,11460
+ 8360,11460,8460,11400
+ 8420,11060,8500,11200
+ 8280,11040,8420,11060
+ 8100,11060,8280,11040
+ 8460,11400,8500,11200
+ 7800,11060,8100,11060
+ 7520,11060,7800,11060
+ 7240,11060,7520,11060
+ 6940,11040,7240,11060
+ 6640,11000,6940,11040
+ 6420,10980,6640,11000
+ 6360,11060,6420,10980
+ 6360,11180,6360,11060
+ 6200,11280,6360,11180
+ 5960,11300,6200,11280
+ 5720,11280,5960,11300
+ 5500,11280,5720,11280
+ 4940,11300,5200,11280
+ 4660,11260,4940,11300
+ 4440,11280,4660,11260
+ 4260,11280,4440,11280
+ 4220,11220,4260,11280
+ 4080,11280,4220,11220
+ 3980,11420,4080,11280
+ 3980,11420,4040,11620
+ 4040,11620,4040,11820
+ 3980,11960,4040,11820
+ 3840,12000,3980,11960
+ 3720,11940,3840,12000
+ 3680,11800,3720,11940
+ 3680,11580,3680,11800
+ 3680,11360,3680,11580
+ 3680,11360,3680,11260
+ 3680,11080,3680,11260
+ 3680,11080,3680,10880
+ 3680,10700,3680,10880
+ 3680,10700,3680,10620
+ 3680,10480,3680,10620
+ 3680,10480,3680,10300
+ 3680,10300,3680,10100
+ 3680,10100,3680,9940
+ 3680,9940,3720,9860
+ 3720,9860,3920,9900
+ 3920,9900,4220,9880
+ 4980,9940,5340,9960
+ 4220,9880,4540,9900
+ 4540,9900,4980,9940
+ 5340,9960,5620,9960
+ 5620,9960,5900,9960
+ 5900,9960,6160,10000
+ 6160,10000,6480,10000
+ 6480,10000,6720,10000
+ 6720,10000,6880,9860
+ 6880,9860,6880,9520
+ 6880,9520,6940,9340
+ 6940,9120,6940,9340
+ 6940,9120,6940,8920
+ 6940,8700,6940,8920
+ 6880,8500,6940,8700
+ 6880,8320,6880,8500
+ 7140,8320,7140,8180
+ 6760,8260,6880,8320
+ 6540,8240,6760,8260
+ 6420,8180,6540,8240
+ 6280,8240,6420,8180
+ 6160,8300,6280,8240
+ 6120,8400,6160,8300
+ 6080,8520,6120,8400
+ 5840,8480,6080,8520
+ 5620,8500,5840,8480
+ 5500,8500,5620,8500
+ 5340,8560,5500,8500
+ 5160,8540,5340,8560
+ 4620,8520,4880,8520
+ 4360,8480,4620,8520
+ 4880,8520,5160,8540
+ 4140,8440,4360,8480
+ 3920,8460,4140,8440
+ 3720,8380,3920,8460
+ 3680,8160,3720,8380
+ 3680,8160,3720,7940
+ 3720,7720,3720,7940
+ 3680,7580,3720,7720
+ 3680,7580,3720,7440
+ 3720,7440,3720,7300
+ 3720,7160,3720,7300
+ 3720,7160,3720,7020
+ 3720,7020,3780,6900
+ 3780,6900,4080,6940
+ 4080,6940,4340,6980
+ 4340,6980,4600,6980
+ 4600,6980,4880,6980
+ 4880,6980,5160,6980
+ 5160,6980,5400,7000
+ 5400,7000,5560,7020
+ 5560,7020,5660,7080
+ 5660,7080,5660,7280
+ 5660,7280,5660,7440
+ 5660,7440,5740,7520
+ 5740,7520,5740,7600
+ 5740,7600,5900,7600
+ 5900,7600,6040,7540
+ 6040,7540,6040,7320
+ 6040,7320,6120,7200
+ 6120,7200,6120,7040
+ 6120,7040,6240,7000
+ 6240,7000,6480,7060
+ 6480,7060,6800,7060
+ 6800,7060,7080,7080
+ 7080,7080,7320,7100
+ 7940,7100,7980,6920
+ 7860,6860,7980,6920
+ 7640,6860,7860,6860
+ 7400,6840,7640,6860
+ 7320,7100,7560,7120
+ 7560,7120,7760,7120
+ 7760,7120,7940,7100
+ 7200,6820,7400,6840
+ 7040,6820,7200,6820
+ 6600,6840,6840,6840
+ 6380,6800,6600,6840
+ 6120,6800,6380,6800
+ 5900,6840,6120,6800
+ 5620,6820,5900,6840
+ 5400,6800,5620,6820
+ 5140,6800,5400,6800
+ 4880,6780,5140,6800
+ 4600,6760,4880,6780
+ 4340,6760,4600,6760
+ 4080,6760,4340,6760
+ 3840,6740,4080,6760
+ 3680,6720,3840,6740
+ 3680,6720,3680,6560
+ 3680,6560,3720,6400
+ 3720,6400,3720,6200
+ 3720,6200,3780,6000
+ 3720,5780,3780,6000
+ 3720,5580,3720,5780
+ 3720,5360,3720,5580
+ 3720,5360,3840,5240
+ 3840,5240,4200,5260
+ 4200,5260,4600,5280
+ 4600,5280,4880,5280
+ 4880,5280,5140,5200
+ 5140,5200,5220,5100
+ 5220,5100,5280,4900
+ 5280,4900,5340,4840
+ 5340,4840,5720,4880
+ 6120,4880,6480,4860
+ 6880,4840,7200,4860
+ 6480,4860,6880,4840
+ 7200,4860,7320,4860
+ 7320,4860,7360,4740
+ 7360,4600,7440,4520
+ 7360,4600,7360,4740
+ 7440,4520,7640,4520
+ 7640,4520,7800,4480
+ 7800,4480,7800,4280
+ 7800,4280,7800,4040
+ 7800,4040,7800,3780
+ 7800,3560,7800,3780
+ 7800,3560,7860,3440
+ 7860,3440,8060,3460
+ 8060,3460,8160,3340
+ 8160,3340,8160,3140
+ 8160,3140,8160,2960
+ 8000,2900,8160,2960
+ 7860,2900,8000,2900
+ 7640,2940,7860,2900
+ 7400,2980,7640,2940
+ 7100,2980,7400,2980
+ 6840,3000,7100,2980
+ 5620,2980,5840,2980
+ 5840,2980,6500,3000
+ 6500,3000,6840,3000
+ 5560,2780,5620,2980
+ 5560,2780,5560,2580
+ 5560,2580,5560,2380
+ 5560,2140,5560,2380
+ 5560,2140,5560,1900
+ 5560,1900,5620,1660
+ 5620,1660,5660,1460
+ 5660,1460,5660,1300
+ 5500,1260,5660,1300
+ 5340,1260,5500,1260
+ 4600,1220,4840,1240
+ 4440,1220,4600,1220
+ 4440,1080,4440,1220
+ 4440,1080,4600,1020
+ 5080,1260,5340,1260
+ 4840,1240,5080,1260
+ 4600,1020,4940,1020
+ 4940,1020,5220,1020
+ 5220,1020,5560,960
+ 5560,960,5660,860
+ 5660,740,5660,860
+ 5280,740,5660,740
+ 4940,780,5280,740
+ 4660,760,4940,780
+ 4500,700,4660,760
+ 4500,520,4500,700
+ 4500,520,4700,460
+ 4700,460,5080,440
+ 5440,420,5740,420
+ 5080,440,5440,420
+ 5740,420,5840,360
+ 5800,280,5840,360
+ 5560,280,5800,280
+ 4980,300,5280,320
+ 4360,320,4660,300
+ 4200,360,4360,320
+ 5280,320,5560,280
+ 4660,300,4980,300
+ 4140,480,4200,360
+ 4140,480,4140,640
+ 4140,640,4200,780
+ 4200,780,4200,980
+ 4200,980,4220,1180
+ 4220,1400,4220,1180
+ 4220,1400,4260,1540
+ 4260,1540,4500,1540
+ 4500,1540,4700,1520
+ 4700,1520,4980,1540
+ 5280,1560,5400,1560
+ 4980,1540,5280,1560
+ 5400,1560,5400,1700
+ 5400,1780,5400,1700
+ 5340,1900,5400,1780
+ 5340,2020,5340,1900
+ 5340,2220,5340,2020
+ 5340,2220,5340,2420
+ 5340,2420,5340,2520
+ 5080,2600,5220,2580
+ 5220,2580,5340,2520
+ 4900,2580,5080,2600
+ 4700,2540,4900,2580
+ 4500,2540,4700,2540
+ 4220,2580,4340,2540
+ 4200,2700,4220,2580
+ 4340,2540,4500,2540
+ 3980,2740,4200,2700
+ 3840,2740,3980,2740
+ 3780,2640,3840,2740
+ 3780,2640,3780,2460
+ 3780,2280,3780,2460
+ 3620,2020,3780,2100
+ 3780,2280,3780,2100
+ 3360,2040,3620,2020
+ 3080,2040,3360,2040
+ 2840,2020,3080,2040
+ 2740,1940,2840,2020
+ 2740,1940,2800,1800
+ 2800,1640,2800,1800
+ 2800,1640,2800,1460
+ 2800,1300,2800,1460
+ 2700,1180,2800,1300
+ 2480,1140,2700,1180
+ 1580,1200,1720,1200
+ 2240,1180,2480,1140
+ 1960,1180,2240,1180
+ 1720,1200,1960,1180
+ 1500,1320,1580,1200
+ 1500,1440,1500,1320
+ 1500,1440,1760,1480
+ 1760,1480,1940,1480
+ 1940,1480,2140,1500
+ 2140,1500,2320,1520
+ 2400,1560,2400,1700
+ 2280,1820,2380,1780
+ 2320,1520,2400,1560
+ 2380,1780,2400,1700
+ 2080,1840,2280,1820
+ 1720,1820,2080,1840
+ 1420,1800,1720,1820
+ 1280,1800,1420,1800
+ 1240,1720,1280,1800
+ 1240,1720,1240,1600
+ 1240,1600,1280,1480
+ 1280,1340,1280,1480
+ 1180,1280,1280,1340
+ 1000,1280,1180,1280
+ 760,1280,1000,1280
+ 360,1240,540,1260
+ 180,1220,360,1240
+ 540,1260,760,1280
+ 180,1080,180,1220
+ 180,1080,180,1000
+ 180,1000,360,940
+ 360,940,540,960
+ 540,960,820,980
+ 1100,980,1200,920
+ 820,980,1100,980
+ 6640,11860,6940,11920
+ 5200,11280,5500,11280
+ 4120,7330,4120,7230
+ 4120,7230,4660,7250
+ 4660,7250,4940,7250
+ 4940,7250,5050,7340
+ 5010,7400,5050,7340
+ 4680,7380,5010,7400
+ 4380,7370,4680,7380
+ 4120,7330,4360,7370
+ 4120,7670,4120,7760
+ 4120,7670,4280,7650
+ 4280,7650,4540,7660
+ 4550,7660,4820,7680
+ 4820,7680,4900,7730
+ 4880,7800,4900,7730
+ 4620,7820,4880,7800
+ 4360,7790,4620,7820
+ 4120,7760,4360,7790
+ 6840,6840,7040,6820
+ 5720,4880,6120,4880
+ 1200,920,1340,810
+ 1340,810,1520,790
+ 1520,790,1770,800
+ 2400,790,2600,750
+ 2600,750,2640,520
+ 2520,470,2640,520
+ 2140,470,2520,470
+ 1760,800,2090,800
+ 2080,800,2400,790
+ 1760,450,2140,470
+ 1420,450,1760,450
+ 1180,440,1420,450
+ 900,480,1180,440
+ 640,450,900,480
+ 360,440,620,450
+ 120,430,360,440
+ 0,520,120,430
+ -20,780,0,520
+ -20,780,-20,1020
+ -20,1020,-20,1150
+ -20,1150,0,1300
+ 0,1470,60,1530
+ 0,1300,0,1470
+ 60,1530,360,1530
+ 360,1530,660,1520
+ 660,1520,980,1520
+ 980,1520,1040,1520
+ 1040,1520,1070,1560
+ 1070,1770,1070,1560
+ 1070,1770,1100,2010
+ 1070,2230,1100,2010
+ 1070,2240,1180,2340
+ 1180,2340,1580,2340
+ 1580,2340,1940,2350
+ 1940,2350,2440,2350
+ 2440,2350,2560,2380
+ 2560,2380,2600,2540
+ 2810,2640,3140,2680
+ 2600,2540,2810,2640
+ 3140,2680,3230,2780
+ 3230,2780,3260,2970
+ 3230,3220,3260,2970
+ 3200,3470,3230,3220
+ 3200,3480,3210,3760
+ 3210,3760,3210,4040
+ 3200,4040,3230,4310
+ 3210,4530,3230,4310
+ 3210,4530,3230,4730
+ 3230,4960,3230,4730
+ 3230,4960,3260,5190
+ 3170,5330,3260,5190
+ 2920,5330,3170,5330
+ 2660,5360,2920,5330
+ 2420,5330,2660,5360
+ 2200,5280,2400,5330
+ 2020,5280,2200,5280
+ 1840,5260,2020,5280
+ 1660,5280,1840,5260
+ 1500,5300,1660,5280
+ 1360,5270,1500,5300
+ 1200,5290,1340,5270
+ 1070,5400,1200,5290
+ 1040,5630,1070,5400
+ 1000,5900,1040,5630
+ 980,6170,1000,5900
+ 980,6280,980,6170
+ 980,6540,980,6280
+ 980,6540,1040,6720
+ 1040,6720,1360,6730
+ 1360,6730,1760,6710
+ 2110,6720,2420,6730
+ 1760,6710,2110,6720
+ 2420,6730,2640,6720
+ 2640,6720,2970,6720
+ 2970,6720,3160,6700
+ 3160,6700,3240,6710
+ 3240,6710,3260,6890
+ 3260,7020,3260,6890
+ 3230,7180,3260,7020
+ 3230,7350,3230,7180
+ 3210,7510,3230,7350
+ 3210,7510,3210,7690
+ 3210,7870,3210,7690
+ 3210,7870,3210,7980
+ 3200,8120,3210,7980
+ 3200,8330,3200,8120
+ 3160,8520,3200,8330
+ 2460,11100,2480,11020
+ 2200,11180,2460,11100
+ 1260,11350,1600,11320
+ 600,11430,930,11400
+ 180,11340,620,11430
+ 1600,11320,1910,11280
+ 1910,11280,2200,11180
+ 923.0029599285435,11398.99893503157,1264.002959928544,11351.99893503157
+#+end_src
+
+* Platformer - The Little Probe - Data - level_lava.txt
+#+begin_src ruby
+ # ./samples/99_genre_platformer/the_little_probe/data/level_lava.txt
+ 100,10740,500,10780
+ 500,10780,960,10760
+ 960,10760,1340,10760
+ 1380,10760,1820,10780
+ 1820,10780,2240,10780
+ 2280,10780,2740,10740
+ 2740,10740,3000,10780
+ 3000,10780,3140,11020
+ -520,8820,-480,9160
+ -520,8480,-520,8820
+ -520,8480,-480,8180
+ -480,8180,-200,8120
+ -200,8120,100,8220
+ 100,8220,420,8240
+ 420,8240,760,8260
+ 760,8260,1140,8280
+ 1140,8280,1500,8200
+ 1500,8200,1880,8240
+ 1880,8240,2240,8260
+ 2240,8260,2320,8480
+ 2320,8480,2380,8680
+ 2240,8860,2380,8680
+ 2240,9080,2240,8860
+ 2240,9080,2320,9260
+ 2320,9260,2480,9440
+ 2480,9440,2600,9640
+ 2480,9840,2600,9640
+ 2400,10020,2480,9840
+ 2240,10080,2400,10020
+ 1960,10080,2240,10080
+ 1720,10080,1960,10080
+ 1460,10080,1720,10080
+ 1180,10080,1420,10080
+ 900,10080,1180,10080
+ 640,10080,900,10080
+ 640,10080,640,9900
+ 60,10520,100,10740
+ 40,10240,60,10520
+ 40,10240,40,9960
+ 40,9960,40,9680
+ 40,9680,40,9360
+ 40,9360,60,9080
+ 60,9080,100,8860
+ 100,8860,460,9040
+ 460,9040,760,9220
+ 760,9220,1140,9220
+ 1140,9220,1720,9200
+ -660,11580,-600,11420
+ -660,11800,-660,11580
+ -660,12000,-660,11800
+ -660,12000,-600,12220
+ -600,12220,-600,12440
+ -600,12440,-600,12640
+ -600,11240,-260,11280
+ -260,11280,100,11240
+ 9000,12360,9020,12400
+ 9020,12620,9020,12400
+ 9020,12840,9020,12620
+ 9020,13060,9020,12840
+ 9020,13060,9020,13240
+ 9020,13240,9020,13420
+ 9020,13420,9020,13600
+ 9020,13600,9020,13780
+ 8880,13900,9020,13780
+ 8560,13800,8880,13900
+ 8220,13780,8560,13800
+ 7860,13760,8220,13780
+ 7640,13780,7860,13760
+ 7360,13800,7640,13780
+ 7100,13800,7360,13800
+ 6540,13760,6800,13780
+ 6800,13780,7100,13800
+ 6280,13760,6540,13760
+ 5760,13760,6280,13760
+ 5220,13780,5760,13760
+ 4700,13760,5220,13780
+ 4200,13740,4700,13760
+ 3680,13720,4200,13740
+ 3140,13700,3680,13720
+ 2600,13680,3140,13700
+ 2040,13940,2600,13680
+ 1640,13940,2040,13940
+ 1200,13960,1640,13940
+ 840,14000,1200,13960
+ 300,13960,840,14000
+ -200,13900,300,13960
+ -600,12840,-600,12640
+ -600,13140,-600,12840
+ -600,13140,-600,13420
+ -600,13700,-600,13420
+ -600,13700,-600,13820
+ -600,13820,-200,13900
+ -600,11240,-560,11000
+ -560,11000,-480,10840
+ -520,10660,-480,10840
+ -520,10660,-520,10480
+ -520,10480,-520,10300
+ -520,10260,-480,10080
+ -480,9880,-440,10060
+ -520,9680,-480,9880
+ -520,9680,-480,9400
+ -480,9400,-480,9160
+ 1820,9880,2140,9800
+ 1540,9880,1820,9880
+ 1200,9920,1500,9880
+ 900,9880,1200,9920
+ 640,9900,840,9880
+ 2380,8760,2800,8760
+ 2800,8760,2840,8660
+ 2840,8660,2840,8420
+ 2840,8160,2840,8420
+ 2800,7900,2840,8160
+ 2800,7900,2800,7720
+ 2800,7540,2800,7720
+ 2800,7540,2800,7360
+ 2700,7220,2800,7360
+ 2400,7220,2700,7220
+ 2080,7240,2400,7220
+ 1760,7320,2080,7240
+ 1380,7360,1720,7320
+ 1040,7400,1340,7360
+ 640,7400,1000,7420
+ 300,7380,640,7400
+ 0,7300,240,7380
+ -300,7180,-60,7300
+ -380,6860,-360,7180
+ -380,6880,-360,6700
+ -360,6700,-260,6540
+ -260,6540,0,6520
+ 0,6520,240,6640
+ 240,6640,460,6640
+ 460,6640,500,6480
+ 500,6260,500,6480
+ 460,6060,500,6260
+ 460,5860,460,6060
+ 460,5860,500,5640
+ 500,5640,540,5440
+ 540,5440,580,5220
+ 580,5220,580,5000
+ 580,4960,580,4740
+ 580,4740,960,4700
+ 960,4700,1140,4760
+ 1140,4760,1420,4740
+ 1420,4740,1720,4700
+ 1720,4700,2000,4740
+ 2000,4740,2380,4760
+ 2380,4760,2700,4800
+ 1720,4600,1760,4300
+ 1760,4300,2200,4340
+ 2200,4340,2560,4340
+ 2560,4340,2740,4340
+ 2160,12580,2440,12400
+ 1820,12840,2160,12580
+ 1500,13080,1820,12840
+ 1140,13340,1500,13080
+ 1140,13340,1580,13220
+ 2110,13080,2520,13000
+ 2520,13000,2900,12800
+ 1580,13220,2110,13080
+ 2900,12800,3200,12680
+ 3200,12680,3440,12640
+ 3440,12640,3720,12460
+ 3720,12460,4040,12320
+ 4040,12320,4360,12200
+ 4360,11940,4380,12180
+ 4360,11700,4360,11940
+ 4360,11700,4540,11500
+ 4540,11500,4880,11540
+ 6000,11660,6280,11640
+ 5440,11600,5720,11610
+ 5720,11610,6000,11660
+ 6280,11640,6760,11720
+ 6760,11720,7060,11780
+ 7060,11780,7360,11810
+ 7360,11810,7640,11840
+ 7640,11840,8000,11830
+ 8000,11830,8320,11850
+ 8320,11850,8390,11800
+ 8330,11760,8390,11800
+ 8160,11760,8330,11760
+ 7910,11750,8160,11760
+ 7660,11740,7900,11750
+ 7400,11730,7660,11740
+ 7160,11680,7400,11730
+ 7080,11570,7160,11680
+ 7080,11570,7100,11350
+ 7100,11350,7440,11280
+ 7440,11280,7940,11280
+ 7960,11280,8360,11280
+ 5840,11540,6650,11170
+ 4880,11540,5440,11600
+ 3410,11830,3420,11300
+ 3410,11260,3520,10920
+ 3520,10590,3520,10920
+ 3520,10590,3540,10260
+ 3520,9900,3540,10240
+ 3520,9900,3640,9590
+ 3640,9570,4120,9590
+ 4140,9590,4600,9680
+ 4620,9680,5030,9730
+ 5120,9750,5520,9800
+ 5620,9820,6080,9800
+ 6130,9810,6580,9820
+ 6640,9820,6800,9700
+ 6780,9400,6800,9700
+ 6780,9400,6840,9140
+ 6820,8860,6840,9120
+ 6780,8600,6820,8830
+ 6720,8350,6780,8570
+ 6480,8340,6720,8320
+ 6260,8400,6480,8340
+ 6050,8580,6240,8400
+ 5760,8630,6040,8590
+ 5520,8690,5740,8630
+ 5120,8690,5450,8700
+ 4570,8670,5080,8690
+ 4020,8610,4540,8670
+ 3540,8480,4020,8610
+ 3520,8230,3520,8480
+ 3520,7930,3520,8230
+ 3520,7930,3540,7630
+ 3480,7320,3540,7610
+ 3480,7280,3500,7010
+ 3500,6980,3680,6850
+ 3680,6850,4220,6840
+ 4230,6840,4760,6850
+ 4780,6850,5310,6860
+ 5310,6860,5720,6940
+ 5720,6940,5880,7250
+ 5880,7250,5900,7520
+ 100,11240,440,11300
+ 440,11300,760,11330
+ 1480,11280,1840,11230
+ 2200,11130,2360,11090
+ 1840,11230,2200,11130
+#+end_src
+
+* Rpg Narrative - Choose Your Own Adventure - decision.rb
+#+begin_src ruby
+ # ./samples/99_genre_rpg_narrative/choose_your_own_adventure/app/decision.rb
+ # Hey there! Welcome to Four Decisions. Here is how you
+ # create your decision tree. Remove =being and =end from the text to
+ # enable the game (just save the file). Change stuff and see what happens!
+
+ def game
+ {
+ starting_decision: :stormy_night,
+ decisions: {
+ stormy_night: {
+ description: 'It was a dark and stormy night. (storyline located in decision.rb)',
+ option_one: {
+ description: 'Go to sleep.',
+ decision: :nap
+ },
+ option_two: {
+ description: 'Watch a movie.',
+ decision: :movie
+ },
+ option_three: {
+ description: 'Go outside.',
+ decision: :go_outside
+ },
+ option_four: {
+ description: 'Get a snack.',
+ decision: :get_a_snack
+ }
+ },
+ nap: {
+ description: 'You took a nap. The end.',
+ option_one: {
+ description: 'Start over.',
+ decision: :stormy_night
+ }
+ }
+ }
+ }
+ end
+
+#+end_src
+
+* Rpg Narrative - Choose Your Own Adventure - main.rb
+#+begin_src ruby
+ # ./samples/99_genre_rpg_narrative/choose_your_own_adventure/app/main.rb
+ =begin
+
+ Reminders:
+
+ - Hashes: Collection of unique keys and their corresponding values. The values can be found
+ using their keys.
+
+ In this sample app, the decisions needed for the game are stored in a hash. In fact, the
+ decision.rb file contains hashes inside of other hashes!
+
+ Each option is a key in the first hash, but also contains a hash (description and
+ decision being its keys) as its value.
+ Go into the decision.rb file and take a look before diving into the code below.
+
+ - args.outputs.labels: An array. The values generate a label.
+ The parameters are [X, Y, TEXT, SIZE, ALIGNMENT, RED, GREEN, BLUE, ALPHA, FONT STYLE]
+ For more information about labels, go to mygame/documentation/02-labels.md.
+
+ - args.keyboard.key_down.KEY: Determines if a key is in the down state or pressed down.
+ For more information about the keyboard, go to mygame/documentation/06-keyboard.md.
+
+ - String interpolation: uses #{} syntax; everything between the #{ and the } is evaluated
+ as Ruby code, and the placeholder is replaced with its corresponding value or result.
+
+ =end
+
+ # This sample app provides users with a story and multiple decisions that they can choose to make.
+ # Users can make a decision using their keyboard, and the story will move forward based on user choices.
+
+ # The decisions available to users are stored in the decision.rb file.
+ # We must have access to it for the game to function properly.
+ GAME_FILE = 'app/decision.rb' # found in app folder
+
+ require GAME_FILE # require used to load another file, import class/method definitions
+
+ # Instructions are given using labels to users if they have not yet set up their story in the decision.rb file.
+ # Otherwise, the game is run.
+ def tick args
+ if !args.state.loaded && !respond_to?(:game) # if game is not loaded and not responding to game symbol's method
+ args.labels << [640, 370, 'Hey there! Welcome to Four Decisions.', 0, 1] # a welcome label is shown
+ args.labels << [640, 340, 'Go to the file called decision.rb and tell me your story.', 0, 1]
+ elsif respond_to?(:game) # otherwise, if responds to game
+ args.state.loaded = true
+ tick_game args # calls tick_game method, runs game
+ end
+
+ if args.state.tick_count.mod_zero? 60 # update every 60 frames
+ t = args.gtk.ffi_file.mtime GAME_FILE # mtime returns modification time for named file
+ if t != args.state.mtime
+ args.state.mtime = t
+ require GAME_FILE # require used to load file
+ args.state.game_definition = nil # game definition and decision are empty
+ args.state.decision_id = nil
+ end
+ end
+ end
+
+ # Runs methods needed for game to function properly
+ # Creates a rectangular border around the screen
+ def tick_game args
+ defaults args
+ args.borders << args.grid.rect
+ render_decision args
+ process_inputs args
+ end
+
+ # Sets default values and uses decision.rb file to define game and decision_id
+ # variable using the starting decision
+ def defaults args
+ args.state.game_definition ||= game
+ args.state.decision_id ||= args.state.game_definition[:starting_decision]
+ end
+
+ # Outputs the possible decision descriptions the user can choose onto the screen
+ # as well as what key to press on their keyboard to make their decision
+ def render_decision args
+ decision = current_decision args
+ # text is either the value of decision's description key or warning that no description exists
+ args.labels << [640, 360, decision[:description] || "No definition found for #{args.state.decision_id}. Please update decision.rb.", 0, 1] # uses string interpolation
+
+ # All decisions are stored in a hash
+ # The descriptions output onto the screen are the values for the description keys of the hash.
+ if decision[:option_one]
+ args.labels << [10, 360, decision[:option_one][:description], 0, 0] # option one's description label
+ args.labels << [10, 335, "(Press 'left' on the keyboard to select this decision)", -5, 0] # label of what key to press to select the decision
+ end
+
+ if decision[:option_two]
+ args.labels << [1270, 360, decision[:option_two][:description], 0, 2] # option two's description
+ args.labels << [1270, 335, "(Press 'right' on the keyboard to select this decision)", -5, 2]
+ end
+
+ if decision[:option_three]
+ args.labels << [640, 45, decision[:option_three][:description], 0, 1] # option three's description
+ args.labels << [640, 20, "(Press 'down' on the keyboard to select this decision)", -5, 1]
+ end
+
+ if decision[:option_four]
+ args.labels << [640, 700, decision[:option_four][:description], 0, 1] # option four's description
+ args.labels << [640, 675, "(Press 'up' on the keyboard to select this decision)", -5, 1]
+ end
+ end
+
+ # Uses keyboard input from the user to make a decision
+ # Assigns the decision as the value of the decision_id variable
+ def process_inputs args
+ decision = current_decision args # calls current_decision method
+
+ if args.keyboard.key_down.left! && decision[:option_one] # if left key pressed and option one exists
+ args.state.decision_id = decision[:option_one][:decision] # value of option one's decision hash key is set to decision_id
+ end
+
+ if args.keyboard.key_down.right! && decision[:option_two] # if right key pressed and option two exists
+ args.state.decision_id = decision[:option_two][:decision] # value of option two's decision hash key is set to decision_id
+ end
+
+ if args.keyboard.key_down.down! && decision[:option_three] # if down key pressed and option three exists
+ args.state.decision_id = decision[:option_three][:decision] # value of option three's decision hash key is set to decision_id
+ end
+
+ if args.keyboard.key_down.up! && decision[:option_four] # if up key pressed and option four exists
+ args.state.decision_id = decision[:option_four][:decision] # value of option four's decision hash key is set to decision_id
+ end
+ end
+
+ # Uses decision_id's value to keep track of current decision being made
+ def current_decision args
+ args.state.game_definition[:decisions][args.state.decision_id] || {} # either has value or is empty
+ end
+
+ # Resets the game.
+ $gtk.reset
+
+#+end_src
+
+* Rpg Narrative - Return Of Serenity - lowrez_simulator.rb
+#+begin_src ruby
+ # ./samples/99_genre_rpg_narrative/return_of_serenity/app/lowrez_simulator.rb
+ ###################################################################################
+ # YOU CAN PLAY AROUND WITH THE CODE BELOW, BUT USE CAUTION AS THIS IS WHAT EMULATES
+ # THE 64x64 CANVAS.
+ ###################################################################################
+
+ TINY_RESOLUTION = 64
+ TINY_SCALE = 720.fdiv(TINY_RESOLUTION + 5)
+ CENTER_OFFSET = 10
+ EMULATED_FONT_SIZE = 20
+ EMULATED_FONT_X_ZERO = 0
+ EMULATED_FONT_Y_ZERO = 46
+
+ def tick args
+ sprites = []
+ labels = []
+ borders = []
+ solids = []
+ mouse = emulate_lowrez_mouse args
+ args.state.show_gridlines = false
+ lowrez_tick args, sprites, labels, borders, solids, mouse
+ render_gridlines_if_needed args
+ render_mouse_crosshairs args, mouse
+ emulate_lowrez_scene args, sprites, labels, borders, solids, mouse
+ end
+
+ def emulate_lowrez_mouse args
+ args.state.new_entity_strict(:lowrez_mouse) do |m|
+ m.x = args.mouse.x.idiv(TINY_SCALE) - CENTER_OFFSET.idiv(TINY_SCALE) - 1
+ m.y = args.mouse.y.idiv(TINY_SCALE)
+ if args.mouse.click
+ m.click = [
+ args.mouse.click.point.x.idiv(TINY_SCALE) - CENTER_OFFSET.idiv(TINY_SCALE) - 1,
+ args.mouse.click.point.y.idiv(TINY_SCALE)
+ ]
+ m.down = m.click
+ else
+ m.click = nil
+ m.down = nil
+ end
+
+ if args.mouse.up
+ m.up = [
+ args.mouse.up.point.x.idiv(TINY_SCALE) - CENTER_OFFSET.idiv(TINY_SCALE) - 1,
+ args.mouse.up.point.y.idiv(TINY_SCALE)
+ ]
+ else
+ m.up = nil
+ end
+ end
+ end
+
+ def render_mouse_crosshairs args, mouse
+ return unless args.state.show_gridlines
+ args.labels << [10, 25, "mouse: #{mouse.x} #{mouse.y}", 255, 255, 255]
+ end
+
+ def emulate_lowrez_scene args, sprites, labels, borders, solids, mouse
+ args.render_target(:lowrez).solids << [0, 0, 1280, 720]
+ args.render_target(:lowrez).sprites << sprites
+ args.render_target(:lowrez).borders << borders
+ args.render_target(:lowrez).solids << solids
+ args.outputs.primitives << labels.map do |l|
+ as_label = l.label
+ l.text.each_char.each_with_index.map do |char, i|
+ [CENTER_OFFSET + EMULATED_FONT_X_ZERO + (as_label.x * TINY_SCALE) + i * 5 * TINY_SCALE,
+ EMULATED_FONT_Y_ZERO + (as_label.y * TINY_SCALE), char,
+ EMULATED_FONT_SIZE, 0, as_label.r, as_label.g, as_label.b, as_label.a, 'fonts/dragonruby-gtk-4x4.ttf'].label
+ end
+ end
+
+ args.sprites << [CENTER_OFFSET, 0, 1280 * TINY_SCALE, 720 * TINY_SCALE, :lowrez]
+ end
+
+ def render_gridlines_if_needed args
+ if args.state.show_gridlines && args.static_lines.length == 0
+ args.static_lines << 65.times.map do |i|
+ [
+ [CENTER_OFFSET + i * TINY_SCALE + 1, 0,
+ CENTER_OFFSET + i * TINY_SCALE + 1, 720, 128, 128, 128],
+ [CENTER_OFFSET + i * TINY_SCALE, 0,
+ CENTER_OFFSET + i * TINY_SCALE, 720, 128, 128, 128],
+ [CENTER_OFFSET, 0 + i * TINY_SCALE,
+ CENTER_OFFSET + 720, 0 + i * TINY_SCALE, 128, 128, 128],
+ [CENTER_OFFSET, 1 + i * TINY_SCALE,
+ CENTER_OFFSET + 720, 1 + i * TINY_SCALE, 128, 128, 128]
+ ]
+ end
+ elsif !args.state.show_gridlines
+ args.static_lines.clear
+ end
+ end
+
+#+end_src
+
+* Rpg Narrative - Return Of Serenity - main.rb
+#+begin_src ruby
+ # ./samples/99_genre_rpg_narrative/return_of_serenity/app/main.rb
+ require 'app/require.rb'
+
+ def defaults args
+ args.outputs.background_color = [0, 0, 0]
+ args.state.last_story_line_text ||= ""
+ args.state.scene_history ||= []
+ args.state.storyline_history ||= []
+ args.state.word_delay ||= 8
+ if args.state.tick_count == 0
+ args.gtk.stop_music
+ args.outputs.sounds << 'sounds/static-loop.ogg'
+ end
+
+ if args.state.last_story_line_text
+ lines = args.state
+ .last_story_line_text
+ .gsub("-", "")
+ .gsub("~", "")
+ .wrapped_lines(50)
+
+ args.outputs.labels << lines.map_with_index { |l, i| [690, 200 - (i * 25), l, 1, 0, 255, 255, 255] }
+ elsif args.state.storyline_history[-1]
+ lines = args.state
+ .storyline_history[-1]
+ .gsub("-", "")
+ .gsub("~", "")
+ .wrapped_lines(50)
+
+ args.outputs.labels << lines.map_with_index { |l, i| [690, 200 - (i * 25), l, 1, 0, 255, 255, 255] }
+ end
+
+ return if args.state.current_scene
+ set_scene(args, day_one_beginning(args))
+ end
+
+ def inputs_move_player args
+ if args.state.scene_changed_at.elapsed_time > 5
+ if args.keyboard.down || args.keyboard.s || args.keyboard.j
+ args.state.player.y -= 0.25
+ elsif args.keyboard.up || args.keyboard.w || args.keyboard.k
+ args.state.player.y += 0.25
+ end
+
+ if args.keyboard.left || args.keyboard.a || args.keyboard.h
+ args.state.player.x -= 0.25
+ elsif args.keyboard.right || args.keyboard.d || args.keyboard.l
+ args.state.player.x += 0.25
+ end
+
+ args.state.player.y = 60 if args.state.player.y > 63
+ args.state.player.y = 0 if args.state.player.y < -3
+ args.state.player.x = 60 if args.state.player.x > 63
+ args.state.player.x = 0 if args.state.player.x < -3
+ end
+ end
+
+ def null_or_empty? ary
+ return true unless ary
+ return true if ary.length == 0
+ return false
+ end
+
+ def calc_storyline_hotspot args
+ hotspots = args.state.storylines.find_all do |hs|
+ args.state.player.inside_rect?(hs.shift_rect(-2, 0))
+ end
+
+ if !null_or_empty?(hotspots) && !args.state.inside_storyline_hotspot
+ _, _, _, _, storyline = hotspots.first
+ queue_storyline_text(args, storyline)
+ args.state.inside_storyline_hotspot = true
+ elsif null_or_empty?(hotspots)
+ args.state.inside_storyline_hotspot = false
+
+ args.state.storyline_queue_empty_at ||= args.state.tick_count
+ args.state.is_storyline_dialog_active = false
+ args.state.scene_storyline_queue.clear
+ end
+ end
+
+ def calc_scenes args
+ hotspots = args.state.scenes.find_all do |hs|
+ args.state.player.inside_rect?(hs.shift_rect(-2, 0))
+ end
+
+ if !null_or_empty?(hotspots) && !args.state.inside_scene_hotspot
+ _, _, _, _, scene_method_or_hash = hotspots.first
+ if scene_method_or_hash.is_a? Symbol
+ set_scene(args, send(scene_method_or_hash, args))
+ args.state.last_hotspot_scene = scene_method_or_hash
+ args.state.scene_history << scene_method_or_hash
+ else
+ set_scene(args, scene_method_or_hash)
+ end
+ args.state.inside_scene_hotspot = true
+ elsif null_or_empty?(hotspots)
+ args.state.inside_scene_hotspot = false
+ end
+ end
+
+ def null_or_whitespace? word
+ return true if !word
+ return true if word.strip.length == 0
+ return false
+ end
+
+ def calc_storyline_presentation args
+ return unless args.state.tick_count > args.state.next_storyline
+ return unless args.state.scene_storyline_queue
+ next_storyline = args.state.scene_storyline_queue.shift
+ if null_or_whitespace? next_storyline
+ args.state.storyline_queue_empty_at ||= args.state.tick_count
+ args.state.is_storyline_dialog_active = false
+ return
+ end
+ args.state.storyline_to_show = next_storyline
+ args.state.is_storyline_dialog_active = true
+ args.state.storyline_queue_empty_at = nil
+ if next_storyline.end_with?(".") || next_storyline.end_with?("!") || next_storyline.end_with?("?") || next_storyline.end_with?("\"")
+ args.state.next_storyline += 60
+ elsif next_storyline.end_with?(",")
+ args.state.next_storyline += 50
+ elsif next_storyline.end_with?(":")
+ args.state.next_storyline += 60
+ else
+ default_word_delay = 13 + args.state.word_delay - 8
+ if next_storyline.gsub("-", "").gsub("~", "").length <= 4
+ default_word_delay = 11 + args.state.word_delay - 8
+ end
+ number_of_syllabals = next_storyline.length - next_storyline.gsub("-", "").length
+ args.state.next_storyline += default_word_delay + number_of_syllabals * (args.state.word_delay + 1)
+ end
+ end
+
+ def inputs_reload_current_scene args
+ return
+ if args.inputs.keyboard.key_down.r!
+ reload_current_scene
+ end
+ end
+
+ def inputs_dismiss_current_storyline args
+ if args.inputs.keyboard.key_down.x!
+ args.state.scene_storyline_queue.clear
+ end
+ end
+
+ def inputs_restart_game args
+ if args.inputs.keyboard.exclamation_point
+ args.gtk.reset_state
+ end
+ end
+
+ def inputs_change_word_delay args
+ if args.inputs.keyboard.key_down.plus || args.inputs.keyboard.key_down.equal_sign
+ args.state.word_delay -= 2
+ if args.state.word_delay < 0
+ args.state.word_delay = 0
+ # queue_storyline_text args, "Text speed at MAXIMUM. Geez, how fast do you read?"
+ else
+ # queue_storyline_text args, "Text speed INCREASED."
+ end
+ end
+
+ if args.inputs.keyboard.key_down.hyphen || args.inputs.keyboard.key_down.underscore
+ args.state.word_delay += 2
+ # queue_storyline_text args, "Text speed DECREASED."
+ end
+ end
+
+ def multiple_lines args, x, y, texts, size = 0, minimum_alpha = nil
+ texts.each_with_index.map do |t, i|
+ [x, y - i * (25 + size * 2), t, size, 0, 255, 255, 255, adornments_alpha(args, 255, minimum_alpha)]
+ end
+ end
+
+ def lowrez_tick args, lowrez_sprites, lowrez_labels, lowrez_borders, lowrez_solids, lowrez_mouse
+ # args.state.show_gridlines = true
+ defaults args
+ render_current_scene args, lowrez_sprites, lowrez_labels, lowrez_solids
+ render_controller args, lowrez_borders
+ lowrez_solids << [0, 0, 64, 64, 0, 0, 0]
+ calc_storyline_presentation args
+ calc_scenes args
+ calc_storyline_hotspot args
+ inputs_move_player args
+ inputs_print_mouse_rect args, lowrez_mouse
+ inputs_reload_current_scene args
+ inputs_dismiss_current_storyline args
+ inputs_change_word_delay args
+ inputs_restart_game args
+ end
+
+ def render_controller args, lowrez_borders
+ args.state.up_button = [85, 40, 15, 15, 255, 255, 255]
+ args.state.down_button = [85, 20, 15, 15, 255, 255, 255]
+ args.state.left_button = [65, 20, 15, 15, 255, 255, 255]
+ args.state.right_button = [105, 20, 15, 15, 255, 255, 255]
+ lowrez_borders << args.state.up_button
+ lowrez_borders << args.state.down_button
+ lowrez_borders << args.state.left_button
+ lowrez_borders << args.state.right_button
+ end
+
+ def inputs_print_mouse_rect args, lowrez_mouse
+ if lowrez_mouse.up
+ args.state.mouse_held = false
+ elsif lowrez_mouse.click
+ mouse_rect = [lowrez_mouse.x, lowrez_mouse.y, 1, 1]
+ if args.state.up_button.intersect_rect? mouse_rect
+ args.state.player.y += 1
+ end
+
+ if args.state.down_button.intersect_rect? mouse_rect
+ args.state.player.y -= 1
+ end
+
+ if args.state.left_button.intersect_rect? mouse_rect
+ args.state.player.x -= 1
+ end
+
+ if args.state.right_button.intersect_rect? mouse_rect
+ args.state.player.x += 1
+ end
+ args.state.mouse_held = true
+ elsif args.state.mouse_held
+ mouse_rect = [lowrez_mouse.x, lowrez_mouse.y, 1, 1]
+ if args.state.up_button.intersect_rect? mouse_rect
+ args.state.player.y += 0.25
+ end
+
+ if args.state.down_button.intersect_rect? mouse_rect
+ args.state.player.y -= 0.25
+ end
+
+ if args.state.left_button.intersect_rect? mouse_rect
+ args.state.player.x -= 0.25
+ end
+
+ if args.state.right_button.intersect_rect? mouse_rect
+ args.state.player.x += 0.25
+ end
+ end
+
+ if lowrez_mouse.click
+ dx = lowrez_mouse.click.x - args.state.previous_mouse_click.x
+ dy = lowrez_mouse.click.y - args.state.previous_mouse_click.y
+ x, y, w, h = args.state.previous_mouse_click.x, args.state.previous_mouse_click.y, dx, dy
+ puts "x #{lowrez_mouse.click.x}, y: #{lowrez_mouse.click.y}"
+ if args.state.previous_mouse_click
+
+ if dx < 0 && dx < 0
+ x = x + w
+ w = w.abs
+ y = y + h
+ h = h.abs
+ end
+
+ w += 1
+ h += 1
+
+ args.state.previous_mouse_click = nil
+ else
+ args.state.previous_mouse_click = lowrez_mouse.click
+ square_x, square_y = lowrez_mouse.click
+ end
+ end
+ end
+
+ def try_centering! word
+ word ||= ""
+ just_word = word.gsub("-", "").gsub(",", "").gsub(".", "").gsub("'", "").gsub('""', "\"-\"")
+ return word if just_word.strip.length == 0
+ return word if just_word.include? "~"
+ return "~#{word}" if just_word.length <= 2
+ if just_word.length.mod_zero? 2
+ center_index = just_word.length.idiv(2) - 1
+ else
+ center_index = (just_word.length - 1).idiv(2)
+ end
+ return "#{word[0..center_index - 1]}~#{word[center_index]}#{word[center_index + 1..-1]}"
+ end
+
+ def queue_storyline args, scene
+ queue_storyline_text args, scene[:storyline]
+ end
+
+ def queue_storyline_text args, text
+ args.state.last_story_line_text = text
+ args.state.storyline_history << text if text
+ words = (text || "").split(" ")
+ words = words.map { |w| try_centering! w }
+ args.state.scene_storyline_queue = words
+ if args.state.scene_storyline_queue.length != 0
+ args.state.scene_storyline_queue.unshift "~$--"
+ args.state.storyline_to_show = "~."
+ else
+ args.state.storyline_to_show = ""
+ end
+ args.state.scene_storyline_queue << ""
+ args.state.next_storyline = args.state.tick_count
+ end
+
+ def set_scene args, scene
+ args.state.current_scene = scene
+ args.state.background = scene[:background] || 'sprites/todo.png'
+ args.state.scene_fade = scene[:fade] || 0
+ args.state.scenes = (scene[:scenes] || []).reject { |s| !s }
+ args.state.scene_render_override = scene[:render_override]
+ args.state.storylines = (scene[:storylines] || []).reject { |s| !s }
+ args.state.scene_changed_at = args.state.tick_count
+ if scene[:player]
+ args.state.player = scene[:player]
+ end
+ args.state.inside_scene_hotspot = false
+ args.state.inside_storyline_hotspot = false
+ queue_storyline args, scene
+ end
+
+ def replay_storyline_rect
+ [26, -1, 7, 4]
+ end
+
+ def labels_for_word word
+ left_side_of_word = ""
+ center_letter = ""
+ right_side_of_word = ""
+
+ if word[0] == "~"
+ left_side_of_word = ""
+ center_letter = word[1]
+ right_side_of_word = word[2..-1]
+ elsif word.length > 0
+ left_side_of_word, right_side_of_word = word.split("~")
+ center_letter = right_side_of_word[0]
+ right_side_of_word = right_side_of_word[1..-1]
+ end
+
+ right_side_of_word = right_side_of_word.gsub("-", "")
+
+ {
+ left: [29 - left_side_of_word.length * 4 - 1 * left_side_of_word.length, 2, left_side_of_word],
+ center: [29, 2, center_letter, 255, 0, 0],
+ right: [34, 2, right_side_of_word]
+ }
+ end
+
+ def render_scenes args, lowrez_sprites
+ lowrez_sprites << args.state.scenes.flat_map do |hs|
+ hotspot_square args, hs.x, hs.y, hs.w, hs.h
+ end
+ end
+
+ def render_storylines args, lowrez_sprites
+ lowrez_sprites << args.state.storylines.flat_map do |hs|
+ hotspot_square args, hs.x, hs.y, hs.w, hs.h
+ end
+ end
+
+ def adornments_alpha args, target_alpha = nil, minimum_alpha = nil
+ return (minimum_alpha || 80) unless args.state.storyline_queue_empty_at
+ target_alpha ||= 255
+ target_alpha * args.state.storyline_queue_empty_at.ease(60)
+ end
+
+ def hotspot_square args, x, y, w, h
+ if w >= 3 && h >= 3
+ [
+ [x + w.idiv(2) + 1, y, w.idiv(2), h, 'sprites/label-background.png', 0, adornments_alpha(args, 50), 23, 23, 23],
+ [x, y, w.idiv(2), h, 'sprites/label-background.png', 0, adornments_alpha(args, 100), 223, 223, 223],
+ [x + 1, y + 1, w - 2, h - 2, 'sprites/label-background.png', 0, adornments_alpha(args, 200), 40, 140, 40],
+ ]
+ else
+ [
+ [x, y, w, h, 'sprites/label-background.png', 0, adornments_alpha(args, 200), 0, 140, 0],
+ ]
+ end
+ end
+
+ def render_storyline_dialog args, lowrez_labels, lowrez_sprites
+ return unless args.state.is_storyline_dialog_active
+ return unless args.state.storyline_to_show
+ labels = labels_for_word args.state.storyline_to_show
+ if true # high rez version
+ scale = 8.88
+ offset = 45
+ size = 25
+ args.outputs.labels << [offset + labels[:left].x.-(1) * scale,
+ labels[:left].y * TINY_SCALE + 55,
+ labels[:left].text, size, 0, 0, 0, 0, 255,
+ 'fonts/manaspc.ttf']
+ center_text = labels[:center].text
+ center_text = "|" if center_text == "$"
+ args.outputs.labels << [offset + labels[:center].x * scale,
+ labels[:center].y * TINY_SCALE + 55,
+ center_text, size, 0, 255, 0, 0, 255,
+ 'fonts/manaspc.ttf']
+ args.outputs.labels << [offset + labels[:right].x * scale,
+ labels[:right].y * TINY_SCALE + 55,
+ labels[:right].text, size, 0, 0, 0, 0, 255,
+ 'fonts/manaspc.ttf']
+ else
+ lowrez_labels << labels[:left]
+ lowrez_labels << labels[:center]
+ lowrez_labels << labels[:right]
+ end
+ args.state.is_storyline_dialog_active = true
+ render_player args, lowrez_sprites
+ lowrez_sprites << [0, 0, 64, 8, 'sprites/label-background.png']
+ end
+
+ def render_player args, lowrez_sprites
+ lowrez_sprites << player_md_down(args, *args.state.player)
+ end
+
+ def render_adornments args, lowrez_sprites
+ render_scenes args, lowrez_sprites
+ render_storylines args, lowrez_sprites
+ return if args.state.is_storyline_dialog_active
+ lowrez_sprites << player_md_down(args, *args.state.player)
+ end
+
+ def global_alpha_percentage args, max_alpha = 255
+ return 255 unless args.state.scene_changed_at
+ return 255 unless args.state.scene_fade
+ return 255 unless args.state.scene_fade > 0
+ return max_alpha * args.state.scene_changed_at.ease(args.state.scene_fade)
+ end
+
+ def render_current_scene args, lowrez_sprites, lowrez_labels, lowrez_solids
+ lowrez_sprites << [0, 0, 64, 64, args.state.background, 0, (global_alpha_percentage args)]
+ if args.state.scene_render_override
+ send args.state.scene_render_override, args, lowrez_sprites, lowrez_labels, lowrez_solids
+ end
+ storyline_to_show = args.state.storyline_to_show || ""
+ render_adornments args, lowrez_sprites
+ render_storyline_dialog args, lowrez_labels, lowrez_sprites
+
+ if args.state.background == 'sprites/tribute-game-over.png'
+ lowrez_sprites << [0, 0, 64, 11, 'sprites/label-background.png', 0, adornments_alpha(args, 200), 0, 0, 0]
+ lowrez_labels << [9, 6, 'Return of', 255, 255, 255]
+ lowrez_labels << [9, 1, ' Serenity', 255, 255, 255]
+ if !args.state.ended
+ args.gtk.stop_music
+ args.outputs.sounds << 'sounds/music-loop.ogg'
+ args.state.ended = true
+ end
+ end
+ end
+
+ def player_md_right args, x, y
+ [x, y, 4, 11, 'sprites/player-right.png', 0, (global_alpha_percentage args)]
+ end
+
+ def player_md_left args, x, y
+ [x, y, 4, 11, 'sprites/player-left.png', 0, (global_alpha_percentage args)]
+ end
+
+ def player_md_up args, x, y
+ [x, y, 4, 11, 'sprites/player-up.png', 0, (global_alpha_percentage args)]
+ end
+
+ def player_md_down args, x, y
+ [x, y, 4, 11, 'sprites/player-down.png', 0, (global_alpha_percentage args)]
+ end
+
+ def player_sm args, x, y
+ [x, y, 3, 7, 'sprites/player-zoomed-out.png', 0, (global_alpha_percentage args)]
+ end
+
+ def player_xs args, x, y
+ [x, y, 1, 4, 'sprites/player-zoomed-out.png', 0, (global_alpha_percentage args)]
+ end
+
+#+end_src
+
+* Rpg Narrative - Return Of Serenity - repl.rb
+#+begin_src ruby
+ # ./samples/99_genre_rpg_narrative/return_of_serenity/app/repl.rb
+ puts $gtk.args.state.current_scene
+
+#+end_src
+
+* Rpg Narrative - Return Of Serenity - require.rb
+#+begin_src ruby
+ # ./samples/99_genre_rpg_narrative/return_of_serenity/app/require.rb
+ require 'app/lowrez_simulator.rb'
+ require 'app/storyline_day_one.rb'
+ require 'app/storyline_blinking_light.rb'
+ require 'app/storyline_serenity_introduction.rb'
+ require 'app/storyline_speed_of_light.rb'
+ require 'app/storyline_serenity_alive.rb'
+ require 'app/storyline_serenity_bio.rb'
+ require 'app/storyline_anka.rb'
+ require 'app/storyline_final_message.rb'
+ require 'app/storyline_final_decision.rb'
+ require 'app/storyline.rb'
+
+#+end_src
+
+* Rpg Narrative - Return Of Serenity - storyline.rb
+#+begin_src ruby
+ # ./samples/99_genre_rpg_narrative/return_of_serenity/app/storyline.rb
+ def hotspot_top
+ [4, 61, 56, 3]
+ end
+
+ def hotspot_bottom
+ [4, 0, 56, 3]
+ end
+
+ def hotspot_top_right
+ [62, 35, 3, 25]
+ end
+
+ def hotspot_bottom_right
+ [62, 0, 3, 25]
+ end
+
+ def storyline_history_include? args, text
+ args.state.storyline_history.any? { |s| s.gsub("-", "").gsub(" ", "").include? text.gsub("-", "").gsub(" ", "") }
+ end
+
+ def blinking_light_side_of_home_render args, lowrez_sprites, lowrez_labels, lowrez_solids
+ lowrez_sprites << [48, 44, 5, 5, 'sprites/square.png', 0, 50 * (args.state.tick_count % 50).fdiv(50), 0, 255, 0]
+ lowrez_sprites << [49, 45, 3, 3, 'sprites/square.png', 0, 100 * (args.state.tick_count % 50).fdiv(50), 0, 255, 0]
+ lowrez_sprites << [50, 46, 1, 1, 'sprites/square.png', 0, 255 * (args.state.tick_count % 50).fdiv(50), 0, 255, 0]
+ end
+
+ def blinking_light_mountain_pass_render args, lowrez_sprites, lowrez_labels, lowrez_solids
+ lowrez_sprites << [18, 47, 5, 5, 'sprites/square.png', 0, 50 * (args.state.tick_count % 50).fdiv(50), 0, 255, 0]
+ lowrez_sprites << [19, 48, 3, 3, 'sprites/square.png', 0, 100 * (args.state.tick_count % 50).fdiv(50), 0, 255, 0]
+ lowrez_sprites << [20, 49, 1, 1, 'sprites/square.png', 0, 255 * (args.state.tick_count % 50).fdiv(50), 0, 255, 0]
+ end
+
+ def blinking_light_path_to_observatory_render args, lowrez_sprites, lowrez_labels, lowrez_solids
+ lowrez_sprites << [0, 26, 5, 5, 'sprites/square.png', 0, 50 * (args.state.tick_count % 50).fdiv(50), 0, 255, 0]
+ lowrez_sprites << [1, 27, 3, 3, 'sprites/square.png', 0, 100 * (args.state.tick_count % 50).fdiv(50), 0, 255, 0]
+ lowrez_sprites << [2, 28, 1, 1, 'sprites/square.png', 0, 255 * (args.state.tick_count % 50).fdiv(50), 0, 255, 0]
+ end
+
+ def blinking_light_observatory_render args, lowrez_sprites, lowrez_labels, lowrez_solids
+ lowrez_sprites << [23, 59, 5, 5, 'sprites/square.png', 0, 50 * (args.state.tick_count % 50).fdiv(50), 0, 255, 0]
+ lowrez_sprites << [24, 60, 3, 3, 'sprites/square.png', 0, 100 * (args.state.tick_count % 50).fdiv(50), 0, 255, 0]
+ lowrez_sprites << [25, 61, 1, 1, 'sprites/square.png', 0, 255 * (args.state.tick_count % 50).fdiv(50), 0, 255, 0]
+ end
+
+ def blinking_light_inside_observatory_render args, lowrez_sprites, lowrez_labels, lowrez_solids
+ lowrez_sprites << [30, 30, 5, 5, 'sprites/square.png', 0, 50 * (args.state.tick_count % 50).fdiv(50), 0, 255, 0]
+ lowrez_sprites << [31, 31, 3, 3, 'sprites/square.png', 0, 100 * (args.state.tick_count % 50).fdiv(50), 0, 255, 0]
+ lowrez_sprites << [32, 32, 1, 1, 'sprites/square.png', 0, 255 * (args.state.tick_count % 50).fdiv(50), 0, 255, 0]
+ end
+
+ def decision_graph context_message, context_action, context_result_one, context_result_two, context_result_three = [], context_result_four = []
+ result_one_scene, result_one_label, result_one_text = context_result_one
+ result_two_scene, result_two_label, result_two_text = context_result_two
+ result_three_scene, result_three_label, result_three_text = context_result_three
+ result_four_scene, result_four_label, result_four_text = context_result_four
+
+ top_level_hash = {
+ background: 'sprites/decision.png',
+ fade: 60,
+ player: [20, 36],
+ storylines: [ ],
+ scenes: [ ]
+ }
+
+ confirmation_result_one_hash = {
+ background: 'sprites/decision.png',
+ scenes: [ ],
+ storylines: [ ]
+ }
+
+ confirmation_result_two_hash = {
+ background: 'sprites/decision.png',
+ scenes: [ ],
+ storylines: [ ]
+ }
+
+ confirmation_result_three_hash = {
+ background: 'sprites/decision.png',
+ scenes: [ ],
+ storylines: [ ]
+ }
+
+ confirmation_result_four_hash = {
+ background: 'sprites/decision.png',
+ scenes: [ ],
+ storylines: [ ]
+ }
+
+ top_level_hash[:storylines] << [ 5, 35, 4, 4, context_message]
+ top_level_hash[:storylines] << [20, 35, 4, 4, context_action]
+
+ confirmation_result_one_hash[:scenes] << [20, 35, 4, 4, top_level_hash]
+ confirmation_result_one_hash[:scenes] << [60, 50, 4, 4, result_one_scene]
+ confirmation_result_one_hash[:storylines] << [40, 50, 4, 4, "#{result_one_label}: \"#{result_one_text}\""]
+ confirmation_result_one_hash[:scenes] << [40, 40, 4, 4, confirmation_result_four_hash] if result_four_scene
+ confirmation_result_one_hash[:scenes] << [40, 30, 4, 4, confirmation_result_three_hash] if result_three_scene
+ confirmation_result_one_hash[:scenes] << [40, 20, 4, 4, confirmation_result_two_hash]
+
+ confirmation_result_two_hash[:scenes] << [20, 35, 4, 4, top_level_hash]
+ confirmation_result_two_hash[:scenes] << [40, 50, 4, 4, confirmation_result_one_hash]
+ confirmation_result_two_hash[:scenes] << [40, 40, 4, 4, confirmation_result_four_hash] if result_four_scene
+ confirmation_result_two_hash[:scenes] << [40, 30, 4, 4, confirmation_result_three_hash] if result_three_scene
+ confirmation_result_two_hash[:scenes] << [60, 20, 4, 4, result_two_scene]
+ confirmation_result_two_hash[:storylines] << [40, 20, 4, 4, "#{result_two_label}: \"#{result_two_text}\""]
+
+ confirmation_result_three_hash[:scenes] << [20, 35, 4, 4, top_level_hash]
+ confirmation_result_three_hash[:scenes] << [40, 50, 4, 4, confirmation_result_one_hash]
+ confirmation_result_three_hash[:scenes] << [40, 40, 4, 4, confirmation_result_four_hash]
+ confirmation_result_three_hash[:scenes] << [60, 30, 4, 4, result_three_scene]
+ confirmation_result_three_hash[:storylines] << [40, 30, 4, 4, "#{result_three_label}: \"#{result_three_text}\""]
+ confirmation_result_three_hash[:scenes] << [40, 20, 4, 4, confirmation_result_two_hash]
+
+ confirmation_result_four_hash[:scenes] << [20, 35, 4, 4, top_level_hash]
+ confirmation_result_four_hash[:scenes] << [40, 50, 4, 4, confirmation_result_one_hash]
+ confirmation_result_four_hash[:scenes] << [60, 40, 4, 4, result_four_scene]
+ confirmation_result_four_hash[:storylines] << [40, 40, 4, 4, "#{result_four_label}: \"#{result_four_text}\""]
+ confirmation_result_four_hash[:scenes] << [40, 30, 4, 4, confirmation_result_three_hash]
+ confirmation_result_four_hash[:scenes] << [40, 20, 4, 4, confirmation_result_two_hash]
+
+ top_level_hash[:scenes] << [40, 50, 4, 4, confirmation_result_one_hash]
+ top_level_hash[:scenes] << [40, 40, 4, 4, confirmation_result_four_hash] if result_four_scene
+ top_level_hash[:scenes] << [40, 30, 4, 4, confirmation_result_three_hash] if result_three_scene
+ top_level_hash[:scenes] << [40, 20, 4, 4, confirmation_result_two_hash]
+
+ top_level_hash
+ end
+
+ def ship_control_hotspot offset_x, offset_y, a, b, c, d
+ results = []
+ results << [ 6 + offset_x, 0 + offset_y, 4, 4, a] if a
+ results << [ 1 + offset_x, 5 + offset_y, 4, 4, b] if b
+ results << [ 6 + offset_x, 5 + offset_y, 4, 4, c] if c
+ results << [ 11 + offset_x, 5 + offset_y, 4, 4, d] if d
+ results
+ end
+
+ def reload_current_scene
+ if $gtk.args.state.last_hotspot_scene
+ set_scene $gtk.args, send($gtk.args.state.last_hotspot_scene, $gtk.args)
+ tick $gtk.args
+ elsif respond_to? :set_scene
+ set_scene $gtk.args, (replied_to_serenity_alive_firmly $gtk.args)
+ tick $gtk.args
+ end
+ $gtk.console.close
+ end
+
+#+end_src
+
+* Rpg Narrative - Return Of Serenity - storyline_anka.rb
#+begin_src ruby
+ # ./samples/99_genre_rpg_narrative/return_of_serenity/app/storyline_anka.rb
+ def anka_inside_room args
+ {
+ background: 'sprites/inside-home.png',
+ player: [34, 35],
+ storylines: [
+ [34, 34, 4, 4, "Ahhhh!!! Oh god, it was just- a nightmare."],
+ ],
+ scenes: [
+ [32, -1, 8, 3, :anka_observatory]
+ ]
+ }
+ end
+
+ def anka_observatory args
+ {
+ background: 'sprites/inside-observatory.png',
+ fade: 60,
+ player: [51, 12],
+ storylines: [
+ [50, 10, 4, 4, "Breathe, Hiro. Just see what's there... everything--- will- be okay."]
+ ],
+ scenes: [
+ [30, 18, 5, 12, :anka_inside_mainframe]
+ ],
+ render_override: :blinking_light_inside_observatory_render
+ }
+ end
+
+ def anka_inside_mainframe args
+ {
+ player: [32, 4],
+ background: 'sprites/mainframe.png',
+ fade: 60,
+ storylines: [
+ [22, 45, 17, 4, (anka_last_reply args)],
+ [45, 45, 4, 4, (anka_current_reply args)],
+ ],
+ scenes: [
+ [*hotspot_top_right, :reply_to_anka]
+ ]
+ }
+ end
+
+ def reply_to_anka args
+ decision_graph anka_current_reply(args),
+ "Matthew's-- wife is doing-- well. What's-- even-- better-- is that he's-- a dad, and he didn't-- even-- know it. Should- I- leave- out the part about-- the crew- being-- in hibernation-- for 20-- years? They- should- enter-- statis-- on a high- note... Right?",
+ [:replied_with_whole_truth, "Whole-- Truth--", anka_reply_whole_truth],
+ [:replied_with_half_truth, "Half-- Truth--", anka_reply_half_truth]
+ end
+
+ def anka_last_reply args
+ if args.state.scene_history.include? :replied_to_serenity_alive_firmly
+ return "Buffer--: #{serenity_alive_firm_reply.quote}"
+ else
+ return "Buffer--: #{serenity_alive_sugarcoated_reply.quote}"
+ end
+ end
+
+ def anka_reply_whole_truth
+ "Matthew's wife is doing-- very-- well. In fact, she was pregnant. Matthew-- is a dad. He has a son. But, I need- all-- of-- you-- to brace-- yourselves. You've-- been in statis-- for 20 years. A lot has changed. Most of Earth's-- population--- didn't-- survive. Tell- Matthew-- that I'm-- sorry he didn't-- get to see- his- son grow- up."
+ end
+
+ def anka_reply_half_truth
+ "Matthew's--- wife- is doing-- very-- well. In fact, she was pregnant. Matthew is a dad! It's a boy! Tell- Matthew-- congrats-- for me. Hope-- to see- all of you- soon."
+ end
+
+ def replied_with_whole_truth args
+ {
+ background: 'sprites/inside-observatory.png',
+ fade: 60,
+ player: [32, 21],
+ scenes: [[60, 0, 4, 32, :replied_to_anka_back_home]],
+ storylines: [
+ [30, 18, 5, 12, "Buffer-- has been set to: #{anka_reply_whole_truth.quote}"],
+ [30, 10, 5, 4, "I- hope- I- did the right- thing- by laying-- it all- out- there."],
+ ]
+ }
+ end
+
+ def replied_with_half_truth args
+ {
+ background: 'sprites/inside-observatory.png',
+ fade: 60,
+ player: [32, 21],
+ scenes: [[60, 0, 4, 32, :replied_to_anka_back_home]],
+ storylines: [
+ [30, 18, 5, 12, "Buffer-- has been set to: #{anka_reply_half_truth.quote}"],
+ [30, 10, 5, 4, "I- hope- I- did the right- thing- by not giving-- them- the whole- truth."],
+ ]
+ }
+ end
+
+ def anka_current_reply args
+ if args.state.scene_history.include? :replied_to_serenity_alive_firmly
+ return "Hello. This is, Aanka. Sasha-- is still- trying-- to gather-- her wits about-- her, given- the gravity--- of your- last- reply. Thank- you- for being-- honest, and thank- you- for the help- with the ship- diagnostics. I was able-- to retrieve-- all of the navigation--- information---- after-- the battery--- swap. We- are ready-- to head back to Earth. Before-- we go- back- into-- statis, Matthew--- wanted-- to know- how his- wife- is doing. Please- reply-- as soon- as you can. He's-- not going-- to get- into-- the statis-- chamber-- until-- he knows- his wife is okay."
+ else
+ return "Hello. This is, Aanka. Thank- you for the help- with the ship's-- diagnostics. I was able-- to retrieve-- all of the navigation--- information--- after-- the battery-- swap. I- know-- that- you didn't-- tell- the whole truth- about-- how far we are from- Earth. Don't-- worry. I understand-- why you did it. We- are ready-- to head back to Earth. Before-- we go- back- into-- statis, Matthew--- wanted-- to know- how his- wife- is doing. Please- reply-- as soon- as you can. He's-- not going-- to get- into-- the statis-- chamber-- until-- he knows- his wife is okay."
+ end
+ end
+
+ def replied_to_anka_back_home args
+ if args.state.scene_history.include? :replied_with_whole_truth
+ return {
+ fade: 60,
+ background: 'sprites/inside-home.png',
+ player: [34, 4],
+ storylines: [
+ [34, 4, 4, 4, "I- hope-- this pit in my stomach-- is gone-- by tomorrow---."],
+ ],
+ scenes: [
+ [30, 38, 12, 13, :final_message_sad],
+ ]
+ }
+ else
+ return {
+ fade: 60,
+ background: 'sprites/inside-home.png',
+ player: [34, 4],
+ storylines: [
+ [34, 4, 4, 4, "I- get the feeling-- I'm going-- to sleep real well tonight--."],
+ ],
+ scenes: [
+ [30, 38, 12, 13, :final_message_happy],
+ ]
+ }
+ end
+ end
+
+#+end_src
+
+* Rpg Narrative - Return Of Serenity - storyline_blinking_light.rb
+#+begin_src ruby
+ # ./samples/99_genre_rpg_narrative/return_of_serenity/app/storyline_blinking_light.rb
+ def the_blinking_light args
+ {
+ fade: 60,
+ background: 'sprites/side-of-home.png',
+ player: [16, 13],
+ scenes: [
+ [52, 24, 11, 5, :blinking_light_mountain_pass],
+ ],
+ render_override: :blinking_light_side_of_home_render
+ }
+ end
+
+ def blinking_light_mountain_pass args
+ {
+ background: 'sprites/mountain-pass-zoomed-out.png',
+ player: [4, 4],
+ scenes: [
+ [18, 47, 5, 5, :blinking_light_path_to_observatory]
+ ],
+ render_override: :blinking_light_mountain_pass_render
+ }
+ end
+
+ def blinking_light_path_to_observatory args
+ {
+ background: 'sprites/path-to-observatory.png',
+ player: [60, 4],
+ scenes: [
+ [0, 26, 5, 5, :blinking_light_observatory]
+ ],
+ render_override: :blinking_light_path_to_observatory_render
+ }
+ end
+
+ def blinking_light_observatory args
+ {
+ background: 'sprites/observatory.png',
+ player: [60, 2],
+ scenes: [
+ [28, 39, 4, 10, :blinking_light_inside_observatory]
+ ],
+ render_override: :blinking_light_observatory_render
+ }
+ end
+
+ def blinking_light_inside_observatory args
+ {
+ background: 'sprites/inside-observatory.png',
+ player: [60, 2],
+ storylines: [
+ [50, 2, 4, 8, "That's weird. I thought- this- mainframe-- was broken--."]
+ ],
+ scenes: [
+ [30, 18, 5, 12, :blinking_light_inside_mainframe]
+ ],
+ render_override: :blinking_light_inside_observatory_render
+ }
+ end
+
+ def blinking_light_inside_mainframe args
+ {
+ background: 'sprites/mainframe.png',
+ fade: 60,
+ player: [30, 4],
+ scenes: [
+ [62, 32, 4, 32, :reply_to_introduction]
+ ],
+ storylines: [
+ [43, 43, 8, 8, "\"Mission-- control--, your- main- comm-- channels-- seem-- to be down. My apologies-- for- using-- this low- level-- exploit--. What's-- going-- on down there? We are ready-- for reentry--.\" Message--- Timestamp---: 4- hours-- 23--- minutes-- ago--."],
+ [30, 30, 4, 4, "There's-- a low- level-- message-- here... NANI.T.F?"],
+ [14, 10, 24, 4, "Oh interesting---. This transistor--- needed-- to be activated--- for the- mainframe-- to work."],
+ [14, 20, 24, 4, "What the heck activated--- this thing- though?"]
+ ]
+ }
+ end
+
+#+end_src
+
+* Rpg Narrative - Return Of Serenity - storyline_day_one.rb
+#+begin_src ruby
+ # ./samples/99_genre_rpg_narrative/return_of_serenity/app/storyline_day_one.rb
+ def day_one_beginning args
+ {
+ background: 'sprites/side-of-home.png',
+ player: [16, 13],
+ scenes: [
+ [0, 0, 64, 2, :day_one_infront_of_home],
+ ],
+ storylines: [
+ [35, 10, 6, 6, "Man. Hard to believe- that today- is the 20th--- anniversary-- of The Impact."]
+ ]
+ }
+ end
+
+ def day_one_infront_of_home args
+ {
+ background: 'sprites/front-of-home.png',
+ player: [56, 23],
+ scenes: [
+ [43, 34, 10, 16, :day_one_home],
+ [62, 0, 3, 40, :day_one_beginning],
+ [0, 4, 3, 20, :day_one_ceremony]
+ ],
+ storylines: [
+ [40, 20, 4, 4, "It looks like everyone- is already- at the rememberance-- ceremony."],
+ ]
+ }
+ end
+
+ def day_one_home args
+ {
+ background: 'sprites/inside-home.png',
+ player: [34, 3],
+ scenes: [
+ [28, 0, 12, 2, :day_one_infront_of_home]
+ ],
+ storylines: [
+ [
+ 38, 4, 4, 4, "My mansion- in all its glory! Okay yea, it's just a shipping- container-. Apparently-, it's nothing- like the luxuries- of the 2040's. But it's- all we have- in- this day and age. And it'll suffice."
+ ],
+ [
+ 28, 7, 4, 7,
+ "Ahhh. My reading- couch. It's so comfortable--."
+ ],
+ [
+ 38, 21, 4, 4,
+ "I'm- lucky- to have a computer--. I'm- one of the few people- with- the skills to put this- thing to good use."
+ ],
+ [
+ 45, 37, 4, 8,
+ "This corner- of my home- is always- warmer-. It's cause of the ref~lected-- light- from the solar-- panels--, just on the other- side- of this wall. It's hard- to believe- there was o~nce-- an unlimited- amount- of electricity--."
+ ],
+ [
+ 32, 40, 8, 10,
+ "This isn't- a good time- to sleep. I- should probably- head to the ceremony-."
+ ],
+ [
+ 25, 21, 5, 12,
+ "Fifteen-- years- of computer-- science-- notes, neatly-- organized. Compiler--- Theory--, Linear--- Algebra---, Game-- Development---... Every-- subject-- imaginable--."
+ ]
+ ]
+ }
+ end
+
+ def day_one_ceremony args
+ {
+ background: 'sprites/tribute.png',
+ player: [57, 21],
+ scenes: [
+ [62, 0, 2, 40, :day_one_infront_of_home],
+ [0, 24, 2, 40, :day_one_infront_of_library]
+ ],
+ storylines: [
+ [53, 12, 3, 8, "It's- been twenty- years since The Impact. Twenty- years, since Halley's-- Comet-- set Earth's- blue- sky on fire."],
+ [45, 12, 3, 8, "The space mission- sent to prevent- Earth's- total- destruction--, was a success. Only- 99.9%------ of the world's- population-- died-- that day. Hey, it's- better-- than 100%---- of humanity-- dying."],
+ [20, 12, 23, 4, "The monument--- reads:---- Here- stands- the tribute-- to Space- Mission-- Serenity--- and- its- crew. You- have- given-- humanity--- a second-- chance."],
+ [15, 12, 3, 8, "Rest- in- peace--- Matthew----, Sasha----, Aanka----"],
+ ]
+ }
+ end
+
+ def day_one_infront_of_library args
+ {
+ background: 'sprites/outside-library.png',
+ player: [57, 21],
+ scenes: [
+ [62, 0, 2, 40, :day_one_ceremony],
+ [49, 39, 6, 9, :day_one_library]
+ ],
+ storylines: [
+ [50, 20, 4, 8, "Shipping- containers-- as far- as the eye- can see. It's- rather- beautiful-- if you ask me. Even- though-- this- view- represents-- all- that's-- left- of humanity-."]
+ ]
+ }
+ end
+
+ def day_one_library args
+ {
+ background: 'sprites/library.png',
+ player: [27, 4],
+ scenes: [
+ [0, 0, 64, 2, :end_day_one_infront_of_library]
+ ],
+ storylines: [
+ [28, 22, 8, 4, "I grew- up- in this library. I've- read every- book- here. My favorites-- were- of course-- anything- computer-- related."],
+ [6, 32, 10, 6, "My favorite-- area--- of the library. The Science-- Section."]
+ ]
+ }
+ end
+
+ def end_day_one_infront_of_library args
+ {
+ background: 'sprites/outside-library.png',
+ player: [51, 33],
+ scenes: [
+ [49, 39, 6, 9, :day_one_library],
+ [62, 0, 2, 40, :end_day_one_monument],
+ ],
+ storylines: [
+ [50, 27, 4, 4, "It's getting late. Better get some sleep."]
+ ]
+ }
+ end
+
+ def end_day_one_monument args
+ {
+ background: 'sprites/tribute.png',
+ player: [2, 36],
+ scenes: [
+ [62, 0, 2, 40, :end_day_one_infront_of_home],
+ ],
+ storylines: [
+ [50, 27, 4, 4, "It's getting late. Better get some sleep."],
+ ]
+ }
+ end
+
+ def end_day_one_infront_of_home args
+ {
+ background: 'sprites/front-of-home.png',
+ player: [1, 17],
+ scenes: [
+ [43, 34, 10, 16, :end_day_one_home],
+ ],
+ storylines: [
+ [20, 10, 4, 4, "It's getting late. Better get some sleep."],
+ ]
+ }
+ end
+
+ def end_day_one_home args
+ {
+ background: 'sprites/inside-home.png',
+ player: [34, 3],
+ scenes: [
+ [32, 40, 8, 10, :end_day_one_dream],
+ ],
+ storylines: [
+ [38, 4, 4, 4, "It's getting late. Better get some sleep."],
+ ]
+ }
+ end
+
+ def end_day_one_dream args
+ {
+ background: 'sprites/dream.png',
+ fade: 60,
+ player: [4, 4],
+ scenes: [
+ [62, 0, 2, 64, :explaining_the_special_power]
+ ],
+ storylines: [
+ [10, 10, 4, 4, "Why- does this- moment-- always- haunt- my dreams?"],
+ [20, 10, 4, 4, "This kid- reads these computer--- science--- books- nonstop-. What's- wrong with him?"],
+ [30, 10, 4, 4, "There- is nothing-- wrong- with him. This behavior-- should be encouraged---! In fact-, I think- he's- special---. Have- you seen- him use- a computer---? It's-- almost-- as if he can- speak-- to it."]
+ ]
+ }
+ end
+
+ def explaining_the_special_power args
+ {
+ fade: 60,
+ background: 'sprites/inside-home.png',
+ player: [32, 30],
+ scenes: [
+ [
+ 38, 21, 4, 4, :explaining_the_special_power_inside_computer
+ ],
+ ]
+ }
+ end
+
+ def explaining_the_special_power_inside_computer args
+ {
+ background: 'sprites/pc.png',
+ fade: 60,
+ player: [34, 4],
+ scenes: [
+ [0, 62, 64, 3, :the_blinking_light]
+ ],
+ storylines: [
+ [14, 20, 24, 4, "So... I have a special-- power--. I don't-- need a mouse-, keyboard--, or even-- a monitor--- to control-- a computer--."],
+ [14, 25, 24, 4, "I only-- pretend-- to use peripherals---, so as not- to freak- anyone--- out."],
+ [14, 30, 24, 4, "Inside-- this silicon--- Universe---, is the only-- place I- feel- at peace."],
+ [14, 35, 24, 4, "It's-- the only-- place where I don't-- feel alone."]
+ ]
+ }
+ end
+
+#+end_src
+
+* Rpg Narrative - Return Of Serenity - storyline_final_decision.rb
+#+begin_src ruby
+ # ./samples/99_genre_rpg_narrative/return_of_serenity/app/storyline_final_decision.rb
+ def final_decision_side_of_home args
+ {
+ fade: 120,
+ background: 'sprites/side-of-home.png',
+ player: [16, 13],
+ scenes: [
+ [52, 24, 11, 5, :final_decision_mountain_pass],
+ ],
+ render_override: :blinking_light_side_of_home_render,
+ storylines: [
+ [28, 13, 8, 4, "Man. Hard to believe- that today- is the 21st--- anniversary-- of The Impact. Serenity--- will- be- home- soon."]
+ ]
+ }
+ end
+
+ def final_decision_mountain_pass args
+ {
+ background: 'sprites/mountain-pass-zoomed-out.png',
+ player: [4, 4],
+ scenes: [
+ [18, 47, 5, 5, :final_decision_path_to_observatory]
+ ],
+ render_override: :blinking_light_mountain_pass_render
+ }
+ end
+
+ def final_decision_path_to_observatory args
+ {
+ background: 'sprites/path-to-observatory.png',
+ player: [60, 4],
+ scenes: [
+ [0, 26, 5, 5, :final_decision_observatory]
+ ],
+ render_override: :blinking_light_path_to_observatory_render
+ }
+ end
+
+ def final_decision_observatory args
+ {
+ background: 'sprites/observatory.png',
+ player: [60, 2],
+ scenes: [
+ [28, 39, 4, 10, :final_decision_inside_observatory]
+ ],
+ render_override: :blinking_light_observatory_render
+ }
+ end
+
+ def final_decision_inside_observatory args
+ {
+ background: 'sprites/inside-observatory.png',
+ player: [60, 2],
+ storylines: [],
+ scenes: [
+ [30, 18, 5, 12, :final_decision_inside_mainframe]
+ ],
+ render_override: :blinking_light_inside_observatory_render
+ }
+ end
+
+ def final_decision_inside_mainframe args
+ {
+ player: [32, 4],
+ background: 'sprites/mainframe.png',
+ storylines: [],
+ scenes: [
+ [*hotspot_top, :final_decision_ship_status],
+ ]
+ }
+ end
+
+ def final_decision_ship_status args
+ {
+ background: 'sprites/serenity.png',
+ fade: 60,
+ player: [30, 10],
+ scenes: [
+ [*hotspot_top_right, :final_decision]
+ ],
+ storylines: [
+ [30, 8, 4, 4, "????"],
+ *final_decision_ship_status_shared(args)
+ ]
+ }
+ end
+
+ def final_decision args
+ decision_graph "Stasis-- Chambers--: UNDERPOWERED, Life- forms-- will be terminated---- unless-- equilibrium----- is reached.",
+ "I CAN'T DO THIS... But... If-- I-- don't--- bring-- the- chambers--- to- equilibrium-----, they all die...",
+ [:final_decision_game_over_noone, "Kill--- Everyone---", "DO--- NOTHING?"],
+ [:final_decision_game_over_matthew, "Kill--- Sasha---", "KILL--- SASHA?"],
+ [:final_decision_game_over_anka, "Kill--- Aanka---", "KILL--- AANKA?"],
+ [:final_decision_game_over_sasha, "Kill--- Matthew---", "KILL--- MATTHEW?"]
+ end
+
+ def final_decision_game_over_noone args
+ {
+ background: 'sprites/tribute-game-over.png',
+ player: [53, 14],
+ fade: 600
+ }
+ end
+
+ def final_decision_game_over_matthew args
+ {
+ background: 'sprites/tribute-game-over.png',
+ player: [53, 14],
+ fade: 600
+ }
+ end
+
+ def final_decision_game_over_anka args
+ {
+ background: 'sprites/tribute-game-over.png',
+ player: [53, 14],
+ fade: 600
+ }
+ end
+
+ def final_decision_game_over_sasha args
+ {
+ background: 'sprites/tribute-game-over.png',
+ player: [53, 14],
+ fade: 600
+ }
+ end
+
+ def final_decision_ship_status_shared args
+ [
+ *ship_control_hotspot(24, 22,
+ "Stasis-- Chambers--: UNDERPOWERED, Life- forms-- will be terminated---- unless-- equilibrium----- is reached. WHAT?! NO!",
+ "Matthew's--- Chamber--: UNDER-- THREAT-- OF-- TERMINATION. WHAT?! NO!",
+ "Aanka's--- Chamber--: UNDER-- THREAT-- OF-- TERMINATION. WHAT?! NO!",
+ "Sasha's--- Chamber--: UNDER-- THREAT-- OF-- TERMINATION. WHAT?! NO!"),
+ ]
+ end
+
+#+end_src
+
+* Rpg Narrative - Return Of Serenity - storyline_final_message.rb
+#+begin_src ruby
+ # ./samples/99_genre_rpg_narrative/return_of_serenity/app/storyline_final_message.rb
+ def final_message_sad args
+ {
+ fade: 60,
+ background: 'sprites/inside-home.png',
+ player: [34, 35],
+ storylines: [
+ [34, 34, 4, 4, "Another-- sleepless-- night..."],
+ ],
+ scenes: [
+ [32, -1, 8, 3, :final_message_observatory]
+ ]
+ }
+ end
+
+ def final_message_happy args
+ {
+ fade: 60,
+ background: 'sprites/inside-home.png',
+ player: [34, 35],
+ storylines: [
+ [34, 34, 4, 4, "Oh man, I slept like rock!"],
+ ],
+ scenes: [
+ [32, -1, 8, 3, :final_message_observatory]
+ ]
+ }
+ end
+
+ def final_message_side_of_home args
+ {
+ fade: 60,
+ background: 'sprites/side-of-home.png',
+ player: [16, 13],
+ scenes: [
+ [52, 24, 11, 5, :final_message_mountain_pass],
+ ],
+ render_override: :blinking_light_side_of_home_render
+ }
+ end
+
+ def final_message_mountain_pass args
+ {
+ background: 'sprites/mountain-pass-zoomed-out.png',
+ player: [4, 4],
+ scenes: [
+ [18, 47, 5, 5, :final_message_path_to_observatory],
+ ],
+ storylines: [
+ [18, 13, 5, 5, "Hnnnnnnnggg. My legs-- are still sore- from yesterday."]
+ ],
+ render_override: :blinking_light_mountain_pass_render
+ }
+ end
+
+ def final_message_path_to_observatory args
+ {
+ background: 'sprites/path-to-observatory.png',
+ player: [60, 4],
+ scenes: [
+ [0, 26, 5, 5, :final_message_observatory]
+ ],
+ storylines: [
+ [22, 20, 10, 10, "This spot--, on the mountain, right here, it's-- perfect. This- is where- I'll-- yeet-- the person-- who is playing-- this- prank- on me."]
+ ],
+ render_override: :blinking_light_path_to_observatory_render
+ }
+ end
+
+ def final_message_observatory args
+ if args.state.scene_history.include? :replied_with_whole_truth
+ return {
+ background: 'sprites/inside-observatory.png',
+ fade: 60,
+ player: [51, 12],
+ storylines: [
+ [50, 10, 4, 4, "Here-- we- go..."]
+ ],
+ scenes: [
+ [30, 18, 5, 12, :final_message_inside_mainframe]
+ ],
+ render_override: :blinking_light_inside_observatory_render
+ }
+ else
+ return {
+ background: 'sprites/inside-observatory.png',
+ fade: 60,
+ player: [51, 12],
+ storylines: [
+ [50, 10, 4, 4, "I feel like I'm-- walking-- on sunshine!"]
+ ],
+ scenes: [
+ [30, 18, 5, 12, :final_message_inside_mainframe]
+ ],
+ render_override: :blinking_light_inside_observatory_render
+ }
+ end
+ end
+
+ def final_message_inside_mainframe args
+ {
+ player: [32, 4],
+ background: 'sprites/mainframe.png',
+ fade: 60,
+ scenes: [[45, 45, 4, 4, :final_message_check_ship_status]]
+ }
+ end
+
+ def final_message_check_ship_status args
+ {
+ background: 'sprites/mainframe.png',
+ storylines: [
+ [45, 45, 4, 4, (final_message_current args)],
+ ],
+ scenes: [
+ [*hotspot_top, :final_message_ship_status],
+ ]
+ }
+ end
+
+ def final_message_ship_status args
+ {
+ background: 'sprites/serenity.png',
+ fade: 60,
+ player: [30, 10],
+ scenes: [
+ [30, 50, 4, 4, :final_message_ship_status_reviewed]
+ ],
+ storylines: [
+ [30, 8, 4, 4, "Let me make- sure- everything--- looks good. It'll-- give me peace- of mind."],
+ *final_message_ship_status_shared(args)
+ ]
+ }
+ end
+
+ def final_message_ship_status_reviewed args
+ {
+ background: 'sprites/serenity.png',
+ fade: 60,
+ scenes: [
+ [*hotspot_bottom, :final_message_summary]
+ ],
+ storylines: [
+ [0, 62, 62, 3, "Whew. Everyone-- is in their- chambers. The engines-- are roaring-- and Serenity-- is coming-- home."],
+ ]
+ }
+ end
+
+ def final_message_ship_status_shared args
+ [
+ *ship_control_hotspot( 0, 50,
+ "Stasis-- Chambers--: Online, All chambers-- are powered. Battery--- Allocation---: 3--- of-- 3--.",
+ "Matthew's--- Chamber--: OCCUPIED----",
+ "Aanka's--- Chamber--: OCCUPIED----",
+ "Sasha's--- Chamber--: OCCUPIED----"),
+ *ship_control_hotspot(12, 35,
+ "Life- Support--: Not-- Needed---",
+ "O2--- Production---: OFF---",
+ "CO2--- Scrubbers---: OFF---",
+ "H2O--- Production---: OFF---"),
+ *ship_control_hotspot(24, 20,
+ "Navigation: Offline---",
+ "Sensor: OFF---",
+ "Heads- Up- Display: DAMAGED---",
+ "Arithmetic--- Unit: DAMAGED----"),
+ *ship_control_hotspot(36, 35,
+ "COMM: Underpowered----",
+ "Text: ON---",
+ "Audio: SEGFAULT---",
+ "Video: DAMAGED---"),
+ *ship_control_hotspot(48, 50,
+ "Engine: Online, Coordinates--- Set- for Earth. Battery--- Allocation---: 3--- of-- 3---",
+ "Engine I: ON---",
+ "Engine II: ON---",
+ "Engine III: ON---")
+ ]
+ end
+
+ def final_message_last_reply args
+ if args.state.scene_history.include? :replied_with_whole_truth
+ return "Buffer--: #{anka_reply_whole_truth.quote}"
+ else
+ return "Buffer--: #{anka_reply_half_truth.quote}"
+ end
+ end
+
+ def final_message_current args
+ if args.state.scene_history.include? :replied_with_whole_truth
+ return "Hey... It's-- me Sasha. Aanka-- is trying-- her best to comfort-- Matthew. This- is the first- time- I've-- ever-- seen-- Matthew-- cry. We'll-- probably-- be in stasis-- by the time you get this message--. Thank- you- again-- for all your help. I look forward-- to meeting-- you in person."
+ else
+ return "Hey! It's-- me Sasha! LOL! Aanka-- and Matthew-- are dancing-- around-- like- goofballs--! They- are both- so adorable! Only-- this- tiny-- little-- genius-- can make-- a battle-- hardened-- general--- put- on a tiara-- and dance- around-- like a fairy-- princess-- XD------ Anyways, we are heading-- back into-- the chambers--. I hope our welcome-- home- parade-- has fireworks!"
+ end
+ end
+
+ def final_message_summary args
+ if args.state.scene_history.include? :replied_with_whole_truth
+ return {
+ background: 'sprites/inside-observatory.png',
+ fade: 60,
+ player: [31, 11],
+ scenes: [[60, 0, 4, 32, :final_decision_side_of_home]],
+ storylines: [
+ [30, 10, 5, 4, "I can't-- imagine-- what they are feeling-- right now. But at least- they- know everything---, and we can- concentrate-- on rebuilding--- this world-- right- off the bat. I can't-- wait to see the future-- they'll-- help- build."],
+ ]
+ }
+ else
+ return {
+ background: 'sprites/inside-observatory.png',
+ fade: 60,
+ player: [31, 11],
+ scenes: [[60, 0, 4, 32, :final_decision_side_of_home]],
+ storylines: [
+ [30, 10, 5, 4, "They all sounded-- so happy. I know- they'll-- be in for a tough- dose- of reality--- when they- arrive. But- at least- they'll-- be around-- all- of us. We'll-- help them- cope."],
+ ]
+ }
+ end
+ end
+
+#+end_src
+
+* Rpg Narrative - Return Of Serenity - storyline_serenity_alive.rb
+#+begin_src ruby
+ # ./samples/99_genre_rpg_narrative/return_of_serenity/app/storyline_serenity_alive.rb
+ def serenity_alive_side_of_home args
+ {
+ fade: 60,
+ background: 'sprites/side-of-home.png',
+ player: [16, 13],
+ scenes: [
+ [52, 24, 11, 5, :serenity_alive_mountain_pass],
+ ],
+ render_override: :blinking_light_side_of_home_render
+ }
+ end
+
+ def serenity_alive_mountain_pass args
+ {
+ background: 'sprites/mountain-pass-zoomed-out.png',
+ player: [4, 4],
+ scenes: [
+ [18, 47, 5, 5, :serenity_alive_path_to_observatory],
+ ],
+ storylines: [
+ [18, 13, 5, 5, "Hnnnnnnnggg. My legs-- are still sore- from yesterday."]
+ ],
+ render_override: :blinking_light_mountain_pass_render
+ }
+ end
+
+ def serenity_alive_path_to_observatory args
+ {
+ background: 'sprites/path-to-observatory.png',
+ player: [60, 4],
+ scenes: [
+ [0, 26, 5, 5, :serenity_alive_observatory]
+ ],
+ storylines: [
+ [22, 20, 10, 10, "This spot--, on the mountain, right here, it's-- perfect. This- is where- I'll-- yeet-- the person-- who is playing-- this- prank- on me."]
+ ],
+ render_override: :blinking_light_path_to_observatory_render
+ }
+ end
+
+ def serenity_alive_observatory args
+ {
+ background: 'sprites/observatory.png',
+ player: [60, 2],
+ scenes: [
+ [28, 39, 4, 10, :serenity_alive_inside_observatory]
+ ],
+ render_override: :blinking_light_observatory_render
+ }
+ end
+
+ def serenity_alive_inside_observatory args
+ {
+ background: 'sprites/inside-observatory.png',
+ player: [60, 2],
+ storylines: [],
+ scenes: [
+ [30, 18, 5, 12, :serenity_alive_inside_mainframe]
+ ],
+ render_override: :blinking_light_inside_observatory_render
+ }
+ end
+
+ def serenity_alive_inside_mainframe args
+ {
+ background: 'sprites/mainframe.png',
+ fade: 60,
+ player: [30, 4],
+ scenes: [
+ [*hotspot_top, :serenity_alive_ship_status],
+ ],
+ storylines: [
+ [22, 45, 17, 4, (serenity_alive_last_reply args)],
+ [45, 45, 4, 4, (serenity_alive_current_message args)],
+ ]
+ }
+ end
+
+ def serenity_alive_ship_status args
+ {
+ background: 'sprites/serenity.png',
+ fade: 60,
+ player: [30, 10],
+ scenes: [
+ [30, 50, 4, 4, :serenity_alive_ship_status_reviewed]
+ ],
+ storylines: [
+ [30, 8, 4, 4, "Serenity? THE--- Mission-- Serenity?! How is that possible? They- are supposed-- to be dead."],
+ [30, 10, 4, 4, "I... can't-- believe-- it. I- can access-- Serenity's-- computer? I- guess my \"superpower----\" isn't limited-- by proximity-- to- a machine--."],
+ *serenity_alive_shared_ship_status(args)
+ ]
+ }
+ end
+
+ def serenity_alive_ship_status_reviewed args
+ {
+ background: 'sprites/serenity.png',
+ fade: 60,
+ scenes: [
+ [*hotspot_bottom, :serenity_alive_time_to_reply]
+ ],
+ storylines: [
+ [0, 62, 62, 3, "Okay. Reviewing-- everything--, it looks- like- I- can- take- the batteries--- from the Stasis--- Chambers--- and- Engine--- to keep- the crew-- alive-- and-- their-- location--- pinpointed---."],
+ ]
+ }
+ end
+
+ def serenity_alive_time_to_reply args
+ decision_graph serenity_alive_current_message(args),
+ "Okay... time to deliver the bad news...",
+ [:replied_to_serenity_alive_firmly, "Firm-- Reply", serenity_alive_firm_reply],
+ [:replied_to_serenity_alive_kindly, "Sugar-- Coated---- Reply", serenity_alive_sugarcoated_reply]
+ end
+
+ def serenity_alive_shared_ship_status args
+ [
+ *ship_control_hotspot( 0, 50,
+ "Stasis-- Chambers--: Online, All chambers-- are powered. Battery--- Allocation---: 3--- of-- 3--, Hmmm. They don't-- need this to be powered-- right- now. Everyone-- is awake.",
+ nil,
+ nil,
+ nil),
+ *ship_control_hotspot(12, 35,
+ "Life- Support--: Offline, Unable--- to- Sustain-- Life. Battery--- Allocation---: 0--- of-- 3---, Okay. That is definitely---- not a good thing.",
+ nil,
+ nil,
+ nil),
+ *ship_control_hotspot(24, 20,
+ "Navigation: Offline, Unable--- to- Calculate--- Location. Battery--- Allocation---: 0--- of-- 3---, Whelp. No wonder-- Sasha-- can't-- get- any-- readings. Their- Navigation--- is completely--- offline.",
+ nil,
+ nil,
+ nil),
+ *ship_control_hotspot(36, 35,
+ "COMM: Underpowered----, Limited--- to- Text-- Based-- COMM. Battery--- Allocation---: 1--- of-- 3---, It's-- lucky- that- their- COMM---- system was able to survive-- twenty-- years--. Just- barely-- it seems.",
+ nil,
+ nil,
+ nil),
+ *ship_control_hotspot(48, 50,
+ "Engine: Online, Full- Control-- Available. Battery--- Allocation---: 3--- of-- 3---, Hmmm. No point of having an engine-- online--, if you don't- know- where you're-- going.",
+ nil,
+ nil,
+ nil)
+ ]
+ end
+
+ def serenity_alive_firm_reply
+ "Serenity, you are at a distance-- farther-- than- Neptune. All- of the ship's-- systems-- are failing. Please- move the batteries---- from- the Stasis-- Chambers-- over- to- Life-- Support--. I also-- need- you to move-- the batteries---- from- the Engines--- to your Navigation---- System."
+ end
+
+ def serenity_alive_sugarcoated_reply
+ "So... you- are- a teeny--- tiny--- bit--- farther-- from Earth- than you think. And you have a teeny--- tiny--- problem-- with your ship. Please-- move the batteries--- from the Stasis--- Chambers--- over to Life--- Support---. I also need you to move the batteries--- from the Engines--- to your- Navigation--- System. Don't-- worry-- Sasha. I'll-- get y'all-- home."
+ end
+
+ def replied_to_serenity_alive_firmly args
+ {
+ background: 'sprites/inside-observatory.png',
+ fade: 60,
+ player: [32, 21],
+ scenes: [
+ [*hotspot_bottom_right, :serenity_alive_path_from_observatory]
+ ],
+ storylines: [
+ [30, 18, 5, 12, "Buffer-- has been set to: #{serenity_alive_firm_reply.quote}"],
+ *serenity_alive_reply_completed_shared_hotspots(args),
+ ]
+ }
+ end
+
+ def replied_to_serenity_alive_kindly args
+ {
+ background: 'sprites/inside-observatory.png',
+ fade: 60,
+ player: [32, 21],
+ scenes: [
+ [*hotspot_bottom_right, :serenity_alive_path_from_observatory]
+ ],
+ storylines: [
+ [30, 18, 5, 12, "Buffer-- has been set to: #{serenity_alive_sugarcoated_reply.quote}"],
+ *serenity_alive_reply_completed_shared_hotspots(args),
+ ]
+ }
+ end
+
+ def serenity_alive_path_from_observatory args
+ {
+ fade: 60,
+ background: 'sprites/path-to-observatory.png',
+ player: [4, 21],
+ scenes: [
+ [*hotspot_bottom_right, :serenity_bio_infront_of_home]
+ ],
+ storylines: [
+ [22, 20, 10, 10, "I'm not sure what's-- worse. Waiting-- for Sasha's-- reply. Or jumping-- off- from- right- here."]
+ ]
+ }
+ end
+
+ def serenity_alive_reply_completed_shared_hotspots args
+ [
+ [30, 10, 5, 4, "I guess it wasn't-- a joke- after-- all."],
+ [40, 10, 5, 4, "I barely-- remember--- the- history----- of the crew."],
+ [50, 10, 5, 4, "It probably--- wouldn't-- hurt- to- refresh-- my memory--."]
+ ]
+ end
+
+ def serenity_alive_last_reply args
+ if args.state.scene_history.include? :replied_to_introduction_seriously
+ return "Buffer--: \"Hello, Who- is sending-- this message--?\""
+ else
+ return "Buffer--: \"New- phone. Who dis?\""
+ end
+ end
+
+ def serenity_alive_current_message args
+ if args.state.scene_history.include? :replied_to_introduction_seriously
+ "This- is Sasha. The Serenity--- crew-- is out of hibernation---- and ready-- for Earth reentry--. But, it seems like we are having-- trouble-- with our Navigation---- systems. Please advise.".quote
+ else
+ "LOL! Thanks for the laugh. I needed that. This- is Sasha. The Serenity--- crew-- is out of hibernation---- and ready-- for Earth reentry--. But, it seems like we are having-- trouble-- with our Navigation---- systems. Can you help me out- babe?".quote
+ end
+ end
+
+#+end_src
+
+* Rpg Narrative - Return Of Serenity - storyline_serenity_bio.rb
+#+begin_src ruby
+ # ./samples/99_genre_rpg_narrative/return_of_serenity/app/storyline_serenity_bio.rb
+ def serenity_bio_infront_of_home args
+ {
+ fade: 60,
+ background: 'sprites/front-of-home.png',
+ player: [54, 23],
+ scenes: [
+ [44, 34, 8, 14, :serenity_bio_inside_home],
+ [0, 3, 3, 22, :serenity_bio_library]
+ ]
+ }
+ end
+
+ def serenity_bio_inside_home args
+ {
+ background: 'sprites/inside-home.png',
+ player: [34, 4],
+ storylines: [
+ [34, 4, 4, 4, "I'm--- completely--- exhausted."],
+ ],
+ scenes: [
+ [30, 38, 12, 13, :serenity_bio_restless_sleep],
+ [32, 0, 8, 3, :serenity_bio_infront_of_home],
+ ]
+ }
+ end
+
+ def serenity_bio_restless_sleep args
+ {
+ fade: 60,
+ background: 'sprites/inside-home.png',
+ storylines: [
+ [32, 38, 10, 13, "I can't-- seem to sleep. I know nothing-- about the- crew-. Maybe- I- should- go read- up- on- them."],
+ ],
+ scenes: [
+ [32, 0, 8, 3, :serenity_bio_infront_of_home],
+ ]
+ }
+ end
+
+ def serenity_bio_library args
+ {
+ background: 'sprites/library.png',
+ fade: 60,
+ player: [30, 7],
+ scenes: [
+ [21, 35, 3, 18, :serenity_bio_book]
+ ]
+ }
+ end
+
+ def serenity_bio_book args
+ {
+ background: 'sprites/book.png',
+ fade: 60,
+ player: [6, 52],
+ storylines: [
+ [ 4, 50, 56, 4, "The Title-- Reads: Never-- Forget-- Mission-- Serenity---"],
+
+ [ 4, 38, 8, 8, "Name: Matthew--- R. Sex: Male--- Age-- at-- Departure: 36-----"],
+ [14, 38, 46, 8, "Tribute-- Text: Matthew graduated-- Magna-- Cum-- Laude-- from MIT--- with-- a- PHD---- in Aero-- Nautical--- Engineering. He was immensely--- competitive, and had an insatiable---- thirst- for aerial-- battle. From the age of twenty, he remained-- undefeated--- in the Israeli-- Air- Force- \"Blue Flag\" combat-- exercises. By the age of 29--- he had already-- risen through- the ranks, and became-- the Lieutenant--- General--- of Lufwaffe. Matthew-- volenteered-- to- pilot-- Mission-- Serenity. To- this day, his wife- and son- are pillars-- of strength- for us. Rest- in Peace- Matthew, we are sorry-- that- news of the pregancy-- never-- reached- you. Please forgive us."],
+
+ [4, 26, 8, 8, "Name: Aanka--- P. Sex: Female--- Age-- at-- Departure: 9-----"],
+ [14, 26, 46, 8, "Tribute-- Text: Aanka--- gratuated--- Magna-- Cum- Laude-- from MIT, at- the- age- of eight, with a- PHD---- in Astro-- Physics. Her-- IQ--- was over 390, the highest-- ever- recorded--- IQ-- in- human-- history. She changed- the landscape-- of Physics-- with her efforts- in- unravelling--- the mysteries--- of- Dark- Matter--. Anka discovered-- the threat- of Halley's-- Comet-- collision--- with Earth. She spear headed-- the global-- effort-- for Misson-- Serenity. Her- multilingual--- address-- to- the world-- brought- us all hope."],
+
+ [4, 14, 8, 8, "Name: Sasha--- N. Sex: Female--- Age-- at-- Departure: 29-----"],
+ [14, 14, 46, 8, "Tribute-- Text: Sasha gratuated-- Magna-- Cum- Laude-- from MIT--- with-- a- PHD---- in Computer---- Science----. She-- was-- brilliant--, strong- willed--, and-- a-- stunningly--- beautiful--- woman---. Sasha---- is- the- creator--- of the world's--- first- Ruby--- Quantum-- Machine---. After-- much- critical--- acclaim--, the Quantum-- Computer-- was placed in MIT's---- Museam-- next- to- Richard--- G. and Thomas--- K.'s---- Lisp-- Machine---. Her- engineering--- skills-- were-- paramount--- for Mission--- Serenity's--- success. Humanity-- misses-- you-- dearly,-- Sasha--. Life-- shines-- a dimmer-- light-- now- that- your- angelic- voice-- can never- be heard- again."],
+ ],
+ scenes: [
+ [*hotspot_bottom, :serenity_bio_finally_to_bed]
+ ]
+ }
+ end
+
+ def serenity_bio_finally_to_bed args
+ {
+ fade: 60,
+ background: 'sprites/inside-home.png',
+ player: [35, 3],
+ storylines: [
+ [34, 4, 4, 4, "Maybe-- I'll-- be able-- to sleep- now..."],
+ ],
+ scenes: [
+ [32, 38, 10, 13, :bad_dream],
+ ]
+ }
+ end
+
+ def bad_dream args
+ {
+ fade: 120,
+ background: 'sprites/inside-home.png',
+ player: [34, 35],
+ storylines: [
+ [34, 34, 4, 4, "Man. I did not- sleep- well- at all..."],
+ ],
+ scenes: [
+ [32, -1, 8, 3, :bad_dream_observatory]
+ ]
+ }
+ end
+
+ def bad_dream_observatory args
+ {
+ background: 'sprites/inside-observatory.png',
+ fade: 120,
+ player: [51, 12],
+ storylines: [
+ [50, 10, 4, 4, "Breathe, Hiro. Just see what's there... everything--- will- be okay."]
+ ],
+ scenes: [
+ [30, 18, 5, 12, :bad_dream_inside_mainframe]
+ ],
+ render_override: :blinking_light_inside_observatory_render
+ }
+ end
+
+ def bad_dream_inside_mainframe args
+ {
+ player: [32, 4],
+ background: 'sprites/mainframe.png',
+ fade: 120,
+ storylines: [
+ [22, 45, 17, 4, (bad_dream_last_reply args)],
+ ],
+ scenes: [
+ [45, 45, 4, 4, :bad_dream_everyone_dead],
+ ]
+ }
+ end
+
+ def bad_dream_everyone_dead args
+ {
+ background: 'sprites/mainframe.png',
+ storylines: [
+ [22, 45, 17, 4, (bad_dream_last_reply args)],
+ [45, 45, 4, 4, "Hi-- Hiro. This is Sasha. By the time- you get this- message, chances-- are we will- already-- be- dead. The batteries--- got- damaged-- during-- removal. And- we don't-- have enough-- power-- for Life-- Support. The air-- is- already--- starting-- to taste- bad. It... would- have been- nice... to go- on a date--- with- you-- when-- I- got- back- to Earth. Anyways, good-- bye-- Hiro-- XOXOXO----"],
+ [22, 5, 17, 4, "Meh. Whatever, I didn't-- want to save them anyways. What- a pain- in my ass."],
+ ],
+ scenes: [
+ [*hotspot_bottom, :anka_inside_room]
+ ]
+ }
+ end
+
+ def bad_dream_last_reply args
+ if args.state.scene_history.include? :replied_to_serenity_alive_firmly
+ return "Buffer--: #{serenity_alive_firm_reply.quote}"
+ else
+ return "Buffer--: #{serenity_alive_sugarcoated_reply.quote}"
+ end
+ end
+
+#+end_src
+
+* Rpg Narrative - Return Of Serenity - storyline_serenity_introduction.rb
+#+begin_src ruby
+ # ./samples/99_genre_rpg_narrative/return_of_serenity/app/storyline_serenity_introduction.rb
+ # decision_graph "Message from Sasha",
+ # "I should reply.",
+ # [:replied_to_introduction_seriously, "Reply Seriously", "Who is this?"],
+ # [:replied_to_introduction_humorously, "Reply Humorously", "New phone who dis?"]
+ def reply_to_introduction args
+ decision_graph "\"Mission-- control--, your- main- comm-- channels-- seem-- to be down. My apologies-- for- using-- this low- level-- exploit--. What's-- going-- on down there? We are ready-- for reentry--.\" Message--- Timestamp---: 4- hours-- 23--- minutes-- ago--.",
+ "Whoever-- pulled- off this exploit-- knows their stuff. I should reply--.",
+ [:replied_to_introduction_seriously, "Serious Reply", "Hello, Who- is sending-- this message--?"],
+ [:replied_to_introduction_humorously, "Humorous Reply", "New phone, who dis?"]
+ end
+
+ def replied_to_introduction_seriously args
+ {
+ background: 'sprites/inside-observatory.png',
+ fade: 60,
+ player: [32, 21],
+ scenes: [
+ *replied_to_introduction_shared_scenes(args)
+ ],
+ storylines: [
+ [30, 18, 5, 12, "Buffer-- has been set to: \"Hello, Who- is sending-- this message--?\""],
+ *replied_to_introduction_shared_storylines(args)
+ ]
+ }
+ end
+
+ def replied_to_introduction_humorously args
+ {
+ background: 'sprites/inside-observatory.png',
+ fade: 60,
+ player: [32, 21],
+ scenes: [
+ *replied_to_introduction_shared_scenes(args)
+ ],
+ storylines: [
+ [30, 18, 5, 12, "Buffer-- has been set to: \"New- phone. Who dis?\""],
+ *replied_to_introduction_shared_storylines(args)
+ ]
+ }
+ end
+
+ def replied_to_introduction_shared_storylines args
+ [
+ [30, 10, 5, 4, "It's-- going-- to take a while-- for this reply-- to make it's-- way back."],
+ [40, 10, 5, 4, "4- hours-- to send a message-- at light speed?! How far away-- is the sender--?"],
+ [50, 10, 5, 4, "I know- I've-- read about-- light- speed- travel-- before--. Maybe-- the library--- still has that- poster."]
+ ]
+ end
+
+ def replied_to_introduction_shared_scenes args
+ [[60, 0, 4, 32, :replied_to_introduction_observatory]]
+ end
+
+ def replied_to_introduction_observatory args
+ {
+ background: 'sprites/observatory.png',
+ player: [28, 39],
+ scenes: [
+ [60, 0, 4, 32, :replied_to_introduction_path_to_observatory]
+ ]
+ }
+ end
+
+ def replied_to_introduction_path_to_observatory args
+ {
+ background: 'sprites/path-to-observatory.png',
+ player: [0, 26],
+ scenes: [
+ [60, 0, 4, 20, :replied_to_introduction_mountain_pass]
+ ],
+ }
+ end
+
+ def replied_to_introduction_mountain_pass args
+ {
+ background: 'sprites/mountain-pass-zoomed-out.png',
+ player: [21, 48],
+ scenes: [
+ [0, 0, 15, 4, :replied_to_introduction_side_of_home]
+ ],
+ storylines: [
+ [15, 28, 5, 3, "At least I'm-- getting-- my- exercise-- in- for- today--."]
+ ]
+ }
+ end
+
+ def replied_to_introduction_side_of_home args
+ {
+ background: 'sprites/side-of-home.png',
+ player: [58, 29],
+ scenes: [
+ [2, 0, 61, 2, :speed_of_light_front_of_home]
+ ],
+ }
+ end
+
+#+end_src
+
+* Rpg Narrative - Return Of Serenity - storyline_speed_of_light.rb
+#+begin_src ruby
+ # ./samples/99_genre_rpg_narrative/return_of_serenity/app/storyline_speed_of_light.rb
+ def speed_of_light_front_of_home args
+ {
+ background: 'sprites/front-of-home.png',
+ player: [54, 23],
+ scenes: [
+ [44, 34, 8, 14, :speed_of_light_inside_home],
+ [0, 3, 3, 22, :speed_of_light_outside_library]
+ ]
+ }
+ end
+
+ def speed_of_light_inside_home args
+ {
+ background: 'sprites/inside-home.png',
+ player: [35, 4],
+ storylines: [
+ [30, 38, 12, 13, "Can't- sleep right now. I have to- find- out- why- it took- over-- 4- hours-- to receive-- that message."]
+ ],
+ scenes: [
+ [32, 0, 8, 3, :speed_of_light_front_of_home],
+ ]
+ }
+ end
+
+ def speed_of_light_outside_library args
+ {
+ background: 'sprites/outside-library.png',
+ player: [55, 19],
+ scenes: [
+ [49, 39, 6, 10, :speed_of_light_library],
+ [61, 11, 3, 20, :speed_of_light_front_of_home]
+ ]
+ }
+ end
+
+ def speed_of_light_library args
+ {
+ background: 'sprites/library.png',
+ player: [30, 7],
+ scenes: [
+ [3, 50, 10, 3, :speed_of_light_celestial_bodies_diagram]
+ ]
+ }
+ end
+
+ def speed_of_light_celestial_bodies_diagram args
+ {
+ background: 'sprites/planets.png',
+ fade: 60,
+ player: [30, 3],
+ scenes: [
+ [56 - 2, 10, 5, 5, :speed_of_light_distance_discovered]
+ ],
+ storylines: [
+ [30, 2, 4, 4, "Here- it is! This is a diagram--- of the solar-- system--. It was printed-- over-- fifty-- years- ago. Geez-- that's-- old."],
+
+ [ 0 - 2, 10, 5, 5, "The label- reads: Sun. The length- of the Astronomical-------- Unit-- (AU), is the distance-- from the Sun- to the Earth. Which is about 150--- million--- kilometers----."],
+ [ 7 - 2, 10, 5, 5, "The label- reads: Mercury. Distance from Sun: 0.39AU------------ or- 3----- light-- minutes--."],
+ [14 - 2, 10, 5, 5, "The label- reads: Venus. Distance from Sun: 0.72AU------------ or- 6----- light-- minutes--."],
+ [21 - 2, 10, 5, 5, "The label- reads: Earth. Distance from Sun: 1.00AU------------ or- 8----- light-- minutes--."],
+ [28 - 2, 10, 5, 5, "The label- reads: Mars. Distance from Sun: 1.52AU------------ or- 12----- light-- minutes--."],
+ [35 - 2, 10, 5, 5, "The label- reads: Jupiter. Distance from Sun: 5.20AU------------ or- 45----- light-- minutes--."],
+ [42 - 2, 10, 5, 5, "The label- reads: Saturn. Distance from Sun: 9.53AU------------ or- 79----- light-- minutes--."],
+ [49 - 2, 10, 5, 5, "The label- reads: Uranus. Distance from Sun: 19.81AU------------ or- 159----- light-- minutes--."],
+ # [56 - 2, 15, 4, 4, "The label- reads: Neptune. Distance from Sun: 30.05AU------------ or- 4.1----- light-- hours--."],
+ [63 - 2, 10, 5, 5, "The label- reads: Pluto. Wait. WTF? Pluto-- isn't-- a planet."],
+ ]
+ }
+ end
+
+ def speed_of_light_distance_discovered args
+ {
+ background: 'sprites/planets.png',
+ scenes: [
+ [13, 0, 44, 3, :speed_of_light_end_of_day]
+ ],
+ storylines: [
+ [ 0 - 2, 10, 5, 5, "The label- reads: Sun. The length- of the Astronomical-------- Unit-- (AU), is the distance-- from the Sun- to the Earth. Which is about 150--- million--- kilometers----."],
+ [ 7 - 2, 10, 5, 5, "The label- reads: Mercury. Distance from Sun: 0.39AU------------ or- 3----- light-- minutes--."],
+ [14 - 2, 10, 5, 5, "The label- reads: Venus. Distance from Sun: 0.72AU------------ or- 6----- light-- minutes--."],
+ [21 - 2, 10, 5, 5, "The label- reads: Earth. Distance from Sun: 1.00AU------------ or- 8----- light-- minutes--."],
+ [28 - 2, 10, 5, 5, "The label- reads: Mars. Distance from Sun: 1.52AU------------ or- 12----- light-- minutes--."],
+ [35 - 2, 10, 5, 5, "The label- reads: Jupiter. Distance from Sun: 5.20AU------------ or- 45----- light-- minutes--."],
+ [42 - 2, 10, 5, 5, "The label- reads: Saturn. Distance from Sun: 9.53AU------------ or- 79----- light-- minutes--."],
+ [49 - 2, 10, 5, 5, "The label- reads: Uranus. Distance from Sun: 19.81AU------------ or- 159----- light-- minutes--."],
+ [56 - 2, 10, 5, 5, "The label- reads: Neptune. Distance from Sun: 30.05AU------------ or- 4.1----- light-- hours--. What?! The message--- I received-- was from a source-- farther-- than-- Neptune?!"],
+ [63 - 2, 10, 5, 5, "The label- reads: Pluto. Dista- Wait... Pluto-- isn't-- a planet. People-- thought- Pluto-- was a planet-- back- then?--"],
+ ]
+ }
+ end
+
+ def speed_of_light_end_of_day args
+ {
+ fade: 60,
+ background: 'sprites/inside-home.png',
+ player: [35, 0],
+ storylines: [
+ [35, 10, 4, 4, "Wonder-- what the reply-- will be. Who- the hell is contacting--- me from beyond-- Neptune? This- has to be some- kind- of- joke."]
+ ],
+ scenes: [
+ [31, 38, 10, 12, :serenity_alive_side_of_home]
+ ]
+ }
+ end
+
+#+end_src
+
+* Rpg Roguelike - Roguelike Line Of Sight - constants.rb
+#+begin_src ruby
+ # ./samples/99_genre_rpg_roguelike/roguelike_line_of_sight/app/constants.rb
SHOW_LEGEND = true
SOURCE_TILE_SIZE = 16
DESTINATION_TILE_SIZE = 16
@@ -18138,8 +20746,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 99_genre_roguelike/roguelike_line_of_sight/app/legend.rb
+* Rpg Roguelike - Roguelike Line Of Sight - legend.rb
#+begin_src ruby
+ # ./samples/99_genre_rpg_roguelike/roguelike_line_of_sight/app/legend.rb
def tick_legend args
return unless SHOW_LEGEND
@@ -18208,8 +20817,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 99_genre_roguelike/roguelike_line_of_sight/app/main.rb
+* Rpg Roguelike - Roguelike Line Of Sight - main.rb
#+begin_src ruby
+ # ./samples/99_genre_rpg_roguelike/roguelike_line_of_sight/app/main.rb
require 'app/constants.rb'
require 'app/sprite_lookup.rb'
require 'app/legend.rb'
@@ -18310,8 +20920,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 99_genre_roguelike/roguelike_line_of_sight/app/sprite_lookup.rb
+* Rpg Roguelike - Roguelike Line Of Sight - sprite_lookup.rb
#+begin_src ruby
+ # ./samples/99_genre_rpg_roguelike/roguelike_line_of_sight/app/sprite_lookup.rb
def sprite_lookup
{
0 => [3, 0],
@@ -18439,8 +21050,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 99_genre_roguelike/roguelike_starting_point/app/main.rb
+* Rpg Roguelike - Roguelike Starting Point - main.rb
#+begin_src ruby
+ # ./samples/99_genre_rpg_roguelike/roguelike_starting_point/app/main.rb
=begin
APIs listing that haven't been encountered in previous sample apps:
@@ -18883,8 +21495,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 99_genre_tactical_rpg/hexagonal_grid/app/main.rb
+* Rpg Tactical - Hexagonal Grid - main.rb
#+begin_src ruby
+ # ./samples/99_genre_rpg_tactical/hexagonal_grid/app/main.rb
class HexagonTileGame
attr_gtk
@@ -18956,8 +21569,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 99_genre_tactical_rpg/isometric_grid/app/main.rb
+* Rpg Tactical - Isometric Grid - main.rb
#+begin_src ruby
+ # ./samples/99_genre_rpg_tactical/isometric_grid/app/main.rb
class Isometric
attr_accessor :grid, :inputs, :state, :outputs
@@ -19223,8 +21837,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* 99_genre_topdown_rpg/topdown_starting_point/app/main.rb
+* Rpg Topdown - Topdown Starting Point - main.rb
#+begin_src ruby
+ # ./samples/99_genre_rpg_topdown/topdown_starting_point/app/main.rb
=begin
APIs listing that haven't been encountered in previous sample apps:
@@ -19336,8 +21951,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* ./dragon/args.rb
+* args.rb
#+begin_src ruby
+ # ./dragon/args.rb
# coding: utf-8
# Copyright 2019 DragonRuby LLC
# MIT License
@@ -19537,8 +22153,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* ./dragon/assert.rb
+* assert.rb
#+begin_src ruby
+ # ./dragon/assert.rb
# coding: utf-8
# Copyright 2019 DragonRuby LLC
# MIT License
@@ -19670,8 +22287,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* ./dragon/attr_gtk.rb
+* attr_gtk.rb
#+begin_src ruby
+ # ./dragon/attr_gtk.rb
# coding: utf-8
# Copyright 2019 DragonRuby LLC
# MIT License
@@ -19716,8 +22334,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* ./dragon/attr_sprite.rb
+* attr_sprite.rb
#+begin_src ruby
+ # ./dragon/attr_sprite.rb
# Copyright 2019 DragonRuby LLC
# MIT License
# attr_sprite.rb has been released under MIT (*only this file*).
@@ -19777,8 +22396,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* ./dragon/console.rb
+* console.rb
#+begin_src ruby
+ # ./dragon/console.rb
# Copyright 2019 DragonRuby LLC
# MIT License
# console.rb has been released under MIT (*only this file*).
@@ -20073,18 +22693,17 @@ Follows is a source code listing for all files that have been open sourced. This
@last_command_errored = false
rescue Exception => e
string_e = "#{e}"
+ puts "* EXCEPTION: #{e}"
+ log "* EXCEPTION: #{e}"
@last_command_errored = true
if (string_e.include? "wrong number of arguments")
method_name = (string_e.split ":")[0].gsub "'", ""
- results = Kernel.docs_search method_name
- if !results.include "* DOCS: No results found."
+ results = (Kernel.docs_search method_name).strip
+ if !results.include? "* DOCS: No results found."
puts results
log results
end
end
-
- puts "#{e}"
- log "#{e}"
end
end
end
@@ -20096,6 +22715,10 @@ Follows is a source code listing for all files that have been open sourced. This
(args.inputs.keyboard.key_up.b && args.inputs.keyboard.key_up.control)
end
+ def scroll_to_bottom
+ @log_offset = 0
+ end
+
def scroll_up_full
@log_offset += lines_on_one_page
@log_offset = @log.size if @log_offset > @log.size
@@ -20291,63 +22914,6 @@ Follows is a source code listing for all files that have been open sourced. This
render_log_offset args
end
- def tick_help args
- tick_help_debounce args
- alpha_rate = 20
- @render_help_target_alpha ||= 255
- @render_help_current_alpha ||= 255
- @render_help_target_alpha += 4 if @render_help_current_alpha == @render_help_target_alpha
- @render_help_current_alpha = (@render_help_current_alpha.towards @render_help_target_alpha, 20)
-
- @render_help_target_alpha = @render_help_target_alpha.clamp(-255, 255)
- @render_help_current_alpha = @render_help_current_alpha.clamp(-255, 255)
-
- [
- "* Prompt Commands: ",
- "You can type any of the following ",
- "commands in the command prompt. ",
- "** docs: Provides API docs. ",
- "** $gtk: Accesses the global runtime.",
- "* Shortcut Keys: ",
- "** full page up: ctrl + b ",
- "** full page down: ctrl + f ",
- "** half page up: ctrl + u ",
- "** half page down: ctrl + d ",
- "** clear prompt: ctrl + g ",
- "** up arrow: next command ",
- "** down arrow: prev command ",
- ].each_with_index do |s, i|
- args.outputs.reserved << [args.grid.right - 10,
- top - 100 - line_height_px * i * 0.8,
- s, -3, 2, 180, 180, 180, (@render_help_current_alpha.clamp 0, 255)].label
- end
- end
-
- def tick_help_debounce args
- hide_log_alpha = -255
- if hidden?
- @render_help_current_alpha = -255
- end
-
- if prompt.last_input_str_changed
- @render_help_target_alpha = hide_log_alpha
- end
-
- if args.inputs.mouse.moved
- @render_help_target_alpha = hide_log_alpha
- end
-
- if args.inputs.mouse.wheel
- @render_help_target_alpha = hide_log_alpha
- end
-
- if @render_help_last_log_invocation_count != @log_invocation_count
- @render_help_target_alpha = hide_log_alpha
- end
-
- @render_help_last_log_invocation_count = @log_invocation_count
- end
-
def render_log_offset args
return if @log_offset <= 0
args.outputs.reserved << font_style.label(
@@ -20404,7 +22970,6 @@ Follows is a source code listing for all files that have been open sourced. This
process_inputs args
return unless should_tick?
calc args
- tick_help args
prompt.tick
menu.tick args
rescue Exception => e
@@ -20564,8 +23129,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* ./dragon/console_color.rb
+* console_color.rb
#+begin_src ruby
+ # ./dragon/console_color.rb
# Copyright 2019 DragonRuby LLC
# MIT License
# console_color.rb has been released under MIT (*only this file*).
@@ -20599,8 +23165,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* ./dragon/console_font_style.rb
+* console_font_style.rb
#+begin_src ruby
+ # ./dragon/console_font_style.rb
# Copyright 2019 DragonRuby LLC
# MIT License
# console_font_style.rb has been released under MIT (*only this file*).
@@ -20644,8 +23211,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* ./dragon/console_menu.rb
+* console_menu.rb
#+begin_src ruby
+ # ./dragon/console_menu.rb
# Copyright 2019 DragonRuby LLC
# MIT License
# console_menu.rb has been released under MIT (*only this file*).
@@ -20653,6 +23221,8 @@ Follows is a source code listing for all files that have been open sourced. This
module GTK
class Console
class Menu
+ attr_accessor :buttons
+
def initialize console
@console = console
end
@@ -20686,28 +23256,63 @@ Follows is a source code listing for all files that have been open sourced. This
@console.hide
end
+ def hide_menu_clicked
+ @menu_shown = :hidden
+ end
+
def framerate_diagnostics_clicked
+ @console.scroll_to_bottom
$gtk.framerate_diagnostics
end
+ def itch_wizard_clicked
+ @console.scroll_to_bottom
+ $wizards.itch.start
+ end
+
+ def docs_clicked
+ @console.scroll_to_bottom
+ log Kernel.docs_classes
+ end
+
+ def scroll_end_clicked
+ @console.scroll_to_bottom
+ end
+
+ def custom_buttons
+ []
+ end
+
def tick args
return unless @console.visible?
@menu_shown ||= :hidden
- if @menu_shown == :hidden
+ if $gtk.production
+ @buttons = [
+ (button id: :record, row: 0, col: 9, text: "record gameplay", method: :record_clicked),
+ (button id: :replay, row: 0, col: 10, text: "start replay", method: :replay_clicked),
+ ]
+ elsif @menu_shown == :hidden
@buttons = [
(button id: :show_menu, row: 0, col: 10, text: "show menu", method: :show_menu_clicked),
]
else
@buttons = [
- (button id: :record, row: 0, col: 4, text: "framerate diagnostics", method: :framerate_diagnostics_clicked),
- (button id: :record, row: 0, col: 5, text: "record", method: :record_clicked),
- (button id: :replay, row: 0, col: 6, text: "replay", method: :replay_clicked),
- (button id: :reset, row: 0, col: 7, text: "reset", method: :reset_clicked),
- (button id: :scroll_up, row: 0, col: 8, text: "scroll up", method: :scroll_up_clicked),
- (button id: :scroll_down, row: 0, col: 9, text: "scroll down", method: :scroll_down_clicked),
- (button id: :close, row: 0, col: 10, text: "close", method: :close_clicked),
+ (button id: :scroll_up, row: 0, col: 6, text: "scroll up", method: :scroll_up_clicked),
+ (button id: :scroll_down, row: 0, col: 7, text: "scroll down", method: :scroll_down_clicked),
+ (button id: :scroll_down, row: 0, col: 8, text: "scroll end", method: :scroll_end_clicked),
+ (button id: :close, row: 0, col: 9, text: "close console", method: :close_clicked),
+ (button id: :hide, row: 0, col: 10, text: "hide menu", method: :hide_menu_clicked),
+
+ (button id: :record, row: 1, col: 7, text: "record gameplay", method: :record_clicked),
+ (button id: :replay, row: 1, col: 8, text: "start replay", method: :replay_clicked),
+ (button id: :record, row: 1, col: 9, text: "framerate diagnostics", method: :framerate_diagnostics_clicked),
+ (button id: :reset, row: 1, col: 10, text: "reset game", method: :reset_clicked),
+
+ (button id: :reset, row: 2, col: 10, text: "docs", method: :docs_clicked),
+ (button id: :reset, row: 2, col: 9, text: "itch wizard", method: :itch_wizard_clicked),
+ *custom_buttons
]
end
@@ -20740,10 +23345,11 @@ Follows is a source code listing for all files that have been open sourced. This
{
id: id,
rect: (rect_for_layout row, col),
+ text: text,
method: method
}.let do |entity|
primitives = []
- primitives << entity[:rect].merge(a: 80).solid
+ primitives << entity[:rect].merge(a: 164).solid
primitives << entity[:rect].merge(r: 255, g: 255, b: 255).border
primitives << text.wrapped_lines(5)
.map_with_index do |l, i|
@@ -20769,8 +23375,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* ./dragon/console_prompt.rb
+* console_prompt.rb
#+begin_src ruby
+ # ./dragon/console_prompt.rb
# Copyright 2019 DragonRuby LLC
# MIT License
# console_prompt.rb has been released under MIT (*only this file*).
@@ -20944,8 +23551,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* ./dragon/controller.rb
+* controller.rb
#+begin_src ruby
+ # ./dragon/controller.rb
# coding: utf-8
# Copyright 2019 DragonRuby LLC
# MIT License
@@ -21071,8 +23679,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* ./dragon/controller/config.rb
+* controller/config.rb
#+begin_src ruby
+ # ./dragon/controller/config.rb
# coding: utf-8
# Copyright 2019 DragonRuby LLC
# MIT License
@@ -21475,8 +24084,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* ./dragon/controller/keys.rb
+* controller/keys.rb
#+begin_src ruby
+ # ./dragon/controller/keys.rb
# coding: utf-8
# Copyright 2019 DragonRuby LLC
# MIT License
@@ -21531,8 +24141,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* ./dragon/directional_input_helper_methods.rb
+* directional_input_helper_methods.rb
#+begin_src ruby
+ # ./dragon/directional_input_helper_methods.rb
# coding: utf-8
# Copyright 2019 DragonRuby LLC
# MIT License
@@ -21628,8 +24239,97 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* ./dragon/geometry.rb
+* easing.rb
+#+begin_src ruby
+ # ./dragon/easing.rb
+ # coding: utf-8
+ # Copyright 2019 DragonRuby LLC
+ # MIT License
+ # easing.rb has been released under MIT (*only this file*).
+
+ module GTK
+ module Easing
+ def self.ease_extended start_tick, current_tick, end_tick, default_before, default_after, *definitions
+ definitions.flatten!
+ definitions = [:identity] if definitions.length == 0
+ duration = end_tick - start_tick
+ elapsed = current_tick - start_tick
+ y = elapsed.percentage_of(duration).cap_min_max(0, 1)
+
+ definitions.map do |definition|
+ y = Easing.exec_definition(definition, start_tick, duration, y)
+ end
+
+ y
+ end
+
+ def self.ease_spline_extended start_tick, current_tick, end_tick, spline
+ duration = end_tick - start_tick
+ t = (current_tick - start_tick).fdiv duration
+ time_allocation_per_curve = 1.fdiv(spline.length)
+ curve_index, curve_t = t.fdiv(time_allocation_per_curve).let do |spline_t|
+ [spline_t.to_i, spline_t - spline_t.to_i]
+ end
+ Geometry.cubic_bezier curve_t, *spline[curve_index]
+ end
+
+ def self.initial_value *definitions
+ definitions.flatten!
+ return Easing.exec_definition (definitions.value(-1) || :identity), 0, 10, 0
+ end
+
+ def self.final_value *definitions
+ definitions.flatten!
+ return Easing.exec_definition (definitions.value(-1) || :identity), 0, 10, 1.0
+ end
+
+ def self.exec_definition definition, start_tick, duration, x
+ if definition.is_a? Symbol
+ return Easing.send(definition, x).cap_min_max(0, 1)
+ elsif definition.is_a? Proc
+ return definition.call(x, start_tick, duration).cap_min_max(0, 1)
+ end
+
+ raise <<-S
+ * ERROR:
+ I don't know how to execute easing function with definition #{definition}.
+
+ S
+ end
+
+ def self.identity x
+ x
+ end
+
+ def self.flip x
+ 1 - x
+ end
+
+ def self.quad x
+ x * x
+ end
+
+ def self.cube x
+ x * x * x
+ end
+
+ def self.quart x
+ x * x * x * x * x
+ end
+
+ def self.quint x
+ x * x * x * x * x * x
+ end
+ end
+ end
+
+ Easing = GTK::Easing
+
+#+end_src
+
+* geometry.rb
#+begin_src ruby
+ # ./dragon/geometry.rb
# coding: utf-8
# Copyright 2019 DragonRuby LLC
# MIT License
@@ -22002,8 +24702,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* ./dragon/grid.rb
+* grid.rb
#+begin_src ruby
+ # ./dragon/grid.rb
# coding: utf-8
# Copyright 2019 DragonRuby LLC
# MIT License
@@ -22196,8 +24897,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* ./dragon/inputs.rb
+* inputs.rb
#+begin_src ruby
+ # ./dragon/inputs.rb
# coding: utf-8
# Copyright 2019 DragonRuby LLC
# MIT License
@@ -22868,8 +25570,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* ./dragon/log.rb
+* log.rb
#+begin_src ruby
+ # ./dragon/log.rb
# coding: utf-8
# Copyright 2019 DragonRuby LLC
# MIT License
@@ -22899,19 +25602,19 @@ Follows is a source code listing for all files that have been open sourced. This
class Log
def self.write_to_log_and_puts *args
return if $gtk.production
- $gtk.append_file 'logs/log.txt', args.join("\n") + "\n"
+ $gtk.append_file_root 'logs/log.txt', args.join("\n") + "\n"
args.each { |obj| $gtk.log obj, self }
end
def self.write_to_log_and_print *args
return if $gtk.production
- $gtk.append_file 'logs/log.txt', args.join("\n")
+ $gtk.append_file_root 'logs/log.txt', args.join("\n")
Object.print(*args)
end
def self.puts_important *args
return if $gtk.production
- $gtk.append_file 'logs/log.txt', args.join("\n")
+ $gtk.append_file_root 'logs/log.txt', args.join("\n")
$gtk.notify! "Important notification occurred."
args.each { |obj| $gtk.log obj }
end
@@ -23137,8 +25840,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* ./dragon/numeric.rb
+* numeric.rb
#+begin_src ruby
+ # ./dragon/numeric.rb
# coding: utf-8
# Copyright 2019 DragonRuby LLC
# MIT License
@@ -23784,8 +26488,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* ./dragon/runtime/framerate_diagnostics.rb
+* runtime/framerate_diagnostics.rb
#+begin_src ruby
+ # ./dragon/runtime/framerate_diagnostics.rb
# Copyright 2019 DragonRuby LLC
# MIT License
# framerate_diagnostics.rb has been released under MIT (*only this file*).
@@ -23954,8 +26659,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* ./dragon/string.rb
+* string.rb
#+begin_src ruby
+ # ./dragon/string.rb
# coding: utf-8
# Copyright 2019 DragonRuby LLC
# MIT License
@@ -24060,8 +26766,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* ./dragon/tests.rb
+* tests.rb
#+begin_src ruby
+ # ./dragon/tests.rb
# coding: utf-8
# Copyright 2019 DragonRuby LLC
# MIT License
@@ -24204,8 +26911,9 @@ Follows is a source code listing for all files that have been open sourced. This
#+end_src
-* ./dragon/trace.rb
+* trace.rb
#+begin_src ruby
+ # ./dragon/trace.rb
# coding: utf-8
# Copyright 2019 DragonRuby LLC
# MIT License
@@ -24273,7 +26981,7 @@ Follows is a source code listing for all files that have been open sourced. This
@traced_classes.clear
$trace_enabled = false
if !$gtk.production
- $gtk.write_file 'logs/trace.txt', "Add trace!(SOMEOBJECT) to the top of ~tick~ and this file will be populated with invocation information.\n"
+ $gtk.write_file_root 'logs/trace.txt', "Add trace!(SOMEOBJECT) to the top of ~tick~ and this file will be populated with invocation information.\n"
end
end
@@ -24295,9 +27003,9 @@ Follows is a source code listing for all files that have been open sourced. This
if $trace_puts.length > 0
text = $trace_puts.join("")
if pad_with_newline
- $gtk.append_file 'logs/trace.txt', "\n" + text.strip
+ $gtk.append_file_root 'logs/trace.txt', "\n" + text.strip
else
- $gtk.append_file 'logs/trace.txt', text.strip
+ $gtk.append_file_root 'logs/trace.txt', text.strip
end
end
$trace_puts.clear