Skip to content

Commit

Permalink
Issue #137 Load spell info (#138)
Browse files Browse the repository at this point in the history
* Issue #137 Load spell info

More details of spell data files have been discovered by
Joris Van Eijden. Implement these in BaKGL

* Add item usage for scrolls
* Add persisting of spells
* Add LearnSpell dialog action
  • Loading branch information
xavieran authored Jan 14, 2024
1 parent 3be9a78 commit f70a3fc
Show file tree
Hide file tree
Showing 22 changed files with 569 additions and 48 deletions.
5 changes: 2 additions & 3 deletions app/display_spells.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#include "bak/camp.hpp"
#include "bak/spells.hpp"

#include "com/logger.hpp"

Expand All @@ -8,9 +8,8 @@ int main(int argc, char** argv)
Logging::LogState::SetLevel(Logging::LogLevel::Debug);
Logging::LogState::Disable("DialogStore");

//BAK::SpellInfo();
BAK::SpellInfo();

BAK::CampData{};
return 0;
}

3 changes: 2 additions & 1 deletion bak/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,10 @@ add_library(bak
screen.hpp screen.cpp
screens.hpp
shop.hpp shop.cpp
skills.hpp skills.cpp
sound.hpp sound.cpp
soundStore.hpp soundStore.cpp
skills.hpp skills.cpp
spells.hpp spells.cpp
tags.hpp tags.cpp
temple.hpp temple.cpp
textureFactory.hpp textureFactory.cpp
Expand Down
15 changes: 13 additions & 2 deletions bak/character.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "bak/condition.hpp"
#include "bak/itemNumbers.hpp"
#include "bak/skills.hpp"
#include "bak/spells.hpp"
#include "bak/types.hpp"
#include "bak/inventory.hpp"

Expand All @@ -25,7 +26,7 @@ class Character final : public IContainer
unsigned index,
const std::string& name,
const Skills& skills,
const std::array<std::uint8_t, 6>& spells,
Spells spells,
const std::array<std::uint8_t, 2>& unknown,
const std::array<std::uint8_t, 7>& unknown2,
const Conditions& conditions,
Expand Down Expand Up @@ -367,10 +368,20 @@ class Character final : public IContainer
GetSkill(static_cast<SkillType>(i));
}

Spells& GetSpells()
{
return mSpells;
}

const Spells& GetSpells() const
{
return mSpells;
}

CharIndex mCharacterIndex;
std::string mName;
mutable Skills mSkills;
std::array<std::uint8_t, 6> mSpells;
Spells mSpells;
std::array<std::uint8_t, 2> mUnknown;
std::array<std::uint8_t, 7> mUnknown2;
Conditions mConditions;
Expand Down
10 changes: 10 additions & 0 deletions bak/dialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,16 @@ DialogSnippet::DialogSnippet(FileBuffer& fb, std::uint8_t dialogFile)
state,
rest});
}
else if (dr == DialogResult::LearnSpell)
{
const auto who = fb.GetUint16LE();
const auto whichSpell = fb.GetUint16LE();
const auto rest = fb.GetArray<4>();
mActions.emplace_back(
LearnSpell{
who,
whichSpell});
}
else if (dr == DialogResult::PlaySound)
{
const auto soundIndex = fb.GetUint16LE();
Expand Down
6 changes: 6 additions & 0 deletions bak/dialogAction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,12 @@ std::ostream& operator<<(std::ostream& os, const SetEndOfDialogState& action)
return os;
}

std::ostream& operator<<(std::ostream& os, const LearnSpell& action)
{
os << "LearnSpell{who: " << action.mWho << ", whichSpell: " << action.mWhichSpell << "}";
return os;
}

std::ostream& operator<<(std::ostream& os, const UnknownAction& action)
{
os << "UnknownAction { "
Expand Down
15 changes: 15 additions & 0 deletions bak/dialogAction.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,20 @@ struct SetEndOfDialogState
std::array<std::uint8_t, 6> mRest;
};

