| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570 |
- /*
- ** Command & Conquer Renegade(tm)
- ** Copyright 2025 Electronic Arts Inc.
- **
- ** This program is free software: you can redistribute it and/or modify
- ** it under the terms of the GNU General Public License as published by
- ** the Free Software Foundation, either version 3 of the License, or
- ** (at your option) any later version.
- **
- ** This program is distributed in the hope that it will be useful,
- ** but WITHOUT ANY WARRANTY; without even the implied warranty of
- ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ** GNU General Public License for more details.
- **
- ** You should have received a copy of the GNU General Public License
- ** along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- /***********************************************************************************************
- *** Confidential - Westwood Studios ***
- ***********************************************************************************************
- * *
- * Project Name : Commando *
- * *
- * $Archive:: /Commando/Code/Commando/priority.cpp $*
- * *
- * $Author:: Steve_t $*
- * *
- * $Modtime:: 2/23/02 12:35p $*
- * *
- * $Revision:: 15 $*
- * *
- *---------------------------------------------------------------------------------------------*
- * Functions: *
- * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- #include "priority.h"
- #include <math.h>
- #include "wwdebug.h"
- #include "wwmath.h"
- #include "vector3.h"
- #include "gameobjmanager.h"
- #include "soldier.h"
- #include "humanphys.h"
- #include "apppackettypes.h"
- #include "vehicle.h"
- #include "useroptions.h"
- #include "playermanager.h"
- #include "wwprofile.h"
- //
- // Class statics
- //
- float cPriority::MaxDistance = 300.0F;
- const float cPriority::TURRET_FACTOR = 0.2f;
- const float cPriority::VEHICLE_FACTOR = 0.85f;
- const float cPriority::SOLDIER_FACTOR = 1.0f;
- const float cPriority::SOLDIER_IN_VEHICLE_FACTOR = 0.1f;
- const float cPriority::BUILDING_FACTOR = 0.2f;
- //-----------------------------------------------------------------------------
- //
- // Compute the priority of the given netobject to the given client
- //
- float
- cPriority::Compute_Object_Priority
- (
- int client_id,
- const Vector3 & client_pos,
- NetworkObjectClass * p_netobject,
- bool do_it_anyway,
- SoldierGameObj * client_soldier
- )
- {
- WWPROFILE("ObjPri");
- WWASSERT(client_id > 0);
- WWASSERT(p_netobject != NULL);
- //
- // Compute the priority of this object to the given client at his given position.
- // Priority depends on physical distance. Objects with no physical location will
- // have a priority of 1.
- //
- float priority = 0.0f;
- if (p_netobject->Is_Client_Dirty(client_id) || do_it_anyway)
- {
- float distance = Get_Object_Distance(client_pos, p_netobject);
- //
- // Priority simply decreases linearly with distance and is zero at MaxDistance.
- //
- priority = 1 - distance / MaxDistance;
- if (priority > 0.0f) {
- priority *= Compute_Facing_Factor(client_id, client_pos, p_netobject, client_soldier);
- }
- if (priority > 0.0f) {
- priority *= Compute_Type_Factor(p_netobject);
- }
- if (priority > 0.0f) {
- priority *= Compute_Relevance_Factor(client_id, p_netobject, client_soldier);
- }
- // Add a bit of a curve to have low priority objects drop away faster.
- if (priority > 0.0f && priority < 1.0f) {
- //float bendy = WWMath::Fast_Sin(priority * DEG_TO_RAD(90.0f));
- //priority = (priority + bendy) / 2.0f;
- float bendy = WWMath::Fast_Asin(priority);
- bendy = (RAD_TO_DEG(bendy)) / 90.0f;
- priority = (priority + bendy) / 2.0f;
- }
- }
- //
- // Override all priority calculations if the client hints that he badly needs an
- // update for this object. The client will hint if there is a vehicle or soldier nearby
- // that hasn't been updated for a suspiciously long time.
- //
- if (p_netobject->Get_Client_Hint_Count(client_id) > 0)
- {
- priority = 1.0f;
- p_netobject->Reset_Client_Hint_Count(client_id);
- /*
- WWDEBUG_SAY(("cPriority::Compute_Object_Priority %5.3f on object %d due to client %d hint.\n",
- priority, p_netobject->Get_Network_ID(), client_id));
- */
- }
- priority = WWMath::Clamp(priority, 0.0f, 1.0f);
- return priority;
- }
- //-----------------------------------------------------------------------------
- float
- cPriority::Compute_Facing_Factor
- (
- int client_id,
- const Vector3 & client_pos,
- NetworkObjectClass * p_netobject,
- SoldierGameObj *client_soldier
- )
- {
- WWASSERT(client_id > 0);
- WWASSERT(p_netobject != NULL);
- float facing_factor = 1;
- SoldierGameObj * p_soldier = client_soldier;
- if (p_soldier == NULL) {
- p_soldier = GameObjManager::Find_Soldier_Of_Client_ID(client_id);
- }
- if (p_soldier != NULL)
- {
- WWASSERT(p_soldier->Peek_Human_Phys() != NULL);
- float client_facing = p_soldier->Peek_Human_Phys()->Get_Heading();
- Vector3 subject_position;
- if (p_netobject->Get_World_Position(subject_position))
- {
- Vector3 position_delta = subject_position - client_pos;
- float subject_facing = WWMath::Atan2(position_delta.Y, position_delta.X);
- float facing_dif = ::fabs(subject_facing - client_facing);
- if (facing_dif > WWMATH_PI)
- {
- facing_dif = 2 * WWMATH_PI - facing_dif;
- }
- facing_factor -= facing_dif / WWMATH_PI * cUserOptions::MaxFacingPenalty.Get();
- }
- }
- return facing_factor;
- }
- //-----------------------------------------------------------------------------
- float
- cPriority::Get_Object_Distance
- (
- const Vector3 & client_pos,
- NetworkObjectClass * p_netobject
- )
- {
- WWASSERT(p_netobject != NULL);
- //
- // Objects without a physical location will return a distance of zero.
- //
- float distance = 0;
- //
- // Get the object's world position (if it has one)
- //
- Vector3 position;
- if (p_netobject->Get_World_Position(position))
- {
- //
- // Simple distance calculation based on the distance
- // between points.
- //
- distance = (position - client_pos).Length();
- }
- return distance;
- }
- //-----------------------------------------------------------------------------
- float
- cPriority::Compute_Type_Factor
- (
- NetworkObjectClass *p_netobject
- )
- {
- float type_factor = 1.0f;
- char type = p_netobject->Get_App_Packet_Type();
- switch (type) {
- case APPPACKETTYPE_SOLDIER:
- type_factor = SOLDIER_FACTOR;
- break;
- case APPPACKETTYPE_TURRET:
- type_factor = TURRET_FACTOR;
- break;
- case APPPACKETTYPE_VEHICLE:
- type_factor = VEHICLE_FACTOR;
- break;
- case APPPACKETTYPE_BUILDING:
- type_factor = BUILDING_FACTOR;
- break;
- default:
- type_factor = 1.0f;
- }
- return(type_factor);
- }
- //-----------------------------------------------------------------------------
- float
- cPriority::Compute_Relevance_Factor
- (
- int client_id,
- NetworkObjectClass * p_netobject,
- SoldierGameObj *client_soldier
- )
- {
- WWASSERT(p_netobject != NULL);
- //
- // This bumps the priority of objects that you are shooting or that are
- // shooting at you.
- //
- bool is_relevant = false;
- int id = p_netobject->Get_Network_ID();
- SoldierGameObj * p_my_soldier = client_soldier;
- if (p_my_soldier == NULL) {
- p_my_soldier = GameObjManager::Find_Soldier_Of_Client_ID(client_id);
- }
- VehicleGameObj * p_my_vehicle = NULL;
- if (p_my_soldier != NULL) {
- p_my_vehicle = GameObjManager::Find_Vehicle_Occupied_By(p_my_soldier);
- }
- if (p_my_soldier != NULL &&
- (p_my_soldier->Get_Last_Object_Id_I_Damaged() == id ||
- p_my_soldier->Get_Last_Object_Id_I_Got_Damaged_By() == id)) {
- is_relevant = true;
- }
- if (p_my_vehicle != NULL &&
- (p_my_vehicle->Get_Last_Object_Id_I_Damaged() == id ||
- p_my_vehicle->Get_Last_Object_Id_I_Got_Damaged_By() == id)) {
- is_relevant = true;
- }
- float factor = 1.0f;
- if (!is_relevant) {
- factor -= cUserOptions::IrrelevancePenalty.Get();
- }
- WWASSERT(factor > 0);
- return factor;
- }
- float
- cPriority::Compute_Object_Priority_2
- (
- int client_id,
- const Vector3 & client_pos,
- NetworkObjectClass * p_netobject,
- bool do_it_anyway,
- SoldierGameObj * client_soldier
- )
- {
- WWPROFILE("ObjPri");
- WWASSERT(client_id > 0);
- WWASSERT(p_netobject != NULL);
- //
- // Compute the priority of this object to the given client at his given position.
- // Priority depends on physical distance. Objects with no physical location will
- // have a priority of 1.
- //
- float priority = 0.0f;
- if (p_netobject->Is_Client_Dirty(client_id) || do_it_anyway)
- {
- float distance = Get_Object_Distance_2(client_pos, p_netobject);
- //
- // Priority simply decreases linearly with distance and is zero at MaxDistance.
- //
- priority = 1 - distance / MaxDistance;
- if (priority > 0.0f) {
- priority *= Compute_Facing_Factor_2(client_id, client_pos, p_netobject, client_soldier);
- }
- if (priority > 0.0f) {
- priority *= Compute_Type_Factor_2(p_netobject, distance);
- }
- if (priority > 0.0f) {
- priority *= Compute_Relevance_Factor_2(client_id, p_netobject, client_soldier);
- }
- // Add a bit of a curve to have low priority objects drop away faster.
- if (priority > 0.0f && priority < 1.0f) {
- //float bendy = WWMath::Fast_Sin(priority * DEG_TO_RAD(90.0f));
- //priority = (priority + bendy) / 2.0f;
- float bendy = WWMath::Fast_Asin(priority);
- bendy = (RAD_TO_DEG(bendy)) / 90.0f;
- priority = (priority + bendy) / 2.0f;
- }
- }
- priority = WWMath::Clamp(priority, 0.0f, 1.0f);
- return priority;
- }
- //-----------------------------------------------------------------------------
- float
- cPriority::Compute_Facing_Factor_2
- (
- int client_id,
- const Vector3 & client_pos,
- NetworkObjectClass * p_netobject,
- SoldierGameObj *client_soldier
- )
- {
- WWASSERT(client_id > 0);
- WWASSERT(p_netobject != NULL);
- float facing_factor = 1;
- SoldierGameObj * p_soldier = client_soldier;
- if (p_soldier == NULL) {
- p_soldier = GameObjManager::Find_Soldier_Of_Client_ID(client_id);
- }
- if (p_soldier != NULL)
- {
- HumanPhysClass *hphys = p_soldier->Peek_Human_Phys();
- WWASSERT(hphys != NULL);
- float client_facing = hphys->Get_Heading();
- Vector3 subject_position;
- if (p_netobject->Get_World_Position(subject_position))
- {
- Vector3 position_delta = subject_position - client_pos;
- float subject_facing = WWMath::Atan2(position_delta.Y, position_delta.X);
- float facing_dif = ::fabs(subject_facing - client_facing);
- if (facing_dif > WWMATH_PI)
- {
- facing_dif = 2 * WWMATH_PI - facing_dif;
- }
- facing_factor -= facing_dif / WWMATH_PI * cUserOptions::MaxFacingPenalty.Get();
- }
- }
- return facing_factor;
- }
- //-----------------------------------------------------------------------------
- float
- cPriority::Get_Object_Distance_2
- (
- const Vector3 & client_pos,
- NetworkObjectClass * p_netobject
- )
- {
- WWASSERT(p_netobject != NULL);
- //
- // Objects without a physical location will return a distance of zero.
- //
- float distance = 0;
- //
- // Get the object's world position (if it has one)
- //
- Vector3 position;
- if (p_netobject->Get_World_Position(position))
- {
- //
- // Simple distance calculation based on the distance
- // between points.
- //
- distance = (position - client_pos).Length();
- }
- return distance;
- }
- //-----------------------------------------------------------------------------
- float
- cPriority::Compute_Type_Factor_2
- (
- NetworkObjectClass *p_netobject,
- float distance
- )
- {
- float type_factor = 1.0f;
- char type = p_netobject->Get_App_Packet_Type();
- switch (type) {
- case APPPACKETTYPE_SOLDIER:
- {
- type_factor = SOLDIER_FACTOR;
- SoldierGameObj *soldier = (SoldierGameObj*) p_netobject;
- if (soldier->Is_In_Vehicle()) {
- type_factor = SOLDIER_IN_VEHICLE_FACTOR;
- }
- }
- break;
- case APPPACKETTYPE_TURRET:
- {
- type_factor = TURRET_FACTOR;
- float range_filter = p_netobject->Get_Filter_Distance();
- if (distance > range_filter) {
- type_factor = 0.0f;
- } else {
- if (distance > 100) {
- type_factor = type_factor / 2.0f;
- }
- }
- break;
- }
- case APPPACKETTYPE_VEHICLE:
- type_factor = VEHICLE_FACTOR;
- break;
- case APPPACKETTYPE_BUILDING:
- type_factor = BUILDING_FACTOR;
- break;
- default:
- type_factor = 1.0f;
- }
- return(type_factor);
- }
- //-----------------------------------------------------------------------------
- float
- cPriority::Compute_Relevance_Factor_2
- (
- int client_id,
- NetworkObjectClass * p_netobject,
- SoldierGameObj *client_soldier
- )
- {
- WWASSERT(p_netobject != NULL);
- //
- // This bumps the priority of objects that you are shooting or that are
- // shooting at you.
- //
- bool is_relevant = false;
- int id = p_netobject->Get_Network_ID();
- SoldierGameObj * p_my_soldier = client_soldier;
- VehicleGameObj * p_my_vehicle = NULL;
- if (p_my_soldier == NULL) {
- p_my_soldier = GameObjManager::Find_Soldier_Of_Client_ID(client_id);
- }
- if (p_my_soldier != NULL) {
- if (p_my_soldier->Is_In_Vehicle()) {
- p_my_vehicle = GameObjManager::Find_Vehicle_Occupied_By(p_my_soldier);
- }
- if ((p_my_soldier->Get_Last_Object_Id_I_Damaged() == id ||
- p_my_soldier->Get_Last_Object_Id_I_Got_Damaged_By() == id)) {
- is_relevant = true;
- }
- }
- if (p_my_vehicle != NULL &&
- (p_my_vehicle->Get_Last_Object_Id_I_Damaged() == id ||
- p_my_vehicle->Get_Last_Object_Id_I_Got_Damaged_By() == id)) {
- is_relevant = true;
- }
- float factor = 1.0f;
- if (!is_relevant) {
- factor -= cUserOptions::IrrelevancePenalty.Get();
- }
- WWASSERT(factor > 0);
- return factor;
- }
|