AI Combat - Alert my friends!

Everything about development and the OpenMW source code.
User avatar
Jyby
Posts: 408
Joined: 10 Dec 2013, 04:16

AI Combat - Alert my friends!

Post by Jyby » 29 Mar 2014, 05:29

I starting to implement the feature where, if a player strikes an actor, friends of that actor will fight the player.
This feature can be found here: http://bugs.openmw.org/issues/1154

I will need to research if there are exceptions to the rule. e.g. in vanilla Morrowind will a Hlaalu member come to the rescue for a Camonna Tong?

I understand this part might require a bit of work. Therefor I suggest we implement with extendability in mind so that we avoid major refactoring down the road. We need to also discuss the best way to handle alerts to promote optimization.

Here is a simplistic run down of the implementation I am proposing:

aicombat.cpp :

Code: Select all

void notifyNeighbors(const MWWorld::Ptr& actor)
{
    // TODO: Check where player is.
    // If in interior <- not sure if we need to check
        // iterate over actors in interior cell (or in range/LOS/awareness)
            // If friend of targeted actor
                Set friend hostile and set their target to player, start pursue   
    // else if in exterior
        // iterate over actors in exterior cell (or in range/LOS/awareness)
            // If friend of targeted actor
                Set friend hostile and set their target to player, start pursue      
    // update mFirstAlert
}
AiCombat::execute

Code: Select all

if(mFirstAlert) 
{
    notifyNeighbors(actor);
}
The above code intends to take an actor who enters combat and alert the actors in range so they too fight the player. Analyze it further you will see that as execute is called for the duration of combat each actor involved will go through this notifying step. But if we use a bool to guard against always calling notifyNeighbors than we will have optimized this procedure.

Also note, notifications will be given to many actors during each execute call because of player movement and should only be sent to those in range of some scaled distance away from the player; we do not want to notify a guy two miles down the road.

A lot of research needs to be done if it has not yet been already.

Your input will speed up my implementation as I will have time this weekend away from my job.

On a personal note:
Thank you guys for your dedication, support, and welcoming to your team! :ugeek:

Jeffrey

EDIT: If the actor is a guard than they need to pursue the crime not enter battle. But this needs to be based on the bounty. A high enough bounty will make guards try to kill you in morrowind.

EDIT: How do I get an iterable list of NPCs from a cell?
Macbook Air 2013 - 1.7GHz Intel i7 - 8 GB - 512 GB SSD - Intel HD 5000
Windows 10 PC - 4GHz Intel i7 - 16 GB - 512 GB SSD - EVGA GTX 1060 SSC

User avatar
Zini
Posts: 5538
Joined: 06 Aug 2011, 15:16

Re: AI Combat - Alert my friends!

Post by Zini » 29 Mar 2014, 07:55

How do I get an iterable list of NPCs from a cell?
From the respective CellStore. Use the get<ESM::NPC>() function.

User avatar
Jyby
Posts: 408
Joined: 10 Dec 2013, 04:16

Re: AI Combat - Alert my friends!

Post by Jyby » 29 Mar 2014, 09:58

