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