Revise AI data handling

Make Hello 16-bit unsigned as it's intended to be
Get rid of redundant mHasAI boolean
Always save AI data subrecord
Adjust creature and NPC default rating values to Morrowind defaults
pull/541/head
Capostrophic 6 years ago
parent acbc885ae6
commit 594ea39f5d

@ -34,6 +34,7 @@
Bug #4828: Potion looping effects VFX are not shown for NPCs Bug #4828: Potion looping effects VFX are not shown for NPCs
Bug #4837: CTD when a mesh with NiLODNode root node with particles is loaded Bug #4837: CTD when a mesh with NiLODNode root node with particles is loaded
Bug #4860: Actors outside of processing range visible for one frame after spawning Bug #4860: Actors outside of processing range visible for one frame after spawning
Bug #4876: AI ratings handling inconsistencies
Feature #2229: Improve pathfinding AI Feature #2229: Improve pathfinding AI
Feature #3442: Default values for fallbacks from ini file Feature #3442: Default values for fallbacks from ini file
Feature #3610: Option to invert X axis Feature #3610: Option to invert X axis

@ -660,7 +660,7 @@ void Record<ESM::Creature>::print()
printTransport(mData.getTransport()); printTransport(mData.getTransport());
std::cout << " Artifical Intelligence: " << mData.mHasAI << std::endl; std::cout << " Artificial Intelligence: " << std::endl;
std::cout << " AI Hello:" << (int)mData.mAiData.mHello << std::endl; std::cout << " AI Hello:" << (int)mData.mAiData.mHello << std::endl;
std::cout << " AI Fight:" << (int)mData.mAiData.mFight << std::endl; std::cout << " AI Fight:" << (int)mData.mAiData.mFight << std::endl;
std::cout << " AI Flee:" << (int)mData.mAiData.mFlee << std::endl; std::cout << " AI Flee:" << (int)mData.mAiData.mFlee << std::endl;
@ -668,7 +668,6 @@ void Record<ESM::Creature>::print()
std::cout << " AI U1:" << (int)mData.mAiData.mU1 << std::endl; std::cout << " AI U1:" << (int)mData.mAiData.mU1 << std::endl;
std::cout << " AI U2:" << (int)mData.mAiData.mU2 << std::endl; std::cout << " AI U2:" << (int)mData.mAiData.mU2 << std::endl;
std::cout << " AI U3:" << (int)mData.mAiData.mU3 << std::endl; std::cout << " AI U3:" << (int)mData.mAiData.mU3 << std::endl;
std::cout << " AI U4:" << (int)mData.mAiData.mU4 << std::endl;
std::cout << " AI Services:" << boost::format("0x%08X") % mData.mAiData.mServices << std::endl; std::cout << " AI Services:" << boost::format("0x%08X") % mData.mAiData.mServices << std::endl;
for (const ESM::AIPackage &package : mData.mAiPackage.mList) for (const ESM::AIPackage &package : mData.mAiPackage.mList)
@ -1079,7 +1078,7 @@ void Record<ESM::NPC>::print()
printTransport(mData.getTransport()); printTransport(mData.getTransport());
std::cout << " Artifical Intelligence: " << mData.mHasAI << std::endl; std::cout << " Artificial Intelligence: " << std::endl;
std::cout << " AI Hello:" << (int)mData.mAiData.mHello << std::endl; std::cout << " AI Hello:" << (int)mData.mAiData.mHello << std::endl;
std::cout << " AI Fight:" << (int)mData.mAiData.mFight << std::endl; std::cout << " AI Fight:" << (int)mData.mAiData.mFight << std::endl;
std::cout << " AI Flee:" << (int)mData.mAiData.mFlee << std::endl; std::cout << " AI Flee:" << (int)mData.mAiData.mFlee << std::endl;
@ -1087,7 +1086,6 @@ void Record<ESM::NPC>::print()
std::cout << " AI U1:" << (int)mData.mAiData.mU1 << std::endl; std::cout << " AI U1:" << (int)mData.mAiData.mU1 << std::endl;
std::cout << " AI U2:" << (int)mData.mAiData.mU2 << std::endl; std::cout << " AI U2:" << (int)mData.mAiData.mU2 << std::endl;
std::cout << " AI U3:" << (int)mData.mAiData.mU3 << std::endl; std::cout << " AI U3:" << (int)mData.mAiData.mU3 << std::endl;
std::cout << " AI U4:" << (int)mData.mAiData.mU4 << std::endl;
std::cout << " AI Services:" << boost::format("0x%08X") % mData.mAiData.mServices << std::endl; std::cout << " AI Services:" << boost::format("0x%08X") % mData.mAiData.mServices << std::endl;
for (const ESM::AIPackage &package : mData.mAiPackage.mList) for (const ESM::AIPackage &package : mData.mAiPackage.mList)

