mirror of
https://github.com/thug1src/thug.git
synced 2025-02-18 18:49:06 +00:00
620 lines
18 KiB
C++
620 lines
18 KiB
C++
///////////////////////////////////////////////////////
|
|
// Proxim.cpp
|
|
|
|
|
|
#include <core/defines.h>
|
|
#include <core/singleton.h>
|
|
#include <core/math.h>
|
|
#include <gfx/camera.h>
|
|
#include <gfx/nx.h>
|
|
#include <gel/object/compositeobjectmanager.h>
|
|
#include <gel/scripting/symboltable.h>
|
|
#include <gel/scripting/checksum.h>
|
|
#include <modules/FrontEnd/FrontEnd.h>
|
|
#include <sk/objects/Proxim.h>
|
|
#include <sk/scripting/nodearray.h>
|
|
#include <sk/modules/skate/skate.h>
|
|
#include <sk/gamenet/gamenet.h>
|
|
#include <sk/objects/skater.h> // used to get position of the skater's camera
|
|
#include <sk/objects/moviecam.h>
|
|
|
|
//#define DEBUG_PROXIM
|
|
|
|
namespace Obj
|
|
{
|
|
|
|
void Proxim_Init()
|
|
{
|
|
Mdl::Skate * skate_mod = Mdl::Skate::Instance();
|
|
|
|
if (skate_mod->mpProximManager)
|
|
{
|
|
Proxim_Cleanup();
|
|
}
|
|
skate_mod->mpProximManager = new CProximManager();
|
|
skate_mod->mpProximManager->m_pFirstNode = NULL;
|
|
}
|
|
|
|
void Proxim_Cleanup()
|
|
{
|
|
Mdl::Skate * skate_mod = Mdl::Skate::Instance();
|
|
if (skate_mod->mpProximManager)
|
|
{
|
|
CProximNode *pNode = skate_mod->mpProximManager->m_pFirstNode;
|
|
while (pNode)
|
|
{
|
|
CProximNode *pNext = pNode->m_pNext;
|
|
delete pNode;
|
|
pNode = pNext;
|
|
}
|
|
|
|
delete skate_mod->mpProximManager;
|
|
skate_mod->mpProximManager = NULL;
|
|
}
|
|
}
|
|
|
|
#define CHECKSUM_TERRAIN_TYPE 0x54cf8532 // "terrainType"
|
|
|
|
void Proxim_AddNode(int node,bool active)
|
|
{
|
|
// printf ("It's a Proxim (%d)\n",node);
|
|
Mdl::Skate * skate_mod = Mdl::Skate::Instance();
|
|
Dbg_Assert(skate_mod->mpProximManager);
|
|
|
|
// create a new Proxim node
|
|
CProximNode *pProximNode = new CProximNode();
|
|
|
|
// Link into the head of the Proxim manager
|
|
pProximNode->m_pNext = skate_mod->mpProximManager->m_pFirstNode;
|
|
skate_mod->mpProximManager->m_pFirstNode = pProximNode;
|
|
|
|
pProximNode->m_node = node;
|
|
|
|
pProximNode->m_active = active; // created at start or not?
|
|
|
|
pProximNode->mp_sector = NULL;
|
|
pProximNode->m_shape = CProximNode::vSHAPE_SPHERE;
|
|
|
|
// Get pointer to the Proxim data
|
|
Script::CScriptStructure *pNode = SkateScript::GetNode(node);
|
|
|
|
// Get name
|
|
if (pNode->GetChecksum("name",&pProximNode->m_name))
|
|
{
|
|
#ifdef DEBUG_PROXIM
|
|
printf ("Proxim: Got Name %s\n",Script::FindChecksumName(pProximNode->m_name));
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
Dbg_MsgAssert(0,("No name in proxim node %d\n",node));
|
|
}
|
|
|
|
// Get shape
|
|
uint32 shape_checksum;
|
|
if (pNode->GetChecksum("shape", &shape_checksum))
|
|
{
|
|
pProximNode->m_shape = CProximNode::sGetShapeFromChecksum(shape_checksum);
|
|
}
|
|
|
|
// Try to find geometry
|
|
pProximNode->InitGeometry(Nx::CEngine::sGetMainScene()->GetSector(pProximNode->m_name));
|
|
|
|
SkateScript::GetPosition(pNode,&pProximNode->m_pos);
|
|
#ifdef DEBUG_PROXIM
|
|
Dbg_Message("Proxim: Pos = (%f, %f, %f)", pProximNode->m_pos[X], pProximNode->m_pos[Y], pProximNode->m_pos[Z]);
|
|
#endif
|
|
|
|
pProximNode->m_type = 0;
|
|
pNode->GetInteger( 0x7321a8d6 /* type */, &pProximNode->m_type );
|
|
#ifdef DEBUG_PROXIM
|
|
printf ("Proxim: Type = %d\n",pProximNode->m_type);
|
|
#endif
|
|
pNode->GetFloat (0xc48391a5 /*radius*/, &pProximNode->m_radius);
|
|
Dbg_MsgAssert(pProximNode->mp_sector || pProximNode->m_radius > 0.0f,( "Radius %f too small in proxim node %d\n",pProximNode->m_radius,node));
|
|
#ifdef DEBUG_PROXIM
|
|
printf ("Proxim: Radius = %f\n",pProximNode->m_radius);
|
|
#endif
|
|
pProximNode->m_radius_squared = pProximNode->m_radius * pProximNode->m_radius;
|
|
|
|
if (pNode->GetChecksum(0x2ca8a299,&pProximNode->m_script)) // Checksum of TriggerScript
|
|
{
|
|
#ifdef DEBUG_PROXIM
|
|
printf ("Proxim: Got Script %s\n",Script::FindChecksumName(pProximNode->m_script));
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
Dbg_MsgAssert(0,("No triggerscript in proxim node %d\n",node));
|
|
}
|
|
|
|
|
|
pProximNode->m_proxim_object = 0;
|
|
pProximNode->m_active_objects = 0;
|
|
pProximNode->m_active_scripts = 0;
|
|
if (pNode->ContainsFlag(CRCD(0x5113f19c,"ProximObject")))
|
|
{
|
|
// for proxim objects, it's best if we start "outside" the objects
|
|
// so if we are actually inside, then the event will trigger
|
|
pProximNode->m_outside_flags = 0xffffffff; // say all outside
|
|
pNode->GetChecksum("Name",&pProximNode->m_proxim_object);
|
|
}
|
|
else
|
|
{
|
|
// for non-proxim objects, it's best if we start "inside" the node
|
|
// in case something is depending on the outside script being called first
|
|
// to keep things shut off. We'll do this by starting with it active
|
|
// and then setting it to inactive.
|
|
pProximNode->m_outside_flags = 0; // say all inside for now....
|
|
pProximNode->m_active = true;
|
|
|
|
// Set the script active flag for each skater that exists
|
|
Obj::CObject *p_obj;
|
|
int object_id = 0;
|
|
while ((p_obj = Obj::CCompositeObjectManager::Instance()->GetObjectByID(object_id)) && (object_id < 32))
|
|
{
|
|
Obj::CSkater *p_skater = (Obj::CSkater *) p_obj;
|
|
if (p_skater->IsLocalClient())
|
|
{
|
|
pProximNode->m_active_scripts |= 1 << object_id;
|
|
}
|
|
object_id++;
|
|
}
|
|
|
|
pProximNode->SetActive(false);
|
|
pProximNode->SetActive(active);
|
|
}
|
|
|
|
}
|
|
|
|
void Proxim_AddedAll()
|
|
{
|
|
|
|
// printf("Added all Proxims\n");
|
|
|
|
Mdl::Skate * skate_mod = Mdl::Skate::Instance();
|
|
Dbg_Assert(skate_mod->mpProximManager);
|
|
CProximNode *pProximNode = skate_mod->mpProximManager->m_pFirstNode;
|
|
while (pProximNode)
|
|
{
|
|
// do any final per-node processing here
|
|
pProximNode = pProximNode->m_pNext;
|
|
}
|
|
|
|
}
|
|
|
|
void Proxim_SetActive( int node, int active )
|
|
{
|
|
Mdl::Skate * skate_mod = Mdl::Skate::Instance();
|
|
|
|
if (!skate_mod->mpProximManager) return;
|
|
|
|
CProximNode *pProximNode = skate_mod->mpProximManager->m_pFirstNode;
|
|
while (pProximNode)
|
|
{
|
|
if (pProximNode->m_node == node)
|
|
{
|
|
pProximNode->SetActive(active);
|
|
return;
|
|
}
|
|
pProximNode = pProximNode->m_pNext;
|
|
}
|
|
}
|
|
|
|
CProximNode * CProximManager::sGetNode(uint32 checksum)
|
|
{
|
|
Mdl::Skate * skate_mod = Mdl::Skate::Instance();
|
|
Dbg_Assert(skate_mod->mpProximManager);
|
|
CProximNode *pProximNode = skate_mod->mpProximManager->m_pFirstNode;
|
|
while (pProximNode)
|
|
{
|
|
if (pProximNode->m_name == checksum)
|
|
{
|
|
return pProximNode;
|
|
}
|
|
pProximNode = pProximNode->m_pNext;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
// Update all the proximity nodes
|
|
// for a certain skater
|
|
// checking for proximity either with the skater or the camera
|
|
void Proxim_Update ( uint32 trigger_mask, CObject* p_script_target, const Mth::Vector& pos )
|
|
{
|
|
#if 0 // TT9254: Too many things were having problems with this. The proxim node scripts themselves
|
|
// will have to do this.
|
|
// Don't update if the game is paused
|
|
if( Mdl::FrontEnd::Instance()->GamePaused() && !(Script::GetInteger(CRCD(0x45e46afd,"goal_editor_placement_mode"))) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
#if 0
|
|
// Don't update if the game is playing a CamAnim
|
|
Mdl::Skate* skate_mod = Mdl::Skate::Instance();
|
|
if ( skate_mod->GetMovieManager()->IsRolling() )
|
|
{
|
|
return;
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
CProximManager* proxim_manager = Mdl::Skate::Instance()->mpProximManager;
|
|
|
|
if (!proxim_manager) return;
|
|
|
|
CProximNode *pProximNode = proxim_manager->m_pFirstNode;
|
|
|
|
while (pProximNode)
|
|
{
|
|
if (!pProximNode->m_active)
|
|
{
|
|
pProximNode = pProximNode->m_pNext;
|
|
continue;
|
|
}
|
|
|
|
bool now_inside = pProximNode->CheckInside(pos);
|
|
|
|
if ( trigger_mask & pProximNode->m_outside_flags)
|
|
{
|
|
// trigger is currently outside, check if moved to inside
|
|
if (now_inside)
|
|
{
|
|
|
|
pProximNode->m_outside_flags &= ~trigger_mask;
|
|
|
|
if ( ! pProximNode->m_proxim_object )
|
|
{
|
|
#ifdef DEBUG_PROXIM
|
|
printf ("+++++ NOW INSIDE, mask = %d running script %s \n",trigger_mask, Script::FindChecksumName(pProximNode->m_script));
|
|
#endif
|
|
proxim_manager->m_inside_flag = true;
|
|
proxim_manager->m_inside_flag_valid = true;
|
|
|
|
if (p_script_target)
|
|
{
|
|
p_script_target->SpawnAndRunScript(pProximNode->m_script,pProximNode->m_node );
|
|
Dbg_MsgAssert(p_script_target->GetID() < 32, ("Object ID %d is greater than 31", pProximNode->m_proxim_object));
|
|
pProximNode->m_active_scripts |= 1 << p_script_target->GetID();
|
|
}
|
|
else
|
|
{
|
|
//Script::SpawnScript(pProximNode->m_script, NULL, NO_NAME, NULL, pProximNode->m_node );
|
|
Script::RunScript(pProximNode->m_script);
|
|
}
|
|
|
|
proxim_manager->m_inside_flag_valid = false;
|
|
}
|
|
else if (p_script_target)
|
|
{
|
|
// Need to create an object with the id pProximNode->m_proxim_object
|
|
|
|
#ifdef DEBUG_PROXIM
|
|
printf ("+++++ NOW INSIDE, creating object %s running script %s \n",Script::FindChecksumName(pProximNode->m_proxim_object),Script::FindChecksumName(pProximNode->m_script));
|
|
#endif
|
|
|
|
Obj::CCompositeObject* pObj = Obj::CCompositeObjectManager::Instance()->CreateCompositeObject();
|
|
pObj->SetID(pProximNode->m_proxim_object + p_script_target->GetID()); // Mick mangle the proxim object ID with the player's ID
|
|
pObj->m_pos = pProximNode->m_pos ;
|
|
|
|
Dbg_MsgAssert(p_script_target->GetID() < 32, ("Object ID %d is greater than 31", pProximNode->m_proxim_object));
|
|
pProximNode->m_active_objects |= 1 << p_script_target->GetID();
|
|
|
|
Script::CStruct component_params; // ProximNode params
|
|
if (pProximNode->HasGeometry())
|
|
{
|
|
// Only add if we want the geometry used
|
|
component_params.AddChecksum("ProximNode", pProximNode->m_name);
|
|
}
|
|
pObj->CreateComponentsFromArray(Script::GetArray("proximobj_composite_structure"), &component_params);
|
|
pObj->Finalize();
|
|
|
|
Script::CStruct params; // dummy empty params
|
|
pObj->SwitchScript(pProximNode->m_script,¶ms);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// skater is currently inside, check if moved outside
|
|
if (!now_inside)
|
|
{
|
|
pProximNode->m_outside_flags |= trigger_mask;
|
|
if ( ! pProximNode->m_proxim_object )
|
|
{
|
|
#ifdef DEBUG_PROXIM
|
|
printf ("----- NOW OUTSIDE, mask = %d running script %s \n",trigger_mask,Script::FindChecksumName(pProximNode->m_script));
|
|
#endif
|
|
proxim_manager->m_inside_flag = false;
|
|
proxim_manager->m_inside_flag_valid = true;
|
|
|
|
if (p_script_target)
|
|
{
|
|
p_script_target->SpawnAndRunScript(pProximNode->m_script,pProximNode->m_node );
|
|
pProximNode->m_active_scripts &= ~(1 << p_script_target->GetID());
|
|
}
|
|
else
|
|
{
|
|
//Script::SpawnScript(pProximNode->m_script, NULL, NO_NAME, NULL, pProximNode->m_node );
|
|
Script::RunScript(pProximNode->m_script);
|
|
}
|
|
|
|
proxim_manager->m_inside_flag_valid = false;
|
|
}
|
|
else if (p_script_target)
|
|
{
|
|
// Need to create an object with the id pProximNode->m_proxim_object
|
|
|
|
#ifdef DEBUG_PROXIM
|
|
printf ("+++++ NOW OUTSIDE, killing %s running script %s \n",Script::FindChecksumName(pProximNode->m_proxim_object),Script::FindChecksumName(pProximNode->m_script));
|
|
#endif
|
|
Obj::CObject *p_obj = Obj::CCompositeObjectManager::Instance()->GetObjectByID(pProximNode->m_proxim_object + p_script_target->GetID());
|
|
if (p_obj)
|
|
{
|
|
p_obj->MarkAsDead();
|
|
}
|
|
pProximNode->m_active_objects &= ~(1 << p_script_target->GetID());
|
|
}
|
|
}
|
|
}
|
|
pProximNode = pProximNode->m_pNext;
|
|
}
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
CProximNode::EShape CProximNode::sGetShapeFromChecksum(uint32 checksum)
|
|
{
|
|
switch (checksum)
|
|
{
|
|
case 0xaa069978: // Sphere
|
|
return vSHAPE_SPHERE;
|
|
|
|
case 0xe460abde: // BoundingBox
|
|
return vSHAPE_BBOX;
|
|
|
|
case 0x3f1e5a7: // NonAxisAlignedBoundingBox
|
|
return vSHAPE_NON_AA_BBOX;
|
|
|
|
case 0x64fba415: // Cylinder
|
|
return vSHAPE_CYLINDER;
|
|
|
|
case 0x6aadf154: // Geometry
|
|
return vSHAPE_GEOMETRY;
|
|
|
|
default:
|
|
Dbg_MsgAssert(0, ("Unknown shape checksum %x\n", checksum));
|
|
return vSHAPE_SPHERE;
|
|
}
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
void CProximNode::SetActive(bool active)
|
|
{
|
|
// Check for changes
|
|
if (m_active != active)
|
|
{
|
|
if (m_active)
|
|
{
|
|
// Turning off node, so treat like were going outside
|
|
if ( m_proxim_object )
|
|
{
|
|
// Delete all created objects
|
|
#ifdef DEBUG_PROXIM
|
|
printf ("----- SETTING ProximNode INACTIVE, killing %s running script %s \n",Script::FindChecksumName(m_proxim_object),Script::FindChecksumName(m_script));
|
|
#endif
|
|
int object_id = 0;
|
|
while (m_active_objects)
|
|
{
|
|
if (m_active_objects & 0x1) // Check if this ID is turned on
|
|
{
|
|
Obj::CObject *p_obj = Obj::CCompositeObjectManager::Instance()->GetObjectByID(m_proxim_object + object_id);
|
|
if (p_obj)
|
|
{
|
|
p_obj->MarkAsDead();
|
|
}
|
|
}
|
|
|
|
// Advance ID
|
|
m_active_objects = m_active_objects >> 1;
|
|
object_id++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#ifdef DEBUG_PROXIM
|
|
printf ("----- SETTING ProximNode INACTIVE, running script %s \n",Script::FindChecksumName(m_script));
|
|
#endif
|
|
CProximManager* proxim_manager = Mdl::Skate::Instance()->mpProximManager;
|
|
|
|
if (proxim_manager)
|
|
{
|
|
int object_id = 0;
|
|
while (m_active_scripts)
|
|
{
|
|
if (m_active_scripts & 0x1) // Check if this ID is turned on
|
|
{
|
|
Obj::CObject *p_obj = Obj::CCompositeObjectManager::Instance()->GetObjectByID(object_id);
|
|
Dbg_MsgAssert(p_obj, ("Can't find object to play script on"));
|
|
proxim_manager->m_inside_flag = false;
|
|
|
|
proxim_manager->m_inside_flag_valid = true;
|
|
p_obj->SpawnAndRunScript( m_script, m_node );
|
|
proxim_manager->m_inside_flag_valid = false;
|
|
}
|
|
|
|
// Advance ID
|
|
m_active_scripts = m_active_scripts >> 1;
|
|
object_id++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Make everything outside
|
|
m_outside_flags = 0xffffffff;
|
|
|
|
m_active = active;
|
|
}
|
|
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
void CProximNode::InitGeometry(Nx::CSector *p_sector)
|
|
{
|
|
mp_sector = p_sector;
|
|
|
|
if (!mp_sector)
|
|
{
|
|
// No Geometry
|
|
Dbg_MsgAssert(m_shape == CProximNode::vSHAPE_SPHERE, ("ProximNode %s with shape %d has no geometry.", Script::FindChecksumName(m_name), m_shape));
|
|
return;
|
|
}
|
|
|
|
#ifdef DEBUG_PROXIM
|
|
Dbg_Message("Found Geometry for Proxim node %s at address %x", Script::FindChecksumName(m_name), mp_sector);
|
|
#endif
|
|
|
|
switch (m_shape)
|
|
{
|
|
case CProximNode::vSHAPE_SPHERE:
|
|
Dbg_MsgAssert(0, ("ProximNode with sphere shape has geometry."));
|
|
break;
|
|
|
|
case CProximNode::vSHAPE_BBOX:
|
|
m_bbox = mp_sector->GetBoundingBox();
|
|
#ifdef DEBUG_PROXIM
|
|
Dbg_Message("Bounding box of geometry (%f, %f, %f) - (%f, %f, %f)",
|
|
m_bbox.GetMin()[X], m_bbox.GetMin()[Y], m_bbox.GetMin()[Z],
|
|
m_bbox.GetMax()[X], m_bbox.GetMax()[Y], m_bbox.GetMax()[Z]);
|
|
#endif
|
|
break;
|
|
|
|
case CProximNode::vSHAPE_NON_AA_BBOX:
|
|
Dbg_MsgAssert(0, ("ProximNode with non axis aligned bounding box shape not supported yet."));
|
|
break;
|
|
|
|
case CProximNode::vSHAPE_CYLINDER:
|
|
Dbg_MsgAssert(0, ("ProximNode with cylinder shape not supported yet."));
|
|
break;
|
|
case CProximNode::vSHAPE_GEOMETRY:
|
|
Dbg_MsgAssert(0, ("ProximNode with geometry shape not supported yet."));
|
|
break;
|
|
}
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
bool CProximNode::HasGeometry() const
|
|
{
|
|
return mp_sector != NULL;
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
bool CProximNode::CheckInside(const Mth::Vector &object_pos) const
|
|
{
|
|
Mth::Vector node_to_object = object_pos - m_pos;
|
|
float dist_squared = node_to_object.LengthSqr();
|
|
|
|
bool inside = false;
|
|
|
|
switch (m_shape)
|
|
{
|
|
case vSHAPE_SPHERE:
|
|
inside = (dist_squared <= m_radius_squared);
|
|
break;
|
|
|
|
case vSHAPE_BBOX:
|
|
inside = m_bbox.Within(object_pos);
|
|
#ifdef DEBUG_PROXIM
|
|
m_bbox.DebugRender(0xff0000ff);
|
|
{
|
|
Mth::Vector closest_point;
|
|
m_bbox.GetClosestIntersectPoint(object_pos, closest_point);
|
|
// Gfx::AddDebugStar(closest_point);
|
|
}
|
|
#endif // DEBUG_PROXIM
|
|
break;
|
|
|
|
default:
|
|
Dbg_MsgAssert(0, ("Can't handle ProximNode type %d", m_shape));
|
|
}
|
|
|
|
return inside;
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
Mth::Vector CProximNode::GetClosestIntersectionPoint(const Mth::Vector &object_pos) const
|
|
{
|
|
Mth::Vector intersect_point;
|
|
|
|
switch (m_shape)
|
|
{
|
|
case vSHAPE_SPHERE:
|
|
{
|
|
// Same for either within or outside sphere
|
|
Mth::Vector direction = object_pos - m_pos;
|
|
direction.Normalize();
|
|
direction *= m_radius;
|
|
|
|
intersect_point = m_pos + direction;
|
|
}
|
|
break;
|
|
|
|
case vSHAPE_BBOX:
|
|
m_bbox.GetClosestIntersectPoint(object_pos, intersect_point);
|
|
break;
|
|
|
|
default:
|
|
Dbg_MsgAssert(0, ("Can't handle ProximNode type %d", m_shape));
|
|
break;
|
|
}
|
|
|
|
#ifdef DEBUG_PROXIM
|
|
// Gfx::AddDebugStar(intersect_point);
|
|
#endif // DEBUG_PROXIM
|
|
|
|
return intersect_point;
|
|
}
|
|
|
|
/*
|
|
{
|
|
// Node 572 (Mick Test)
|
|
Position = (-4060.666992,131.999329,-4604.379395)
|
|
Angles = (0.000000,-3.141593,0.000000)
|
|
Name = TRG_Micks_test
|
|
Class = ProximNode
|
|
Type = skater
|
|
radius = 1200
|
|
TriggerScript = xxx_test
|
|
}
|
|
*/
|
|
|
|
|
|
}
|
|
|
|
|