00001
00002 #include "revolt.h"
00003 #include "main.h"
00004 #include "weapon.h"
00005 #include "car.h"
00006 #include "ctrlread.h"
00007 #include "player.h"
00008 #include "geom.h"
00009 #include "move.h"
00010 #include "field.h"
00011 #include "timing.h"
00012 #include "spark.h"
00013 #include "drawobj.h"
00014 #ifdef _PC
00015 #include "shadow.h"
00016 #endif
00017 #include "obj_init.h"
00018 #include "visibox.h"
00019 #ifdef _PC
00020 #include "mirror.h"
00021 #include "input.h"
00022 #endif
00023 #include "camera.h"
00024
00025 #define MAX_FIREWORK_AGE Real(1.2)
00026
00027
00028
00029 void FireWorkMove(OBJECT *obj);
00030 void FireworkExplode(OBJECT *obj);
00031 void TurboAIHandler(OBJECT *obj);
00032 void TurboMoveHandler(OBJECT *obj);
00033 void PuttyBombMove(OBJECT *obj);
00034
00035
00036
00037 long OilSlickCount;
00038 OILSLICK_LIST OilSlickList[OILSLICK_LIST_MAX];
00039
00040 static VEC WaterBombVel = {0.0f, -1500.0f, 2000.0f};
00041 static VEC WaterBombOff = {0.0f, -32.0f, 0.0f};
00042 static VEC BombSmokeVel = {0.0f, -80.0f, 0.0f};
00043
00044
00046
00048
00049 void ResetOilSlickList(void)
00050 {
00051 OilSlickCount = 0;
00052 }
00053
00055
00057
00058 static void WeaponSetupTest(OBJECT *obj)
00059 {
00060
00061
00062 obj->Light = AllocLight();
00063 if (obj->Light)
00064 {
00065 obj->Light->Reach = 1024;
00066 obj->Light->Flag = LIGHT_FIXED | LIGHT_MOVING;
00067 obj->Light->Type= LIGHT_OMNI;
00068 switch (rand() & 3)
00069 {
00070 case 0:
00071 obj->Light->r = 128;
00072 obj->Light->g = 0;
00073 obj->Light->b = 0;
00074 break;
00075
00076 case 1:
00077 obj->Light->r = 0;
00078 obj->Light->g = 128;
00079 obj->Light->b = 0;
00080 break;
00081
00082 case 2:
00083 obj->Light->r = 0;
00084 obj->Light->g = 0;
00085 obj->Light->b = 128;
00086 break;
00087
00088 case 3:
00089 obj->Light->r = 128;
00090 obj->Light->g = 0;
00091 obj->Light->b = 128;
00092 break;
00093 }
00094 }
00095
00096
00097 RotTransVector(&obj->body.Centre.WMatrix, &obj->body.Centre.Pos, &obj->player->car.WeaponOffset, &obj->body.Centre.Pos);
00098
00099
00100 obj->CollType = COLL_TYPE_BODY;
00101 obj->collhandler = (COLL_HANDLER)COL_BodyCollHandler;
00102
00103
00104 obj->body.Centre.Mass = Real(0.1f);
00105 obj->body.Centre.InvMass = ONE / Real(0.1f);
00106 SetMat(&obj->body.BodyInertia, Real(100), ZERO, ZERO, ZERO, Real(100), ZERO, ZERO, ZERO, Real(100));
00107 SetMat(&obj->body.BodyInvInertia, ONE / Real(100), ZERO, ZERO, ZERO, ONE / Real(100), ZERO, ZERO, ZERO, ONE / Real(100));
00108
00109 obj->body.Centre.Hardness = Real(0.7);
00110 obj->body.Centre.Resistance = Real(0.0001);
00111 obj->body.DefaultAngRes = Real(0.005);
00112 obj->body.AngResistance = Real(0.005);
00113 obj->body.AngResMod = Real(1.0);
00114 obj->body.Centre.Grip = Real(0.015);
00115 obj->body.Centre.StaticFriction = Real(1.5);
00116 obj->body.Centre.KineticFriction = Real(1.1);
00117
00118
00119 SetBodySphere(&obj->body);
00120 obj->body.CollSkin.Sphere = (SPHERE *)malloc(sizeof(SPHERE));
00121 SetVecZero(&obj->body.CollSkin.Sphere[0].Pos);
00122 obj->body.CollSkin.Sphere[0].Radius = Real(30);
00123 obj->body.CollSkin.NSpheres = 1;
00124 CreateCopyCollSkin(&obj->body.CollSkin);
00125 MakeTightLocalBBox(&obj->body.CollSkin);
00126 BuildWorldSkin(&obj->body.CollSkin, &obj->body.Centre.Pos, &obj->body.Centre.WMatrix);
00127
00128
00129 SetVector(&obj->body.Centre.Vel, obj->body.Centre.WMatrix.m[LX] * 2560, obj->body.Centre.WMatrix.m[LY] * 2560, obj->body.Centre.WMatrix.m[LZ] * 2560);
00130 }
00131
00133
00135
00136 static void WeaponMoveTest(OBJECT *obj)
00137 {
00138
00139
00140
00141 if (obj->Light)
00142 {
00143 obj->Light->x = obj->body.Centre.Pos.v[X];
00144 obj->Light->y = obj->body.Centre.Pos.v[Y];
00145 obj->Light->z = obj->body.Centre.Pos.v[Z];
00146 }
00147
00148
00149
00150 MOV_MoveBody(obj);
00151 }
00152
00153 #ifdef _PC
00155 // init weapon //
00157
00158 long InitShockwave(OBJECT *obj, long *flags)
00159 {
00160 VEC bVec, dir, axis;
00161 BBOX bBox;
00162 SHOCKWAVE_OBJ *shockwave = (SHOCKWAVE_OBJ*)obj->Data;
00163
00164
00165
00166 obj->player = (PLAYER*)flags[0];
00167
00168
00169
00170 shockwave->Alive = TRUE;
00171 shockwave->Age = 0.0f;
00172 shockwave->Reach = 1024.0f;
00173
00174 RotTransVector(&obj->body.Centre.WMatrix, &obj->body.Centre.Pos, &obj->player->car.WeaponOffset, &obj->body.Centre.Pos);
00175 VecEqScalarVec(&obj->body.Centre.Vel, SHOCKWAVE_VEL, &obj->body.Centre.WMatrix.mv[L]);
00176
00177 VecPlusScalarVec(&obj->body.Centre.Pos, -SHOCKWAVE_VEL, &obj->body.Centre.Vel, &shockwave->OldPos);
00178
00179
00180
00181 obj->aihandler = (AI_HANDLER)ShockwaveHandler;
00182 obj->renderhandler = (RENDER_HANDLER)RenderShockwave;
00183 obj->collhandler = (COLL_HANDLER)COL_BodyCollHandler;
00184 obj->movehandler = (MOVE_HANDLER)MOV_MoveBody;
00185
00186
00187
00188 obj->CollType = COLL_TYPE_BODY;
00189
00190 obj->body.Centre.Mass = Real(1.0);
00191 obj->body.Centre.InvMass = ONE / Real(1.0);
00192 SetMat(&obj->body.BodyInertia, Real(100), ZERO, ZERO, ZERO, Real(100), ZERO, ZERO, ZERO, Real(100));
00193 SetMat(&obj->body.BodyInvInertia, ONE / Real(100), ZERO, ZERO, ZERO, ONE / Real(100), ZERO, ZERO, ZERO, ONE / Real(100));
00194
00195 obj->body.Centre.Hardness = Real(0.1);
00196 obj->body.Centre.Resistance = Real(0.0);
00197 obj->body.DefaultAngRes = Real(0.0);
00198 obj->body.AngResistance = Real(0.0);
00199 obj->body.AngResMod = Real(1.0);
00200 obj->body.Centre.Grip = Real(0.0);
00201 obj->body.Centre.StaticFriction = Real(0.0);
00202 obj->body.Centre.KineticFriction = Real(0.0);
00203
00204
00205
00206 SetBodySphere(&obj->body);
00207 obj->body.CollSkin.Sphere = (SPHERE *)malloc(sizeof(SPHERE));
00208 SetVecZero(&obj->body.CollSkin.Sphere[0].Pos);
00209 obj->body.CollSkin.Sphere[0].Radius = SHOCKWAVE_RAD;
00210 obj->body.CollSkin.NSpheres = 1;
00211 CreateCopyCollSkin(&obj->body.CollSkin);
00212 MakeTightLocalBBox(&obj->body.CollSkin);
00213 BuildWorldSkin(&obj->body.CollSkin, &obj->body.Centre.Pos, &obj->body.Centre.WMatrix);
00214
00215 obj->body.CollSkin.AllowObjColls = FALSE;
00216
00217
00218
00219 obj->Light = AllocLight();
00220 if (obj->Light)
00221 {
00222 obj->Light->Reach = 1024;
00223 obj->Light->Flag = LIGHT_FIXED | LIGHT_MOVING;
00224 obj->Light->Type = LIGHT_OMNI;
00225 obj->Light->r = 0;
00226 obj->Light->g = 0;
00227 obj->Light->b = 128;
00228 }
00229
00230
00231
00232 obj->Sfx3D = CreateSfx3D(SFX_SHOCKWAVE, SFX_MAX_VOL, 22050, TRUE, &obj->body.Centre.Pos);
00233
00234
00235
00236 SetBBox(&bBox, -shockwave->Reach, shockwave->Reach, -shockwave->Reach, shockwave->Reach, -shockwave->Reach, shockwave->Reach);
00237 SetVec(&bVec, shockwave->Reach / 2, shockwave->Reach / 2, shockwave->Reach / 2);
00238 VecPlusScalarVec(&obj->body.Centre.Vel, -Real(12000), &UpVec, &dir);
00239 NormalizeVec(&dir);
00240 VecEqScalarVec(&axis, Real(50000), &obj->body.Centre.WMatrix.mv[R]);
00241 obj->Field = AddLinearTwistField(
00242 obj->player->ownobj->ObjID,
00243 FIELD_PRIORITY_MIN,
00244 &obj->body.Centre.Pos,
00245 &obj->body.Centre.WMatrix,
00246 &bBox,
00247 &bVec,
00248 &dir,
00249 -Real(6000),
00250 &axis,
00251 ZERO);
00252
00253 obj->FieldPriority = FIELD_PRIORITY_MAX;
00254
00255
00256
00257 return TRUE;
00258 }
00259
00261
00263
00264 long InitFirework(OBJECT *obj, long *flags)
00265 {
00266 REAL dRLen, speedMod;
00267 VEC dR, dir;
00268 MAT *playerMat;
00269 FIREWORK_OBJ *firework = (FIREWORK_OBJ*)obj->Data;
00270
00271
00272
00273 obj->renderflag.envmap = FALSE;
00274 obj->renderflag.light = FALSE;
00275
00276
00277
00278 obj->movehandler = (MOVE_HANDLER)FireworkHandler;
00279 obj->CollType = COLL_TYPE_BODY;
00280 obj->collhandler = (COLL_HANDLER)COL_BodyCollHandler;
00281
00282
00283
00284 obj->DefaultModel = LoadOneLevelModel(LEVEL_MODEL_FIREWORK, FALSE, obj->renderflag, TPAGE_FX1);
00285 if (obj->DefaultModel == -1) return FALSE;
00286
00287
00288
00289 obj->player = (PLAYER*)flags[0];
00290 playerMat = &obj->player->car.Body->Centre.WMatrix;
00291
00292
00293 firework->Exploded = FALSE;
00294 firework->Age = ZERO;
00295 firework->Target = obj->player->PickupTarget;
00296
00297
00298 RotTransVector(&obj->body.Centre.WMatrix, &obj->body.Centre.Pos, &obj->player->car.WeaponOffset, &obj->body.Centre.Pos);
00299
00300
00301 obj->body.Centre.Mass = Real(0.1f);
00302 obj->body.Centre.InvMass = ONE / Real(0.1f);
00303 SetMat(&obj->body.BodyInertia, Real(100), ZERO, ZERO, ZERO, Real(100), ZERO, ZERO, ZERO, Real(100));
00304 SetMat(&obj->body.BodyInvInertia, ONE / Real(100), ZERO, ZERO, ZERO, ONE / Real(100), ZERO, ZERO, ZERO, ONE / Real(100));
00305
00306 obj->body.Centre.Hardness = Real(0.7);
00307 obj->body.Centre.Resistance = Real(0.003);
00308 obj->body.DefaultAngRes = Real(0.01);
00309 obj->body.AngResistance = Real(0.01);
00310 obj->body.AngResMod = Real(1.0);
00311 obj->body.Centre.Grip = Real(0.015);
00312 obj->body.Centre.StaticFriction = Real(1.5);
00313 obj->body.Centre.KineticFriction = Real(1.1);
00314
00315
00316 SetBodyConvex(&obj->body);
00317 obj->body.CollSkin.AllowObjColls = FALSE;
00318 obj->body.CollSkin.NConvex = LevelModel[obj->DefaultModel].CollSkin.NConvex;
00319 obj->body.CollSkin.NSpheres = LevelModel[obj->DefaultModel].CollSkin.NSpheres;
00320 obj->body.CollSkin.Convex = LevelModel[obj->DefaultModel].CollSkin.Convex;
00321 obj->body.CollSkin.Sphere = LevelModel[obj->DefaultModel].CollSkin.Sphere;
00322 CopyBBox(&LevelModel[obj->DefaultModel].CollSkin.TightBBox, &obj->body.CollSkin.TightBBox);
00323 CreateCopyCollSkin(&obj->body.CollSkin);
00324 BuildWorldSkin(&obj->body.CollSkin, &obj->body.Centre.Pos, &obj->body.Centre.WMatrix);
00325
00326
00327 if (firework->Target != NULL) {
00328 VecMinusVec(&firework->Target->body.Centre.Pos, &obj->body.Centre.Pos, &dR);
00329 dRLen = VecLen(&dR) / 2;
00330 speedMod = (dRLen - WEAPON_RANGE_MIN) / (WEAPON_RANGE_MAX - WEAPON_RANGE_MIN);
00331 speedMod = (speedMod * speedMod * speedMod * speedMod) / 8;
00332 } else {
00333 dRLen = WEAPON_RANGE_MAX / 3;
00334 speedMod = ONE / 4;
00335 }
00336 VecEqScalarVec(&dir, dRLen / WEAPON_RANGE_MAX, &playerMat->mv[U]);
00337 VecPlusEqScalarVec(&dir, dRLen / WEAPON_RANGE_MAX - ONE, &playerMat->mv[L]);
00338 NormalizeVec(&dir);
00339 CopyVec(&dir, &obj->body.Centre.WMatrix.mv[U]);
00340 BuildMatrixFromUp(&obj->body.Centre.WMatrix);
00341 SetBodyPos(&obj->body, &obj->body.Centre.Pos, &obj->body.Centre.WMatrix);
00342 VecPlusScalarVec(&obj->player->car.Body->Centre.Vel, 1500 * speedMod, &dir, &obj->body.Centre.Vel);
00343
00344
00345 obj->Sfx3D = CreateSfx3D(SFX_FIREWORK, SFX_MAX_VOL, 22050, TRUE, &obj->body.Centre.Pos);
00346
00347
00348 firework->Trail = GetFreeTrail(TRAIL_SMOKE);
00349 if (firework->Trail != NULL) {
00350 CopyVec(&obj->body.Centre.Pos, &firework->Trail->Pos[0]);
00351 firework->TrailTime = ZERO;
00352 }
00353
00354
00355 return TRUE;
00356 }
00357
00359
00361
00362 long InitPuttyBomb(OBJECT *obj, long *flags)
00363 {
00364 PUTTYBOMB_OBJ *bomb;
00365 PUTTYBOMB_VERT *vert;
00366 MODEL *model;
00367 long i;
00368
00369
00370
00371 obj->renderflag.envmap = FALSE;
00372 obj->renderflag.light = FALSE;
00373 obj->renderflag.reflect = FALSE;
00374 obj->renderflag.meshfx = FALSE;
00375
00376
00377
00378 obj->aihandler = (AI_HANDLER)PuttyBombHandler;
00379 obj->movehandler = (MOVE_HANDLER)PuttyBombMove;
00380 obj->renderhandler = NULL;
00381
00382
00383
00384 obj->DefaultModel = LoadOneLevelModel(LEVEL_MODEL_BOMBBALL, FALSE, obj->renderflag, 0);
00385 if (obj->DefaultModel == -1)
00386 return FALSE;
00387
00388
00389
00390 obj->player = (PLAYER*)flags[0];
00391
00392
00393
00394 obj->Data = malloc(sizeof(PUTTYBOMB_OBJ) + sizeof (PUTTYBOMB_VERT) * LevelModel[obj->DefaultModel].Model.VertNum);
00395 if (!obj->Data) return FALSE;
00396 bomb = (PUTTYBOMB_OBJ*)obj->Data;
00397
00398 bomb->Timer = PUTTYBOMB_COUNTDOWN;
00399 obj->player->car.IsBomb = TRUE;
00400 obj->player->car.WillDetonate = FALSE;
00401 obj->player->car.NoReturnTimer = PUTTYBOMB_NORETURN_TIME;
00402 bomb->OrigAerialLen = obj->player->car.Aerial.Length;
00403
00404
00405
00406 model = &LevelModel[obj->DefaultModel].Model;
00407
00408 if (model->QuadNumRGB)
00409 {
00410 model->QuadNumTex = model->QuadNumRGB;
00411 model->TriNumTex = model->TriNumRGB;
00412 model->QuadNumRGB = 0;
00413 model->TriNumRGB = 0;
00414
00415 for (i = 0 ; i < model->PolyNum ; i++)
00416 {
00417 model->PolyPtr[i].Tpage = TPAGE_FX3;
00418 model->PolyPtr[i].Type |= POLY_DOUBLE | POLY_SEMITRANS | POLY_SEMITRANS_ONE;
00419
00420 *(long*)&model->PolyRGB[i].rgb[0] = 0xffffff;
00421 *(long*)&model->PolyRGB[i].rgb[1] = 0xffffff;
00422 *(long*)&model->PolyRGB[i].rgb[2] = 0xffffff;
00423 *(long*)&model->PolyRGB[i].rgb[3] = 0xffffff;
00424 }
00425 }
00426
00427 vert = (PUTTYBOMB_VERT*)(bomb + 1);
00428 for (i = 0 ; i < LevelModel[obj->DefaultModel].Model.VertNum ; i++)
00429 {
00430 vert[i].Time = frand(RAD);
00431 vert[i].TimeAdd = frand(5.0f) + 5.0f;
00432 if (rand() & 1) vert[i].TimeAdd = -vert[i].TimeAdd;
00433 }
00434
00435
00436
00437 obj->Sfx3D = CreateSfx3D(SFX_FUSE, SFX_MAX_VOL, 22050, TRUE, &obj->player->car.Body->Centre.Pos);
00438
00439
00440
00441 return TRUE;
00442 }
00443
00445
00447
00448 long InitWaterBomb(OBJECT *obj, long *flags)
00449 {
00450 WATERBOMB_OBJ *bomb = (WATERBOMB_OBJ*)obj->Data;
00451 VEC vec;
00452
00453
00454
00455 obj->renderflag.light = FALSE;
00456
00457
00458
00459 obj->aihandler = (AI_HANDLER)WaterBombHandler;
00460 obj->collhandler = (COLL_HANDLER)COL_BodyCollHandler;
00461 obj->movehandler = (MOVE_HANDLER)MOV_MoveBody;
00462 obj->renderhandler = (RENDER_HANDLER)RenderWaterBomb;
00463
00464
00465
00466 obj->DefaultModel = LoadOneLevelModel(LEVEL_MODEL_WATERBOMB, FALSE, obj->renderflag, 0);
00467 if (obj->DefaultModel == -1) return FALSE;
00468
00469
00470
00471 obj->player = (PLAYER*)flags[0];
00472
00473
00474
00475 bomb->Age = 0.0f;
00476 bomb->BangTol = frand(WATERBOMB_BANG_VAR) + WATERBOMB_BANG_MIN;
00477
00478
00479
00480 RotTransVector(&obj->body.Centre.WMatrix, &obj->body.Centre.Pos, &obj->player->car.WeaponOffset, &obj->body.Centre.Pos);
00481 RotVector(&obj->body.Centre.WMatrix, &WaterBombVel, &vec);
00482
00483 SetVector(&obj->body.Centre.Vel, vec.v[X] + obj->player->car.Body->Centre.Vel.v[X], vec.v[Y], vec.v[Z] + obj->player->car.Body->Centre.Vel.v[Z]);
00484
00485 VecEqScalarVec(&obj->body.AngVel, -15.0f, &obj->body.Centre.WMatrix.mv[R]);
00486
00487
00488
00489 obj->Sfx3D = CreateSfx3D(SFX_WATERBOMB, SFX_MAX_VOL, 22050, TRUE, &obj->body.Centre.Pos);
00490
00491
00492
00493 obj->body.Centre.Mass = Real(0.6f);
00494 obj->body.Centre.InvMass = ONE / Real(0.6f);
00495 SetMat(&obj->body.BodyInertia, Real(100), ZERO, ZERO, ZERO, Real(100), ZERO, ZERO, ZERO, Real(100));
00496 SetMat(&obj->body.BodyInvInertia, ONE / Real(100), ZERO, ZERO, ZERO, ONE / Real(100), ZERO, ZERO, ZERO, ONE / Real(100));
00497
00498 obj->body.Centre.Hardness = Real(0.2);
00499 obj->body.Centre.Resistance = Real(0.001);
00500 obj->body.DefaultAngRes = Real(0.005);
00501 obj->body.AngResistance = Real(0.005);
00502 obj->body.AngResMod = Real(1.0);
00503 obj->body.Centre.Grip = Real(0.02);
00504 obj->body.Centre.StaticFriction = Real(2.0);
00505 obj->body.Centre.KineticFriction = Real(1.5);
00506
00507
00508
00509 obj->CollType = COLL_TYPE_BODY;
00510 SetBodySphere(&obj->body);
00511 obj->body.CollSkin.Sphere = (SPHERE *)malloc(sizeof(SPHERE));
00512 CopyVec(&WaterBombOff, &obj->body.CollSkin.Sphere[0].Pos);
00513 obj->body.CollSkin.Sphere[0].Radius = WATERBOMB_RADIUS;
00514 obj->body.CollSkin.NSpheres = 1;
00515 CreateCopyCollSkin(&obj->body.CollSkin);
00516 MakeTightLocalBBox(&obj->body.CollSkin);
00517 BuildWorldSkin(&obj->body.CollSkin, &obj->body.Centre.Pos, &obj->body.Centre.WMatrix);
00518
00519
00520
00521 return TRUE;
00522 }
00523
00525
00527
00528 long InitElectroPulse(OBJECT *obj, long *flags)
00529 {
00530 long i, ram, off;
00531 REAL mul;
00532 ELECTROPULSE_OBJ *electro;
00533 MODEL *smodel, *dmodel;
00534 ELECTROPULSE_VERT *evert;
00535
00536
00537
00538 obj->renderflag.envmap = FALSE;
00539 obj->renderflag.light = FALSE;
00540 obj->renderflag.reflect = FALSE;
00541 obj->renderflag.meshfx = FALSE;
00542
00543
00544
00545 obj->aihandler = (AI_HANDLER)ElectroPulseHandler;
00546 obj->renderhandler = (RENDER_HANDLER)RenderElectroPulse;
00547
00548
00549
00550 obj->player = (PLAYER*)flags[0];
00551
00552
00553
00554 smodel = &obj->player->car.Models->Body[0];
00555
00556 ram = sizeof(ELECTROPULSE_OBJ);
00557 ram += sizeof(MODEL_POLY) * smodel->PolyNum;
00558 ram += sizeof(POLY_RGB) * smodel->PolyNum;
00559 ram += sizeof(MODEL_VERTEX) * smodel->VertNum;
00560 ram += sizeof(ELECTROPULSE_VERT) * smodel->VertNum;
00561
00562 obj->Data = malloc(ram);
00563 if (!obj->Data)
00564 return FALSE;
00565
00566
00567
00568 electro = (ELECTROPULSE_OBJ*)obj->Data;
00569 electro->Age = 0.0f;
00570 electro->JumpFlag = 0;
00571
00572
00573
00574 dmodel = &electro->Model;
00575
00576 memcpy(dmodel, smodel, sizeof(MODEL));
00577 dmodel->PolyPtr = (MODEL_POLY*)(electro + 1);
00578 dmodel->PolyRGB = (POLY_RGB*)(dmodel->PolyPtr + dmodel->PolyNum);
00579 dmodel->VertPtr = (MODEL_VERTEX*)(dmodel->PolyRGB + dmodel->PolyNum);
00580
00581 off = (long)dmodel->VertPtr - (long)smodel->VertPtr;
00582
00583 for (i = 0 ; i < dmodel->PolyNum ; i++)
00584 {
00585 dmodel->PolyPtr[i] = smodel->PolyPtr[i];
00586
00587 dmodel->PolyPtr[i].Type |= POLY_SEMITRANS | POLY_SEMITRANS_ONE;
00588 dmodel->PolyPtr[i].Tpage = TPAGE_FX1;
00589
00590 dmodel->PolyPtr[i].v0 = (MODEL_VERTEX*)((long)dmodel->PolyPtr[i].v0 + off);
00591 dmodel->PolyPtr[i].v1 = (MODEL_VERTEX*)((long)dmodel->PolyPtr[i].v1 + off);
00592 dmodel->PolyPtr[i].v2 = (MODEL_VERTEX*)((long)dmodel->PolyPtr[i].v2 + off);
00593 dmodel->PolyPtr[i].v3 = (MODEL_VERTEX*)((long)dmodel->PolyPtr[i].v3 + off);
00594
00595 *(long*)&dmodel->PolyRGB[i].rgb[0] = 0;
00596 *(long*)&dmodel->PolyRGB[i].rgb[1] = 0;
00597 *(long*)&dmodel->PolyRGB[i].rgb[2] = 0;
00598 *(long*)&dmodel->PolyRGB[i].rgb[3] = 0;
00599 }
00600
00601 for (i = 0 ; i < dmodel->VertNum ; i++)
00602 {
00603 dmodel->VertPtr[i] = smodel->VertPtr[i];
00604
00605 mul = 2.0f / Length((VEC*)&dmodel->VertPtr[i].x) + 1.0f;
00606 dmodel->VertPtr[i].x *= mul;
00607 dmodel->VertPtr[i].y *= mul;
00608 dmodel->VertPtr[i].z *= mul;
00609 }
00610
00611
00612
00613 evert = (ELECTROPULSE_VERT*)(dmodel->VertPtr + dmodel->VertNum);
00614 for (i = 0 ; i < dmodel->VertNum ; i++)
00615 {
00616 evert[i].Time = frand(RAD);
00617 evert[i].TimeAdd = frand(5.0f) + 1.0f;
00618 if (rand() & 1) evert[i].TimeAdd = -evert[i].TimeAdd;
00619 }
00620
00621
00622
00623 obj->Light = AllocLight();
00624 if (obj->Light)
00625 {
00626 obj->Light->Reach = 768;
00627 obj->Light->Flag = LIGHT_FIXED | LIGHT_MOVING;
00628 obj->Light->Type = LIGHT_OMNI;
00629 obj->Light->r = 0;
00630 obj->Light->g = 0;
00631 obj->Light->b = 0;
00632 }
00633
00634
00635
00636 obj->Sfx3D = CreateSfx3D(SFX_ELECTROPULSE, SFX_MAX_VOL, 22050, TRUE, &obj->body.Centre.Pos);
00637
00638
00639
00640 return TRUE;
00641 }
00642 #endif
00643
00645
00647
00648 long InitOilSlick(OBJECT *obj, long *flags)
00649 {
00650 OILSLICK_OBJ *oil = (OILSLICK_OBJ*)obj->Data;
00651 CAR *car;
00652 REAL time;
00653 VEC vec;
00654
00655
00656
00657 obj->aihandler = (AI_HANDLER)OilSlickHandler;
00658 #ifdef _PC
00659 obj->renderhandler = (RENDER_HANDLER)RenderOilSlick;
00660 #endif
00661 #ifdef _N64
00662 obj->renderhandler = NULL;
00663 #endif
00664
00665
00666
00667 obj->player = (PLAYER*)flags[0];
00668
00669
00670
00671 car = &obj->player->car;
00672
00673 oil->Mode = 0;
00674 oil->Age = 0.0f;
00675
00676 CopyVec(&car->Body->Centre.Pos, &obj->body.Centre.Pos);
00677
00678 SetVector(&obj->body.Centre.Vel, 0, 0, 0);
00679
00680 SetVector(&vec, obj->body.Centre.Pos.v[X], obj->body.Centre.Pos.v[Y] + 1000.0f, obj->body.Centre.Pos.v[Z]);
00681 LineOfSightDist(&obj->body.Centre.Pos, &vec, &time, NULL);
00682 if (time > 0.0f && time < 1.0f)
00683 oil->LandHeight = obj->body.Centre.Pos.v[Y] + time * 1000.0f;
00684 else
00685 oil->LandHeight = vec.v[Y];
00686
00687 oil->MaxSize = (REAL)flags[1];
00688
00689
00690
00691 return TRUE;
00692 }
00693
00695
00697
00698 long InitOilSlickDropper(OBJECT *obj, long *flags)
00699 {
00700 OILSLICK_DROPPER_OBJ *dropper = (OILSLICK_DROPPER_OBJ*)obj->Data;
00701
00702
00703
00704 obj->aihandler = (AI_HANDLER)OilSlickDropperHandler;
00705
00706
00707
00708 obj->player = (PLAYER*)flags[0];
00709
00710
00711
00712 dropper->Count = 0;
00713 dropper->Age = 0;
00714
00715 CopyVec(&obj->body.Centre.Pos, &dropper->LastPos);
00716
00717
00718
00719 return TRUE;
00720 }
00721
00722 #ifdef _PC
00724 // init weapon //
00726
00727 long InitChromeBall(OBJECT *obj, long *flags)
00728 {
00729 CHROMEBALL_OBJ *ball = (CHROMEBALL_OBJ*)obj->Data;
00730 MODEL *model;
00731 long i, col;
00732
00733
00734
00735 obj->aihandler = (AI_HANDLER)ChromeBallHandler;
00736 obj->movehandler = (MOVE_HANDLER)MOV_MoveBody;
00737 obj->collhandler = (COLL_HANDLER)COL_BodyCollHandler;
00738 obj->renderhandler = (RENDER_HANDLER)RenderChromeBall;
00739
00740
00741
00742 obj->DefaultModel = LoadOneLevelModel(LEVEL_MODEL_CHROMEBALL, FALSE, obj->renderflag, 0);
00743 if (obj->DefaultModel == -1) return FALSE;
00744
00745
00746
00747 obj->player = (PLAYER*)flags[0];
00748
00749
00750
00751 ball->Age = 0.0f;
00752 ball->Radius = CHROMEBALL_MIN_RAD;
00753
00754
00755
00756 VecPlusScalarVec(&obj->player->car.BodyWorldPos, -70.0f, &obj->player->car.Body->Centre.WMatrix.mv[L], &obj->body.Centre.Pos);
00757 VecPlusScalarVec(&obj->player->car.Body->Centre.Vel, -512.0f, &obj->player->car.Body->Centre.WMatrix.mv[L], &obj->body.Centre.Vel);
00758
00759
00760
00761 obj->Sfx3D = CreateSfx3D(SFX_CHROMEBALL, SFX_MIN_VOL, 22050, TRUE, &obj->body.Centre.Pos);
00762
00763
00764
00765 obj->body.Centre.Mass = Real(3.0f);
00766 obj->body.Centre.InvMass = ONE / Real(3.0f);
00767 SetMat(&obj->body.BodyInertia, Real(100), ZERO, ZERO, ZERO, Real(100), ZERO, ZERO, ZERO, Real(100));
00768 SetMat(&obj->body.BodyInvInertia, ONE / Real(100), ZERO, ZERO, ZERO, ONE / Real(100), ZERO, ZERO, ZERO, ONE / Real(100));
00769
00770 obj->body.Centre.Hardness = Real(0.2);
00771 obj->body.Centre.Resistance = Real(0.001);
00772 obj->body.DefaultAngRes = Real(0.005);
00773 obj->body.AngResistance = Real(0.005);
00774 obj->body.AngResMod = Real(1.0);
00775 obj->body.Centre.Grip = Real(0.1);
00776 obj->body.Centre.StaticFriction = Real(2.0);
00777 obj->body.Centre.KineticFriction = Real(1.0);
00778
00779
00780
00781 obj->CollType = COLL_TYPE_BODY;
00782 SetBodySphere(&obj->body);
00783 obj->body.CollSkin.Sphere = (SPHERE *)malloc(sizeof(SPHERE));
00784 SetVecZero(&obj->body.CollSkin.Sphere[0].Pos);
00785 obj->body.CollSkin.Sphere[0].Radius = CHROMEBALL_MAX_RAD;
00786 obj->body.CollSkin.NSpheres = 1;
00787 CreateCopyCollSkin(&obj->body.CollSkin);
00788 MakeTightLocalBBox(&obj->body.CollSkin);
00789 BuildWorldSkin(&obj->body.CollSkin, &obj->body.Centre.Pos, &obj->body.Centre.WMatrix);
00790 obj->body.CollSkin.WorldSphere[0].Radius = CHROMEBALL_MIN_RAD;
00791
00792
00793
00794 model = &LevelModel[obj->DefaultModel].Model;
00795 if (model->QuadNumRGB)
00796 {
00797 model->QuadNumTex = model->QuadNumRGB;
00798 model->TriNumTex = model->TriNumRGB;
00799 model->QuadNumRGB = 0;
00800 model->TriNumRGB = 0;
00801
00802 for (i = 0 ; i < model->VertNum ; i++)
00803 {
00804 col = (rand() & 63) + 32;
00805 model->VertPtr[i].color = col | col << 8 | col << 16;
00806 }
00807
00808 for (i = 0 ; i < model->PolyNum ; i++)
00809 {
00810 model->PolyPtr[i].Tpage = TPAGE_FX1;
00811 model->PolyPtr[i].tu0 = model->PolyPtr[i].tu3 = 242.0f / 256.0f;
00812 model->PolyPtr[i].tu1 = model->PolyPtr[i].tu2 = 254.0f / 256.0f;
00813 model->PolyPtr[i].tv0 = model->PolyPtr[i].tv1 = 242.0f / 256.0f;
00814 model->PolyPtr[i].tv2 = model->PolyPtr[i].tv3 = 254.0f / 256.0f;
00815
00816 *(long*)&model->PolyRGB[i].rgb[0] = model->PolyPtr[i].v0->color;
00817 *(long*)&model->PolyRGB[i].rgb[1] = model->PolyPtr[i].v1->color;
00818 *(long*)&model->PolyRGB[i].rgb[2] = model->PolyPtr[i].v2->color;
00819
00820 if (model->PolyPtr[i].Type & POLY_QUAD)
00821 *(long*)&model->PolyRGB[i].rgb[3] = model->PolyPtr[i].v3->color;
00822 }
00823 }
00824
00825
00826
00827 return TRUE;
00828 }
00829
00831
00833
00834 long InitClone(OBJECT *obj, long *flags)
00835 {
00836 CLONE_OBJ *clone = (CLONE_OBJ*)obj->Data;
00837
00838
00839
00840 return TRUE;
00841 }
00842
00844
00846
00847 long InitTurbo(OBJECT *obj, long *flags)
00848 {
00849
00850 TURBO_OBJ *turbo = (TURBO_OBJ*)obj->Data;
00851
00852
00853
00854 obj->aihandler = (AI_HANDLER)Turbo2Handler;
00855 obj->movehandler = (MOVE_HANDLER)TurboMoveHandler;
00856
00857
00858
00859 obj->player = (PLAYER*)flags[0];
00860
00861
00862
00863 turbo->Age = turbo->SparkTime = ZERO;
00864 turbo->LifeTime = TO_TIME(Real(3));
00865 turbo->Force = TO_FORCE(Real(3500));
00866
00867
00868
00869
00870
00871
00872
00873
00874
00875
00876
00877 return TRUE;
00878 }
00879
00881
00883
00884 long InitTurbo2(OBJECT *obj, long *flags)
00885 {
00886 TURBO2_OBJ *turbo = (TURBO2_OBJ*)obj->Data;
00887
00888
00889
00890 obj->aihandler = (AI_HANDLER)Turbo2Handler;
00891
00892
00893
00894 obj->player = (PLAYER*)flags[0];
00895
00896
00897
00898 turbo->Age = 0.0f;
00899 turbo->LifeTime = 3.0f;
00900
00901
00902
00903 return TRUE;
00904 }
00905
00907
00909
00910 long InitSpring(OBJECT *obj, long *flags)
00911 {
00912 SPRING_OBJ *spring = (SPRING_OBJ*)obj->Data;
00913
00914
00915
00916 obj->player = (PLAYER*)flags[0];
00917
00918
00919
00920 obj->aihandler = (AI_HANDLER)SpringHandler;
00921
00922
00923
00924 return TRUE;
00925 }
00926
00928
00930
00931 long InitElectroZapped(OBJECT *obj, long *flags)
00932 {
00933 long i, ram, off;
00934 REAL mul;
00935 ELECTROZAPPED_OBJ *electro;
00936 MODEL *smodel, *dmodel;
00937 ELECTROZAPPED_VERT *evert;
00938
00939
00940
00941 obj->renderflag.envmap = FALSE;
00942 obj->renderflag.light = FALSE;
00943 obj->renderflag.reflect = FALSE;
00944 obj->renderflag.meshfx = FALSE;
00945
00946
00947
00948 obj->aihandler = (AI_HANDLER)ElectroZappedHandler;
00949 obj->renderhandler = (RENDER_HANDLER)RenderElectroZapped;
00950
00951
00952
00953 obj->player = (PLAYER*)flags[0];
00954
00955
00956
00957 smodel = &obj->player->car.Models->Body[0];
00958
00959 ram = sizeof(ELECTROZAPPED_OBJ);
00960 ram += sizeof(MODEL_POLY) * smodel->PolyNum;
00961 ram += sizeof(POLY_RGB) * smodel->PolyNum;
00962 ram += sizeof(MODEL_VERTEX) * smodel->VertNum;
00963 ram += sizeof(ELECTROZAPPED_VERT) * smodel->VertNum;
00964
00965 obj->Data = malloc(ram);
00966 if (!obj->Data)
00967 return FALSE;
00968
00969
00970
00971 electro = (ELECTROZAPPED_OBJ*)obj->Data;
00972
00973
00974
00975 dmodel = &electro->Model;
00976
00977 memcpy(dmodel, smodel, sizeof(MODEL));
00978 dmodel->PolyPtr = (MODEL_POLY*)(electro + 1);
00979 dmodel->PolyRGB = (POLY_RGB*)(dmodel->PolyPtr + dmodel->PolyNum);
00980 dmodel->VertPtr = (MODEL_VERTEX*)(dmodel->PolyRGB + dmodel->PolyNum);
00981
00982 off = (long)dmodel->VertPtr - (long)smodel->VertPtr;
00983
00984 for (i = 0 ; i < dmodel->PolyNum ; i++)
00985 {
00986 dmodel->PolyPtr[i] = smodel->PolyPtr[i];
00987
00988 dmodel->PolyPtr[i].Type |= POLY_SEMITRANS | POLY_SEMITRANS_ONE;
00989 dmodel->PolyPtr[i].Tpage = TPAGE_FX1;
00990
00991 dmodel->PolyPtr[i].v0 = (MODEL_VERTEX*)((long)dmodel->PolyPtr[i].v0 + off);
00992 dmodel->PolyPtr[i].v1 = (MODEL_VERTEX*)((long)dmodel->PolyPtr[i].v1 + off);
00993 dmodel->PolyPtr[i].v2 = (MODEL_VERTEX*)((long)dmodel->PolyPtr[i].v2 + off);
00994 dmodel->PolyPtr[i].v3 = (MODEL_VERTEX*)((long)dmodel->PolyPtr[i].v3 + off);
00995
00996 *(long*)&dmodel->PolyRGB[i].rgb[0] = 0;
00997 *(long*)&dmodel->PolyRGB[i].rgb[1] = 0;
00998 *(long*)&dmodel->PolyRGB[i].rgb[2] = 0;
00999 *(long*)&dmodel->PolyRGB[i].rgb[3] = 0;
01000 }
01001
01002 for (i = 0 ; i < dmodel->VertNum ; i++)
01003 {
01004 dmodel->VertPtr[i] = smodel->VertPtr[i];
01005
01006 mul = 2.0f / Length((VEC*)&dmodel->VertPtr[i].x) + 1.0f;
01007 dmodel->VertPtr[i].x *= mul;
01008 dmodel->VertPtr[i].y *= mul;
01009 dmodel->VertPtr[i].z *= mul;
01010 }
01011
01012
01013
01014 evert = (ELECTROZAPPED_VERT*)(dmodel->VertPtr + dmodel->VertNum);
01015 for (i = 0 ; i < dmodel->VertNum ; i++)
01016 {
01017 evert[i].Time = frand(RAD);
01018 evert[i].TimeAdd = frand(5.0f) + 1.0f;
01019 if (rand() & 1) evert[i].TimeAdd = -evert[i].TimeAdd;
01020 }
01021
01022
01023
01024 return TRUE;
01025 }
01026
01028
01030
01031 long InitBombGlow(OBJECT *obj, long *flags)
01032 {
01033 long i, ram, off;
01034 REAL mul;
01035 BOMBGLOW_OBJ *glow;
01036 MODEL *smodel, *dmodel;
01037 BOMBGLOW_VERT *gvert;
01038
01039
01040
01041 obj->renderflag.envmap = FALSE;
01042 obj->renderflag.light = FALSE;
01043 obj->renderflag.reflect = FALSE;
01044 obj->renderflag.meshfx = FALSE;
01045
01046
01047
01048 obj->aihandler = (AI_HANDLER)BombGlowHandler;
01049 obj->renderhandler = (RENDER_HANDLER)RenderBombGlow;
01050
01051
01052
01053 obj->player = (PLAYER*)flags[0];
01054
01055
01056
01057 smodel = &obj->player->car.Models->Body[0];
01058
01059 ram = sizeof(BOMBGLOW_OBJ);
01060 ram += sizeof(MODEL_POLY) * smodel->PolyNum;
01061 ram += sizeof(POLY_RGB) * smodel->PolyNum;
01062 ram += sizeof(MODEL_VERTEX) * smodel->VertNum;
01063 ram += sizeof(BOMBGLOW_VERT) * smodel->VertNum;
01064
01065 obj->Data = malloc(ram);
01066 if (!obj->Data)
01067 return FALSE;
01068
01069
01070
01071 glow = (BOMBGLOW_OBJ*)obj->Data;
01072 glow->Timer = 0.0f;
01073
01074
01075
01076 dmodel = &glow->Model;
01077
01078 memcpy(dmodel, smodel, sizeof(MODEL));
01079 dmodel->PolyPtr = (MODEL_POLY*)(glow + 1);
01080 dmodel->PolyRGB = (POLY_RGB*)(dmodel->PolyPtr + dmodel->PolyNum);
01081 dmodel->VertPtr = (MODEL_VERTEX*)(dmodel->PolyRGB + dmodel->PolyNum);
01082
01083 off = (long)dmodel->VertPtr - (long)smodel->VertPtr;
01084
01085 for (i = 0 ; i < dmodel->PolyNum ; i++)
01086 {
01087 dmodel->PolyPtr[i] = smodel->PolyPtr[i];
01088
01089 dmodel->PolyPtr[i].Type |= POLY_SEMITRANS | POLY_SEMITRANS_ONE;
01090 dmodel->PolyPtr[i].Tpage = TPAGE_FX3;
01091
01092 dmodel->PolyPtr[i].v0 = (MODEL_VERTEX*)((long)dmodel->PolyPtr[i].v0 + off);
01093 dmodel->PolyPtr[i].v1 = (MODEL_VERTEX*)((long)dmodel->PolyPtr[i].v1 + off);
01094 dmodel->PolyPtr[i].v2 = (MODEL_VERTEX*)((long)dmodel->PolyPtr[i].v2 + off);
01095 dmodel->PolyPtr[i].v3 = (MODEL_VERTEX*)((long)dmodel->PolyPtr[i].v3 + off);
01096
01097 *(long*)&dmodel->PolyRGB[i].rgb[0] = 0;
01098 *(long*)&dmodel->PolyRGB[i].rgb[1] = 0;
01099 *(long*)&dmodel->PolyRGB[i].rgb[2] = 0;
01100 *(long*)&dmodel->PolyRGB[i].rgb[3] = 0;
01101 }
01102
01103 for (i = 0 ; i < dmodel->VertNum ; i++)
01104 {
01105 dmodel->VertPtr[i] = smodel->VertPtr[i];
01106
01107 mul = 2.0f / Length((VEC*)&dmodel->VertPtr[i].x) + 1.0f;
01108 dmodel->VertPtr[i].x *= mul;
01109 dmodel->VertPtr[i].y *= mul;
01110 dmodel->VertPtr[i].z *= mul;
01111 }
01112
01113
01114
01115 gvert = (BOMBGLOW_VERT*)(dmodel->VertPtr + dmodel->VertNum);
01116 for (i = 0 ; i < dmodel->VertNum ; i++)
01117 {
01118 gvert[i].Time = frand(RAD);
01119 gvert[i].TimeAdd = frand(5.0f) + 1.0f;
01120 if (rand() & 1) gvert[i].TimeAdd = -gvert[i].TimeAdd;
01121 }
01122
01123
01124
01125 return TRUE;
01126 }
01127
01129
01131
01132 void ShockwaveHandler(OBJECT *obj)
01133 {
01134 SHOCKWAVE_OBJ *shockwave = (SHOCKWAVE_OBJ*)obj->Data;
01135 VEC vec, vec2, vec3, vec4;
01136 REAL mul;
01137 long i, count;
01138
01139
01140
01141 if (shockwave->Alive)
01142 {
01143
01144
01145
01146 shockwave->Age += TimeStep;
01147
01148
01149
01150 FTOL(TimeStep * 200.0f, count);
01151 CopyVec(&obj->body.Centre.Pos, &vec3);
01152 VecEqScalarVec(&vec4, 1.0f / 200.0f, &obj->body.Centre.Vel);
01153
01154 for (i = 0 ; i < count ; i++)
01155 {
01156 SetVector(&vec, frand(1.0f) - 0.5f, frand(1.0f) - 0.5f, 0.0f);
01157 mul = 64.0f / Length(&vec);
01158 VecMulScalar(&vec, mul);
01159 RotVector(&obj->body.Centre.WMatrix, &vec, &vec2);
01160 VecPlusScalarVec(&vec3, 0.1f, &vec2, &vec);
01161 CreateSpark(SPARK_BLUE, &vec, &vec2, 0.0f, 0);
01162
01163 AddVector(&vec3, &vec4, &vec3);
01164 }
01165
01166
01167
01168 if (obj->Light)
01169 {
01170 obj->Light->x = obj->body.Centre.Pos.v[X];
01171 obj->Light->y = obj->body.Centre.Pos.v[Y];
01172 obj->Light->z = obj->body.Centre.Pos.v[Z];
01173 }
01174
01175
01176
01177 if (obj->Sfx3D)
01178 {
01179 CopyVec(&obj->body.Centre.Pos, &obj->Sfx3D->Pos);
01180 }
01181
01182
01183
01184 if (shockwave->Age > 0.25f)
01185 {
01186 SubVector(&obj->body.Centre.Pos, &shockwave->OldPos, &vec);
01187 if (Length(&vec) / TimeStep < SHOCKWAVE_MIN_VEL)
01188 shockwave->Age = SHOCKWAVE_MAX_AGE;
01189 }
01190
01191 CopyVec(&obj->body.Centre.Pos, &shockwave->OldPos);
01192
01193
01194
01195 if (shockwave->Age >= SHOCKWAVE_MAX_AGE)
01196 {
01197 shockwave->Alive = FALSE;
01198
01199 if (obj->Sfx3D)
01200 FreeSfx3D(obj->Sfx3D);
01201
01202 if (obj->Field)
01203 {
01204 RemoveField(obj->Field);
01205 obj->Field = NULL;
01206 }
01207
01208 for (i = 0 ; i < 128 ; i++)
01209 {
01210 SetVector(&vec, frand(2.0f) - 1.0f, -frand(3.0f), frand(2.0f) - 1.0f);
01211 mul = (frand(512.0f) + 512.0f) / Length(&vec);
01212 VecMulScalar(&vec, mul);
01213 CreateSpark(SPARK_BIGBLUE, &obj->body.Centre.Pos, &vec, 0.0f, 0);
01214 }
01215 }
01216 }
01217
01218
01219
01220 else
01221 {
01222 shockwave->Reach -= TimeStep * 4096;
01223 if (shockwave->Reach < 0)
01224 {
01225 OBJ_FreeObject(obj);
01226 return;
01227 }
01228
01229 if (obj->Light)
01230 {
01231 FTOL(shockwave->Reach / 8.0f, obj->Light->b);
01232 }
01233 }
01234
01235
01236
01237 SetBBox(&shockwave->Box,
01238 obj->body.Centre.Pos.v[X] - shockwave->Reach,
01239 obj->body.Centre.Pos.v[X] + shockwave->Reach,
01240 obj->body.Centre.Pos.v[Y] - shockwave->Reach,
01241 obj->body.Centre.Pos.v[Y] + shockwave->Reach,
01242 obj->body.Centre.Pos.v[Z] - shockwave->Reach,
01243 obj->body.Centre.Pos.v[Z] + shockwave->Reach);
01244
01245 AddWorldMeshFx(ShockwaveWorldMeshFxChecker, obj);
01246 AddModelMeshFx(ShockwaveModelMeshFxChecker, obj);
01247 }
01248
01250
01252
01253 void FireworkHandler(OBJECT *obj)
01254 {
01255 FIREWORK_OBJ *firework = (FIREWORK_OBJ *)obj->Data;
01256
01257
01258 if (obj->Sfx3D)
01259 {
01260 CopyVec(&obj->body.Centre.Pos, &obj->Sfx3D->Pos);
01261 }
01262
01263
01264 firework->Age += TimeStep;
01265
01266
01267 if (firework->Age < MAX_FIREWORK_AGE) {
01268
01269 FireWorkMove(obj);
01270 } else {
01271 if (!firework->Exploded) {
01272
01273 FireworkExplode(obj);
01274 } else {
01275
01276 if ((obj->Light != NULL) && (firework->Age < MAX_FIREWORK_AGE + 0.8)) {
01277 obj->Light->r = 128 + (long)(frand(32)) - (long)((128 * (firework->Age - MAX_FIREWORK_AGE)) / 0.8);
01278 obj->Light->g = 32 - (long)((32 * (firework->Age - MAX_FIREWORK_AGE)) / 0.8);
01279 obj->Light->b = 64 - (long)((64 * (firework->Age - MAX_FIREWORK_AGE)) / 0.8);
01280 } else {
01281
01282 OBJ_FreeObject(obj);
01283 }
01284 }
01285 }
01286
01287 }
01288
01289 void FireWorkMove(OBJECT *obj)
01290 {
01291 REAL dRLen, impMod;
01292 VEC dR, imp, offset;
01293
01294 FIREWORK_OBJ *firework = (FIREWORK_OBJ *)obj->Data;
01295
01296
01297 if (firework->Target != NULL) {
01298 VecMinusVec(&firework->Target->body.Centre.Pos, &obj->body.Centre.Pos, &dR);
01299 dRLen = VecLen(&dR);
01300 if (dRLen > SMALL_REAL) {
01301 VecDivScalar(&dR, dRLen / 2.5f);
01302 } else {
01303 firework->Age = MAX_FIREWORK_AGE;
01304 return;
01305 }
01306 } else {
01307 CopyVec(&DownVec, &dR);
01308 dRLen = WEAPON_RANGE_MAX;
01309 }
01310
01311
01312 impMod = ONE;
01313 VecEqScalarVec(&imp, -0.5f * impMod * FLD_Gravity * TimeStep, &obj->body.Centre.WMatrix.mv[U]);
01314 ApplyParticleImpulse(&obj->body.Centre, &imp);
01315
01316 VecEqScalarVec(&imp, -0.005f * FLD_Gravity * TimeStep, &dR);
01317 VecEqScalarVec(&offset, 50, &obj->body.Centre.WMatrix.mv[U]);
01318 ApplyBodyImpulse(&obj->body, &imp, &offset);
01319
01320
01321
01322
01323
01324
01325
01326
01327 UpdateBody(&obj->body, TimeStep);
01328
01329
01330
01331
01332
01333
01334 firework->SparkTime += TimeStep;
01335 if (firework->SparkTime > 0.005 && frand(ONE) < HALF) {
01336 CreateSpark(SPARK_SPARK, &obj->body.Centre.Pos, &ZeroVector, 80, 0);
01337 firework->SparkTime = ZERO;
01338 }
01339
01340
01341 if (firework->Trail != NULL) {
01342 firework->TrailTime += TimeStep;
01343 if (firework->TrailTime > firework->Trail->Data->LifeTime / firework->Trail->MaxTrails) {
01344 UpdateTrail(firework->Trail, &obj->body.Centre.Pos);
01345 firework->TrailTime = ZERO;
01346 } else {
01347 ModifyFirstTrail(firework->Trail, &obj->body.Centre.Pos);
01348 }
01349
01350 }
01351
01352
01353 }
01354
01355 void FireworkExplode(OBJECT *obj)
01356 {
01357 int iFlash;
01358 VEC vel;
01359 FIREWORK_OBJ *firework = (FIREWORK_OBJ *)obj->Data;
01360
01361
01362 #ifdef _PC
01363 if (obj->Sfx3D)
01364 {
01365 FreeSfx3D(obj->Sfx3D);
01366 }
01367 #endif
01368 obj->DefaultModel = -1;
01369 obj->renderhandler = NULL;
01370
01371
01372 if (firework->Trail != NULL) {
01373 FreeTrail(firework->Trail);
01374 }
01375
01376
01377 PlaySfx3D(SFX_FIREWORK_BANG, SFX_MAX_VOL, 22050, &obj->body.Centre.Pos);
01378
01379
01380 CreateSpark(SPARK_EXPLOSION1, &obj->body.Centre.Pos, &ZeroVector, 0, 0);
01381
01382
01383 VecEqScalarVec(&vel, 60, &UpVec);
01384 for (iFlash = 0; iFlash < 3; iFlash++) {
01385 CreateSpark(SPARK_SMOKE2, &obj->body.Centre.Pos, &vel, 60, 0);
01386 }
01387
01388
01389
01390 VecEqScalarVec(&vel, 300, &UpVec);
01391 for (iFlash = 0; iFlash < 30; iFlash++) {
01392 CreateSpark(SPARK_SMALLORANGE, &obj->body.Centre.Pos, &vel, 600, 0);
01393 CreateSpark(SPARK_SMALLRED, &obj->body.Centre.Pos, &vel, 800, 0);
01394 }
01395
01396
01397 obj->Light = AllocLight();
01398 if (obj->Light)
01399 {
01400 obj->Light->Reach = 1024;
01401 obj->Light->Flag = LIGHT_FIXED;
01402 obj->Light->Type = LIGHT_OMNI;
01403 obj->Light->r = 128;
01404 obj->Light->g = 32;
01405 obj->Light->b = 64;
01406 obj->Light->x = obj->body.Centre.Pos.v[X];
01407 obj->Light->y = obj->body.Centre.Pos.v[Y];
01408 obj->Light->z = obj->body.Centre.Pos.v[Z];
01409 }
01410
01411 firework->Exploded = TRUE;
01412 }
01413
01415
01417
01418 void PuttyBombHandler(OBJECT *obj)
01419 {
01420 PUTTYBOMB_OBJ *bomb = (PUTTYBOMB_OBJ*)obj->Data;
01421 long i, j, k, vcount, per, sides, flag;
01422 VEC vec, off, imp, *pos;
01423 MAT mat;
01424 REAL dx, dy, dz, dist, len, rot, mul, mass;
01425 BBOX box;
01426 CUBE_HEADER *cube;
01427 WORLD_POLY *wp;
01428 WORLD_VERTEX **wv;
01429 long *wrgb;
01430 MODEL_RGB *mrgb;
01431 NEWCOLLPOLY *p;
01432 COLLGRID *header;
01433
01434
01435
01436 obj->player->car.AddLit -= (long)(TimeStep * 2000);
01437 if (obj->player->car.AddLit < -1000) obj->player->car.AddLit = -1000;
01438
01439
01440
01441 if (obj->Sfx3D)
01442 {
01443 CopyVec(&obj->player->car.Body->Centre.Pos, &obj->Sfx3D->Pos);
01444 }
01445
01446
01447
01448 bomb->Timer -= TimeStep;
01449 if (obj->player->car.WillDetonate == FALSE){
01450
01451 if (bomb->Timer < ZERO)
01452 {
01453
01454 obj->player->car.WillDetonate = TRUE;
01455 bomb->Timer = PUTTYBOMB_COUNTDOWN2;
01456 if (obj->Sfx3D)
01457 {
01458 FreeSfx3D(obj->Sfx3D);
01459 obj->Sfx3D = NULL;
01460 }
01461 flag = (long)obj->player;
01462 CreateObject(&obj->player->car.Body->Centre.Pos, &obj->player->car.Body->Centre.WMatrix, OBJECT_TYPE_BOMBGLOW, &flag);
01463 }
01464 else
01465 {
01466
01467 obj->player->car.Aerial.Length = bomb->OrigAerialLen * bomb->Timer / PUTTYBOMB_COUNTDOWN;
01468
01469
01470 CreateSpark(SPARK_SPARK2, &obj->player->car.Aerial.Section[AERIAL_LASTSECTION].Pos, &obj->player->car.Body->Centre.Vel, 50, 0);
01471 CreateSpark(SPARK_SPARK2, &obj->player->car.Aerial.Section[AERIAL_LASTSECTION].Pos, &obj->player->car.Body->Centre.Vel, 50, 0);
01472 }
01473 }
01474 else if (bomb->Timer <= 0.0f)
01475 {
01476
01477
01478
01479 CopyVec(&obj->player->car.Body->Centre.Pos, &bomb->Pos);
01480
01481 bomb->Timer = 0.0f;
01482 bomb->SphereRadius = 80.0f;
01483
01484 SubVector(&bomb->Pos, &CAM_MainCamera->WPos, &vec);
01485 CAM_MainCamera->Shake = 1.0f - (Length(&vec) / 2048.0f);
01486 if (CAM_MainCamera->Shake < 0.0f) CAM_MainCamera->Shake = 0.0f;
01487
01488 obj->aihandler = (AI_HANDLER)PuttyBombBang;
01489 obj->renderhandler = (RENDER_HANDLER)RenderPuttyBombBang;
01490
01491
01492
01493 PlaySfx3D(SFX_PUTTYBOMB_BANG, SFX_MAX_VOL, 22050, &bomb->Pos);
01494
01495
01496
01497 obj->Light = AllocLight();
01498 if (obj->Light)
01499 {
01500 CopyVec(&bomb->Pos, (VEC*)&obj->Light->x);
01501 obj->Light->Reach = 1024;
01502 obj->Light->Flag = LIGHT_FIXED | LIGHT_MOVING;
01503 obj->Light->Type = LIGHT_OMNI;
01504 obj->Light->r = 0;
01505 obj->Light->g = 0;
01506 obj->Light->b = 0;
01507 }
01508
01509
01510
01511 for (i = 0 ; i < PUTTYBOMB_BANG_NUM ; i++)
01512 {
01513 bomb->Bang[i].Age = -frand(PUTTYBOMB_BANG_STAGGER);
01514 bomb->Bang[i].Size = 64.0f - bomb->Bang[i].Age * 64.0f;
01515 bomb->Bang[i].Life = PUTTYBOMB_ONE_BANG_TIME - PUTTYBOMB_BANG_STAGGER - bomb->Bang[i].Age;
01516 SetVector(&bomb->Bang[i].Vel, 0.0f, -frand(64.0f) - 64.0f, 0.0f);
01517
01518 SetVector(&vec, 0, 0, PUTTYBOMB_BANG_RADIUS * (-bomb->Bang[i].Age / PUTTYBOMB_BANG_STAGGER));
01519 RotMatrixZYX(&mat, frand(0.25f) - 0.25f, frand(1.0f), 0.0f);
01520 RotTransVector(&mat, &bomb->Pos, &vec, &bomb->Bang[i].Pos);
01521 }
01522
01523
01524
01525 bomb->SmokeTime = 0.0f;
01526
01527 for (i = 0 ; i < PUTTYBOMB_SMOKE_NUM ; i++)
01528 {
01529 bomb->SmokeVert[i] = rand() % obj->player->car.Models->Body->VertNum;
01530 }
01531
01532
01533
01534 SetBBox(&box,
01535 bomb->Pos.v[X] - PUTTYBOMB_SCORCH_RADIUS,
01536 bomb->Pos.v[X] + PUTTYBOMB_SCORCH_RADIUS,
01537 bomb->Pos.v[Y] - PUTTYBOMB_SCORCH_RADIUS,
01538 bomb->Pos.v[Y] + PUTTYBOMB_SCORCH_RADIUS,
01539 bomb->Pos.v[Z] - PUTTYBOMB_SCORCH_RADIUS,
01540 bomb->Pos.v[Z] + PUTTYBOMB_SCORCH_RADIUS);
01541
01542 cube = World.Cube;
01543 for (i = 0 ; i < World.CubeNum ; i++, cube++)
01544 {
01545 if (cube->Xmin > box.XMax || cube->Xmax < box.XMin || cube->Ymin > box.YMax || cube->Ymax < box.YMin || cube->Zmin > box.ZMax || cube->Zmax < box.ZMin) continue;
01546
01547 dx = cube->CentreX - bomb->Pos.v[X];
01548 dy = cube->CentreY - bomb->Pos.v[Y];
01549 dz = cube->CentreZ - bomb->Pos.v[Z];
01550 if ((float)sqrt(dx * dx + dy * dy + dz * dz) > PUTTYBOMB_SCORCH_RADIUS + cube->Radius) continue;
01551
01552 wp = cube->Model.PolyPtr;
01553 for (j = cube->Model.PolyNum ; j ; j--, wp++)
01554 {
01555 wv = &wp->v0;
01556 wrgb = &wp->rgb0;
01557 vcount = 3 + (wp->Type & 1);
01558 for (k = 0 ; k < vcount ; k++)
01559 {
01560 SubVector(&bomb->Pos, (VEC*)&wv[k]->x, &vec);
01561 len = Length(&vec);
01562 if (len < PUTTYBOMB_SCORCH_RADIUS)
01563 {
01564 FTOL((1.0f - len / PUTTYBOMB_SCORCH_RADIUS) * 512.0f, per);
01565 if (per > 256) per = 256;
01566
01567 mrgb = (MODEL_RGB*)&wrgb[k];
01568 mrgb->r += (unsigned char)(((48 - mrgb->r) * per) >> 8);
01569 mrgb->g += (unsigned char)(((24 - mrgb->g) * per) >> 8);
01570 mrgb->b += (unsigned char)(((0 - mrgb->b) * per) >> 8);
01571 mrgb->a += (unsigned char)(((255 - mrgb->a) * per) >> 8);
01572 }
01573 }
01574 }
01575 }
01576
01577
01578
01579 SetVector(&imp, 0.0f, 0.0f, 0.0f);
01580 pos = &obj->player->car.Body->Centre.Pos;
01581 mass = obj->player->car.Body->Centre.Mass * 0.2f + 0.4f;
01582
01583 header = PosToCollGrid(pos);
01584 if (header)
01585 {
01586 for (i = 0 ; i < header->NCollPolys ; i++)
01587 {
01588 p = header->CollPolyPtr[i];
01589 sides = IsPolyQuad(p) ? 4 : 3;
01590
01591 for (j = 0 ; j < sides ; j++)
01592 {
01593 if (PlaneDist(&p->EdgePlane[j], pos) > 0.0f)
01594 break;
01595 }
01596
01597 if (j == sides)
01598 {
01599 dist = PlaneDist(&p->Plane, pos);
01600 if (dist > 0.0f && dist < PUTTYBOMB_BANG_IMPULSE_RANGE)
01601 {
01602 mul = (PUTTYBOMB_BANG_IMPULSE_RANGE - dist) * 20.0f * mass;
01603 VecPlusEqScalarVec(&imp, mul, (VEC*)&p->Plane);
01604 }
01605 }
01606 }
01607 }
01608
01609 rot = frand(RAD);
01610 mul = frand(20.0f);
01611 SetVector(&off, (float)sin(rot) * mul, 0.0f, (float)cos(rot) * mul);
01612 ApplyBodyImpulse(obj->player->car.Body, &imp, &off);
01613
01614
01615
01616 obj->player->car.Aerial.Length = bomb->OrigAerialLen;
01617 }
01618 }
01619
01621
01623
01624 void PuttyBombBang(OBJECT *obj)
01625 {
01626 PUTTYBOMB_OBJ *bomb = (PUTTYBOMB_OBJ*)obj->Data;
01627 PUTTYBOMB_VERT *vert;
01628 MODEL *model = &LevelModel[obj->DefaultModel].Model;
01629 MODEL_VERTEX *mv;
01630 VEC vec;
01631 long i;
01632
01633
01634
01635 if (bomb->Timer < PUTTYBOMB_SPHERE_TIME)
01636 {
01637 obj->player->car.AddLit -= (long)(TimeStep * 2000);
01638 if (obj->player->car.AddLit < -1000) obj->player->car.AddLit = -1000;
01639 }
01640
01641
01642
01643 if (obj->Light)
01644 {
01645 FTOL((float)sin(bomb->Timer / PUTTYBOMB_BANG_TIME * (RAD / 2.0f)) * 240.0f + frand(15.0f), obj->Light->r);
01646 obj->Light->g = obj->Light->r >> 1;
01647 }
01648
01649
01650
01651 for (i = 0 ; i < PUTTYBOMB_BANG_NUM ; i++)
01652 {
01653 if (bomb->Bang[i].Age < 0.0f)
01654 {
01655 VecPlusEqScalarVec(&bomb->Bang[i].Pos, TimeStep, &obj->player->car.Body->Centre.Vel);
01656
01657 bomb->Bang[i].Vel.v[X] = obj->player->car.Body->Centre.Vel.v[X];
01658 bomb->Bang[i].Vel.v[Z] = obj->player->car.Body->Centre.Vel.v[Z];
01659 }
01660 else
01661 {
01662 VecPlusEqScalarVec(&bomb->Bang[i].Pos, TimeStep, &bomb->Bang[i].Vel);
01663
01664 bomb->Bang[i].Vel.v[X] *= (1.0f - 1.5f * TimeStep);
01665 bomb->Bang[i].Vel.v[Z] *= (1.0f - 1.5f * TimeStep);
01666 }
01667
01668 bomb->Bang[i].Age += TimeStep;
01669 }
01670
01671
01672
01673 if (bomb->Timer > PUTTYBOMB_SPHERE_TIME)
01674 {
01675 bomb->SmokeTime += TimeStep;
01676 if (bomb->SmokeTime >= 0.1f)
01677 {
01678 for (i = 0 ; i < PUTTYBOMB_SMOKE_NUM ; i++)
01679 {
01680 RotTransVector(&obj->player->car.Body->Centre.WMatrix, &obj->player->car.BodyWorldPos, (VEC*)&obj->player->car.Models->Body->VertPtr[bomb->SmokeVert[i]].x, &vec);
01681 CreateSpark(SPARK_SMOKE3, &vec, &BombSmokeVel, 16.0f, 0);
01682 }
01683 bomb->SmokeTime -= 0.1f;
01684 }
01685 }
01686
01687
01688
01689 vert = (PUTTYBOMB_VERT*)(bomb + 1);
01690 mv = model->VertPtr;
01691
01692 for (i = model->VertNum ; i ; i--, mv++, vert++)
01693 {
01694 vert->Time += vert->TimeAdd * TimeStep;
01695
01696 mv->tu = (float)sin(vert->Time) * (12.0f / 256.0f) + (36.0f / 256.0f);
01697 mv->tv = (float)cos(vert->Time) * (12.0f / 256.0f) + (68.0f / 256.0f);
01698 }
01699
01700
01701
01702 if (bomb->SphereRadius < 512.0f)
01703 bomb->SphereRadius += (512.0f - bomb->SphereRadius) * 0.07f * TimeFactor;
01704
01705
01706
01707 bomb->Timer += TimeStep;
01708 if (bomb->Timer >= PUTTYBOMB_BANG_TIME)
01709 {
01710 obj->player->car.IsBomb = FALSE;
01711 OBJ_FreeObject(obj);
01712 return;
01713 }
01714
01715
01716
01717 if (bomb->Timer < PUTTYBOMB_SPHERE_TIME)
01718 {
01719 SetBBox(&bomb->Box,
01720 bomb->Pos.v[X] - bomb->SphereRadius - PUTTYBOMB_PUSH_RANGE,
01721 bomb->Pos.v[X] + bomb->SphereRadius + PUTTYBOMB_PUSH_RANGE,
01722 bomb->Pos.v[Y] - bomb->SphereRadius - PUTTYBOMB_PUSH_RANGE,
01723 bomb->Pos.v[Y] + bomb->SphereRadius + PUTTYBOMB_PUSH_RANGE,
01724 bomb->Pos.v[Z] - bomb->SphereRadius - PUTTYBOMB_PUSH_RANGE,
01725 bomb->Pos.v[Z] + bomb->SphereRadius + PUTTYBOMB_PUSH_RANGE);
01726
01727 AddWorldMeshFx(PuttyBombWorldMeshFxChecker, obj);
01728 AddModelMeshFx(PuttyBombModelMeshFxChecker, obj);
01729 }
01730 }
01731
01732 void PuttyBombMove(OBJECT *obj)
01733 {
01734 PLAYER *player;
01735 PUTTYBOMB_OBJ *bomb = (PUTTYBOMB_OBJ*)obj->Data;
01736
01737
01738 if (obj->player->car.WillDetonate) return;
01739
01740
01741 for (player = PLR_PlayerHead; player != NULL; player = player ->next) {
01742 if (player == obj->player) continue;
01743
01744
01745 if (!IsPairCollided(obj->player->ownobj, player->ownobj)) continue;
01746
01747
01748 if (player->car.NoReturnTimer > ZERO) continue;
01749
01750
01751 obj->player->car.NoReturnTimer = PUTTYBOMB_NORETURN_TIME;
01752 obj->player->car.Aerial.Length = bomb->OrigAerialLen;
01753 obj->player->car.IsBomb = FALSE;
01754 obj->player->car.WillDetonate = FALSE;
01755
01756 player->car.IsBomb = TRUE;
01757 player->car.WillDetonate = FALSE;
01758 bomb->OrigAerialLen = player->car.Aerial.Length;
01759 obj->player->car.NoReturnTimer = PUTTYBOMB_NORETURN_TIME;
01760 obj->player = player;
01761
01762 }
01763 }
01764
01765
01767
01769
01770 void WaterBombHandler(OBJECT *obj)
01771 {
01772 long flag;
01773 WATERBOMB_OBJ *bomb = (WATERBOMB_OBJ*)obj->Data;
01774 MAT mat;
01775 VEC pos;
01776 REAL dist;
01777
01778
01779
01780 bomb->Age += TimeStep;
01781
01782
01783
01784 if (obj->Sfx3D)
01785 {
01786 CopyVec(&obj->body.Centre.Pos, &obj->Sfx3D->Pos);
01787 }
01788
01789
01790
01791 bomb->ScalarHoriz = (float)sin((float)TIME2MS(TimerCurrent) / 100.0f) / 10.0f + 1.0f;
01792 bomb->ScalarVert = 2.0f - bomb->ScalarHoriz;
01793
01794
01795
01796 if (obj->body.BangMag)
01797 {
01798 bomb->BangTol -= obj->body.BangMag;
01799 if (obj->body.BangPlane.v[Y] > -0.7f && bomb->BangTol < 0.0f)
01800 bomb->BangTol = 0.0f;
01801
01802 obj->body.BangMag = 0.0f;
01803 }
01804
01805
01806
01807 if (bomb->BangTol < 0.0f || bomb->Age > WATERBOMB_MAX_AGE)
01808 {
01809 PlaySfx3D(SFX_WATERBOMB_HIT, SFX_MAX_VOL, 22050, &obj->body.Centre.Pos);
01810
01811
01812
01813
01814 dist = -PlaneDist(&obj->body.BangPlane, &obj->body.Centre.Pos);
01815 VecPlusScalarVec(&obj->body.Centre.Pos, dist, (VEC*)&obj->body.BangPlane, &pos);
01816
01817 SetVec(&mat.mv[U], -obj->body.BangPlane.v[A], -obj->body.BangPlane.v[B], -obj->body.BangPlane.v[C]);
01818 SetVec(&mat.mv[L], mat.m[UY], mat.m[UZ], mat.m[UX]);
01819 CrossProduct(&mat.mv[U], &mat.mv[L], &mat.mv[R]);
01820 CrossProduct(&mat.mv[R], &mat.mv[U], &mat.mv[L]);
01821
01822 CreateObject(&pos, &mat, OBJECT_TYPE_SPLASH, &flag);
01823
01824 OBJ_FreeObject(obj);
01825 }
01826 }
01827
01829
01831
01832 void ElectroPulseHandler(OBJECT *obj)
01833 {
01834 long i, rgb, lmul, flag;
01835 ELECTROPULSE_OBJ *electro = (ELECTROPULSE_OBJ*)obj->Data;
01836 MODEL *dmodel, *model = (MODEL*)&electro->Model;
01837 MODEL_POLY *mp;
01838 POLY_RGB *mrgb;
01839 MODEL_VERTEX *mv;
01840 ELECTROPULSE_VERT *evert;
01841 PLAYER *player;
01842 VEC delta, vec, *nvec1, *nvec2, *pos, rotpos, v1, v2;
01843 REAL dist, ndist;
01844
01845
01846
01847 mv = model->VertPtr;
01848 evert = (ELECTROPULSE_VERT*)(model->VertPtr + model->VertNum);
01849
01850 for (i = model->VertNum ; i ; i--, mv++, evert++)
01851 {
01852 evert->Time += evert->TimeAdd * TimeStep;
01853
01854 mv->tu = (float)sin(evert->Time) * (24.0f / 256.0f) + (96.0f / 256.0f);
01855 mv->tv = (float)cos(evert->Time) * (24.0f / 256.0f) + (96.0f / 256.0f);
01856 }
01857
01858
01859
01860 if (electro->Age < 0.5f)
01861 {
01862 FTOL(electro->Age * 511.0f, lmul);
01863 }
01864 else if (electro->Age > 9.5f)
01865 {
01866 FTOL((10.0f - electro->Age) * 511.0f, lmul);
01867 }
01868 else
01869 {
01870 lmul = 255;
01871 }
01872
01873 rgb = lmul | lmul << 8 | lmul << 16;
01874
01875 mp = model->PolyPtr;
01876 mrgb = model->PolyRGB;
01877
01878 for (i = model->PolyNum ; i ; i--, mp++, mrgb++)
01879 {
01880 mp->tu0 = mp->v0->tu;
01881 mp->tv0 = mp->v0->tv;
01882
01883 mp->tu1 = mp->v1->tu;
01884 mp->tv1 = mp->v1->tv;
01885
01886 mp->tu2 = mp->v2->tu;
01887 mp->tv2 = mp->v2->tv;
01888
01889 if (mp->Type & POLY_QUAD)
01890 {
01891 mp->tu3 = mp->v3->tu;
01892 mp->tv3 = mp->v3->tv;
01893 }
01894
01895 *(long*)&mrgb->rgb[0] = rgb;
01896 *(long*)&mrgb->rgb[1] = rgb;
01897 *(long*)&mrgb->rgb[2] = rgb;
01898 *(long*)&mrgb->rgb[3] = rgb;
01899 }
01900
01901
01902
01903 if (obj->Light)
01904 {
01905 CopyVec(&obj->player->car.Body->Centre.Pos, (VEC*)&obj->Light->x);
01906
01907 obj->Light->b = lmul / 4 + (rand() & 31);
01908 }
01909
01910
01911
01912 if (obj->Sfx3D)
01913 {
01914 CopyVec(&obj->player->car.Body->Centre.Pos, &obj->Sfx3D->Pos);
01915
01916 obj->Sfx3D->Vol = SFX_MAX_VOL * lmul / 255;
01917 }
01918
01919
01920
01921 electro->Age += TimeStep;
01922 if (electro->Age > 10.0f)
01923 {
01924 OBJ_FreeObject(obj);
01925 return;
01926 }
01927
01928
01929
01930 electro->JumpFlag = 0;
01931
01932 pos = &obj->player->car.BodyWorldPos;
01933
01934 for (player = PLR_PlayerHead ; player ; player = player->next)
01935 {
01936 if (player == obj->player)
01937 continue;
01938
01939 SubVector(pos, &player->car.BodyWorldPos, &delta);
01940 dist = delta.v[X] * delta.v[X] + delta.v[Y] * delta.v[Y] + delta.v[Z] * delta.v[Z];
01941 if (dist > (ELECTRO_RANGE * ELECTRO_RANGE))
01942 continue;
01943
01944
01945
01946 if (!player->car.PowerTimer)
01947 {
01948 flag = (long)player;
01949 CreateObject(&player->car.Body->Centre.Pos, &player->car.Body->Centre.WMatrix, OBJECT_TYPE_ELECTROZAPPED, &flag);
01950 }
01951
01952 player->car.PowerTimer = ELECTRO_KILL_TIME;
01953
01954
01955
01956 SubVector(pos, &player->car.BodyWorldPos, &delta);
01957 TransposeRotVector(&player->car.Body->Centre.WMatrix, &delta, &rotpos);
01958
01959 dmodel = &player->car.Models->Body[0];
01960
01961 ndist = 1000000;
01962 mv = dmodel->VertPtr;
01963
01964 for (i = dmodel->VertNum ; i ; i--, mv++)
01965 {
01966 SubVector((VEC*)&mv->x, &rotpos, &vec);
01967 dist = vec.v[X] * vec.v[X] + vec.v[Y] * vec.v[Y] + vec.v[Z] * vec.v[Z];
01968 if (dist < ndist)
01969 {
01970 ndist = dist;
01971 nvec1 = (VEC*)&mv->x;
01972 }
01973 }
01974
01975
01976
01977 SubVector(&player->car.BodyWorldPos, pos, &delta);
01978 TransposeRotVector(&obj->player->car.Body->Centre.WMatrix, &delta, &rotpos);
01979
01980 ndist = 1000000;
01981 mv = model->VertPtr;
01982
01983 for (i = model->VertNum ; i ; i--, mv++)
01984 {
01985 SubVector((VEC*)&mv->x, &rotpos, &vec);
01986 dist = vec.v[X] * vec.v[X] + vec.v[Y] * vec.v[Y] + vec.v[Z] * vec.v[Z];
01987 if (dist < ndist)
01988 {
01989 ndist = dist;
01990 nvec2 = (VEC*)&mv->x;
01991 }
01992 }
01993
01994
01995
01996 electro->Player[electro->JumpFlag] = player;
01997
01998 CopyVec(nvec1, &electro->JumpPos1[electro->JumpFlag]);
01999 CopyVec(nvec2, &electro->JumpPos2[electro->JumpFlag]);
02000
02001
02002
02003 RotTransVector(&player->car.Body->Centre.WMatrix, &player->car.BodyWorldPos, &electro->JumpPos1[electro->JumpFlag], &v1);
02004 RotTransVector(&obj->player->car.Body->Centre.WMatrix, &obj->player->car.BodyWorldPos, &electro->JumpPos2[electro->JumpFlag], &v2);
02005
02006 FTOL(TimeStep * 50.0f + 1.0f, i);
02007 for ( ; i ; i--)
02008 {
02009 CreateSpark(SPARK_ELECTRIC, &v1, &ZeroVector, 200, 0);
02010 CreateSpark(SPARK_ELECTRIC, &v2, &ZeroVector, 200, 0);
02011 }
02012
02013
02014
02015 electro->JumpFlag++;
02016 }
02017 }
02018 #endif
02019
02021
02023
02024 void OilSlickHandler(OBJECT *obj)
02025 {
02026 long i;
02027 OILSLICK_OBJ *oil = (OILSLICK_OBJ*)obj->Data;
02028 VEC vec, pos, vel, v0, v1, v2, v3;
02029 MAT mat;
02030 REAL mul, time;
02031 PLANE *plane;
02032
02033
02034
02035 if (!oil->Mode)
02036 {
02037
02038
02039
02040 oil->Age += TimeStep;
02041
02042
02043
02044 obj->body.Centre.Vel.v[Y] += OILSLICK_GRAV * TimeStep;
02045 obj->body.Centre.Pos.v[Y] += obj->body.Centre.Vel.v[Y] * TimeStep;
02046 if (obj->body.Centre.Pos.v[Y] >= oil->LandHeight)
02047 {
02048 oil->Mode = 1;
02049 oil->Age = 0.0f;
02050 oil->Size = OILSLICK_MIN_SIZE;
02051
02052 RotMatrixY(&mat, frand(1.0f));
02053
02054 SetVector(&v0, -1.0f, 0, 1.0f);
02055 SetVector(&v1, 1.0f, 0, 1.0f);
02056 SetVector(&v2, 1.0f, 0, -1.0f);
02057 SetVector(&v3, -1.0f, 0, -1.0f);
02058
02059 RotVector(&mat, &v0, &oil->Vel[0]);
02060 RotVector(&mat, &v1, &oil->Vel[1]);
02061 RotVector(&mat, &v2, &oil->Vel[2]);
02062 RotVector(&mat, &v3, &oil->Vel[3]);
02063
02064 SetVector(&pos, obj->body.Centre.Pos.v[X], oil->LandHeight - 32.0f, obj->body.Centre.Pos.v[Z]);
02065
02066 SetVector(&v0, -OILSLICK_MIN_SIZE, 0, OILSLICK_MIN_SIZE);
02067 SetVector(&v1, OILSLICK_MIN_SIZE, 0, OILSLICK_MIN_SIZE);
02068 SetVector(&v2, OILSLICK_MIN_SIZE, 0, -OILSLICK_MIN_SIZE);
02069 SetVector(&v3, -OILSLICK_MIN_SIZE, 0, -OILSLICK_MIN_SIZE);
02070
02071 RotTransVector(&mat, &pos, &v0, &oil->Pos[0]);
02072 RotTransVector(&mat, &pos, &v1, &oil->Pos[1]);
02073 RotTransVector(&mat, &pos, &v2, &oil->Pos[2]);
02074 RotTransVector(&mat, &pos, &v3, &oil->Pos[3]);
02075 }
02076 }
02077
02078
02079
02080 if (oil->Mode)
02081 {
02082
02083
02084
02085 mul = (oil->MaxSize - oil->Size) * TimeStep;
02086 oil->Size += mul;
02087
02088 for (i = 0 ; i < 4 ; i++)
02089 {
02090 CopyVec(&oil->Vel[i], &vel);
02091
02092 SetVector(&vec, oil->Pos[i].v[X], oil->Pos[i].v[Y] + 1024, oil->Pos[i].v[Z]);
02093 LineOfSightDist(&oil->Pos[i], &vec, &time, &plane);
02094 if (time > 0.0f && time < 1.0f)
02095 {
02096 vel.v[X] += plane->v[X] * 2.0f;
02097 vel.v[Z] += plane->v[Z] * 2.0f;
02098 }
02099
02100 VecPlusEqScalarVec(&oil->Pos[i], mul, &vel);
02101 }
02102
02103
02104
02105 if (OilSlickCount < OILSLICK_LIST_MAX)
02106 {
02107 OilSlickList[OilSlickCount].X = obj->body.Centre.Pos.v[X];
02108 OilSlickList[OilSlickCount].Z = obj->body.Centre.Pos.v[Z];
02109 OilSlickList[OilSlickCount].Radius = oil->Size;
02110 OilSlickList[OilSlickCount].SquaredRadius = oil->Size * oil->Size;
02111
02112 OilSlickList[OilSlickCount].Ymin = oil->Ymin;
02113 OilSlickList[OilSlickCount].Ymax = oil->Ymax;
02114
02115 OilSlickCount++;
02116 }
02117
02118
02119
02120 oil->Age += TimeStep;
02121 if (oil->Age > 30.0f)
02122 {
02123 OBJ_FreeObject(obj);
02124 }
02125 }
02126 }
02127
02129
02131
02132 void OilSlickDropperHandler(OBJECT *obj)
02133 {
02134 OILSLICK_DROPPER_OBJ *dropper = (OILSLICK_DROPPER_OBJ*)obj->Data;
02135 long flags[2];
02136 REAL len, mul;
02137 VEC delta;
02138 CAR *car;
02139
02140
02141
02142 car = &obj->player->car;
02143
02144 if (!dropper->Count)
02145 {
02146 len = DROPPER_GAP;
02147 }
02148 else
02149 {
02150 SubVector(&car->Body->Centre.Pos, &dropper->LastPos, &delta);
02151 len = Length(&delta);
02152 }
02153
02154 if (len >= DROPPER_GAP)
02155 {
02156
02157
02158
02159 mul = DROPPER_GAP / len;
02160 VecPlusScalarVec(&dropper->LastPos, mul, &delta, &dropper->LastPos);
02161
02162 flags[0] = (long)obj->player;
02163 FTOL(OILSLICK_MAX_SIZE - (float)dropper->Count * 16.0f, flags[1]);
02164
02165 CreateObject(&dropper->LastPos, &car->Body->Centre.WMatrix, OBJECT_TYPE_OILSLICK, flags);
02166
02167 dropper->Count++;
02168 }
02169
02170
02171
02172
02173 dropper->Age += TimeStep;
02174 if (dropper->Age > 1.0f || dropper->Count >= 3)
02175 {
02176 OBJ_FreeObject(obj);
02177 }
02178 }
02179
02180 #ifdef _PC
02182 // weapon handler //
02184
02185 void ChromeBallHandler(OBJECT *obj)
02186 {
02187 long vel;
02188 CHROMEBALL_OBJ *ball = (CHROMEBALL_OBJ*)obj->Data;
02189
02190
02191
02192 ball->Age += TimeStep;
02193
02194
02195
02196 if (ball->Age < 0.5f)
02197 ball->Radius = (CHROMEBALL_MAX_RAD - CHROMEBALL_MIN_RAD) * ball->Age * 2.0f + CHROMEBALL_MIN_RAD;
02198 else if (ball->Age > 29.0f)
02199 ball->Radius = (CHROMEBALL_MAX_RAD - CHROMEBALL_MIN_RAD) * (30.0f - ball->Age) + CHROMEBALL_MIN_RAD;
02200 else
02201 ball->Radius = CHROMEBALL_MAX_RAD;
02202
02203 obj->body.CollSkin.Sphere[0].Radius = obj->body.CollSkin.WorldSphere[0].Radius = obj->body.CollSkin.OldWorldSphere[0].Radius = ball->Radius;
02204
02205
02206
02207 if (obj->Sfx3D)
02208 {
02209 FTOL(Length(&obj->body.Centre.Vel), vel);
02210
02211 obj->Sfx3D->Freq = 5000 + vel * 4;
02212
02213 obj->Sfx3D->Vol = vel / 2;
02214 if (obj->Sfx3D->Vol > SFX_MAX_VOL) obj->Sfx3D->Vol = SFX_MAX_VOL;
02215
02216 CopyVec(&obj->body.Centre.Pos, &obj->Sfx3D->Pos);
02217 }
02218
02219
02220 if (obj->body.BangMag > TO_VEL(Real(300))) {
02221 long vol, freq;
02222
02223
02224
02225 vol = SFX_MAX_VOL;
02226
02227 freq = 22050;
02228
02229 PlaySfx3D(SFX_CHROMEBALL_HIT, vol, freq, &obj->body.Centre.Pos);
02230 obj->body.Banged = FALSE;
02231 obj->body.BangMag = ZERO;
02232 }
02233
02234
02235
02236 if (ball->Age >= 30.0f)
02237 {
02238 OBJ_FreeObject(obj);
02239 }
02240 }
02241
02243
02245
02246 void CloneHandler(OBJECT *obj)
02247 {
02248 }
02249
02251
02253
02254 void TurboAIHandler(OBJECT *obj)
02255 {
02256
02257 VEC pos, vel;
02258 TURBO_OBJ *turbo = (TURBO_OBJ *)obj->Data;
02259
02260 turbo->Age += TimeStep;
02261 turbo->SparkTime += TimeStep;
02262
02263 if (turbo->SparkTime > 0.01) {
02264 VecEqScalarVec(&vel, HALF, &obj->player->car.Body->Centre.Vel);
02265 pos.v[X] = obj->player->car.Body->Centre.Pos.v[X] + frand(30) - 15;
02266 pos.v[Y] = obj->player->car.Body->Centre.Pos.v[Y] + frand(30) - 15;
02267 pos.v[Z] = obj->player->car.Body->Centre.Pos.v[Z] + frand(30) - 15;
02268
02269 CreateSpark(SPARK_SPARK, &pos, &vel, TO_VEL(Real(100)), 0);
02270 }
02271
02272 if (turbo->Age < turbo->LifeTime) {
02273
02274 obj->player->car.TopSpeed = TO_VEL(MPH2OGU_SPEED * 75) * (ONE + HALF * (ONE - turbo->Age / turbo->LifeTime));
02275 } else {
02276 obj->player->car.TopSpeed = obj->player->car.DefaultTopSpeed;
02277
02278
02279
02280
02281
02282
02283 OBJ_FreeObject(obj);
02284 }
02285
02286 }
02287
02288 void TurboMoveHandler(OBJECT *obj)
02289 {
02290
02291 TURBO_OBJ *turbo = (TURBO_OBJ *)obj->Data;
02292
02293
02294
02295
02296
02297
02298
02299
02300
02301
02302
02303
02304
02305
02306 }
02307
02309
02311
02312 void Turbo2Handler(OBJECT *obj)
02313 {
02314 TURBO2_OBJ *turbo = (TURBO2_OBJ*)obj->Data;
02315
02316
02317
02318
02319
02320
02321
02322
02323
02324
02325
02326
02327
02328
02329
02330
02331
02332
02333
02334
02335
02336
02337
02338
02339 turbo->Age += TimeStep;
02340 if (turbo->Age < turbo->LifeTime)
02341 {
02342 obj->player->car.TopSpeed = TO_VEL(MPH2OGU_SPEED * 75) * (ONE + HALF * (ONE - turbo->Age / turbo->LifeTime));
02343 }
02344 else
02345 {
02346 OBJ_FreeObject(obj);
02347 }
02348 }
02349
02351
02353
02354 void SpringHandler(OBJECT *obj)
02355 {
02356 VEC imp;
02357
02358 ScalarVecPlusScalarVec(-obj->player->car.Body->Centre.Mass * 1000, &obj->player->car.Body->Centre.WMatrix.mv[U], obj->player->car.Body->Centre.Mass * 1000, &obj->player->car.Body->Centre.WMatrix.mv[L], &imp)
02359 VecPlusEqVec(&obj->player->car.Body->Centre.Impulse, &imp);
02360
02361 OBJ_FreeObject(obj);
02362 }
02363
02365
02367
02368 void ElectroZappedHandler(OBJECT *obj)
02369 {
02370 long i, rgb, lmul;
02371 ELECTROZAPPED_OBJ *electro = (ELECTROZAPPED_OBJ*)obj->Data;
02372 MODEL *model = (MODEL*)&electro->Model;
02373 MODEL_POLY *mp;
02374 POLY_RGB *mrgb;
02375 MODEL_VERTEX *mv;
02376 ELECTROZAPPED_VERT *evert;
02377
02378
02379
02380 mv = model->VertPtr;
02381 evert = (ELECTROZAPPED_VERT*)(model->VertPtr + model->VertNum);
02382
02383 for (i = model->VertNum ; i ; i--, mv++, evert++)
02384 {
02385 evert->Time += evert->TimeAdd * TimeStep;
02386
02387 mv->tu = (float)sin(evert->Time) * (24.0f / 256.0f) + (96.0f / 256.0f);
02388 mv->tv = (float)cos(evert->Time) * (24.0f / 256.0f) + (96.0f / 256.0f);
02389 }
02390
02391
02392
02393 FTOL(obj->player->car.PowerTimer * 80.0f, lmul);
02394
02395 rgb = lmul | lmul << 8 | lmul << 16;
02396
02397 mp = model->PolyPtr;
02398 mrgb = model->PolyRGB;
02399
02400 for (i = model->PolyNum ; i ; i--, mp++, mrgb++)
02401 {
02402 mp->tu0 = mp->v0->tu;
02403 mp->tv0 = mp->v0->tv;
02404
02405 mp->tu1 = mp->v1->tu;
02406 mp->tv1 = mp->v1->tv;
02407
02408 mp->tu2 = mp->v2->tu;
02409 mp->tv2 = mp->v2->tv;
02410
02411 if (mp->Type & POLY_QUAD)
02412 {
02413 mp->tu3 = mp->v3->tu;
02414 mp->tv3 = mp->v3->tv;
02415 }
02416
02417 *(long*)&mrgb->rgb[0] = rgb;
02418 *(long*)&mrgb->rgb[1] = rgb;
02419 *(long*)&mrgb->rgb[2] = rgb;
02420 *(long*)&mrgb->rgb[3] = rgb;
02421 }
02422
02423
02424
02425 if (!obj->player->car.PowerTimer)
02426 {
02427 OBJ_FreeObject(obj);
02428 return;
02429 }
02430 }
02431
02433
02435
02436 void BombGlowHandler(OBJECT *obj)
02437 {
02438 long i, rgb, lmul;
02439 BOMBGLOW_OBJ *glow = (BOMBGLOW_OBJ*)obj->Data;
02440 MODEL *model = (MODEL*)&glow->Model;
02441 MODEL_POLY *mp;
02442 POLY_RGB *mrgb;
02443 MODEL_VERTEX *mv;
02444 BOMBGLOW_VERT *gvert;
02445
02446
02447
02448 mv = model->VertPtr;
02449 gvert = (BOMBGLOW_VERT*)(model->VertPtr + model->VertNum);
02450
02451 for (i = model->VertNum ; i ; i--, mv++, gvert++)
02452 {
02453 gvert->Time += gvert->TimeAdd * TimeStep;
02454
02455 mv->tu = (float)sin(gvert->Time) * (12.0f / 256.0f) + (36.0f / 256.0f);
02456 mv->tv = (float)cos(gvert->Time) * (12.0f / 256.0f) + (44.0f / 256.0f);
02457 }
02458
02459
02460
02461 FTOL(glow->Timer / PUTTYBOMB_COUNTDOWN2 * 128.0f, lmul);
02462 rgb = lmul | lmul << 8 | lmul << 16;
02463
02464 mp = model->PolyPtr;
02465 mrgb = model->PolyRGB;
02466
02467 for (i = model->PolyNum ; i ; i--, mp++, mrgb++)
02468 {
02469 mp->tu0 = mp->v0->tu;
02470 mp->tv0 = mp->v0->tv;
02471
02472 mp->tu1 = mp->v1->tu;
02473 mp->tv1 = mp->v1->tv;
02474
02475 mp->tu2 = mp->v2->tu;
02476 mp->tv2 = mp->v2->tv;
02477
02478 if (mp->Type & POLY_QUAD)
02479 {
02480 mp->tu3 = mp->v3->tu;
02481 mp->tv3 = mp->v3->tv;
02482 }
02483
02484 *(long*)&mrgb->rgb[0] = rgb;
02485 *(long*)&mrgb->rgb[1] = rgb;
02486 *(long*)&mrgb->rgb[2] = rgb;
02487 *(long*)&mrgb->rgb[3] = rgb;
02488 }
02489
02490
02491
02492 glow->Timer += TimeStep;
02493 if (glow->Timer >= PUTTYBOMB_COUNTDOWN2)
02494 {
02495 OBJ_FreeObject(obj);
02496 return;
02497 }
02498 }
02499
02501
02503
02504 void RenderShockwave(OBJECT *obj)
02505 {
02506 SHOCKWAVE_OBJ *shockwave = (SHOCKWAVE_OBJ*)obj->Data;
02507 FACING_POLY poly;
02508 MAT mat;
02509 REAL ang;
02510
02511
02512
02513 if (shockwave->Alive)
02514 {
02515 poly.Xsize = poly.Ysize = 40.0f;
02516 poly.Tpage = TPAGE_FX1;
02517 poly.U = 0.0f / 256.0f;
02518 poly.V = 64.0f / 256.0f;
02519 poly.Usize = poly.Vsize = 64.0f / 256.0f;
02520 poly.RGB = 0xffffff;
02521
02522 ang = (float)TIME2MS(CurrentTimer()) / 2000.0f;
02523
02524 RotMatrixZ(&mat, ang);
02525 DrawFacingPolyRotMirror(&obj->body.Centre.Pos, &mat, &poly, 1, -128);
02526
02527 RotMatrixZ(&mat, -ang);
02528 DrawFacingPolyRotMirror(&obj->body.Centre.Pos, &mat, &poly, 1, -128);
02529 }
02530 }
02531
02533
02535
02536 void ShockwaveWorldMeshFxChecker(void *data)
02537 {
02538 long i, j;
02539 CUBE_HEADER **cubelist;
02540 OBJECT *obj = (OBJECT*)data;
02541 SHOCKWAVE_OBJ *shockwave = (SHOCKWAVE_OBJ*)obj->Data;
02542 VEC vec, *pos = &obj->body.Centre.Pos;
02543 WORLD_VERTEX *wv;
02544 WORLD_MIRROR_VERTEX *wmv;
02545 REAL dist, mul, pull;
02546
02547
02548
02549 cubelist = World.CubeList;
02550
02551 for (i = 0 ; i < WorldCubeCount ; i++)
02552 {
02553
02554
02555
02556 if (cubelist[i]->Xmin > shockwave->Box.XMax || cubelist[i]->Xmax < shockwave->Box.XMin ||
02557 cubelist[i]->Ymin > shockwave->Box.YMax || cubelist[i]->Ymax < shockwave->Box.YMin ||
02558 cubelist[i]->Zmin > shockwave->Box.ZMax || cubelist[i]->Zmax < shockwave->Box.ZMin)
02559 continue;
02560
02561
02562
02563 SubVector((VEC*)&cubelist[i]->CentreX, pos, &vec);
02564 if (Length(&vec) > cubelist[i]->Radius + shockwave->Reach)
02565 continue;
02566
02567
02568
02569 if (cubelist[i]->MeshFxFlag & MESHFX_USENEWVERTS)
02570 {
02571 wv = cubelist[i]->Model.VertPtr;
02572 for (j = cubelist[i]->Model.VertNum ; j ; j--, wv++)
02573 {
02574 SubVector((VEC*)&wv->x2, pos, &vec);
02575 dist = Length(&vec);
02576 if (dist < shockwave->Reach)
02577 {
02578 pull = (shockwave->Reach - dist) * SHOCKWAVE_PULL_MAX_MUL;
02579 if (pull > dist * SHOCKWAVE_PULL_MIN_MUL) pull = dist * SHOCKWAVE_PULL_MIN_MUL;
02580 mul = pull / dist;
02581 VecMinusScalarVec((VEC*)&wv->x2, mul, &vec, (VEC*)&wv->x2);
02582 }
02583 }
02584
02585 wmv = cubelist[i]->Model.MirrorVertPtr;
02586 for (j = cubelist[i]->Model.MirrorVertNum ; j ; j--, wmv++)
02587 {
02588 SubVector((VEC*)&wmv->RealVertex->x2, pos, &vec);
02589 dist = Length(&vec);
02590 if (dist < shockwave->Reach)
02591 {
02592 pull = (shockwave->Reach - dist) * SHOCKWAVE_PULL_MAX_MUL;
02593 if (pull > dist * SHOCKWAVE_PULL_MIN_MUL) pull = dist * SHOCKWAVE_PULL_MIN_MUL;
02594 mul = pull / dist;
02595 VecMinusScalarVec((VEC*)&wmv->x2, mul, &vec, (VEC*)&wmv->x2);
02596 }
02597 }
02598 }
02599 else
02600 {
02601 wv = cubelist[i]->Model.VertPtr;
02602 for (j = cubelist[i]->Model.VertNum ; j ; j--, wv++)
02603 {
02604 SubVector((VEC*)&wv->x, pos, &vec);
02605 dist = Length(&vec);
02606 if (dist < shockwave->Reach)
02607 {
02608 pull = (shockwave->Reach - dist) * SHOCKWAVE_PULL_MAX_MUL;
02609 if (pull > dist * SHOCKWAVE_PULL_MIN_MUL) pull = dist * SHOCKWAVE_PULL_MIN_MUL;
02610 mul = pull / dist;
02611 VecMinusScalarVec((VEC*)&wv->x, mul, &vec, (VEC*)&wv->x2);
02612 }
02613 else
02614 {
02615 CopyVec((VEC*)&wv->x, (VEC*)&wv->x2);
02616 }
02617 }
02618
02619 wmv = cubelist[i]->Model.MirrorVertPtr;
02620 for (j = cubelist[i]->Model.MirrorVertNum ; j ; j--, wmv++)
02621 {
02622 SubVector((VEC*)&wmv->RealVertex->x, pos, &vec);
02623 dist = Length(&vec);
02624 if (dist < shockwave->Reach)
02625 {
02626 pull = (shockwave->Reach - dist) * SHOCKWAVE_PULL_MAX_MUL;
02627 if (pull > dist * SHOCKWAVE_PULL_MIN_MUL) pull = dist * SHOCKWAVE_PULL_MIN_MUL;
02628 mul = pull / dist;
02629 VecMinusScalarVec((VEC*)&wmv->x, mul, &vec, (VEC*)&wmv->x2);
02630 }
02631 else
02632 {
02633 CopyVec((VEC*)&wmv->x, (VEC*)&wmv->x2);
02634 }
02635 }
02636 }
02637
02638
02639
02640 cubelist[i]->MeshFxFlag |= MESHFX_USENEWVERTS;
02641 }
02642 }
02643
02645
02647
02648 void ShockwaveModelMeshFxChecker(void *data)
02649 {
02650 long j;
02651 REAL pull, dist, mul, rad = ModelMeshModel->Radius;
02652 OBJECT *obj = (OBJECT*)data;
02653 SHOCKWAVE_OBJ *shockwave = (SHOCKWAVE_OBJ*)obj->Data;
02654 VEC delta, newdelta, vec;
02655 MODEL_VERTEX *mv;
02656
02657
02658
02659 if (ModelMeshPos->v[X] + rad < shockwave->Box.XMin ||
02660 ModelMeshPos->v[X] - rad > shockwave->Box.XMax ||
02661 ModelMeshPos->v[Y] + rad < shockwave->Box.YMin ||
02662 ModelMeshPos->v[Y] - rad > shockwave->Box.YMax ||
02663 ModelMeshPos->v[Z] + rad < shockwave->Box.ZMin ||
02664 ModelMeshPos->v[Z] - rad > shockwave->Box.ZMax)
02665 return;
02666
02667
02668
02669 SubVector(&obj->body.Centre.Pos, ModelMeshPos, &delta);
02670
02671
02672
02673 dist = Length(&delta);
02674 if (dist > rad + shockwave->Reach)
02675 return;
02676
02677
02678
02679 TransposeRotVector(ModelMeshMat, &delta, &newdelta);
02680
02681
02682
02683 if (ModelMeshModel->Xmax < newdelta.v[X] - shockwave->Reach ||
02684 ModelMeshModel->Xmin > newdelta.v[X] + shockwave->Reach ||
02685 ModelMeshModel->Ymax < newdelta.v[Y] - shockwave->Reach ||
02686 ModelMeshModel->Ymin > newdelta.v[Y] + shockwave->Reach ||
02687 ModelMeshModel->Zmax < newdelta.v[Z] - shockwave->Reach ||
02688 ModelMeshModel->Zmin > newdelta.v[Z] + shockwave->Reach)
02689 return;
02690
02691
02692
02693 mv = ModelMeshModel->VertPtr;
02694
02695 if (*ModelMeshFlag & MODEL_USENEWVERTS)
02696 {
02697 for (j = ModelMeshModel->VertNum ; j ; j--, mv++)
02698 {
02699 SubVector((VEC*)&mv->x2, &newdelta, &vec);
02700 dist = Length(&vec);
02701 if (dist < shockwave->Reach)
02702 {
02703 pull = (shockwave->Reach - dist) * SHOCKWAVE_PULL_MAX_MUL;
02704 if (pull > dist * SHOCKWAVE_PULL_MIN_MUL) pull = dist * SHOCKWAVE_PULL_MIN_MUL;
02705 mul = pull / dist;
02706 VecMinusScalarVec((VEC*)&mv->x2, mul, &vec, (VEC*)&mv->x2);
02707 }
02708 }
02709 }
02710 else
02711 {
02712 for (j = ModelMeshModel->VertNum ; j ; j--, mv++)
02713 {
02714 SubVector((VEC*)&mv->x, &newdelta, &vec);
02715 dist = Length(&vec);
02716 if (dist < shockwave->Reach)
02717 {
02718 pull = (shockwave->Reach - dist) * SHOCKWAVE_PULL_MAX_MUL;
02719 if (pull > dist * SHOCKWAVE_PULL_MIN_MUL) pull = dist * SHOCKWAVE_PULL_MIN_MUL;
02720 mul = pull / dist;
02721 VecMinusScalarVec((VEC*)&mv->x, mul, &vec, (VEC*)&mv->x2);
02722 }
02723 else
02724 {
02725 CopyVec((VEC*)&mv->x, (VEC*)&mv->x2);
02726 }
02727 }
02728 }
02729
02730
02731
02732 *ModelMeshFlag |= MODEL_USENEWVERTS;
02733 }
02734
02736
02738
02739 void PuttyBombWorldMeshFxChecker(void *data)
02740 {
02741 long i, j;
02742 CUBE_HEADER **cubelist;
02743 OBJECT *obj = (OBJECT*)data;
02744 PUTTYBOMB_OBJ *bomb = (PUTTYBOMB_OBJ*)obj->Data;
02745 VEC vec, *pos = &bomb->Pos;
02746 WORLD_VERTEX *wv;
02747 WORLD_MIRROR_VERTEX *wmv;
02748 REAL dist, mul, push, scalar;
02749
02750
02751
02752 cubelist = World.CubeList;
02753
02754 for (i = 0 ; i < WorldCubeCount ; i++)
02755 {
02756
02757
02758
02759 if (cubelist[i]->Xmin > bomb->Box.XMax || cubelist[i]->Xmax < bomb->Box.XMin ||
02760 cubelist[i]->Ymin > bomb->Box.YMax || cubelist[i]->Ymax < bomb->Box.YMin ||
02761 cubelist[i]->Zmin > bomb->Box.ZMax || cubelist[i]->Zmax < bomb->Box.ZMin)
02762 continue;
02763
02764
02765
02766 SubVector((VEC*)&cubelist[i]->CentreX, pos, &vec);
02767 if (Length(&vec) > cubelist[i]->Radius + bomb->SphereRadius + PUTTYBOMB_PUSH_RANGE)
02768 continue;
02769
02770
02771
02772 scalar = (PUTTYBOMB_SPHERE_TIME - bomb->Timer) / PUTTYBOMB_SPHERE_TIME;
02773
02774 if (cubelist[i]->MeshFxFlag & MESHFX_USENEWVERTS)
02775 {
02776 wv = cubelist[i]->Model.VertPtr;
02777 for (j = cubelist[i]->Model.VertNum ; j ; j--, wv++)
02778 {
02779 SubVector((VEC*)&wv->x2, pos, &vec);
02780 dist = Length(&vec);
02781
02782 push = (PUTTYBOMB_PUSH_RANGE - abs(bomb->SphereRadius - dist)) * scalar;
02783 if (push > 0.0f)
02784 {
02785 mul = push / dist;
02786 VecPlusScalarVec((VEC*)&wv->x2, mul, &vec, (VEC*)&wv->x2);
02787 }
02788 }
02789
02790 wmv = cubelist[i]->Model.MirrorVertPtr;
02791 for (j = cubelist[i]->Model.MirrorVertNum ; j ; j--, wmv++)
02792 {
02793 SubVector((VEC*)&wmv->RealVertex->x2, pos, &vec);
02794 dist = Length(&vec);
02795
02796 push = (PUTTYBOMB_PUSH_RANGE - abs(bomb->SphereRadius - dist)) * scalar;
02797 if (push > 0.0f)
02798 {
02799 mul = push / dist;
02800 VecPlusScalarVec((VEC*)&wmv->x2, mul, &vec, (VEC*)&wmv->x2);
02801 }
02802 }
02803 }
02804 else
02805 {
02806 wv = cubelist[i]->Model.VertPtr;
02807 for (j = cubelist[i]->Model.VertNum ; j ; j--, wv++)
02808 {
02809 SubVector((VEC*)&wv->x, pos, &vec);
02810 dist = Length(&vec);
02811
02812 push = (PUTTYBOMB_PUSH_RANGE - abs(bomb->SphereRadius - dist)) * scalar;
02813 if (push > 0.0f)
02814 {
02815 mul = push / dist;
02816 VecPlusScalarVec((VEC*)&wv->x, mul, &vec, (VEC*)&wv->x2);
02817 }
02818 else
02819 {
02820 CopyVec((VEC*)&wv->x, (VEC*)&wv->x2);
02821 }
02822 }
02823
02824 wmv = cubelist[i]->Model.MirrorVertPtr;
02825 for (j = cubelist[i]->Model.MirrorVertNum ; j ; j--, wmv++)
02826 {
02827 SubVector((VEC*)&wmv->RealVertex->x, pos, &vec);
02828 dist = Length(&vec);
02829
02830 push = (PUTTYBOMB_PUSH_RANGE - abs(bomb->SphereRadius - dist)) * scalar;
02831 if (push > 0.0f)
02832 {
02833 mul = push / dist;
02834 VecPlusScalarVec((VEC*)&wmv->x, mul, &vec, (VEC*)&wmv->x2);
02835 }
02836 else
02837 {
02838 CopyVec((VEC*)&wmv->x, (VEC*)&wmv->x2);
02839 }
02840 }
02841 }
02842
02843
02844
02845 cubelist[i]->MeshFxFlag |= MESHFX_USENEWVERTS;
02846 }
02847 }
02848
02850
02852
02853 void PuttyBombModelMeshFxChecker(void *data)
02854 {
02855 long j;
02856 REAL push, dist, mul, scalar, rad = ModelMeshModel->Radius;
02857 OBJECT *obj = (OBJECT*)data;
02858 PUTTYBOMB_OBJ *bomb = (PUTTYBOMB_OBJ*)obj->Data;
02859 VEC delta, newdelta, vec;
02860 MODEL_VERTEX *mv;
02861
02862
02863
02864 if (ModelMeshPos->v[X] + rad < bomb->Box.XMin ||
02865 ModelMeshPos->v[X] - rad > bomb->Box.XMax ||
02866 ModelMeshPos->v[Y] + rad < bomb->Box.YMin ||
02867 ModelMeshPos->v[Y] - rad > bomb->Box.YMax ||
02868 ModelMeshPos->v[Z] + rad < bomb->Box.ZMin ||
02869 ModelMeshPos->v[Z] - rad > bomb->Box.ZMax)
02870 return;
02871
02872
02873
02874 SubVector(&bomb->Pos, ModelMeshPos, &delta);
02875
02876
02877
02878 dist = Length(&delta);
02879 if (dist > rad + bomb->SphereRadius + PUTTYBOMB_PUSH_RANGE)
02880 return;
02881
02882
02883
02884 TransposeRotVector(ModelMeshMat, &delta, &newdelta);
02885
02886
02887
02888 if (ModelMeshModel->Xmax < newdelta.v[X] - bomb->SphereRadius ||
02889 ModelMeshModel->Xmin > newdelta.v[X] + bomb->SphereRadius ||
02890 ModelMeshModel->Ymax < newdelta.v[Y] - bomb->SphereRadius ||
02891 ModelMeshModel->Ymin > newdelta.v[Y] + bomb->SphereRadius ||
02892 ModelMeshModel->Zmax < newdelta.v[Z] - bomb->SphereRadius ||
02893 ModelMeshModel->Zmin > newdelta.v[Z] + bomb->SphereRadius)
02894 return;
02895
02896
02897
02898 scalar = (PUTTYBOMB_SPHERE_TIME - bomb->Timer) / PUTTYBOMB_SPHERE_TIME;
02899
02900 mv = ModelMeshModel->VertPtr;
02901
02902 if (*ModelMeshFlag & MODEL_USENEWVERTS)
02903 {
02904 for (j = ModelMeshModel->VertNum ; j ; j--, mv++)
02905 {
02906 SubVector((VEC*)&mv->x2, &newdelta, &vec);
02907 dist = Length(&vec);
02908
02909 push = (PUTTYBOMB_PUSH_RANGE - abs(bomb->SphereRadius - dist)) * scalar;
02910 if (push > 0.0f)
02911 {
02912 mul = push / dist;
02913 VecPlusScalarVec((VEC*)&mv->x2, mul, &vec, (VEC*)&mv->x2);
02914 }
02915 }
02916 }
02917 else
02918 {
02919 for (j = ModelMeshModel->VertNum ; j ; j--, mv++)
02920 {
02921 SubVector((VEC*)&mv->x, &newdelta, &vec);
02922 dist = Length(&vec);
02923
02924 push = (PUTTYBOMB_PUSH_RANGE - abs(bomb->SphereRadius - dist)) * scalar;
02925 if (push > 0.0f)
02926 {
02927 mul = push / dist;
02928 VecPlusScalarVec((VEC*)&mv->x, mul, &vec, (VEC*)&mv->x2);
02929 }
02930 else
02931 {
02932 CopyVec((VEC*)&mv->x, (VEC*)&mv->x2);
02933 }
02934 }
02935 }
02936
02937
02938
02939 *ModelMeshFlag |= MODEL_USENEWVERTS;
02940 }
02941
02943
02945
02946 void RenderElectroPulse(OBJECT *obj)
02947 {
02948 long i;
02949 ELECTROPULSE_OBJ *electro = (ELECTROPULSE_OBJ*)obj->Data;
02950 CAR *car = &obj->player->car;
02951 VEC v1, v2;
02952 PLAYER *nplayer;
02953
02954
02955
02956 obj->renderflag.visible |= RenderObjectModel(&car->Body->Centre.WMatrix, &car->BodyWorldPos, &electro->Model, obj->EnvRGB, obj->renderflag);
02957
02958
02959
02960 for (i = 0 ; i < electro->JumpFlag ; i++)
02961 {
02962 nplayer = (PLAYER*)electro->Player[i];
02963
02964 RotTransVector(&nplayer->car.Body->Centre.WMatrix, &nplayer->car.BodyWorldPos, &electro->JumpPos1[i], &v1);
02965 RotTransVector(&obj->player->car.Body->Centre.WMatrix, &obj->player->car.BodyWorldPos, &electro->JumpPos2[i], &v2);
02966 DrawJumpSpark(&v1, &v2);
02967 }
02968 }
02969
02971
02973
02974 void RenderOilSlick(OBJECT *obj)
02975 {
02976 OILSLICK_OBJ *oil = (OILSLICK_OBJ*)obj->Data;
02977 FACING_POLY poly;
02978 long rgb;
02979 BOUNDING_BOX box;
02980
02981
02982
02983 if (!oil->Mode)
02984 {
02985 if (oil->Age < 0.5f)
02986 poly.Xsize = poly.Ysize = oil->Age * 48.0f + 8.0f;
02987 else
02988 poly.Xsize = poly.Ysize = 32.0f;
02989
02990 poly.U = 130.0f / 256.0f;
02991 poly.V = 66.0f / 256.0f;
02992 poly.Usize = poly.Vsize = 60.0f / 256.0f;
02993 poly.Tpage = TPAGE_FX1;
02994 poly.RGB = 0xffffff;
02995
02996 DrawFacingPoly(&obj->body.Centre.Pos, &poly, 2, 0);
02997 }
02998
02999
03000
03001 else
03002 {
03003 SET_TPAGE(TPAGE_FX1);
03004
03005 if (oil->Age < 28.0f)
03006 {
03007 rgb = 0xffffff;
03008 }
03009 else
03010 {
03011 FTOL((30.0f - oil->Age) * 127, rgb);
03012 rgb |= (rgb << 8) | (rgb << 16);
03013 }
03014
03015 DrawShadow(&oil->Pos[0], &oil->Pos[1], &oil->Pos[2], &oil->Pos[3], 130.0f / 256.0f, 66.0f / 256.0f, 60.0f / 256.0f, 60.0f / 256.0f, rgb, -2.0f, 256.0f, 2, TPAGE_FX1, &box);
03016
03017 oil->Ymin = box.Ymin - 1.0f;
03018 oil->Ymax = box.Ymax + 1.0f;
03019 }
03020 }
03021
03023
03025
03026 void RenderChromeBall(OBJECT *obj)
03027 {
03028 CHROMEBALL_OBJ *ball = (CHROMEBALL_OBJ*)obj->Data;
03029 CAR *car = &obj->player->car;
03030 MAT mat;
03031 REAL mul;
03032 REAL z;
03033 BOUNDING_BOX box;
03034 MODEL *model = &LevelModel[obj->DefaultModel].Model;
03035 VEC v0, v1, v2, v3, *pos = &obj->body.Centre.Pos;
03036 long visflag;
03037 short flag = MODEL_ENV;
03038
03039
03040
03041 CopyMat(&obj->body.Centre.WMatrix, &mat);
03042 mul = ball->Radius / LevelModel[obj->DefaultModel].Model.Radius;
03043 mat.m[XX] *= mul;
03044 mat.m[XY] *= mul;
03045 mat.m[XZ] *= mul;
03046 mat.m[YX] *= mul;
03047 mat.m[YY] *= mul;
03048 mat.m[YZ] *= mul;
03049 mat.m[ZX] *= mul;
03050 mat.m[ZY] *= mul;
03051 mat.m[ZZ] *= mul;
03052
03053
03054
03055 box.Xmin = pos->v[X] - model->Radius;
03056 box.Xmax = pos->v[X] + model->Radius;
03057 box.Ymin = pos->v[Y] - model->Radius;
03058 box.Ymax = pos->v[Y] + model->Radius;
03059 box.Zmin = pos->v[Z] - model->Radius;
03060 box.Zmax = pos->v[Z] + model->Radius;
03061
03062
03063
03064 if (TestObjectVisiboxes(&box))
03065 return;
03066
03067
03068
03069 visflag = TestSphereToFrustum(pos, ball->Radius, &z);
03070 if (visflag == SPHERE_OUT) return;
03071 if (visflag == SPHERE_IN) flag |= MODEL_DONOTCLIP;
03072
03073
03074
03075 obj->renderflag.visible = TRUE;
03076
03077
03078
03079 SetEnvStatic(pos, &obj->body.Centre.WMatrix, 0x808080, 0.0f, 0.1f, 0.5f);
03080
03081
03082
03083 if (CheckObjectLight(pos, &box, model->Radius))
03084 {
03085 flag |= MODEL_LIT;
03086 AddModelLight(model, pos, &obj->body.Centre.WMatrix);
03087 }
03088
03089
03090
03091 if (RenderSettings.Mirror)
03092 {
03093 if (GetMirrorPlane(pos))
03094 {
03095 if (ViewCameraPos.v[Y] < MirrorHeight)
03096 flag |= MODEL_MIRROR;
03097 }
03098 }
03099
03100
03101
03102 if (z + model->Radius > RenderSettings.FogStart && DxState.Fog)
03103 {
03104 ModelVertFog = (pos->v[Y] - RenderSettings.VertFogStart) * RenderSettings.VertFogMul;
03105 if (ModelVertFog < 0) ModelVertFog = 0;
03106 if (ModelVertFog > 255) ModelVertFog = 255;
03107
03108 flag |= MODEL_FOG;
03109 FOG_ON();
03110 }
03111
03112
03113
03114 CheckModelMeshFx(model, &obj->body.Centre.WMatrix, pos, &flag);
03115
03116
03117
03118 DrawModel(model, &mat, pos, flag);
03119
03120
03121
03122 if (flag & MODEL_FOG)
03123 FOG_OFF();
03124
03125
03126
03127 SetVector(&v0, pos->v[X] - ball->Radius, pos->v[Y], pos->v[Z] - ball->Radius);
03128 SetVector(&v1, pos->v[X] + ball->Radius, pos->v[Y], pos->v[Z] - ball->Radius);
03129 SetVector(&v2, pos->v[X] + ball->Radius, pos->v[Y], pos->v[Z] + ball->Radius);
03130 SetVector(&v3, pos->v[X] - ball->Radius, pos->v[Y], pos->v[Z] + ball->Radius);
03131
03132 DrawShadow(&v0, &v1, &v2, &v3, 193.0f / 256.0f, 129.0f / 256.0f, 62.0f / 256.0f, 62.0f / 256.0f, 0x808080, -2.0f, 0.0f, 2, TPAGE_FX1, NULL);
03133 }
03134
03136
03138
03139 void RenderElectroZapped(OBJECT *obj)
03140 {
03141 ELECTROZAPPED_OBJ *electro = (ELECTROZAPPED_OBJ*)obj->Data;
03142 CAR *car = &obj->player->car;
03143
03144
03145
03146 obj->renderflag.visible |= RenderObjectModel(&car->Body->Centre.WMatrix, &car->BodyWorldPos, &electro->Model, obj->EnvRGB, obj->renderflag);
03147 }
03148
03150
03152
03153 void RenderBombGlow(OBJECT *obj)
03154 {
03155 BOMBGLOW_OBJ *glow = (BOMBGLOW_OBJ*)obj->Data;
03156 CAR *car = &obj->player->car;
03157
03158
03159
03160 obj->renderflag.visible |= RenderObjectModel(&car->Body->Centre.WMatrix, &car->BodyWorldPos, &glow->Model, obj->EnvRGB, obj->renderflag);
03161 }
03162
03164
03166
03167 void RenderWaterBomb(OBJECT *obj)
03168 {
03169 WATERBOMB_OBJ *bomb = (WATERBOMB_OBJ*)obj->Data;
03170 VEC vec, vec2;
03171 MAT mat;
03172
03173
03174
03175 SetVector(&vec2, WaterBombOff.v[X], WaterBombOff.v[Y] + (WATERBOMB_RADIUS * bomb->ScalarHoriz) - WATERBOMB_RADIUS, WaterBombOff.v[Z]);
03176 RotTransVector(&obj->body.Centre.WMatrix, &obj->body.Centre.Pos, &vec2, &vec);
03177 CopyMatrix(&obj->body.Centre.WMatrix, &mat);
03178
03179 mat.m[RX] *= bomb->ScalarHoriz;
03180 mat.m[RY] *= bomb->ScalarHoriz;
03181 mat.m[RZ] *= bomb->ScalarHoriz;
03182 mat.m[LX] *= bomb->ScalarHoriz;
03183 mat.m[LY] *= bomb->ScalarHoriz;
03184 mat.m[LZ] *= bomb->ScalarHoriz;
03185
03186 mat.m[YX] *= bomb->ScalarVert;
03187 mat.m[YY] *= bomb->ScalarVert;
03188 mat.m[YZ] *= bomb->ScalarVert;
03189
03190
03191
03192 obj->renderflag.visible |= RenderObjectModel(&mat, &vec, &LevelModel[obj->DefaultModel].Model, obj->EnvRGB, obj->renderflag);
03193 }
03194
03196
03198
03199 void RenderPuttyBombBang(OBJECT *obj)
03200 {
03201 PUTTYBOMB_OBJ *bomb = (PUTTYBOMB_OBJ*)obj->Data;
03202 long i, frame, rgb;
03203 REAL mul, x, z, tu, tv, size;
03204 FACING_POLY poly;
03205 MAT mat;
03206 MODEL *model = &LevelModel[obj->DefaultModel].Model;
03207 MODEL_POLY *mp;
03208 POLY_RGB *mrgb;
03209 VEC v0, v1, v2, v3;
03210
03211
03212
03213 poly.Usize = poly.Vsize = 30.0f / 256.0f;
03214 poly.Tpage = TPAGE_FX3;
03215 poly.RGB = 0xffffff;
03216
03217 for (i = 0 ; i < PUTTYBOMB_BANG_NUM ; i++) if (bomb->Bang[i].Age >= 0.0f && bomb->Bang[i].Age < bomb->Bang[i].Life)
03218 {
03219 FTOL(bomb->Bang[i].Age / bomb->Bang[i].Life * 16.0f, frame);
03220 poly.U = ((float)(frame & 7) * 32.0f + 1.0f) / 256.0f;
03221 poly.V = ((float)(frame / 8) * 32.0f + 33.0f) / 256.0f;
03222
03223 poly.Xsize = poly.Ysize = bomb->Bang[i].Size;
03224
03225 DrawFacingPoly(&bomb->Bang[i].Pos, &poly, 1, 0.0f);
03226 }
03227
03228
03229
03230 if (bomb->Timer < PUTTYBOMB_SPHERE_TIME)
03231 {
03232
03233
03234
03235 FTOL((PUTTYBOMB_SPHERE_TIME - bomb->Timer) / PUTTYBOMB_SPHERE_TIME * 255.0f, rgb);
03236 rgb |= rgb << 8 | rgb << 16;
03237
03238 mp = model->PolyPtr;
03239 mrgb = model->PolyRGB;
03240
03241 for (i = model->PolyNum ; i ; i--, mp++, mrgb++)
03242 {
03243 mp->tu0 = mp->v0->tu;
03244 mp->tv0 = mp->v0->tv;
03245
03246 mp->tu1 = mp->v1->tu;
03247 mp->tv1 = mp->v1->tv;
03248
03249 mp->tu2 = mp->v2->tu;
03250 mp->tv2 = mp->v2->tv;
03251
03252 if (mp->Type & POLY_QUAD)
03253 {
03254 mp->tu3 = mp->v3->tu;
03255 mp->tv3 = mp->v3->tv;
03256 }
03257
03258 *(long*)&mrgb->rgb[0] = rgb;
03259 *(long*)&mrgb->rgb[1] = rgb;
03260 *(long*)&mrgb->rgb[2] = rgb;
03261 *(long*)&mrgb->rgb[3] = rgb;
03262 }
03263
03264
03265
03266 CopyMatrix(&Identity, &mat);
03267
03268 mul = bomb->SphereRadius / model->Radius;
03269
03270 VecMulScalar(&mat.mv[R], mul);
03271 VecMulScalar(&mat.mv[U], mul);
03272 VecMulScalar(&mat.mv[L], mul);
03273
03274 if (obj->DefaultModel != -1)
03275 obj->renderflag.visible |= RenderObjectModel(&mat, &bomb->Pos, &LevelModel[obj->DefaultModel].Model, 0, obj->renderflag);
03276
03277
03278
03279 if (bomb->Timer < PUTTYBOMB_SPHERE_TIME)
03280 {
03281 size = bomb->SphereRadius * 0.5f;
03282
03283 for (x = -2.0f ; x < 2.0f ; x++) for (z = -2.0f ; z < 2.0f ; z++)
03284 {
03285 SetVector(&v0, x * size + bomb->Pos.v[X], bomb->Pos.v[Y] - 256.0f, z * size + bomb->Pos.v[Z]);
03286 SetVector(&v1, v0.v[X] + size, bomb->Pos.v[Y] - 256.0f, v0.v[Z]);
03287 SetVector(&v2, v0.v[X] + size, bomb->Pos.v[Y] - 256.0f, v0.v[Z] + size);
03288 SetVector(&v3, v0.v[X], bomb->Pos.v[Y] - 256.0f, v0.v[Z] + size);
03289
03290 tu = (64.0f + x * 31.0f) / 256.0f;
03291 tv = (192.0f + z * 31.0f) / 256.0f;
03292
03293 DrawShadow(&v0, &v1, &v2, &v3, tu, tv, 31.0f / 256.0f, 31.0f / 256.0f, rgb, -2.0f, 512.0f, 1, TPAGE_FX3, NULL);
03294 }
03295 }
03296 }
03297 }
03298
03299 #endif
03300
03302
03303
03304
03306
03307 OBJECT *WeaponTarget(OBJECT *playerObj)
03308 {
03309 REAL score, best;
03310 REAL dRLen, lookdR;
03311 VEC dR;
03312 PLAYER *target, *bestTarget, *player;
03313
03314
03315 best = -LARGEDIST;
03316 bestTarget = NULL;
03317 player = playerObj->player;
03318
03319 Assert(player != NULL);
03320
03321
03322 for (target = PLR_PlayerHead; target != NULL; target = target->next) {
03323
03324
03325 if ((target->type != PLAYER_CPU) && (player->type != PLAYER_REMOTE) && (player->type != PLAYER_LOCAL)) continue;
03326
03327
03328 if (target == player) continue;
03329
03330
03331 VecMinusVec(&target->car.Body->Centre.Pos, &player->car.Body->Centre.Pos, &dR);
03332 dRLen = VecLen(&dR);
03333 if (dRLen > SMALL_REAL) {
03334 VecDivScalar(&dR, dRLen);
03335 } else {
03336 SetVecZero(&dR);
03337 }
03338
03339
03340 if ((dRLen > WEAPON_RANGE_MAX) || (dRLen < WEAPON_RANGE_MIN)) continue;
03341
03342
03343 lookdR = VecDotVec(&dR, &player->car.Body->Centre.WMatrix.mv[L]) - WEAPON_DIR_OFFSET;
03344
03345
03346 if ((dRLen > (WEAPON_RANGE_MAX * lookdR)) || (lookdR < ZERO)) {
03347 continue;
03348 }
03349
03350
03351 score = (WEAPON_RANGE_MAX / (dRLen + WEAPON_RANGE_OFFSET)) * (lookdR * lookdR * lookdR * lookdR);
03352
03353 if (score > best) {
03354 best = score;
03355 bestTarget = target;
03356 }
03357
03358 }
03359
03360 if (bestTarget == NULL) {
03361 return NULL;
03362 }
03363
03364 return bestTarget->ownobj;
03365 }