00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include "revolt.h"
00018 #ifndef _PSX
00019 #include "main.h"
00020 #endif
00021 #include "geom.h"
00022 #include "particle.h"
00023 #include "model.h"
00024 #include "aerial.h"
00025 #include "newcoll.h"
00026 #include "body.h"
00027 #include "car.h"
00028 #include "ctrlread.h"
00029 #include "object.h"
00030 #include "ainode.h"
00031 #include "move.h"
00032 #include "player.h"
00033 #ifndef _PSX
00034 #include "timing.h"
00035 #endif
00036 #include "ai.h"
00037 #include "ai_car.h"
00038 #include "spark.h"
00039 #include "newcoll.h"
00040 #ifndef _PSX
00041 #include "obj_init.h"
00042 #endif
00043 #ifdef _PC
00044 #include "registry.h"
00045 #include "ghost.h"
00046 #include "input.h"
00047 #endif
00048 #include "weapon.h"
00049 #ifndef _PSX
00050 #include "visibox.h"
00051 #endif
00052
00053
00054
00055
00056
00057
00058 long AI_Testing = FALSE;
00059
00060
00061
00062
00063
00064 static VEC PlanePropOff = {0, -120, 110};
00065 static VEC CopterBlade1Off = {0, -340, 66};
00066 static VEC CopterBlade2Off = {28, -252, -200};
00067 static VEC TrainSteamOffset = {0, -550, -196};
00068 static VEC TrainSteamDir = {0, -350, 0};
00069 static VEC BoatSteamOffset = {0, -350, 0};
00070 static VEC BoatSteamVel = {0, -500, -100};
00071 static VEC TrainWheelOffsets[] = {{98, -136, 330}, {-98, -136, 330}, {98, -92, -204}, {-98, -92, -204}};
00072
00073
00074
00075
00076
00077 void AI_ProcessAllAIs(void);
00078 void AI_CarAiHandler(OBJECT *obj);
00079
00080 static void UpdateCarFinishDist(PLAYER *player);
00081 static void UpdatePlayerPickup(PLAYER *player);
00082 static void UpdateCarSfx(CAR *car);
00083 static void UpdateCarMisc(CAR *car);
00084 static void TurnCopter(OBJECT *obj);
00085 static void FlyCopter(OBJECT *obj);
00086 static void CopterWait(OBJECT *obj);
00087 void NewCopterDest(OBJECT *obj);
00088 void AI_LaserHandler(OBJECT *obj);
00089
00090 void SparkGenHandler(OBJECT *obj);
00091
00092
00093
00094 #ifdef _PC
00095 long SfxScrapeList[] = {
00096 SFX_SCRAPE1,
00097 SFX_SCRAPE1,
00098 SFX_SCRAPE1,
00099 SFX_SCRAPE1,
00100 SFX_SCRAPE1,
00101 SFX_SCRAPE1,
00102 SFX_SCRAPE1,
00103 SFX_SCRAPE1,
00104 SFX_SCRAPE1,
00105 SFX_SCRAPE1,
00106 SFX_SCRAPE1,
00107 SFX_SCRAPE1,
00108 SFX_SCRAPE1,
00109 SFX_SCRAPE1,
00110 SFX_SCRAPE1,
00111 SFX_SCRAPE1,
00112 SFX_SCRAPE1,
00113 SFX_SCRAPE1,
00114 SFX_SCRAPE1,
00115 SFX_SCRAPE1,
00116 SFX_SCRAPE1,
00117 SFX_SCRAPE1,
00118 SFX_SCRAPE1,
00119 };
00120 #endif
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130 void AI_ProcessAllAIs(void)
00131 {
00132 OBJECT *obj, *next;
00133
00134 for (obj = OBJ_ObjectHead ; obj ; )
00135 {
00136 next = obj->next;
00137 if (obj->aihandler)
00138 {
00139 obj->aihandler(obj);
00140 }
00141 obj = next;
00142 }
00143 }
00144
00145
00146
00147
00149
00151
00152 void AI_CarAiHandler(OBJECT *obj)
00153 {
00154 obj->player->LastValidRailCamNode = obj->player->ValidRailCamNode;
00155 obj->player->ValidRailCamNode = -1;
00156 #ifndef _PSX
00157 CAI_CarHelper(obj->player);
00158 UpdateCarFinishDist(obj->player);
00159 #endif
00160 #ifdef _PC
00161 CarAccTimings(&obj->player->car);
00162 UpdateCarSfx(&obj->player->car);
00163 UpdatePlayerPickup(obj->player);
00164 #endif
00165 UpdateCarMisc(&obj->player->car);
00166
00167 #ifndef _PSX
00168 if (AI_Testing)
00169 {
00170 obj->player->CarAI.CurNode = AIN_GetForwardNode(obj->player, 200, (REAL *)&obj->player->CarAI.NodeDist);
00171 }
00172 #endif
00173 }
00174
00175 void AI_RemoteAiHandler(OBJECT *obj)
00176 {
00177 obj->player->LastValidRailCamNode = obj->player->ValidRailCamNode;
00178 obj->player->ValidRailCamNode = -1;
00179 #ifdef _PC
00180
00181 UpdateCarFinishDist(obj->player);
00182 UpdateCarSfx(&obj->player->car);
00183 UpdateCarMisc(&obj->player->car);
00184 UpdatePlayerPickup(obj->player);
00185 #endif
00186 }
00187
00188 void AI_GhostCarAiHandler(OBJECT *obj)
00189 {
00190 obj->player->LastValidRailCamNode = obj->player->ValidRailCamNode;
00191 obj->player->ValidRailCamNode = -1;
00192 #ifdef _PC
00193 MOV_MoveGhost(obj);
00194 UpdateCarFinishDist(obj->player);
00195 UpdateCarSfx(&obj->player->car);
00196 UpdateCarMisc(&obj->player->car);
00197 UpdatePlayerPickup(obj->player);
00198 #endif
00199 }
00200
00202
00204
00205 static void UpdateCarFinishDist(PLAYER *player)
00206 {
00207 #ifndef _PSX
00208
00209 AINODE *cnode, *nnode;
00210 REAL cdist, ndist, dist, add, max;
00211 VEC vec, norm;
00212 long i;
00213
00214
00215
00216 if (!AiNodeNum)
00217 return;
00218
00219
00220
00221 cnode = &AiNode[player->CarAI.FinishDistNode];
00222 SubVector(&cnode->Centre, &player->car.Body->Centre.Pos, &vec);
00223 cdist = vec.v[X] * vec.v[X] + vec.v[Y] * vec.v[Y] + vec.v[Z] * vec.v[Z];
00224
00225 ndist = FLT_MAX;
00226
00227
00228
00229 for (i = 0 ; i < MAX_AINODE_LINKS ; i++)
00230 {
00231 if (cnode->Prev[i])
00232 {
00233 SubVector(&cnode->Prev[i]->Centre, &player->car.Body->Centre.Pos, &vec);
00234 dist = vec.v[X] * vec.v[X] + vec.v[Y] * vec.v[Y] + vec.v[Z] * vec.v[Z];
00235
00236 if (dist < ndist)
00237 {
00238 ndist = dist;
00239 nnode = cnode->Prev[i];
00240 }
00241 }
00242
00243 if (cnode->Next[i])
00244 {
00245 SubVector(&cnode->Next[i]->Centre, &player->car.Body->Centre.Pos, &vec);
00246 dist = vec.v[X] * vec.v[X] + vec.v[Y] * vec.v[Y] + vec.v[Z] * vec.v[Z];
00247
00248 if (dist < ndist)
00249 {
00250 ndist = dist;
00251 nnode = cnode->Next[i];
00252 }
00253 }
00254 }
00255
00256
00257
00258 if (ndist < cdist)
00259 {
00260 player->CarAI.FinishDistNode = (long)(nnode - AiNode);
00261 }
00262
00263
00264
00265 SetVector(&norm, -cnode->RVec.v[Z], cnode->RVec.v[Y], cnode->RVec.v[X]);
00266 SubVector(&player->car.Body->Centre.Pos, &cnode->Centre, &vec);
00267 player->CarAI.FinishDist = cnode->FinishDist + DotProduct(&norm, &vec);
00268
00269
00270
00271 player->CarAI.WrongWay = (DotProduct(&norm, &player->car.Body->Centre.WMatrix.mv[L]) > 0.7f);
00272
00273
00274
00275 dist = player->CarAI.FinishDist / AiNodeTotalDist;
00276 add = dist - player->CarAI.FinishDistPanel;
00277
00278 if (add > 0.5f) add -= 1.0f;
00279 else if (add < -0.5f) add += 1.0f;
00280
00281 max = 0.1f * TimeStep;
00282 if (add > max) add = max;
00283 else if (add < -max) add = -max;
00284
00285 player->CarAI.FinishDistPanel += add;
00286 if (player->CarAI.FinishDistPanel >= 1.0f) player->CarAI.FinishDistPanel -= 1.0f;
00287 else if (player->CarAI.FinishDistPanel < 0.0f) player->CarAI.FinishDistPanel += 1.0f;
00288
00289 #endif
00290 }
00291
00293
00295 #ifndef _PSX
00296 static void UpdatePlayerPickup(PLAYER *player)
00297 {
00298 REAL f;
00299
00300
00301
00302 static long pickup = PICKUP_NONE;
00303 #ifdef _PC
00304 if (Keys[DIK_RSHIFT] && !LastKeys[DIK_RSHIFT] && player == PLR_LocalPlayer)
00305 #endif
00306 #ifdef _N64
00307 if ((player == PLR_LocalPlayer) && (player->controls.digital & CTRL_SELWEAPON))
00308 #endif
00309 {
00310 pickup = (pickup + 1) % PICKUP_NUM;
00311 player->PickupType = pickup;
00312 player->PickupNum = 1000000;
00313 }
00314
00315
00316
00317 if (player->PickupCycleSpeed) {
00318
00319
00320
00321 player->PickupCycleSpeed -= TimeStep;
00322
00323
00324
00325 player->PickupCycleType += player->PickupCycleSpeed * TimeStep * 2.0f;
00326 if (player->PickupCycleType > PICKUP_NUM)
00327 player->PickupCycleType -= PICKUP_NUM;
00328
00329
00330
00331 f = 1.0f - (player->PickupCycleType - (float)(long)player->PickupCycleType);
00332 if (player->PickupCycleSpeed < f)
00333 {
00334
00335
00336
00337 player->PickupCycleSpeed = 0;
00338 player->PickupType = (long)(player->PickupCycleType + 0.5f) % PICKUP_NUM;
00339 player->PickupTarget = NULL;
00340
00341 if (player->PickupType == PICKUP_FIREWORKPACK)
00342 player->PickupNum = 3;
00343 else
00344 player->PickupNum = 1;
00345 }
00346
00347 }
00348
00349
00350 if ((player->PickupType == PICKUP_FIREWORK) || (player->PickupType == PICKUP_FIREWORKPACK)) {
00351 player->PickupTarget = WeaponTarget(player->ownobj);
00352 }
00353 }
00354 #endif
00355
00357
00359 #ifdef _PC
00360 static void UpdateCarSfx(CAR *car)
00361 {
00362 long i, revs, vel, maxvol, time, sfx, screech;
00363
00364
00365
00366 FTOL(abs(car->Revs), revs);
00367 FTOL(Length(&car->Body->Centre.Vel), vel);
00368
00369
00370
00371 if (car->SfxEngine)
00372 {
00373 car->SfxEngine->Freq = 10000 + revs * 80;
00374
00375 car->SfxEngine->Vol = revs / 2;
00376 if (car->SfxEngine->Vol > SFX_MAX_VOL) car->SfxEngine->Vol = SFX_MAX_VOL;
00377
00378 CopyVec(&car->Body->Centre.Pos, &car->SfxEngine->Pos);
00379 }
00380
00381
00382
00383 if (car->Body->ScrapeMaterial == MATERIAL_NONE)
00384 {
00385 if (car->SfxScrape)
00386 {
00387 FreeSfx3D(car->SfxScrape);
00388 car->SfxScrape = NULL;
00389 }
00390 }
00391 else
00392 {
00393 sfx = SfxScrapeList[car->Body->ScrapeMaterial];
00394
00395 if (!car->SfxScrape)
00396 {
00397 car->SfxScrape = CreateSfx3D(sfx, 0, 0, TRUE, &car->Body->Centre.Pos);
00398 car->ScrapeMaterial = car->Body->ScrapeMaterial;
00399 }
00400
00401 if (car->SfxScrape)
00402 {
00403 car->SfxScrape->Freq = 20000 + vel * 5;
00404
00405 FTOL(TimeStep * 600.0f, time);
00406 if (!time) time = 1;
00407 maxvol = car->SfxScrape->Vol + time;
00408 if (maxvol > SFX_MAX_VOL) maxvol = SFX_MAX_VOL;
00409
00410 car->SfxScrape->Vol = vel / 10;
00411 if (car->SfxScrape->Vol > maxvol) car->SfxScrape->Vol = maxvol;
00412
00413 CopyVec(&car->Body->Centre.Pos, &car->SfxScrape->Pos);
00414
00415 if (car->ScrapeMaterial != car->Body->ScrapeMaterial)
00416 {
00417 ChangeSfxSample3D(car->SfxScrape, sfx);
00418 car->ScrapeMaterial = car->Body->ScrapeMaterial;
00419 }
00420 }
00421 }
00422
00423
00424
00425 screech = FALSE;
00426 for (i = 0 ; i < CAR_NWHEELS ; i++)
00427 {
00428 if (IsWheelPresent(&car->Wheel[i]) && IsWheelSkidding(&car->Wheel[i]) && IsWheelInContact(&car->Wheel[i]))
00429 {
00430 screech = TRUE;
00431 break;
00432 }
00433 }
00434
00435 if (!screech)
00436 {
00437 if (car->SfxScreech)
00438 {
00439 FreeSfx3D(car->SfxScreech);
00440 car->SfxScreech = NULL;
00441 }
00442 }
00443 else
00444 {
00445 if (!car->SfxScreech)
00446 {
00447 car->SfxScreech = CreateSfx3D(SFX_SCREECH, 0, 0, TRUE, &car->Body->Centre.Pos);
00448 }
00449
00450 if (car->SfxScreech)
00451 {
00452 car->SfxScreech->Freq = 15000 + vel * 2;
00453
00454 FTOL(TimeStep * 600.0f, time);
00455 if (!time) time = 1;
00456 maxvol = car->SfxScreech->Vol + time;
00457 if (maxvol > SFX_MAX_VOL) maxvol = SFX_MAX_VOL;
00458
00459 car->SfxScreech->Vol = vel / 10;
00460 if (car->SfxScreech->Vol > maxvol) car->SfxScreech->Vol = maxvol;
00461
00462 CopyVec(&car->Body->Centre.Pos, &car->SfxScreech->Pos);
00463 }
00464 }
00465 }
00466 #endif
00467
00469
00471 static void UpdateCarMisc(CAR *car)
00472 {
00473 VEC vec;
00474 MAT mat1, mat2;
00475
00476
00477
00478 #ifdef _PC
00479 if (RenderSettings.Env)
00480 {
00481 SubVector(&car->Body->Centre.Pos, &car->Body->Centre.OldPos, &vec);
00482 RotMatrixZYX(&mat1, vec.v[X] / 6144, 0, vec.v[Z] / 6144);
00483 MulMatrix(&car->EnvMatrix, &mat1, &mat2);
00484 CopyMatrix(&mat2, &car->EnvMatrix);
00485 }
00486 #endif
00487
00488
00489
00490 if (car->PowerTimer)
00491 {
00492 car->PowerTimer -= TimeStep;
00493 if (car->PowerTimer < 0.0f)
00494 car->PowerTimer = 0.0f;
00495 }
00496
00497
00498
00499 #ifdef _PC
00500 if (car->AddLit > 0)
00501 {
00502 car->AddLit -= (long)(TimeStep * 1000);
00503 if (car->AddLit < 0) car->AddLit = 0;
00504 }
00505 else if (car->AddLit < 0)
00506 {
00507 car->AddLit += (long)(TimeStep * 1000);
00508 if (car->AddLit > 0) car->AddLit = 0;
00509 }
00510 #endif
00511
00512
00513 if (car->NoReturnTimer > ZERO) {
00514 car->NoReturnTimer -= TimeStep;
00515 }
00516
00517
00518 #ifdef _PC
00519 if (car->Body->BangMag > TO_VEL(Real(300))) {
00520 long vol, freq;
00521
00522
00523
00524 vol = SFX_MAX_VOL;
00525
00526 freq = 22050;
00527
00528 PlaySfx3D(SFX_CHROMEBALL_HIT, vol, freq, &car->Body->Centre.Pos);
00529 }
00530 #endif
00531 car->Body->Banged = FALSE;
00532 car->Body->BangMag = ZERO;
00533 }
00534
00536
00538 #ifndef _PSX
00539
00540 void AI_BarrelHandler(OBJECT *obj)
00541 {
00542 MAT mat, mat2;
00543 BARREL_OBJ *barrel = (BARREL_OBJ*)obj->Data;
00544
00545
00546
00547 if (!obj->renderflag.visible)
00548 return;
00549
00550
00551
00552 RotMatrixX(&mat, barrel->SpinSpeed * TimeFactor);
00553 MulMatrix(&obj->body.Centre.WMatrix, &mat, &mat2);
00554 NormalizeMatrix(&mat2);
00555 CopyMatrix(&mat2, &obj->body.Centre.WMatrix);
00556 }
00557 #endif
00558
00560
00562 #ifndef _PSX
00563 void AI_PlanetHandler(OBJECT *obj)
00564 {
00565 long i;
00566 MAT mat, mat2;
00567 VEC vec;
00568 OBJECT *findobj, *findsun;
00569 REAL len;
00570 PLANET_OBJ *planet = (PLANET_OBJ*)obj->Data, *findplanet;
00571 SUN_OBJ *sun = (SUN_OBJ*)obj->Data;
00572
00573
00574
00575 if (!obj->objref)
00576 {
00577 for (findobj = OBJ_ObjectHead ; findobj ; findobj = findobj->next)
00578 {
00579 findplanet = (PLANET_OBJ*)findobj->Data;
00580 if (findobj->Type == OBJECT_TYPE_PLANET && findplanet->OwnPlanet == planet->OrbitPlanet)
00581 {
00582 obj->objref = findobj;
00583
00584 for (findsun = OBJ_ObjectHead ; findsun ; findsun = findsun->next)
00585 if (findsun->Type == OBJECT_TYPE_PLANET && ((PLANET_OBJ*)findsun->Data)->OwnPlanet == PLANET_SUN)
00586 planet->VisiMask = ((SUN_OBJ*)(findsun->Data))->VisiMask;
00587
00588 break;
00589 }
00590 }
00591
00592 if (!obj->objref)
00593 return;
00594
00595 if (planet->OwnPlanet != PLANET_SUN)
00596 {
00597
00598 SubVector(&obj->body.Centre.Pos, &obj->objref->body.Centre.Pos, &vec);
00599 len = Length(&vec);
00600 SetVector(&planet->OrbitOffset, 0, 0, len);
00601
00602 BuildLookMatrixForward(&obj->objref->body.Centre.Pos, &obj->body.Centre.Pos, &mat2);
00603
00604 RotMatrixZ(&mat, 0.1f);
00605 MulMatrix(&mat2, &mat, &planet->OrbitMatrix);
00606 }
00607 }
00608
00609
00610 if (planet->OwnPlanet != planet->OrbitPlanet)
00611 {
00612 RotMatrixX(&mat, planet->OrbitSpeed * TimeFactor);
00613 MulMatrix(&planet->OrbitMatrix, &mat, &mat2);
00614 NormalizeMatrix(&mat2);
00615 CopyMatrix(&mat2, &planet->OrbitMatrix);
00616 RotTransVector(&planet->OrbitMatrix, &obj->objref->body.Centre.Pos, &planet->OrbitOffset, &obj->body.Centre.Pos);
00617 }
00618
00619
00620
00621
00622 if (!obj->renderflag.visible)
00623 return;
00624
00625
00626
00627 RotMatrixY(&mat, planet->SpinSpeed * TimeFactor);
00628 MulMatrix(&obj->body.Centre.WMatrix, &mat, &mat2);
00629 NormalizeMatrix(&mat2);
00630 CopyMatrix(&mat2, &obj->body.Centre.WMatrix);
00631
00632
00633
00634 if (planet->OwnPlanet != PLANET_SUN)
00635 return;
00636
00637
00638
00639 for (i = 0 ; i < SUN_OVERLAY_NUM ; i++)
00640 {
00641
00642
00643
00644
00645 sun->Overlay[i].Rot += sun->Overlay[i].RotVel * TimeFactor;
00646
00647 sun->Overlay[i].r += (rand() % 5) - 2;
00648 if (sun->Overlay[i].r > 128) sun->Overlay[i].r = 128;
00649 else if (sun->Overlay[i].r < 96) sun->Overlay[i].r = 96;
00650
00651 sun->Overlay[i].g += (rand() % 5) - 2;
00652 if (sun->Overlay[i].g > 128) sun->Overlay[i].g = 128;
00653 else if (sun->Overlay[i].g < 96) sun->Overlay[i].g = 96;
00654
00655 sun->Overlay[i].b += (rand() % 5) - 2;
00656 if (sun->Overlay[i].b > 96) sun->Overlay[i].b = 96;
00657 else if (sun->Overlay[i].b < 64) sun->Overlay[i].b = 64;
00658
00659 sun->Overlay[i].rgb = (sun->Overlay[i].r << 16) | (sun->Overlay[i].g << 8) | sun->Overlay[i].b;
00660 }
00661 }
00662 #endif
00663
00665
00667 #ifndef _PSX
00668 void AI_PlaneHandler(OBJECT *obj)
00669 {
00670 MAT mat;
00671 PLANE_OBJ *plane = (PLANE_OBJ*)obj->Data;
00672
00673
00674
00675 plane->Rot += plane->Speed * TimeFactor;
00676 RotMatrixY(&mat, plane->Rot);
00677 MulMatrix(&mat, &plane->BankMatrix, &obj->body.Centre.WMatrix);
00678 RotTransVector(&mat, &plane->GenPos, &plane->Offset, &obj->body.Centre.Pos);
00679
00680
00681
00682 RotMatrixZ(&mat, (float)TIME2MS(CurrentTimer()) / 500.0f);
00683 MulMatrix(&obj->body.Centre.WMatrix, &mat, &plane->PropMatrix);
00684 RotTransVector(&obj->body.Centre.WMatrix, &obj->body.Centre.Pos, &PlanePropOff, &plane->PropPos);
00685
00686
00687
00688 #ifdef _PC
00689 if (obj->Sfx3D)
00690 {
00691 CopyVec(&obj->body.Centre.Pos, &obj->Sfx3D->Pos);
00692 }
00693 #endif
00694 }
00695
00697
00699 void AI_CopterHandler(OBJECT *obj)
00700 {
00701 MAT mat;
00702 COPTER_OBJ *copter = (COPTER_OBJ*)obj->Data;
00703
00704
00705 switch (copter->State) {
00706 case COPTER_WAIT:
00707 CopterWait(obj);
00708 break;
00709 case COPTER_TURNING:
00710 TurnCopter(obj);
00711 break;
00712 case COPTER_FLYING:
00713 FlyCopter(obj);
00714 break;
00715 default:
00716 break;
00717 }
00718
00719
00720
00721
00722 RotMatrixY(&mat, (float)TIME2MS(CurrentTimer()) / 500.0f);
00723 MulMatrix(&obj->body.Centre.WMatrix, &mat, &copter->BladeMatrix1);
00724 RotTransVector(&obj->body.Centre.WMatrix, &obj->body.Centre.Pos, &CopterBlade1Off, &copter->BladePos1);
00725
00726 RotMatrixX(&mat, (float)TIME2MS(CurrentTimer()) / 400.0f);
00727 MulMatrix(&obj->body.Centre.WMatrix, &mat, &copter->BladeMatrix2);
00728 RotTransVector(&obj->body.Centre.WMatrix, &obj->body.Centre.Pos, &CopterBlade2Off, &copter->BladePos2);
00729
00730
00731 #ifdef _PC
00732 if (obj->Sfx3D)
00733 {
00734 CopyVec(&obj->body.Centre.Pos, &obj->Sfx3D->Pos);
00735 }
00736 #endif
00737 }
00738
00739
00740 void TurnCopter(OBJECT *obj)
00741 {
00742 COPTER_OBJ *copter = (COPTER_OBJ*)obj->Data;
00743
00744
00745
00746 copter->State = COPTER_FLYING;
00747 return;
00748
00749
00750
00751 SLerpQuat(&copter->OldInitialQuat, &copter->InitialQuat, copter->TurnTime / 5, &copter->CurrentUpQuat);
00752 NormalizeQuat(&copter->CurrentUpQuat);
00753 CopyQuat(&copter->CurrentUpQuat, &obj->body.Centre.Quat);
00754 copter->TurnTime += TimeStep;
00755
00756
00757 QuatToMat(&obj->body.Centre.Quat, &obj->body.Centre.WMatrix);
00758
00759 }
00760
00761
00762 void FlyCopter(OBJECT *obj)
00763 {
00764 bool reachedDest;
00765 REAL dRLen, velDest, vel, t;
00766 VEC dR, axis;
00767 QUATERNION dQuat;
00768 COPTER_OBJ *copter = (COPTER_OBJ*)obj->Data;
00769
00770 reachedDest = FALSE;
00771
00772
00773 VecMinusVec(&obj->body.Centre.Pos, &copter->Destination, &dR);
00774 dRLen = VecLen(&dR);
00775
00776
00777 if (dRLen < 10) {
00778 reachedDest = TRUE;
00779 }
00780
00781
00782 velDest = (dRLen);
00783 if (velDest > copter->MaxVel) velDest = copter->MaxVel;
00784
00785 vel = VecLen(&obj->body.Centre.Vel);
00786 if (vel < velDest) {
00787 vel += copter->Acc * TimeStep;
00788 } else if (vel > velDest) {
00789 vel = velDest;
00790 }
00791 if (vel < ZERO) {
00792 vel = ZERO;
00793 reachedDest = TRUE;
00794 }
00795
00796
00797 VecEqScalarVec(&obj->body.Centre.Vel, vel, &copter->Direction);
00798 VecPlusEqScalarVec(&obj->body.Centre.Pos, TimeStep, &obj->body.Centre.Vel);
00799
00800
00801
00802 t = HALF * ((float)sin(((copter->TurnTime - 2.5f) / 5) * PI) + ONE);
00803 SLerpQuat(&copter->OldInitialQuat, &copter->InitialQuat, t, &copter->CurrentUpQuat);
00804 NormalizeQuat(&copter->CurrentUpQuat);
00805 copter->TurnTime += TimeStep;
00806 if (copter->TurnTime >= 5) copter->TurnTime = 5;
00807
00808
00809 VecCrossVec(&copter->Direction, &UpVec, &axis);
00810 VecMulScalar(&axis, -0.15f * vel / copter->MaxVel);
00811
00812
00813 VecMulQuat(&axis, &copter->CurrentUpQuat, &dQuat);
00814 QuatPlusQuat(&copter->CurrentUpQuat, &dQuat, &obj->body.Centre.Quat);
00815 NormalizeQuat(&obj->body.Centre.Quat);
00816 QuatToMat(&obj->body.Centre.Quat, &obj->body.Centre.WMatrix);
00817
00818 if (reachedDest) {
00819 NewCopterDest(obj);
00820 copter->State = COPTER_TURNING;
00821 }
00822
00823 }
00824
00825 void CopterWait(OBJECT *obj)
00826 {
00827 REAL dPosLen;
00828 COPTER_OBJ *copter = (COPTER_OBJ*)obj->Data;
00829
00830
00831 copter->TurnTime += TimeStep;
00832 if (copter->TurnTime > 2) {
00833
00834
00835 SetVec(&copter->Destination,
00836 obj->body.Centre.Pos.v[X] - 600 * obj->body.Centre.WMatrix.mv[L].v[X],
00837 copter->FlyBox.YMin,
00838 obj->body.Centre.Pos.v[Z] - 600 * obj->body.Centre.WMatrix.mv[L].v[Z]);
00839 VecMinusVec(&copter->Destination, &obj->body.Centre.Pos, &copter->Direction);
00840 dPosLen = VecLen(&copter->Direction);
00841 VecDivScalar(&copter->Direction, dPosLen);
00842 CopyQuat(&copter->CurrentUpQuat, &copter->OldInitialQuat);
00843 copter->State = COPTER_FLYING;
00844 }
00845 }
00846
00847
00848 void NewCopterDest(OBJECT *obj)
00849 {
00850 int its;
00851 MAT newMat;
00852 REAL dPosLen, lookLen;
00853 VEC look;
00854 COPTER_OBJ *copter = (COPTER_OBJ*)obj->Data;
00855
00856 SetVecZero(&obj->body.Centre.Vel);
00857 CopyQuat(&copter->CurrentUpQuat, &copter->OldInitialQuat);
00858 copter->TurnTime = ZERO;
00859
00860
00861 its = 0;
00862 do {
00863 SetVec(&copter->Destination,
00864 copter->FlyBox.XMin + frand(ONE) * (copter->FlyBox.XMax - copter->FlyBox.XMin),
00865 copter->FlyBox.YMin + frand(ONE) * (copter->FlyBox.YMax - copter->FlyBox.YMin),
00866 copter->FlyBox.ZMin + frand(ONE) * (copter->FlyBox.ZMax - copter->FlyBox.ZMin));
00867 VecMinusVec(&copter->Destination, &obj->body.Centre.Pos, &copter->Direction);
00868 dPosLen = VecLen(&copter->Direction);
00869 } while (dPosLen < Real(1000) && ++its < 10);
00870 VecDivScalar(&copter->Direction, dPosLen);
00871
00872
00873 if (frand(ONE) > Real(0.2)) {
00874 SetVec(&look, copter->Direction.v[X], ZERO, copter->Direction.v[Z]);
00875 lookLen = VecLen(&look);
00876 if (lookLen > SMALL_REAL) {
00877 VecDivScalar(&look, lookLen);
00878 CopyVec(&look, &newMat.mv[L]);
00879 CopyVec(&DownVec, &newMat.mv[U]);
00880 VecCrossVec(&DownVec, &look, &newMat.mv[R]);
00881 MatToQuat(&newMat, &copter->InitialQuat);
00882 }
00883 }
00884
00885 copter->State = COPTER_FLYING;
00886 }
00887 #endif //ifndef _PSX
00888
00890
00892 #ifdef _PC
00893 void AI_DragonHandler(OBJECT *obj)
00894 {
00895 long i, j, col;
00896 MODEL *model;
00897 VEC vec;
00898 MAT mat;
00899 DRAGON_OBJ *dragon = (DRAGON_OBJ*)obj->Data;
00900
00901
00902
00903 if (!obj->renderflag.visible && dragon->Count > 6.0f)
00904 return;
00905
00906
00907
00908 if (dragon->HeadModel)
00909 model = &LevelModel[dragon->HeadModel].Model;
00910 else
00911 model = NULL;
00912
00913
00914
00915 dragon->Count += TimeStep;
00916 if (dragon->Count > 8.0f) dragon->Count -= 8.0f;
00917
00918
00919
00920 if (model)
00921 {
00922 if (dragon->Count <= 2.0f)
00923 {
00924 SetModelMorph(model, 0, 1, dragon->Count / 2.0f);
00925 }
00926
00927 else if (dragon->Count <= 4.0f)
00928 {
00929 if (dragon->Count < 2.2f)
00930 SetModelMorph(model, 0, 1, (float)sin((dragon->Count - 2.0f) * 2.5f * RAD) * 0.03f + 1.0f);
00931 else
00932 SetModelMorph(model, 1, 0, 0);
00933 }
00934
00935 else if (dragon->Count <= 6.0f)
00936 {
00937 SetModelMorph(model, 0, 1, (6.0f - dragon->Count) / 2.0f);
00938 }
00939
00940 else
00941 {
00942 if (dragon->Count < 6.2f)
00943 SetModelMorph(model, 1, 0, (float)sin((dragon->Count - 6.0f) * 2.5f * RAD) * 0.03f + 1.0f);
00944 else
00945 SetModelMorph(model, 0, 0, 0);
00946 }
00947 }
00948
00949
00950
00951 if (dragon->Count > 2.0f && dragon->Count < 4.0f)
00952 {
00953
00954
00955
00956 if (!obj->Light)
00957 {
00958 obj->Light = AllocLight();
00959 if (obj->Light)
00960 {
00961 CopyVec(&dragon->FireGenPoint, (VEC*)&obj->Light->x);
00962 obj->Light->Reach = 1024;
00963 obj->Light->Flag = LIGHT_FIXED | LIGHT_MOVING;
00964 obj->Light->Type= LIGHT_OMNINORMAL;
00965 obj->Light->r = 0;
00966 obj->Light->g = 0;
00967 obj->Light->b = 0;
00968
00969 obj->Sfx3D = CreateSfx3D(SFX_TOY_DRAGON, SFX_MAX_VOL, 22050, FALSE, &dragon->FireGenPoint);
00970 }
00971 }
00972
00973
00974
00975 if (obj->Light)
00976 {
00977 if (dragon->Count < 2.5f)
00978 {
00979 FTOL((dragon->Count - 2.0f) * 448, obj->Light->r);
00980 obj->Light->r += rand() & 31;
00981 }
00982 else
00983 {
00984 obj->Light->r = (rand() & 31) + 224;
00985 }
00986
00987 obj->Light->g = obj->Light->r >> 1;
00988 }
00989
00990
00991
00992 if ((long)(CurrentTimer() - dragon->FireGenTime) >= 0)
00993 {
00994
00995 for (j = 0 ; j < 2 ; j++) for (i = 0 ; i < DRAGON_FIRE_NUM ; i++) if (!dragon->Fire[i].Time)
00996 {
00997 SetVector(&vec, 0, 0, frand(32));
00998 RotMatrixZYX(&mat, 0, frand(1.0f), frand(0.5f) - 0.25f);
00999 RotTransVector(&mat, &dragon->FireGenPoint, &vec, &dragon->Fire[i].Pos);
01000
01001 dragon->Fire[i].Time = 0.5f;
01002 dragon->Fire[i].MinSize = frand(8) + 8;
01003 dragon->Fire[i].Spin = frand(1);
01004 dragon->Fire[i].SpinSpeed = frand(0.02f) - 0.01f;
01005
01006 dragon->FireGenTime = CurrentTimer() + MS2TIME(20);
01007 break;
01008 }
01009 }
01010 }
01011
01012
01013
01014 else
01015 {
01016 if (obj->Light)
01017 {
01018 if (dragon->Count < 4.5f)
01019 {
01020 FTOL((4.5f - dragon->Count) * 448, obj->Light->r);
01021 obj->Light->r += rand() & 31;
01022 obj->Light->g = obj->Light->r >> 1;
01023 }
01024 else
01025 {
01026 FreeLight(obj->Light);
01027 obj->Light = NULL;
01028
01029 if (obj->Sfx3D) if (!obj->Sfx3D->Sample)
01030 {
01031 FreeSfx3D(obj->Sfx3D);
01032 obj->Sfx3D = NULL;
01033 }
01034 }
01035 }
01036 }
01037
01038
01039
01040 for (i = 0 ; i < DRAGON_FIRE_NUM ; i++) if (dragon->Fire[i].Time)
01041 {
01042 dragon->Fire[i].Pos.v[X] += dragon->FireGenDir.v[X] * TimeFactor;
01043 dragon->Fire[i].Pos.v[Y] += dragon->FireGenDir.v[Y] * TimeFactor;
01044 dragon->Fire[i].Pos.v[Z] += dragon->FireGenDir.v[Z] * TimeFactor;
01045
01046 dragon->Fire[i].Size = dragon->Fire[i].Time * 32 + dragon->Fire[i].MinSize;
01047
01048 dragon->Fire[i].Spin += dragon->Fire[i].SpinSpeed * TimeFactor;
01049 RotMatrixZ(&dragon->Fire[i].Matrix, dragon->Fire[i].Spin);
01050
01051 FTOL(dragon->Fire[i].Time * 511, col);
01052 dragon->Fire[i].rgb = col | (col << 8) | (col << 16);
01053
01054 dragon->Fire[i].Time -= TimeStep;
01055 if (dragon->Fire[i].Time < 0) dragon->Fire[i].Time = 0;
01056 }
01057 }
01058 #endif
01059
01061
01063 #ifdef _PC
01064 void AI_WaterHandler(OBJECT *obj)
01065 {
01066 long i;
01067 WATER_OBJ *water = (WATER_OBJ*)obj->Data;
01068 MODEL *model = &LevelModel[obj->DefaultModel].Model;
01069 WATER_VERTEX *wv;
01070 MODEL_VERTEX *mv;
01071 MODEL_POLY *mp;
01072 POLY_RGB *mrgb;
01073 VEC vec1, vec2, norm;
01074
01075
01076
01077 if (!obj->renderflag.visible)
01078 return;
01079
01080
01081
01082 wv = water->Vert;
01083 mv = model->VertPtr;
01084
01085 for (i = 0 ; i < water->VertNum ; i++, wv++, mv++)
01086 {
01087 wv->Time += TimeStep;
01088 while (wv->Time >= wv->TotalTime) wv->Time -= wv->TotalTime;
01089 mv->y = wv->Height + (float)sin(wv->Time / wv->TotalTime * RAD) * water->Scale;
01090
01091 mv->nx = mv->ny = mv->nz = 0;
01092 mv->a = 0;
01093 }
01094
01095
01096
01097 mp = model->PolyPtr;
01098
01099 for (i = model->PolyNum ; i ; i--, mp++)
01100 {
01101 SubVector((VEC*)&mp->v1->x, (VEC*)&mp->v0->x, &vec1);
01102 SubVector((VEC*)&mp->v2->x, (VEC*)&mp->v0->x, &vec2);
01103 CrossProduct(&vec2, &vec1, &norm);
01104 NormalizeVector(&norm);
01105
01106 AddVector((VEC*)&mp->v0->nx, &norm, (VEC*)&mp->v0->nx);
01107 mp->v0->a++;
01108
01109 AddVector((VEC*)&mp->v1->nx, &norm, (VEC*)&mp->v1->nx);
01110 mp->v1->a++;
01111
01112 AddVector((VEC*)&mp->v2->nx, &norm, (VEC*)&mp->v2->nx);
01113 mp->v2->a++;
01114 }
01115
01116 mv = model->VertPtr;
01117
01118 for (i = 0 ; i < water->VertNum ; i++, mv++)
01119 {
01120 mv->nx /= mv->a;
01121 mv->ny /= mv->a;
01122 mv->nz /= mv->a;
01123
01124 mv->tu = mv->nx * 6.0f + 0.5f;
01125 mv->tv = mv->nz * 6.0f + 0.5f;
01126
01127 FTOL((mv->ny + 1.0f) * 11000.0f + 192.0f, mv->a);
01128 }
01129
01130
01131
01132 mp = model->PolyPtr;
01133 mrgb = model->PolyRGB;
01134
01135 for (i = model->PolyNum ; i ; i--, mp++, mrgb++)
01136 {
01137 mp->tu0 = mp->v0->tu;
01138 mp->tv0 = mp->v0->tv;
01139
01140 mp->tu1 = mp->v1->tu;
01141 mp->tv1 = mp->v1->tv;
01142
01143 mp->tu2 = mp->v2->tu;
01144 mp->tv2 = mp->v2->tv;
01145
01146 mrgb->rgb[0].a = (unsigned char)mp->v0->a;
01147 mrgb->rgb[1].a = (unsigned char)mp->v1->a;
01148 mrgb->rgb[2].a = (unsigned char)mp->v2->a;
01149 }
01150 }
01151 #endif
01152
01153 #ifdef _N64
01154 void AI_WaterHandler(OBJECT *obj)
01155 {
01156 long ii;
01157 WATER_OBJ *water = (WATER_OBJ*)obj->Data;
01158 MODEL *model = &LevelModel[obj->DefaultModel].Model;
01159 WATER_VERTEX *wv;
01160 Vtx *mv;
01161
01162
01163 if (!obj->renderflag.visible)
01164 return;
01165
01166
01167 wv = water->Vert;
01168 mv = model->hdr->evtxptr;
01169
01170 for (ii = 0; ii < water->VertNum; ii++, wv++, mv++)
01171 {
01172 wv->Time += TimeStep;
01173 while (wv->Time >= wv->TotalTime) wv->Time -= wv->TotalTime;
01174 mv->n.ob[1] = wv->Height + (float)sin(wv->Time / wv->TotalTime * RAD) * water->Scale;
01175 mv->n.n[0] = (char)((float)(sin(wv->Time / wv->TotalTime * RAD) * 127));
01176 mv->n.n[2] = (char)((float)(cosf(wv->Time / wv->TotalTime * RAD) * 127));
01177 }
01178 }
01179 #endif
01180
01182
01184 #ifdef _PC
01185
01186 void AI_BoatHandler(OBJECT *obj)
01187 {
01188 BOAT_OBJ *boat = (BOAT_OBJ*)obj->Data;
01189
01190 MAT mat;
01191
01192
01193
01194 if (!obj->renderflag.visible)
01195 return;
01196
01197
01198
01199 boat->TimeX += TimeStep;
01200 while (boat->TimeX >= boat->TotalTimeX) boat->TimeX -= boat->TotalTimeX;
01201
01202 boat->TimeHeight += TimeStep;
01203 while (boat->TimeHeight >= boat->TotalTimeHeight) boat->TimeHeight -= boat->TotalTimeHeight;
01204
01205 boat->TimeZ += TimeStep;
01206 while (boat->TimeZ >= boat->TotalTimeZ) boat->TimeZ -= boat->TotalTimeZ;
01207
01208
01209
01210 obj->body.Centre.Pos.v[Y] = boat->Height + (float)sin(boat->TimeHeight / boat->TotalTimeHeight * RAD) * 15.0f;
01211
01212
01213
01214 RotMatrixZYX(&mat, (float)sin(boat->TimeZ / boat->TotalTimeZ * RAD) / 90.0f, 0, (float)sin(boat->TimeX / boat->TotalTimeX * RAD) / 90.0f);
01215 MulMatrix(&boat->Ori, &mat, &obj->body.Centre.WMatrix);
01216
01217
01218
01219
01220
01221
01222
01223
01224
01225
01226
01227
01228
01229
01230
01231 }
01232 #endif
01233
01235
01237 #ifdef _PC
01238
01239 void AI_RadarHandler(OBJECT *obj)
01240 {
01241 RADAR_OBJ *radar = (RADAR_OBJ*)obj->Data;
01242
01243
01244
01245 radar->Time += TimeStep;
01246 RotMatrixY(&obj->body.Centre.WMatrix, radar->Time * 0.75f);
01247
01248
01249
01250 if (radar->Light2)
01251 CopyVec(&obj->body.Centre.WMatrix.mv[R], &radar->Light2->DirMatrix.mv[L]);
01252
01253 if (radar->Light1)
01254 SetVector(&radar->Light1->DirMatrix.mv[L], -obj->body.Centre.WMatrix.m[RX], -obj->body.Centre.WMatrix.m[RY], -obj->body.Centre.WMatrix.m[RZ]);
01255 }
01256 #endif
01257
01259
01261 #ifdef _PC
01262
01263 void AI_BalloonHandler(OBJECT *obj)
01264 {
01265 BALLOON_OBJ *balloon = (BALLOON_OBJ*)obj->Data;
01266
01267
01268
01269 if (!obj->renderflag.visible)
01270 return;
01271
01272
01273
01274 balloon->Time += TimeStep;
01275 obj->body.Centre.Pos.v[Y] = balloon->Height + (float)sin(balloon->Time) * 16;
01276 }
01277 #endif
01278
01280
01282 #ifdef _PC
01283
01284 void AI_HorseRipper(OBJECT *obj)
01285 {
01286 HORSE_OBJ *horse = (HORSE_OBJ*)obj->Data;
01287 MAT mat;
01288 REAL rock;
01289
01290
01291
01292 horse->Time += TimeStep * 4.0f;
01293 rock = (float)sin(horse->Time);
01294
01295
01296
01297 if (horse->CreakFlag > 0)
01298 {
01299 if (rock > horse->CreakFlag)
01300 {
01301 horse->CreakFlag = -horse->CreakFlag;
01302 PlaySfx3D(SFX_TOY_CREAK, SFX_MAX_VOL, 20000, &obj->body.Centre.Pos);
01303 }
01304 }
01305 else
01306 {
01307 if (rock < horse->CreakFlag)
01308 {
01309 horse->CreakFlag = -horse->CreakFlag;
01310 PlaySfx3D(SFX_TOY_CREAK, SFX_MAX_VOL, 17000, &obj->body.Centre.Pos);
01311 }
01312 }
01313
01314
01315
01316 if (!obj->renderflag.visible)
01317 return;
01318
01319
01320
01321 RotMatrixX(&mat, rock / 50.0f);
01322 MulMatrix(&horse->Mat, &mat, &obj->body.Centre.WMatrix);
01323 }
01324 #endif
01325
01327
01329 #ifdef _PC
01330
01331 void AI_TrainHandler(OBJECT *obj)
01332 {
01333 long i, flag;
01334 TRAIN_OBJ *train = (TRAIN_OBJ*)obj->Data;
01335 VEC vec, vec2;
01336 PLAYER *player;
01337
01338
01339
01340 train->TimeFront -= TimeStep * 0.5f;
01341 train->TimeBack -= TimeStep * 0.3f;
01342
01343
01344
01345 for (i = 0 ; i < 4 ; i++)
01346 {
01347 AddVector(&obj->body.Centre.Pos, &TrainWheelOffsets[i], &train->WheelPos[i]);
01348 }
01349
01350
01351
01352 if (obj->Sfx3D)
01353 {
01354 CopyVec(&obj->body.Centre.Pos, &obj->Sfx3D->Pos);
01355 }
01356
01357
01358
01359 AddVector(&obj->body.Centre.Pos, &TrainSteamOffset, &vec);
01360
01361 train->SteamTime += TimeStep;
01362 if (train->SteamTime > 0.1f)
01363 {
01364 train->SteamTime -= 0.1f;
01365 CreateSpark(SPARK_SMOKE2, &vec, &TrainSteamDir, ZERO, 0);
01366 }
01367
01368
01369
01370 flag = FALSE;
01371
01372 for (player = PLR_PlayerHead ; player ; player = player->next)
01373 {
01374 SubVector(&obj->body.Centre.Pos, &player->car.Body->Centre.Pos, &vec2);
01375 if (abs(vec2.v[X]) < 400 && vec2.v[Z] > -400 && vec2.v[Z] < 800)
01376 {
01377 flag = TRUE;
01378 break;
01379 }
01380 }
01381
01382 if (flag)
01383 {
01384 if (train->WhistleFlag)
01385 {
01386 train->WhistleFlag = FALSE;
01387 PlaySfx3D(SFX_TOY_WHISTLE, SFX_MAX_VOL, 22050, &vec);
01388 }
01389 }
01390 else
01391 {
01392 train->WhistleFlag = TRUE;
01393 }
01394 }
01395 #endif
01396
01398
01400 #ifdef _PC
01401
01402 void AI_StrobeHandler(OBJECT *obj)
01403 {
01404 long num, diff, per, col;
01405 STROBE_OBJ *strobe = (STROBE_OBJ*)obj->Data;
01406
01407
01408
01409 num = (TIME2MS(CurrentTimer()) / 20) % strobe->StrobeCount;
01410 diff = num - strobe->StrobeNum;
01411 if (diff < -strobe->StrobeCount / 2) diff += strobe->StrobeCount;
01412 if (diff > strobe->StrobeCount / 2) diff -= strobe->StrobeCount;
01413
01414
01415
01416 if (diff < -strobe->FadeUp || diff > strobe->FadeDown)
01417 {
01418 if (obj->Light)
01419 {
01420 FreeLight(obj->Light);
01421 obj->Light = NULL;
01422 }
01423 strobe->Glow = 0;
01424 }
01425
01426
01427
01428 else
01429 {
01430 if (!obj->Light)
01431 {
01432 obj->Light = AllocLight();
01433 if (obj->Light)
01434 {
01435 obj->Light->x = strobe->LightPos.v[X];
01436 obj->Light->y = strobe->LightPos.v[Y];
01437 obj->Light->z = strobe->LightPos.v[Z];
01438 obj->Light->Reach = strobe->Range;
01439 obj->Light->Flag = LIGHT_FIXED | LIGHT_MOVING;
01440 obj->Light->Type= LIGHT_OMNI;
01441 }
01442 }
01443
01444 if (obj->Light)
01445 {
01446 if (diff < 0) per = (diff + strobe->FadeUp) * (100 / strobe->FadeUp);
01447 else per = (strobe->FadeDown - diff) * (100 / strobe->FadeDown);
01448
01449 obj->Light->r = strobe->r * per / 100;
01450 obj->Light->g = strobe->g * per / 100;
01451 obj->Light->b = strobe->b * per / 100;
01452
01453 col = (obj->Light->r << 16) | (obj->Light->g << 8) | obj->Light->b;
01454 }
01455 strobe->Glow = (float)per / 100.0f;
01456 }
01457 }
01458 #endif
01459
01461
01462
01463
01465
01466 #ifdef _PC
01467 void SparkGenHandler(OBJECT *obj)
01468 {
01469 int ii, nTries;
01470 VEC pos, vel;
01471 SPARK_GEN *sparkGen = (SPARK_GEN *)obj->Data;
01472
01473
01474 sparkGen->Time += TimeStep;
01475
01476
01477 if (CamVisiMask & sparkGen->VisiMask) return;
01478
01479 nTries = 1 + (int)(TimeStep / sparkGen->MaxTime);
01480 if (nTries > 5) nTries = 5;
01481 for (ii = 0; ii < nTries; ii++) {
01482
01483
01484 if (frand(ONE) > sparkGen->Time / sparkGen->MaxTime) continue;
01485 sparkGen->Time = ZERO;
01486
01487 if (sparkGen->Parent != NULL) {
01488
01489 VecMulMat(&obj->body.Centre.Pos, &sparkGen->Parent->body.Centre.WMatrix, &pos);
01490 VecPlusEqVec(&pos, &sparkGen->Parent->body.Centre.Pos);
01491 VecMulMat(&sparkGen->SparkVel, &sparkGen->Parent->body.Centre.WMatrix, &vel);
01492
01493
01494 CreateSpark(sparkGen->Type, &pos, &vel, sparkGen->SparkVelVar, sparkGen->VisiMask);
01495 } else {
01496
01497 CreateSpark(sparkGen->Type, &obj->body.Centre.Pos, &sparkGen->SparkVel, sparkGen->SparkVelVar, sparkGen->VisiMask);
01498 }
01499 }
01500 }
01501 #endif
01502
01504
01506
01507 #ifdef _PC
01508 void AI_SpacemanHandler(OBJECT *obj)
01509 {
01510 MAT mat1, mat2;
01511 SPACEMAN_OBJ *spaceman = (SPACEMAN_OBJ*)obj->Data;
01512
01513 RotMatrixZYX(&mat1, 0.001f, 0.001f, 0);
01514 MulMatrix(&obj->body.Centre.WMatrix, &mat1, &mat2);
01515 CopyMatrix(&mat2, &obj->body.Centre.WMatrix);
01516 }
01517 #endif
01518
01520
01522
01523 #ifdef _PC
01524 void AI_PickupHandler(OBJECT *obj)
01525 {
01526 long col, flag;
01527 REAL mul;
01528 PICKUP_OBJ *pickup = (PICKUP_OBJ*)obj->Data;
01529 PLAYER *player;
01530 OBJECT *bombobj;
01531 PUTTYBOMB_OBJ *bomb;
01532
01533
01534
01535 switch (pickup->Mode)
01536 {
01537
01538
01539
01540 case 0:
01541
01542 pickup->Timer -= TimeStep;
01543 if (pickup->Timer <= 0)
01544 {
01545 pickup->Mode = 1;
01546 pickup->Timer = 0.0f;
01547 pickup->Clone = (!(rand() & 7));
01548
01549 obj->EnvRGB = 0xffff80;
01550 }
01551
01552 break;
01553
01554
01555
01556 case 1:
01557
01558
01559
01560 pickup->Timer += TimeStep;
01561
01562
01563
01564 RotMatrixY(&obj->body.Centre.WMatrix, TIME2MS(CurrentTimer()) / 2000.0f);
01565 if (pickup->Timer < 1.6f)
01566 {
01567 if (pickup->Timer < 0.5f)
01568 mul = 0;
01569 else if (pickup->Timer < 1.0f)
01570 mul = (pickup->Timer - 0.5f) * 2.0f + (float)sin((pickup->Timer - 0.5f) * RAD) / 1.5f;
01571 else if (pickup->Timer < 1.35f)
01572 mul = 1.0f - (float)sin((pickup->Timer - 1.0f) * 2.85714f * PI) / 6.0f;
01573 else
01574 mul = 1.0f + (float)sin((pickup->Timer - 1.35f) * 4.0f * PI) / 12.0f;
01575
01576 obj->body.Centre.WMatrix.m[XX] *= mul;
01577 obj->body.Centre.WMatrix.m[YY] *= mul;
01578 obj->body.Centre.WMatrix.m[ZZ] *= mul;
01579 }
01580
01581
01582
01583 if (!obj->Light)
01584 {
01585 obj->Light = AllocLight();
01586 if (obj->Light)
01587 {
01588 CopyVec(&obj->body.Centre.Pos, (VEC*)&obj->Light->x);
01589 obj->Light->Reach = 512;
01590 obj->Light->Flag = LIGHT_FIXED | LIGHT_MOVING;
01591 obj->Light->Type = LIGHT_OMNI;
01592 }
01593 }
01594
01595
01596
01597 if (obj->Light)
01598 {
01599 if (pickup->Timer < 0.75f)
01600 {
01601 FTOL(pickup->Timer * 340.0f, col);
01602 }
01603 else
01604 {
01605 col = 255;
01606 }
01607
01608 if (!pickup->Clone)
01609 {
01610 obj->Light->r = col;
01611 obj->Light->g = col * 3 / 4;
01612 obj->Light->b = 0;
01613 }
01614 else
01615 {
01616 obj->Light->r = 0;
01617 obj->Light->g = -col;
01618 obj->Light->b = -col;
01619 }
01620 }
01621
01622
01623
01624 obj->CollType = COLL_TYPE_BODY;
01625
01626 for (player = PLR_PlayerHead ; player ; player = player->next)
01627 {
01628 if (player != GHO_GhostPlayer && !player->PickupNum && !player->PickupCycleSpeed)
01629 {
01630 COL_NBodyColls = 0;
01631 DetectCarBodyColls(&player->car, &obj->body);
01632 if (COL_NBodyColls)
01633 {
01634 pickup->Mode = 2;
01635 pickup->Timer = 0.0f;
01636
01637 SetVector(&pickup->Vel, player->ownobj->body.Centre.Vel.v[X] / 2.0f, -64.0f, player->ownobj->body.Centre.Vel.v[Z] / 2.0f);
01638
01639 if (!pickup->Clone)
01640 {
01641 PlaySfx3D(SFX_PICKUP, SFX_MAX_VOL, 22050, &obj->body.Centre.Pos);
01642
01643 player->PickupCycleType = frand(PICKUP_NUM);
01644 player->PickupCycleSpeed = frand(1.0f) + 4.0f;
01645 }
01646 else
01647 {
01648 PlaySfx3D(SFX_PICKUP_CLONE, SFX_MAX_VOL, 22050, &obj->body.Centre.Pos);
01649
01650 flag = (long)player;
01651 bombobj = CreateObject(&player->car.Body->Centre.Pos, &player->car.Body->Centre.WMatrix, OBJECT_TYPE_PUTTYBOMB, &flag);
01652 if (bombobj)
01653 {
01654 bomb = (PUTTYBOMB_OBJ*)bombobj->Data;
01655 bomb->Timer = 0.0f;
01656 player->car.WillDetonate = TRUE;
01657 }
01658 }
01659
01660 break;
01661 }
01662 }
01663 }
01664
01665 obj->CollType = COLL_TYPE_NONE;
01666
01667 break;
01668
01669
01670
01671 case 2:
01672
01673
01674
01675 pickup->Timer += TimeStep;
01676
01677
01678
01679 RotMatrixY(&obj->body.Centre.WMatrix, TIME2MS(CurrentTimer()) / 2000.0f);
01680
01681 mul = pickup->Timer * 2.0f + 1.0f;
01682
01683 obj->body.Centre.WMatrix.m[XX] *= mul;
01684 obj->body.Centre.WMatrix.m[YY] *= mul;
01685 obj->body.Centre.WMatrix.m[ZZ] *= mul;
01686
01687
01688
01689 FTOL(-pickup->Timer * 255.0f + 255.0f, col);
01690
01691 obj->EnvRGB = col >> 1 | col << 8 | col << 16;
01692
01693
01694
01695 if (obj->Light)
01696 {
01697 if (!pickup->Clone)
01698 {
01699 obj->Light->r = col;
01700 obj->Light->g = col * 3 / 4;
01701 obj->Light->b = 0;
01702 }
01703 else
01704 {
01705 obj->Light->r = 0;
01706 obj->Light->g = -col;
01707 obj->Light->b = -col;
01708 }
01709 }
01710
01711
01712
01713 VecPlusScalarVec(&pickup->Pos, pickup->Timer, &pickup->Vel, &obj->body.Centre.Pos);
01714
01715
01716
01717 if (pickup->Timer > 1.0f)
01718 {
01719 pickup->Mode = 0;
01720 pickup->Timer = PICKUP_GEN_TIME;
01721
01722 CopyVec(&pickup->Pos, &obj->body.Centre.Pos);
01723
01724 if (obj->Light)
01725 {
01726 FreeLight(obj->Light);
01727 obj->Light = NULL;
01728 }
01729 }
01730
01731 break;
01732 }
01733 }
01734 #endif
01735
01737
01739
01740 #ifdef _PC
01741 void AI_DissolveModelHandler(OBJECT *obj)
01742 {
01743 long i, alpha, col;
01744 MODEL_POLY *mp;
01745 POLY_RGB *mrgb;
01746 DISSOLVE_OBJ *dissolve = (DISSOLVE_OBJ*)obj->Data;
01747 DISSOLVE_PARTICLE *particle = (DISSOLVE_PARTICLE*)(dissolve->Model.VertPtr + dissolve->Model.VertNum);
01748 VEC centre, delta[4];
01749 MAT mat;
01750
01751
01752
01753 FTOL(255.0f - dissolve->Age * 127, alpha);
01754 mp = dissolve->Model.PolyPtr;
01755 mrgb = dissolve->Model.PolyRGB;
01756
01757 for (i = 0 ; i < dissolve->Model.PolyNum ; i++, mp++, mrgb++, particle++)
01758 {
01759
01760
01761
01762 mrgb->rgb[0].a = (unsigned char)alpha;
01763 mrgb->rgb[1].a = (unsigned char)alpha;
01764 mrgb->rgb[2].a = (unsigned char)alpha;
01765 mrgb->rgb[3].a = (unsigned char)alpha;
01766
01767
01768
01769 centre.v[X] = (mp->v0->x + mp->v1->x + mp->v2->x + mp->v3->x) / 4.0f;
01770 centre.v[Y] = (mp->v0->y + mp->v1->y + mp->v2->y + mp->v3->y) / 4.0f;
01771 centre.v[Z] = (mp->v0->z + mp->v1->z + mp->v2->z + mp->v3->z) / 4.0f;
01772
01773 SubVector((VEC*)&mp->v0->x, ¢re, &delta[0]);
01774 SubVector((VEC*)&mp->v1->x, ¢re, &delta[1]);
01775 SubVector((VEC*)&mp->v2->x, ¢re, &delta[2]);
01776 SubVector((VEC*)&mp->v3->x, ¢re, &delta[3]);
01777
01778
01779
01780 RotMatrixZYX(&mat, particle->Rot.v[X] * TimeStep, particle->Rot.v[Y] * TimeStep, particle->Rot.v[Z] * TimeStep);
01781
01782 RotTransVector(&mat, ¢re, &delta[0], (VEC*)&mp->v0->x);
01783 RotTransVector(&mat, ¢re, &delta[1], (VEC*)&mp->v1->x);
01784 RotTransVector(&mat, ¢re, &delta[2], (VEC*)&mp->v2->x);
01785 RotTransVector(&mat, ¢re, &delta[3], (VEC*)&mp->v3->x);
01786
01787
01788
01789 particle->Vel.v[Y] += 192.0f * TimeStep;
01790
01791 VecPlusEqScalarVec((VEC*)&mp->v0->x, TimeStep, &particle->Vel);
01792 VecPlusEqScalarVec((VEC*)&mp->v1->x, TimeStep, &particle->Vel);
01793 VecPlusEqScalarVec((VEC*)&mp->v2->x, TimeStep, &particle->Vel);
01794 VecPlusEqScalarVec((VEC*)&mp->v3->x, TimeStep, &particle->Vel);
01795 }
01796
01797
01798
01799 FTOL(255.0f - dissolve->Age * 127, col);
01800 ((MODEL_RGB*)&dissolve->EnvRGB)->r = ((MODEL_RGB*)&obj->EnvRGB)->r * col / 256;
01801 ((MODEL_RGB*)&dissolve->EnvRGB)->g = ((MODEL_RGB*)&obj->EnvRGB)->g * col / 256;
01802 ((MODEL_RGB*)&dissolve->EnvRGB)->b = ((MODEL_RGB*)&obj->EnvRGB)->b * col / 256;
01803
01804
01805
01806 dissolve->Age += TimeStep;
01807 if (dissolve->Age > 2.0f)
01808 OBJ_FreeObject(obj);
01809 }
01810 #endif
01811
01813
01815
01816 #ifdef _PC
01817 void AI_LaserHandler(OBJECT *obj)
01818 {
01819 VEC vel, pos;
01820 LASER_OBJ *laser = (LASER_OBJ *)obj->Data;
01821
01822
01823 if (!obj->renderflag.visible) return;
01824
01825
01826 if (laser->ObjectCollide) {
01827 LineOfSightObj(&obj->body.Centre.Pos, &laser->Dest, &laser->Dist);
01828 } else {
01829 laser->Dist = ONE;
01830 }
01831
01832
01833 if (laser->Dist < ONE) {
01834 VecEqScalarVec(&vel, -100, &obj->body.Centre.WMatrix.mv[L]);
01835 VecPlusScalarVec(&obj->body.Centre.Pos, laser->Dist, &laser->Delta, &pos)
01836 CreateSpark(SPARK_SPARK, &pos, &vel, 200, laser->VisiMask);
01837 }
01838 }
01839 #endif
01840
01842
01844
01845 #ifdef _PC
01846 void AI_SplashHandler(OBJECT *obj)
01847 {
01848 long i;
01849 SPLASH_OBJ *splash = (SPLASH_OBJ *)obj->Data;
01850 SPLASH_POLY *spoly;
01851 REAL grav;
01852
01853
01854
01855 spoly = splash->Poly;
01856 for (i = 0 ; i < SPLASH_POLY_NUM ; i++, spoly++) if (spoly->Frame < 16.0f)
01857 {
01858 spoly->Frame += spoly->FrameAdd * TimeStep;
01859 if (spoly->Frame >= 16.0f)
01860 {
01861 splash->Count--;
01862 continue;
01863 }
01864
01865 grav = 384.0f * TimeStep;
01866 spoly->Vel[0].v[Y] += grav;
01867 spoly->Vel[1].v[Y] += grav;
01868 spoly->Vel[2].v[Y] += grav;
01869 spoly->Vel[3].v[Y] += grav;
01870
01871 VecPlusEqScalarVec(&spoly->Pos[0], TimeStep, &spoly->Vel[0]);
01872 VecPlusEqScalarVec(&spoly->Pos[1], TimeStep, &spoly->Vel[1]);
01873 VecPlusEqScalarVec(&spoly->Pos[2], TimeStep, &spoly->Vel[2]);
01874 VecPlusEqScalarVec(&spoly->Pos[3], TimeStep, &spoly->Vel[3]);
01875 }
01876
01877
01878
01879 if (!splash->Count)
01880 {
01881 OBJ_FreeObject(obj);
01882 }
01883 }
01884 #endif
01885
01886
01888
01889
01890
01892
01893 #ifdef _PC
01894
01895 void AI_SpeedupAIHandler(OBJECT *obj)
01896 {
01897 SPEEDUP_OBJ *speedup = (SPEEDUP_OBJ *)obj->Data;
01898
01899
01900 if (speedup->ChangeTime == ZERO) return;
01901
01902
01903 speedup->Time += TimeStep;
01904 if (speedup->Time > speedup->ChangeTime) {
01905 if (speedup->Speed == speedup->LoSpeed) {
01906 speedup->Speed = speedup->HiSpeed;
01907 } else {
01908 speedup->Speed = speedup->LoSpeed;
01909 }
01910 speedup->Time = ZERO;
01911 }
01912 }
01913
01914
01915 void SpeedupImpulse(CAR *car)
01916 {
01917 REAL time, depth, velDotNorm, vel, impMag;
01918 VEC dPos, wPos;
01919 BBOX bBox;
01920 OBJECT *obj;
01921 SPEEDUP_OBJ *speedup;
01922
01923
01924 for (obj = OBJ_ObjectHead; obj != NULL; obj = obj->next) {
01925
01926 if (obj->Type != OBJECT_TYPE_SPEEDUP) continue;
01927 speedup = (SPEEDUP_OBJ *)obj->Data;
01928
01929
01930 if (!BBTestXZY(&speedup->CollPoly.BBox, &car->BBox)) continue;
01931
01932
01933 SetBBox(&bBox,
01934 Min(car->Body->Centre.Pos.v[X], car->Body->Centre.OldPos.v[X]),
01935 Max(car->Body->Centre.Pos.v[X], car->Body->Centre.OldPos.v[X]),
01936 Min(car->Body->Centre.Pos.v[Y], car->Body->Centre.OldPos.v[Y]),
01937 Max(car->Body->Centre.Pos.v[Y], car->Body->Centre.OldPos.v[Y]),
01938 Min(car->Body->Centre.Pos.v[Z], car->Body->Centre.OldPos.v[Z]),
01939 Max(car->Body->Centre.Pos.v[Z], car->Body->Centre.OldPos.v[Z]));
01940 if(!BBTestYXZ(&bBox, &speedup->CollPoly.BBox)) continue;
01941
01942
01943 if (!LinePlaneIntersect(&car->Body->Centre.OldPos, &car->Body->Centre.Pos, &speedup->CollPoly.Plane, &time, &depth)) {
01944 continue;
01945 }
01946
01947
01948 VecMinusVec(&car->Body->Centre.Pos, &car->Body->Centre.OldPos, &dPos);
01949 VecPlusScalarVec(&car->Body->Centre.OldPos, time, &dPos, &wPos);
01950
01951
01952 if (!PointInCollPolyBounds(&wPos, &speedup->CollPoly)) {
01953 continue;
01954 }
01955
01956
01957 velDotNorm = VecDotVec(&car->Body->Centre.Vel, PlaneNormal(&speedup->CollPoly.Plane));
01958 if (velDotNorm > ZERO) {
01959 vel = VecDotVec(&car->Body->Centre.Vel, &car->Body->Centre.WMatrix.mv[L]);
01960 if (vel > ZERO) {
01961 impMag = car->Body->Centre.Mass * (speedup->Speed - vel);
01962 } else {
01963 impMag = car->Body->Centre.Mass * (-speedup->Speed - vel);
01964 }
01965 } else {
01966 vel = VecDotVec(&car->Body->Centre.Vel, &car->Body->Centre.WMatrix.mv[L]);
01967 if (vel > ZERO) {
01968 impMag = car->Body->Centre.Mass * (-speedup->LoSpeed - vel);
01969 } else {
01970 impMag = car->Body->Centre.Mass * (speedup->LoSpeed - vel);
01971 }
01972 }
01973
01974 if (depth < ZERO) {
01975 VecPlusEqScalarVec(&car->Body->Centre.Shift, -2 * (depth - COLL_EPSILON), &speedup->CollPoly.Plane);
01976 }
01977
01978
01979
01980 VecPlusEqScalarVec(&car->Body->Centre.Impulse, impMag, &car->Body->Centre.WMatrix.mv[L]);
01981
01982 }
01983
01984
01985 }
01986 #endif
01987