mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-03-12 04:14:05 +00:00
Merge branch 'downsized' into 'master'
Remove explicitly sized reads See merge request OpenMW/openmw!3663
This commit is contained in:
commit
2873f971a6
@ -1084,14 +1084,8 @@ namespace EsmTool
|
||||
std::cout << " Rank: " << (int)mData.mNpdt.mRank << std::endl;
|
||||
|
||||
std::cout << " Attributes:" << std::endl;
|
||||
std::cout << " Strength: " << (int)mData.mNpdt.mStrength << std::endl;
|
||||
std::cout << " Intelligence: " << (int)mData.mNpdt.mIntelligence << std::endl;
|
||||
std::cout << " Willpower: " << (int)mData.mNpdt.mWillpower << std::endl;
|
||||
std::cout << " Agility: " << (int)mData.mNpdt.mAgility << std::endl;
|
||||
std::cout << " Speed: " << (int)mData.mNpdt.mSpeed << std::endl;
|
||||
std::cout << " Endurance: " << (int)mData.mNpdt.mEndurance << std::endl;
|
||||
std::cout << " Personality: " << (int)mData.mNpdt.mPersonality << std::endl;
|
||||
std::cout << " Luck: " << (int)mData.mNpdt.mLuck << std::endl;
|
||||
for (size_t i = 0; i != mData.mNpdt.mAttributes.size(); i++)
|
||||
std::cout << " " << attributeLabel(i) << ": " << int(mData.mNpdt.mAttributes[i]) << std::endl;
|
||||
|
||||
std::cout << " Skills:" << std::endl;
|
||||
for (size_t i = 0; i != mData.mNpdt.mSkills.size(); i++)
|
||||
@ -1169,19 +1163,23 @@ namespace EsmTool
|
||||
std::cout << " Description: " << mData.mDescription << std::endl;
|
||||
std::cout << " Flags: " << raceFlags(mData.mData.mFlags) << std::endl;
|
||||
|
||||
for (int i = 0; i < 2; ++i)
|
||||
std::cout << " Male:" << std::endl;
|
||||
for (int j = 0; j < ESM::Attribute::Length; ++j)
|
||||
{
|
||||
bool male = i == 0;
|
||||
|
||||
std::cout << (male ? " Male:" : " Female:") << std::endl;
|
||||
|
||||
for (int j = 0; j < ESM::Attribute::Length; ++j)
|
||||
std::cout << " " << ESM::Attribute::indexToRefId(j) << ": "
|
||||
<< mData.mData.mAttributeValues[j].getValue(male) << std::endl;
|
||||
|
||||
std::cout << " Height: " << mData.mData.mHeight.getValue(male) << std::endl;
|
||||
std::cout << " Weight: " << mData.mData.mWeight.getValue(male) << std::endl;
|
||||
ESM::RefId id = ESM::Attribute::indexToRefId(j);
|
||||
std::cout << " " << id << ": " << mData.mData.getAttribute(id, true) << std::endl;
|
||||
}
|
||||
std::cout << " Height: " << mData.mData.mMaleHeight << std::endl;
|
||||
std::cout << " Weight: " << mData.mData.mMaleWeight << std::endl;
|
||||
|
||||
std::cout << " Female:" << std::endl;
|
||||
for (int j = 0; j < ESM::Attribute::Length; ++j)
|
||||
{
|
||||
ESM::RefId id = ESM::Attribute::indexToRefId(j);
|
||||
std::cout << " " << id << ": " << mData.mData.getAttribute(id, false) << std::endl;
|
||||
}
|
||||
std::cout << " Height: " << mData.mData.mFemaleHeight << std::endl;
|
||||
std::cout << " Weight: " << mData.mData.mFemaleWeight << std::endl;
|
||||
|
||||
for (const auto& bonus : mData.mData.mBonus)
|
||||
// Not all races have 7 skills.
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "converter.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <osgDB/WriteFile>
|
||||
@ -90,14 +91,14 @@ namespace ESSImport
|
||||
|
||||
struct MAPH
|
||||
{
|
||||
unsigned int size;
|
||||
unsigned int value;
|
||||
uint32_t size;
|
||||
uint32_t value;
|
||||
};
|
||||
|
||||
void ConvertFMAP::read(ESM::ESMReader& esm)
|
||||
{
|
||||
MAPH maph;
|
||||
esm.getHNTSized<8>(maph, "MAPH");
|
||||
esm.getHNT("MAPH", maph.size, maph.value);
|
||||
std::vector<char> data;
|
||||
esm.getSubNameIs("MAPD");
|
||||
esm.getSubHeader();
|
||||
@ -278,7 +279,7 @@ namespace ESSImport
|
||||
while (esm.isNextSub("MPCD"))
|
||||
{
|
||||
float notepos[3];
|
||||
esm.getHTSized<3 * sizeof(float)>(notepos);
|
||||
esm.getHT(notepos);
|
||||
|
||||
// Markers seem to be arranged in a 32*32 grid, notepos has grid-indices.
|
||||
// This seems to be the reason markers can't be placed everywhere in interior cells,
|
||||
|
@ -1,6 +1,7 @@
|
||||
#ifndef OPENMW_ESSIMPORT_ACDT_H
|
||||
#define OPENMW_ESSIMPORT_ACDT_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
#include "importscri.hpp"
|
||||
@ -25,14 +26,12 @@ namespace ESSImport
|
||||
};
|
||||
|
||||
/// Actor data, shared by (at least) REFR and CellRef
|
||||
#pragma pack(push)
|
||||
#pragma pack(1)
|
||||
struct ACDT
|
||||
{
|
||||
// Note, not stored at *all*:
|
||||
// - Level changes are lost on reload, except for the player (there it's in the NPC record).
|
||||
unsigned char mUnknown[12];
|
||||
unsigned int mFlags;
|
||||
uint32_t mFlags;
|
||||
float mBreathMeter; // Seconds left before drowning
|
||||
unsigned char mUnknown2[20];
|
||||
float mDynamic[3][2];
|
||||
@ -41,7 +40,7 @@ namespace ESSImport
|
||||
float mMagicEffects[27]; // Effect attributes:
|
||||
// https://wiki.openmw.org/index.php?title=Research:Magic#Effect_attributes
|
||||
unsigned char mUnknown4[4];
|
||||
unsigned int mGoldPool;
|
||||
uint32_t mGoldPool;
|
||||
unsigned char mCountDown; // seen the same value as in ACSC.mCorpseClearCountdown, maybe
|
||||
// this one is for respawning?
|
||||
unsigned char mUnknown5[3];
|
||||
@ -60,7 +59,6 @@ namespace ESSImport
|
||||
unsigned char mUnknown[3];
|
||||
float mTime;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
struct ActorData
|
||||
{
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "importcellref.hpp"
|
||||
|
||||
#include <components/esm3/esmreader.hpp>
|
||||
#include <cstdint>
|
||||
|
||||
namespace ESSImport
|
||||
{
|
||||
@ -44,19 +45,14 @@ namespace ESSImport
|
||||
bool isDeleted = false;
|
||||
ESM::CellRef::loadData(esm, isDeleted);
|
||||
|
||||
mActorData.mHasACDT = false;
|
||||
if (esm.isNextSub("ACDT"))
|
||||
{
|
||||
mActorData.mHasACDT = true;
|
||||
esm.getHTSized<264>(mActorData.mACDT);
|
||||
}
|
||||
mActorData.mHasACDT
|
||||
= esm.getHNOT("ACDT", mActorData.mACDT.mUnknown, mActorData.mACDT.mFlags, mActorData.mACDT.mBreathMeter,
|
||||
mActorData.mACDT.mUnknown2, mActorData.mACDT.mDynamic, mActorData.mACDT.mUnknown3,
|
||||
mActorData.mACDT.mAttributes, mActorData.mACDT.mMagicEffects, mActorData.mACDT.mUnknown4,
|
||||
mActorData.mACDT.mGoldPool, mActorData.mACDT.mCountDown, mActorData.mACDT.mUnknown5);
|
||||
|
||||
mActorData.mHasACSC = false;
|
||||
if (esm.isNextSub("ACSC"))
|
||||
{
|
||||
mActorData.mHasACSC = true;
|
||||
esm.getHTSized<112>(mActorData.mACSC);
|
||||
}
|
||||
mActorData.mHasACSC = esm.getHNOT("ACSC", mActorData.mACSC.mUnknown1, mActorData.mACSC.mFlags,
|
||||
mActorData.mACSC.mUnknown2, mActorData.mACSC.mCorpseClearCountdown, mActorData.mACSC.mUnknown3);
|
||||
|
||||
if (esm.isNextSub("ACSL"))
|
||||
esm.skipHSubSize(112);
|
||||
@ -122,23 +118,17 @@ namespace ESSImport
|
||||
}
|
||||
|
||||
// FIXME: not all actors have this, add flag
|
||||
if (esm.isNextSub("CHRD")) // npc only
|
||||
esm.getHExact(mActorData.mSkills, 27 * 2 * sizeof(int));
|
||||
esm.getHNOT("CHRD", mActorData.mSkills); // npc only
|
||||
|
||||
if (esm.isNextSub("CRED")) // creature only
|
||||
esm.getHExact(mActorData.mCombatStats, 3 * 2 * sizeof(int));
|
||||
esm.getHNOT("CRED", mActorData.mCombatStats); // creature only
|
||||
|
||||
mActorData.mSCRI.load(esm);
|
||||
|
||||
if (esm.isNextSub("ND3D"))
|
||||
esm.skipHSub();
|
||||
|
||||
mActorData.mHasANIS = false;
|
||||
if (esm.isNextSub("ANIS"))
|
||||
{
|
||||
mActorData.mHasANIS = true;
|
||||
esm.getHTSized<8>(mActorData.mANIS);
|
||||
}
|
||||
mActorData.mHasANIS
|
||||
= esm.getHNOT("ANIS", mActorData.mANIS.mGroupIndex, mActorData.mANIS.mUnknown, mActorData.mANIS.mTime);
|
||||
|
||||
if (esm.isNextSub("LVCR"))
|
||||
{
|
||||
@ -155,13 +145,13 @@ namespace ESSImport
|
||||
// DATA should occur for all references, except levelled creature spawners
|
||||
// I've seen DATA *twice* on a creature record, and with the exact same content too! weird
|
||||
// alarmvoi0000.ess
|
||||
esm.getHNOTSized<24>(mPos, "DATA");
|
||||
esm.getHNOTSized<24>(mPos, "DATA");
|
||||
for (int i = 0; i < 2; ++i)
|
||||
esm.getHNOT("DATA", mPos.pos, mPos.rot);
|
||||
|
||||
mDeleted = 0;
|
||||
if (esm.isNextSub("DELE"))
|
||||
{
|
||||
unsigned int deleted;
|
||||
uint32_t deleted;
|
||||
esm.getHT(deleted);
|
||||
mDeleted = ((deleted >> 24) & 0x2) != 0; // the other 3 bytes seem to be uninitialized garbage
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "importcntc.hpp"
|
||||
|
||||
#include <components/esm3/esmreader.hpp>
|
||||
#include <cstdint>
|
||||
|
||||
namespace ESSImport
|
||||
{
|
||||
|
@ -14,7 +14,7 @@ namespace ESSImport
|
||||
/// Changed container contents
|
||||
struct CNTC
|
||||
{
|
||||
int mIndex;
|
||||
int32_t mIndex;
|
||||
|
||||
Inventory mInventory;
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include "importinventory.hpp"
|
||||
#include <components/esm3/aipackage.hpp>
|
||||
#include <cstdint>
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
@ -15,7 +16,7 @@ namespace ESSImport
|
||||
/// Creature changes
|
||||
struct CREC
|
||||
{
|
||||
int mIndex;
|
||||
int32_t mIndex;
|
||||
|
||||
Inventory mInventory;
|
||||
ESM::AIPackageList mAiPackages;
|
||||
|
@ -8,11 +8,11 @@ namespace ESSImport
|
||||
void DIAL::load(ESM::ESMReader& esm)
|
||||
{
|
||||
// See ESM::Dialogue::Type enum, not sure why we would need this here though
|
||||
int type = 0;
|
||||
int32_t type = 0;
|
||||
esm.getHNOT(type, "DATA");
|
||||
|
||||
// Deleted dialogue in a savefile. No clue what this means...
|
||||
int deleted = 0;
|
||||
int32_t deleted = 0;
|
||||
esm.getHNOT(deleted, "DELE");
|
||||
|
||||
mIndex = 0;
|
||||
|
@ -1,5 +1,8 @@
|
||||
#ifndef OPENMW_ESSIMPORT_IMPORTDIAL_H
|
||||
#define OPENMW_ESSIMPORT_IMPORTDIAL_H
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
class ESMReader;
|
||||
@ -10,7 +13,7 @@ namespace ESSImport
|
||||
|
||||
struct DIAL
|
||||
{
|
||||
int mIndex; // Journal index
|
||||
int32_t mIndex; // Journal index
|
||||
|
||||
void load(ESM::ESMReader& esm);
|
||||
};
|
||||
|
@ -9,17 +9,17 @@ namespace ESSImport
|
||||
{
|
||||
esm.getSubNameIs("GMDT");
|
||||
esm.getSubHeader();
|
||||
if (esm.getSubSize() == 92)
|
||||
{
|
||||
esm.getExact(&mGMDT, 92);
|
||||
mGMDT.mSecundaPhase = 0;
|
||||
}
|
||||
else if (esm.getSubSize() == 96)
|
||||
{
|
||||
esm.getTSized<96>(mGMDT);
|
||||
}
|
||||
else
|
||||
esm.fail("unexpected subrecord size for GAME.GMDT");
|
||||
bool hasSecundaPhase = esm.getSubSize() == 96;
|
||||
esm.getT(mGMDT.mCellName);
|
||||
esm.getT(mGMDT.mFogColour);
|
||||
esm.getT(mGMDT.mFogDensity);
|
||||
esm.getT(mGMDT.mCurrentWeather);
|
||||
esm.getT(mGMDT.mNextWeather);
|
||||
esm.getT(mGMDT.mWeatherTransition);
|
||||
esm.getT(mGMDT.mTimeOfNextTransition);
|
||||
esm.getT(mGMDT.mMasserPhase);
|
||||
if (hasSecundaPhase)
|
||||
esm.getT(mGMDT.mSecundaPhase);
|
||||
|
||||
mGMDT.mWeatherTransition &= (0x000000ff);
|
||||
mGMDT.mSecundaPhase &= (0x000000ff);
|
||||
|
@ -1,6 +1,8 @@
|
||||
#ifndef OPENMW_ESSIMPORT_GAME_H
|
||||
#define OPENMW_ESSIMPORT_GAME_H
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
class ESMReader;
|
||||
@ -15,12 +17,12 @@ namespace ESSImport
|
||||
struct GMDT
|
||||
{
|
||||
char mCellName[64]{};
|
||||
int mFogColour{ 0 };
|
||||
int32_t mFogColour{ 0 };
|
||||
float mFogDensity{ 0.f };
|
||||
int mCurrentWeather{ 0 }, mNextWeather{ 0 };
|
||||
int mWeatherTransition{ 0 }; // 0-100 transition between weathers, top 3 bytes may be garbage
|
||||
int32_t mCurrentWeather{ 0 }, mNextWeather{ 0 };
|
||||
int32_t mWeatherTransition{ 0 }; // 0-100 transition between weathers, top 3 bytes may be garbage
|
||||
float mTimeOfNextTransition{ 0.f }; // weather changes when gamehour == timeOfNextTransition
|
||||
int mMasserPhase{ 0 }, mSecundaPhase{ 0 }; // top 3 bytes may be garbage
|
||||
int32_t mMasserPhase{ 0 }, mSecundaPhase{ 0 }; // top 3 bytes may be garbage
|
||||
};
|
||||
|
||||
GMDT mGMDT;
|
||||
|
@ -12,7 +12,7 @@ namespace ESSImport
|
||||
while (esm.isNextSub("NPCO"))
|
||||
{
|
||||
ContItem contItem;
|
||||
esm.getHTSized<36>(contItem);
|
||||
esm.getHT(contItem.mCount, contItem.mItem.mData);
|
||||
|
||||
InventoryItem item;
|
||||
item.mId = contItem.mItem.toString();
|
||||
@ -28,7 +28,7 @@ namespace ESSImport
|
||||
bool newStack = esm.isNextSub("XIDX");
|
||||
if (newStack)
|
||||
{
|
||||
unsigned int idx;
|
||||
uint32_t idx;
|
||||
esm.getHT(idx);
|
||||
separateStacks = true;
|
||||
item.mCount = 1;
|
||||
@ -40,7 +40,7 @@ namespace ESSImport
|
||||
bool isDeleted = false;
|
||||
item.ESM::CellRef::loadData(esm, isDeleted);
|
||||
|
||||
int charge = -1;
|
||||
int32_t charge = -1;
|
||||
esm.getHNOT(charge, "XHLT");
|
||||
item.mChargeInt = charge;
|
||||
|
||||
@ -60,7 +60,7 @@ namespace ESSImport
|
||||
// this is currently not handled properly.
|
||||
|
||||
esm.getSubHeader();
|
||||
int itemIndex; // index of the item in the NPCO list
|
||||
int32_t itemIndex; // index of the item in the NPCO list
|
||||
esm.getT(itemIndex);
|
||||
|
||||
if (itemIndex < 0 || itemIndex >= int(mItems.size()))
|
||||
@ -68,7 +68,7 @@ namespace ESSImport
|
||||
|
||||
// appears to be a relative index for only the *possible* slots this item can be equipped in,
|
||||
// i.e. 0 most of the time
|
||||
int slotIndex;
|
||||
int32_t slotIndex;
|
||||
esm.getT(slotIndex);
|
||||
|
||||
mItems[itemIndex].mRelativeEquipmentSlot = slotIndex;
|
||||
|
@ -1,6 +1,7 @@
|
||||
#ifndef OPENMW_ESSIMPORT_IMPORTINVENTORY_H
|
||||
#define OPENMW_ESSIMPORT_IMPORTINVENTORY_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@ -19,7 +20,7 @@ namespace ESSImport
|
||||
|
||||
struct ContItem
|
||||
{
|
||||
int mCount;
|
||||
int32_t mCount;
|
||||
ESM::NAME32 mItem;
|
||||
};
|
||||
|
||||
@ -28,8 +29,8 @@ namespace ESSImport
|
||||
struct InventoryItem : public ESM::CellRef
|
||||
{
|
||||
std::string mId;
|
||||
int mCount;
|
||||
int mRelativeEquipmentSlot;
|
||||
int32_t mCount;
|
||||
int32_t mRelativeEquipmentSlot;
|
||||
SCRI mSCRI;
|
||||
};
|
||||
std::vector<InventoryItem> mItems;
|
||||
|
@ -10,7 +10,7 @@ namespace ESSImport
|
||||
while (esm.isNextSub("KNAM"))
|
||||
{
|
||||
std::string refId = esm.getHString();
|
||||
int count;
|
||||
int32_t count;
|
||||
esm.getHNT(count, "CNAM");
|
||||
mKillCounter[refId] = count;
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
#ifndef OPENMW_ESSIMPORT_KLST_H
|
||||
#define OPENMW_ESSIMPORT_KLST_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
@ -18,9 +19,9 @@ namespace ESSImport
|
||||
void load(ESM::ESMReader& esm);
|
||||
|
||||
/// RefId, kill count
|
||||
std::map<std::string, int> mKillCounter;
|
||||
std::map<std::string, int32_t> mKillCounter;
|
||||
|
||||
int mWerewolfKills;
|
||||
int32_t mWerewolfKills;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ namespace ESSImport
|
||||
|
||||
void NPCC::load(ESM::ESMReader& esm)
|
||||
{
|
||||
esm.getHNTSized<8>(mNPDT, "NPDT");
|
||||
esm.getHNT("NPDT", mNPDT.mDisposition, mNPDT.unknown, mNPDT.mReputation, mNPDT.unknown2, mNPDT.mIndex);
|
||||
|
||||
while (esm.isNextSub("AI_W") || esm.isNextSub("AI_E") || esm.isNextSub("AI_T") || esm.isNextSub("AI_F")
|
||||
|| esm.isNextSub("AI_A"))
|
||||
|
@ -2,6 +2,7 @@
|
||||
#define OPENMW_ESSIMPORT_NPCC_H
|
||||
|
||||
#include <components/esm3/aipackage.hpp>
|
||||
#include <cstdint>
|
||||
|
||||
#include "importinventory.hpp"
|
||||
|
||||
@ -21,7 +22,7 @@ namespace ESSImport
|
||||
unsigned char unknown;
|
||||
unsigned char mReputation;
|
||||
unsigned char unknown2;
|
||||
int mIndex;
|
||||
int32_t mIndex;
|
||||
} mNPDT;
|
||||
|
||||
Inventory mInventory;
|
||||
|
@ -19,7 +19,12 @@ namespace ESSImport
|
||||
mMNAM = esm.getHString();
|
||||
}
|
||||
|
||||
esm.getHNTSized<212>(mPNAM, "PNAM");
|
||||
esm.getHNT("PNAM", mPNAM.mPlayerFlags, mPNAM.mLevelProgress, mPNAM.mSkillProgress, mPNAM.mSkillIncreases,
|
||||
mPNAM.mTelekinesisRangeBonus, mPNAM.mVisionBonus, mPNAM.mDetectKeyMagnitude,
|
||||
mPNAM.mDetectEnchantmentMagnitude, mPNAM.mDetectAnimalMagnitude, mPNAM.mMarkLocation.mX,
|
||||
mPNAM.mMarkLocation.mY, mPNAM.mMarkLocation.mZ, mPNAM.mMarkLocation.mRotZ, mPNAM.mMarkLocation.mCellX,
|
||||
mPNAM.mMarkLocation.mCellY, mPNAM.mUnknown3, mPNAM.mVerticalRotation.mData, mPNAM.mSpecIncreases,
|
||||
mPNAM.mUnknown4);
|
||||
|
||||
if (esm.isNextSub("SNAM"))
|
||||
esm.skipHSub();
|
||||
@ -50,12 +55,7 @@ namespace ESSImport
|
||||
if (esm.isNextSub("NAM3"))
|
||||
esm.skipHSub();
|
||||
|
||||
mHasENAM = false;
|
||||
if (esm.isNextSub("ENAM"))
|
||||
{
|
||||
mHasENAM = true;
|
||||
esm.getHTSized<8>(mENAM);
|
||||
}
|
||||
mHasENAM = esm.getHNOT("ENAM", mENAM.mCellX, mENAM.mCellY);
|
||||
|
||||
if (esm.isNextSub("LNAM"))
|
||||
esm.skipHSub();
|
||||
@ -63,16 +63,12 @@ namespace ESSImport
|
||||
while (esm.isNextSub("FNAM"))
|
||||
{
|
||||
FNAM fnam;
|
||||
esm.getHTSized<44>(fnam);
|
||||
esm.getHT(
|
||||
fnam.mRank, fnam.mUnknown1, fnam.mReputation, fnam.mFlags, fnam.mUnknown2, fnam.mFactionName.mData);
|
||||
mFactions.push_back(fnam);
|
||||
}
|
||||
|
||||
mHasAADT = false;
|
||||
if (esm.isNextSub("AADT")) // Attack animation data?
|
||||
{
|
||||
mHasAADT = true;
|
||||
esm.getHTSized<44>(mAADT);
|
||||
}
|
||||
mHasAADT = esm.getHNOT("AADT", mAADT.animGroupIndex, mAADT.mUnknown5); // Attack animation data?
|
||||
|
||||
if (esm.isNextSub("KNAM"))
|
||||
esm.skipHSub(); // assigned Quick Keys, I think
|
||||
|
@ -1,6 +1,7 @@
|
||||
#ifndef OPENMW_ESSIMPORT_PLAYER_H
|
||||
#define OPENMW_ESSIMPORT_PLAYER_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@ -17,7 +18,7 @@ namespace ESSImport
|
||||
/// Other player data
|
||||
struct PCDT
|
||||
{
|
||||
int mBounty;
|
||||
int32_t mBounty;
|
||||
std::string mBirthsign;
|
||||
|
||||
std::vector<std::string> mKnownDialogueTopics;
|
||||
@ -41,13 +42,11 @@ namespace ESSImport
|
||||
PlayerFlags_LevitationDisabled = 0x80000
|
||||
};
|
||||
|
||||
#pragma pack(push)
|
||||
#pragma pack(1)
|
||||
struct FNAM
|
||||
{
|
||||
unsigned char mRank;
|
||||
unsigned char mUnknown1[3];
|
||||
int mReputation;
|
||||
int32_t mReputation;
|
||||
unsigned char mFlags; // 0x1: unknown, 0x2: expelled
|
||||
unsigned char mUnknown2[3];
|
||||
ESM::NAME32 mFactionName;
|
||||
@ -59,7 +58,7 @@ namespace ESSImport
|
||||
{
|
||||
float mX, mY, mZ; // worldspace position
|
||||
float mRotZ; // Z angle in radians
|
||||
int mCellX, mCellY; // grid coordinates; for interior cells this is always (0, 0)
|
||||
int32_t mCellX, mCellY; // grid coordinates; for interior cells this is always (0, 0)
|
||||
};
|
||||
|
||||
struct Rotation
|
||||
@ -67,15 +66,15 @@ namespace ESSImport
|
||||
float mData[3][3];
|
||||
};
|
||||
|
||||
int mPlayerFlags; // controls, camera and draw state
|
||||
unsigned int mLevelProgress;
|
||||
int32_t mPlayerFlags; // controls, camera and draw state
|
||||
uint32_t mLevelProgress;
|
||||
float mSkillProgress[27]; // skill progress, non-uniform scaled
|
||||
unsigned char mSkillIncreases[8]; // number of skill increases for each attribute
|
||||
int mTelekinesisRangeBonus; // in units; seems redundant
|
||||
int32_t mTelekinesisRangeBonus; // in units; seems redundant
|
||||
float mVisionBonus; // range: <0.0, 1.0>; affected by light spells and Get/Mod/SetPCVisionBonus
|
||||
int mDetectKeyMagnitude; // seems redundant
|
||||
int mDetectEnchantmentMagnitude; // seems redundant
|
||||
int mDetectAnimalMagnitude; // seems redundant
|
||||
int32_t mDetectKeyMagnitude; // seems redundant
|
||||
int32_t mDetectEnchantmentMagnitude; // seems redundant
|
||||
int32_t mDetectAnimalMagnitude; // seems redundant
|
||||
MarkLocation mMarkLocation;
|
||||
unsigned char mUnknown3[4];
|
||||
Rotation mVerticalRotation;
|
||||
@ -85,16 +84,15 @@ namespace ESSImport
|
||||
|
||||
struct ENAM
|
||||
{
|
||||
int mCellX;
|
||||
int mCellY;
|
||||
int32_t mCellX;
|
||||
int32_t mCellY;
|
||||
};
|
||||
|
||||
struct AADT // 44 bytes
|
||||
{
|
||||
int animGroupIndex; // See convertANIS() for the mapping.
|
||||
int32_t animGroupIndex; // See convertANIS() for the mapping.
|
||||
unsigned char mUnknown5[40];
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
std::vector<FNAM> mFactions;
|
||||
PNAM mPNAM;
|
||||
|
@ -10,7 +10,9 @@ namespace ESSImport
|
||||
while (esm.isNextSub("PNAM"))
|
||||
{
|
||||
PNAM pnam;
|
||||
esm.getHTSized<184>(pnam);
|
||||
esm.getHT(pnam.mAttackStrength, pnam.mSpeed, pnam.mUnknown, pnam.mFlightTime, pnam.mSplmIndex,
|
||||
pnam.mUnknown2, pnam.mVelocity.mValues, pnam.mPosition.mValues, pnam.mUnknown3, pnam.mActorId.mData,
|
||||
pnam.mArrowId.mData, pnam.mBowId.mData);
|
||||
mProjectiles.push_back(pnam);
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include <components/esm/esmcommon.hpp>
|
||||
#include <components/esm/util.hpp>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
namespace ESM
|
||||
@ -16,15 +17,13 @@ namespace ESSImport
|
||||
struct PROJ
|
||||
{
|
||||
|
||||
#pragma pack(push)
|
||||
#pragma pack(1)
|
||||
struct PNAM // 184 bytes
|
||||
{
|
||||
float mAttackStrength;
|
||||
float mSpeed;
|
||||
unsigned char mUnknown[4 * 2];
|
||||
float mFlightTime;
|
||||
int mSplmIndex; // reference to a SPLM record (0 for ballistic projectiles)
|
||||
int32_t mSplmIndex; // reference to a SPLM record (0 for ballistic projectiles)
|
||||
unsigned char mUnknown2[4];
|
||||
ESM::Vector3 mVelocity;
|
||||
ESM::Vector3 mPosition;
|
||||
@ -35,7 +34,6 @@ namespace ESSImport
|
||||
|
||||
bool isMagic() const { return mSplmIndex != 0; }
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
std::vector<PNAM> mProjectiles;
|
||||
|
||||
|
@ -7,7 +7,8 @@ namespace ESSImport
|
||||
|
||||
void SCPT::load(ESM::ESMReader& esm)
|
||||
{
|
||||
esm.getHNTSized<52>(mSCHD, "SCHD");
|
||||
esm.getHNT("SCHD", mSCHD.mName.mData, mSCHD.mData.mNumShorts, mSCHD.mData.mNumLongs, mSCHD.mData.mNumFloats,
|
||||
mSCHD.mData.mScriptDataSize, mSCHD.mData.mStringTableSize);
|
||||
|
||||
mSCRI.load(esm);
|
||||
|
||||
|
@ -3,6 +3,8 @@
|
||||
|
||||
#include "importscri.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include <components/esm/esmcommon.hpp>
|
||||
#include <components/esm3/loadscpt.hpp>
|
||||
|
||||
@ -29,7 +31,7 @@ namespace ESSImport
|
||||
SCRI mSCRI;
|
||||
|
||||
bool mRunning;
|
||||
int mRefNum; // Targeted reference, -1: no reference
|
||||
int32_t mRefNum; // Targeted reference, -1: no reference
|
||||
|
||||
void load(ESM::ESMReader& esm);
|
||||
};
|
||||
|
@ -9,7 +9,7 @@ namespace ESSImport
|
||||
{
|
||||
mScript = esm.getHNOString("SCRI");
|
||||
|
||||
int numShorts = 0, numLongs = 0, numFloats = 0;
|
||||
int32_t numShorts = 0, numLongs = 0, numFloats = 0;
|
||||
if (esm.isNextSub("SLCS"))
|
||||
{
|
||||
esm.getSubHeader();
|
||||
@ -23,7 +23,7 @@ namespace ESSImport
|
||||
esm.getSubHeader();
|
||||
for (int i = 0; i < numShorts; ++i)
|
||||
{
|
||||
short val;
|
||||
int16_t val;
|
||||
esm.getT(val);
|
||||
mShorts.push_back(val);
|
||||
}
|
||||
@ -35,7 +35,7 @@ namespace ESSImport
|
||||
esm.getSubHeader();
|
||||
for (int i = 0; i < numLongs; ++i)
|
||||
{
|
||||
int val;
|
||||
int32_t val;
|
||||
esm.getT(val);
|
||||
mLongs.push_back(val);
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include <components/esm3/variant.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
namespace ESM
|
||||
|
@ -11,13 +11,15 @@ namespace ESSImport
|
||||
{
|
||||
ActiveSpell spell;
|
||||
esm.getHT(spell.mIndex);
|
||||
esm.getHNTSized<160>(spell.mSPDT, "SPDT");
|
||||
esm.getHNT("SPDT", spell.mSPDT.mType, spell.mSPDT.mId.mData, spell.mSPDT.mUnknown,
|
||||
spell.mSPDT.mCasterId.mData, spell.mSPDT.mSourceId.mData, spell.mSPDT.mUnknown2);
|
||||
spell.mTarget = esm.getHNOString("TNAM");
|
||||
|
||||
while (esm.isNextSub("NPDT"))
|
||||
{
|
||||
ActiveEffect effect;
|
||||
esm.getHTSized<56>(effect.mNPDT);
|
||||
esm.getHT(effect.mNPDT.mAffectedActorId.mData, effect.mNPDT.mUnknown, effect.mNPDT.mMagnitude,
|
||||
effect.mNPDT.mSecondsActive, effect.mNPDT.mUnknown2);
|
||||
|
||||
// Effect-specific subrecords can follow:
|
||||
// - INAM for disintegration and bound effects
|
||||
|
@ -2,6 +2,7 @@
|
||||
#define OPENMW_ESSIMPORT_IMPORTSPLM_H
|
||||
|
||||
#include <components/esm/esmcommon.hpp>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
namespace ESM
|
||||
@ -15,11 +16,9 @@ namespace ESSImport
|
||||
struct SPLM
|
||||
{
|
||||
|
||||
#pragma pack(push)
|
||||
#pragma pack(1)
|
||||
struct SPDT // 160 bytes
|
||||
{
|
||||
int mType; // 1 = spell, 2 = enchantment, 3 = potion
|
||||
int32_t mType; // 1 = spell, 2 = enchantment, 3 = potion
|
||||
ESM::NAME32 mId; // base ID of a spell/enchantment/potion
|
||||
unsigned char mUnknown[4 * 4];
|
||||
ESM::NAME32 mCasterId;
|
||||
@ -31,31 +30,29 @@ namespace ESSImport
|
||||
{
|
||||
ESM::NAME32 mAffectedActorId;
|
||||
unsigned char mUnknown[4 * 2];
|
||||
int mMagnitude;
|
||||
int32_t mMagnitude;
|
||||
float mSecondsActive;
|
||||
unsigned char mUnknown2[4 * 2];
|
||||
};
|
||||
|
||||
struct INAM // 40 bytes
|
||||
{
|
||||
int mUnknown;
|
||||
int32_t mUnknown;
|
||||
unsigned char mUnknown2;
|
||||
ESM::FixedString<35> mItemId; // disintegrated item / bound item / item to re-equip after expiration
|
||||
};
|
||||
|
||||
struct CNAM // 36 bytes
|
||||
{
|
||||
int mUnknown; // seems to always be 0
|
||||
int32_t mUnknown; // seems to always be 0
|
||||
ESM::NAME32 mSummonedOrCommandedActor[32];
|
||||
};
|
||||
|
||||
struct VNAM // 4 bytes
|
||||
{
|
||||
int mUnknown;
|
||||
int32_t mUnknown;
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
struct ActiveEffect
|
||||
{
|
||||
NPDT mNPDT;
|
||||
@ -63,7 +60,7 @@ namespace ESSImport
|
||||
|
||||
struct ActiveSpell
|
||||
{
|
||||
int mIndex;
|
||||
int32_t mIndex;
|
||||
SPDT mSPDT;
|
||||
std::string mTarget;
|
||||
std::vector<ActiveEffect> mActiveEffects;
|
||||
|
@ -41,17 +41,17 @@ void CSMTools::RaceCheckStage::performPerRecord(int stage, CSMDoc::Messages& mes
|
||||
messages.add(id, "Description is missing", "", CSMDoc::Message::Severity_Warning);
|
||||
|
||||
// test for positive height
|
||||
if (race.mData.mHeight.mMale <= 0)
|
||||
if (race.mData.mMaleHeight <= 0)
|
||||
messages.add(id, "Male height is non-positive", "", CSMDoc::Message::Severity_Error);
|
||||
|
||||
if (race.mData.mHeight.mFemale <= 0)
|
||||
if (race.mData.mFemaleHeight <= 0)
|
||||
messages.add(id, "Female height is non-positive", "", CSMDoc::Message::Severity_Error);
|
||||
|
||||
// test for non-negative weight
|
||||
if (race.mData.mWeight.mMale < 0)
|
||||
if (race.mData.mMaleWeight < 0)
|
||||
messages.add(id, "Male weight is negative", "", CSMDoc::Message::Severity_Error);
|
||||
|
||||
if (race.mData.mWeight.mFemale < 0)
|
||||
if (race.mData.mFemaleWeight < 0)
|
||||
messages.add(id, "Female weight is negative", "", CSMDoc::Message::Severity_Error);
|
||||
|
||||
/// \todo check data members that can't be edited in the table view
|
||||
|
@ -693,22 +693,12 @@ void CSMTools::ReferenceableCheckStage::npcCheck(
|
||||
}
|
||||
else if (npc.mNpdt.mHealth != 0)
|
||||
{
|
||||
if (npc.mNpdt.mStrength == 0)
|
||||
messages.add(id, "Strength is equal to zero", "", CSMDoc::Message::Severity_Warning);
|
||||
if (npc.mNpdt.mIntelligence == 0)
|
||||
messages.add(id, "Intelligence is equal to zero", "", CSMDoc::Message::Severity_Warning);
|
||||
if (npc.mNpdt.mWillpower == 0)
|
||||
messages.add(id, "Willpower is equal to zero", "", CSMDoc::Message::Severity_Warning);
|
||||
if (npc.mNpdt.mAgility == 0)
|
||||
messages.add(id, "Agility is equal to zero", "", CSMDoc::Message::Severity_Warning);
|
||||
if (npc.mNpdt.mSpeed == 0)
|
||||
messages.add(id, "Speed is equal to zero", "", CSMDoc::Message::Severity_Warning);
|
||||
if (npc.mNpdt.mEndurance == 0)
|
||||
messages.add(id, "Endurance is equal to zero", "", CSMDoc::Message::Severity_Warning);
|
||||
if (npc.mNpdt.mPersonality == 0)
|
||||
messages.add(id, "Personality is equal to zero", "", CSMDoc::Message::Severity_Warning);
|
||||
if (npc.mNpdt.mLuck == 0)
|
||||
messages.add(id, "Luck is equal to zero", "", CSMDoc::Message::Severity_Warning);
|
||||
for (size_t i = 0; i < npc.mNpdt.mAttributes.size(); ++i)
|
||||
{
|
||||
if (npc.mNpdt.mAttributes[i] == 0)
|
||||
messages.add(id, ESM::Attribute::indexToRefId(i).getRefIdString() + " is equal to zero", {},
|
||||
CSMDoc::Message::Severity_Warning);
|
||||
}
|
||||
}
|
||||
|
||||
if (level <= 0)
|
||||
|
@ -570,19 +570,34 @@ namespace CSMWorld
|
||||
|
||||
QVariant get(const Record<ESXRecordT>& record) const override
|
||||
{
|
||||
const ESM::Race::MaleFemaleF& value = mWeight ? record.get().mData.mWeight : record.get().mData.mHeight;
|
||||
|
||||
return mMale ? value.mMale : value.mFemale;
|
||||
if (mWeight)
|
||||
{
|
||||
if (mMale)
|
||||
return record.get().mData.mMaleWeight;
|
||||
return record.get().mData.mFemaleWeight;
|
||||
}
|
||||
if (mMale)
|
||||
return record.get().mData.mMaleHeight;
|
||||
return record.get().mData.mFemaleHeight;
|
||||
}
|
||||
|
||||
void set(Record<ESXRecordT>& record, const QVariant& data) override
|
||||
{
|
||||
ESXRecordT record2 = record.get();
|
||||
|
||||
ESM::Race::MaleFemaleF& value = mWeight ? record2.mData.mWeight : record2.mData.mHeight;
|
||||
|
||||
(mMale ? value.mMale : value.mFemale) = data.toFloat();
|
||||
|
||||
if (mWeight)
|
||||
{
|
||||
if (mMale)
|
||||
record2.mData.mMaleWeight = data.toFloat();
|
||||
else
|
||||
record2.mData.mFemaleWeight = data.toFloat();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mMale)
|
||||
record2.mData.mMaleHeight = data.toFloat();
|
||||
else
|
||||
record2.mData.mFemaleHeight = data.toFloat();
|
||||
}
|
||||
record.setModified(record2);
|
||||
}
|
||||
|
||||
|
@ -741,8 +741,8 @@ namespace CSMWorld
|
||||
QVariant RaceAttributeAdapter::getData(const Record<ESM::Race>& record, int subRowIndex, int subColIndex) const
|
||||
{
|
||||
ESM::Race race = record.get();
|
||||
|
||||
if (subRowIndex < 0 || subRowIndex >= ESM::Attribute::Length)
|
||||
ESM::RefId attribute = ESM::Attribute::indexToRefId(subRowIndex);
|
||||
if (attribute.empty())
|
||||
throw std::runtime_error("index out of range");
|
||||
|
||||
switch (subColIndex)
|
||||
@ -750,9 +750,9 @@ namespace CSMWorld
|
||||
case 0:
|
||||
return subRowIndex;
|
||||
case 1:
|
||||
return race.mData.mAttributeValues[subRowIndex].mMale;
|
||||
return race.mData.getAttribute(attribute, true);
|
||||
case 2:
|
||||
return race.mData.mAttributeValues[subRowIndex].mFemale;
|
||||
return race.mData.getAttribute(attribute, false);
|
||||
default:
|
||||
throw std::runtime_error("Race Attribute subcolumn index out of range");
|
||||
}
|
||||
@ -762,8 +762,8 @@ namespace CSMWorld
|
||||
Record<ESM::Race>& record, const QVariant& value, int subRowIndex, int subColIndex) const
|
||||
{
|
||||
ESM::Race race = record.get();
|
||||
|
||||
if (subRowIndex < 0 || subRowIndex >= ESM::Attribute::Length)
|
||||
ESM::RefId attribute = ESM::Attribute::indexToRefId(subRowIndex);
|
||||
if (attribute.empty())
|
||||
throw std::runtime_error("index out of range");
|
||||
|
||||
switch (subColIndex)
|
||||
@ -771,10 +771,10 @@ namespace CSMWorld
|
||||
case 0:
|
||||
return; // throw an exception here?
|
||||
case 1:
|
||||
race.mData.mAttributeValues[subRowIndex].mMale = value.toInt();
|
||||
race.mData.setAttribute(attribute, true, value.toInt());
|
||||
break;
|
||||
case 2:
|
||||
race.mData.mAttributeValues[subRowIndex].mFemale = value.toInt();
|
||||
race.mData.setAttribute(attribute, false, value.toInt());
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("Race Attribute subcolumn index out of range");
|
||||
|
@ -938,30 +938,9 @@ QVariant CSMWorld::NpcAttributesRefIdAdapter::getNestedData(
|
||||
|
||||
if (subColIndex == 0)
|
||||
return subRowIndex;
|
||||
else if (subColIndex == 1)
|
||||
switch (subRowIndex)
|
||||
{
|
||||
case 0:
|
||||
return static_cast<int>(npcStruct.mStrength);
|
||||
case 1:
|
||||
return static_cast<int>(npcStruct.mIntelligence);
|
||||
case 2:
|
||||
return static_cast<int>(npcStruct.mWillpower);
|
||||
case 3:
|
||||
return static_cast<int>(npcStruct.mAgility);
|
||||
case 4:
|
||||
return static_cast<int>(npcStruct.mSpeed);
|
||||
case 5:
|
||||
return static_cast<int>(npcStruct.mEndurance);
|
||||
case 6:
|
||||
return static_cast<int>(npcStruct.mPersonality);
|
||||
case 7:
|
||||
return static_cast<int>(npcStruct.mLuck);
|
||||
default:
|
||||
return QVariant(); // throw an exception here?
|
||||
}
|
||||
else
|
||||
return QVariant(); // throw an exception here?
|
||||
else if (subColIndex == 1 && subRowIndex >= 0 && subRowIndex < ESM::Attribute::Length)
|
||||
return static_cast<int>(npcStruct.mAttributes[subRowIndex]);
|
||||
return QVariant(); // throw an exception here?
|
||||
}
|
||||
|
||||
void CSMWorld::NpcAttributesRefIdAdapter::setNestedData(
|
||||
@ -972,36 +951,8 @@ void CSMWorld::NpcAttributesRefIdAdapter::setNestedData(
|
||||
ESM::NPC npc = record.get();
|
||||
ESM::NPC::NPDTstruct52& npcStruct = npc.mNpdt;
|
||||
|
||||
if (subColIndex == 1)
|
||||
switch (subRowIndex)
|
||||
{
|
||||
case 0:
|
||||
npcStruct.mStrength = static_cast<unsigned char>(value.toInt());
|
||||
break;
|
||||
case 1:
|
||||
npcStruct.mIntelligence = static_cast<unsigned char>(value.toInt());
|
||||
break;
|
||||
case 2:
|
||||
npcStruct.mWillpower = static_cast<unsigned char>(value.toInt());
|
||||
break;
|
||||
case 3:
|
||||
npcStruct.mAgility = static_cast<unsigned char>(value.toInt());
|
||||
break;
|
||||
case 4:
|
||||
npcStruct.mSpeed = static_cast<unsigned char>(value.toInt());
|
||||
break;
|
||||
case 5:
|
||||
npcStruct.mEndurance = static_cast<unsigned char>(value.toInt());
|
||||
break;
|
||||
case 6:
|
||||
npcStruct.mPersonality = static_cast<unsigned char>(value.toInt());
|
||||
break;
|
||||
case 7:
|
||||
npcStruct.mLuck = static_cast<unsigned char>(value.toInt());
|
||||
break;
|
||||
default:
|
||||
return; // throw an exception here?
|
||||
}
|
||||
if (subColIndex == 1 && subRowIndex >= 0 && subRowIndex < ESM::Attribute::Length)
|
||||
npcStruct.mAttributes[subRowIndex] = static_cast<unsigned char>(value.toInt());
|
||||
else
|
||||
return; // throw an exception here?
|
||||
|
||||
|
@ -92,13 +92,7 @@ namespace
|
||||
const auto& attributes = MWBase::Environment::get().getESMStore()->get<ESM::Attribute>();
|
||||
int level = creatureStats.getLevel();
|
||||
for (const ESM::Attribute& attribute : attributes)
|
||||
{
|
||||
auto index = ESM::Attribute::refIdToIndex(attribute.mId);
|
||||
assert(index >= 0);
|
||||
|
||||
const ESM::Race::MaleFemale& value = race->mData.mAttributeValues[static_cast<size_t>(index)];
|
||||
creatureStats.setAttribute(attribute.mId, male ? value.mMale : value.mFemale);
|
||||
}
|
||||
creatureStats.setAttribute(attribute.mId, race->mData.getAttribute(attribute.mId, male));
|
||||
|
||||
// class bonus
|
||||
const ESM::Class* class_ = MWBase::Environment::get().getESMStore()->get<ESM::Class>().find(npc->mClass);
|
||||
@ -319,14 +313,8 @@ namespace MWClass
|
||||
for (size_t i = 0; i < ref->mBase->mNpdt.mSkills.size(); ++i)
|
||||
data->mNpcStats.getSkill(ESM::Skill::indexToRefId(i)).setBase(ref->mBase->mNpdt.mSkills[i]);
|
||||
|
||||
data->mNpcStats.setAttribute(ESM::Attribute::Strength, ref->mBase->mNpdt.mStrength);
|
||||
data->mNpcStats.setAttribute(ESM::Attribute::Intelligence, ref->mBase->mNpdt.mIntelligence);
|
||||
data->mNpcStats.setAttribute(ESM::Attribute::Willpower, ref->mBase->mNpdt.mWillpower);
|
||||
data->mNpcStats.setAttribute(ESM::Attribute::Agility, ref->mBase->mNpdt.mAgility);
|
||||
data->mNpcStats.setAttribute(ESM::Attribute::Speed, ref->mBase->mNpdt.mSpeed);
|
||||
data->mNpcStats.setAttribute(ESM::Attribute::Endurance, ref->mBase->mNpdt.mEndurance);
|
||||
data->mNpcStats.setAttribute(ESM::Attribute::Personality, ref->mBase->mNpdt.mPersonality);
|
||||
data->mNpcStats.setAttribute(ESM::Attribute::Luck, ref->mBase->mNpdt.mLuck);
|
||||
for (size_t i = 0; i < ref->mBase->mNpdt.mAttributes.size(); ++i)
|
||||
data->mNpcStats.setAttribute(ESM::Attribute::indexToRefId(i), ref->mBase->mNpdt.mAttributes[i]);
|
||||
|
||||
data->mNpcStats.setHealth(ref->mBase->mNpdt.mHealth);
|
||||
data->mNpcStats.setMagicka(ref->mBase->mNpdt.mMana);
|
||||
@ -1199,24 +1187,24 @@ namespace MWClass
|
||||
if (ptr == MWMechanics::getPlayer() && ptr.isInCell() && MWBase::Environment::get().getWorld()->isFirstPerson())
|
||||
{
|
||||
if (ref->mBase->isMale())
|
||||
scale *= race->mData.mHeight.mMale;
|
||||
scale *= race->mData.mMaleHeight;
|
||||
else
|
||||
scale *= race->mData.mHeight.mFemale;
|
||||
scale *= race->mData.mFemaleHeight;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (ref->mBase->isMale())
|
||||
{
|
||||
scale.x() *= race->mData.mWeight.mMale;
|
||||
scale.y() *= race->mData.mWeight.mMale;
|
||||
scale.z() *= race->mData.mHeight.mMale;
|
||||
scale.x() *= race->mData.mMaleWeight;
|
||||
scale.y() *= race->mData.mMaleWeight;
|
||||
scale.z() *= race->mData.mMaleHeight;
|
||||
}
|
||||
else
|
||||
{
|
||||
scale.x() *= race->mData.mWeight.mFemale;
|
||||
scale.y() *= race->mData.mWeight.mFemale;
|
||||
scale.z() *= race->mData.mHeight.mFemale;
|
||||
scale.x() *= race->mData.mFemaleWeight;
|
||||
scale.y() *= race->mData.mFemaleWeight;
|
||||
scale.z() *= race->mData.mFemaleHeight;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1966,7 +1966,7 @@ namespace MWMechanics
|
||||
{
|
||||
const ESM::NPC* npc = mPtr.get<ESM::NPC>()->mBase;
|
||||
const ESM::Race* race = world->getStore().get<ESM::Race>().find(npc->mRace);
|
||||
float weight = npc->isMale() ? race->mData.mWeight.mMale : race->mData.mWeight.mFemale;
|
||||
float weight = npc->isMale() ? race->mData.mMaleWeight : race->mData.mFemaleWeight;
|
||||
scale *= weight;
|
||||
}
|
||||
|
||||
|
@ -134,14 +134,9 @@ namespace MWMechanics
|
||||
for (size_t i = 0; i < player->mNpdt.mSkills.size(); ++i)
|
||||
npcStats.getSkill(ESM::Skill::indexToRefId(i)).setBase(player->mNpdt.mSkills[i]);
|
||||
|
||||
creatureStats.setAttribute(ESM::Attribute::Strength, player->mNpdt.mStrength);
|
||||
creatureStats.setAttribute(ESM::Attribute::Intelligence, player->mNpdt.mIntelligence);
|
||||
creatureStats.setAttribute(ESM::Attribute::Willpower, player->mNpdt.mWillpower);
|
||||
creatureStats.setAttribute(ESM::Attribute::Agility, player->mNpdt.mAgility);
|
||||
creatureStats.setAttribute(ESM::Attribute::Speed, player->mNpdt.mSpeed);
|
||||
creatureStats.setAttribute(ESM::Attribute::Endurance, player->mNpdt.mEndurance);
|
||||
creatureStats.setAttribute(ESM::Attribute::Personality, player->mNpdt.mPersonality);
|
||||
creatureStats.setAttribute(ESM::Attribute::Luck, player->mNpdt.mLuck);
|
||||
for (size_t i = 0; i < player->mNpdt.mAttributes.size(); ++i)
|
||||
npcStats.setAttribute(ESM::Attribute::indexToRefId(i), player->mNpdt.mSkills[i]);
|
||||
|
||||
const MWWorld::ESMStore& esmStore = *MWBase::Environment::get().getESMStore();
|
||||
|
||||
// race
|
||||
@ -152,13 +147,7 @@ namespace MWMechanics
|
||||
bool male = (player->mFlags & ESM::NPC::Female) == 0;
|
||||
|
||||
for (const ESM::Attribute& attribute : esmStore.get<ESM::Attribute>())
|
||||
{
|
||||
auto index = ESM::Attribute::refIdToIndex(attribute.mId);
|
||||
assert(index >= 0);
|
||||
|
||||
const ESM::Race::MaleFemale& value = race->mData.mAttributeValues[static_cast<size_t>(index)];
|
||||
creatureStats.setAttribute(attribute.mId, male ? value.mMale : value.mFemale);
|
||||
}
|
||||
creatureStats.setAttribute(attribute.mId, race->mData.getAttribute(attribute.mId, male));
|
||||
|
||||
for (const ESM::Skill& skill : esmStore.get<ESM::Skill>())
|
||||
{
|
||||
|
@ -454,7 +454,7 @@ namespace MWWorld
|
||||
{
|
||||
const auto npc = caster.get<ESM::NPC>()->mBase;
|
||||
const auto race = store.get<ESM::Race>().find(npc->mRace);
|
||||
speed *= npc->isMale() ? race->mData.mWeight.mMale : race->mData.mWeight.mFemale;
|
||||
speed *= npc->isMale() ? race->mData.mMaleWeight : race->mData.mFemaleWeight;
|
||||
}
|
||||
osg::Vec3f direction = orient * osg::Vec3f(0, 1, 0);
|
||||
direction.normalize();
|
||||
|
@ -18,9 +18,9 @@ namespace ESM
|
||||
struct EpochTimeStamp
|
||||
{
|
||||
float mGameHour;
|
||||
int mDay;
|
||||
int mMonth;
|
||||
int mYear;
|
||||
int32_t mDay;
|
||||
int32_t mMonth;
|
||||
int32_t mYear;
|
||||
};
|
||||
|
||||
// Pixel color value. Standard four-byte rr,gg,bb,aa format.
|
||||
|
@ -15,12 +15,7 @@ namespace ESM
|
||||
{
|
||||
esm.getHNT("DATA", mData.mDistance, mData.mDuration, mData.mTimeOfDay, mData.mIdle, mData.mShouldRepeat);
|
||||
esm.getHNT("STAR", mDurationData.mRemainingDuration, mDurationData.unused); // was mStartTime
|
||||
mStoredInitialActorPosition = false;
|
||||
if (esm.isNextSub("POS_"))
|
||||
{
|
||||
mStoredInitialActorPosition = true;
|
||||
esm.getHT(mInitialActorPosition.mValues);
|
||||
}
|
||||
mStoredInitialActorPosition = esm.getHNOT("POS_", mInitialActorPosition.mValues);
|
||||
}
|
||||
|
||||
void AiWander::save(ESMWriter& esm) const
|
||||
|
@ -11,17 +11,9 @@ namespace ESM
|
||||
{
|
||||
mWorldspace = esm.getHNString("SPAC");
|
||||
|
||||
if (esm.isNextSub("CIDX"))
|
||||
{
|
||||
esm.getHT(mIndex.mX, mIndex.mY);
|
||||
mPaged = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
mPaged = false;
|
||||
mIndex.mX = 0;
|
||||
mIndex.mY = 0;
|
||||
}
|
||||
mIndex.mX = 0;
|
||||
mIndex.mY = 0;
|
||||
mPaged = esm.getHNOT("CIDX", mIndex.mX, mIndex.mY);
|
||||
}
|
||||
|
||||
void CellId::save(ESMWriter& esm) const
|
||||
|
@ -116,7 +116,7 @@ namespace ESM
|
||||
cellRef.mTeleport = true;
|
||||
}
|
||||
else
|
||||
esm.skipHTSized<24, ESM::Position>();
|
||||
esm.skipHSub();
|
||||
break;
|
||||
case fourCC("DNAM"):
|
||||
getHStringOrSkip(cellRef.mDestCell);
|
||||
@ -134,7 +134,7 @@ namespace ESM
|
||||
if constexpr (load)
|
||||
esm.getHT(cellRef.mPos.pos, cellRef.mPos.rot);
|
||||
else
|
||||
esm.skipHTSized<24, decltype(cellRef.mPos)>();
|
||||
esm.skipHSub();
|
||||
break;
|
||||
case fourCC("NAM0"):
|
||||
{
|
||||
|
@ -263,7 +263,7 @@ namespace ESM
|
||||
{
|
||||
FormId res;
|
||||
if (wide)
|
||||
getHNTSized<8>(res, tag);
|
||||
getHNT(tag, res.mIndex, res.mContentFile);
|
||||
else
|
||||
getHNT(res.mIndex, tag);
|
||||
return res;
|
||||
@ -496,7 +496,8 @@ namespace ESM
|
||||
case RefIdType::FormId:
|
||||
{
|
||||
FormId formId{};
|
||||
getTSized<8>(formId);
|
||||
getT(formId.mIndex);
|
||||
getT(formId.mContentFile);
|
||||
if (applyContentFileMapping(formId))
|
||||
return RefId(formId);
|
||||
else
|
||||
|
@ -131,10 +131,10 @@ namespace ESM
|
||||
ESM::RefId getCellId();
|
||||
|
||||
// Read data of a given type, stored in a subrecord of a given name
|
||||
template <typename X, typename = std::enable_if_t<IsReadable<X>>>
|
||||
template <typename X>
|
||||
void getHNT(X& x, NAME name)
|
||||
{
|
||||
getHNTSized<sizeof(X)>(x, name);
|
||||
getHNT(name, x);
|
||||
}
|
||||
|
||||
template <class... Args>
|
||||
@ -149,26 +149,21 @@ namespace ESM
|
||||
}
|
||||
|
||||
// Optional version of getHNT
|
||||
template <typename X, typename = std::enable_if_t<IsReadable<X>>>
|
||||
template <typename X>
|
||||
void getHNOT(X& x, NAME name)
|
||||
{
|
||||
getHNOTSized<sizeof(X)>(x, name);
|
||||
getHNOT(name, x);
|
||||
}
|
||||
|
||||
// Version with extra size checking, to make sure the compiler
|
||||
// doesn't mess up our struct padding.
|
||||
template <std::size_t size, typename X>
|
||||
void getHNTSized(X& x, NAME name)
|
||||
{
|
||||
getSubNameIs(name);
|
||||
getHTSized<size>(x);
|
||||
}
|
||||
|
||||
template <std::size_t size, typename X>
|
||||
void getHNOTSized(X& x, NAME name)
|
||||
template <class... Args>
|
||||
bool getHNOT(NAME name, Args&... args)
|
||||
{
|
||||
if (isNextSub(name))
|
||||
getHTSized<size>(x);
|
||||
{
|
||||
getHT(args...);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get data of a given type/size, including subrecord header
|
||||
@ -185,37 +180,13 @@ namespace ESM
|
||||
template <typename T, typename = std::enable_if_t<IsReadable<T>>>
|
||||
void skipHT()
|
||||
{
|
||||
skipHTSized<sizeof(T), T>();
|
||||
}
|
||||
|
||||
// Version with extra size checking, to make sure the compiler
|
||||
// doesn't mess up our struct padding.
|
||||
template <std::size_t size, typename X>
|
||||
void getHTSized(X& x)
|
||||
{
|
||||
getSubHeader();
|
||||
if (mCtx.leftSub != size)
|
||||
reportSubSizeMismatch(size, mCtx.leftSub);
|
||||
getTSized<size>(x);
|
||||
}
|
||||
|
||||
template <std::size_t size, typename T>
|
||||
void skipHTSized()
|
||||
{
|
||||
static_assert(sizeof(T) == size);
|
||||
constexpr size_t size = sizeof(T);
|
||||
getSubHeader();
|
||||
if (mCtx.leftSub != size)
|
||||
reportSubSizeMismatch(size, mCtx.leftSub);
|
||||
skip(size);
|
||||
}
|
||||
|
||||
template <std::size_t size, typename X>
|
||||
void getTSized(X& x)
|
||||
{
|
||||
static_assert(sizeof(X) == size);
|
||||
getExact(&x, size);
|
||||
}
|
||||
|
||||
// Read a string by the given name if it is the next record.
|
||||
std::string getHNOString(NAME name);
|
||||
|
||||
@ -333,7 +304,7 @@ namespace ESM
|
||||
mEsm->read(static_cast<char*>(x), static_cast<std::streamsize>(size));
|
||||
}
|
||||
|
||||
void getName(NAME& name) { getTSized<4>(name); }
|
||||
void getName(NAME& name) { getT(name.mData); }
|
||||
void getUint(uint32_t& u) { getT(u); }
|
||||
|
||||
std::string getMaybeFixedStringSize(std::size_t size);
|
||||
|
@ -17,6 +17,47 @@ namespace ESM
|
||||
return mSkills.at(index);
|
||||
}
|
||||
|
||||
void RankData::load(ESMReader& esm)
|
||||
{
|
||||
esm.getT(mAttribute1);
|
||||
esm.getT(mAttribute2);
|
||||
esm.getT(mPrimarySkill);
|
||||
esm.getT(mFavouredSkill);
|
||||
esm.getT(mFactReaction);
|
||||
}
|
||||
|
||||
void RankData::save(ESMWriter& esm) const
|
||||
{
|
||||
esm.writeT(mAttribute1);
|
||||
esm.writeT(mAttribute2);
|
||||
esm.writeT(mPrimarySkill);
|
||||
esm.writeT(mFavouredSkill);
|
||||
esm.writeT(mFactReaction);
|
||||
}
|
||||
|
||||
void Faction::FADTstruct::load(ESMReader& esm)
|
||||
{
|
||||
esm.getSubHeader();
|
||||
esm.getT(mAttribute);
|
||||
for (auto& rank : mRankData)
|
||||
rank.load(esm);
|
||||
esm.getT(mSkills);
|
||||
esm.getT(mIsHidden);
|
||||
if (mIsHidden > 1)
|
||||
esm.fail("Unknown flag!");
|
||||
}
|
||||
|
||||
void Faction::FADTstruct::save(ESMWriter& esm) const
|
||||
{
|
||||
esm.startSubRecord("FADT");
|
||||
esm.writeT(mAttribute);
|
||||
for (const auto& rank : mRankData)
|
||||
rank.save(esm);
|
||||
esm.writeT(mSkills);
|
||||
esm.writeT(mIsHidden);
|
||||
esm.endRecord("FADT");
|
||||
}
|
||||
|
||||
void Faction::load(ESMReader& esm, bool& isDeleted)
|
||||
{
|
||||
isDeleted = false;
|
||||
@ -47,9 +88,7 @@ namespace ESM
|
||||
mRanks[rankCounter++] = esm.getHString();
|
||||
break;
|
||||
case fourCC("FADT"):
|
||||
esm.getHTSized<240>(mData);
|
||||
if (mData.mIsHidden > 1)
|
||||
esm.fail("Unknown flag!");
|
||||
mData.load(esm);
|
||||
hasData = true;
|
||||
break;
|
||||
case fourCC("ANAM"):
|
||||
@ -101,7 +140,7 @@ namespace ESM
|
||||
esm.writeHNString("RNAM", rank, 32);
|
||||
}
|
||||
|
||||
esm.writeHNT("FADT", mData, 240);
|
||||
mData.save(esm);
|
||||
|
||||
for (auto it = mReactions.begin(); it != mReactions.end(); ++it)
|
||||
{
|
||||
|
@ -30,6 +30,9 @@ namespace ESM
|
||||
int32_t mPrimarySkill, mFavouredSkill;
|
||||
|
||||
int32_t mFactReaction; // Reaction from faction members
|
||||
|
||||
void load(ESMReader& esm);
|
||||
void save(ESMWriter& esm) const;
|
||||
};
|
||||
|
||||
struct Faction
|
||||
@ -60,6 +63,9 @@ namespace ESM
|
||||
|
||||
int32_t getSkill(size_t index, bool ignored = false) const;
|
||||
///< Throws an exception for invalid values of \a index.
|
||||
|
||||
void load(ESMReader& esm);
|
||||
void save(ESMWriter& esm) const;
|
||||
}; // 240 bytes
|
||||
|
||||
FADTstruct mData;
|
||||
|
@ -59,23 +59,31 @@ namespace ESM
|
||||
if (esm.getSubSize() == 52)
|
||||
{
|
||||
mNpdtType = NPC_DEFAULT;
|
||||
esm.getExact(&mNpdt, 52);
|
||||
esm.getT(mNpdt.mLevel);
|
||||
esm.getT(mNpdt.mAttributes);
|
||||
esm.getT(mNpdt.mSkills);
|
||||
esm.getT(mNpdt.mUnknown1);
|
||||
esm.getT(mNpdt.mHealth);
|
||||
esm.getT(mNpdt.mMana);
|
||||
esm.getT(mNpdt.mFatigue);
|
||||
esm.getT(mNpdt.mDisposition);
|
||||
esm.getT(mNpdt.mReputation);
|
||||
esm.getT(mNpdt.mRank);
|
||||
esm.getT(mNpdt.mUnknown2);
|
||||
esm.getT(mNpdt.mGold);
|
||||
}
|
||||
else if (esm.getSubSize() == 12)
|
||||
{
|
||||
// Reading into temporary NPDTstruct12 object
|
||||
NPDTstruct12 npdt12;
|
||||
mNpdtType = NPC_WITH_AUTOCALCULATED_STATS;
|
||||
esm.getExact(&npdt12, 12);
|
||||
|
||||
// Clearing the mNdpt struct to initialize all values
|
||||
blankNpdt();
|
||||
// Swiching to an internal representation
|
||||
mNpdt.mLevel = npdt12.mLevel;
|
||||
mNpdt.mDisposition = npdt12.mDisposition;
|
||||
mNpdt.mReputation = npdt12.mReputation;
|
||||
mNpdt.mRank = npdt12.mRank;
|
||||
mNpdt.mGold = npdt12.mGold;
|
||||
esm.getT(mNpdt.mLevel);
|
||||
esm.getT(mNpdt.mDisposition);
|
||||
esm.getT(mNpdt.mReputation);
|
||||
esm.getT(mNpdt.mRank);
|
||||
esm.skip(3);
|
||||
esm.getT(mNpdt.mGold);
|
||||
}
|
||||
else
|
||||
esm.fail("NPC_NPDT must be 12 or 52 bytes long");
|
||||
@ -146,20 +154,32 @@ namespace ESM
|
||||
|
||||
if (mNpdtType == NPC_DEFAULT)
|
||||
{
|
||||
esm.writeHNT("NPDT", mNpdt, 52);
|
||||
esm.startSubRecord("NPDT");
|
||||
esm.writeT(mNpdt.mLevel);
|
||||
esm.writeT(mNpdt.mAttributes);
|
||||
esm.writeT(mNpdt.mSkills);
|
||||
esm.writeT(mNpdt.mUnknown1);
|
||||
esm.writeT(mNpdt.mHealth);
|
||||
esm.writeT(mNpdt.mMana);
|
||||
esm.writeT(mNpdt.mFatigue);
|
||||
esm.writeT(mNpdt.mDisposition);
|
||||
esm.writeT(mNpdt.mReputation);
|
||||
esm.writeT(mNpdt.mRank);
|
||||
esm.writeT(mNpdt.mUnknown2);
|
||||
esm.writeT(mNpdt.mGold);
|
||||
esm.endRecord("NPDT");
|
||||
}
|
||||
else if (mNpdtType == NPC_WITH_AUTOCALCULATED_STATS)
|
||||
{
|
||||
NPDTstruct12 npdt12;
|
||||
npdt12.mLevel = mNpdt.mLevel;
|
||||
npdt12.mDisposition = mNpdt.mDisposition;
|
||||
npdt12.mReputation = mNpdt.mReputation;
|
||||
npdt12.mRank = mNpdt.mRank;
|
||||
npdt12.mUnknown1 = 0;
|
||||
npdt12.mUnknown2 = 0;
|
||||
npdt12.mUnknown3 = 0;
|
||||
npdt12.mGold = mNpdt.mGold;
|
||||
esm.writeHNT("NPDT", npdt12, 12);
|
||||
esm.startSubRecord("NPDT");
|
||||
esm.writeT(mNpdt.mLevel);
|
||||
esm.writeT(mNpdt.mDisposition);
|
||||
esm.writeT(mNpdt.mReputation);
|
||||
esm.writeT(mNpdt.mRank);
|
||||
constexpr char padding[] = { 0, 0, 0 };
|
||||
esm.writeT(padding);
|
||||
esm.writeT(mNpdt.mGold);
|
||||
esm.endRecord("NPDT");
|
||||
}
|
||||
|
||||
esm.writeHNT("FLAG", ((mBloodType << 10) + mFlags));
|
||||
@ -213,8 +233,7 @@ namespace ESM
|
||||
void NPC::blankNpdt()
|
||||
{
|
||||
mNpdt.mLevel = 0;
|
||||
mNpdt.mStrength = mNpdt.mIntelligence = mNpdt.mWillpower = mNpdt.mAgility = mNpdt.mSpeed = mNpdt.mEndurance
|
||||
= mNpdt.mPersonality = mNpdt.mLuck = 0;
|
||||
mNpdt.mAttributes.fill(0);
|
||||
mNpdt.mSkills.fill(0);
|
||||
mNpdt.mReputation = 0;
|
||||
mNpdt.mHealth = mNpdt.mMana = mNpdt.mFatigue = 0;
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "aipackage.hpp"
|
||||
#include "components/esm/attr.hpp"
|
||||
#include "components/esm/defs.hpp"
|
||||
#include "components/esm/refid.hpp"
|
||||
#include "loadcont.hpp"
|
||||
@ -74,13 +75,10 @@ namespace ESM
|
||||
NPC_DEFAULT = 52
|
||||
};
|
||||
|
||||
#pragma pack(push)
|
||||
#pragma pack(1)
|
||||
|
||||
struct NPDTstruct52
|
||||
{
|
||||
int16_t mLevel;
|
||||
unsigned char mStrength, mIntelligence, mWillpower, mAgility, mSpeed, mEndurance, mPersonality, mLuck;
|
||||
std::array<unsigned char, Attribute::Length> mAttributes;
|
||||
|
||||
// mSkill can grow up to 200, it must be unsigned
|
||||
std::array<unsigned char, Skill::Length> mSkills;
|
||||
@ -92,18 +90,6 @@ namespace ESM
|
||||
int32_t mGold;
|
||||
}; // 52 bytes
|
||||
|
||||
// Structure for autocalculated characters.
|
||||
// This is only used for load and save operations.
|
||||
struct NPDTstruct12
|
||||
{
|
||||
int16_t mLevel;
|
||||
// see above
|
||||
unsigned char mDisposition, mReputation, mRank;
|
||||
char mUnknown1, mUnknown2, mUnknown3;
|
||||
int32_t mGold;
|
||||
}; // 12 bytes
|
||||
#pragma pack(pop)
|
||||
|
||||
unsigned char mNpdtType;
|
||||
// Worth noting when saving the struct:
|
||||
// Although we might read a NPDTstruct12 in, we use NPDTstruct52 internally
|
||||
|
@ -70,7 +70,12 @@ namespace ESM
|
||||
for (uint16_t i = 0; i < mData.mPoints; ++i)
|
||||
{
|
||||
Point p;
|
||||
esm.getExact(&p, sizeof(Point));
|
||||
esm.getT(p.mX);
|
||||
esm.getT(p.mY);
|
||||
esm.getT(p.mZ);
|
||||
esm.getT(p.mAutogenerated);
|
||||
esm.getT(p.mConnectionNum);
|
||||
esm.getT(p.mUnknown);
|
||||
mPoints.push_back(p);
|
||||
edgeCount += p.mConnectionNum;
|
||||
}
|
||||
|
@ -3,16 +3,63 @@
|
||||
#include "esmreader.hpp"
|
||||
#include "esmwriter.hpp"
|
||||
|
||||
#include <components/esm/attr.hpp>
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
int Race::MaleFemale::getValue(bool male) const
|
||||
int32_t Race::RADTstruct::getAttribute(ESM::RefId attribute, bool male) const
|
||||
{
|
||||
return male ? mMale : mFemale;
|
||||
int index = ESM::Attribute::refIdToIndex(attribute);
|
||||
if (index < 0)
|
||||
return 0;
|
||||
index *= 2;
|
||||
if (!male)
|
||||
index++;
|
||||
return mAttributeValues[static_cast<size_t>(index)];
|
||||
}
|
||||
|
||||
float Race::MaleFemaleF::getValue(bool male) const
|
||||
void Race::RADTstruct::setAttribute(ESM::RefId attribute, bool male, int32_t value)
|
||||
{
|
||||
return male ? mMale : mFemale;
|
||||
int index = ESM::Attribute::refIdToIndex(attribute);
|
||||
if (index < 0)
|
||||
return;
|
||||
index *= 2;
|
||||
if (!male)
|
||||
index++;
|
||||
mAttributeValues[static_cast<size_t>(index)] = value;
|
||||
}
|
||||
|
||||
void Race::RADTstruct::load(ESMReader& esm)
|
||||
{
|
||||
esm.getSubHeader();
|
||||
for (auto& bonus : mBonus)
|
||||
{
|
||||
esm.getT(bonus.mSkill);
|
||||
esm.getT(bonus.mBonus);
|
||||
}
|
||||
esm.getT(mAttributeValues);
|
||||
esm.getT(mMaleHeight);
|
||||
esm.getT(mFemaleHeight);
|
||||
esm.getT(mMaleWeight);
|
||||
esm.getT(mFemaleWeight);
|
||||
esm.getT(mFlags);
|
||||
}
|
||||
|
||||
void Race::RADTstruct::save(ESMWriter& esm) const
|
||||
{
|
||||
esm.startSubRecord("RADT");
|
||||
for (const auto& bonus : mBonus)
|
||||
{
|
||||
esm.writeT(bonus.mSkill);
|
||||
esm.writeT(bonus.mBonus);
|
||||
}
|
||||
esm.writeT(mAttributeValues);
|
||||
esm.writeT(mMaleHeight);
|
||||
esm.writeT(mFemaleHeight);
|
||||
esm.writeT(mMaleWeight);
|
||||
esm.writeT(mFemaleWeight);
|
||||
esm.writeT(mFlags);
|
||||
esm.endRecord("RADT");
|
||||
}
|
||||
|
||||
void Race::load(ESMReader& esm, bool& isDeleted)
|
||||
@ -37,7 +84,7 @@ namespace ESM
|
||||
mName = esm.getHString();
|
||||
break;
|
||||
case fourCC("RADT"):
|
||||
esm.getHTSized<140>(mData);
|
||||
mData.load(esm);
|
||||
hasData = true;
|
||||
break;
|
||||
case fourCC("DESC"):
|
||||
@ -71,7 +118,7 @@ namespace ESM
|
||||
}
|
||||
|
||||
esm.writeHNOCString("FNAM", mName);
|
||||
esm.writeHNT("RADT", mData, 140);
|
||||
mData.save(esm);
|
||||
mPowers.save(esm);
|
||||
esm.writeHNOString("DESC", mDescription);
|
||||
}
|
||||
@ -90,11 +137,10 @@ namespace ESM
|
||||
bonus.mBonus = 0;
|
||||
}
|
||||
|
||||
for (auto& attribute : mData.mAttributeValues)
|
||||
attribute.mMale = attribute.mFemale = 1;
|
||||
mData.mAttributeValues.fill(1);
|
||||
|
||||
mData.mHeight.mMale = mData.mHeight.mFemale = 1;
|
||||
mData.mWeight.mMale = mData.mWeight.mFemale = 1;
|
||||
mData.mMaleHeight = mData.mFemaleHeight = 1;
|
||||
mData.mMaleWeight = mData.mFemaleWeight = 1;
|
||||
|
||||
mData.mFlags = 0;
|
||||
}
|
||||
|
@ -31,20 +31,6 @@ namespace ESM
|
||||
int32_t mBonus;
|
||||
};
|
||||
|
||||
struct MaleFemale
|
||||
{
|
||||
int32_t mMale, mFemale;
|
||||
|
||||
int getValue(bool male) const;
|
||||
};
|
||||
|
||||
struct MaleFemaleF
|
||||
{
|
||||
float mMale, mFemale;
|
||||
|
||||
float getValue(bool male) const;
|
||||
};
|
||||
|
||||
enum Flags
|
||||
{
|
||||
Playable = 0x01,
|
||||
@ -57,14 +43,20 @@ namespace ESM
|
||||
std::array<SkillBonus, 7> mBonus;
|
||||
|
||||
// Attribute values for male/female
|
||||
std::array<MaleFemale, 8> mAttributeValues;
|
||||
std::array<int32_t, 16> mAttributeValues;
|
||||
|
||||
// The actual eye level height (in game units) is (probably) given
|
||||
// as 'height' times 128. This has not been tested yet.
|
||||
MaleFemaleF mHeight, mWeight;
|
||||
float mMaleHeight, mFemaleHeight, mMaleWeight, mFemaleWeight;
|
||||
|
||||
int32_t mFlags; // 0x1 - playable, 0x2 - beast race
|
||||
|
||||
int32_t getAttribute(ESM::RefId attribute, bool male) const;
|
||||
void setAttribute(ESM::RefId attribute, bool male, int32_t value);
|
||||
|
||||
void load(ESMReader& esm);
|
||||
void save(ESMWriter& esm) const;
|
||||
|
||||
}; // Size = 140 bytes
|
||||
|
||||
RADTstruct mData;
|
||||
|
@ -20,10 +20,8 @@ namespace ESM
|
||||
|
||||
void Header::load(ESMReader& esm)
|
||||
{
|
||||
if (esm.isNextSub("FORM"))
|
||||
esm.getHT(mFormatVersion);
|
||||
else
|
||||
mFormatVersion = DefaultFormatVersion;
|
||||
mFormatVersion = DefaultFormatVersion;
|
||||
esm.getHNOT("FORM", mFormatVersion);
|
||||
|
||||
if (esm.isNextSub("HEDR"))
|
||||
{
|
||||
@ -43,10 +41,8 @@ namespace ESM
|
||||
mMaster.push_back(m);
|
||||
}
|
||||
|
||||
if (esm.isNextSub("GMDT"))
|
||||
{
|
||||
esm.getHTSized<124>(mGameData);
|
||||
}
|
||||
esm.getHNOT("GMDT", mGameData.mCurrentHealth, mGameData.mMaximumHealth, mGameData.mHour, mGameData.unknown1,
|
||||
mGameData.mCurrentCell.mData, mGameData.unknown2, mGameData.mPlayerName.mData);
|
||||
if (esm.isNextSub("SCRD"))
|
||||
{
|
||||
esm.getSubHeader();
|
||||
|
@ -11,9 +11,6 @@ namespace ESM
|
||||
class ESMReader;
|
||||
class ESMWriter;
|
||||
|
||||
#pragma pack(push)
|
||||
#pragma pack(1)
|
||||
|
||||
struct Data
|
||||
{
|
||||
/* File format version. This is actually a float, the supported
|
||||
@ -38,8 +35,6 @@ namespace ESM
|
||||
NAME32 mPlayerName;
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
/// \brief File header record
|
||||
struct Header
|
||||
{
|
||||
|
@ -32,15 +32,8 @@ namespace ESM
|
||||
mCount = 1;
|
||||
esm.getHNOT(mCount, "COUN");
|
||||
|
||||
if (esm.isNextSub("POS_"))
|
||||
{
|
||||
std::array<float, 6> pos;
|
||||
esm.getHT(pos);
|
||||
memcpy(mPosition.pos, pos.data(), sizeof(float) * 3);
|
||||
memcpy(mPosition.rot, pos.data() + 3, sizeof(float) * 3);
|
||||
}
|
||||
else
|
||||
mPosition = mRef.mPos;
|
||||
mPosition = mRef.mPos;
|
||||
esm.getHNOT("POS_", mPosition.pos, mPosition.rot);
|
||||
|
||||
mFlags = 0;
|
||||
esm.getHNOT(mFlags, "FLAG");
|
||||
|
@ -13,16 +13,11 @@ namespace ESM
|
||||
|
||||
mCellId = esm.getCellId();
|
||||
|
||||
esm.getHNTSized<12>(mLastKnownExteriorPosition, "LKEP");
|
||||
esm.getHNT("LKEP", mLastKnownExteriorPosition);
|
||||
|
||||
if (esm.isNextSub("MARK"))
|
||||
{
|
||||
mHasMark = true;
|
||||
esm.getHTSized<24>(mMarkedPosition);
|
||||
mHasMark = esm.getHNOT("MARK", mMarkedPosition.pos, mMarkedPosition.rot);
|
||||
if (mHasMark)
|
||||
mMarkedCell = esm.getCellId();
|
||||
}
|
||||
else
|
||||
mHasMark = false;
|
||||
|
||||
// Automove, no longer used.
|
||||
if (esm.isNextSub("AMOV"))
|
||||
|
@ -17,8 +17,8 @@ namespace ESM
|
||||
void BaseProjectileState::load(ESMReader& esm)
|
||||
{
|
||||
mId = esm.getHNRefId("ID__");
|
||||
esm.getHNTSized<12>(mPosition, "VEC3");
|
||||
esm.getHNTSized<16>(mOrientation, "QUAT");
|
||||
esm.getHNT("VEC3", mPosition.mValues);
|
||||
esm.getHNT("QUAT", mOrientation.mValues);
|
||||
esm.getHNT(mActorId, "ACTO");
|
||||
}
|
||||
|
||||
@ -58,7 +58,7 @@ namespace ESM
|
||||
BaseProjectileState::load(esm);
|
||||
|
||||
mBowId = esm.getHNRefId("BOW_");
|
||||
esm.getHNTSized<12>(mVelocity, "VEL_");
|
||||
esm.getHNT("VEL_", mVelocity.mValues);
|
||||
|
||||
mAttackStrength = 1.f;
|
||||
esm.getHNOT(mAttackStrength, "STR_");
|
||||
|
@ -17,7 +17,7 @@ namespace ESM
|
||||
mPlayerCellName = esm.getHNRefId("PLCE").toString();
|
||||
else
|
||||
mPlayerCellName = esm.getHNString("PLCE");
|
||||
esm.getHNTSized<16>(mInGameTime, "TSTM");
|
||||
esm.getHNT("TSTM", mInGameTime.mGameHour, mInGameTime.mDay, mInGameTime.mMonth, mInGameTime.mYear);
|
||||
esm.getHNT(mTimePlayed, "TIME");
|
||||
mDescription = esm.getHNString("DESC");
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user