/* ======================= LevelPlayerRegionUpdate Updates the tracking of which player is in which region, and the general traffic of which players have been spotted in which regions of the level. ======================= */ void LevelPlayerRegionUpdate(void) { int player, neighbor, team, region_index, neighbor_index; int num_players[TEAM_NUM_TEAMS]; region_t *region; gentity_t *ent; // Update which region each player is currently in memset(num_players, 0, sizeof(num_players)); for (player = 0; player < MAX_CLIENTS; player++) { // Ignore spectators (and other teamless entities) ent = &g_entities[player]; team = EntityTeam(ent); if (team == TEAM_SPECTATOR) { player_region[player] = -1; continue; } // Found another player of this team num_players[team]++; // Compute this player's region region = LevelNearestRegion(ent->r.currentOrigin); player_region[player] = LevelRegionIndex(region); // Don't track players without a region if (player_region[player] < 0) continue; // Remember which regions from which this player was probably visible for (neighbor = 0; neighbor < MAX_REGION_NEIGHBORS && region->local_neighbor[neighbor]; neighbor++) { // Ignore neighbors that aren't visible from this region if ( !(region->visible & (1 << neighbor)) ) continue; // Mark that this player was visible near this region neighbor_index = LevelRegionIndex(region->local_neighbor[neighbor]); region_traffic[neighbor_index][team].actual++; } } // Update the number of possible sightings of each team in each region for (region_index = 0; region_index < num_regions; region_index++) for (team = 0; team < TEAM_NUM_TEAMS; team++) region_traffic[region_index][team].potential += num_players[team]; }
Node::Node() : m_nodeId(0), m_pParentNode(nullptr), m_gridPos(0.0f, 0.0f), m_worldPos(0.0f, 0.0f), m_isObstacle(false), m_pObstacle(nullptr), m_territoryOwner(EntityTeam(None)), m_isEntranceToBase(false), m_isAttackPosition(None), m_movementCost(0.0f), m_heuristicValue(0.0f) { for(unsigned int i = 0; i < NumberOfDirections; ++i) { m_coverProvided[i] = false; } }
/* ============== BotTrafficData Obtains the traffic data at the given point for teammates and enemies of the given bot. Returns a pointer to the region nearest that point, or NULL if there are no defined regions. ============== */ region_t *BotTrafficData(bot_state_t *bs, vec3_t loc, history_t *teammate, history_t *enemy) { int i, num_neighbors, team; float dists[TRAFFIC_NEIGHBORS], weights[TRAFFIC_NEIGHBORS], weight_total, min_dist; region_t *neighbors[TRAFFIC_NEIGHBORS], *closest; history_t *traffic, *team_traffic, *enemy_traffic; static history_t no_traffic = { 0, 1 }; // Fudged traffic data for situations that // lack traffic (eg. teammates in free for all) // Find the closest regions to this point num_neighbors = LevelNearestRegions(loc, TRAFFIC_NEIGHBORS, neighbors, dists); // Setup nothing if no neighbors could be found if (num_neighbors < 0) return NULL; // Weight nearer regions more than further regions and find the nearest neighbor memset(weights, 0, sizeof(weights)); weight_total = 0.0; min_dist = -1; closest = NULL; for (i = 0; i < num_neighbors; i++) { // If this point is the exact center of a region, use only that region's data if (dists[i] <= 0) { memset(weights, 0, sizeof(weights)); weights[i] = 1.0; weight_total = weights[i]; closest = neighbors[i]; break; } // The weight is inversely proportional to the distance weights[i] = 1.0 / dists[i]; weight_total += weights[i]; // Test if this region is nearer than the other options if (!closest || dists[i] < min_dist) { closest = neighbors[i]; min_dist = dists[i]; } } // Normalize the sum of the weights to 1.0 if (weight_total > 0.0) { for (i = 0; i < num_neighbors; i++) weights[i] /= weight_total; } // Find out what team the bot is on team = EntityTeam(bs->ent); // Add each region's data to the average memset(teammate, 0, sizeof(history_t)); memset(enemy, 0, sizeof(history_t)); for (i = 0; i < num_neighbors; i++) { // Look up the traffic data for this region traffic = region_traffic[LevelRegionIndex(neighbors[i])]; // Organize the data as teammate traffic and enemy traffic switch (team) { case TEAM_RED: team_traffic = &traffic[TEAM_RED ]; enemy_traffic = &traffic[TEAM_BLUE]; break; case TEAM_BLUE: team_traffic = &traffic[TEAM_BLUE]; enemy_traffic = &traffic[TEAM_RED ]; break; case TEAM_FREE: default: team_traffic = &no_traffic; enemy_traffic = &traffic[TEAM_FREE]; break; } // Track teammate traffic teammate->actual += weights[i] * team_traffic->actual; teammate->potential += weights[i] * team_traffic->potential; // Track enemy traffic enemy->actual += weights[i] * enemy_traffic->actual; enemy->potential += weights[i] * enemy_traffic->potential; } // Inform the caller of the closest neighbor return closest; }