#include "script/common.lua" #include "game.lua" #include "score.lua" #include "ui_helpers.lua" #include "ui_extensions.lua" #include "debug.lua" gUiScaleUpFactor = 0 gSubjectPos = 0 gCurrentMessage = 0 gSelectedMessage = 0 gLevelScale = nil gTabScroll = 0 gMissionSelected = nil gMissionViewed = nil gMissionHighlighted = nil gMissionScale = 0 gLevelSelected = nil gLevelViewed = nil gLevelHighlighted = nil gLevelScale = 0 gMessageSelected = nil gMessageAttachmentScale = 0 gMessageRightPanelScaleOnSelect = 0 gMessageScale = 0 gRankInfoScale = 0 gCashInfoScale = 0 gNoCash = nil gCash = nil gToolSelected = nil gToolOutput = nil gToolScale = 0 gHoverTop = nil gHoverDebug = nil gHoverScore = nil gHoverCash = nil gDebugScale = 0 gTimeSinceMessageRead = nil gShowLargeUI = nil gRankInfoHeight = nil gEarnCashWindowWidth = nil gEarnCashWindowHeight = nil gToolRightPanelScaleOnSelect = nil gToolDescWidth = nil gToolDescHeight = nil gSkipMissionJustPressed = nil gNoLoadingScreen = false ----------- -- UTILITY FUNCTIONS ----------- function setFont(t, c) if t == "h1" then UiFont("bold.ttf", 42) end if t == "h1.5" then UiFont("bold.ttf", 32) end if t == "h2" then UiFont("bold.ttf", 26) end if t == "button" then UiFont("regular.ttf", 24) end if t == "p" then UiFont("regular.ttf", 23) end if t == "name" then UiFont("bold.ttf", 23) end if c == "mark" then Ui.Color(Ui.Style.Color.Mark) elseif c == "dim" then Ui.Color(Ui.Style.Color.Dim) -- selected elseif c == "sel" then Ui.Color(Ui.Style.Color.Yellow) elseif c ~= "nocolor" then Ui.Color(Ui.Style.Color.White) end end function UiListEx(w, h, items, state, scrollUp, scrollDown) local contentHeight = state.contentSpan if isGamepadInUse() then if InputDown(scrollUp) then state:addOffset(InputValue(scrollUp) * 8, h, contentHeight, true) end if InputDown(scrollDown) then state:addOffset(-InputValue(scrollDown) * 8, h, contentHeight, true) end end UiIgnoreNavigation() UiList(w, h, items, state) end function indexOf(array, value) for i, v in ipairs(array) do if v == value then return i end end return nil end function isGamepadInUse() return GetString("game.input.curdevice") == "gamepad" end function forGamepad(f) if isGamepadInUse() then UiPush() UiResetColor() f() UiPop() return true end return false end ----------- -- CHECK FUNCTIONS ----------- function hasUnreadMessages() local messages = ListKeys("savegame.message") for i=1,#messages do if GetInt("savegame.message."..messages[i]) == 1 then return true end end return false end function inCarib() --Evaluate if we're in caribbean hub based on level path return string.find(GetString("game.levelpath"), "hub_carib") end function isMessageReceived(messageId) return GetInt("savegame.message."..messageId) > 0 end function isMessageRead(messageId, delay) if not delay then delay = 0 end return GetInt("savegame.message."..messageId) == 2 and (delay == 0 or gTimeSinceMessageRead > delay) end function isMissionCompleted(missionId) return missionId and getMissionScore(missionId) > 0 end function isSideMission(missionId) local m = gMissions[missionId] return m and m.sidemission end function isMissionInMessageCompleted(messageId) return isMissionCompleted(gMessages[messageId].mission) end function getTotalScore() local score = 0 local missions = ListKeys("savegame.mission") for i=1,#missions do score = score + GetInt("savegame.mission."..missions[i]..".score") end return score end function getUnfinishedMissionCount(levelId) local count = 0 for id,mission in pairs(gMissions) do if mission.level == levelId then if GetBool("savegame.mission."..id) and GetInt("savegame.mission."..id..".score") == 0 then count = count + 1 end end end return count end function getRank(score) local name for i=1,#gRanks do if score >= gRanks[i].score then name = gRanks[i].name end end return name end function maxRankTextWidth() local result = 0 for i=1,#gRanks do result = math.max(GetTextSize(gRanks[i].name), result) end return math.max(result, GetTextSize(GetTranslatedStringByKey("N_NEXT_RANK"))) end function receiveMessage(messageId) UiSound("terminal/new-message.ogg") SetInt("savegame.message."..messageId, 1) end function unlockMission(missionId) if missionId == nil or missionId == "" then return end SetInt("savegame.mission."..missionId, 1) syncActivities(missionId, false, false) end function isMissionUnlocked(missionId) return GetInt("savegame.mission."..missionId) == 1 end function getLevelMissions(level) local missions = ListKeys("savegame.mission") local levelMissions = {} for i=1,#missions do local missionId = missions[i] if gMissions[missionId] then if gMissions[missionId].level == level then levelMissions[#levelMissions+1] = missionId end end end return levelMissions end function getUnlockedLevels() local missions = ListKeys("savegame.mission") local levels = {} local tmp = {} for i=1,#missions do local missionId = missions[i] if gMissions[missionId] then local level = gMissions[missionId].level if level ~= "" and tmp[level] == nil then tmp[level] = 1 levels[#levels+1] = level end end end return levels end function getMissionScore(missionId) return GetInt("savegame.mission."..missionId..".score") end function getMessageForMission(missionId) for id,msg in pairs(gMessages) do if msg.mission == missionId then return msg end end return nil end function hasRank(rank) for i=1,#gRanks do if string.lower(gRanks[i].name) == string.lower(rank) then return getTotalScore() >= gRanks[i].score end end return false end function startMission(id) if gMissions[id] then StartLevel(id, gMissions[id].file, gMissions[id].layers, gNoLoadingScreen) end end ----------- -- TERMINAL UI ----------- Terminal = { currentPanel = {}, SetTab = function (self, tab) UiSound("terminal/tab.ogg") self.currentPanel = tab SetValue("gTabScroll", tab.TabScroll, "cosine", 0.4) end, Button = function(self, text, callback) local w,_ = GetTextSize((text)) if UiTextButton(text) then callback() end UiTranslate(w + self.Tabs.marginRight,0) end, TabButton = function (self, tab) if self.currentPanel == tab then Ui.Color(Ui.Style.Terminal.Tabs.TextSelected) else Ui.Color(Ui.Style.Terminal.Tabs.Text) end self:Button(tab.Name, function() self:SetTab(tab) end) end, ShowMessage = function(self, id) self:SetTab(self.messages) self.messages.rightPanel:Select(id) end } Terminal.Top = {} Terminal.Top.Rank = { Draw = function() end } Terminal.Top.Tabs = { content = {}, wholeSize = 0, marginRight = 50, Draw = function (self) UiFont("bold.ttf", 42) self.wholeSize = self.marginRight * (#self.content - 1) for _, button in pairs(self.content) do self.wholeSize = self.wholeSize + GetTextSize(button.Name) end for _, tab in pairs(self.content) do Terminal:TabButton(tab) end end } Terminal.Top.Cash = { Draw = function() end } Terminal.Tabs = Terminal.Top.Tabs Terminal.messages = { Name = "loc@UI_BUTTON_MESSAGES", TabScroll = 0, leftPanel = {}, rightPanel = {}, ----------------------------------- scaleYMessageWindow = 1, ----------------------------------- } table.insert(Terminal.Tabs.content, 1, Terminal.messages) Terminal.missions = { Name = "loc@UI_BUTTON_MISSIONS", TabScroll = 1, LeftPanelWidth = 630, RightPanelWidth = 800, Height = 800, } table.insert(Terminal.Tabs.content, 2, Terminal.missions) -- TODO: It is necessary to set the height of the scroll bar --in a more appropriate way, this is a dynamic value that -- depends on the scaling of the interface. function Terminal:CreateScrollBar(height) --assert(height ~= nil) height = height or 650 return { w = 8.0, h = 127.0, draw = function(self) UiPush() UiTranslate(2.0, 0) UiColor(1, 1, 1, 1) UiImageBox("common/rect_c#ffffff_o1.00_cr3.png", self.w, self.h, 3, 3) UiPop() end, }, { w = 12.0, h = height, draw = function(self) UiPush() UiColor(1, 1, 1, 1) UiImageBox("common/rect_c#525252_o1.00_cr4.png", self.w, self.h, 4, 4) UiPop() end, } end Terminal.tools = { Name = "loc@UI_BUTTON_TOOLS", TabScroll = 2, LeftPanelWidth = 550, RightPanelWidth = 800, Height = 800, ScrollBar = UiCreateScrollBar(Terminal:CreateScrollBar()) } table.insert(Terminal.Tabs.content, 3, Terminal.tools) for _, tab in ipairs(Terminal.Tabs.content) do tab.SetCurrent = function(self) Terminal:SetTab(self) end end Terminal.currentPanel = Terminal.messages ----------- -- TERMINAL UTILITY FUNCTIONS ----------- function setTab(tab) UiSound("terminal/tab.ogg") gTabSelected = tab if tab == "messages" then SetValue("gTabScroll", 0, "cosine", 0.4) elseif tab == "missions" then SetValue("gTabScroll", 1, "cosine", 0.4) elseif tab == "tools" then SetValue("gTabScroll", 2, "cosine", 0.4) end end function showMessageByMission(mission) for id,_ in pairs(gMessages) do if gMessages[id].mission == mission then setTab("messages") return end end end function showMission(mission) Terminal.missions:SetCurrent() if gLevelSelected ~= gMissions[mission].level then gLevelHighlighted = gMissions[mission].level gLevelSelected = "" SetValue("gLevelScale", 0) end if gMissionSelected ~= mission then gMissionHighlighted = mission gMissionSelected = "" SetValue("gMissionScale", 0) end end function drawStars(stars, starsMax) UiPush() UiTranslate(-11, -8) UiAlign("center middle") UiColor(1, 0.9, 0) for i=1, stars do UiImage("terminal/star.png") UiTranslate(-24, 0) end if stars < starsMax then UiColor(.4, .4, .4) for i=1, starsMax-stars do UiImage("terminal/star.png") UiTranslate(-24, 0) end end UiPop() end -- Helper to drawTools function drawBars(v, ma) UiPush() local barWidth = 16 local totalWidth = 8 * (barWidth + 4) UiTranslate(-totalWidth, 0) Ui.Color(0xD9D9D9) for i=1,v do UiImage("common/tool-update-filled.png") UiTranslate(barWidth + 4, 0) end for i=v+1,ma do UiPush() Ui.Color(0x727272) UiImage("common/tool-update-filled.png") UiPop() UiTranslate(barWidth + 4, 0) end UiPop() return totalWidth end function selectTool(id) gToolSelected = id gToolOutput = 0 SetValue("gToolScale", 1, "cosine", 0.3) if gToolScale == 1 then gToolRightPanelScaleOnSelect = 0.95 SetValue("gToolRightPanelScaleOnSelect", 1, "bounce", 0.5) else gToolRightPanelScaleOnSelect = 1 end end ----------- -- TERMINAL IMPLEMENTATION ----------- function Terminal:draw() UiPush() UiIgnoreNavigation() local x = -1920 * gTabScroll UiTranslate(x, 0) if gTabScroll < 1 then self.messages:Draw() end UiTranslate(1920, 0) if gTabScroll > 0 and gTabScroll < 2 then self.missions:Draw() end UiTranslate(1920, 0) if gTabScroll > 1 then self.tools:Draw() end UiPop() UiPush() UiIgnoreNavigation() self.Top:Draw() UiPop() if InputPressed("menu_cancel") and (Terminal.currentPanel ~= self.missions or gLevelScale == 0) then SetPlayerScreen(0) end if not GetBool("game.player.usescreen") then if hasUnreadMessages() then UiPush() if math.fmod(GetTime(), 1.0) > 0.4 then UiTranslate(UiCenter(), UiMiddle()-100) UiAlign("center middle") UiWindow(700, 150) UiTranslate(UiCenter(), UiMiddle()) UiColor(.4,.4,.4) UiImageBox("terminal/levelbox.png", UiWidth(), UiHeight(), 5, 17) setFont("h1") UiScale(2.0) UiColor(1,1,1) UiText("loc@UI_TEXT_NEW_MESSAGE") end UiPop() end else UiSetCursorState(UI_CURSOR_HIDE) -- we draw mouse by ourselves, but not lock it end local index = indexOf(self.Top.Tabs.content, self.currentPanel) if InputPressed("menu_prev") then if index ~= nil and index > 1 then self.SetTab(self, self.Top.Tabs.content[index - 1]) end end if InputPressed("menu_next") then if index ~= nil and index < #self.Top.Tabs.content then self.SetTab(self, self.Top.Tabs.content[index + 1]) end end end function Terminal.Top:Draw() UiPush() local topHeight = 58 UiScale(gUiScaleUpFactor) UiColor(0.1,0.1,0.1) UiRect(UiWidth(), topHeight) gHoverTop = UiIsMouseInRect(UiWidth(), topHeight) setFont("h1") UiTranslate(UiCenter()/gUiScaleUpFactor - self.Tabs.wholeSize / 2, 25) UiAlign("middle") if hasUnreadMessages() and math.fmod(GetTime(), 1.0) > 0.5 then UiPush() UiColor(.5, .8, 1) UiTranslate(-20, 5) UiImage("terminal/new-message-dot.png") UiPop() end UiTranslate(0, 5) forGamepad(function () UiTranslate(-45, 0) UiAlign("right middle") UiText("[[menu:menu_prev;iconsize=50,50]]") end) self.Tabs:Draw() forGamepad(function () UiAlign("left middle") UiText("[[menu:menu_next;iconsize=50,50]]") end) UiPop() UiPush() UiScale(gUiScaleUpFactor) setFont("name") local score = getTotalScore() local strScore = tostring(score) local strScoreWidth = GetTextSize(strScore) local cash = GetInt("savegame.cash") gCash = gCash + (cash-gCash)*GetTimeStep()*5 if math.abs(gCash - cash) < 1 then gCash = cash end local rw,_ = GetTextSize(getRank(score)) local scorePos = 0 local textScore = GetTranslatedStringByKey("UI_TEXT_SCORE") local rankFrameWidth = 12 + GetTextSize(textScore) + 8 + strScoreWidth + 40 + rw + 40 local rankFrameHeight = 38 UiPush() local Align = function(a) UiAlign((a or "").." middle") end UiTranslate(40, 10) UiColor(.2,.2,.2) UiImageBox("common/box-solid-10.png", rankFrameWidth, rankFrameHeight, 10, 10) if gHoverScore then UiColor(1,1,1) else UiColor(.8,.8,.8) end UiTranslate(12, rankFrameHeight/2) Align("left") local w = UiText(textScore) UiTranslate(w + 8, 0) scorePos = UiGetRelativePos() + strScoreWidth scorePos = scorePos - 40 UiText(strScore) UiTranslate(strScoreWidth+40, 0) UiText(getRank(score)) UiPop() UiPush() local padding = 20 UiTranslate(UiWidth()/gUiScaleUpFactor - 2*padding, 10) UiAlign("right") UiIsMouseInRect(155+rw, rankFrameHeight) UiColor(.2,.2,.2) local textWidth = UiGetTextSize(GetTranslatedStringByKey("UI_TEXT_CASH_$," .. math.floor(gCash))) UiImageBox("common/box-solid-10.png", textWidth + 2 * padding, rankFrameHeight, 10, 10) if gHoverCash then UiColor(1,1,1) else UiColor(.8,.8,.8) end UiTranslate(0, rankFrameHeight / 2) UiPush() Align("right") UiTranslate(-padding, 0) UiText(GetTranslatedStringByKey("UI_TEXT_CASH_$," .. math.floor(gCash))) UiPop() if gNoCash > 0 and Terminal.currentPanel == Terminal.tools then UiColor(0.8,0.8,0.8,gNoCash) UiTranslate(0, 2 * UiFontHeight()) UiText("loc@UI_TEXT_NOT_ENOUGH") end UiPop() local overScore = UiIsMouseInRect(195+rw, topHeight) if overScore and not gHoverScore then SetValue("gRankInfoScale", 1, "bounce", 0.4) elseif not overScore and gHoverScore then SetValue("gRankInfoScale", 0, "easein", 0.2) end gHoverScore = overScore if gRankInfoScale > 0 then UiPush() UiTranslate(40, 55) UiScale(1, gRankInfoScale) UiColor(.2,.2,.2) local imageBoxWidth = scorePos + 40 + maxRankTextWidth() + 20 if imageBoxWidth < rankFrameWidth then imageBoxWidth = rankFrameWidth end UiImageBox("common/box-solid-10.png", imageBoxWidth, gRankInfoHeight, 10, 10) UiPush() UiColor(.8, .8, .8) UiTranslate(0, 30) local didCurrent = false for i=#gRanks, 1, -1 do local valid = true local s = gRanks[i].score local n = gRanks[i].name if score < s then if score < gRanks[i-1].score then valid = false else n = GetTranslatedStringByKey("N_NEXT_RANK") UiColor(0.4, 0.4, 0.4) end else if didCurrent then UiColor(.7,.7,.7) else UiColor(1,1,1) didCurrent = true end end if valid then UiPush() UiTranslate(scorePos, 0) UiAlign("right") UiText(s) UiTranslate(40, 0) UiAlign("left") UiText(n) UiPop() UiTranslate(0, 24) end end UiTranslate(10, 10) setFont("p") UiColor(.6, .6, .6) UiWordWrap(imageBoxWidth - 20) UiText(GetTranslatedStringByKey("UI_TEXT_COMPLETE_MISSIONS"), true) _,gRankInfoHeight = UiGetRelativePos() UiPop() UiPop() end UiPush() UiTranslate(UiWidth()/gUiScaleUpFactor-190, 0) local overCash = UiIsMouseInRect(190, topHeight) UiPop() if overCash and not gHoverCash then SetValue("gCashInfoScale", 1, "bounce", 0.4) elseif not overCash and gHoverCash then SetValue("gCashInfoScale", 0, "easein", 0.2) end gHoverCash = overCash if gCashInfoScale > 0 then UiPush() --[[ NOTE: There is a word wrapping issue in Asian languages (UiWordWrap can't fit 200 text in this case for some reason), so a workaround is to increase the window width depending on the width of the text in Asian languages ]] --[[ FIXME: UiWordWrap incorrect on Asian ]] local preferredWidth = 240 UiTranslate(UiWidth()/gUiScaleUpFactor-((gEarnCashWindowWidth or 0) + 2 * padding), 55) UiScale(1, gCashInfoScale) UiColor(.2,.2,.2) UiImageBox("common/box-solid-10.png", gEarnCashWindowWidth, gEarnCashWindowHeight, 10, 10) UiPush() UiColor(.8, .8, .8) UiTranslate(20, 30) setFont("p") UiColor(.6, .6, .6) UiWordWrap(preferredWidth - 2 * padding) gEarnCashWindowWidth,_ = UiText("loc@UI_TEXT_EARN_CASH", true) gEarnCashWindowWidth = math.max(preferredWidth, (gEarnCashWindowWidth or 0) + 2 * padding) _, gEarnCashWindowHeight = UiGetRelativePos() UiPop() UiPop() end UiPop() end function Terminal.messages:showByMission(mission) for id,_ in pairs(gMessages) do if gMessages[id].mission == mission then self.Select(id) self:SetCurrent() return end end end function controllerHint() forGamepad(function () UiResetColor() UiTranslate(UiWidth() / 2, UiHeight() - 60) local hints = {} if Terminal.currentPanel == Terminal.messages and Terminal.messages.rightPanel.ScrollBar and Terminal.messages.rightPanel.ScrollBar.isShown then table.insert(hints, { ico = "[[menu:gamepad_right_stick;iconsize=42,42]]", txt = "loc@UI_TEXT_SCROLL"}) end table.insert(hints, { ico = "[[menu:menu_cancel;iconsize=42,42]]", txt = "loc@UI_BUTTON_EXIT" }) UiDrawHintsCentered(hints) end) end function Terminal.messages:Draw() controllerHint() UiPush() self.largerUIscale = 1.0 self.scaleYMessageWindow = 1.0 local windowTop = 140 if isGamepadInUse() then windowTop = 98 end local w = self.leftPanel.WindowWidth + self.rightPanel.WindowWidth*gMessageScale + 20 UiTranslate((UiCenter()/self.largerUIscale-w/2), windowTop) gSelectedMessage = 0 self.leftPanel:Draw() self.rightPanel:Draw() if gSelectedMessage == 0 then gSubjectPos = 0 end UiPop() end Terminal.messages.leftPanel = { WindowWidth = 548, WindowHeight = 860, ScrollBar = UiCreateScrollBar(Terminal:CreateScrollBar()), Draw = function(self) local scaleYMessageWindow = Terminal.messages.scaleYMessageWindow if self.ScrollBar.isShown then self.WindowWidth = 560 end UiPush() UiColor(.2, .2, .2) UiImageBox( "common/box-solid-10.png", self.WindowWidth, self.WindowHeight / scaleYMessageWindow, 10, 10 ) setFont("h1.5") local messageFrameWidth = 508 local messageFrameHeight = 72 UiTranslate(20,50) UiPush() UiFont("medium.ttf", 36) UiText("loc@UI_TEXT_INBOX") UiPop() UiTranslate(0, 24) local itemWidth = 508 local itemHeight = 80 local messages = ToListItems( ReverseTable(ListKeys("savegame.message")), function() return itemWidth, itemHeight end, function(message, i) local id = message.data local msg = gMessages[id] local client = gClients[msg.from] if not client then print(GetTranslatedStringByKey("UNKNOWN_CLIENT") .. msg.from) end local fromName = client.name local image = client.image local subject = GetTranslatedStringByKey(msg.subject) local isRead = isMessageRead(id) local mission = msg.mission local hub = msg.hub UiPush() local selected = Terminal.messages.rightPanel.Selected == id local hovered = false if (self.mouseOver and UiIsMouseInRect(messageFrameWidth, messageFrameHeight)) then hovered = true if (InputPressed("lmb") or InputPressed("menu_accept")) then UiSound("terminal/message-select.ogg") Terminal.messages.rightPanel:Select(id) gMessageSelected = id end end if selected or hovered or not isRead then Ui.Color(Ui.Style.Terminal.Messages.Selected) else Ui.Color(Ui.Style.Terminal.Messages.Background) end UiImageBox("common/box-solid-6.png", messageFrameWidth-2, messageFrameHeight, 6, 6) UiColor(1, 1, 1) local imageWidth,imageHeight = UiGetImageSize(image) local imageScale = 0.875 UiPush() UiTranslate(9, 9) if isRead then UiPush() UiScale(imageScale, imageScale) UiBeginFrame() UiImage(image) imageWidth,imageHeight = UiEndFrame() UiPop() else imageWidth = imageWidth * imageScale imageHeight = imageHeight * imageScale UiPush() UiColor(.5, .8, 1) UiPush() local dot = "terminal/new-message-dot.png" local dw, dh = UiGetImageSize(dot) UiTranslate((imageWidth - dw) / 2, (imageHeight - dh) / 2) UiImage(dot) UiPop() --DebugQuad(imageWidth, imageHeight) UiPop() end UiPop() UiPush() UiTranslate(imageWidth / imageScale+10, 10) local color = selected and "sel" or "" setFont("name", color) UiText(fromName) local width = 370 local height = 32 local subjectTextWidth, _ = GetTextSize(subject) local subjectDeltaWidth = subjectTextWidth - width if subjectDeltaWidth > 0 then UiWindow(width, itemHeight, true, true) end if UiIsMouseInRect(width, itemHeight) then if gCurrentMessage ~= id then gSubjectPos = 0 gCurrentMessage = id end if subjectDeltaWidth > 0 then UiTranslate(-gSubjectPos, height) if gSubjectPos < subjectDeltaWidth then gSubjectPos = gSubjectPos + 1 end else UiTranslate(0, height) end gSelectedMessage = id else UiTranslate(0, height) end setFont("p") UiText(subject) UiPop() if mission then UiPush() UiAlign("middle") UiTranslate(messageFrameWidth - 50, messageFrameHeight / 2) local completed = isMissionCompleted(mission) if completed then UiPush() Ui.Color(0x66D166) UiImage("terminal/checkmark.png") UiPop() else UiPush() if isSideMission(mission) then Ui.Color(0x9AB4CDCD) UiScale(0.9) else Ui.Color(0xE6E6E6FF) end UiImage("terminal/attachment.png") UiPop() end UiPop() end if hub then UiPush() UiAlign("middle") UiTranslate(messageFrameWidth - 50, messageFrameHeight / 2) UiColor(0.8, 0.7, 0.6, 1) UiImage("terminal/attachment.png") UiPop() end UiPop() end ) self.mouseOver = UiIsMouseInRect(508, 765/scaleYMessageWindow) local contentHeight = 765/scaleYMessageWindow self.ScrollBar.background.h = contentHeight UiIgnoreNavigation() UiListEx(messageFrameWidth+3, contentHeight, messages, self.ScrollBar, "menu_up", "menu_down") UiPop() end } RightPanelInputOverride = { Forced = true } Terminal.messages.rightPanel = { WindowWidth = 970, WindowHeight = 860, Selected = "", MessagePart = 1, MessageOutput = 0, MessageOutputSpeed = 1, MessagePause = 0, DebugMessageContentHeight = false, ScrollBar = nil, Draw = function(self) local scaleYMessageWindow = Terminal.messages.scaleYMessageWindow if self.ScrollBar and self.ScrollBar.isShown then self.WindowWidth = 982 end local windowWidth = self.WindowWidth local windowHeight = self.WindowHeight local messageOffsetX = Terminal.messages.leftPanel.WindowWidth do UiPush() UiTranslate(messageOffsetX + 20, 0) UiScale(gMessageScale, 1) UiColor(.23, .23, .23) UiScale(gMessageRightPanelScaleOnSelect) UiImageBox("common/box-solid-10.png", windowWidth, windowHeight, 10, 10) UiTranslate(20, 50) local mission = "" local tool = "" local hub = "" if self.Selected ~= "" then local msg = gMessages[self.Selected] local name = gClients[msg.from].name local image = gClients[msg.from].image local subject = msg.subject local body = msg.body mission = msg.mission tool = msg.tool hub = msg.hub UiPush() UiTranslate(46, 16) UiAlign("center middle") UiColor(1,1,1) UiPush() UiScale(1.4, 1.4) UiImage(image) UiPop() UiTranslate(60, -10) UiAlign("left") setFont("h1") UiText(name) UiTranslate(0, 45) UiColorFilter(1,1,1,0.8) UiFont("regular.ttf", 36) UiText(subject) UiPop() UiTranslate(0, 80) local partCount = #body local partsHeight = 0 local symbolCount = 930 UiFont("regular.ttf", 27) UiWordWrap(symbolCount) UiAlign("top left") UiScale(1,1) for i=1,partCount do local type = UiTextSymbolsSub(body[i][1], 1, 3) if type == "div" then partsHeight = partsHeight + 4 elseif type == "img" then local _,h = UiGetImageSize(body[i][2]) partsHeight = partsHeight + h elseif type == "txt" then local _,h = GetTextSize(body[i][2]) partsHeight = partsHeight + h + 30 if i == partCount then partsHeight = partsHeight - 20 end end end if self.MessagePause > 0 then self.MessagePause = self.MessagePause - GetTimeStep() else if self.MessageOutput < 1.0 then self.MessageOutput = self.MessageOutput + GetTimeStep() * self.MessageOutputSpeed if self.MessageOutput >= 1.0 then self.MessagePause = 0.15 end else if self.MessagePart < partCount then self.MessagePart = self.MessagePart + 1 self.MessageOutput = 0 local type = UiTextSymbolsSub(body[self.MessagePart][1], 1, 3) if type == "div" then self.MessageOutput = 1 elseif type == "img" then self.MessageOutput = 0 self.MessageOutputSpeed = 2 UiSound("terminal/image.ogg") elseif type == "txt" then local l = string.len(GetTranslatedStringByKey(body[self.MessagePart][2])) if l < 100 then self.MessageOutputSpeed = 4 UiSound("terminal/printout250.ogg") elseif l < 400 then self.MessageOutputSpeed = 2 UiSound("terminal/printout500.ogg") else self.MessageOutputSpeed = 1 UiSound("terminal/printout1000.ogg") end end else if gMessageAttachmentScale == 0 and (mission or tool or hub) then UiSound("terminal/message-mission.ogg") SetValue("gMessageAttachmentScale", 1, "bounce", 0.6) end end end end self.MessageOutputSpeed = self.DebugMessageContentHeight and 100 or self.MessageOutputSpeed local contentWidth = windowWidth - 40 if self.ScrollBar and self.ScrollBar.isShown then contentWidth = contentWidth - 8 end local contentHeight = 632/scaleYMessageWindow self.ScrollBar.background.h = contentHeight UiListEx( contentWidth, contentHeight, {{ w = 900, h = partsHeight, draw = function(_) if self.DebugMessageContentHeight then UiPush() UiColor(1,0,0,0.5) UiRect(self.w, self.h) UiTranslate(0,self.h) UiColor(0,1,0,0.5) UiRect(self.w, 40) UiPop() end for i=1,self.MessagePart do local type = UiTextSymbolsSub(body[i][1], 1, 3) local extra = UiTextSymbolsSub(body[i][1], 5, #body[i][1]) local arg = GetTranslatedStringByKey(body[i][2]) if string.find(extra, "gray") then UiColor(.7, .7, .7) elseif string.find(extra, "green") then UiColor(.3, 1, .3) elseif string.find(extra, "red") then UiColor(1, .3, .3) elseif string.find(extra, "blue") then UiColor(.3, .3, 1) elseif string.find(extra, "yellow") then UiColor(1, 1, .3) elseif string.find(extra, "cyan") then UiColor(.3, 1, 1) elseif string.find(extra, "magenta") then UiColor(1, .3, 1) else UiColor(1, 1, 1) end if type == "txt" then UiPush() UiColorFilter(1,1,1,0.8) if string.find(extra, "h1") then setFont("h1", "nocolor") elseif string.find(extra, "h2") then setFont("h2", "nocolor") else --Ui.Color(Ui.Style.Color.White) UiFont("regular.ttf", 27) end UiFont("regular.ttf", 27) local maxChars = 10000 if i == self.MessagePart then maxChars = self.MessageOutput * string.len(arg) end UiScale(1,1) if self.DebugMessageContentHeight then UiPush() local w1,h1 = GetTextSize(arg) UiColor(1,1,1,0.5) UiRect(w1,h1) UiPop() end local _, h = UiText(arg, false, maxChars) UiPop() UiTranslate(0, h + 30) elseif type == "img" then UiPush() UiAlign("top center") UiTranslate(contentWidth/2 - 8, 8) UiPush() local imgScale = 0.895 UiScale(imgScale) if gShowLargeUI then UiScale(0.8*imgScale) end local w,h = UiImage(arg) UiColor(.25, .25, .25) UiImageBox("common/circle_10x10.png", w, h, 10, 10) if gShowLargeUI then h = h*0.8*imgScale end UiPop() if i == self.MessagePart then UiPush() local bh = h*self.MessageOutput UiTranslate(0, bh) UiColor(0.25,0.25,0.25) UiRect(w, h-bh+1) UiPop() end UiPop() UiTranslate(0, h) elseif type == "div" then UiPush() UiTranslate(0, -8) Ui.Color(0xD9D9D9) UiRect(windowWidth-40, 2) UiTranslate(0, 4) UiPop() end end end }}, self.ScrollBar, "up", "down") end UiPop() if (mission or tool or hub) and gMessageAttachmentScale > 0 then UiPush() setFont("button") UiTranslate(messageOffsetX - 15 + windowWidth / 2.0, windowHeight - 30 / scaleYMessageWindow) UiScale(gMessageAttachmentScale * (1 + math.sin(GetTime()*10)*0.03)) UiButtonImageBox("common/box-outline-6.png", 6, 6, 0.96, 0.96, 0.96) UiButtonHoverColor(hexrgb(Ui.Style.Color.Yellow)) local buttonText = "" if mission and gMissions[mission] then local txt = GetTranslatedStringByKey("TXT_MISSION") if isSideMission(mission) then txt = GetTranslatedStringByKey("TXT_SIDE_MISSION") --UiColor(0.9, 0.95, 1.0) end buttonText = txt .. " - " .. GetTranslatedStringByKey(gMissions[mission].title) UiTranslate(-(UiGetTextSize(buttonText) / 2.0), 0) if UiTextButton(buttonText) then showMission(mission) end elseif tool then buttonText = GetTranslatedStringByKey("UI_BUTTON_TOOL_") .. gTools[tool].name UiTranslate(-(UiGetTextSize(buttonText) / 2.0), 0) if UiTextButton(buttonText) then Terminal.TabButton(Terminal.tools) selectTool(tool) end elseif hub then if hub == "carib" then buttonText = GetTranslatedStringByKey("UI_BUTTON_TRAVEL_TO_ISLANDS") UiTranslate(-(UiGetTextSize(buttonText) / 2.0), 0) if UiTextButton(buttonText) then gDisableEvaluation = true StartLevel("hub30", "hub_carib.xml", "v30") end else buttonText = GetTranslatedStringByKey("UI_BUTTON_TRAVEL_BACK") UiTranslate(-(UiGetTextSize(buttonText) / 2.0), 0) if UiTextButton(buttonText) then gDisableEvaluation = true StartLevel("hub40", "hub.xml", "part2 v40") end end end UiPop() end end end, Select = function(self, id) if gMessages[id].music and GetInt("savegame.message."..id) == 1 then PlayMusic(gMessages[id].music) --gNoLoadingScreen = true -- Would be nice, but there's an audio glitch somewhere end SetInt("savegame.message."..id, 2) SetValue("gMessageScale", 1, "cosine", 0.3) if gMessages[id].mission then unlockMission(gMessages[id].mission) end if self.Selected == id then return end self.ScrollBar = UiCreateScrollBar(Terminal:CreateScrollBar(590)) self.Selected = id self.MessagePart = 0 self.MessageOutput = 1 if gMessageScale == 1 then gMessageRightPanelScaleOnSelect = 0.95 SetValue("gMessageRightPanelScaleOnSelect", 1, "bounce", 0.5) else gMessageRightPanelScaleOnSelect = 1 end SetValue("gMessageAttachmentScale", 0) gTimeSinceMessageRead = 0 end } function Terminal.tools:Draw() controllerHint() local windowWidth = 492 local windowHeight = 860 local rightPanelWidth = 842 local windowTop = 140 if isGamepadInUse() then windowTop = 98 end local w = windowWidth + (rightPanelWidth + 20) * gToolScale UiTranslate((UiCenter()-w/2), windowTop) -------------------------- TOOL SELECTION ----------------------------------------- local imageWidth = 440 local toolButtonHeight = 54 UiPush() local tools = ToListItems( ListKeys("savegame.tool"), function() return imageWidth, toolButtonHeight end, function(tool, idx) local id = tool.data if gTools[id] then UiPush() local hovered = false local selected = gToolSelected == id if self.mouseOver and UiIsMouseInRect(imageWidth, toolButtonHeight) then hovered = true if (InputPressed("lmb") or InputPressed("menu_accept")) then UiSound("terminal/tool.ogg") UiSound("terminal/printout500.ogg", 0.5) selectTool(id) end end if hovered or selected then Ui.Color(Ui.Style.Terminal.Tools.Selected) else Ui.Color(Ui.Style.Terminal.Tools.Background) end UiImageBox("common/box-solid-4.png", imageWidth, toolButtonHeight-2, 4, 4) Ui.Color(selected and Ui.Style.Terminal.Messages.TextSelected or Ui.Style.Color.White) UiAlign("middle") UiTranslate(10, toolButtonHeight / 2) UiFont("medium.ttf", 27) UiText(gTools[id].name) UiPop() end end ) UiColor(0.2, 0.2, 0.2) UiImageBox("common/box-solid-10.png", windowWidth, windowHeight, 10, 10) UiTranslate(20, 50) UiPush() UiFont("medium.ttf", 36) UiColor(1, 1, 1) UiText(GetTranslatedStringByKey("UI_TEXT_TOOLS")) UiPop() UiTranslate(0, 30) local contentHeight = windowHeight - 100 Terminal.tools.ScrollBar.background.h = contentHeight self.mouseOver = UiIsMouseInRect(imageWidth, contentHeight) UiListEx(imageWidth+4, contentHeight, tools, Terminal.tools.ScrollBar, "menu_up", "menu_down") UiPop() -------------------------- DRAW TOOL ----------------------------------------- local tool = gTools[gToolSelected] local toolOffsetX = windowWidth if tool then windowWidth = rightPanelWidth windowHeight = 860 local margin = 20 UiAlign("left top") UiPush() UiTranslate(toolOffsetX + margin, 0) UiScale(gToolRightPanelScaleOnSelect) UiScale(gToolScale,1) UiColor(.23, .23, .23) UiImageBox("common/box-solid-10.png", windowWidth, windowHeight, 10, 10) UiWindow(windowWidth, windowHeight) UiColor(1,1,1) local contentWidth = 462 UiTranslate(margin, margin) UiPush() UiColor(1, 1, 1) UiFont("medium.ttf", 36) local _, h = UiText(tool.name) UiTranslate(0, h + margin) UiColor(1,1,1,0.5) UiFont("medium.ttf", 26) UiWordWrap(contentWidth) if gToolOutput < 1 then gToolOutput = gToolOutput + GetTimeStep() end local maxChars = string.len(GetTranslatedStringByKey(tool.desc))*gToolOutput UiText(tool.desc, false, maxChars) UiPop() UiPush() local frameWidth = 320 local frameHeight = 300 UiTranslate(contentWidth + margin, 0) UiColor(1,1,1) UiAlign("center middle") UiTranslate(frameWidth/2, frameHeight/2) UiScale(gToolScale * (math.sin(GetTime())*0.1+1.1)) UiScale(0.5) UiImage("terminal/tool/"..tool.image) UiPop() local canAfford = true local updateIsHovered = false -------------------------- UPGRADES----------------------------------------- if #tool.upgrades > 0 then local info = {x = 0, y = 0, text = ""} local cash = GetInt("savegame.cash") local upgradeFillHeight = 58 contentWidth = 802 UiTranslate(0, 340) UiPush() UiColor(1,1,1,0.5) UiFont("medium.ttf", 27) UiText("loc@UI_TEXT_ATTRIBUTE") UiAlign("top center") UiTranslate(701, 0) UiText("loc@UI_TEXT_UPGRADE") UiPop() UiTranslate(0, 44) for i=1,#tool.upgrades do local upgrade = tool.upgrades[i] local hovered = false UiPush() UiPush() UiAlign("middle") UiTranslate(0, upgradeFillHeight/2) if UiIsMouseInRect(contentWidth, upgradeFillHeight) then hovered = true updateIsHovered = true UiPush() Ui.Color(0xD9D9D930) UiImageBox("common/box-solid-11.png", contentWidth, upgradeFillHeight, 10, 10) UiPop() info.text = upgrade.desc local x,_ = UiGetRelativePos() UiPush() UiAlign("top") setFont("p", "dim") UiTranslate(contentWidth - x + 40, -upgradeFillHeight/2) Ui.Color(0x3B3B3B) UiImageBox("common/box-solid-11.png", (gToolDescWidth or 230) + 40, (gToolDescHeight or 110) + 20, 10, 10) UiTranslate(20,10) UiWordWrap(200) Ui.Color(Ui.Style.Color.White) gToolDescWidth, gToolDescHeight = UiText(info.text) UiPop() end UiPop() local key = "savegame.tool."..gToolSelected.."."..upgrade.id local current = upgrade.default if HasKey(key) then current = GetInt(key) end local buttonWidth = 180 local buttonHeight = 38 local upgradePrice = upgrade.price local buttonPos = contentWidth - 10 UiPush() UiAlign("middle left") Ui:MediumFont(22) UiColor(1,1,1) if hovered then Ui.Color(Ui.Style.Color.Yellow) end UiPush() UiTranslate(10, upgradeFillHeight / 2) UiText(upgrade.name) UiPop() UiPush() UiAlign("middle left") local x,_ = buttonPos - buttonWidth - 83, upgradeFillHeight / 2 - 9 UiTranslate(x, upgradeFillHeight / 2) w = drawBars(math.ceil(current / upgrade.step), math.ceil(upgrade.max / upgrade.step)) UiTranslate(-w - 10, 0) UiPush() local text = current if hovered then Ui.Color(Ui.Style.Color.White) if current < upgrade.max then canAfford = upgradePrice <= cash if canAfford then text = text.."(+"..upgrade.step..")" end end end UiAlign("right middle") UiText(text) UiPop() UiPop() UiPop() UiAlign("right middle") UiTranslate(buttonPos, upgradeFillHeight / 2) if current < upgrade.max then UiPush() UiButtonHoverColor(1, 1, 1) UiIgnoreNavigation() if upgradePrice > cash then UiDisableInput() UiColorFilter(1,1,1,0.5) end UiFont("regular.ttf", 26) Ui.Color(0xdbdbdb) if hovered and upgradePrice <= cash then UiButtonHoverColor(hexrgb(Ui.Style.Color.Yellow)) UiButtonImageBox("common/box-outline-7.png", 6, 6, rgb(255, 255, 127)) Ui.Color(Ui.Style.Color.Yellow) else UiButtonImageBox("common/box-outline-7.png", 6, 6, rgb(120, 120, 120)) end UiButtonImageBox("common/box-outline-7.png", 6, 6, rgb(120, 120, 120)) if UiTextButton("$"..upgradePrice, buttonWidth, buttonHeight) then UiSound("terminal/upgrade.ogg") UiSound("terminal/cash-counter.ogg", 0.5) current = current + upgrade.step if current > upgrade.max then current = upgrade.max end SetInt(key, current) SetInt("game.tool."..gToolSelected.."."..upgrade.id, current) if upgrade.id == "ammo" then SetInt("game.tool."..gToolSelected..".ammo.max", current) end SetInt("game.tool."..gToolSelected.."."..upgrade.id, current) SetInt("savegame.cash", cash-upgradePrice) Command("pros.eventToolUpgrade", gToolSelected, upgrade.id, current, upgradePrice) end UiPop() end UiPop() UiTranslate(0, upgradeFillHeight) end else UiFont("medium.ttf", 27) UiColor(1, 1, 1) UiAlign("left top") local tw, _ = GetTextSize(GetTranslatedStringByKey("UI_TEXT_NO_UPGRADES")) UiTranslate((windowWidth - tw)/2, windowHeight - 200) UiText("loc@UI_TEXT_NO_UPGRADES") end if updateIsHovered and not canAfford then SetValue("gNoCash", 1, "linear", 0.3) else SetValue("gNoCash", 0, "linear", 0.3) end UiPop() end end function Terminal.missions:Draw() local level = gLevelScale UiPush() if level > 0 then UiDisableInput() UiIgnoreNavigation() end setFont("h2") --PART 2 if isMissionUnlocked("carib_alarm") then UiImage("terminal/map_carib.jpg") else UiImage("terminal/map.jpg") end UiPush() if inCarib() then UiTranslate(1680, 725) else UiTranslate(839, 570) end UiAlign("center middle") UiImage("terminal/map_x.png") UiPop() local levels = getUnlockedLevels() for i=1,#levels do local id = levels[i] local title = GetTranslatedStringByKey(gLevels[id].map_title) local x = gLevels[id].map_x local y = gLevels[id].map_y local unfinishedCount = getUnfinishedMissionCount(id) UiPush() local levelScore = getLevelScore(id) local textScores = GetTranslatedStringByKey("UI_TEXT_SCORE") .. " " ..levelScore UiTranslate(x, y) UiScale(gUiScaleUpFactor) local w,_ = UiGetTextSize(title) local scoresWidth = UiGetTextSize(textScores) if scoresWidth > w then w = scoresWidth end w = w + 40 if w < 100 then w = 100 end local paddingRight = 30 local screenWidth = UiWidth() local rightEdge = x + w / 2 + paddingRight if rightEdge > screenWidth then local shiftAmount = rightEdge - screenWidth UiTranslate(-shiftAmount, 0) end local h = 48 if levelScore > 0 then h = h + 34 end --if unfinishedCount > 0 then -- h = h + 20 --end UiAlign("center middle") local over = UiIsMouseInRect(40, 40) UiPush() UiTranslate(0, 20+h/2) over = over or UiIsMouseInRect(w, h) UiPop() if over and gLevelSelected == "" then if (InputPressed("lmb") or InputPressed("menu_accept")) then UiSound("terminal/level.ogg", 1, 1.1) gLevelSelected = id gLevelViewed = id gMissionSelected = "" gLevelHighlighted = "" SetValue("gMissionScale", 0) SetValue("gLevelScale", 1, "easeout", 0.3) Terminal.missions.detail.ScrollBar:reset() end end UiPush() if over then UiColor(1, 1, 0.5) end if id == gLevelHighlighted then UiPush() UiTranslate(-20-w/2+ math.sin(GetTime()*10)*8, 40) UiImage("terminal/arrow.png") UiPop() end if unfinishedCount > 0 then UiScale(1) UiImage("terminal/level-dot.png") UiFont("bold.ttf", 27) UiColor(0,0,0) UiText(unfinishedCount) else UiScale(1) UiImage("terminal/level-dot.png") end UiPop() UiTranslate(0, 20) UiColor(0.2, 0.2, 0.2, 0.8) UiAlign("center") UiImageBox("common/box-solid-11.png", w, h, 10, 10) if over then UiColor(1, 1, 0.5) else UiColor(1,1,1) end UiTranslate(0, 32) UiFont("bold.ttf", 27) UiText(title) if levelScore > 0 then UiTranslate(0, 34) UiFont("regular.ttf", 27) UiText(textScores) end UiPop() end UiPop() if level > 0 then self.detail:Draw(gLevelViewed) end controllerHint() end Terminal.missions.detail = { ScrollBar = UiCreateScrollBar(Terminal:CreateScrollBar(230)), leftPanelWidth = 817, leftPanelHeight = 860, rightPanelWidth = 610, rightPanelHeight = 860, Draw = function (self, id) self.ScrollBar.itemsPadding = 10 local levelFade = gLevelScale UiPush() UiColor(0, 0, 0, 0.7*levelFade) UiRect(UiWidth(), UiHeight()) UiPop() local hoverLevel = false local hoverMission = false UiPush() local width = self.leftPanelWidth local height = self.leftPanelHeight local x = gLevels[id].map_x*(1-levelFade) + UiCenter()*levelFade local y = gLevels[id].map_y*(1-levelFade) + UiMiddle()*levelFade UiTranslate(x,y) UiColorFilter(1,1,1, levelFade) UiScale(levelFade) local margin = 30 if isGamepadInUse() then margin = -12 end UiTranslate(-width/2 - (self.rightPanelWidth/2+10)*gMissionScale,-height/2+margin) hoverLevel = UiIsMouseInRect(width, height) UiPush() UiColor(0.2, 0.2, 0.2) UiImageBox("common/box-solid-10.png", width, height, 10, 10) UiPop() UiPush() UiPush() UiAlign("center top") UiTranslate(width/2,20) UiPush() UiScale(0.947, 1.0) UiImage(gLevels[id].image) UiPop() UiTranslate(0, 212) fixedWidthText(GetTranslatedStringByKey(gLevels[id].title.."_UPPERCASE"), 550, "bold.ttf", 36) UiPop() UiTranslate(20, 295) UiPush() UiTextAlignment("center") UiColor(1, 1, 1, 0.5) UiWordWrap(777) local h, _ = fixedWidthText(gLevels[id].desc, 777, "medium.ttf", 27) UiPop() UiTranslate(0, h-4) local missions = getLevelMissions(gLevelViewed) local missionList = ToListItems(missions, function() return 780, 48 end, Terminal.missions.detail.DrawMissionItem) local contentHeight = 460 self.ScrollBar.background.h = contentHeight UiListEx(777, contentHeight, missionList, self.ScrollBar, "menu_up", "menu_down") UiPop() local levelScore = getLevelScore(id) if levelScore > 0 then UiPush() UiTranslate(width/2, height-32) UiFont("bold.ttf", 27) UiAlign("center middle") UiText(GetTranslatedStringByKey("UI_TEXT_SCORE") .. " " .. levelScore) UiPop() end local missionScale = gMissionScale if missionScale > 0 then width = self.rightPanelWidth height = self.rightPanelHeight UiTranslate(self.leftPanelWidth + 18, 0) UiScale(missionScale, 1) hoverMission = UiIsMouseInRect(width, height) UiColorFilter(1,1,1,missionScale) UiWindow(width, height, true) UiPush() UiColor(0.23, 0.23, 0.23) UiImageBox("common/box-solid-10.png", width, height, 10, 10) UiPop() UiPush() UiTranslate(20,50) UiPush() UiAlign("left") UiColor(1, 1, 1) fixedWidthText(gMissions[gMissionViewed].title, 450, "bold.ttf", 36) UiPop() UiPush() UiTranslate(0, 48) UiFont("regular.ttf", 27) UiWordWrap(570) UiColor(1, 1, 1, 0.8) _, h = UiText(gMissions[gMissionViewed].desc) UiTranslate(0, h + 24) UiColor(1, 1, 1, 0.6) local message = getMessageForMission(gMissionViewed) if message then local messageText = GetTranslatedStringByKey("UI_BUTTON_VIEW_EMAIL," .. gClients[message.from].name) _, h = UiGetTextSize(messageText) UiButtonHoverColor(hexrgb(Ui.Style.Color.Yellow)) if UiTextButton(messageText) then Terminal:ShowMessage(gMissionViewed) end UiTranslate(0, h + 5) end local score = getMissionScore(gMissionViewed) local timeLeft = GetFloat("savegame.mission."..gMissionViewed..".timeleft") local missionTime = GetFloat("savegame.mission."..gMissionViewed..".missiontime") if gSkipMissionJustPressed then score = 0 end if score > 0 then UiTranslate(0, 42) UiPush() UiFont("medium.ttf", 32) UiColor(1, 1, 1) UiText(GetTranslatedStringByKey("UI_TEXT_HIGHSCORE").." "..getLevelScore(id)) UiPop() UiTranslate(0, 14) drawScore(gMissionViewed, score, timeLeft, missionTime, false, 570, true) end UiPop() UiPop() UiPush() UiAlign("left middle") setFont("button") UiButtonImageBox("common/box-outline-6.png", 6, 6, 0.96, 0.96, 0.96) UiTranslate(0, height-64) if gSkipMissionJustPressed then UiDisableInput() UiIgnoreNavigation() end local enableSkip = (score == 0 and GetInt("options.game.missionskipping") == 1) local padding = 20 local buttonWidth = 275 Ui:MediumFont(30) UiButtonHoverColor(hexrgb(Ui.Style.Color.Yellow)) if enableSkip then UiPush() UiTranslate(padding, 0) if UiTextButton("loc@UI_BUTTON_SKIP_MISSION", buttonWidth, 48) then skipMission(gMissionViewed) gDisableEvaluation = true if gMissionViewed == "frustrum_chase" then startCinematic("ending1") elseif gMissionViewed == "cullington_bomb" then startCinematic("ending2") else startHub() end gSkipMissionJustPressed = true end UiPop() end UiPush() UiAlign("center middle") if (enableSkip) then UiTranslate(UiWidth() - padding - buttonWidth / 2, 0) else UiTranslate(UiCenter(), 0) end -- NOTE: look ugly --UiScale(1.1 + math.sin(GetTime()*10)*0.06) local playText = GetTranslatedStringByKey("UI_BUTTON_PLAY") if score > 0 then playText = GetTranslatedStringByKey("PLAYTEXT_REPLAY_MISSION") end UiButtonHoverColor(hexrgb(Ui.Style.Color.Yellow)) if UiTextButton(playText, buttonWidth, 48) then startMission(gMissionViewed) end UiPop() UiPop() end UiPop() local hoverAnything = hoverLevel or hoverMission or gHoverTop or gHoverDebug if Terminal.currentPanel == Terminal.missions and gLevelScale == 1 and InputPressed("menu_cancel") or ((InputPressed("lmb") or InputPressed("menu_accept")) and not hoverAnything) then UiSound("terminal/level.ogg", 1, 0.9) SetValue("gLevelScale", 0, "easein", 0.3) gLevelSelected = "" gMissionSelected = "" end end } function Terminal.missions.detail:DrawMissionItem(i) local id = self.data local title = gMissions[id].title local details = getScoreDetails(id, getMissionScore(id)); local itemWidth = 777 local itemHeight = 54 UiAlign("left middle") UiTranslate(0, 30) local haveMarker = false if id == gMissionHighlighted then UiPush() UiTranslate(12 + math.sin(GetTime()*10)*4, 0) UiImage("terminal/arrow.png") UiPop() haveMarker = true else if isMissionCompleted(id) then UiPush() UiTranslate(10, 0) UiImage("terminal/checkmark.png") UiPop() haveMarker = true end end if id == gMissionSelected then UiColor(1,1,1,0.1) UiImageBox("common/box-solid-6.png", itemWidth, itemHeight, 6, 6) end if UiIsMouseInRect(itemWidth, itemHeight) then UiColor(1,1,1,0.08) UiImageBox("common/box-solid-6.png", itemWidth, itemHeight, 6, 6) if (InputPressed("lmb") or InputPressed("menu_accept")) then gMissionHighlighted = "" if gMissionSelected == id then UiSound("terminal/mission.ogg", 1, 0.9) SetValue("gMissionScale", 0, "cosine", 0.2) gMissionSelected = "" else UiSound("terminal/mission.ogg", 1, 1.1) gMissionSelected = id gMissionViewed = id SetValue("gMissionScale", 1, "cosine", 0.2) end end end if id == gMissionSelected then UiColor(1, 1, 0.5) else UiColor(1,1,1) end UiFont("medium.ttf", 27) if haveMarker then UiTranslate(60, 0) else UiTranslate(10, 0) end UiText(title) UiColor(1,1,1) local count = details.required + details.optional + details.bonuses local taken = details.requiredTaken + details.optionalTaken + details.bonusesTaken local offset = 760 if haveMarker then offset = 710 end UiTranslate(offset, 0) drawTargetDots(count, taken, false) end function init() gMissionSelected = "" gMissionViewed = "" gMissionHighlighted = "" gMissionScale = 0 gLevelSelected = "" gLevelViewed = "" gLevelHighlighted = "" gLevelScale = 0 gMessageSelected = "" gMessageAttachmentScale = 0 gMessageRightPanelScaleOnSelect = 0 gMessageScale = 0 gRankInfoScale = 0 gCashInfoScale = 0 gNoCash = 0 gCash = GetInt("savegame.cash") gToolSelected = "none" gToolOutput = 0 gToolScale = 0 gHoverTop = false gHoverDebug = false gHoverScore = false gHoverCash = false gDebugScale = 0 gTabScroll = Terminal.currentPanel.TabScroll gTimeSinceMessageRead = 0 gShowLargeUI = GetBool("game.largeui") if gShowLargeUI then gUiScaleUpFactor = 1.1 else gUiScaleUpFactor = 1.0 end local msg = ListKeys("savegame.message") for i=1, #msg do local id = msg[i] if gMessages[id]==nil then ClearKey("savegame.message."..id) end end end function tick() gTimeSinceMessageRead = gTimeSinceMessageRead + GetTimeStep() evaluate() end function evaluate() if gDisableEvaluation then return end -- BOSS if not isMessageReceived("boss_intro") then receiveMessage("boss_intro") end if not isMessageReceived("mall_intro") and isMessageRead("boss_intro", 3) then receiveMessage("mall_intro") end if not isMessageReceived("boss_busted") and isMissionCompleted("mall_intro") then receiveMessage("boss_busted") end if not isMessageReceived("lee_computers") and isMessageRead("boss_busted", 3) then receiveMessage("lee_computers") end if not isMessageReceived("lee_login") and isMissionCompleted("lee_computers") then receiveMessage("lee_login") end if not isMessageReceived("boss_coffee") and isMissionCompleted("lee_login") then receiveMessage("boss_coffee") end if not isMessageReceived("marina_demolish") and isMessageRead("boss_coffee", 4) then receiveMessage("marina_demolish") end if not isMessageReceived("marina_cars") and isMissionCompleted("marina_demolish") then receiveMessage("marina_cars") end if not isMessageReceived("mansion_pool") and isMissionCompleted("marina_cars")then receiveMessage("mansion_pool") end if not isMessageReceived("marina_gps") and isMessageRead("mansion_pool", 2) then receiveMessage("marina_gps") end if not isMessageReceived("lee_safe") and (isMissionCompleted("marina_gps") or isMissionCompleted("mansion_pool")) then receiveMessage("lee_safe") end if not isMessageReceived("lockelle_parade_ad") and isMissionCompleted("mansion_art") then receiveMessage("lockelle_parade_ad") end if not isMessageReceived("lee_safe_done") and isMissionCompleted("lee_safe") then receiveMessage("lee_safe_done") end if not isMessageReceived("lee_tower") and isMissionCompleted("mansion_pool") and isMissionCompleted("marina_gps") then receiveMessage("lee_tower") end ------------------------------------------------------------------------------------------------ if not isMessageReceived("boss_encourage_1") and isMissionCompleted("lee_tower") then receiveMessage("boss_encourage_1") end if not isMessageReceived("mansion_art") and isMissionCompleted("lee_tower") then receiveMessage("mansion_art") end if not isMessageReceived("marina_tools") and isMessageRead("mansion_art", 3) then receiveMessage("marina_tools") end if not isMessageReceived("marina_art_back") and isMissionCompleted("mansion_art") then receiveMessage("marina_art_back") end if not isMessageReceived("marina_art_back_done") and isMissionCompleted("marina_art_back") then receiveMessage("marina_art_back_done") end if not isMessageReceived("mansion_fraud") and isMessageRead("marina_art_back_done", 3) then receiveMessage("mansion_fraud") end if not isMessageReceived("caveisland_computers") and isMissionCompleted("marina_art_back") then receiveMessage("caveisland_computers") end if not isMessageReceived("mansion_race") and isMissionCompleted("caveisland_computers") then receiveMessage("mansion_race") end if not isMessageReceived("mansion_safe") and isMissionCompleted("caveisland_computers") then receiveMessage("mansion_safe") end if not isMessageReceived("mall_foodcourt") and isMissionCompleted("mansion_safe") then receiveMessage("mall_foodcourt") end if not isMessageReceived("lee_powerplant") and isMissionCompleted("mansion_safe") then receiveMessage("lee_powerplant") end if not isMessageReceived("caveisland_propane") and isMissionCompleted("lee_powerplant") then receiveMessage("caveisland_propane") end if not isMessageReceived("lee_powerplant_done") and isMissionCompleted("lee_powerplant") then receiveMessage("lee_powerplant_done") end if not isMessageReceived("caveisland_dishes") and isMessageRead("lee_powerplant_done", 3) then receiveMessage("caveisland_dishes") end if not isMessageReceived("boss_encourage_2") and isMissionCompleted("caveisland_dishes") then receiveMessage("boss_encourage_2") end if not isMessageReceived("lee_flooding") and isMissionCompleted("caveisland_dishes") then receiveMessage("lee_flooding") end if not isMessageReceived("frustrum_chase") and isMissionCompleted("lee_flooding") then unlockMission("frustrum_chase") receiveMessage("frustrum_chase") if isMissionCompleted("frustrum_chase") then --If mission was completed before going back to hub, mark as read SetInt("savegame.message.frustrum_chase", 2) end end ------------------------------------------------------------------------------ ------------------------------------------------------------------------------ ------------------------------------------------------------------------------ -- -- P A R T 2 -- ------------------------------------------------------------------------------ ------------------------------------------------------------------------------ ------------------------------------------------------------------------------ if not isMessageReceived("boss_part2") and isMissionCompleted("frustrum_chase") then receiveMessage("boss_part2") end if not isMessageReceived("factory_espionage") and isMessageRead("boss_part2", 3) then receiveMessage("factory_espionage") end if not isMessageReceived("factory_espionage_done") and isMissionCompleted("factory_espionage") then receiveMessage("factory_espionage_done") end if not isMessageReceived("caveisland_ingredients") and isMessageRead("factory_espionage_done", 3) then receiveMessage("caveisland_ingredients") end if not isMessageReceived("frustrum_tornado") and isMissionCompleted("caveisland_ingredients") then receiveMessage("frustrum_tornado") end if not isMessageReceived("mall_shipping") and isMissionCompleted("frustrum_tornado") then receiveMessage("mall_shipping") end if not isMessageReceived("mall_shipping_done") and isMissionCompleted("mall_shipping") then receiveMessage("mall_shipping_done") end --Begin carib if not isMessageReceived("carib_travel") and isMessageRead("mall_shipping_done", 3) then receiveMessage("carib_travel") end --If we're in carib hub and didn't receive the first message, then do so if not isMessageReceived("carib_alarm") and inCarib() then receiveMessage("carib_alarm") end --If we've arrived in carib remove travel attachment if isMessageReceived("carib_alarm") then gMessages["carib_travel"].hub = nil end if not isMessageReceived("boss_vacation") and isMissionCompleted("carib_alarm") then receiveMessage("boss_vacation") end if not isMessageReceived("carib_barrels") and isMessageRead("boss_vacation", 3) then receiveMessage("carib_barrels") end if not isMessageReceived("carib_destroy") and isMissionCompleted("carib_barrels") then receiveMessage("carib_destroy") end if not isMessageReceived("carib_yacht") and isMissionCompleted("carib_destroy") then receiveMessage("carib_yacht") end if not isMessageReceived("carib_last") and isMessageRead("carib_yacht", 3) then receiveMessage("carib_last") end --End carib --If last mission in carib is completed and we're back in lockelle, continue story there if not isMessageReceived("frustrum_vehicle") and isMissionCompleted("carib_destroy") and not inCarib() then receiveMessage("frustrum_vehicle") end --Remove travel back home attachment if we've already done that if isMessageReceived("frustrum_vehicle") then gMessages["carib_last"].hub = nil end if not isMessageReceived("mall_decorations") and isMessageRead("frustrum_vehicle", 3) then receiveMessage("mall_decorations") end if not isMessageReceived("factory_tools") and isMissionCompleted("frustrum_vehicle") then receiveMessage("factory_tools") end if not isMessageReceived("mall_radiolink") and isMessageRead("factory_tools", 3) then receiveMessage("mall_radiolink") end if not isMessageReceived("frustrum_pawnshop") and isMissionCompleted("mall_radiolink") then receiveMessage("frustrum_pawnshop") end if not isMessageReceived("factory_robot") and isMessageRead("frustrum_pawnshop", 3) then receiveMessage("factory_robot") end if not isMessageReceived("lee_woonderland") and isMissionCompleted("factory_robot") and isMissionCompleted("mall_decorations") then receiveMessage("lee_woonderland") end if not isMessageReceived("factory_explosive") and isMissionCompleted("factory_robot") then receiveMessage("factory_explosive") end if not isMessageReceived("tracy_dinner") and isMissionCompleted("factory_explosive") then receiveMessage("tracy_dinner") end if not isMessageReceived("factory_explosive_done") and isMissionCompleted("factory_explosive") then receiveMessage("factory_explosive_done") end if not isMessageReceived("caveisland_roboclear") and isMessageRead("factory_explosive_done", 3) then receiveMessage("caveisland_roboclear") end if not isMessageReceived("caveisland_roboclear_done1") and isMissionCompleted("caveisland_roboclear") then receiveMessage("caveisland_roboclear_done1") end if not isMessageReceived("caveisland_roboclear_done2") and isMessageRead("caveisland_roboclear_done1", 3) then receiveMessage("caveisland_roboclear_done2") end if not isMessageReceived("cullington_bomb") and isMessageRead("caveisland_roboclear_done2", 3) then receiveMessage("cullington_bomb") end end ----------------------------------------------------------------------------------------------------------------------------------------- function draw() UiPush() UiIgnoreNavigation() UiPush() if gDebugScale > 0 then local w = UiWidth() local h = UiHeight() local dw = 300*gDebugScale local mw = UiWidth() - dw UiPush() UiScale(gDebugScale, 1) UiWindow(300, h, true) if terminalDebug then terminalDebug() end UiPop() UiTranslate(dw, 0) UiScale(mw/w, 1) UiWindow(w, h, true) end Terminal:draw() UiPop() if not GetBool("game.deploy") then UiPush() setFont("h2") UiTranslate(60, 1066) UiColor(1, 1, 1, 0.5) UiAlign("center middle") gHoverDebug = UiIsMouseInRect(100, 30) if UiTextButton("loc@UI_BUTTON_DEBUG") then if gDebugScale > 0 then SetValue("gDebugScale", 0, "cosine", 0.2) else SetValue("gDebugScale", 1, "cosine", 0.2) end end UiPop() end UiPop() end function Button(text, callback) local w,_ = UiGetTextSize(GetTranslatedStringByKey(text)) if UiTextButton(text) then callback() end UiTranslate(w + terminalTabs.marginRight,0) end function TabButton(text, tab) if gTabSelected == tab then UiColor(1,1,1) else UiColor(0.7, 0.7, 0.7) end Button(text, function() setTab(tab) end) end terminalTabs = { content = { {"loc@UI_BUTTON_MESSAGES", "messages"}, {"loc@UI_BUTTON_MISSIONS", "missions"}, {"loc@UI_BUTTON_TOOLS", "tools"}, }, wholeSize = 0, marginRight = 10, Draw = function (self) self.wholeSize = self.marginRight * (#self.content - 1) for _, button in pairs(self.content) do self.wholeSize = self.wholeSize + UiGetTextSize(GetTranslatedStringByKey(button[1])) end for _, button in pairs(self.content) do TabButton(button[1], button[2]) end end } function drawTop() UiPush() UiScale(gUiScaleUpFactor) UiColor(0.1,0.1,0.1) UiRect(UiWidth(), 50) gHoverTop = UiIsMouseInRect(UiWidth(), 50) setFont("h1") UiTranslate(UiCenter()/gUiScaleUpFactor - terminalTabs.wholeSize / 2, 25) UiAlign("middle") if hasUnreadMessages() and math.fmod(GetTime(), 1.0) > 0.5 then UiPush() UiColor(.5, .8, 1) UiTranslate(-20, 0) UiImage("terminal/new-message-dot.png") UiPop() end terminalTabs:Draw() UiPop() UiPush() UiScale(gUiScaleUpFactor) setFont("h2") local score = getTotalScore() local cash = GetInt("savegame.cash") gCash = gCash + (cash-gCash)*GetTimeStep()*5 if math.abs(gCash - cash) < 1 then gCash = cash end local rw,_ = UiGetTextSize(getRank(score)) UiPush() UiTranslate(20, 10) UiColor(.2,.2,.2) UiImageBox("common/box-solid-10.png", 155+rw, 34, 10, 10) if gHoverScore then UiColor(1,1,1) else UiColor(.8,.8,.8) end UiTranslate(20, 24) local textScore = GetTranslatedStringByKey("UI_TEXT_SCORE") UiText(textScore) UiTranslate(UiGetTextSize(textScore) + 60, 0) UiAlign("right") UiText(score) UiTranslate(20, 0) UiAlign("left") UiText(getRank(score)) UiPop() UiPush() local padding = 20 UiTranslate(UiWidth()/gUiScaleUpFactor - (20), 10) UiAlign("right") UiColor(.2,.2,.2) local textCash = GetTranslatedStringByKey("UI_TEXT_CASH_$," .. math.floor(gCash)) local textWidth = UiGetTextSize(textCash) UiImageBox("common/box-solid-10.png", textWidth + 2 * padding, 34, 10, 10) if gHoverCash then UiColor(1,1,1) else UiColor(.8,.8,.8) end UiTranslate(-padding, 24) UiText(textCash) if gNoCash > 0 then UiColor(0.8,0.8,0.8,gNoCash) UiTranslate(-20, 40) UiText("loc@UI_TEXT_NOT_ENOUGH") end UiPop() local overScore = UiIsMouseInRect(195+rw, 50) if overScore and not gHoverScore then SetValue("gRankInfoScale", 1, "bounce", 0.4) elseif not overScore and gHoverScore then SetValue("gRankInfoScale", 0, "easein", 0.2) end gHoverScore = overScore if gRankInfoScale > 0 then UiPush() UiTranslate(20, 55) UiScale(1, gRankInfoScale) UiColor(.2,.2,.2) UiImageBox("common/box-solid-10.png", 155+rw, gRankInfoHeight, 10, 10) UiPush() UiColor(.8, .8, .8) UiTranslate(0, 30) local didCurrent = false for i=#gRanks, 1, -1 do local valid = true local s = gRanks[i].score local n = gRanks[i].name if score < s then if score < gRanks[i-1].score then valid = false else n = GetTranslatedStringByKey("N_NEXT_RANK") UiColor(0.4, 0.4, 0.4) end else if didCurrent then UiColor(.7,.7,.7) else UiColor(1,1,1) didCurrent = true end end if valid then UiPush() UiTranslate(110, 0) UiAlign("right") UiText(s) UiTranslate(20, 0) UiAlign("left") UiText(n) UiPop() UiTranslate(0, 24) end end UiTranslate(10, 10) setFont("p") UiColor(.6, .6, .6) UiWordWrap(280) UiText(GetTranslatedStringByKey("UI_TEXT_COMPLETE_MISSIONS"), true) _,gRankInfoHeight = UiGetRelativePos() UiPop() UiPop() end UiPush() UiTranslate(UiWidth()/gUiScaleUpFactor-190, 0) local overCash = UiIsMouseInRect(190, 50) UiPop() if overCash and not gHoverCash then SetValue("gCashInfoScale", 1, "bounce", 0.4) elseif not overCash and gHoverCash then SetValue("gCashInfoScale", 0, "easein", 0.2) end gHoverCash = overCash if gCashInfoScale > 0 then UiPush() --[[ NOTE: There is a word wrapping issue in Asian languages (UiWordWrap can't fit 200 text in this case for some reason), so a workaround is to increase the window width depending on the width of the text in Asian languages ]] --[[ FIXME: UiWordWrap incorrect on Asian ]] local preferredWidth = 240 UiTranslate(UiWidth()/gUiScaleUpFactor-((gEarnCashWindowWidth or 0) + 2 * padding), 55) UiScale(1, gCashInfoScale) UiColor(.2,.2,.2) UiImageBox("common/box-solid-10.png", gEarnCashWindowWidth, gEarnCashWindowHeight, 10, 10) UiPush() UiColor(.8, .8, .8) UiTranslate(20, 30) setFont("p") UiColor(.6, .6, .6) UiWordWrap(preferredWidth - 2 * padding) gEarnCashWindowWidth,_ = UiText("loc@UI_TEXT_EARN_CASH", true) gEarnCashWindowWidth = math.max(preferredWidth, (gEarnCashWindowWidth or 0) + 2 * padding) _, gEarnCashWindowHeight = UiGetRelativePos() UiPop() UiPop() end UiPop() end