初次提交

This commit is contained in:
2026-07-20 10:56:52 +08:00
commit 7bcc0026e0
462 changed files with 50191 additions and 0 deletions
+122
View File
@@ -0,0 +1,122 @@
## StatusManager — 状态效果管理(Autoload: StatusManager
## 权威来源:combat_mechanics_depth.md §3.2.5、implementation_plan.md §2.4
extends Node
const STATUS_BATCH_LIMIT: int = 500
var _active_statuses: Array = [] # Array[StatusInstance]
var _physics_frame: int = 0
func _physics_process(delta: float) -> void:
_physics_frame += 1
var use_batch: bool = _active_statuses.size() > STATUS_BATCH_LIMIT
var batch_parity: int = _physics_frame % 2
var i: int = _active_statuses.size() - 1
while i >= 0:
var inst: StatusInstance = _active_statuses[i]
if use_batch and (inst.entity_id % 2) != batch_parity:
i -= 1
continue
inst.remaining_duration -= delta
inst.tick_accumulator += delta
if inst.type_def and not inst.type_def.is_combo_tracker and inst.type_def.dot_damage_per_tick > 0.0:
var interval: float = max(0.001, inst.type_def.tick_interval)
while inst.tick_accumulator >= interval:
inst.tick_accumulator -= interval
_apply_dot_tick(inst)
if inst.remaining_duration <= 0.0:
_active_statuses[i] = _active_statuses[_active_statuses.size() - 1]
_active_statuses.pop_back()
i -= 1
## 施加状态;duration < 0 时使用 StatusTypeDef 默认 duration
func apply(entity_id: int, status_type_id: int, stacks: int = 1, duration: float = -1.0, owner_id: int = -1) -> void:
var typedef: StatusTypeDef = StatusRegistry.get_type(status_type_id)
if typedef == null:
push_warning("StatusManager.apply: 未知 status_id=%d" % status_type_id)
return
var dur: float = typedef.duration if duration < 0.0 else duration
var existing_idx: int = _find(entity_id, status_type_id)
if existing_idx >= 0:
var inst: StatusInstance = _active_statuses[existing_idx]
match typedef.stack_mode:
StatusTypeDef.StackMode.REFRESH:
inst.remaining_duration = dur
inst.stacks = max(inst.stacks, stacks)
StatusTypeDef.StackMode.INTENSITY:
var cap: int = typedef.max_stacks if typedef.max_stacks > 0 else 9999
inst.stacks = min(inst.stacks + stacks, cap)
inst.remaining_duration = dur
StatusTypeDef.StackMode.INDEPENDENT:
pass # 独立实例:追加新条目
if typedef.stack_mode != StatusTypeDef.StackMode.INDEPENDENT:
EventBus.emit(EventID.STATUS_APPLIED, {
"target_id": entity_id, "status_type": status_type_id, "stacks": inst.stacks
})
return
var inst_new := StatusInstance.new()
inst_new.setup(entity_id, typedef, stacks, dur, owner_id)
_active_statuses.append(inst_new)
EventBus.emit(EventID.STATUS_APPLIED, {
"target_id": entity_id, "status_type": status_type_id, "stacks": inst_new.stacks
})
func get_stacks(entity_id: int, status_type_id: int) -> int:
var idx: int = _find(entity_id, status_type_id)
if idx < 0:
return 0
return _active_statuses[idx].stacks
func has_status(entity_id: int, status_type_id: int) -> bool:
return _find(entity_id, status_type_id) >= 0
func remove_all_for_entity(entity_id: int) -> void:
var i: int = _active_statuses.size() - 1
while i >= 0:
if _active_statuses[i].entity_id == entity_id:
_active_statuses[i] = _active_statuses[_active_statuses.size() - 1]
_active_statuses.pop_back()
i -= 1
func remove_source(owner_id: int) -> void:
var i: int = _active_statuses.size() - 1
while i >= 0:
if _active_statuses[i].owner_id == owner_id:
_active_statuses[i] = _active_statuses[_active_statuses.size() - 1]
_active_statuses.pop_back()
i -= 1
func get_active_count() -> int:
return _active_statuses.size()
func reset() -> void:
_active_statuses.clear()
_physics_frame = 0
func _find(entity_id: int, status_type_id: int) -> int:
for i in _active_statuses.size():
var inst: StatusInstance = _active_statuses[i]
if inst.entity_id == entity_id and inst.status_type_id == status_type_id:
return i
return -1
func _apply_dot_tick(inst: StatusInstance) -> void:
if not EnemyManager.has_entity(inst.entity_id):
return
var dmg: float = inst.type_def.dot_damage_per_tick * float(inst.stacks)
if dmg <= 0.0:
return
EnemyManager.apply_damage(inst.entity_id, dmg, inst.owner_id, false)
func _swap_and_pop(idx: int) -> void:
var last: int = _active_statuses.size() - 1
if idx != last:
_active_statuses[idx] = _active_statuses[last]
_active_statuses.pop_back()