@ -87,6 +87,7 @@ namespace CSMWorld
//CONCRETE TYPES ENDS HERE //CONCRETE TYPES ENDS HERE
Display_UnsignedInteger8, Display_UnsignedInteger8,
Display_UnsignedInteger16,
Display_Integer, Display_Integer,
Display_Float, Display_Float,
Display_Double, Display_Double,

@ -627,12 +627,12 @@ namespace CSMWorld
RecordT record2 = record.get(); RecordT record2 = record.get();
if (column==mActors.mHello) if (column==mActors.mHello)
record2.mAiData.mHello = value.toInt(); record2.mAiData.mHello = value.toInt();
else if (column==mActors.mFlee) else if (column==mActors.mFlee) // Flee, Fight and Alarm ratings are probabilities.
record2.mAiData.mFlee = value.toInt(); record2.mAiData.mFlee = std::min(100, value.toInt());
else if (column==mActors.mFight) else if (column==mActors.mFight)
record2.mAiData.mFight = value.toInt(); record2.mAiData.mFight = std::min(100, value.toInt());
else if (column==mActors.mAlarm) else if (column==mActors.mAlarm)
record2.mAiData.mAlarm = value.toInt(); record2.mAiData.mAlarm = std::min(100, value.toInt());
else else
{ {
typename std::map<const RefIdColumn *, unsigned int>::const_iterator iter = typename std::map<const RefIdColumn *, unsigned int>::const_iterator iter =

@ -128,7 +128,7 @@ CSMWorld::RefIdCollection::RefIdCollection()
ActorColumns actorsColumns (nameColumns); ActorColumns actorsColumns (nameColumns);
mColumns.push_back (RefIdColumn (Columns::ColumnId_AiHello, ColumnBase::Display_UnsignedInteger8)); mColumns.push_back (RefIdColumn (Columns::ColumnId_AiHello, ColumnBase::Display_UnsignedInteger16));
actorsColumns.mHello = &mColumns.back(); actorsColumns.mHello = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_AiFlee, ColumnBase::Display_UnsignedInteger8)); mColumns.push_back (RefIdColumn (Columns::ColumnId_AiFlee, ColumnBase::Display_UnsignedInteger8));
actorsColumns.mFlee = &mColumns.back(); actorsColumns.mFlee = &mColumns.back();

@ -219,6 +219,13 @@ QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleO
return sb; return sb;
} }
case CSMWorld::ColumnBase::Display_UnsignedInteger16:
{
DialogueSpinBox *sb = new DialogueSpinBox(parent);
sb->setRange(0, std::numeric_limits<unsigned short>::max());
return sb;
}
case CSMWorld::ColumnBase::Display_Var: case CSMWorld::ColumnBase::Display_Var:
return new QLineEdit(parent); return new QLineEdit(parent);

@ -608,11 +608,7 @@ namespace MWClass
int Creature::getServices(const MWWorld::ConstPtr &actor) const int Creature::getServices(const MWWorld::ConstPtr &actor) const
{ {
const MWWorld::LiveCellRef<ESM::Creature>* ref = actor.get<ESM::Creature>(); return actor.get<ESM::Creature>()->mBase->mAiData.mServices;
if (ref->mBase->mHasAI)
return ref->mBase->mAiData.mServices;
else
return 0;
} }
bool Creature::isPersistent(const MWWorld::ConstPtr &actor) const bool Creature::isPersistent(const MWWorld::ConstPtr &actor) const

@ -1205,11 +1205,7 @@ namespace MWClass
int Npc::getServices(const MWWorld::ConstPtr &actor) const int Npc::getServices(const MWWorld::ConstPtr &actor) const
{ {
const MWWorld::LiveCellRef<ESM::NPC>* ref = actor.get<ESM::NPC>(); return actor.get<ESM::NPC>()->mBase->mAiData.mServices;
if (ref->mBase->mHasAI)
return ref->mBase->mAiData.mServices;
else
return 0;
} }