struct LearnSpell
{
LearnSpell(
std::uint16_t who,
std::uint16_t whichSpell)
:
mWho(who),
mWhichSpell(whichSpell)
{}

std::uint16_t mWho;
std::uint16_t mWhichSpell;
};

struct UnknownAction
{
UnknownAction(
Expand Down Expand Up @@ -214,6 +228,7 @@ using DialogAction = std::variant<
Teleport,
UpdateCharacters,
SetEndOfDialogState,
LearnSpell,
UnknownAction>;

std::ostream& operator<<(std::ostream& os, const DialogAction& d);
Expand Down
2 changes: 1 addition & 1 deletion bak/dialogSources.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ class DialogSources
static constexpr auto mConsumeAntiVenom = 0x1b776f;
static constexpr auto mNoSpaceForNewItem = 0x1b775b;
static constexpr auto mCantConsumeAlcohol = 0x1b775c;
static constexpr auto mWarriorCantUseMagiciansItem = 0x1b7745;
static constexpr auto mWarriorCantUseMagiciansItem = KeyTarget{0x1b7745};
static constexpr auto mMagicianCantUseWarriorsItem = 0x1b7771;
static constexpr auto mCantUseItemRightNow = 0x1b7746;
static constexpr auto mCantUseItemDuringCombat = 0x1b7747;
Expand Down
35 changes: 21 additions & 14 deletions bak/gameData.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "bak/gameData.hpp"
#include "bak/save.hpp"
#include "bak/spells.hpp"

#include "bak/container.hpp"
#include "bak/inventory.hpp"
Expand Down Expand Up @@ -81,14 +82,14 @@ void GameData::SetBitValueAt(unsigned byteOffset, unsigned bitOffset, unsigned v
mBuffer.Seek(byteOffset);
mBuffer.PutUint16LE(data);

mLogger.Debug() << __FUNCTION__ << std::hex <<
mLogger.Spam() << __FUNCTION__ << std::hex <<
" " << byteOffset << " " << bitOffset
<< " original[" << +originalData << "] new[" << +data <<"]\n" << std::dec;
}

void GameData::SetEventFlag(unsigned eventPtr, unsigned value)
{
mLogger.Debug() << __FUNCTION__ << " " << std::hex << eventPtr
mLogger.Spam() << __FUNCTION__ << " " << std::hex << eventPtr
<< " to: " << value << std::dec << "\n";
if (eventPtr >= 0xdac0)
{
Expand Down Expand Up @@ -125,7 +126,7 @@ void GameData::SetEventDialogAction(const SetFlag& setFlag)
^ setFlag.mAlwaysZero;
mBuffer.Seek(offset);

mLogger.Debug() << __FUNCTION__ << std::hex <<
mLogger.Spam() << __FUNCTION__ << std::hex <<
" " << setFlag << " offset: " << offset
<< " data[" << +data << "] new[" << +newData <<"]\n" << std::dec;
mBuffer.PutUint8(newData);
Expand Down Expand Up @@ -475,18 +476,26 @@ std::vector<Character> GameData::LoadCharacters()
unsigned characters = sCharacterCount;

std::vector<Character> chars;
auto spellInfo = SpellInfo{};

for (unsigned character = 0; character < characters; character++)
{
mBuffer.Seek(GetCharacterNameOffset(character));
auto name = mBuffer.GetString(sCharacterNameLength);

mBuffer.Seek(GetCharacterSkillOffset(character));
mLogger.Spam() << "Name: " << name << "@"
mLogger.Debug() << "Name: " << name << "@"
<< std::hex << mBuffer.Tell() << std::dec << "\n";

auto characterNameOffset = mBuffer.GetArray<2>();
auto spells = mBuffer.GetArray<6>();
auto spells = Spells{mBuffer.GetArray<6>()};
for (const auto& spell : spellInfo.GetSpells())
{
if (spell.HasSpell(spells))
{
mLogger.Debug() << " " << spell.mName << "\n";
}
}

auto skills = Skills{};

Expand Down Expand Up @@ -679,11 +688,11 @@ std::vector<GenericContainer> GameData::LoadShops()
for (unsigned i = 0; i < sShopsCount; i++)
{
const unsigned address = mBuffer.Tell();
mLogger.Debug() << " Container: " << i
mLogger.Spam() << " Container: " << i
<< " addr: " << std::hex << address << std::dec << std::endl;
auto container = LoadGenericContainer<ContainerGDSLocationTag>(mBuffer);
shops.emplace_back(std::move(container));
mLogger.Debug() << shops.back() << "\n";
mLogger.Spam() << shops.back() << "\n";
}

return shops;
Expand Down Expand Up @@ -718,7 +727,7 @@ void GameData::LoadChapterOffsetP()
constexpr unsigned chapterOffsetsStart = 0x11a3;
mBuffer.Seek(chapterOffsetsStart);

mLogger.Spam() << "Chapter Offsets Start @"
mLogger.Debug() << "Chapter Offsets Start @"
<< std::hex << chapterOffsetsStart << std::dec << std::endl;

for (unsigned i = 0; i < 10; i++)
Expand All @@ -730,10 +739,10 @@ void GameData::LoadChapterOffsetP()
unsigned addr = mBuffer.GetUint32LE();
ss << " a: " << std::hex << addr << std::dec;
}
mLogger.Spam() << ss.str() << std::endl;
mLogger.Debug() << ss.str() << std::endl;
}

mLogger.Spam() << "Chapter Offsets End @"
mLogger.Debug() << "Chapter Offsets End @"
<< std::hex << mBuffer.Tell() << std::dec << std::endl;
}

Expand Down Expand Up @@ -777,9 +786,7 @@ void GameData::LoadCombatStats(unsigned offset, unsigned num)
mLogger.Info() << "Combat #" << std::dec << i
<< " " << std::hex << mBuffer.Tell() << std::endl;
mLogger.Info() << std::hex << mBuffer.GetUint16LE() << std::endl << std::dec;
// These are spells
//mBuffer.DumpAndSkip(6);
mBuffer.Skip(6);
auto spells = Spells(mBuffer.GetArray<6>());

std::stringstream ss{""};
for (const auto& stat : {
Expand All @@ -792,7 +799,7 @@ void GameData::LoadCombatStats(unsigned offset, unsigned num)
<< +mBuffer.GetUint8() << " " << +mBuffer.GetUint8() << " ";
mBuffer.Skip(2);
}
mBuffer.Skip(7);
mBuffer.Skip(7); // Conditions?
mLogger.Info() << ss.str() << std::endl;
}
mLogger.Info() << "Combat Stats End @"
Expand Down
17 changes: 16 additions & 1 deletion bak/gameState.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class GameState
0,
"None",
Skills{},
{},
Spells{{}},
{},
{},
Conditions{},
Expand Down Expand Up @@ -444,6 +444,21 @@ class GameState
load.mTarget == 1); // best or worst skill
mSkillValue = value;
},
[&](const BAK::LearnSpell& learnSpell)
{
// This is always 5 - which must mean the party magician
mLogger.Debug() << "Learning Spell: " << learnSpell << "\n";
assert(learnSpell.mWho == 5);
mParty.ForEachActiveCharacter(
[&](auto& character){
if (character.IsSpellcaster())
{
character.GetSpells().SetSpell(learnSpell.mWhichSpell);
return true;
}
return false;
});
},
[&](const auto& a){
mLogger.Debug() << "Doing nothing for: " << a << "\n";
}},
Expand Down
2 changes: 1 addition & 1 deletion bak/inventoryItem.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class InventoryItem

