randomnize spawn scores. ignore last player spawn point.
This commit is contained in:
parent
e88c91b1ab
commit
bc32417ba1
@ -40,6 +40,8 @@ f64 SaturateF64(f64 v) { return v < 0 ? 0 : v > 1 ? 1 : v; }
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Float ops
|
||||
|
||||
//- Sign
|
||||
|
||||
i32 SignF32(f32 v)
|
||||
{
|
||||
return (v >= 0) - (v < 0);
|
||||
@ -50,6 +52,18 @@ i32 SignF64(f64 v)
|
||||
return (v >= 0) - (v < 0);
|
||||
}
|
||||
|
||||
//- Norm
|
||||
|
||||
f32 NormU32(u32 v)
|
||||
{
|
||||
return (f32)(v & (((u32)1 << 24) - 1)) / (f32)((u32)1 << 24);
|
||||
}
|
||||
|
||||
f64 NormU64(u64 v)
|
||||
{
|
||||
return (f64)(v & (((u64)1 << 53) - 1)) / (f64)((u64)1 << 53);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Exponential ops
|
||||
|
||||
|
||||
@ -261,6 +261,10 @@ f64 SaturateF64(f64 v);
|
||||
i32 SignF32(f32 v);
|
||||
i32 SignF64(f64 v);
|
||||
|
||||
//- Norm
|
||||
f32 NormU32(u32 v);
|
||||
f64 NormU64(u64 v);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Exponential ops
|
||||
|
||||
|
||||
@ -9,7 +9,12 @@ u64 RandU64FromState(RandState *state)
|
||||
return seed ^ MixU64(++state->counter);
|
||||
}
|
||||
|
||||
f32 RandF32FromState(RandState *state, f32 range_start, f32 range_end)
|
||||
{
|
||||
return range_start + (range_end - range_start) * NormU32(RandU64FromState(state));
|
||||
}
|
||||
|
||||
f64 RandF64FromState(RandState *state, f64 range_start, f64 range_end)
|
||||
{
|
||||
return range_start + (range_end - range_start) * ((f64)(RandU64FromState(state) % RandMaxF64) / (f64)RandMaxF64);
|
||||
return range_start + (range_end - range_start) * NormU64(RandU64FromState(state));
|
||||
}
|
||||
|
||||
@ -7,11 +7,9 @@ Struct(RandState)
|
||||
u64 counter;
|
||||
};
|
||||
|
||||
// TODO: Use a value that gives good precision when dividing into range 0 -> 1
|
||||
#define RandMaxF64 U64Max
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Rand ops
|
||||
|
||||
u64 RandU64FromState(RandState *state);
|
||||
f32 RandF32FromState(RandState *state, f32 range_start, f32 range_end);
|
||||
f64 RandF64FromState(RandState *state, f64 range_start, f64 range_end);
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Mergesort types
|
||||
|
||||
// Compare functions should
|
||||
// Comparison functions should
|
||||
// return a positive value if a should go before b
|
||||
// return a negative value if a should go after b
|
||||
// return 0 otherwise
|
||||
@ -104,6 +104,15 @@ Inline void Mergesort(void *items, u64 item_count, u64 item_size, MergesortCompa
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Shuffle utils
|
||||
|
||||
#define ShuffleStructs(ptr, count, seed) ShuffleStructs_((ptr), sizeof(*(ptr)), (count), (seed))
|
||||
Inline void ShuffleStructs_(void *items, u64 item_count, u64 item_size, u64 seed)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Dict utils
|
||||
|
||||
|
||||
104
src/pp/pp.c
104
src/pp/pp.c
@ -1513,23 +1513,99 @@ void P_StepFrame(P_Frame *frame)
|
||||
P_Ent *local_guy = P_EntFromKey(frame, local_player->guy);
|
||||
|
||||
//////////////////////////////
|
||||
//- Spawn entities
|
||||
//- Spawn guys
|
||||
|
||||
// {
|
||||
// //////////////////////////////
|
||||
// //- Push bullets
|
||||
if (!is_predicting)
|
||||
{
|
||||
P_EntList new_guys = Zi;
|
||||
for (P_Ent *player = P_FirstEnt(frame); !P_IsEntNil(player); player = P_NextEnt(player))
|
||||
{
|
||||
if (player->is_player)
|
||||
{
|
||||
if (P_IsKeyNil(player->guy))
|
||||
{
|
||||
player->guy = P_RandKey();
|
||||
}
|
||||
P_Ent *guy = P_EntFromKey(frame, player->guy);
|
||||
if (P_IsEntNil(guy))
|
||||
{
|
||||
guy = P_PushTempEnt(scratch.arena, &new_guys);
|
||||
guy->is_guy = 1;
|
||||
guy->has_weapon = 1;
|
||||
guy->key = player->guy;
|
||||
|
||||
// for (P_Ent *ent = P_FirstEnt(frame); !P_IsEntNil(ent); ent = P_NextEnt(ent))
|
||||
// {
|
||||
// if (ent->control.fire_held)
|
||||
// {
|
||||
// if (ent->has_weapon)
|
||||
// {
|
||||
//- Choose guy spawn point
|
||||
{
|
||||
P_Ent *highest_scoring_spawn = &P_NilEnt;
|
||||
{
|
||||
Struct(SpawnNode)
|
||||
{
|
||||
SpawnNode *next;
|
||||
P_Ent *ent;
|
||||
f32 score;
|
||||
};
|
||||
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
i64 spawns_count = 0;
|
||||
SpawnNode *first_spawn = 0;
|
||||
SpawnNode *last_spawn = 0;
|
||||
|
||||
// Push spawns
|
||||
for (P_Ent *spawn_ent = P_FirstEnt(frame); !P_IsEntNil(spawn_ent); spawn_ent = P_NextEnt(spawn_ent))
|
||||
{
|
||||
if (spawn_ent->is_guy_spawn)
|
||||
{
|
||||
SpawnNode *spawn = PushStruct(scratch.arena, SpawnNode);
|
||||
SllQueuePush(first_spawn, last_spawn, spawn);
|
||||
spawn->ent = spawn_ent;
|
||||
spawn->score = P_WorldPitch * 1000;
|
||||
++spawns_count;
|
||||
}
|
||||
}
|
||||
|
||||
// Score spawns
|
||||
for (P_Ent *ent = P_FirstEnt(frame); !P_IsEntNil(ent); ent = P_NextEnt(ent))
|
||||
{
|
||||
b32 should_score = 0;
|
||||
if (ent->is_guy)
|
||||
{
|
||||
should_score = 1;
|
||||
}
|
||||
if (should_score)
|
||||
{
|
||||
for (SpawnNode *spawn = first_spawn; spawn; spawn = spawn->next)
|
||||
{
|
||||
// TODO: Something better than linear distance for scoring
|
||||
f32 score = Vec2Len(SubVec2(ent->xf.t, spawn->ent->xf.t));
|
||||
spawn->score = MinF32(spawn->score, score);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Find highest scoring spawn
|
||||
i64 highest_score = -Inf;
|
||||
for (SpawnNode *spawn = first_spawn; spawn; spawn = spawn->next)
|
||||
{
|
||||
b32 ignore_spawn = spawns_count > 1 && P_MatchKey(spawn->ent->key, player->spawn);
|
||||
if (!ignore_spawn)
|
||||
{
|
||||
f32 rand_score_spread = 5;
|
||||
f32 virtual_score = spawn->score + rand_score_spread * NormU32(RandU64FromState(&world->rand));
|
||||
if (virtual_score > highest_score)
|
||||
{
|
||||
highest_score = virtual_score;
|
||||
highest_scoring_spawn = spawn->ent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
guy->xf = highest_scoring_spawn->xf;
|
||||
player->spawn = highest_scoring_spawn->key;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
P_SpawnEntsFromList(frame, new_guys);
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- Update guy controls from player controls
|
||||
|
||||
@ -132,6 +132,8 @@ Struct(P_Ent)
|
||||
|
||||
//- Player
|
||||
|
||||
P_Key spawn;
|
||||
|
||||
b32 is_player;
|
||||
P_Key guy;
|
||||
|
||||
|
||||
BIN
src/pp/pp_res/prefab/GuySpawn.ase
(Stored with Git LFS)
BIN
src/pp/pp_res/prefab/GuySpawn.ase
(Stored with Git LFS)
Binary file not shown.
@ -295,90 +295,6 @@ void S_TickForever(WaveLaneCtx *lane)
|
||||
P_SpawnEntsFromList(world_frame, new_players);
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- Spawn guys
|
||||
|
||||
{
|
||||
P_EntList new_guys = Zi;
|
||||
for (P_Ent *player = P_FirstEnt(world_frame); !P_IsEntNil(player); player = P_NextEnt(player))
|
||||
{
|
||||
if (player->is_player)
|
||||
{
|
||||
if (P_IsKeyNil(player->guy))
|
||||
{
|
||||
player->guy = P_RandKey();
|
||||
}
|
||||
P_Ent *guy = P_EntFromKey(world_frame, player->guy);
|
||||
if (P_IsEntNil(guy))
|
||||
{
|
||||
guy = P_PushTempEnt(frame_arena, &new_guys);
|
||||
guy->is_guy = 1;
|
||||
guy->has_weapon = 1;
|
||||
guy->key = player->guy;
|
||||
|
||||
//- Choose guy spawn point
|
||||
{
|
||||
P_Ent *highest_scoring_spawn = &P_NilEnt;
|
||||
{
|
||||
Struct(SpawnNode)
|
||||
{
|
||||
SpawnNode *next;
|
||||
f32 score;
|
||||
P_Ent *ent;
|
||||
};
|
||||
SpawnNode *first_spawn_node = 0;
|
||||
SpawnNode *last_spawn_node = 0;
|
||||
|
||||
// Push spawns
|
||||
for (P_Ent *spawn = P_FirstEnt(world_frame); !P_IsEntNil(spawn); spawn = P_NextEnt(spawn))
|
||||
{
|
||||
if (spawn->is_guy_spawn)
|
||||
{
|
||||
SpawnNode *spawn_node = PushStruct(frame_arena, SpawnNode);
|
||||
SllQueuePush(first_spawn_node, last_spawn_node, spawn_node);
|
||||
spawn_node->ent = spawn;
|
||||
spawn_node->score = Inf;
|
||||
}
|
||||
}
|
||||
|
||||
// Score spawns
|
||||
for (P_Ent *ent = P_FirstEnt(world_frame); !P_IsEntNil(ent); ent = P_NextEnt(ent))
|
||||
{
|
||||
b32 should_score = 0;
|
||||
if (ent->is_guy)
|
||||
{
|
||||
should_score = 1;
|
||||
}
|
||||
if (should_score)
|
||||
{
|
||||
for (SpawnNode *spawn_node = first_spawn_node; spawn_node; spawn_node = spawn_node->next)
|
||||
{
|
||||
f32 score = Vec2Len(SubVec2(ent->xf.t, spawn_node->ent->xf.t));
|
||||
spawn_node->score = MinF32(spawn_node->score, score);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Find highest scoring spawn_node
|
||||
i64 highest_score = -Inf;
|
||||
for (SpawnNode *spawn_node = first_spawn_node; spawn_node; spawn_node = spawn_node->next)
|
||||
{
|
||||
if (spawn_node->score > highest_score)
|
||||
{
|
||||
highest_score = spawn_node->score;
|
||||
highest_scoring_spawn = spawn_node->ent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
guy->xf = highest_scoring_spawn->xf;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
P_SpawnEntsFromList(world_frame, new_guys);
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- Read snapshots
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user