00001
00002
00003
00004
00005
00006 #include "cg_local.h"
00007
00008
00009
00010
00011
00012
00013
00014
00015 void CG_BubbleTrail( vec3_t start, vec3_t end, float spacing ) {
00016 vec3_t move;
00017 vec3_t vec;
00018 float len;
00019 int i;
00020
00021 if ( cg_noProjectileTrail.integer ) {
00022 return;
00023 }
00024
00025 VectorCopy (start, move);
00026 VectorSubtract (end, start, vec);
00027 len = VectorNormalize (vec);
00028
00029
00030 i = rand() % (int)spacing;
00031 VectorMA( move, i, vec, move );
00032
00033 VectorScale (vec, spacing, vec);
00034
00035 for ( ; i < len; i += spacing ) {
00036 localEntity_t *le;
00037 refEntity_t *re;
00038
00039 le = CG_AllocLocalEntity();
00040 le->leFlags = LEF_PUFF_DONT_SCALE;
00041 le->leType = LE_MOVE_SCALE_FADE;
00042 le->startTime = cg.time;
00043 le->endTime = cg.time + 1000 + random() * 250;
00044 le->lifeRate = 1.0 / ( le->endTime - le->startTime );
00045
00046 re = &le->refEntity;
00047 re->shaderTime = cg.time / 1000.0f;
00048
00049 re->reType = RT_SPRITE;
00050 re->rotation = 0;
00051 re->radius = 3;
00052 re->customShader = 0;
00053 re->shaderRGBA[0] = 0xff;
00054 re->shaderRGBA[1] = 0xff;
00055 re->shaderRGBA[2] = 0xff;
00056 re->shaderRGBA[3] = 0xff;
00057
00058 le->color[3] = 1.0;
00059
00060 le->pos.trType = TR_LINEAR;
00061 le->pos.trTime = cg.time;
00062 VectorCopy( move, le->pos.trBase );
00063 le->pos.trDelta[0] = crandom()*5;
00064 le->pos.trDelta[1] = crandom()*5;
00065 le->pos.trDelta[2] = crandom()*5 + 6;
00066
00067 VectorAdd (move, vec, move);
00068 }
00069 }
00070
00071
00072
00073
00074
00075
00076
00077
00078 localEntity_t *CG_SmokePuff( const vec3_t p, const vec3_t vel,
00079 float radius,
00080 float r, float g, float b, float a,
00081 float duration,
00082 int startTime,
00083 int fadeInTime,
00084 int leFlags,
00085 qhandle_t hShader ) {
00086 static int seed = 0x92;
00087 localEntity_t *le;
00088 refEntity_t *re;
00089
00090
00091 le = CG_AllocLocalEntity();
00092 le->leFlags = leFlags;
00093 le->radius = radius;
00094
00095 re = &le->refEntity;
00096 re->rotation = Q_random( &seed ) * 360;
00097 re->radius = radius;
00098 re->shaderTime = startTime / 1000.0f;
00099
00100 le->leType = LE_MOVE_SCALE_FADE;
00101 le->startTime = startTime;
00102 le->fadeInTime = fadeInTime;
00103 le->endTime = startTime + duration;
00104 if ( fadeInTime > startTime ) {
00105 le->lifeRate = 1.0 / ( le->endTime - le->fadeInTime );
00106 }
00107 else {
00108 le->lifeRate = 1.0 / ( le->endTime - le->startTime );
00109 }
00110 le->color[0] = r;
00111 le->color[1] = g;
00112 le->color[2] = b;
00113 le->color[3] = a;
00114
00115
00116 le->pos.trType = TR_LINEAR;
00117 le->pos.trTime = startTime;
00118 VectorCopy( vel, le->pos.trDelta );
00119 VectorCopy( p, le->pos.trBase );
00120
00121 VectorCopy( p, re->origin );
00122 re->customShader = hShader;
00123
00124 re->shaderRGBA[0] = le->color[0] * 0xff;
00125 re->shaderRGBA[1] = le->color[1] * 0xff;
00126 re->shaderRGBA[2] = le->color[2] * 0xff;
00127 re->shaderRGBA[3] = 0xff;
00128
00129 re->reType = RT_SPRITE;
00130 re->radius = le->radius;
00131
00132 return le;
00133 }
00134
00135 int CGDEBUG_SaberColor( int saberColor )
00136 {
00137 switch( (int)(saberColor) )
00138 {
00139 case SABER_RED:
00140 return 0x000000ff;
00141 break;
00142 case SABER_ORANGE:
00143 return 0x000088ff;
00144 break;
00145 case SABER_YELLOW:
00146 return 0x0000ffff;
00147 break;
00148 case SABER_GREEN:
00149 return 0x0000ff00;
00150 break;
00151 case SABER_BLUE:
00152 return 0x00ff0000;
00153 break;
00154 case SABER_PURPLE:
00155 return 0x00ff00ff;
00156 break;
00157 default:
00158 return saberColor;
00159 break;
00160 }
00161 }
00162
00163 void CG_TestLine( vec3_t start, vec3_t end, int time, unsigned int color, int radius) {
00164 localEntity_t *le;
00165 refEntity_t *re;
00166
00167 le = CG_AllocLocalEntity();
00168 le->leType = LE_LINE;
00169 le->startTime = cg.time;
00170 le->endTime = cg.time + time;
00171 le->lifeRate = 1.0 / ( le->endTime - le->startTime );
00172
00173 re = &le->refEntity;
00174 VectorCopy( start, re->origin );
00175 VectorCopy( end, re->oldorigin);
00176 re->shaderTime = cg.time / 1000.0f;
00177
00178 re->reType = RT_LINE;
00179 re->radius = 0.5*radius;
00180 re->customShader = cgs.media.whiteShader;
00181
00182 re->shaderTexCoord[0] = re->shaderTexCoord[1] = 1.0f;
00183
00184 if (color==0)
00185 {
00186 re->shaderRGBA[0] = re->shaderRGBA[1] = re->shaderRGBA[2] = re->shaderRGBA[3] = 0xff;
00187 }
00188 else
00189 {
00190 color = CGDEBUG_SaberColor( color );
00191 re->shaderRGBA[0] = color & 0xff;
00192 color >>= 8;
00193 re->shaderRGBA[1] = color & 0xff;
00194 color >>= 8;
00195 re->shaderRGBA[2] = color & 0xff;
00196
00197
00198 re->shaderRGBA[3] = 0xff;
00199 }
00200
00201 le->color[3] = 1.0;
00202
00203
00204 }
00205
00206
00207
00208
00209
00210
00211 void CG_ThrowChunk( vec3_t origin, vec3_t velocity, qhandle_t hModel, int optionalSound, int startalpha ) {
00212 localEntity_t *le;
00213 refEntity_t *re;
00214
00215 le = CG_AllocLocalEntity();
00216 re = &le->refEntity;
00217
00218 le->leType = LE_FRAGMENT;
00219 le->startTime = cg.time;
00220 le->endTime = le->startTime + 5000 + random() * 3000;
00221
00222 VectorCopy( origin, re->origin );
00223 AxisCopy( axisDefault, re->axis );
00224 re->hModel = hModel;
00225
00226 le->pos.trType = TR_GRAVITY;
00227 le->angles.trType = TR_GRAVITY;
00228 VectorCopy( origin, le->pos.trBase );
00229 VectorCopy( velocity, le->pos.trDelta );
00230 VectorSet(le->angles.trBase, 20, 20, 20);
00231 VectorCopy( velocity, le->angles.trDelta );
00232 le->pos.trTime = cg.time;
00233 le->angles.trTime = cg.time;
00234
00235 le->leFlags = LEF_TUMBLE;
00236
00237 le->angles.trBase[YAW] = 180;
00238
00239 le->bounceFactor = 0.3f;
00240 le->bounceSound = optionalSound;
00241
00242 le->forceAlpha = startalpha;
00243 }
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254 static float offX[20][20],
00255 offZ[20][20];
00256
00257 #define FX_ALPHA_NONLINEAR 0x00000004
00258 #define FX_APPLY_PHYSICS 0x02000000
00259 #define FX_USE_ALPHA 0x08000000
00260
00261 static void CG_DoGlassQuad( vec3_t p[4], vec2_t uv[4], qboolean stick, int time, vec3_t dmgDir )
00262 {
00263 float bounce;
00264 vec3_t rotDelta;
00265 vec3_t vel, accel;
00266 vec3_t rgb1;
00267 addpolyArgStruct_t apArgs;
00268 int i, i_2;
00269
00270 VectorSet( vel, crandom() * 12, crandom() * 12, -1 );
00271
00272 if ( !stick )
00273 {
00274
00275 VectorMA( vel, 0.3f, dmgDir, vel );
00276 }
00277
00278
00279 VectorSet( accel, 0.0f, 0.0f, -(600.0f + random() * 100.0f ) );
00280
00281
00282
00283 VectorSet( rgb1, 1.0f, 1.0f, 1.0f );
00284
00285
00286 bounce = random() * 0.2f + 0.15f;
00287
00288
00289 VectorSet( rotDelta, crandom() * 40.0f, crandom() * 40.0f, 0.0f );
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311 i = 0;
00312 i_2 = 0;
00313
00314 while (i < 4)
00315 {
00316 while (i_2 < 3)
00317 {
00318 apArgs.p[i][i_2] = p[i][i_2];
00319
00320 i_2++;
00321 }
00322
00323 i_2 = 0;
00324 i++;
00325 }
00326
00327 i = 0;
00328 i_2 = 0;
00329
00330 while (i < 4)
00331 {
00332 while (i_2 < 2)
00333 {
00334 apArgs.ev[i][i_2] = uv[i][i_2];
00335
00336 i_2++;
00337 }
00338
00339 i_2 = 0;
00340 i++;
00341 }
00342
00343 apArgs.numVerts = 4;
00344 VectorCopy(vel, apArgs.vel);
00345 VectorCopy(accel, apArgs.accel);
00346
00347 apArgs.alpha1 = 0.15f;
00348 apArgs.alpha2 = 0.0f;
00349 apArgs.alphaParm = 85.0f;
00350
00351 VectorCopy(rgb1, apArgs.rgb1);
00352 VectorCopy(rgb1, apArgs.rgb2);
00353
00354 apArgs.rgbParm = 0.0f;
00355
00356 VectorCopy(rotDelta, apArgs.rotationDelta);
00357
00358 apArgs.bounce = bounce;
00359 apArgs.motionDelay = time;
00360 apArgs.killTime = 6000;
00361 apArgs.shader = cgs.media.glassShardShader;
00362 apArgs.flags = (FX_APPLY_PHYSICS | FX_ALPHA_NONLINEAR | FX_USE_ALPHA);
00363
00364 trap_FX_AddPoly(&apArgs);
00365 }
00366
00367 static void CG_CalcBiLerp( vec3_t verts[4], vec3_t subVerts[4], vec2_t uv[4] )
00368 {
00369 vec3_t temp;
00370
00371
00372 VectorScale( verts[0], 1.0f - uv[0][0], subVerts[0] );
00373 VectorMA( subVerts[0], uv[0][0], verts[1], subVerts[0] );
00374 VectorScale( subVerts[0], 1.0f - uv[0][1], temp );
00375 VectorScale( verts[3], 1.0f - uv[0][0], subVerts[0] );
00376 VectorMA( subVerts[0], uv[0][0], verts[2], subVerts[0] );
00377 VectorMA( temp, uv[0][1], subVerts[0], subVerts[0] );
00378
00379 VectorScale( verts[0], 1.0f - uv[1][0], subVerts[1] );
00380 VectorMA( subVerts[1], uv[1][0], verts[1], subVerts[1] );
00381 VectorScale( subVerts[1], 1.0f - uv[1][1], temp );
00382 VectorScale( verts[3], 1.0f - uv[1][0], subVerts[1] );
00383 VectorMA( subVerts[1], uv[1][0], verts[2], subVerts[1] );
00384 VectorMA( temp, uv[1][1], subVerts[1], subVerts[1] );
00385
00386 VectorScale( verts[0], 1.0f - uv[2][0], subVerts[2] );
00387 VectorMA( subVerts[2], uv[2][0], verts[1], subVerts[2] );
00388 VectorScale( subVerts[2], 1.0f - uv[2][1], temp );
00389 VectorScale( verts[3], 1.0f - uv[2][0], subVerts[2] );
00390 VectorMA( subVerts[2], uv[2][0], verts[2], subVerts[2] );
00391 VectorMA( temp, uv[2][1], subVerts[2], subVerts[2] );
00392
00393 VectorScale( verts[0], 1.0f - uv[3][0], subVerts[3] );
00394 VectorMA( subVerts[3], uv[3][0], verts[1], subVerts[3] );
00395 VectorScale( subVerts[3], 1.0f - uv[3][1], temp );
00396 VectorScale( verts[3], 1.0f - uv[3][0], subVerts[3] );
00397 VectorMA( subVerts[3], uv[3][0], verts[2], subVerts[3] );
00398 VectorMA( temp, uv[3][1], subVerts[3], subVerts[3] );
00399 }
00400
00401
00402
00403
00404 static void CG_CalcHeightWidth( vec3_t verts[4], float *height, float *width )
00405 {
00406 vec3_t dir1, dir2, cross;
00407
00408 VectorSubtract( verts[3], verts[0], dir1 );
00409 VectorSubtract( verts[1], verts[0], dir2 );
00410 CrossProduct( dir1, dir2, cross );
00411 *width = VectorNormalize( cross ) / VectorNormalize( dir1 );
00412 VectorSubtract( verts[2], verts[0], dir2 );
00413 CrossProduct( dir1, dir2, cross );
00414 *width += VectorNormalize( cross ) / VectorNormalize( dir1 );
00415 *width *= 0.5f;
00416
00417 VectorSubtract( verts[1], verts[0], dir1 );
00418 VectorSubtract( verts[2], verts[0], dir2 );
00419 CrossProduct( dir1, dir2, cross );
00420 *height = VectorNormalize( cross ) / VectorNormalize( dir1 );
00421 VectorSubtract( verts[3], verts[0], dir2 );
00422 CrossProduct( dir1, dir2, cross );
00423 *height += VectorNormalize( cross ) / VectorNormalize( dir1 );
00424 *height *= 0.5f;
00425 }
00426
00427
00428
00429
00430 void CG_InitGlass( void )
00431 {
00432 int i, t;
00433
00434
00435
00436 for ( i = 0; i < 20; i++ )
00437 {
00438 for ( t = 0; t < 20; t++ )
00439 {
00440 offX[t][i] = crandom() * 0.03f;
00441 offZ[i][t] = crandom() * 0.03f;
00442 }
00443 }
00444 }
00445
00446 void Vector2Set(vec2_t a,float b,float c)
00447 {
00448 a[0] = b;
00449 a[1] = c;
00450 }
00451
00452 #define TIME_DECAY_SLOW 0.1f
00453 #define TIME_DECAY_MED 0.04f
00454 #define TIME_DECAY_FAST 0.009f
00455
00456 void CG_DoGlass( vec3_t verts[4], vec3_t normal, vec3_t dmgPt, vec3_t dmgDir, float dmgRadius, int maxShards )
00457 {
00458 int i, t;
00459 int mxHeight, mxWidth;
00460 float height, width;
00461 float stepWidth, stepHeight;
00462 float timeDecay;
00463 float x, z;
00464 float xx, zz;
00465 float dif;
00466 int time = 0;
00467 int glassShards = 0;
00468 qboolean stick = qtrue;
00469 vec3_t subVerts[4];
00470 vec2_t biPoints[4];
00471
00472
00473
00474
00475 CG_CalcHeightWidth( verts, &height, &width );
00476
00477 trap_S_StartSound( dmgPt, -1, CHAN_AUTO, trap_S_RegisterSound("sound/effects/glassbreak1.wav"));
00478
00479
00480 if ( height < 100 )
00481 {
00482 stepHeight = 0.2f;
00483 mxHeight = 5;
00484 timeDecay = TIME_DECAY_SLOW;
00485 }
00486 else if ( height > 220 )
00487 {
00488 stepHeight = 0.05f;
00489 mxHeight = 20;
00490 timeDecay = TIME_DECAY_FAST;
00491 }
00492 else
00493 {
00494 stepHeight = 0.1f;
00495 mxHeight = 10;
00496 timeDecay = TIME_DECAY_MED;
00497 }
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523 stepWidth = (0.25f - (width*0.0002));
00524 mxWidth = width*0.2;
00525 timeDecay = ( timeDecay + TIME_DECAY_FAST ) * 0.5f;
00526
00527 if (stepWidth < 0.01f)
00528 {
00529 stepWidth = 0.01f;
00530 }
00531 if (mxWidth < 5)
00532 {
00533 mxWidth = 5;
00534 }
00535
00536 for ( z = 0.0f, i = 0; z < 1.0f; z += stepHeight, i++ )
00537 {
00538 for ( x = 0.0f, t = 0; x < 1.0f; x += stepWidth, t++ )
00539 {
00540
00541 if ( t > 0 && t < mxWidth )
00542 {
00543 xx = x - offX[i][t];
00544 }
00545 else
00546 {
00547 xx = x;
00548 }
00549
00550 if ( i > 0 && i < mxHeight )
00551 {
00552 zz = z - offZ[t][i];
00553 }
00554 else
00555 {
00556 zz = z;
00557 }
00558
00559 Vector2Set( biPoints[0], xx, zz );
00560
00561 if ( t + 1 > 0 && t + 1 < mxWidth )
00562 {
00563 xx = x - offX[i][t + 1];
00564 }
00565 else
00566 {
00567 xx = x;
00568 }
00569
00570 if ( i > 0 && i < mxHeight )
00571 {
00572 zz = z - offZ[t + 1][i];
00573 }
00574 else
00575 {
00576 zz = z;
00577 }
00578
00579 Vector2Set( biPoints[1], xx + stepWidth, zz );
00580
00581 if ( t + 1 > 0 && t + 1 < mxWidth )
00582 {
00583 xx = x - offX[i + 1][t + 1];
00584 }
00585 else
00586 {
00587 xx = x;
00588 }
00589
00590 if ( i + 1 > 0 && i + 1 < mxHeight )
00591 {
00592 zz = z - offZ[t + 1][i + 1];
00593 }
00594 else
00595 {
00596 zz = z;
00597 }
00598
00599 Vector2Set( biPoints[2], xx + stepWidth, zz + stepHeight);
00600
00601 if ( t > 0 && t < mxWidth )
00602 {
00603 xx = x - offX[i + 1][t];
00604 }
00605 else
00606 {
00607 xx = x;
00608 }
00609
00610 if ( i + 1 > 0 && i + 1 < mxHeight )
00611 {
00612 zz = z - offZ[t][i + 1];
00613 }
00614 else
00615 {
00616 zz = z;
00617 }
00618
00619 Vector2Set( biPoints[3], xx, zz + stepHeight );
00620
00621 CG_CalcBiLerp( verts, subVerts, biPoints );
00622
00623 dif = DistanceSquared( subVerts[0], dmgPt ) * timeDecay - random() * 32;
00624
00625
00626 dif -= dmgRadius * dmgRadius;
00627
00628 if ( dif > 1 )
00629 {
00630 stick = qtrue;
00631 time = dif + random() * 200;
00632 }
00633 else
00634 {
00635 stick = qfalse;
00636 time = 0;
00637 }
00638
00639 CG_DoGlassQuad( subVerts, biPoints, stick, time, dmgDir );
00640 glassShards++;
00641
00642 if (maxShards && glassShards >= maxShards)
00643 {
00644 return;
00645 }
00646 }
00647 }
00648 }
00649
00650
00651
00652
00653
00654
00655
00656 void CG_GlassShatter(int entnum, vec3_t dmgPt, vec3_t dmgDir, float dmgRadius, int maxShards)
00657 {
00658 vec3_t verts[4], normal;
00659
00660 if (cgs.inlineDrawModel[cg_entities[entnum].currentState.modelindex])
00661 {
00662 trap_R_GetBModelVerts(cgs.inlineDrawModel[cg_entities[entnum].currentState.modelindex], verts, normal);
00663 CG_DoGlass(verts, normal, dmgPt, dmgDir, dmgRadius, maxShards);
00664 }
00665
00666 }
00667
00668
00669
00670
00671
00672
00673
00674 void CG_GlassShatter_Old(int entnum, vec3_t org, vec3_t mins, vec3_t maxs)
00675 {
00676 vec3_t velocity, a, shardorg, dif, difx;
00677 float windowmass;
00678 float shardsthrow = 0;
00679 char chunkname[256];
00680
00681 trap_S_StartSound(org, entnum, CHAN_BODY, trap_S_RegisterSound("sound/effects/glassbreak1.wav"));
00682
00683 VectorSubtract(maxs, mins, a);
00684
00685 windowmass = VectorLength(a);
00686
00687 while (shardsthrow < windowmass)
00688 {
00689 velocity[0] = crandom()*150;
00690 velocity[1] = crandom()*150;
00691 velocity[2] = 150 + crandom()*75;
00692
00693 Com_sprintf(chunkname, sizeof(chunkname), "models/chunks/glass/glchunks_%i.md3", Q_irand(1, 6));
00694 VectorCopy(org, shardorg);
00695
00696 dif[0] = (maxs[0]-mins[0])/2;
00697 dif[1] = (maxs[1]-mins[1])/2;
00698 dif[2] = (maxs[2]-mins[2])/2;
00699
00700 if (dif[0] < 2)
00701 {
00702 dif[0] = 2;
00703 }
00704 if (dif[1] < 2)
00705 {
00706 dif[1] = 2;
00707 }
00708 if (dif[2] < 2)
00709 {
00710 dif[2] = 2;
00711 }
00712
00713 difx[0] = Q_irand(1, (dif[0]*0.9)*2);
00714 difx[1] = Q_irand(1, (dif[1]*0.9)*2);
00715 difx[2] = Q_irand(1, (dif[2]*0.9)*2);
00716
00717 if (difx[0] > dif[0])
00718 {
00719 shardorg[0] += difx[0]-(dif[0]);
00720 }
00721 else
00722 {
00723 shardorg[0] -= difx[0];
00724 }
00725 if (difx[1] > dif[1])
00726 {
00727 shardorg[1] += difx[1]-(dif[1]);
00728 }
00729 else
00730 {
00731 shardorg[1] -= difx[1];
00732 }
00733 if (difx[2] > dif[2])
00734 {
00735 shardorg[2] += difx[2]-(dif[2]);
00736 }
00737 else
00738 {
00739 shardorg[2] -= difx[2];
00740 }
00741
00742
00743
00744 CG_ThrowChunk( shardorg, velocity, trap_R_RegisterModel( chunkname ), 0, 254 );
00745
00746 shardsthrow += 10;
00747 }
00748 }
00749
00750
00751
00752
00753
00754
00755
00756 #define DEBRIS_SPECIALCASE_ROCK -1
00757 #define DEBRIS_SPECIALCASE_CHUNKS -2
00758 #define DEBRIS_SPECIALCASE_WOOD -3
00759 #define DEBRIS_SPECIALCASE_GLASS -4
00760
00761 #define NUM_DEBRIS_MODELS_GLASS 8
00762 #define NUM_DEBRIS_MODELS_WOOD 8
00763 #define NUM_DEBRIS_MODELS_CHUNKS 3
00764 #define NUM_DEBRIS_MODELS_ROCKS 4 //12
00765
00766 int dbModels_Glass[NUM_DEBRIS_MODELS_GLASS];
00767 int dbModels_Wood[NUM_DEBRIS_MODELS_WOOD];
00768 int dbModels_Chunks[NUM_DEBRIS_MODELS_CHUNKS];
00769 int dbModels_Rocks[NUM_DEBRIS_MODELS_ROCKS];
00770
00771 void CG_CreateDebris(int entnum, vec3_t org, vec3_t mins, vec3_t maxs, int debrissound, int debrismodel)
00772 {
00773 vec3_t velocity, a, shardorg, dif, difx;
00774 float windowmass;
00775 float shardsthrow = 0;
00776 int omodel = debrismodel;
00777
00778 if (omodel == DEBRIS_SPECIALCASE_GLASS && !dbModels_Glass[0])
00779 {
00780 dbModels_Glass[0] = trap_R_RegisterModel("models/chunks/metal/metal1_1.md3");
00781 dbModels_Glass[1] = trap_R_RegisterModel("models/chunks/metal/metal1_2.md3");
00782 dbModels_Glass[2] = trap_R_RegisterModel("models/chunks/metal/metal1_3.md3");
00783 dbModels_Glass[3] = trap_R_RegisterModel("models/chunks/metal/metal1_4.md3");
00784 dbModels_Glass[4] = trap_R_RegisterModel("models/chunks/metal/metal2_1.md3");
00785 dbModels_Glass[5] = trap_R_RegisterModel("models/chunks/metal/metal2_2.md3");
00786 dbModels_Glass[6] = trap_R_RegisterModel("models/chunks/metal/metal2_3.md3");
00787 dbModels_Glass[7] = trap_R_RegisterModel("models/chunks/metal/metal2_4.md3");
00788 }
00789 if (omodel == DEBRIS_SPECIALCASE_WOOD && !dbModels_Wood[0])
00790 {
00791 dbModels_Wood[0] = trap_R_RegisterModel("models/chunks/crate/crate1_1.md3");
00792 dbModels_Wood[1] = trap_R_RegisterModel("models/chunks/crate/crate1_2.md3");
00793 dbModels_Wood[2] = trap_R_RegisterModel("models/chunks/crate/crate1_3.md3");
00794 dbModels_Wood[3] = trap_R_RegisterModel("models/chunks/crate/crate1_4.md3");
00795 dbModels_Wood[4] = trap_R_RegisterModel("models/chunks/crate/crate2_1.md3");
00796 dbModels_Wood[5] = trap_R_RegisterModel("models/chunks/crate/crate2_2.md3");
00797 dbModels_Wood[6] = trap_R_RegisterModel("models/chunks/crate/crate2_3.md3");
00798 dbModels_Wood[7] = trap_R_RegisterModel("models/chunks/crate/crate2_4.md3");
00799 }
00800 if (omodel == DEBRIS_SPECIALCASE_CHUNKS && !dbModels_Chunks[0])
00801 {
00802 dbModels_Chunks[0] = trap_R_RegisterModel("models/chunks/generic/chunks_1.md3");
00803 dbModels_Chunks[1] = trap_R_RegisterModel("models/chunks/generic/chunks_2.md3");
00804 }
00805 if (omodel == DEBRIS_SPECIALCASE_ROCK && !dbModels_Rocks[0])
00806 {
00807 dbModels_Rocks[0] = trap_R_RegisterModel("models/chunks/rock/rock1_1.md3");
00808 dbModels_Rocks[1] = trap_R_RegisterModel("models/chunks/rock/rock1_2.md3");
00809 dbModels_Rocks[2] = trap_R_RegisterModel("models/chunks/rock/rock1_3.md3");
00810 dbModels_Rocks[3] = trap_R_RegisterModel("models/chunks/rock/rock1_4.md3");
00811
00812
00813
00814
00815
00816
00817
00818
00819
00820
00821 }
00822
00823 VectorSubtract(maxs, mins, a);
00824
00825 windowmass = VectorLength(a);
00826
00827 while (shardsthrow < windowmass)
00828 {
00829 velocity[0] = crandom()*150;
00830 velocity[1] = crandom()*150;
00831 velocity[2] = 150 + crandom()*75;
00832
00833 if (omodel == DEBRIS_SPECIALCASE_GLASS)
00834 {
00835 debrismodel = dbModels_Glass[Q_irand(0, NUM_DEBRIS_MODELS_GLASS-1)];
00836 }
00837 else if (omodel == DEBRIS_SPECIALCASE_WOOD)
00838 {
00839 debrismodel = dbModels_Wood[Q_irand(0, NUM_DEBRIS_MODELS_WOOD-1)];
00840 }
00841 else if (omodel == DEBRIS_SPECIALCASE_CHUNKS)
00842 {
00843 debrismodel = dbModels_Chunks[Q_irand(0, NUM_DEBRIS_MODELS_CHUNKS-1)];
00844 }
00845 else if (omodel == DEBRIS_SPECIALCASE_ROCK)
00846 {
00847 debrismodel = dbModels_Rocks[Q_irand(0, NUM_DEBRIS_MODELS_ROCKS-1)];
00848 }
00849
00850 VectorCopy(org, shardorg);
00851
00852 dif[0] = (maxs[0]-mins[0])/2;
00853 dif[1] = (maxs[1]-mins[1])/2;
00854 dif[2] = (maxs[2]-mins[2])/2;
00855
00856 if (dif[0] < 2)
00857 {
00858 dif[0] = 2;
00859 }
00860 if (dif[1] < 2)
00861 {
00862 dif[1] = 2;
00863 }
00864 if (dif[2] < 2)
00865 {
00866 dif[2] = 2;
00867 }
00868
00869 difx[0] = Q_irand(1, (dif[0]*0.9)*2);
00870 difx[1] = Q_irand(1, (dif[1]*0.9)*2);
00871 difx[2] = Q_irand(1, (dif[2]*0.9)*2);
00872
00873 if (difx[0] > dif[0])
00874 {
00875 shardorg[0] += difx[0]-(dif[0]);
00876 }
00877 else
00878 {
00879 shardorg[0] -= difx[0];
00880 }
00881 if (difx[1] > dif[1])
00882 {
00883 shardorg[1] += difx[1]-(dif[1]);
00884 }
00885 else
00886 {
00887 shardorg[1] -= difx[1];
00888 }
00889 if (difx[2] > dif[2])
00890 {
00891 shardorg[2] += difx[2]-(dif[2]);
00892 }
00893 else
00894 {
00895 shardorg[2] -= difx[2];
00896 }
00897
00898
00899
00900 CG_ThrowChunk( shardorg, velocity, debrismodel, debrissound, 0 );
00901
00902 shardsthrow += 10;
00903 }
00904 }
00905
00906
00907
00908
00909
00910
00911
00912
00913
00914
00915
00916
00917
00918
00919 void CG_ExplosionEffects( vec3_t origin, float intensity, int radius, int time )
00920 {
00921
00922
00923 vec3_t dir;
00924 float dist, intensityScale;
00925 float realIntensity;
00926
00927 VectorSubtract( cg.refdef.vieworg, origin, dir );
00928 dist = VectorNormalize( dir );
00929
00930
00931
00932 if ( dist > radius )
00933 return;
00934
00935 intensityScale = 1 - ( dist / (float) radius );
00936 realIntensity = intensity * intensityScale;
00937
00938 CGCam_Shake( realIntensity, time );
00939 }
00940
00941
00942
00943
00944
00945
00946
00947
00948
00949 void CG_MiscModelExplosion( vec3_t mins, vec3_t maxs, int size, material_t chunkType )
00950 {
00951 int ct = 13;
00952 float r;
00953 vec3_t org, mid, dir;
00954 char *effect = NULL, *effect2 = NULL;
00955 int eID1, eID2 = 0;
00956 int i;
00957
00958 VectorAdd( mins, maxs, mid );
00959 VectorScale( mid, 0.5f, mid );
00960
00961 switch( chunkType )
00962 {
00963 case MAT_GLASS:
00964 effect = "chunks/glassbreak";
00965 ct = 5;
00966 break;
00967 case MAT_GLASS_METAL:
00968 effect = "chunks/glassbreak";
00969 effect2 = "chunks/metalexplode";
00970 ct = 5;
00971 break;
00972 case MAT_ELECTRICAL:
00973 case MAT_ELEC_METAL:
00974 effect = "chunks/sparkexplode";
00975 ct = 5;
00976 break;
00977 case MAT_METAL:
00978 case MAT_METAL2:
00979 case MAT_METAL3:
00980 case MAT_CRATE1:
00981 case MAT_CRATE2:
00982 effect = "chunks/metalexplode";
00983 ct = 2;
00984 break;
00985 case MAT_GRATE1:
00986 effect = "chunks/grateexplode";
00987 ct = 8;
00988 break;
00989 case MAT_ROPE:
00990 ct = 20;
00991 effect = "chunks/ropebreak";
00992 break;
00993 case MAT_WHITE_METAL:
00994 case MAT_DRK_STONE:
00995 case MAT_LT_STONE:
00996 case MAT_GREY_STONE:
00997 case MAT_SNOWY_ROCK:
00998 switch( size )
00999 {
01000 case 2:
01001 effect = "chunks/rockbreaklg";
01002 break;
01003 case 1:
01004 default:
01005 effect = "chunks/rockbreakmed";
01006 break;
01007 }
01008 }
01009
01010 if ( !effect )
01011 {
01012 return;
01013 }
01014
01015 ct += 7 * size;
01016
01017
01018
01019
01020 eID1 = trap_FX_RegisterEffect( effect );
01021
01022 if ( effect2 && effect2[0] )
01023 {
01024
01025 eID2 = trap_FX_RegisterEffect( effect2 );
01026 }
01027
01028
01029 for ( i = 0; i < ct; i++ )
01030 {
01031 int j;
01032 for( j = 0; j < 3; j++ )
01033 {
01034 r = random() * 0.8f + 0.1f;
01035 org[j] = ( r * mins[j] + ( 1 - r ) * maxs[j] );
01036 }
01037
01038
01039 VectorSubtract( org, mid, dir );
01040 VectorNormalize( dir );
01041
01042 if ( effect2 && effect2[0] && ( rand() & 1 ))
01043 {
01044 trap_FX_PlayEffectID( eID2, org, dir, -1, -1 );
01045 }
01046 else
01047 {
01048 trap_FX_PlayEffectID( eID1, org, dir, -1, -1 );
01049 }
01050 }
01051 }
01052
01053
01054
01055
01056
01057
01058
01059
01060
01061 void CG_Chunks( int owner, vec3_t origin, const vec3_t normal, const vec3_t mins, const vec3_t maxs,
01062 float speed, int numChunks, material_t chunkType, int customChunk, float baseScale )
01063 {
01064 localEntity_t *le;
01065 refEntity_t *re;
01066 vec3_t dir;
01067 int i, j, k;
01068 int chunkModel = 0;
01069 leBounceSoundType_t bounce = LEBS_NONE;
01070 float r, speedMod = 1.0f;
01071 qboolean chunk = qfalse;
01072
01073 if ( chunkType == MAT_NONE )
01074 {
01075
01076 return;
01077 }
01078
01079
01080 switch( chunkType )
01081 {
01082 case MAT_GLASS:
01083 trap_S_StartSound( NULL, owner, CHAN_BODY, cgs.media.glassChunkSound );
01084 return;
01085 break;
01086 case MAT_GRATE1:
01087 trap_S_StartSound( NULL, owner, CHAN_BODY, cgs.media.grateSound );
01088 return;
01089 break;
01090 case MAT_ELECTRICAL:
01091 trap_S_StartSound( NULL, owner, CHAN_BODY, trap_S_RegisterSound (va("sound/ambience/spark%d.wav", Q_irand(1, 6))) );
01092 return;
01093 break;
01094 case MAT_DRK_STONE:
01095 case MAT_LT_STONE:
01096 case MAT_GREY_STONE:
01097 case MAT_WHITE_METAL:
01098 case MAT_SNOWY_ROCK:
01099 trap_S_StartSound( NULL, owner, CHAN_BODY, cgs.media.rockBreakSound );
01100 bounce = LEBS_ROCK;
01101 speedMod = 0.5f;
01102 break;
01103 case MAT_GLASS_METAL:
01104 trap_S_StartSound( NULL, owner, CHAN_BODY, cgs.media.glassChunkSound );
01105 bounce = LEBS_METAL;
01106 break;
01107 case MAT_CRATE1:
01108 case MAT_CRATE2:
01109 trap_S_StartSound( NULL, owner, CHAN_BODY, cgs.media.crateBreakSound[Q_irand(0,1)] );
01110 break;
01111 case MAT_METAL:
01112 case MAT_METAL2:
01113 case MAT_METAL3:
01114 case MAT_ELEC_METAL:
01115 trap_S_StartSound( NULL, owner, CHAN_BODY, cgs.media.chunkSound );
01116 bounce = LEBS_METAL;
01117 speedMod = 0.8f;
01118 break;
01119 case MAT_ROPE:
01120
01121 return;
01122 break;
01123 }
01124
01125 if ( baseScale <= 0.0f )
01126 {
01127 baseScale = 1.0f;
01128 }
01129
01130
01131 for( i = 0; i < numChunks; i++ )
01132 {
01133 if ( customChunk > 0 )
01134 {
01135
01136 if ( cgs.gameModels[customChunk] )
01137 {
01138 chunk = qtrue;
01139 chunkModel = cgs.gameModels[customChunk];
01140 }
01141 }
01142
01143 if ( !chunk )
01144 {
01145
01146 switch( chunkType )
01147 {
01148 case MAT_METAL2:
01149 chunkModel = cgs.media.chunkModels[CHUNK_METAL2][Q_irand(0, 3)];
01150 break;
01151 case MAT_GREY_STONE:
01152 chunkModel = cgs.media.chunkModels[CHUNK_ROCK1][Q_irand(0, 3)];
01153 break;
01154 case MAT_LT_STONE:
01155 chunkModel = cgs.media.chunkModels[CHUNK_ROCK2][Q_irand(0, 3)];
01156 break;
01157 case MAT_DRK_STONE:
01158 chunkModel = cgs.media.chunkModels[CHUNK_ROCK3][Q_irand(0, 3)];
01159 break;
01160 case MAT_SNOWY_ROCK:
01161 if ( Q_irand( 0, 1 ) )
01162 {
01163 chunkModel = cgs.media.chunkModels[CHUNK_ROCK1][Q_irand(0, 3)];
01164 }
01165 else
01166 {
01167 chunkModel = cgs.media.chunkModels[CHUNK_ROCK3][Q_irand(0, 3)];
01168 }
01169 break;
01170 case MAT_WHITE_METAL:
01171 chunkModel = cgs.media.chunkModels[CHUNK_WHITE_METAL][Q_irand(0, 3)];
01172 break;
01173 case MAT_CRATE1:
01174 chunkModel = cgs.media.chunkModels[CHUNK_CRATE1][Q_irand(0, 3)];
01175 break;
01176 case MAT_CRATE2:
01177 chunkModel = cgs.media.chunkModels[CHUNK_CRATE2][Q_irand(0, 3)];
01178 break;
01179 case MAT_ELEC_METAL:
01180 case MAT_GLASS_METAL:
01181 case MAT_METAL:
01182 chunkModel = cgs.media.chunkModels[CHUNK_METAL1][Q_irand(0, 3)];
01183 break;
01184 case MAT_METAL3:
01185 if ( rand() & 1 )
01186 {
01187 chunkModel = cgs.media.chunkModels[CHUNK_METAL1][Q_irand(0, 3)];
01188 }
01189 else
01190 {
01191 chunkModel = cgs.media.chunkModels[CHUNK_METAL2][Q_irand(0, 3)];
01192 }
01193 break;
01194 }
01195 }
01196
01197
01198 if ( chunkModel )
01199 {
01200 le = CG_AllocLocalEntity();
01201 re = &le->refEntity;
01202
01203 re->hModel = chunkModel;
01204 le->leType = LE_FRAGMENT;
01205 le->endTime = cg.time + 1300 + random() * 900;
01206
01207
01208 for( j = 0; j < 3; j++ )
01209 {
01210 r = random() * 0.8f + 0.1f;
01211 re->origin[j] = ( r * mins[j] + ( 1 - r ) * maxs[j] );
01212 }
01213 VectorCopy( re->origin, le->pos.trBase );
01214
01215
01216 VectorSubtract( re->origin, origin, dir );
01217 VectorNormalize( dir );
01218 VectorScale( dir, flrand( speed * 0.5f, speed * 1.25f ) * speedMod, le->pos.trDelta );
01219
01220
01221 VectorSet( le->angles.trBase, random() * 360, random() * 360, random() * 360 );
01222
01223 le->angles.trDelta[0] = crandom();
01224 le->angles.trDelta[1] = crandom();
01225 le->angles.trDelta[2] = 0;
01226
01227 VectorScale( le->angles.trDelta, random() * 600.0f + 200.0f, le->angles.trDelta );
01228
01229 le->pos.trType = TR_GRAVITY;
01230 le->angles.trType = TR_LINEAR;
01231 le->pos.trTime = le->angles.trTime = cg.time;
01232 le->bounceFactor = 0.2f + random() * 0.2f;
01233 le->leFlags |= LEF_TUMBLE;
01234
01235 le->leBounceSoundType = bounce;
01236
01237
01238 le->radius = flrand( baseScale * 0.75f, baseScale * 1.25f );
01239 re->nonNormalizedAxes = qtrue;
01240 AxisCopy( axisDefault, re->axis );
01241 for( k = 0; k < 3; k++ )
01242 {
01243 re->modelScale[k] = le->radius;
01244 }
01245 ScaleModelAxis(re);
01246
01247
01248
01249
01250
01251
01252 }
01253 }
01254 }
01255
01256
01257
01258
01259
01260
01261 void CG_ScorePlum( int client, vec3_t org, int score ) {
01262 localEntity_t *le;
01263 refEntity_t *re;
01264 vec3_t angles;
01265 static vec3_t lastPos;
01266
01267
01268 if (client != cg.predictedPlayerState.clientNum || cg_scorePlum.integer == 0) {
01269 return;
01270 }
01271
01272 le = CG_AllocLocalEntity();
01273 le->leFlags = 0;
01274 le->leType = LE_SCOREPLUM;
01275 le->startTime = cg.time;
01276 le->endTime = cg.time + 4000;
01277 le->lifeRate = 1.0 / ( le->endTime - le->startTime );
01278
01279
01280 le->color[0] = le->color[1] = le->color[2] = le->color[3] = 1.0;
01281 le->radius = score;
01282
01283 VectorCopy( org, le->pos.trBase );
01284 if (org[2] >= lastPos[2] - 20 && org[2] <= lastPos[2] + 20) {
01285 le->pos.trBase[2] -= 20;
01286 }
01287
01288
01289 VectorCopy(org, lastPos);
01290
01291
01292 re = &le->refEntity;
01293
01294 re->reType = RT_SPRITE;
01295 re->radius = 16;
01296
01297 VectorClear(angles);
01298 AnglesToAxis( angles, re->axis );
01299 }
01300
01301
01302
01303
01304
01305
01306 localEntity_t *CG_MakeExplosion( vec3_t origin, vec3_t dir,
01307 qhandle_t hModel, int numFrames, qhandle_t shader,
01308 int msec, qboolean isSprite, float scale, int flags )
01309 {
01310 float ang = 0;
01311 localEntity_t *ex;
01312 int offset;
01313 vec3_t tmpVec, newOrigin;
01314
01315 if ( msec <= 0 ) {
01316 CG_Error( "CG_MakeExplosion: msec = %i", msec );
01317 }
01318
01319
01320 offset = rand() & 63;
01321
01322 ex = CG_AllocLocalEntity();
01323 if ( isSprite ) {
01324 ex->leType = LE_SPRITE_EXPLOSION;
01325 ex->refEntity.rotation = rand() % 360;
01326 ex->radius = scale;
01327 VectorScale( dir, 16, tmpVec );
01328 VectorAdd( tmpVec, origin, newOrigin );
01329 } else {
01330 ex->leType = LE_EXPLOSION;
01331 VectorCopy( origin, newOrigin );
01332
01333
01334 if ( !dir )
01335 {
01336 AxisClear( ex->refEntity.axis );
01337 }
01338 else
01339 {
01340 if ( !(flags & LEF_NO_RANDOM_ROTATE) )
01341 ang = rand() % 360;
01342 VectorCopy( dir, ex->refEntity.axis[0] );
01343 RotateAroundDirection( ex->refEntity.axis, ang );
01344 }
01345 }
01346
01347 ex->startTime = cg.time - offset;
01348 ex->endTime = ex->startTime + msec;
01349
01350
01351 ex->refEntity.shaderTime = ex->startTime / 1000.0f;
01352
01353 ex->refEntity.hModel = hModel;
01354 ex->refEntity.customShader = shader;
01355 ex->lifeRate = (float)numFrames / msec;
01356 ex->leFlags = flags;
01357
01358
01359 if (scale != 1) {
01360 ex->refEntity.nonNormalizedAxes = qtrue;
01361
01362 VectorScale( ex->refEntity.axis[0], scale, ex->refEntity.axis[0] );
01363 VectorScale( ex->refEntity.axis[1], scale, ex->refEntity.axis[1] );
01364 VectorScale( ex->refEntity.axis[2], scale, ex->refEntity.axis[2] );
01365 }
01366
01367 VectorCopy ( newOrigin, ex->refEntity.origin);
01368 VectorCopy ( newOrigin, ex->refEntity.oldorigin );
01369
01370 ex->color[0] = ex->color[1] = ex->color[2] = 1.0;
01371
01372 return ex;
01373 }
01374
01375
01376
01377
01378
01379
01380
01381
01382
01383
01384 #define NUM_SPARKS 12
01385 #define NUM_PUFFS 1
01386 #define NUM_EXPLOSIONS 4
01387
01388 void CG_SurfaceExplosion( vec3_t origin, vec3_t normal, float radius, float shake_speed, qboolean smoke )
01389 {
01390 localEntity_t *le;
01391
01392 vec3_t direction, new_org;
01393 vec3_t velocity = { 0, 0, 0 };
01394 vec3_t temp_org, temp_vel;
01395 float scale, dscale;
01396 int i, numSparks;
01397
01398
01399 numSparks = 16 + (random() * 16.0f);
01400
01401 for ( i = 0; i < numSparks; i++ )
01402 {
01403 scale = 0.25f + (random() * 2.0f);
01404 dscale = -scale*0.5;
01405
01406
01407
01408
01409
01410
01411
01412
01413
01414
01415
01416
01417
01418
01419
01420
01421
01422
01423 }
01424
01425
01426
01427 VectorMA( origin,