function initQuests()
--instead of always searching the quests, just map entry ids to their quests
entryToQuest = {}
for questIdx, quest in pairs(quests) do
quests[questIdx].stateType = const.ENTRY_TYPE_NONE
for objIdx,objective in pairs(quest.objectives) do
quests[questIdx].objectives[objIdx].stateType = const.ENTRY_TYPE_NONE
for entryIdx,entry in pairs(objective.entries) do
quests[questIdx].objectives[objIdx].entries[entryIdx].stateType = const.ENTRY_TYPE_NONE
entryToQuest[entry.id] = questIdx
end
end
end
end
function compareByRecvTime(o1,o2)
if(not o1.recvTime and not o2.recvTime) then return false end
if(not o1.recvTime) then return false end
if(not o2.recvTime) then return true end
return o1.recvTime > o2.recvTime
end
function buildEntry(text, recvTime, stateType, chapter, timeStamp)
local entry =
{
text = text,
recvTime = recvTime,
stateType = stateType,
timeStamp = timeStamp,
chapters = {}
}
entry.chapters[chapter] = 1
return entry
end
--Update a journal entry by the strref/journalId
function updateJournalEntry(journalId, recvTime, stateType, chapter, timeStamp)
if(stateType == const.ENTRY_TYPE_USER) then
local entry = buildEntry(journalId, recvTime, stateType, chapter, timeStamp)
table.insert(userNotes,entry)
--update display data
buildQuestDisplay()
return
end
--find the quest that is parent to this entry.
--NOTE this can be placed in a loop if there needs to be more than quest to an entry
--this would just mean entryToQuest returns a table that we iterate over
local questId = entryToQuest[journalId]
if questId == nil or stateType == const.ENTRY_TYPE_INFO then
--add loose entries into the looseEntries table so they still get displayed.
for _,entry in pairs(looseEntries) do
if entry.text == journalId then
return
end
end
local entry = buildEntry(journalId, recvTime, stateType, chapter, timeStamp)
table.insert(looseEntries,entry)
--update display data
buildQuestDisplay()
return
end
local quest = quests[questId]
if quest == nil then
print("JOURNAL ERROR - no quest entry associated with questId "..questId)
return
end
local previous = nil
--traverse quest to find objective and entry
for objIdx,objective in pairs(quest.objectives) do
for entryIdx,entry in pairs(objective.entries) do
if(entry.id == journalId) then
--now we know where our quest, objective, and entry are
--update quest, objective and entry appropriately
entry.recvTime = recvTime
entry.stateType = stateType
if(not entry.chapters) then entry.chapters = {} end
entry.chapters[chapter] = 1
entry.timeStamp = timeStamp
objective.entries[entryIdx] = entry
objective.recvTime = recvTime
if(not objective.chapters) then objective.chapters = {} end
objective.chapters[chapter] = 1
if(objective.stateType \~= const.ENTRY_TYPE_COMPLETE) then
objective.stateType = stateType
end
quest.objectives[objIdx] = objective
quest.recvTime = recvTime
if(not quest.chapters) then quest.chapters = {} end
quest.chapters[chapter] = 1
if(quest.stateType \~= const.ENTRY_TYPE_COMPLETE) then
quest.stateType = stateType
end
--mark any previous objective as complete
if(entry.previous \~= nil) then
for objIdx2,objective2 in pairs(quest.objectives) do
for k, prevObj in pairs(entry.previous) do
if(prevObj == objective2.text) then
quest.objectives[objIdx2].stateType = const.ENTRY_TYPE_COMPLETE
end
end
end
end
quests[questId] = quest
--remove all in subgroup (except myself!)
if(stateType == const.JOURNAL_STATE_COMPLETE and entry.subGroup) then
for k,v in pairs(subGroups[entry.subGroup]) do
if(v.id \~= entry.id) then
removeJournalEntry(v.id)
end
end
end
end
end
end
--sort the objectives.
table.sort(quest.objectives,compareByRecvTime)
--update display data
buildQuestDisplay()
end
function checkEntryComplete(journalId, stateType)
--Check if a journal entry is part of a quest that's already complete
--If anything other than an unfinished entry return false.
if(stateType \~= const.ENTRY_TYPE_INPROGRESS) then return false end
--Check if my quest is marked complete.
local questIndex = entryToQuest[journalId]
if (quests[questIndex].stateType == const.ENTRY_TYPE_COMPLETE) then
return 1
else
return 0
end
end
--this should maybe be done recursively, but i kinda want direct control over each level
function buildQuestDisplay()
--this is basically just a flatten
questDisplay = {}
journalDisplay = {}
local journalEntries = {} --temp holding table for sorting the entries
for k,quest in pairs(quests) do
--skip inactive quests
if(quest.stateType \~= nil and quest.stateType \~= const.ENTRY_TYPE_NONE) then
quest.quest = 1 -- tell the renderer what type of entry this is
table.insert(questDisplay, quest)
local curQuestIdx = #questDisplay --we'll need to modify current quest with it's children, store a reference.
local questChildren = {}
for k2,objective in pairs(quest.objectives) do
if(objective.stateType \~= const.ENTRY_TYPE_NONE) then
objective.objective = 1
objective.parent = curQuestIdx
if(objective.text == Infinity_FetchString(quest.text) or objective.text == nil) then
objective.text = objective.entries[1].timeStamp
end
if(objective.stateType \~= const.ENTRY_TYPE_INFO) then
--info entries should not go into quests
table.insert(questDisplay, objective)
table.insert(questChildren, #questDisplay)
end
local curObjectiveIdx = #questDisplay
local objectiveChildren = {}
for k3,entry in pairs(objective.entries) do
entry.entry = 1
entry.parent = curObjectiveIdx
table.insert(questDisplay, entry)
table.insert(objectiveChildren, #questDisplay)
end
questDisplay[curObjectiveIdx].children = objectiveChildren
end
end
questDisplay[curQuestIdx].children = questChildren
end
end
-- add the user entries to the journal display
for k,entry in pairs(userNotes) do
entry.entry = 1
table.insert(journalEntries,entry)
end
--add the loose entries (entries without quests) to the journal display
for k,entry in pairs(looseEntries) do
entry.entry = 1
table.insert(journalEntries,entry)
end
table.sort(journalEntries, compareByRecvTime)
for k,entry in pairs(journalEntries) do
local title = {}
title.title = 1
title.text = entry.timeStamp
title.chapters = entry.chapters
table.insert(journalDisplay,title)
table.insert(journalDisplay, entry)
end
end
function questContainsSearchString(row)
if(journalSearchString == nil or journalSearchString == "") then return 1 end --no search string, do nothing
local text = Infinity_FetchString(questDisplay[row].text)
if(string.find(string.lower(text),string.lower(journalSearchString))) then return 1 end -- string contains search string.
if(questDisplay[row].children == nil) then return nil end --no children, does not contain search string.
for k,v in pairs(questDisplay[row].children) do
--Infinity_Log(v)
if(containsSearchString(v)) then return 1 end -- one of children contains search string
end
return nil --does not contain search string
end
function containsChapter(tab, chapter)
if(not tab) then return nil end
return tab[chapter]
end
function entryEnabled(row)
local rowTab = questDisplay[row]
if(rowTab == nil or rowTab.entry == nil or not containsChapter(rowTab.chapters,chapter)) then return nil end
if(objectiveEnabled(rowTab.parent) and questDisplay[rowTab.parent].expanded) then return 1 else return nil end
end
function getEntryText(row)
return questDisplay[row].timeStamp .. "\n" .. questDisplay[row].text
end
function objectiveEnabled(row)
local rowTab = questDisplay[row]
if(rowTab == nil or rowTab.objective == nil or not containsChapter(rowTab.chapters,chapter)) then return nil end
if(questEnabled(rowTab.parent) and questDisplay[rowTab.parent].expanded) then return 1 else return nil end
end
function getObjectiveText(row)
local rowTab = questDisplay[row]
if (rowTab == nil) then return nil end
local text = rowTab.text
if(text == "" or text == nil) then
text = t("NO_OBJECTIVE_NORMAL")
end
--objectives shouldn't really display a completed state since they don't actually follow a progression.
--if(getFinished(row)) then
-- text = "^0xFF666666" .. text .. " (Finished)^-"
--end
return text
end
--Many thanks to 'lefreut'
function childrenContainsChapter(children)
for k,v in pairs(children) do
if containsChapter(questDisplay[v].chapters,chapter) then
return true
end
end
return nil
end
function questEnabled(row)
--return (questDisplay[row] and questDisplay[row].quest and containsChapter(questDisplay[row].chapters,chapter) and (#questDisplay[row].children > 0))
return (questDisplay[row] and questDisplay[row].quest and containsChapter(questDisplay[row].chapters,chapter) and childrenContainsChapter(questDisplay[row].children))
end
function getQuestText(row)
local rowTab = questDisplay[row]
if (rowTab == nil) then return nil end
local text = Infinity_FetchString(rowTab.text)
if(getFinished(row)) then
text = "^0xFFaaaaaa" .. text .. " (" .. t("OBJECTIVE_FINISHED_NORMAL") .. ")^-"
end
return text
end
function getArrowFrame(row)
if(questDisplay[row] == nil or (questDisplay[row].objective == nil and questDisplay[row].quest == nil)) then return "" end
if(questDisplay[row].expanded) then
return 0
else
return 1
end
end
function getArrowEnabled(row)
if(questDisplay[row].quest == nil and questDisplay[row].objective == nil) then return nil end
if(questDisplay[row].objective and not objectiveEnabled(row)) then return nil end
if(questDisplay[row].quest and not questEnabled(row)) then return nil end
return 1
end
function getFinished(row)
if(questDisplay[row].stateType == const.ENTRY_TYPE_COMPLETE) then return 1 else return nil end
end
function showObjectiveSeperator(row)
local tab = questDisplay[row]
if(objectiveEnabled(row) or entryEnabled(row)) then
--seperator is enabled for objective or entry as long as the next thing is an objective.
--search until we find something enabled or end of table.
local idx = row + 1
while(questDisplay[idx]) do
if(objectiveEnabled(idx)) then
return 1
else
if(questEnabled(idx) or entryEnabled(idx)) then
return nil
end
end
idx = idx + 1
end
end
end
function getJournalTitleEnabled(row)
return journalDisplay[row].title and containsChapter(journalDisplay[row].chapters,chapter) and journalContainsSearchString(row)
end
function getJournalTitleText(row)
return journalDisplay[row].text
end
function getJournalEntryEnabled(row)
return journalDisplay[row].entry and containsChapter(journalDisplay[row].chapters,chapter) and journalContainsSearchString(row)
end
function getJournalEntryText(row)
local text = Infinity_FetchString(journalDisplay[row].text)
if(text == nil or text == "") then
text = journalDisplay[row].text
end
if(journalSearchString and journalSearchString \~= "") then
--do the search string highlight
text = highlightString(text, journalSearchString, "^0xFF0000FF")
end
return text
end
function getJournalDarken(row)
local entry = journalDisplay[row]
if(entry.title) then
return (row == selectedJournal or row + 1 == selectedJournal)
end
if(entry.entry) then
return (row == selectedJournal or row - 1 == selectedJournal)
end
end
function journalContainsSearchString(row)
if(journalSearchString == nil or journalSearchString == "") then return 1 end --no search string, do nothing
local text = Infinity_FetchString(journalDisplay[row].text)
if(text == "") then text = journalDisplay[row].text end --no stringref, use the text.
if(string.find(string.lower(text),string.lower(journalSearchString))) then return 1 end -- string contains search string.
--check if the corresponding row to this one contains the string.
local pairText = nil
if(journalDisplay[row].title) then
--check the corresponding entry
pairText = Infinity_FetchString(journalDisplay[row+1].text) or journalDisplay[row+1].text
if(pairText == "") then pairText = journalDisplay[row+1].text end
else
if (journalDisplay[row].entry) then
pairText = Infinity_FetchString(journalDisplay[row-1].text) or journalDisplay[row-1].text
if(pairText == "") then pairText = journalDisplay[row-1].text end
end
end
if(string.find(string.lower(pairText),string.lower(journalSearchString))) then return 1 end -- pair string contains search string.
return nil --does not contain search string
end
function dragJournal()
local offsetX,offsetY,menuWidth,menuHeight = Infinity_GetMenuArea('JOURNAL')
offsetX = offsetX + motionX
offsetY = offsetY + motionY
--clamping
if(offsetX < 80) then
offsetX = 80
end
if(offsetY < 0) then
offsetY = 0
end
local screenWidth, screenHeight = Infinity_GetScreenSize()
if(offsetX > screenWidth - 80 - menuWidth) then
offsetX = screenWidth - 80 - menuWidth
end
if(offsetY > screenHeight - menuHeight) then
offsetY = screenHeight - menuHeight
end
Infinity_SetOffset('JOURNAL', offsetX, offsetY)
end
function journalEntryClickable(selectedJournal)
local entry = journalDisplay[selectedJournal]
if(entry) then return true end
end
function getJournalEntryRef(selectedJournal)
local entry = journalDisplay[selectedJournal]
if(not entry) then return end
if(entry.title) then
return journalDisplay[selectedJournal + 1].text
else
return entry.text
end
end
function getJournalBackgroundFrame()
if(journalMode == const.JOURNAL_MODE_QUESTS) then
return 0
else
return 1
end
end
journalMode = const.JOURNAL_MODE_QUESTS
journalSearchString = ""
`
menu
{
name 'JOURNAL'
align left top
offset 80 0
ignoreEsc
onopen "
reinitQuests()
buildQuestDisplay()
chapter = math.max(0,Infinity_GetMaxChapterPage());
"
label --background background
{
area 0 0 501 773
mosaic "QUESTBAK"
}
label --Background
{
area 0 0 485 747
bam "QUESTBG"
sequence 0
frame lua "getJournalBackgroundFrame()"
}
handle
{
area 0 0 472 80
actionDrag
"
dragJournal()
"
}
button
{
area 216 22 134 34
text "JOURNAL_LABEL"
text style "label_parchment"
text point 16
action "journalMode = const.JOURNAL_MODE_JOURNAL"
}
button
{
area 34 18 136 42
text "QUESTS_LABEL"
text style "label_parchment"
text point 16
action "journalMode = const.JOURNAL_MODE_QUESTS"
}
button
{
area 419 13 66 67
on esc
bam "XBUTT"
action
"
e:GetActiveEngine():OnLeftPanelButtonClick(2)
"
}
label -- Chapter
{
area 85 610 146 60
text lua "chapterText()"
text style "label_parchment"
mosaic "PCHAPTER"
}
button --prev chapter
{
area 48 610 41 60
bam "PARROW"
sequence 0
action
"
incrChapter(-1);
"
}
button
{
area 224 610 41 60
bam "PARROW"
sequence 1
action
"
incrChapter(1);
"
}
--[Bug #20368] Recent events button cut for now.
--
--button
--{
-- enabled "journalMode == const.JOURNAL_MODE_QUESTS"
-- area 278 616 162 47
-- bam "PAPERBUT"
-- sequence 1
-- text "RECENT_EVENTS_LABEL"
-- text style "button_parchment"
-- action
-- "
-- Infinity_PushMenu('JOURNAL_RECENT_EVENTS')
-- "
--}
label
{
enabled "journalMode == const.JOURNAL_MODE_JOURNAL"
area 54 88 374 32
fill 50 50 50 150
}
edit
{
enabled "journalMode == const.JOURNAL_MODE_JOURNAL"
area 62 88 357 32
var journalSearchString
placeholder "ENTER_SEARCH_TERM_NORMAL"
text style "edit"
maxlines 1
}
list
{
column
{
width 10
label
{
area 0 0 31 31
enabled "getArrowEnabled(rowNumber)"
bam "PCHEV"
frame lua "getArrowFrame(rowNumber)"
text style "label_parchment"
align top center
}
}
column {
width 90
label
{
enabled "questEnabled(rowNumber)"
area 0 0 -1 -1
rectangle 1
rectangle opacity 150
}
label
{
enabled "questEnabled(rowNumber)"
area 8 0 -1 -1
text lua "getQuestText(rowNumber)"
text style "label"
align left center
}
label
{
enabled "objectiveEnabled(rowNumber)"
area 16 0 -1 -1
pad 0 10 0 10
text lua "getObjectiveText(rowNumber)"
text style "normal_parchment"
}
label
{
enabled "entryEnabled(rowNumber)"
area 16 0 -1 -1
pad 0 10 0 10
text lua "getEntryText(rowNumber)"
text style "normal_parchment"
text color M
}
}
enabled "journalMode == const.JOURNAL_MODE_QUESTS"
rowheight dynamic
hidehighlight
seperator "showObjectiveSeperator(rowNumber)"
table "questDisplay"
var selectedQuest
scrollbar 'GUISCRP'
area 48 98 404 480
action
"
if(questDisplay[selectedQuest].expanded) then
questDisplay[selectedQuest].expanded = nil
else
questDisplay[selectedQuest].expanded = 1
end
"
}
list --journal
{
column
{
width 100
--light
label
{
enabled "getJournalTitleEnabled(rowNumber) and not getJournalDarken(rowNumber)"
area 0 0 -1 -1
pad 0 16 0 0
text lua "getJournalTitleText(rowNumber)"
text style "label_parchment"
text color 0 120 0 255
}
label
{
enabled "getJournalEntryEnabled(rowNumber) and not getJournalDarken(rowNumber)"
area 0 0 -1 -1
pad 8 16 0 16
text lua "getJournalEntryText(rowNumber)"
text style "normal_parchment"
}
--dark
label
{
enabled "(getJournalTitleEnabled(rowNumber) or getJournalEntryEnabled(rowNumber)) and getJournalDarken(rowNumber)"
area 0 0 -1 -1
fill 0 0 0 150
}
label
{
enabled "getJournalTitleEnabled(rowNumber) and getJournalDarken(rowNumber)"
area 0 0 -1 -1
pad 0 16 0 0
text lua "getJournalTitleText(rowNumber)"
text style "label_parchment"
text color 255 100 100 255
}
label
{
enabled "getJournalEntryEnabled(rowNumber) and getJournalDarken(rowNumber)"
area 0 0 -1 -1
pad 8 16 0 16
text lua "getJournalEntryText(rowNumber)"
text style "normal_parchment"
text color 'B'
}
}
enabled "journalMode == const.JOURNAL_MODE_JOURNAL"
seperator "getJournalEntryEnabled(rowNumber)"
rowheight dynamic
hidehighlight
table "journalDisplay"
var selectedJournal
scrollbar 'GUISCRP'
area 54 128 386 450
}
label
{
area 58 569 382 25
mosaic PAPERSEP
}
button
{
enabled "journalMode == const.JOURNAL_MODE_JOURNAL"
area 272 594 162 47
bam "PAPERBUT"
sequence 1
text "ADD_ENTRY_LABEL"
text style "button_parchment"
action
"
journalMode = const.JOURNAL_MODE_EDIT
journalNoteEdit = ''
journalNoteEditRef = nil
Infinity_FocusTextEdit('journalNoteEditArea')
"
}
button
{
enabled "journalMode == const.JOURNAL_MODE_JOURNAL"
clickable lua "journalEntryClickable(selectedJournal)"
area 272 641 162 47
bam "PAPERBUT"
sequence 1
text "EDIT_ENTRY_LABEL"
text style "button_parchment"
action
"
journalNoteEditRef = getJournalEntryRef(selectedJournal)
journalNoteEdit = Infinity_FetchString(journalNoteEditRef)
journalMode = const.JOURNAL_MODE_EDIT
"
}
label
{
enabled "journalMode == const.JOURNAL_MODE_EDIT"
area 48 88 392 36
text style "normal_parchment"
text "WRITE_ENTRY_TEXT"
}
label
{
enabled "journalMode == const.JOURNAL_MODE_EDIT"
area 58 140 376 4
fill 10 71 1 255
}
label
{
enabled "journalMode == const.JOURNAL_MODE_EDIT"
area 58 144 382 42
text style "label"
text color 0 120 0 255
text lua "Infinity_GetTimeString()"
}
edit
{
name "journalNoteEditArea"
enabled "journalMode == const.JOURNAL_MODE_EDIT"
area 58 186 382 383
text style "edit_parchment"
var journalNoteEdit
scrollbar 'GUISCRP'
}
button
{
on escape
enabled "journalMode == const.JOURNAL_MODE_EDIT"
area 272 641 162 47
bam "PAPERBUT"
sequence 1
text "CANCEL_BUTTON"
text style "button_parchment"
action
"
journalMode = const.JOURNAL_MODE_JOURNAL
"
}
button
{
enabled "journalMode == const.JOURNAL_MODE_EDIT"
area 272 594 162 47
bam "PAPERBUT"
sequence 1
text "DONE_BUTTON"
text style "button_parchment"
action
"
if(journalNoteEditRef == nil) then
Infinity_OnAddUserEntry(journalNoteEdit)
else
Infinity_OnEditUserEntry(journalNoteEditRef, journalNoteEdit)
end
journalMode = const.JOURNAL_MODE_JOURNAL
"
}
}
menu
{
name 'JOURNAL_RECENT_EVENTS'
align center center
modal
label
{
area 0 0 672 672
mosaic "RECENTEV"
}
label
{
area 158 52 354 46
text "RECENT_EVENTS_TITLE"
text style "title"
}
button
{
area 594 10 33 35
bam "XBUTT"
action
"
Infinity_PopMenu('JOURNAL_RECENT_EVENTS')
"
}
text
{
area 126 106 422 458
text "Recent events text will go here."
text style "normal"
}
button
{
area 320 572 200 40
text "DONE_BUTTON"
text style 'button'
bam GUIBUTNT
sequence 2
action
"
Infinity_PopMenu('JOURNAL_RECENT_EVENTS')
"
}
}
`
function processQuestsWithStyle()
out = ""
for k,v in pairs(quests_old) do
local questStrref = v[3]
out = out .. "createQuest ( " .. questStrref .. " )\n"
for k2,v2 in pairs(journals_quests_old) do
if(v2[2] == k) then
local subgroup = v2[const.ENTRIES_IDX_SUBGROUP]
if(subgroup == 0) then subgroup = "nil" end
out = out .. "createEntry ( " .. questStrref .. ", -1, " .. v2[1] .. ", {}, " .. subgroup .." )\n"
end
end
end
Infinity_Log(out)
end