Subversion Repositories Games.Carmageddon

Rev

Rev 18 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. #include "oppoproc.h"
  2. #include "errors.h"
  3. #include "globvars.h"
  4. #include "harness/trace.h"
  5. #include "opponent.h"
  6. #include "pd/sys.h"
  7. #include <brender/brender.h>
  8. #include <math.h>
  9. #include <stdlib.h>
  10.  
  11. // IDA: int __usercall StraightestArcForCorner2D@<EAX>(br_vector2 *pCent@<EAX>, br_scalar *pRadius@<EDX>, br_scalar *pEntry_length@<EBX>, int *pLeft_not_right@<ECX>, br_vector2 *p1, br_vector2 *p2, br_vector2 *p3, br_scalar pWidth12, br_scalar pWidth23)
  12. int StraightestArcForCorner2D(br_vector2* pCent, br_scalar* pRadius, br_scalar* pEntry_length, int* pLeft_not_right, br_vector2* p1, br_vector2* p2, br_vector2* p3, br_scalar pWidth12, br_scalar pWidth23) {
  13.     //br_vector2 rel1; // Pierre-Marie Baty -- unused variable
  14.     //br_vector2 rel3; // Pierre-Marie Baty -- unused variable
  15.     //br_vector2 rot1; // Pierre-Marie Baty -- unused variable
  16.     //br_vector2 rot1u; // Pierre-Marie Baty -- unused variable
  17.     //br_scalar len12_squared; // Pierre-Marie Baty -- unused variable
  18.     //br_scalar len23_squared; // Pierre-Marie Baty -- unused variable
  19.     //br_scalar c; // Pierre-Marie Baty -- unused variable
  20.     //br_scalar numerator; // Pierre-Marie Baty -- unused variable
  21.     //br_scalar x; // Pierre-Marie Baty -- unused variable
  22.     //br_scalar __block0___scale; // Pierre-Marie Baty -- unused variable
  23.     LOG_TRACE("(%p, %p, %p, %p, %p, %p, %p, %f, %f)", pCent, pRadius, pEntry_length, pLeft_not_right, p1, p2, p3, pWidth12, pWidth23);
  24.     NOT_IMPLEMENTED();
  25. }
  26.  
  27. // There appears to be two different implementations of this function in different binaries.
  28. // One does calculations in 2d space, this one calculates in 3d space.
  29. static void StraightestArcForCorner(float* p1, float* p2, float* p3, br_vector3* p4, br_vector3* p5, br_vector3* p6, br_vector3* p7, br_vector3* p8, float p9, float p10) {
  30.     br_vector3 rel1;
  31.     br_vector3 rel3;
  32.     br_vector3 rot1;
  33.     br_scalar tmp;
  34.     br_scalar tmp2;
  35.     br_scalar tmp3;
  36.     br_scalar tmp4;
  37.     LOG_TRACE("(%p, %p, %p, %p, %p, %p, %p, %p, %f, %f)", p1, p2, p3, p4, p5, p6, p7, p8, p9, p10);
  38.  
  39.     BrVector3Sub(&rel1, p6, p5);
  40.     rel1.v[1] = 0.f;
  41.     BrVector3Sub(&rel3, p4, p5);
  42.     rel3.v[1] = 0.f;
  43.     *p3 = BrVector3Length(&rel3);
  44.     if (*p3 <= BR_SCALAR_EPSILON) {
  45.         *p2 = 0.001f;
  46.         *p3 = 0.001f;
  47.     }
  48.     tmp = BrVector3Dot(&rel1, &rel3);
  49.     BrVector3Cross(&rot1, &rel1, &rel3);
  50.     tmp2 = sqrtf(tmp * tmp + rot1.v[1] * rot1.v[1]);
  51.     tmp3 = fabsf(rot1.v[1] / tmp2);
  52.     tmp4 = p10 * tmp / tmp2 + p9;
  53.     if ((tmp3 < 1.f && fabsf(tmp4) > tmp3 * 1000.f) || tmp3 < 0.001f) {
  54.         *p1 = 1000.f;
  55.         *p2 = 1000.f;
  56.     } else {
  57.         tmp4 = tmp4 / tmp3;
  58.         tmp3 = tmp3 / (tmp / tmp2 + 1.f);
  59.         *p2 = tmp3 * p10 + sqrtf(tmp3 * p10) + tmp4;
  60.         *p1 = *p2 * tmp3;
  61.     }
  62. }
  63.  
  64. // IDA: br_scalar __usercall CornerFudge@<ST0>(tCar_spec *pCar_spec@<EAX>)
  65. br_scalar CornerFudge(tCar_spec* pCar_spec) {
  66.     LOG_TRACE("(%p)", pCar_spec);
  67.  
  68.     return 1.4f;
  69. }
  70.  
  71. // IDA: br_scalar __usercall MaxCurvatureForCarSpeed@<ST0>(tCar_spec *pCar@<EAX>, br_scalar pSpeed)
  72. br_scalar MaxCurvatureForCarSpeed(tCar_spec* pCar, br_scalar pSpeed) {
  73.     br_scalar curv;
  74.     LOG_TRACE("(%p, %f)", pCar, pSpeed);
  75.  
  76.     if (pSpeed >= 12.5f) {
  77.         curv = pCar->maxcurve * 12.5f / pSpeed;
  78.     } else {
  79.         curv = pCar->maxcurve;
  80.     }
  81.     return curv;
  82. }
  83.  
  84. // IDA: br_scalar __usercall Vector2Cross@<ST0>(br_vector2 *pA@<EAX>, br_vector2 *pB@<EDX>)
  85. br_scalar Vector2Cross(br_vector2* pA, br_vector2* pB) {
  86.     LOG_TRACE("(%p, %p)", pA, pB);
  87.     NOT_IMPLEMENTED();
  88. }
  89.  
  90. // IDA: tFollow_path_result __usercall EndOfPath@<EAX>(tOpponent_spec *pOpponent_spec@<EAX>)
  91. tFollow_path_result EndOfPath(tOpponent_spec* pOpponent_spec) {
  92.     //tCar_spec* car_spec; // Pierre-Marie Baty -- unused variable
  93.     LOG_TRACE("(%p)", pOpponent_spec);
  94.     NOT_IMPLEMENTED();
  95. }
  96.  
  97. // IDA: int __usercall RoughlyColinear@<EAX>(br_vector2 *p1@<EAX>, br_vector2 *p2@<EDX>, br_vector2 *p3@<EBX>)
  98. int RoughlyColinear(br_vector2* p1, br_vector2* p2, br_vector2* p3) {
  99.     //br_vector2 rel1; // Pierre-Marie Baty -- unused variable
  100.     //br_vector2 rel2; // Pierre-Marie Baty -- unused variable
  101.     //br_vector2 sum; // Pierre-Marie Baty -- unused variable
  102.     //br_scalar cross; // Pierre-Marie Baty -- unused variable
  103.     //br_scalar dot; // Pierre-Marie Baty -- unused variable
  104.     //br_scalar wibble; // Pierre-Marie Baty -- unused variable
  105.     LOG_TRACE("(%p, %p, %p)", p1, p2, p3);
  106.     NOT_IMPLEMENTED();
  107. }
  108.  
  109. // IDA: int __usercall GetStraight@<EAX>(br_vector2 *pStart@<EAX>, br_vector2 *pFinish@<EDX>, br_scalar *pWidth@<EBX>, int section1@<ECX>, tOpponent_spec *pOpponent_spec, tFollow_path_data *data)
  110. int GetStraight(br_vector2* pStart, br_vector2* pFinish, br_scalar* pWidth, int section1, tOpponent_spec* pOpponent_spec, tFollow_path_data* data) {
  111.     //int section; // Pierre-Marie Baty -- unused variable
  112.     //br_vector2 next; // Pierre-Marie Baty -- unused variable
  113.     //br_scalar next_width; // Pierre-Marie Baty -- unused variable
  114.     LOG_TRACE("(%p, %p, %p, %d, %p, %p)", pStart, pFinish, pWidth, section1, pOpponent_spec, data);
  115.     NOT_IMPLEMENTED();
  116. }
  117.  
  118. // IDA: tFollow_path_result __usercall ProcessFollowPath@<EAX>(tOpponent_spec *pOpponent_spec@<EAX>, tProcess_objective_command pCommand@<EDX>, int pPursuit_mode@<EBX>, int pIgnore_end@<ECX>, int pNever_struggle)
  119. tFollow_path_result ProcessFollowPath(tOpponent_spec* pOpponent_spec, tProcess_objective_command pCommand, int pPursuit_mode, int pIgnore_end, int pNever_struggle) {
  120.     tS16 real_section_no;
  121.     tFollow_path_data* data;
  122.     br_vector3 wank;
  123.     br_vector3 wank2;
  124.     br_vector3* not_our_dir;
  125.     br_vector3 section_dir;
  126.     br_vector3 section_v;
  127.     br_vector3 start;
  128.     //br_vector3 corner; // Pierre-Marie Baty -- unused variable
  129.     br_vector3 next;
  130.     br_vector3 goal_dir;
  131.     //br_vector3 intersect; // Pierre-Marie Baty -- unused variable
  132.     br_vector3 a;
  133.     br_vector3 p;
  134.     br_vector3 car_to_end;
  135.     br_actor* car_master_actor;
  136.     br_scalar stopped_speed;
  137.     br_scalar dist_to_end;
  138.     br_scalar t;
  139.     br_scalar acc;
  140.     br_scalar speed;
  141.     br_scalar dist_to_goal;
  142.     br_scalar section_width;
  143.     br_scalar goal_width;
  144.     br_scalar desired_speed;
  145.     br_scalar dist_along;
  146.     br_scalar acc_factor;
  147.     br_scalar max_acc;
  148.     //br_scalar speed_to_goal; // Pierre-Marie Baty -- unused variable
  149.     br_scalar error;
  150.     br_scalar radius;
  151.     //br_scalar entry_len; // Pierre-Marie Baty -- unused variable
  152.     br_scalar corner_speed2;
  153.     //br_scalar distance; // Pierre-Marie Baty -- unused variable
  154.     br_scalar stopping_distance;
  155.     br_scalar corner_speed;
  156.     br_scalar dot_a;
  157.     br_scalar dot_d;
  158.     //br_scalar further_along; // Pierre-Marie Baty -- unused variable
  159.     tCar_spec* car_spec;
  160.     int engine_damage;
  161.     int trans_damage;
  162.     int section_no;
  163.     int sx;
  164.     int just_fucking_brake;
  165.     //br_vector2 oppo_pos2d; // Pierre-Marie Baty -- unused variable
  166.     //br_vector2 start2d; // Pierre-Marie Baty -- unused variable
  167.     //br_vector2 finish2d; // Pierre-Marie Baty -- unused variable
  168.     //br_vector2 next2d; // Pierre-Marie Baty -- unused variable
  169.     //br_vector2 oppo_pos_rel; // Pierre-Marie Baty -- unused variable
  170.     //br_vector2 oppo_pos_rel_next; // Pierre-Marie Baty -- unused variable
  171.     //br_vector2 section_rel; // Pierre-Marie Baty -- unused variable
  172.     //br_vector2 section_rel_next; // Pierre-Marie Baty -- unused variable
  173.     //br_vector2 v2d; // Pierre-Marie Baty -- unused variable
  174.     //br_vector2 corner2d; // Pierre-Marie Baty -- unused variable
  175.     //br_vector2 after_corner2d; // Pierre-Marie Baty -- unused variable
  176.     //br_vector2 next_turning_cent; // Pierre-Marie Baty -- unused variable
  177.     //br_vector2 temp2d; // Pierre-Marie Baty -- unused variable
  178.     //br_scalar section_len; // Pierre-Marie Baty -- unused variable
  179.     //br_scalar section_len_next; // Pierre-Marie Baty -- unused variable
  180.     //br_scalar pos_error; // Pierre-Marie Baty -- unused variable
  181.     //br_scalar pos_error_next; // Pierre-Marie Baty -- unused variable
  182.     //br_scalar pos_error_factor; // Pierre-Marie Baty -- unused variable
  183.     //br_scalar sin_error; // Pierre-Marie Baty -- unused variable
  184.     //br_scalar corner_radius; // Pierre-Marie Baty -- unused variable
  185.     //br_scalar corner_entry_length; // Pierre-Marie Baty -- unused variable
  186.     //br_scalar corner_distance; // Pierre-Marie Baty -- unused variable
  187.     br_scalar speed2d;
  188.     //br_scalar stemp1; // Pierre-Marie Baty -- unused variable
  189.     br_scalar width;
  190.     br_scalar next_width;
  191.     br_scalar next_turning_radius;
  192.     br_scalar next_corner_size;
  193.     //br_scalar later_width; // Pierre-Marie Baty -- unused variable
  194.     br_scalar effective_speed_factor;
  195.     //int first_straight; // Pierre-Marie Baty -- unused variable
  196.     //int next_straight; // Pierre-Marie Baty -- unused variable
  197.     //int left_not_right; // Pierre-Marie Baty -- unused variable
  198.     //int later_straight; // Pierre-Marie Baty -- unused variable
  199.     //int next_left_not_right; // Pierre-Marie Baty -- unused variable
  200.     LOG_TRACE("(%p, %d, %d, %d, %d)", pOpponent_spec, pCommand, pPursuit_mode, pIgnore_end, pNever_struggle);
  201.  
  202.     car_spec = pOpponent_spec->car_spec;
  203.     engine_damage = car_spec->damage_units[0].damage_level;
  204.     trans_damage = car_spec->damage_units[1].damage_level;
  205.     data = &pOpponent_spec->follow_path_data;
  206.     car_master_actor = car_spec->car_master_actor;
  207.  
  208.     if (pCommand == ePOC_start) {
  209.         data->first_section_no = GetOpponentsFirstSection(pOpponent_spec);
  210.         data->section_no = data->first_section_no;
  211.         dr_dprintf("%s: ProcessFollowPath() - new task started, first real section #%d", pOpponent_spec->car_spec->driver_name, GetOpponentsRealSection(pOpponent_spec, data->first_section_no));
  212.         data->has_moved_during_this_task = 0;
  213.         data->struggle_time = 0;
  214.         data->last_finished_struggle_time = gTime_stamp_for_this_munging;
  215.         data->prev_acc = 0.f;
  216.         data->prev_acc_error = 0.f;
  217.         data->borrowed_time_start = gTime_stamp_for_this_munging;
  218.         data->last_struggle_section = -1;
  219.         data->made_it = 1;
  220.         data->cheating = 0;
  221.         data->cornering = 0;
  222.         if (!pOpponent_spec->cheating && !pOpponent_spec->physics_me) {
  223.             dr_dprintf("%s: Rematerialising from ePOC_start in ProcessFollowPath()...", pOpponent_spec->car_spec->driver_name);
  224.             RematerialiseOpponentOnNearestSection(pOpponent_spec, BrVector3Length(&car_spec->v));
  225.         }
  226.         return eFPR_OK;
  227.     } else if (pCommand == ePOC_run) {
  228.         if (pOpponent_spec->follow_path_data.cheating || pOpponent_spec->cheating) {
  229.             return FollowCheatyPath(pOpponent_spec);
  230.         }
  231.         if (!pIgnore_end && !data->made_it && data->borrowed_time_start + 1000 < gTime_stamp_for_this_munging && gTime_stamp_for_this_munging < data->borrowed_time_start + 10000) {
  232.             BrVector3Sub(&section_dir, GetOpponentsSectionFinishNodePoint(pOpponent_spec, data->section_no), GetOpponentsSectionStartNodePoint(pOpponent_spec, data->section_no));
  233.             BrVector3Sub(&goal_dir, &car_master_actor->t.t.translate.t, GetOpponentsSectionStartNodePoint(pOpponent_spec, data->section_no));
  234.             dist_along = BrVector3LengthSquared(&goal_dir) / BrVector3LengthSquared(&section_dir);
  235.             BrVector3Scale(&section_v, &section_dir, dist_along);
  236.             BrVector3Sub(&wank, &goal_dir, &section_v);
  237.             goal_width = BrVector3Length(&wank);
  238.             if (GetOpponentsSectionWidth(pOpponent_spec, data->section_no) >= goal_width) {
  239.                 data->made_it = 1;
  240.             }
  241.         }
  242.         if (data->borrowed_time_start + 10000 < gTime_stamp_for_this_munging && !data->made_it) {
  243.             dr_dprintf("%s: ProcessFollowPath() giving up due to not making the corner", pOpponent_spec->car_spec->driver_name);
  244.             return eFPR_given_up;
  245.         }
  246.         car_spec->keys.acc = 1;
  247.         speed = BrVector3Length(&car_spec->v);
  248.         if (speed > 0.2f) {
  249.             data->has_moved_during_this_task = 1;
  250.             pOpponent_spec->has_moved_at_some_point = 1;
  251.         }
  252.         if (data->struggle_time) {
  253.             if (data->struggle_time + 150 * (5 * data->number_of_struggles - 5) + 2750 >= gTime_stamp_for_this_munging) {
  254.                 if (data->struggle_time + 150 * (5 * data->number_of_struggles - 5) + 2000 >= gTime_stamp_for_this_munging) {
  255.                     car_spec->brake_force = 0.0f;
  256.                     car_spec->acc_force = car_spec->M * -6.0f;
  257.                 } else {
  258.                     car_spec->acc_force = 0.0f;
  259.                     car_spec->brake_force = car_spec->M * 15.0f;
  260.                 }
  261.                 car_spec->curvature = 0.0f;
  262.                 return eFPR_OK;
  263.             }
  264.             dr_dprintf("%s: done struggling. speed = %.2f m/s", pOpponent_spec->car_spec->driver_name, speed);
  265.             data->made_it = 0;
  266.             data->borrowed_time_start = gTime_stamp_for_this_munging;
  267.             data->struggle_time = 0;
  268.             data->last_finished_struggle_time = gTime_stamp_for_this_munging;
  269.             car_spec->brake_force = 0.0f;
  270.             car_spec->acc_force = 0.0f;
  271.         } else {
  272.             if (pIgnore_end) {
  273.                 stopped_speed = 0.06666667f;
  274.             } else {
  275.                 stopped_speed = 0.2f;
  276.             }
  277.             if (!pNever_struggle && stopped_speed >= speed && data->last_finished_struggle_time + 2000 < gTime_stamp_for_this_munging && (pPursuit_mode || data->has_moved_during_this_task != 0)) {
  278.                 dr_dprintf("%s: 'Stopped,' section #%d, speed = %.2f m/s, about to start a-strugglin'", pOpponent_spec->car_spec->driver_name, data->section_no, speed);
  279.                 data->struggle_time = gTime_stamp_for_this_munging;
  280.                 if (pIgnore_end || data->section_no != data->last_struggle_section) {
  281.                     data->last_struggle_section = data->section_no;
  282.                     data->number_of_struggles = 0;
  283.                 } else {
  284.                     if (data->number_of_struggles >= 3) {
  285.                         car_spec->acc_force = 0.0f;
  286.                         car_spec->brake_force = 0.0f;
  287.                         dr_dprintf("%s: Giving up trying to follow path 'cos we've struggled too much", pOpponent_spec->car_spec->driver_name);
  288.                         return eFPR_given_up;
  289.                     }
  290.                     data->number_of_struggles++;
  291.                 }
  292.             }
  293.         }
  294.         BrVector3Sub(&car_to_end, GetOpponentsSectionFinishNodePoint(pOpponent_spec, data->section_no), &pOpponent_spec->car_spec->car_master_actor->t.t.translate.t);
  295.         car_to_end.v[1] = 0.0f;
  296.         dist_to_end = BrVector3Length(&car_to_end) * WORLD_SCALE;
  297.         dist_to_goal = dist_to_end;
  298.         if (dist_to_end > 15.0f) {
  299.             BrVector3Sub(&wank, GetOpponentsSectionFinishNodePoint(pOpponent_spec, data->section_no), GetOpponentsSectionStartNodePoint(pOpponent_spec, data->section_no));
  300.             BrVector3Normalise(&a, &wank);
  301.             BrVector3Sub(&wank, &pOpponent_spec->car_spec->car_master_actor->t.t.translate.t, GetOpponentsSectionStartNodePoint(pOpponent_spec, data->section_no));
  302.  
  303.             dot_a = BrVector3Dot(&a, &wank); // v62.v[2] * wank.v[2] + v62.v[1] * wank.v[1] + v62.v[0] * wank.v[0];
  304.             wank2.v[0] = a.v[0] * dot_a;
  305.             wank2.v[2] = a.v[2] * dot_a;
  306.             car_to_end.v[0] = wank2.v[0] - wank.v[0];
  307.             car_to_end.v[2] = wank2.v[2] - wank.v[2];
  308.             car_to_end.v[1] = 0.0f;
  309.             dist_to_end = BrVector3Length(&car_to_end) * WORLD_SCALE;
  310.             if (dist_to_end < 15.0f) {
  311.                 t = sqrtf(225.0f - dist_to_end * dist_to_end) / WORLD_SCALE;
  312.                 if (t + dot_a >= 0.0) {
  313.                     wank.v[0] = a.v[0] * t;
  314.                     wank.v[2] = a.v[2] * t;
  315.                     wank.v[1] = 0.0f;
  316.                     BrVector3Accumulate(&car_to_end, &wank);
  317.                 } else {
  318.                     BrVector3Sub(&car_to_end, GetOpponentsSectionStartNodePoint(pOpponent_spec, data->section_no), &pOpponent_spec->car_spec->car_master_actor->t.t.translate.t);
  319.                     dist_to_end = BrVector3Length(&car_to_end) * WORLD_SCALE;
  320.                     BrVector3Scale(&car_to_end, &car_to_end, 15.0f / dist_to_end);
  321.                 }
  322.                 dist_to_end = 15.0f;
  323.             } else if (dot_a < 0.0f) {
  324.                 BrVector3Sub(&car_to_end, GetOpponentsSectionStartNodePoint(pOpponent_spec, data->section_no), &pOpponent_spec->car_spec->car_master_actor->t.t.translate.t);
  325.                 dist_to_end = BrVector3Length(&car_to_end) * WORLD_SCALE;
  326.                 BrVector3Scale(&car_to_end, &car_to_end, 15.0f / dist_to_end);
  327.             }
  328.         }
  329.         section_width = GetOpponentsSectionWidth(pOpponent_spec, data->section_no) * WORLD_SCALE;
  330.         if (!pIgnore_end && speed * 1.5f > dist_to_goal) {
  331.             dr_dprintf("%s: ProcessFollowPath() - *** CHANGING SECTIONS ***", pOpponent_spec->car_spec->driver_name);
  332.             dr_dprintf("%s: ProcessFollowPath() - current section %d(#%d)", pOpponent_spec->car_spec->driver_name, data->section_no, GetOpponentsRealSection(pOpponent_spec, data->section_no));
  333.             data->section_no = GetOpponentsNextSection(pOpponent_spec, data->section_no);
  334.             if (data->section_no == -1) {
  335.                 car_spec->acc_force = 0.0f;
  336.                 car_spec->brake_force = 0.0f;
  337.                 dr_dprintf("%s: ProcessFollowPath() - reached end of path", pOpponent_spec->car_spec->driver_name);
  338.                 return eFPR_end_of_path;
  339.             }
  340.             car_to_end.v[1] = 0.0f;
  341.             real_section_no = GetOpponentsRealSection(pOpponent_spec, data->section_no);
  342.             dr_dprintf("%s: ProcessFollowPath() - next section %d(#%d)", pOpponent_spec->car_spec->driver_name, data->section_no, GetOpponentsRealSection(pOpponent_spec, data->section_no));
  343.             data->last_struggle_section = -1;
  344.             data->borrowed_time_start = gTime_stamp_for_this_munging;
  345.             data->made_it = 1;
  346.             data->last_distance = 0.0f;
  347.         }
  348.         not_our_dir = (br_vector3*)&car_master_actor->t.t.mat.m[2];
  349.  
  350.         BrVector3Cross(&wank, &car_to_end, not_our_dir);
  351.  
  352.         radius = GetOpponentsSectionWidth(pOpponent_spec, data->section_no) * 0.5f;
  353.         just_fucking_brake = 0;
  354.         dot_d = BrVector3Dot(&car_to_end, not_our_dir);
  355.         if (dot_d > 0.0f && speed > 10.0f) {
  356.             data->desired_speed = 6.0f;
  357.             car_spec->curvature = 0.0f;
  358.             just_fucking_brake = 1;
  359.         } else {
  360.             if ((wank.v[1] > 0.0f && dot_d > 0.0f) || GetOpponentsSectionWidth(pOpponent_spec, data->section_no) < wank.v[1]) {
  361.                 car_spec->curvature = MaxCurvatureForCarSpeed(car_spec, speed);
  362.                 data->desired_speed = 6.0f;
  363.             } else if ((wank.v[1] < 0.0f && dot_d > 0.0) || -GetOpponentsSectionWidth(pOpponent_spec, data->section_no) > wank.v[1]) {
  364.                 car_spec->curvature = -MaxCurvatureForCarSpeed(car_spec, speed);
  365.                 data->desired_speed = 6.0f;
  366.             } else if (wank.v[1] > radius) {
  367.                 car_spec->curvature = MaxCurvatureForCarSpeed(car_spec, speed) * 0.05f;
  368.                 data->desired_speed = 80.0f;
  369.             } else if (-radius > wank.v[1]) {
  370.                 car_spec->curvature = -(MaxCurvatureForCarSpeed(car_spec, speed) * 0.05f);
  371.                 data->desired_speed = 80.0f;
  372.             } else {
  373.                 car_spec->curvature = 0.0f;
  374.                 data->desired_speed = 80.0f;
  375.             }
  376.         }
  377.         if (just_fucking_brake) {
  378.             car_spec->brake_force = car_spec->M * 15.0f;
  379.             car_spec->acc_force = 0.0f;
  380.         } else {
  381.             if (GetOpponentsNextSection(pOpponent_spec, data->section_no) != -1) {
  382.                 next_turning_radius = pOpponent_spec->car_spec->car_master_actor->t.t.translate.t.v[0] * -wank.v[2] + pOpponent_spec->car_spec->car_master_actor->t.t.translate.t.v[2] * wank.v[0];
  383.                 next_corner_size = GetOpponentsSectionFinishNodePoint(pOpponent_spec, data->section_no)->v[0] * -wank.v[2];
  384.                 next_turning_radius = next_turning_radius - (GetOpponentsSectionFinishNodePoint(pOpponent_spec, data->section_no)->v[2] * wank.v[0] + next_corner_size);
  385.                 // FIXME: added temporary variable
  386.                 float v104 = -wank.v[2] * not_our_dir->v[0] + not_our_dir->v[2] * wank.v[0];
  387.                 if (v104 * next_turning_radius > 0.0f) {
  388.                     goal_width = 0.0f;
  389.                     speed2d = speed * speed / 24.0f + speed * 1.5f;
  390.                     BrVector3Copy(&p, &pOpponent_spec->car_spec->car_master_actor->t.t.translate.t);
  391.                     BrVector3Scale(&start, not_our_dir, -(next_turning_radius / v104));
  392.                     BrVector3Accumulate(&start, &pOpponent_spec->car_spec->car_master_actor->t.t.translate.t);
  393.                     section_no = data->section_no;
  394.                     for (sx = 0; GetOpponentsNextSection(pOpponent_spec, section_no) != -1 && sx < 4; sx++) {
  395.                         BrVector3Copy(&next, GetOpponentsSectionFinishNodePoint(pOpponent_spec, GetOpponentsNextSection(pOpponent_spec, section_no)));
  396.                         next_width = GetOpponentsSectionWidth(pOpponent_spec, GetOpponentsNextSection(pOpponent_spec, section_no));
  397.                         width = GetOpponentsSectionWidth(pOpponent_spec, data->section_no);
  398.                         StraightestArcForCorner(&corner_speed, &corner_speed2, &dot_a, &p, &start, &next, &p, &start, width, next_width);
  399.                         dot_a *= WORLD_SCALE;
  400.                         goal_width += dot_a;
  401.                         if (goal_width > speed2d) {
  402.                             break;
  403.                         }
  404.                         corner_speed *= WORLD_SCALE;
  405.                         corner_speed2 *= WORLD_SCALE;
  406.                         stopping_distance = CornerFudge(car_spec) * CornerFudge(car_spec) * (corner_speed * 10.0);
  407.                         desired_speed = sqrtf(stopping_distance);
  408.                         if (GetOpponentsSectionMaxSpeed(pOpponent_spec, data->section_no, 1) < desired_speed) {
  409.                             desired_speed = GetOpponentsSectionMaxSpeed(pOpponent_spec, data->section_no, 1);
  410.                             stopping_distance = desired_speed * desired_speed;
  411.                         }
  412.                         if (goal_width - corner_speed2 < (speed * speed - stopping_distance) / 24.0f + desired_speed * 1.5f && data->desired_speed > desired_speed) {
  413.                             data->desired_speed = desired_speed;
  414.                         }
  415.                         BrVector3Copy(&p, &start);
  416.                         BrVector3Copy(&start, &next);
  417.                         section_no = GetOpponentsNextSection(pOpponent_spec, section_no);
  418.                     }
  419.                 }
  420.             }
  421.             effective_speed_factor = CAR_SPEC_GET_SPEED_FACTOR(car_spec);
  422.             acc_factor = MAX(1.0f, effective_speed_factor);
  423.             if (engine_damage > 50 && engine_damage < 98) {
  424.                 acc_factor -= (engine_damage - 50) * 0.0125f;
  425.             } else if (engine_damage >= 98) {
  426.                 acc_factor -= 0.6f;
  427.             }
  428.             if (trans_damage > 50 && trans_damage < 98) {
  429.                 acc_factor -= (trans_damage - 50) * 0.00625f;
  430.             } else if (trans_damage >= 98) {
  431.                 acc_factor -= 0.3f;
  432.             }
  433.             if (engine_damage >= 99 || trans_damage >= 99) {
  434.                 acc_factor = 0.0f;
  435.             }
  436.             max_acc = acc_factor * 10.0f;
  437.             // TODO: ?? corner_speed2[10] = v30;
  438.             error = data->desired_speed * effective_speed_factor - speed;
  439.             acc = (error - data->prev_acc_error) * 1000.0f / gFrame_period_for_this_munging * 0.1f + error + data->prev_acc;
  440.             if (acc > max_acc) {
  441.                 acc = max_acc;
  442.             }
  443.             if (acc < -max_acc) {
  444.                 acc = -max_acc;
  445.             }
  446.             data->prev_acc = acc;
  447.             data->prev_acc_error = error;
  448.             acc = car_spec->M * acc;
  449.             if (acc <= 0.0f) {
  450.                 car_spec->acc_force = 0.0f;
  451.                 car_spec->brake_force = -acc;
  452.             } else {
  453.                 car_spec->acc_force = acc;
  454.                 car_spec->brake_force = 0.0f;
  455.             }
  456.         }
  457.         return eFPR_OK;
  458.     }
  459.  
  460.     BrFatal("C:\\Msdev\\Projects\\DethRace\\OPPOPROC.C", 1420, "C:\\Msdev\\Projects\\DethRace\\OPPOPROC.C line %d", 140);
  461.     return eFPR_OK;
  462. }
  463.  
  464. // IDA: tFollow_path_result __usercall FollowCheatyPath@<EAX>(tOpponent_spec *pOpponent_spec@<EAX>)
  465. tFollow_path_result FollowCheatyPath(tOpponent_spec* pOpponent_spec) {
  466.     tFollow_path_data* data;
  467.     br_vector3 a;
  468.     br_vector3 p;
  469.     br_vector3 section_v;
  470.     br_vector3 car_to_end;
  471.     br_vector3 car_to_intersect;
  472.     br_vector3* start;
  473.     br_vector3* finish;
  474.     br_scalar t;
  475.     br_scalar frame_period_in_secs;
  476.     //br_scalar distance_left; // Pierre-Marie Baty -- unused variable
  477.     br_scalar distance_to_end;
  478.     br_scalar distance_to_intersect;
  479.     br_scalar section_min;
  480.     br_scalar section_max;
  481.     br_scalar desired_speed_BRU;
  482.     LOG_TRACE("(%p)", pOpponent_spec);
  483.  
  484.     data = &pOpponent_spec->follow_path_data;
  485.     start = GetOpponentsSectionStartNodePoint(pOpponent_spec, pOpponent_spec->follow_path_data.section_no);
  486.     finish = GetOpponentsSectionFinishNodePoint(pOpponent_spec, pOpponent_spec->follow_path_data.section_no);
  487.     if ((pOpponent_spec->follow_path_data.cheating ^ pOpponent_spec->cheating) != 0) {
  488.         data->cheating = pOpponent_spec->cheating;
  489.         if (data->cheating) {
  490.             dr_dprintf("%s: Dematerialising", pOpponent_spec->car_spec->driver_name);
  491.             BrVector3Sub(&section_v, finish, start);
  492.             BrVector3Sub(&car_to_end, &pOpponent_spec->car_spec->car_master_actor->t.t.translate.t, start);
  493.             t = BrVector3Dot(&section_v, &car_to_end) / BrVector3LengthSquared(&section_v);
  494.             if (t < 0.0f) {
  495.                 BrVector3Copy(&data->cheaty_intersect, start);
  496.             } else if (t > 1.f) {
  497.                 BrVector3Copy(&data->cheaty_intersect, finish);
  498.             } else {
  499.                 BrVector3Scale(&data->cheaty_intersect, &section_v, t);
  500.                 BrVector3Accumulate(&data->cheaty_intersect, start);
  501.             }
  502.             BrVector3Sub(&car_to_intersect, &data->cheaty_intersect, &pOpponent_spec->car_spec->car_master_actor->t.t.translate.t);
  503.             distance_to_intersect = BrVector3Length(&car_to_intersect);
  504.             frame_period_in_secs = gFrame_period_for_this_munging / 1000.0f * 20.0f;
  505.             TurnOpponentPhysicsOff(pOpponent_spec);
  506.             if (distance_to_intersect >= frame_period_in_secs) {
  507.                 data->moving_to_intersect = 1;
  508.                 BrVector3Normalise(&car_to_intersect, &car_to_intersect);
  509.                 BrVector3Scale(&car_to_intersect, &car_to_intersect, frame_period_in_secs);
  510.                 BrVector3Accumulate(&pOpponent_spec->car_spec->car_master_actor->t.t.translate.t, &car_to_intersect);
  511.                 return eFPR_OK;
  512.             } else {
  513.                 data->moving_to_intersect = 0;
  514.                 BrVector3Copy(&pOpponent_spec->car_spec->car_master_actor->t.t.translate.t, &data->cheaty_intersect);
  515.                 return eFPR_OK;
  516.             }
  517.         }
  518.         BrVector3Sub(&p, finish, start);
  519.         PointActorAlongThisBloodyVector(pOpponent_spec->car_spec->car_master_actor, &p);
  520.         BrVector3Sub(&a, finish, &pOpponent_spec->car_spec->car_master_actor->t.t.translate.t);
  521.         distance_to_end = BrVector3Length(&a);
  522.         dr_dprintf("%s: Rematerialising from FollowCheatyPath()...", pOpponent_spec->car_spec->driver_name);
  523.         if (data->section_no < 0) {
  524.             PDEnterDebugger("No useful section number in ProcessCheatyPath()");
  525.         }
  526.  
  527.         section_max = GetOpponentsSectionMaxSpeed(pOpponent_spec, data->section_no, 1);
  528.         section_min = GetOpponentsSectionMinSpeed(pOpponent_spec, data->section_no, 1);
  529.  
  530.         if (section_max < 255) {
  531.             desired_speed_BRU = section_max / WORLD_SCALE;
  532.         } else if (section_min > 0) {
  533.             desired_speed_BRU = section_min / WORLD_SCALE;
  534.         } else {
  535.             desired_speed_BRU = MIN(7.0f, MAX(1.0f, distance_to_end * 2.0f));
  536.         }
  537.         if (RematerialiseOpponentOnNearestSection(pOpponent_spec, desired_speed_BRU)) {
  538.             pOpponent_spec->car_spec->brake_force = 0.0f;
  539.             pOpponent_spec->car_spec->acc_force = 0.0f;
  540.             if (distance_to_end >= 5.0f) {
  541.                 pOpponent_spec->car_spec->acc_force = pOpponent_spec->car_spec->M / 2.0f;
  542.             } else {
  543.                 pOpponent_spec->car_spec->brake_force = pOpponent_spec->car_spec->M * 15.0f;
  544.             }
  545.             return eFPR_OK;
  546.         }
  547.         data->cheating = 1;
  548.     }
  549.     frame_period_in_secs = gFrame_period_for_this_munging / 1000.0f * 20.0f;
  550.     if (data->moving_to_intersect) {
  551.         BrVector3Sub(&car_to_intersect, &data->cheaty_intersect, &pOpponent_spec->car_spec->car_master_actor->t.t.translate.t);
  552.         distance_to_intersect = BrVector3Length(&car_to_intersect);
  553.         if (distance_to_intersect < frame_period_in_secs) {
  554.             data->moving_to_intersect = 0;
  555.             BrVector3Copy(&pOpponent_spec->car_spec->car_master_actor->t.t.translate.t, &data->cheaty_intersect);
  556.         } else {
  557.             BrVector3Normalise(&car_to_intersect, &car_to_intersect);
  558.             BrVector3Scale(&car_to_intersect, &car_to_intersect, frame_period_in_secs);
  559.             BrVector3Accumulate(&pOpponent_spec->car_spec->car_master_actor->t.t.translate.t, &car_to_intersect);
  560.         }
  561.         return eFPR_OK;
  562.     }
  563.  
  564.     BrVector3Sub(&p, finish, start);
  565.     BrVector3Normalise(&p, &p);
  566.     while (frame_period_in_secs > 0.0f) {
  567.         BrVector3Sub(&a, finish, &pOpponent_spec->car_spec->car_master_actor->t.t.translate.t);
  568.         distance_to_end = BrVector3Length(&a);
  569.         if (distance_to_end < frame_period_in_secs) {
  570.             BrVector3Accumulate(&pOpponent_spec->car_spec->car_master_actor->t.t.translate.t, &a);
  571.             frame_period_in_secs -= distance_to_end;
  572.             dr_dprintf("%s: ProcessFollowPath() - current section %d(#%d) (cheating)", pOpponent_spec->car_spec->driver_name, data->section_no, GetOpponentsRealSection(pOpponent_spec, data->section_no));
  573.             data->section_no = GetOpponentsNextSection(pOpponent_spec, data->section_no);
  574.             if (data->section_no == -1) {
  575.                 pOpponent_spec->car_spec->acc_force = 0.0f;
  576.                 pOpponent_spec->car_spec->brake_force = 0.0f;
  577.                 dr_dprintf("%s: ProcessFollowPath() - reached end of path while cheating", pOpponent_spec->car_spec->driver_name);
  578.                 return eFPR_end_of_path;
  579.             }
  580.             dr_dprintf("%s: ProcessFollowPath() - next section %d(#%d) (cheating)", pOpponent_spec->car_spec->driver_name, data->section_no, GetOpponentsRealSection(pOpponent_spec, data->section_no));
  581.             start = GetOpponentsSectionStartNodePoint(pOpponent_spec, data->section_no);
  582.             finish = GetOpponentsSectionFinishNodePoint(pOpponent_spec, data->section_no);
  583.             BrVector3Sub(&p, finish, start);
  584.             BrVector3Normalise(&p, &p);
  585.         } else {
  586.             BrVector3Scale(&p, &p, frame_period_in_secs);
  587.             BrVector3Accumulate(&pOpponent_spec->car_spec->car_master_actor->t.t.translate.t, &p);
  588.             frame_period_in_secs = 0.0;
  589.         }
  590.     }
  591.     return eFPR_OK;
  592. }
  593.