diff --git a/CHANGELOG.md b/CHANGELOG.md index f51650473b..d27c0e6392 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,7 @@ 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 #4860: Actors outside of processing range visible for one frame after spawning + Bug #4876: AI ratings handling inconsistencies Feature #2229: Improve pathfinding AI Feature #3442: Default values for fallbacks from ini file Feature #3610: Option to invert X axis diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index 6cd32077c1..cfd658fc94 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -660,7 +660,7 @@ void Record::print() 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 Fight:" << (int)mData.mAiData.mFight << std::endl; std::cout << " AI Flee:" << (int)mData.mAiData.mFlee << std::endl; @@ -668,7 +668,6 @@ void Record::print() std::cout << " AI U1:" << (int)mData.mAiData.mU1 << 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 U4:" << (int)mData.mAiData.mU4 << std::endl; std::cout << " AI Services:" << boost::format("0x%08X") % mData.mAiData.mServices << std::endl; for (const ESM::AIPackage &package : mData.mAiPackage.mList) @@ -1079,7 +1078,7 @@ void Record::print() 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 Fight:" << (int)mData.mAiData.mFight << std::endl; std::cout << " AI Flee:" << (int)mData.mAiData.mFlee << std::endl; @@ -1087,7 +1086,6 @@ void Record::print() std::cout << " AI U1:" << (int)mData.mAiData.mU1 << 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 U4:" << (int)mData.mAiData.mU4 << std::endl; std::cout << " AI Services:" << boost::format("0x%08X") % mData.mAiData.mServices << std::endl; for (const ESM::AIPackage &package : mData.mAiPackage.mList) diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index 94ebbef554..b4eee86308 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -87,6 +87,7 @@ namespace CSMWorld //CONCRETE TYPES ENDS HERE Display_UnsignedInteger8, + Display_UnsignedInteger16, Display_Integer, Display_Float, Display_Double, diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index c05a20d078..16b7739f70 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -627,12 +627,12 @@ namespace CSMWorld RecordT record2 = record.get(); if (column==mActors.mHello) record2.mAiData.mHello = value.toInt(); - else if (column==mActors.mFlee) - record2.mAiData.mFlee = value.toInt(); + else if (column==mActors.mFlee) // Flee, Fight and Alarm ratings are probabilities. + record2.mAiData.mFlee = std::min(100, value.toInt()); else if (column==mActors.mFight) - record2.mAiData.mFight = value.toInt(); + record2.mAiData.mFight = std::min(100, value.toInt()); else if (column==mActors.mAlarm) - record2.mAiData.mAlarm = value.toInt(); + record2.mAiData.mAlarm = std::min(100, value.toInt()); else { typename std::map::const_iterator iter = diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 89d3462043..bd68494922 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -128,7 +128,7 @@ CSMWorld::RefIdCollection::RefIdCollection() 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(); mColumns.push_back (RefIdColumn (Columns::ColumnId_AiFlee, ColumnBase::Display_UnsignedInteger8)); actorsColumns.mFlee = &mColumns.back(); diff --git a/apps/opencs/view/world/util.cpp b/apps/opencs/view/world/util.cpp index fef805d566..3aee51e980 100644 --- a/apps/opencs/view/world/util.cpp +++ b/apps/opencs/view/world/util.cpp @@ -219,6 +219,13 @@ QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleO return sb; } + case CSMWorld::ColumnBase::Display_UnsignedInteger16: + { + DialogueSpinBox *sb = new DialogueSpinBox(parent); + sb->setRange(0, std::numeric_limits::max()); + return sb; + } + case CSMWorld::ColumnBase::Display_Var: return new QLineEdit(parent); diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 94f75dfc6a..8f17a30389 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -608,11 +608,7 @@ namespace MWClass int Creature::getServices(const MWWorld::ConstPtr &actor) const { - const MWWorld::LiveCellRef* ref = actor.get(); - if (ref->mBase->mHasAI) - return ref->mBase->mAiData.mServices; - else - return 0; + return actor.get()->mBase->mAiData.mServices; } bool Creature::isPersistent(const MWWorld::ConstPtr &actor) const diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 1fe7eec4ee..5e03477c4a 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1205,11 +1205,7 @@ namespace MWClass int Npc::getServices(const MWWorld::ConstPtr &actor) const { - const MWWorld::LiveCellRef* ref = actor.get(); - if (ref->mBase->mHasAI) - return ref->mBase->mAiData.mServices; - else - return 0; + return actor.get()->mBase->mAiData.mServices; } diff --git a/components/esm/aipackage.cpp b/components/esm/aipackage.cpp index efcd6651ea..abbd2c62cd 100644 --- a/components/esm/aipackage.cpp +++ b/components/esm/aipackage.cpp @@ -7,7 +7,7 @@ namespace ESM { void AIData::blank() { - mHello = mU1 = mFight = mFlee = mAlarm = mU2 = mU3 = mU4 = 0; + mHello = mFight = mFlee = mAlarm = mU1 = mU2 = mU3 = 0; mServices = 0; } diff --git a/components/esm/aipackage.hpp b/components/esm/aipackage.hpp index 5e08806c8b..026e65dd82 100644 --- a/components/esm/aipackage.hpp +++ b/components/esm/aipackage.hpp @@ -16,10 +16,9 @@ namespace ESM struct AIData { - unsigned char mHello; - char mU1; + unsigned short mHello; // This is the base value for greeting distance [0, 65535] 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 void blank(); diff --git a/components/esm/loadcrea.cpp b/components/esm/loadcrea.cpp index f04439041d..17f03c69b3 100644 --- a/components/esm/loadcrea.cpp +++ b/components/esm/loadcrea.cpp @@ -22,8 +22,9 @@ namespace ESM { mTransport.mList.clear(); mScale = 1.f; - mHasAI = false; mAiData.blank(); + mAiData.mFight = 90; + mAiData.mFlee = 20; bool hasName = false; bool hasNpdt = false; @@ -68,7 +69,6 @@ namespace ESM { break; case ESM::FourCC<'A','I','D','T'>::value: esm.getHExact(&mAiData, sizeof(mAiData)); - mHasAI = true; break; case ESM::FourCC<'D','O','D','T'>::value: case ESM::FourCC<'D','N','A','M'>::value: @@ -128,14 +128,7 @@ namespace ESM { mInventory.save(esm); mSpells.save(esm); - if (mAiData.mHello != 0 - || mAiData.mFight != 0 - || mAiData.mFlee != 0 - || mAiData.mAlarm != 0 - || mAiData.mServices != 0) - { - esm.writeHNT("AIDT", mAiData, sizeof(mAiData)); - } + esm.writeHNT("AIDT", mAiData, sizeof(mAiData)); mTransport.save(esm); mAiPackage.save(esm); } @@ -159,8 +152,9 @@ namespace ESM { mOriginal.clear(); mInventory.mList.clear(); mSpells.mList.clear(); - mHasAI = false; mAiData.blank(); + mAiData.mFight = 90; + mAiData.mFlee = 20; mAiPackage.mList.clear(); mTransport.mList.clear(); } diff --git a/components/esm/loadcrea.hpp b/components/esm/loadcrea.hpp index a5147619cf..be6a72b8d2 100644 --- a/components/esm/loadcrea.hpp +++ b/components/esm/loadcrea.hpp @@ -91,7 +91,6 @@ struct Creature InventoryList mInventory; SpellList mSpells; - bool mHasAI; AIData mAiData; AIPackageList mAiPackage; Transport mTransport; diff --git a/components/esm/loadnpc.cpp b/components/esm/loadnpc.cpp index 6e7ba66c52..db6b6d31b8 100644 --- a/components/esm/loadnpc.cpp +++ b/components/esm/loadnpc.cpp @@ -19,7 +19,7 @@ namespace ESM mTransport.mList.clear(); mAiPackage.mList.clear(); mAiData.blank(); - mHasAI = false; + mAiData.mHello = mAiData.mFight = mAiData.mFlee = 30; bool hasName = false; bool hasNpdt = false; @@ -96,7 +96,6 @@ namespace ESM break; case ESM::FourCC<'A','I','D','T'>::value: esm.getHExact(&mAiData, sizeof(mAiData)); - mHasAI= true; break; case ESM::FourCC<'D','O','D','T'>::value: case ESM::FourCC<'D','N','A','M'>::value: @@ -165,14 +164,7 @@ namespace ESM mInventory.save(esm); mSpells.save(esm); - if (mAiData.mHello != 0 - || mAiData.mFight != 0 - || mAiData.mFlee != 0 - || mAiData.mAlarm != 0 - || mAiData.mServices != 0) - { - esm.writeHNT("AIDT", mAiData, sizeof(mAiData)); - } + esm.writeHNT("AIDT", mAiData, sizeof(mAiData)); mTransport.save(esm); @@ -198,7 +190,7 @@ namespace ESM mInventory.mList.clear(); mSpells.mList.clear(); mAiData.blank(); - mHasAI = false; + mAiData.mHello = mAiData.mFight = mAiData.mFlee = 30; mTransport.mList.clear(); mAiPackage.mList.clear(); mName.clear(); diff --git a/components/esm/loadnpc.hpp b/components/esm/loadnpc.hpp index fbe1dca1f1..746913008e 100644 --- a/components/esm/loadnpc.hpp +++ b/components/esm/loadnpc.hpp @@ -122,7 +122,6 @@ struct NPC SpellList mSpells; AIData mAiData; - bool mHasAI; Transport mTransport;