Subversion Repositories Games.Carmageddon

Rev

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

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