Files
infinitefusion-e18/Data/Scripts/017_Minigames/003_Minigame_SlotMachine.rb

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