Last active
October 6, 2021 15:43
-
-
Save zhuowei/3dfbe335b89fcd5f3fc0dae741ce0ac6 to your computer and use it in GitHub Desktop.
Partially decompiled source of Bloom by Jake White & Ben Busche
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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