Implement AI related magic effects (calm, frenzy, rally, demoralize, turn undead)

This commit is contained in:
scrawl 2014-01-05 01:34:35 +01:00
parent 634a53211c
commit 14b70a3ce6
10 changed files with 81 additions and 30 deletions

View file

@ -263,7 +263,7 @@ namespace
static const char *sCreatureTypes[] = static const char *sCreatureTypes[] =
{ {
"Creature", "Deadra", "Undead", "Humanoid", 0 "Creature", "Daedra", "Undead", "Humanoid", 0
}; };
static const char *sWeaponTypes[] = static const char *sWeaponTypes[] =
@ -342,4 +342,4 @@ std::vector<std::string> CSMWorld::Columns::getEnums (ColumnId column)
} }
return enums; return enums;
} }

View file

@ -84,10 +84,10 @@ namespace MWClass
data->mCreatureStats.getAiSequence().fill(ref->mBase->mAiPackage); data->mCreatureStats.getAiSequence().fill(ref->mBase->mAiPackage);
data->mCreatureStats.setAiSetting (0, ref->mBase->mAiData.mHello); data->mCreatureStats.setAiSetting (MWMechanics::CreatureStats::AI_Hello, ref->mBase->mAiData.mHello);
data->mCreatureStats.setAiSetting (1, ref->mBase->mAiData.mFight); data->mCreatureStats.setAiSetting (MWMechanics::CreatureStats::AI_Fight, ref->mBase->mAiData.mFight);
data->mCreatureStats.setAiSetting (2, ref->mBase->mAiData.mFlee); data->mCreatureStats.setAiSetting (MWMechanics::CreatureStats::AI_Flee, ref->mBase->mAiData.mFlee);
data->mCreatureStats.setAiSetting (3, ref->mBase->mAiData.mAlarm); data->mCreatureStats.setAiSetting (MWMechanics::CreatureStats::AI_Alarm, ref->mBase->mAiData.mAlarm);
// spells // spells
for (std::vector<std::string>::const_iterator iter (ref->mBase->mSpells.mList.begin()); for (std::vector<std::string>::const_iterator iter (ref->mBase->mSpells.mList.begin());

View file

@ -309,10 +309,10 @@ namespace MWClass
data->mNpcStats.getAiSequence().fill(ref->mBase->mAiPackage); data->mNpcStats.getAiSequence().fill(ref->mBase->mAiPackage);
data->mNpcStats.setAiSetting (0, ref->mBase->mAiData.mHello); data->mNpcStats.setAiSetting (MWMechanics::CreatureStats::AI_Hello, ref->mBase->mAiData.mHello);
data->mNpcStats.setAiSetting (1, ref->mBase->mAiData.mFight); data->mNpcStats.setAiSetting (MWMechanics::CreatureStats::AI_Fight, ref->mBase->mAiData.mFight);
data->mNpcStats.setAiSetting (2, ref->mBase->mAiData.mFlee); data->mNpcStats.setAiSetting (MWMechanics::CreatureStats::AI_Flee, ref->mBase->mAiData.mFlee);
data->mNpcStats.setAiSetting (3, ref->mBase->mAiData.mAlarm); data->mNpcStats.setAiSetting (MWMechanics::CreatureStats::AI_Alarm, ref->mBase->mAiData.mAlarm);
// spells // spells
for (std::vector<std::string>::const_iterator iter (ref->mBase->mSpells.mList.begin()); for (std::vector<std::string>::const_iterator iter (ref->mBase->mSpells.mList.begin());

View file

@ -279,7 +279,8 @@ int MWDialogue::Filter::getSelectStructInteger (const SelectWrapper& select) con
case SelectWrapper::Function_AiSetting: case SelectWrapper::Function_AiSetting:
return MWWorld::Class::get (mActor).getCreatureStats (mActor).getAiSetting (select.getArgument()); return MWWorld::Class::get (mActor).getCreatureStats (mActor).getAiSetting (
(MWMechanics::CreatureStats::AiSetting)select.getArgument()).getModified();
case SelectWrapper::Function_PcAttribute: case SelectWrapper::Function_PcAttribute:

View file

@ -172,7 +172,7 @@ namespace MWMechanics
float d = sqrt((actorpos.pos[0] - playerpos.pos[0])*(actorpos.pos[0] - playerpos.pos[0]) float d = sqrt((actorpos.pos[0] - playerpos.pos[0])*(actorpos.pos[0] - playerpos.pos[0])
+(actorpos.pos[1] - playerpos.pos[1])*(actorpos.pos[1] - playerpos.pos[1]) +(actorpos.pos[1] - playerpos.pos[1])*(actorpos.pos[1] - playerpos.pos[1])
+(actorpos.pos[2] - playerpos.pos[2])*(actorpos.pos[2] - playerpos.pos[2])); +(actorpos.pos[2] - playerpos.pos[2])*(actorpos.pos[2] - playerpos.pos[2]));
float fight = ptr.getClass().getCreatureStats(ptr).getAiSetting(1); float fight = ptr.getClass().getCreatureStats(ptr).getAiSetting(CreatureStats::AI_Fight).getModified();
float disp = 100; //creatures don't have disposition, so set it to 100 by default float disp = 100; //creatures don't have disposition, so set it to 100 by default
if(ptr.getTypeName() == typeid(ESM::NPC).name()) if(ptr.getTypeName() == typeid(ESM::NPC).name())
{ {
@ -341,6 +341,30 @@ namespace MWMechanics
creatureStats.setDynamic(i, stat); creatureStats.setDynamic(i, stat);
} }
// AI setting modifiers
int creature = !ptr.getClass().isNpc();
if (creature && ptr.get<ESM::Creature>()->mBase->mData.mType == ESM::Creature::Humanoid)
creature = false;
// Note: the Creature variants only work on normal creatures, not on daedra or undead creatures.
if (!creature || ptr.get<ESM::Creature>()->mBase->mData.mType == ESM::Creature::Creatures)
{
Stat<int> stat = creatureStats.getAiSetting(CreatureStats::AI_Fight);
stat.setModifier(creatureStats.getMagicEffects().get(ESM::MagicEffect::FrenzyHumanoid+creature).mMagnitude
- creatureStats.getMagicEffects().get(ESM::MagicEffect::CalmHumanoid+creature).mMagnitude);
creatureStats.setAiSetting(CreatureStats::AI_Fight, stat);
stat = creatureStats.getAiSetting(CreatureStats::AI_Flee);
stat.setModifier(creatureStats.getMagicEffects().get(ESM::MagicEffect::DemoralizeHumanoid+creature).mMagnitude
- creatureStats.getMagicEffects().get(ESM::MagicEffect::RallyHumanoid+creature).mMagnitude);
creatureStats.setAiSetting(CreatureStats::AI_Flee, stat);
}
if (creature && ptr.get<ESM::Creature>()->mBase->mData.mType == ESM::Creature::Undead)
{
Stat<int> stat = creatureStats.getAiSetting(CreatureStats::AI_Flee);
stat.setModifier(creatureStats.getMagicEffects().get(ESM::MagicEffect::TurnUndead).mMagnitude);
creatureStats.setAiSetting(CreatureStats::AI_Flee, stat);
}
// Apply disintegration (reduces item health) // Apply disintegration (reduces item health)
float disintegrateWeapon = effects.get(ESM::MagicEffect::DisintegrateWeapon).mMagnitude; float disintegrateWeapon = effects.get(ESM::MagicEffect::DisintegrateWeapon).mMagnitude;
if (disintegrateWeapon > 0) if (disintegrateWeapon > 0)

View file

@ -122,7 +122,7 @@ namespace MWMechanics
return mLevel; return mLevel;
} }
int CreatureStats::getAiSetting (int index) const Stat<int> CreatureStats::getAiSetting (AiSetting index) const
{ {
assert (index>=0 && index<4); assert (index>=0 && index<4);
return mAiSettings[index]; return mAiSettings[index];
@ -240,12 +240,18 @@ namespace MWMechanics
mAttackingOrSpell = attackingOrSpell; mAttackingOrSpell = attackingOrSpell;
} }
void CreatureStats::setAiSetting (int index, int value) void CreatureStats::setAiSetting (AiSetting index, Stat<int> value)
{ {
assert (index>=0 && index<4); assert (index>=0 && index<4);
mAiSettings[index] = value; mAiSettings[index] = value;
} }
void CreatureStats::setAiSetting (AiSetting index, int base)
{
Stat<int> stat(base);
setAiSetting(index, stat);
}
bool CreatureStats::isDead() const bool CreatureStats::isDead() const
{ {
return mDead; return mDead;

View file

@ -24,7 +24,7 @@ namespace MWMechanics
Spells mSpells; Spells mSpells;
ActiveSpells mActiveSpells; ActiveSpells mActiveSpells;
MagicEffects mMagicEffects; MagicEffects mMagicEffects;
int mAiSettings[4]; Stat<int> mAiSettings[4];
AiSequence mAiSequence; AiSequence mAiSequence;
float mLevelHealthBonus; float mLevelHealthBonus;
bool mDead; bool mDead;
@ -85,9 +85,6 @@ namespace MWMechanics
int getLevel() const; int getLevel() const;
int getAiSetting (int index) const;
///< 0: hello, 1 fight, 2 flee, 3 alarm
Spells & getSpells(); Spells & getSpells();
ActiveSpells & getActiveSpells(); ActiveSpells & getActiveSpells();
@ -125,8 +122,16 @@ namespace MWMechanics
void setLevel(int level); void setLevel(int level);
void setAiSetting (int index, int value); enum AiSetting
///< 0: hello, 1 fight, 2 flee, 3 alarm {
AI_Hello,
AI_Fight,
AI_Flee,
AI_Alarm
};
void setAiSetting (AiSetting index, Stat<int> value);
void setAiSetting (AiSetting index, int base);
Stat<int> getAiSetting (AiSetting index) const;
const AiSequence& getAiSequence() const; const AiSequence& getAiSequence() const;

View file

@ -605,8 +605,12 @@ namespace MWMechanics
{ {
float s = int(r * fPerDieRollMult * fPerTempMult); float s = int(r * fPerDieRollMult * fPerTempMult);
npcStats.setAiSetting (2, std::max(0, std::min(100, npcStats.getAiSetting (2) + int(std::max(iPerMinChange, s))))); int flee = npcStats.getAiSetting(MWMechanics::CreatureStats::AI_Flee).getBase();
npcStats.setAiSetting (1, std::max(0, std::min(100, npcStats.getAiSetting (1) + int(std::min(-iPerMinChange, -s))))); int fight = npcStats.getAiSetting(MWMechanics::CreatureStats::AI_Fight).getBase();
npcStats.setAiSetting (MWMechanics::CreatureStats::AI_Flee,
std::max(0, std::min(100, flee + int(std::max(iPerMinChange, s)))));
npcStats.setAiSetting (MWMechanics::CreatureStats::AI_Fight,
std::max(0, std::min(100, fight + int(std::min(-iPerMinChange, -s)))));
} }
float c = -std::abs(int(r * fPerDieRollMult)); float c = -std::abs(int(r * fPerDieRollMult));
@ -640,8 +644,12 @@ namespace MWMechanics
{ {
float s = c * fPerDieRollMult * fPerTempMult; float s = c * fPerDieRollMult * fPerTempMult;
npcStats.setAiSetting (2, std::max(0, std::min(100, npcStats.getAiSetting (2) + std::min(-int(iPerMinChange), int(-s))))); int flee = npcStats.getAiSetting (CreatureStats::AI_Flee).getBase();
npcStats.setAiSetting (1, std::max(0, std::min(100, npcStats.getAiSetting (1) + std::max(int(iPerMinChange), int(s))))); int fight = npcStats.getAiSetting (CreatureStats::AI_Fight).getBase();
npcStats.setAiSetting (CreatureStats::AI_Flee,
std::max(0, std::min(100, flee + std::min(-int(iPerMinChange), int(-s)))));
npcStats.setAiSetting (CreatureStats::AI_Fight,
std::max(0, std::min(100, fight + std::max(int(iPerMinChange), int(s)))));
} }
x = int(-c * fPerDieRollMult); x = int(-c * fPerDieRollMult);

View file

@ -225,7 +225,8 @@ namespace MWScript
{ {
MWWorld::Ptr ptr = R()(runtime); MWWorld::Ptr ptr = R()(runtime);
runtime.push(MWWorld::Class::get (ptr).getCreatureStats (ptr).getAiSetting (mIndex)); runtime.push(MWWorld::Class::get (ptr).getCreatureStats (ptr).getAiSetting (
(MWMechanics::CreatureStats::AiSetting)mIndex).getModified());
} }
}; };
template<class R> template<class R>
@ -241,8 +242,11 @@ namespace MWScript
Interpreter::Type_Integer value = runtime[0].mInteger; Interpreter::Type_Integer value = runtime[0].mInteger;
runtime.pop(); runtime.pop();
MWWorld::Class::get (ptr).getCreatureStats (ptr).setAiSetting (mIndex, MWMechanics::CreatureStats::AiSetting setting
MWWorld::Class::get (ptr).getCreatureStats (ptr).getAiSetting (mIndex) + value); = MWMechanics::CreatureStats::AiSetting(mIndex);
MWWorld::Class::get (ptr).getCreatureStats (ptr).setAiSetting (setting,
MWWorld::Class::get (ptr).getCreatureStats (ptr).getAiSetting (setting).getBase() + value);
} }
}; };
template<class R> template<class R>
@ -258,8 +262,11 @@ namespace MWScript
Interpreter::Type_Integer value = runtime[0].mInteger; Interpreter::Type_Integer value = runtime[0].mInteger;
runtime.pop(); runtime.pop();
MWWorld::Class::get (ptr).getCreatureStats (ptr).setAiSetting (mIndex, MWMechanics::CreatureStats::AiSetting setting = (MWMechanics::CreatureStats::AiSetting)mIndex;
value);
MWMechanics::Stat<int> stat = ptr.getClass().getCreatureStats(ptr).getAiSetting(setting);
stat.setModified(value, 0);
ptr.getClass().getCreatureStats(ptr).setAiSetting(setting, stat);
} }
}; };

View file

@ -40,7 +40,7 @@ struct Creature
enum Type enum Type
{ {
Creatures = 0, Creatures = 0,
Deadra = 1, Daedra = 1,
Undead = 2, Undead = 2,
Humanoid = 3 Humanoid = 3
}; };