auto GetItemIndex() const { return mItemIndex; }
auto GetQuantity() const { return mCondition; }
auto GetScroll() const { return mCondition; }
auto GetSpell() const { return mCondition; }
auto GetCondition() const { return mCondition; }
auto GetStatus() const { return mStatus; }
auto GetModifierMask() const { return mModifiers; }
Expand Down
12 changes: 9 additions & 3 deletions bak/monster.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ MonsterNames::MonsterNames()
{
auto fb = FileBufferFactory::Get().CreateDataBuffer("MNAMES.DAT");
const auto monsters = fb.GetUint32LE();
logger.Spam() << "Loading keywords" << "\n";
logger.Spam() << "Length: " << monsters << "\n";
logger.Spam() << "Loading monsters: " << "\n";
logger.Spam() << "Monsters: " << monsters << "\n";

std::vector<unsigned> offsets{};
for (unsigned i = 0; i < monsters; i++)
Expand All @@ -36,7 +36,13 @@ MonsterNames::MonsterNames()
unsigned p = 0;
for (auto offset : offsets)
{
if (start + offset > fb.GetSize()) continue;
if (start + offset > fb.GetSize())
{
logger.Spam() << "Seeking past end of file!\n";
strings.emplace_back("INVALID MONSTER");
mMonsterNames.emplace_back("INVALID MONSTER");
continue;
}
fb.Seek(start + offset);
const auto& keyword = strings.emplace_back(fb.GetString());
logger.Spam() << p++ << " " << keyword << std::endl;
Expand Down
13 changes: 13 additions & 0 deletions bak/monster.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ namespace BAK {

class MonsterNames
{
static constexpr std::string sInvalidMonster = "INVALID MONSTER";
public:
MonsterNames();

Expand All @@ -36,6 +37,18 @@ class MonsterNames
std::uint8_t mColorSwap;
};

const std::string& GetMonsterName(MonsterIndex monster) const
{
if (monster.mValue < mMonsterNames.size())
{
return mMonsterNames[monster.mValue];
}
else
{
return sInvalidMonster;
}
}

const std::string& GetMonsterAnimationFile(MonsterIndex monster) const
{
ASSERT(monster.mValue < mMonsterPrefixes.size());
Expand Down
6 changes: 3 additions & 3 deletions bak/objectInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ ObjectIndex::ObjectIndex()
for (unsigned i = 0; i < sObjectCount; i++)
{
const auto name = fb.GetString(30);
logger.Debug() << "ItemOff: " << std::hex << fb.Tell() << std::dec << "\n";
logger.Spam() << "ItemOff: " << std::hex << fb.Tell() << std::dec << "\n";
const auto unknown = fb.GetArray<2>();
const auto flags = fb.GetUint16LE();
const auto unknown2 = fb.GetArray<2>();
Expand Down Expand Up @@ -254,10 +254,10 @@ ObjectIndex::ObjectIndex()
dullFactor1,
minimumCondition};

logger.Debug() << i << std::hex << " Unknown0: " << unknown << "|2 "
logger.Spam() << i << std::hex << " Unknown0: " << unknown << "|2 "
<< unknown2 << "|5 "
<< unknown5 << "|" << name << std::dec << "\n";
logger.Debug() << "ItmIndex:" << i << " " << mObjects[i] << "\n";
logger.Spam() << "ItmIndex:" << i << " " << mObjects[i] << "\n";
}
}

Expand Down
8 changes: 6 additions & 2 deletions bak/save.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,12 @@ void Save(const Character& c, FileBuffer& fb)
const auto charIndex = c.mCharacterIndex.mValue;
// Skills
fb.Seek(BAK::GameData::GetCharacterSkillOffset(charIndex));
fb.Skip(2); // Unknown
fb.Skip(6); // FIXME: Spells...
fb.Skip(2); // Character name offset
auto* spells = reinterpret_cast<const std::uint8_t*>(&c.GetSpells().mSpells);
for (unsigned i = 0; i < 6; i++)
{
fb.PutUint8(spells[i]);
}

const auto& skills = c.GetSkills();
for (unsigned i = 0; i < Skills::sSkills; i++)
Expand Down
Loading

0 comments on commit f70a3fc

Please sign in to comment.