ESS-Importer: Convert ballistic projectiles (Feature #2320)

pull/290/head
MiroslavR 7 years ago
parent bd667c3847
commit 6e869c3123

@ -16,6 +16,7 @@ set(ESSIMPORTER_FILES
importjour.cpp
importscri.cpp
importscpt.cpp
importproj.cpp
importercontext.cpp
converter.cpp
convertacdt.cpp

@ -6,6 +6,7 @@
#include <components/esm/creaturestate.hpp>
#include <components/esm/containerstate.hpp>
#include <components/esm/projectilestate.hpp>
#include "convertcrec.hpp"
#include "convertcntc.hpp"
@ -53,6 +54,36 @@ namespace
return true;
return false;
}
void splitIndexedRefId(const std::string& indexedRefId, int& refIndex, std::string& refId)
{
std::stringstream stream;
stream << std::hex << indexedRefId.substr(indexedRefId.size()-8,8);
stream >> refIndex;
refId = indexedRefId.substr(0,indexedRefId.size()-8);
}
int convertActorId(const std::string& indexedRefId, ESSImport::Context& context)
{
if (isIndexedRefId(indexedRefId))
{
int refIndex;
std::string refId;
splitIndexedRefId(indexedRefId, refIndex, refId);
auto it = context.mActorIdMap.find(std::make_pair(refIndex, refId));
if (it == context.mActorIdMap.end())
return -1;
return it->second;
}
else if (indexedRefId == "PlayerSaveGame")
{
return context.mPlayer.mObject.mCreatureStats.mActorId;
}
return -1;
}
}
namespace ESSImport
@ -322,12 +353,9 @@ namespace ESSImport
}
else
{
std::stringstream stream;
stream << std::hex << cellref.mIndexedRefId.substr(cellref.mIndexedRefId.size()-8,8);
int refIndex;
stream >> refIndex;
splitIndexedRefId(cellref.mIndexedRefId, refIndex, out.mRefID);
out.mRefID = cellref.mIndexedRefId.substr(0,cellref.mIndexedRefId.size()-8);
std::string idLower = Misc::StringUtils::lowerCase(out.mRefID);
std::map<std::pair<int, std::string>, NPCC>::const_iterator npccIt = mContext->mNpcChanges.find(
@ -347,6 +375,10 @@ namespace ESSImport
convertNpcData(cellref, objstate.mNpcStats);
convertNPCC(npccIt->second, objstate);
convertCellRef(cellref, objstate);
objstate.mCreatureStats.mActorId = mContext->generateActorId();
mContext->mActorIdMap.insert(std::make_pair(std::make_pair(refIndex, out.mRefID), objstate.mCreatureStats.mActorId));
esm.writeHNT ("OBJE", ESM::REC_NPC_);
objstate.save(esm);
continue;
@ -383,6 +415,10 @@ namespace ESSImport
convertACSC(cellref.mACSC, objstate.mCreatureStats);
convertCREC(crecIt->second, objstate);
convertCellRef(cellref, objstate);
objstate.mCreatureStats.mActorId = mContext->generateActorId();
mContext->mActorIdMap.insert(std::make_pair(std::make_pair(refIndex, out.mRefID), objstate.mCreatureStats.mActorId));
esm.writeHNT ("OBJE", ESM::REC_CREA);
objstate.save(esm);
continue;
@ -413,4 +449,44 @@ namespace ESSImport
}
}
void ConvertPROJ::read(ESM::ESMReader& esm)
{
mProj.load(esm);
}
void ConvertPROJ::write(ESM::ESMWriter& esm)
{
for (const PROJ::PNAM& pnam : mProj.mProjectiles)
{
if (!pnam.isMagic())
{
ESM::ProjectileState out;
out.mId = pnam.mArrowId.toString();
out.mPosition = pnam.mPosition;
out.mOrientation.mValues[0] = out.mOrientation.mValues[1] = out.mOrientation.mValues[2] = 0.0f;
out.mOrientation.mValues[3] = 1.0f;
out.mActorId = convertActorId(pnam.mActorId.toString(), *mContext);
out.mBowId = pnam.mBowId.toString();
out.mVelocity = pnam.mVelocity;
out.mAttackStrength = pnam.mAttackStrength;
esm.startRecord(ESM::REC_PROJ);
out.save(esm);
esm.endRecord(ESM::REC_PROJ);
}
else
{
// TODO: Implement magic projectile conversion.
/*esm.startRecord(ESM::REC_MPRJ);
out.save(esm);
esm.endRecord(ESM::REC_MPRJ);*/
std::cerr << "Warning: Skipped conversion for magic projectile \"" << pnam.mArrowId.toString() << "\" (not implemented)" << std::endl;
continue;
}
}
}
}

