package main import rand "core:math/rand" import hm "core:container/handle_map" import rl "vendor:raylib" MAX_ATTACK_HITS :: 32 Attack :: struct { using base: BaseEntity, parent: Handle, dir: rl.Vector2, dmg: i32, crit: f32, radius: f32, arc: f32, lifetime: f32, color: rl.Color, hit: [MAX_ATTACK_HITS]Handle, hit_count: u8, } init_attack :: proc(state: ^GameState, a: Attack) -> Handle { return spawn(state, Entity{v = a}) } attack_update :: proc(state: ^GameState, a: ^Attack, h: Handle, dt: f32) { if a.parent != {} { if pe := get_entity(state, a.parent); pe != nil { a.pos = get_base(pe).pos } else { a.marked = true return } } it := hm.iterator_make(&state.entities) for e, eh in hm.iterate(&it) { #partial switch &v in e.v { case Enemy: if v.hp <= 0 || v.marked do continue if attack_has_hit(a, eh) do continue to := v.pos - a.pos dist := rl.Vector2Length(to) if dist > a.radius do continue // дуга: угол между dir и направлением на врага angle := rl.Vector2Angle(a.dir, rl.Vector2Normalize(to)) if angle > a.arc * 0.5 do continue dmg := a.dmg crit_hit := rand.float32() < a.crit if crit_hit do dmg *= 2 v.hp -= dmg attack_add_hit(a, eh) } } if a.lifetime > 0 { a.lifetime -= dt } else { a.marked = true } } attack_has_hit :: proc(a: ^Attack, h: Handle) -> bool { for i in 0 ..< a.hit_count { if a.hit[i] == h do return true } return false } attack_add_hit :: proc(a: ^Attack, h: Handle) { if a.hit_count >= MAX_ATTACK_HITS do return a.hit[a.hit_count] = h a.hit_count += 1 }