Subversion Repositories Games.Carmageddon

Rev

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

  1. #include "oil.h"
  2. #include "brender/brender.h"
  3. #include "finteray.h"
  4. #include "globvars.h"
  5. #include "globvrpb.h"
  6. #include "harness/trace.h"
  7. #include "loading.h"
  8. #include "network.h"
  9. #include "piping.h"
  10. #include "utility.h"
  11. #include <math.h>
  12. #include <stdlib.h>
  13.  
  14. char* gOil_pixie_names[1] = { "OIL.PIX" };
  15. int gNext_oil_pixie = 0;
  16. br_scalar gZ_buffer_diff;
  17. br_scalar gMin_z_diff;
  18. br_pixelmap* gOil_pixies[1];
  19. tOil_spill_info gOily_spills[15];
  20.  
  21. // IDA: void __cdecl InitOilSpills()
  22. void InitOilSpills(void) {
  23.     int i;
  24.     br_model* the_model;
  25.     br_material* the_material;
  26.     LOG_TRACE("()");
  27.  
  28.     for (i = 0; i < COUNT_OF(gOil_pixie_names); i++) {
  29.         gOil_pixies[i] = LoadPixelmap(gOil_pixie_names[i]);
  30.         BrMapAdd(gOil_pixies[i]);
  31.     }
  32.  
  33.     for (i = 0; i < COUNT_OF(gOily_spills); i++) {
  34.         the_material = BrMaterialAllocate(NULL);
  35.         BrMaterialAdd(the_material);
  36.         the_material->ka = 0.99f;
  37.         the_material->kd = 0.0f;
  38.         the_material->ks = 0.0f;
  39.         the_material->power = 0.0f;
  40.         the_material->index_base = 0;
  41.         the_material->flags |= BR_MATF_LIGHT;
  42.         the_material->flags |= BR_MATF_PERSPECTIVE;
  43.         the_material->flags |= BR_MATF_SMOOTH;
  44.         // TODO: added by dethrace, investigate why oil spills in OG do not need this flag set to render correctly
  45.         the_material->flags |= BR_MATF_TWO_SIDED;
  46.         the_material->index_range = 0;
  47.         the_material->colour_map = NULL;
  48.         BrMatrix23Identity(&the_material->map_transform);
  49.         the_material->index_shade = BrTableFind("IDENTITY.TAB");
  50.         BrMaterialUpdate(the_material, BR_MATU_ALL);
  51.         the_model = BrModelAllocate(NULL, 4, 2);
  52.         the_model->flags |= BR_MODF_KEEP_ORIGINAL;
  53.  
  54.         the_model->faces[0].vertices[0] = 2;
  55.         the_model->faces[0].vertices[1] = 1;
  56.         the_model->faces[0].vertices[2] = 0;
  57.         the_model->faces[0].material = NULL;
  58.         the_model->faces[0].smoothing = 1;
  59.         the_model->faces[1].vertices[0] = 3;
  60.         the_model->faces[1].vertices[1] = 2;
  61.         the_model->faces[1].vertices[2] = 0;
  62.         the_model->faces[1].material = NULL;
  63.         the_model->faces[1].smoothing = 1;
  64.         BrVector3Set(&the_model->vertices[0].p, -1.f, 0.f, -1.f);
  65.         BrVector2Set(&the_model->vertices[0].map, 0.f, 1.f);
  66.         BrVector3Set(&the_model->vertices[1].p, 1.f, 0.f, 1.f);
  67.         BrVector2Set(&the_model->vertices[1].map, 0.f, 0.f);
  68.         BrVector3Set(&the_model->vertices[2].p, 1.f, 0.f, -1.f);
  69.         BrVector2Set(&the_model->vertices[2].map, 1.f, 0.f);
  70.         BrVector3Set(&the_model->vertices[3].p, -1.f, 0.f, 1.f);
  71.         BrVector2Set(&the_model->vertices[3].map, 1.f, 1.f);
  72.         gOily_spills[i].actor = BrActorAllocate(BR_ACTOR_MODEL, NULL);
  73.         gOily_spills[i].actor->model = the_model;
  74.         gOily_spills[i].actor->render_style = BR_RSTYLE_NONE;
  75.         gOily_spills[i].actor->material = the_material;
  76.         BrActorAdd(gNon_track_actor, gOily_spills[i].actor);
  77.     }
  78. }
  79.  
  80. // IDA: void __cdecl ResetOilSpills()
  81. void ResetOilSpills(void) {
  82.     int i;
  83.     LOG_TRACE("()");
  84.  
  85.     for (i = 0; i < COUNT_OF(gOily_spills); i++) {
  86.         gOily_spills[i].actor->render_style = BR_RSTYLE_NONE;
  87.         gOily_spills[i].car = NULL;
  88.         gOily_spills[i].stop_time = 0;
  89.     }
  90. }
  91.  
  92. // IDA: void __usercall QueueOilSpill(tCar_spec *pCar@<EAX>)
  93. void QueueOilSpill(tCar_spec* pCar) {
  94.     int i;
  95.     int oily_index;
  96.     int oldest_one;
  97.     tU32 the_time;
  98.     tU32 oldest_time;
  99.     LOG_TRACE("(%p)", pCar);
  100.  
  101.     oldest_one = 0;
  102.     oily_index = -1;
  103.     the_time = GetTotalTime();
  104.     oldest_time = GetTotalTime();
  105.  
  106.     for (i = 0; i < COUNT_OF(gOily_spills); i++) {
  107.         if (gOily_spills[i].car == pCar && the_time < gOily_spills[i].spill_time + 5000) {
  108.             return;
  109.         }
  110.     }
  111.  
  112.     for (i = 0; i < COUNT_OF(gOily_spills); i++) {
  113.         if (gOily_spills[i].car == NULL) {
  114.             oily_index = i;
  115.             break;
  116.         }
  117.         if (gOily_spills[i].spill_time < oldest_time) {
  118.             oldest_time = gOily_spills[i].spill_time;
  119.             oldest_one = i;
  120.         }
  121.     }
  122.  
  123.     if (oily_index < 0) {
  124.         oily_index = oldest_one;
  125.     }
  126.     gOily_spills[oily_index].car = pCar;
  127.     gOily_spills[oily_index].spill_time = the_time + 500;
  128.     gOily_spills[oily_index].full_size = SRandomBetween(.35f, .6f);
  129.     gOily_spills[oily_index].grow_rate = SRandomBetween(3e-5f, 10e-5f);
  130.     gOily_spills[oily_index].current_size = .1f;
  131.     gOily_spills[oily_index].actor->render_style = BR_RSTYLE_NONE;
  132. }
  133.  
  134. // IDA: int __usercall OKToSpillOil@<EAX>(tOil_spill_info *pOil@<EAX>)
  135. int OKToSpillOil(tOil_spill_info* pOil) {
  136.     //br_scalar temp; // Pierre-Marie Baty -- unused variable
  137.     //br_scalar size_with_margin; // Pierre-Marie Baty -- unused variable
  138.     br_scalar distance;
  139.     br_scalar mr_dotty;
  140.     br_vector3 v;
  141.     br_vector3 ray_pos;
  142.     br_vector3 ray_dir;
  143.     br_vector3 normal;
  144.     tCar_spec* car;
  145.     int i;
  146.     int face_count;
  147.     int found_one;
  148.     br_angle angle_to_rotate_by;
  149.     tBounds kev_bounds;
  150.     tFace_ref the_list[10];
  151.     tFace_ref* face_ref;
  152.     LOG_TRACE("(%p)", pOil);
  153.  
  154.     car = pOil->car;
  155.     if (car->driver >= eDriver_net_human && car->damage_units[eDamage_engine].damage_level <= 98 && car->damage_units[eDamage_transmission].damage_level <= 98) {
  156.         return 0;
  157.     }
  158.     angle_to_rotate_by = IRandomBetween(0, 0xffff);
  159.     kev_bounds.original_bounds.min.v[0] = -pOil->full_size;
  160.     kev_bounds.original_bounds.min.v[1] = 1.5f * car->car_model_actors[car->principal_car_actor].actor->model->bounds.min.v[1];
  161.     kev_bounds.original_bounds.min.v[2] = -pOil->full_size;
  162.     kev_bounds.original_bounds.max.v[0] = pOil->full_size;
  163.     kev_bounds.original_bounds.max.v[1] = car->car_model_actors[car->principal_car_actor].actor->model->bounds.max.v[1];
  164.     kev_bounds.original_bounds.max.v[2] = pOil->full_size;
  165.     BrMatrix34PreRotateY(&pOil->actor->t.t.mat, angle_to_rotate_by);
  166.     kev_bounds.mat = &car->car_master_actor->t.t.mat;
  167.     face_count = FindFacesInBox(&kev_bounds, the_list, COUNT_OF(the_list));
  168.     BrVector3Set(&v, .0f, .2f, .0f);
  169.     BrMatrix34ApplyP(&ray_pos, &v, &car->car_master_actor->t.t.mat);
  170.     BrVector3Set(&ray_dir, 0.f, kev_bounds.original_bounds.min.v[1] - kev_bounds.original_bounds.max.v[1], 0.f);\
  171.     if (face_count == 0) {
  172.         return 0;
  173.     }
  174.     found_one = 0;
  175.     for (i = 0; i < face_count; i++) {
  176.         face_ref = &the_list[i];
  177.         if (!found_one) {
  178.             CheckSingleFace(face_ref, &ray_pos, &ray_dir, &normal, &distance);
  179.             if (distance < 100.f) {
  180.                 found_one = 1;
  181.                 BrVector3Copy((br_vector3*)pOil->actor->t.t.mat.m[1], &normal);
  182.                 BrVector3Set(&v, 0.f, 0.f, 1.f);
  183.                 BrVector3Cross((br_vector3*)pOil->actor->t.t.mat.m[0], &normal, &v);
  184.                 BrVector3Set(&v, 1.f, 0.f, 0.f);
  185.                 BrVector3Cross((br_vector3*)pOil->actor->t.t.mat.m[2], &normal, &v);
  186.                 BrVector3Scale(&v, &ray_dir, distance);
  187.                 BrVector3Add(&pOil->pos, &ray_pos, &v);
  188.                 BrMatrix34PreRotateY(&pOil->actor->t.t.mat, angle_to_rotate_by);
  189.             }
  190.         }
  191.     }
  192.     if (!found_one || normal.v[1] < .97f) {
  193.         return 0;
  194.     }
  195.     for (i = 0; i < face_count; i++) {
  196.         face_ref = &the_list[i];
  197.         mr_dotty = BrVector3Dot(&face_ref->normal, &normal);
  198.         if (mr_dotty < .98f && (mr_dotty > .8f || !NormalSideOfPlane(&pOil->actor->t.t.translate.t, &face_ref->normal, face_ref->d))) {
  199.             return 0;
  200.         }
  201.     }
  202.     return 1;
  203. }
  204.  
  205. // IDA: void __usercall Vector3Interpolate(br_vector3 *pDst@<EAX>, br_vector3 *pFrom@<EDX>, br_vector3 *pTo@<EBX>, br_scalar pP)
  206. void Vector3Interpolate(br_vector3* pDst, br_vector3* pFrom, br_vector3* pTo, br_scalar pP) {
  207.     LOG_TRACE("(%p, %p, %p, %f)", pDst, pFrom, pTo, pP);
  208.  
  209.     pDst->v[0] = (pTo->v[0] - pFrom->v[0]) * pP + pFrom->v[0];
  210.     pDst->v[1] = (pTo->v[1] - pFrom->v[1]) * pP + pFrom->v[1];
  211.     pDst->v[2] = (pTo->v[2] - pFrom->v[2]) * pP + pFrom->v[2];
  212. }
  213.  
  214. // IDA: void __usercall EnsureGroundDetailVisible(br_vector3 *pNew_pos@<EAX>, br_vector3 *pGround_normal@<EDX>, br_vector3 *pOld_pos@<EBX>)
  215. void EnsureGroundDetailVisible(br_vector3* pNew_pos, br_vector3* pGround_normal, br_vector3* pOld_pos) {
  216.     br_scalar factor;
  217.     br_scalar s;
  218.     br_scalar dist;
  219.     br_vector3 to_camera;
  220.     LOG_TRACE("(%p, %p, %p)", pNew_pos, pGround_normal, pOld_pos);
  221.  
  222.     to_camera.v[0] = gCamera_to_world.m[3][0] - pOld_pos->v[0];
  223.     to_camera.v[1] = gCamera_to_world.m[3][1] - pOld_pos->v[1];
  224.     to_camera.v[2] = gCamera_to_world.m[3][2] - pOld_pos->v[2];
  225.     dist = BrVector3Length(&to_camera);
  226.     if (dist > BR_SCALAR_EPSILON) {
  227.         factor = BrVector3Dot(pGround_normal, &to_camera) / dist;
  228.         if (fabsf(factor) <= 0.01f) {
  229.             s = 0.01f;
  230.         } else {
  231.             s = 0.01f / factor;
  232.             if (s > 0.1f) {
  233.                 s = 0.1f;
  234.             }
  235.         }
  236.         Vector3Interpolate(pNew_pos, pOld_pos, (br_vector3*)gCamera_to_world.m[3], s);
  237.     }
  238. }
  239.  
  240. // IDA: void __usercall MungeOilsHeightAboveGround(tOil_spill_info *pOil@<EAX>)
  241. void MungeOilsHeightAboveGround(tOil_spill_info* pOil) {
  242.     LOG_TRACE("(%p)", pOil);
  243.  
  244.     EnsureGroundDetailVisible(&pOil->actor->t.t.look_up.t, &pOil->actor->t.t.look_up.up, &pOil->pos);
  245. }
  246.  
  247. // IDA: void __usercall MungeIndexedOilsHeightAboveGround(int pIndex@<EAX>)
  248. void MungeIndexedOilsHeightAboveGround(int pIndex) {
  249.     LOG_TRACE("(%d)", pIndex);
  250.  
  251.     MungeOilsHeightAboveGround(&gOily_spills[pIndex]);
  252. }
  253.  
  254. // IDA: void __usercall SetInitialOilStuff(tOil_spill_info *pOil@<EAX>, br_model *pModel@<EDX>)
  255. void SetInitialOilStuff(tOil_spill_info* pOil, br_model* pModel) {
  256.     LOG_TRACE("(%p, %p)", pOil, pModel);
  257.  
  258.     pModel->vertices[0].p.v[0] = -0.1f;
  259.     pModel->vertices[0].p.v[2] = -0.1f;
  260.     pModel->vertices[1].p.v[0] =  0.1f;
  261.     pModel->vertices[1].p.v[2] = -0.1f;
  262.     pModel->vertices[2].p.v[0] =  0.1f;
  263.     pModel->vertices[2].p.v[2] =  0.1f;
  264.     pModel->vertices[3].p.v[0] = -0.1f;
  265.     pModel->vertices[3].p.v[2] =  0.1f;
  266.     pOil->actor->render_style = BR_RSTYLE_FACES;
  267.     BrMaterialUpdate(pOil->actor->material, BR_MATU_ALL);
  268.     BrModelUpdate(pModel, BR_MODU_ALL);
  269. }
  270.  
  271. // IDA: void __usercall ProcessOilSpills(tU32 pFrame_period@<EAX>)
  272. void ProcessOilSpills(tU32 pFrame_period) {
  273.     int i;
  274.     tU32 time;
  275.     br_model* the_model;
  276.     br_scalar grow_amount;
  277.     //br_scalar initial_size; // Pierre-Marie Baty -- unused variable
  278.     br_scalar this_size;
  279.     br_vector3 v;
  280.     tNet_message* message;
  281.     LOG_TRACE("(%d)", pFrame_period);
  282.  
  283.     time = GetTotalTime();
  284.     for (i = 0; i < COUNT_OF(gOily_spills); i++) {
  285.         if (gOily_spills[i].car == NULL) {
  286.             gOily_spills[i].actor->render_style = BR_RSTYLE_NONE;
  287.         } else {
  288.             the_model = gOily_spills[i].actor->model;
  289.             if (gOily_spills[i].actor->render_style == BR_RSTYLE_NONE &&
  290.                 gOily_spills[i].spill_time <= time &&
  291.                 fabsf(gOily_spills[i].car->v.v[0]) < .01f &&
  292.                 fabsf(gOily_spills[i].car->v.v[1]) < .01f &&
  293.                 fabsf(gOily_spills[i].car->v.v[2]) < .01f) {
  294.                 if (gAction_replay_mode) {
  295.                     SetInitialOilStuff(&gOily_spills[i], the_model);
  296.                 } else {
  297.                     if (!OKToSpillOil(&gOily_spills[i])) {
  298.                         gOily_spills[i].car = NULL;
  299.                     } else {
  300.                         gOily_spills[i].spill_time = time;
  301.                         gOily_spills[i].actor->material->colour_map = gOil_pixies[gNext_oil_pixie];
  302.                         gNext_oil_pixie++;
  303.                         if (gNext_oil_pixie >= COUNT_OF(gOil_pixies)) {
  304.                             gNext_oil_pixie = 0;
  305.                         }
  306.                         BrVector3Copy(&gOily_spills[i].original_pos, &gOily_spills[i].car->pos);
  307.                         PipeSingleOilSpill(i,
  308.                             &gOily_spills[i].actor->t.t.mat,
  309.                             gOily_spills[i].full_size,
  310.                             gOily_spills[i].grow_rate,
  311.                             gOily_spills[i].spill_time,
  312.                             gOily_spills[i].stop_time,
  313.                             gOily_spills[i].car,
  314.                             &gOily_spills[i].original_pos,
  315.                             gOily_spills[i].actor->material->colour_map);
  316.                         gOily_spills[i].stop_time = 0;
  317.                         SetInitialOilStuff(&gOily_spills[i], the_model);
  318.                         if (gNet_mode != eNet_mode_none) {
  319.                             message = NetBuildMessage(30, 0);
  320.                             message->contents.data.oil_spill.player = NetPlayerFromCar(gOily_spills[i].car)->ID;
  321.                             message->contents.data.oil_spill.full_size = gOily_spills[i].full_size;
  322.                             message->contents.data.oil_spill.grow_rate = gOily_spills[i].grow_rate;
  323.                             message->contents.data.oil_spill.current_size = gOily_spills[i].current_size;
  324.                             NetGuaranteedSendMessageToAllPlayers(gCurrent_net_game, message, NULL);
  325.                         }
  326.                     }
  327.                 }
  328.             } else {
  329.                 if (gOily_spills[i].actor->render_style == BR_RSTYLE_FACES &&
  330.                     (gOily_spills[i].stop_time == 0 || time < gOily_spills[i].stop_time)) {
  331.                     BrVector3Sub(&v, &gOily_spills[i].original_pos, &gOily_spills[i].car->pos);
  332.                     grow_amount = BrVector3LengthSquared(&v);
  333.                     if (gOily_spills[i].stop_time != 0 || grow_amount <= 0.2f) {
  334.                         this_size = 0.1f + (time - gOily_spills[i].spill_time) * gOily_spills[i].grow_rate;
  335.                         if (this_size >= 0.1f) {
  336.                             gOily_spills[i].actor->render_style = BR_RSTYLE_FACES;
  337.                             if (this_size <= gOily_spills[i].full_size) {
  338.                                 the_model->vertices[0].p.v[0] = -this_size;
  339.                                 the_model->vertices[0].p.v[2] = -this_size;
  340.                                 the_model->vertices[1].p.v[0] = this_size;
  341.                                 the_model->vertices[1].p.v[2] = -this_size;
  342.                                 the_model->vertices[2].p.v[0] = this_size;
  343.                                 the_model->vertices[2].p.v[2] = this_size;
  344.                                 the_model->vertices[3].p.v[0] = -this_size;
  345.                                 the_model->vertices[3].p.v[2] = this_size;
  346.                                 gOily_spills[i].current_size = this_size;
  347.                             } else {
  348.                                 the_model->vertices[0].p.v[0] = -gOily_spills[i].full_size;
  349.                                 the_model->vertices[0].p.v[2] = -gOily_spills[i].full_size;
  350.                                 the_model->vertices[1].p.v[0] = gOily_spills[i].full_size;
  351.                                 the_model->vertices[1].p.v[2] = -gOily_spills[i].full_size;
  352.                                 the_model->vertices[2].p.v[0] = gOily_spills[i].full_size;
  353.                                 the_model->vertices[2].p.v[2] = gOily_spills[i].full_size;
  354.                                 the_model->vertices[3].p.v[0] = -gOily_spills[i].full_size;
  355.                                 the_model->vertices[3].p.v[2] = gOily_spills[i].full_size;
  356.                                 gOily_spills[i].current_size = gOily_spills[i].full_size;
  357.                             }
  358.                             BrModelUpdate(the_model, BR_MODU_ALL);
  359.                         } else {
  360.                             gOily_spills[i].actor->render_style = BR_RSTYLE_NONE;
  361.                         }
  362.                     } else {
  363.                         gOily_spills[i].stop_time = time;
  364.                         continue;
  365.                     }
  366.                 }
  367.             }
  368.         }
  369.         if (gOily_spills[i].actor->render_style == BR_RSTYLE_FACES) {
  370.             MungeOilsHeightAboveGround(&gOily_spills[i]);
  371.         }
  372.     }
  373. }
  374.  
  375. // IDA: int __cdecl GetOilSpillCount()
  376. int GetOilSpillCount(void) {
  377.     //LOG_TRACE("()");
  378.  
  379.     return COUNT_OF(gOily_spills);
  380. }
  381.  
  382. // IDA: void __usercall GetOilSpillDetails(int pIndex@<EAX>, br_actor **pActor@<EDX>, br_scalar *pSize@<EBX>)
  383. void GetOilSpillDetails(int pIndex, br_actor** pActor, br_scalar* pSize) {
  384.     LOG_TRACE("(%d, %p, %p)", pIndex, pActor, pSize);
  385.  
  386.     if (gOily_spills[pIndex].car != NULL) {
  387.         *pActor = gOily_spills[pIndex].actor;
  388.         *pSize = gOily_spills[pIndex].full_size;
  389.     } else {
  390.         *pActor = NULL;
  391.     }
  392. }
  393.  
  394. #define SQR(V) ((V)*(V))
  395.  
  396. // IDA: int __usercall PointInSpill@<EAX>(br_vector3 *pV@<EAX>, int pSpill@<EDX>)
  397. int PointInSpill(br_vector3* pV, int pSpill) {
  398.     LOG_TRACE("(%p, %d)", pV, pSpill);
  399.  
  400.     return gOily_spills[pSpill].current_size * gOily_spills[pSpill].current_size * 0.8f > SQR(pV->v[0] / WORLD_SCALE - gOily_spills[pSpill].actor->t.t.translate.t.v[0])
  401.         && gOily_spills[pSpill].current_size * gOily_spills[pSpill].current_size * 0.8f > SQR(pV->v[2] / WORLD_SCALE - gOily_spills[pSpill].actor->t.t.translate.t.v[2])
  402.         && fabsf(pV->v[1] / WORLD_SCALE - gOily_spills[pSpill].actor->t.t.translate.t.v[1]) < 0.1f;
  403. }
  404.  
  405. // IDA: void __usercall GetOilFrictionFactors(tCar_spec *pCar@<EAX>, br_scalar *pFl_factor@<EDX>, br_scalar *pFr_factor@<EBX>, br_scalar *pRl_factor@<ECX>, br_scalar *pRr_factor)
  406. void GetOilFrictionFactors(tCar_spec* pCar, br_scalar* pFl_factor, br_scalar* pFr_factor, br_scalar* pRl_factor, br_scalar* pRr_factor) {
  407.     int i;
  408.     br_vector3 wheel_world;
  409.     LOG_TRACE("(%p, %p, %p, %p, %p)", pCar, pFl_factor, pFr_factor, pRl_factor, pRr_factor);
  410.  
  411.     *pFl_factor = 1.0f;
  412.     *pFr_factor = 1.0f;
  413.     *pRl_factor = 1.0f;
  414.     *pRr_factor = 1.0f;
  415.     switch (pCar->driver) {
  416.     case eDriver_non_car_unused_slot:
  417.     case eDriver_non_car:
  418.         return;
  419.     default:
  420.         break;
  421.     }
  422.     if (pCar->shadow_intersection_flags != 0) {
  423.         for (i = 0; i < COUNT_OF(gOily_spills); i++) {
  424.             if (((1 << i) & pCar->shadow_intersection_flags) != 0 && gOily_spills[i].car != NULL) {
  425.                 BrMatrix34ApplyP(&wheel_world, &pCar->wpos[2], &pCar->car_master_actor->t.t.mat);
  426.                 if (PointInSpill(&wheel_world, i)) {
  427.                     pCar->oil_remaining[2] = SRandomBetween(1.5f, 2.5f);
  428.                 }
  429.                 BrMatrix34ApplyP(&wheel_world, &pCar->wpos[3], &pCar->car_master_actor->t.t.mat);
  430.                 if (PointInSpill(&wheel_world, i)) {
  431.                     pCar->oil_remaining[3] = SRandomBetween(1.5f, 2.5f);
  432.                 }
  433.                 BrMatrix34ApplyP(&wheel_world, &pCar->wpos[0], &pCar->car_master_actor->t.t.mat);
  434.                 if (PointInSpill(&wheel_world, i)) {
  435.                     pCar->oil_remaining[0] = SRandomBetween(1.5f, 2.5f);
  436.                 }
  437.                 BrMatrix34ApplyP(&wheel_world, &pCar->wpos[1], &pCar->car_master_actor->t.t.mat);
  438.                 if (PointInSpill(&wheel_world, i)) {
  439.                     pCar->oil_remaining[1] = SRandomBetween(1.5f, 2.5f);
  440.                 }
  441.             }
  442.         }
  443.     }
  444.     if (pCar->oil_remaining[2] != 0.0f) {
  445.         *pFl_factor = SRandomBetween(0.01f, 0.15f);
  446.     }
  447.     if (pCar->oil_remaining[3] != 0.0f) {
  448.         *pFr_factor = SRandomBetween(0.01f, 0.15f);
  449.     }
  450.     if (pCar->oil_remaining[0] != 0.0f) {
  451.         *pRl_factor = SRandomBetween(0.01f, 0.15f);
  452.     }
  453.     if (pCar->oil_remaining[1] != 0.0f) {
  454.         *pRr_factor = SRandomBetween(0.01f, 0.15f);
  455.     }
  456. }
  457.  
  458. // IDA: void __usercall AdjustOilSpill(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)
  459. void AdjustOilSpill(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) {
  460.     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);
  461.  
  462.     BrMatrix34Copy(&gOily_spills[pIndex].actor->t.t.mat, pMat);
  463.     gOily_spills[pIndex].full_size = pFull_size;
  464.     gOily_spills[pIndex].grow_rate = pGrow_rate;
  465.     gOily_spills[pIndex].spill_time = pSpill_time;
  466.     gOily_spills[pIndex].stop_time = pStop_time;
  467.     gOily_spills[pIndex].car = pCar;
  468.     BrVector3Copy(&gOily_spills[pIndex].original_pos, pOriginal_pos);
  469.     gOily_spills[pIndex].actor->material->colour_map = pPixelmap;
  470.     gOily_spills[pIndex].actor->render_style = BR_RSTYLE_NONE;
  471. }
  472.  
  473. // IDA: void __usercall ReceivedOilSpill(tNet_contents *pContents@<EAX>)
  474. void ReceivedOilSpill(tNet_contents* pContents) {
  475.     int i;
  476.     int oily_index;
  477.     int oldest_one;
  478.     tU32 the_time;
  479.     tU32 oldest_time;
  480.     tCar_spec* car;
  481.     LOG_TRACE("(%p)", pContents);
  482.  
  483.     oldest_one = 0;
  484.     car = NetCarFromPlayerID(pContents->data.oil_spill.player);
  485.     if (car == NULL) {
  486.         return;
  487.     }
  488.     oily_index = -1;
  489.     the_time = GetTotalTime();
  490.     oldest_time = GetTotalTime();
  491.     for (i = 0; i < COUNT_OF(gOily_spills); i++) {
  492.         if (gOily_spills[i].car == car && the_time < gOily_spills[i].spill_time + 5000) {
  493.             return;
  494.         }
  495.     }
  496.     for (i = 0; i < COUNT_OF(gOily_spills); i++) {
  497.         if (gOily_spills[i].car == NULL) {
  498.             oily_index = i;
  499.             break;
  500.         }
  501.         if (gOily_spills[i].spill_time < oldest_time) {
  502.             oldest_time = gOily_spills[i].spill_time;
  503.             oldest_one = i;
  504.         }
  505.     }
  506.     if (oily_index < 0) {
  507.         oily_index = oldest_one;
  508.     }
  509.     gOily_spills[oily_index].car = car;
  510.     gOily_spills[oily_index].spill_time = the_time;
  511.     gOily_spills[oily_index].full_size = pContents->data.oil_spill.full_size;
  512.     gOily_spills[oily_index].grow_rate = pContents->data.oil_spill.grow_rate;
  513.     gOily_spills[oily_index].current_size = pContents->data.oil_spill.current_size;
  514.     gOily_spills[oily_index].actor->render_style = BR_RSTYLE_NONE;
  515. }
  516.