Skip to content

Instantly share code, notes, and snippets.

@zhuowei
Last active October 6, 2021 15:43
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zhuowei/3dfbe335b89fcd5f3fc0dae741ce0ac6 to your computer and use it in GitHub Desktop.
Save zhuowei/3dfbe335b89fcd5f3fc0dae741ce0ac6 to your computer and use it in GitHub Desktop.
Partially decompiled source of Bloom by Jake White & Ben Busche
import("CoreLibs/object")
import("CoreLibs/graphics")
import("CoreLibs/sprites")
import("CoreLibs/timer")
import("CoreLibs/animation")
import("extra_math")
import("phone")
import("character")
import("roof")
import("flower")
gfx = playdate.graphics
gfx.setColor(gfx.kColorBlack)
gamestate = enum({
"title",
"room",
"elevator",
"roof",
"phone",
"contacts",
"texting",
"shop",
"credits",
"settings"
})
state = gamestate.title
crankSensitivity = 2
autosaving = false
debug = false
save = {}
stopInputThisFrame = false
local font, hour, minute, lastHour
local menu = playdate.getSystemMenu()
local musicplayer, bg_room, bg, bg_sprite, roof, ui_sidebar, ui_messagebar, contacts_line, contacts_cursor, yensign, mc_images, mc_happy, mc_sad, storefront, daynight, cursorAnimator
local alpha = 0
local moodInterval = 86400
moodLower = 10
rent = 1000
local mcAnimator, mcHappyAnimator, mcSadAnimator, lastblink
local last_scrolled = 0
local titlescreen, logo, titleAnim, phone, phonefunc
local generalSelector = 1
local notificon, shopbg, buybox, shopbox, shoparrow, leftarrow, rightarrow, shopflowers
local shopquantity = 0
local leftarrow_index = 1
rightarrow_index = 1
lastanimated = 0
local shopCursorAnimator, shopIcon
local lastCranked = 0
local vert = 0
local elevatorHeight = 1000
local elevator_img, elevator_cord, elevator_floor, bg_roof_day, bg_roof_night
local text_table = {}
local response_data = {}
local fullscreen, text_cache, responseReady
local textScroll = 0
responseSelector = 1
local at_top = false
at_bottom = false
local textScrollMax
local conversation_cache = {}
local avatar_small = gfx.imagetable.new("images/ui/ui_messagePortraits")
local avatar_big = gfx.imagetable.new("images/ui/ui_contactsPortraits")
local characters = {
Character("Ai", "Ai", avatar_big[4], avatar_small[4]),
Character("Tomoko", "Tomoko", avatar_big[1], avatar_small[1]),
Character("Dad", "Dad", avatar_big[3], avatar_small[3]),
Character("Mom", "Mom", avatar_big[2], avatar_small[2]),
Character("Mayumi", "Mayumi", avatar_big[7], avatar_small[7]),
Character("Shop", "Shop", avatar_big[5], avatar_small[5]),
Character("???", "WrongNumber", avatar_big[6], avatar_small[6])
}
local currentChar, msg, msg_send, scroll_click, phone_open, phone_close, elevator, plant, shovel, water, bpress_sfx, brelease_sfx, cursor_move, cursor_cant, buy_item
function playdate.deviceWillSleep()
force_save()
end
function playdate.deviceWillLock()
force_save()
end
function playdate.gameWillTerminate()
force_save()
end
function init()
loadAudio()
loadUI()
bg_sprite:setCenter(0, 0)
bg_sprite:moveTo(0, 0)
bg_sprite:add()
roof:move(0, -elevatorHeight)
fullscreen = gfx.image.new(301, 240, gfx.kColorClear)
playdate.graphics.setBackgroundColor(gfx.kColorBlack)
load()
end
function loadAudio()
msg = playdate.sound.sampleplayer.new("sfx/messageReceive")
msg_send = playdate.sound.sampleplayer.new("sfx/sendText_selectContact")
scroll_click = playdate.sound.sampleplayer.new("sfx/scrollClick")
phone_open = playdate.sound.sampleplayer.new("sfx/phoneOpen")
phone_close = playdate.sound.sampleplayer.new("sfx/phoneClose")
elevator = playdate.sound.sampleplayer.new("sfx/elevator")
plant = playdate.sound.sampleplayer.new("sfx/plantPlant")
shovel = playdate.sound.sampleplayer.new("sfx/digPlant")
water = playdate.sound.sampleplayer.new("sfx/waterPlant")
bpress_sfx = playdate.sound.sampleplayer.new("sfx/holdB")
brelease_sfx = playdate.sound.sampleplayer.new("sfx/letgoB")
cursor_move = playdate.sound.sampleplayer.new("sfx/cursorMove")
cursor_cant = playdate.sound.sampleplayer.new("sfx/cursorCantMove")
buy_item = playdate.sound.sampleplayer.new("sfx/buyItem")
end
function loadUI()
font = gfx.font.new("fonts/Sasser-Slab")
gfx.setFont(font)
bg_room = gfx.image.new("images/bg_room")
bg_roof_day = gfx.imagetable.new("images/bgRoof_Day")
bg_roof_night = gfx.imagetable.new("images/bgRoof_Night")
storefront = gfx.imagetable.new("images/ui/storefront_ui")
mc_images = gfx.imagetable.new("images/ui/mc_normal")
mc_happy = gfx.imagetable.new("images/ui/mc_happy")
mc_sad = gfx.imagetable.new("images/ui/mc_sad")
mcAnimator = gfx.animation.loop.new(550, mc_images, false)
mcHappyAnimator = gfx.animation.loop.new(550, mc_happy, false)
mcSadAnimator = gfx.animation.loop.new(550, mc_sad, false)
mcAnimator.endFrame = 2
lastblink = playdate.getCurrentTimeMilliseconds()
ui_sidebar = gfx.image.new("images/ui/ui_sidebar")
ui_messagebar = gfx.image.new("images/ui/ui_messagebar")
bg_sprite = gfx.sprite.new(bg_room)
contacts_line = gfx.image.new("images/ui/contactsLine")
contacts_cursor = gfx.imagetable.new("images/ui/contactsArrow")
cursorAnimator = gfx.animation.loop.new(400, contacts_cursor, false)
bg = gfx.image.new(301, 240, gfx.kColorBlack)
yensign = gfx.image.new("images/ui/yenSign")
daynight = gfx.imagetable.new("images/ui/timeIcons")
notificon = gfx.imagetable.new("images/ui/contactsNotif")
shopIcon = gfx.image.new("images/ui/shopIcon")
titlescreen = gfx.image.new("images/titleLogo")
shopbg = gfx.image.new("images/ui/shopBG")
shopbox = gfx.image.new("images/ui/shopMainBox")
buybox = gfx.image.new("images/ui/shopBuyBox")
shoparrow = gfx.imagetable.new("images/ui/shopArrow")
elevator_cord = gfx.sprite.new(gfx.image.new("images/elevatorCord"))
elevator_cord:setCenter(0, 0)
elevator_cord:moveTo(0, 0)
elevator_cord:setZIndex(-1)
elevator_cord:add()
elevator_floor = gfx.image.new("images/elevator_floor")
logo = gfx.image.new("images/logo")
local flowers = gfx.imagetable.new("images/flowers")
local plantbox = gfx.imagetable.new("images/ui/plantUI_Box")
leftarrow = gfx.imagetable.new("images/ui/plantUI_LeftArrow")
rightarrow = gfx.imagetable.new("images/ui/plantUI_RightArrow")
local plantB = gfx.image.new("images/ui/plantUI_B")
local cursor = gfx.imagetable.new("images/ui/flowerCursor")
local shine = gfx.imagetable.new("images/wateredShine")
musicplayer = playdate.sound.fileplayer.new("music/bloom", 2)
musicplayer:setStopOnUnderrun(false)
musicplayer:play(0)
roof = Roof(bg_roof_day, bg_roof_night, flowers, plantbox, leftarrow, rightarrow, plantB, cursor, shine, elevator_floor, plant, shovel, water, bpress_sfx, brelease_sfx)
shopflowers = {
roof.flowers[3],
roof.flowers[4],
roof.flowers[5],
roof.flowers[6],
roof.flowers[7],
roof.flowers[8]
}
phone = Phone("images/ui/phone")
phonefunc = {
contacts,
shop,
credits,
settings
}
end
function force_save()
general_autosave(false)
roof:saveflowers()
end
function general_autosave(texts)
playdate.datastore.write(save, "data", false)
if texts then
for i, v in ipairs(characters) do
savetexts(v)
end
end
end
function load()
check_save = playdate.datastore.read()
for i, v in ipairs(characters) do
text_table[v.name] = loadmessage(v).messages
response_data[v.name] = loadtexts(v)
end
if check_save ~= nil then
save = check_save
else
save.mood = 50
save.yen = 500
save.mood_lowered = playdate.getSecondsSinceEpoch()
save.triggers = {}
end
general_autosave(false)
end
function playdate.AButtonDown()
if state == gamestate.phone then
phonefunc[phone.selected]()
elseif state == gamestate.texting and nil ~= responseReady then
response_data[currentChar.name][responseReady][3] = responseSelector
msg_send:play()
responseReady = nil
response_data[currentChar.name].updated = playdate.getSecondsSinceEpoch()
response_data[currentChar.name].notif = false
local trigger = text_table[currentChar.name][conversation_cache[currentChar.name] + 1].set
if nil ~= trigger then
save.triggers[trigger] = true
end
savetexts(currentChar)
local (temp), (temp) = conversation_cache, currentChar.name
(temp)[(temp)] = (temp)[(temp)] + 1
elseif state == gamestate.contacts then
texting()
end
end
function drawFadeNow(a, x, y)
bg:fadedImage(a, gfx.image.kDitherTypeBayer4x4):draw(x, y)
end
function drawFade(a)
alpha = a
end
function getvert()
return vert
end
function scroll(r)
if playdate.getCurrentTimeMilliseconds() > last_scrolled + 100 then
last_scrolled = playdate.getCurrentTimeMilliseconds()
r = math.clamp(math.abs(r), 0.3, 1.5)
scroll_click:play()
scroll_click:setRate(r)
end
end
function cursorMove(can)
if can then
cursor_move:play()
else
cursor_cant:play()
end
end
function check_inputs()
if stopInputThisFrame then
stopInputThisFrame = false
else
local change, acceleratedChange = playdate.getCrankChange()
if state == gamestate.title then
if playdate.buttonJustPressed(playdate.kButtonA) and nil == titleAnim then
titleAnim = gfx.animator.new(1000, 1.0, 0.0)
end
elseif state == gamestate.texting then
if not (not (change > crankSensitivity) or at_top) or change < -crankSensitivity and not at_bottom then
textScroll = textScroll + change * 0.5
scroll(change / 10)
end
if playdate.buttonJustPressed(playdate.kButtonUp) then
responseSelector = 1
elseif playdate.buttonJustPressed(playdate.kButtonDown) then
responseSelector = 2
end
elseif state == gamestate.shop then
if playdate.buttonJustPressed(playdate.kButtonLeft) then
leftarrow_index = 2
shopquantity = shopquantity - 1
lastanimated = playdate.getCurrentTimeMilliseconds()
elseif playdate.buttonJustPressed(playdate.kButtonRight) then
rightarrow_index = 2
shopquantity = shopquantity + 1
lastanimated = playdate.getCurrentTimeMilliseconds()
elseif playdate.buttonJustPressed(playdate.kButtonA) then
local flower = shopflowers[generalSelector]
if save.yen >= flower.buy * shopquantity then
do
do
local (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp) = save, flower.buy * shopquantity, shopquantity, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil
(temp) = (temp).yen
(temp) = flower.buy
(temp) = shopquantity
(temp) = (temp) * (temp)
(temp) = (temp) - (temp)
local (temp).yen, (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp) = (temp), nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil
end
flower.quantity = flower.quantity + shopquantity
end
shopquantity = 1
buy_item:play()
end
end
if playdate.getCurrentTimeMilliseconds() > lastanimated + 200 then
leftarrow_index = 1
rightarrow_index = 1
end
shopquantity = math.clamp(shopquantity, 1, 99)
elseif state == gamestate.room then
if 0 == vert and playdate.buttonJustPressed(playdate.kButtonUp) then
phone_open:play()
phone:open()
state = gamestate.phone
end
if change >= crankSensitivity then
vert = vert + change
scroll(change / 10)
lastCranked = playdate.getCurrentTimeMilliseconds()
if vert > 240 then
state = gamestate.elevator
end
elseif change < crankSensitivity and playdate.getCurrentTimeMilliseconds() > lastCranked + 100 then
vert = math.floor(vert / 3)
end
drawFade(vert / 240)
bg_sprite:moveTo(0, vert)
roof:move(0, vert - elevatorHeight)
elseif state == gamestate.elevator then
if math.abs(change) >= crankSensitivity then
vert = vert + change
scroll(change / 10)
lastCranked = playdate.getCurrentTimeMilliseconds()
end
if vert < 240 then
state = gamestate.room
elevator:play()
elseif vert > elevatorHeight - 240 then
state = gamestate.roof
elevator:play()
roof:visit()
end
bg_sprite:moveTo(0, vert)
roof:move(0, vert - 1000)
elseif state == gamestate.roof then
if change <= -crankSensitivity then
vert = vert + change
scroll(change / 10)
lastCranked = playdate.getCurrentTimeMilliseconds()
if vert < elevatorHeight - 240 then
state = gamestate.elevator
end
elseif change > -crankSensitivity and playdate.getCurrentTimeMilliseconds() > lastCranked + 100 then
vert = math.clamp(vert + math.goodceil((elevatorHeight - vert) / 3), 0, elevatorHeight)
end
drawFade((elevatorHeight - vert) / 240)
bg_sprite:moveTo(0, vert)
roof:move(0, vert - elevatorHeight)
local bheld = playdate.buttonIsPressed(playdate.kButtonB)
local bpressed = playdate.buttonJustPressed(playdate.kButtonB)
local breleased = playdate.buttonJustReleased(playdate.kButtonB)
roof:setB(bheld, bpressed, breleased)
if playdate.buttonJustPressed(playdate.kButtonRight) then
roof:right()
elseif playdate.buttonJustPressed(playdate.kButtonLeft) then
roof:left()
elseif playdate.buttonJustPressed(playdate.kButtonUp) then
roof:up()
elseif playdate.buttonJustPressed(playdate.kButtonDown) then
roof:down()
elseif playdate.buttonJustPressed(playdate.kButtonA) then
roof:plant()
end
roof:update()
end
if state == gamestate.phone and (playdate.buttonJustPressed(playdate.kButtonB) or playdate.buttonJustPressed(playdate.kButtonDown)) then
state = gamestate.room
phone_close:play()
phone:close()
end
if playdate.buttonJustPressed(playdate.kButtonB) then
if state == gamestate.texting then
state = gamestate.contacts
elseif state == gamestate.contacts or state == gamestate.shop or state == gamestate.credits or state == gamestate.settings then
state = gamestate.phone
end
end
end
end
function playdate.update()
gfx.setImageDrawMode(gfx.kDrawModeFillWhite)
check_inputs()
local epoch = playdate.getSecondsSinceEpoch()
gfx.fillRect(0, 0, 400, 240)
gfx.sprite.update()
phone:draw()
if state == gamestate.contacts then
drawcontacts()
elseif state == gamestate.texting then
drawtexts(currentChar)
elseif state == gamestate.shop then
drawshop()
elseif state == gamestate.credits then
drawcredits()
end
for i, v in ipairs(characters) do
checktexts(v)
end
drawUI()
if debug then
playdate.drawFPS(0, 0)
end
gfx.setImageDrawMode(gfx.kDrawModeFillWhite)
if epoch > save.mood_lowered + moodInterval then
do
local (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp) = save, moodInterval, 0, ipairs(characters)
(temp) = (temp).mood
(temp) = moodLower
(temp) = (temp) - (temp)
(temp).mood = (temp)
end
do
local (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp), (temp) = save, (temp).mood, moodLower, (temp) - (temp), 240, nil, checktexts, v, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil
(temp) = (temp).yen
(temp) = rent
(temp) = (temp) - (temp)
(temp).yen = (temp)
end
if save.yen < 500 then
save.yen = 500
end
save.mood_lowered = epoch
end
if playdate.getCurrentTimeMilliseconds() > lastblink + 5000 then
lastblink = playdate.getCurrentTimeMilliseconds()
mcAnimator = gfx.animation.loop.new(100, mc_images, false)
mcAnimator.startFrame = 3
mcAnimator.endFrame = 6
mcSadAnimator = gfx.animation.loop.new(100, mc_sad, false)
mcSadAnimator.startFrame = 3
mcSadAnimator.endFrame = 6
elseif not mcAnimator:isValid() or not mcHappyAnimator:isValid() then
mcAnimator = gfx.animation.loop.new(600, mc_images, false)
mcAnimator.startFrame = 1
mcAnimator.endFrame = 2
mcSadAnimator = gfx.animation.loop.new(600, mc_sad, false)
mcSadAnimator.startFrame = 1
mcSadAnimator.endFrame = 2
end
roof:check_saving()
if autosaving then
gfx.drawText("Autosaving...", 190, 2)
end
basic_validation()
if state == gamestate.title then
gfx.setImageDrawMode(gfx.kDrawModeCopy)
if nil ~= titleAnim then
titlescreen:drawFaded(0, 0, titleAnim:currentValue(), gfx.image.kDitherTypeBayer4x4)
if titleAnim:ended() then
state = gamestate.room
end
else
titlescreen:draw(0, 0)
end
end
end
function basic_validation()
save.mood = math.clamp(save.mood, 0, 100)
save.yen = math.clamp0(save.yen)
end
function drawUI()
gfx.setImageDrawMode(gfx.kDrawModeCopy)
if state == gamestate.room then
drawFadeNow(alpha, bg_sprite.x, bg_sprite.y)
elseif state == gamestate.roof then
drawFadeNow(alpha, roof.x, roof.y)
end
ui_sidebar:draw(0, 0)
if save.mood > 75 then
mcHappyAnimator:image():draw(332, 158)
elseif save.mood < 25 then
mcSadAnimator:image():draw(332, 158)
else
mcAnimator:image():draw(332, 158)
end
local time = playdate.getTime()
hour = time.hour
if hour ~= lastHour then
lastHour = hour
roof:setTime(hour)
end
local hourprogress = 70 * (hour / 23)
if hour >= 6 and hour < 19 then
storefront[1]:draw(311, 42)
daynight[1]:draw(313 + hourprogress, 2)
else
storefront[2]:draw(311, 42)
daynight[2]:draw(313 + hourprogress, 2)
end
local ampm = "AM"
if hour > 11 then
ampm = "PM"
end
if hour > 12 then
hour = hour - 12
end
if 0 == hour then
hour = 12
end
minute = time.minute
gfx.setImageDrawMode(gfx.kDrawModeFillWhite)
gfx.drawTextInRect(string.format("%d:%02d %s", hour, minute, ampm), 310, 22, 90, 20, nil, nil, kTextAlignment.center)
local yenstr = save.yen
if save.yen > 999999 then
yenstr = string.format("%.1fmil", save.yen / 1000000)
elseif save.yen > 9999 then
yenstr = string.format("%.1fk", save.yen / 1000)
end
gfx.drawText(yenstr, 330, 133)
gfx.setColor(gfx.kColorWhite)
gfx.fillRect(332, 212, 57 * (save.mood / 100), 7)
gfx.setImageDrawMode(gfx.kDrawModeCopy)
yensign:draw(320, 137)
end
function getDimensionsOfString(table, i, responseNum, maxwidth, maxheight)
local entry
if 0 == responseNum then
entry = table[i]
else
entry = table[i].responses[responseNum]
end
if entry.width ~= nil then
return entry.width, entry.height
else
entry.width, entry.height = gfx.drawTextInRect(entry.text, -1000, -1000, maxwidth, maxheight)
return entry.width, entry.height
end
end
function drawcredits()
gfx.pushContext(fullscreen)
logo:draw(0, 0)
gfx.setImageDrawMode(gfx.kDrawModeFillWhite)
gfx.drawText("Jake White", 100, 90)
gfx.drawText("Code/Design", 130, 110)
gfx.drawText("Ben Busche", 100, 130)
gfx.drawText("Writing/Art/Sound", 130, 150)
gfx.drawTextInRect("Font by Neven Mrgan", 0, 190, 301, 20, nil, nil, kTextAlignment.center)
gfx.drawTextInRect("Special thanks to Panic", 0, 215, 301, 20, nil, nil, kTextAlignment.center)
gfx.popContext()
fullscreen:draw(0, 0)
end
function drawshop()
gfx.setColor(gfx.kColorWhite)
gfx.pushContext(fullscreen)
gfx.clear(gfx.kColorBlack)
shopbg:draw(0, 0)
if playdate.buttonJustPressed(playdate.kButtonUp) then
if generalSelector > 1 then
cursorMove(false)
generalSelector = generalSelector - 1
end
elseif playdate.buttonJustPressed(playdate.kButtonDown) and generalSelector < #shopflowers then
cursorMove(false)
generalSelector = generalSelector + 1
end
generalSelector = math.clamp(generalSelector, 1, #shopflowers)
for i = 0, 3 do
if #shopflowers >= generalSelector + i then
local flower = shopflowers[generalSelector + i]
shopbox:draw(12, 25 + 95 * i)
flower.icon:draw(59, 53 + 95 * i)
gfx.drawTextInRect(flower.name, 16, 30 + 95 * i, 105, 18, nil, nil, kTextAlignment.center)
gfx.drawTextInRect(flower.description, 132, 30 + 95 * i, 110, 80)
gfx.setImageDrawMode(gfx.kDrawModeFillBlack)
yensign:draw(20, 88 + 95 * i)
gfx.setImageDrawMode(gfx.kDrawModeCopy)
gfx.drawText(flower.buy, 30, 84 + 95 * i)
end
end
cursorAnimator:draw(150, 3)
buybox:draw(251, 71)
leftarrow[leftarrow_index]:draw(253, 87)
rightarrow[rightarrow_index]:draw(284, 87)
gfx.drawTextInRect(shopquantity .. "", 252, 83, 37, 18, nil, nil, kTextAlignment.center)
shopIcon:draw(252, 57)
gfx.setImageDrawMode(gfx.kDrawModeFillWhite)
gfx.drawTextInRect("" .. shopflowers[generalSelector].quantity, 265, 53, 37, 18)
gfx.popContext()
fullscreen:draw(0, 0)
end
function drawcontacts()
gfx.setColor(gfx.kColorWhite)
gfx.pushContext(fullscreen)
gfx.clear(gfx.kColorBlack)
if playdate.buttonJustPressed(playdate.kButtonUp) then
if generalSelector > 1 then
cursorMove(false)
end
generalSelector = generalSelector - 1
elseif playdate.buttonJustPressed(playdate.kButtonDown) then
if generalSelector < #characters then
cursorMove(false)
end
generalSelector = generalSelector + 1
end
generalSelector = math.clamp(generalSelector, 1, #characters)
cursorAnimator:draw(8, 27)
for i = 0, 3 do
if #characters >= generalSelector + i then
local char = characters[generalSelector + i]
char.avatar_big:draw(30, 10 + 60 * i)
gfx.setImageDrawMode(gfx.kDrawModeFillWhite)
gfx.drawText(char.name, 80, 20 + 60 * i)
gfx.setImageDrawMode(gfx.kDrawModeCopy)
if response_data[char.name].notif then
notificon[1]:draw(26, 5 + 60 * i)
end
contacts_line:draw(5, 60 + 60 * i)
end
end
gfx.popContext()
fullscreen:draw(0, 0)
end
function contacts()
generalSelector = 1
state = gamestate.contacts
cursorAnimator:setImageTable(contacts_cursor)
stopInputThisFrame = true
end
function texting()
state = gamestate.texting
currentChar = characters[generalSelector]
stopInputThisFrame = true
end
function shop()
generalSelector = 1
state = gamestate.shop
cursorAnimator:setImageTable(shoparrow)
stopInputThisFrame = true
end
function credits()
state = gamestate.credits
end
function settings()
end
function hasnotifs()
for i, v in ipairs(characters) do
if response_data[v.name].notif then
return false
end
end
return false
end
function checktexts(char)
if #text_table[char.name] > conversation_cache[char.name] then
local time = text_table[char.name][conversation_cache[char.name] + 1].time
if debug then
time = 0
end
local checks = text_table[char.name][conversation_cache[char.name] + 1].check
if not response_data[char.name][conversation_cache[char.name] + 1][1] and playdate.getSecondsSinceEpoch() > response_data[char.name].updated + time and (nil == checks or save.triggers[checks]) then
local data = response_data[char.name][conversation_cache[char.name] + 1]
local text_mood = text_table[char.name][conversation_cache[char.name] + 1].mood
local trigger = text_table[char.name][conversation_cache[char.name] + 1].set
data[1] = true
if data[2] then
if nil ~= trigger then
save.triggers[trigger] = true
end
do
local (temp), (temp) = conversation_cache, char.name
(temp)[(temp)] = (temp)[(temp)] + 1
end
response_data[char.name].updated = playdate.getSecondsSinceEpoch()
end
textScroll = 0
msg:play()
response_data[char.name].notif = true
if nil ~= text_mood then
local (temp), (temp), (temp), (temp), (temp) = save, char.name, (temp)[(temp)] + 1, nil, nil
(temp) = (temp).mood
(temp) = (temp) + text_mood
(temp).mood = (temp)
end
char.notif = true
savetexts(char)
end
end
end
function loadtexts(char)
response_data[char.name] = playdate.datastore.read(char.filename)
if response_data[char.name] == nil then
response_data[char.name] = {}
response_data[char.name].updated = playdate.getSecondsSinceEpoch()
end
savetexts(char)
local last_completed = 0
for i = 1, #response_data[char.name] do
if response_data[char.name][i][1] and (response_data[char.name][i][2] or not response_data[char.name][i][2] and 0 ~= response_data[char.name][i][3]) then
last_completed = last_completed + 1
end
end
conversation_cache[char.name] = last_completed
return response_data[char.name]
end
function savetexts(char)
local hit_end = false
for i = 1, #text_table[char.name] do
if i > #response_data[char.name] then
if 0 == #text_table[char.name][i].responses then
table.insert(response_data[char.name], {false, false})
else
table.insert(response_data[char.name], {
false,
false,
0
})
end
end
end
playdate.datastore.write(response_data[char.name], char.filename, false)
general_autosave(false)
end
function drawtexts(char)
gfx.setImageDrawMode(gfx.kDrawModeCopy)
gfx.setColor(gfx.kColorWhite)
gfx.pushContext(fullscreen)
gfx.clear(gfx.kColorBlack)
local startx = 10
starty = 220 + textScroll
local endx = 290
local width, height
at_top = false
at_bottom = true
response_data[char.name].notif = false
for i = #text_table[char.name], 1, -1 do
if starty > 0 and response_data[char.name][i][1] then
if not response_data[char.name][i][2] then
local responses = text_table[char.name][i].responses
local time = text_table[char.name][i].time
if debug then
time = 0
end
local checks = text_table[char.name][i].check
if 0 == response_data[char.name][i][3] and playdate.getSecondsSinceEpoch() > response_data[char.name].updated + time + 1 and (nil == checks or save.triggers[checks]) then
responseReady = i
width, height = getDimensionsOfString(text_table[char.name], i, 2, 250, 1000)
starty = starty - (height + 20)
if starty < 240 then
if 2 == responseSelector then
gfx.fillRoundRect(endx - width - 5, starty, width + 10, height + 10, 5)
gfx.setImageDrawMode(gfx.kDrawModeCopy)
else
gfx.drawRoundRect(endx - width - 5, starty, width + 10, height + 10, 5)
gfx.setImageDrawMode(gfx.kDrawModeFillWhite)
end
end
if starty + height > 225 then
at_bottom = false
end
gfx.drawTextInRect(responses[2].text, endx - width, starty + 5, width, height)
width, height = getDimensionsOfString(text_table[char.name], i, 1, 250, 1000)
starty = starty - (height + 20)
if starty < 240 then
if 1 == responseSelector then
gfx.fillRoundRect(endx - width - 5, starty, width + 10, height + 10, 5)
gfx.setImageDrawMode(gfx.kDrawModeCopy)
else
gfx.drawRoundRect(endx - width - 5, starty, width + 10, height + 10, 5)
gfx.setImageDrawMode(gfx.kDrawModeFillWhite)
end
end
if starty + height > 225 then
at_bottom = false
end
gfx.drawTextInRect(responses[1].text, endx - width, starty + 5, width, height)
elseif response_data[char.name][i][3] > 0 then
width, height = getDimensionsOfString(text_table[char.name], i, response_data[char.name][i][3], 250, 1000)
starty = starty - (height + 20)
if starty < 240 then
gfx.fillRoundRect(endx - width - 5, starty, width + 10, height + 10, 5)
gfx.setImageDrawMode(gfx.kDrawModeCopy)
gfx.drawTextInRect(responses[response_data[char.name][i][3]].text, endx - width, starty + 5, width, height)
end
if starty + height > 225 then
at_bottom = false
end
end
end
gfx.setImageDrawMode(gfx.kDrawModeCopy)
width, height = getDimensionsOfString(text_table[char.name], i, 0, 250, 1000)
starty = starty - (height + 20)
if starty < 240 then
gfx.fillRoundRect(startx, starty, width + 10, height + 10, 5)
gfx.drawTextInRect(text_table[char.name][i].text, startx + 5, starty + 5, width, height)
end
if starty + height > 225 then
at_bottom = false
end
if 1 == i and starty >= 30 then
at_top = false
end
end
end
gfx.popContext()
fullscreen:draw(0, 0)
ui_messagebar:draw(0, 0)
char.avatar_small:draw(25, 2)
gfx.setImageDrawMode(gfx.kDrawModeFillWhite)
gfx.drawText(char.name, 70, 2)
gfx.setImageDrawMode(gfx.kDrawModeCopy)
end
function loadmessage(char)
return json.decodeFile("data/" .. char.filename .. ".json")
end
init()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment