LoreBooks adds a new UI Element and a simple interface to add longer length books to Outward, it was made as for the Unbound mod but you can use this mod for your own mod without requiring Unbound.
Usage : Create a folder called "LoreBooks" in your root mod folder, create an xml file inside the LoreBooks folder, like the below example.
ItemID - The in-game Item created to allow the user to collect and open your book, you can use SideLoader to create this. The ID would be whatever your custom Items ID is. BookUID - A Unique ID for your book, allowing you to reference it from c# if required.
-2905_Emonomicon.xml
<LoreBookDefinition>
<ItemID>-2905</ItemID>
<TargetItemID>5600050</TargetItemID>
<BookUID>emo.emonomicon</BookUID>
<BookTitle>The EMONOMICON</BookTitle>
<BookDescription>A vile, profane book, mainly used to demonstrate some features of LoreBooks.</BookDescription>
<UseVisual>true</UseVisual>
<VisualColor>
<r>97</r>
<g>0</g>
<b>153</b>
<a>255</a>
</VisualColor>
<BookTitle>
<![CDATA[
Emonomicon
]]>
</BookTitle>
<BookTitlePageContent>
<![CDATA[
<b>This book contains information on the features available to modders.</b>
<i>LoreBooks has limited support for dynamic varibles in the text</i>
Character Name : {0}
HP ({1} / {2})
STAMINA ({3} / {4})
Scene Name {5}
]]>
</BookTitlePageContent>
<Pages>
<PageContent>
<PageTitle>LoreBooks Features (Events)</PageTitle>
<TextContent>
<![CDATA[
<b>Events</b>
You can trigger events on certain actions, such as applying a status effect to the character opening the book.
(you are now bleeding, go to the next page).
]]>
</TextContent>
</PageContent>
<PageContent>
<PageTitle>LoreBooks Features(Interactive)</PageTitle>
<TextContent>
<![CDATA[
<color=red>Bleeding</color> Fixed!
<i>You can only read this book while you have more than zero Current Mana. Or anything you choose, such as quest completion, items owned, or area the player is in.</i>
You can also press the default "Use" key (Space on PC) with certain books! Try it on this page.
]]>
</TextContent>
</PageContent>
</Pages>
</LoreBookDefinition>
If you want to use rich text formatting (<color=green>Text BOLD> etc you need to escape the entire text with...
<![CDATA[
then close it with
]]>
As shown in the example.
<TextContent>
<![CDATA[
<color=red>Bleeding</color> Fixed!
<i>You can only read this book while you have more than zero Current Mana. Or anything you choose, such as quest completion, items owned, or area the player is in.</i>
You can also press the default "Use" key (Space on PC) with certain books! Try it on this page.
]]>
</TextContent>
You can also Define LoreBooks via code
//your mods Awake method
internal void Awake()
{
Log = this.Logger;
Log.LogMessage($"{NAME} Loaded.");
//register to the mods on ready event, you can add books once this is called
LoreBooksMod.Instance.OnReady += OnReadyEvent;
//this is called after all book definitions are loaded, so you can reference the book and register to c# events
//LoreBooksMod.Instance.OnBooksLoaded += OnBookLoadingComplete;
}
private void OnReadyEvent()
{
//mod is ready to add books
DefineABook();
}
private void DefineABook()
{
//an image loaded elsewhere
Sprite SomeHeaderImageForTitle = null;
LoreBook Newbook = new LoreBook("SOMEGUID", "SOME TITLE", "SOME TITLE PAGE CONTENT", SomeHeaderImageForTitle, null);
//an image loaded elsewhere
Sprite SomeHeaderImageForPage = null;
//first (0) is always Title page
Newbook.AddOrUpdatePageContent(0, new PageContent(SomeHeaderImageForPage, "SOME TITLE", "SOME TITLE PAGE CONTENT"));
//add another
Newbook.AddOrUpdatePageContent(1, new PageContent(SomeHeaderImageForPage, "SOME TITLE PAGE 1", "SOME TITLE PAGE 1"));
//add the book to the main mod so it can be shown on the BookUI
//itemID, BookUID, LoreBook
LoreBooksMod.Instance.AddLoreBook(-9999, "SOMEGUID", Newbook);
}
You can also reference books once the OnBooksLoaded event has fired, allowing you to react to certain events. The Emonomicon (ItemID -2105) contains an example of each of the features, spawn it in and read it to learn a bit more otherwise here is a c# example of that same book.
internal void Awake()
{
//this is called after all book definitions are loaded, so you can reference the book and register to c# events
LoreBooksMod.Instance.OnBooksLoaded += OnBookLoadingComplete;
//SL.OnPacksLoaded += SL_OnPacksLoaded;
//new Harmony(GUID).PatchAll();
}
private void OnBookLoadingComplete()
{
//do things with the emonomicon
if (LoreBooksMod.Instance.HasLoreBook("emo.emonomicon"))
{
//get the book reference
LoreBook featureBook = LoreBooksMod.Instance.GetLoreBook("emo.emonomicon");
if (featureBook != null)
{
Dictionary<AreaManager.AreaEnum, Area> Areas = new Dictionary<AreaManager.AreaEnum, Area>();
Area Harmattan = AreaManager.Instance.GetArea(AreaManager.AreaEnum.Harmattan);
Areas.Add(AreaManager.AreaEnum.Harmattan, Harmattan);
Area CierzoOutside = AreaManager.Instance.GetArea(AreaManager.AreaEnum.CierzoOutside);
Areas.Add(AreaManager.AreaEnum.CierzoOutside, CierzoOutside);
Area Berg = AreaManager.Instance.GetArea(AreaManager.AreaEnum.Berg);
Areas.Add(AreaManager.AreaEnum.Berg, Berg);
Area Monsoon = AreaManager.Instance.GetArea(AreaManager.AreaEnum.Monsoon);
Areas.Add(AreaManager.AreaEnum.Monsoon, Monsoon);
int StartingPageCount = featureBook.PageCount;
foreach (var area in Areas)
{
if (!featureBook.HasPage(StartingPageCount))
{
PageContent pagContent = new PageContent(area.Value.GetMapScreen(), $"{area.Value.GetName()}", area.Value.GetName());
pagContent.IsButtonPage = true;
PageContent Page = pagContent.AddButton($"Teleport To {area.Value.GetName()}", (UIBookPanel UIBookPanel, Character Character) =>
{
StartCoroutine(OutwardHelpers.TeleportToArea(Character, LoreBooksMod.Instance.GetBookManagerForCharacter(Character), area.Key));
});
featureBook.AddOrUpdatePageContent(StartingPageCount, pagContent);
featureBook.LockPage(StartingPageCount);
StartingPageCount++;
}
}
featureBook.OnPageOpened += (Character Character, int index) =>
{
if (index == 1)
{
Character.StatusEffectMngr.AddStatusEffect("Bleeding");
}
else if(index != 1 || index != 0)
{
if (Character.StatusEffectMngr.HasStatusEffect("Bleeding"))
{
Character.StatusEffectMngr.RemoveStatusWithIdentifierName("Bleeding");
}
}
};
featureBook.OnInteractKeyPressed += (LoreBook LoreBook, int page, Character Character) =>
{
//if on page 2
if (page == 2)
{
LoreBook.UnlockPages(new int[] { 3, 4, 5, 6 });
}
return false;
};
featureBook.CanOpenPredicate += (Character Character, LoreBook LoreBook) =>
{
if (Character.Mana <= 0)
{
Character.CharacterUI.NotificationPanel.ShowNotification("You cannot open the Emonomicon without a deeper understanding of magic.. find the source of the conflux.");
return false;
}
return true;
};
}
}
}