载入中...
搜索中...
未找到
CombatLoop.cpp
浏览该文件的文档.
1#include "combat/CombatLoop.h"
2
5
6namespace eve::combat {
7namespace {
8
9bool invulnerable(const CombatActionWindowState* windows, const CombatCharacterRuntime* characters,
10 SubjectRef subject) {
11 if (windows && windows->isInvulnerable(subject)) return true;
12 if (!characters) return false;
13 auto state = characters->state(subject);
14 return state && state.value().invulnerable;
15}
16
17bool dodging(const CombatCharacterRuntime* characters, SubjectRef subject) {
18 if (!characters) return false;
19 auto state = characters->state(subject);
20 return state && state.value().mode == CombatCharacterMode::Dodging && state.value().invulnerable;
21}
22
23} // namespace
24
26 if (!characters_ || !melee_)
28 Diagnostic::error(DiagnosticCode::NotFound, "combat loop requires character and melee runtimes", "loop"));
29
30 CombatLoopFrame frame;
31 frame.tick = step.tick;
32
33 if (enemies_) {
34 for (const auto& state : characters_->states()) {
35 auto posed = enemies_->setPosition(state.subject, state.position.x, state.position.y, state.position.z);
36 if (!posed) return Result<CombatLoopFrame>::failure(posed.status());
37 }
38 auto steering = enemies_->nextSteering(step.tick);
39 if (!steering) return Result<CombatLoopFrame>::failure(steering.status());
40 frame.enemySteering = steering.value();
41 for (const auto& steer : frame.enemySteering) {
42 auto moved = characters_->setMoveIntent(steer.subject, steer.moveDirection, steer.speedFraction);
43 if (!moved) return Result<CombatLoopFrame>::failure(moved.status());
44 }
45 }
46
47 if (cancelResolver_ && cancelSubject_.isValid() && !cancelAbility_.format().empty()) {
49 request.subject = cancelSubject_;
50 request.currentAbility = cancelAbility_;
51 request.tick = step.tick;
52 auto resolved = cancelResolver_->resolve(request);
53 if (resolved)
54 frame.cancels.push_back(std::move(resolved).takeValue());
55 else if (resolved.status().code() != StatusCode::NotFound)
56 return Result<CombatLoopFrame>::failure(resolved.status());
57 }
58
59 if (feel_) {
60 for (const auto& state : characters_->states()) {
61 auto frozen = characters_->setTimeFrozen(state.subject, feel_->isFrozen(state.subject));
62 if (!frozen) return Result<CombatLoopFrame>::failure(frozen.status());
63 }
64 }
65
66 if (targets_) {
67 for (const auto& state : characters_->states()) {
68 if (state.mode != CombatCharacterMode::Attacking) continue;
69 if (feel_ && feel_->isFrozen(state.subject)) continue;
70 auto lock = targets_->state(state.subject);
71 if (!lock || !lock.value().target) continue;
72 auto target = characters_->state(*lock.value().target);
73 if (!target) continue;
75 warp.attacker = state.position;
76 warp.target = target.value().position;
77 warp.attackerFacing = state.facing;
78 warp.desiredDistance = 1.4;
79 warp.maxTranslation = 0.12;
80 warp.remainingBudget = 0.6;
81 auto solved = CombatMotionWarp::solve(warp);
82 if (!solved) {
83 if (solved.status().code() == StatusCode::Conflict) continue;
84 return Result<CombatLoopFrame>::failure(solved.status());
85 }
86 auto faced = characters_->setFacing(state.subject, solved.value().facing);
87 if (!faced) return Result<CombatLoopFrame>::failure(faced.status());
88 if (solved.value().translation.x != 0.0 || solved.value().translation.z != 0.0) {
89 auto applied = characters_->setRootMotionDelta(state.subject, solved.value().translation);
90 if (!applied) return Result<CombatLoopFrame>::failure(applied.status());
91 }
92 }
93 }
94
95 auto locomotion = characters_->advance(step);
96 if (!locomotion) return Result<CombatLoopFrame>::failure(locomotion.status());
97 frame.locomotion = std::move(locomotion).takeValue();
98
99 for (const auto& state : characters_->states()) {
100 auto posed = melee_->setHurtboxPose(state.subject, "torso",
101 {{state.position.x, state.position.y + 1.0, state.position.z}, 0.0});
102 if (!posed && posed.status().code() != StatusCode::NotFound)
103 return Result<CombatLoopFrame>::failure(posed.status());
104 (void)posed;
105 }
106
107 auto melee = melee_->advance(step.tick);
108 if (!melee) return Result<CombatLoopFrame>::failure(melee.status());
109 frame.melee = std::move(melee).takeValue();
110
111 if (states_) {
112 for (const auto& hit : frame.melee.hits) {
113 if (dodging(characters_, hit.target)) {
114 frame.perfectDodges.push_back({hit.target, hit.source, hit.hitboxId});
115 continue;
116 }
117 if (invulnerable(windows_, characters_, hit.target)) continue;
118 DamageRequest request;
119 request.source = hit.source;
120 request.target = hit.target;
121 request.actionExecution = hit.actionExecution;
122 request.damageType = hit.damageType;
123 request.healthDamage = hit.healthDamage;
124 request.poiseDamage = hit.poiseDamage;
125 request.knockback = hit.knockback;
126 if (guards_) {
127 auto guarded = guards_->mitigate(hit.target, request);
128 if (!guarded) return Result<CombatLoopFrame>::failure(guarded.status());
129 frame.guards.push_back(guarded.value());
130 if (guarded.value().result != GuardResult::None) continue;
131 }
132 const auto found = states_->find(hit.target.format());
133 if (found == states_->end())
135 Diagnostic::error(DiagnosticCode::NotFound, "loop damage target missing", hit.target.format()));
136 DamageRuntime damage;
137 auto outcome = damage.apply(found->second, request);
138 if (!outcome) return Result<CombatLoopFrame>::failure(outcome.status());
139 if (feel_) {
140 auto felt = feel_->applyFromOutcome(outcome.value());
141 if (!felt) return Result<CombatLoopFrame>::failure(felt.status());
142 }
143 auto reacted = characters_->applyDamageReaction(
144 hit.target, outcome.value().reaction,
145 feel_ ? feel_->state(hit.target).hitstunRemaining : Duration::zero(), outcome.value().knockback);
146 if (!reacted) return Result<CombatLoopFrame>::failure(reacted.status());
147 frame.outcomes.push_back(std::move(outcome).takeValue());
148 }
149 }
150
151 if (feel_) {
152 auto felt = feel_->advance(step);
153 if (!felt) return Result<CombatLoopFrame>::failure(felt.status());
154 }
155
156 if (cameraFocus_.isValid()) {
157 auto focus = characters_->state(cameraFocus_);
158 if (focus) {
159 CombatCameraFramingRequest framing;
160 framing.player = focus.value().position;
161 framing.playerFacing = focus.value().facing;
162 if (targets_) {
163 auto lock = targets_->state(cameraFocus_);
164 if (lock && lock.value().target) {
165 auto locked = characters_->state(*lock.value().target);
166 if (locked) framing.lockTarget = locked.value().position;
167 }
168 }
169 auto view = CombatCameraFraming::solve(framing);
170 if (!view) return Result<CombatLoopFrame>::failure(view.status());
171 frame.camera = view.value();
172 }
173 }
175}
176
177} // namespace eve::combat
LogicalId target
double value
bool locked
Combat-owned active hitbox and invulnerability projections.
int subject
Definition AnimSmr.cpp:163
One-frame composition of character, melee, guard, feel and camera.
Bounded attack translation/facing correction toward a lock target.
float warp
const GltfImportRequest & request
bool hit
glm::mat4 view
bool found
float step
Definition TreeMesh.cpp:314
static Diagnostic error(DiagnosticCode code, std::string message, std::string path={}, DiagnosticDetails details={}, std::string source={})
Construct an error diagnostic with the standard error severity.
Definition Diagnostic.h:125
const std::string & format() const noexcept
Returns the canonical namespace:name representation.
Definition Identity.h:436
Move-only operation result carrying either a value or Status.
Definition Result.h:155
static Result success(T value)
Construct a successful result owning value.
Definition Result.h:164
static Result failure(Status status)
Construct a failed result from a structured status.
Definition Result.h:175
static Status success(StatusCode code=StatusCode::Ok)
Construct a successful status with an explicit non-error outcome.
Definition Status.h:81
bool isValid() const noexcept
Return whether this reference is valid and non-nil.
Definition SubjectRef.h:38
Result< CombatCancelResolution > resolve(const CombatCancelResolveRequest &request)
Expire the buffer, consume the best allowed input, and optionally match the combo graph.
Result< void > setFacing(SubjectRef subject, CombatVector3 facing)
Replace planar facing from a finite XZ vector; Y is ignored.
Result< void > setTimeFrozen(SubjectRef subject, bool frozen)
Pause integration for hitstop while retaining the committed pose.
Result< void > setRootMotionDelta(SubjectRef subject, CombatVector3 delta)
Queue one frame of authored root-motion delta consumed by the next advance.
Result< CombatCharacterAdvance > advance(const SimulationStep &step)
Atomically advance every character using only the supplied deterministic step.
std::vector< CombatCharacterState > states() const
Return owning states in stable subject-id order.
Result< CombatCharacterState > state(SubjectRef subject) const
Return an owning state snapshot, or NotFound for a stale subject.
Result< void > setMoveIntent(SubjectRef subject, CombatVector3 direction, double speedFraction)
Set normalized planar movement intent.
Result< std::vector< CombatEnemySteering > > nextSteering(SimulationTick tick) const
Emit approach steering for Mid/Far enemies that are Idle (not punishing).
Result< void > setPosition(SubjectRef subject, double x, double y, double z)
Provide world positions for band checks (enemies and their targets).
Result< CombatLoopFrame > advance(const SimulationStep &step)
Advance every wired runtime with the supplied deterministic step.
static Result< CombatWarpResult > solve(const CombatWarpRequest &request)
Solve one warp step from owning request data.
Result< CombatLockState > state(SubjectRef owner) const
Return owning lock state or NotFound.
bool isFrozen(SubjectRef subject) const noexcept
Whether the subject currently has positive hitstop remaining.
Definition HitFeel.cpp:121
Result< void > setHurtboxPose(SubjectRef subject, std::string_view hurtboxId, MeleePose pose)
Update the current world pose of one registered hurtbox.
Definition MeleeHit.cpp:203
One deterministic fixed-step emitted by SimulationClock.
Definition Time.h:158
Inputs for one deterministic cancel/combo resolution.
Owning audit of one composed combat frame.
Definition CombatLoop.h:33
std::vector< CombatEnemySteering > enemySteering
Definition CombatLoop.h:41
CombatCharacterAdvance locomotion
Definition CombatLoop.h:35
std::vector< CombatCancelResolution > cancels
Definition CombatLoop.h:40
Input for one deterministic motion-warp solve.