Browse Source

Add tests for quest randomisation code

Required splitting the code to a separate function so it can be tested in isolation
pull/2396/head
ephphatha 5 years ago committed by Anders Jenbo
parent
commit
0efb134e18
  1. 2
      .circleci/config.yml
  2. 1
      CMakeLists.txt
  3. 26
      Source/quests.cpp
  4. 7
      Source/quests.h
  5. 73
      test/quests_test.cpp

2
.circleci/config.yml

@ -24,7 +24,7 @@ jobs:
steps:
- checkout
- run: apt-get update -y
- run: apt-get install -y cmake curl g++ git lcov libgtest-dev libfmt-dev libsdl2-dev libsdl2-ttf-dev libsodium-dev
- run: apt-get install -y cmake curl g++ git lcov libgtest-dev libgmock-dev libfmt-dev libsdl2-dev libsdl2-ttf-dev libsodium-dev
- run: cmake -S. -Bbuild -DRUN_TESTS=ON -DENABLE_CODECOVERAGE=ON
- run: cmake --build build -j 2
- run: cmake --build build -j 2 --target test

1
CMakeLists.txt

@ -532,6 +532,7 @@ if(RUN_TESTS)
test/missiles_test.cpp
test/pack_test.cpp
test/player_test.cpp
test/quests_test.cpp
test/random_test.cpp
test/scrollrt_test.cpp
test/stores_test.cpp

26
Source/quests.cpp

