Subversion Repositories Games.Carmageddon

Rev

Rev 1 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. #include "piping.h"
  2. #include "brender.h"
  3. #include "car.h"
  4. #include "crush.h"
  5. #include "errors.h"
  6. #include "formats.h"
  7. #include "globvars.h"
  8. #include "globvrpb.h"
  9. #include "graphics.h"
  10. #include "harness/trace.h"
  11. #include "oil.h"
  12. #include "opponent.h"
  13. #include "pedestrn.h"
  14. #include "replay.h"
  15. #include "skidmark.h"
  16. #include "sound.h"
  17. #include "spark.h"
  18. #include "sys.h"
  19. #include "utility.h"
  20. #include "world.h"
  21. #include <stdlib.h>
  22. #include <string.h>
  23.  
  24. tU8* gPipe_buffer_start = NULL;
  25. int gDisable_sound = 0;
  26. int gDisable_advance = 0;
  27. int gMax_rewind_chunks = 1000;
  28. float gWall_severity = 0.f;
  29. tPipe_reset_proc* gReset_procs[32] = {
  30.     NULL,
  31.     NULL,
  32.     NULL,
  33.     NULL,
  34.     NULL,
  35.     NULL,
  36.     NULL,
  37.     NULL,
  38.     NULL,
  39.     NULL,
  40.     NULL,
  41.     ResetAllPedestrians,
  42.     NULL,
  43.     NULL,
  44.     NULL,
  45.     NULL,
  46.     NULL,
  47.     ResetAllPedGibs,
  48.     NULL,
  49.     ResetSparks,
  50.     ResetShrapnel,
  51.     ResetScreenWobble,
  52.     NULL,
  53.     NULL,
  54.     ResetSmoke,
  55.     NULL,
  56.     NULL,
  57.     NULL,
  58.     NULL,
  59.     NULL,
  60.     ResetProxRay,
  61.     NULL,
  62. };
  63. tPiped_registration_snapshot gRegistration_snapshots[5];
  64. tPipe_smudge_data* gSmudge_space;
  65. tU32 gOldest_time;
  66. int gCurrent_snapshot_registration_index;
  67. tPipe_chunk* gMr_chunky;
  68. tCar_spec* gCar_ptr;
  69. br_vector3 gZero_vector;
  70. tPipe_chunk_type gReentrancy_array[5];
  71. tU32 gLast_time;
  72. tPipe_model_geometry_data* gModel_geometry_space;
  73. tU32 gEnd_time;
  74. tU32 gTrigger_time;
  75. int gReentrancy_count;
  76. br_vector3 gCar_pos;
  77. br_vector3 gReference_pos;
  78. br_scalar gMax_distance;
  79. tU32 gLoop_abort_time;
  80. br_vector3 gWall_impact_point;
  81. tU8* gPipe_buffer_working_end;
  82. tU32 gYoungest_time;
  83. tU8* gPipe_buffer_phys_end;
  84. tU8* gLocal_buffer_record_ptr;
  85. tU8* gPipe_play_ptr;
  86. tU8* gEnd_of_session;
  87. tU8* gPipe_record_ptr;
  88. tU8* gPipe_buffer_oldest;
  89. tU32 gPipe_buffer_size;
  90. tU8* gLocal_buffer;
  91. tU32 gLocal_buffer_size;
  92. tPipe_chunk* gIncidentChunk; // FIXME: added by DethRace (really needed?)
  93.  
  94. #define LOCAL_BUFFER_SIZE 15000
  95.  
  96. #if defined(DETHRACE_REPLAY_DEBUG)
  97. #define REPLAY_DEBUG_CHUNK_MAGIC1 0x1ed6ef85
  98. #define REPLAY_DEBUG_SESSION_MAGIC1 0x617bbc04
  99. #define REPLAY_DEBUG_ASSERT(test) assert(test)
  100. #include <assert.h>
  101. #else
  102. #define REPLAY_DEBUG_ASSERT(test)
  103. #endif
  104.  
  105. #if defined(DETHRACE_FIX_BUGS)
  106. #define PIPE_ALIGN(V) (((V) + sizeof(void*) - 1) & ~(sizeof(void*) - 1))
  107. #endif
  108.  
  109. // IDA: void __usercall GetReducedPos(br_vector3 *v@<EAX>, tReduced_pos *p@<EDX>)
  110. void GetReducedPos(br_vector3* v, tReduced_pos* p) {
  111.     LOG_TRACE("(%p, %p)", v, p);
  112.  
  113.     v->v[0] = p->v[0] / 800.f;
  114.     v->v[1] = p->v[1] / 800.f;
  115.     v->v[2] = p->v[2] / 800.f;
  116.     BrVector3Accumulate(v, &gProgram_state.current_car.car_master_actor->t.t.translate.t);
  117. }
  118.  
  119. // IDA: void __usercall SaveReducedPos(tReduced_pos *p@<EAX>, br_vector3 *v@<EDX>)
  120. void SaveReducedPos(tReduced_pos* p, br_vector3* v) {
  121.     br_vector3 tv;
  122.     LOG_TRACE("(%p, %p)", p, v);
  123.  
  124.     BrVector3Sub(&tv, v, &gProgram_state.current_car.car_master_actor->t.t.translate.t);
  125.     p->v[0] = tv.v[0] * 800.f;
  126.     p->v[1] = tv.v[1] * 800.f;
  127.     p->v[2] = tv.v[2] * 800.f;
  128. }
  129.  
  130. // IDA: int __cdecl PipeSearchForwards()
  131. int PipeSearchForwards(void) {
  132.     LOG_TRACE("()");
  133.  
  134.     if (gPipe_play_ptr == gPipe_record_ptr) {
  135.         return 0;
  136.     }
  137.     if (gPipe_play_ptr == gPipe_buffer_oldest) {
  138.         return 1;
  139.     }
  140.     if (GetReplayRate() == 0.f) {
  141.         return GetReplayDirection() > 0;
  142.     } else {
  143.         return GetReplayRate() > 0.f;
  144.     }
  145. }
  146.  
  147. // IDA: int __cdecl IsActionReplayAvailable()
  148. int IsActionReplayAvailable(void) {
  149.     LOG_TRACE("()");
  150.  
  151.     return gPipe_buffer_start != NULL;
  152. }
  153.  
  154. // IDA: int __cdecl SomeReplayLeft()
  155. int SomeReplayLeft(void) {
  156.     LOG_TRACE("()");
  157.  
  158.     return ((GetReplayDirection() >= 1 && gPipe_play_ptr != gPipe_record_ptr) || (GetReplayDirection() <= -1 && gPipe_play_ptr != gPipe_buffer_oldest));
  159. }
  160.  
  161. // IDA: void __cdecl DisablePipedSounds()
  162. void DisablePipedSounds(void) {
  163.     LOG_TRACE("()");
  164.  
  165.     gDisable_sound = 1;
  166. }
  167.  
  168. // IDA: void __cdecl EnablePipedSounds()
  169. void EnablePipedSounds(void) {
  170.     LOG_TRACE("()");
  171.  
  172.     gDisable_sound = 0;
  173. }
  174.  
  175. // IDA: tU32 __usercall LengthOfSession@<EAX>(tPipe_session *pSession@<EAX>)
  176. tU32 LengthOfSession(tPipe_session* pSession) {
  177.     int i;
  178.     tU32 running_total;
  179.     tPipe_chunk* the_chunk;
  180.     LOG_TRACE("(%p)", pSession);
  181.  
  182. #define SIZEOF_CHUNK(MEMBER) (offsetof(tPipe_chunk, chunk_data) + sizeof(pSession->chunks.chunk_data.MEMBER))
  183. #define ROUND_UP(V, M) (((V) + (M)-1) & (~((M)-1)))
  184.  
  185.     REPLAY_DEBUG_ASSERT(pSession->pipe_magic1 == REPLAY_DEBUG_SESSION_MAGIC1);
  186.  
  187.     switch (pSession->chunk_type) {
  188.     case ePipe_chunk_actor_rstyle:
  189.         running_total = SIZEOF_CHUNK(actor_rstyle_data) * pSession->number_of_chunks;
  190.         break;
  191.     case ePipe_chunk_actor_translate:
  192.         running_total = SIZEOF_CHUNK(actor_translate_data) * pSession->number_of_chunks;
  193.         break;
  194.     case ePipe_chunk_actor_transform:
  195.         running_total = SIZEOF_CHUNK(actor_transform_data) * pSession->number_of_chunks;
  196.         break;
  197.     case ePipe_chunk_actor_create:
  198.         running_total = 0;
  199.         break;
  200.     case ePipe_chunk_actor_destroy:
  201.         running_total = 0;
  202.         break;
  203.     case ePipe_chunk_actor_relink:
  204.         running_total = SIZEOF_CHUNK(actor_relink_data) * pSession->number_of_chunks;
  205.         break;
  206.     case ePipe_chunk_actor_material:
  207.         running_total = SIZEOF_CHUNK(actor_material_data) * pSession->number_of_chunks;
  208.         break;
  209.     case ePipe_chunk_face_material:
  210.         running_total = SIZEOF_CHUNK(face_material_data) * pSession->number_of_chunks;
  211.         break;
  212.     case ePipe_chunk_material_trans:
  213.         running_total = SIZEOF_CHUNK(material_trans_data) * pSession->number_of_chunks;
  214.         break;
  215.     case ePipe_chunk_material_pixelmap:
  216.         running_total = SIZEOF_CHUNK(material_pixelmap_data) * pSession->number_of_chunks;
  217.         break;
  218.     case ePipe_chunk_model_geometry:
  219.         running_total = 0;
  220.         for (i = 0; i < pSession->number_of_chunks; i++) {
  221.             the_chunk = (tPipe_chunk*)&((tU8*)&pSession->chunks)[running_total];
  222.             running_total += the_chunk->chunk_data.model_geometry_data.vertex_count * sizeof(tChanged_vertex) + offsetof(tPipe_model_geometry_data, vertex_changes) + offsetof(tPipe_chunk, chunk_data);
  223.         }
  224.         break;
  225.     case ePipe_chunk_pedestrian:
  226.         running_total = 0;
  227.         for (i = 0; i < pSession->number_of_chunks; i++) {
  228.             the_chunk = (tPipe_chunk*)&(((tU8*)&pSession->chunks)[running_total]);
  229.             if (the_chunk->chunk_data.pedestrian_data.hit_points <= 0) {
  230.                 running_total += SIZEOF_CHUNK(pedestrian_data);
  231.             } else {
  232.                 running_total += offsetof(tPipe_pedestrian_data, spin_period) + offsetof(tPipe_chunk, chunk_data);
  233.             }
  234.         }
  235.         break;
  236.     case ePipe_chunk_frame_boundary:
  237.         running_total = SIZEOF_CHUNK(frame_boundary_data);
  238.         break;
  239.     case ePipe_chunk_car:
  240.         running_total = SIZEOF_CHUNK(car_data) * pSession->number_of_chunks;
  241.         break;
  242.     case ePipe_chunk_sound:
  243.         running_total = SIZEOF_CHUNK(sound_data) * pSession->number_of_chunks;
  244.         break;
  245.     case ePipe_chunk_damage:
  246.         running_total = SIZEOF_CHUNK(damage_data);
  247.         break;
  248.     case ePipe_chunk_special:
  249.         running_total = SIZEOF_CHUNK(special_data) * pSession->number_of_chunks;
  250.         break;
  251.     case ePipe_chunk_ped_gib:
  252.         running_total = SIZEOF_CHUNK(ped_gib_data) * pSession->number_of_chunks;
  253.         break;
  254.     case ePipe_chunk_incident:
  255.         running_total = SIZEOF_CHUNK(incident_data) * pSession->number_of_chunks;
  256.         break;
  257.     case ePipe_chunk_spark:
  258.         running_total = SIZEOF_CHUNK(spark_data) * pSession->number_of_chunks;
  259.         break;
  260.     case ePipe_chunk_shrapnel:
  261.         running_total = 0;
  262.         for (i = 0; i < pSession->number_of_chunks; i++) {
  263.             the_chunk = (tPipe_chunk*)&((tU8*)&pSession->chunks)[running_total];
  264.             if (the_chunk->subject_index & 0x8000) {
  265.                 running_total += SIZEOF_CHUNK(shrapnel_data);
  266.             } else {
  267.                 running_total += offsetof(tPipe_shrapnel_data, age) + offsetof(tPipe_chunk, chunk_data);
  268.             }
  269.         }
  270.         break;
  271.     case ePipe_chunk_screen_shake:
  272.         running_total = SIZEOF_CHUNK(screen_shake_data) * pSession->number_of_chunks;
  273.         break;
  274.     case ePipe_chunk_groove_stop:
  275.         running_total = SIZEOF_CHUNK(groove_stop_data) * pSession->number_of_chunks;
  276.         break;
  277.     case ePipe_chunk_non_car:
  278.         running_total = SIZEOF_CHUNK(non_car_data) * pSession->number_of_chunks;
  279.         break;
  280.     case ePipe_chunk_smoke:
  281.         running_total = SIZEOF_CHUNK(smoke_data) * pSession->number_of_chunks;
  282.         break;
  283.     case ePipe_chunk_oil_spill:
  284.         running_total = SIZEOF_CHUNK(oil_data) * pSession->number_of_chunks;
  285.         break;
  286.     case ePipe_chunk_smoke_column:
  287.         running_total = ROUND_UP(SIZEOF_CHUNK(smoke_column_data), 4) * pSession->number_of_chunks;
  288.         break;
  289.     case ePipe_chunk_flame:
  290.         running_total = SIZEOF_CHUNK(flame_data) * pSession->number_of_chunks;
  291.         break;
  292.     case ePipe_chunk_smudge:
  293.         running_total = 0;
  294.         for (i = 0; i < pSession->number_of_chunks; i++) {
  295.             the_chunk = (tPipe_chunk*)&((tU8*)&pSession->chunks)[running_total];
  296.             running_total += the_chunk->chunk_data.smudge_data.vertex_count * sizeof(tSmudged_vertex) + offsetof(tPipe_smudge_data, vertex_changes) + offsetof(tPipe_chunk, chunk_data);
  297.         }
  298.         break;
  299.     case ePipe_chunk_splash:
  300.         running_total = SIZEOF_CHUNK(splash_data) * pSession->number_of_chunks;
  301.         break;
  302.     case ePipe_chunk_prox_ray:
  303.         running_total = SIZEOF_CHUNK(prox_ray_data) * pSession->number_of_chunks;
  304.         break;
  305.     case ePipe_chunk_skid_adjustment:
  306.         running_total = SIZEOF_CHUNK(skid_adjustment) * pSession->number_of_chunks;
  307.         break;
  308.     default:
  309.         running_total = 0;
  310.         break;
  311.     }
  312.     running_total += offsetof(tPipe_session, chunks) + sizeof(tU16);
  313.     if (running_total % 2 != 0) {
  314.         FatalError(kFatalError_PipingSystem);
  315.     }
  316.     return running_total;
  317. }
  318.  
  319. // IDA: void __usercall StartPipingSession2(tPipe_chunk_type pThe_type@<EAX>, int pMunge_reentrancy@<EDX>)
  320. void StartPipingSession2(tPipe_chunk_type pThe_type, int pMunge_reentrancy) {
  321.     LOG_TRACE("(%d, %d)", pThe_type, pMunge_reentrancy);
  322.  
  323.     if (gPipe_buffer_start != NULL && !gAction_replay_mode && gProgram_state.racing) {
  324.         if (pMunge_reentrancy) {
  325.             if (gReentrancy_count != 0) {
  326.                 gReentrancy_array[gReentrancy_count - 1] = ((tPipe_session*)gLocal_buffer)->chunk_type;
  327.                 EndPipingSession2(0);
  328.             }
  329.             gReentrancy_count++;
  330.         }
  331.         ((tPipe_session*)gLocal_buffer)->chunk_type = pThe_type;
  332.         ((tPipe_session*)gLocal_buffer)->number_of_chunks = 0;
  333. #if defined(DETHRACE_REPLAY_DEBUG)
  334.         ((tPipe_session*)gLocal_buffer)->pipe_magic1 = REPLAY_DEBUG_SESSION_MAGIC1;
  335. #endif
  336.         gLocal_buffer_size = offsetof(tPipe_session, chunks);
  337.         gMr_chunky = &((tPipe_session*)gLocal_buffer)->chunks;
  338.     }
  339. }
  340.  
  341. // IDA: void __usercall StartPipingSession(tPipe_chunk_type pThe_type@<EAX>)
  342. void StartPipingSession(tPipe_chunk_type pThe_type) {
  343.     LOG_TRACE("(%d)", pThe_type);
  344.  
  345.     StartPipingSession2(pThe_type, 1);
  346. }
  347.  
  348. // IDA: void __usercall EndPipingSession2(int pMunge_reentrancy@<EAX>)
  349. void EndPipingSession2(int pMunge_reentrancy) {
  350.     int a;
  351.     LOG_TRACE("(%d)", pMunge_reentrancy);
  352.  
  353.     if (gPipe_buffer_start != NULL && !gAction_replay_mode && gProgram_state.racing) {
  354.         // Each session ends with a tU16, containing the session size
  355.         *(tU16*)&gLocal_buffer[gLocal_buffer_size] = gLocal_buffer_size;
  356.         a = gLocal_buffer_size;
  357.         gLocal_buffer_size += sizeof(tU16);
  358.         REPLAY_DEBUG_ASSERT(LengthOfSession((tPipe_session*)gLocal_buffer) == gLocal_buffer_size);
  359. #if defined(DETHRACE_FIX_BUGS)
  360.         gLocal_buffer_size = PIPE_ALIGN(gLocal_buffer_size);
  361.         *(tU16*)&gLocal_buffer[gLocal_buffer_size - sizeof(tU16)] = gLocal_buffer_size - sizeof(tU16);
  362. #endif
  363.         if (((tPipe_session*)gLocal_buffer)->number_of_chunks != 0 && (gLocal_buffer_size < LOCAL_BUFFER_SIZE || a == LOCAL_BUFFER_SIZE - 2)) {
  364.             if (gPipe_buffer_phys_end < gPipe_record_ptr + gLocal_buffer_size) {
  365.                 // Put session at begin of pipe, as no place at end
  366.                 gPipe_buffer_working_end = gPipe_record_ptr;
  367.                 gPipe_buffer_oldest = gPipe_buffer_start;
  368.                 gPipe_record_ptr = gPipe_buffer_start;
  369.             }
  370.             while (gPipe_record_ptr <= gPipe_buffer_oldest && gPipe_buffer_oldest < gPipe_record_ptr + gLocal_buffer_size) {
  371.                 // Remove older sessions
  372. #if defined(DETHRACE_FIX_BUGS)
  373.                 gPipe_buffer_oldest += PIPE_ALIGN(LengthOfSession((tPipe_session*)gPipe_buffer_oldest));
  374. #else
  375.                 gPipe_buffer_oldest += LengthOfSession((tPipe_session*)gPipe_buffer_oldest);
  376. #endif
  377.                 if (gPipe_buffer_working_end <= gPipe_buffer_oldest) {
  378.                     gPipe_buffer_working_end = gPipe_buffer_phys_end;
  379.                     gPipe_buffer_oldest = gPipe_buffer_start;
  380.                 }
  381.             }
  382.             if (gPipe_buffer_oldest == NULL) {
  383.                 gPipe_buffer_oldest = gPipe_record_ptr;
  384.             }
  385.             memcpy(gPipe_record_ptr, gLocal_buffer, gLocal_buffer_size);
  386.             gPipe_record_ptr += gLocal_buffer_size;
  387.             if (gPipe_buffer_working_end < gPipe_record_ptr) {
  388.                 gPipe_buffer_working_end = gPipe_record_ptr;
  389.             }
  390.         }
  391.         if (pMunge_reentrancy) {
  392.             if (gReentrancy_count != 0) {
  393.                 gReentrancy_count--;
  394.                 if (gReentrancy_count != 0) {
  395.                     StartPipingSession2(gReentrancy_array[gReentrancy_count - 1], 0);
  396.                 }
  397.             }
  398.         }
  399.     }
  400. }
  401.  
  402. // IDA: void __cdecl EndPipingSession()
  403. void EndPipingSession(void) {
  404.     LOG_TRACE("()");
  405.  
  406.     EndPipingSession2(1);
  407. }
  408.  
  409. // IDA: void __usercall AddDataToSession(int pSubject_index@<EAX>, void *pData@<EDX>, tU32 pData_length@<EBX>)
  410. void AddDataToSession(int pSubject_index, void* pData, tU32 pData_length) {
  411.     tU32 temp_buffer_size;
  412.     //int variable_for_breaking_on; // Pierre-Marie Baty -- unused variable
  413.     LOG_TRACE("(%d, %p, %d)", pSubject_index, pData, pData_length);
  414.  
  415.     if (gPipe_buffer_start != NULL && !gAction_replay_mode && gProgram_state.racing) {
  416.         temp_buffer_size = gLocal_buffer_size + offsetof(tPipe_chunk, chunk_data) + pData_length;
  417.         if (temp_buffer_size >= LOCAL_BUFFER_SIZE) {
  418.             return;
  419.         }
  420.         REPLAY_DEBUG_ASSERT(((tPipe_session*)gLocal_buffer)->pipe_magic1 == REPLAY_DEBUG_SESSION_MAGIC1);
  421.         ((tPipe_session*)gLocal_buffer)->number_of_chunks++;
  422.         gMr_chunky->subject_index = pSubject_index;
  423. #if defined(DETHRACE_REPLAY_DEBUG)
  424.         gMr_chunky->chunk_magic1 = REPLAY_DEBUG_CHUNK_MAGIC1;
  425. #endif
  426.         memcpy(&gMr_chunky->chunk_data, pData, pData_length);
  427.         gMr_chunky = (tPipe_chunk*)(((tU8*)&gMr_chunky->chunk_data) + pData_length);
  428.         gLocal_buffer_size = temp_buffer_size;
  429.     }
  430. }
  431.  
  432. // IDA: void __usercall AddModelGeometryToPipingSession(tU16 pCar_ID@<EAX>, int pModel_index@<EDX>, int pVertex_count@<EBX>, tChanged_vertex *pCoordinates@<ECX>)
  433. void AddModelGeometryToPipingSession(tU16 pCar_ID, int pModel_index, int pVertex_count, tChanged_vertex* pCoordinates) {
  434.     tU32 data_size;
  435.     LOG_TRACE("(%d, %d, %d, %p)", pCar_ID, pModel_index, pVertex_count, pCoordinates);
  436.  
  437.     if (gModel_geometry_space != NULL) {
  438.         if (pVertex_count > 600) {
  439.             pVertex_count = 600;
  440.         }
  441.         data_size = offsetof(tPipe_model_geometry_data, vertex_changes) + pVertex_count * sizeof(tChanged_vertex);
  442.         gModel_geometry_space->vertex_count = pVertex_count;
  443.         gModel_geometry_space->model_index = pModel_index;
  444.         memcpy(gModel_geometry_space->vertex_changes, pCoordinates, pVertex_count * sizeof(tChanged_vertex));
  445.         AddDataToSession(pCar_ID, gModel_geometry_space, data_size);
  446.     }
  447. }
  448.  
  449. // IDA: void __usercall AddSmudgeToPipingSession(tU16 pCar_ID@<EAX>, int pModel_index@<EDX>, int pVertex_count@<EBX>, tSmudged_vertex *pCoordinates@<ECX>)
  450. void AddSmudgeToPipingSession(tU16 pCar_ID, int pModel_index, int pVertex_count, tSmudged_vertex* pCoordinates) {
  451.     tU32 data_size;
  452.     LOG_TRACE("(%d, %d, %d, %p)", pCar_ID, pModel_index, pVertex_count, pCoordinates);
  453.  
  454.     if (gSmudge_space != NULL) {
  455.         if (pVertex_count > 600) {
  456.             pVertex_count = 600;
  457.         }
  458.         gSmudge_space->vertex_count = pVertex_count;
  459.         gSmudge_space->model_index = pModel_index;
  460.         memcpy(gSmudge_space->vertex_changes, pCoordinates, pVertex_count * sizeof(tSmudged_vertex));
  461.         data_size = offsetof(tPipe_smudge_data, vertex_changes) + pVertex_count * sizeof(tSmudged_vertex);
  462.         AddDataToSession(pCar_ID, gSmudge_space, data_size);
  463.     }
  464. }
  465.  
  466. // IDA: void __usercall AddPedestrianToPipingSession(int pPedestrian_index@<EAX>, br_matrix34 *pTrans@<EDX>, tU8 pAction_index@<EBX>, tU8 pFrame_index@<ECX>, tS8 pHit_points, int pDone_initial, tU16 pParent_ID, float pSpin_period, br_scalar pJump_magnitude, br_vector3 *pOffset)
  467. void AddPedestrianToPipingSession(int pPedestrian_index, br_matrix34* pTrans, tU8 pAction_index, tU8 pFrame_index, tS8 pHit_points, int pDone_initial, tU16 pParent_ID, float pSpin_period, br_scalar pJump_magnitude, br_vector3* pOffset) {
  468.     tPipe_pedestrian_data data;
  469.     tU32 data_size;
  470.     LOG_TRACE("(%d, %p, %d, %d, %d, %d, %d, %f, %f, %p)", pPedestrian_index, pTrans, pAction_index, pFrame_index, pHit_points, pDone_initial, pParent_ID, pSpin_period, pJump_magnitude, pOffset);
  471.  
  472.     if (pFrame_index == 0xff) {
  473.         pFrame_index = 0;
  474.     }
  475.     data.action_and_frame_index = (pDone_initial ? 1 : 0) << 7 | pAction_index << 4 | pFrame_index;
  476.     data.hit_points = pHit_points;
  477.     data.new_translation.v[0] = pTrans->m[3][0];
  478.     data.new_translation.v[1] = pTrans->m[3][1];
  479.     data.new_translation.v[2] = pTrans->m[3][2];
  480.     data.parent = pParent_ID;
  481.     if (pHit_points <= 0) {
  482.         data.spin_period = pSpin_period;
  483.         data.parent_actor = GetPedestrianActor(pPedestrian_index)->parent;
  484.         BrVector3Copy(&data.offset, pOffset);
  485.         data.jump_magnitude = pJump_magnitude;
  486.         data_size = sizeof(tPipe_pedestrian_data);
  487.     } else {
  488.         data_size = offsetof(tPipe_pedestrian_data, spin_period);
  489.     }
  490.     AddDataToSession(pPedestrian_index, &data, data_size);
  491. }
  492.  
  493. // IDA: void __usercall AddSparkToPipingSession(int pSpark_index@<EAX>, br_vector3 *pPos@<EDX>, br_vector3 *pV@<EBX>)
  494. void AddSparkToPipingSession(int pSpark_index, br_vector3* pPos, br_vector3* pV) {
  495.     tPipe_spark_data data;
  496.     LOG_TRACE("(%d, %p, %p)", pSpark_index, pPos, pV);
  497.  
  498.     BrVector3Copy(&data.pos, pPos);
  499.     BrVector3Copy(&data.v, pV);
  500.     AddDataToSession(pSpark_index, &data, sizeof(tPipe_spark_data));
  501. }
  502.  
  503. // IDA: void __usercall AddShrapnelToPipingSession(int pShrapnel_index@<EAX>, br_vector3 *pPos@<EDX>, tU16 pAge@<EBX>, br_material *pMaterial@<ECX>)
  504. void AddShrapnelToPipingSession(int pShrapnel_index, br_vector3* pPos, tU16 pAge, br_material* pMaterial) {
  505.     tPipe_shrapnel_data data;
  506.     tU32 data_size;
  507.     LOG_TRACE("(%d, %p, %d, %p)", pShrapnel_index, pPos, pAge, pMaterial);
  508.  
  509.     BrVector3Copy(&data.pos, pPos);
  510.     if ((pShrapnel_index & 0x8000) != 0) {
  511.         data.age = pAge;
  512.         data.material = pMaterial;
  513.         data_size = sizeof(tPipe_shrapnel_data);
  514.     } else {
  515.         data_size = offsetof(tPipe_shrapnel_data, age);
  516.     }
  517.     AddDataToSession(pShrapnel_index, &data, data_size);
  518. }
  519.  
  520. // IDA: void __usercall AddScreenWobbleToPipingSession(int pWobble_x@<EAX>, int pWobble_y@<EDX>)
  521. void AddScreenWobbleToPipingSession(int pWobble_x, int pWobble_y) {
  522.     tPipe_screen_shake_data data;
  523.     LOG_TRACE("(%d, %d)", pWobble_x, pWobble_y);
  524.  
  525.     data.wobble_x = pWobble_x;
  526.     data.wobble_y = pWobble_y;
  527.     AddDataToSession(0, &data, sizeof(tPipe_screen_shake_data));
  528. }
  529.  
  530. // IDA: void __usercall AddGrooveStopToPipingSession(int pGroove_index@<EAX>, br_matrix34 *pMatrix@<EDX>, int pPath_interrupt@<EBX>, int pObject_interrupt@<ECX>, float pPath_resumption, float pObject_resumption)
  531. void AddGrooveStopToPipingSession(int pGroove_index, br_matrix34* pMatrix, int pPath_interrupt, int pObject_interrupt, float pPath_resumption, float pObject_resumption) {
  532.     tPipe_groove_stop_data data;
  533.     LOG_TRACE("(%d, %p, %d, %d, %f, %f)", pGroove_index, pMatrix, pPath_interrupt, pObject_interrupt, pPath_resumption, pObject_resumption);
  534.  
  535.     BrMatrix34Copy(&data.matrix, pMatrix);
  536.     data.path_interrupt = pPath_interrupt;
  537.     data.object_interrupt = pObject_interrupt;
  538.     data.path_resumption = pPath_resumption;
  539.     data.object_resumption = pObject_resumption;
  540.     AddDataToSession(pGroove_index, &data, sizeof(tPipe_groove_stop_data));
  541. }
  542.  
  543. // IDA: void __usercall AddNonCarToPipingSession(int pIndex@<EAX>, br_actor *pActor@<EDX>)
  544. void AddNonCarToPipingSession(int pIndex, br_actor* pActor) {
  545.     tPipe_non_car_data data;
  546.     LOG_TRACE("(%d, %p)", pIndex, pActor);
  547.  
  548.     BrMatrix34Copy(&data.mat, &pActor->t.t.mat);
  549.     data.actor = pActor;
  550.     AddDataToSession(pIndex, &data, sizeof(tPipe_non_car_data));
  551. }
  552.  
  553. // IDA: void __usercall AddSmokeToPipingSession(int pIndex@<EAX>, tU8 pType@<EDX>, br_vector3 *pPos@<EBX>, br_scalar pRadius, br_scalar pStrength)
  554. void AddSmokeToPipingSession(int pIndex, tU8 pType, br_vector3* pPos, br_scalar pRadius, br_scalar pStrength) {
  555.     tPipe_smoke_data data;
  556.     LOG_TRACE("(%d, %d, %p, %f, %f)", pIndex, pType, pPos, pRadius, pStrength);
  557.  
  558.     SaveReducedPos(&data.pos, pPos);
  559.     data.type = pType;
  560.     data.radius = pRadius * 1024.f;
  561.     data.strength = pStrength * 255.f;
  562.     AddDataToSession(pIndex, &data, sizeof(tPipe_smoke_data));
  563. }
  564.  
  565. // IDA: void __usercall AddSmokeColumnToPipingSession(int pIndex@<EAX>, tCar_spec *pCar@<EDX>, int pVertex@<EBX>, int pColour@<ECX>)
  566. void AddSmokeColumnToPipingSession(int pIndex, tCar_spec* pCar, int pVertex, int pColour) {
  567.     tPipe_smoke_column_data data;
  568.     LOG_TRACE("(%d, %p, %d, %d)", pIndex, pCar, pVertex, pColour);
  569.  
  570.     data.car_ID = pCar->car_ID;
  571.     data.vertex = pVertex;
  572.     AddDataToSession(pColour << 14 | pIndex, &data, sizeof(tPipe_smoke_column_data));
  573. }
  574.  
  575. // IDA: void __usercall AddFlameToPipingSession(int pIndex@<EAX>, int pFrame_count@<EDX>, br_scalar pScale_x, br_scalar pScale_y, br_scalar pOffset_x, br_scalar pOffset_z)
  576. void AddFlameToPipingSession(int pIndex, int pFrame_count, br_scalar pScale_x, br_scalar pScale_y, br_scalar pOffset_x, br_scalar pOffset_z) {
  577.     tPipe_flame_data data;
  578.     LOG_TRACE("(%d, %d, %f, %f, %f, %f)", pIndex, pFrame_count, pScale_x, pScale_y, pOffset_x, pOffset_z);
  579.  
  580.     data.frame_count = pFrame_count;
  581.     data.scale_x = pScale_x;
  582.     data.scale_y = pScale_y;
  583.     data.offset_x = pOffset_x;
  584.     data.offset_z = pOffset_z;
  585.     AddDataToSession(pIndex, &data, sizeof(tPipe_flame_data));
  586. }
  587.  
  588. // IDA: void __usercall AddSplashToPipingSession(tCollision_info *pCar@<EAX>)
  589. void AddSplashToPipingSession(tCollision_info* pCar) {
  590.     tPipe_splash_data data;
  591.     LOG_TRACE("(%p)", pCar);
  592.  
  593.     if (pCar->driver >= eDriver_oppo) {
  594.         data.d = pCar->water_d;
  595.         BrVector3Copy(&data.normal, &pCar->water_normal);
  596.         AddDataToSession(pCar->car_ID, &data, sizeof(tPipe_splash_data));
  597.     }
  598. }
  599.  
  600. // IDA: void __usercall AddOilSpillToPipingSession(int pIndex@<EAX>, br_matrix34 *pMat@<EDX>, br_scalar pFull_size, br_scalar pGrow_rate, tU32 pSpill_time, tU32 pStop_time, tCar_spec *pCar, br_vector3 *pOriginal_pos, br_pixelmap *pPixelmap)
  601. void AddOilSpillToPipingSession(int pIndex, br_matrix34* pMat, br_scalar pFull_size, br_scalar pGrow_rate, tU32 pSpill_time, tU32 pStop_time, tCar_spec* pCar, br_vector3* pOriginal_pos, br_pixelmap* pPixelmap) {
  602.     tPipe_oil_spill_data data;
  603.     LOG_TRACE("(%d, %p, %f, %f, %d, %d, %p, %p, %p)", pIndex, pMat, pFull_size, pGrow_rate, pSpill_time, pStop_time, pCar, pOriginal_pos, pPixelmap);
  604.  
  605.     BrMatrix34Copy(&data.mat, pMat);
  606.     data.full_size = pFull_size;
  607.     data.grow_rate = pGrow_rate;
  608.     data.spill_time = pSpill_time;
  609.     data.previous_stop_time = pStop_time;
  610.     data.car = pCar;
  611.     BrVector3Copy(&data.original_pos, pOriginal_pos);
  612.     data.pixelmap = pPixelmap;
  613.     AddDataToSession(pIndex, &data, sizeof(tPipe_oil_spill_data));
  614. }
  615.  
  616. // IDA: void __usercall AddFrameFinishToPipingSession(tU32 pThe_time@<EAX>)
  617. void AddFrameFinishToPipingSession(tU32 pThe_time) {
  618.     tPipe_frame_boundary_data data;
  619.     LOG_TRACE("(%d)", pThe_time);
  620.  
  621.     data.time = pThe_time;
  622.     AddDataToSession(0, &data, sizeof(tPipe_frame_boundary_data));
  623. }
  624.  
  625. // IDA: void __usercall AddCarToPipingSession(int pCar_ID@<EAX>, br_matrix34 *pCar_mat@<EDX>, br_vector3 *pCar_velocity@<EBX>, float pSpeedo_speed, float pLf_sus_position, float pRf_sus_position, float pLr_sus_position, float pRr_sus_position, float pSteering_angle, br_scalar pRevs, int pGear, int pFrame_coll_flag)
  626. void AddCarToPipingSession(int pCar_ID, br_matrix34* pCar_mat, br_vector3* pCar_velocity, float pSpeedo_speed, float pLf_sus_position, float pRf_sus_position, float pLr_sus_position, float pRr_sus_position, float pSteering_angle, br_scalar pRevs, int pGear, int pFrame_coll_flag) {
  627.     tPipe_car_data data;
  628.     LOG_TRACE("(%d, %p, %p, %f, %f, %f, %f, %f, %f, %f, %d, %d)", pCar_ID, pCar_mat, pCar_velocity, pSpeedo_speed, pLf_sus_position, pRf_sus_position, pLr_sus_position, pRr_sus_position, pSteering_angle, pRevs, pGear, pFrame_coll_flag);
  629.  
  630.     BrMatrix34Copy(&data.transformation, pCar_mat);
  631.     BrVector3Copy(&data.velocity, pCar_velocity);
  632.     data.speedo_speed = pSpeedo_speed * 32767.f / 0.07f;
  633.     data.lf_sus_position = pLf_sus_position * 127.f / .15f;
  634.     data.rf_sus_position = pRf_sus_position * 127.f / .15f;
  635.     data.lr_sus_position = pLr_sus_position * 127.f / .15f;
  636.     data.rr_sus_position = pRr_sus_position * 127.f / .15f;
  637.     data.steering_angle = pSteering_angle * 32767.f / 60.f;
  638.     data.revs_and_gear = (pGear + 1) << 12 | (pFrame_coll_flag ? 0 : 1) << 11 | ((((int)pRevs) / 10) & 0x7ff);
  639.     AddDataToSession(pCar_ID, &data, sizeof(tPipe_car_data));
  640. }
  641.  
  642. // IDA: void __usercall AddSoundToPipingSession(tS3_outlet_ptr pOutlet@<EAX>, int pSound_index@<EDX>, tS3_volume pL_volume@<EBX>, tS3_volume pR_volume@<ECX>, tS3_pitch pPitch, br_vector3 *pPos)
  643. void AddSoundToPipingSession(tS3_outlet_ptr pOutlet, int pSound_index, tS3_volume pL_volume, tS3_volume pR_volume, tS3_pitch pPitch, br_vector3* pPos) {
  644.     tPipe_sound_data data;
  645.     LOG_TRACE("(%d, %d, %d, %d, %d, %p)", pOutlet, pSound_index, pL_volume, pR_volume, pPitch, pPos);
  646.  
  647.     data.pitch = pPitch;
  648.     if (pPos == NULL) {
  649.         BrVector3Set(&data.position, 0.f, 0.f, 0.f);
  650.     } else {
  651.         BrVector3Copy(&data.position, pPos);
  652.     }
  653.     data.volume = (pR_volume << 8) | (pL_volume << 0);
  654.     data.outlet_index = GetIndexFromOutlet(pOutlet);
  655.     AddDataToSession(pSound_index, &data, sizeof(tPipe_sound_data));
  656. }
  657.  
  658. // IDA: void __usercall AddDamageToPipingSession(int pCar_ID@<EAX>, tS8 *pDifferences@<EDX>)
  659. void AddDamageToPipingSession(int pCar_ID, tS8* pDifferences) {
  660.     tPipe_damage_data data;
  661.     int i;
  662.     LOG_TRACE("(%d, %p)", pCar_ID, pDifferences);
  663.  
  664.     for (i = 0; i < COUNT_OF(data.damage_delta); i++) {
  665.         data.damage_delta[i] = pDifferences[i];
  666.     }
  667.     AddDataToSession(pCar_ID, &data, sizeof(tPipe_damage_data));
  668. }
  669.  
  670. // IDA: void __usercall AddSpecialToPipingSession(tSpecial_type pType@<EAX>)
  671. void AddSpecialToPipingSession(tSpecial_type pType) {
  672.     tPipe_special_data data;
  673.     LOG_TRACE("(%d)", pType);
  674.  
  675.     AddDataToSession(pType, &data, sizeof(tPipe_special_data));
  676. }
  677.  
  678. // IDA: void __usercall AddPedGibToPipingSession(int pIndex@<EAX>, br_matrix34 *pTrans@<EDX>, int pSize@<EBX>, int pGib_index@<ECX>, int pPed_index)
  679. void AddPedGibToPipingSession(int pIndex, br_matrix34* pTrans, int pSize, int pGib_index, int pPed_index) {
  680.     tPipe_ped_gib_data data;
  681.     LOG_TRACE("(%d, %p, %d, %d, %d)", pIndex, pTrans, pSize, pGib_index, pPed_index);
  682.  
  683.     data.ped_parent_index = pPed_index;
  684.     data.size = pSize;
  685.     data.gib_index = pGib_index;
  686.     BrMatrix34Copy(&data.transform, pTrans);
  687.     AddDataToSession(pIndex, &data, sizeof(tPipe_ped_gib_data));
  688. }
  689.  
  690. // IDA: void __cdecl AddCarIncidentToPipingSession(float pSeverity, tCar_spec *pCar, br_vector3 *pImpact_point)
  691. void AddCarIncidentToPipingSession(float pSeverity, tCar_spec* pCar, br_vector3* pImpact_point) {
  692.     tPipe_incident_data data;
  693.     LOG_TRACE("(%f, %p, %p)", pSeverity, pCar, pImpact_point);
  694.  
  695.     data.severity = pSeverity;
  696.     data.info.car_info.car_ID = pCar->car_ID;
  697.     BrVector3Copy(&data.info.car_info.impact_point, pImpact_point);
  698.     AddDataToSession(1, &data, sizeof(tPipe_incident_data));
  699. }
  700.  
  701. // IDA: void __usercall AddPedIncidentToPipingSession(int pPed_index@<EAX>, br_actor *pActor@<EDX>)
  702. void AddPedIncidentToPipingSession(int pPed_index, br_actor* pActor) {
  703.     tPipe_incident_data data;
  704.     LOG_TRACE("(%d, %p)", pPed_index, pActor);
  705.  
  706.     data.severity = 0.f;
  707.     data.info.ped_info.ped_index = pPed_index;
  708.     data.info.ped_info.actor = pActor;
  709.     AddDataToSession(0, &data, sizeof(tPipe_incident_data));
  710. }
  711.  
  712. // IDA: void __cdecl AddWallIncidentToPipingSession(float pSeverity, br_vector3 *pImpact_point)
  713. void AddWallIncidentToPipingSession(float pSeverity, br_vector3* pImpact_point) {
  714.     tPipe_incident_data data;
  715.     LOG_TRACE("(%f, %p)", pSeverity, pImpact_point);
  716.  
  717.     data.severity = pSeverity;
  718.     BrVector3Copy(&data.info.wall_info.pos, pImpact_point);
  719.     AddDataToSession(2, &data, sizeof(tPipe_incident_data));
  720. }
  721.  
  722. // IDA: void __usercall AddProxRayToPipingSession(int pRay_index@<EAX>, tCar_spec *pCar@<EDX>, tU16 pPed_index@<EBX>, tU32 pTime@<ECX>)
  723. void AddProxRayToPipingSession(int pRay_index, tCar_spec* pCar, tU16 pPed_index, tU32 pTime) {
  724.     tPipe_prox_ray_data data;
  725.     LOG_TRACE("(%d, %p, %d, %d)", pRay_index, pCar, pPed_index, pTime);
  726.  
  727.     data.ped_index = pPed_index;
  728.     data.car_ID = pCar->car_ID;
  729.     data.time = pTime;
  730.     AddDataToSession(pRay_index, &data, sizeof(tPipe_prox_ray_data));
  731. }
  732.  
  733. // IDA: void __usercall AddSkidAdjustmentToPipingSession(int pSkid_num@<EAX>, br_matrix34 *pMatrix@<EDX>, int pMaterial_index@<EBX>)
  734. void AddSkidAdjustmentToPipingSession(int pSkid_num, br_matrix34* pMatrix, int pMaterial_index) {
  735.     tPipe_skid_adjustment adjustment;
  736.     LOG_TRACE("(%d, %p, %d)", pSkid_num, pMatrix, pMaterial_index);
  737.  
  738.     BrMatrix34Copy(&adjustment.matrix, pMatrix);
  739.     adjustment.material_index = pMaterial_index;
  740.     AddDataToSession(pSkid_num, &adjustment, sizeof(tPipe_skid_adjustment));
  741. }
  742.  
  743. // IDA: void __usercall PipeSingleModelGeometry(tU16 pCar_ID@<EAX>, int pModel_index@<EDX>, int pVertex_count@<EBX>, tChanged_vertex *pCoordinates@<ECX>)
  744. void PipeSingleModelGeometry(tU16 pCar_ID, int pModel_index, int pVertex_count, tChanged_vertex* pCoordinates) {
  745.     LOG_TRACE("(%d, %d, %d, %p)", pCar_ID, pModel_index, pVertex_count, pCoordinates);
  746.  
  747.     StartPipingSession(ePipe_chunk_model_geometry);
  748.     AddModelGeometryToPipingSession(pCar_ID, pModel_index, pVertex_count, pCoordinates);
  749.     EndPipingSession();
  750. }
  751.  
  752. // IDA: void __usercall PipeSinglePedestrian(int pPedestrian_index@<EAX>, br_matrix34 *pTrans@<EDX>, tU8 pAction_index@<EBX>, tU8 pFrame_index@<ECX>, tS8 pHit_points, int pDone_initial, tU16 pParent_ID, float pSpin_period, br_scalar pJump_magnitude, br_vector3 *pOffset)
  753. void PipeSinglePedestrian(int pPedestrian_index, br_matrix34* pTrans, tU8 pAction_index, tU8 pFrame_index, tS8 pHit_points, int pDone_initial, tU16 pParent_ID, float pSpin_period, br_scalar pJump_magnitude, br_vector3* pOffset) {
  754.     LOG_TRACE("(%d, %p, %d, %d, %d, %d, %d, %f, %f, %p)", pPedestrian_index, pTrans, pAction_index, pFrame_index, pHit_points, pDone_initial, pParent_ID, pSpin_period, pJump_magnitude, pOffset);
  755.  
  756.     StartPipingSession(ePipe_chunk_pedestrian);
  757.     AddPedestrianToPipingSession(pPedestrian_index, pTrans, pAction_index,
  758.         pFrame_index, pHit_points, pDone_initial, pParent_ID, pSpin_period,
  759.         pJump_magnitude, pOffset);
  760.     EndPipingSession();
  761. }
  762.  
  763. // IDA: void __usercall PipeSingleCar(int pCar_ID@<EAX>, br_matrix34 *pCar_mat@<EDX>, br_vector3 *pCar_velocity@<EBX>, float pSpeedo_speed, float pLf_sus_position, float pRf_sus_position, float pLr_sus_position, float pRr_sus_position, float pSteering_angle, br_scalar pRevs, int pGear, int pFrame_coll_flag)
  764. void PipeSingleCar(int pCar_ID, br_matrix34* pCar_mat, br_vector3* pCar_velocity, float pSpeedo_speed, float pLf_sus_position, float pRf_sus_position, float pLr_sus_position, float pRr_sus_position, float pSteering_angle, br_scalar pRevs, int pGear, int pFrame_coll_flag) {
  765.     LOG_TRACE("(%d, %p, %p, %f, %f, %f, %f, %f, %f, %f, %d, %d)", pCar_ID, pCar_mat, pCar_velocity, pSpeedo_speed, pLf_sus_position, pRf_sus_position, pLr_sus_position, pRr_sus_position, pSteering_angle, pRevs, pGear, pFrame_coll_flag);
  766.  
  767.     StartPipingSession(ePipe_chunk_car);
  768.     AddCarToPipingSession(pCar_ID, pCar_mat, pCar_velocity, pSpeedo_speed,
  769.         pLf_sus_position, pRf_sus_position, pLr_sus_position, pRr_sus_position,
  770.         pSteering_angle, pRevs, pGear, pFrame_coll_flag);
  771.     EndPipingSession();
  772. }
  773.  
  774. // IDA: void __usercall PipeSingleSound(tS3_outlet_ptr pOutlet@<EAX>, int pSound_index@<EDX>, tS3_volume pL_volume@<EBX>, tS3_volume pR_volume@<ECX>, tS3_pitch pPitch, br_vector3 *pPos)
  775. void PipeSingleSound(tS3_outlet_ptr pOutlet, int pSound_index, tS3_volume pL_volume, tS3_volume pR_volume, tS3_pitch pPitch, br_vector3* pPos) {
  776.     LOG_TRACE("(%d, %d, %d, %d, %d, %p)", pOutlet, pSound_index, pL_volume, pR_volume, pPitch, pPos);
  777.  
  778.     if (!gAction_replay_mode && gProgram_state.racing) {
  779.         StartPipingSession(ePipe_chunk_sound);
  780.         AddSoundToPipingSession(pOutlet, pSound_index, pL_volume, pR_volume, pPitch, pPos);
  781.         EndPipingSession();
  782.     }
  783. }
  784.  
  785. // IDA: void __usercall PipeSingleOilSpill(int pIndex@<EAX>, br_matrix34 *pMat@<EDX>, br_scalar pFull_size, br_scalar pGrow_rate, tU32 pSpill_time, tU32 pStop_time, tCar_spec *pCar, br_vector3 *pOriginal_pos, br_pixelmap *pPixelmap)
  786. void PipeSingleOilSpill(int pIndex, br_matrix34* pMat, br_scalar pFull_size, br_scalar pGrow_rate, tU32 pSpill_time, tU32 pStop_time, tCar_spec* pCar, br_vector3* pOriginal_pos, br_pixelmap* pPixelmap) {
  787.     LOG_TRACE("(%d, %p, %f, %f, %d, %d, %p, %p, %p)", pIndex, pMat, pFull_size, pGrow_rate, pSpill_time, pStop_time, pCar, pOriginal_pos, pPixelmap);
  788.  
  789.     StartPipingSession(ePipe_chunk_oil_spill);
  790.     AddOilSpillToPipingSession(pIndex, pMat, pFull_size, pGrow_rate,
  791.         pSpill_time, pStop_time, pCar, pOriginal_pos, pPixelmap);
  792.     EndPipingSession();
  793. }
  794.  
  795. // IDA: void __usercall PipeSingleDamage(int pCar_ID@<EAX>, tS8 *pDifferences@<EDX>)
  796. void PipeSingleDamage(int pCar_ID, tS8* pDifferences) {
  797.     LOG_TRACE("(%d, %p)", pCar_ID, pDifferences);
  798.  
  799.     StartPipingSession(ePipe_chunk_damage);
  800.     AddDamageToPipingSession(pCar_ID, pDifferences);
  801.     EndPipingSession();
  802. }
  803.  
  804. // IDA: void __usercall PipeSingleSpecial(tSpecial_type pType@<EAX>)
  805. void PipeSingleSpecial(tSpecial_type pType) {
  806.     LOG_TRACE("(%d)", pType);
  807.  
  808.     StartPipingSession(ePipe_chunk_special);
  809.     AddSpecialToPipingSession(pType);
  810.     EndPipingSession();
  811. }
  812.  
  813. // IDA: void __usercall PipeSinglePedGib(int pIndex@<EAX>, br_matrix34 *pTrans@<EDX>, int pSize@<EBX>, int pGib_index@<ECX>, int pPed_index)
  814. void PipeSinglePedGib(int pIndex, br_matrix34* pTrans, int pSize, int pGib_index, int pPed_index) {
  815.     LOG_TRACE("(%d, %p, %d, %d, %d)", pIndex, pTrans, pSize, pGib_index, pPed_index);
  816.  
  817.     StartPipingSession(ePipe_chunk_ped_gib);
  818.     AddPedGibToPipingSession(pIndex, pTrans, pSize, pGib_index, pPed_index);
  819.     EndPipingSession();
  820. }
  821.  
  822. // IDA: void __cdecl PipeSingleCarIncident(float pSeverity, tCar_spec *pCar, br_vector3 *pImpact_point)
  823. void PipeSingleCarIncident(float pSeverity, tCar_spec* pCar, br_vector3* pImpact_point) {
  824.     LOG_TRACE("(%f, %p, %p)", pSeverity, pCar, pImpact_point);
  825.  
  826.     StartPipingSession(ePipe_chunk_incident);
  827.     AddCarIncidentToPipingSession(pSeverity, pCar, pImpact_point);
  828.     EndPipingSession();
  829. }
  830.  
  831. // IDA: void __usercall PipeSinglePedIncident(int pPed_index@<EAX>, br_actor *pActor@<EDX>)
  832. void PipeSinglePedIncident(int pPed_index, br_actor* pActor) {
  833.     LOG_TRACE("(%d, %p)", pPed_index, pActor);
  834.  
  835.     StartPipingSession(ePipe_chunk_incident);
  836.     AddPedIncidentToPipingSession(pPed_index, pActor);
  837.     EndPipingSession();
  838.     gWall_severity = 0.f;
  839. }
  840.  
  841. // IDA: void __cdecl PipeSingleWallIncident(float pSeverity, br_vector3 *pImpact_point)
  842. void PipeSingleWallIncident(float pSeverity, br_vector3* pImpact_point) {
  843.     LOG_TRACE("(%f, %p)", pSeverity, pImpact_point);
  844.  
  845.     if (pSeverity > gWall_severity) {
  846.         gWall_severity = pSeverity;
  847.         BrVector3Copy(&gWall_impact_point, pImpact_point);
  848.     }
  849. }
  850.  
  851. // IDA: void __usercall PipeSingleScreenShake(int pWobble_x@<EAX>, int pWobble_y@<EDX>)
  852. void PipeSingleScreenShake(int pWobble_x, int pWobble_y) {
  853.     LOG_TRACE("(%d, %d)", pWobble_x, pWobble_y);
  854.  
  855.     StartPipingSession(ePipe_chunk_screen_shake);
  856.     AddScreenWobbleToPipingSession(pWobble_x, pWobble_y);
  857.     EndPipingSession();
  858. }
  859.  
  860. // IDA: void __usercall PipeSingleGrooveStop(int pGroove_index@<EAX>, br_matrix34 *pMatrix@<EDX>, int pPath_interrupt@<EBX>, int pObject_interrupt@<ECX>, float pPath_resumption, float pObject_resumption)
  861. void PipeSingleGrooveStop(int pGroove_index, br_matrix34* pMatrix, int pPath_interrupt, int pObject_interrupt, float pPath_resumption, float pObject_resumption) {
  862.     LOG_TRACE("(%d, %p, %d, %d, %f, %f)", pGroove_index, pMatrix, pPath_interrupt, pObject_interrupt, pPath_resumption, pObject_resumption);
  863.  
  864.     StartPipingSession(ePipe_chunk_groove_stop);
  865.     AddGrooveStopToPipingSession(pGroove_index, pMatrix, pPath_interrupt,
  866.         pObject_interrupt, pPath_resumption, pObject_resumption);
  867.     EndPipingSession();
  868. }
  869.  
  870. // IDA: void __cdecl PipeFrameFinish()
  871. void PipeFrameFinish(void) {
  872.     LOG_TRACE("()");
  873.  
  874.     if (gWall_severity != 0.f) {
  875.         StartPipingSession(ePipe_chunk_incident);
  876.         AddWallIncidentToPipingSession(gWall_severity, &gWall_impact_point);
  877.         EndPipingSession();
  878.         gWall_severity = 0.f;
  879.     }
  880.     StartPipingSession(ePipe_chunk_frame_boundary);
  881.     AddFrameFinishToPipingSession(GetTotalTime());
  882.     EndPipingSession();
  883. }
  884.  
  885. // IDA: void __cdecl PipingFrameReset()
  886. void PipingFrameReset(void) {
  887.     int i;
  888.     LOG_TRACE("()");
  889.  
  890.     for (i = 0; i < COUNT_OF(gReset_procs); i++) {
  891.         if (gReset_procs[i] != NULL) {
  892.             gReset_procs[i]();
  893.         }
  894.     }
  895. }
  896.  
  897. // IDA: void __usercall PipeSingleSkidAdjustment(int pSkid_num@<EAX>, br_matrix34 *pMatrix@<EDX>, int pMaterial_index@<EBX>)
  898. void PipeSingleSkidAdjustment(int pSkid_num, br_matrix34* pMatrix, int pMaterial_index) {
  899.     LOG_TRACE("(%d, %p, %d)", pSkid_num, pMatrix, pMaterial_index);
  900.  
  901.     StartPipingSession(ePipe_chunk_skid_adjustment);
  902.     AddSkidAdjustmentToPipingSession(pSkid_num, pMatrix, pMaterial_index);
  903.     EndPipingSession();
  904. }
  905.  
  906. // IDA: void __cdecl ResetPiping()
  907. void ResetPiping(void) {
  908.     LOG_TRACE("()");
  909.  
  910.     gWall_severity = 0.f;
  911.     gPipe_buffer_oldest = NULL;
  912.     gPipe_record_ptr = gPipe_buffer_start;
  913.     gPipe_buffer_working_end = gPipe_buffer_phys_end;
  914.     gReentrancy_count = 0;
  915. }
  916.  
  917. // IDA: void __cdecl InitialisePiping()
  918. void InitialisePiping(void) {
  919.     LOG_TRACE("()");
  920.  
  921.     if (!gAusterity_mode && gNet_mode == eNet_mode_none) {
  922.         PDAllocateActionReplayBuffer((char**)&gPipe_buffer_start, &gPipe_buffer_size);
  923.         gPipe_buffer_phys_end = gPipe_buffer_start + gPipe_buffer_size;
  924.         gSmudge_space = BrMemAllocate(offsetof(tPipe_smudge_data, vertex_changes) + sizeof(tSmudged_vertex) * 2400, kMem_pipe_model_geometry);
  925.         // DAT_00532008 = 0;
  926.         BrVector3SetFloat(&gZero_vector, 0.f, 0.f, 0.f);
  927.         gModel_geometry_space = (tPipe_model_geometry_data*)gSmudge_space;
  928.         gLocal_buffer = BrMemAllocate(LOCAL_BUFFER_SIZE, kMem_pipe_model_geometry);
  929.     } else {
  930.         gPipe_buffer_start = NULL;
  931.         gLocal_buffer = NULL;
  932.         gModel_geometry_space = NULL;
  933.         gSmudge_space = NULL;
  934.     }
  935.     ResetPiping();
  936. }
  937.  
  938. // IDA: void __cdecl DisposePiping()
  939. void DisposePiping(void) {
  940.     LOG_TRACE("()");
  941.  
  942.     if (gPipe_buffer_start != NULL) {
  943.         PDDisposeActionReplayBuffer((char*)gPipe_buffer_start);
  944.     }
  945.     gPipe_buffer_start = NULL;
  946.     if (gModel_geometry_space != NULL) {
  947.         BrMemFree(gModel_geometry_space);
  948.         gModel_geometry_space = NULL;
  949.     }
  950.     if (gLocal_buffer != NULL) {
  951.         BrMemFree(gLocal_buffer);
  952.         gLocal_buffer = NULL;
  953.     }
  954. }
  955.  
  956. // IDA: void __cdecl InitLastDamageArrayEtc()
  957. void InitLastDamageArrayEtc(void) {
  958.     int i;
  959.     int j;
  960.     int cat;
  961.     int car_count;
  962.     tCar_spec* car;
  963.     LOG_TRACE("()");
  964.  
  965.     for (cat = eVehicle_self; cat <= eVehicle_not_really; cat++) {
  966.         if (cat == eVehicle_self) {
  967.             car_count = 1;
  968.         } else {
  969.             car_count = GetCarCount(cat);
  970.         }
  971.         for (i = 0; i < car_count; i++) {
  972.             if (cat == eVehicle_self) {
  973.                 car = &gProgram_state.current_car;
  974.             } else {
  975.                 car = GetCarSpec(cat, i);
  976.             }
  977.             if (cat != eVehicle_not_really) {
  978.                 for (j = 0; j < COUNT_OF(car->frame_start_damage); j++) {
  979.                     car->frame_start_damage[j] = 0;
  980.                 }
  981.             }
  982.             car->car_ID = (cat << 8) | i;
  983.         }
  984.     }
  985. }
  986.  
  987. // IDA: void __cdecl ResetCars()
  988. void ResetCars(void) {
  989.     tCar_spec* car;
  990.     int cat;
  991.     int i;
  992.     int car_count;
  993.     LOG_TRACE("()");
  994.  
  995.     for (cat = eVehicle_self; cat < eVehicle_not_really; cat++) {
  996.         if (cat == eVehicle_self) {
  997.             car_count = 1;
  998.         } else {
  999.             car_count = GetCarCount(cat);
  1000.         }
  1001.         for (i = 0; i < car_count; i++) {
  1002.             if (cat == eVehicle_self) {
  1003.                 car = &gProgram_state.current_car;
  1004.             } else {
  1005.                 car = GetCarSpec(cat, i);
  1006.             }
  1007.             car->active = 0;
  1008.         }
  1009.     }
  1010. }
  1011.  
  1012. // IDA: void __cdecl PipeCarPositions()
  1013. void PipeCarPositions(void) {
  1014.     tCar_spec* car;
  1015.     int cat;
  1016.     int i;
  1017.     int j;
  1018.     int car_count;
  1019.     int session_started;
  1020.     int difference_found;
  1021.     tS8 damage_deltas[12];
  1022.     LOG_TRACE("()");
  1023.  
  1024.     StartPipingSession(ePipe_chunk_car);
  1025.     for (cat = eVehicle_self; cat < eVehicle_not_really; cat++) {
  1026.         if (cat == eVehicle_self) {
  1027.             car_count = 1;
  1028.         } else {
  1029.             car_count = GetCarCount(cat);
  1030.         }
  1031.         for (i = 0; i < car_count; i++) {
  1032.             if (cat == eVehicle_self) {
  1033.                 car = &gProgram_state.current_car;
  1034.             } else {
  1035.                 car = GetCarSpec(cat, i);
  1036.             }
  1037.             AddCarToPipingSession((cat << 8) | i,
  1038.                 &car->car_master_actor->t.t.mat, &car->v, car->speedo_speed,
  1039.                 car->lf_sus_position, car->rf_sus_position, car->lr_sus_position, car->rr_sus_position,
  1040.                 car->steering_angle, car->revs, car->gear, car->frame_collision_flag);
  1041.         }
  1042.     }
  1043.     EndPipingSession();
  1044.     session_started = 0;
  1045.     for (cat = eVehicle_self; cat < eVehicle_net_player; cat++) {
  1046.         if (cat == eVehicle_self) {
  1047.             car_count = 1;
  1048.         } else {
  1049.             car_count = GetCarCount(cat);
  1050.         }
  1051.         for (i = 0; i < car_count; i++) {
  1052.             if (cat == eVehicle_self) {
  1053.                 car = &gProgram_state.current_car;
  1054.             } else {
  1055.                 car = GetCarSpec(cat, i);
  1056.             }
  1057.             if (car->active) {
  1058.                 difference_found = 0;
  1059.                 for (j = 0; j < COUNT_OF(car->damage_units); j++) {
  1060.                     damage_deltas[j] = car->damage_units[j].damage_level - car->frame_start_damage[j];
  1061.                     difference_found |= damage_deltas[j];
  1062.                     car->frame_start_damage[j] = car->damage_units[j].damage_level;
  1063.                 }
  1064.                 if (difference_found) {
  1065.                     if (!session_started) {
  1066.                         StartPipingSession(ePipe_chunk_damage);
  1067.                         session_started = 1;
  1068.                     }
  1069.                     AddDamageToPipingSession((cat << 8) | i, damage_deltas);
  1070.                 }
  1071.             }
  1072.         }
  1073.     }
  1074.     if (session_started) {
  1075.         EndPipingSession();
  1076.     }
  1077. }
  1078.  
  1079. // IDA: void __cdecl ResetPipePlayToEnd()
  1080. void ResetPipePlayToEnd(void) {
  1081.     LOG_TRACE("()");
  1082.  
  1083.     gPipe_play_ptr = gPipe_record_ptr;
  1084. }
  1085.  
  1086. // IDA: void __cdecl ResetPipePlayToStart()
  1087. void ResetPipePlayToStart(void) {
  1088.     LOG_TRACE("()");
  1089.  
  1090.     gPipe_play_ptr = gPipe_buffer_oldest;
  1091. }
  1092.  
  1093. // IDA: tU8* __cdecl GetPipePlayPtr()
  1094. tU8* GetPipePlayPtr(void) {
  1095.     LOG_TRACE("()");
  1096.  
  1097.     return gPipe_play_ptr;
  1098. }
  1099.  
  1100. // IDA: void __usercall SetPipePlayPtr(tU8 *pPtr@<EAX>)
  1101. void SetPipePlayPtr(tU8* pPtr) {
  1102.     LOG_TRACE("(%p)", pPtr);
  1103.  
  1104.     gPipe_play_ptr = pPtr;
  1105. }
  1106.  
  1107. // IDA: void __usercall AdvanceChunkPtr(tPipe_chunk **pChunk@<EAX>, tChunk_subject_index pType@<EDX>)
  1108. void AdvanceChunkPtr(tPipe_chunk** pChunk, tChunk_subject_index pType) {
  1109.     tPipe_chunk* old_chunk;
  1110.     LOG_TRACE("(%p, %d)", pChunk, pType);
  1111.  
  1112.     old_chunk = *pChunk;
  1113.     if (gDisable_advance) {
  1114.         return;
  1115.     }
  1116.     switch (pType) {
  1117.     case ePipe_chunk_model_geometry:
  1118.         *(tU8**)pChunk += offsetof(tPipe_model_geometry_data, vertex_changes) + (*pChunk)->chunk_data.model_geometry_data.vertex_count * sizeof(tChanged_vertex);
  1119.         break;
  1120.     case ePipe_chunk_pedestrian:
  1121.         *(tU8**)pChunk += (((*pChunk)->chunk_data.pedestrian_data.hit_points <= 0) ? sizeof(tPipe_pedestrian_data) : offsetof(tPipe_pedestrian_data, spin_period));
  1122.         break;
  1123.     case ePipe_chunk_frame_boundary:
  1124.         *(tU8**)pChunk += sizeof(tPipe_frame_boundary_data);
  1125.         break;
  1126.     case ePipe_chunk_car:
  1127.         *(tU8**)pChunk += sizeof(tPipe_car_data);
  1128.         break;
  1129.     case ePipe_chunk_sound:
  1130.         *(tU8**)pChunk += sizeof(tPipe_sound_data);
  1131.         break;
  1132.     case ePipe_chunk_damage:
  1133.         *(tU8**)pChunk += sizeof(tPipe_damage_data);
  1134.         break;
  1135.     case ePipe_chunk_special:
  1136.         *(tU8**)pChunk += sizeof(tPipe_special_data);
  1137.         break;
  1138.     case ePipe_chunk_ped_gib:
  1139.         *(tU8**)pChunk += sizeof(tPipe_ped_gib_data);
  1140.         break;
  1141.     case ePipe_chunk_incident:
  1142.         *(tU8**)pChunk += sizeof(tPipe_incident_data);
  1143.         break;
  1144.     case ePipe_chunk_spark:
  1145.         *(tU8**)pChunk += sizeof(tPipe_spark_data);
  1146.         break;
  1147.     case ePipe_chunk_shrapnel:
  1148.         *(tU8**)pChunk += (((*pChunk)->subject_index & 0x8000) ? sizeof(tPipe_shrapnel_data) : offsetof(tPipe_shrapnel_data, age));
  1149.         break;
  1150.     case ePipe_chunk_screen_shake:
  1151.         *(tU8**)pChunk += sizeof(tPipe_screen_shake_data);
  1152.         break;
  1153.     case ePipe_chunk_groove_stop:
  1154.         *(tU8**)pChunk += sizeof(tPipe_groove_stop_data);
  1155.         break;
  1156.     case ePipe_chunk_non_car:
  1157.         *(tU8**)pChunk += sizeof(tPipe_non_car_data);
  1158.         break;
  1159.     case ePipe_chunk_smoke:
  1160.         *(tU8**)pChunk += sizeof(tPipe_smoke_data);
  1161.         break;
  1162.     case ePipe_chunk_oil_spill:
  1163.         *(tU8**)pChunk += sizeof(tPipe_oil_spill_data);
  1164.         break;
  1165.     case ePipe_chunk_smoke_column:
  1166.         *(tU8**)pChunk += sizeof(tPipe_smoke_column_data);
  1167.         break;
  1168.     case ePipe_chunk_flame:
  1169.         *(tU8**)pChunk += sizeof(tPipe_flame_data);
  1170.         break;
  1171.     case ePipe_chunk_smudge:
  1172.         *(tU8**)pChunk += offsetof(tPipe_smudge_data, vertex_changes) + (*pChunk)->chunk_data.smudge_data.vertex_count * sizeof(tSmudged_vertex);
  1173.         break;
  1174.     case ePipe_chunk_splash:
  1175.         *(tU8**)pChunk += sizeof(tPipe_splash_data);
  1176.         break;
  1177.     case ePipe_chunk_prox_ray:
  1178.         *(tU8**)pChunk += sizeof(tPipe_prox_ray_data);
  1179.         break;
  1180.     case ePipe_chunk_skid_adjustment:
  1181.         *(tU8**)pChunk += sizeof(tPipe_skid_adjustment);
  1182.         break;
  1183.     }
  1184.     *(tU8**)pChunk += offsetof(tPipe_chunk, chunk_data);
  1185.  
  1186.     /* Fail-safe to avoid reading junk data from the session after */
  1187.     if (*(tU8**)pChunk == gEnd_of_session) {
  1188.         *pChunk = old_chunk;
  1189.     } else if (*(tU8**)pChunk > gEnd_of_session) {
  1190.         *pChunk = old_chunk;
  1191.     }
  1192. }
  1193.  
  1194. // IDA: void __usercall ApplyModelGeometry(tPipe_chunk **pChunk@<EAX>)
  1195. void ApplyModelGeometry(tPipe_chunk** pChunk) {
  1196.     int i;
  1197.     br_model* model_ptr;
  1198.     tCar_spec* car;
  1199.     LOG_TRACE("(%p)", pChunk);
  1200.  
  1201.     if (((*pChunk)->subject_index & 0xff00) == 0) {
  1202.         car = &gProgram_state.current_car;
  1203.     } else {
  1204.         car = GetCarSpec((*pChunk)->subject_index >> 8, (*pChunk)->subject_index & 0xff);
  1205.     }
  1206.     model_ptr = car->car_model_actors[(*pChunk)->chunk_data.model_geometry_data.model_index].actor->model;
  1207.     for (i = 0; i < (*pChunk)->chunk_data.model_geometry_data.vertex_count; i++) {
  1208.         BrVector3Accumulate(&model_ptr->vertices[(*pChunk)->chunk_data.model_geometry_data.vertex_changes[i].vertex_index].p,
  1209.             &(*pChunk)->chunk_data.model_geometry_data.vertex_changes[i].delta_coordinates);
  1210.     }
  1211.     SetModelForUpdate(model_ptr, car, 0);
  1212.     AdvanceChunkPtr(pChunk, ePipe_chunk_model_geometry);
  1213. }
  1214.  
  1215. // IDA: void __usercall DoSmudge(tPipe_chunk **pChunk@<EAX>, int pDir@<EDX>)
  1216. void DoSmudge(tPipe_chunk** pChunk, int pDir) {
  1217.     int i;
  1218.     int v;
  1219.     tU8 inc;
  1220.     br_model* model_ptr;
  1221.     tCar_spec* car;
  1222.     //int group; // Pierre-Marie Baty -- unused variable
  1223.     LOG_TRACE("(%p, %d)", pChunk, pDir);
  1224.  
  1225.     if (((*pChunk)->subject_index & 0xff00) == 0) {
  1226.         car = &gProgram_state.current_car;
  1227.     } else {
  1228.         car = GetCarSpec((*pChunk)->subject_index >> 8, (*pChunk)->subject_index & 0xff);
  1229.     }
  1230.     model_ptr = car->car_model_actors[(*pChunk)->chunk_data.smudge_data.model_index].actor->model;
  1231.     for (i = 0; i < (*pChunk)->chunk_data.smudge_data.vertex_count; i++) {
  1232.         v = (*pChunk)->chunk_data.smudge_data.vertex_changes[i].vertex_index;
  1233.         inc = (*pChunk)->chunk_data.smudge_data.vertex_changes[i].light_index * pDir;
  1234.         V11MODEL(model_ptr)->groups->vertex_colours[v] = ((V11MODEL(model_ptr)->groups->vertex_colours[v] >> 24) + inc) << 24;
  1235.         if (model_ptr->flags & BR_MODF_UPDATEABLE) {
  1236.             model_ptr->vertices[V11MODEL(model_ptr)->groups->vertex_user[v]].index = (V11MODEL(model_ptr)->groups->vertex_colours[v] >> 24) + inc;
  1237.         }
  1238.     }
  1239. }
  1240.  
  1241. // IDA: void __usercall ApplySmudge(tPipe_chunk **pChunk@<EAX>)
  1242. void ApplySmudge(tPipe_chunk** pChunk) {
  1243.     LOG_TRACE("(%p)", pChunk);
  1244.  
  1245.     DoSmudge(pChunk, 1);
  1246.     AdvanceChunkPtr(pChunk, ePipe_chunk_smudge);
  1247. }
  1248.  
  1249. // IDA: void __usercall ApplyPedestrian(tPipe_chunk **pChunk@<EAX>)
  1250. void ApplyPedestrian(tPipe_chunk** pChunk) {
  1251.     LOG_TRACE("(%p)", pChunk);
  1252.  
  1253.     AdjustPedestrian(
  1254.         (*pChunk)->subject_index,
  1255.         ((*pChunk)->chunk_data.pedestrian_data.action_and_frame_index & 0x70) >> 4,
  1256.         (*pChunk)->chunk_data.pedestrian_data.action_and_frame_index & 0x0f,
  1257.         (*pChunk)->chunk_data.pedestrian_data.hit_points,
  1258.         (*pChunk)->chunk_data.pedestrian_data.action_and_frame_index >> 7,
  1259.         (*pChunk)->chunk_data.pedestrian_data.parent,
  1260.         (*pChunk)->chunk_data.pedestrian_data.parent_actor,
  1261.         (*pChunk)->chunk_data.pedestrian_data.spin_period,
  1262.         (*pChunk)->chunk_data.pedestrian_data.jump_magnitude,
  1263.         &(*pChunk)->chunk_data.pedestrian_data.offset,
  1264.         &(*pChunk)->chunk_data.pedestrian_data.new_translation);
  1265.     AdvanceChunkPtr(pChunk, ePipe_chunk_pedestrian);
  1266. }
  1267.  
  1268. // IDA: void __usercall ApplySpark(tPipe_chunk **pChunk@<EAX>)
  1269. void ApplySpark(tPipe_chunk** pChunk) {
  1270.     LOG_TRACE("(%p)", pChunk);
  1271.  
  1272.     AdjustSpark((*pChunk)->subject_index,
  1273.         &(*pChunk)->chunk_data.spark_data.pos,
  1274.         &(*pChunk)->chunk_data.spark_data.v);
  1275.     AdvanceChunkPtr(pChunk, ePipe_chunk_spark);
  1276. }
  1277.  
  1278. // IDA: void __usercall ApplyShrapnel(tPipe_chunk **pChunk@<EAX>)
  1279. void ApplyShrapnel(tPipe_chunk** pChunk) {
  1280.     LOG_TRACE("(%p)", pChunk);
  1281.  
  1282.     AdjustShrapnel((*pChunk)->subject_index,
  1283.         &(*pChunk)->chunk_data.shrapnel_data.pos,
  1284.         (*pChunk)->chunk_data.shrapnel_data.age,
  1285.         (*pChunk)->chunk_data.shrapnel_data.material);
  1286.     AdvanceChunkPtr(pChunk, ePipe_chunk_shrapnel);
  1287. }
  1288.  
  1289. // IDA: void __usercall ApplyScreenWobble(tPipe_chunk **pChunk@<EAX>)
  1290. void ApplyScreenWobble(tPipe_chunk** pChunk) {
  1291.     LOG_TRACE("(%p)", pChunk);
  1292.  
  1293.     SetScreenWobble((*pChunk)->chunk_data.screen_shake_data.wobble_x,
  1294.         (*pChunk)->chunk_data.screen_shake_data.wobble_y);
  1295.     AdvanceChunkPtr(pChunk, ePipe_chunk_screen_shake);
  1296. }
  1297.  
  1298. // IDA: void __usercall ApplyGrooveStop(tPipe_chunk **pChunk@<EAX>)
  1299. void ApplyGrooveStop(tPipe_chunk** pChunk) {
  1300.     LOG_TRACE("(%p)", pChunk);
  1301.  
  1302.     SetGrooveInterrupt((*pChunk)->subject_index,
  1303.         &(*pChunk)->chunk_data.groove_stop_data.matrix,
  1304.         (*pChunk)->chunk_data.groove_stop_data.path_interrupt,
  1305.         (*pChunk)->chunk_data.groove_stop_data.object_interrupt,
  1306.         (*pChunk)->chunk_data.groove_stop_data.path_resumption,
  1307.         (*pChunk)->chunk_data.groove_stop_data.object_resumption);
  1308.     AdvanceChunkPtr(pChunk, ePipe_chunk_groove_stop);
  1309. }
  1310.  
  1311. // IDA: void __usercall ApplyNonCar(tPipe_chunk **pChunk@<EAX>)
  1312. void ApplyNonCar(tPipe_chunk** pChunk) {
  1313.     LOG_TRACE("(%p)", pChunk);
  1314.  
  1315.     AdjustNonCar((*pChunk)->chunk_data.non_car_data.actor,
  1316.         &(*pChunk)->chunk_data.non_car_data.mat);
  1317.     AdvanceChunkPtr(pChunk, ePipe_chunk_non_car);
  1318. }
  1319.  
  1320. // IDA: void __usercall ApplySmoke(tPipe_chunk **pChunk@<EAX>)
  1321. void ApplySmoke(tPipe_chunk** pChunk) {
  1322.     br_vector3 pos;
  1323.     LOG_TRACE("(%p)", pChunk);
  1324.  
  1325.     GetReducedPos(&pos, &(*pChunk)->chunk_data.smoke_data.pos);
  1326.     AdjustSmoke((*pChunk)->subject_index,
  1327.         (*pChunk)->chunk_data.smoke_data.type,
  1328.         &pos,
  1329.         (*pChunk)->chunk_data.smoke_data.radius / 1024.f,
  1330.         (*pChunk)->chunk_data.smoke_data.strength / 256.f);
  1331.     AdvanceChunkPtr(pChunk, ePipe_chunk_smoke);
  1332. }
  1333.  
  1334. // IDA: void __usercall ApplySmokeColumn(tPipe_chunk **pChunk@<EAX>)
  1335. void ApplySmokeColumn(tPipe_chunk** pChunk) {
  1336.     LOG_TRACE("(%p)", pChunk);
  1337.  
  1338.     AdjustSmokeColumn((*pChunk)->subject_index & 0x3fff,
  1339.         ((((*pChunk)->chunk_data.smoke_column_data.car_ID) >> 8) == 0) ? &gProgram_state.current_car : GetCarSpec((*pChunk)->chunk_data.smoke_column_data.car_ID >> 8, (*pChunk)->chunk_data.smoke_column_data.car_ID & 0xff),
  1340.         (*pChunk)->chunk_data.smoke_column_data.vertex,
  1341.         (*pChunk)->subject_index >> 14);
  1342.     AdvanceChunkPtr(pChunk, ePipe_chunk_smoke_column);
  1343. }
  1344.  
  1345. // IDA: void __usercall ApplyFlame(tPipe_chunk **pChunk@<EAX>)
  1346. void ApplyFlame(tPipe_chunk** pChunk) {
  1347.     LOG_TRACE("(%p)", pChunk);
  1348.  
  1349.     AdjustFlame((*pChunk)->subject_index,
  1350.         (*pChunk)->chunk_data.flame_data.frame_count,
  1351.         (*pChunk)->chunk_data.flame_data.scale_x,
  1352.         (*pChunk)->chunk_data.flame_data.scale_y,
  1353.         (*pChunk)->chunk_data.flame_data.offset_x,
  1354. #if DETHRACE_FIX_BUGS
  1355.         (*pChunk)->chunk_data.flame_data.offset_z);
  1356. #else
  1357.         (*pChunk)->chunk_data.flame_data.offset_x);
  1358. #endif
  1359.     AdvanceChunkPtr(pChunk, ePipe_chunk_flame);
  1360. }
  1361.  
  1362. // IDA: void __usercall ApplySplash(tPipe_chunk **pChunk@<EAX>)
  1363. void ApplySplash(tPipe_chunk** pChunk) {
  1364.     tCar_spec* c;
  1365.     LOG_TRACE("(%p)", pChunk);
  1366.  
  1367.     if (((*pChunk)->subject_index & 0xff00) == 0) {
  1368.         c = &gProgram_state.current_car;
  1369.     } else {
  1370.         c = GetCarSpec((*pChunk)->subject_index >> 8, (*pChunk)->subject_index & 0xff);
  1371.     }
  1372.     c->water_d = (*pChunk)->chunk_data.splash_data.d;
  1373.     BrVector3Copy(&c->water_normal, &(*pChunk)->chunk_data.splash_data.normal);
  1374.     AdvanceChunkPtr(pChunk, ePipe_chunk_splash);
  1375. }
  1376.  
  1377. // IDA: void __usercall ApplyOilSpill(tPipe_chunk **pChunk@<EAX>, tU32 pStop_time@<EDX>)
  1378. void ApplyOilSpill(tPipe_chunk** pChunk, tU32 pStop_time) {
  1379.     LOG_TRACE("(%p, %d)", pChunk, pStop_time);
  1380.  
  1381.     AdjustOilSpill((*pChunk)->subject_index,
  1382.         &(*pChunk)->chunk_data.oil_data.mat,
  1383.         (*pChunk)->chunk_data.oil_data.full_size,
  1384.         (*pChunk)->chunk_data.oil_data.grow_rate,
  1385.         (*pChunk)->chunk_data.oil_data.spill_time,
  1386.         pStop_time,
  1387.         (*pChunk)->chunk_data.oil_data.car,
  1388.         &(*pChunk)->chunk_data.oil_data.original_pos,
  1389.         (*pChunk)->chunk_data.oil_data.pixelmap);
  1390.     AdvanceChunkPtr(pChunk, ePipe_chunk_oil_spill);
  1391. }
  1392.  
  1393. // IDA: void __usercall ApplyFrameBoundary(tPipe_chunk **pChunk@<EAX>)
  1394. void ApplyFrameBoundary(tPipe_chunk** pChunk) {
  1395.     //tU32 result; // Pierre-Marie Baty -- unused variable
  1396.     LOG_TRACE("(%p)", pChunk);
  1397.  
  1398.     gLast_replay_frame_time = (*pChunk)->chunk_data.frame_boundary_data.time;
  1399.     // DAT_0054b244 = PDGetTotalTime();
  1400.     AdvanceChunkPtr(pChunk, ePipe_chunk_frame_boundary);
  1401. }
  1402.  
  1403. // IDA: void __usercall ApplySound(tPipe_chunk **pChunk@<EAX>)
  1404. void ApplySound(tPipe_chunk** pChunk) {
  1405.     LOG_TRACE("(%p)", pChunk);
  1406.  
  1407.     if (!gDisable_sound) {
  1408.         if ((*pChunk)->chunk_data.sound_data.volume == 0) {
  1409.             DRS3StartSound2(GetOutletFromIndex((*pChunk)->chunk_data.sound_data.outlet_index),
  1410.                 (*pChunk)->subject_index,
  1411.                 1,
  1412.                 -1,
  1413.                 -1,
  1414.                 65535.f * GetReplayRate(),
  1415.                 0x10000);
  1416.         } else if (BrVector3LengthSquared(&(*pChunk)->chunk_data.sound_data.position) == 0) {
  1417.             DRS3StartSound2(GetOutletFromIndex((*pChunk)->chunk_data.sound_data.outlet_index),
  1418.                 (*pChunk)->subject_index,
  1419.                 1,
  1420.                 (*pChunk)->chunk_data.sound_data.volume & 0xff,
  1421.                 (*pChunk)->chunk_data.sound_data.volume >> 8,
  1422.                 (float)(*pChunk)->chunk_data.sound_data.pitch * fabsf(GetReplayRate()),
  1423.                 0x10000);
  1424.         } else {
  1425.             DRS3StartSound3D(GetOutletFromIndex((*pChunk)->chunk_data.sound_data.outlet_index),
  1426.                 (*pChunk)->subject_index,
  1427.                 &(*pChunk)->chunk_data.sound_data.position,
  1428.                 &gZero_vector,
  1429.                 1,
  1430.                 (*pChunk)->chunk_data.sound_data.volume,
  1431.                 (float)(*pChunk)->chunk_data.sound_data.pitch * fabsf(GetReplayRate()),
  1432.                 0x10000);
  1433.         }
  1434.     }
  1435.     AdvanceChunkPtr(pChunk, ePipe_chunk_sound);
  1436. }
  1437.  
  1438. // IDA: void __usercall ApplyCar(tPipe_chunk **pChunk@<EAX>)
  1439. void ApplyCar(tPipe_chunk** pChunk) {
  1440.     tCar_spec* car;
  1441.     br_vector3 com_offset_c;
  1442.     br_vector3 com_offset_w;
  1443.     LOG_TRACE("(%p)", pChunk);
  1444.  
  1445.     if (((*pChunk)->subject_index & 0xff00) == 0) {
  1446.         car = &gProgram_state.current_car;
  1447.     } else {
  1448.         car = GetCarSpec((*pChunk)->subject_index >> 8, (*pChunk)->subject_index & 0x00ff);
  1449.     }
  1450.     BrMatrix34Copy(&car->car_master_actor->t.t.mat, &(*pChunk)->chunk_data.car_data.transformation);
  1451.     BrVector3Copy(&car->v, &(*pChunk)->chunk_data.car_data.velocity);
  1452.     BrMatrix34TApplyV(&car->velocity_car_space, &car->v, &car->car_master_actor->t.t.mat);
  1453.     BrVector3InvScale(&car->velocity_car_space, &car->velocity_car_space, WORLD_SCALE);
  1454.     if (BrVector3LengthSquared(&car->velocity_car_space) >= .0001f) {
  1455.         BrVector3Normalise(&car->direction, &car->v);
  1456.     } else {
  1457.         BrVector3Negate(&car->direction, (br_vector3*)car->car_master_actor->t.t.mat.m[2]);
  1458.     }
  1459.     BrVector3Copy(&car->pos, &car->car_master_actor->t.t.translate.t);
  1460.     BrVector3InvScale(&com_offset_c, &car->cmpos, WORLD_SCALE);
  1461.     BrMatrix34ApplyV(&com_offset_w, &com_offset_c, &car->car_master_actor->t.t.mat);
  1462.     BrVector3Accumulate(&car->pos, &com_offset_w);
  1463.     car->speedo_speed = .07f * (*pChunk)->chunk_data.car_data.speedo_speed / 32767.f;
  1464.     car->lf_sus_position = 0.15f * (*pChunk)->chunk_data.car_data.lf_sus_position / 127.f;
  1465.     car->rf_sus_position = 0.15f * (*pChunk)->chunk_data.car_data.rf_sus_position / 127.f;
  1466.     car->lr_sus_position = 0.15f * (*pChunk)->chunk_data.car_data.lr_sus_position / 127.f;
  1467.     car->rr_sus_position = 0.15f * (*pChunk)->chunk_data.car_data.rr_sus_position / 127.f;
  1468.     car->steering_angle = 60.f * (*pChunk)->chunk_data.car_data.steering_angle / 32767.f;
  1469.     car->revs = 10 * ((*pChunk)->chunk_data.car_data.revs_and_gear & 0x7ff);
  1470.     car->gear = ((*pChunk)->chunk_data.car_data.revs_and_gear >> 12) - 1;
  1471.     car->frame_collision_flag = ((*pChunk)->chunk_data.car_data.revs_and_gear >> 11) & 0x1;
  1472.     AdvanceChunkPtr(pChunk, ePipe_chunk_car);
  1473. }
  1474.  
  1475. // IDA: void __usercall ApplyDamage(tPipe_chunk **pChunk@<EAX>)
  1476. void ApplyDamage(tPipe_chunk** pChunk) {
  1477.     tCar_spec* car;
  1478.     int i;
  1479.     LOG_TRACE("(%p)", pChunk);
  1480.  
  1481.     if (((*pChunk)->subject_index & 0xff00) == 0) {
  1482.         car = &gProgram_state.current_car;
  1483.     } else {
  1484.         car = GetCarSpec((*pChunk)->subject_index >> 8, (*pChunk)->subject_index & 0x00ff);
  1485.     }
  1486.     for (i = 0; i < COUNT_OF(car->damage_units); i++) {
  1487.         car->damage_units[i].damage_level += (*pChunk)->chunk_data.damage_data.damage_delta[i];
  1488.     }
  1489.     AdvanceChunkPtr(pChunk, ePipe_chunk_damage);
  1490. }
  1491.  
  1492. // IDA: void __usercall ApplySpecial(tPipe_chunk **pChunk@<EAX>)
  1493. void ApplySpecial(tPipe_chunk** pChunk) {
  1494.     LOG_TRACE("(%p)", pChunk);
  1495.  
  1496.     switch ((*pChunk)->subject_index) {
  1497.     case 0:
  1498.         if (fabsf(GetReplayRate()) <= 1.f) {
  1499.             FadePaletteDown();
  1500.         }
  1501.         break;
  1502.     case 1:
  1503.         gPed_scale_factor = 2.0f;
  1504.         break;
  1505.     case 2:
  1506.         gPed_scale_factor = 1.0f;
  1507.         break;
  1508.     case 3:
  1509.         gPed_scale_factor = 0.5f;
  1510.         break;
  1511.     case 4:
  1512.         gPed_scale_factor = 1.0f;
  1513.         break;
  1514.     }
  1515.     AdvanceChunkPtr(pChunk, ePipe_chunk_special);
  1516. }
  1517.  
  1518. // IDA: void __usercall ApplyPedGib(tPipe_chunk **pChunk@<EAX>)
  1519. void ApplyPedGib(tPipe_chunk** pChunk) {
  1520.     LOG_TRACE("(%p)", pChunk);
  1521.  
  1522.     AdjustPedGib((*pChunk)->subject_index,
  1523.         (*pChunk)->chunk_data.ped_gib_data.size,
  1524.         (*pChunk)->chunk_data.ped_gib_data.gib_index,
  1525.         (*pChunk)->chunk_data.ped_gib_data.ped_parent_index,
  1526.         &(*pChunk)->chunk_data.ped_gib_data.transform);
  1527.     AdvanceChunkPtr(pChunk, ePipe_chunk_ped_gib);
  1528. }
  1529.  
  1530. // IDA: void __usercall ApplyProxRay(tPipe_chunk **pChunk@<EAX>)
  1531. void ApplyProxRay(tPipe_chunk** pChunk) {
  1532.     LOG_TRACE("(%p)", pChunk);
  1533.  
  1534.     AdjustProxRay(
  1535.         (*pChunk)->subject_index,
  1536.         (*pChunk)->chunk_data.prox_ray_data.car_ID,
  1537.         (*pChunk)->chunk_data.prox_ray_data.ped_index,
  1538.         (*pChunk)->chunk_data.prox_ray_data.time);
  1539.     AdvanceChunkPtr(pChunk, ePipe_chunk_prox_ray);
  1540. }
  1541.  
  1542. // IDA: void __usercall ApplySkidAdjustment(tPipe_chunk **pChunk@<EAX>)
  1543. void ApplySkidAdjustment(tPipe_chunk** pChunk) {
  1544.     LOG_TRACE("(%p)", pChunk);
  1545.  
  1546.     AdjustSkid((*pChunk)->subject_index,
  1547.         &(*pChunk)->chunk_data.skid_adjustment.matrix,
  1548.         (*pChunk)->chunk_data.skid_adjustment.material_index);
  1549.     AdvanceChunkPtr(pChunk, ePipe_chunk_skid_adjustment);
  1550. }
  1551.  
  1552. // IDA: int __usercall ApplyPipedSession@<EAX>(tU8 **pPtr@<EAX>)
  1553. int ApplyPipedSession(tU8** pPtr) {
  1554.     int i;
  1555.     int return_value;
  1556.     tPipe_chunk* chunk_ptr;
  1557.     tPipe_chunk_type chunk_type;
  1558.     LOG_TRACE("(%p)", pPtr);
  1559.  
  1560.     if (*pPtr == gPipe_record_ptr) {
  1561.         return 1;
  1562.     }
  1563.     gEnd_of_session = *pPtr + (LengthOfSession((tPipe_session*)*pPtr) - sizeof(tU16));
  1564.     REPLAY_DEBUG_ASSERT(((tPipe_session*)*pPtr)->pipe_magic1 == REPLAY_DEBUG_SESSION_MAGIC1);
  1565.     chunk_ptr = (tPipe_chunk*)(*pPtr + offsetof(tPipe_session, chunks));
  1566.     return_value = 0;
  1567.     chunk_type = ((tPipe_session*)*pPtr)->chunk_type;
  1568.     for (i = 0; i < ((tPipe_session*)*pPtr)->number_of_chunks; i++) {
  1569.         switch (chunk_type) {
  1570.         case ePipe_chunk_model_geometry:
  1571.             ApplyModelGeometry(&chunk_ptr);
  1572.             break;
  1573.         case ePipe_chunk_pedestrian:
  1574.             ApplyPedestrian(&chunk_ptr);
  1575.             break;
  1576.         case ePipe_chunk_frame_boundary:
  1577.             ApplyFrameBoundary(&chunk_ptr);
  1578.             return_value = 1;
  1579.             break;
  1580.         case ePipe_chunk_car:
  1581.             ApplyCar(&chunk_ptr);
  1582.             break;
  1583.         case ePipe_chunk_sound:
  1584.             ApplySound(&chunk_ptr);
  1585.             break;
  1586.         case ePipe_chunk_damage:
  1587.             ApplyDamage(&chunk_ptr);
  1588.             break;
  1589.         case ePipe_chunk_special:
  1590.             ApplySpecial(&chunk_ptr);
  1591.             break;
  1592.         case ePipe_chunk_ped_gib:
  1593.             ApplyPedGib(&chunk_ptr);
  1594.             break;
  1595.         case ePipe_chunk_incident:
  1596.             AdvanceChunkPtr(&chunk_ptr, ePipe_chunk_incident);
  1597.             break;
  1598.         case ePipe_chunk_spark:
  1599.             ApplySpark(&chunk_ptr);
  1600.             break;
  1601.         case ePipe_chunk_shrapnel:
  1602.             ApplyShrapnel(&chunk_ptr);
  1603.             break;
  1604.         case ePipe_chunk_screen_shake:
  1605.             ApplyScreenWobble(&chunk_ptr);
  1606.             break;
  1607.         case ePipe_chunk_groove_stop:
  1608.             ApplyGrooveStop(&chunk_ptr);
  1609.             break;
  1610.         case ePipe_chunk_non_car:
  1611.             ApplyNonCar(&chunk_ptr);
  1612.             break;
  1613.         case ePipe_chunk_smoke:
  1614.             ApplySmoke(&chunk_ptr);
  1615.             break;
  1616.         case ePipe_chunk_oil_spill:
  1617.             ApplyOilSpill(&chunk_ptr, 0);
  1618.             break;
  1619.         case ePipe_chunk_smoke_column:
  1620.             ApplySmokeColumn(&chunk_ptr);
  1621.             break;
  1622.         case ePipe_chunk_flame:
  1623.             ApplyFlame(&chunk_ptr);
  1624.             break;
  1625.         case ePipe_chunk_smudge:
  1626.             ApplySmudge(&chunk_ptr);
  1627.             break;
  1628.         case ePipe_chunk_splash:
  1629.             ApplySplash(&chunk_ptr);
  1630.             break;
  1631.         case ePipe_chunk_prox_ray:
  1632.             ApplyProxRay(&chunk_ptr);
  1633.             break;
  1634.         case ePipe_chunk_skid_adjustment:
  1635.             ApplySkidAdjustment(&chunk_ptr);
  1636.             break;
  1637.         default:
  1638.             break;
  1639.         }
  1640.     }
  1641. #if defined(DETHRACE_FIX_BUGS)
  1642.     *pPtr += PIPE_ALIGN(LengthOfSession((tPipe_session*)*pPtr));
  1643. #else
  1644.     *pPtr += LengthOfSession((tPipe_session*)*pPtr);
  1645. #endif
  1646.     if (*pPtr >= gPipe_buffer_working_end && *pPtr != gPipe_record_ptr) {
  1647.         *pPtr = gPipe_buffer_start;
  1648.     }
  1649.     return return_value;
  1650. }
  1651.  
  1652. // IDA: int __usercall MoveSessionPointerBackOne@<EAX>(tU8 **pPtr@<EAX>)
  1653. int MoveSessionPointerBackOne(tU8** pPtr) {
  1654.     LOG_TRACE("(%p)", pPtr);
  1655.  
  1656.     if (*pPtr == gPipe_buffer_oldest && *pPtr != gPipe_record_ptr) {
  1657.         return 1;
  1658.     }
  1659.     if (*pPtr == gPipe_buffer_start) {
  1660.         *pPtr = gPipe_buffer_working_end;
  1661.     }
  1662.     *pPtr -= sizeof(tU16);
  1663.     REPLAY_DEBUG_ASSERT(*(tU16*)*pPtr != 0);
  1664.     *pPtr -= *(tU16*)*pPtr;
  1665.     REPLAY_DEBUG_ASSERT(((tPipe_session*)*pPtr)->pipe_magic1 == REPLAY_DEBUG_SESSION_MAGIC1);
  1666.     return 0;
  1667. }
  1668.  
  1669. // IDA: int __usercall MoveSessionPointerForwardOne@<EAX>(tU8 **pPtr@<EAX>)
  1670. int MoveSessionPointerForwardOne(tU8** pPtr) {
  1671.     LOG_TRACE("(%p)", pPtr);
  1672.  
  1673.     REPLAY_DEBUG_ASSERT(((tPipe_session*)*pPtr)->pipe_magic1 == REPLAY_DEBUG_SESSION_MAGIC1);
  1674. #if defined(DETHRACE_FIX_BUGS)
  1675.     *pPtr += PIPE_ALIGN(LengthOfSession((tPipe_session*)*pPtr));
  1676. #else
  1677.     *pPtr += LengthOfSession((tPipe_session*)*pPtr);
  1678. #endif
  1679.     if (*pPtr >= gPipe_buffer_working_end && *pPtr != gPipe_record_ptr) {
  1680.         *pPtr = gPipe_buffer_start;
  1681.     }
  1682.     return *pPtr == gPipe_record_ptr;
  1683. }
  1684.  
  1685. // IDA: tPipe_chunk* __usercall FindPreviousChunk@<EAX>(tU8 *pPtr@<EAX>, tPipe_chunk_type pType@<EDX>, tChunk_subject_index pIndex@<EBX>)
  1686. tPipe_chunk* FindPreviousChunk(tU8* pPtr, tPipe_chunk_type pType, tChunk_subject_index pIndex) {
  1687.     tU8* ptr;
  1688.     int i;
  1689.     int reached_end;
  1690.     int chunk_counter;
  1691.     tPipe_chunk* mr_chunky;
  1692.     tChunk_subject_index masked_index;
  1693.     LOG_TRACE("(%p, %d, %d)", pPtr, pType, pIndex);
  1694.  
  1695.     ptr = pPtr;
  1696.     chunk_counter = 0;
  1697.     masked_index = pIndex & 0x0fff;
  1698.     while (1) {
  1699.         if (!MoveSessionPointerBackOne(&ptr)) {
  1700.             reached_end = chunk_counter >= gMax_rewind_chunks;
  1701.             chunk_counter++;
  1702.         } else {
  1703.             reached_end = 1;
  1704.         }
  1705.         if (!reached_end) {
  1706.             gEnd_of_session = ptr + LengthOfSession((tPipe_session*)ptr) - sizeof(tU16);
  1707.             mr_chunky = &((tPipe_session*)ptr)->chunks;
  1708.             for (i = 0; i < ((tPipe_session*)ptr)->number_of_chunks && ((tPipe_session*)ptr)->chunk_type == pType; i++) {
  1709.                 if ((mr_chunky->subject_index & 0xfff) == masked_index) {
  1710.                     return mr_chunky;
  1711.                 }
  1712.                 AdvanceChunkPtr(&mr_chunky, pType);
  1713.             }
  1714.         }
  1715.         if (reached_end) {
  1716.             return NULL;
  1717.         }
  1718.     }
  1719. }
  1720.  
  1721. // IDA: void __usercall UndoModelGeometry(tPipe_chunk **pChunk@<EAX>)
  1722. void UndoModelGeometry(tPipe_chunk** pChunk) {
  1723.     int i;
  1724.     br_model* model_ptr;
  1725.     tCar_spec* car;
  1726.     LOG_TRACE("(%p)", pChunk);
  1727.  
  1728.     if (((*pChunk)->subject_index & 0xff00) == 0) {
  1729.         car = &gProgram_state.current_car;
  1730.     } else {
  1731.         car = GetCarSpec((*pChunk)->subject_index >> 8, (*pChunk)->subject_index & 0x00ff);
  1732.     }
  1733.     model_ptr = car->car_model_actors[(*pChunk)->chunk_data.model_geometry_data.model_index].actor->model;
  1734.     for (i = 0; i < (*pChunk)->chunk_data.model_geometry_data.vertex_count; i++) {
  1735.         BrVector3Sub(&model_ptr->vertices[(*pChunk)->chunk_data.model_geometry_data.vertex_changes[i].vertex_index].p,
  1736.             &model_ptr->vertices[(*pChunk)->chunk_data.model_geometry_data.vertex_changes[i].vertex_index].p,
  1737.             &(*pChunk)->chunk_data.model_geometry_data.vertex_changes[i].delta_coordinates);
  1738.     }
  1739.     SetModelForUpdate(model_ptr, car, 0);
  1740.     AdvanceChunkPtr(pChunk, ePipe_chunk_model_geometry);
  1741. }
  1742.  
  1743. // IDA: void __usercall UndoSmudge(tPipe_chunk **pChunk@<EAX>)
  1744. void UndoSmudge(tPipe_chunk** pChunk) {
  1745.     //int i; // Pierre-Marie Baty -- unused variable
  1746.     //br_model* model_ptr; // Pierre-Marie Baty -- unused variable
  1747.     //tCar_spec* car; // Pierre-Marie Baty -- unused variable
  1748.     LOG_TRACE("(%p)", pChunk);
  1749.  
  1750.     DoSmudge(pChunk, -1);
  1751.     AdvanceChunkPtr(pChunk, ePipe_chunk_smudge);
  1752. }
  1753.  
  1754. // IDA: void __usercall UndoPedestrian(tPipe_chunk **pChunk@<EAX>, tPipe_chunk *pPrev_chunk@<EDX>)
  1755. void UndoPedestrian(tPipe_chunk** pChunk, tPipe_chunk* pPrev_chunk) {
  1756.     tPipe_chunk* temp_prev_chunk;
  1757.     LOG_TRACE("(%p, %p)", pChunk, pPrev_chunk);
  1758.  
  1759.     temp_prev_chunk = pPrev_chunk;
  1760.     if (pPrev_chunk == NULL) {
  1761.         ApplyPedestrian(pChunk);
  1762.     } else {
  1763.         gDisable_advance = 1;
  1764.         ApplyPedestrian(&temp_prev_chunk);
  1765.         gDisable_advance = 0;
  1766.         AdvanceChunkPtr(pChunk, ePipe_chunk_pedestrian);
  1767.     }
  1768. }
  1769.  
  1770. // IDA: void __usercall UndoFrameBoundary(tPipe_chunk **pChunk@<EAX>, tPipe_chunk *pPrev_chunk@<EDX>)
  1771. void UndoFrameBoundary(tPipe_chunk** pChunk, tPipe_chunk* pPrev_chunk) {
  1772.     //tPipe_chunk* temp_prev_chunk; // Pierre-Marie Baty -- unused variable
  1773.     LOG_TRACE("(%p, %p)", pChunk, pPrev_chunk);
  1774.  
  1775.     ApplyFrameBoundary(pChunk);
  1776.     AdvanceChunkPtr(pChunk, ePipe_chunk_frame_boundary);
  1777. }
  1778.  
  1779. // IDA: void __usercall UndoCar(tPipe_chunk **pChunk@<EAX>, tPipe_chunk *pPrev_chunk@<EDX>)
  1780. void UndoCar(tPipe_chunk** pChunk, tPipe_chunk* pPrev_chunk) {
  1781.     tPipe_chunk* temp_prev_chunk;
  1782.     LOG_TRACE("(%p, %p)", pChunk, pPrev_chunk);
  1783.  
  1784.     temp_prev_chunk = pPrev_chunk;
  1785.     if (pPrev_chunk == NULL) {
  1786.         ApplyCar(pChunk);
  1787.     } else {
  1788.         gDisable_advance = 1;
  1789.         ApplyCar(&temp_prev_chunk);
  1790.         gDisable_advance = 0;
  1791.         AdvanceChunkPtr(pChunk, ePipe_chunk_car);
  1792.     }
  1793. }
  1794.  
  1795. // IDA: void __usercall UndoSound(tPipe_chunk **pChunk@<EAX>)
  1796. void UndoSound(tPipe_chunk** pChunk) {
  1797.     LOG_TRACE("(%p)", pChunk);
  1798.  
  1799.     AdvanceChunkPtr(pChunk, ePipe_chunk_sound);
  1800. }
  1801.  
  1802. // IDA: void __usercall UndoDamage(tPipe_chunk **pChunk@<EAX>)
  1803. void UndoDamage(tPipe_chunk** pChunk) {
  1804.     tCar_spec* car;
  1805.     int i;
  1806.     LOG_TRACE("(%p)", pChunk);
  1807.  
  1808.     if (((*pChunk)->subject_index & 0xff00) == 0) {
  1809.         car = &gProgram_state.current_car;
  1810.     } else {
  1811.         car = GetCarSpec((*pChunk)->subject_index >> 8, (*pChunk)->subject_index & 0xff);
  1812.     }
  1813.     for (i = 0; i < COUNT_OF(car->damage_units); i++) {
  1814.         car->damage_units[i].damage_level -= (*pChunk)->chunk_data.damage_data.damage_delta[i];
  1815.     }
  1816.     AdvanceChunkPtr(pChunk, ePipe_chunk_damage);
  1817. }
  1818.  
  1819. // IDA: void __usercall UndoSpecial(tPipe_chunk **pChunk@<EAX>)
  1820. void UndoSpecial(tPipe_chunk** pChunk) {
  1821.     LOG_TRACE("(%p)", pChunk);
  1822.  
  1823.     if ((*pChunk)->subject_index == 0) {
  1824.         ApplySpecial(pChunk);
  1825.     } else {
  1826.         switch ((*pChunk)->subject_index) {
  1827.         case 1:
  1828.             gPed_scale_factor = 1.0f;
  1829.             break;
  1830.         case 2:
  1831.             gPed_scale_factor = 2.0f;
  1832.             break;
  1833.         case 3:
  1834.             gPed_scale_factor = 1.0f;
  1835.             break;
  1836.         case 4:
  1837.             gPed_scale_factor = 0.5f;
  1838.             break;
  1839.         }
  1840.         AdvanceChunkPtr(pChunk, ePipe_chunk_special);
  1841.     }
  1842. }
  1843.  
  1844. // IDA: void __usercall UndoPedGib(tPipe_chunk **pChunk@<EAX>, tPipe_chunk *pPrev_chunk@<EDX>)
  1845. void UndoPedGib(tPipe_chunk** pChunk, tPipe_chunk* pPrev_chunk) {
  1846.     tPipe_chunk* temp_prev_chunk;
  1847.     LOG_TRACE("(%p, %p)", pChunk, pPrev_chunk);
  1848.  
  1849.     temp_prev_chunk = pPrev_chunk;
  1850.     gDisable_advance = 1;
  1851.     if (pPrev_chunk != NULL) {
  1852.         ApplyPedGib(&temp_prev_chunk);
  1853.     }
  1854.     gDisable_advance = 0;
  1855.     AdvanceChunkPtr(pChunk, ePipe_chunk_ped_gib);
  1856. }
  1857.  
  1858. // IDA: void __usercall UndoSpark(tPipe_chunk **pChunk@<EAX>, tPipe_chunk *pPrev_chunk@<EDX>)
  1859. void UndoSpark(tPipe_chunk** pChunk, tPipe_chunk* pPrev_chunk) {
  1860.     tPipe_chunk* temp_prev_chunk;
  1861.     LOG_TRACE("(%p, %p)", pChunk, pPrev_chunk);
  1862.  
  1863.     temp_prev_chunk = pPrev_chunk;
  1864.     gDisable_advance = 1;
  1865.     if (pPrev_chunk != NULL) {
  1866.         ApplySpark(&temp_prev_chunk);
  1867.     }
  1868.     gDisable_advance = 0;
  1869.     AdvanceChunkPtr(pChunk, ePipe_chunk_spark);
  1870. }
  1871.  
  1872. // IDA: void __usercall UndoShrapnel(tPipe_chunk **pChunk@<EAX>, tPipe_chunk *pPrev_chunk@<EDX>)
  1873. void UndoShrapnel(tPipe_chunk** pChunk, tPipe_chunk* pPrev_chunk) {
  1874.     tPipe_chunk* temp_prev_chunk;
  1875.     LOG_TRACE("(%p, %p)", pChunk, pPrev_chunk);
  1876.  
  1877.     temp_prev_chunk = pPrev_chunk;
  1878.     gDisable_advance = 1;
  1879.     if (pPrev_chunk != NULL) {
  1880.         ApplyShrapnel(&temp_prev_chunk);
  1881.     }
  1882.     gDisable_advance = 0;
  1883.     AdvanceChunkPtr(pChunk, ePipe_chunk_shrapnel);
  1884. }
  1885.  
  1886. // IDA: void __usercall UndoScreenWobble(tPipe_chunk **pChunk@<EAX>, tPipe_chunk *pPrev_chunk@<EDX>)
  1887. void UndoScreenWobble(tPipe_chunk** pChunk, tPipe_chunk* pPrev_chunk) {
  1888.     tPipe_chunk* temp_prev_chunk;
  1889.     LOG_TRACE("(%p, %p)", pChunk, pPrev_chunk);
  1890.  
  1891.     temp_prev_chunk = pPrev_chunk;
  1892.     gDisable_advance = 1;
  1893.     if (pPrev_chunk == NULL) {
  1894.         SetScreenWobble(0, 0);
  1895.     } else {
  1896.         ApplyScreenWobble(&temp_prev_chunk);
  1897.     }
  1898.     gDisable_advance = 0;
  1899.     AdvanceChunkPtr(pChunk, ePipe_chunk_screen_shake);
  1900. }
  1901.  
  1902. // IDA: void __usercall UndoGrooveStop(tPipe_chunk **pChunk@<EAX>, tPipe_chunk *pPrev_chunk@<EDX>)
  1903. void UndoGrooveStop(tPipe_chunk** pChunk, tPipe_chunk* pPrev_chunk) {
  1904.     tPipe_chunk* temp_prev_chunk;
  1905.     LOG_TRACE("(%p, %p)", pChunk, pPrev_chunk);
  1906.  
  1907.     temp_prev_chunk = pPrev_chunk;
  1908.     gDisable_advance = 1;
  1909.     if (pPrev_chunk != NULL) {
  1910.         ApplyGrooveStop(&temp_prev_chunk);
  1911.     }
  1912.     gDisable_advance = 0;
  1913.     AdvanceChunkPtr(pChunk, ePipe_chunk_groove_stop);
  1914. }
  1915.  
  1916. // IDA: void __usercall UndoNonCar(tPipe_chunk **pChunk@<EAX>, tPipe_chunk *pPrev_chunk@<EDX>)
  1917. void UndoNonCar(tPipe_chunk** pChunk, tPipe_chunk* pPrev_chunk) {
  1918.     tPipe_chunk* temp_prev_chunk;
  1919.     LOG_TRACE("(%p, %p)", pChunk, pPrev_chunk);
  1920.  
  1921.     temp_prev_chunk = pPrev_chunk;
  1922.     gDisable_advance = 1;
  1923.     if (pPrev_chunk != NULL) {
  1924.         ApplyNonCar(&temp_prev_chunk);
  1925.     }
  1926.     gDisable_advance = 0;
  1927.     AdvanceChunkPtr(pChunk, ePipe_chunk_non_car);
  1928. }
  1929.  
  1930. // IDA: void __usercall UndoSmoke(tPipe_chunk **pChunk@<EAX>, tPipe_chunk *pPrev_chunk@<EDX>)
  1931. void UndoSmoke(tPipe_chunk** pChunk, tPipe_chunk* pPrev_chunk) {
  1932.     tPipe_chunk* temp_prev_chunk;
  1933.     LOG_TRACE("(%p, %p)", pChunk, pPrev_chunk);
  1934.  
  1935.     temp_prev_chunk = pPrev_chunk;
  1936.     gDisable_advance = 1;
  1937.     if (pPrev_chunk != NULL) {
  1938.         ApplySmoke(&temp_prev_chunk);
  1939.     }
  1940.     gDisable_advance = 0;
  1941.     AdvanceChunkPtr(pChunk, ePipe_chunk_smoke);
  1942. }
  1943.  
  1944. // IDA: void __usercall UndoSmokeColumn(tPipe_chunk **pChunk@<EAX>, tPipe_chunk *pPrev_chunk@<EDX>)
  1945. void UndoSmokeColumn(tPipe_chunk** pChunk, tPipe_chunk* pPrev_chunk) {
  1946.     //tPipe_chunk* temp_prev_chunk; // Pierre-Marie Baty -- unused variable
  1947.     LOG_TRACE("(%p, %p)", pChunk, pPrev_chunk);
  1948.  
  1949.     ApplySmokeColumn(pChunk);
  1950. }
  1951.  
  1952. // IDA: void __usercall UndoFlame(tPipe_chunk **pChunk@<EAX>, tPipe_chunk *pPrev_chunk@<EDX>)
  1953. void UndoFlame(tPipe_chunk** pChunk, tPipe_chunk* pPrev_chunk) {
  1954.     LOG_TRACE("(%p, %p)", pChunk, pPrev_chunk);
  1955.  
  1956.     ApplyFlame(pChunk);
  1957. }
  1958.  
  1959. // IDA: void __usercall UndoSplash(tPipe_chunk **pChunk@<EAX>, tPipe_chunk *pPrev_chunk@<EDX>)
  1960. void UndoSplash(tPipe_chunk** pChunk, tPipe_chunk* pPrev_chunk) {
  1961.     tPipe_chunk* temp_prev_chunk;
  1962.     LOG_TRACE("(%p, %p)", pChunk, pPrev_chunk);
  1963.  
  1964.     temp_prev_chunk = pPrev_chunk;
  1965.     gDisable_advance = 1;
  1966.     if (pPrev_chunk == NULL) {
  1967.         ((((*pChunk)->subject_index & 0xff00) == 0) ? &gProgram_state.current_car : GetCarSpec((*pChunk)->subject_index >> 8, (*pChunk)->subject_index & 0xff))->water_d = 10000.f;
  1968.     } else {
  1969.         ApplySplash(&temp_prev_chunk);
  1970.     }
  1971.     gDisable_advance = 0;
  1972.     AdvanceChunkPtr(pChunk, ePipe_chunk_splash);
  1973. }
  1974.  
  1975. // IDA: void __usercall UndoOilSpill(tPipe_chunk **pChunk@<EAX>, tPipe_chunk *pPrev_chunk@<EDX>)
  1976. void UndoOilSpill(tPipe_chunk** pChunk, tPipe_chunk* pPrev_chunk) {
  1977.     tPipe_chunk* temp_prev_chunk;
  1978.     LOG_TRACE("(%p, %p)", pChunk, pPrev_chunk);
  1979.  
  1980.     temp_prev_chunk = pPrev_chunk;
  1981.     gDisable_advance = 1;
  1982.     if (pPrev_chunk != NULL) {
  1983.         ApplyOilSpill(&temp_prev_chunk, (*pChunk)->chunk_data.oil_data.previous_stop_time);
  1984.     }
  1985.     gDisable_advance = 0;
  1986.     AdvanceChunkPtr(pChunk, ePipe_chunk_oil_spill);
  1987. }
  1988.  
  1989. // IDA: void __usercall UndoProxRay(tPipe_chunk **pChunk@<EAX>)
  1990. void UndoProxRay(tPipe_chunk** pChunk) {
  1991.     LOG_TRACE("(%p)", pChunk);
  1992.  
  1993.     ApplyProxRay(pChunk);
  1994. }
  1995.  
  1996. // IDA: void __usercall UndoSkidAdjustment(tPipe_chunk **pChunk@<EAX>, tPipe_chunk *pPrev_chunk@<EDX>)
  1997. void UndoSkidAdjustment(tPipe_chunk** pChunk, tPipe_chunk* pPrev_chunk) {
  1998.     LOG_TRACE("(%p, %p)", pChunk, pPrev_chunk);
  1999.  
  2000.     gDisable_advance = 1;
  2001.     if (pPrev_chunk == NULL) {
  2002.         HideSkid((*pChunk)->subject_index);
  2003.     } else {
  2004.         ApplySkidAdjustment(&pPrev_chunk);
  2005.     }
  2006.     gDisable_advance = 0;
  2007.     AdvanceChunkPtr(pChunk, ePipe_chunk_skid_adjustment);
  2008. }
  2009.  
  2010. // IDA: int __usercall UndoPipedSession@<EAX>(tU8 **pPtr@<EAX>)
  2011. int UndoPipedSession(tU8** pPtr) {
  2012.     tPipe_chunk* chunk_ptr;
  2013.     tPipe_chunk* prev_chunk;
  2014.     tU8* temp_ptr;
  2015.     tU8* pushed_end_of_session;
  2016.     int i;
  2017.     tPipe_chunk_type chunk_type;
  2018.     LOG_TRACE("(%p)", pPtr);
  2019.  
  2020.     if (MoveSessionPointerBackOne(pPtr)) {
  2021.         return 1;
  2022.     }
  2023.     REPLAY_DEBUG_ASSERT(((tPipe_session*)*pPtr)->pipe_magic1 == REPLAY_DEBUG_SESSION_MAGIC1);
  2024.     gEnd_of_session = *pPtr + LengthOfSession((tPipe_session*)*pPtr) - sizeof(tU16);
  2025.     chunk_ptr = &((tPipe_session*)*pPtr)->chunks;
  2026.     chunk_type = ((tPipe_session*)*pPtr)->chunk_type;
  2027.     pushed_end_of_session = gEnd_of_session;
  2028.     for (i = 0; i < ((tPipe_session*)*pPtr)->number_of_chunks; i++) {
  2029.         if (!(chunk_type == ePipe_chunk_model_geometry || chunk_type == ePipe_chunk_sound || chunk_type == ePipe_chunk_damage || chunk_type == ePipe_chunk_special || chunk_type == ePipe_chunk_incident || chunk_type == ePipe_chunk_prox_ray || chunk_type == ePipe_chunk_smudge)) {
  2030.             prev_chunk = FindPreviousChunk(*pPtr, ((tPipe_session*)*pPtr)->chunk_type, chunk_ptr->subject_index);
  2031.         }
  2032.         REPLAY_DEBUG_ASSERT(((tPipe_chunk*)chunk_ptr)->chunk_magic1 == REPLAY_DEBUG_CHUNK_MAGIC1);
  2033.         gEnd_of_session = pushed_end_of_session;
  2034.         switch (chunk_type) {
  2035.         case ePipe_chunk_model_geometry:
  2036.             UndoModelGeometry(&chunk_ptr);
  2037.             break;
  2038.         case ePipe_chunk_pedestrian:
  2039.             UndoPedestrian(&chunk_ptr, prev_chunk);
  2040.             break;
  2041.         case ePipe_chunk_frame_boundary:
  2042.             UndoFrameBoundary(&chunk_ptr, prev_chunk);
  2043.             break;
  2044.         case ePipe_chunk_car:
  2045.             UndoCar(&chunk_ptr, prev_chunk);
  2046.             break;
  2047.         case ePipe_chunk_sound:
  2048.             UndoSound(&chunk_ptr);
  2049.             break;
  2050.         case ePipe_chunk_damage:
  2051.             UndoDamage(&chunk_ptr);
  2052.             break;
  2053.         case ePipe_chunk_special:
  2054.             UndoSpecial(&chunk_ptr);
  2055.             break;
  2056.         case ePipe_chunk_ped_gib:
  2057.             UndoPedGib(&chunk_ptr, prev_chunk);
  2058.             break;
  2059.         case ePipe_chunk_incident:
  2060.             AdvanceChunkPtr(&chunk_ptr, ePipe_chunk_incident);
  2061.             break;
  2062.         case ePipe_chunk_spark:
  2063.             UndoSpark(&chunk_ptr, prev_chunk);
  2064.             break;
  2065.         case ePipe_chunk_shrapnel:
  2066.             UndoShrapnel(&chunk_ptr, prev_chunk);
  2067.             break;
  2068.         case ePipe_chunk_screen_shake:
  2069.             UndoScreenWobble(&chunk_ptr, prev_chunk);
  2070.             break;
  2071.         case ePipe_chunk_groove_stop:
  2072.             UndoGrooveStop(&chunk_ptr, prev_chunk);
  2073.             break;
  2074.         case ePipe_chunk_non_car:
  2075.             UndoNonCar(&chunk_ptr, prev_chunk);
  2076.             break;
  2077.         case ePipe_chunk_smoke:
  2078.             UndoSmoke(&chunk_ptr, prev_chunk);
  2079.             break;
  2080.         case ePipe_chunk_oil_spill:
  2081.             UndoOilSpill(&chunk_ptr, prev_chunk);
  2082.             break;
  2083.         case ePipe_chunk_smoke_column:
  2084.             UndoSmokeColumn(&chunk_ptr, prev_chunk);
  2085.             break;
  2086.         case ePipe_chunk_flame:
  2087.             UndoFlame(&chunk_ptr, prev_chunk);
  2088.             break;
  2089.         case ePipe_chunk_smudge:
  2090.             UndoSmudge(&chunk_ptr);
  2091.             break;
  2092.         case ePipe_chunk_splash:
  2093.             UndoSplash(&chunk_ptr, prev_chunk);
  2094.             break;
  2095.         case ePipe_chunk_prox_ray:
  2096.             UndoProxRay(&chunk_ptr);
  2097.             break;
  2098.         case ePipe_chunk_skid_adjustment:
  2099.             UndoSkidAdjustment(&chunk_ptr, prev_chunk);
  2100.             break;
  2101.         default:
  2102.             break;
  2103.         }
  2104.     }
  2105.     temp_ptr = *pPtr;
  2106.     if (MoveSessionPointerBackOne(&temp_ptr)) {
  2107.         return 1;
  2108.     }
  2109.     return ((tPipe_session*)temp_ptr)->chunk_type == ePipe_chunk_frame_boundary;
  2110. }
  2111.  
  2112. // IDA: tU32 __usercall FindPrevFrameTime@<EAX>(tU8 *pPtr@<EAX>)
  2113. tU32 FindPrevFrameTime(tU8* pPtr) {
  2114.     tU8* temp_ptr;
  2115.     LOG_TRACE("(%p)", pPtr);
  2116.  
  2117.     temp_ptr = pPtr;
  2118.     do {
  2119.         if (MoveSessionPointerBackOne(&temp_ptr)) {
  2120.             return 0;
  2121.         }
  2122.     } while (((tPipe_session*)temp_ptr)->chunk_type != ePipe_chunk_frame_boundary);
  2123.     return ((tPipe_session*)temp_ptr)->chunks.chunk_data.frame_boundary_data.time;
  2124. }
  2125.  
  2126. // IDA: void __usercall ScanBuffer(tU8 **pPtr@<EAX>, tPipe_chunk_type pType@<EDX>, tU32 pDefault_time@<EBX>, int (*pCall_back)(tPipe_chunk*, int, tU32)@<ECX>, int (*pTime_check)(tU32))
  2127. void ScanBuffer(tU8** pPtr, tPipe_chunk_type pType, tU32 pDefault_time, int (*pCall_back)(tPipe_chunk*, int, tU32), int (*pTime_check)(tU32)) {
  2128.     //tPipe_chunk* chunk_ptr; // Pierre-Marie Baty -- unused variable
  2129.     tU32 the_time;
  2130.     LOG_TRACE("(%p, %d, %d, %p, %p)", pPtr, pType, pDefault_time, pCall_back, pTime_check);
  2131.  
  2132.     the_time = pDefault_time;
  2133.     while (1) {
  2134.         if (PipeSearchForwards() ? MoveSessionPointerForwardOne(pPtr) : MoveSessionPointerBackOne(pPtr)) {
  2135.             return;
  2136.         }
  2137.         gEnd_of_session = *pPtr + LengthOfSession((tPipe_session*)*pPtr) - sizeof(tU16);
  2138.         if (((tPipe_session*)*pPtr)->chunk_type == ePipe_chunk_frame_boundary) {
  2139.             the_time = ((tPipe_session*)*pPtr)->chunks.chunk_data.frame_boundary_data.time;
  2140.         } else if (((tPipe_session*)*pPtr)->chunk_type == pType) {
  2141.             if (pCall_back(&((tPipe_session*)*pPtr)->chunks, ((tPipe_session*)*pPtr)->number_of_chunks, the_time)) {
  2142.                 return;
  2143.             }
  2144.         }
  2145.         if (pTime_check != NULL) {
  2146.             if (!pTime_check(the_time)) {
  2147.                 return;
  2148.             }
  2149.         }
  2150.     }
  2151. }
  2152.  
  2153. // IDA: int __usercall CheckSound@<EAX>(tPipe_chunk *pChunk_ptr@<EAX>, int pChunk_count@<EDX>, tU32 pTime@<EBX>)
  2154. int CheckSound(tPipe_chunk* pChunk_ptr, int pChunk_count, tU32 pTime) {
  2155.     //int i; // Pierre-Marie Baty -- unused variable
  2156.     //int sound_length; // Pierre-Marie Baty -- unused variable
  2157.     //tPipe_chunk* temp_ptr; // Pierre-Marie Baty -- unused variable
  2158.     LOG_TRACE("(%p, %d, %d)", pChunk_ptr, pChunk_count, pTime);
  2159.  
  2160.     STUB_ONCE();
  2161.     return 1;
  2162. }
  2163.  
  2164. // IDA: int __usercall SoundTimeout@<EAX>(tU32 pTime@<EAX>)
  2165. int SoundTimeout(tU32 pTime) {
  2166.     LOG_TRACE("(%d)", pTime);
  2167.     NOT_IMPLEMENTED();
  2168. }
  2169.  
  2170. // IDA: void __usercall ScanAndPlaySoundsToBe(tU8 *pPtr@<EAX>, tU32 pOldest_time@<EDX>, tU32 pYoungest_time@<EBX>)
  2171. void ScanAndPlaySoundsToBe(tU8* pPtr, tU32 pOldest_time, tU32 pYoungest_time) {
  2172.     //tU8* temp_ptr; // Pierre-Marie Baty -- unused variable
  2173.     LOG_TRACE("(%p, %d, %d)", pPtr, pOldest_time, pYoungest_time);
  2174.     NOT_IMPLEMENTED();
  2175. }
  2176.  
  2177. // IDA: int __usercall CheckCar@<EAX>(tPipe_chunk *pChunk_ptr@<EAX>, int pChunk_count@<EDX>, tU32 pTime@<EBX>)
  2178. int CheckCar(tPipe_chunk* pChunk_ptr, int pChunk_count, tU32 pTime) {
  2179.     int i;
  2180.     tCar_spec* car;
  2181.     br_vector3 com_offset_c;
  2182.     br_vector3 com_offset_w;
  2183.     br_vector3 difference;
  2184.     tPipe_chunk* temp_ptr;
  2185.     LOG_TRACE("(%p, %d, %d)", pChunk_ptr, pChunk_count, pTime);
  2186.  
  2187.     temp_ptr = pChunk_ptr;
  2188.     if (PipeSearchForwards()) {
  2189.         if (pTime <= gOldest_time) {
  2190.             return 0;
  2191.         }
  2192.     } else {
  2193.         if (pTime >= gOldest_time) {
  2194.             return 0;
  2195.         }
  2196.     }
  2197.     for (i = 0; i < pChunk_count; i++) {
  2198.         if ((temp_ptr->subject_index & 0xff00) == 0) {
  2199.             car = &gProgram_state.current_car;
  2200.         } else {
  2201.             car = GetCarSpec(temp_ptr->subject_index >> 8, temp_ptr->subject_index & 0xff);
  2202.         }
  2203.         if (car == gCar_ptr) {
  2204.             BrVector3Copy(&gCar_pos, (br_vector3*)temp_ptr->chunk_data.car_data.transformation.m[3]);
  2205.             BrVector3InvScale(&com_offset_c, &car->cmpos, WORLD_SCALE);
  2206.             BrMatrix34ApplyV(&com_offset_w, &com_offset_c, &temp_ptr->chunk_data.car_data.transformation);
  2207.             BrVector3Accumulate(&gCar_pos, &com_offset_w);
  2208.             BrVector3Sub(&difference, &gCar_pos, &gReference_pos);
  2209.             if (BrVector3LengthSquared(&difference) <= gMax_distance) {
  2210.                 gTrigger_time = pTime;
  2211.                 return 0;
  2212.             } else {
  2213.                 gTrigger_time = pTime;
  2214.                 return 1;
  2215.             }
  2216.         }
  2217.         AdvanceChunkPtr(&temp_ptr, ePipe_chunk_car);
  2218.     }
  2219.     return 0;
  2220. }
  2221.  
  2222. // IDA: int __usercall CarTimeout@<EAX>(tU32 pTime@<EAX>)
  2223. int CarTimeout(tU32 pTime) {
  2224.     LOG_TRACE("(%d)", pTime);
  2225.  
  2226.     if (PipeSearchForwards()) {
  2227.         if (pTime > gYoungest_time) {
  2228.             return 0;
  2229.         }
  2230.     } else {
  2231.         if (pTime < gYoungest_time) {
  2232.             return 0;
  2233.         }
  2234.     }
  2235.     return 1;
  2236. }
  2237.  
  2238. // IDA: void __usercall ScanCarsPositions(tCar_spec *pCar@<EAX>, br_vector3 *pSource_pos@<EDX>, br_scalar pMax_distance_sqr, tU32 pOffset_time, tU32 pTime_period, br_vector3 *pCar_pos, tU32 *pTime_returned)
  2239. void ScanCarsPositions(tCar_spec* pCar, br_vector3* pSource_pos, br_scalar pMax_distance_sqr, tU32 pOffset_time, tU32 pTime_period, br_vector3* pCar_pos, tU32* pTime_returned) {
  2240.     tU8* temp_ptr;
  2241.     LOG_TRACE("(%p, %p, %f, %d, %d, %p, %p)", pCar, pSource_pos, pMax_distance_sqr, pOffset_time, pTime_period, pCar_pos, pTime_returned);
  2242.  
  2243.     temp_ptr = gPipe_play_ptr;
  2244.     gTrigger_time = 0;
  2245.     gMax_distance = pMax_distance_sqr;
  2246.     BrVector3Copy(&gReference_pos, pSource_pos);
  2247.     gCar_ptr = pCar;
  2248.  
  2249.     if (PipeSearchForwards()) {
  2250.         gOldest_time = GetTotalTime() + pOffset_time;
  2251.         gYoungest_time = gOldest_time + pTime_period;
  2252.     } else {
  2253.         gOldest_time = GetTotalTime() - pOffset_time;
  2254.         gYoungest_time = gOldest_time - pTime_period;
  2255.     }
  2256.  
  2257.     ScanBuffer(&temp_ptr, ePipe_chunk_car, GetTotalTime(), CheckCar, CarTimeout);
  2258.     BrVector3Copy(pCar_pos, &gCar_pos);
  2259.     if (pCar_pos->v[0] > 500.f) {
  2260.         Vector3AddFloats(pCar_pos, pCar_pos, -1000.f, -1000.f, -1000.f);
  2261.     }
  2262.     *pTime_returned = gTrigger_time;
  2263. }
  2264.  
  2265. // IDA: int __usercall CheckIncident@<EAX>(tPipe_chunk *pChunk_ptr@<EAX>, int pChunk_count@<EDX>, tU32 pTime@<EBX>)
  2266. int CheckIncident(tPipe_chunk* pChunk_ptr, int pChunk_count, tU32 pTime) {
  2267.     LOG_TRACE("(%p, %d, %d)", pChunk_ptr, pChunk_count, pTime);
  2268.  
  2269.     if (PipeSearchForwards()) {
  2270.         if (pTime <= gOldest_time) {
  2271.             return 0;
  2272.         }
  2273.     } else {
  2274.         if (gOldest_time <= pTime) {
  2275.             return 0;
  2276.         }
  2277.     }
  2278.     gIncidentChunk = pChunk_ptr;
  2279.     gTrigger_time = pTime;
  2280.     return 1;
  2281. }
  2282.  
  2283. // IDA: int __usercall GetNextIncident@<EAX>(tU32 pOffset_time@<EAX>, tIncident_type *pIncident_type@<EDX>, float *pSeverity@<EBX>, tIncident_info *pInfo@<ECX>, tU32 *pTime_away)
  2284. int GetNextIncident(tU32 pOffset_time, tIncident_type* pIncident_type, float* pSeverity, tIncident_info* pInfo, tU32* pTime_away) {
  2285.     tU8* temp_ptr;
  2286.     LOG_TRACE("(%d, %p, %p, %p, %p)", pOffset_time, pIncident_type, pSeverity, pInfo, pTime_away);
  2287.  
  2288.     temp_ptr = gPipe_play_ptr;
  2289.     gTrigger_time = 0;
  2290.     if (PipeSearchForwards()) {
  2291.         gOldest_time = GetTotalTime() + pOffset_time;
  2292.     } else {
  2293.         gOldest_time = GetTotalTime() - pOffset_time;
  2294.     }
  2295.     ScanBuffer(&temp_ptr, ePipe_chunk_incident, GetTotalTime(), CheckIncident, NULL);
  2296.     if (gTrigger_time != 0) {
  2297.         *pTime_away = gTrigger_time - GetTotalTime();
  2298.         *pIncident_type = gIncidentChunk->subject_index;
  2299.         *pSeverity = gIncidentChunk->chunk_data.incident_data.severity;
  2300.         if (*pIncident_type == eIncident_ped) {
  2301.             pInfo->ped_info.ped_actor = GetPedestrianActor(gIncidentChunk->chunk_data.incident_data.info.ped_info.ped_index);
  2302.             pInfo->ped_info.murderer_actor = gIncidentChunk->chunk_data.incident_data.info.ped_info.actor;
  2303.         } else if (*pIncident_type == eIncident_car) {
  2304.             if ((gIncidentChunk->chunk_data.incident_data.info.car_info.car_ID & 0xff00) == 0) {
  2305.                 pInfo->car_info.car = &gProgram_state.current_car;
  2306.             } else {
  2307.                 pInfo->car_info.car = GetCarSpec(gIncidentChunk->chunk_data.incident_data.info.car_info.car_ID >> 8,
  2308.                     gIncidentChunk->chunk_data.incident_data.info.car_info.car_ID & 0xff);
  2309.             }
  2310.             BrVector3Copy(&pInfo->car_info.impact_point, &gIncidentChunk->chunk_data.incident_data.info.car_info.impact_point);
  2311.         } else if (*pIncident_type == eIncident_wall) {
  2312.             BrVector3Copy(&pInfo->wall_info.pos, &gIncidentChunk->chunk_data.incident_data.info.wall_info.pos);
  2313.         }
  2314.     }
  2315.     return gTrigger_time;
  2316. }
  2317.  
  2318. // IDA: tU32 __cdecl GetARStartTime()
  2319. tU32 GetARStartTime(void) {
  2320.     tU8* temp_ptr;
  2321.     LOG_TRACE("()");
  2322.  
  2323.     temp_ptr = gPipe_buffer_oldest;
  2324.     do {
  2325.         if (MoveSessionPointerForwardOne(&temp_ptr)) {
  2326.             return 0;
  2327.         }
  2328.     } while (((tPipe_session*)temp_ptr)->chunk_type != ePipe_chunk_frame_boundary);
  2329.     return ((tPipe_session*)temp_ptr)->chunks.chunk_data.frame_boundary_data.time;
  2330. }
  2331.