00001
00002
00003
00004
00005 #include "g_local.h"
00006 #include "../ghoul2/G2.h"
00007
00008 #include "ai_main.h"
00009
00010 #define HOLOCRON_RESPAWN_TIME 30000
00011 #define MAX_AMMO_GIVE 2
00012 #define STATION_RECHARGE_TIME 100
00013
00014 void HolocronThink(gentity_t *ent);
00015 extern vmCvar_t g_MaxHolocronCarry;
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 void SP_info_camp( gentity_t *self ) {
00026 G_SetOrigin( self, self->s.origin );
00027 }
00028
00029
00030
00031
00032
00033 void SP_info_null( gentity_t *self ) {
00034 G_FreeEntity( self );
00035 }
00036
00037
00038
00039
00040
00041
00042 void SP_info_notnull( gentity_t *self ){
00043 G_SetOrigin( self, self->s.origin );
00044 }
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086 static void misc_lightstyle_set ( gentity_t *ent)
00087 {
00088 const int mLightStyle = ent->count;
00089 const int mLightSwitchStyle = ent->bounceCount;
00090 const int mLightOffStyle = ent->fly_sound_debounce_time;
00091 if (!ent->alt_fire)
00092 {
00093 if (mLightOffStyle)
00094 {
00095 char lightstyle[32];
00096 trap_GetConfigstring(CS_LIGHT_STYLES + (mLightOffStyle*3)+0, lightstyle, 32);
00097 trap_SetConfigstring(CS_LIGHT_STYLES + (mLightStyle*3)+0, lightstyle);
00098
00099 trap_GetConfigstring(CS_LIGHT_STYLES + (mLightOffStyle*3)+1, lightstyle, 32);
00100 trap_SetConfigstring(CS_LIGHT_STYLES + (mLightStyle*3)+1, lightstyle);
00101
00102 trap_GetConfigstring(CS_LIGHT_STYLES + (mLightOffStyle*3)+2, lightstyle, 32);
00103 trap_SetConfigstring(CS_LIGHT_STYLES + (mLightStyle*3)+2, lightstyle);
00104 }else
00105 {
00106 trap_SetConfigstring(CS_LIGHT_STYLES + (mLightStyle*3)+0, "a");
00107 trap_SetConfigstring(CS_LIGHT_STYLES + (mLightStyle*3)+1, "a");
00108 trap_SetConfigstring(CS_LIGHT_STYLES + (mLightStyle*3)+2, "a");
00109 }
00110 }
00111 else
00112 {
00113 if (mLightSwitchStyle)
00114 {
00115 char lightstyle[32];
00116 trap_GetConfigstring(CS_LIGHT_STYLES + (mLightSwitchStyle*3)+0, lightstyle, 32);
00117 trap_SetConfigstring(CS_LIGHT_STYLES + (mLightStyle*3)+0, lightstyle);
00118
00119 trap_GetConfigstring(CS_LIGHT_STYLES + (mLightSwitchStyle*3)+1, lightstyle, 32);
00120 trap_SetConfigstring(CS_LIGHT_STYLES + (mLightStyle*3)+1, lightstyle);
00121
00122 trap_GetConfigstring(CS_LIGHT_STYLES + (mLightSwitchStyle*3)+2, lightstyle, 32);
00123 trap_SetConfigstring(CS_LIGHT_STYLES + (mLightStyle*3)+2, lightstyle);
00124 }
00125 else
00126 {
00127 trap_SetConfigstring(CS_LIGHT_STYLES + (mLightStyle*3)+0, "z");
00128 trap_SetConfigstring(CS_LIGHT_STYLES + (mLightStyle*3)+1, "z");
00129 trap_SetConfigstring(CS_LIGHT_STYLES + (mLightStyle*3)+2, "z");
00130 }
00131 }
00132 }
00133
00134 void misc_dlight_use ( gentity_t *ent, gentity_t *other, gentity_t *activator )
00135 {
00136 G_ActivateBehavior(ent,BSET_USE);
00137
00138 ent->alt_fire = !ent->alt_fire;
00139 misc_lightstyle_set (ent);
00140 }
00141
00142 void SP_light( gentity_t *self ) {
00143 if (!self->targetname )
00144 {
00145 G_FreeEntity( self );
00146 return;
00147 }
00148
00149 G_SpawnInt( "style", "0", &self->count );
00150 G_SpawnInt( "switch_style", "0", &self->bounceCount );
00151 G_SpawnInt( "style_off", "0", &self->fly_sound_debounce_time );
00152 G_SetOrigin( self, self->s.origin );
00153 trap_LinkEntity( self );
00154
00155 self->use = misc_dlight_use;
00156
00157 self->s.eType = ET_GENERAL;
00158 self->alt_fire = qfalse;
00159 self->r.svFlags |= SVF_NOCLIENT;
00160
00161 if ( !(self->spawnflags & 4) )
00162 {
00163 self->alt_fire = qtrue;
00164 }
00165 misc_lightstyle_set (self);
00166 }
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177 void TeleportPlayer( gentity_t *player, vec3_t origin, vec3_t angles ) {
00178 gentity_t *tent;
00179 qboolean isNPC = qfalse;
00180 if (player->s.eType == ET_NPC)
00181 {
00182 isNPC = qtrue;
00183 }
00184
00185
00186
00187 if ( player->client->sess.sessionTeam != TEAM_SPECTATOR ) {
00188 tent = G_TempEntity( player->client->ps.origin, EV_PLAYER_TELEPORT_OUT );
00189 tent->s.clientNum = player->s.clientNum;
00190
00191 tent = G_TempEntity( origin, EV_PLAYER_TELEPORT_IN );
00192 tent->s.clientNum = player->s.clientNum;
00193 }
00194
00195
00196 trap_UnlinkEntity (player);
00197
00198 VectorCopy ( origin, player->client->ps.origin );
00199 player->client->ps.origin[2] += 1;
00200
00201
00202 AngleVectors( angles, player->client->ps.velocity, NULL, NULL );
00203 VectorScale( player->client->ps.velocity, 400, player->client->ps.velocity );
00204 player->client->ps.pm_time = 160;
00205 player->client->ps.pm_flags |= PMF_TIME_KNOCKBACK;
00206
00207
00208 player->client->ps.eFlags ^= EF_TELEPORT_BIT;
00209
00210
00211 SetClientViewAngle( player, angles );
00212
00213
00214 if ( player->client->sess.sessionTeam != TEAM_SPECTATOR ) {
00215 G_KillBox (player);
00216 }
00217
00218
00219 BG_PlayerStateToEntityState( &player->client->ps, &player->s, qtrue );
00220 if (isNPC)
00221 {
00222 player->s.eType = ET_NPC;
00223 }
00224
00225
00226 VectorCopy( player->client->ps.origin, player->r.currentOrigin );
00227
00228 if ( player->client->sess.sessionTeam != TEAM_SPECTATOR ) {
00229 trap_LinkEntity (player);
00230 }
00231 }
00232
00233
00234
00235
00236
00237
00238
00239 void SP_misc_teleporter_dest( gentity_t *ent ) {
00240 }
00241
00242
00243
00244
00245
00246
00247
00248
00249 void SP_misc_model( gentity_t *ent ) {
00250
00251 #if 0
00252 ent->s.modelindex = G_ModelIndex( ent->model );
00253 VectorSet (ent->r.mins, -16, -16, -16);
00254 VectorSet (ent->r.maxs, 16, 16, 16);
00255 trap_LinkEntity (ent);
00256
00257 G_SetOrigin( ent, ent->s.origin );
00258 VectorCopy( ent->s.angles, ent->s.apos.trBase );
00259 #else
00260 G_FreeEntity( ent );
00261 #endif
00262 }
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277 void SP_misc_model_static(gentity_t *ent)
00278 {
00279 G_FreeEntity( ent );
00280 }
00281
00282
00283
00284
00285 void SP_misc_G2model( gentity_t *ent ) {
00286
00287 #if 0
00288 char name1[200] = "models/players/kyle/modelmp.glm";
00289 trap_G2API_InitGhoul2Model(&ent->s, name1, G_ModelIndex( name1 ), 0, 0, 0, 0);
00290 trap_G2API_SetBoneAnim(ent->s.ghoul2, 0, "model_root", 0, 12, BONE_ANIM_OVERRIDE_LOOP, 1.0f, level.time, -1, -1);
00291 ent->s.radius = 150;
00292
00293
00294 trap_LinkEntity (ent);
00295
00296 G_SetOrigin( ent, ent->s.origin );
00297 VectorCopy( ent->s.angles, ent->s.apos.trBase );
00298 #else
00299 G_FreeEntity( ent );
00300 #endif
00301 }
00302
00303
00304
00305 void locateCamera( gentity_t *ent ) {
00306 vec3_t dir;
00307 gentity_t *target;
00308 gentity_t *owner;
00309
00310 owner = G_PickTarget( ent->target );
00311 if ( !owner ) {
00312 G_Printf( "Couldn't find target for misc_partal_surface\n" );
00313 G_FreeEntity( ent );
00314 return;
00315 }
00316 ent->r.ownerNum = owner->s.number;
00317
00318
00319 if ( owner->spawnflags & 1 ) {
00320 ent->s.frame = 25;
00321 } else if ( owner->spawnflags & 2 ) {
00322 ent->s.frame = 75;
00323 }
00324
00325
00326 if ( owner->spawnflags & 4 ) {
00327
00328 ent->s.powerups = 0;
00329 }
00330 else {
00331 ent->s.powerups = 1;
00332 }
00333
00334
00335 ent->s.clientNum = owner->s.clientNum;
00336
00337 VectorCopy( owner->s.origin, ent->s.origin2 );
00338
00339
00340 target = G_PickTarget( owner->target );
00341 if ( target ) {
00342 VectorSubtract( target->s.origin, owner->s.origin, dir );
00343 VectorNormalize( dir );
00344 } else {
00345 G_SetMovedir( owner->s.angles, dir );
00346 }
00347
00348 ent->s.eventParm = DirToByte( dir );
00349 }
00350
00351
00352
00353
00354
00355 void SP_misc_portal_surface(gentity_t *ent) {
00356 VectorClear( ent->r.mins );
00357 VectorClear( ent->r.maxs );
00358 trap_LinkEntity (ent);
00359
00360 ent->r.svFlags = SVF_PORTAL;
00361 ent->s.eType = ET_PORTAL;
00362
00363 if ( !ent->target ) {
00364 VectorCopy( ent->s.origin, ent->s.origin2 );
00365 } else {
00366 ent->think = locateCamera;
00367 ent->nextthink = level.time + 100;
00368 }
00369 }
00370
00371
00372
00373
00374
00375 void SP_misc_portal_camera(gentity_t *ent) {
00376 float roll;
00377
00378 VectorClear( ent->r.mins );
00379 VectorClear( ent->r.maxs );
00380 trap_LinkEntity (ent);
00381
00382 G_SpawnFloat( "roll", "0", &roll );
00383
00384 ent->s.clientNum = roll/360.0 * 256;
00385 }
00386
00387
00388
00389
00390 void SP_misc_bsp(gentity_t *ent)
00391 {
00392 char temp[MAX_QPATH];
00393 char *out;
00394 float newAngle;
00395 int tempint;
00396
00397 G_SpawnFloat( "angle", "0", &newAngle );
00398 if (newAngle != 0.0)
00399 {
00400 ent->s.angles[1] = newAngle;
00401 }
00402
00403 ent->s.angles[0] = 0.0;
00404 ent->s.angles[2] = 0.0;
00405
00406 G_SpawnString("bspmodel", "", &out);
00407
00408 ent->s.eFlags = EF_PERMANENT;
00409
00410
00411 G_SpawnInt( "spacing", "0", &tempint);
00412 ent->s.time2 = tempint;
00413 G_SpawnInt( "flatten", "0", &tempint);
00414 ent->s.time = tempint;
00415
00416 Com_sprintf(temp, MAX_QPATH, "#%s", out);
00417 trap_SetBrushModel( ent, temp );
00418 G_BSPIndex(temp);
00419
00420 level.mNumBSPInstances++;
00421 Com_sprintf(temp, MAX_QPATH, "%d-", level.mNumBSPInstances);
00422 VectorCopy(ent->s.origin, level.mOriginAdjust);
00423 level.mRotationAdjust = ent->s.angles[1];
00424 level.mTargetAdjust = temp;
00425
00426 level.mBSPInstanceDepth++;
00427
00428
00429
00430
00431 G_SpawnString("teamfilter", "", &out);
00432 strcpy(level.mTeamFilter, out);
00433
00434 VectorCopy( ent->s.origin, ent->s.pos.trBase );
00435 VectorCopy( ent->s.origin, ent->r.currentOrigin );
00436 VectorCopy( ent->s.angles, ent->s.apos.trBase );
00437 VectorCopy( ent->s.angles, ent->r.currentAngles );
00438
00439 ent->s.eType = ET_MOVER;
00440
00441 trap_LinkEntity (ent);
00442
00443 trap_SetActiveSubBSP(ent->s.modelindex);
00444 G_SpawnEntitiesFromString(qtrue);
00445 trap_SetActiveSubBSP(-1);
00446
00447 level.mBSPInstanceDepth--;
00448
00449 level.mTeamFilter[0] = 0;
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462 }
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482 void AddSpawnField(char *field, char *value);
00483 #define MAX_INSTANCE_TYPES 16
00484 void SP_terrain(gentity_t *ent)
00485 {
00486 char temp[MAX_INFO_STRING];
00487 char final[MAX_QPATH];
00488 char seed[MAX_QPATH];
00489 char missionType[MAX_QPATH];
00490
00491 int shaderNum, i;
00492 char *value;
00493 int terrainID;
00494
00495
00496 trap_Cvar_Set("RMG", "1");
00497 g_RMG.integer = 1;
00498
00499 VectorClear (ent->s.angles);
00500 trap_SetBrushModel( ent, ent->model );
00501
00502
00503
00504 shaderNum = 0;
00505
00506 if (g_RMG.integer)
00507 {
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524 trap_Cvar_VariableStringBuffer("RMG_seed", seed, MAX_QPATH);
00525 trap_Cvar_VariableStringBuffer("RMG_mission", missionType, MAX_QPATH);
00526
00527
00528
00529
00530 }
00531
00532
00533 temp[0] = 0;
00534 G_SpawnString("heightmap", "", &value);
00535 Info_SetValueForKey(temp, "heightMap", value);
00536
00537 G_SpawnString("numpatches", "400", &value);
00538 Info_SetValueForKey(temp, "numPatches", va("%d", atoi(value)));
00539
00540 G_SpawnString("terxels", "4", &value);
00541 Info_SetValueForKey(temp, "terxels", va("%d", atoi(value)));
00542
00543 Info_SetValueForKey(temp, "seed", seed);
00544 Info_SetValueForKey(temp, "minx", va("%f", ent->r.mins[0]));
00545 Info_SetValueForKey(temp, "miny", va("%f", ent->r.mins[1]));
00546 Info_SetValueForKey(temp, "minz", va("%f", ent->r.mins[2]));
00547 Info_SetValueForKey(temp, "maxx", va("%f", ent->r.maxs[0]));
00548 Info_SetValueForKey(temp, "maxy", va("%f", ent->r.maxs[1]));
00549 Info_SetValueForKey(temp, "maxz", va("%f", ent->r.maxs[2]));
00550
00551 Info_SetValueForKey(temp, "modelIndex", va("%d", ent->s.modelindex));
00552
00553 G_SpawnString("terraindef", "grassyhills", &value);
00554 Info_SetValueForKey(temp, "terrainDef", value);
00555
00556 G_SpawnString("instancedef", "", &value);
00557 Info_SetValueForKey(temp, "instanceDef", value);
00558
00559 G_SpawnString("miscentdef", "", &value);
00560 Info_SetValueForKey(temp, "miscentDef", value);
00561
00562 Info_SetValueForKey(temp, "missionType", missionType);
00563
00564 for(i = 0; i < MAX_INSTANCE_TYPES; i++)
00565 {
00566 trap_Cvar_VariableStringBuffer(va("RMG_instance%d", i), final, MAX_QPATH);
00567 if(strlen(final))
00568 {
00569 Info_SetValueForKey(temp, va("inst%d", i), final);
00570 }
00571 }
00572
00573
00574 G_SpawnString("densitymap", "", &value);
00575 Info_SetValueForKey(temp, "densityMap", value);
00576
00577 Info_SetValueForKey(temp, "shader", va("%d", shaderNum));
00578 G_SpawnString("texturescale", "0.005", &value);
00579 Info_SetValueForKey(temp, "texturescale", va("%f", atof(value)));
00580
00581
00582 terrainID = trap_CM_RegisterTerrain(temp);
00583
00584
00585 Info_SetValueForKey(temp, "terrainId", va("%d", terrainID));
00586
00587
00588
00589
00590
00591
00592
00593
00594 trap_SetConfigstring(CS_TERRAINS + terrainID, temp);
00595
00596
00597 ent->r.contents = CONTENTS_TERRAIN;
00598 ent->r.svFlags = SVF_NOCLIENT;
00599 ent->s.eFlags = EF_PERMANENT;
00600 ent->s.eType = ET_TERRAIN;
00601
00602
00603 trap_LinkEntity(ent);
00604
00605
00606 if ( g_RMG.integer )
00607 {
00608 trap_RMG_Init(terrainID);
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630 }
00631 }
00632
00633
00634
00635
00636
00637
00638 void G_PortalifyEntities(gentity_t *ent)
00639 {
00640 int i = 0;
00641 gentity_t *scan = NULL;
00642
00643 while (i < MAX_GENTITIES)
00644 {
00645 scan = &g_entities[i];
00646
00647 if (scan && scan->inuse && scan->s.number != ent->s.number && trap_InPVS(ent->s.origin, scan->r.currentOrigin))
00648 {
00649 trace_t tr;
00650
00651 trap_Trace(&tr, ent->s.origin, vec3_origin, vec3_origin, scan->r.currentOrigin, ent->s.number, CONTENTS_SOLID);
00652
00653 if (tr.fraction == 1.0 || (tr.entityNum == scan->s.number && tr.entityNum != ENTITYNUM_NONE && tr.entityNum != ENTITYNUM_WORLD))
00654 {
00655 if (!scan->client || scan->s.eType == ET_NPC)
00656 {
00657 scan->s.isPortalEnt = qtrue;
00658 }
00659 }
00660 }
00661
00662 i++;
00663 }
00664
00665 ent->think = G_FreeEntity;
00666 ent->nextthink = level.time;
00667 }
00668
00669
00670
00671
00672
00673
00674
00675 void SP_misc_skyportal_orient (gentity_t *ent)
00676 {
00677 G_FreeEntity(ent);
00678 }
00679
00680
00681
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693
00694 void SP_misc_skyportal (gentity_t *ent)
00695 {
00696 char *fov;
00697 vec3_t fogv;
00698 int fogn;
00699 int fogf;
00700 int isfog = 0;
00701
00702 float fov_x;
00703
00704 G_SpawnString ("fov", "80", &fov);
00705 fov_x = atof (fov);
00706
00707 isfog += G_SpawnVector ("fogcolor", "0 0 0", fogv);
00708 isfog += G_SpawnInt ("fognear", "0", &fogn);
00709 isfog += G_SpawnInt ("fogfar", "300", &fogf);
00710
00711 trap_SetConfigstring( CS_SKYBOXORG, va("%.2f %.2f %.2f %.1f %i %.2f %.2f %.2f %i %i", ent->s.origin[0], ent->s.origin[1], ent->s.origin[2], fov_x, (int)isfog, fogv[0], fogv[1], fogv[2], fogn, fogf ) );
00712
00713 ent->think = G_PortalifyEntities;
00714 ent->nextthink = level.time + 1050;
00715 }
00716
00717
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727
00728
00729
00730
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744
00745
00746
00747
00748
00749
00750
00751
00752
00753
00754
00755
00756
00757
00758
00759
00760 void HolocronRespawn(gentity_t *self)
00761 {
00762 self->s.modelindex = (self->count - 128);
00763 }
00764
00765 void HolocronPopOut(gentity_t *self)
00766 {
00767 if (Q_irand(1, 10) < 5)
00768 {
00769 self->s.pos.trDelta[0] = 150 + Q_irand(1, 100);
00770 }
00771 else
00772 {
00773 self->s.pos.trDelta[0] = -150 - Q_irand(1, 100);
00774 }
00775 if (Q_irand(1, 10) < 5)
00776 {
00777 self->s.pos.trDelta[1] = 150 + Q_irand(1, 100);
00778 }
00779 else
00780 {
00781 self->s.pos.trDelta[1] = -150 - Q_irand(1, 100);
00782 }
00783 self->s.pos.trDelta[2] = 150 + Q_irand(1, 100);
00784 }
00785
00786 void HolocronTouch(gentity_t *self, gentity_t *other, trace_t *trace)
00787 {
00788 int i = 0;
00789 int othercarrying = 0;
00790 float time_lowest = 0;
00791 int index_lowest = -1;
00792 int hasall = 1;
00793 int forceReselect = WP_NONE;
00794
00795 if (trace)
00796 {
00797 self->s.groundEntityNum = trace->entityNum;
00798 }
00799
00800 if (!other || !other->client || other->health < 1)
00801 {
00802 return;
00803 }
00804
00805 if (!self->s.modelindex)
00806 {
00807 return;
00808 }
00809
00810 if (self->enemy)
00811 {
00812 return;
00813 }
00814
00815 if (other->client->ps.holocronsCarried[self->count])
00816 {
00817 return;
00818 }
00819
00820 if (other->client->ps.holocronCantTouch == self->s.number && other->client->ps.holocronCantTouchTime > level.time)
00821 {
00822 return;
00823 }
00824
00825 while (i < NUM_FORCE_POWERS)
00826 {
00827 if (other->client->ps.holocronsCarried[i])
00828 {
00829 othercarrying++;
00830
00831 if (index_lowest == -1 || other->client->ps.holocronsCarried[i] < time_lowest)
00832 {
00833 index_lowest = i;
00834 time_lowest = other->client->ps.holocronsCarried[i];
00835 }
00836 }
00837 else if (i != self->count)
00838 {
00839 hasall = 0;
00840 }
00841 i++;
00842 }
00843
00844 if (hasall)
00845 {
00846
00847 }
00848
00849 if (!(other->client->ps.fd.forcePowersActive & (1 << other->client->ps.fd.forcePowerSelected)))
00850 {
00851 if (self->count != FP_SABER_OFFENSE && self->count != FP_SABER_DEFENSE && self->count != FP_SABERTHROW && self->count != FP_LEVITATION)
00852 {
00853 other->client->ps.fd.forcePowerSelected = self->count;
00854 }
00855 }
00856
00857 if (g_MaxHolocronCarry.integer && othercarrying >= g_MaxHolocronCarry.integer)
00858 {
00859 other->client->ps.holocronsCarried[index_lowest] = 0;
00860
00861
00862
00863
00864
00865
00866
00867
00868
00869
00870
00871
00872
00873
00874 }
00875
00876
00877 G_AddEvent( other, EV_ITEM_PICKUP, self->s.number );
00878
00879 other->client->ps.holocronsCarried[self->count] = level.time;
00880 self->s.modelindex = 0;
00881 self->enemy = other;
00882
00883 self->pos2[0] = 1;
00884 self->pos2[1] = level.time + HOLOCRON_RESPAWN_TIME;
00885
00886
00887
00888
00889
00890
00891
00892
00893
00894
00895
00896
00897
00898
00899 if (forceReselect != WP_NONE)
00900 {
00901 G_AddEvent(other, EV_NOAMMO, forceReselect);
00902 }
00903
00904
00905 }
00906
00907 void HolocronThink(gentity_t *ent)
00908 {
00909 if (ent->pos2[0] && (!ent->enemy || !ent->enemy->client || ent->enemy->health < 1))
00910 {
00911 if (ent->enemy && ent->enemy->client)
00912 {
00913 HolocronRespawn(ent);
00914 VectorCopy(ent->enemy->client->ps.origin, ent->s.pos.trBase);
00915 VectorCopy(ent->enemy->client->ps.origin, ent->s.origin);
00916 VectorCopy(ent->enemy->client->ps.origin, ent->r.currentOrigin);
00917
00918 HolocronPopOut(ent);
00919 ent->enemy->client->ps.holocronsCarried[ent->count] = 0;
00920 ent->enemy = NULL;
00921
00922 goto justthink;
00923 }
00924 }
00925 else if (ent->pos2[0] && ent->enemy && ent->enemy->client)
00926 {
00927 ent->pos2[1] = level.time + HOLOCRON_RESPAWN_TIME;
00928 }
00929
00930 if (ent->enemy && ent->enemy->client)
00931 {
00932 if (!ent->enemy->client->ps.holocronsCarried[ent->count])
00933 {
00934 ent->enemy->client->ps.holocronCantTouch = ent->s.number;
00935 ent->enemy->client->ps.holocronCantTouchTime = level.time + 5000;
00936
00937 HolocronRespawn(ent);
00938 VectorCopy(ent->enemy->client->ps.origin, ent->s.pos.trBase);
00939 VectorCopy(ent->enemy->client->ps.origin, ent->s.origin);
00940 VectorCopy(ent->enemy->client->ps.origin, ent->r.currentOrigin);
00941
00942 HolocronPopOut(ent);
00943 ent->enemy = NULL;
00944
00945 goto justthink;
00946 }
00947
00948 if (!ent->enemy->inuse || (ent->enemy->client && ent->enemy->client->ps.fallingToDeath))
00949 {
00950 if (ent->enemy->inuse && ent->enemy->client)
00951 {
00952 ent->enemy->client->ps.holocronBits &= ~(1 << ent->count);
00953 ent->enemy->client->ps.holocronsCarried[ent->count] = 0;
00954 }
00955 ent->enemy = NULL;
00956 HolocronRespawn(ent);
00957 VectorCopy(ent->s.origin2, ent->s.pos.trBase);
00958 VectorCopy(ent->s.origin2, ent->s.origin);
00959 VectorCopy(ent->s.origin2, ent->r.currentOrigin);
00960
00961 ent->s.pos.trTime = level.time;
00962
00963 ent->pos2[0] = 0;
00964
00965 trap_LinkEntity(ent);
00966
00967 goto justthink;
00968 }
00969 }
00970
00971 if (ent->pos2[0] && ent->pos2[1] < level.time)
00972 {
00973 VectorCopy(ent->s.origin2, ent->s.pos.trBase);
00974 VectorCopy(ent->s.origin2, ent->s.origin);
00975 VectorCopy(ent->s.origin2, ent->r.currentOrigin);
00976
00977 ent->s.pos.trTime = level.time;
00978
00979 ent->pos2[0] = 0;
00980
00981 trap_LinkEntity(ent);
00982 }
00983
00984 justthink:
00985 ent->nextthink = level.time + 50;
00986
00987 if (ent->s.pos.trDelta[0] || ent->s.pos.trDelta[1] || ent->s.pos.trDelta[2])
00988 {
00989 G_RunObject(ent);
00990 }
00991 }
00992
00993 void SP_misc_holocron(gentity_t *ent)
00994 {
00995 vec3_t dest;
00996 trace_t tr;
00997
00998 if (g_gametype.integer != GT_HOLOCRON)
00999 {
01000 G_FreeEntity(ent);
01001 return;
01002 }
01003
01004 if (HasSetSaberOnly())
01005 {
01006 if (ent->count == FP_SABER_OFFENSE ||
01007 ent->count == FP_SABER_DEFENSE ||
01008 ent->count == FP_SABERTHROW)
01009 {
01010 G_FreeEntity(ent);
01011 return;
01012 }
01013 }
01014
01015 ent->s.isJediMaster = qtrue;
01016
01017 VectorSet( ent->r.maxs, 8, 8, 8 );
01018 VectorSet( ent->r.mins, -8, -8, -8 );
01019
01020 ent->s.origin[2] += 0.1;
01021 ent->r.maxs[2] -= 0.1;
01022
01023 VectorSet( dest, ent->s.origin[0], ent->s.origin[1], ent->s.origin[2] - 4096 );
01024 trap_Trace( &tr, ent->s.origin, ent->r.mins, ent->r.maxs, dest, ent->s.number, MASK_SOLID );
01025 if ( tr.startsolid )
01026 {
01027 G_Printf ("SP_misc_holocron: misc_holocron startsolid at %s\n", vtos(ent->s.origin));
01028 G_FreeEntity( ent );
01029 return;
01030 }
01031
01032
01033 ent->r.maxs[2] += 0.1;
01034
01035
01036
01037
01038 G_SetOrigin( ent, tr.endpos );
01039
01040 if (ent->count < 0)
01041 {
01042 ent->count = 0;
01043 }
01044
01045 if (ent->count >= NUM_FORCE_POWERS)
01046 {
01047 ent->count = NUM_FORCE_POWERS-1;
01048 }
01049
01050
01051
01052
01053
01054
01055
01056
01057
01058
01059
01060 ent->enemy = NULL;
01061
01062 ent->flags = FL_BOUNCE_HALF;
01063
01064 ent->s.modelindex = (ent->count - 128);
01065 ent->s.eType = ET_HOLOCRON;
01066 ent->s.pos.trType = TR_GRAVITY;
01067 ent->s.pos.trTime = level.time;
01068
01069 ent->r.contents = CONTENTS_TRIGGER;
01070 ent->clipmask = MASK_SOLID;
01071
01072 ent->s.trickedentindex4 = ent->count;
01073
01074 if (forcePowerDarkLight[ent->count] == FORCE_DARKSIDE)
01075 {
01076 ent->s.trickedentindex3 = 1;
01077 }
01078 else if (forcePowerDarkLight[ent->count] == FORCE_LIGHTSIDE)
01079 {
01080 ent->s.trickedentindex3 = 2;
01081 }
01082 else
01083 {
01084 ent->s.trickedentindex3 = 3;
01085 }
01086
01087 ent->physicsObject = qtrue;
01088
01089 VectorCopy(ent->s.pos.trBase, ent->s.origin2);
01090
01091 ent->touch = HolocronTouch;
01092
01093 trap_LinkEntity(ent);
01094
01095 ent->think = HolocronThink;
01096 ent->nextthink = level.time + 50;
01097 }
01098
01099
01100
01101
01102
01103
01104
01105
01106
01107 void Use_Shooter( gentity_t *ent, gentity_t *other, gentity_t *activator ) {
01108 vec3_t dir;
01109 float deg;
01110 vec3_t up, right;
01111
01112
01113 if ( ent->enemy ) {
01114 VectorSubtract( ent->enemy->r.currentOrigin, ent->s.origin, dir );
01115 VectorNormalize( dir );
01116 } else {
01117 VectorCopy( ent->movedir, dir );
01118 }
01119
01120
01121 PerpendicularVector( up, dir );
01122 CrossProduct( up, dir, right );
01123
01124 deg = crandom() * ent->random;
01125 VectorMA( dir, deg, up, dir );
01126
01127 deg = crandom() * ent->random;
01128 VectorMA( dir, deg, right, dir );
01129
01130 VectorNormalize( dir );
01131
01132 switch ( ent->s.weapon ) {
01133 case WP_BLASTER:
01134 WP_FireBlasterMissile( ent, ent->s.origin, dir, qfalse );
01135 break;
01136 }
01137
01138 G_AddEvent( ent, EV_FIRE_WEAPON, 0 );
01139 }
01140
01141
01142 static void InitShooter_Finish( gentity_t *ent ) {
01143 ent->enemy = G_PickTarget( ent->target );
01144 ent->think = 0;
01145 ent->nextthink = 0;
01146 }
01147
01148 void InitShooter( gentity_t *ent, int weapon ) {
01149 ent->use = Use_Shooter;
01150 ent->s.weapon = weapon;
01151
01152 RegisterItem( BG_FindItemForWeapon( weapon ) );
01153
01154 G_SetMovedir( ent->s.angles, ent->movedir );
01155
01156 if ( !ent->random ) {
01157 ent->random = 1.0;
01158 }
01159 ent->random = sin( M_PI * ent->random / 180 );
01160
01161 if ( ent->target ) {
01162 ent->think = InitShooter_Finish;
01163 ent->nextthink = level.time + 500;
01164 }
01165 trap_LinkEntity( ent );
01166 }
01167
01168
01169
01170
01171
01172 void SP_shooter_blaster( gentity_t *ent ) {
01173 InitShooter( ent, WP_BLASTER);
01174 }
01175
01176 void check_recharge(gentity_t *ent)
01177 {
01178 if (ent->fly_sound_debounce_time < level.time ||
01179 !ent->activator ||
01180 !ent->activator->client ||
01181 !(ent->activator->client->pers.cmd.buttons & BUTTON_USE))
01182 {
01183 if (ent->activator)
01184 {
01185 G_Sound(ent, CHAN_AUTO, ent->genericValue7);
01186 }
01187 ent->s.loopSound = 0;
01188 ent->s.loopIsSoundset = qfalse;
01189 ent->activator = NULL;
01190 ent->fly_sound_debounce_time = 0;
01191 }
01192
01193 if (!ent->activator)
01194 {
01195 if (ent->genericValue8 < level.time)
01196 {
01197 if (ent->count < ent->genericValue4)
01198 {
01199 ent->count++;
01200 }
01201 ent->genericValue8 = level.time + ent->genericValue5;
01202 }
01203 }
01204 ent->s.health = ent->count;
01205 ent->nextthink = level.time;
01206 }
01207
01208
01209
01210
01211
01212
01213 void EnergyShieldStationSettings(gentity_t *ent)
01214 {
01215 G_SpawnInt( "count", "200", &ent->count );
01216
01217 G_SpawnInt("chargerate", "0", &ent->genericValue5);
01218
01219 if (!ent->genericValue5)
01220 {
01221 ent->genericValue5 = STATION_RECHARGE_TIME;
01222 }
01223 }
01224
01225
01226
01227
01228
01229
01230 void shield_power_converter_use( gentity_t *self, gentity_t *other, gentity_t *activator)
01231 {
01232 int dif,add;
01233 int stop = 1;
01234
01235 if (!activator || !activator->client)
01236 {
01237 return;
01238 }
01239
01240 if ( g_gametype.integer == GT_SIEGE
01241 && other
01242 && other->client
01243 && other->client->siegeClass )
01244 {
01245 if ( !bgSiegeClasses[other->client->siegeClass].maxarmor )
01246 {
01247 G_Sound(self, CHAN_AUTO, G_SoundIndex("sound/interface/shieldcon_empty"));
01248 return;
01249 }
01250 }
01251
01252 if (self->setTime < level.time)
01253 {
01254 int maxArmor;
01255 if (!self->s.loopSound)
01256 {
01257 self->s.loopSound = G_SoundIndex("sound/interface/shieldcon_run");
01258 self->s.loopIsSoundset = qfalse;
01259 }
01260 self->setTime = level.time + 100;
01261
01262 if ( g_gametype.integer == GT_SIEGE
01263 && other
01264 && other->client
01265 && other->client->siegeClass != -1 )
01266 {
01267 maxArmor = bgSiegeClasses[other->client->siegeClass].maxarmor;
01268 }
01269 else
01270 {
01271 maxArmor = activator->client->ps.stats[STAT_MAX_HEALTH];
01272 }
01273 dif = maxArmor - activator->client->ps.stats[STAT_ARMOR];
01274
01275 if (dif > 0)
01276 {
01277 if (dif >MAX_AMMO_GIVE)
01278 {
01279 add = MAX_AMMO_GIVE;
01280 }
01281 else
01282 {
01283 add = dif;
01284 }
01285
01286 if (self->count<add)
01287 {
01288 add = self->count;
01289 }
01290
01291 if (!self->genericValue12)
01292 {
01293 self->count -= add;
01294 }
01295 if (self->count <= 0)
01296 {
01297 self->setTime = 0;
01298 }
01299 stop = 0;
01300
01301 self->fly_sound_debounce_time = level.time + 500;
01302 self->activator = activator;
01303
01304 activator->client->ps.stats[STAT_ARMOR] += add;
01305 }
01306 }
01307
01308 if (stop || self->count <= 0)
01309 {
01310 if (self->s.loopSound && self->setTime < level.time)
01311 {
01312 if (self->count <= 0)
01313 {
01314 G_Sound(self, CHAN_AUTO, G_SoundIndex("sound/interface/shieldcon_empty"));
01315 }
01316 else
01317 {
01318 G_Sound(self, CHAN_AUTO, self->genericValue7);
01319 }
01320 }
01321 self->s.loopSound = 0;
01322 self->s.loopIsSoundset = qfalse;
01323 if (self->setTime < level.time)
01324 {
01325 self->setTime = level.time + self->genericValue5+100;
01326 }
01327 }
01328 }
01329
01330
01331 void ammo_generic_power_converter_use( gentity_t *self, gentity_t *other, gentity_t *activator)
01332 {
01333 int add;
01334
01335 int stop = 1;
01336
01337 if (!activator || !activator->client)
01338 {
01339 return;
01340 }
01341
01342 if (self->setTime < level.time)
01343 {
01344 qboolean gaveSome = qfalse;
01345
01346
01347
01348
01349
01350
01351
01352
01353
01354
01355
01356
01357
01358
01359
01360
01361
01362
01363
01364
01365
01366
01367
01368
01369
01370
01371
01372
01373
01374
01375
01376
01377
01378
01379
01380
01381
01382
01383
01384
01385
01386
01387
01388
01389
01390
01391
01392
01393
01394
01395
01396
01397
01398
01399
01400
01401
01402
01403
01404
01405
01406
01407
01408
01409
01410
01411
01412
01413
01414 int i = AMMO_BLASTER;
01415 if (!self->s.loopSound)
01416 {
01417 self->s.loopSound = G_SoundIndex("sound/interface/ammocon_run");
01418 self->s.loopIsSoundset = qfalse;
01419 }
01420
01421 self->fly_sound_debounce_time = level.time + 500;
01422 self->activator = activator;
01423 while (i < AMMO_MAX)
01424 {
01425 add = ammoData[i].max*0.05;
01426 if (add < 1)
01427 {
01428 add = 1;
01429 }
01430 if ( ( (activator->client->ps.eFlags & EF_DOUBLE_AMMO) && (activator->client->ps.ammo[i] < ammoData[i].max*2)) ||
01431 ( activator->client->ps.ammo[i] < ammoData[i].max ) )
01432 {
01433 gaveSome = qtrue;
01434 if ( g_gametype.integer == GT_SIEGE && i == AMMO_ROCKETS && activator->client->ps.ammo[i] >= 10 )
01435 {
01436 gaveSome = qfalse;
01437 }
01438 activator->client->ps.ammo[i] += add;
01439 if ( g_gametype.integer == GT_SIEGE && i == AMMO_ROCKETS && activator->client->ps.ammo[i] >= 10 )
01440 {
01441 activator->client->ps.ammo[i] = 10;
01442 }
01443 else if ( activator->client->ps.eFlags & EF_DOUBLE_AMMO )
01444 {
01445 if (activator->client->ps.ammo[i] >= ammoData[i].max * 2)
01446 {
01447 activator->client->ps.ammo[i] = ammoData[i].max * 2;
01448 }
01449 else
01450 {
01451 stop = 0;
01452 }
01453 }
01454 else
01455 {
01456 if (activator->client->ps.ammo[i] >= ammoData[i].max)
01457 {
01458 activator->client->ps.ammo[i] = ammoData[i].max;
01459 }
01460 else
01461 {
01462 stop = 0;
01463 }
01464 }
01465 }
01466 i++;
01467 if (!self->genericValue12 && gaveSome)
01468 {
01469 int sub = (add*0.2);
01470 if (sub < 1)
01471 {
01472 sub = 1;
01473 }
01474 self->count -= sub;
01475 if (self->count <= 0)
01476 {
01477 self->count = 0;
01478 stop = 1;
01479 break;
01480 }
01481 }
01482 }
01483 }
01484
01485 if (stop || self->count <= 0)
01486 {
01487 if (self->s.loopSound && self->setTime < level.time)
01488 {
01489 if (self->count <= 0)
01490 {
01491 G_Sound(self, CHAN_AUTO, G_SoundIndex("sound/interface/ammocon_empty"));
01492 }
01493 else
01494 {
01495 G_Sound(self, CHAN_AUTO, self->genericValue7);
01496 }
01497 }
01498 self->s.loopSound = 0;
01499 self->s.loopIsSoundset = qfalse;
01500 if (self->setTime < level.time)
01501 {
01502 self->setTime = level.time + self->genericValue5+100;
01503 }
01504 }
01505 }
01506
01507
01508
01509
01510
01511
01512
01513
01514
01515 void SP_misc_ammo_floor_unit(gentity_t *ent)
01516 {
01517 vec3_t dest;
01518 trace_t tr;
01519
01520 VectorSet( ent->r.mins, -16, -16, 0 );
01521 VectorSet( ent->r.maxs, 16, 16, 40 );
01522
01523 ent->s.origin[2] += 0.1f;
01524 ent->r.maxs[2] -= 0.1f;
01525
01526 VectorSet( dest, ent->s.origin[0], ent->s.origin[1], ent->s.origin[2] - 4096 );
01527 trap_Trace( &tr, ent->s.origin, ent->r.mins, ent->r.maxs, dest, ent->s.number, MASK_SOLID );
01528 if ( tr.startsolid )
01529 {
01530 G_Printf ("SP_misc_ammo_floor_unit: misc_ammo_floor_unit startsolid at %s\n", vtos(ent->s.origin));
01531 G_FreeEntity( ent );
01532 return;
01533 }
01534
01535
01536 ent->r.maxs[2] += 0.1f;
01537
01538
01539 ent->s.groundEntityNum = tr.entityNum;
01540
01541 G_SetOrigin( ent, tr.endpos );
01542
01543 if (!ent->health)
01544 {
01545 ent->health = 60;
01546 }
01547
01548 if (!ent->model || !ent->model[0])
01549 {
01550 ent->model = "/models/items/a_pwr_converter.md3";
01551 }
01552
01553 ent->s.modelindex = G_ModelIndex( ent->model );
01554
01555 ent->s.eFlags = 0;
01556 ent->r.svFlags |= SVF_PLAYER_USABLE;
01557 ent->r.contents = CONTENTS_SOLID;
01558 ent->clipmask = MASK_SOLID;
01559
01560 EnergyShieldStationSettings(ent);
01561
01562 ent->genericValue4 = ent->count;
01563 ent->think = check_recharge;
01564
01565 G_SpawnInt("nodrain", "0", &ent->genericValue12);
01566
01567 if (!ent->genericValue12)
01568 {
01569 ent->s.maxhealth = ent->s.health = ent->count;
01570 }
01571 ent->s.shouldtarget = qtrue;
01572 ent->s.teamowner = 0;
01573 ent->s.owner = ENTITYNUM_NONE;
01574
01575 ent->nextthink = level.time + 200;
01576
01577 ent->use = ammo_generic_power_converter_use;
01578
01579 VectorCopy( ent->s.angles, ent->s.apos.trBase );
01580 trap_LinkEntity (ent);
01581
01582 G_SoundIndex("sound/interface/ammocon_run");
01583 ent->genericValue7 = G_SoundIndex("sound/interface/ammocon_done");
01584 G_SoundIndex("sound/interface/ammocon_empty");
01585
01586 if (g_gametype.integer == GT_SIEGE)
01587 {
01588 ent->r.svFlags |= SVF_BROADCAST;
01589 ent->s.eFlags |= EF_RADAROBJECT;
01590 ent->s.genericenemyindex = G_IconIndex("gfx/mp/siegeicons/desert/weapon_recharge");
01591 }
01592 }
01593
01594
01595
01596
01597
01598
01599
01600
01601
01602 void SP_misc_shield_floor_unit( gentity_t *ent )
01603 {
01604 vec3_t dest;
01605 trace_t tr;
01606
01607 if (g_gametype.integer != GT_CTF &&
01608 g_gametype.integer != GT_CTY &&
01609 g_gametype.integer != GT_SIEGE)
01610 {
01611 G_FreeEntity( ent );
01612 return;
01613 }
01614
01615 VectorSet( ent->r.mins, -16, -16, 0 );
01616 VectorSet( ent->r.maxs, 16, 16, 40 );
01617
01618 ent->s.origin[2] += 0.1;
01619 ent->r.maxs[2] -= 0.1;
01620
01621 VectorSet( dest, ent->s.origin[0], ent->s.origin[1], ent->s.origin[2] - 4096 );
01622 trap_Trace( &tr, ent->s.origin, ent->r.mins, ent->r.maxs, dest, ent->s.number, MASK_SOLID );
01623 if ( tr.startsolid )
01624 {
01625 G_Printf ("SP_misc_shield_floor_unit: misc_shield_floor_unit startsolid at %s\n", vtos(ent->s.origin));
01626 G_FreeEntity( ent );
01627 return;
01628 }
01629
01630
01631 ent->r.maxs[2] += 0.1;
01632
01633
01634 ent->s.groundEntityNum = tr.entityNum;
01635
01636 G_SetOrigin( ent, tr.endpos );
01637
01638 if (!ent->health)
01639 {
01640 ent->health = 60;
01641 }
01642
01643 if (!ent->model || !ent->model[0])
01644 {
01645 ent->model = "/models/items/a_shield_converter.md3";
01646 }
01647
01648 ent->s.modelindex = G_ModelIndex( ent->model );
01649
01650 ent->s.eFlags = 0;
01651 ent->r.svFlags |= SVF_PLAYER_USABLE;
01652 ent->r.contents = CONTENTS_SOLID;
01653 ent->clipmask = MASK_SOLID;
01654
01655 EnergyShieldStationSettings(ent);
01656
01657 ent->genericValue4 = ent->count;
01658 ent->think = check_recharge;
01659
01660 G_SpawnInt("nodrain", "0", &ent->genericValue12);
01661
01662 if (!ent->genericValue12)
01663 {
01664 ent->s.maxhealth = ent->s.health = ent->count;
01665 }
01666 ent->s.shouldtarget = qtrue;
01667 ent->s.teamowner = 0;
01668 ent->s.owner = ENTITYNUM_NONE;
01669
01670 ent->nextthink = level.time + 200;
01671
01672 ent->use = shield_power_converter_use;
01673
01674 VectorCopy( ent->s.angles, ent->s.apos.trBase );
01675 trap_LinkEntity (ent);
01676
01677 G_SoundIndex("sound/interface/shieldcon_run");
01678 ent->genericValue7 = G_SoundIndex("sound/interface/shieldcon_done");
01679 G_SoundIndex("sound/interface/shieldcon_empty");
01680
01681 if (g_gametype.integer == GT_SIEGE)
01682 {
01683 ent->r.svFlags |= SVF_BROADCAST;
01684 ent->s.eFlags |= EF_RADAROBJECT;
01685 ent->s.genericenemyindex = G_IconIndex("gfx/mp/siegeicons/desert/shield_recharge");
01686 }
01687 }
01688
01689
01690
01691
01692
01693
01694
01695
01696
01697 void SP_misc_model_shield_power_converter( gentity_t *ent )
01698 {
01699 if (!ent->health)
01700 {
01701 ent->health = 60;
01702 }
01703
01704 VectorSet (ent->r.mins, -16, -16, -16);
01705 VectorSet (ent->r.maxs, 16, 16, 16);
01706
01707 ent->s.modelindex = G_ModelIndex( ent->model );
01708
01709 ent->s.eFlags = 0;
01710 ent->r.svFlags |= SVF_PLAYER_USABLE;
01711 ent->r.contents = CONTENTS_SOLID;
01712 ent->clipmask = MASK_SOLID;
01713
01714 EnergyShieldStationSettings(ent);
01715
01716 ent->genericValue4 = ent->count;
01717 ent->think = check_recharge;
01718
01719 ent->s.maxhealth = ent->s.health = ent->count;
01720 ent->s.shouldtarget = qtrue;
01721 ent->s.teamowner = 0;
01722 ent->s.owner = ENTITYNUM_NONE;
01723
01724 ent->nextthink = level.time + 200;
01725
01726 ent->use = shield_power_converter_use;
01727
01728 G_SetOrigin( ent, ent->s.origin );
01729 VectorCopy( ent->s.angles, ent->s.apos.trBase );
01730 trap_LinkEntity (ent);
01731
01732
01733
01734 ent->s.modelindex2 = G_ModelIndex("/models/items/psd_big.md3");
01735 }
01736
01737
01738
01739
01740
01741
01742
01743 void EnergyAmmoStationSettings(gentity_t *ent)
01744 {
01745 G_SpawnInt( "count", "200", &ent->count );
01746 }
01747
01748
01749
01750
01751
01752
01753 void ammo_power_converter_use( gentity_t *self, gentity_t *other, gentity_t *activator)
01754 {
01755 int add = 0.0f;
01756 qboolean overcharge;
01757
01758 int stop = 1;
01759
01760 if (!activator || !activator->client)
01761 {
01762 return;
01763 }
01764
01765 if (self->setTime < level.time)
01766 {
01767 overcharge = qfalse;
01768
01769 if (!self->s.loopSound)
01770 {
01771 self->s.loopSound = G_SoundIndex("sound/player/pickupshield.wav");
01772 }
01773
01774 self->setTime = level.time + 100;
01775
01776 if (self->count)
01777 {
01778 int i = AMMO_BLASTER;
01779 while (i < AMMO_MAX)
01780 {
01781 add = ammoData[i].max*0.1;
01782 if (add < 1)
01783 {
01784 add = 1;
01785 }
01786 if (activator->client->ps.ammo[i] < ammoData[i].max)
01787 {
01788 activator->client->ps.ammo[i] += add;
01789 if (activator->client->ps.ammo[i] > ammoData[i].max)
01790 {
01791 activator->client->ps.ammo[i] = ammoData[i].max;
01792 }
01793 }
01794 i++;
01795 }
01796 if (!self->genericValue12)
01797 {
01798 self->count -= add;
01799 }
01800 stop = 0;
01801
01802 self->fly_sound_debounce_time = level.time + 500;
01803 self->activator = activator;
01804
01805
01806
01807
01808
01809
01810
01811
01812
01813
01814
01815
01816
01817
01818
01819
01820
01821
01822
01823
01824
01825
01826
01827
01828
01829
01830
01831
01832
01833
01834
01835
01836
01837
01838
01839
01840
01841
01842
01843
01844
01845 }
01846 }
01847
01848 if (stop)
01849 {
01850 self->s.loopSound = 0;
01851 self->s.loopIsSoundset = qfalse;
01852 }
01853 }
01854
01855
01856
01857
01858
01859
01860
01861
01862
01863
01864 void SP_misc_model_ammo_power_converter( gentity_t *ent )
01865 {
01866 if (!ent->health)
01867 {
01868 ent->health = 60;
01869 }
01870
01871 VectorSet (ent->r.mins, -16, -16, -16);
01872 VectorSet (ent->r.maxs, 16, 16, 16);
01873
01874 ent->s.modelindex = G_ModelIndex( ent->model );
01875
01876 ent->s.eFlags = 0;
01877 ent->r.svFlags |= SVF_PLAYER_USABLE;
01878 ent->r.contents = CONTENTS_SOLID;
01879 ent->clipmask = MASK_SOLID;
01880
01881 G_SpawnInt("nodrain", "0", &ent->genericValue12);
01882 ent->use = ammo_power_converter_use;
01883
01884 EnergyAmmoStationSettings(ent);
01885
01886 ent->genericValue4 = ent->count;
01887 ent->think = check_recharge;
01888
01889 if (!ent->genericValue12)
01890 {
01891 ent->s.maxhealth = ent->s.health = ent->count;
01892 }
01893 ent->s.shouldtarget = qtrue;
01894 ent->s.teamowner = 0;
01895 ent->s.owner = ENTITYNUM_NONE;
01896
01897 ent->nextthink = level.time + 200;
01898
01899 G_SetOrigin( ent, ent->s.origin );
01900 VectorCopy( ent->s.angles, ent->s.apos.trBase );
01901 trap_LinkEntity (ent);
01902
01903
01904 }
01905
01906
01907
01908
01909
01910
01911 void EnergyHealthStationSettings(gentity_t *ent)
01912 {
01913 G_SpawnInt( "count", "200", &ent->count );
01914 }
01915
01916
01917
01918
01919
01920
01921 void health_power_converter_use( gentity_t *self, gentity_t *other, gentity_t *activator)
01922 {
01923 int dif,add;
01924 int stop = 1;
01925
01926 if (!activator || !activator->client)
01927 {
01928 return;
01929 }
01930
01931 if (self->setTime < level.time)
01932 {
01933 if (!self->s.loopSound)
01934 {
01935 self->s.loopSound = G_SoundIndex("sound/player/pickuphealth.wav");
01936 }
01937 self->setTime = level.time + 100;
01938
01939 dif = activator->client->ps.stats[STAT_MAX_HEALTH] - activator->health;
01940
01941 if (dif > 0)
01942 {
01943 if (dif >5)
01944 {
01945 add = 5;
01946 }
01947 else
01948 {
01949 add = dif;
01950 }
01951
01952 if (self->count<add)
01953 {
01954 add = self->count;
01955 }
01956
01957
01958 stop = 0;
01959
01960 self->fly_sound_debounce_time = level.time + 500;
01961 self->activator = activator;
01962
01963 activator->health += add;
01964 }
01965 }
01966
01967 if (stop)
01968 {
01969 self->s.loopSound = 0;
01970 self->s.loopIsSoundset = qfalse;
01971 }
01972 }
01973
01974
01975
01976
01977
01978
01979
01980
01981
01982 void SP_misc_model_health_power_converter( gentity_t *ent )
01983 {
01984 if (!ent->health)
01985 {
01986 ent->health = 60;
01987 }
01988
01989 VectorSet (ent->r.mins, -16, -16, -16);
01990 VectorSet (ent->r.maxs, 16, 16, 16);
01991
01992 ent->s.modelindex = G_ModelIndex( ent->model );
01993
01994 ent->s.eFlags = 0;
01995 ent->r.svFlags |= SVF_PLAYER_USABLE;
01996 ent->r.contents = CONTENTS_SOLID;
01997 ent->clipmask = MASK_SOLID;
01998
01999 ent->use = health_power_converter_use;
02000
02001 EnergyHealthStationSettings(ent);
02002
02003 ent->genericValue4 = ent->count;
02004 ent->think = check_recharge;
02005
02006
02007 ent->s.shouldtarget = qtrue;
02008 ent->s.teamowner = 0;
02009 ent->s.owner = ENTITYNUM_NONE;
02010
02011 ent->nextthink = level.time + 200;
02012
02013 G_SetOrigin( ent, ent->s.origin );
02014 VectorCopy( ent->s.angles, ent->s.apos.trBase );
02015 trap_LinkEntity (ent);
02016
02017
02018 G_SoundIndex("sound/player/pickuphealth.wav");
02019 ent->genericValue7 = G_SoundIndex("sound/interface/shieldcon_done");
02020
02021 if (g_gametype.integer == GT_SIEGE)
02022 {
02023 ent->r.svFlags |= SVF_BROADCAST;
02024 ent->s.eFlags |= EF_RADAROBJECT;
02025 ent->s.genericenemyindex = G_IconIndex("gfx/mp/siegeicons/desert/bacta");
02026 }
02027 }
02028
02029 #if 0 //damage box stuff
02030 void DmgBoxHit( gentity_t *self, gentity_t *other, trace_t *trace )
02031 {
02032 return;
02033 }
02034
02035 void DmgBoxUpdateSelf(gentity_t *self)
02036 {
02037 gentity_t *owner = &g_entities[self->r.ownerNum];
02038
02039 if (!owner || !owner->client || !owner->inuse)
02040 {
02041 goto killMe;
02042 }
02043
02044 if (self->damageRedirect == DAMAGEREDIRECT_HEAD &&
02045 owner->client->damageBoxHandle_Head != self->s.number)
02046 {
02047 goto killMe;
02048 }
02049
02050 if (self->damageRedirect == DAMAGEREDIRECT_RLEG &&
02051 owner->client->damageBoxHandle_RLeg != self->s.number)
02052 {
02053 goto killMe;
02054 }
02055
02056 if (self->damageRedirect == DAMAGEREDIRECT_LLEG &&
02057 owner->client->damageBoxHandle_LLeg != self->s.number)
02058 {
02059 goto killMe;
02060 }
02061
02062 if (owner->health < 1)
02063 {
02064 goto killMe;
02065 }
02066
02067
02068
02069 trap_LinkEntity(self);
02070
02071 self->nextthink = level.time;
02072 return;
02073
02074 killMe:
02075 self->think = G_FreeEntity;
02076 self->nextthink = level.time;
02077 }
02078
02079 void DmgBoxAbsorb_Die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod )
02080 {
02081 self->health = 1;
02082 }
02083
02084 void DmgBoxAbsorb_Pain(gentity_t *self, gentity_t *attacker, int damage)
02085 {
02086 self->health = 1;
02087 }
02088
02089 gentity_t *CreateNewDamageBox( gentity_t *ent )
02090 {
02091 gentity_t *dmgBox;
02092
02093
02094
02095 dmgBox = G_Spawn();
02096 dmgBox->classname = "dmg_box";
02097
02098 dmgBox->r.svFlags = SVF_USE_CURRENT_ORIGIN;
02099 dmgBox->r.ownerNum = ent->s.number;
02100
02101 dmgBox->clipmask = 0;
02102 dmgBox->r.contents = MASK_PLAYERSOLID;
02103
02104 dmgBox->mass = 5000;
02105
02106 dmgBox->s.eFlags |= EF_NODRAW;
02107 dmgBox->r.svFlags |= SVF_NOCLIENT;
02108
02109 dmgBox->touch = DmgBoxHit;
02110
02111 dmgBox->takedamage = qtrue;
02112
02113 dmgBox->health = 1;
02114
02115 dmgBox->pain = DmgBoxAbsorb_Pain;
02116 dmgBox->die = DmgBoxAbsorb_Die;
02117
02118 dmgBox->think = DmgBoxUpdateSelf;
02119 dmgBox->nextthink = level.time + 50;
02120
02121 return dmgBox;
02122 }
02123
02124 void ATST_ManageDamageBoxes(gentity_t *ent)
02125 {
02126 vec3_t headOrg, lLegOrg, rLegOrg;
02127 vec3_t fwd, right, up, flatAngle;
02128
02129 if (!ent->client->damageBoxHandle_Head)
02130 {
02131 gentity_t *dmgBox = CreateNewDamageBox(ent);
02132
02133 if (dmgBox)
02134 {
02135 VectorSet( dmgBox->r.mins, ATST_MINS0, ATST_MINS1, ATST_MINS2 );
02136 VectorSet( dmgBox->r.maxs, ATST_MAXS0, ATST_MAXS1, ATST_HEADSIZE );
02137
02138 ent->client->damageBoxHandle_Head = dmgBox->s.number;
02139 dmgBox->damageRedirect = DAMAGEREDIRECT_HEAD;
02140 dmgBox->damageRedirectTo = ent->s.number;
02141 }
02142 }
02143 if (!ent->client->damageBoxHandle_RLeg)
02144 {
02145 gentity_t *dmgBox = CreateNewDamageBox(ent);
02146
02147 if (dmgBox)
02148 {
02149 VectorSet( dmgBox->r.mins, ATST_MINS0/4, ATST_MINS1/4, ATST_MINS2 );
02150 VectorSet( dmgBox->r.maxs, ATST_MAXS0/4, ATST_MAXS1/4, ATST_MAXS2-ATST_HEADSIZE );
02151
02152 ent->client->damageBoxHandle_RLeg = dmgBox->s.number;
02153 dmgBox->damageRedirect = DAMAGEREDIRECT_RLEG;
02154 dmgBox->damageRedirectTo = ent->s.number;
02155 }
02156 }
02157 if (!ent->client->damageBoxHandle_LLeg)
02158 {
02159 gentity_t *dmgBox = CreateNewDamageBox(ent);
02160
02161 if (dmgBox)
02162 {
02163 VectorSet( dmgBox->r.mins, ATST_MINS0/4, ATST_MINS1/4, ATST_MINS2 );
02164 VectorSet( dmgBox->r.maxs, ATST_MAXS0/4, ATST_MAXS1/4, ATST_MAXS2-ATST_HEADSIZE );
02165
02166 ent->client->damageBoxHandle_LLeg = dmgBox->s.number;
02167 dmgBox->damageRedirect = DAMAGEREDIRECT_LLEG;
02168 dmgBox->damageRedirectTo = ent->s.number;
02169 }
02170 }
02171
02172 if (!ent->client->damageBoxHandle_Head ||
02173 !ent->client->damageBoxHandle_LLeg ||
02174 !ent->client->damageBoxHandle_RLeg)
02175 {
02176 return;
02177 }
02178
02179 VectorCopy(ent->client->ps.origin, headOrg);
02180 headOrg[2] += (ATST_MAXS2-ATST_HEADSIZE);
02181
02182 VectorCopy(ent->client->ps.viewangles, flatAngle);
02183 flatAngle[PITCH] = 0;
02184 flatAngle[ROLL] = 0;
02185
02186 AngleVectors(flatAngle, fwd, right, up);
02187
02188 VectorCopy(ent->client->ps.origin, lLegOrg);
02189 VectorCopy(ent->client->ps.origin, rLegOrg);
02190
02191 lLegOrg[0] -= right[0]*32;
02192 lLegOrg[1] -= right[1]*32;
02193 lLegOrg[2] -= right[2]*32;
02194
02195 rLegOrg[0] += right[0]*32;
02196 rLegOrg[1] += right[1]*32;
02197 rLegOrg[2] += right[2]*32;
02198
02199 G_SetOrigin(&g_entities[ent->client->damageBoxHandle_Head], headOrg);
02200 G_SetOrigin(&g_entities[ent->client->damageBoxHandle_LLeg], lLegOrg);
02201 G_SetOrigin(&g_entities[ent->client->damageBoxHandle_RLeg], rLegOrg);
02202 }
02203
02204 int G_PlayerBecomeATST(gentity_t *ent)
02205 {
02206 if (!ent || !ent->client)
02207 {
02208 return 0;
02209 }
02210
02211 if (ent->client->ps.weaponTime > 0)
02212 {
02213 return 0;
02214 }
02215
02216 if (ent->client->ps.forceHandExtend != HANDEXTEND_NONE)
02217 {
02218 return 0;
02219 }
02220
02221 if (ent->client->ps.zoomMode)
02222 {
02223 return 0;
02224 }
02225
02226 if (ent->client->ps.usingATST)
02227 {
02228 ent->client->ps.usingATST = qfalse;
02229 ent->client->ps.forceHandExtend = HANDEXTEND_WEAPONREADY;
02230 }
02231 else
02232 {
02233 ent->client->ps.usingATST = qtrue;
02234 }
02235
02236 ent->client->ps.weaponTime = 1000;
02237
02238 return 1;
02239 }
02240 #endif
02241
02242
02243
02244
02245
02246
02247
02248
02249
02250
02251
02252
02253
02254
02255
02256
02257
02258
02259
02260 #define FX_RUNNER_RESERVED 0x800000
02261 #define FX_ENT_RADIUS 32
02262 extern int BMS_START;
02263 extern int BMS_MID;
02264 extern int BMS_END;
02265
02266 void fx_runner_think( gentity_t *ent )
02267 {
02268 BG_EvaluateTrajectory( &ent->s.pos, level.time, ent->r.currentOrigin );
02269 BG_EvaluateTrajectory( &ent->s.apos, level.time, ent->r.currentAngles );
02270
02271
02272 if (ent->s.isPortalEnt)
02273 {
02274
02275 }
02276 else
02277 {
02278
02279 }
02280
02281
02282 ent->s.modelindex2 = FX_STATE_CONTINUOUS;
02283
02284 VectorCopy(ent->r.currentAngles, ent->s.angles);
02285 VectorCopy(ent->r.currentOrigin, ent->s.origin);
02286
02287 ent->nextthink = level.time + ent->delay + random() * ent->random;
02288
02289 if ( ent->spawnflags & 4 )
02290 {
02291 G_RadiusDamage( ent->r.currentOrigin, ent, ent->splashDamage, ent->splashRadius, ent, ent, MOD_UNKNOWN );
02292 }
02293
02294 if ( ent->target2 && ent->target2[0] )
02295 {
02296
02297 G_UseTargets2( ent, ent, ent->target2 );
02298 }
02299
02300 if ( !(ent->spawnflags & 2 ) && !ent->s.loopSound )
02301 {
02302 if ( ent->soundSet && ent->soundSet[0] )
02303 {
02304 ent->s.soundSetIndex = G_SoundSetIndex(ent->soundSet);
02305 ent->s.loopIsSoundset = qtrue;
02306 ent->s.loopSound = BMS_MID;
02307 }
02308 }
02309
02310 }
02311
02312
02313 void fx_runner_use( gentity_t *self, gentity_t *other, gentity_t *activator )
02314 {
02315 if (self->s.isPortalEnt)
02316 {
02317 self->r.svFlags |= SVF_BROADCAST;
02318 }
02319
02320 if ( self->spawnflags & 2 )
02321 {
02322
02323
02324 int saveState = self->s.modelindex2 + 1;
02325
02326 fx_runner_think( self );
02327 self->nextthink = -1;
02328
02329 self->s.modelindex2 = saveState;
02330 if (self->s.modelindex2 > FX_STATE_ONE_SHOT_LIMIT)
02331 {
02332 self->s.modelindex2 = FX_STATE_ONE_SHOT;
02333 }
02334
02335 if ( self->target2 )
02336 {
02337
02338 G_UseTargets2( self, self, self->target2 );
02339 }
02340
02341 if ( self->soundSet && self->soundSet[0] )
02342 {
02343 self->s.soundSetIndex = G_SoundSetIndex(self->soundSet);
02344 G_AddEvent( self, EV_BMODEL_SOUND, BMS_START);
02345 }
02346 }
02347 else
02348 {
02349
02350 self->think = fx_runner_think;
02351
02352
02353 if ( self->nextthink == -1 )
02354 {
02355
02356
02357 fx_runner_think( self );
02358
02359 if ( self->soundSet && self->soundSet[0] )
02360 {
02361 self->s.soundSetIndex = G_SoundSetIndex(self->soundSet);
02362 G_AddEvent( self, EV_BMODEL_SOUND, BMS_START);
02363 self->s.loopSound = BMS_MID;
02364 self->s.loopIsSoundset = qtrue;
02365 }
02366 }
02367 else
02368 {
02369
02370 self->nextthink = -1;
02371
02372
02373 self->s.modelindex2 = FX_STATE_OFF;
02374
02375 if ( self->soundSet && self->soundSet[0] )
02376 {
02377 self->s.soundSetIndex = G_SoundSetIndex(self->soundSet);
02378 G_AddEvent( self, EV_BMODEL_SOUND, BMS_END );
02379 self->s.loopSound = 0;
02380 self->s.loopIsSoundset = qfalse;
02381 }
02382 }
02383 }
02384 }
02385
02386
02387 void fx_runner_link( gentity_t *ent )
02388 {
02389 vec3_t dir;
02390
02391 if ( ent->target && ent->target[0] )
02392 {
02393
02394 gentity_t *target = NULL;
02395
02396 target = G_Find( target, FOFS(targetname), ent->target );
02397
02398 if ( !target )
02399 {
02400
02401 Com_Printf( "fx_runner_link: target specified but not found: %s\n", ent->target );
02402 Com_Printf( " -assuming UP orientation.\n" );
02403 }
02404 else
02405 {
02406
02407 VectorSubtract( target->s.origin, ent->s.origin, dir );
02408 VectorNormalize( dir );
02409 vectoangles( dir, ent->s.angles );
02410 }
02411 }
02412
02413
02414 if ( ent->target2 && ent->target2[0] )
02415 {
02416 gentity_t *target = NULL;
02417
02418 target = G_Find( target, FOFS(targetname), ent->target2 );
02419
02420 if ( !target )
02421 {
02422
02423 Com_Printf( "fx_runner_link: target2 was specified but is not valid: %s\n", ent->target2 );
02424 }
02425 }
02426
02427 G_SetAngles( ent, ent->s.angles );
02428
02429 if ( ent->spawnflags & 1 || ent->spawnflags & 2 )
02430 {
02431
02432 ent->nextthink = -1;
02433 }
02434 else
02435 {
02436 if ( ent->soundSet && ent->soundSet[0] )
02437 {
02438 ent->s.soundSetIndex = G_SoundSetIndex(ent->soundSet);
02439 ent->s.loopSound = BMS_MID;
02440 ent->s.loopIsSoundset = qtrue;
02441 }
02442
02443
02444 ent->think = fx_runner_think;
02445 ent->nextthink = level.time + 200;
02446 }
02447
02448
02449 if ( ent->targetname && ent->targetname[0] )
02450 {
02451 ent->use = fx_runner_use;
02452 }
02453 }
02454
02455
02456 void SP_fx_runner( gentity_t *ent )
02457 {
02458 char *fxFile;
02459
02460 G_SpawnString( "fxFile", "", &fxFile );
02461
02462 G_SpawnInt( "delay", "200", &ent->delay );
02463 G_SpawnFloat( "random", "0", &ent->random );
02464 G_SpawnInt( "splashRadius", "16", &ent->splashRadius );
02465 G_SpawnInt( "splashDamage", "5", &ent->splashDamage );
02466
02467 if (!ent->s.angles[0] && !ent->s.angles[1] && !ent->s.angles[2])
02468 {
02469
02470 VectorSet( ent->s.angles, -90, 0, 0 );
02471 }
02472
02473 if ( !fxFile || !fxFile[0] )
02474 {
02475 Com_Printf( S_COLOR_RED"ERROR: fx_runner %s at %s has no fxFile specified\n", ent->targetname, vtos(ent->s.origin) );
02476 G_FreeEntity( ent );
02477 return;
02478 }
02479
02480
02481
02482 ent->s.modelindex = G_EffectIndex( fxFile );
02483
02484
02485 ent->s.eType = ET_FX;
02486 ent->s.speed = ent->delay;
02487 ent->s.time = ent->random;
02488 ent->s.modelindex2 = FX_STATE_OFF;
02489
02490
02491 ent->think = fx_runner_link;
02492 ent->nextthink = level.time + 400;
02493
02494
02495 G_SetOrigin( ent, ent->s.origin );
02496
02497 VectorSet( ent->r.maxs, FX_ENT_RADIUS, FX_ENT_RADIUS, FX_ENT_RADIUS );
02498 VectorScale( ent->r.maxs, -1, ent->r.mins );
02499
02500 trap_LinkEntity( ent );
02501 }
02502
02503
02504
02505
02506
02507
02508
02509 void SP_CreateSpaceDust( gentity_t *ent )
02510 {
02511 G_EffectIndex(va("*spacedust %i", ent->count));
02512
02513 }
02514
02515
02516
02517
02518
02519
02520
02521
02522 void SP_CreateSnow( gentity_t *ent )
02523 {
02524 G_EffectIndex("*snow");
02525 G_EffectIndex("*fog");
02526 G_EffectIndex("*constantwind (100 100 -100)");
02527 }
02528
02529
02530
02531
02532
02533
02534
02535 void SP_CreateRain( gentity_t *ent )
02536 {
02537 G_EffectIndex(va("*rain init %i", ent->count));
02538 }
02539
02540 qboolean gEscaping = qfalse;
02541 int gEscapeTime = 0;
02542
02543 void Use_Target_Screenshake( gentity_t *ent, gentity_t *other, gentity_t *activator )
02544 {
02545 qboolean bGlobal = qfalse;
02546
02547 if (ent->genericValue6)
02548 {
02549 bGlobal = qtrue;
02550 }
02551
02552 G_ScreenShake(ent->s.origin, NULL, ent->speed, ent->genericValue5, bGlobal);
02553 }
02554
02555 void SP_target_screenshake(gentity_t *ent)
02556 {
02557 G_SpawnFloat( "intensity", "10", &ent->speed );
02558
02559 G_SpawnInt( "duration", "800", &ent->genericValue5 );
02560
02561 G_SpawnInt( "globalshake", "1", &ent->genericValue6 );
02562
02563
02564 ent->use = Use_Target_Screenshake;
02565 }
02566
02567 void LogExit( const char *string );
02568
02569 void Use_Target_Escapetrig( gentity_t *ent, gentity_t *other, gentity_t *activator )
02570 {
02571 if (!ent->genericValue6)
02572 {
02573 gEscaping = qtrue;
02574 gEscapeTime = level.time + ent->genericValue5;
02575 }
02576 else if (gEscaping)
02577 {
02578 int i = 0;
02579 gEscaping = qfalse;
02580 while (i < MAX_CLIENTS)
02581 {
02582 if (g_entities[i].inuse && g_entities[i].client && g_entities[i].health > 0 &&
02583 g_entities[i].client->sess.sessionTeam != TEAM_SPECTATOR &&
02584 !(g_entities[i].client->ps.pm_flags & PMF_FOLLOW))
02585 {
02586 AddScore(&g_entities[i], g_entities[i].client->ps.origin, 100);
02587 }
02588 i++;
02589 }
02590 if (activator && activator->inuse && activator->client)
02591 {
02592 AddScore(activator, activator->client->ps.origin, 500);
02593 }
02594
02595 LogExit("Escaped!");
02596 }
02597 }
02598
02599 void SP_target_escapetrig(gentity_t *ent)
02600 {
02601 if (g_gametype.integer != GT_SINGLE_PLAYER)
02602 {
02603 G_FreeEntity(ent);
02604 return;
02605 }
02606
02607 G_SpawnInt( "escapetime", "60000", &ent->genericValue5);
02608
02609 G_SpawnInt( "escapegoal", "0", &ent->genericValue6);
02610
02611
02612 ent->use = Use_Target_Escapetrig;
02613 }
02614
02615
02616
02617
02618
02619
02620
02621
02622
02623 void maglock_die(gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod)
02624 {
02625
02626 if ( self->activator )
02627 {
02628 self->activator->lockCount--;
02629 if ( !self->activator->lockCount )
02630 {
02631 self->activator->flags &= ~FL_INACTIVE;
02632 }
02633 }
02634
02635
02636 G_UseTargets( self, attacker );
02637
02638
02639
02640 }
02641
02642 void maglock_link( gentity_t *self );
02643 gentity_t *G_FindDoorTrigger( gentity_t *ent );
02644
02645 void SP_misc_maglock ( gentity_t *self )
02646 {
02647
02648
02649
02650 self->s.modelindex = G_ModelIndex( "models/map_objects/imp_detention/door_lock.md3" );
02651 self->genericValue1 = G_EffectIndex( "maglock/explosion" );
02652
02653 G_SetOrigin( self, self->s.origin );
02654
02655 self->think = maglock_link;
02656
02657 self->nextthink = level.time + START_TIME_FIND_LINKS+200;
02658 }
02659 void maglock_link( gentity_t *self )
02660 {
02661
02662 vec3_t forward, start, end;
02663 trace_t trace;
02664 gentity_t *traceEnt;
02665
02666 AngleVectors( self->s.angles, forward, NULL, NULL );
02667 VectorMA( self->s.origin, 128, forward, end );
02668 VectorMA( self->s.origin, -4, forward, start );
02669
02670 trap_Trace( &trace, start, vec3_origin, vec3_origin, end, self->s.number, MASK_SHOT );
02671
02672 if ( trace.allsolid || trace.startsolid )
02673 {
02674 Com_Error( ERR_DROP,"misc_maglock at %s in solid\n", vtos(self->s.origin) );
02675 G_FreeEntity( self );
02676 return;
02677 }
02678 if ( trace.fraction == 1.0 )
02679 {
02680 self->think = maglock_link;
02681 self->nextthink = level.time + 100;
02682
02683
02684
02685
02686 return;
02687 }
02688 traceEnt = &g_entities[trace.entityNum];
02689 if ( trace.entityNum >= ENTITYNUM_WORLD || !traceEnt || Q_stricmp( "func_door", traceEnt->classname ) )
02690 {
02691 self->think = maglock_link;
02692 self->nextthink = level.time + 100;
02693
02694
02695 return;
02696 }
02697
02698
02699
02700 self->activator = G_FindDoorTrigger( traceEnt );
02701 if ( !self->activator )
02702 {
02703 self->activator = traceEnt;
02704 }
02705 self->activator->lockCount++;
02706 self->activator->flags |= FL_INACTIVE;
02707
02708
02709 vectoangles( trace.plane.normal, end );
02710 G_SetOrigin( self, trace.endpos );
02711 G_SetAngles( self, end );
02712
02713
02714
02715
02716 VectorSet( self->r.mins, -8, -8, -8 );
02717 VectorSet( self->r.maxs, 8, 8, 8 );
02718 self->r.contents = CONTENTS_CORPSE;
02719
02720
02721 self->flags |= FL_SHIELDED;
02722 self->takedamage = qtrue;
02723 self->health = 10;
02724 self->die = maglock_die;
02725
02726
02727 trap_LinkEntity( self );
02728 }
02729
02730 void faller_touch(gentity_t *self, gentity_t *other, trace_t *trace)
02731 {
02732 if (self->epVelocity[2] < -100 && self->genericValue7 < level.time)
02733 {
02734 int r = Q_irand(1, 3);
02735
02736 if (r == 1)
02737 {
02738 self->genericValue11 = G_SoundIndex("sound/chars/stofficer1/misc/pain25");
02739 }
02740 else if (r == 2)
02741 {
02742 self->genericValue11 = G_SoundIndex("sound/chars/stofficer1/misc/pain50");
02743 }
02744 else
02745 {
02746 self->genericValue11 = G_SoundIndex("sound/chars/stofficer1/misc/pain75");
02747 }
02748
02749 G_EntitySound(self, CHAN_VOICE, self->genericValue11);
02750 G_EntitySound(self, CHAN_AUTO, self->genericValue10);
02751
02752 self->genericValue6 = level.time + 3000;
02753
02754 self->genericValue7 = level.time + 200;
02755 }
02756 }
02757
02758 void faller_think(gentity_t *ent)
02759 {
02760 float gravity = 3.0f;
02761 float mass = 0.09f;
02762 float bounce = 1.1f;
02763
02764 if (ent->genericValue6 < level.time)
02765 {
02766 ent->think = G_FreeEntity;
02767 ent->nextthink = level.time;
02768 return;
02769 }
02770
02771 if (ent->epVelocity[2] < -100)
02772 {
02773 if (!ent->genericValue8)
02774 {
02775 G_EntitySound(ent, CHAN_VOICE, ent->genericValue9);
02776 ent->genericValue8 = 1;
02777 }
02778 }
02779 else
02780 {
02781 ent->genericValue8 = 0;
02782 }
02783
02784 G_RunExPhys(ent, gravity, mass, bounce, qtrue, NULL, 0);
02785 VectorScale(ent->epVelocity, 10.0f, ent->s.pos.trDelta);
02786 ent->nextthink = level.time + 25;
02787 }
02788
02789 void misc_faller_create( gentity_t *ent, gentity_t *other, gentity_t *activator )
02790 {
02791 gentity_t *faller = G_Spawn();
02792
02793 faller->genericValue10 = G_SoundIndex("sound/player/fallsplat");
02794 faller->genericValue9 = G_SoundIndex("sound/chars/stofficer1/misc/falling1");
02795 faller->genericValue8 = 0;
02796 faller->genericValue7 = 0;
02797
02798 faller->genericValue6 = level.time + 15000;
02799
02800 G_SetOrigin(faller, ent->s.origin);
02801
02802 faller->s.modelGhoul2 = 1;
02803 faller->s.modelindex = G_ModelIndex("models/players/stormtrooper/model.glm");
02804 faller->s.g2radius = 100;
02805
02806 faller->s.customRGBA[0]=Q_irand(1,255);
02807 faller->s.customRGBA[1]=Q_irand(1,255);
02808 faller->s.customRGBA[2]=Q_irand(1,255);
02809 faller->s.customRGBA[3]=255;
02810
02811 VectorSet(faller->r.mins, -15, -15, DEFAULT_MINS_2);
02812 VectorSet(faller->r.maxs, 15, 15, DEFAULT_MAXS_2);
02813
02814 faller->clipmask = MASK_PLAYERSOLID;
02815 faller->r.contents = MASK_PLAYERSOLID;
02816
02817 faller->s.eFlags = (EF_RAG|EF_CLIENTSMOOTH);
02818
02819 faller->think = faller_think;
02820 faller->nextthink = level.time;
02821
02822 faller->touch = faller_touch;
02823
02824 faller->epVelocity[0] = flrand(-256.0f, 256.0f);
02825 faller->epVelocity[1] = flrand(-256.0f, 256.0f);
02826
02827 trap_LinkEntity(faller);
02828 }
02829
02830 void misc_faller_think(gentity_t *ent)
02831 {
02832 misc_faller_create(ent, ent, ent);
02833 ent->nextthink = level.time + ent->genericValue1 + Q_irand(0, ent->genericValue2);
02834 }
02835
02836
02837
02838
02839
02840
02841
02842
02843
02844 void SP_misc_faller(gentity_t *ent)
02845 {
02846 G_ModelIndex("models/players/stormtrooper/model.glm");
02847 G_SoundIndex("sound/chars/stofficer1/misc/pain25");
02848 G_SoundIndex("sound/chars/stofficer1/misc/pain50");
02849 G_SoundIndex("sound/chars/stofficer1/misc/pain75");
02850 G_SoundIndex("sound/chars/stofficer1/misc/falling1");
02851 G_SoundIndex("sound/player/fallsplat");
02852
02853 G_SpawnInt("interval", "500", &ent->genericValue1);
02854 G_SpawnInt("fudgefactor", "0", &ent->genericValue2);
02855
02856 if (!ent->targetname || !ent->targetname[0])
02857 {
02858 ent->think = misc_faller_think;
02859 ent->nextthink = level.time + ent->genericValue1 + Q_irand(0, ent->genericValue2);
02860 }
02861 else
02862 {
02863 ent->use = misc_faller_create;
02864 }
02865 }
02866
02867
02868 #define TAG_GENERIC_NAME "__WORLD__" //If a designer chooses this name, cut a finger off as an example to the others
02869
02870
02871
02872
02873 #define MAX_TAGS 256
02874 #define MAX_TAG_OWNERS 16
02875
02876
02877
02878
02879 typedef struct tagOwner_s
02880 {
02881 char name[MAX_REFNAME];
02882 reference_tag_t tags[MAX_TAGS];
02883 qboolean inuse;
02884 } tagOwner_t;
02885
02886 tagOwner_t refTagOwnerMap[MAX_TAG_OWNERS];
02887
02888 tagOwner_t *FirstFreeTagOwner(void)
02889 {
02890 int i = 0;
02891
02892 while (i < MAX_TAG_OWNERS)
02893 {
02894 if (!refTagOwnerMap[i].inuse)
02895 {
02896 return &refTagOwnerMap[i];
02897 }
02898 i++;
02899 }
02900
02901 Com_Printf("WARNING: MAX_TAG_OWNERS (%i) REF TAG LIMIT HIT\n", MAX_TAG_OWNERS);
02902 return NULL;
02903 }
02904
02905 reference_tag_t *FirstFreeRefTag(tagOwner_t *tagOwner)
02906 {
02907 int i = 0;
02908
02909 assert(tagOwner);
02910
02911 while (i < MAX_TAGS)
02912 {
02913 if (!tagOwner->tags[i].inuse)
02914 {
02915 return &tagOwner->tags[i];
02916 }
02917 i++;
02918 }
02919
02920 Com_Printf("WARNING: MAX_TAGS (%i) REF TAG LIMIT HIT\n", MAX_TAGS);
02921 return NULL;
02922 }
02923
02924
02925
02926
02927
02928
02929
02930 void TAG_Init( void )
02931 {
02932 int i = 0;
02933 int x = 0;
02934
02935 while (i < MAX_TAG_OWNERS)
02936 {
02937 while (x < MAX_TAGS)
02938 {
02939 memset(&refTagOwnerMap[i].tags[x], 0, sizeof(refTagOwnerMap[i].tags[x]));
02940 x++;
02941 }
02942 memset(&refTagOwnerMap[i], 0, sizeof(refTagOwnerMap[i]));
02943 i++;
02944 }
02945 }
02946
02947
02948
02949
02950
02951
02952
02953 tagOwner_t *TAG_FindOwner( const char *owner )
02954 {
02955 int i = 0;
02956
02957 while (i < MAX_TAG_OWNERS)
02958 {
02959 if (refTagOwnerMap[i].inuse && !Q_stricmp(refTagOwnerMap[i].name, owner))
02960 {
02961 return &refTagOwnerMap[i];
02962 }
02963 i++;
02964 }
02965
02966 return NULL;
02967 }
02968
02969
02970
02971
02972
02973
02974
02975 reference_tag_t *TAG_Find( const char *owner, const char *name )
02976 {
02977 tagOwner_t *tagOwner = NULL;
02978 int i = 0;
02979
02980 if (owner && owner[0])
02981 {
02982 tagOwner = TAG_FindOwner(owner);
02983 }
02984 if (!tagOwner)
02985 {
02986 tagOwner = TAG_FindOwner(TAG_GENERIC_NAME);
02987 }
02988
02989
02990 if (!tagOwner)
02991 {
02992 tagOwner = TAG_FindOwner( TAG_GENERIC_NAME );
02993
02994 if (!tagOwner)
02995 {
02996 return NULL;
02997 }
02998 }
02999
03000 while (i < MAX_TAGS)
03001 {
03002 if (tagOwner->tags[i].inuse && !Q_stricmp(tagOwner->tags[i].name, name))
03003 {
03004 return &tagOwner->tags[i];
03005 }
03006 i++;
03007 }
03008
03009
03010 tagOwner = TAG_FindOwner( TAG_GENERIC_NAME );
03011
03012 if (!tagOwner)
03013 {
03014 return NULL;
03015 }
03016
03017 i = 0;
03018 while (i < MAX_TAGS)
03019 {
03020 if (tagOwner->tags[i].inuse && !Q_stricmp(tagOwner->tags[i].name, name))
03021 {
03022 return &tagOwner->tags[i];
03023 }
03024 i++;
03025 }
03026
03027 return NULL;
03028 }
03029
03030
03031
03032
03033
03034
03035
03036 reference_tag_t *TAG_Add( const char *name, const char *owner, vec3_t origin, vec3_t angles, int radius, int flags )
03037 {
03038 reference_tag_t *tag = NULL;
03039 tagOwner_t *tagOwner = NULL;
03040
03041
03042 if ( TAG_Find( owner, name ) )
03043 {
03044 Com_Printf(S_COLOR_RED"Duplicate tag name \"%s\"\n", name );
03045 return NULL;
03046 }
03047
03048
03049 if ( !owner || !owner[0] )
03050 {
03051
03052 owner = TAG_GENERIC_NAME;
03053 }
03054
03055 tagOwner = TAG_FindOwner( owner );
03056
03057 if (!tagOwner)
03058 {
03059
03060 tagOwner = FirstFreeTagOwner();
03061
03062 if (!tagOwner)
03063 {
03064 assert(0);
03065 return 0;
03066 }
03067 }
03068
03069
03070
03071 tag = FirstFreeRefTag(tagOwner);
03072
03073 if (!tag)
03074 {
03075 assert(0);
03076 return NULL;
03077 }
03078
03079
03080 VectorCopy( origin, tag->origin );
03081 VectorCopy( angles, tag->angles );
03082 tag->radius = radius;
03083 tag->flags = flags;
03084
03085 if ( !name || !name[0] )
03086 {
03087 Com_Printf(S_COLOR_RED"ERROR: Nameless ref_tag found at (%i %i %i)\n", (int)origin[0], (int)origin[1], (int)origin[2]);
03088 return NULL;
03089 }
03090
03091
03092
03093 Q_strncpyz( (char *) tagOwner->name, owner, MAX_REFNAME );
03094 Q_strlwr( (char *) tagOwner->name );
03095
03096
03097 Q_strncpyz( (char *) tag->name, name, MAX_REFNAME );
03098 Q_strlwr( (char *) tag->name );
03099
03100 tagOwner->inuse = qtrue;
03101 tag->inuse = qtrue;
03102
03103 return tag;
03104 }
03105
03106
03107
03108
03109
03110
03111
03112 int TAG_GetOrigin( const char *owner, const char *name, vec3_t origin )
03113 {
03114 reference_tag_t *tag = TAG_Find( owner, name );
03115
03116 if (!tag)
03117 {
03118 VectorClear(origin);
03119 return 0;
03120 }
03121
03122 VectorCopy( tag->origin, origin );
03123
03124 return 1;
03125 }
03126
03127
03128
03129
03130
03131
03132
03133
03134 int TAG_GetOrigin2( const char *owner, const char *name, vec3_t origin )
03135 {
03136 reference_tag_t *tag = TAG_Find( owner, name );
03137
03138 if( tag == NULL )
03139 {
03140 return 0;
03141 }
03142
03143 VectorCopy( tag->origin, origin );
03144
03145 return 1;
03146 }
03147
03148
03149
03150
03151
03152
03153 int TAG_GetAngles( const char *owner, const char *name, vec3_t angles )
03154 {
03155 reference_tag_t *tag = TAG_Find( owner, name );
03156
03157 if (!tag)
03158 {
03159 assert(0);
03160 return 0;
03161 }
03162
03163 VectorCopy( tag->angles, angles );
03164
03165 return 1;
03166 }
03167
03168
03169
03170
03171
03172
03173
03174 int TAG_GetRadius( const char *owner, const char *name )
03175 {
03176 reference_tag_t *tag = TAG_Find( owner, name );
03177
03178 if (!tag)
03179 {
03180 assert(0);
03181 return 0;
03182 }
03183
03184 return tag->radius;
03185 }
03186
03187
03188
03189
03190
03191
03192
03193 int TAG_GetFlags( const char *owner, const char *name )
03194 {
03195 reference_tag_t *tag = TAG_Find( owner, name );
03196
03197 if (!tag)
03198 {
03199 assert(0);
03200 return 0;
03201 }
03202
03203 return tag->flags;
03204 }
03205
03206
03207
03208
03209
03210
03211
03212
03213
03214
03215
03216
03217
03218
03219
03220
03221
03222
03223
03224
03225
03226
03227
03228
03229
03230
03231
03232
03233
03234
03235
03236
03237
03238
03239
03240
03241
03242
03243
03244
03245
03246
03247
03248
03249
03250
03251
03252
03253
03254
03255
03256
03257
03258
03259
03260
03261
03262
03263
03264
03265
03266
03267 void ref_link ( gentity_t *ent )
03268 {
03269 reference_tag_t *tag;
03270
03271 if ( ent->target )
03272 {
03273
03274 gentity_t *target = G_Find( NULL, FOFS(targetname), ent->target );
03275 vec3_t dir;
03276
03277 if ( target )
03278 {
03279
03280 VectorSubtract( target->s.origin, ent->s.origin, dir );
03281 VectorNormalize( dir );
03282 vectoangles( dir, ent->s.angles );
03283
03284
03285 }
03286 else
03287 {
03288 Com_Printf( S_COLOR_RED"ERROR: ref_tag (%s) has invalid target (%s)", ent->targetname, ent->target );
03289 }
03290 }
03291
03292
03293 tag = TAG_Add( ent->targetname, ent->ownername, ent->s.origin, ent->s.angles, 16, 0 );
03294
03295
03296
03297 G_FreeEntity( ent );
03298 }
03299
03300 void SP_reference_tag ( gentity_t *ent )
03301 {
03302 if ( ent->target )
03303 {
03304
03305 ent->think = ref_link;
03306 ent->nextthink = level.time + START_TIME_LINK_ENTS;
03307 }
03308 else
03309 {
03310 ref_link( ent );
03311 }
03312 }
03313
03314
03315
03316
03317
03318
03319
03320
03321
03322
03323
03324
03325
03326
03327
03328
03329
03330
03331
03332
03333
03334
03335
03336
03337
03338
03339
03340
03341
03342
03343
03344
03345 #define MAX_SHOOTERS 16
03346 typedef struct shooterClient_s
03347 {
03348 gclient_t cl;
03349 qboolean inuse;
03350 } shooterClient_t;
03351 static shooterClient_t g_shooterClients[MAX_SHOOTERS];
03352 static qboolean g_shooterClientInit = qfalse;
03353
03354 gclient_t *G_ClientForShooter(void)
03355 {
03356 int i = 0;
03357
03358 if (!g_shooterClientInit)
03359 {
03360 memset(g_shooterClients, 0, sizeof(shooterClient_t)*MAX_SHOOTERS);
03361 g_shooterClientInit = qtrue;
03362 }
03363
03364 while (i < MAX_SHOOTERS)
03365 {
03366 if (!g_shooterClients[i].inuse)
03367 {
03368 return &g_shooterClients[i].cl;
03369 }
03370 i++;
03371 }
03372
03373 Com_Error(ERR_DROP, "No free shooter clients - hit MAX_SHOOTERS");
03374 return NULL;
03375 }
03376
03377 void G_FreeClientForShooter(gclient_t *cl)
03378 {
03379 int i = 0;
03380 while (i < MAX_SHOOTERS)
03381 {
03382 if (&g_shooterClients[i].cl == cl)
03383 {
03384 g_shooterClients[i].inuse = qfalse;
03385 return;
03386 }
03387 i++;
03388 }
03389 }
03390
03391 void misc_weapon_shooter_fire( gentity_t *self )
03392 {
03393 FireWeapon( self, (self->spawnflags&1) );
03394 if ( (self->spawnflags&2) )
03395 {
03396 self->think = misc_weapon_shooter_fire;
03397 self->nextthink = level.time + self->wait;
03398 }
03399 }
03400
03401 void misc_weapon_shooter_use ( gentity_t *self, gentity_t *other, gentity_t *activator )
03402 {
03403 if ( self->think == misc_weapon_shooter_fire )
03404 {
03405
03406
03407
03408
03409
03410 self->nextthink = 0;
03411 return;
03412 }
03413
03414 misc_weapon_shooter_fire( self );
03415 }
03416
03417 void misc_weapon_shooter_aim( gentity_t *self )
03418 {
03419
03420 if ( self->target )
03421 {
03422 gentity_t *targ = G_Find( NULL, FOFS(targetname), self->target );
03423 if ( targ )
03424 {
03425 self->enemy = targ;
03426 VectorSubtract( targ->r.currentOrigin, self->r.currentOrigin, self->pos1 );
03427 VectorCopy( targ->r.currentOrigin, self->pos1 );
03428 vectoangles( self->pos1, self->client->ps.viewangles );
03429 SetClientViewAngle( self, self->client->ps.viewangles );
03430
03431 self->nextthink = level.time + FRAMETIME;
03432 }
03433 else
03434 {
03435 self->enemy = NULL;
03436 }
03437 }
03438 }
03439
03440 #include "../namespace_begin.h"
03441 extern stringID_table_t WPTable[];
03442 #include "../namespace_end.h"
03443
03444 void SP_misc_weapon_shooter( gentity_t *self )
03445 {
03446 char *s;
03447
03448
03449 self->client = G_ClientForShooter();
03450
03451 G_SpawnString("weapon", "", &s);
03452
03453
03454 self->s.weapon = self->client->ps.weapon = WP_BLASTER;
03455 if ( s && s[0] )
03456 {
03457 self->s.weapon = self->client->ps.weapon = GetIDForString( WPTable, s );
03458 }
03459
03460 RegisterItem(BG_FindItemForWeapon(self->s.weapon));
03461
03462
03463 VectorCopy( self->s.origin, self->client->renderInfo.muzzlePoint );
03464
03465
03466
03467
03468 if ( self->target )
03469 {
03470 self->think = misc_weapon_shooter_aim;
03471 self->nextthink = level.time + START_TIME_LINK_ENTS;
03472 }
03473 else
03474 {
03475 VectorCopy( self->s.angles, self->client->ps.viewangles );
03476 AngleVectors( self->s.angles, self->pos1, NULL, NULL );
03477 }
03478
03479
03480 self->use = misc_weapon_shooter_use;
03481
03482 if ( !self->wait )
03483 {
03484 self->wait = 500;
03485 }
03486 }
03487
03488
03489
03490
03491 void SP_misc_weather_zone( gentity_t *ent )
03492 {
03493 G_FreeEntity(ent);
03494 }