@ -161,16 +161,8 @@ void InitQuests()
}
if (!gbIsMultiplayer && sgOptions.Gameplay.bRandomizeQuests) {
SetRndSeed(glSeedTbl[15]);
if (GenerateRnd(2) != 0)
Quests[Q_PWATER]._qactive = QUEST_NOTAVAIL;
else
Quests[Q_SKELKING]._qactive = QUEST_NOTAVAIL;
Quests[QuestGroup1[GenerateRnd(sizeof(QuestGroup1) / sizeof(int))]]._qactive = QUEST_NOTAVAIL;
Quests[QuestGroup2[GenerateRnd(sizeof(QuestGroup2) / sizeof(int))]]._qactive = QUEST_NOTAVAIL;
Quests[QuestGroup3[GenerateRnd(sizeof(QuestGroup3) / sizeof(int))]]._qactive = QUEST_NOTAVAIL;
Quests[QuestGroup4[GenerateRnd(sizeof(QuestGroup4) / sizeof(int))]]._qactive = QUEST_NOTAVAIL;
// Quests are set from the seed used to generate level 16.
InitialiseQuestPools(glSeedTbl[15], Quests);
}
#ifdef _DEBUG
if (questdebug != -1)
@ -192,6 +184,20 @@ void InitQuests()
Quests[Q_BETRAYER]._qvar1 = 2;
}
void InitialiseQuestPools(uint32_t seed, QuestStruct quests[])
{
SetRndSeed(seed);
if (GenerateRnd(2) != 0)
quests[Q_PWATER]._qactive = QUEST_NOTAVAIL;
else
quests[Q_SKELKING]._qactive = QUEST_NOTAVAIL;
quests[QuestGroup1[GenerateRnd(sizeof(QuestGroup1) / sizeof(int))]]._qactive = QUEST_NOTAVAIL;
quests[QuestGroup2[GenerateRnd(sizeof(QuestGroup2) / sizeof(int))]]._qactive = QUEST_NOTAVAIL;
quests[QuestGroup3[GenerateRnd(sizeof(QuestGroup3) / sizeof(int))]]._qactive = QUEST_NOTAVAIL;
quests[QuestGroup4[GenerateRnd(sizeof(QuestGroup4) / sizeof(int))]]._qactive = QUEST_NOTAVAIL;
}
void CheckQuests()
{
if (gbIsSpawn)

7
Source/quests.h

@ -78,6 +78,13 @@ extern dungeon_type ReturnLevelType;
extern int ReturnLevel;
void InitQuests();
/**
* @brief Deactivates quests from each quest pool at random to provide variety for single player games
* @param seed The seed used to control which quests are deactivated
* @param quests The available quest list, this function will make some of them inactive by the time it returns
*/
void InitialiseQuestPools(uint32_t seed, QuestStruct quests[]);
void CheckQuests();
bool ForceQuests();
bool QuestStatus(int i);

73
test/quests_test.cpp

@ -0,0 +1,73 @@
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include "quests.h"
#include "objdat.h" // For quest IDs
namespace devilution {
void ResetQuests()
{
for (auto &quest : Quests)
quest._qactive = QUEST_INIT;
}
std::vector<quest_state> GetActiveFlagsForSlice(std::initializer_list<quest_id> ids)
{
std::vector<quest_state> temp;
for (auto id : ids)
temp.push_back(Quests[id]._qactive);
return temp;
}
TEST(QuestTest, SinglePlayerBadPools)
{
ResetQuests();
// (INT_MIN >> 16) % 2 = 0, so the times when the RNG calls GenerateRnd(2) don't end up with a negative value.
InitialiseQuestPools(1457187811, Quests);
EXPECT_EQ(Quests[Q_SKELKING]._qactive, QUEST_NOTAVAIL) << "Skeleton King quest is deactivated with 'bad' seed";
ResetQuests();
InitialiseQuestPools(988045466, Quests);
EXPECT_THAT(GetActiveFlagsForSlice({ Q_BUTCHER, Q_LTBANNER, Q_GARBUD }), ::testing::Each(QUEST_INIT)) << "All quests in pool 2 remain active with 'bad' seed";
ResetQuests();
InitialiseQuestPools(4203210069U, Quests);
EXPECT_THAT(GetActiveFlagsForSlice({ Q_BLIND, Q_ROCK, Q_BLOOD }), ::testing::Each(QUEST_INIT)) << "All quests in pool 3 remain active with 'bad' seed";
ResetQuests();
InitialiseQuestPools(2557708932U, Quests);
EXPECT_THAT(GetActiveFlagsForSlice({ Q_MUSHROOM, Q_ZHAR, Q_ANVIL }), ::testing::Each(QUEST_INIT)) << "All quests in pool 4 remain active with 'bad' seed";
ResetQuests();
InitialiseQuestPools(1272442071, Quests);
EXPECT_EQ(Quests[Q_VEIL]._qactive, QUEST_NOTAVAIL) << "Lachdan quest is deactivated with 'bad' seed";
}
TEST(QuestTest, SinglePlayerGoodPools)
{
ResetQuests();
InitialiseQuestPools(509604, Quests);
EXPECT_EQ(Quests[Q_SKELKING]._qactive, QUEST_INIT) << "Expected Skeleton King quest to be available with the given seed";
EXPECT_EQ(Quests[Q_PWATER]._qactive, QUEST_NOTAVAIL) << "Expected Poison Water quest to be deactivated with the given seed";
EXPECT_EQ(Quests[Q_BUTCHER]._qactive, QUEST_INIT) << "Expected Butcher quest to be available with the given seed";
EXPECT_EQ(Quests[Q_LTBANNER]._qactive, QUEST_INIT) << "Expected Ogden's Sign quest to be available with the given seed";
EXPECT_EQ(Quests[Q_GARBUD]._qactive, QUEST_NOTAVAIL) << "Expected Gharbad the Weak quest to be deactivated with the given seed";
EXPECT_EQ(Quests[Q_BLIND]._qactive, QUEST_INIT) << "Expected Halls of the Blind quest to be available with the given seed";
EXPECT_EQ(Quests[Q_ROCK]._qactive, QUEST_NOTAVAIL) << "Expected Magic Rock quest to be deactivated with the given seed";
EXPECT_EQ(Quests[Q_BLOOD]._qactive, QUEST_INIT) << "Expected Valor quest to be available with the given seed";
EXPECT_EQ(Quests[Q_MUSHROOM]._qactive, QUEST_INIT) << "Expected Black Mushroom quest to be available with the given seed";
EXPECT_EQ(Quests[Q_ZHAR]._qactive, QUEST_NOTAVAIL) << "Expected Zhar the Mad quest to be deactivated with the given seed";
EXPECT_EQ(Quests[Q_ANVIL]._qactive, QUEST_INIT) << "Expected Anvil of Fury quest to be available with the given seed";
EXPECT_EQ(Quests[Q_VEIL]._qactive, QUEST_NOTAVAIL) << "Expected Lachdanan quest to be deactivated with the given seed";
EXPECT_EQ(Quests[Q_WARLORD]._qactive, QUEST_INIT) << "Expected Warlord of Blood quest to be available with the given seed";
}
} // namespace devilution
Loading…
Cancel
Save