初次提交
This commit is contained in:
@@ -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()
|
||||
Reference in New Issue
Block a user