diff --git a/src/pp/pp.c b/src/pp/pp.c index 93dbe434..42884441 100644 --- a/src/pp/pp.c +++ b/src/pp/pp.c @@ -1378,7 +1378,8 @@ P_Space P_SpaceFromWalls(Arena *arena, P_Frame *frame) { Vec2 p0 = VEC2(wall->start.x / P_TilesPerMeter - P_WorldPitch / 2, wall->start.y / P_TilesPerMeter - P_WorldPitch / 2); Vec2 p1 = VEC2(wall->end.x / P_TilesPerMeter - P_WorldPitch / 2, wall->end.y / P_TilesPerMeter - P_WorldPitch / 2); - P_Shape shape = P_ShapeFromDesc(.count = 2, .points = { p0, p1 }, .radius = 0.01 ); + // P_Shape shape = P_ShapeFromDesc(.count = 2, .points = { p0, p1 }, .radius = 0.01 ); + P_Shape shape = P_ShapeFromDesc(.count = 2, .points = { p0, p1 }, .radius = 0.0 ); Rng2 aabb = P_BoundingBoxFromShape(shape); aabb = AddRng2Vec2(aabb, VEC2(P_WorldPitch / 2.0, P_WorldPitch / 2.0)); aabb.p0 = FloorVec2(aabb.p0); @@ -1729,6 +1730,7 @@ void P_SpawnEntsFromList(P_Frame *frame, P_EntList ents) dst->next_in_bin = old_next_in_bin; dst->prev_in_bin = old_prev_in_bin; dst->created_at_ns = frame->time_ns; + dst->created_at_tick = frame->tick; ++frame->ents_count; } } @@ -2717,6 +2719,7 @@ void P_StepFrame(P_Frame *frame) Vec2 fire_pos = Zi; Vec2 fire_dir = Zi; + Vec2 fire_base = Zi; if (can_fire) { Vec2 look = firer->control.look; @@ -2764,6 +2767,13 @@ void P_StepFrame(P_Frame *frame) SPR_Ray fire_ray = wep.rays[SPR_RayKind_Ap]; fire_pos = MulAffineVec2(wep_pix_to_world_af, fire_ray.pos); fire_dir = NormRot(MulAffineBasisVec2(wep_pix_to_world_af, fire_ray.dir)); + + fire_base = MulVec2(PerpVec2(NegVec2(firer->xf.r)), WedgeVec2(firer->xf.r, SubVec2(firer->xf.t, fire_pos))); + fire_base = AddVec2(fire_base, firer->xf.t); + + P_DebugDrawLine(fire_base, fire_pos, Color_Yellow); + P_DebugDrawPoint(fire_base, Color_Yellow); + P_DebugDrawPoint(fire_pos, Color_Red); } // FIXME: Prevent obstructed weapons from firing through walls @@ -2795,6 +2805,7 @@ void P_StepFrame(P_Frame *frame) Vec2 dir = Vec2FromAngle(angle); + bullet->bullet_base = fire_base; bullet->bullet_start = fire_pos; bullet->bullet_end = AddVec2(bullet->bullet_start, MulVec2(dir, speed)); bullet->bullet_firer = firer->key; @@ -2817,60 +2828,93 @@ void P_StepFrame(P_Frame *frame) if (bullet->is_bullet) { bullet->has_hit = 0; - Vec2 ray_start = bullet->bullet_start; - Vec2 ray_end = bullet->bullet_end; - Vec2 ray_dir = SubVec2(ray_end, ray_start); + + Struct(BulletPath) + { + BulletPath *next; + Vec2 start; + Vec2 end; + }; + BulletPath *first_bullet_path = 0; + BulletPath *last_bullet_path = 0; + + if (bullet->created_at_tick == frame->tick) + { + // On bullet's first tick, we want to ensure that the firer/weapon + // wasn't obstructed (e.g. to prevent shooting through walls), so we + // insert a path from the bullet's base to its starting position before + // its actual firing path + BulletPath *path = PushStruct(scratch.arena, BulletPath); + SllQueuePush(first_bullet_path, last_bullet_path, path); + path->start = bullet->bullet_base; + path->end = bullet->bullet_start; + } + + { + BulletPath *path = PushStruct(scratch.arena, BulletPath); + SllQueuePush(first_bullet_path, last_bullet_path, path); + path->start = bullet->bullet_start; + path->end = bullet->bullet_end; + } P_DebugDrawLine(bullet->bullet_start, bullet->bullet_end, Color_Red); - P_Space *cast_spaces[] = { - &world->walls_space, - &post_solve_ents_space, - }; - - P_SpaceEntryList cast_entries = Zi; - P_UniqueSpaceEntriesFromRay( - scratch.arena, - &cast_entries, - countof(cast_spaces), - cast_spaces, - ray_start, - ray_end - ); - P_EntKey victim_key = Zi; P_RaycastResult victim_raycast = Zi; { - f32 closest_len_sq = Inf; - for (P_SpaceEntryNode *entry_node = cast_entries.first; entry_node; entry_node = entry_node->next) + for (BulletPath *path = first_bullet_path; path; path = path->next) { - P_SpaceEntry *entry = &entry_node->entry; - P_EntKey potential_victim_key = (P_EntKey) { .v = entry->shape_id }; - if (!P_MatchEntKey(potential_victim_key, bullet->bullet_firer)) + Vec2 path_dir = SubVec2(path->end, path->start); + P_Space *cast_spaces[] = { + &world->walls_space, + &post_solve_ents_space, + }; + P_SpaceEntryList cast_entries = Zi; + P_UniqueSpaceEntriesFromRay( + scratch.arena, + &cast_entries, + countof(cast_spaces), + cast_spaces, + path->start, + path->end + ); + f32 closest_len_sq = Inf; + for (P_SpaceEntryNode *entry_node = cast_entries.first; entry_node; entry_node = entry_node->next) { - P_Shape potential_victim_shape = entry->shape; - P_RaycastResult entrance_raycast = P_RaycastShape(potential_victim_shape, ray_start, ray_dir); - Vec2 entrance = entrance_raycast.p; - if (entrance_raycast.is_intersecting) + P_SpaceEntry *entry = &entry_node->entry; + P_EntKey potential_victim_key = (P_EntKey) { .v = entry->shape_id }; + if (!P_MatchEntKey(potential_victim_key, bullet->bullet_firer)) { - P_RaycastResult exit_raycast = P_RaycastShape(potential_victim_shape, ray_start, NegVec2(ray_dir)); - Vec2 exit = exit_raycast.p; - f32 da = DotVec2(ray_dir, SubVec2(entrance, ray_start)); - f32 db = DotVec2(ray_dir, SubVec2(exit, ray_start)); - if (db > 0 && (da <= Vec2LenSq(ray_dir) || da <= 0)) + P_Shape potential_victim_shape = entry->shape; + P_RaycastResult entrance_raycast = P_RaycastShape(potential_victim_shape, path->start, path_dir); + Vec2 entrance = entrance_raycast.p; + if (entrance_raycast.is_intersecting) { - f32 len_sq = Vec2LenSq(SubVec2(entrance_raycast.p, ray_start)); - if (len_sq < closest_len_sq) + P_RaycastResult exit_raycast = P_RaycastShape(potential_victim_shape, path->start, NegVec2(path_dir)); + Vec2 exit = exit_raycast.p; + f32 da = DotVec2(path_dir, SubVec2(entrance, path->start)); + f32 db = DotVec2(path_dir, SubVec2(exit, path->start)); + if (db > 0 && (da <= Vec2LenSq(path_dir) || da <= 0)) { - closest_len_sq = len_sq; - victim_key = potential_victim_key; - victim_raycast = entrance_raycast; + f32 len_sq = Vec2LenSq(SubVec2(entrance_raycast.p, path->start)); + if (len_sq < closest_len_sq) + { + closest_len_sq = len_sq; + victim_key = potential_victim_key; + victim_raycast = entrance_raycast; + } } } } } + if (!P_IsEntKeyNil(victim_key)) + { + // No need to check future paths if this path hit + break; + } } } + P_Ent *victim = P_EntFromKey(frame, victim_key); // TODO: Truncate bullet trail diff --git a/src/pp/pp.h b/src/pp/pp.h index b9da36e8..5a563ad4 100644 --- a/src/pp/pp.h +++ b/src/pp/pp.h @@ -110,6 +110,7 @@ Struct(P_Ent) P_EntKey key; u64 rand_seq; i64 created_at_ns; + i64 created_at_tick; //- Build data @@ -129,6 +130,7 @@ Struct(P_Ent) P_EntKey bullet_firer; b32 is_bullet; + Vec2 bullet_base; Vec2 bullet_start; Vec2 bullet_end;