Code: Select all

        const MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
        MWWorld::CellStore* cell = player.getCell();

        // TODO: Check where player is.
        // If in interior <- not sure if we need to check
        if(!cell->isExterior())
        {
            // iterate over actors in interior cell (or in range/LOS/awareness)


            for(MWWorld::CellRefList<ESM::NPC>::List::const_iterator it (cell->get<ESM::NPC>().mList.begin()); 
                                                                    it != cell->get<ESM::NPC>().mList.end(); ++it) // list
            {
                MWWorld::Class* ptr = // get pointer of npc
                if(notAlerted( ptr )
                {
                    mFirstAlert = true;
                    
                    execute(ptr;
                }
                    //Set friend hostile and set their target to player, start pursue  
            }
        } 
        // else if in exterior
            // iterate over actors in exterior cell (or in range/LOS/awareness)
                // If friend of targeted actor
                    //Set friend hostile and set their target to player, start pursue      
        // update mFirstAlert
I'm having trouble figuring out how to get the NPC pointer from a reference list.

And can we be sure that reference list is the way to go? Will it account for the movement of npcs? Is it live?
Macbook Air 2013 - 1.7GHz Intel i7 - 8 GB - 512 GB SSD - Intel HD 5000
Windows 10 PC - 4GHz Intel i7 - 16 GB - 512 GB SSD - EVGA GTX 1060 SSC

User avatar
Zini
Posts: 5538
Joined: 06 Aug 2011, 15:16

Re: AI Combat - Alert my friends!

Post by Zini » 29 Mar 2014, 10:23

MWWorld::Ptr ptr (&*iter, cell);

The reference stays valid as long as the NPC does not change cells.

User avatar
Jyby
Posts: 408
Joined: 10 Dec 2013, 04:16

Re: AI Combat - Alert my friends!

Post by Jyby » 29 Mar 2014, 17:44

Does anyone know if we have anything implemented that allows an NPC to be told to attack?

setting hostility and alarm in creature stats does not work!


EDIT: Work in progress... It such a shame how messy aicombat and mechanics are. We should consider a modest and make an aialert.ialert.
Anyways: https://www.youtube.com/watch?v=w5z-p5sP_X8
Last edited by Jyby on 29 Mar 2014, 18:30, edited 2 times in total.
Macbook Air 2013 - 1.7GHz Intel i7 - 8 GB - 512 GB SSD - Intel HD 5000
Windows 10 PC - 4GHz Intel i7 - 16 GB - 512 GB SSD - EVGA GTX 1060 SSC

User avatar
gus
Posts: 390
Joined: 11 Aug 2011, 15:41

Re: AI Combat - Alert my friends!

Post by gus » 29 Mar 2014, 18:10

mwmechanics/actors.cpp line 213

good to see I'm not alone with AI :)

User avatar
Jyby
Posts: 408
Joined: 10 Dec 2013, 04:16

Re: AI Combat - Alert my friends!

Post by Jyby » 29 Mar 2014, 18:26

gus wrote:mwmechanics/actors.cpp line 213

good to see I'm not alone with AI :)
Thanks a bit to late though ;)
AI is so cool! I want to create an aialert package and put all of the crime and alarm details in there.
Want to work on it together and draw up a plan?? We should obviously wait for Zini's input...
Macbook Air 2013 - 1.7GHz Intel i7 - 8 GB - 512 GB SSD - Intel HD 5000
Windows 10 PC - 4GHz Intel i7 - 16 GB - 512 GB SSD - EVGA GTX 1060 SSC

User avatar
gus
Posts: 390
Joined: 11 Aug 2011, 15:41

Re: AI Combat - Alert my friends!

Post by gus » 29 Mar 2014, 18:39

not exactly sure of what you mean. Wanna come on IRC to discus further?

User avatar
Jyby
Posts: 408
Joined: 10 Dec 2013, 04:16

Re: AI Combat - Alert my friends!

Post by Jyby » 29 Mar 2014, 20:46

Macbook Air 2013 - 1.7GHz Intel i7 - 8 GB - 512 GB SSD - Intel HD 5000
Windows 10 PC - 4GHz Intel i7 - 16 GB - 512 GB SSD - EVGA GTX 1060 SSC

User avatar
scrawl
Posts: 2152
Joined: 18 Feb 2012, 11:51

Re: AI Combat - Alert my friends!

Post by scrawl » 29 Mar 2014, 21:32

First, this has nothing to do with combat. NPCs will also rush to help if you steal from someone, etc. The code you should be looking at is MechanicsManager::reportCrime. It is incomplete, because we don't have any research on how this notification feature works. As you already mentioned, faction probably plays a role. Each faction also has its opinion towards other factions. On UESP, they are called "friends and foes", in our code its called Faction reaction.

Code: Select all

    struct Reaction
    {
        std::string mFaction;
        int mReaction;
    };

    std::vector<Reaction> mReactions;
I am guessing whether or not one faction will help another depends on their opinion towards that faction.

fAlarmRadius probably has something to do with the distance over which NPC's calls for help can be heard. There is also an Alarm AI setting. Not sure what this one does. Maybe controls how likely someone is to respond to another NPCs call for help? There are also NPCs with an Alarm value of 0. From my findings, those NPCs should never report crimes, they just curse you but you don't get any bounty.
Also, there are GMSTs iAlarm<Crime> for each crime.

What causes an NPC to attack is increasing its Fight AI setting. There is a iFight<Crime> GMST for each crime. It's unclear if the NPCs Fight setting is increased every time you commit another crime, or added to the NPCs base fight setting (ie the one specified in the ESM).

Similarly, there are iDisp<Crime> GMSTs for disposition modifiers. I am guessing those should also be applied if the NPC did not report the crime (e.g. Alarm setting of 0)? And again, not sure if cumulative?

Completely unknown GMSTs (no clue):
iFightAlarmMult 1
fFightDispMult 0.2

Other things missing for Feature # Crime and Punishment:

Calming NPCs after paying the fine / going to jail

- Does it only calm NPCs in the active cells, or in the whole world?
- Does it only calm NPCs that reacted to the last crime committed, or all crimes ever committed?
- Does it calm NPCs who were already hostile to begin with? (probably not)
- Does it calm NPCs who went hostile for other reasons (e.g. taunt)?

Punishment in Census and Excise office (https://bugs.openmw.org/issues/1097)

In the tutorial, you are not supposed to get punished for crimes. This is not working properly, because the dialogue entry responsible for this uses the CreatureStats::isAlarmed function which currently always returns false. I suppose this needs to be set whenever an NPC notices a crime. But then when is it reset, and how (same questions apply as for Calming NPCs)?

Guards

This one is probably the simplest. When guards become notified of a crime they should run to the player and force dialogue, causing them to get arrested. What constitutes a guard is probably controlled by the Guard faction.

At a certain bounty level (iCrimeThreshold) guards always arrest on sight, and at another level (iCrimeThreshold * iCrimeThresholdMultiplier?) they attack on sight (after forcing dialogue and telling you you've earned the death penalty).
How do I get an iterable list of NPCs from a cell?
You don't need to. There is already a MWMechanics::Actors::getActorsInRange function available from within MechanicsManager.
Also note, notifications will be given to many actors during each execute call because of player movement
That is completely unnecessary. One notification will be enough. That spawns an AiCombat package to be executed each frame which will handle the rest (following the player, stopping if the player goes invisible [not implemented yet], etc)

Post Reply