main.rb
#!/usr/bin/env ruby
require 'Qt'
require './gameboard.rb'
require './options_dialog.rb'
require './highscore_dialog.rb'
GAMEBOARD_WIDTH = 8
GAMEBOARD_HEIGHT = 5
class RubyVariant < Qt::Variant
# all these shenanigans is necessary to be able to emit
# a hash from a signal. You can emit a ruby class by wrapping it in
# a QVariant, but the built in ruby hash won't work with this, it needs
# to be wrapped inside another class
def initialize value
super()
@value = value
end
def value
@value.value
end
class MyHash
attr_accessor :value
def initialize value
@value = value
end
end
end
class MainWindow < Qt::MainWindow
slots 'moveMove(int,int)'
def initialize
super
resize(750,800)
setWindowTitle "Ribble"
$status_bar = statusBar
statusBar.show()
@previous_game_score = nil
@status_label = Qt::Label.new("tempmsg")
statusBar.addPermanentWidget @status_label
setup_menubar
#load options and high scores
@filename = "ribble.dat"
@high_scores = {:large=>[],
:medium=>[],
:small=>[]}
@options = {:mode=>:classic,:size=>:medium,:piece_type=>:bouncy_balls}
if File.exists? @filename
load_settings_and_scores
else
# create file and put initial data
puts "createing " + @filename + " with " + @options.to_s
save_settings_and_scores
end
@previous_highscore_name = ""
new_game
end
def setup_menubar
quit = Qt::Action.new "&Quit", self
game = menuBar().addMenu "&Game"
new_action = Qt::Action.new "&New Game", self
restart_action = Qt::Action.new "&Restart Game", self
options_action = Qt::Action.new "&Options", self
highscores_action = Qt::Action.new "&High Scores", self
quit_action = Qt::Action.new "&Quit", self
game.addAction new_action
game.addAction restart_action
game.addAction options_action
game.addAction highscores_action
game.addAction quit_action
new_action.connect(SIGNAL :triggered) do
@gameboard = nil
new_game
end
restart_action.connect(SIGNAL :triggered) do
@gameboard = nil
new_game @seed
end
options_action.connect(SIGNAL :triggered) do
options_dialog = OptionsDialog.new self, @options
options_dialog.connect(SIGNAL('options_changed(QVariant)')) do |opt|
@options = opt.value
save_settings_and_scores
new_game
end
options_dialog.exec
end
highscores_action.connect(SIGNAL :triggered) do
HighScoreDialog.new(self, @high_scores).exec
end
quit_action.connect(SIGNAL :triggered) do
Qt::Application.instance.quit
end
about = menuBar().addAction "&About"
about.connect(SIGNAL :triggered) do
Qt::MessageBox.information( self, "About","Ribble, a Same Game clone. By Joe Hufford. 2013")
end
end
def keyPressEvent event
if event.key == Qt::Key_R and event.modifiers == Qt::ControlModifier
new_game @seed
elsif event.key == Qt::Key_N and event.modifiers == Qt::ControlModifier
new_game
end
end
def new_game seed=nil
#determine board size and piece size
gbw,gbh,pcs = 8,5,65 if @options[:size] == :small
gbw,gbh,pcs = 15,10,65 if @options[:size] == :medium
gbw,gbh,pcs = 20,15,50 if @options[:size] == :large
if seed.nil?
@seed = rand 65535
end
@gameboard = Gameboard.new self, gbw, gbh, pcs, @seed, @options[:piece_type] #old gameboard gets gc'd
resize(gbw*pcs, gbh*pcs+50)
@gameboard.connect(SIGNAL 'highlightedPointsChanged(int)') do |val|
statusBar.showMessage(val.to_s)
end
@gameboard.connect(SIGNAL 'pointsChanged(int)') do |val|
str = ""
unless @previous_game_score.nil?
str = "Previous Game: #{@previous_game_score} "
end
@status_label.setText(str + " Current Game: #{val.to_s}")
end
@gameboard.connect(SIGNAL 'done(int,bool)') do |points,cleared|
if cleared
Qt::MessageBox.information( self, "Cleared!","Cleared it baby! 2x bonus!")
points *= 2
end
@previous_game_score = points
new_score = handle_high_score points
if new_score
HighScoreDialog.new(self, @high_scores).exec
end
ask_new_game = Qt::Dialog.new(self) do
setWindowTitle "Your score: #{points.to_s}"
new_game_pb = Qt::PushButton.new "Play New Gameboard"
new_game_pb.setDefault true
new_game_pb.connect(SIGNAL :clicked){done(1)}
repeat_game_pb = Qt::PushButton.new "Play Same Gameboard Again"
repeat_game_pb.connect(SIGNAL :clicked){done(2)}
quit_pb = Qt::PushButton.new "Quit"
quit_pb.connect(SIGNAL :clicked){done(0)}
vl = Qt::VBoxLayout.new do
addWidget new_game_pb
addWidget repeat_game_pb
addWidget quit_pb
end
setLayout vl
end
newggame_response = ask_new_game.exec()
if newggame_response == 1
new_game
elsif newggame_response == 2
new_game @seed
else
Qt::Application.instance.quit
end
end
resizeEvent(nil)
str = ""
unless @previous_game_score.nil?
str = "Previous Game: #{@previous_game_score} "
end
@status_label.setText(str + "Current Game: #{@gameboard.points.to_s}")
setCentralWidget @gameboard
end
def handle_high_score points
high_scores = @high_scores[@options[:size]].sort{|a,b| b[1]<=>a[1]}
lower = high_scores.select{|val| val[1]<points} #top 10 scores that are lower than current score
if (high_scores[0].nil?) or (high_scores.length<10) or (not lower.empty?)
name = Qt::InputDialog.getText self, "New Top Ten Score", "You scored #{points}\nEnter your name", Qt::LineEdit::Normal, @previous_highscore_name
@previous_highscore_name = name
#delete the lowest high score
#store new high score
if high_scores.length == 10
high_scores.insert(10-lower.length,[name,points])
high_scores.pop
else
high_scores << [name,points]
end
@high_scores[@options[:size]] = high_scores
save_settings_and_scores
return true
end
false
end
def save_settings_and_scores
File.open @filename,"w" do |f|
Marshal.dump @options, f
Marshal.dump @high_scores, f
end
end
def load_settings_and_scores
File.open @filename,"r" do |f|
@options = Marshal.load f
@high_scores = Marshal.load f
end
end
def resizeEvent(event)
puts "MainWindow resizeEvent#{width} #{height}"
@gameboard.window_resize(self.width,self.height-(menuBar.height+statusBar.height))
end
end
Qt::Application.new(ARGV) do
mainwindow = MainWindow.new
mainwindow.show
exec
end