Skip to content

Commit

Permalink
Make followers and objecthint classes derive from JSONConfig. Add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
FreeSlave committed Nov 26, 2024
1 parent 0de8001 commit e75a279
Show file tree
Hide file tree
Showing 7 changed files with 200 additions and 16 deletions.
13 changes: 7 additions & 6 deletions dlls/followers.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#include "util.h"
#include "logger.h"
#include "string_utils.h"
#include "json_utils.h"

Expand Down Expand Up @@ -27,20 +27,21 @@ const char followersSchema[] = R"(
}
)";

bool FollowersDescription::ReadFromFile(const char *fileName)
const char* FollowersDescription::Schema() const
{
Document document;
if (!ReadJsonDocumentWithSchemaFromFile(document, fileName, followersSchema))
return false;
return followersSchema;
}

bool FollowersDescription::ReadFromDocument(rapidjson::Document& document, const char* fileName)
{
auto monstersIt = document.FindMember("fast_recruit_monsters");
if (monstersIt != document.MemberEnd())
{
Value& a = monstersIt->value;
for (auto it = a.Begin(); it != a.End(); ++it)
{
const char* recruitName = it->GetString();
ALERT(at_console, "Registered recruit: %s\n", recruitName);
LOG("Registered recruit: %s\n", recruitName);
fastRecruitMonsters.push_back(std::string(recruitName));
}
}
Expand Down
11 changes: 7 additions & 4 deletions dlls/followers.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,24 @@

#include <vector>
#include <string>
#include "json_config.h"

class FollowersDescription
class FollowersDescription : public JSONConfig
{
public:
FollowersDescription(): fastRecruitRange(500.0f) {}
bool ReadFromFile(const char* fileName);
float FastRecruitRange() const {
return fastRecruitRange;
}
std::vector<std::string>::const_iterator RecruitsBegin() {
std::vector<std::string>::const_iterator RecruitsBegin() const {
return fastRecruitMonsters.begin();
}
std::vector<std::string>::const_iterator RecruitsEnd() {
std::vector<std::string>::const_iterator RecruitsEnd() const {
return fastRecruitMonsters.cend();
}
protected:
const char* Schema() const;
bool ReadFromDocument(rapidjson::Document& document, const char* fileName);
private:
std::vector<std::string> fastRecruitMonsters;
float fastRecruitRange;
Expand Down
11 changes: 7 additions & 4 deletions dlls/objecthint_spec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -145,12 +145,13 @@ static void ReportUndefinedTemplate(const char* fileName, const char* subject, c
g_errorCollector.AddFormattedError("%s: %s refers to the template '%s' which is not defined", fileName, subject, templateName);
}

void ObjectHintCatalog::ReadFromFile(const char* fileName)
const char* ObjectHintCatalog::Schema() const
{
Document document;
if (!ReadJsonDocumentWithSchemaFromFile(document, fileName, objectHintCatalogSchema))
return;
return objectHintCatalogSchema;
}

bool ObjectHintCatalog::ReadFromDocument(rapidjson::Document& document, const char* fileName)
{
{
auto it = document.FindMember("visuals");
if (it != document.MemberEnd())
Expand Down Expand Up @@ -282,6 +283,8 @@ void ObjectHintCatalog::ReadFromFile(const char* fileName)
}
}
}

return true;
}

ObjectHintCatalog g_objectHintCatalog;
7 changes: 5 additions & 2 deletions dlls/objecthint_spec.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <map>
#include <string>

#include "json_config.h"
#include "spritehint_flags.h"
#include "template_property_types.h"

Expand Down Expand Up @@ -34,15 +35,17 @@ struct ObjectHintSpec
float verticalOffset = 0.0f;
};

struct ObjectHintCatalog
struct ObjectHintCatalog : public JSONConfig
{
void ReadFromFile(const char* fileName);
const ObjectHintSpec* GetSpec(const char* name);
const ObjectHintSpec* GetSpecByEntityName(const char* name);
const ObjectHintSpec* GetSpecByPickupName(const char* name);
float GetMaxDistance() const;
bool HasAnyTemplates() const;

protected:
const char* Schema() const;
bool ReadFromDocument(rapidjson::Document& document, const char* fileName);
private:
const ObjectHintSpec* GetSpec(const std::string& name);

Expand Down
4 changes: 4 additions & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ add_executable(test
fixed_string_test.cpp
fixed_vector_test.cpp
parsetext_test.cpp
followers_test.cpp
objecthint_test.cpp
soundscripts_test.cpp
visuals_test.cpp
warpball_test.cpp
Expand All @@ -28,6 +30,8 @@ add_executable(test
../game_shared/parsetext.cpp
../game_shared/random_utils.cpp
../game_shared/util_shared.cpp
../dlls/followers.cpp
../dlls/objecthint_spec.cpp
../dlls/soundscripts.cpp
../dlls/visuals.cpp
../dlls/warpball.cpp
Expand Down
31 changes: 31 additions & 0 deletions tests/followers_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#include <gtest/gtest.h>
#include <algorithm>
#include "followers.h"

const char followers[] = R"(
{
"fast_recruit_monsters": ["monster_scientist", "monster_barney"],
"fast_recruit_range": 666
}
)";

TEST(Followers, Parse) {
FollowersDescription f;
ASSERT_TRUE(f.ReadFromContents(followers, ""));

EXPECT_EQ(f.FastRecruitRange(), 666);

std::array<std::string, 2> a = {"monster_scientist", "monster_barney"};
EXPECT_TRUE(std::equal(f.RecruitsBegin(), f.RecruitsEnd(), a.cbegin()));
}

const char followersNonunique[] = R"(
{
"fast_recruit_monsters": ["monster_barney", "monster_scientist", "monster_barney"],
}
)";

TEST(Followers, NonUniqueFollowers) {
FollowersDescription f;
ASSERT_FALSE(f.ReadFromContents(followersNonunique, ""));
}
139 changes: 139 additions & 0 deletions tests/objecthint_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
#include <gtest/gtest.h>
#include "objecthint_spec.h"

const char objecthints[] = R"(
{
"visuals": {
"base": {
"sprite": "sprites/hud_brackets.spr"
},
"interactable": {
"color": [255, 200, 50],
"sprite": "sprites/hud_brackets.spr"
},
"charged": {
"color": [0, 255, 0],
"sprite": "sprites/hud_charged.spr",
"scale": 1.2
},
"depleted": {
"color": [255, 0, 0],
"sprite": "sprites/hud_depleted.spr"
},
"lock": {
"color": [255, 50, 0],
"sprite": "sprites/hud_brackets.spr"
}
},
"templates": {
"button": {
"interaction": {
"default": "interactable",
"unusable": null,
"locked": "lock"
}
},
"charger": {
"interaction": {
"default": "charged",
"unusable": "depleted"
}
},
"pickup": {
"scan": {
"default": "base",
"unusable": null
},
"interaction": {
"default": "interactable",
"unusable": null
},
"distance": 256
},
"hidden": {}
},
"entity_mapping": {
"func_button": "button",
"func_rot_button": "button",
"func_healthcharger": "charger",
"func_recharge": "charger",
"item_pickup": "pickup"
},
"pickup_mapping": {
"charger_item": "charger",
"button_item": "button"
}
}
)";

TEST(ObjectHint, Parse) {
ObjectHintCatalog c;
ASSERT_TRUE(c.ReadFromContents(objecthints, ""));

{
const ObjectHintSpec* buttonSpec = c.GetSpec("button");
ASSERT_TRUE(buttonSpec != nullptr);
ASSERT_TRUE(buttonSpec->interactionVisualSet.defaultVisual != nullptr);
ASSERT_TRUE(buttonSpec->interactionVisualSet.unusableVisual == nullptr);
ASSERT_TRUE(buttonSpec->interactionVisualSet.lockedVisual != nullptr);
EXPECT_FALSE(buttonSpec->scanVisualSet.HasAnySpriteDefined());

EXPECT_EQ(buttonSpec->interactionVisualSet.defaultVisual->color, Color(255, 200, 50));
EXPECT_EQ(buttonSpec->interactionVisualSet.defaultVisual->sprite, "sprites/hud_brackets.spr");
EXPECT_EQ(buttonSpec->interactionVisualSet.defaultVisual->scale, 1.0f);

EXPECT_EQ(buttonSpec->interactionVisualSet.lockedVisual->color, Color(255, 50, 0));

EXPECT_EQ(buttonSpec, c.GetSpecByEntityName("func_button"));
EXPECT_EQ(buttonSpec, c.GetSpecByEntityName("func_rot_button"));
}

{
const ObjectHintSpec* chargerSpec = c.GetSpec("charger");
ASSERT_TRUE(chargerSpec != nullptr);
ASSERT_TRUE(chargerSpec->interactionVisualSet.defaultVisual != nullptr);
ASSERT_TRUE(chargerSpec->interactionVisualSet.unusableVisual != nullptr);
EXPECT_EQ(chargerSpec->interactionVisualSet.lockedVisual, chargerSpec->interactionVisualSet.defaultVisual);

EXPECT_EQ(chargerSpec->interactionVisualSet.defaultVisual->color, Color(0, 255, 0));
EXPECT_EQ(chargerSpec->interactionVisualSet.defaultVisual->sprite, "sprites/hud_charged.spr");
EXPECT_EQ(chargerSpec->interactionVisualSet.defaultVisual->scale, 1.2f);

EXPECT_EQ(chargerSpec->interactionVisualSet.unusableVisual->color, Color(255, 0, 0));
EXPECT_EQ(chargerSpec->interactionVisualSet.unusableVisual->sprite, "sprites/hud_depleted.spr");

EXPECT_EQ(chargerSpec, c.GetSpecByEntityName("func_healthcharger"));
EXPECT_EQ(chargerSpec, c.GetSpecByEntityName("func_recharge"));
}

{
const ObjectHintSpec* pickupSpec = c.GetSpec("pickup");
ASSERT_TRUE(pickupSpec != nullptr);
ASSERT_TRUE(pickupSpec->interactionVisualSet.defaultVisual != nullptr);
ASSERT_TRUE(pickupSpec->interactionVisualSet.unusableVisual == nullptr);
EXPECT_EQ(pickupSpec->interactionVisualSet.lockedVisual, pickupSpec->interactionVisualSet.defaultVisual);

ASSERT_TRUE(pickupSpec->scanVisualSet.defaultVisual != nullptr);
ASSERT_TRUE(pickupSpec->scanVisualSet.unusableVisual == nullptr);
EXPECT_EQ(pickupSpec->scanVisualSet.lockedVisual, pickupSpec->scanVisualSet.defaultVisual);

EXPECT_EQ(pickupSpec->interactionVisualSet.defaultVisual->color, Color(255, 200, 50));

EXPECT_EQ(pickupSpec, c.GetSpecByEntityName("item_pickup"));

const ObjectHintSpec* item1Spec = c.GetSpecByPickupName("charger_item");
ASSERT_TRUE(item1Spec != nullptr);
EXPECT_EQ(item1Spec, c.GetSpec("charger"));

const ObjectHintSpec* item2Spec = c.GetSpecByPickupName("button_item");
ASSERT_TRUE(item2Spec != nullptr);
EXPECT_EQ(item2Spec, c.GetSpec("button"));
}

{
const ObjectHintSpec* hiddenSpec = c.GetSpec("hidden");
ASSERT_TRUE(hiddenSpec != nullptr);
EXPECT_FALSE(hiddenSpec->interactionVisualSet.HasAnySpriteDefined());
EXPECT_FALSE(hiddenSpec->scanVisualSet.HasAnySpriteDefined());
}
}

0 comments on commit e75a279

Please sign in to comment.