@ -7,7 +7,7 @@ namespace ESM
{ {
void AIData::blank() void AIData::blank()
{ {
mHello = mU1 = mFight = mFlee = mAlarm = mU2 = mU3 = mU4 = 0; mHello = mFight = mFlee = mAlarm = mU1 = mU2 = mU3 = 0;
mServices = 0; mServices = 0;
} }

@ -16,10 +16,9 @@ namespace ESM
struct AIData struct AIData
{ {
unsigned char mHello; unsigned short mHello; // This is the base value for greeting distance [0, 65535]
char mU1;
unsigned char mFight, mFlee, mAlarm; // These are probabilities [0, 100] unsigned char mFight, mFlee, mAlarm; // These are probabilities [0, 100]
char mU2, mU3, mU4; // Unknown values char mU1, mU2, mU3; // Unknown values
int mServices; // See the Services enum int mServices; // See the Services enum
void blank(); void blank();

@ -22,8 +22,9 @@ namespace ESM {
mTransport.mList.clear(); mTransport.mList.clear();
mScale = 1.f; mScale = 1.f;
mHasAI = false;
mAiData.blank(); mAiData.blank();
mAiData.mFight = 90;
mAiData.mFlee = 20;
bool hasName = false; bool hasName = false;
bool hasNpdt = false; bool hasNpdt = false;
@ -68,7 +69,6 @@ namespace ESM {
break; break;
case ESM::FourCC<'A','I','D','T'>::value: case ESM::FourCC<'A','I','D','T'>::value:
esm.getHExact(&mAiData, sizeof(mAiData)); esm.getHExact(&mAiData, sizeof(mAiData));
mHasAI = true;
break; break;
case ESM::FourCC<'D','O','D','T'>::value: case ESM::FourCC<'D','O','D','T'>::value:
case ESM::FourCC<'D','N','A','M'>::value: case ESM::FourCC<'D','N','A','M'>::value:
@ -128,14 +128,7 @@ namespace ESM {
mInventory.save(esm); mInventory.save(esm);
mSpells.save(esm); mSpells.save(esm);
if (mAiData.mHello != 0 esm.writeHNT("AIDT", mAiData, sizeof(mAiData));
|| mAiData.mFight != 0
|| mAiData.mFlee != 0
|| mAiData.mAlarm != 0
|| mAiData.mServices != 0)
{
esm.writeHNT("AIDT", mAiData, sizeof(mAiData));
}
mTransport.save(esm); mTransport.save(esm);
mAiPackage.save(esm); mAiPackage.save(esm);
} }
@ -159,8 +152,9 @@ namespace ESM {
mOriginal.clear(); mOriginal.clear();
mInventory.mList.clear(); mInventory.mList.clear();
mSpells.mList.clear(); mSpells.mList.clear();
mHasAI = false;
mAiData.blank(); mAiData.blank();
mAiData.mFight = 90;
mAiData.mFlee = 20;
mAiPackage.mList.clear(); mAiPackage.mList.clear();
mTransport.mList.clear(); mTransport.mList.clear();
} }

@ -91,7 +91,6 @@ struct Creature
InventoryList mInventory; InventoryList mInventory;
SpellList mSpells; SpellList mSpells;
bool mHasAI;
AIData mAiData; AIData mAiData;
AIPackageList mAiPackage; AIPackageList mAiPackage;
Transport mTransport; Transport mTransport;

@ -19,7 +19,7 @@ namespace ESM
mTransport.mList.clear(); mTransport.mList.clear();
mAiPackage.mList.clear(); mAiPackage.mList.clear();
mAiData.blank(); mAiData.blank();
mHasAI = false; mAiData.mHello = mAiData.mFight = mAiData.mFlee = 30;
bool hasName = false; bool hasName = false;
bool hasNpdt = false; bool hasNpdt = false;
@ -96,7 +96,6 @@ namespace ESM
break; break;
case ESM::FourCC<'A','I','D','T'>::value: case ESM::FourCC<'A','I','D','T'>::value:
esm.getHExact(&mAiData, sizeof(mAiData)); esm.getHExact(&mAiData, sizeof(mAiData));
mHasAI= true;
break; break;
case ESM::FourCC<'D','O','D','T'>::value: case ESM::FourCC<'D','O','D','T'>::value:
case ESM::FourCC<'D','N','A','M'>::value: case ESM::FourCC<'D','N','A','M'>::value:
@ -165,14 +164,7 @@ namespace ESM
mInventory.save(esm); mInventory.save(esm);
mSpells.save(esm); mSpells.save(esm);
if (mAiData.mHello != 0 esm.writeHNT("AIDT", mAiData, sizeof(mAiData));
|| mAiData.mFight != 0
|| mAiData.mFlee != 0
|| mAiData.mAlarm != 0
|| mAiData.mServices != 0)
{
esm.writeHNT("AIDT", mAiData, sizeof(mAiData));
}
mTransport.save(esm); mTransport.save(esm);
@ -198,7 +190,7 @@ namespace ESM
mInventory.mList.clear(); mInventory.mList.clear();
mSpells.mList.clear(); mSpells.mList.clear();
mAiData.blank(); mAiData.blank();
mHasAI = false; mAiData.mHello = mAiData.mFight = mAiData.mFlee = 30;
mTransport.mList.clear(); mTransport.mList.clear();
mAiPackage.mList.clear(); mAiPackage.mList.clear();
mName.clear(); mName.clear();

@ -122,7 +122,6 @@ struct NPC
SpellList mSpells; SpellList mSpells;
AIData mAiData; AIData mAiData;
bool mHasAI;
Transport mTransport; Transport mTransport;

Loading…
Cancel
Save