unique weapon properties
This commit is contained in:
parent
6602fcdccf
commit
4b207e81fe
@ -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
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
252
src/pp/pp.c
252
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,20 +2055,26 @@ 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];
|
||||
// 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);
|
||||
@ -1963,6 +2082,7 @@ void P_StepFrame(P_Frame *frame)
|
||||
SllStackPush(world->first_free_ent, ent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- Query ents
|
||||
@ -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;
|
||||
|
||||
29
src/pp/pp.h
29
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);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
BIN
src/pp/pp_res/guy/guy.ase
(Stored with Git LFS)
Normal file
BIN
src/pp/pp_res/guy/guy.ase
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
src/pp/pp_res/sprite/bla.ase
(Stored with Git LFS)
BIN
src/pp/pp_res/sprite/bla.ase
(Stored with Git LFS)
Binary file not shown.
BIN
src/pp/pp_res/sprite/bla2.ase
(Stored with Git LFS)
BIN
src/pp/pp_res/sprite/bla2.ase
(Stored with Git LFS)
Binary file not shown.
BIN
src/pp/pp_res/sprite/bla3.ase
(Stored with Git LFS)
BIN
src/pp/pp_res/sprite/bla3.ase
(Stored with Git LFS)
Binary file not shown.
BIN
src/pp/pp_res/wep/launcher.ase
(Stored with Git LFS)
Normal file
BIN
src/pp/pp_res/wep/launcher.ase
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -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;
|
||||
|
||||
@ -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")))
|
||||
{
|
||||
|
||||
@ -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);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user