mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-10-02 10:53:44 +00:00
The client's TacArcBehavior::Cast (0x00fb2d10) sorts the targets in the arc nearest first, or by weight when distance_weight or angle_weight is set (sortWithWeights, 0x00f58cd0: distance_weight * (max range - distance) / max range + angle_weight * (180 - angle) / 180, heaviest first). With use_attack_priority, SortByAttackPriority (0x00f72900) then buckets them by GetAttackPriority, lowest first, keeping that order inside each bucket; only the DestroyableComponent answers it, and an object without one counts as 1. DoHit keeps the first max targets. Nothing else ranks targets: enemies are taken over nearer smashables only because their attack_priority (1) is lower than most smashables' (10). use_attack_priority is off when a behavior does not set it (TacArcBehavior:: Initialize, 0x00f9b980), as before. The server sorted by distance only and ignored the flag, so a one-target swing hit the nearest crate instead of the enemy behind it. OrderTargets now does the client's ordering, with equal targets in ascending id order (the order the client's id set hands them over in); the chosen targets are still written in ascending id order (issue 1045). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
70 lines
2.6 KiB
C++
70 lines
2.6 KiB
C++
#pragma once
|
|
#include "Behavior.h"
|
|
#include "dCommonVars.h"
|
|
#include "NiPoint3.h"
|
|
#include <forward_list>
|
|
#include <set>
|
|
#include <vector>
|
|
|
|
class TacArcBehavior final : public Behavior {
|
|
public:
|
|
explicit TacArcBehavior(const uint32_t behavior_id) : Behavior(behavior_id) {}
|
|
void Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override;
|
|
void Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override;
|
|
void Load() override;
|
|
|
|
// use_attack_priority, off when the behavior does not set it
|
|
bool UsesAttackPriority() const { return m_useAttackPriority; }
|
|
|
|
// Reads the target count and ids the way the client writes them: at most maxTargets, returned ascending and
|
|
// without empty ids. False when the data is cut short or lists too many targets.
|
|
static bool ReadTargets(RakNet::BitStream& bitStream, uint32_t maxTargets, std::set<LWOOBJID>& targets);
|
|
|
|
// Writes the first maxTargets of ordered (see OrderTargets) as the client does and returns them in the order
|
|
// their action data follows (ascending id)
|
|
static std::set<LWOOBJID> WriteTargets(RakNet::BitStream& bitStream, const std::vector<LWOOBJID>& ordered, uint32_t maxTargets);
|
|
|
|
// A target in the arc and what the client orders it by
|
|
struct Candidate {
|
|
LWOOBJID id = LWOOBJID_EMPTY;
|
|
float distance = 0.0f;
|
|
float angle = 0.0f; // degrees from the caster's forward, 0 straight ahead
|
|
int32_t attackPriority = 1;
|
|
};
|
|
|
|
// Orders candidates the way the client does before it keeps the first max targets: nearest first, or highest
|
|
// weight first when distance_weight or angle_weight is set; then, with use_attack_priority, lower attack priority
|
|
// first, keeping that order within each priority. Equal candidates stay in ascending id order.
|
|
static std::vector<LWOOBJID> OrderTargets(std::vector<Candidate> candidates, float distanceWeight, float angleWeight, float maxRange, bool useAttackPriority);
|
|
private:
|
|
float m_maxRange;
|
|
float m_height;
|
|
float m_distanceWeight;
|
|
float m_angleWeight;
|
|
float m_angle;
|
|
float m_minRange;
|
|
NiPoint3 m_offset;
|
|
uint32_t m_method;
|
|
float m_upperBound;
|
|
float m_lowerBound;
|
|
bool m_usePickedTarget;
|
|
bool m_useTargetPostion;
|
|
bool m_checkEnv;
|
|
bool m_useAttackPriority;
|
|
Behavior* m_action;
|
|
Behavior* m_missAction;
|
|
Behavior* m_blockedAction;
|
|
uint32_t m_maxTargets;
|
|
float m_farHeight;
|
|
float m_farWidth;
|
|
float m_nearHeight;
|
|
float m_nearWidth;
|
|
|
|
std::forward_list<int32_t> m_ignoreFactionList {};
|
|
std::forward_list<int32_t> m_includeFactionList {};
|
|
bool m_targetSelf;
|
|
bool m_targetEnemy;
|
|
bool m_targetFriend;
|
|
bool m_targetTeam;
|
|
};
|