From 4b207e81feeecc51dd6d5ed50c792cb039d21d77 Mon Sep 17 00:00:00 2001 From: jacob Date: Wed, 11 Feb 2026 22:17:09 -0600 Subject: [PATCH] unique weapon properties --- src/base/base_math.c | 14 + src/base/base_math.h | 5 + src/pp/pp.c | 262 +++++++++++++----- src/pp/pp.h | 29 +- src/pp/pp_res/guy/guy.ase | 3 + src/pp/pp_res/{sprite => }/palette.ase | 0 src/pp/pp_res/sprite/bla.ase | 3 - src/pp/pp_res/sprite/bla2.ase | 3 - src/pp/pp_res/sprite/bla3.ase | 3 - src/pp/pp_res/wep/launcher.ase | 3 + .../pp_res/{sprite/raah.ase => wep/uzi.ase} | 0 src/pp/pp_sim/pp_sim_core.c | 3 +- src/pp/pp_transcode.c | 14 +- src/pp/pp_vis/pp_vis_core.c | 14 +- 14 files changed, 256 insertions(+), 100 deletions(-) create mode 100644 src/pp/pp_res/guy/guy.ase rename src/pp/pp_res/{sprite => }/palette.ase (100%) delete mode 100644 src/pp/pp_res/sprite/bla.ase delete mode 100644 src/pp/pp_res/sprite/bla2.ase delete mode 100644 src/pp/pp_res/sprite/bla3.ase create mode 100644 src/pp/pp_res/wep/launcher.ase rename src/pp/pp_res/{sprite/raah.ase => wep/uzi.ase} (100%) diff --git a/src/base/base_math.c b/src/base/base_math.c index cd030b94..5c1bcfaf 100644 --- a/src/base/base_math.c +++ b/src/base/base_math.c @@ -1157,6 +1157,20 @@ Vec2 NormRot(Vec2 r) return r; } +//////////////////////////////////////////////////////////// +//~ Line + +Vec2 IntersectLines(Vec2 a0, Vec2 b0, Vec2 a1, Vec2 b1) +{ + Vec2 vab0 = SubVec2(b0, a0); + Vec2 vab1 = SubVec2(b1, a1); + Vec2 va0a1 = SubVec2(a1, a0); + f32 denom = WedgeVec2(vab0, vab1); + f32 t0 = WedgeVec2(va0a1, vab1) / denom; + Vec2 result = AddVec2(a0, MulVec2(vab0, t0)); + return result; +} + //////////////////////////////////////////////////////////// //~ Spring diff --git a/src/base/base_math.h b/src/base/base_math.h index 692ba4fa..e1fac023 100644 --- a/src/base/base_math.h +++ b/src/base/base_math.h @@ -521,6 +521,11 @@ Vec2 MulXformVec2(Xform xf, Vec2 v); Xform NormXform(Xform xf); Vec2 NormRot(Vec2 r); +//////////////////////////////////////////////////////////// +//~ Line + +Vec2 IntersectLines(Vec2 a0, Vec2 b0, Vec2 a1, Vec2 b1); + //////////////////////////////////////////////////////////// //~ Spring diff --git a/src/pp/pp.c b/src/pp/pp.c index c0a1b36d..5bdeb0c8 100644 --- a/src/pp/pp.c +++ b/src/pp/pp.c @@ -244,29 +244,42 @@ P_Shape P_WorldShapeFromEnt(P_Ent *ent) //////////////////////////////////////////////////////////// //~ Animation helpers -P_Anim P_AnimFromEnt(P_Ent *ent, i64 time_ns) +P_Anim P_AnimFromEnt(P_Frame *frame, P_Ent *ent) { P_Anim result = Zi; + P_Ent *wep = P_EntFromKey(frame, ent->weapon); // TODO: Determine animation dynamically i64 animation_rate_ns = NsFromSeconds(0.100); { - i64 walk_duration_ns = time_ns; + i64 walk_duration_ns = frame->time_ns; result.frame_seq = walk_duration_ns / animation_rate_ns; + // result.span = SPR_SpanKeyFromName(Lit("test")); result.span = SPR_SpanKeyFromName(Lit("walk")); } // TODO: Use prefab lookup + if (ent->is_guy) { - result.sheet = SPR_SheetKeyFromResource(ResourceKeyFromStore(&P_Resources, Lit("sprite/bla3.ase"))); - result.wep_sheet = SPR_SheetKeyFromResource(ResourceKeyFromStore(&P_Resources, Lit("sprite/raah.ase"))); + result.sheet = SPR_SheetKeyFromResource(ResourceKeyFromStore(&P_Resources, Lit("guy/guy.ase"))); } - else if (ent->is_guy_spawn) + + if (ent->is_guy_spawn) { result.sheet = SPR_SheetKeyFromResource(ResourceKeyFromStore(&P_Resources, Lit("prefab/GuySpawn.ase"))); } + if (wep->is_uzi) + { + result.wep_sheet = SPR_SheetKeyFromResource(ResourceKeyFromStore(&P_Resources, Lit("wep/uzi.ase"))); + } + + if (wep->is_launcher) + { + result.wep_sheet = SPR_SheetKeyFromResource(ResourceKeyFromStore(&P_Resources, Lit("wep/launcher.ase"))); + } + return result; } @@ -374,7 +387,7 @@ P_CollisionResult P_CollisionResultFromShapes(P_Shape shape0, P_Shape shape1) P_CollisionResult result = Zi; TempArena scratch = BeginScratchNoConflict(); - f32 tolerance = 0.00005f; // How close can non-overlapping shapes be before collision is considered + f32 tolerance = 0.05f; // How close can non-overlapping shapes be before collision is considered f32 min_unique_pt_dist_sq = (0.001f * 0.001f); // NOTE: Should always be less than tolerance, since colliding = 1 if origin is within this distance. u32 max_iterations = 64; // To prevent extremely large prototypes when origin is in exact center of rounded feature @@ -1141,6 +1154,16 @@ P_Ent *P_EntFromKey(P_Frame *frame, P_EntKey key) return result; } +P_Ent *P_SourcePlayerFromEnt(P_Frame *frame, P_Ent *ent) +{ + P_Ent *result = ent; + while (!P_IsEntNil(result) && !result->is_player) + { + result = P_EntFromKey(frame, result->source); + } + return result; +} + P_Constraint *P_ConstraintFromKey(P_Frame *frame, P_ConstraintKey key) { P_Constraint *result = &P_NilConstraint; @@ -1237,6 +1260,7 @@ P_Space P_SpaceFromEnts(Arena *arena, P_Frame *frame) aabb = IntersectRng2(aabb, space_aabb); if (!IsRng2Empty(aabb)) { + ++space.unique_entries_count; for (i32 y = aabb.p0.y; y < aabb.p1.y; ++y) { for (i32 x = aabb.p0.x; x < aabb.p1.x; ++x) @@ -1247,6 +1271,7 @@ P_Space P_SpaceFromEnts(Arena *arena, P_Frame *frame) SllStackPush(cell->first, entry_node); entry_node->entry.shape = shape; entry_node->entry.shape_id = ent->key.v; + ++space.entries_count; } } } @@ -1401,9 +1426,7 @@ P_Space P_SpaceFromWalls(Arena *arena, P_Frame *frame) id = MixU64s(id, (((u64)wall->start.x) | ((u64)wall->start.y << 32))); id = MixU64s(id, (((u64)wall->end.x) | ((u64)wall->end.y << 32))); - // FIXME: Remove this - // TrueRand(StringFromStruct(&id)); - + ++space.unique_entries_count; for (i32 y = aabb.p0.y; y < aabb.p1.y; ++y) { for (i32 x = aabb.p0.x; x < aabb.p1.x; ++x) @@ -1416,6 +1439,7 @@ P_Space P_SpaceFromWalls(Arena *arena, P_Frame *frame) entry_node->entry.shape_id = id; entry_node->entry.dir.x = (wall->dir == WallDir_Right) + ((wall->dir == WallDir_Left) * -1); entry_node->entry.dir.y = (wall->dir == WallDir_Down) + ((wall->dir == WallDir_Up) * -1); + ++space.entries_count; } } } @@ -1436,6 +1460,7 @@ P_SpaceCell P_SpaceCellFromPos(P_Space *space, Vec2 pos) return result; } +// TODO: Parameterized bin-count void P_UniqueSpaceEntriesFromRay(Arena *arena, P_SpaceEntryList *result, i32 spaces_count, P_Space **spaces, Vec2 ray_p0, Vec2 ray_p1) { TempArena scratch = BeginScratch(arena); @@ -1444,6 +1469,8 @@ void P_UniqueSpaceEntriesFromRay(Arena *arena, P_SpaceEntryList *result, i32 spa u64 bins_count = 256; BinEntry **bins = PushStructs(scratch.arena, BinEntry *, bins_count); + P_DebugDrawLine(ray_p0, ray_p1, Color_Red); + // TODO: Clip to avoid unnecessary iterations outside of world bounds ray_p0 = AddVec2(ray_p0, VEC2(P_WorldPitch / 2.0, P_WorldPitch / 2.0)); ray_p1 = AddVec2(ray_p1, VEC2(P_WorldPitch / 2.0, P_WorldPitch / 2.0)); @@ -1470,7 +1497,7 @@ void P_UniqueSpaceEntriesFromRay(Arena *arena, P_SpaceEntryList *result, i32 spa { Vec2 world_pos = Vec2FromVec(grid_pos); world_pos = SubVec2(world_pos, VEC2(P_WorldPitch / 2.0, P_WorldPitch / 2.0)); - P_DebugDrawRect(RNG2(world_pos, AddVec2(world_pos, VEC2(1, 1))), Color_Cyan); + P_DebugDrawRect(RNG2(world_pos, AddVec2(world_pos, VEC2(1, 1))), VEC4(0.85, 0.5, 0.75, 0.75)); } for (i32 space_idx = 0; space_idx < spaces_count; ++space_idx) { @@ -1616,6 +1643,63 @@ void P_DebugDrawFrame(P_Frame *frame) { if (P_tl.debug_draw_enabled) { + P_World *world = frame->world; + + ////////////////////////////// + //- Draw walls + + { + TempArena scratch = BeginScratchNoConflict(); + { + Struct(BinEntry) { BinEntry *next; u64 shape_id; }; + u64 bins_count = NextPow2U64(world->walls_space.unique_entries_count * 4); + BinEntry **bins = PushStructs(scratch.arena, BinEntry *, bins_count); + + i64 cells_count = world->walls_space.dims.x * world->walls_space.dims.y; + for (i64 cell_idx = 0; cell_idx < cells_count; ++cell_idx) + { + P_SpaceCell *cell = &world->walls_space.cells[cell_idx]; + for (P_SpaceEntryNode *space_entry_node = cell->first; space_entry_node; space_entry_node = space_entry_node->next) + { + P_SpaceEntry *space_entry = &space_entry_node->entry; + BinEntry **bin = &bins[space_entry->shape_id % bins_count]; + BinEntry *bin_entry = *bin; + for (; bin_entry; bin_entry = bin_entry->next) + { + if (bin_entry->shape_id == space_entry->shape_id) + { + break; + } + } + if (!bin_entry) + { + // Draw unique wall + { + bin_entry = PushStruct(scratch.arena, BinEntry); + bin_entry->shape_id = space_entry->shape_id; + SllStackPush(*bin, bin_entry); + } + { + Vec4 color = VEC4(0.5, 0.75, 0.5, 0.75); + P_DebugDrawShape(space_entry->shape, color); + } + } + } + } + } + EndScratch(scratch); + } + + for (i32 cell_y = 0; cell_y < world->walls_space.dims.y; ++cell_y) + { + for (i32 cell_x = 0; cell_x < world->walls_space.dims.x; ++cell_x) + { + } + } + + ////////////////////////////// + //- Draw entities + for (P_Ent *ent = P_FirstEnt(frame); !P_IsEntNil(ent); ent = P_NextEnt(ent)) { P_Shape world_shape = P_WorldShapeFromEnt(ent); @@ -1651,6 +1735,35 @@ void P_DebugDrawFrame(P_Frame *frame) P_DebugDrawLine(p0, p1, color); } } + + ////////////////////////////// + //- Draw constraints + + for (P_Constraint *constraint = P_FirstConstraint(frame); !P_IsConstraintNil(constraint); constraint = P_NextConstraint(constraint)) + { + P_Ent *ent0 = P_EntFromKey(frame, constraint->ent0); + P_Ent *ent1 = P_EntFromKey(frame, constraint->ent1); + Vec2 normal = constraint->normal; + Vec2 center0 = constraint->static_center0; + Vec2 center1 = constraint->static_center1; + if (!P_IsEntNil(ent0)) + { + center0 = P_WorldShapeFromEnt(ent0).center_of_mass; + } + if (!P_IsEntNil(ent1)) + { + center1 = P_WorldShapeFromEnt(ent1).center_of_mass; + } + + for (i32 contact_idx = 0; contact_idx < constraint->points_count; ++contact_idx) + { + P_ContactPoint *contact = &constraint->points[contact_idx]; + Vec2 p0 = AddVec2(center0, contact->vcp0); + Vec2 p1 = AddVec2(center1, contact->vcp1); + P_DebugDrawPoint(p0, Color_Cyan); + P_DebugDrawLine(p0, AddVec2(p0, normal), Color_White); + } + } } } @@ -1942,25 +2055,32 @@ void P_StepFrame(P_Frame *frame) { i64 ents_to_prune_count = 0; - P_Ent **ents_to_prune = PushStructsNoZero(scratch.arena, P_Ent *, frame->ents_count); + P_EntKey *ents_to_prune = PushStructsNoZero(scratch.arena, P_EntKey, frame->ents_count); for (P_Ent *ent = P_FirstEnt(frame); !P_IsEntNil(ent); ent = P_NextEnt(ent)) { if (ent->exists <= 0) { - ents_to_prune[ents_to_prune_count] = ent; - ents_to_prune_count += 1; + ents_to_prune[ents_to_prune_count++] = ent->key; + if (!P_IsEntKeyNil(ent->weapon)) + { + ents_to_prune[ents_to_prune_count++] = ent->weapon; + } } } for (i64 prune_idx = 0; prune_idx < ents_to_prune_count; ++prune_idx) { - // FIXME: Ensure sure prunes are received by player - P_Ent *ent = ents_to_prune[prune_idx]; - P_EntBin *bin = &frame->ent_bins[ent->key.v % frame->ent_bins_count]; - DllQueueRemoveNP(bin->first, bin->last, ent, next_in_bin, prev_in_bin); - DllQueueRemoveNPZ(&P_NilEnt, frame->first_ent, frame->last_ent, ent, next, prev); - frame->ents_count -= 1; - SllStackPush(world->first_free_ent, ent); + // FIXME: Ensure sure prunes are received by clients + P_EntKey key = ents_to_prune[prune_idx]; + P_Ent *ent = P_EntFromKey(frame, key); + if (!P_IsEntNil(ent)) + { + P_EntBin *bin = &frame->ent_bins[ent->key.v % frame->ent_bins_count]; + DllQueueRemoveNP(bin->first, bin->last, ent, next_in_bin, prev_in_bin); + DllQueueRemoveNPZ(&P_NilEnt, frame->first_ent, frame->last_ent, ent, next, prev); + frame->ents_count -= 1; + SllStackPush(world->first_free_ent, ent); + } } } @@ -1976,7 +2096,7 @@ void P_StepFrame(P_Frame *frame) if (!is_predicting) { - P_EntList new_guys = Zi; + P_EntList queued_ents = Zi; for (P_Ent *player = P_FirstEnt(frame); !P_IsEntNil(player); player = P_NextEnt(player)) { if (player->is_player) @@ -1988,11 +2108,10 @@ void P_StepFrame(P_Frame *frame) P_Ent *guy = P_EntFromKey(frame, player->guy); if (P_IsEntNil(guy)) { - guy = P_PushTempEnt(scratch.arena, &new_guys); + guy = P_PushTempEnt(scratch.arena, &queued_ents); guy->is_guy = 1; - guy->has_weapon = 1; guy->key = player->guy; - guy->player = player->key; + guy->source = player->key; //- Choose guy spawn point { @@ -2065,9 +2184,37 @@ void P_StepFrame(P_Frame *frame) } } } - P_SpawnEntsFromList(frame, new_guys); + P_SpawnEntsFromList(frame, queued_ents); } + ////////////////////////////// + //- Equip spawned guys + + // TODO: Remove this (weapon testing) + + { + P_EntList queued_ents = Zi; + for (P_Ent *guy = P_FirstEnt(frame); !P_IsEntNil(guy); guy = P_NextEnt(guy)) + { + if (guy->is_guy && guy->created_at_tick == frame->tick) + { + P_Ent *weapon = P_EntFromKey(frame, guy->weapon); + if (!weapon->is_weapon) + { + weapon = P_PushTempEnt(scratch.arena, &queued_ents); + weapon->is_weapon = 1; + weapon->key = P_RandEntKey(); + weapon->source = guy->key; + // weapon->is_uzi = 1; + weapon->is_launcher = 1; + guy->weapon = weapon->key; + } + } + } + P_SpawnEntsFromList(frame, queued_ents); + } + + ////////////////////////////// //- Update guy controls from player controls @@ -2243,7 +2390,8 @@ void P_StepFrame(P_Frame *frame) if (!skip_collision && !IsVec2Zero(space_entry->dir)) { // Skip collision if normal violates one-way direction - f32 threshold = 0.5; + // f32 threshold = 0.5; + f32 threshold = 0; skip_collision = DotVec2(space_entry->dir, collision.collision_normal) >= threshold; } @@ -2351,21 +2499,6 @@ void P_StepFrame(P_Frame *frame) contact->vcp0 = vcp0; contact->vcp1 = vcp1; contact->starting_separation = collision_point.separation; - - // Debug draw - // { - // // P_Ent *ent0 = P_EntFromKey(frame, constraint->ent0); - // // P_Ent *ent1 = P_EntFromKey(frame, constraint->ent1); - // Vec2 normal = constraint->normal; - // Vec2 center0 = Zi; - // Vec2 center1 = Zi; - // if (!P_IsEntNil(ent0)) center0 = P_WorldShapeFromEnt(ent0).center_of_mass; - // if (!P_IsEntNil(ent1)) center1 = P_WorldShapeFromEnt(ent1).center_of_mass; - // Vec2 p0 = AddVec2(center0, vcp0); - // Vec2 p1 = AddVec2(center1, vcp1); - // P_DebugDrawPoint(p0, Color_Cyan); - // P_DebugDrawLine(p0, AddVec2(p0, normal), Color_White); - // } } } } @@ -2711,8 +2844,9 @@ void P_StepFrame(P_Frame *frame) P_EntList bullets_to_spawn = Zi; for (P_Ent *firer = P_FirstEnt(frame); !P_IsEntNil(firer); firer = P_NextEnt(firer)) { - if (firer->has_weapon && firer->control.fire_held) - // if (firer->has_weapon && firer->control.fire_presses) + P_Ent *weapon = P_EntFromKey(frame, firer->weapon); + if (weapon->is_weapon && firer->control.fire_held) + // if (weapon->is_weapon && firer->control.fire_presses) { // i64 fire_delta_ns = frame->time_ns - firer->last_fire_ns; @@ -2736,7 +2870,7 @@ void P_StepFrame(P_Frame *frame) if (can_fire) { Vec2 look = firer->control.look; - P_Anim anim = P_AnimFromEnt(firer, frame->time_ns); + P_Anim anim = P_AnimFromEnt(frame, firer); SPR_Sprite body = SPR_SpriteFromSheet(anim.sheet, anim.span, anim.frame_seq); SPR_Sprite wep = SPR_SpriteFromSheet(anim.wep_sheet, anim.span, anim.frame_seq); @@ -2829,7 +2963,8 @@ void P_StepFrame(P_Frame *frame) bullet->bullet_base1 = fire_base1; bullet->bullet_start = fire_pos; bullet->bullet_end = AddVec2(bullet->bullet_start, MulVec2(dir, speed)); - bullet->bullet_firer = firer->key; + bullet->source = weapon->key; + bullet->damage_attribution = firer->source; } } firer->last_fire_ns = frame->time_ns; @@ -2848,6 +2983,10 @@ void P_StepFrame(P_Frame *frame) { if (bullet->is_bullet) { + P_Ent *bullet_weapon = P_EntFromKey(frame, bullet->source); + P_Ent *bullet_guy = P_EntFromKey(frame, bullet_weapon->source); + P_Ent *bullet_damager = P_EntFromKey(frame, bullet->damage_attribution); + bullet->has_hit = 0; Struct(BulletPath) @@ -2888,12 +3027,11 @@ void P_StepFrame(P_Frame *frame) path->end = bullet->bullet_end; } - P_DebugDrawLine(bullet->bullet_start, bullet->bullet_end, Color_Red); - P_EntKey victim_key = Zi; P_RaycastResult victim_raycast = Zi; + b32 hit = 0; { - for (BulletPath *path = first_bullet_path; path; path = path->next) + for (BulletPath *path = first_bullet_path; path && !hit; path = path->next) { Vec2 path_dir = SubVec2(path->end, path->start); P_Space *cast_spaces[] = { @@ -2914,7 +3052,7 @@ void P_StepFrame(P_Frame *frame) { 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)) + if (!P_MatchEntKey(potential_victim_key, bullet_guy->key) || P_IsEntKeyNil(bullet_guy->key)) { P_Shape potential_victim_shape = entry->shape; P_RaycastResult entrance_raycast = P_RaycastShape(potential_victim_shape, path->start, path_dir); @@ -2933,23 +3071,18 @@ void P_StepFrame(P_Frame *frame) closest_len_sq = len_sq; victim_key = potential_victim_key; victim_raycast = entrance_raycast; + hit = 1; } } } } } - if (!P_IsEntKeyNil(victim_key)) - { - // No need to check subsequent paths if this path hit - break; - } } } - P_Ent *victim = P_EntFromKey(frame, victim_key); // TODO: Truncate bullet trail - if (!P_IsEntKeyNil(victim_key)) + if (hit) { bullet->has_hit = 1; bullet->hit_entry = victim_raycast.p; @@ -2969,18 +3102,9 @@ void P_StepFrame(P_Frame *frame) // TODO: Remove this if (!P_IsEntNil(victim)) { - P_Ent *damager = bullet; - if (!damager->is_player) + if (bullet_damager->is_player) { - damager = P_EntFromKey(frame, damager->bullet_firer); - } - if (!damager->is_player) - { - damager = P_EntFromKey(frame, damager->player); - } - if (damager->is_player) - { - victim->last_damaging_player = damager->key; + victim->damage_attribution = bullet_damager->key; } victim->health -= 0.25; } @@ -3011,8 +3135,8 @@ void P_StepFrame(P_Frame *frame) P_Ent *old_guy = P_EntFromKey(prev_frame, guy->key); if (old_guy->health > 0) { - P_Ent *player = P_EntFromKey(frame, guy->player); - P_Ent *killer = P_EntFromKey(frame, guy->last_damaging_player); + P_Ent *player = P_EntFromKey(frame, guy->source); + P_Ent *killer = P_EntFromKey(frame, guy->damage_attribution); if (player->is_player) { player->deaths += 1; diff --git a/src/pp/pp.h b/src/pp/pp.h index eeba5cac..ebd8b5bb 100644 --- a/src/pp/pp.h +++ b/src/pp/pp.h @@ -122,13 +122,8 @@ Struct(P_Ent) Xform xf; - // TODO: Remove this (weapon testing) - i64 last_fire_ns; - b32 has_weapon; - //- Bullet / hit - P_EntKey bullet_firer; b32 is_bullet; Vec2 bullet_base0; Vec2 bullet_base1; @@ -140,10 +135,18 @@ Struct(P_Ent) Vec2 hit_entry_normal; P_MaterialKind hit_material; + //- Player / guy / weapon / bullet + + P_EntKey source; + //- Player / Guy P_Control control; + //- Guy / Bullet + + P_EntKey damage_attribution; + //- Player P_EntKey spawn; @@ -160,8 +163,15 @@ Struct(P_Ent) //- Guy - P_EntKey player; - P_EntKey last_damaging_player; + P_EntKey weapon; + + //- Weapon + + b32 is_weapon; + b32 is_uzi; + b32 is_launcher; + + i64 last_fire_ns; //- Spawn @@ -293,6 +303,8 @@ Struct(P_SpaceCell) Struct(P_Space) { + i64 entries_count; + i64 unique_entries_count; Vec2I32 dims; P_SpaceCell *cells; }; @@ -603,7 +615,7 @@ P_Shape P_WorldShapeFromEnt(P_Ent *ent); //////////////////////////////////////////////////////////// //~ Animation helpers -P_Anim P_AnimFromEnt(P_Ent *ent, i64 time_ns); +P_Anim P_AnimFromEnt(P_Frame *frame, P_Ent *ent); //////////////////////////////////////////////////////////// //~ Collision @@ -623,6 +635,7 @@ Vec2 P_EdgePointFromShape(P_Shape shape, Vec2 dir); //~ Lookup helpers P_Ent *P_EntFromKey(P_Frame *frame, P_EntKey key); +P_Ent *P_SourcePlayerFromEnt(P_Frame *frame, P_Ent *ent); P_Constraint *P_ConstraintFromKey(P_Frame *frame, P_ConstraintKey key); //////////////////////////////////////////////////////////// diff --git a/src/pp/pp_res/guy/guy.ase b/src/pp/pp_res/guy/guy.ase new file mode 100644 index 00000000..3249e456 --- /dev/null +++ b/src/pp/pp_res/guy/guy.ase @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:98fc28f80634d140f4174f357ea2d51d84d6a2d4a6b7fd8a361da69bf9f1c200 +size 3551 diff --git a/src/pp/pp_res/sprite/palette.ase b/src/pp/pp_res/palette.ase similarity index 100% rename from src/pp/pp_res/sprite/palette.ase rename to src/pp/pp_res/palette.ase diff --git a/src/pp/pp_res/sprite/bla.ase b/src/pp/pp_res/sprite/bla.ase deleted file mode 100644 index d1c08681..00000000 --- a/src/pp/pp_res/sprite/bla.ase +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3147cb9b3eefc5fd176d3ffd289908231e0eb2126df02875762acab956bb3cbf -size 788 diff --git a/src/pp/pp_res/sprite/bla2.ase b/src/pp/pp_res/sprite/bla2.ase deleted file mode 100644 index e5fbdd7a..00000000 --- a/src/pp/pp_res/sprite/bla2.ase +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:09ba23b624d3bc6c5aecd3f6fc34f96b6e2c0098b95efa0fb96eeefb139d4e24 -size 2773 diff --git a/src/pp/pp_res/sprite/bla3.ase b/src/pp/pp_res/sprite/bla3.ase deleted file mode 100644 index 383be1d9..00000000 --- a/src/pp/pp_res/sprite/bla3.ase +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:970fa7fd4366377968765630188fa04531e6534e20b814c46404aacca01cf6fa -size 3551 diff --git a/src/pp/pp_res/wep/launcher.ase b/src/pp/pp_res/wep/launcher.ase new file mode 100644 index 00000000..26e215cf --- /dev/null +++ b/src/pp/pp_res/wep/launcher.ase @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f7022bb2ec2a06d96bcdfe272a025e82a613727808ff5aa9981d084883e7fda8 +size 549 diff --git a/src/pp/pp_res/sprite/raah.ase b/src/pp/pp_res/wep/uzi.ase similarity index 100% rename from src/pp/pp_res/sprite/raah.ase rename to src/pp/pp_res/wep/uzi.ase diff --git a/src/pp/pp_sim/pp_sim_core.c b/src/pp/pp_sim/pp_sim_core.c index 47885185..90c38ce4 100644 --- a/src/pp/pp_sim/pp_sim_core.c +++ b/src/pp/pp_sim/pp_sim_core.c @@ -591,8 +591,7 @@ void S_TickForever(WaveLaneCtx *lane) guy = P_PushTempEnt(frame_arena, &ents); guy->key = P_RandEntKey(); guy->is_guy = 1; - guy->has_weapon = 1; - guy->player = bot->key; + guy->source = bot->key; bot->guy = guy->key; } guy->xf = msg->xf; diff --git a/src/pp/pp_transcode.c b/src/pp/pp_transcode.c index 83babd44..7995dfd4 100644 --- a/src/pp/pp_transcode.c +++ b/src/pp/pp_transcode.c @@ -47,9 +47,9 @@ String P_PackWorld(Arena *arena, P_World *src_world) { result.len += PushString(arena, Lit(" bot\n")).len; } - if (ent->has_weapon) + if (ent->is_weapon) { - result.len += PushString(arena, Lit(" has_weapon\n")).len; + result.len += PushString(arena, Lit(" is_weapon\n")).len; } if (ent->is_bullet) { @@ -70,7 +70,7 @@ String P_PackWorld(Arena *arena, P_World *src_world) result.len += StringF(arena, " look: \"%F\"\n", FmtFloat2(ent->control.look)).len; result.len += StringF(arena, " health: \"%F\"\n", FmtFloat(ent->health)).len; result.len += StringF(arena, " guy: \"0x%F\"\n", FmtHex(ent->guy.v)).len; - result.len += StringF(arena, " player: \"0x%F\"\n", FmtHex(ent->player.v)).len; + result.len += StringF(arena, " source: \"0x%F\"\n", FmtHex(ent->source.v)).len; result.len += StringF(arena, " kills: \"%F\"\n", FmtFloat(ent->kills)).len; result.len += StringF(arena, " deaths: \"%F\"\n", FmtFloat(ent->deaths)).len; result.len += StringF(arena, " text: \"%F\"\n", FmtString(CR_SanitizeString(scratch.arena, STRING(ent->string_len, ent->string_text)))).len; @@ -164,9 +164,9 @@ P_UnpackedWorld P_UnpackWorld(Arena *arena, String packed) { ent->is_bot = 1; } - if (MatchString(prop->value, Lit("has_weapon"))) + if (MatchString(prop->value, Lit("weapon"))) { - ent->has_weapon = 1; + ent->is_weapon = 1; } if (MatchString(prop->value, Lit("bullet"))) { @@ -214,9 +214,9 @@ P_UnpackedWorld P_UnpackWorld(Arena *arena, String packed) { ent->guy.v = CR_IntFromString(attr->value); } - if (MatchString(attr->name, Lit("player"))) + if (MatchString(attr->name, Lit("source"))) { - ent->player.v = CR_IntFromString(attr->value); + ent->source.v = CR_IntFromString(attr->value); } if (MatchString(attr->name, Lit("kills"))) { diff --git a/src/pp/pp_vis/pp_vis_core.c b/src/pp/pp_vis/pp_vis_core.c index f5d43595..3a175046 100644 --- a/src/pp/pp_vis/pp_vis_core.c +++ b/src/pp/pp_vis/pp_vis_core.c @@ -842,7 +842,7 @@ void V_TickForever(WaveLaneCtx *lane) //- Compute movement & look f32 max_look_radius = 5; - f32 min_look_radius = 0.01; + f32 min_look_radius = 0.025; frame->is_looking = !frame->is_editing && !frame->palette.is_showing && !frame->held_buttons[Button_Alt]; frame->is_moving = !frame->is_editing; @@ -964,6 +964,7 @@ void V_TickForever(WaveLaneCtx *lane) target_camera_pos.x = ClampF32(target_camera_pos.x, -world_pitch / 2, world_pitch / 2); target_camera_pos.y = ClampF32(target_camera_pos.y, -world_pitch / 2, world_pitch / 2); target_camera_zoom = ClampF32(target_camera_zoom, min_zoom, max_zoom); + // Interpolate camera { if (prev_frame->tick == 0) @@ -1825,7 +1826,7 @@ void V_TickForever(WaveLaneCtx *lane) { P_Ent *ent = local_guy; - P_Anim anim = P_AnimFromEnt(ent, local_frame->time_ns); + P_Anim anim = P_AnimFromEnt(local_frame, ent); SPR_Sprite body = SPR_SpriteFromSheet(anim.sheet, anim.span, anim.frame_seq); SPR_Sprite wep = SPR_SpriteFromSheet(anim.wep_sheet, anim.span, anim.frame_seq); @@ -1890,8 +1891,11 @@ void V_TickForever(WaveLaneCtx *lane) Vec2 desired_chamber_pos = MulVec2(PerpVec2(desired_fire_dir), WedgeVec2(desired_fire_dir, SubVec2(desired_fire_pos, desired_hold_pos))); desired_chamber_pos = AddVec2(desired_chamber_pos, desired_hold_pos); - Vec2 desired_crosshair_base = MulVec2(PerpVec2(NegVec2(desired_ent_to_world_af.bx)), WedgeVec2(desired_ent_to_world_af.bx, SubVec2(desired_ent_to_world_af.og, desired_chamber_pos))); - desired_crosshair_base = AddVec2(desired_crosshair_base, desired_ent_to_world_af.og); + Vec2 desired_crosshair_base = IntersectLines( + desired_ent_to_world_af.og, AddVec2(desired_ent_to_world_af.og, desired_ent_to_world_af.by), + desired_fire_pos, desired_chamber_pos + ); + desired_crosshair_base = SubVec2(desired_crosshair_base, MulVec2(NormVec2(desired_fire_dir), min_look_radius)); frame->world_guy_origin = desired_ent_to_world_af.og; frame->world_crosshair_base = desired_crosshair_base; @@ -2072,7 +2076,7 @@ void V_TickForever(WaveLaneCtx *lane) for (DrawNode *draw_node = first_draw_node; draw_node; draw_node = draw_node->next) { P_Ent *ent = draw_node->ent; - P_Anim anim = P_AnimFromEnt(ent, local_frame->time_ns); + P_Anim anim = P_AnimFromEnt(local_frame, ent); Vec2 pix_scale = VEC2(1.0 / P_CellsPerMeter, 1.0 / P_CellsPerMeter); Affine ent_to_world_af = MulAffineXform(AffineIdentity, ent->xf);