@ -35,6 +35,7 @@
#include "importques.hpp"
#include "importjour.hpp"
#include "importscpt.hpp"
#include "importproj.h"
#include "convertacdt.hpp"
#include "convertnpcc.hpp"
@ -593,6 +594,17 @@ private:
std::vector<ESM::GlobalScript> mScripts;
};
/// Projectile converter
class ConvertPROJ : public Converter
{
public:
virtual int getStage() override { return 2; }
virtual void read(ESM::ESMReader& esm) override;
virtual void write(ESM::ESMWriter& esm) override;
private:
PROJ mProj;
};
}
#endif

@ -303,6 +303,7 @@ namespace ESSImport
converters[ESM::REC_QUES] = std::shared_ptr<Converter>(new ConvertQUES());
converters[recJOUR ] = std::shared_ptr<Converter>(new ConvertJOUR());
converters[ESM::REC_SCPT] = std::shared_ptr<Converter>(new ConvertSCPT());
converters[ESM::REC_PROJ] = std::shared_ptr<Converter>(new ConvertPROJ());
// TODO:
// - REGN (weather in certain regions?)
@ -420,6 +421,19 @@ namespace ESSImport
context.mPlayer.save(writer);
writer.endRecord(ESM::REC_PLAY);
writer.startRecord(ESM::REC_ACTC);
writer.writeHNT("COUN", context.mNextActorId);
writer.endRecord(ESM::REC_ACTC);
// Stage 2 requires cell references to be written / actors IDs assigned
for (std::map<unsigned int, std::shared_ptr<Converter> >::const_iterator it = converters.begin();
it != converters.end(); ++it)
{
if (it->second->getStage() != 2)
continue;
it->second->write(writer);
}
writer.startRecord (ESM::REC_DIAS);
context.mDialogueState.save(writer);
writer.endRecord(ESM::REC_DIAS);

@ -48,6 +48,9 @@ namespace ESSImport
std::map<std::pair<int, std::string>, NPCC> mNpcChanges;
std::map<std::pair<int, std::string>, CNTC> mContainerChanges;
std::map<std::pair<int, std::string>, int> mActorIdMap;
int mNextActorId;
std::map<std::string, ESM::Creature> mCreatures;
std::map<std::string, ESM::NPC> mNpcs;
@ -56,6 +59,7 @@ namespace ESSImport
, mMonth(0)
, mYear(0)
, mHour(0.f)
, mNextActorId(0)
{
mPlayer.mAutoMove = 0;
ESM::CellId playerCellId;
@ -71,12 +75,18 @@ namespace ESSImport
mPlayer.mObject.blank();
mPlayer.mObject.mEnabled = true;
mPlayer.mObject.mRef.mRefID = "player"; // REFR.mRefID would be PlayerSaveGame
mPlayer.mObject.mCreatureStats.mActorId = generateActorId();
mGlobalMapState.mBounds.mMinX = 0;
mGlobalMapState.mBounds.mMaxX = 0;
mGlobalMapState.mBounds.mMinY = 0;
mGlobalMapState.mBounds.mMaxY = 0;
}
int generateActorId()
{
return mNextActorId++;
}
};
}

@ -0,0 +1,18 @@
#include "importproj.h"
#include <components/esm/esmreader.hpp>
namespace ESSImport
{
void ESSImport::PROJ::load(ESM::ESMReader& esm)
{
while (esm.isNextSub("PNAM"))
{
PNAM pnam;
esm.getHT(pnam);
mProjectiles.push_back(pnam);
}
}
}

@ -0,0 +1,47 @@
#ifndef OPENMW_ESSIMPORT_IMPORTPROJ_H
#define OPENMW_ESSIMPORT_IMPORTPROJ_H
#include <vector>
#include <components/esm/esmcommon.hpp>
#include <components/esm/util.hpp>
namespace ESM
{
class ESMReader;
}
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)
unsigned char mUnknown2[4];
ESM::Vector3 mVelocity;
ESM::Vector3 mPosition;
unsigned char mUnknown3[4*9];
ESM::NAME32 mActorId; // indexed refID (with the exception of "PlayerSaveGame")
ESM::NAME32 mArrowId;
ESM::NAME32 mBowId;
bool isMagic() const { return mSplmIndex != 0; }
};
#pragma pack(pop)
std::vector<PNAM> mProjectiles;
void load(ESM::ESMReader& esm);
};
}
#endif
Loading…
Cancel
Save