00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "g_local.h"
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 void MatchTeam( gentity_t *teamLeader, int moverState, int time );
00037
00038 typedef struct {
00039 gentity_t *ent;
00040 vec3_t origin;
00041 vec3_t angles;
00042 float deltayaw;
00043 } pushed_t;
00044 pushed_t pushed[MAX_GENTITIES], *pushed_p;
00045
00046
00047
00048
00049
00050
00051
00052
00053 gentity_t *G_TestEntityPosition( gentity_t *ent ) {
00054 trace_t tr;
00055 int mask;
00056
00057 if ( ent->clipmask ) {
00058 mask = ent->clipmask;
00059 } else {
00060 mask = MASK_SOLID;
00061 }
00062 if ( ent->client ) {
00063 trap_Trace( &tr, ent->client->ps.origin, ent->r.mins, ent->r.maxs, ent->client->ps.origin, ent->s.number, mask );
00064 } else {
00065 trap_Trace( &tr, ent->s.pos.trBase, ent->r.mins, ent->r.maxs, ent->s.pos.trBase, ent->s.number, mask );
00066 }
00067
00068 if (tr.startsolid)
00069 return &g_entities[ tr.entityNum ];
00070
00071 return NULL;
00072 }
00073
00074
00075
00076
00077
00078
00079 void G_CreateRotationMatrix(vec3_t angles, vec3_t matrix[3]) {
00080 AngleVectors(angles, matrix[0], matrix[1], matrix[2]);
00081 VectorInverse(matrix[1]);
00082 }
00083
00084
00085
00086
00087
00088
00089 void G_TransposeMatrix(vec3_t matrix[3], vec3_t transpose[3]) {
00090 int i, j;
00091 for (i = 0; i < 3; i++) {
00092 for (j = 0; j < 3; j++) {
00093 transpose[i][j] = matrix[j][i];
00094 }
00095 }
00096 }
00097
00098
00099
00100
00101
00102
00103 void G_RotatePoint(vec3_t point, vec3_t matrix[3]) {
00104 vec3_t tvec;
00105
00106 VectorCopy(point, tvec);
00107 point[0] = DotProduct(matrix[0], tvec);
00108 point[1] = DotProduct(matrix[1], tvec);
00109 point[2] = DotProduct(matrix[2], tvec);
00110 }
00111
00112
00113
00114
00115
00116
00117
00118
00119 qboolean G_TryPushingEntity( gentity_t *check, gentity_t *pusher, vec3_t move, vec3_t amove ) {
00120 vec3_t matrix[3], transpose[3];
00121 vec3_t org, org2, move2;
00122 gentity_t *block;
00123
00124
00125
00126 if ( ( pusher->s.eFlags & EF_MOVER_STOP ) &&
00127 check->s.groundEntityNum != pusher->s.number ) {
00128 return qfalse;
00129 }
00130
00131
00132 if (pushed_p > &pushed[MAX_GENTITIES]) {
00133 G_Error( "pushed_p > &pushed[MAX_GENTITIES]" );
00134 }
00135 pushed_p->ent = check;
00136 VectorCopy (check->s.pos.trBase, pushed_p->origin);
00137 VectorCopy (check->s.apos.trBase, pushed_p->angles);
00138 if ( check->client ) {
00139 pushed_p->deltayaw = check->client->ps.delta_angles[YAW];
00140 VectorCopy (check->client->ps.origin, pushed_p->origin);
00141 }
00142 pushed_p++;
00143
00144
00145
00146 G_CreateRotationMatrix( amove, transpose );
00147 G_TransposeMatrix( transpose, matrix );
00148 if ( check->client ) {
00149 VectorSubtract (check->client->ps.origin, pusher->r.currentOrigin, org);
00150 }
00151 else {
00152 VectorSubtract (check->s.pos.trBase, pusher->r.currentOrigin, org);
00153 }
00154 VectorCopy( org, org2 );
00155 G_RotatePoint( org2, matrix );
00156 VectorSubtract (org2, org, move2);
00157
00158 VectorAdd (check->s.pos.trBase, move, check->s.pos.trBase);
00159 VectorAdd (check->s.pos.trBase, move2, check->s.pos.trBase);
00160 if ( check->client ) {
00161 VectorAdd (check->client->ps.origin, move, check->client->ps.origin);
00162 VectorAdd (check->client->ps.origin, move2, check->client->ps.origin);
00163
00164 check->client->ps.delta_angles[YAW] += ANGLE2SHORT(amove[YAW]);
00165 }
00166
00167
00168 if ( check->s.groundEntityNum != pusher->s.number ) {
00169 check->s.groundEntityNum = -1;
00170 }
00171
00172 block = G_TestEntityPosition( check );
00173 if (!block) {
00174
00175 if ( check->client ) {
00176 VectorCopy( check->client->ps.origin, check->r.currentOrigin );
00177 } else {
00178 VectorCopy( check->s.pos.trBase, check->r.currentOrigin );
00179 }
00180 trap_LinkEntity (check);
00181 return qtrue;
00182 }
00183
00184
00185
00186
00187 VectorCopy( (pushed_p-1)->origin, check->s.pos.trBase);
00188 if ( check->client ) {
00189 VectorCopy( (pushed_p-1)->origin, check->client->ps.origin);
00190 }
00191 VectorCopy( (pushed_p-1)->angles, check->s.apos.trBase );
00192 block = G_TestEntityPosition (check);
00193 if ( !block ) {
00194 check->s.groundEntityNum = -1;
00195 pushed_p--;
00196 return qtrue;
00197 }
00198
00199
00200 return qfalse;
00201 }
00202
00203
00204
00205
00206
00207
00208 qboolean G_CheckProxMinePosition( gentity_t *check ) {
00209 vec3_t start, end;
00210 trace_t tr;
00211
00212 VectorMA(check->s.pos.trBase, 0.125, check->movedir, start);
00213 VectorMA(check->s.pos.trBase, 2, check->movedir, end);
00214 trap_Trace( &tr, start, NULL, NULL, end, check->s.number, MASK_SOLID );
00215
00216 if (tr.startsolid || tr.fraction < 1)
00217 return qfalse;
00218
00219 return qtrue;
00220 }
00221
00222
00223
00224
00225
00226
00227 qboolean G_TryPushingProxMine( gentity_t *check, gentity_t *pusher, vec3_t move, vec3_t amove ) {
00228 vec3_t forward, right, up;
00229 vec3_t org, org2, move2;
00230 int ret;
00231
00232
00233 VectorSubtract (vec3_origin, amove, org);
00234 AngleVectors (org, forward, right, up);
00235
00236
00237 VectorAdd (check->s.pos.trBase, move, check->s.pos.trBase);
00238
00239
00240 VectorSubtract (check->s.pos.trBase, pusher->r.currentOrigin, org);
00241 org2[0] = DotProduct (org, forward);
00242 org2[1] = -DotProduct (org, right);
00243 org2[2] = DotProduct (org, up);
00244 VectorSubtract (org2, org, move2);
00245 VectorAdd (check->s.pos.trBase, move2, check->s.pos.trBase);
00246
00247 ret = G_CheckProxMinePosition( check );
00248 if (ret) {
00249 VectorCopy( check->s.pos.trBase, check->r.currentOrigin );
00250 trap_LinkEntity (check);
00251 }
00252 return ret;
00253 }
00254
00255 void G_ExplodeMissile( gentity_t *ent );
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266 qboolean G_MoverPush( gentity_t *pusher, vec3_t move, vec3_t amove, gentity_t **obstacle ) {
00267 int i, e;
00268 gentity_t *check;
00269 vec3_t mins, maxs;
00270 pushed_t *p;
00271 int entityList[MAX_GENTITIES];
00272 int listedEntities;
00273 vec3_t totalMins, totalMaxs;
00274
00275 *obstacle = NULL;
00276
00277
00278
00279
00280 if ( pusher->r.currentAngles[0] || pusher->r.currentAngles[1] || pusher->r.currentAngles[2]
00281 || amove[0] || amove[1] || amove[2] ) {
00282 float radius;
00283
00284 radius = RadiusFromBounds( pusher->r.mins, pusher->r.maxs );
00285 for ( i = 0 ; i < 3 ; i++ ) {
00286 mins[i] = pusher->r.currentOrigin[i] + move[i] - radius;
00287 maxs[i] = pusher->r.currentOrigin[i] + move[i] + radius;
00288 totalMins[i] = mins[i] - move[i];
00289 totalMaxs[i] = maxs[i] - move[i];
00290 }
00291 } else {
00292 for (i=0 ; i<3 ; i++) {
00293 mins[i] = pusher->r.absmin[i] + move[i];
00294 maxs[i] = pusher->r.absmax[i] + move[i];
00295 }
00296
00297 VectorCopy( pusher->r.absmin, totalMins );
00298 VectorCopy( pusher->r.absmax, totalMaxs );
00299 for (i=0 ; i<3 ; i++) {
00300 if ( move[i] > 0 ) {
00301 totalMaxs[i] += move[i];
00302 } else {
00303 totalMins[i] += move[i];
00304 }
00305 }
00306 }
00307
00308
00309 trap_UnlinkEntity( pusher );
00310
00311 listedEntities = trap_EntitiesInBox( totalMins, totalMaxs, entityList, MAX_GENTITIES );
00312
00313
00314 VectorAdd( pusher->r.currentOrigin, move, pusher->r.currentOrigin );
00315 VectorAdd( pusher->r.currentAngles, amove, pusher->r.currentAngles );
00316 trap_LinkEntity( pusher );
00317
00318
00319 for ( e = 0 ; e < listedEntities ; e++ ) {
00320 check = &g_entities[ entityList[ e ] ];
00321
00322 #ifdef MISSIONPACK
00323 if ( check->s.eType == ET_MISSILE ) {
00324
00325 if ( !strcmp(check->classname, "prox mine") ) {
00326
00327 if ( check->enemy == pusher ) {
00328 if (!G_TryPushingProxMine( check, pusher, move, amove )) {
00329
00330 check->s.loopSound = 0;
00331 G_AddEvent( check, EV_PROXIMITY_MINE_TRIGGER, 0 );
00332 G_ExplodeMissile(check);
00333 if (check->activator) {
00334 G_FreeEntity(check->activator);
00335 check->activator = NULL;
00336 }
00337
00338 }
00339 }
00340 else {
00341
00342 if (!G_CheckProxMinePosition( check )) {
00343
00344 check->s.loopSound = 0;
00345 G_AddEvent( check, EV_PROXIMITY_MINE_TRIGGER, 0 );
00346 G_ExplodeMissile(check);
00347 if (check->activator) {
00348 G_FreeEntity(check->activator);
00349 check->activator = NULL;
00350 }
00351
00352 }
00353 }
00354 continue;
00355 }
00356 }
00357 #endif
00358
00359 if ( check->s.eType != ET_ITEM && check->s.eType != ET_PLAYER && !check->physicsObject ) {
00360 continue;
00361 }
00362
00363
00364 if ( check->s.groundEntityNum != pusher->s.number ) {
00365
00366 if ( check->r.absmin[0] >= maxs[0]
00367 || check->r.absmin[1] >= maxs[1]
00368 || check->r.absmin[2] >= maxs[2]
00369 || check->r.absmax[0] <= mins[0]
00370 || check->r.absmax[1] <= mins[1]
00371 || check->r.absmax[2] <= mins[2] ) {
00372 continue;
00373 }
00374
00375
00376 if (!G_TestEntityPosition (check)) {
00377 continue;
00378 }
00379 }
00380
00381
00382 if ( G_TryPushingEntity( check, pusher, move, amove ) ) {
00383 continue;
00384 }
00385
00386
00387
00388
00389 if ( pusher->s.pos.trType == TR_SINE || pusher->s.apos.trType == TR_SINE ) {
00390 G_Damage( check, pusher, pusher, NULL, NULL, 99999, 0, MOD_CRUSH );
00391 continue;
00392 }
00393
00394
00395
00396 *obstacle = check;
00397
00398
00399
00400
00401 for ( p=pushed_p-1 ; p>=pushed ; p-- ) {
00402 VectorCopy (p->origin, p->ent->s.pos.trBase);
00403 VectorCopy (p->angles, p->ent->s.apos.trBase);
00404 if ( p->ent->client ) {
00405 p->ent->client->ps.delta_angles[YAW] = p->deltayaw;
00406 VectorCopy (p->origin, p->ent->client->ps.origin);
00407 }
00408 trap_LinkEntity (p->ent);
00409 }
00410 return qfalse;
00411 }
00412
00413 return qtrue;
00414 }
00415
00416
00417
00418
00419
00420
00421
00422 void G_MoverTeam( gentity_t *ent ) {
00423 vec3_t move, amove;
00424 gentity_t *part, *obstacle;
00425 vec3_t origin, angles;
00426
00427 obstacle = NULL;
00428
00429
00430
00431
00432 pushed_p = pushed;
00433 for (part = ent ; part ; part=part->teamchain) {
00434
00435 BG_EvaluateTrajectory( &part->s.pos, level.time, origin );
00436 BG_EvaluateTrajectory( &part->s.apos, level.time, angles );
00437 VectorSubtract( origin, part->r.currentOrigin, move );
00438 VectorSubtract( angles, part->r.currentAngles, amove );
00439 if ( !G_MoverPush( part, move, amove, &obstacle ) ) {
00440 break;
00441 }
00442 }
00443
00444 if (part) {
00445
00446 for ( part = ent ; part ; part = part->teamchain ) {
00447 part->s.pos.trTime += level.time - level.previousTime;
00448 part->s.apos.trTime += level.time - level.previousTime;
00449 BG_EvaluateTrajectory( &part->s.pos, level.time, part->r.currentOrigin );
00450 BG_EvaluateTrajectory( &part->s.apos, level.time, part->r.currentAngles );
00451 trap_LinkEntity( part );
00452 }
00453
00454
00455 if (ent->blocked) {
00456 ent->blocked( ent, obstacle );
00457 }
00458 return;
00459 }
00460
00461
00462 for ( part = ent ; part ; part = part->teamchain ) {
00463
00464 if ( part->s.pos.trType == TR_LINEAR_STOP ) {
00465 if ( level.time >= part->s.pos.trTime + part->s.pos.trDuration ) {
00466 if ( part->reached ) {
00467 part->reached( part );
00468 }
00469 }
00470 }
00471 }
00472 }
00473
00474
00475
00476
00477
00478
00479
00480 void G_RunMover( gentity_t *ent ) {
00481
00482
00483 if ( ent->flags & FL_TEAMSLAVE ) {
00484 return;
00485 }
00486
00487
00488 if ( ent->s.pos.trType != TR_STATIONARY || ent->s.apos.trType != TR_STATIONARY ) {
00489 G_MoverTeam( ent );
00490 }
00491
00492
00493 G_RunThink( ent );
00494 }
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511 void SetMoverState( gentity_t *ent, moverState_t moverState, int time ) {
00512 vec3_t delta;
00513 float f;
00514
00515 ent->moverState = moverState;
00516
00517 ent->s.pos.trTime = time;
00518 switch( moverState ) {
00519 case MOVER_POS1:
00520 VectorCopy( ent->pos1, ent->s.pos.trBase );
00521 ent->s.pos.trType = TR_STATIONARY;
00522 break;
00523 case MOVER_POS2:
00524 VectorCopy( ent->pos2, ent->s.pos.trBase );
00525 ent->s.pos.trType = TR_STATIONARY;
00526 break;
00527 case MOVER_1TO2:
00528 VectorCopy( ent->pos1, ent->s.pos.trBase );
00529 VectorSubtract( ent->pos2, ent->pos1, delta );
00530 f = 1000.0 / ent->s.pos.trDuration;
00531 VectorScale( delta, f, ent->s.pos.trDelta );
00532 ent->s.pos.trType = TR_LINEAR_STOP;
00533 break;
00534 case MOVER_2TO1:
00535 VectorCopy( ent->pos2, ent->s.pos.trBase );
00536 VectorSubtract( ent->pos1, ent->pos2, delta );
00537 f = 1000.0 / ent->s.pos.trDuration;
00538 VectorScale( delta, f, ent->s.pos.trDelta );
00539 ent->s.pos.trType = TR_LINEAR_STOP;
00540 break;
00541 }
00542 BG_EvaluateTrajectory( &ent->s.pos, level.time, ent->r.currentOrigin );
00543 trap_LinkEntity( ent );
00544 }
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554 void MatchTeam( gentity_t *teamLeader, int moverState, int time ) {
00555 gentity_t *slave;
00556
00557 for ( slave = teamLeader ; slave ; slave = slave->teamchain ) {
00558 SetMoverState( slave, moverState, time );
00559 }
00560 }
00561
00562
00563
00564
00565
00566
00567
00568
00569 void ReturnToPos1( gentity_t *ent ) {
00570 MatchTeam( ent, MOVER_2TO1, level.time );
00571
00572
00573 ent->s.loopSound = ent->soundLoop;
00574
00575
00576 if ( ent->sound2to1 ) {
00577 G_AddEvent( ent, EV_GENERAL_SOUND, ent->sound2to1 );
00578 }
00579 }
00580
00581
00582
00583
00584
00585
00586
00587 void Reached_BinaryMover( gentity_t *ent ) {
00588
00589
00590 ent->s.loopSound = ent->soundLoop;
00591
00592 if ( ent->moverState == MOVER_1TO2 ) {
00593
00594 SetMoverState( ent, MOVER_POS2, level.time );
00595
00596
00597 if ( ent->soundPos2 ) {
00598 G_AddEvent( ent, EV_GENERAL_SOUND, ent->soundPos2 );
00599 }
00600
00601
00602 ent->think = ReturnToPos1;
00603 ent->nextthink = level.time + ent->wait;
00604
00605
00606 if ( !ent->activator ) {
00607 ent->activator = ent;
00608 }
00609 G_UseTargets( ent, ent->activator );
00610 } else if ( ent->moverState == MOVER_2TO1 ) {
00611
00612 SetMoverState( ent, MOVER_POS1, level.time );
00613
00614
00615 if ( ent->soundPos1 ) {
00616 G_AddEvent( ent, EV_GENERAL_SOUND, ent->soundPos1 );
00617 }
00618
00619
00620 if ( ent->teammaster == ent || !ent->teammaster ) {
00621 trap_AdjustAreaPortalState( ent, qfalse );
00622 }
00623 } else {
00624 G_Error( "Reached_BinaryMover: bad moverState" );
00625 }
00626 }
00627
00628
00629
00630
00631
00632
00633
00634 void Use_BinaryMover( gentity_t *ent, gentity_t *other, gentity_t *activator ) {
00635 int total;
00636 int partial;
00637
00638
00639 if ( ent->flags & FL_TEAMSLAVE ) {
00640 Use_BinaryMover( ent->teammaster, other, activator );
00641 return;
00642 }
00643
00644 ent->activator = activator;
00645
00646 if ( ent->moverState == MOVER_POS1 ) {
00647
00648
00649 MatchTeam( ent, MOVER_1TO2, level.time + 50 );
00650
00651
00652 if ( ent->sound1to2 ) {
00653 G_AddEvent( ent, EV_GENERAL_SOUND, ent->sound1to2 );
00654 }
00655
00656
00657 ent->s.loopSound = ent->soundLoop;
00658
00659
00660 if ( ent->teammaster == ent || !ent->teammaster ) {
00661 trap_AdjustAreaPortalState( ent, qtrue );
00662 }
00663 return;
00664 }
00665
00666
00667 if ( ent->moverState == MOVER_POS2 ) {
00668 ent->nextthink = level.time + ent->wait;
00669 return;
00670 }
00671
00672
00673 if ( ent->moverState == MOVER_2TO1 ) {
00674 total = ent->s.pos.trDuration;
00675 partial = level.time - ent->s.pos.trTime;
00676 if ( partial > total ) {
00677 partial = total;
00678 }
00679
00680 MatchTeam( ent, MOVER_1TO2, level.time - ( total - partial ) );
00681
00682 if ( ent->sound1to2 ) {
00683 G_AddEvent( ent, EV_GENERAL_SOUND, ent->sound1to2 );
00684 }
00685 return;
00686 }
00687
00688
00689 if ( ent->moverState == MOVER_1TO2 ) {
00690 total = ent->s.pos.trDuration;
00691 partial = level.time - ent->s.pos.trTime;
00692 if ( partial > total ) {
00693 partial = total;
00694 }
00695
00696 MatchTeam( ent, MOVER_2TO1, level.time - ( total - partial ) );
00697
00698 if ( ent->sound2to1 ) {
00699 G_AddEvent( ent, EV_GENERAL_SOUND, ent->sound2to1 );
00700 }
00701 return;
00702 }
00703 }
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715 void InitMover( gentity_t *ent ) {
00716 vec3_t move;
00717 float distance;
00718 float light;
00719 vec3_t color;
00720 qboolean lightSet, colorSet;
00721 char *sound;
00722
00723
00724
00725 if ( ent->model2 ) {
00726 ent->s.modelindex2 = G_ModelIndex( ent->model2 );
00727 }
00728
00729
00730 if ( G_SpawnString( "noise", "100", &sound ) ) {
00731 ent->s.loopSound = G_SoundIndex( sound );
00732 }
00733
00734
00735 lightSet = G_SpawnFloat( "light", "100", &light );
00736 colorSet = G_SpawnVector( "color", "1 1 1", color );
00737 if ( lightSet || colorSet ) {
00738 int r, g, b, i;
00739
00740 r = color[0] * 255;
00741 if ( r > 255 ) {
00742 r = 255;
00743 }
00744 g = color[1] * 255;
00745 if ( g > 255 ) {
00746 g = 255;
00747 }
00748 b = color[2] * 255;
00749 if ( b > 255 ) {
00750 b = 255;
00751 }
00752 i = light / 4;
00753 if ( i > 255 ) {
00754 i = 255;
00755 }
00756 ent->s.constantLight = r | ( g << 8 ) | ( b << 16 ) | ( i << 24 );
00757 }
00758
00759
00760 ent->use = Use_BinaryMover;
00761 ent->reached = Reached_BinaryMover;
00762
00763 ent->moverState = MOVER_POS1;
00764 ent->r.svFlags = SVF_USE_CURRENT_ORIGIN;
00765 ent->s.eType = ET_MOVER;
00766 VectorCopy (ent->pos1, ent->r.currentOrigin);
00767 trap_LinkEntity (ent);
00768
00769 ent->s.pos.trType = TR_STATIONARY;
00770 VectorCopy( ent->pos1, ent->s.pos.trBase );
00771
00772
00773 VectorSubtract( ent->pos2, ent->pos1, move );
00774 distance = VectorLength( move );
00775 if ( ! ent->speed ) {
00776 ent->speed = 100;
00777 }
00778 VectorScale( move, ent->speed, ent->s.pos.trDelta );
00779 ent->s.pos.trDuration = distance * 1000 / ent->speed;
00780 if ( ent->s.pos.trDuration <= 0 ) {
00781 ent->s.pos.trDuration = 1;
00782 }
00783 }
00784
00785
00786
00787
00788
00789
00790
00791
00792
00793
00794
00795
00796
00797
00798
00799
00800
00801
00802 void Blocked_Door( gentity_t *ent, gentity_t *other ) {
00803
00804 if ( !other->client ) {
00805
00806 if( other->s.eType == ET_ITEM && other->item->giType == IT_TEAM ) {
00807 Team_DroppedFlagThink( other );
00808 return;
00809 }
00810 G_TempEntity( other->s.origin, EV_ITEM_POP );
00811 G_FreeEntity( other );
00812 return;
00813 }
00814
00815 if ( ent->damage ) {
00816 G_Damage( other, ent, ent, NULL, NULL, ent->damage, 0, MOD_CRUSH );
00817 }
00818 if ( ent->spawnflags & 4 ) {
00819 return;
00820 }
00821
00822
00823 Use_BinaryMover( ent, ent, other );
00824 }
00825
00826
00827
00828
00829
00830
00831 static void Touch_DoorTriggerSpectator( gentity_t *ent, gentity_t *other, trace_t *trace ) {
00832 int i, axis;
00833 vec3_t origin, dir, angles;
00834
00835 axis = ent->count;
00836 VectorClear(dir);
00837 if (fabs(other->s.origin[axis] - ent->r.absmax[axis]) <
00838 fabs(other->s.origin[axis] - ent->r.absmin[axis])) {
00839 origin[axis] = ent->r.absmin[axis] - 10;
00840 dir[axis] = -1;
00841 }
00842 else {
00843 origin[axis] = ent->r.absmax[axis] + 10;
00844 dir[axis] = 1;
00845 }
00846 for (i = 0; i < 3; i++) {
00847 if (i == axis) continue;
00848 origin[i] = (ent->r.absmin[i] + ent->r.absmax[i]) * 0.5;
00849 }
00850 vectoangles(dir, angles);
00851 TeleportPlayer(other, origin, angles );
00852 }
00853
00854
00855
00856
00857
00858
00859 void Touch_DoorTrigger( gentity_t *ent, gentity_t *other, trace_t *trace ) {
00860 if ( other->client && other->client->sess.sessionTeam == TEAM_SPECTATOR ) {
00861
00862 if ( ent->parent->moverState != MOVER_1TO2 &&
00863 ent->parent->moverState != MOVER_POS2) {
00864 Touch_DoorTriggerSpectator( ent, other, trace );
00865 }
00866 }
00867 else if ( ent->parent->moverState != MOVER_1TO2 ) {
00868 Use_BinaryMover( ent->parent, ent, other );
00869 }
00870 }
00871
00872
00873
00874
00875
00876
00877
00878
00879
00880
00881 void Think_SpawnNewDoorTrigger( gentity_t *ent ) {
00882 gentity_t *other;
00883 vec3_t mins, maxs;
00884 int i, best;
00885
00886
00887 for ( other = ent ; other ; other = other->teamchain ) {
00888 other->takedamage = qtrue;
00889 }
00890
00891
00892 VectorCopy (ent->r.absmin, mins);
00893 VectorCopy (ent->r.absmax, maxs);
00894
00895 for (other = ent->teamchain ; other ; other=other->teamchain) {
00896 AddPointToBounds (other->r.absmin, mins, maxs);
00897 AddPointToBounds (other->r.absmax, mins, maxs);
00898 }
00899
00900
00901 best = 0;
00902 for ( i = 1 ; i < 3 ; i++ ) {
00903 if ( maxs[i] - mins[i] < maxs[best] - mins[best] ) {
00904 best = i;
00905 }
00906 }
00907 maxs[best] += 120;
00908 mins[best] -= 120;
00909
00910
00911 other = G_Spawn ();
00912 other->classname = "door_trigger";
00913 VectorCopy (mins, other->r.mins);
00914 VectorCopy (maxs, other->r.maxs);
00915 other->parent = ent;
00916 other->r.contents = CONTENTS_TRIGGER;
00917 other->touch = Touch_DoorTrigger;
00918
00919 other->count = best;
00920 trap_LinkEntity (other);
00921
00922 MatchTeam( ent, ent->moverState, level.time );
00923 }
00924
00925 void Think_MatchTeam( gentity_t *ent ) {
00926 MatchTeam( ent, ent->moverState, level.time );
00927 }
00928
00929
00930
00931
00932
00933
00934
00935
00936
00937
00938
00939
00940
00941
00942
00943
00944
00945
00946 void SP_func_door (gentity_t *ent) {
00947 vec3_t abs_movedir;
00948 float distance;
00949 vec3_t size;
00950 float lip;
00951
00952 ent->sound1to2 = ent->sound2to1 = G_SoundIndex("sound/movers/doors/dr1_strt.wav");
00953 ent->soundPos1 = ent->soundPos2 = G_SoundIndex("sound/movers/doors/dr1_end.wav");
00954
00955 ent->blocked = Blocked_Door;
00956
00957
00958 if (!ent->speed)
00959 ent->speed = 400;
00960
00961
00962 if (!ent->wait)
00963 ent->wait = 2;
00964 ent->wait *= 1000;
00965
00966
00967 G_SpawnFloat( "lip", "8", &lip );
00968
00969
00970 G_SpawnInt( "dmg", "2", &ent->damage );
00971
00972
00973 VectorCopy( ent->s.origin, ent->pos1 );
00974
00975
00976 trap_SetBrushModel( ent, ent->model );
00977 G_SetMovedir (ent->s.angles, ent->movedir);
00978 abs_movedir[0] = fabs(ent->movedir[0]);
00979 abs_movedir[1] = fabs(ent->movedir[1]);
00980 abs_movedir[2] = fabs(ent->movedir[2]);
00981 VectorSubtract( ent->r.maxs, ent->r.mins, size );
00982 distance = DotProduct( abs_movedir, size ) - lip;
00983 VectorMA( ent->pos1, distance, ent->movedir, ent->pos2 );
00984
00985
00986 if ( ent->spawnflags & 1 ) {
00987 vec3_t temp;
00988
00989 VectorCopy( ent->pos2, temp );
00990 VectorCopy( ent->s.origin, ent->pos2 );
00991 VectorCopy( temp, ent->pos1 );
00992 }
00993
00994 InitMover( ent );
00995
00996 ent->nextthink = level.time + FRAMETIME;
00997
00998 if ( ! (ent->flags & FL_TEAMSLAVE ) ) {
00999 int health;
01000
01001 G_SpawnInt( "health", "0", &health );
01002 if ( health ) {
01003 ent->takedamage = qtrue;
01004 }
01005 if ( ent->targetname || health ) {
01006
01007 ent->think = Think_MatchTeam;
01008 } else {
01009 ent->think = Think_SpawnNewDoorTrigger;
01010 }
01011 }
01012
01013
01014 }
01015
01016
01017
01018
01019
01020
01021
01022
01023
01024
01025
01026
01027
01028
01029
01030
01031 void Touch_Plat( gentity_t *ent, gentity_t *other, trace_t *trace ) {
01032 if ( !other->client || other->client->ps.stats[STAT_HEALTH] <= 0 ) {
01033 return;
01034 }
01035
01036
01037 if ( ent->moverState == MOVER_POS2 ) {
01038 ent->nextthink = level.time + 1000;
01039 }
01040 }
01041
01042
01043
01044
01045
01046
01047
01048
01049 void Touch_PlatCenterTrigger(gentity_t *ent, gentity_t *other, trace_t *trace ) {
01050 if ( !other->client ) {
01051 return;
01052 }
01053
01054 if ( ent->parent->moverState == MOVER_POS1 ) {
01055 Use_BinaryMover( ent->parent, ent, other );
01056 }
01057 }
01058
01059
01060
01061
01062
01063
01064
01065
01066
01067
01068
01069 void SpawnPlatTrigger( gentity_t *ent ) {
01070 gentity_t *trigger;
01071 vec3_t tmin, tmax;
01072
01073
01074
01075 trigger = G_Spawn();
01076 trigger->classname = "plat_trigger";
01077 trigger->touch = Touch_PlatCenterTrigger;
01078 trigger->r.contents = CONTENTS_TRIGGER;
01079 trigger->parent = ent;
01080
01081 tmin[0] = ent->pos1[0] + ent->r.mins[0] + 33;
01082 tmin[1] = ent->pos1[1] + ent->r.mins[1] + 33;
01083 tmin[2] = ent->pos1[2] + ent->r.mins[2];
01084
01085 tmax[0] = ent->pos1[0] + ent->r.maxs[0] - 33;
01086 tmax[1] = ent->pos1[1] + ent->r.maxs[1] - 33;
01087 tmax[2] = ent->pos1[2] + ent->r.maxs[2] + 8;
01088
01089 if ( tmax[0] <= tmin[0] ) {
01090 tmin[0] = ent->pos1[0] + (ent->r.mins[0] + ent->r.maxs[0]) *0.5;
01091 tmax[0] = tmin[0] + 1;
01092 }
01093 if ( tmax[1] <= tmin[1] ) {
01094 tmin[1] = ent->pos1[1] + (ent->r.mins[1] + ent->r.maxs[1]) *0.5;
01095 tmax[1] = tmin[1] + 1;
01096 }
01097
01098 VectorCopy (tmin, trigger->r.mins);
01099 VectorCopy (tmax, trigger->r.maxs);
01100
01101 trap_LinkEntity (trigger);
01102 }
01103
01104
01105
01106
01107
01108
01109
01110
01111
01112
01113
01114
01115
01116 void SP_func_plat (gentity_t *ent) {
01117 float lip, height;
01118
01119 ent->sound1to2 = ent->sound2to1 = G_SoundIndex("sound/movers/plats/pt1_strt.wav");
01120 ent->soundPos1 = ent->soundPos2 = G_SoundIndex("sound/movers/plats/pt1_end.wav");
01121
01122 VectorClear (ent->s.angles);
01123
01124 G_SpawnFloat( "speed", "200", &ent->speed );
01125 G_SpawnInt( "dmg", "2", &ent->damage );
01126 G_SpawnFloat( "wait", "1", &ent->wait );
01127 G_SpawnFloat( "lip", "8", &lip );
01128
01129 ent->wait = 1000;
01130
01131
01132 trap_SetBrushModel( ent, ent->model );
01133
01134 if ( !G_SpawnFloat( "height", "0", &height ) ) {
01135 height = (ent->r.maxs[2] - ent->r.mins[2]) - lip;
01136 }
01137
01138
01139 VectorCopy( ent->s.origin, ent->pos2 );
01140 VectorCopy( ent->pos2, ent->pos1 );
01141 ent->pos1[2] -= height;
01142
01143 InitMover( ent );
01144
01145
01146
01147 ent->touch = Touch_Plat;
01148
01149 ent->blocked = Blocked_Door;
01150
01151 ent->parent = ent;
01152
01153
01154 if ( !ent->targetname ) {
01155 SpawnPlatTrigger(ent);
0