mirror of
https://github.com/OpenMW/openmw.git
synced 2025-04-17 15:06:44 +00:00
Merge remote-tracking branch 'greye/aidata'
This commit is contained in:
commit
bc34fab17f
12 changed files with 202 additions and 74 deletions
|
@ -61,10 +61,10 @@ namespace MWClass
|
||||||
|
|
||||||
data->mCreatureStats.setLevel(ref->base->data.level);
|
data->mCreatureStats.setLevel(ref->base->data.level);
|
||||||
|
|
||||||
data->mCreatureStats.setHello(ref->base->AI.hello);
|
data->mCreatureStats.setHello(ref->base->mAiData.mHello);
|
||||||
data->mCreatureStats.setFight(ref->base->AI.fight);
|
data->mCreatureStats.setFight(ref->base->mAiData.mFight);
|
||||||
data->mCreatureStats.setFlee(ref->base->AI.flee);
|
data->mCreatureStats.setFlee(ref->base->mAiData.mFlee);
|
||||||
data->mCreatureStats.setAlarm(ref->base->AI.alarm);
|
data->mCreatureStats.setAlarm(ref->base->mAiData.mAlarm);
|
||||||
|
|
||||||
// store
|
// store
|
||||||
ptr.getRefData().setCustomData (data.release());
|
ptr.getRefData().setCustomData (data.release());
|
||||||
|
|
|
@ -100,10 +100,10 @@ namespace MWClass
|
||||||
/// \todo do something with npdt12 maybe:p
|
/// \todo do something with npdt12 maybe:p
|
||||||
}
|
}
|
||||||
|
|
||||||
data->mCreatureStats.setHello(ref->base->AI.hello);
|
data->mCreatureStats.setHello(ref->base->mAiData.mHello);
|
||||||
data->mCreatureStats.setFight(ref->base->AI.fight);
|
data->mCreatureStats.setFight(ref->base->mAiData.mFight);
|
||||||
data->mCreatureStats.setFlee(ref->base->AI.flee);
|
data->mCreatureStats.setFlee(ref->base->mAiData.mFlee);
|
||||||
data->mCreatureStats.setAlarm(ref->base->AI.alarm);
|
data->mCreatureStats.setAlarm(ref->base->mAiData.mAlarm);
|
||||||
|
|
||||||
// store
|
// store
|
||||||
ptr.getRefData().setCustomData (data.release());
|
ptr.getRefData().setCustomData (data.release());
|
||||||
|
|
|
@ -769,14 +769,14 @@ namespace MWDialogue
|
||||||
if (mActor.getTypeName() == typeid(ESM::NPC).name())
|
if (mActor.getTypeName() == typeid(ESM::NPC).name())
|
||||||
{
|
{
|
||||||
MWWorld::LiveCellRef<ESM::NPC>* ref = mActor.get<ESM::NPC>();
|
MWWorld::LiveCellRef<ESM::NPC>* ref = mActor.get<ESM::NPC>();
|
||||||
if (ref->base->hasAI)
|
if (ref->base->mHasAI)
|
||||||
services = ref->base->AI.services;
|
services = ref->base->mAiData.mServices;
|
||||||
}
|
}
|
||||||
else if (mActor.getTypeName() == typeid(ESM::Creature).name())
|
else if (mActor.getTypeName() == typeid(ESM::Creature).name())
|
||||||
{
|
{
|
||||||
MWWorld::LiveCellRef<ESM::Creature>* ref = mActor.get<ESM::Creature>();
|
MWWorld::LiveCellRef<ESM::Creature>* ref = mActor.get<ESM::Creature>();
|
||||||
if (ref->base->hasAI)
|
if (ref->base->mHasAI)
|
||||||
services = ref->base->AI.services;
|
services = ref->base->mAiData.mServices;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (services & ESM::NPC::Weapon
|
if (services & ESM::NPC::Weapon
|
||||||
|
|
|
@ -291,14 +291,14 @@ namespace MWGui
|
||||||
if (mPtr.getTypeName() == typeid(ESM::NPC).name())
|
if (mPtr.getTypeName() == typeid(ESM::NPC).name())
|
||||||
{
|
{
|
||||||
MWWorld::LiveCellRef<ESM::NPC>* ref = mPtr.get<ESM::NPC>();
|
MWWorld::LiveCellRef<ESM::NPC>* ref = mPtr.get<ESM::NPC>();
|
||||||
if (ref->base->hasAI)
|
if (ref->base->mHasAI)
|
||||||
services = ref->base->AI.services;
|
services = ref->base->mAiData.mServices;
|
||||||
}
|
}
|
||||||
else if (mPtr.getTypeName() == typeid(ESM::Creature).name())
|
else if (mPtr.getTypeName() == typeid(ESM::Creature).name())
|
||||||
{
|
{
|
||||||
MWWorld::LiveCellRef<ESM::Creature>* ref = mPtr.get<ESM::Creature>();
|
MWWorld::LiveCellRef<ESM::Creature>* ref = mPtr.get<ESM::Creature>();
|
||||||
if (ref->base->hasAI)
|
if (ref->base->mHasAI)
|
||||||
services = ref->base->AI.services;
|
services = ref->base->mAiData.mServices;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \todo what about potions, there doesn't seem to be a flag for them??
|
/// \todo what about potions, there doesn't seem to be a flag for them??
|
||||||
|
|
|
@ -43,7 +43,7 @@ add_component_dir (esm
|
||||||
loadclas loadclot loadcont loadcrea loadcrec loaddial loaddoor loadench loadfact loadglob loadgmst
|
loadclas loadclot loadcont loadcrea loadcrec loaddial loaddoor loadench loadfact loadglob loadgmst
|
||||||
loadinfo loadingr loadland loadlevlist loadligh loadlocks loadltex loadmgef loadmisc loadnpcc
|
loadinfo loadingr loadland loadlevlist loadligh loadlocks loadltex loadmgef loadmisc loadnpcc
|
||||||
loadnpc loadpgrd loadrace loadregn loadscpt loadskil loadsndg loadsoun loadspel loadsscr loadstat
|
loadnpc loadpgrd loadrace loadregn loadscpt loadskil loadsndg loadsoun loadspel loadsscr loadstat
|
||||||
loadweap records
|
loadweap records aipackage
|
||||||
)
|
)
|
||||||
|
|
||||||
add_component_dir (misc
|
add_component_dir (misc
|
||||||
|
|
37
components/esm/aipackage.cpp
Normal file
37
components/esm/aipackage.cpp
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
#include "aipackage.hpp"
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
void AIPackageList::load(ESMReader &esm)
|
||||||
|
{
|
||||||
|
while (esm.hasMoreSubs()) {
|
||||||
|
// initialize every iteration
|
||||||
|
AIPackage pack;
|
||||||
|
esm.getSubName();
|
||||||
|
if (esm.retSubName() == 0x54444e43) { // CNDT
|
||||||
|
mList.back().mCellName = esm.getHString();
|
||||||
|
} else if (esm.retSubName() == AI_Wander) {
|
||||||
|
pack.mType = AI_Wander;
|
||||||
|
esm.getHExact(&pack.mWander, 14);
|
||||||
|
mList.push_back(pack);
|
||||||
|
} else if (esm.retSubName() == AI_Travel) {
|
||||||
|
pack.mType = AI_Travel;
|
||||||
|
esm.getHExact(&pack.mTravel, 16);
|
||||||
|
mList.push_back(pack);
|
||||||
|
} else if (esm.retSubName() == AI_Escort ||
|
||||||
|
esm.retSubName() == AI_Follow)
|
||||||
|
{
|
||||||
|
pack.mType =
|
||||||
|
(esm.retSubName() == AI_Escort) ? AI_Escort : AI_Follow;
|
||||||
|
esm.getHExact(&pack.mTarget, 48);
|
||||||
|
mList.push_back(pack);
|
||||||
|
} else if (esm.retSubName() == AI_Activate) {
|
||||||
|
pack.mType = AI_Activate;
|
||||||
|
esm.getHExact(&pack.mActivate, 33);
|
||||||
|
mList.push_back(pack);
|
||||||
|
} else { // not AI package related data, so leave
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
95
components/esm/aipackage.hpp
Normal file
95
components/esm/aipackage.hpp
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
#ifndef OPENMW_ESM_AIPACKAGE_H
|
||||||
|
#define OPENMW_ESM_AIPACKAGE_H
|
||||||
|
|
||||||
|
#include "esm_reader.hpp"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
#pragma pack(push)
|
||||||
|
#pragma pack(1)
|
||||||
|
|
||||||
|
struct AIData
|
||||||
|
{
|
||||||
|
// These are probabilities
|
||||||
|
char mHello, mU1, mFight, mFlee, mAlarm, mU2, mU3, mU4;
|
||||||
|
// The last u's might be the skills that this NPC can train you
|
||||||
|
// in?
|
||||||
|
int mServices; // See the Services enum
|
||||||
|
}; // 12 bytes
|
||||||
|
|
||||||
|
struct AIWander
|
||||||
|
{
|
||||||
|
short mDistance;
|
||||||
|
short mDuration;
|
||||||
|
unsigned char mTimeOfDay;
|
||||||
|
unsigned char mIdle[8];
|
||||||
|
unsigned char mUnk;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AITravel
|
||||||
|
{
|
||||||
|
float mX, mY, mZ;
|
||||||
|
long mUnk;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AITarget
|
||||||
|
{
|
||||||
|
float mX, mY, mZ;
|
||||||
|
short mDuration;
|
||||||
|
NAME32 mId;
|
||||||
|
short mUnk;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AIActivate
|
||||||
|
{
|
||||||
|
NAME32 mName;
|
||||||
|
unsigned char mUnk;
|
||||||
|
};
|
||||||
|
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
AI_Wander = 0x575f4941,
|
||||||
|
AI_Travel = 0x545f4941,
|
||||||
|
AI_Follow = 0x465f4941,
|
||||||
|
AI_Escort = 0x455f4941,
|
||||||
|
AI_Activate = 0x415f4941,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \note Used for storaging packages in a single container
|
||||||
|
/// w/o manual memory allocation accordingly to policy standards
|
||||||
|
struct AIPackage
|
||||||
|
{
|
||||||
|
int mType;
|
||||||
|
|
||||||
|
// Anonymous union
|
||||||
|
union
|
||||||
|
{
|
||||||
|
AIWander mWander;
|
||||||
|
AITravel mTravel;
|
||||||
|
AITarget mTarget;
|
||||||
|
AIActivate mActivate;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \note for AITarget only, placed here to stick with union,
|
||||||
|
/// overhead should be not so awful
|
||||||
|
std::string mCellName;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AIPackageList
|
||||||
|
{
|
||||||
|
std::vector<AIPackage> mList;
|
||||||
|
|
||||||
|
/// \note This breaks consistency of subrecords reading:
|
||||||
|
/// after calling it subrecord name is already read, so
|
||||||
|
/// it needs to use retSubName() if needed. But, hey, there
|
||||||
|
/// is only one field left (XSCL) and only two records uses AI
|
||||||
|
void load(ESMReader &esm);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -49,23 +49,23 @@ union NAME_T
|
||||||
char name[LEN];
|
char name[LEN];
|
||||||
int32_t val;
|
int32_t val;
|
||||||
|
|
||||||
bool operator==(const char *str)
|
bool operator==(const char *str) const
|
||||||
{
|
{
|
||||||
for(int i=0; i<LEN; i++)
|
for(int i=0; i<LEN; i++)
|
||||||
if(name[i] != str[i]) return false;
|
if(name[i] != str[i]) return false;
|
||||||
else if(name[i] == 0) return true;
|
else if(name[i] == 0) return true;
|
||||||
return str[LEN] == 0;
|
return str[LEN] == 0;
|
||||||
}
|
}
|
||||||
bool operator!=(const char *str) { return !((*this)==str); }
|
bool operator!=(const char *str) const { return !((*this)==str); }
|
||||||
|
|
||||||
bool operator==(const std::string &str)
|
bool operator==(const std::string &str) const
|
||||||
{
|
{
|
||||||
return (*this) == str.c_str();
|
return (*this) == str.c_str();
|
||||||
}
|
}
|
||||||
bool operator!=(const std::string &str) { return !((*this)==str); }
|
bool operator!=(const std::string &str) const { return !((*this)==str); }
|
||||||
|
|
||||||
bool operator==(int v) { return v == val; }
|
bool operator==(int v) const { return v == val; }
|
||||||
bool operator!=(int v) { return v != val; }
|
bool operator!=(int v) const { return v != val; }
|
||||||
|
|
||||||
std::string toString() const { return std::string(name, strnlen(name, LEN)); }
|
std::string toString() const { return std::string(name, strnlen(name, LEN)); }
|
||||||
};
|
};
|
||||||
|
|
|
@ -18,29 +18,18 @@ void Creature::load(ESMReader &esm, const std::string& id)
|
||||||
esm.getHNOT(scale, "XSCL");
|
esm.getHNOT(scale, "XSCL");
|
||||||
|
|
||||||
inventory.load(esm);
|
inventory.load(esm);
|
||||||
|
mSpells.load(esm);
|
||||||
|
|
||||||
if (esm.isNextSub("AIDT"))
|
if (esm.isNextSub("AIDT"))
|
||||||
{
|
{
|
||||||
esm.getHExact(&AI, sizeof(AI));
|
esm.getHExact(&mAiData, sizeof(mAiData));
|
||||||
hasAI = true;
|
mHasAI = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
hasAI = false;
|
mHasAI = false;
|
||||||
|
|
||||||
// More subrecords:
|
mAiPackage.load(esm);
|
||||||
// AI_W - wander (14 bytes, i don't understand it)
|
|
||||||
// short distance
|
|
||||||
// byte duration
|
|
||||||
// byte timeOfDay
|
|
||||||
// byte idle[10]
|
|
||||||
//
|
|
||||||
// Rest is optional:
|
|
||||||
// AI_T - travel?
|
|
||||||
// AI_F - follow?
|
|
||||||
// AI_E - escort?
|
|
||||||
// AI_A - activate?
|
|
||||||
esm.skipRecord();
|
esm.skipRecord();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
#include "esm_reader.hpp"
|
#include "esm_reader.hpp"
|
||||||
#include "loadcont.hpp"
|
#include "loadcont.hpp"
|
||||||
|
#include "defs.hpp"
|
||||||
|
#include "aipackage.hpp"
|
||||||
|
|
||||||
namespace ESM
|
namespace ESM
|
||||||
{
|
{
|
||||||
|
@ -51,15 +53,6 @@ struct Creature
|
||||||
int gold;
|
int gold;
|
||||||
}; // 96 bytes
|
}; // 96 bytes
|
||||||
|
|
||||||
struct AIDTstruct
|
|
||||||
{
|
|
||||||
// These are probabilities
|
|
||||||
char hello, u1, fight, flee, alarm, u2, u3, u4;
|
|
||||||
// The last u's might be the skills that this NPC can train you
|
|
||||||
// in?
|
|
||||||
int services; // See the NPC::Services enum
|
|
||||||
}; // 12 bytes
|
|
||||||
|
|
||||||
NPDTstruct data;
|
NPDTstruct data;
|
||||||
|
|
||||||
int flags;
|
int flags;
|
||||||
|
@ -69,9 +62,11 @@ struct Creature
|
||||||
|
|
||||||
// Defined in loadcont.hpp
|
// Defined in loadcont.hpp
|
||||||
InventoryList inventory;
|
InventoryList inventory;
|
||||||
|
SpellList mSpells;
|
||||||
|
|
||||||
bool hasAI;
|
bool mHasAI;
|
||||||
AIDTstruct AI;
|
AIData mAiData;
|
||||||
|
AIPackageList mAiPackage;
|
||||||
|
|
||||||
std::string mId;
|
std::string mId;
|
||||||
|
|
||||||
|
|
|
@ -36,12 +36,22 @@ void NPC::load(ESMReader &esm, const std::string& id)
|
||||||
|
|
||||||
if (esm.isNextSub("AIDT"))
|
if (esm.isNextSub("AIDT"))
|
||||||
{
|
{
|
||||||
esm.getHExact(&AI, sizeof(AI));
|
esm.getHExact(&mAiData, sizeof(mAiData));
|
||||||
hasAI = true;
|
mHasAI= true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
hasAI = false;
|
mHasAI = false;
|
||||||
|
|
||||||
|
while (esm.isNextSub("DODT") || esm.isNextSub("DNAM")) {
|
||||||
|
if (esm.retSubName() == 0x54444f44) { // DODT struct
|
||||||
|
Dest dodt;
|
||||||
|
esm.getHExact(&dodt.mPos, 24);
|
||||||
|
mTransport.push_back(dodt);
|
||||||
|
} else if (esm.retSubName() == 0x4d414e44) { // DNAM struct
|
||||||
|
mTransport.back().mCellName = esm.getHString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mAiPackage.load(esm);
|
||||||
esm.skipRecord();
|
esm.skipRecord();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "esm_reader.hpp"
|
#include "esm_reader.hpp"
|
||||||
#include "loadcont.hpp"
|
#include "loadcont.hpp"
|
||||||
#include "defs.hpp"
|
#include "defs.hpp"
|
||||||
|
#include "aipackage.hpp"
|
||||||
|
|
||||||
namespace ESM {
|
namespace ESM {
|
||||||
|
|
||||||
|
@ -71,18 +72,14 @@ struct NPC
|
||||||
unknown1, unknown2, unknown3;
|
unknown1, unknown2, unknown3;
|
||||||
int gold; // ?? not certain
|
int gold; // ?? not certain
|
||||||
}; // 12 bytes
|
}; // 12 bytes
|
||||||
|
|
||||||
struct AIDTstruct
|
|
||||||
{
|
|
||||||
// These are probabilities
|
|
||||||
char hello, u1, fight, flee, alarm, u2, u3, u4;
|
|
||||||
// The last u's might be the skills that this NPC can train you
|
|
||||||
// in?
|
|
||||||
int services; // See the Services enum
|
|
||||||
}; // 12 bytes
|
|
||||||
|
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
struct Dest
|
||||||
|
{
|
||||||
|
Position mPos;
|
||||||
|
std::string mCellName;
|
||||||
|
};
|
||||||
|
|
||||||
NPDTstruct52 npdt52;
|
NPDTstruct52 npdt52;
|
||||||
NPDTstruct12 npdt12; // Use this if npdt52.gold == -10
|
NPDTstruct12 npdt12; // Use this if npdt52.gold == -10
|
||||||
|
|
||||||
|
@ -91,11 +88,16 @@ struct NPC
|
||||||
InventoryList inventory;
|
InventoryList inventory;
|
||||||
SpellList spells;
|
SpellList spells;
|
||||||
|
|
||||||
AIDTstruct AI;
|
AIData mAiData;
|
||||||
bool hasAI;
|
bool mHasAI;
|
||||||
|
|
||||||
std::string name, model, race, cls, faction, script,
|
std::vector<Dest> mTransport;
|
||||||
hair, head; // body parts
|
AIPackageList mAiPackage;
|
||||||
|
|
||||||
|
std::string name, model, race, cls, faction, script;
|
||||||
|
|
||||||
|
// body parts
|
||||||
|
std::string hair, head;
|
||||||
|
|
||||||
std::string mId;
|
std::string mId;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue