mirror of
https://github.com/infinitefusion/infinitefusion-e18.git
synced 2025-12-06 06:01:46 +00:00
410 lines
13 KiB
Ruby
410 lines
13 KiB
Ruby
################################################################################
|
|
# "Slot Machine" mini-game
|
|
# By Maruno
|
|
#-------------------------------------------------------------------------------
|
|
# Run with: pbSlotMachine(1)
|
|
# - The number is either 0 (easy), 1 (default) or 2 (hard).
|
|
################################################################################
|
|
class SlotMachineReel < BitmapSprite
|
|
attr_accessor :reel
|
|
attr_accessor :toppos
|
|
attr_accessor :spinning
|
|
attr_accessor :stopping
|
|
attr_accessor :slipping
|
|
|
|
SCROLLSPEED = 16 # Must be a divisor of 48
|
|
ICONSPOOL = [[0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7], # 0 - Easy
|
|
[0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 4, 4, 5, 6, 7], # 1 - Medium (default)
|
|
[0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 4, 4, 5, 6, 7]] # 2 - Hard
|
|
SLIPPING = [0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 3]
|
|
|
|
def initialize(x, y, difficulty = 1)
|
|
@viewport = Viewport.new(x, y, 64, 144)
|
|
@viewport.z = 99999
|
|
super(64, 144, @viewport)
|
|
@reel = []
|
|
ICONSPOOL[difficulty].length.times do |i|
|
|
@reel.push(ICONSPOOL[difficulty][i])
|
|
end
|
|
@reel.shuffle!
|
|
@toppos = 0
|
|
@spinning = false
|
|
@stopping = false
|
|
@slipping = 0
|
|
@index = rand(@reel.length)
|
|
@images = AnimatedBitmap.new(_INTL("Graphics/Pictures/Slot Machine/images"))
|
|
@shading = AnimatedBitmap.new("Graphics/Pictures/Slot Machine/ReelOverlay")
|
|
update
|
|
end
|
|
|
|
def startSpinning
|
|
@spinning = true
|
|
end
|
|
|
|
def stopSpinning(noslipping = false)
|
|
@stopping = true
|
|
@slipping = SLIPPING[rand(SLIPPING.length)]
|
|
@slipping = 0 if noslipping
|
|
end
|
|
|
|
def showing
|
|
array = []
|
|
3.times do |i|
|
|
num = @index - i
|
|
num += @reel.length if num < 0
|
|
array.push(@reel[num])
|
|
end
|
|
return array # [0] = top, [1] = middle, [2] = bottom
|
|
end
|
|
|
|
def update
|
|
self.bitmap.clear
|
|
if @toppos == 0 && @stopping && @slipping == 0
|
|
@spinning = @stopping = false
|
|
end
|
|
if @spinning
|
|
@toppos += SCROLLSPEED
|
|
if @toppos > 0
|
|
@toppos -= 48
|
|
@index = (@index + 1) % @reel.length
|
|
@slipping -= 1 if @slipping > 0
|
|
end
|
|
end
|
|
4.times do |i|
|
|
num = @index - i
|
|
num += @reel.length if num < 0
|
|
self.bitmap.blt(0, @toppos + (i * 48), @images.bitmap, Rect.new(@reel[num] * 64, 0, 64, 48))
|
|
end
|
|
self.bitmap.blt(0, 0, @shading.bitmap, Rect.new(0, 0, 64, 144))
|
|
end
|
|
end
|
|
|
|
|
|
|
|
class SlotMachineScore < BitmapSprite
|
|
attr_reader :score
|
|
|
|
def initialize(x, y, score = 0)
|
|
@viewport = Viewport.new(x, y, 70, 22)
|
|
@viewport.z = 99999
|
|
super(70, 22, @viewport)
|
|
@numbers = AnimatedBitmap.new("Graphics/Pictures/Slot Machine/numbers")
|
|
self.score = score
|
|
end
|
|
|
|
def score=(value)
|
|
@score = value
|
|
@score = Settings::MAX_COINS if @score > Settings::MAX_COINS
|
|
refresh
|
|
end
|
|
|
|
def refresh
|
|
self.bitmap.clear
|
|
5.times do |i|
|
|
digit = (@score / (10**i)) % 10 # Least significant digit first
|
|
self.bitmap.blt(14 * (4 - i), 0, @numbers.bitmap, Rect.new(digit * 14, 0, 14, 22))
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
|
|
class SlotMachineScene
|
|
attr_accessor :gameRunning
|
|
attr_accessor :gameEnd
|
|
attr_accessor :wager
|
|
attr_accessor :replay
|
|
|
|
def update
|
|
pbUpdateSpriteHash(@sprites)
|
|
end
|
|
|
|
def pbPayout
|
|
@replay = false
|
|
payout = 0
|
|
bonus = 0
|
|
wonRow = []
|
|
# Get reel pictures
|
|
reel1 = @sprites["reel1"].showing
|
|
reel2 = @sprites["reel2"].showing
|
|
reel3 = @sprites["reel3"].showing
|
|
combinations = [[reel1[1], reel2[1], reel3[1]], # Centre row
|
|
[reel1[0], reel2[0], reel3[0]], # Top row
|
|
[reel1[2], reel2[2], reel3[2]], # Bottom row
|
|
[reel1[0], reel2[1], reel3[2]], # Diagonal top left -> bottom right
|
|
[reel1[2], reel2[1], reel3[0]]] # Diagonal bottom left -> top right
|
|
combinations.length.times do |i|
|
|
break if i >= 1 && @wager <= 1 # One coin = centre row only
|
|
break if i >= 3 && @wager <= 2 # Two coins = three rows only
|
|
wonRow[i] = true
|
|
case combinations[i]
|
|
when [1, 1, 1] # Three Magnemites
|
|
payout += 8
|
|
when [2, 2, 2] # Three Shellders
|
|
payout += 8
|
|
when [3, 3, 3] # Three Pikachus
|
|
payout += 15
|
|
when [4, 4, 4] # Three Psyducks
|
|
payout += 15
|
|
when [5, 5, 6], [5, 6, 5], [6, 5, 5], [6, 6, 5], [6, 5, 6], [5, 6, 6] # 777 multi-colored
|
|
payout += 90
|
|
bonus = 1 if bonus < 1
|
|
when [5, 5, 5], [6, 6, 6] # Red 777, blue 777
|
|
payout += 300
|
|
bonus = 2 if bonus < 2
|
|
when [7, 7, 7] # Three replays
|
|
@replay = true
|
|
else
|
|
if combinations[i][0] == 0 # Left cherry
|
|
if combinations[i][1] == 0 # Centre cherry as well
|
|
payout += 4
|
|
else
|
|
payout += 2
|
|
end
|
|
else
|
|
wonRow[i] = false
|
|
end
|
|
end
|
|
end
|
|
@sprites["payout"].score = payout
|
|
frame = 0
|
|
if payout > 0 || @replay
|
|
if bonus > 0
|
|
pbMEPlay("Slots big win")
|
|
else
|
|
pbMEPlay("Slots win")
|
|
end
|
|
# Show winning animation
|
|
timePerFrame = Graphics.frame_rate / 8
|
|
until frame == Graphics.frame_rate * 3
|
|
Graphics.update
|
|
Input.update
|
|
update
|
|
@sprites["window2"].bitmap&.clear
|
|
@sprites["window1"].setBitmap(sprintf("Graphics/Pictures/Slot Machine/win"))
|
|
@sprites["window1"].src_rect.set(152 * ((frame / timePerFrame) % 4), 0, 152, 208)
|
|
if bonus > 0
|
|
@sprites["window2"].setBitmap(sprintf("Graphics/Pictures/Slot Machine/bonus"))
|
|
@sprites["window2"].src_rect.set(152 * (bonus - 1), 0, 152, 208)
|
|
end
|
|
@sprites["light1"].visible = true
|
|
@sprites["light1"].src_rect.set(0, 26 * ((frame / timePerFrame) % 4), 96, 26)
|
|
@sprites["light2"].visible = true
|
|
@sprites["light2"].src_rect.set(0, 26 * ((frame / timePerFrame) % 4), 96, 26)
|
|
(1..5).each do |i|
|
|
if wonRow[i - 1]
|
|
@sprites["row#{i}"].visible = (frame / timePerFrame).even?
|
|
else
|
|
@sprites["row#{i}"].visible = false
|
|
end
|
|
end
|
|
frame += 1
|
|
end
|
|
@sprites["light1"].visible = false
|
|
@sprites["light2"].visible = false
|
|
@sprites["window1"].src_rect.set(0, 0, 152, 208)
|
|
# Pay out
|
|
loop do
|
|
break if @sprites["payout"].score <= 0
|
|
Graphics.update
|
|
Input.update
|
|
update
|
|
@sprites["payout"].score -= 1
|
|
@sprites["credit"].score += 1
|
|
if Input.trigger?(Input::USE) || @sprites["credit"].score == Settings::MAX_COINS
|
|
@sprites["credit"].score += @sprites["payout"].score
|
|
@sprites["payout"].score = 0
|
|
end
|
|
end
|
|
(Graphics.frame_rate / 2).times do
|
|
Graphics.update
|
|
Input.update
|
|
update
|
|
end
|
|
else
|
|
# Show losing animation
|
|
timePerFrame = Graphics.frame_rate / 4
|
|
until frame == Graphics.frame_rate * 2
|
|
Graphics.update
|
|
Input.update
|
|
update
|
|
@sprites["window2"].bitmap&.clear
|
|
@sprites["window1"].setBitmap(sprintf("Graphics/Pictures/Slot Machine/lose"))
|
|
@sprites["window1"].src_rect.set(152 * ((frame / timePerFrame) % 2), 0, 152, 208)
|
|
frame += 1
|
|
end
|
|
end
|
|
@wager = 0
|
|
end
|
|
|
|
def pbStartScene(difficulty)
|
|
@sprites = {}
|
|
@viewport = Viewport.new(0, 0, Graphics.width, Graphics.height)
|
|
@viewport.z = 99999
|
|
addBackgroundPlane(@sprites, "bg", "Slot Machine/bg", @viewport)
|
|
@sprites["reel1"] = SlotMachineReel.new(64, 112, difficulty)
|
|
@sprites["reel2"] = SlotMachineReel.new(144, 112, difficulty)
|
|
@sprites["reel3"] = SlotMachineReel.new(224, 112, difficulty)
|
|
(1..3).each do |i|
|
|
@sprites["button#{i}"] = IconSprite.new(68 + (80 * (i - 1)), 260, @viewport)
|
|
@sprites["button#{i}"].setBitmap(sprintf("Graphics/Pictures/Slot Machine/button"))
|
|
@sprites["button#{i}"].visible = false
|
|
end
|
|
(1..5).each do |i|
|
|
y = [170, 122, 218, 82, 82][i - 1]
|
|
@sprites["row#{i}"] = IconSprite.new(2, y, @viewport)
|
|
@sprites["row#{i}"].setBitmap(sprintf("Graphics/Pictures/Slot Machine/line%1d%s",
|
|
1 + (i / 2), (i >= 4) ? ((i == 4) ? "a" : "b") : ""))
|
|
@sprites["row#{i}"].visible = false
|
|
end
|
|
@sprites["light1"] = IconSprite.new(16, 32, @viewport)
|
|
@sprites["light1"].setBitmap(sprintf("Graphics/Pictures/Slot Machine/lights"))
|
|
@sprites["light1"].visible = false
|
|
@sprites["light2"] = IconSprite.new(240, 32, @viewport)
|
|
@sprites["light2"].setBitmap(sprintf("Graphics/Pictures/Slot Machine/lights"))
|
|
@sprites["light2"].mirror = true
|
|
@sprites["light2"].visible = false
|
|
@sprites["window1"] = IconSprite.new(358, 96, @viewport)
|
|
@sprites["window1"].setBitmap(sprintf("Graphics/Pictures/Slot Machine/insert"))
|
|
@sprites["window1"].src_rect.set(0, 0, 152, 208)
|
|
@sprites["window2"] = IconSprite.new(358, 96, @viewport)
|
|
@sprites["credit"] = SlotMachineScore.new(360, 66, $player.coins)
|
|
@sprites["payout"] = SlotMachineScore.new(438, 66, 0)
|
|
@wager = 0
|
|
update
|
|
pbFadeInAndShow(@sprites)
|
|
end
|
|
|
|
def pbMain
|
|
frame = 0
|
|
spinFrameTime = Graphics.frame_rate / 4
|
|
insertFrameTime = Graphics.frame_rate * 4 / 10
|
|
loop do
|
|
Graphics.update
|
|
Input.update
|
|
update
|
|
@sprites["window1"].bitmap&.clear
|
|
@sprites["window2"].bitmap&.clear
|
|
if @sprites["credit"].score == Settings::MAX_COINS
|
|
pbMessage(_INTL("You've got {1} Coins.", Settings::MAX_COINS.to_s_formatted))
|
|
break
|
|
elsif $player.coins == 0
|
|
pbMessage(_INTL("You've run out of Coins.\nGame over!"))
|
|
break
|
|
elsif @gameRunning # Reels are spinning
|
|
@sprites["window1"].setBitmap(sprintf("Graphics/Pictures/Slot Machine/stop"))
|
|
@sprites["window1"].src_rect.set(152 * ((frame / spinFrameTime) % 4), 0, 152, 208)
|
|
if Input.trigger?(Input::USE)
|
|
pbSEPlay("Slots stop")
|
|
if @sprites["reel1"].spinning
|
|
@sprites["reel1"].stopSpinning(@replay)
|
|
@sprites["button1"].visible = true
|
|
elsif @sprites["reel2"].spinning
|
|
@sprites["reel2"].stopSpinning(@replay)
|
|
@sprites["button2"].visible = true
|
|
elsif @sprites["reel3"].spinning
|
|
@sprites["reel3"].stopSpinning(@replay)
|
|
@sprites["button3"].visible = true
|
|
end
|
|
end
|
|
if !@sprites["reel3"].spinning
|
|
@gameEnd = true
|
|
@gameRunning = false
|
|
end
|
|
elsif @gameEnd # Reels have been stopped
|
|
pbPayout
|
|
# Reset graphics
|
|
@sprites["button1"].visible = false
|
|
@sprites["button2"].visible = false
|
|
@sprites["button3"].visible = false
|
|
(1..5).each do |i|
|
|
@sprites["row#{i}"].visible = false
|
|
end
|
|
@gameEnd = false
|
|
else # Awaiting coins for the next spin
|
|
@sprites["window1"].setBitmap(sprintf("Graphics/Pictures/Slot Machine/insert"))
|
|
@sprites["window1"].src_rect.set(152 * ((frame / insertFrameTime) % 2), 0, 152, 208)
|
|
if @wager > 0
|
|
@sprites["window2"].setBitmap(sprintf("Graphics/Pictures/Slot Machine/press"))
|
|
@sprites["window2"].src_rect.set(152 * ((frame / insertFrameTime) % 2), 0, 152, 208)
|
|
end
|
|
if Input.trigger?(Input::DOWN) && @wager < 3 && @sprites["credit"].score > 0
|
|
pbSEPlay("Slots coin")
|
|
@wager += 1
|
|
@sprites["credit"].score -= 1
|
|
if @wager >= 3
|
|
@sprites["row5"].visible = true
|
|
@sprites["row4"].visible = true
|
|
elsif @wager >= 2
|
|
@sprites["row3"].visible = true
|
|
@sprites["row2"].visible = true
|
|
elsif @wager >= 1
|
|
@sprites["row1"].visible = true
|
|
end
|
|
elsif @wager >= 3 || (@wager > 0 && @sprites["credit"].score == 0) ||
|
|
(Input.trigger?(Input::USE) && @wager > 0) || @replay
|
|
if @replay
|
|
@wager = 3
|
|
(1..5).each do |i|
|
|
@sprites["row#{i}"].visible = true
|
|
end
|
|
end
|
|
@sprites["reel1"].startSpinning
|
|
@sprites["reel2"].startSpinning
|
|
@sprites["reel3"].startSpinning
|
|
frame = 0
|
|
@gameRunning = true
|
|
elsif Input.trigger?(Input::BACK) && @wager == 0
|
|
break
|
|
end
|
|
end
|
|
frame = (frame + 1) % (Graphics.frame_rate * 4)
|
|
end
|
|
old_coins = $player.coins
|
|
$player.coins = @sprites["credit"].score
|
|
if $player.coins > old_coins
|
|
$stats.coins_won += $player.coins - old_coins
|
|
elsif $player.coins < old_coins
|
|
$stats.coins_lost += old_coins - $player.coins
|
|
end
|
|
end
|
|
|
|
def pbEndScene
|
|
pbFadeOutAndHide(@sprites)
|
|
pbDisposeSpriteHash(@sprites)
|
|
@viewport.dispose
|
|
end
|
|
end
|
|
|
|
|
|
|
|
class SlotMachine
|
|
def initialize(scene)
|
|
@scene = scene
|
|
end
|
|
|
|
def pbStartScreen(difficulty)
|
|
@scene.pbStartScene(difficulty)
|
|
@scene.pbMain
|
|
@scene.pbEndScene
|
|
end
|
|
end
|
|
|
|
|
|
|
|
def pbSlotMachine(difficulty = 1)
|
|
if !$bag.has?(:COINCASE)
|
|
pbMessage(_INTL("It's a Slot Machine."))
|
|
elsif $player.coins == 0
|
|
pbMessage(_INTL("You don't have any Coins to play!"))
|
|
elsif $player.coins == Settings::MAX_COINS
|
|
pbMessage(_INTL("Your Coin Case is full!"))
|
|
else
|
|
pbFadeOutIn {
|
|
scene = SlotMachineScene.new
|
|
screen = SlotMachine.new(scene)
|
|
screen.pbStartScreen(difficulty)
|
|
}
|
|
end
|
|
end
|