Skip to content

Attitude Solvers

Attitude Solvers encapsulates the logic used to determine what's the attitude between Faction Members.

Similar to the Faction Database, it's not an object used directly but instead, it's used by the Subsystem to determine the Attitude between Factions.

Since projects can have many different requirements to perform such evaluation, this object is very easy to extend. The framework provides a some classes worth mentioning:

  • The NinjaFactionAttitudeSolver base class.
  • The FactionSolver_SimpleAttitudeCheck that simply determines attitude based on different factions and their configuration, both for the Default Attitudes and custom Attitudes provides via the Attitude Matrix.
  • The FactionSolver_TargetReputation that has a more elaborate strategy, based on an amount of reputation and multiple reputation tiers. We'll discuss this one in more detail in the Reputation section.

Faction Solver: Simple Attitude Check

The default Faction Solver will evaluate the Attitude based on a Source and Target Faction Data. Even though it's a very straightforward solver, it does a few different things with the Source and Target Faction Data.

Here's a diagram to represent its operation:

    flowchart TD
        A[Check Attitude] --> B{Is Same Faction?}
        B --> |Yes| C[Attitude Towards Same Faction]
        B --> |No| D{Has Custom Attitude?}
        C --> G[Attitude Solved]
        D --> |Yes| E[Specific Attitude for Target Faction]
        D --> |No| F[Default Attitude Towards Other Factions]
        E --> G[Attitude Solved]
        F --> G[Attitude Solved]

Create a new Faction Attitude Solver

The base NinjaFactionAttitudeSolver class will provide utility functions such as access to the Faction Database and helper methods to retrieve the Faction Member Component and Main Faction from a target.

You can implement your Database using Blueprints or C++. Here's an example that will create a chaotic agent, that will always return a random attitude.

Create Attitude Solvers Blueprints using the Context Menu

In your Content Browser, you can right-click within your target folder and under the "Factions" category, there's an option to create the Faction Attitude Solver Blueprint!

Custom Attitude Solver Example

#pragma once

#include "CoreMinimal.h"
#include "NinjaFactionAttitudeSolver.h"
#include "FactionSolver_CrazySolver.generated.h"

UCLASS(DisplayName = "Faction Database: Data Array")
class PLUGINLABS_API UFactionSolver_CrazySolver : public UNinjaFactionAttitudeSolver
{

    GENERATED_BODY()

public:

    // -- Begin Faction Attitude Solver implementation
    virtual ETeamAttitude::Type SolveAttitude_Implementation(const AActor* Source, const AActor* Target) const override;
    // -- End Faction Attitude Solver implementation

};
#include "FactionSolver_CrazySolver.h"

ETeamAttitude::Type UFactionSolver_CrazySolver::SolveAttitude_Implementation(const AActor* Source, const AActor* Target) const
{
    // Yikes! o.O
    return FMath::RandBool() ? ETeamAttitude::Friendly : ETeamAttitude::Hostile;
}

At this point, you would configure the new Attitude Solver Class in the Project Settings page. It's up to you to further experiment with that or continue using the default solver.

The SolveAttitude Function is the only one that you must implement. But depending on what you are trying to achieve, is worth knowing that there's a InitializeSolver that can be used, to perform startup tasks.

If you override the initialization, make sure to call the super/parent implementation!

Next Steps

Now that we covered the Faction Attitude Solver object, you can decide if you'd prefer to move onto the Faction Membership section and start configuring your Faction Members, or if you want to know more about Attitude Solving and check the Reputation Section.