From b1066de81de13f493ce2b94207bcbbf7e7d0d722 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 26 Jan 2014 00:16:56 +0100 Subject: [PATCH] Revert "Merge remote-tracking branch 'mrcheko/master'" This reverts commit 4e360136b10061e29fd60492544aad59850513e7, reversing changes made to 047bbe43b2ca08a63c8e18d2b4af52e0dbefb37b. Conflicts: apps/openmw/mwmechanics/aicombat.cpp --- apps/openmw/mwmechanics/actors.cpp | 3 +- apps/openmw/mwmechanics/aicombat.cpp | 426 +++++----------------- apps/openmw/mwmechanics/aicombat.hpp | 26 +- apps/openmw/mwmechanics/aisequence.cpp | 7 +- apps/openmw/mwmechanics/aisequence.hpp | 5 +- apps/openmw/mwmechanics/character.cpp | 4 +- apps/openmw/mwmechanics/character.hpp | 10 +- apps/openmw/mwmechanics/creaturestats.cpp | 11 +- apps/openmw/mwscript/aiextensions.cpp | 23 +- 9 files changed, 135 insertions(+), 380 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 35783bd9fc..272b9a0d03 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -13,7 +13,6 @@ #include "../mwworld/inventorystore.hpp" #include "../mwworld/manualref.hpp" #include "../mwworld/actionequip.hpp" -#include "../mwworld/player.hpp" #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" @@ -209,7 +208,7 @@ namespace MWMechanics && LOS ) { - creatureStats.getAiSequence().stack(AiCombat(MWBase::Environment::get().getWorld()->getPlayer().getPlayer())); + creatureStats.getAiSequence().stack(AiCombat("player")); creatureStats.setHostile(true); } } diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index f246185106..700cea2f30 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -4,18 +4,15 @@ #include "../mwworld/class.hpp" #include "../mwworld/timestamp.hpp" - +#include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/dialoguemanager.hpp" -#include "character.hpp" -#include "../mwworld/inventorystore.hpp" - #include "creaturestats.hpp" +#include "npcstats.hpp" #include -#include namespace { @@ -25,80 +22,107 @@ namespace return 1.0; return -1.0; } - - void determineAttackType(const MWWorld::Ptr& actor, MWMechanics::Movement &movement); - //chooses an attack depending on probability to avoid uniformity - void chooseBestAttack(const ESM::Weapon* weapon, MWMechanics::Movement &movement); } namespace MWMechanics { - AiCombat::AiCombat(const MWWorld::Ptr& actor) : - mTarget(actor), - mTimerAttack(0), - mTimerReact(0), - mTimerCombatMove(0), - mCloseUp(false), - mReadyToAttack(false), - mStrike(false), - mCombatMove(false), - mMovement() + + AiCombat::AiCombat(const std::string &targetId) + :mTargetId(targetId),mTimer(0),mTimer2(0) { } bool AiCombat::execute (const MWWorld::Ptr& actor,float duration) { - //General description - if(!actor.getClass().getCreatureStats(actor).isHostile()) - return true; - if (mTarget.getClass().getCreatureStats(mTarget).isDead()) + if(!MWWorld::Class::get(actor).getCreatureStats(actor).isHostile()) return true; + + const MWWorld::Ptr target = MWBase::Environment::get().getWorld()->getPtr(mTargetId, false); + + if (target.getClass().getCreatureStats(target).isDead()) return true; - //Update every frame - if(mReadyToAttack) - determineAttackType(actor, mMovement); + if(MWWorld::Class::get(actor).getCreatureStats(actor).getHealth().getCurrent() <= 0) return true; - if(mCombatMove) + actor.getClass().getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, true); + + if (actor.getClass().hasInventoryStore(actor)) { - mTimerCombatMove -= duration; - if( mTimerCombatMove <= 0) + MWMechanics::DrawState_ state = actor.getClass().getCreatureStats(actor).getDrawState(); + if (state == MWMechanics::DrawState_Spell || state == MWMechanics::DrawState_Nothing) + actor.getClass().getCreatureStats(actor).setDrawState(MWMechanics::DrawState_Weapon); + //MWWorld::Class::get(actor).getCreatureStats(actor).setAttackingOrSpell(true); + } + + ESM::Position pos = actor.getRefData().getPosition(); + const ESM::Pathgrid *pathgrid = + MWBase::Environment::get().getWorld()->getStore().get().search(*actor.getCell()->mCell); + + float xCell = 0; + float yCell = 0; + + if (actor.getCell()->mCell->isExterior()) + { + xCell = actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE; + yCell = actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE; + } + + ESM::Pathgrid::Point dest; + dest.mX = target.getRefData().getPosition().pos[0]; + dest.mY = target.getRefData().getPosition().pos[1]; + dest.mZ = target.getRefData().getPosition().pos[2]; + + ESM::Pathgrid::Point start; + start.mX = pos.pos[0]; + start.mY = pos.pos[1]; + start.mZ = pos.pos[2]; + + mTimer2 = mTimer2 + duration; + + if(!mPathFinder.isPathConstructed()) + mPathFinder.buildPath(start, dest, pathgrid, xCell, yCell, true); + else + { + mPathFinder2.buildPath(start, dest, pathgrid, xCell, yCell, true); + ESM::Pathgrid::Point lastPt = mPathFinder.getPath().back(); + if((mTimer2 > 0.25)&&(mPathFinder2.getPathSize() < mPathFinder.getPathSize() || + (dest.mX - lastPt.mX)*(dest.mX - lastPt.mX)+(dest.mY - lastPt.mY)*(dest.mY - lastPt.mY)+(dest.mZ - lastPt.mZ)*(dest.mZ - lastPt.mZ) > 200*200)) { - mTimerCombatMove = 0; - mMovement.mPosition[1] = mMovement.mPosition[0] = 0; - mCombatMove = false; + mTimer2 = 0; + mPathFinder = mPathFinder2; } } - actor.getClass().getMovementSettings(actor) = mMovement; - - //actor.getClass().getCreatureStats(actor).setAttackingOrSpell(mReadyToAttack); - mTimerAttack -= duration; - actor.getClass().getCreatureStats(actor).setAttackingOrSpell(mStrike); - float tReaction = 0.25f; - if(mTimerReact < tReaction) + mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1],pos.pos[2]); + + float zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]); + + // TODO: use movement settings instead of rotating directly + MWBase::Environment::get().getWorld()->rotateObject(actor, 0, 0, zAngle, false); + MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1; + + + float range = 100; + MWWorld::Class::get(actor).getCreatureStats(actor).setAttackingOrSpell(false); + if((dest.mX - start.mX)*(dest.mX - start.mX)+(dest.mY - start.mY)*(dest.mY - start.mY)+(dest.mZ - start.mZ)*(dest.mZ - start.mZ) + < range*range) { - mTimerReact += duration; - return false; - } + float directionX = dest.mX - start.mX; + float directionY = dest.mY - start.mY; + float directionResult = sqrt(directionX * directionX + directionY * directionY); - //Update with period = tReaction + zAngle = Ogre::Radian( Ogre::Math::ACos(directionY / directionResult) * sgn(Ogre::Math::ASin(directionX / directionResult)) ).valueDegrees(); + // TODO: use movement settings instead of rotating directly + MWBase::Environment::get().getWorld()->rotateObject(actor, 0, 0, zAngle, false); - mTimerReact = 0; + mPathFinder.clearPath(); - //actual attacking logic - //TODO: Some skills affect period of strikes.For berserk-like style period ~ 0.25f - float attackPeriod = 1.0f; - if(mReadyToAttack) - { - if(mTimerAttack <= -attackPeriod) + if(mTimer == 0) + { + MWWorld::Class::get(actor).getCreatureStats(actor).setAttackingOrSpell(false); + //mTimer = mTimer + duration; + } + if( mTimer > 1) { - //TODO: should depend on time between 'start' to 'min attack' - //for better controlling of NPCs' attack strength. - //Also it seems that this time is different for slash/thrust/chop - mTimerAttack = 0.35f * static_cast(rand())/RAND_MAX; - mStrike = true; - - //say a provoking combat phrase if (actor.getClass().isNpc()) { const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); @@ -109,242 +133,21 @@ namespace MWMechanics MWBase::Environment::get().getDialogueManager()->say(actor, "attack"); } } - } - else if (mTimerAttack <= 0) - mStrike = false; - } - else - { - mTimerAttack = -attackPeriod; - mStrike = false; - } - - const MWWorld::Class &cls = actor.getClass(); - const ESM::Weapon *weapon = NULL; - MWMechanics::WeaponType weaptype; - float weapRange, weapSpeed = 1.0f; - actor.getClass().getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, true); - - if(actor.getClass().hasInventoryStore(actor)) - { - MWMechanics::DrawState_ state = actor.getClass().getCreatureStats(actor).getDrawState(); - if (state == MWMechanics::DrawState_Spell || state == MWMechanics::DrawState_Nothing) - actor.getClass().getCreatureStats(actor).setDrawState(MWMechanics::DrawState_Weapon); - - //Get weapon speed and range - MWWorld::ContainerStoreIterator weaponSlot = - MWMechanics::getActiveWeapon(cls.getCreatureStats(actor), cls.getInventoryStore(actor), &weaptype); - if (weaptype == WeapType_HandToHand) - { - const MWWorld::Store &gmst = - MWBase::Environment::get().getWorld()->getStore().get(); - weapRange = gmst.find("fHandToHandReach")->getFloat(); + MWWorld::Class::get(actor).getCreatureStats(actor).setAttackingOrSpell(true); + mTimer = 0; } else { - weapon = weaponSlot->get()->mBase; - weapRange = weapon->mData.mReach; - weapSpeed = weapon->mData.mSpeed; + mTimer = mTimer + duration; } - weapRange *= 100.0f; + + MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; + //MWWorld::Class::get(actor).getCreatureStats(actor).setAttackingOrSpell(!MWWorld::Class::get(actor).getCreatureStats(actor).getAttackingOrSpell()); } - else //is creature - { - weaptype = WeapType_HandToHand; //doesn't matter, should only reflect if it is melee or distant weapon - weapRange = 150; //TODO: use true attack range (the same problem in Creature::hit) - } - - //MWWorld::Class::get(actor).getCreatureStats(actor).setAttackingOrSpell(false); - - ESM::Position pos = actor.getRefData().getPosition(); - - float zAngle; - - float rangeMelee; - float rangeCloseUp; - bool distantCombat = false; - if (weaptype==WeapType_BowAndArrow || weaptype==WeapType_Crossbow || weaptype==WeapType_ThowWeapon) // || WeapType_Spell_OnTarget - { - rangeMelee = 1000; // TODO: should depend on archer skill - rangeCloseUp = 0; //doesn't needed when attacking from distance - distantCombat = true; - } - else - { - rangeMelee = weapRange; - rangeCloseUp = 300; - } - - Ogre::Vector3 vStart(pos.pos[0], pos.pos[1], pos.pos[2]); - ESM::Position targetPos = mTarget.getRefData().getPosition(); - Ogre::Vector3 vDest(targetPos.pos[0], targetPos.pos[1], targetPos.pos[2]); - Ogre::Vector3 vDir = vDest - vStart; - float distBetween = vDir.length(); - - if(distBetween < rangeMelee || (distBetween <= rangeCloseUp && mCloseUp) ) - { - //Melee and Close-up combat - vDir.z = 0; - float dirLen = vDir.length(); - zAngle = Ogre::Radian( Ogre::Math::ACos(vDir.y / dirLen) * sgn(Ogre::Math::ASin(vDir.x / dirLen)) ).valueDegrees(); - - // TODO: use movement settings instead of rotating directly - MWBase::Environment::get().getWorld()->rotateObject(actor, 0, 0, zAngle, false); - - if(mPathFinder.isPathConstructed()) - mPathFinder.clearPath(); - - //MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; - - //bool LOS = MWBase::Environment::get().getWorld()->getLOS(actor, mTarget); - if (mCloseUp && distBetween > rangeMelee) - { - //Close-up combat: just run up on target - mMovement.mPosition[1] = 1; - } - else - { - //Melee: stop running and attack - mMovement.mPosition[1] = 0; - chooseBestAttack(weapon, mMovement); - - if(mMovement.mPosition[0] != 0 || mMovement.mPosition[1]) - { - mTimerCombatMove = 0.1f + 0.1f * static_cast(rand())/RAND_MAX; - mCombatMove = true; - } - else if(!distantCombat || (distantCombat && rangeMelee/5)) - { - //apply sideway movement (kind of dodging) with some probability - if(static_cast(rand())/RAND_MAX < 0.25) - { - mMovement.mPosition[0] = static_cast(rand())/RAND_MAX < 0.5? 1: -1; - mTimerCombatMove = 0.05f + 0.15f * static_cast(rand())/RAND_MAX; - mCombatMove = true; - } - } - - if(distantCombat && distBetween < rangeMelee/4) - { - mMovement.mPosition[1] = -1; - } - - mReadyToAttack = true; - //only once got in melee combat, actor is allowed to use close-up shortcutting - mCloseUp = true; - } - } - else - { - //target is at far distance: build & follow the path - mCloseUp = false; - - buildNewPath(actor); - - //delete visited path node - mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1],pos.pos[2]); - - zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]); - - // TODO: use movement settings instead of rotating directly - MWBase::Environment::get().getWorld()->rotateObject(actor, 0, 0, zAngle, false); - //MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1; - mMovement.mPosition[1] = 1; - mReadyToAttack = false; - } - - if(distBetween > rangeMelee) - { - //special run attack; it shouldn't affect melee combat tactics - if(actor.getClass().getMovementSettings(actor).mPosition[1] == 1) - { - //check if actor can overcome the distance = distToTarget - attackerWeapRange - //less than in time of playing weapon anim from 'start' to 'hit' tags (t_swing) - //then start attacking - float speed1 = cls.getSpeed(actor); - float speed2 = mTarget.getClass().getSpeed(mTarget); - if(mTarget.getClass().getMovementSettings(mTarget).mPosition[0] == 0 - && mTarget.getClass().getMovementSettings(mTarget).mPosition[1] == 0) - speed2 = 0; - - float s1 = distBetween - weapRange; - float t = s1/speed1; - float s2 = speed2 * t; - float t_swing = 0.17f/weapSpeed;//0.17 should be the time of playing weapon anim from 'start' to 'hit' tags - if (t + s2/speed1 <= t_swing) - { - mReadyToAttack = true; - if(mTimerAttack <= -attackPeriod) - { - mTimerAttack = 0.3f*static_cast(rand())/RAND_MAX; - mStrike = true; - } - } - } - } - return false; } - void AiCombat::buildNewPath(const MWWorld::Ptr& actor) - { - //Construct path to target - ESM::Pathgrid::Point dest; - dest.mX = mTarget.getRefData().getPosition().pos[0]; - dest.mY = mTarget.getRefData().getPosition().pos[1]; - dest.mZ = mTarget.getRefData().getPosition().pos[2]; - Ogre::Vector3 newPathTarget = Ogre::Vector3(dest.mX, dest.mY, dest.mZ); - - ESM::Pathgrid::Point lastPt = mPathFinder.getPath().back(); - Ogre::Vector3 currPathTarget(lastPt.mX, lastPt.mY, lastPt.mZ); - float dist = Ogre::Math::Abs((newPathTarget - currPathTarget).length()); - - float targetPosThreshold; - bool isOutside = actor.getCell()->mCell->isExterior(); - if (isOutside) - targetPosThreshold = 300; - else - targetPosThreshold = 100; - - if(dist > targetPosThreshold) - { - //construct new path only if target has moved away more than on - ESM::Position pos = actor.getRefData().getPosition(); - - ESM::Pathgrid::Point start; - start.mX = pos.pos[0]; - start.mY = pos.pos[1]; - start.mZ = pos.pos[2]; - - const ESM::Pathgrid *pathgrid = - MWBase::Environment::get().getWorld()->getStore().get().search(*actor.getCell()->mCell); - - float xCell = 0; - float yCell = 0; - - if (actor.getCell()->mCell->isExterior()) - { - xCell = actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE; - yCell = actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE; - } - - if(!mPathFinder.isPathConstructed()) - mPathFinder.buildPath(start, dest, pathgrid, xCell, yCell, isOutside); - else - { - PathFinder newPathFinder; - newPathFinder.buildPath(start, dest, pathgrid, xCell, yCell, isOutside); - - //TO EXPLORE: - //maybe here is a mistake (?): PathFinder::getPathSize() returns number of grid points in the path, - //not the actual path length. Here we should know if the new path is actually more effective. - //if(pathFinder2.getPathSize() < mPathFinder.getPathSize()) - mPathFinder = newPathFinder; - } - } - } - int AiCombat::getTypeId() const { return TypeIdCombat; @@ -355,64 +158,15 @@ namespace MWMechanics return 1; } - MWWorld::Ptr AiCombat::getTarget() const + const std::string &AiCombat::getTargetId() const { - return mTarget; + return mTargetId; } + AiCombat *MWMechanics::AiCombat::clone() const { return new AiCombat(*this); } } -namespace -{ -void determineAttackType(const MWWorld::Ptr& actor, MWMechanics::Movement &movement) -{ - if (movement.mPosition[0] && !movement.mPosition[1]) //sideway - actor.getClass().getCreatureStats(actor).setAttackType(MWMechanics::CreatureStats::AT_Slash); - else if (movement.mPosition[1]) //forward - actor.getClass().getCreatureStats(actor).setAttackType(MWMechanics::CreatureStats::AT_Thrust); - else - actor.getClass().getCreatureStats(actor).setAttackType(MWMechanics::CreatureStats::AT_Chop); -} - -void chooseBestAttack(const ESM::Weapon* weapon, MWMechanics::Movement &movement) -{ - //the more damage attackType deals the more probability it has - - if (weapon == NULL) - { - //hand-to-hand and creatures' attacks handled here - //hand-to-hand deals equal damage - float roll = static_cast(rand())/RAND_MAX; - if(roll <= 0.333f) //side punch - { - movement.mPosition[0] = (static_cast(rand())/RAND_MAX < 0.5f)? 1: -1; - movement.mPosition[1] = 0; - } - else if(roll <= 0.666f) //forward punch - movement.mPosition[1] = 1; - - return; - } - - int slash = (weapon->mData.mSlash[0] + weapon->mData.mSlash[1])/2; - int chop = (weapon->mData.mChop[0] + weapon->mData.mChop[1])/2; - int thrust = (weapon->mData.mThrust[0] + weapon->mData.mThrust[1])/2; - - float total = slash + chop + thrust; - - float roll = static_cast(rand())/RAND_MAX; - if(roll <= static_cast(slash)/total) - { - movement.mPosition[0] = (static_cast(rand())/RAND_MAX < 0.5f)? 1: -1; - movement.mPosition[1] = 0; - } - else if(roll <= (static_cast(slash) + static_cast(thrust))/total) - movement.mPosition[1] = 1; - //else chop -} - -} diff --git a/apps/openmw/mwmechanics/aicombat.hpp b/apps/openmw/mwmechanics/aicombat.hpp index ab9b9a8214..82efc043b9 100644 --- a/apps/openmw/mwmechanics/aicombat.hpp +++ b/apps/openmw/mwmechanics/aicombat.hpp @@ -7,14 +7,12 @@ #include "movement.hpp" -#include "../mwbase/world.hpp" - namespace MWMechanics { class AiCombat : public AiPackage { public: - AiCombat(const MWWorld::Ptr& actor); + AiCombat(const std::string &targetId); virtual AiCombat *clone() const; @@ -25,25 +23,15 @@ namespace MWMechanics virtual unsigned int getPriority() const; - MWWorld::Ptr getTarget() const; + const std::string &getTargetId() const; private: + std::string mTargetId; + PathFinder mPathFinder; - //controls duration of the actual strike - float mTimerAttack; - float mTimerReact; - //controls duration of the sideway & forward moves - //when mCombatMove is true - float mTimerCombatMove; - - bool mReadyToAttack, mStrike; - bool mCloseUp; - bool mCombatMove; - - MWMechanics::Movement mMovement; - MWWorld::Ptr mTarget; - - void buildNewPath(const MWWorld::Ptr& actor); + PathFinder mPathFinder2; + float mTimer; + float mTimer2; }; } diff --git a/apps/openmw/mwmechanics/aisequence.cpp b/apps/openmw/mwmechanics/aisequence.cpp index 3902b91866..73caa6ca76 100644 --- a/apps/openmw/mwmechanics/aisequence.cpp +++ b/apps/openmw/mwmechanics/aisequence.cpp @@ -55,12 +55,13 @@ int MWMechanics::AiSequence::getTypeId() const return mPackages.front()->getTypeId(); } -MWWorld::Ptr MWMechanics::AiSequence::getCombatTarget() const +bool MWMechanics::AiSequence::getCombatTarget(std::string &targetActorId) const { if (getTypeId() != AiPackage::TypeIdCombat) - return MWWorld::Ptr(); + return false; const AiCombat *combat = static_cast(mPackages.front()); - return combat->getTarget(); + targetActorId = combat->getTargetId(); + return true; } void MWMechanics::AiSequence::stopCombat() diff --git a/apps/openmw/mwmechanics/aisequence.hpp b/apps/openmw/mwmechanics/aisequence.hpp index 075c43ff71..d65c316160 100644 --- a/apps/openmw/mwmechanics/aisequence.hpp +++ b/apps/openmw/mwmechanics/aisequence.hpp @@ -36,8 +36,9 @@ namespace MWMechanics int getTypeId() const; ///< @see enum AiPackage::TypeId - MWWorld::Ptr getCombatTarget () const; - ///< Return the combat target if a combat package is active, or an empty Ptr otherwise + bool getCombatTarget (std::string &targetActorId) const; + ///< Return true and assign target if combat package is currently + /// active, return false otherwise void stopCombat(); ///< Removes all combat packages until first non-combat or stack empty. diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 2f5b0ca6c4..64df7becce 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -310,7 +310,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat } -void getWeaponGroup(WeaponType weaptype, std::string &group) +void CharacterController::getWeaponGroup(WeaponType weaptype, std::string &group) { const WeaponInfo *info = std::find_if(sWeaponTypeList, sWeaponTypeListEnd, FindWeaponType(weaptype)); if(info != sWeaponTypeListEnd) @@ -318,7 +318,7 @@ void getWeaponGroup(WeaponType weaptype, std::string &group) } -MWWorld::ContainerStoreIterator getActiveWeapon(CreatureStats &stats, MWWorld::InventoryStore &inv, WeaponType *weaptype) +MWWorld::ContainerStoreIterator CharacterController::getActiveWeapon(CreatureStats &stats, MWWorld::InventoryStore &inv, WeaponType *weaptype) { if(stats.getDrawState() == DrawState_Spell) { diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 915de93eba..112ea18ceb 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -169,6 +169,12 @@ class CharacterController void refreshCurrentAnims(CharacterState idle, CharacterState movement, bool force=false); + static void getWeaponGroup(WeaponType weaptype, std::string &group); + + static MWWorld::ContainerStoreIterator getActiveWeapon(CreatureStats &stats, + MWWorld::InventoryStore &inv, + WeaponType *weaptype); + void clearAnimQueue(); bool updateWeaponState(bool inwater, bool isrunning); @@ -205,10 +211,6 @@ public: void forceStateUpdate(); }; - void getWeaponGroup(WeaponType weaptype, std::string &group); - MWWorld::ContainerStoreIterator getActiveWeapon(CreatureStats &stats, - MWWorld::InventoryStore &inv, - WeaponType *weaptype); } #endif /* GAME_MWMECHANICS_CHARACTER_HPP */ diff --git a/apps/openmw/mwmechanics/creaturestats.cpp b/apps/openmw/mwmechanics/creaturestats.cpp index ec300f6f0e..c6522f08fe 100644 --- a/apps/openmw/mwmechanics/creaturestats.cpp +++ b/apps/openmw/mwmechanics/creaturestats.cpp @@ -348,9 +348,14 @@ namespace MWMechanics bool CreatureStats::getCreatureTargetted() const { - if (mAiSequence.getCombatTarget().isEmpty()) - return false; - return mAiSequence.getCombatTarget().getTypeName() == typeid(ESM::Creature).name(); + std::string target; + if (mAiSequence.getCombatTarget(target)) + { + MWWorld::Ptr targetPtr; + targetPtr = MWBase::Environment::get().getWorld()->getPtr(target, true); + return targetPtr.getTypeName() == typeid(ESM::Creature).name(); + } + return false; } float CreatureStats::getEvasion() const diff --git a/apps/openmw/mwscript/aiextensions.cpp b/apps/openmw/mwscript/aiextensions.cpp index 75c6351033..09b1ed4477 100644 --- a/apps/openmw/mwscript/aiextensions.cpp +++ b/apps/openmw/mwscript/aiextensions.cpp @@ -412,10 +412,16 @@ namespace MWScript std::string testedTargetId = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); - const MWMechanics::CreatureStats& creatureStats = actor.getClass().getCreatureStats(actor); + const MWMechanics::CreatureStats& creatureStats = MWWorld::Class::get(actor).getCreatureStats(actor); + std::string currentTargetId; - MWWorld::Ptr target = creatureStats.getAiSequence().getCombatTarget(); - runtime.push(Misc::StringUtils::ciEqual(target.getCellRef().mRefID, testedTargetId)); + bool targetsAreEqual = false; + if (creatureStats.getAiSequence().getCombatTarget (currentTargetId)) + { + if (currentTargetId == testedTargetId) + targetsAreEqual = true; + } + runtime.push(int(targetsAreEqual)); } }; @@ -426,14 +432,13 @@ namespace MWScript virtual void execute (Interpreter::Runtime &runtime) { MWWorld::Ptr actor = R()(runtime); - std::string targetID = runtime.getStringLiteral (runtime[0].mInteger); + std::string actorID = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); - MWMechanics::CreatureStats& creatureStats = actor.getClass().getCreatureStats(actor); - - creatureStats.setHostile(true); - creatureStats.getAiSequence().stack( - MWMechanics::AiCombat(MWBase::Environment::get().getWorld()->getPtr(targetID, true) )); + MWMechanics::CreatureStats& creatureStats = MWWorld::Class::get(actor).getCreatureStats(actor); + creatureStats.getAiSequence().stack(MWMechanics::AiCombat(actorID)); + if (actorID == "player") + creatureStats.setHostile(true); } };