Skip to content

Commit

Permalink
add QuestPinnedRenderer
Browse files Browse the repository at this point in the history
  • Loading branch information
jube committed Oct 14, 2024
1 parent 3ef44b4 commit 1d693af
Show file tree
Hide file tree
Showing 15 changed files with 277 additions and 45 deletions.
2 changes: 0 additions & 2 deletions code/bits/AspectRenderer.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#ifndef AKGR_ASPECT_RENDERER_H
#define AKGR_ASPECT_RENDERER_H

#include <cstdint>
#include <gf2/core/Id.h>
#include <gf2/core/TextStyle.h>

Expand All @@ -10,7 +9,6 @@
#include <gf2/graphics/TextEntity.h>

#include "WorldResources.h"
#include "gf2/core/ShapeBuffer.h"

namespace akgr {
class Akagoria;
Expand Down
131 changes: 131 additions & 0 deletions code/bits/QuestPinnedRenderer.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
#include "QuestPinnedRenderer.h"

#include "Akagoria.h"
#include "QuestData.h"

namespace akgr {

namespace {

gf::RichTextStyle compute_quest_style()
{
gf::RichTextStyle style;
style.set_style("title", { 1.2f, gf::White, gf::FontStyle::Bold });
style.set_style("history", { 1.0f, gf::Yellow, gf::FontStyle::Bold });
style.set_style("current", { 1.0f, gf::White, gf::FontStyle::Italic });
style.set_style("progress", { 1.0f, gf::White, gf::None });
return style;
}

}

QuestPinnedRenderer::QuestPinnedRenderer(Akagoria* game, const WorldResources& resources)
: m_game(game)
, m_atlas({ 1024, 1024 }, game->render_manager())
, m_style(compute_quest_style())
, m_quest_texts({ initial_text(resources), initial_text(resources), initial_text(resources), initial_text(resources), initial_text(resources) })
{
}

void QuestPinnedRenderer::update(gf::Time time)
{
std::vector<QuestState*> visible_quests;

for (auto& quest : m_game->world_state()->hero.quests) {
if (quest.status != QuestStatus::Visible) {
continue;
}

visible_quests.push_back(&quest);
}

if (visible_quests.empty()) {
return;
}

std::sort(visible_quests.begin(), visible_quests.end(), [](const QuestState* lhs, const QuestState* rhs) {
if (lhs->data->scope == QuestScope::History) {
return true;
}

if (rhs->data->scope == QuestScope::History) {
return false;
}

return lhs->last_update > rhs->last_update;
});

if (visible_quests.size() > PinnedQuestCount) {
visible_quests.resize(PinnedQuestCount);
}

m_quest_count = visible_quests.size();

for (std::size_t i = 0; i < m_quest_count; ++i) {
auto& quest = visible_quests[i];
const std::size_t step_index = quest->current_step;

gf::TextData data = m_default_text_data;

if (quest->data->scope == QuestScope::History) {
data.content = fmt::format("<style=title><style=history>{}</></>", quest->data->title);
} else {
data.content = fmt::format("<style=title>{}</>", quest->data->title);
}

switch (quest->type()) {
case QuestType::None:
break;
case QuestType::Hunt:
{
data.content += '\n';

const auto& quest_state = std::get<HuntQuestState>(quest->features);
const auto& quest_data = std::get<HuntQuestData>(quest->data->steps[step_index].features);

data.content += fmt::format("→ <style=current>{}</> <style=progress>{}/{}</>", quest->data->steps[step_index].description, quest_state.amount, quest_data.count);
}
break;
case QuestType::Talk:
{
data.content += '\n';
data.content += fmt::format("→ <style=current>{}</>", quest->data->steps[step_index].description);
}
break;
case QuestType::Farm:
{
data.content += '\n';

const auto& quest_state = std::get<FarmQuestState>(quest->features);
const auto& quest_data = std::get<FarmQuestData>(quest->data->steps[step_index].features);

data.content += fmt::format("→ <style=current>{}</> <style=progress>{}/{}</>", quest->data->steps[step_index].description, quest_state.amount, quest_data.count);
}
break;
case QuestType::Explore:
{
data.content += '\n';
data.content += fmt::format("→ {}", quest->data->steps[step_index].description);
}
break;
}

m_quest_texts[i].text().update(data, m_game->render_manager()); // NOLINT
m_quest_texts[i].set_location({ 1300, 200 }); // NOLINT
}

}

void QuestPinnedRenderer::render(gf::RenderRecorder& recorder)
{
for (std::size_t i = 0; i < m_quest_count; ++i) {
m_quest_texts[i].render(recorder); // NOLINT
}
}

gf::RichTextEntity QuestPinnedRenderer::initial_text(const WorldResources& resources)
{
return { &m_atlas, &m_style, resources.pinned_quest_text, m_game->render_manager(), m_game->resource_manager() };
}

}
39 changes: 39 additions & 0 deletions code/bits/QuestPinnedRenderer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#ifndef AKGR_QUEST_RENDERER_H
#define AKGR_QUEST_RENDERER_H

#include <array>

#include <gf2/graphics/Entity.h>
#include <gf2/graphics/TextEntity.h>

#include "WorldResources.h"

namespace akgr {

class Akagoria;

class QuestPinnedRenderer : public gf::Entity {
public:
QuestPinnedRenderer(Akagoria* game, const WorldResources& resources);

void update(gf::Time time) override;
void render(gf::RenderRecorder& recorder) override;

private:
gf::RichTextEntity initial_text(const WorldResources& resources);

static constexpr std::size_t PinnedQuestCount = 5;

Akagoria* m_game = nullptr;
gf::FontAtlas m_atlas;
gf::RichTextStyle m_style;

gf::TextData m_default_text_data;

std::size_t m_quest_count = 0;
std::array<gf::RichTextEntity, PinnedQuestCount> m_quest_texts;
};

}

#endif // AKGR_QUEST_RENDERER_H
47 changes: 47 additions & 0 deletions code/bits/QuestState.cc
Original file line number Diff line number Diff line change
@@ -1 +1,48 @@
#include "QuestState.h"

#include <cassert>

namespace akgr {

void QuestState::reset_features()
{
assert(current_step < data->steps.size());
const QuestStepData& step = data->steps[current_step];

switch (step.type()) {
case QuestType::None:
{
features = {};
}
break;
case QuestType::Hunt:
{
HuntQuestState state = {};
state.amount = 0;
features = state;
}
break;
case QuestType::Talk:
{
TalkQuestState state = {};
features = state;
}
break;
case QuestType::Farm:
{
FarmQuestState state = {};
state.amount = 0;
features = state;
}
break;
case QuestType::Explore:
{
ExploreQuestState state = {};
features = state;
}
break;
}

}

}
5 changes: 4 additions & 1 deletion code/bits/QuestState.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,18 @@ namespace akgr {
struct QuestState {
DataReference<QuestData> data;
QuestStatus status = QuestStatus::Started;
int64_t last_update = 0;
uint32_t current_step = 0;
std::variant<std::monostate, HuntQuestState, TalkQuestState, FarmQuestState, ExploreQuestState> features;

QuestType type() const { return static_cast<QuestType>(features.index()); }

void reset_features();
};

template<typename Archive>
Archive& operator|(Archive& ar, gf::MaybeConst<QuestState, Archive>& state) {
return ar | state.data | state.status | state.current_step | state.features;
return ar | state.data | state.status | state.last_update | state.current_step | state.features;
}

}
Expand Down
26 changes: 24 additions & 2 deletions code/bits/Script.cc
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
#include "Script.h"

#include <cassert>
#include <ctime>

#include <fstream>

#include <gf2/core/Id.h>

#include "Akagoria.h"
#include "DataLexicon.h"
#include "DataReference.h"
#include "QuestState.h"

namespace akgr {

Expand Down Expand Up @@ -76,6 +77,8 @@ namespace akgr {
return &Script::add_character;
case "add_dialog_to_character(_,_)"_id:
return &Script::add_dialog_to_character;
case "start_quest(_)"_id:
return &Script::start_quest;
default:
break;
}
Expand Down Expand Up @@ -441,6 +444,25 @@ namespace akgr {
agateSlotSetNil(vm, AGATE_RETURN_SLOT);
}

// start_quest(quest)
void Script::start_quest(AgateVM* vm)
{
const char* quest_id = agateSlotGetString(vm, 1);

gf::Log::info("[SCRIPT] World.start_quest({})", quest_id);

QuestState quest;
quest.data.id = gf::hash_string(quest_id);
quest.data.bind_from(data(vm).quests);
check_reference(quest.data, quest_id);
quest.last_update = std::time(nullptr);
quest.status = (quest.data->scope == QuestScope::History) ? QuestStatus::Visible : QuestStatus::Started;
quest.reset_features();

state(vm).hero.quests.push_back(quest);

agateSlotSetNil(vm, AGATE_RETURN_SLOT);
}


Akagoria& Script::game(AgateVM* vm)
Expand Down
2 changes: 2 additions & 0 deletions code/bits/Script.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ namespace akgr {
static void start_dialog(AgateVM* vm);
static void add_dialog_to_character(AgateVM* vm);

static void start_quest(AgateVM* vm);

private:
static Akagoria& game(AgateVM* vm);
static const WorldData& data(AgateVM* vm);
Expand Down
40 changes: 4 additions & 36 deletions code/bits/WorldModel.cc
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#include "WorldModel.h"

#include <ctime>

#include <gf2/core/Math.h>
#include <gf2/core/Log.h>

Expand Down Expand Up @@ -217,47 +219,13 @@ namespace akgr {
bool WorldModel::advance_in_quest(QuestState& quest)
{
++quest.current_step;
quest.last_update = static_cast<int64_t>(std::time(nullptr));

if (quest.current_step == quest.data->steps.size()) {
return true;
}

const QuestStepData& step = quest.data->steps[quest.current_step];

switch (step.type()) {
case QuestType::None:
{
quest.features = {};
}
break;
case QuestType::Hunt:
{
HuntQuestState state = {};
state.amount = 0;
quest.features = state;
}
break;
case QuestType::Talk:
{
TalkQuestState state = {};
quest.features = state;
}
break;
case QuestType::Farm:
{
FarmQuestState state = {};
state.amount = 0;
quest.features = state;
}
break;
case QuestType::Explore:
{
ExploreQuestState state = {};
quest.features = state;
}
break;
}

quest.reset_features();
return false;
}

Expand Down
Loading

0 comments on commit 1d693af

Please sign in to comment.