diff --git a/reaction/cgame/.#cg_weapons.c.1.11 b/reaction/cgame/.#cg_weapons.c.1.11 deleted file mode 100644 index a5124dae..00000000 --- a/reaction/cgame/.#cg_weapons.c.1.11 +++ /dev/null @@ -1,2396 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// -// cg_weapons.c -- events and effects dealing with weapons -#include "cg_local.h" - -/* -========================== -CG_MachineGunEjectBrass -========================== -*/ -static void CG_MachineGunEjectBrass( centity_t *cent ) { - localEntity_t *le; - refEntity_t *re; - vec3_t velocity, xvelocity; - vec3_t offset, xoffset; - float waterScale = 1.0f; - vec3_t v[3]; - - if ( cg_brassTime.integer <= 0 ) { - return; - } - - le = CG_AllocLocalEntity(); - re = &le->refEntity; - - velocity[0] = 0; - velocity[1] = -50 + 40 * crandom(); - velocity[2] = 100 + 50 * crandom(); - - le->leType = LE_FRAGMENT; - le->startTime = cg.time; - le->endTime = le->startTime + cg_brassTime.integer + ( cg_brassTime.integer / 4 ) * random(); - - le->pos.trType = TR_GRAVITY; - le->pos.trTime = cg.time - (rand()&15); - - AnglesToAxis( cent->lerpAngles, v ); - - offset[0] = 8; - offset[1] = -4; - offset[2] = 24; - - xoffset[0] = offset[0] * v[0][0] + offset[1] * v[1][0] + offset[2] * v[2][0]; - xoffset[1] = offset[0] * v[0][1] + offset[1] * v[1][1] + offset[2] * v[2][1]; - xoffset[2] = offset[0] * v[0][2] + offset[1] * v[1][2] + offset[2] * v[2][2]; - VectorAdd( cent->lerpOrigin, xoffset, re->origin ); - - VectorCopy( re->origin, le->pos.trBase ); - - if ( CG_PointContents( re->origin, -1 ) & CONTENTS_WATER ) { - waterScale = 0.10f; - } - - xvelocity[0] = velocity[0] * v[0][0] + velocity[1] * v[1][0] + velocity[2] * v[2][0]; - xvelocity[1] = velocity[0] * v[0][1] + velocity[1] * v[1][1] + velocity[2] * v[2][1]; - xvelocity[2] = velocity[0] * v[0][2] + velocity[1] * v[1][2] + velocity[2] * v[2][2]; - VectorScale( xvelocity, waterScale, le->pos.trDelta ); - - AxisCopy( axisDefault, re->axis ); - re->hModel = cgs.media.machinegunBrassModel; - - le->bounceFactor = 0.4 * waterScale; - - le->angles.trType = TR_LINEAR; - le->angles.trTime = cg.time; - le->angles.trBase[0] = rand()&31; - le->angles.trBase[1] = rand()&31; - le->angles.trBase[2] = rand()&31; - le->angles.trDelta[0] = 2; - le->angles.trDelta[1] = 1; - le->angles.trDelta[2] = 0; - - le->leFlags = LEF_TUMBLE; - le->leBounceSoundType = LEBS_BRASS; - le->leMarkType = LEMT_NONE; -} - -/* -========================== -CG_ShotgunEjectBrass -========================== -*/ -static void CG_ShotgunEjectBrass( centity_t *cent ) { - localEntity_t *le; - refEntity_t *re; - vec3_t velocity, xvelocity; - vec3_t offset, xoffset; - vec3_t v[3]; - int i,isHC; - if (cent->currentState.weapon == WP_HANDCANNON) isHC=1; - else - { - isHC=0; - } - - if ( cg_brassTime.integer <= 0 ) { - return; - } - - for ( i = 0; i < isHC + 1; i++ ) { - float waterScale = 1.0f; - - le = CG_AllocLocalEntity(); - re = &le->refEntity; - - velocity[0] = 60 + 60 * crandom(); - if ( i == 0 ) { - velocity[1] = 40 + 10 * crandom(); - } else { - velocity[1] = -40 + 10 * crandom(); - } - velocity[2] = 100 + 50 * crandom(); - - le->leType = LE_FRAGMENT; - le->startTime = cg.time; - le->endTime = le->startTime + cg_brassTime.integer*3 + cg_brassTime.integer * random(); - - le->pos.trType = TR_GRAVITY; - le->pos.trTime = cg.time; - - AnglesToAxis( cent->lerpAngles, v ); - - offset[0] = 8; - offset[1] = 0; - offset[2] = 24; - - xoffset[0] = offset[0] * v[0][0] + offset[1] * v[1][0] + offset[2] * v[2][0]; - xoffset[1] = offset[0] * v[0][1] + offset[1] * v[1][1] + offset[2] * v[2][1]; - xoffset[2] = offset[0] * v[0][2] + offset[1] * v[1][2] + offset[2] * v[2][2]; - VectorAdd( cent->lerpOrigin, xoffset, re->origin ); - VectorCopy( re->origin, le->pos.trBase ); - if ( CG_PointContents( re->origin, -1 ) & CONTENTS_WATER ) { - waterScale = 0.10f; - } - - xvelocity[0] = velocity[0] * v[0][0] + velocity[1] * v[1][0] + velocity[2] * v[2][0]; - xvelocity[1] = velocity[0] * v[0][1] + velocity[1] * v[1][1] + velocity[2] * v[2][1]; - xvelocity[2] = velocity[0] * v[0][2] + velocity[1] * v[1][2] + velocity[2] * v[2][2]; - VectorScale( xvelocity, waterScale, le->pos.trDelta ); - - AxisCopy( axisDefault, re->axis ); - - re->hModel = cgs.media.shotgunBrassModel; - le->bounceFactor = 0.3f; - - le->angles.trType = TR_LINEAR; - le->angles.trTime = cg.time; - le->angles.trBase[0] = rand()&31; - le->angles.trBase[1] = rand()&31; - le->angles.trBase[2] = rand()&31; - le->angles.trDelta[0] = 1; - le->angles.trDelta[1] = 0.5; - le->angles.trDelta[2] = 0; - - le->leFlags = LEF_TUMBLE; - le->leBounceSoundType = LEBS_BRASS; - le->leMarkType = LEMT_NONE; - } -} - - -#ifdef MISSIONPACK -/* -========================== -CG_NailgunEjectBrass -========================== -*/ -static void CG_NailgunEjectBrass( centity_t *cent ) { - localEntity_t *smoke; - vec3_t origin; - vec3_t v[3]; - vec3_t offset; - vec3_t xoffset; - vec3_t up; - - AnglesToAxis( cent->lerpAngles, v ); - - offset[0] = 0; - offset[1] = -12; - offset[2] = 24; - - xoffset[0] = offset[0] * v[0][0] + offset[1] * v[1][0] + offset[2] * v[2][0]; - xoffset[1] = offset[0] * v[0][1] + offset[1] * v[1][1] + offset[2] * v[2][1]; - xoffset[2] = offset[0] * v[0][2] + offset[1] * v[1][2] + offset[2] * v[2][2]; - VectorAdd( cent->lerpOrigin, xoffset, origin ); - - VectorSet( up, 0, 0, 64 ); - - smoke = CG_SmokePuff( origin, up, 32, 1, 1, 1, 0.33f, 700, cg.time, 0, 0, cgs.media.smokePuffShader ); - // use the optimized local entity add - smoke->leType = LE_SCALE_FADE; -} -#endif - - -/* -========================== -CG_RailTrail -========================== -*/ -void CG_RailTrail( clientInfo_t *ci, vec3_t start, vec3_t end ) { - localEntity_t *le; - refEntity_t *re; - - // - // rings - // - le = CG_AllocLocalEntity(); - re = &le->refEntity; - - le->leType = LE_FADE_RGB; - le->startTime = cg.time; - le->endTime = cg.time + cg_railTrailTime.value; - le->lifeRate = 1.0 / ( le->endTime - le->startTime ); - - re->shaderTime = cg.time / 1000.0f; - re->reType = RT_RAIL_RINGS; - re->customShader = cgs.media.railRingsShader; - - VectorCopy( start, re->origin ); - VectorCopy( end, re->oldorigin ); - - // nudge down a bit so it isn't exactly in center - re->origin[2] -= 8; - re->oldorigin[2] -= 8; - - le->color[0] = ci->color[0] * 0.75; - le->color[1] = ci->color[1] * 0.75; - le->color[2] = ci->color[2] * 0.75; - le->color[3] = 1.0f; - - AxisClear( re->axis ); - - // - // core - // - le = CG_AllocLocalEntity(); - re = &le->refEntity; - - le->leType = LE_FADE_RGB; - le->startTime = cg.time; - le->endTime = cg.time + cg_railTrailTime.value; - le->lifeRate = 1.0 / ( le->endTime - le->startTime ); - - re->shaderTime = cg.time / 1000.0f; - re->reType = RT_RAIL_CORE; - re->customShader = cgs.media.railCoreShader; - - VectorCopy( start, re->origin ); - VectorCopy( end, re->oldorigin ); - - // nudge down a bit so it isn't exactly in center - re->origin[2] -= 8; - re->oldorigin[2] -= 8; - - le->color[0] = ci->color[0] * 0.75; - le->color[1] = ci->color[1] * 0.75; - le->color[2] = ci->color[2] * 0.75; - le->color[3] = 1.0f; - - AxisClear( re->axis ); -} - -/* -========================== -CG_RocketTrail -========================== -*/ -static void CG_RocketTrail( centity_t *ent, const weaponInfo_t *wi ) { - int step; - vec3_t origin, lastPos; - int t; - int startTime, contents; - int lastContents; - entityState_t *es; - vec3_t up; - localEntity_t *smoke; - - up[0] = 0; - up[1] = 0; - up[2] = 0; - - step = 50; - - es = &ent->currentState; - startTime = ent->trailTime; - t = step * ( (startTime + step) / step ); - - BG_EvaluateTrajectory( &es->pos, cg.time, origin ); - contents = CG_PointContents( origin, -1 ); - - // if object (e.g. grenade) is stationary, don't toss up smoke - if ( es->pos.trType == TR_STATIONARY ) { - ent->trailTime = cg.time; - return; - } - - BG_EvaluateTrajectory( &es->pos, ent->trailTime, lastPos ); - lastContents = CG_PointContents( lastPos, -1 ); - - ent->trailTime = cg.time; - - if ( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ) { - if ( contents & lastContents & CONTENTS_WATER ) { - CG_BubbleTrail( lastPos, origin, 8 ); - } - return; - } - - for ( ; t <= ent->trailTime ; t += step ) { - BG_EvaluateTrajectory( &es->pos, t, lastPos ); - - smoke = CG_SmokePuff( lastPos, up, - wi->trailRadius, - 1, 1, 1, 0.33f, - wi->wiTrailTime, - t, - 0, - 0, - cgs.media.smokePuffShader ); - // use the optimized local entity add - smoke->leType = LE_SCALE_FADE; - } - -} - -#ifdef MISSIONPACK -/* -========================== -CG_NailTrail -========================== -*/ -static void CG_NailTrail( centity_t *ent, const weaponInfo_t *wi ) { - int step; - vec3_t origin, lastPos; - int t; - int startTime, contents; - int lastContents; - entityState_t *es; - vec3_t up; - localEntity_t *smoke; - - up[0] = 0; - up[1] = 0; - up[2] = 0; - - step = 50; - - es = &ent->currentState; - startTime = ent->trailTime; - t = step * ( (startTime + step) / step ); - - BG_EvaluateTrajectory( &es->pos, cg.time, origin ); - contents = CG_PointContents( origin, -1 ); - - // if object (e.g. grenade) is stationary, don't toss up smoke - if ( es->pos.trType == TR_STATIONARY ) { - ent->trailTime = cg.time; - return; - } - - BG_EvaluateTrajectory( &es->pos, ent->trailTime, lastPos ); - lastContents = CG_PointContents( lastPos, -1 ); - - ent->trailTime = cg.time; - - if ( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ) { - if ( contents & lastContents & CONTENTS_WATER ) { - CG_BubbleTrail( lastPos, origin, 8 ); - } - return; - } - - for ( ; t <= ent->trailTime ; t += step ) { - BG_EvaluateTrajectory( &es->pos, t, lastPos ); - - smoke = CG_SmokePuff( lastPos, up, - wi->trailRadius, - 1, 1, 1, 0.33f, - wi->wiTrailTime, - t, - 0, - 0, - cgs.media.nailPuffShader ); - // use the optimized local entity add - smoke->leType = LE_SCALE_FADE; - } - -} -#endif - -/* -========================== -CG_GrappleTrail -========================== -*/ -void CG_GrappleTrail( centity_t *ent, const weaponInfo_t *wi ) { - vec3_t origin; - entityState_t *es; - vec3_t forward, up; - refEntity_t beam; - - es = &ent->currentState; - - BG_EvaluateTrajectory( &es->pos, cg.time, origin ); - ent->trailTime = cg.time; - - memset( &beam, 0, sizeof( beam ) ); - //FIXME adjust for muzzle position - VectorCopy ( cg_entities[ ent->currentState.otherEntityNum ].lerpOrigin, beam.origin ); - beam.origin[2] += 26; - AngleVectors( cg_entities[ ent->currentState.otherEntityNum ].lerpAngles, forward, NULL, up ); - VectorMA( beam.origin, -6, up, beam.origin ); - VectorCopy( origin, beam.oldorigin ); - - if (Distance( beam.origin, beam.oldorigin ) < 64 ) - return; // Don't draw if close - - beam.reType = RT_LIGHTNING; - beam.customShader = cgs.media.lightningShader; - - AxisClear( beam.axis ); - beam.shaderRGBA[0] = 0xff; - beam.shaderRGBA[1] = 0xff; - beam.shaderRGBA[2] = 0xff; - beam.shaderRGBA[3] = 0xff; - trap_R_AddRefEntityToScene( &beam ); -} - -/* -========================== -CG_GrenadeTrail -========================== -*/ -static void CG_GrenadeTrail( centity_t *ent, const weaponInfo_t *wi ) { - CG_RocketTrail( ent, wi ); -} - - -/* -================= -CG_RegisterWeapon - -The server says this item is used on this level -================= -*/ -void CG_RegisterWeapon( int weaponNum ) { - weaponInfo_t *weaponInfo; - gitem_t *item, *ammo; - char path[MAX_QPATH]; - vec3_t mins, maxs; - int i; - - weaponInfo = &cg_weapons[weaponNum]; - - if ( weaponNum == 0 ) { - return; - } - - if ( weaponInfo->registered ) { - return; - } - - memset( weaponInfo, 0, sizeof( *weaponInfo ) ); - weaponInfo->registered = qtrue; - - for ( item = bg_itemlist + 1 ; item->classname ; item++ ) { - if ( item->giType == IT_WEAPON && item->giTag == weaponNum ) { - weaponInfo->item = item; - break; - } - } - if ( !item->classname ) { - CG_Error( "Couldn't find weapon %i", weaponNum ); - } - CG_RegisterItemVisuals( item - bg_itemlist ); - - // load cmodel before model so filecache works - weaponInfo->weaponModel = trap_R_RegisterModel( item->world_model[0] ); - - // calc midpoint for rotation - trap_R_ModelBounds( weaponInfo->weaponModel, mins, maxs ); - for ( i = 0 ; i < 3 ; i++ ) { - weaponInfo->weaponMidpoint[i] = mins[i] + 0.5 * ( maxs[i] - mins[i] ); - } - - weaponInfo->weaponIcon = trap_R_RegisterShader( item->icon ); - weaponInfo->ammoIcon = trap_R_RegisterShader( item->icon ); - - for ( ammo = bg_itemlist + 1 ; ammo->classname ; ammo++ ) { - if ( ammo->giType == IT_AMMO && ammo->giTag == weaponNum ) { - break; - } - } - if ( ammo->classname && ammo->world_model[0] ) { - weaponInfo->ammoModel = trap_R_RegisterModel( ammo->world_model[0] ); - } - - strcpy( path, item->world_model[0] ); - COM_StripExtension( path, path ); - strcat( path, "_flash.md3" ); - weaponInfo->flashModel = trap_R_RegisterModel( path ); - - strcpy( path, item->world_model[0] ); - COM_StripExtension( path, path ); - strcat( path, "_barrel.md3" ); - weaponInfo->barrelModel = trap_R_RegisterModel( path ); - - strcpy( path, item->world_model[0] ); - COM_StripExtension( path, path ); - strcat( path, "_hand.md3" ); - weaponInfo->handsModel = trap_R_RegisterModel( path ); - - if ( !weaponInfo->handsModel ) { - weaponInfo->handsModel = trap_R_RegisterModel( "models/weapons2/shotgun/shotgun_hand.md3" ); - } - - weaponInfo->loopFireSound = qfalse; - switch ( weaponNum ) { -/*Blaze: Dont need this - case WP_GAUNTLET: - MAKERGB( weaponInfo->flashDlightColor, 0.6f, 0.6f, 1.0f ); - weaponInfo->firingSound = trap_S_RegisterSound( "sound/weapons/melee/fstrun.wav", qfalse ); - weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/melee/fstatck.wav", qfalse ); - break; - - case WP_LIGHTNING: - MAKERGB( weaponInfo->flashDlightColor, 0.6f, 0.6f, 1.0f ); - weaponInfo->readySound = trap_S_RegisterSound( "sound/weapons/melee/fsthum.wav", qfalse ); - weaponInfo->firingSound = trap_S_RegisterSound( "sound/weapons/lightning/lg_hum.wav", qfalse ); - - weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/lightning/lg_fire.wav", qfalse ); - cgs.media.lightningShader = trap_R_RegisterShader( "lightningBolt"); - cgs.media.lightningExplosionModel = trap_R_RegisterModel( "models/weaphits/crackle.md3" ); - cgs.media.sfx_lghit1 = trap_S_RegisterSound( "sound/weapons/lightning/lg_hit.wav", qfalse ); - cgs.media.sfx_lghit2 = trap_S_RegisterSound( "sound/weapons/lightning/lg_hit2.wav", qfalse ); - cgs.media.sfx_lghit3 = trap_S_RegisterSound( "sound/weapons/lightning/lg_hit3.wav", qfalse ); - - break; - - case WP_GRAPPLING_HOOK: - MAKERGB( weaponInfo->flashDlightColor, 0.6f, 0.6f, 1.0f ); - weaponInfo->missileModel = trap_R_RegisterModel( "models/ammo/rocket/rocket.md3" ); - weaponInfo->missileTrailFunc = CG_GrappleTrail; - weaponInfo->missileDlight = 200; - weaponInfo->wiTrailTime = 2000; - weaponInfo->trailRadius = 64; - MAKERGB( weaponInfo->missileDlightColor, 1, 0.75f, 0 ); - weaponInfo->readySound = trap_S_RegisterSound( "sound/weapons/melee/fsthum.wav", qfalse ); - weaponInfo->firingSound = trap_S_RegisterSound( "sound/weapons/melee/fstrun.wav", qfalse ); - break; - -#ifdef MISSIONPACK - case WP_CHAINGUN: - weaponInfo->firingSound = trap_S_RegisterSound( "sound/weapons/vulcan/wvulfire.wav", qfalse ); - weaponInfo->loopFireSound = qtrue; - MAKERGB( weaponInfo->flashDlightColor, 1, 1, 0 ); - weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/vulcan/vulcanf1b.wav", qfalse ); - weaponInfo->flashSound[1] = trap_S_RegisterSound( "sound/weapons/vulcan/vulcanf2b.wav", qfalse ); - weaponInfo->flashSound[2] = trap_S_RegisterSound( "sound/weapons/vulcan/vulcanf3b.wav", qfalse ); - weaponInfo->flashSound[3] = trap_S_RegisterSound( "sound/weapons/vulcan/vulcanf4b.wav", qfalse ); - weaponInfo->ejectBrassFunc = CG_MachineGunEjectBrass; - cgs.media.bulletExplosionShader = trap_R_RegisterShader( "bulletExplosion" ); - break; -#endif - - case WP_MACHINEGUN: - MAKERGB( weaponInfo->flashDlightColor, 1, 1, 0 ); - weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/machinegun/machgf1b.wav", qfalse ); - weaponInfo->flashSound[1] = trap_S_RegisterSound( "sound/weapons/machinegun/machgf2b.wav", qfalse ); - weaponInfo->flashSound[2] = trap_S_RegisterSound( "sound/weapons/machinegun/machgf3b.wav", qfalse ); - weaponInfo->flashSound[3] = trap_S_RegisterSound( "sound/weapons/machinegun/machgf4b.wav", qfalse ); - weaponInfo->ejectBrassFunc = CG_MachineGunEjectBrass; - cgs.media.bulletExplosionShader = trap_R_RegisterShader( "bulletExplosion" ); - break; - - case WP_SHOTGUN: - MAKERGB( weaponInfo->flashDlightColor, 1, 1, 0 ); - weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/shotgun/sshotf1b.wav", qfalse ); - weaponInfo->ejectBrassFunc = CG_ShotgunEjectBrass; - break; - - case WP_ROCKET_LAUNCHER: - weaponInfo->missileModel = trap_R_RegisterModel( "models/ammo/rocket/rocket.md3" ); - weaponInfo->missileSound = trap_S_RegisterSound( "sound/weapons/rocket/rockfly.wav", qfalse ); - weaponInfo->missileTrailFunc = CG_RocketTrail; - weaponInfo->missileDlight = 200; - weaponInfo->wiTrailTime = 2000; - weaponInfo->trailRadius = 64; - - MAKERGB( weaponInfo->missileDlightColor, 1, 0.75f, 0 ); - MAKERGB( weaponInfo->flashDlightColor, 1, 0.75f, 0 ); - - weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/rocket/rocklf1a.wav", qfalse ); - cgs.media.rocketExplosionShader = trap_R_RegisterShader( "rocketExplosion" ); - break; - -#ifdef MISSIONPACK - case WP_PROX_LAUNCHER: - weaponInfo->missileModel = trap_R_RegisterModel( "models/weaphits/proxmine.md3" ); - weaponInfo->missileTrailFunc = CG_GrenadeTrail; - weaponInfo->wiTrailTime = 700; - weaponInfo->trailRadius = 32; - MAKERGB( weaponInfo->flashDlightColor, 1, 0.70f, 0 ); - weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/proxmine/wstbfire.wav", qfalse ); - cgs.media.grenadeExplosionShader = trap_R_RegisterShader( "grenadeExplosion" ); - break; -#endif - - case WP_GRENADE_LAUNCHER: - weaponInfo->missileModel = trap_R_RegisterModel( "models/ammo/grenade1.md3" ); - weaponInfo->missileTrailFunc = CG_GrenadeTrail; - weaponInfo->wiTrailTime = 700; - weaponInfo->trailRadius = 32; - MAKERGB( weaponInfo->flashDlightColor, 1, 0.70f, 0 ); - weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/grenade/grenlf1a.wav", qfalse ); - cgs.media.grenadeExplosionShader = trap_R_RegisterShader( "grenadeExplosion" ); - break; - -#ifdef MISSIONPACK - case WP_NAILGUN: - weaponInfo->ejectBrassFunc = CG_NailgunEjectBrass; - weaponInfo->missileTrailFunc = CG_NailTrail; - weaponInfo->missileSound = trap_S_RegisterSound( "sound/weapons/nailgun/wnalflit.wav", qfalse ); - weaponInfo->trailRadius = 16; - weaponInfo->wiTrailTime = 250; - weaponInfo->missileModel = trap_R_RegisterModel( "models/weaphits/nail.md3" ); - MAKERGB( weaponInfo->flashDlightColor, 1, 0.75f, 0 ); - weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/nailgun/wnalfire.wav", qfalse ); - break; -#endif - - case WP_PLASMAGUN: - weaponInfo->missileSound = trap_S_RegisterSound( "sound/weapons/plasma/lasfly.wav", qfalse ); - MAKERGB( weaponInfo->flashDlightColor, 0.6f, 0.6f, 1.0f ); - weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/plasma/hyprbf1a.wav", qfalse ); - cgs.media.plasmaExplosionShader = trap_R_RegisterShader( "plasmaExplosion" ); - break; - - case WP_RAILGUN: - weaponInfo->readySound = trap_S_RegisterSound( "sound/weapons/railgun/rg_hum.wav", qfalse ); - MAKERGB( weaponInfo->flashDlightColor, 1, 0.5f, 0 ); - weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/railgun/railgf1a.wav", qfalse ); - cgs.media.railExplosionShader = trap_R_RegisterShader( "railExplosion" ); - cgs.media.railRingsShader = trap_R_RegisterShader( "railDisc" ); - cgs.media.railCoreShader = trap_R_RegisterShader( "railCore" ); - break; - - case WP_BFG: - weaponInfo->readySound = trap_S_RegisterSound( "sound/weapons/bfg/bfg_hum.wav", qfalse ); - MAKERGB( weaponInfo->flashDlightColor, 1, 0.7f, 1 ); - weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/bfg/bfg_fire.wav", qfalse ); - cgs.media.bfgExplosionShader = trap_R_RegisterShader( "bfgExplosion" ); - weaponInfo->missileModel = trap_R_RegisterModel( "models/weaphits/bfg.md3" ); - weaponInfo->missileSound = trap_S_RegisterSound( "sound/weapons/rocket/rockfly.wav", qfalse ); - break; -*/ -//Blaze: Reaction Pistol - case WP_PISTOL: - MAKERGB( weaponInfo->flashDlightColor, 1, 1, 0 ); - weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/mk23/mk23fire.wav", qfalse ); - weaponInfo->ejectBrassFunc = CG_MachineGunEjectBrass; - cgs.media.bulletExplosionShader = trap_R_RegisterShader( "bulletExplosion" ); - break; - case WP_KNIFE: - - weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/knife/slash.wav", qfalse ); - weaponInfo->missileModel = trap_R_RegisterModel("models/weapons2/knife/knife.md3"); - //weaponInfo->missileTrailFunc = CG_GrenadeTrail; - MAKERGB( weaponInfo->flashDlightColor, 1, 0.70f, 0 ); - //cgs.media.grenadeExplosionShader = trap_R_RegisterShader( "grenadeExplosion" ); - weaponInfo->wiTrailTime = 700; - weaponInfo->trailRadius = 32; - break; - case WP_M4: - weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/m4/m4fire.wav", qfalse ); - weaponInfo->ejectBrassFunc = CG_MachineGunEjectBrass; - cgs.media.bulletExplosionShader = trap_R_RegisterShader( "bulletExplosion" ); - break; - case WP_SSG3000: - weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/ssg3000/ssgfire.wav", qfalse ); - weaponInfo->ejectBrassFunc = CG_MachineGunEjectBrass; - cgs.media.bulletExplosionShader = trap_R_RegisterShader( "bulletExplosion" ); - break; - case WP_MP5: - weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/mp5/mp5fire1.wav", qfalse ); - weaponInfo->ejectBrassFunc = CG_MachineGunEjectBrass; - cgs.media.bulletExplosionShader = trap_R_RegisterShader( "bulletExplosion" ); - break; - case WP_HANDCANNON: - weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/handcannon/cannon_fire.wav", qfalse ); - weaponInfo->ejectBrassFunc = CG_ShotgunEjectBrass; - cgs.media.bulletExplosionShader = trap_R_RegisterShader( "bulletExplosion" ); - break; - case WP_M3: - MAKERGB( weaponInfo->flashDlightColor, 1, 1, 0 ); - weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/shotgun/sshotf1b.wav", qfalse ); - weaponInfo->ejectBrassFunc = CG_ShotgunEjectBrass; - break; - - case WP_AKIMBO: - weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/mk23/mk23fire.wav", qfalse ); - weaponInfo->flashSound[1] = trap_S_RegisterSound( "sound/weapons/mk23/mk23fire.wav", qfalse ); - weaponInfo->ejectBrassFunc = CG_MachineGunEjectBrass; - cgs.media.bulletExplosionShader = trap_R_RegisterShader( "bulletExplosion" ); - break; - case WP_GRENADE: - weaponInfo->missileModel = trap_R_RegisterModel( "models/weapons2/grenade/3rd_grenade.md3" ); - weaponInfo->missileTrailFunc = CG_GrenadeTrail; - weaponInfo->wiTrailTime = 700; - weaponInfo->trailRadius = 32; - MAKERGB( weaponInfo->flashDlightColor, 1, 0.70f, 0 ); - weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/grenade/grenlf1a.wav", qfalse ); - cgs.media.grenadeExplosionShader = trap_R_RegisterShader( "grenadeExplosion" ); - break; - - default: - //MAKERGB( weaponInfo->flashDlightColor, 1, 1, 1 ); - //weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/rocket/rocklf1a.wav", qfalse ); - break; - } -} - -/* -================= -CG_RegisterItemVisuals - -The server says this item is used on this level -================= -*/ -void CG_RegisterItemVisuals( int itemNum ) { - itemInfo_t *itemInfo; - gitem_t *item; - - itemInfo = &cg_items[ itemNum ]; - if ( itemInfo->registered ) { - return; - } - - item = &bg_itemlist[ itemNum ]; - - memset( itemInfo, 0, sizeof( &itemInfo ) ); - itemInfo->registered = qtrue; - - itemInfo->models[0] = trap_R_RegisterModel( item->world_model[0] ); - - itemInfo->icon = trap_R_RegisterShader( item->icon ); - - if ( item->giType == IT_WEAPON ) { - CG_RegisterWeapon( item->giTag ); - } - - // - // powerups have an accompanying ring or sphere - // - if ( item->giType == IT_POWERUP || item->giType == IT_HEALTH || - item->giType == IT_ARMOR || item->giType == IT_HOLDABLE ) { - if ( item->world_model[1] ) { - itemInfo->models[1] = trap_R_RegisterModel( item->world_model[1] ); - } - } -} - - -/* -======================================================================================== - -VIEW WEAPON - -======================================================================================== -*/ - -/* -================= -CG_MapTorsoToWeaponFrame - -================= -*/ -static int CG_MapTorsoToWeaponFrame( clientInfo_t *ci, int frame ) { - - // change weapon - if ( frame >= ci->animations[TORSO_DROP].firstFrame - && frame < ci->animations[TORSO_DROP].firstFrame + 9 ) { - return frame - ci->animations[TORSO_DROP].firstFrame + 6; - } - - // stand attack - if ( frame >= ci->animations[TORSO_ATTACK].firstFrame - && frame < ci->animations[TORSO_ATTACK].firstFrame + 6 ) { - return 1 + frame - ci->animations[TORSO_ATTACK].firstFrame; - } - - // stand attack 2 - if ( frame >= ci->animations[TORSO_ATTACK2].firstFrame - && frame < ci->animations[TORSO_ATTACK2].firstFrame + 6 ) { - return 1 + frame - ci->animations[TORSO_ATTACK2].firstFrame; - } - - return 0; -} - - -/* -============== -CG_CalculateWeaponPosition -============== -*/ -static void CG_CalculateWeaponPosition( vec3_t origin, vec3_t angles ) { - float scale; - int delta; - float fracsin; - - VectorCopy( cg.refdef.vieworg, origin ); - VectorCopy( cg.refdefViewAngles, angles ); - - // on odd legs, invert some angles - if ( cg.bobcycle & 1 ) { - scale = -cg.xyspeed; - } else { - scale = cg.xyspeed; - } - - // gun angles from bobbing - angles[ROLL] += scale * cg.bobfracsin * 0.005; - angles[YAW] += scale * cg.bobfracsin * 0.01; - angles[PITCH] += cg.xyspeed * cg.bobfracsin * 0.005; - - // drop the weapon when landing - delta = cg.time - cg.landTime; - if ( delta < LAND_DEFLECT_TIME ) { - origin[2] += cg.landChange*0.25 * delta / LAND_DEFLECT_TIME; - } else if ( delta < LAND_DEFLECT_TIME + LAND_RETURN_TIME ) { - origin[2] += cg.landChange*0.25 * - (LAND_DEFLECT_TIME + LAND_RETURN_TIME - delta) / LAND_RETURN_TIME; - } - -#if 0 - // drop the weapon when stair climbing - delta = cg.time - cg.stepTime; - if ( delta < STEP_TIME/2 ) { - origin[2] -= cg.stepChange*0.25 * delta / (STEP_TIME/2); - } else if ( delta < STEP_TIME ) { - origin[2] -= cg.stepChange*0.25 * (STEP_TIME - delta) / (STEP_TIME/2); - } -#endif - - // idle drift - scale = cg.xyspeed + 40; - fracsin = sin( cg.time * 0.001 ); - angles[ROLL] += scale * fracsin * 0.01; - angles[YAW] += scale * fracsin * 0.01; - angles[PITCH] += scale * fracsin * 0.01; -} - - -/* -=============== -CG_LightningBolt - -Origin will be the exact tag point, which is slightly -different than the muzzle point used for determining hits. -The cent should be the non-predicted cent if it is from the player, -so the endpoint will reflect the simulated strike (lagging the predicted -angle) -=============== -*/ -static void CG_LightningBolt( centity_t *cent, vec3_t origin ) { - trace_t trace; - refEntity_t beam; - vec3_t forward; - vec3_t muzzlePoint, endPoint; -//Blaze: LG No longer exists -// if ( cent->currentState.weapon != WP_LIGHTNING ) { -// return; -// } - - memset( &beam, 0, sizeof( beam ) ); - - // find muzzle point for this frame - VectorCopy( cent->lerpOrigin, muzzlePoint ); - AngleVectors( cent->lerpAngles, forward, NULL, NULL ); - - // FIXME: crouch - muzzlePoint[2] += DEFAULT_VIEWHEIGHT; - - VectorMA( muzzlePoint, 14, forward, muzzlePoint ); - - // project forward by the lightning range - VectorMA( muzzlePoint, LIGHTNING_RANGE, forward, endPoint ); - - // see if it hit a wall - CG_Trace( &trace, muzzlePoint, vec3_origin, vec3_origin, endPoint, - cent->currentState.number, MASK_SHOT ); - - // this is the endpoint - VectorCopy( trace.endpos, beam.oldorigin ); - - // use the provided origin, even though it may be slightly - // different than the muzzle origin - VectorCopy( origin, beam.origin ); - - beam.reType = RT_LIGHTNING; - beam.customShader = cgs.media.lightningShader; - trap_R_AddRefEntityToScene( &beam ); - - // add the impact flare if it hit something - if ( trace.fraction < 1.0 ) { - vec3_t angles; - vec3_t dir; - - VectorSubtract( beam.oldorigin, beam.origin, dir ); - VectorNormalize( dir ); - - memset( &beam, 0, sizeof( beam ) ); - beam.hModel = cgs.media.lightningExplosionModel; - - VectorMA( trace.endpos, -16, dir, beam.origin ); - - // make a random orientation - angles[0] = rand() % 360; - angles[1] = rand() % 360; - angles[2] = rand() % 360; - AnglesToAxis( angles, beam.axis ); - trap_R_AddRefEntityToScene( &beam ); - } -} - - -/* -=============== -CG_SpawnRailTrail - -Origin will be the exact tag point, which is slightly -different than the muzzle point used for determining hits. -=============== -*/ -static void CG_SpawnRailTrail( centity_t *cent, vec3_t origin ) { - clientInfo_t *ci; - - //Blaze: No more rail gun - //if ( cent->currentState.weapon != WP_RAILGUN ) { - // return; - //} - if ( !cent->pe.railgunFlash ) { - return; - } - cent->pe.railgunFlash = qtrue; - ci = &cgs.clientinfo[ cent->currentState.clientNum ]; - //Blaze: No Rail Trail - //CG_RailTrail( ci, origin, cent->pe.railgunImpact ); -} - - -/* -====================== -CG_MachinegunSpinAngle -====================== -*/ -#define SPIN_SPEED 0.9 -#define COAST_TIME 1000 -static float CG_MachinegunSpinAngle( centity_t *cent ) { - int delta; - float angle; - float speed; - - delta = cg.time - cent->pe.barrelTime; - if ( cent->pe.barrelSpinning ) { - angle = cent->pe.barrelAngle + delta * SPIN_SPEED; - } else { - if ( delta > COAST_TIME ) { - delta = COAST_TIME; - } - - speed = 0.5 * ( SPIN_SPEED + (float)( COAST_TIME - delta ) / COAST_TIME ); - angle = cent->pe.barrelAngle + delta * speed; - } - - if ( cent->pe.barrelSpinning == !(cent->currentState.eFlags & EF_FIRING) ) { - cent->pe.barrelTime = cg.time; - cent->pe.barrelAngle = AngleMod( angle ); - cent->pe.barrelSpinning = !!(cent->currentState.eFlags & EF_FIRING); -#ifdef MISSIONPACK - if ( cent->currentState.weapon == WP_CHAINGUN && !cent->pe.barrelSpinning ) { - trap_S_StartSound( NULL, cent->currentState.number, CHAN_WEAPON, trap_S_RegisterSound( "sound/weapons/vulcan/wvulwind.wav", qfalse ) ); - } -#endif - } - - return angle; -} - - -/* -======================== -CG_AddWeaponWithPowerups -======================== -*/ -static void CG_AddWeaponWithPowerups( refEntity_t *gun, int powerups ) { - // add powerup effects - if ( powerups & ( 1 << PW_INVIS ) ) { - gun->customShader = cgs.media.invisShader; - trap_R_AddRefEntityToScene( gun ); - } else { - trap_R_AddRefEntityToScene( gun ); - - if ( powerups & ( 1 << PW_BATTLESUIT ) ) { - gun->customShader = cgs.media.battleWeaponShader; - trap_R_AddRefEntityToScene( gun ); - } - if ( powerups & ( 1 << PW_QUAD ) ) { - gun->customShader = cgs.media.quadWeaponShader; - trap_R_AddRefEntityToScene( gun ); - } - } -} - - -/* -============= -CG_AddPlayerWeapon - -Used for both the view weapon (ps is valid) and the world modelother character models (ps is NULL) -The main player will have this called for BOTH cases, so effects like light and -sound should only be done on the world model case. -============= -*/ -void CG_AddPlayerWeapon( refEntity_t *parent, playerState_t *ps, centity_t *cent, int team ) { - refEntity_t gun; -//Blaze: Can remove this because no more spinning barrel -// refEntity_t barrel; - refEntity_t flash; - vec3_t angles; - float frac; - weapon_t weaponNum; - weaponInfo_t *weapon; - centity_t *nonPredictedCent; -// int col; - - weaponNum = cent->currentState.weapon; - - CG_RegisterWeapon( weaponNum ); - weapon = &cg_weapons[weaponNum]; - - // add the weapon - memset( &gun, 0, sizeof( gun ) ); - VectorCopy( parent->lightingOrigin, gun.lightingOrigin ); - gun.shadowPlane = parent->shadowPlane; - gun.renderfx = parent->renderfx; - - // set custom shading for railgun refire rate - //if ( ps ) { - //Blaze: No Railgun - //if ( cg.predictedPlayerState.weapon == WP_RAILGUN - // && cg.predictedPlayerState.weaponstate == WEAPON_FIRING ) { - // float f; - - // f = (float)cg.predictedPlayerState.weaponTime / 1500; - // gun.shaderRGBA[1] = 0; - // gun.shaderRGBA[0] = - // gun.shaderRGBA[2] = 255 * ( 1.0 - f ); - //} else { - gun.shaderRGBA[0] = 255; - gun.shaderRGBA[1] = 255; - gun.shaderRGBA[2] = 255; - gun.shaderRGBA[3] = 255; - //} - //} - if (ps == NULL) - { - switch (weaponNum)//Blaze: Used to make the third person weapon models different then 1st person - { - case 0: - //gun.hModel = trap_R_RegisterModel( "models/weapons2/mk23/3rd_mk23.md3" ); - //No Case zero - break; - case 1: - gun.hModel = trap_R_RegisterModel("models/weapons2/knife/3rd_knife.md3"); - break; - case 2: - gun.hModel = trap_R_RegisterModel("models/weapons2/mk23/3rd_mk23.md3"); - break; - case 3: - gun.hModel = trap_R_RegisterModel("models/weapons2/m4/3rd_m4.md3"); - break; - case 4: - gun.hModel = trap_R_RegisterModel("models/weapons2/ssg3000/3rd_ssg3000.md3"); - break; - case 5: - gun.hModel = trap_R_RegisterModel("models/weapons2/mp5/3rd_mp5.md3"); - break; - case 6: - gun.hModel = trap_R_RegisterModel("models/weapons2/m3/3rd_m3.md3"); - break; - case 7: - gun.hModel = trap_R_RegisterModel("models/weapons2/handcannon/3rd_handcannon.md3"); - break; - case 8: - gun.hModel = trap_R_RegisterModel("models/weapons2/mk23/3rd_mk23.md3"); - break; - case 9: - gun.hModel = trap_R_RegisterModel("models/weapons2/grenade/3rd_grenade.md3"); - break; - } - - } - else - { - gun.hModel = weapon->weaponModel; - } - - if (!gun.hModel) { - return; - } - - if ( !ps ) { - // add weapon ready sound - cent->pe.lightningFiring = qfalse; - if ( ( cent->currentState.eFlags & EF_FIRING ) && weapon->firingSound ) { - // lightning gun and guantlet make a different sound when fire is held down - trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, weapon->firingSound ); - cent->pe.lightningFiring = qtrue; - } else if ( weapon->readySound ) { - trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, weapon->readySound ); - } - } - if (ps == NULL) - { - /* resizing code - msec = cg.time - cent->miscTime; - if ( msec >= 0 && msec < ITEM_SCALEUP_TIME ) { - frac = (float)msec / ITEM_SCALEUP_TIME; - VectorScale( ent.axis[0], frac, ent.axis[0] ); - VectorScale( ent.axis[1], frac, ent.axis[1] ); - VectorScale( ent.axis[2], frac, ent.axis[2] ); - ent.nonNormalizedAxes = qtrue; - } else { - frac = 1.0; - } - */ - if (weaponNum == 4)//Blaze: Scale the Sniper Rifle down a bit - { - frac = 0.8f; - VectorScale(parent->axis[0], frac, parent->axis[0]); - //VectorScale(parent->axis[1], frac, parent->axis[1]); - //VectorScale(parent->axis[2], frac, parent->axis[2]); - } - - } - CG_PositionEntityOnTag( &gun, parent, parent->hModel, "tag_weapon"); - - CG_AddWeaponWithPowerups( &gun, cent->currentState.powerups ); - - // add the spinning barrel - //Blaze: No Spinning Barrel - /* - if ( weapon->barrelModel ) { - memset( &barrel, 0, sizeof( barrel ) ); - VectorCopy( parent->lightingOrigin, barrel.lightingOrigin ); - barrel.shadowPlane = parent->shadowPlane; - barrel.renderfx = parent->renderfx; - - barrel.hModel = weapon->barrelModel; - angles[YAW] = 0; - angles[PITCH] = 0; - angles[ROLL] = CG_MachinegunSpinAngle( cent ); - AnglesToAxis( angles, barrel.axis ); - - CG_PositionRotatedEntityOnTag( &barrel, &gun, weapon->weaponModel, "tag_barrel" ); - - CG_AddWeaponWithPowerups( &barrel, cent->currentState.powerups ); - }*/ - - // make sure we aren't looking at cg.predictedPlayerEntity for LG - nonPredictedCent = &cg_entities[cent->currentState.clientNum]; - - // if the index of the nonPredictedCent is not the same as the clientNum - // then this is a fake player (like on teh single player podiums), so - // go ahead and use the cent - if( ( nonPredictedCent - cg_entities ) != cent->currentState.clientNum ) { - nonPredictedCent = cent; - } - - // add the flash - //Blaze: no more of these - /* - if ( ( weaponNum == WP_LIGHTNING || weaponNum == WP_GAUNTLET || weaponNum == WP_GRAPPLING_HOOK ) - && ( nonPredictedCent->currentState.eFlags & EF_FIRING ) ) - { - // continuous flash - } else { - // impulse flash - if ( cg.time - cent->muzzleFlashTime > MUZZLE_FLASH_TIME && !cent->pe.railgunFlash ) { - return; - } - } - */ - - memset( &flash, 0, sizeof( flash ) ); - VectorCopy( parent->lightingOrigin, flash.lightingOrigin ); - flash.shadowPlane = parent->shadowPlane; - flash.renderfx = parent->renderfx; - - flash.hModel = weapon->flashModel; - if (!flash.hModel) { - return; - } - angles[YAW] = 0; - angles[PITCH] = 0; - angles[ROLL] = crandom() * 10; - AnglesToAxis( angles, flash.axis ); - - // colorize the railgun blast - //Blaze: No more railgun - /* - if ( weaponNum == WP_RAILGUN ) { - clientInfo_t *ci; - - ci = &cgs.clientinfo[ cent->currentState.clientNum ]; - flash.shaderRGBA[0] = 255 * ci->color[0]; - flash.shaderRGBA[1] = 255 * ci->color[1]; - flash.shaderRGBA[2] = 255 * ci->color[2]; - } - */ - //Blaze: No flash - //CG_PositionRotatedEntityOnTag( &flash, &gun, weapon->weaponModel, "tag_flash"); - //trap_R_AddRefEntityToScene( &flash ); - - if ( ps || cg.renderingThirdPerson || - cent->currentState.number != cg.predictedPlayerState.clientNum ) { - // add lightning bolt - //Blaze: No need for this - //CG_LightningBolt( nonPredictedCent, flash.origin ); - - // add rail trail - //Blaze: no need for this - //CG_SpawnRailTrail( cent, flash.origin ); -/* - if ( team == TEAM_RED ) { - col = 1; - } - else if ( team == TEAM_BLUE ) { - col = 2; - } - else { - col = 0; - } - - // make a dlight for the flash - if ( weapon->flashDlightColor[col][0] || weapon->flashDlightColor[col][1] || weapon->flashDlightColor[col][2] ) { - trap_R_AddLightToScene( flash.origin, 300 + (rand()&31), weapon->flashDlightColor[col][0], - weapon->flashDlightColor[col][1], weapon->flashDlightColor[col][2] ); - } -*/ - if ( weapon->flashDlightColor[0] || weapon->flashDlightColor[1] || weapon->flashDlightColor[2] ) { - trap_R_AddLightToScene( flash.origin, 300 + (rand()&31), weapon->flashDlightColor[0], - weapon->flashDlightColor[1], weapon->flashDlightColor[2] ); - } - } -} - -/* -============== -CG_AddViewWeapon - -Add the weapon, and flash for the player's view -============== -*/ -void CG_AddViewWeapon( playerState_t *ps ) { - refEntity_t hand; - centity_t *cent; - clientInfo_t *ci; - float fovOffset; - vec3_t angles; - weaponInfo_t *weapon; - //Blaze: Reaction vars for gun positions - float rxn_gunx, rxn_guny, rxn_gunz; - - - - if ( ps->persistant[PERS_TEAM] == TEAM_SPECTATOR ) { - return; - } - - if ( ps->pm_type == PM_INTERMISSION ) { - return; - } - - // no gun if in third person view - if ( cg.renderingThirdPerson ) { - return; - } - - // allow the gun to be completely removed - if ( !cg_drawGun.integer ) { -//Blaze: Removed these -// vec3_t origin; - -// if ( cg.predictedPlayerState.eFlags & EF_FIRING ) { - // special hack for lightning gun... -// VectorCopy( cg.refdef.vieworg, origin ); -// VectorMA( origin, -8, cg.refdef.viewaxis[2], origin ); -// CG_LightningBolt( &cg_entities[ps->clientNum], origin ); -// } - return; - } - - // don't draw if testing a gun model - if ( cg.testGun ) { - return; - } -//Blaze start: Reaction gun positioning - rxn_gunx = cg_gun_x.value; - rxn_guny = cg_gun_y.value; - rxn_gunz = cg_gun_z.value; - //Blaze: Gun xyz coords changes - switch(ps->weapon) - { - case WP_PISTOL: - rxn_gunx -= 4; - break; - case WP_M4: - rxn_gunx += 10; - break; - case WP_SSG3000: - rxn_gunx += 10; - break; - case WP_AKIMBO: - rxn_gunx += 10; - } - - if ((rxn_drawWeapon.integer > 1 ) && (rxn_drawWeapon.integer < 4 )) - { - rxn_guny = cg_gun_y.value + 4*(rxn_drawWeapon.integer-1); - } - //Blaze end: - - // drop gun lower at higher fov - if ( cg_fov.integer > 90 ) { - fovOffset = -0.2 * ( cg_fov.integer - 90 ); - } else { - fovOffset = 0; - } - - cent = &cg.predictedPlayerEntity; // &cg_entities[cg.snap->ps.clientNum]; - CG_RegisterWeapon( ps->weapon ); - weapon = &cg_weapons[ ps->weapon ]; - - memset (&hand, 0, sizeof(hand)); - - // set up gun position - CG_CalculateWeaponPosition( hand.origin, angles ); -//Blaze start: reaction gun positioning - VectorMA( hand.origin, rxn_gunx, cg.refdef.viewaxis[0], hand.origin ); - VectorMA( hand.origin, rxn_guny, cg.refdef.viewaxis[1], hand.origin ); - VectorMA( hand.origin, (rxn_gunz + fovOffset), cg.refdef.viewaxis[2], hand.origin ); -//Blaze end: - -//Blaze: Use above code instead -// VectorMA( hand.origin, cg_gun_x.value, cg.refdef.viewaxis[0], hand.origin ); -// VectorMA( hand.origin, cg_gun_y.value, cg.refdef.viewaxis[1], hand.origin ); -// VectorMA( hand.origin, (cg_gun_z.value+fovOffset), cg.refdef.viewaxis[2], hand.origin ); - - AnglesToAxis( angles, hand.axis ); - - // map torso animations to weapon animations - if ( cg_gun_frame.integer ) { - // development tool - hand.frame = hand.oldframe = cg_gun_frame.integer; - hand.backlerp = 0; - } else { - // get clientinfo for animation map - ci = &cgs.clientinfo[ cent->currentState.clientNum ]; - hand.frame = CG_MapTorsoToWeaponFrame( ci, cent->pe.torso.frame ); - hand.oldframe = CG_MapTorsoToWeaponFrame( ci, cent->pe.torso.oldFrame ); - hand.backlerp = cent->pe.torso.backlerp; - } - - hand.hModel = weapon->handsModel; - hand.renderfx = RF_DEPTHHACK | RF_FIRST_PERSON | RF_MINLIGHT; - - // add everything onto the hand - CG_AddPlayerWeapon( &hand, ps, &cg.predictedPlayerEntity, ps->persistant[PERS_TEAM] ); -} - -/* -============================================================================== - -WEAPON SELECTION - -============================================================================== -*/ - -/* -=================== -CG_DrawWeaponSelect -=================== -*/ -void CG_DrawWeaponSelect( void ) { - int i; - int bits; - int count; - int x, y, w; - char *name; - float *color; - - // don't display if dead - if ( cg.predictedPlayerState.stats[STAT_HEALTH] <= 0 ) { - return; - } - - color = CG_FadeColor( cg.weaponSelectTime, WEAPON_SELECT_TIME ); - if ( !color ) { - return; - } - trap_R_SetColor( color ); - - // showing weapon select clears pickup item display, but not the blend blob - cg.itemPickupTime = 0; - - // count the number of weapons owned - bits = cg.snap->ps.stats[ STAT_WEAPONS ]; - count = 0; - for ( i = 1 ; i < 16 ; i++ ) { - if ( bits & ( 1 << i ) ) { - count++; - } - } - - x = 320 - count * 20; - y = 380; - - for ( i = 1 ; i < 16 ; i++ ) { - if ( !( bits & ( 1 << i ) ) ) { - continue; - } - - CG_RegisterWeapon( i ); - - // draw weapon icon - CG_DrawPic( x, y, 32, 32, cg_weapons[i].weaponIcon ); - - // draw selection marker - if ( i == cg.weaponSelect ) { - CG_DrawPic( x-4, y-4, 40, 40, cgs.media.selectShader ); - } - - // no ammo cross on top - if ( !cg.snap->ps.ammo[ i ] ) { - CG_DrawPic( x, y, 32, 32, cgs.media.noammoShader ); - } - - x += 40; - } - - // draw the selected name - if ( cg_weapons[ cg.weaponSelect ].item ) { - name = cg_weapons[ cg.weaponSelect ].item->pickup_name; - if ( name ) { - w = CG_DrawStrlen( name ) * BIGCHAR_WIDTH; - x = ( SCREEN_WIDTH - w ) / 2; - CG_DrawBigStringColor(x, y - 22, name, color); - } - } - - trap_R_SetColor( NULL ); -} - - -/* -=============== -CG_WeaponSelectable -=============== -*/ -static qboolean CG_WeaponSelectable( int i ) { - //Blaze: Check the amount of clips too for the weapon rotate code - if ( !cg.snap->ps.ammo[i] && !cg.snap->ps.stats[STAT_CLIPS] ) { - return qfalse; - } - if ( ! (cg.snap->ps.stats[ STAT_WEAPONS ] & ( 1 << i ) ) ) { - return qfalse; - } - - return qtrue; -} - -/* -=============== -CG_NextWeapon_f -=============== -*/ -void CG_NextWeapon_f( void ) { - int i; - int original; - - if ( !cg.snap ) { - return; - } - if ( cg.snap->ps.pm_flags & PMF_FOLLOW ) { - return; - } - - cg.weaponSelectTime = cg.time; - original = cg.weaponSelect; - - for ( i = 0 ; i < 16 ; i++ ) { - cg.weaponSelect++; - if ( cg.weaponSelect == 16 ) { - cg.weaponSelect = 0; - } - //Blaze: Allow full Cycle - //if ( cg.weaponSelect == WP_GAUNTLET ) { - // continue; // never cycle to gauntlet - //} - if ( CG_WeaponSelectable( cg.weaponSelect ) ) { - break; - } - } - if ( i == 16 ) { - cg.weaponSelect = original; - } -} - -/* -=============== -CG_PrevWeapon_f -=============== -*/ -void CG_PrevWeapon_f( void ) { - int i; - int original; - - if ( !cg.snap ) { - return; - } - if ( cg.snap->ps.pm_flags & PMF_FOLLOW ) { - return; - } - - cg.weaponSelectTime = cg.time; - original = cg.weaponSelect; - - for ( i = 0 ; i < 16 ; i++ ) { - cg.weaponSelect--; - if ( cg.weaponSelect == -1 ) { - cg.weaponSelect = 15; - } - //Blaze: Allow full Cycle - //if ( cg.weaponSelect == WP_GAUNTLET ) { - // continue; // never cycle to gauntlet - //} - if ( CG_WeaponSelectable( cg.weaponSelect ) ) { - break; - } - } - if ( i == 16 ) { - cg.weaponSelect = original; - } -} - -// Hawkins (weapon command) -void rxn_weapon(void){ - if(cg.snap->ps.weapon==WP_SSG3000) { - if ( cg.zoomLevel == 3 ) { - cg.zoomLevel=0; - cg.zoomed=qfalse; - CG_Printf("Zoomed to 1x\n"); - } else { - switch(++cg.zoomLevel){ - case 0: CG_Printf("Zoomed to 1x\n"); break; - case 1: CG_Printf("Zoomed to 2x\n"); break; - case 2: CG_Printf("Zoomed to 4x\n"); break; - case 3: CG_Printf("Zoomed to 6x\n"); break; - } - cg.zoomed = qtrue; - cg.zoomTime = cg.time; - } - cg.zoomTime = cg.time; - } - - trap_SendClientCommand ("weapon"); - -} - - -void rxn_zoom1x(void) { - cg.zoomLevel=0; - cg.zoomed=qfalse; - cg.zoomTime = cg.time; -} - - - - -/* -=============== -CG_Weapon_f -=============== -*/ -void CG_Weapon_f( void ) { - int num; - - // Hawkins (give 'weapon' dual meaning.) - if(trap_Argc()==1){ - rxn_weapon(); - return; - } - - if ( !cg.snap ) { - return; - } - if ( cg.snap->ps.pm_flags & PMF_FOLLOW ) { - return; - } - - num = atoi( CG_Argv( 1 ) ); - - if ( num < 1 || num > 15 ) { - return; - } - - cg.weaponSelectTime = cg.time; - - if ( ! ( cg.snap->ps.stats[STAT_WEAPONS] & ( 1 << num ) ) ) { - return; // don't have the weapon - } - - rxn_zoom1x(); - trap_SendClientCommand("unzoom"); - - cg.weaponSelect = num; -} - - - - -/* -void CG_ZoomUp_f( void ) { - if ( !cg.zoomed ) { - return; - } - cg.zoomed = qfalse; - cg.zoomTime = cg.time; -} -*/ - - - -/* -=================== -CG_OutOfAmmoChange - -The current weapon has just run out of ammo -=================== -*/ -void CG_OutOfAmmoChange( void ) { - int i; - - cg.weaponSelectTime = cg.time; - - for ( i = 15 ; i > 0 ; i-- ) { - if ( CG_WeaponSelectable( i ) ) { - cg.weaponSelect = i; - break; - } - } -} - - - -/* -=================================================================================================== - -WEAPON EVENTS - -=================================================================================================== -*/ - -/* -================ -CG_FireWeapon - -Caused by an EV_FIRE_WEAPON event -================ -*/ -void CG_FireWeapon( centity_t *cent ) { - entityState_t *ent; - int c; - weaponInfo_t *weap; - - ent = ¢->currentState; - if ( ent->weapon == WP_NONE ) { - return; - } - if ( ent->weapon >= WP_NUM_WEAPONS ) { - CG_Error( "CG_FireWeapon: ent->weapon >= WP_NUM_WEAPONS" ); - return; - } - weap = &cg_weapons[ ent->weapon ]; - - // mark the entity as muzzle flashing, so when it is added it will - // append the flash to the weapon model - cent->muzzleFlashTime = cg.time; - - // lightning gun only does this this on initial press - //Blaze: no more Lighting gun - /* - if ( ent->weapon == WP_LIGHTNING ) { - if ( cent->pe.lightningFiring ) { - return; - } - } - */ - - // play quad sound if needed - if ( cent->currentState.powerups & ( 1 << PW_QUAD ) ) { - trap_S_StartSound (NULL, cent->currentState.number, CHAN_ITEM, cgs.media.quadSound ); - } - - // play a sound - for ( c = 0 ; c < 4 ; c++ ) { - if ( !weap->flashSound[c] ) { - break; - } - } - if ( c > 0 ) { - c = rand() % c; - if ( weap->flashSound[c] ) - { - trap_S_StartSound( NULL, ent->number, CHAN_WEAPON, weap->flashSound[c] ); - } - } - - // do brass ejection - if ( weap->ejectBrassFunc && cg_brassTime.integer > 0 ) { - weap->ejectBrassFunc( cent ); - } -} - - -/* -================= -CG_MissileHitWall - -Caused by an EV_MISSILE_MISS event, or directly by local bullet tracing -================= -*/ -void CG_MissileHitWall( int weapon, int clientNum, vec3_t origin, vec3_t dir, impactSound_t soundType ) { - qhandle_t mod; - qhandle_t mark; - qhandle_t shader; - sfxHandle_t sfx; - float radius; - float light; - vec3_t lightColor; - localEntity_t *le; - int r; - qboolean alphaFade; - qboolean isSprite; - int duration; - - mark = 0; - radius = 32; - sfx = 0; - mod = 0; - shader = 0; - light = 0; - lightColor[0] = 1; - lightColor[1] = 1; - lightColor[2] = 0; - - // set defaults - isSprite = qfalse; - duration = 600; - - switch ( weapon ) { - -/* -#ifdef MISSIONPACK - case WP_NAILGUN: - if( soundType == IMPACTSOUND_FLESH ) { - sfx = cgs.media.sfx_nghitflesh; - } else if( soundType == IMPACTSOUND_METAL ) { - sfx = cgs.media.sfx_nghitmetal; - } else { - sfx = cgs.media.sfx_nghit; - } - mark = cgs.media.holeMarkShader; - radius = 12; - break; -#endif - case WP_LIGHTNING: - // no explosion at LG impact, it is added with the beam - r = rand() & 3; - if ( r < 2 ) { - sfx = cgs.media.sfx_lghit2; - } else if ( r == 2 ) { - sfx = cgs.media.sfx_lghit1; - } else { - sfx = cgs.media.sfx_lghit3; - } - mark = cgs.media.holeMarkShader; - radius = 12; - break; -#ifdef MISSIONPACK - case WP_PROX_LAUNCHER: - mod = cgs.media.dishFlashModel; - shader = cgs.media.grenadeExplosionShader; - sfx = cgs.media.sfx_proxexp; - mark = cgs.media.burnMarkShader; - radius = 64; - light = 300; - isSprite = qtrue; - break; -#endif - case WP_GRENADE_LAUNCHER: - mod = cgs.media.dishFlashModel; - shader = cgs.media.grenadeExplosionShader; - sfx = cgs.media.sfx_rockexp; - mark = cgs.media.burnMarkShader; - radius = 64; - light = 300; - isSprite = qtrue; - break; - case WP_ROCKET_LAUNCHER: - mod = cgs.media.dishFlashModel; - shader = cgs.media.rocketExplosionShader; - sfx = cgs.media.sfx_rockexp; - mark = cgs.media.burnMarkShader; - radius = 64; - light = 300; - isSprite = qtrue; - duration = 1000; - lightColor[0] = 1; - lightColor[1] = 0.75; - lightColor[2] = 0.0; -// CG_BigExplode( origin ); - break; - case WP_RAILGUN: - mod = cgs.media.ringFlashModel; - shader = cgs.media.railExplosionShader; - sfx = cgs.media.sfx_plasmaexp; - mark = cgs.media.energyMarkShader; - radius = 24; - break; - case WP_PLASMAGUN: - mod = cgs.media.ringFlashModel; - shader = cgs.media.plasmaExplosionShader; - sfx = cgs.media.sfx_plasmaexp; - mark = cgs.media.energyMarkShader; - radius = 16; - break; - case WP_BFG: - mod = cgs.media.dishFlashModel; - shader = cgs.media.bfgExplosionShader; - sfx = cgs.media.sfx_rockexp; - mark = cgs.media.burnMarkShader; - radius = 32; - isSprite = qtrue; - break; - case WP_SHOTGUN: - mod = cgs.media.bulletFlashModel; - shader = cgs.media.bulletExplosionShader; - mark = cgs.media.bulletMarkShader; - sfx = 0; - radius = 4; - break; - -#ifdef MISSIONPACK - case WP_CHAINGUN: - mod = cgs.media.bulletFlashModel; - if( soundType == IMPACTSOUND_FLESH ) { - sfx = cgs.media.sfx_chghitflesh; - } else if( soundType == IMPACTSOUND_METAL ) { - sfx = cgs.media.sfx_chghitmetal; - } else { - sfx = cgs.media.sfx_chghit; - } - mark = cgs.media.bulletMarkShader; - - r = rand() & 3; - if ( r < 2 ) { - sfx = cgs.media.sfx_ric1; - } else if ( r == 2 ) { - sfx = cgs.media.sfx_ric2; - } else { - sfx = cgs.media.sfx_ric3; - } - - radius = 8; - break; -#endif - - case WP_MACHINEGUN: - mod = cgs.media.bulletFlashModel; - shader = cgs.media.bulletExplosionShader; - mark = cgs.media.bulletMarkShader; - - r = rand() & 3; - if ( r < 2 ) { - sfx = cgs.media.sfx_ric1; - } else if ( r == 2 ) { - sfx = cgs.media.sfx_ric2; - } else { - sfx = cgs.media.sfx_ric3; - } - - radius = 8; - break; - } -*///Blaze: Reaction M4 - case WP_M4: - mod = cgs.media.bulletFlashModel; - shader = cgs.media.bulletExplosionShader; - mark = cgs.media.bulletMarkShader; - - r = rand() & 3; - if ( r < 2 ) { - sfx = cgs.media.sfx_ric1; - } else if ( r == 2 ) { - sfx = cgs.media.sfx_ric2; - } else { - sfx = cgs.media.sfx_ric3; - } - - radius = 8; - break; -//Blaze: Reaction Pistol - case WP_PISTOL: - mod = cgs.media.bulletFlashModel; - shader = cgs.media.bulletExplosionShader; - mark = cgs.media.bulletMarkShader; - - r = rand() & 3; - if ( r < 2 ) { - sfx = cgs.media.sfx_ric1; - } else if ( r == 2 ) { - sfx = cgs.media.sfx_ric2; - } else { - sfx = cgs.media.sfx_ric3; - } - - radius = 8; - break; -//Blaze: Reaction MP5 - case WP_MP5: - mod = cgs.media.bulletFlashModel; - shader = cgs.media.bulletExplosionShader; - mark = cgs.media.bulletMarkShader; - - r = rand() & 3; - if ( r < 2 ) { - sfx = cgs.media.sfx_ric1; - } else if ( r == 2 ) { - sfx = cgs.media.sfx_ric2; - } else { - sfx = cgs.media.sfx_ric3; - } - - radius = 8; - break; -//Blaze: Reaction Shotgun - case WP_M3: - mod = cgs.media.bulletFlashModel; - shader = cgs.media.bulletExplosionShader; - mark = cgs.media.bulletMarkShader; - sfx = 0; - radius = 4; - break; - case WP_HANDCANNON: - mod = cgs.media.bulletFlashModel; - shader = cgs.media.bulletExplosionShader; - mark = cgs.media.bulletMarkShader; - sfx = 0; - radius = 4; - break; - case WP_AKIMBO: - mod = cgs.media.bulletFlashModel; - shader = cgs.media.bulletExplosionShader; - mark = cgs.media.bulletMarkShader; - sfx = 0; - radius = 4; - break; - case WP_GRENADE: - mod = cgs.media.dishFlashModel; - shader = cgs.media.grenadeExplosionShader; - sfx = cgs.media.sfx_rockexp; - mark = cgs.media.burnMarkShader; - radius = 64; - light = 300; - isSprite = qtrue; - break; - - case WP_KNIFE: - /* - mod = cgs.media.dishFlashModel; - //shader = cgs.media.grenadeExplosionShader; - sfx = cgs.media.sfx_rockexp; - mark = cgs.media.burnMarkShader; - radius = 64; - light = 300; - isSprite = qtrue; - break; -*/ - mod = cgs.media.bulletFlashModel; - shader = cgs.media.bulletExplosionShader; - mark = cgs.media.bulletMarkShader; - sfx = 0; - radius = 4; - - break; - default: - break; - } - - if ( sfx ) { - trap_S_StartSound( origin, ENTITYNUM_WORLD, CHAN_AUTO, sfx ); - } - - // - // create the explosion - // - if ( mod ) { - le = CG_MakeExplosion( origin, dir, - mod, shader, - duration, isSprite ); - le->light = light; - VectorCopy( lightColor, le->lightColor ); - //Blaze: No railgun - /* - if ( weapon == WP_RAILGUN ) { - // colorize with client color - VectorCopy( cgs.clientinfo[clientNum].color, le->color ); - } - */ - } - - // - // impact mark - // - alphaFade = (mark == cgs.media.energyMarkShader); // plasma fades alpha, all others fade color - //Blaze: No more railgun - //if ( weapon == WP_RAILGUN ) { - // float *color; - - // colorize with client color - // color = cgs.clientinfo[clientNum].color; - // CG_ImpactMark( mark, origin, dir, random()*360, color[0],color[1], color[2],1, alphaFade, radius, qfalse ); - //} else { - CG_ImpactMark( mark, origin, dir, random()*360, 1,1,1,1, alphaFade, radius, qfalse ); - //} -} - - -/* -================= -CG_MissileHitPlayer -================= -*/ -void CG_MissileHitPlayer( int weapon, vec3_t origin, vec3_t dir, int entityNum ) { - CG_Bleed( origin, entityNum ); - - // some weapons will make an explosion with the blood, while - // others will just make the blood - //Blaze: None of these are valid - /* - switch ( weapon ) { - case WP_GRENADE_LAUNCHER: - case WP_ROCKET_LAUNCHER: -#ifdef MISSIONPACK - case WP_NAILGUN: - case WP_CHAINGUN: - case WP_PROX_LAUNCHER: -#endif - CG_MissileHitWall( weapon, 0, origin, dir, IMPACTSOUND_FLESH ); - break; - default: - break; - } - */ -} - - - -/* -============================================================================ - -SHOTGUN TRACING - -============================================================================ -*/ - -/* -================ -CG_ShotgunPellet -================ -*/ -static void CG_ShotgunPellet( vec3_t start, vec3_t end, int skipNum ) { - trace_t tr; - int sourceContentType, destContentType; - - CG_Trace( &tr, start, NULL, NULL, end, skipNum, MASK_SHOT ); - - sourceContentType = trap_CM_PointContents( start, 0 ); - destContentType = trap_CM_PointContents( tr.endpos, 0 ); - - // FIXME: should probably move this cruft into CG_BubbleTrail - if ( sourceContentType == destContentType ) { - if ( sourceContentType & CONTENTS_WATER ) { - CG_BubbleTrail( start, tr.endpos, 32 ); - } - } else if ( sourceContentType & CONTENTS_WATER ) { - trace_t trace; - - trap_CM_BoxTrace( &trace, end, start, NULL, NULL, 0, CONTENTS_WATER ); - CG_BubbleTrail( start, trace.endpos, 32 ); - } else if ( destContentType & CONTENTS_WATER ) { - trace_t trace; - - trap_CM_BoxTrace( &trace, start, end, NULL, NULL, 0, CONTENTS_WATER ); - CG_BubbleTrail( tr.endpos, trace.endpos, 32 ); - } - - if ( tr.surfaceFlags & SURF_NOIMPACT ) { - return; - } - - if ( cg_entities[tr.entityNum].currentState.eType == ET_PLAYER ) { - //Blaze: Changed WP_SHOTGUN to WP_M3 - CG_MissileHitPlayer( WP_M3, tr.endpos, tr.plane.normal, tr.entityNum ); - } else { - if ( tr.surfaceFlags & SURF_NOIMPACT ) { - // SURF_NOIMPACT will not make a flame puff or a mark - return; - } - if ( tr.surfaceFlags & SURF_METALSTEPS ) { - //Blaze: Changed WP_SHOTGUN to WP_M3 - CG_MissileHitWall( WP_M3, 0, tr.endpos, tr.plane.normal, IMPACTSOUND_METAL ); - } else { - //Blaze: Changed WP_SHOTGUN to WP_M3 - CG_MissileHitWall( WP_M3, 0, tr.endpos, tr.plane.normal, IMPACTSOUND_DEFAULT ); - } - } -} - -/* -================ -CG_ShotgunPattern - -Perform the same traces the server did to locate the -hit splashes (FIXME: ranom seed isn't synce anymore) -================ -*/ -static void CG_ShotgunPattern( vec3_t origin, vec3_t origin2, int otherEntNum,qboolean ism3 ) { - int i; - float r, u; - vec3_t end; - vec3_t forward, right, up; - - // derive the right and up vectors from the forward vector, because - // the client won't have any other information - VectorNormalize2( origin2, forward ); - PerpendicularVector( right, forward ); - CrossProduct( forward, right, up ); - - // generate the "random" spread pattern - for ( i = 0 ; i < DEFAULT_SHOTGUN_COUNT ; i++ ) { - if (ism3) - { - r = crandom() * DEFAULT_SHOTGUN_SPREAD * 16; - u = crandom() * DEFAULT_SHOTGUN_SPREAD * 16; - } - else - { - r = crandom() * DEFAULT_HANDCANNON_SPREAD * 16 * 4; - u = crandom() * DEFAULT_HANDCANNON_SPREAD * 16 * 4; - } VectorMA( origin, 8192 * 16, forward, end); - VectorMA (end, r, right, end); - VectorMA (end, u, up, end); - - CG_ShotgunPellet( origin, end, otherEntNum ); - } -} - -/* -============== -CG_ShotgunFire -============== -*/ -void CG_ShotgunFire( entityState_t *es, qboolean ism3) { - vec3_t v; - int contents; - - VectorSubtract( es->origin2, es->pos.trBase, v ); - VectorNormalize( v ); - VectorScale( v, 32, v ); - VectorAdd( es->pos.trBase, v, v ); - if ( cgs.glconfig.hardwareType != GLHW_RAGEPRO ) { - // ragepro can't alpha fade, so don't even bother with smoke - vec3_t up; - - contents = trap_CM_PointContents( es->pos.trBase, 0 ); - if ( !( contents & CONTENTS_WATER ) ) { - VectorSet( up, 0, 0, 8 ); - CG_SmokePuff( v, up, 32, 1, 1, 1, 0.33f, 900, cg.time, 0, LEF_PUFF_DONT_SCALE, cgs.media.shotgunSmokePuffShader ); - } - } - if (ism3) - { - CG_ShotgunPattern( es->pos.trBase, es->origin2, es->otherEntityNum,ism3); - } - else - { - CG_ShotgunPattern( es->pos.trBase, es->origin2, es->otherEntityNum,ism3); - es->origin2[1] += 5; - CG_ShotgunPattern( es->pos.trBase, es->origin2, es->otherEntityNum,ism3); - } -} - -/* -============================================================================ - -BULLETS - -============================================================================ -*/ - - -/* -=============== -CG_Tracer -=============== -*/ -void CG_Tracer( vec3_t source, vec3_t dest ) { - vec3_t forward, right; - polyVert_t verts[4]; - vec3_t line; - float len, begin, end; - vec3_t start, finish; - vec3_t midpoint; - - // tracer - VectorSubtract( dest, source, forward ); - len = VectorNormalize( forward ); - - // start at least a little ways from the muzzle - if ( len < 100 ) { - return; - } - begin = 50 + random() * (len - 60); - end = begin + cg_tracerLength.value; - if ( end > len ) { - end = len; - } - VectorMA( source, begin, forward, start ); - VectorMA( source, end, forward, finish ); - - line[0] = DotProduct( forward, cg.refdef.viewaxis[1] ); - line[1] = DotProduct( forward, cg.refdef.viewaxis[2] ); - - VectorScale( cg.refdef.viewaxis[1], line[1], right ); - VectorMA( right, -line[0], cg.refdef.viewaxis[2], right ); - VectorNormalize( right ); - - VectorMA( finish, cg_tracerWidth.value, right, verts[0].xyz ); - verts[0].st[0] = 0; - verts[0].st[1] = 1; - verts[0].modulate[0] = 255; - verts[0].modulate[1] = 255; - verts[0].modulate[2] = 255; - verts[0].modulate[3] = 255; - - VectorMA( finish, -cg_tracerWidth.value, right, verts[1].xyz ); - verts[1].st[0] = 1; - verts[1].st[1] = 0; - verts[1].modulate[0] = 255; - verts[1].modulate[1] = 255; - verts[1].modulate[2] = 255; - verts[1].modulate[3] = 255; - - VectorMA( start, -cg_tracerWidth.value, right, verts[2].xyz ); - verts[2].st[0] = 1; - verts[2].st[1] = 1; - verts[2].modulate[0] = 255; - verts[2].modulate[1] = 255; - verts[2].modulate[2] = 255; - verts[2].modulate[3] = 255; - - VectorMA( start, cg_tracerWidth.value, right, verts[3].xyz ); - verts[3].st[0] = 0; - verts[3].st[1] = 0; - verts[3].modulate[0] = 255; - verts[3].modulate[1] = 255; - verts[3].modulate[2] = 255; - verts[3].modulate[3] = 255; - - trap_R_AddPolyToScene( cgs.media.tracerShader, 4, verts ); - - midpoint[0] = ( start[0] + finish[0] ) * 0.5; - midpoint[1] = ( start[1] + finish[1] ) * 0.5; - midpoint[2] = ( start[2] + finish[2] ) * 0.5; - - // add the tracer sound - trap_S_StartSound( midpoint, ENTITYNUM_WORLD, CHAN_AUTO, cgs.media.tracerSound ); - -} - - -/* -====================== -CG_CalcMuzzlePoint -====================== -*/ -static qboolean CG_CalcMuzzlePoint( int entityNum, vec3_t muzzle ) { - vec3_t forward; - centity_t *cent; - int anim; - - if ( entityNum == cg.snap->ps.clientNum ) { - VectorCopy( cg.snap->ps.origin, muzzle ); - muzzle[2] += cg.snap->ps.viewheight; - AngleVectors( cg.snap->ps.viewangles, forward, NULL, NULL ); - VectorMA( muzzle, 14, forward, muzzle ); - return qtrue; - } - - cent = &cg_entities[entityNum]; - if ( !cent->currentValid ) { - return qfalse; - } - - VectorCopy( cent->currentState.pos.trBase, muzzle ); - - AngleVectors( cent->currentState.apos.trBase, forward, NULL, NULL ); - anim = cent->currentState.legsAnim & ~ANIM_TOGGLEBIT; - if ( anim == LEGS_WALKCR || anim == LEGS_IDLECR ) { - muzzle[2] += CROUCH_VIEWHEIGHT; - } else { - muzzle[2] += DEFAULT_VIEWHEIGHT; - } - - VectorMA( muzzle, 14, forward, muzzle ); - - return qtrue; - -} - -/* -====================== -CG_Bullet - -Renders bullet effects. -====================== -*/ -void CG_Bullet( vec3_t end, int sourceEntityNum, vec3_t normal, qboolean flesh, int fleshEntityNum ) { - trace_t trace; - int sourceContentType, destContentType; - vec3_t start; - - // if the shooter is currently valid, calc a source point and possibly - // do trail effects - if ( sourceEntityNum >= 0 && cg_tracerChance.value > 0 ) { - if ( CG_CalcMuzzlePoint( sourceEntityNum, start ) ) { - sourceContentType = trap_CM_PointContents( start, 0 ); - destContentType = trap_CM_PointContents( end, 0 ); - - // do a complete bubble trail if necessary - if ( ( sourceContentType == destContentType ) && ( sourceContentType & CONTENTS_WATER ) ) { - CG_BubbleTrail( start, end, 32 ); - } - // bubble trail from water into air - else if ( ( sourceContentType & CONTENTS_WATER ) ) { - trap_CM_BoxTrace( &trace, end, start, NULL, NULL, 0, CONTENTS_WATER ); - CG_BubbleTrail( start, trace.endpos, 32 ); - } - // bubble trail from air into water - else if ( ( destContentType & CONTENTS_WATER ) ) { - trap_CM_BoxTrace( &trace, start, end, NULL, NULL, 0, CONTENTS_WATER ); - CG_BubbleTrail( trace.endpos, end, 32 ); - } - - // draw a tracer - if ( random() < cg_tracerChance.value ) { - CG_Tracer( start, end ); - } - } - } - - // impact splash and mark - if ( flesh ) { - CG_Bleed( end, fleshEntityNum ); - } else { - //Blaze: Changed WP_MACHINEGUN to WP_PISTOL - CG_MissileHitWall( WP_PISTOL, 0, end, normal, IMPACTSOUND_DEFAULT ); - } - -} diff --git a/reaction/cgame/.#cg_weapons.c.1.8 b/reaction/cgame/.#cg_weapons.c.1.8 deleted file mode 100644 index 0e65a754..00000000 --- a/reaction/cgame/.#cg_weapons.c.1.8 +++ /dev/null @@ -1,2296 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// -// cg_weapons.c -- events and effects dealing with weapons -#include "cg_local.h" - -/* -========================== -CG_MachineGunEjectBrass -========================== -*/ -static void CG_MachineGunEjectBrass( centity_t *cent ) { - localEntity_t *le; - refEntity_t *re; - vec3_t velocity, xvelocity; - vec3_t offset, xoffset; - float waterScale = 1.0f; - vec3_t v[3]; - - if ( cg_brassTime.integer <= 0 ) { - return; - } - - le = CG_AllocLocalEntity(); - re = &le->refEntity; - - velocity[0] = 0; - velocity[1] = -50 + 40 * crandom(); - velocity[2] = 100 + 50 * crandom(); - - le->leType = LE_FRAGMENT; - le->startTime = cg.time; - le->endTime = le->startTime + cg_brassTime.integer + ( cg_brassTime.integer / 4 ) * random(); - - le->pos.trType = TR_GRAVITY; - le->pos.trTime = cg.time - (rand()&15); - - AnglesToAxis( cent->lerpAngles, v ); - - offset[0] = 8; - offset[1] = -4; - offset[2] = 24; - - xoffset[0] = offset[0] * v[0][0] + offset[1] * v[1][0] + offset[2] * v[2][0]; - xoffset[1] = offset[0] * v[0][1] + offset[1] * v[1][1] + offset[2] * v[2][1]; - xoffset[2] = offset[0] * v[0][2] + offset[1] * v[1][2] + offset[2] * v[2][2]; - VectorAdd( cent->lerpOrigin, xoffset, re->origin ); - - VectorCopy( re->origin, le->pos.trBase ); - - if ( CG_PointContents( re->origin, -1 ) & CONTENTS_WATER ) { - waterScale = 0.10f; - } - - xvelocity[0] = velocity[0] * v[0][0] + velocity[1] * v[1][0] + velocity[2] * v[2][0]; - xvelocity[1] = velocity[0] * v[0][1] + velocity[1] * v[1][1] + velocity[2] * v[2][1]; - xvelocity[2] = velocity[0] * v[0][2] + velocity[1] * v[1][2] + velocity[2] * v[2][2]; - VectorScale( xvelocity, waterScale, le->pos.trDelta ); - - AxisCopy( axisDefault, re->axis ); - re->hModel = cgs.media.machinegunBrassModel; - - le->bounceFactor = 0.4 * waterScale; - - le->angles.trType = TR_LINEAR; - le->angles.trTime = cg.time; - le->angles.trBase[0] = rand()&31; - le->angles.trBase[1] = rand()&31; - le->angles.trBase[2] = rand()&31; - le->angles.trDelta[0] = 2; - le->angles.trDelta[1] = 1; - le->angles.trDelta[2] = 0; - - le->leFlags = LEF_TUMBLE; - le->leBounceSoundType = LEBS_BRASS; - le->leMarkType = LEMT_NONE; -} - -/* -========================== -CG_ShotgunEjectBrass -========================== -*/ -static void CG_ShotgunEjectBrass( centity_t *cent ) { - localEntity_t *le; - refEntity_t *re; - vec3_t velocity, xvelocity; - vec3_t offset, xoffset; - vec3_t v[3]; - int i,isHC; - if (cent->currentState.weapon == WP_HANDCANNON) isHC=1; - else - { - isHC=0; - } - - if ( cg_brassTime.integer <= 0 ) { - return; - } - - for ( i = 0; i < isHC + 1; i++ ) { - float waterScale = 1.0f; - - le = CG_AllocLocalEntity(); - re = &le->refEntity; - - velocity[0] = 60 + 60 * crandom(); - if ( i == 0 ) { - velocity[1] = 40 + 10 * crandom(); - } else { - velocity[1] = -40 + 10 * crandom(); - } - velocity[2] = 100 + 50 * crandom(); - - le->leType = LE_FRAGMENT; - le->startTime = cg.time; - le->endTime = le->startTime + cg_brassTime.integer*3 + cg_brassTime.integer * random(); - - le->pos.trType = TR_GRAVITY; - le->pos.trTime = cg.time; - - AnglesToAxis( cent->lerpAngles, v ); - - offset[0] = 8; - offset[1] = 0; - offset[2] = 24; - - xoffset[0] = offset[0] * v[0][0] + offset[1] * v[1][0] + offset[2] * v[2][0]; - xoffset[1] = offset[0] * v[0][1] + offset[1] * v[1][1] + offset[2] * v[2][1]; - xoffset[2] = offset[0] * v[0][2] + offset[1] * v[1][2] + offset[2] * v[2][2]; - VectorAdd( cent->lerpOrigin, xoffset, re->origin ); - VectorCopy( re->origin, le->pos.trBase ); - if ( CG_PointContents( re->origin, -1 ) & CONTENTS_WATER ) { - waterScale = 0.10f; - } - - xvelocity[0] = velocity[0] * v[0][0] + velocity[1] * v[1][0] + velocity[2] * v[2][0]; - xvelocity[1] = velocity[0] * v[0][1] + velocity[1] * v[1][1] + velocity[2] * v[2][1]; - xvelocity[2] = velocity[0] * v[0][2] + velocity[1] * v[1][2] + velocity[2] * v[2][2]; - VectorScale( xvelocity, waterScale, le->pos.trDelta ); - - AxisCopy( axisDefault, re->axis ); - - re->hModel = cgs.media.shotgunBrassModel; - le->bounceFactor = 0.3f; - - le->angles.trType = TR_LINEAR; - le->angles.trTime = cg.time; - le->angles.trBase[0] = rand()&31; - le->angles.trBase[1] = rand()&31; - le->angles.trBase[2] = rand()&31; - le->angles.trDelta[0] = 1; - le->angles.trDelta[1] = 0.5; - le->angles.trDelta[2] = 0; - - le->leFlags = LEF_TUMBLE; - le->leBounceSoundType = LEBS_BRASS; - le->leMarkType = LEMT_NONE; - } -} - - -#ifdef MISSIONPACK -/* -========================== -CG_NailgunEjectBrass -========================== -*/ -static void CG_NailgunEjectBrass( centity_t *cent ) { - localEntity_t *smoke; - vec3_t origin; - vec3_t v[3]; - vec3_t offset; - vec3_t xoffset; - vec3_t up; - - AnglesToAxis( cent->lerpAngles, v ); - - offset[0] = 0; - offset[1] = -12; - offset[2] = 24; - - xoffset[0] = offset[0] * v[0][0] + offset[1] * v[1][0] + offset[2] * v[2][0]; - xoffset[1] = offset[0] * v[0][1] + offset[1] * v[1][1] + offset[2] * v[2][1]; - xoffset[2] = offset[0] * v[0][2] + offset[1] * v[1][2] + offset[2] * v[2][2]; - VectorAdd( cent->lerpOrigin, xoffset, origin ); - - VectorSet( up, 0, 0, 64 ); - - smoke = CG_SmokePuff( origin, up, 32, 1, 1, 1, 0.33f, 700, cg.time, 0, 0, cgs.media.smokePuffShader ); - // use the optimized local entity add - smoke->leType = LE_SCALE_FADE; -} -#endif - - -/* -========================== -CG_RailTrail -========================== -*/ -void CG_RailTrail( clientInfo_t *ci, vec3_t start, vec3_t end ) { - localEntity_t *le; - refEntity_t *re; - - // - // rings - // - le = CG_AllocLocalEntity(); - re = &le->refEntity; - - le->leType = LE_FADE_RGB; - le->startTime = cg.time; - le->endTime = cg.time + cg_railTrailTime.value; - le->lifeRate = 1.0 / ( le->endTime - le->startTime ); - - re->shaderTime = cg.time / 1000.0f; - re->reType = RT_RAIL_RINGS; - re->customShader = cgs.media.railRingsShader; - - VectorCopy( start, re->origin ); - VectorCopy( end, re->oldorigin ); - - // nudge down a bit so it isn't exactly in center - re->origin[2] -= 8; - re->oldorigin[2] -= 8; - - le->color[0] = ci->color[0] * 0.75; - le->color[1] = ci->color[1] * 0.75; - le->color[2] = ci->color[2] * 0.75; - le->color[3] = 1.0f; - - AxisClear( re->axis ); - - // - // core - // - le = CG_AllocLocalEntity(); - re = &le->refEntity; - - le->leType = LE_FADE_RGB; - le->startTime = cg.time; - le->endTime = cg.time + cg_railTrailTime.value; - le->lifeRate = 1.0 / ( le->endTime - le->startTime ); - - re->shaderTime = cg.time / 1000.0f; - re->reType = RT_RAIL_CORE; - re->customShader = cgs.media.railCoreShader; - - VectorCopy( start, re->origin ); - VectorCopy( end, re->oldorigin ); - - // nudge down a bit so it isn't exactly in center - re->origin[2] -= 8; - re->oldorigin[2] -= 8; - - le->color[0] = ci->color[0] * 0.75; - le->color[1] = ci->color[1] * 0.75; - le->color[2] = ci->color[2] * 0.75; - le->color[3] = 1.0f; - - AxisClear( re->axis ); -} - -/* -========================== -CG_RocketTrail -========================== -*/ -static void CG_RocketTrail( centity_t *ent, const weaponInfo_t *wi ) { - int step; - vec3_t origin, lastPos; - int t; - int startTime, contents; - int lastContents; - entityState_t *es; - vec3_t up; - localEntity_t *smoke; - - up[0] = 0; - up[1] = 0; - up[2] = 0; - - step = 50; - - es = &ent->currentState; - startTime = ent->trailTime; - t = step * ( (startTime + step) / step ); - - BG_EvaluateTrajectory( &es->pos, cg.time, origin ); - contents = CG_PointContents( origin, -1 ); - - // if object (e.g. grenade) is stationary, don't toss up smoke - if ( es->pos.trType == TR_STATIONARY ) { - ent->trailTime = cg.time; - return; - } - - BG_EvaluateTrajectory( &es->pos, ent->trailTime, lastPos ); - lastContents = CG_PointContents( lastPos, -1 ); - - ent->trailTime = cg.time; - - if ( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ) { - if ( contents & lastContents & CONTENTS_WATER ) { - CG_BubbleTrail( lastPos, origin, 8 ); - } - return; - } - - for ( ; t <= ent->trailTime ; t += step ) { - BG_EvaluateTrajectory( &es->pos, t, lastPos ); - - smoke = CG_SmokePuff( lastPos, up, - wi->trailRadius, - 1, 1, 1, 0.33f, - wi->wiTrailTime, - t, - 0, - 0, - cgs.media.smokePuffShader ); - // use the optimized local entity add - smoke->leType = LE_SCALE_FADE; - } - -} - -#ifdef MISSIONPACK -/* -========================== -CG_NailTrail -========================== -*/ -static void CG_NailTrail( centity_t *ent, const weaponInfo_t *wi ) { - int step; - vec3_t origin, lastPos; - int t; - int startTime, contents; - int lastContents; - entityState_t *es; - vec3_t up; - localEntity_t *smoke; - - up[0] = 0; - up[1] = 0; - up[2] = 0; - - step = 50; - - es = &ent->currentState; - startTime = ent->trailTime; - t = step * ( (startTime + step) / step ); - - BG_EvaluateTrajectory( &es->pos, cg.time, origin ); - contents = CG_PointContents( origin, -1 ); - - // if object (e.g. grenade) is stationary, don't toss up smoke - if ( es->pos.trType == TR_STATIONARY ) { - ent->trailTime = cg.time; - return; - } - - BG_EvaluateTrajectory( &es->pos, ent->trailTime, lastPos ); - lastContents = CG_PointContents( lastPos, -1 ); - - ent->trailTime = cg.time; - - if ( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ) { - if ( contents & lastContents & CONTENTS_WATER ) { - CG_BubbleTrail( lastPos, origin, 8 ); - } - return; - } - - for ( ; t <= ent->trailTime ; t += step ) { - BG_EvaluateTrajectory( &es->pos, t, lastPos ); - - smoke = CG_SmokePuff( lastPos, up, - wi->trailRadius, - 1, 1, 1, 0.33f, - wi->wiTrailTime, - t, - 0, - 0, - cgs.media.nailPuffShader ); - // use the optimized local entity add - smoke->leType = LE_SCALE_FADE; - } - -} -#endif - -/* -========================== -CG_GrappleTrail -========================== -*/ -void CG_GrappleTrail( centity_t *ent, const weaponInfo_t *wi ) { - vec3_t origin; - entityState_t *es; - vec3_t forward, up; - refEntity_t beam; - - es = &ent->currentState; - - BG_EvaluateTrajectory( &es->pos, cg.time, origin ); - ent->trailTime = cg.time; - - memset( &beam, 0, sizeof( beam ) ); - //FIXME adjust for muzzle position - VectorCopy ( cg_entities[ ent->currentState.otherEntityNum ].lerpOrigin, beam.origin ); - beam.origin[2] += 26; - AngleVectors( cg_entities[ ent->currentState.otherEntityNum ].lerpAngles, forward, NULL, up ); - VectorMA( beam.origin, -6, up, beam.origin ); - VectorCopy( origin, beam.oldorigin ); - - if (Distance( beam.origin, beam.oldorigin ) < 64 ) - return; // Don't draw if close - - beam.reType = RT_LIGHTNING; - beam.customShader = cgs.media.lightningShader; - - AxisClear( beam.axis ); - beam.shaderRGBA[0] = 0xff; - beam.shaderRGBA[1] = 0xff; - beam.shaderRGBA[2] = 0xff; - beam.shaderRGBA[3] = 0xff; - trap_R_AddRefEntityToScene( &beam ); -} - -/* -========================== -CG_GrenadeTrail -========================== -*/ -static void CG_GrenadeTrail( centity_t *ent, const weaponInfo_t *wi ) { - CG_RocketTrail( ent, wi ); -} - - -/* -================= -CG_RegisterWeapon - -The server says this item is used on this level -================= -*/ -void CG_RegisterWeapon( int weaponNum ) { - weaponInfo_t *weaponInfo; - gitem_t *item, *ammo; - char path[MAX_QPATH]; - vec3_t mins, maxs; - int i; - - weaponInfo = &cg_weapons[weaponNum]; - - if ( weaponNum == 0 ) { - return; - } - - if ( weaponInfo->registered ) { - return; - } - - memset( weaponInfo, 0, sizeof( *weaponInfo ) ); - weaponInfo->registered = qtrue; - - for ( item = bg_itemlist + 1 ; item->classname ; item++ ) { - if ( item->giType == IT_WEAPON && item->giTag == weaponNum ) { - weaponInfo->item = item; - break; - } - } - if ( !item->classname ) { - CG_Error( "Couldn't find weapon %i", weaponNum ); - } - CG_RegisterItemVisuals( item - bg_itemlist ); - - // load cmodel before model so filecache works - weaponInfo->weaponModel = trap_R_RegisterModel( item->world_model[0] ); - - // calc midpoint for rotation - trap_R_ModelBounds( weaponInfo->weaponModel, mins, maxs ); - for ( i = 0 ; i < 3 ; i++ ) { - weaponInfo->weaponMidpoint[i] = mins[i] + 0.5 * ( maxs[i] - mins[i] ); - } - - weaponInfo->weaponIcon = trap_R_RegisterShader( item->icon ); - weaponInfo->ammoIcon = trap_R_RegisterShader( item->icon ); - - for ( ammo = bg_itemlist + 1 ; ammo->classname ; ammo++ ) { - if ( ammo->giType == IT_AMMO && ammo->giTag == weaponNum ) { - break; - } - } - if ( ammo->classname && ammo->world_model[0] ) { - weaponInfo->ammoModel = trap_R_RegisterModel( ammo->world_model[0] ); - } - - strcpy( path, item->world_model[0] ); - COM_StripExtension( path, path ); - strcat( path, "_flash.md3" ); - weaponInfo->flashModel = trap_R_RegisterModel( path ); - - strcpy( path, item->world_model[0] ); - COM_StripExtension( path, path ); - strcat( path, "_barrel.md3" ); - weaponInfo->barrelModel = trap_R_RegisterModel( path ); - - strcpy( path, item->world_model[0] ); - COM_StripExtension( path, path ); - strcat( path, "_hand.md3" ); - weaponInfo->handsModel = trap_R_RegisterModel( path ); - - if ( !weaponInfo->handsModel ) { - weaponInfo->handsModel = trap_R_RegisterModel( "models/weapons2/shotgun/shotgun_hand.md3" ); - } - - weaponInfo->loopFireSound = qfalse; - - switch ( weaponNum ) { -/*Blaze: Dont need this - case WP_GAUNTLET: - MAKERGB( weaponInfo->flashDlightColor, 0.6f, 0.6f, 1.0f ); - weaponInfo->firingSound = trap_S_RegisterSound( "sound/weapons/melee/fstrun.wav", qfalse ); - weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/melee/fstatck.wav", qfalse ); - break; - - case WP_LIGHTNING: - MAKERGB( weaponInfo->flashDlightColor, 0.6f, 0.6f, 1.0f ); - weaponInfo->readySound = trap_S_RegisterSound( "sound/weapons/melee/fsthum.wav", qfalse ); - weaponInfo->firingSound = trap_S_RegisterSound( "sound/weapons/lightning/lg_hum.wav", qfalse ); - - weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/lightning/lg_fire.wav", qfalse ); - cgs.media.lightningShader = trap_R_RegisterShader( "lightningBolt"); - cgs.media.lightningExplosionModel = trap_R_RegisterModel( "models/weaphits/crackle.md3" ); - cgs.media.sfx_lghit1 = trap_S_RegisterSound( "sound/weapons/lightning/lg_hit.wav", qfalse ); - cgs.media.sfx_lghit2 = trap_S_RegisterSound( "sound/weapons/lightning/lg_hit2.wav", qfalse ); - cgs.media.sfx_lghit3 = trap_S_RegisterSound( "sound/weapons/lightning/lg_hit3.wav", qfalse ); - - break; - - case WP_GRAPPLING_HOOK: - MAKERGB( weaponInfo->flashDlightColor, 0.6f, 0.6f, 1.0f ); - weaponInfo->missileModel = trap_R_RegisterModel( "models/ammo/rocket/rocket.md3" ); - weaponInfo->missileTrailFunc = CG_GrappleTrail; - weaponInfo->missileDlight = 200; - weaponInfo->wiTrailTime = 2000; - weaponInfo->trailRadius = 64; - MAKERGB( weaponInfo->missileDlightColor, 1, 0.75f, 0 ); - weaponInfo->readySound = trap_S_RegisterSound( "sound/weapons/melee/fsthum.wav", qfalse ); - weaponInfo->firingSound = trap_S_RegisterSound( "sound/weapons/melee/fstrun.wav", qfalse ); - break; - -#ifdef MISSIONPACK - case WP_CHAINGUN: - weaponInfo->firingSound = trap_S_RegisterSound( "sound/weapons/vulcan/wvulfire.wav", qfalse ); - weaponInfo->loopFireSound = qtrue; - MAKERGB( weaponInfo->flashDlightColor, 1, 1, 0 ); - weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/vulcan/vulcanf1b.wav", qfalse ); - weaponInfo->flashSound[1] = trap_S_RegisterSound( "sound/weapons/vulcan/vulcanf2b.wav", qfalse ); - weaponInfo->flashSound[2] = trap_S_RegisterSound( "sound/weapons/vulcan/vulcanf3b.wav", qfalse ); - weaponInfo->flashSound[3] = trap_S_RegisterSound( "sound/weapons/vulcan/vulcanf4b.wav", qfalse ); - weaponInfo->ejectBrassFunc = CG_MachineGunEjectBrass; - cgs.media.bulletExplosionShader = trap_R_RegisterShader( "bulletExplosion" ); - break; -#endif - - case WP_MACHINEGUN: - MAKERGB( weaponInfo->flashDlightColor, 1, 1, 0 ); - weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/machinegun/machgf1b.wav", qfalse ); - weaponInfo->flashSound[1] = trap_S_RegisterSound( "sound/weapons/machinegun/machgf2b.wav", qfalse ); - weaponInfo->flashSound[2] = trap_S_RegisterSound( "sound/weapons/machinegun/machgf3b.wav", qfalse ); - weaponInfo->flashSound[3] = trap_S_RegisterSound( "sound/weapons/machinegun/machgf4b.wav", qfalse ); - weaponInfo->ejectBrassFunc = CG_MachineGunEjectBrass; - cgs.media.bulletExplosionShader = trap_R_RegisterShader( "bulletExplosion" ); - break; - - case WP_SHOTGUN: - MAKERGB( weaponInfo->flashDlightColor, 1, 1, 0 ); - weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/shotgun/sshotf1b.wav", qfalse ); - weaponInfo->ejectBrassFunc = CG_ShotgunEjectBrass; - break; - - case WP_ROCKET_LAUNCHER: - weaponInfo->missileModel = trap_R_RegisterModel( "models/ammo/rocket/rocket.md3" ); - weaponInfo->missileSound = trap_S_RegisterSound( "sound/weapons/rocket/rockfly.wav", qfalse ); - weaponInfo->missileTrailFunc = CG_RocketTrail; - weaponInfo->missileDlight = 200; - weaponInfo->wiTrailTime = 2000; - weaponInfo->trailRadius = 64; - - MAKERGB( weaponInfo->missileDlightColor, 1, 0.75f, 0 ); - MAKERGB( weaponInfo->flashDlightColor, 1, 0.75f, 0 ); - - weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/rocket/rocklf1a.wav", qfalse ); - cgs.media.rocketExplosionShader = trap_R_RegisterShader( "rocketExplosion" ); - break; - -#ifdef MISSIONPACK - case WP_PROX_LAUNCHER: - weaponInfo->missileModel = trap_R_RegisterModel( "models/weaphits/proxmine.md3" ); - weaponInfo->missileTrailFunc = CG_GrenadeTrail; - weaponInfo->wiTrailTime = 700; - weaponInfo->trailRadius = 32; - MAKERGB( weaponInfo->flashDlightColor, 1, 0.70f, 0 ); - weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/proxmine/wstbfire.wav", qfalse ); - cgs.media.grenadeExplosionShader = trap_R_RegisterShader( "grenadeExplosion" ); - break; -#endif - - case WP_GRENADE_LAUNCHER: - weaponInfo->missileModel = trap_R_RegisterModel( "models/ammo/grenade1.md3" ); - weaponInfo->missileTrailFunc = CG_GrenadeTrail; - weaponInfo->wiTrailTime = 700; - weaponInfo->trailRadius = 32; - MAKERGB( weaponInfo->flashDlightColor, 1, 0.70f, 0 ); - weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/grenade/grenlf1a.wav", qfalse ); - cgs.media.grenadeExplosionShader = trap_R_RegisterShader( "grenadeExplosion" ); - break; - -#ifdef MISSIONPACK - case WP_NAILGUN: - weaponInfo->ejectBrassFunc = CG_NailgunEjectBrass; - weaponInfo->missileTrailFunc = CG_NailTrail; - weaponInfo->missileSound = trap_S_RegisterSound( "sound/weapons/nailgun/wnalflit.wav", qfalse ); - weaponInfo->trailRadius = 16; - weaponInfo->wiTrailTime = 250; - weaponInfo->missileModel = trap_R_RegisterModel( "models/weaphits/nail.md3" ); - MAKERGB( weaponInfo->flashDlightColor, 1, 0.75f, 0 ); - weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/nailgun/wnalfire.wav", qfalse ); - break; -#endif - - case WP_PLASMAGUN: - weaponInfo->missileSound = trap_S_RegisterSound( "sound/weapons/plasma/lasfly.wav", qfalse ); - MAKERGB( weaponInfo->flashDlightColor, 0.6f, 0.6f, 1.0f ); - weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/plasma/hyprbf1a.wav", qfalse ); - cgs.media.plasmaExplosionShader = trap_R_RegisterShader( "plasmaExplosion" ); - break; - - case WP_RAILGUN: - weaponInfo->readySound = trap_S_RegisterSound( "sound/weapons/railgun/rg_hum.wav", qfalse ); - MAKERGB( weaponInfo->flashDlightColor, 1, 0.5f, 0 ); - weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/railgun/railgf1a.wav", qfalse ); - cgs.media.railExplosionShader = trap_R_RegisterShader( "railExplosion" ); - cgs.media.railRingsShader = trap_R_RegisterShader( "railDisc" ); - cgs.media.railCoreShader = trap_R_RegisterShader( "railCore" ); - break; - - case WP_BFG: - weaponInfo->readySound = trap_S_RegisterSound( "sound/weapons/bfg/bfg_hum.wav", qfalse ); - MAKERGB( weaponInfo->flashDlightColor, 1, 0.7f, 1 ); - weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/bfg/bfg_fire.wav", qfalse ); - cgs.media.bfgExplosionShader = trap_R_RegisterShader( "bfgExplosion" ); - weaponInfo->missileModel = trap_R_RegisterModel( "models/weaphits/bfg.md3" ); - weaponInfo->missileSound = trap_S_RegisterSound( "sound/weapons/rocket/rockfly.wav", qfalse ); - break; -*/ -//Blaze: Reaction Pistol - case WP_PISTOL: - MAKERGB( weaponInfo->flashDlightColor, 1, 1, 0 ); - weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/mk23/mk23fire.wav", qfalse ); - weaponInfo->ejectBrassFunc = CG_MachineGunEjectBrass; - cgs.media.bulletExplosionShader = trap_R_RegisterShader( "bulletExplosion" ); - break; - case WP_KNIFE: - weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/knife/slash.wav", qfalse ); - break; - case WP_M4: - weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/m4/m4fire.wav", qfalse ); - weaponInfo->ejectBrassFunc = CG_MachineGunEjectBrass; - cgs.media.bulletExplosionShader = trap_R_RegisterShader( "bulletExplosion" ); - break; - case WP_SSG3000: - weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/ssg3000/ssgfire.wav", qfalse ); - weaponInfo->ejectBrassFunc = CG_MachineGunEjectBrass; - cgs.media.bulletExplosionShader = trap_R_RegisterShader( "bulletExplosion" ); - break; - case WP_MP5: - weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/mp5/mp5fire1.wav", qfalse ); - weaponInfo->ejectBrassFunc = CG_MachineGunEjectBrass; - cgs.media.bulletExplosionShader = trap_R_RegisterShader( "bulletExplosion" ); - break; - case WP_HANDCANNON: - weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/handcannon/cannon_fire.wav", qfalse ); - weaponInfo->ejectBrassFunc = CG_ShotgunEjectBrass; - cgs.media.bulletExplosionShader = trap_R_RegisterShader( "bulletExplosion" ); - break; - case WP_M3: - MAKERGB( weaponInfo->flashDlightColor, 1, 1, 0 ); - weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/shotgun/sshotf1b.wav", qfalse ); - weaponInfo->ejectBrassFunc = CG_ShotgunEjectBrass; - break; - - case WP_AKIMBO: - weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/mk23/mk23fire.wav", qfalse ); - weaponInfo->flashSound[1] = trap_S_RegisterSound( "sound/weapons/mk23/mk23fire.wav", qfalse ); - weaponInfo->ejectBrassFunc = CG_MachineGunEjectBrass; - cgs.media.bulletExplosionShader = trap_R_RegisterShader( "bulletExplosion" ); - break; - case WP_GRENADE: - //Blaze: Need to work on this more - //weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/handcannon/cannon_fire.wav" ); - //weaponInfo->ejectBrassFunc = CG_MachineGunEjectBrass; - //cgs.media.bulletExplosionShader = trap_R_RegisterShader( "bulletExplosion" ); - break; - - default: - MAKERGB( weaponInfo->flashDlightColor, 1, 1, 1 ); - weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/rocket/rocklf1a.wav", qfalse ); - break; - } -} - -/* -================= -CG_RegisterItemVisuals - -The server says this item is used on this level -================= -*/ -void CG_RegisterItemVisuals( int itemNum ) { - itemInfo_t *itemInfo; - gitem_t *item; - - itemInfo = &cg_items[ itemNum ]; - if ( itemInfo->registered ) { - return; - } - - item = &bg_itemlist[ itemNum ]; - - memset( itemInfo, 0, sizeof( &itemInfo ) ); - itemInfo->registered = qtrue; - - itemInfo->models[0] = trap_R_RegisterModel( item->world_model[0] ); - - itemInfo->icon = trap_R_RegisterShader( item->icon ); - - if ( item->giType == IT_WEAPON ) { - CG_RegisterWeapon( item->giTag ); - } - - // - // powerups have an accompanying ring or sphere - // - if ( item->giType == IT_POWERUP || item->giType == IT_HEALTH || - item->giType == IT_ARMOR || item->giType == IT_HOLDABLE ) { - if ( item->world_model[1] ) { - itemInfo->models[1] = trap_R_RegisterModel( item->world_model[1] ); - } - } -} - - -/* -======================================================================================== - -VIEW WEAPON - -======================================================================================== -*/ - -/* -================= -CG_MapTorsoToWeaponFrame - -================= -*/ -static int CG_MapTorsoToWeaponFrame( clientInfo_t *ci, int frame ) { - - // change weapon - if ( frame >= ci->animations[TORSO_DROP].firstFrame - && frame < ci->animations[TORSO_DROP].firstFrame + 9 ) { - return frame - ci->animations[TORSO_DROP].firstFrame + 6; - } - - // stand attack - if ( frame >= ci->animations[TORSO_ATTACK].firstFrame - && frame < ci->animations[TORSO_ATTACK].firstFrame + 6 ) { - return 1 + frame - ci->animations[TORSO_ATTACK].firstFrame; - } - - // stand attack 2 - if ( frame >= ci->animations[TORSO_ATTACK2].firstFrame - && frame < ci->animations[TORSO_ATTACK2].firstFrame + 6 ) { - return 1 + frame - ci->animations[TORSO_ATTACK2].firstFrame; - } - - return 0; -} - - -/* -============== -CG_CalculateWeaponPosition -============== -*/ -static void CG_CalculateWeaponPosition( vec3_t origin, vec3_t angles ) { - float scale; - int delta; - float fracsin; - - VectorCopy( cg.refdef.vieworg, origin ); - VectorCopy( cg.refdefViewAngles, angles ); - - // on odd legs, invert some angles - if ( cg.bobcycle & 1 ) { - scale = -cg.xyspeed; - } else { - scale = cg.xyspeed; - } - - // gun angles from bobbing - angles[ROLL] += scale * cg.bobfracsin * 0.005; - angles[YAW] += scale * cg.bobfracsin * 0.01; - angles[PITCH] += cg.xyspeed * cg.bobfracsin * 0.005; - - // drop the weapon when landing - delta = cg.time - cg.landTime; - if ( delta < LAND_DEFLECT_TIME ) { - origin[2] += cg.landChange*0.25 * delta / LAND_DEFLECT_TIME; - } else if ( delta < LAND_DEFLECT_TIME + LAND_RETURN_TIME ) { - origin[2] += cg.landChange*0.25 * - (LAND_DEFLECT_TIME + LAND_RETURN_TIME - delta) / LAND_RETURN_TIME; - } - -#if 0 - // drop the weapon when stair climbing - delta = cg.time - cg.stepTime; - if ( delta < STEP_TIME/2 ) { - origin[2] -= cg.stepChange*0.25 * delta / (STEP_TIME/2); - } else if ( delta < STEP_TIME ) { - origin[2] -= cg.stepChange*0.25 * (STEP_TIME - delta) / (STEP_TIME/2); - } -#endif - - // idle drift - scale = cg.xyspeed + 40; - fracsin = sin( cg.time * 0.001 ); - angles[ROLL] += scale * fracsin * 0.01; - angles[YAW] += scale * fracsin * 0.01; - angles[PITCH] += scale * fracsin * 0.01; -} - - -/* -=============== -CG_LightningBolt - -Origin will be the exact tag point, which is slightly -different than the muzzle point used for determining hits. -The cent should be the non-predicted cent if it is from the player, -so the endpoint will reflect the simulated strike (lagging the predicted -angle) -=============== -*/ -static void CG_LightningBolt( centity_t *cent, vec3_t origin ) { - trace_t trace; - refEntity_t beam; - vec3_t forward; - vec3_t muzzlePoint, endPoint; -//Blaze: LG No longer exists -// if ( cent->currentState.weapon != WP_LIGHTNING ) { -// return; -// } - - memset( &beam, 0, sizeof( beam ) ); - - // find muzzle point for this frame - VectorCopy( cent->lerpOrigin, muzzlePoint ); - AngleVectors( cent->lerpAngles, forward, NULL, NULL ); - - // FIXME: crouch - muzzlePoint[2] += DEFAULT_VIEWHEIGHT; - - VectorMA( muzzlePoint, 14, forward, muzzlePoint ); - - // project forward by the lightning range - VectorMA( muzzlePoint, LIGHTNING_RANGE, forward, endPoint ); - - // see if it hit a wall - CG_Trace( &trace, muzzlePoint, vec3_origin, vec3_origin, endPoint, - cent->currentState.number, MASK_SHOT ); - - // this is the endpoint - VectorCopy( trace.endpos, beam.oldorigin ); - - // use the provided origin, even though it may be slightly - // different than the muzzle origin - VectorCopy( origin, beam.origin ); - - beam.reType = RT_LIGHTNING; - beam.customShader = cgs.media.lightningShader; - trap_R_AddRefEntityToScene( &beam ); - - // add the impact flare if it hit something - if ( trace.fraction < 1.0 ) { - vec3_t angles; - vec3_t dir; - - VectorSubtract( beam.oldorigin, beam.origin, dir ); - VectorNormalize( dir ); - - memset( &beam, 0, sizeof( beam ) ); - beam.hModel = cgs.media.lightningExplosionModel; - - VectorMA( trace.endpos, -16, dir, beam.origin ); - - // make a random orientation - angles[0] = rand() % 360; - angles[1] = rand() % 360; - angles[2] = rand() % 360; - AnglesToAxis( angles, beam.axis ); - trap_R_AddRefEntityToScene( &beam ); - } -} - - -/* -=============== -CG_SpawnRailTrail - -Origin will be the exact tag point, which is slightly -different than the muzzle point used for determining hits. -=============== -*/ -static void CG_SpawnRailTrail( centity_t *cent, vec3_t origin ) { - clientInfo_t *ci; - - //Blaze: No more rail gun - //if ( cent->currentState.weapon != WP_RAILGUN ) { - // return; - //} - if ( !cent->pe.railgunFlash ) { - return; - } - cent->pe.railgunFlash = qtrue; - ci = &cgs.clientinfo[ cent->currentState.clientNum ]; - //Blaze: No Rail Trail - //CG_RailTrail( ci, origin, cent->pe.railgunImpact ); -} - - -/* -====================== -CG_MachinegunSpinAngle -====================== -*/ -#define SPIN_SPEED 0.9 -#define COAST_TIME 1000 -static float CG_MachinegunSpinAngle( centity_t *cent ) { - int delta; - float angle; - float speed; - - delta = cg.time - cent->pe.barrelTime; - if ( cent->pe.barrelSpinning ) { - angle = cent->pe.barrelAngle + delta * SPIN_SPEED; - } else { - if ( delta > COAST_TIME ) { - delta = COAST_TIME; - } - - speed = 0.5 * ( SPIN_SPEED + (float)( COAST_TIME - delta ) / COAST_TIME ); - angle = cent->pe.barrelAngle + delta * speed; - } - - if ( cent->pe.barrelSpinning == !(cent->currentState.eFlags & EF_FIRING) ) { - cent->pe.barrelTime = cg.time; - cent->pe.barrelAngle = AngleMod( angle ); - cent->pe.barrelSpinning = !!(cent->currentState.eFlags & EF_FIRING); -#ifdef MISSIONPACK - if ( cent->currentState.weapon == WP_CHAINGUN && !cent->pe.barrelSpinning ) { - trap_S_StartSound( NULL, cent->currentState.number, CHAN_WEAPON, trap_S_RegisterSound( "sound/weapons/vulcan/wvulwind.wav", qfalse ) ); - } -#endif - } - - return angle; -} - - -/* -======================== -CG_AddWeaponWithPowerups -======================== -*/ -static void CG_AddWeaponWithPowerups( refEntity_t *gun, int powerups ) { - // add powerup effects - if ( powerups & ( 1 << PW_INVIS ) ) { - gun->customShader = cgs.media.invisShader; - trap_R_AddRefEntityToScene( gun ); - } else { - trap_R_AddRefEntityToScene( gun ); - - if ( powerups & ( 1 << PW_BATTLESUIT ) ) { - gun->customShader = cgs.media.battleWeaponShader; - trap_R_AddRefEntityToScene( gun ); - } - if ( powerups & ( 1 << PW_QUAD ) ) { - gun->customShader = cgs.media.quadWeaponShader; - trap_R_AddRefEntityToScene( gun ); - } - } -} - - -/* -============= -CG_AddPlayerWeapon - -Used for both the view weapon (ps is valid) and the world modelother character models (ps is NULL) -The main player will have this called for BOTH cases, so effects like light and -sound should only be done on the world model case. -============= -*/ -void CG_AddPlayerWeapon( refEntity_t *parent, playerState_t *ps, centity_t *cent, int team ) { - refEntity_t gun; -//Blaze: Can remove this because no more spinning barrel -// refEntity_t barrel; - refEntity_t flash; - vec3_t angles; - float frac; - weapon_t weaponNum; - weaponInfo_t *weapon; - centity_t *nonPredictedCent; -// int col; - - weaponNum = cent->currentState.weapon; - - CG_RegisterWeapon( weaponNum ); - weapon = &cg_weapons[weaponNum]; - - // add the weapon - memset( &gun, 0, sizeof( gun ) ); - VectorCopy( parent->lightingOrigin, gun.lightingOrigin ); - gun.shadowPlane = parent->shadowPlane; - gun.renderfx = parent->renderfx; - - // set custom shading for railgun refire rate - //if ( ps ) { - //Blaze: No Railgun - //if ( cg.predictedPlayerState.weapon == WP_RAILGUN - // && cg.predictedPlayerState.weaponstate == WEAPON_FIRING ) { - // float f; - - // f = (float)cg.predictedPlayerState.weaponTime / 1500; - // gun.shaderRGBA[1] = 0; - // gun.shaderRGBA[0] = - // gun.shaderRGBA[2] = 255 * ( 1.0 - f ); - //} else { - gun.shaderRGBA[0] = 255; - gun.shaderRGBA[1] = 255; - gun.shaderRGBA[2] = 255; - gun.shaderRGBA[3] = 255; - //} - //} - if (ps == NULL) - { - switch (weaponNum)//Blaze: Used to make the third person weapon models different then 1st person - { - case 0: - //gun.hModel = trap_R_RegisterModel( "models/weapons2/mk23/3rd_mk23.md3" ); - //No Case zero - break; - case 1: - gun.hModel = trap_R_RegisterModel("models/weapons2/knife/3rd_knife.md3"); - break; - case 2: - gun.hModel = trap_R_RegisterModel("models/weapons2/mk23/3rd_mk23.md3"); - break; - case 3: - gun.hModel = trap_R_RegisterModel("models/weapons2/m4/3rd_m4.md3"); - break; - case 4: - gun.hModel = trap_R_RegisterModel("models/weapons2/ssg3000/3rd_ssg3000.md3"); - break; - case 5: - gun.hModel = trap_R_RegisterModel("models/weapons2/mp5/3rd_mp5.md3"); - break; - case 6: - gun.hModel = trap_R_RegisterModel("models/weapons2/m3/3rd_m3.md3"); - break; - case 7: - gun.hModel = trap_R_RegisterModel("models/weapons2/handcannon/3rd_handcannon.md3"); - break; - case 8: - gun.hModel = trap_R_RegisterModel("models/weapons2/mk23/3rd_mk23.md3"); - break; - case 9: - gun.hModel = trap_R_RegisterModel("models/weapons2/grenade/3rd_grenade.md3"); - break; - } - - } - else - { - gun.hModel = weapon->weaponModel; - } - - if (!gun.hModel) { - return; - } - - if ( !ps ) { - // add weapon ready sound - cent->pe.lightningFiring = qfalse; - if ( ( cent->currentState.eFlags & EF_FIRING ) && weapon->firingSound ) { - // lightning gun and guantlet make a different sound when fire is held down - trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, weapon->firingSound ); - cent->pe.lightningFiring = qtrue; - } else if ( weapon->readySound ) { - trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, weapon->readySound ); - } - } - if (ps == NULL) - { - /* resizing code - msec = cg.time - cent->miscTime; - if ( msec >= 0 && msec < ITEM_SCALEUP_TIME ) { - frac = (float)msec / ITEM_SCALEUP_TIME; - VectorScale( ent.axis[0], frac, ent.axis[0] ); - VectorScale( ent.axis[1], frac, ent.axis[1] ); - VectorScale( ent.axis[2], frac, ent.axis[2] ); - ent.nonNormalizedAxes = qtrue; - } else { - frac = 1.0; - } - */ - if (weaponNum == 4)//Blaze: Scale the Sniper Rifle down a bit - { - frac = 0.8f; - VectorScale(parent->axis[0], frac, parent->axis[0]); - //VectorScale(parent->axis[1], frac, parent->axis[1]); - //VectorScale(parent->axis[2], frac, parent->axis[2]); - } - - } - CG_PositionEntityOnTag( &gun, parent, parent->hModel, "tag_weapon"); - - CG_AddWeaponWithPowerups( &gun, cent->currentState.powerups ); - - // add the spinning barrel - //Blaze: No Spinning Barrel - /* - if ( weapon->barrelModel ) { - memset( &barrel, 0, sizeof( barrel ) ); - VectorCopy( parent->lightingOrigin, barrel.lightingOrigin ); - barrel.shadowPlane = parent->shadowPlane; - barrel.renderfx = parent->renderfx; - - barrel.hModel = weapon->barrelModel; - angles[YAW] = 0; - angles[PITCH] = 0; - angles[ROLL] = CG_MachinegunSpinAngle( cent ); - AnglesToAxis( angles, barrel.axis ); - - CG_PositionRotatedEntityOnTag( &barrel, &gun, weapon->weaponModel, "tag_barrel" ); - - CG_AddWeaponWithPowerups( &barrel, cent->currentState.powerups ); - }*/ - - // make sure we aren't looking at cg.predictedPlayerEntity for LG - nonPredictedCent = &cg_entities[cent->currentState.clientNum]; - - // if the index of the nonPredictedCent is not the same as the clientNum - // then this is a fake player (like on teh single player podiums), so - // go ahead and use the cent - if( ( nonPredictedCent - cg_entities ) != cent->currentState.clientNum ) { - nonPredictedCent = cent; - } - - // add the flash - //Blaze: no more of these - /* - if ( ( weaponNum == WP_LIGHTNING || weaponNum == WP_GAUNTLET || weaponNum == WP_GRAPPLING_HOOK ) - && ( nonPredictedCent->currentState.eFlags & EF_FIRING ) ) - { - // continuous flash - } else { - // impulse flash - if ( cg.time - cent->muzzleFlashTime > MUZZLE_FLASH_TIME && !cent->pe.railgunFlash ) { - return; - } - } - */ - - memset( &flash, 0, sizeof( flash ) ); - VectorCopy( parent->lightingOrigin, flash.lightingOrigin ); - flash.shadowPlane = parent->shadowPlane; - flash.renderfx = parent->renderfx; - - flash.hModel = weapon->flashModel; - if (!flash.hModel) { - return; - } - angles[YAW] = 0; - angles[PITCH] = 0; - angles[ROLL] = crandom() * 10; - AnglesToAxis( angles, flash.axis ); - - // colorize the railgun blast - //Blaze: No more railgun - /* - if ( weaponNum == WP_RAILGUN ) { - clientInfo_t *ci; - - ci = &cgs.clientinfo[ cent->currentState.clientNum ]; - flash.shaderRGBA[0] = 255 * ci->color[0]; - flash.shaderRGBA[1] = 255 * ci->color[1]; - flash.shaderRGBA[2] = 255 * ci->color[2]; - } - */ - //Blaze: No flash - //CG_PositionRotatedEntityOnTag( &flash, &gun, weapon->weaponModel, "tag_flash"); - //trap_R_AddRefEntityToScene( &flash ); - - if ( ps || cg.renderingThirdPerson || - cent->currentState.number != cg.predictedPlayerState.clientNum ) { - // add lightning bolt - //Blaze: No need for this - //CG_LightningBolt( nonPredictedCent, flash.origin ); - - // add rail trail - //Blaze: no need for this - //CG_SpawnRailTrail( cent, flash.origin ); -/* - if ( team == TEAM_RED ) { - col = 1; - } - else if ( team == TEAM_BLUE ) { - col = 2; - } - else { - col = 0; - } - - // make a dlight for the flash - if ( weapon->flashDlightColor[col][0] || weapon->flashDlightColor[col][1] || weapon->flashDlightColor[col][2] ) { - trap_R_AddLightToScene( flash.origin, 300 + (rand()&31), weapon->flashDlightColor[col][0], - weapon->flashDlightColor[col][1], weapon->flashDlightColor[col][2] ); - } -*/ - if ( weapon->flashDlightColor[0] || weapon->flashDlightColor[1] || weapon->flashDlightColor[2] ) { - trap_R_AddLightToScene( flash.origin, 300 + (rand()&31), weapon->flashDlightColor[0], - weapon->flashDlightColor[1], weapon->flashDlightColor[2] ); - } - } -} - -/* -============== -CG_AddViewWeapon - -Add the weapon, and flash for the player's view -============== -*/ -void CG_AddViewWeapon( playerState_t *ps ) { - refEntity_t hand; - centity_t *cent; - clientInfo_t *ci; - float fovOffset; - vec3_t angles; - weaponInfo_t *weapon; - //Blaze: Reaction vars for gun positions - float rxn_gunx, rxn_guny, rxn_gunz; - - - - if ( ps->persistant[PERS_TEAM] == TEAM_SPECTATOR ) { - return; - } - - if ( ps->pm_type == PM_INTERMISSION ) { - return; - } - - // no gun if in third person view - if ( cg.renderingThirdPerson ) { - return; - } - - // allow the gun to be completely removed - if ( !cg_drawGun.integer ) { -//Blaze: Removed these -// vec3_t origin; - -// if ( cg.predictedPlayerState.eFlags & EF_FIRING ) { - // special hack for lightning gun... -// VectorCopy( cg.refdef.vieworg, origin ); -// VectorMA( origin, -8, cg.refdef.viewaxis[2], origin ); -// CG_LightningBolt( &cg_entities[ps->clientNum], origin ); -// } - return; - } - - // don't draw if testing a gun model - if ( cg.testGun ) { - return; - } -//Blaze start: Reaction gun positioning - rxn_gunx = cg_gun_x.value; - rxn_guny = cg_gun_y.value; - rxn_gunz = cg_gun_z.value; - //Blaze: Gun xyz coords changes - switch(ps->weapon) - { - case WP_PISTOL: - rxn_gunx -= 4; - break; - case WP_M4: - rxn_gunx += 10; - break; - case WP_SSG3000: - rxn_gunx += 10; - break; - case WP_AKIMBO: - rxn_gunx += 10; - } - - if ((rxn_drawWeapon.integer > 1 ) && (rxn_drawWeapon.integer < 4 )) - { - rxn_guny = cg_gun_y.value + 4*(rxn_drawWeapon.integer-1); - } - //Blaze end: - - // drop gun lower at higher fov - if ( cg_fov.integer > 90 ) { - fovOffset = -0.2 * ( cg_fov.integer - 90 ); - } else { - fovOffset = 0; - } - - cent = &cg.predictedPlayerEntity; // &cg_entities[cg.snap->ps.clientNum]; - CG_RegisterWeapon( ps->weapon ); - weapon = &cg_weapons[ ps->weapon ]; - - memset (&hand, 0, sizeof(hand)); - - // set up gun position - CG_CalculateWeaponPosition( hand.origin, angles ); -//Blaze start: reaction gun positioning - VectorMA( hand.origin, rxn_gunx, cg.refdef.viewaxis[0], hand.origin ); - VectorMA( hand.origin, rxn_guny, cg.refdef.viewaxis[1], hand.origin ); - VectorMA( hand.origin, (rxn_gunz + fovOffset), cg.refdef.viewaxis[2], hand.origin ); -//Blaze end: - -//Blaze: Use above code instead -// VectorMA( hand.origin, cg_gun_x.value, cg.refdef.viewaxis[0], hand.origin ); -// VectorMA( hand.origin, cg_gun_y.value, cg.refdef.viewaxis[1], hand.origin ); -// VectorMA( hand.origin, (cg_gun_z.value+fovOffset), cg.refdef.viewaxis[2], hand.origin ); - - AnglesToAxis( angles, hand.axis ); - - // map torso animations to weapon animations - if ( cg_gun_frame.integer ) { - // development tool - hand.frame = hand.oldframe = cg_gun_frame.integer; - hand.backlerp = 0; - } else { - // get clientinfo for animation map - ci = &cgs.clientinfo[ cent->currentState.clientNum ]; - hand.frame = CG_MapTorsoToWeaponFrame( ci, cent->pe.torso.frame ); - hand.oldframe = CG_MapTorsoToWeaponFrame( ci, cent->pe.torso.oldFrame ); - hand.backlerp = cent->pe.torso.backlerp; - } - - hand.hModel = weapon->handsModel; - hand.renderfx = RF_DEPTHHACK | RF_FIRST_PERSON | RF_MINLIGHT; - - // add everything onto the hand - CG_AddPlayerWeapon( &hand, ps, &cg.predictedPlayerEntity, ps->persistant[PERS_TEAM] ); -} - -/* -============================================================================== - -WEAPON SELECTION - -============================================================================== -*/ - -/* -=================== -CG_DrawWeaponSelect -=================== -*/ -void CG_DrawWeaponSelect( void ) { - int i; - int bits; - int count; - int x, y, w; - char *name; - float *color; - - // don't display if dead - if ( cg.predictedPlayerState.stats[STAT_HEALTH] <= 0 ) { - return; - } - - color = CG_FadeColor( cg.weaponSelectTime, WEAPON_SELECT_TIME ); - if ( !color ) { - return; - } - trap_R_SetColor( color ); - - // showing weapon select clears pickup item display, but not the blend blob - cg.itemPickupTime = 0; - - // count the number of weapons owned - bits = cg.snap->ps.stats[ STAT_WEAPONS ]; - count = 0; - for ( i = 1 ; i < 16 ; i++ ) { - if ( bits & ( 1 << i ) ) { - count++; - } - } - - x = 320 - count * 20; - y = 380; - - for ( i = 1 ; i < 16 ; i++ ) { - if ( !( bits & ( 1 << i ) ) ) { - continue; - } - - CG_RegisterWeapon( i ); - - // draw weapon icon - CG_DrawPic( x, y, 32, 32, cg_weapons[i].weaponIcon ); - - // draw selection marker - if ( i == cg.weaponSelect ) { - CG_DrawPic( x-4, y-4, 40, 40, cgs.media.selectShader ); - } - - // no ammo cross on top - if ( !cg.snap->ps.ammo[ i ] ) { - CG_DrawPic( x, y, 32, 32, cgs.media.noammoShader ); - } - - x += 40; - } - - // draw the selected name - if ( cg_weapons[ cg.weaponSelect ].item ) { - name = cg_weapons[ cg.weaponSelect ].item->pickup_name; - if ( name ) { - w = CG_DrawStrlen( name ) * BIGCHAR_WIDTH; - x = ( SCREEN_WIDTH - w ) / 2; - CG_DrawBigStringColor(x, y - 22, name, color); - } - } - - trap_R_SetColor( NULL ); -} - - -/* -=============== -CG_WeaponSelectable -=============== -*/ -static qboolean CG_WeaponSelectable( int i ) { - //Blaze: Check the amount of clips too for the weapon rotate code - if ( !cg.snap->ps.ammo[i] && !cg.snap->ps.stats[STAT_CLIPS] ) { - return qfalse; - } - if ( ! (cg.snap->ps.stats[ STAT_WEAPONS ] & ( 1 << i ) ) ) { - return qfalse; - } - - return qtrue; -} - -/* -=============== -CG_NextWeapon_f -=============== -*/ -void CG_NextWeapon_f( void ) { - int i; - int original; - - if ( !cg.snap ) { - return; - } - if ( cg.snap->ps.pm_flags & PMF_FOLLOW ) { - return; - } - - cg.weaponSelectTime = cg.time; - original = cg.weaponSelect; - - for ( i = 0 ; i < 16 ; i++ ) { - cg.weaponSelect++; - if ( cg.weaponSelect == 16 ) { - cg.weaponSelect = 0; - } - //Blaze: Allow full Cycle - //if ( cg.weaponSelect == WP_GAUNTLET ) { - // continue; // never cycle to gauntlet - //} - if ( CG_WeaponSelectable( cg.weaponSelect ) ) { - break; - } - } - if ( i == 16 ) { - cg.weaponSelect = original; - } -} - -/* -=============== -CG_PrevWeapon_f -=============== -*/ -void CG_PrevWeapon_f( void ) { - int i; - int original; - - if ( !cg.snap ) { - return; - } - if ( cg.snap->ps.pm_flags & PMF_FOLLOW ) { - return; - } - - cg.weaponSelectTime = cg.time; - original = cg.weaponSelect; - - for ( i = 0 ; i < 16 ; i++ ) { - cg.weaponSelect--; - if ( cg.weaponSelect == -1 ) { - cg.weaponSelect = 15; - } - //Blaze: Allow full Cycle - //if ( cg.weaponSelect == WP_GAUNTLET ) { - // continue; // never cycle to gauntlet - //} - if ( CG_WeaponSelectable( cg.weaponSelect ) ) { - break; - } - } - if ( i == 16 ) { - cg.weaponSelect = original; - } -} - -/* -=============== -CG_Weapon_f -=============== -*/ -void CG_Weapon_f( void ) { - int num; - - if ( !cg.snap ) { - return; - } - if ( cg.snap->ps.pm_flags & PMF_FOLLOW ) { - return; - } - - num = atoi( CG_Argv( 1 ) ); - - if ( num < 1 || num > 15 ) { - return; - } - - cg.weaponSelectTime = cg.time; - - if ( ! ( cg.snap->ps.stats[STAT_WEAPONS] & ( 1 << num ) ) ) { - return; // don't have the weapon - } - - cg.weaponSelect = num; -} - -/* -=================== -CG_OutOfAmmoChange - -The current weapon has just run out of ammo -=================== -*/ -void CG_OutOfAmmoChange( void ) { - int i; - - cg.weaponSelectTime = cg.time; - - for ( i = 15 ; i > 0 ; i-- ) { - if ( CG_WeaponSelectable( i ) ) { - cg.weaponSelect = i; - break; - } - } -} - - - -/* -=================================================================================================== - -WEAPON EVENTS - -=================================================================================================== -*/ - -/* -================ -CG_FireWeapon - -Caused by an EV_FIRE_WEAPON event -================ -*/ -void CG_FireWeapon( centity_t *cent ) { - entityState_t *ent; - int c; - weaponInfo_t *weap; - - ent = ¢->currentState; - if ( ent->weapon == WP_NONE ) { - return; - } - if ( ent->weapon >= WP_NUM_WEAPONS ) { - CG_Error( "CG_FireWeapon: ent->weapon >= WP_NUM_WEAPONS" ); - return; - } - weap = &cg_weapons[ ent->weapon ]; - - // mark the entity as muzzle flashing, so when it is added it will - // append the flash to the weapon model - cent->muzzleFlashTime = cg.time; - - // lightning gun only does this this on initial press - //Blaze: no more Lighting gun - /* - if ( ent->weapon == WP_LIGHTNING ) { - if ( cent->pe.lightningFiring ) { - return; - } - } - */ - - // play quad sound if needed - if ( cent->currentState.powerups & ( 1 << PW_QUAD ) ) { - trap_S_StartSound (NULL, cent->currentState.number, CHAN_ITEM, cgs.media.quadSound ); - } - - // play a sound - for ( c = 0 ; c < 4 ; c++ ) { - if ( !weap->flashSound[c] ) { - break; - } - } - if ( c > 0 ) { - c = rand() % c; - if ( weap->flashSound[c] ) - { - trap_S_StartSound( NULL, ent->number, CHAN_WEAPON, weap->flashSound[c] ); - } - } - - // do brass ejection - if ( weap->ejectBrassFunc && cg_brassTime.integer > 0 ) { - weap->ejectBrassFunc( cent ); - } -} - - -/* -================= -CG_MissileHitWall - -Caused by an EV_MISSILE_MISS event, or directly by local bullet tracing -================= -*/ -void CG_MissileHitWall( int weapon, int clientNum, vec3_t origin, vec3_t dir, impactSound_t soundType ) { - qhandle_t mod; - qhandle_t mark; - qhandle_t shader; - sfxHandle_t sfx; - float radius; - float light; - vec3_t lightColor; - localEntity_t *le; - int r; - qboolean alphaFade; - qboolean isSprite; - int duration; - - mark = 0; - radius = 32; - sfx = 0; - mod = 0; - shader = 0; - light = 0; - lightColor[0] = 1; - lightColor[1] = 1; - lightColor[2] = 0; - - // set defaults - isSprite = qfalse; - duration = 600; - - switch ( weapon ) { - default: -/* -#ifdef MISSIONPACK - case WP_NAILGUN: - if( soundType == IMPACTSOUND_FLESH ) { - sfx = cgs.media.sfx_nghitflesh; - } else if( soundType == IMPACTSOUND_METAL ) { - sfx = cgs.media.sfx_nghitmetal; - } else { - sfx = cgs.media.sfx_nghit; - } - mark = cgs.media.holeMarkShader; - radius = 12; - break; -#endif - case WP_LIGHTNING: - // no explosion at LG impact, it is added with the beam - r = rand() & 3; - if ( r < 2 ) { - sfx = cgs.media.sfx_lghit2; - } else if ( r == 2 ) { - sfx = cgs.media.sfx_lghit1; - } else { - sfx = cgs.media.sfx_lghit3; - } - mark = cgs.media.holeMarkShader; - radius = 12; - break; -#ifdef MISSIONPACK - case WP_PROX_LAUNCHER: - mod = cgs.media.dishFlashModel; - shader = cgs.media.grenadeExplosionShader; - sfx = cgs.media.sfx_proxexp; - mark = cgs.media.burnMarkShader; - radius = 64; - light = 300; - isSprite = qtrue; - break; -#endif - case WP_GRENADE_LAUNCHER: - mod = cgs.media.dishFlashModel; - shader = cgs.media.grenadeExplosionShader; - sfx = cgs.media.sfx_rockexp; - mark = cgs.media.burnMarkShader; - radius = 64; - light = 300; - isSprite = qtrue; - break; - case WP_ROCKET_LAUNCHER: - mod = cgs.media.dishFlashModel; - shader = cgs.media.rocketExplosionShader; - sfx = cgs.media.sfx_rockexp; - mark = cgs.media.burnMarkShader; - radius = 64; - light = 300; - isSprite = qtrue; - duration = 1000; - lightColor[0] = 1; - lightColor[1] = 0.75; - lightColor[2] = 0.0; -// CG_BigExplode( origin ); - break; - case WP_RAILGUN: - mod = cgs.media.ringFlashModel; - shader = cgs.media.railExplosionShader; - sfx = cgs.media.sfx_plasmaexp; - mark = cgs.media.energyMarkShader; - radius = 24; - break; - case WP_PLASMAGUN: - mod = cgs.media.ringFlashModel; - shader = cgs.media.plasmaExplosionShader; - sfx = cgs.media.sfx_plasmaexp; - mark = cgs.media.energyMarkShader; - radius = 16; - break; - case WP_BFG: - mod = cgs.media.dishFlashModel; - shader = cgs.media.bfgExplosionShader; - sfx = cgs.media.sfx_rockexp; - mark = cgs.media.burnMarkShader; - radius = 32; - isSprite = qtrue; - break; - case WP_SHOTGUN: - mod = cgs.media.bulletFlashModel; - shader = cgs.media.bulletExplosionShader; - mark = cgs.media.bulletMarkShader; - sfx = 0; - radius = 4; - break; - -#ifdef MISSIONPACK - case WP_CHAINGUN: - mod = cgs.media.bulletFlashModel; - if( soundType == IMPACTSOUND_FLESH ) { - sfx = cgs.media.sfx_chghitflesh; - } else if( soundType == IMPACTSOUND_METAL ) { - sfx = cgs.media.sfx_chghitmetal; - } else { - sfx = cgs.media.sfx_chghit; - } - mark = cgs.media.bulletMarkShader; - - r = rand() & 3; - if ( r < 2 ) { - sfx = cgs.media.sfx_ric1; - } else if ( r == 2 ) { - sfx = cgs.media.sfx_ric2; - } else { - sfx = cgs.media.sfx_ric3; - } - - radius = 8; - break; -#endif - - case WP_MACHINEGUN: - mod = cgs.media.bulletFlashModel; - shader = cgs.media.bulletExplosionShader; - mark = cgs.media.bulletMarkShader; - - r = rand() & 3; - if ( r < 2 ) { - sfx = cgs.media.sfx_ric1; - } else if ( r == 2 ) { - sfx = cgs.media.sfx_ric2; - } else { - sfx = cgs.media.sfx_ric3; - } - - radius = 8; - break; - } -*///Blaze: Reaction M4 - case WP_M4: - mod = cgs.media.bulletFlashModel; - shader = cgs.media.bulletExplosionShader; - mark = cgs.media.bulletMarkShader; - - r = rand() & 3; - if ( r < 2 ) { - sfx = cgs.media.sfx_ric1; - } else if ( r == 2 ) { - sfx = cgs.media.sfx_ric2; - } else { - sfx = cgs.media.sfx_ric3; - } - - radius = 8; - break; -//Blaze: Reaction Pistol - case WP_PISTOL: - mod = cgs.media.bulletFlashModel; - shader = cgs.media.bulletExplosionShader; - mark = cgs.media.bulletMarkShader; - - r = rand() & 3; - if ( r < 2 ) { - sfx = cgs.media.sfx_ric1; - } else if ( r == 2 ) { - sfx = cgs.media.sfx_ric2; - } else { - sfx = cgs.media.sfx_ric3; - } - - radius = 8; - break; -//Blaze: Reaction MP5 - case WP_MP5: - mod = cgs.media.bulletFlashModel; - shader = cgs.media.bulletExplosionShader; - mark = cgs.media.bulletMarkShader; - - r = rand() & 3; - if ( r < 2 ) { - sfx = cgs.media.sfx_ric1; - } else if ( r == 2 ) { - sfx = cgs.media.sfx_ric2; - } else { - sfx = cgs.media.sfx_ric3; - } - - radius = 8; - break; -//Blaze: Reaction Shotgun - case WP_M3: - mod = cgs.media.bulletFlashModel; - shader = cgs.media.bulletExplosionShader; - mark = cgs.media.bulletMarkShader; - sfx = 0; - radius = 4; - break; - case WP_HANDCANNON: - mod = cgs.media.bulletFlashModel; - shader = cgs.media.bulletExplosionShader; - mark = cgs.media.bulletMarkShader; - sfx = 0; - radius = 4; - break; - case WP_AKIMBO: - mod = cgs.media.bulletFlashModel; - shader = cgs.media.bulletExplosionShader; - mark = cgs.media.bulletMarkShader; - sfx = 0; - radius = 4; - break; - case WP_GRENADE: - break; - case WP_KNIFE: - break; - } - - if ( sfx ) { - trap_S_StartSound( origin, ENTITYNUM_WORLD, CHAN_AUTO, sfx ); - } - - // - // create the explosion - // - if ( mod ) { - le = CG_MakeExplosion( origin, dir, - mod, shader, - duration, isSprite ); - le->light = light; - VectorCopy( lightColor, le->lightColor ); - //Blaze: No railgun - /* - if ( weapon == WP_RAILGUN ) { - // colorize with client color - VectorCopy( cgs.clientinfo[clientNum].color, le->color ); - } - */ - } - - // - // impact mark - // - alphaFade = (mark == cgs.media.energyMarkShader); // plasma fades alpha, all others fade color - //Blaze: No more railgun - //if ( weapon == WP_RAILGUN ) { - // float *color; - - // colorize with client color - // color = cgs.clientinfo[clientNum].color; - // CG_ImpactMark( mark, origin, dir, random()*360, color[0],color[1], color[2],1, alphaFade, radius, qfalse ); - //} else { - CG_ImpactMark( mark, origin, dir, random()*360, 1,1,1,1, alphaFade, radius, qfalse ); - //} -} - - -/* -================= -CG_MissileHitPlayer -================= -*/ -void CG_MissileHitPlayer( int weapon, vec3_t origin, vec3_t dir, int entityNum ) { - CG_Bleed( origin, entityNum ); - - // some weapons will make an explosion with the blood, while - // others will just make the blood - //Blaze: None of these are valid - /* - switch ( weapon ) { - case WP_GRENADE_LAUNCHER: - case WP_ROCKET_LAUNCHER: -#ifdef MISSIONPACK - case WP_NAILGUN: - case WP_CHAINGUN: - case WP_PROX_LAUNCHER: -#endif - CG_MissileHitWall( weapon, 0, origin, dir, IMPACTSOUND_FLESH ); - break; - default: - break; - } - */ -} - - - -/* -============================================================================ - -SHOTGUN TRACING - -============================================================================ -*/ - -/* -================ -CG_ShotgunPellet -================ -*/ -static void CG_ShotgunPellet( vec3_t start, vec3_t end, int skipNum ) { - trace_t tr; - int sourceContentType, destContentType; - - CG_Trace( &tr, start, NULL, NULL, end, skipNum, MASK_SHOT ); - - sourceContentType = trap_CM_PointContents( start, 0 ); - destContentType = trap_CM_PointContents( tr.endpos, 0 ); - - // FIXME: should probably move this cruft into CG_BubbleTrail - if ( sourceContentType == destContentType ) { - if ( sourceContentType & CONTENTS_WATER ) { - CG_BubbleTrail( start, tr.endpos, 32 ); - } - } else if ( sourceContentType & CONTENTS_WATER ) { - trace_t trace; - - trap_CM_BoxTrace( &trace, end, start, NULL, NULL, 0, CONTENTS_WATER ); - CG_BubbleTrail( start, trace.endpos, 32 ); - } else if ( destContentType & CONTENTS_WATER ) { - trace_t trace; - - trap_CM_BoxTrace( &trace, start, end, NULL, NULL, 0, CONTENTS_WATER ); - CG_BubbleTrail( tr.endpos, trace.endpos, 32 ); - } - - if ( tr.surfaceFlags & SURF_NOIMPACT ) { - return; - } - - if ( cg_entities[tr.entityNum].currentState.eType == ET_PLAYER ) { - //Blaze: Changed WP_SHOTGUN to WP_M3 - CG_MissileHitPlayer( WP_M3, tr.endpos, tr.plane.normal, tr.entityNum ); - } else { - if ( tr.surfaceFlags & SURF_NOIMPACT ) { - // SURF_NOIMPACT will not make a flame puff or a mark - return; - } - if ( tr.surfaceFlags & SURF_METALSTEPS ) { - //Blaze: Changed WP_SHOTGUN to WP_M3 - CG_MissileHitWall( WP_M3, 0, tr.endpos, tr.plane.normal, IMPACTSOUND_METAL ); - } else { - //Blaze: Changed WP_SHOTGUN to WP_M3 - CG_MissileHitWall( WP_M3, 0, tr.endpos, tr.plane.normal, IMPACTSOUND_DEFAULT ); - } - } -} - -/* -================ -CG_ShotgunPattern - -Perform the same traces the server did to locate the -hit splashes (FIXME: ranom seed isn't synce anymore) -================ -*/ -static void CG_ShotgunPattern( vec3_t origin, vec3_t origin2, int otherEntNum,qboolean ism3 ) { - int i; - float r, u; - vec3_t end; - vec3_t forward, right, up; - - // derive the right and up vectors from the forward vector, because - // the client won't have any other information - VectorNormalize2( origin2, forward ); - PerpendicularVector( right, forward ); - CrossProduct( forward, right, up ); - - // generate the "random" spread pattern - for ( i = 0 ; i < DEFAULT_SHOTGUN_COUNT ; i++ ) { - if (ism3) - { - Com_Printf("M3 Code\n"); - r = crandom() * DEFAULT_SHOTGUN_SPREAD * 16; - u = crandom() * DEFAULT_SHOTGUN_SPREAD * 16; - } - else - { - Com_Printf("HC Code\n"); - r = crandom() * DEFAULT_HANDCANNON_SPREAD * 16; - u = crandom() * DEFAULT_HANDCANNON_SPREAD * 16; - } VectorMA( origin, 8192 * 16, forward, end); - VectorMA (end, r, right, end); - VectorMA (end, u, up, end); - - CG_ShotgunPellet( origin, end, otherEntNum ); - } -} - -/* -============== -CG_ShotgunFire -============== -*/ -void CG_ShotgunFire( entityState_t *es ) { - vec3_t v; - int contents; - - VectorSubtract( es->origin2, es->pos.trBase, v ); - VectorNormalize( v ); - VectorScale( v, 32, v ); - VectorAdd( es->pos.trBase, v, v ); - if ( cgs.glconfig.hardwareType != GLHW_RAGEPRO ) { - // ragepro can't alpha fade, so don't even bother with smoke - vec3_t up; - - contents = trap_CM_PointContents( es->pos.trBase, 0 ); - if ( !( contents & CONTENTS_WATER ) ) { - VectorSet( up, 0, 0, 8 ); - CG_SmokePuff( v, up, 32, 1, 1, 1, 0.33f, 900, cg.time, 0, LEF_PUFF_DONT_SCALE, cgs.media.shotgunSmokePuffShader ); - } - } - CG_ShotgunPattern( es->pos.trBase, es->origin2, es->otherEntityNum,qtrue); -} - -/* -============================================================================ - -BULLETS - -============================================================================ -*/ - - -/* -=============== -CG_Tracer -=============== -*/ -void CG_Tracer( vec3_t source, vec3_t dest ) { - vec3_t forward, right; - polyVert_t verts[4]; - vec3_t line; - float len, begin, end; - vec3_t start, finish; - vec3_t midpoint; - - // tracer - VectorSubtract( dest, source, forward ); - len = VectorNormalize( forward ); - - // start at least a little ways from the muzzle - if ( len < 100 ) { - return; - } - begin = 50 + random() * (len - 60); - end = begin + cg_tracerLength.value; - if ( end > len ) { - end = len; - } - VectorMA( source, begin, forward, start ); - VectorMA( source, end, forward, finish ); - - line[0] = DotProduct( forward, cg.refdef.viewaxis[1] ); - line[1] = DotProduct( forward, cg.refdef.viewaxis[2] ); - - VectorScale( cg.refdef.viewaxis[1], line[1], right ); - VectorMA( right, -line[0], cg.refdef.viewaxis[2], right ); - VectorNormalize( right ); - - VectorMA( finish, cg_tracerWidth.value, right, verts[0].xyz ); - verts[0].st[0] = 0; - verts[0].st[1] = 1; - verts[0].modulate[0] = 255; - verts[0].modulate[1] = 255; - verts[0].modulate[2] = 255; - verts[0].modulate[3] = 255; - - VectorMA( finish, -cg_tracerWidth.value, right, verts[1].xyz ); - verts[1].st[0] = 1; - verts[1].st[1] = 0; - verts[1].modulate[0] = 255; - verts[1].modulate[1] = 255; - verts[1].modulate[2] = 255; - verts[1].modulate[3] = 255; - - VectorMA( start, -cg_tracerWidth.value, right, verts[2].xyz ); - verts[2].st[0] = 1; - verts[2].st[1] = 1; - verts[2].modulate[0] = 255; - verts[2].modulate[1] = 255; - verts[2].modulate[2] = 255; - verts[2].modulate[3] = 255; - - VectorMA( start, cg_tracerWidth.value, right, verts[3].xyz ); - verts[3].st[0] = 0; - verts[3].st[1] = 0; - verts[3].modulate[0] = 255; - verts[3].modulate[1] = 255; - verts[3].modulate[2] = 255; - verts[3].modulate[3] = 255; - - trap_R_AddPolyToScene( cgs.media.tracerShader, 4, verts ); - - midpoint[0] = ( start[0] + finish[0] ) * 0.5; - midpoint[1] = ( start[1] + finish[1] ) * 0.5; - midpoint[2] = ( start[2] + finish[2] ) * 0.5; - - // add the tracer sound - trap_S_StartSound( midpoint, ENTITYNUM_WORLD, CHAN_AUTO, cgs.media.tracerSound ); - -} - - -/* -====================== -CG_CalcMuzzlePoint -====================== -*/ -static qboolean CG_CalcMuzzlePoint( int entityNum, vec3_t muzzle ) { - vec3_t forward; - centity_t *cent; - int anim; - - if ( entityNum == cg.snap->ps.clientNum ) { - VectorCopy( cg.snap->ps.origin, muzzle ); - muzzle[2] += cg.snap->ps.viewheight; - AngleVectors( cg.snap->ps.viewangles, forward, NULL, NULL ); - VectorMA( muzzle, 14, forward, muzzle ); - return qtrue; - } - - cent = &cg_entities[entityNum]; - if ( !cent->currentValid ) { - return qfalse; - } - - VectorCopy( cent->currentState.pos.trBase, muzzle ); - - AngleVectors( cent->currentState.apos.trBase, forward, NULL, NULL ); - anim = cent->currentState.legsAnim & ~ANIM_TOGGLEBIT; - if ( anim == LEGS_WALKCR || anim == LEGS_IDLECR ) { - muzzle[2] += CROUCH_VIEWHEIGHT; - } else { - muzzle[2] += DEFAULT_VIEWHEIGHT; - } - - VectorMA( muzzle, 14, forward, muzzle ); - - return qtrue; - -} - -/* -====================== -CG_Bullet - -Renders bullet effects. -====================== -*/ -void CG_Bullet( vec3_t end, int sourceEntityNum, vec3_t normal, qboolean flesh, int fleshEntityNum ) { - trace_t trace; - int sourceContentType, destContentType; - vec3_t start; - - // if the shooter is currently valid, calc a source point and possibly - // do trail effects - if ( sourceEntityNum >= 0 && cg_tracerChance.value > 0 ) { - if ( CG_CalcMuzzlePoint( sourceEntityNum, start ) ) { - sourceContentType = trap_CM_PointContents( start, 0 ); - destContentType = trap_CM_PointContents( end, 0 ); - - // do a complete bubble trail if necessary - if ( ( sourceContentType == destContentType ) && ( sourceContentType & CONTENTS_WATER ) ) { - CG_BubbleTrail( start, end, 32 ); - } - // bubble trail from water into air - else if ( ( sourceContentType & CONTENTS_WATER ) ) { - trap_CM_BoxTrace( &trace, end, start, NULL, NULL, 0, CONTENTS_WATER ); - CG_BubbleTrail( start, trace.endpos, 32 ); - } - // bubble trail from air into water - else if ( ( destContentType & CONTENTS_WATER ) ) { - trap_CM_BoxTrace( &trace, start, end, NULL, NULL, 0, CONTENTS_WATER ); - CG_BubbleTrail( trace.endpos, end, 32 ); - } - - // draw a tracer - if ( random() < cg_tracerChance.value ) { - CG_Tracer( start, end ); - } - } - } - - // impact splash and mark - if ( flesh ) { - CG_Bleed( end, fleshEntityNum ); - } else { - //Blaze: Changed WP_MACHINEGUN to WP_PISTOL - CG_MissileHitWall( WP_PISTOL, 0, end, normal, IMPACTSOUND_DEFAULT ); - } - -} diff --git a/reaction/cgame/.#cgame.plg.1.6 b/reaction/cgame/.#cgame.plg.1.6 deleted file mode 100644 index 4eeb8c61..00000000 --- a/reaction/cgame/.#cgame.plg.1.6 +++ /dev/null @@ -1,57 +0,0 @@ - -
--- - diff --git a/reaction/game/.#ai_chat.c.1.2 b/reaction/game/.#ai_chat.c.1.2 deleted file mode 100644 index f2bd8987..00000000 --- a/reaction/game/.#ai_chat.c.1.2 +++ /dev/null @@ -1,1209 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// - -/***************************************************************************** - * name: ai_chat.c - * - * desc: Quake3 bot AI - * - * $Archive: /MissionPack/code/game/ai_chat.c $ - * $Author$ - * $Revision$ - * $Modtime: 11/19/00 8:39a $ - * $Date$ - * - *****************************************************************************/ - -#include "g_local.h" -#include "botlib.h" -#include "be_aas.h" -#include "be_ea.h" -#include "be_ai_char.h" -#include "be_ai_chat.h" -#include "be_ai_gen.h" -#include "be_ai_goal.h" -#include "be_ai_move.h" -#include "be_ai_weap.h" -// -#include "ai_main.h" -#include "ai_dmq3.h" -#include "ai_chat.h" -#include "ai_cmd.h" -#include "ai_dmnet.h" -// -#include "chars.h" //characteristics -#include "inv.h" //indexes into the inventory -#include "syn.h" //synonyms -#include "match.h" //string matching types and vars - -// for the voice chats -//Blaze: was there a extra ../ here? -#include "../ui/menudef.h" - -#define TIME_BETWEENCHATTING 25 - - -/* -================== -BotNumActivePlayers -================== -*/ -int BotNumActivePlayers(void) { - int i, num; - char buf[MAX_INFO_STRING]; - static int maxclients; - - if (!maxclients) - maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients"); - - num = 0; - for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) { - trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf)); - //if no config string or no name - if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue; - //skip spectators - if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR) continue; - // - num++; - } - return num; -} - -/* -================== -BotIsFirstInRankings -================== -*/ -int BotIsFirstInRankings(bot_state_t *bs) { - int i, score; - char buf[MAX_INFO_STRING]; - static int maxclients; - playerState_t ps; - - if (!maxclients) - maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients"); - - score = bs->cur_ps.persistant[PERS_SCORE]; - for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) { - trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf)); - //if no config string or no name - if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue; - //skip spectators - if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR) continue; - // - BotAI_GetClientState(i, &ps); - if (score < ps.persistant[PERS_SCORE]) return qfalse; - } - return qtrue; -} - -/* -================== -BotIsLastInRankings -================== -*/ -int BotIsLastInRankings(bot_state_t *bs) { - int i, score; - char buf[MAX_INFO_STRING]; - static int maxclients; - playerState_t ps; - - if (!maxclients) - maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients"); - - score = bs->cur_ps.persistant[PERS_SCORE]; - for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) { - trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf)); - //if no config string or no name - if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue; - //skip spectators - if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR) continue; - // - BotAI_GetClientState(i, &ps); - if (score > ps.persistant[PERS_SCORE]) return qfalse; - } - return qtrue; -} - -/* -================== -BotFirstClientInRankings -================== -*/ -char *BotFirstClientInRankings(void) { - int i, bestscore, bestclient; - char buf[MAX_INFO_STRING]; - static char name[32]; - static int maxclients; - playerState_t ps; - - if (!maxclients) - maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients"); - - bestscore = -999999; - bestclient = 0; - for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) { - trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf)); - //if no config string or no name - if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue; - //skip spectators - if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR) continue; - // - BotAI_GetClientState(i, &ps); - if (ps.persistant[PERS_SCORE] > bestscore) { - bestscore = ps.persistant[PERS_SCORE]; - bestclient = i; - } - } - EasyClientName(bestclient, name, 32); - return name; -} - -/* -================== -BotLastClientInRankings -================== -*/ -char *BotLastClientInRankings(void) { - int i, worstscore, bestclient; - char buf[MAX_INFO_STRING]; - static char name[32]; - static int maxclients; - playerState_t ps; - - if (!maxclients) - maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients"); - - worstscore = 999999; - bestclient = 0; - for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) { - trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf)); - //if no config string or no name - if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue; - //skip spectators - if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR) continue; - // - BotAI_GetClientState(i, &ps); - if (ps.persistant[PERS_SCORE] < worstscore) { - worstscore = ps.persistant[PERS_SCORE]; - bestclient = i; - } - } - EasyClientName(bestclient, name, 32); - return name; -} - -/* -================== -BotRandomOpponentName -================== -*/ -char *BotRandomOpponentName(bot_state_t *bs) { - int i, count; - char buf[MAX_INFO_STRING]; - int opponents[MAX_CLIENTS], numopponents; - static int maxclients; - static char name[32]; - - if (!maxclients) - maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients"); - - numopponents = 0; - opponents[0] = 0; - for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) { - if (i == bs->client) continue; - // - trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf)); - //if no config string or no name - if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue; - //skip spectators - if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR) continue; - //skip team mates - if (BotSameTeam(bs, i)) continue; - // - opponents[numopponents] = i; - numopponents++; - } - count = random() * numopponents; - for (i = 0; i < numopponents; i++) { - count--; - if (count <= 0) { - EasyClientName(opponents[i], name, sizeof(name)); - return name; - } - } - EasyClientName(opponents[0], name, sizeof(name)); - return name; -} - -/* -================== -BotMapTitle -================== -*/ - -char *BotMapTitle(void) { - char info[1024]; - static char mapname[128]; - - trap_GetServerinfo(info, sizeof(info)); - - strncpy(mapname, Info_ValueForKey( info, "mapname" ), sizeof(mapname)-1); - mapname[sizeof(mapname)-1] = '\0'; - - return mapname; -} - - -/* -================== -BotWeaponNameForMeansOfDeath -================== -*/ - -char *BotWeaponNameForMeansOfDeath(int mod) { - switch(mod) { - case MOD_SHOTGUN: return "Shotgun"; - case MOD_GAUNTLET: return "Gauntlet"; - case MOD_MACHINEGUN: return "Machinegun"; - case MOD_GRENADE: - case MOD_GRENADE_SPLASH: return "Grenade Launcher"; - case MOD_ROCKET: - case MOD_ROCKET_SPLASH: return "Rocket Launcher"; - case MOD_PLASMA: - case MOD_PLASMA_SPLASH: return "Plasmagun"; - case MOD_RAILGUN: return "Railgun"; - case MOD_LIGHTNING: return "Lightning Gun"; - case MOD_BFG: - case MOD_BFG_SPLASH: return "BFG10K"; -#ifdef MISSIONPACK - case MOD_NAIL: return "Nailgun"; - case MOD_CHAINGUN: return "Chaingun"; - case MOD_PROXIMITY_MINE: return "Proximity Launcher"; - case MOD_KAMIKAZE: return "Kamikaze"; - case MOD_JUICED: return "Prox mine"; -#endif - case MOD_GRAPPLE: return "Grapple"; - default: return "[unknown weapon]"; - } -} - -/* -================== -BotRandomWeaponName -================== -*/ -char *BotRandomWeaponName(void) { - int rnd; - -#ifdef MISSIONPACK - rnd = random() * 11.9; -#else - rnd = random() * 8.9; -#endif - switch(rnd) { - case 0: return "Gauntlet"; - case 1: return "Shotgun"; - case 2: return "Machinegun"; - case 3: return "Grenade Launcher"; - case 4: return "Rocket Launcher"; - case 5: return "Plasmagun"; - case 6: return "Railgun"; - case 7: return "Lightning Gun"; -#ifdef MISSIONPACK - case 8: return "Nailgun"; - case 9: return "Chaingun"; - case 10: return "Proximity Launcher"; -#endif - default: return "BFG10K"; - } -} - -/* -================== -BotVisibleEnemies -================== -*/ -int BotVisibleEnemies(bot_state_t *bs) { - float vis; - int i; - aas_entityinfo_t entinfo; - - for (i = 0; i < MAX_CLIENTS; i++) { - - if (i == bs->client) continue; - // - BotEntityInfo(i, &entinfo); - // - if (!entinfo.valid) continue; - //if the enemy isn't dead and the enemy isn't the bot self - if (EntityIsDead(&entinfo) || entinfo.number == bs->entitynum) continue; - //if the enemy is invisible and not shooting - if (EntityIsInvisible(&entinfo) && !EntityIsShooting(&entinfo)) { - continue; - } - //if on the same team - if (BotSameTeam(bs, i)) continue; - //check if the enemy is visible - vis = BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, i); - if (vis > 0) return qtrue; - } - return qfalse; -} - -/* -================== -BotValidChatPosition -================== -*/ -int BotValidChatPosition(bot_state_t *bs) { - vec3_t point, start, end, mins, maxs; - bsp_trace_t trace; - - //if the bot is dead all positions are valid - if (BotIsDead(bs)) return qtrue; - //never start chatting with a powerup - if (bs->inventory[INVENTORY_QUAD] || - bs->inventory[INVENTORY_HASTE] || - bs->inventory[INVENTORY_INVISIBILITY] || - bs->inventory[INVENTORY_REGEN] || - bs->inventory[INVENTORY_FLIGHT]) return qfalse; - //must be on the ground - //if (bs->cur_ps.groundEntityNum != ENTITYNUM_NONE) return qfalse; - //do not chat if in lava or slime - VectorCopy(bs->origin, point); - point[2] -= 24; - if (trap_PointContents(point,bs->entitynum) & (CONTENTS_LAVA|CONTENTS_SLIME)) return qfalse; - //do not chat if under water - VectorCopy(bs->origin, point); - point[2] += 32; - if (trap_PointContents(point,bs->entitynum) & MASK_WATER) return qfalse; - //must be standing on the world entity - VectorCopy(bs->origin, start); - VectorCopy(bs->origin, end); - start[2] += 1; - end[2] -= 10; - trap_AAS_PresenceTypeBoundingBox(PRESENCE_CROUCH, mins, maxs); - BotAI_Trace(&trace, start, mins, maxs, end, bs->client, MASK_SOLID); - if (trace.ent != ENTITYNUM_WORLD) return qfalse; - //the bot is in a position where it can chat - return qtrue; -} - -/* -================== -BotChat_EnterGame -================== -*/ -int BotChat_EnterGame(bot_state_t *bs) { - char name[32]; - float rnd; - - if (bot_nochat.integer) return qfalse; - if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse; - //don't chat in teamplay - if (TeamPlayIsOn()) return qfalse; - // don't chat in tournament mode - if (gametype == GT_TOURNAMENT) return qfalse; - rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_ENTEREXITGAME, 0, 1); - if (!bot_fastchat.integer) { - if (random() > rnd) return qfalse; - } - if (BotNumActivePlayers() <= 1) return qfalse; - if (!BotValidChatPosition(bs)) return qfalse; - BotAI_BotInitialChat(bs, "game_enter", - EasyClientName(bs->client, name, 32), // 0 - BotRandomOpponentName(bs), // 1 - "[invalid var]", // 2 - "[invalid var]", // 3 - BotMapTitle(), // 4 - NULL); - bs->lastchat_time = FloatTime(); - bs->chatto = CHAT_ALL; - return qtrue; -} - -/* -================== -BotChat_ExitGame -================== -*/ -int BotChat_ExitGame(bot_state_t *bs) { - char name[32]; - float rnd; - - if (bot_nochat.integer) return qfalse; - if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse; - //don't chat in teamplay - if (TeamPlayIsOn()) return qfalse; - // don't chat in tournament mode - if (gametype == GT_TOURNAMENT) return qfalse; - rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_ENTEREXITGAME, 0, 1); - if (!bot_fastchat.integer) { - if (random() > rnd) return qfalse; - } - if (BotNumActivePlayers() <= 1) return qfalse; - // - BotAI_BotInitialChat(bs, "game_exit", - EasyClientName(bs->client, name, 32), // 0 - BotRandomOpponentName(bs), // 1 - "[invalid var]", // 2 - "[invalid var]", // 3 - BotMapTitle(), // 4 - NULL); - bs->lastchat_time = FloatTime(); - bs->chatto = CHAT_ALL; - return qtrue; -} - -/* -================== -BotChat_StartLevel -================== -*/ -int BotChat_StartLevel(bot_state_t *bs) { - char name[32]; - float rnd; - - if (bot_nochat.integer) return qfalse; - if (BotIsObserver(bs)) return qfalse; - if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse; - //don't chat in teamplay - if (TeamPlayIsOn()) { - trap_EA_Command(bs->client, "vtaunt"); - return qfalse; - } - // don't chat in tournament mode - if (gametype == GT_TOURNAMENT) return qfalse; - rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_STARTENDLEVEL, 0, 1); - if (!bot_fastchat.integer) { - if (random() > rnd) return qfalse; - } - if (BotNumActivePlayers() <= 1) return qfalse; - BotAI_BotInitialChat(bs, "level_start", - EasyClientName(bs->client, name, 32), // 0 - NULL); - bs->lastchat_time = FloatTime(); - bs->chatto = CHAT_ALL; - return qtrue; -} - -/* -================== -BotChat_EndLevel -================== -*/ -int BotChat_EndLevel(bot_state_t *bs) { - char name[32]; - float rnd; - - if (bot_nochat.integer) return qfalse; - if (BotIsObserver(bs)) return qfalse; - if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse; - // teamplay - if (TeamPlayIsOn()) - { - if (BotIsFirstInRankings(bs)) { - trap_EA_Command(bs->client, "vtaunt"); - } - return qtrue; - } - // don't chat in tournament mode - if (gametype == GT_TOURNAMENT) return qfalse; - rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_STARTENDLEVEL, 0, 1); - if (!bot_fastchat.integer) { - if (random() > rnd) return qfalse; - } - if (BotNumActivePlayers() <= 1) return qfalse; - // - if (BotIsFirstInRankings(bs)) { - BotAI_BotInitialChat(bs, "level_end_victory", - EasyClientName(bs->client, name, 32), // 0 - BotRandomOpponentName(bs), // 1 - "[invalid var]", // 2 - BotLastClientInRankings(), // 3 - BotMapTitle(), // 4 - NULL); - } - else if (BotIsLastInRankings(bs)) { - BotAI_BotInitialChat(bs, "level_end_lose", - EasyClientName(bs->client, name, 32), // 0 - BotRandomOpponentName(bs), // 1 - BotFirstClientInRankings(), // 2 - "[invalid var]", // 3 - BotMapTitle(), // 4 - NULL); - } - else { - BotAI_BotInitialChat(bs, "level_end", - EasyClientName(bs->client, name, 32), // 0 - BotRandomOpponentName(bs), // 1 - BotFirstClientInRankings(), // 2 - BotLastClientInRankings(), // 3 - BotMapTitle(), // 4 - NULL); - } - bs->lastchat_time = FloatTime(); - bs->chatto = CHAT_ALL; - return qtrue; -} - -/* -================== -BotChat_Death -================== -*/ -int BotChat_Death(bot_state_t *bs) { - char name[32]; - float rnd; - - if (bot_nochat.integer) return qfalse; - if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse; - rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_DEATH, 0, 1); - // don't chat in tournament mode - if (gametype == GT_TOURNAMENT) return qfalse; - //if fast chatting is off - if (!bot_fastchat.integer) { - if (random() > rnd) return qfalse; - } - if (BotNumActivePlayers() <= 1) return qfalse; - // - if (bs->lastkilledby >= 0 && bs->lastkilledby < MAX_CLIENTS) - EasyClientName(bs->lastkilledby, name, 32); - else - strcpy(name, "[world]"); - // - if (TeamPlayIsOn() && BotSameTeam(bs, bs->lastkilledby)) { - if (bs->lastkilledby == bs->client) return qfalse; - BotAI_BotInitialChat(bs, "death_teammate", name, NULL); - bs->chatto = CHAT_TEAM; - } - else - { - //teamplay - if (TeamPlayIsOn()) { - trap_EA_Command(bs->client, "vtaunt"); - return qtrue; - } - // - if (bs->botdeathtype == MOD_WATER) - BotAI_BotInitialChat(bs, "death_drown", BotRandomOpponentName(bs), NULL); - else if (bs->botdeathtype == MOD_SLIME) - BotAI_BotInitialChat(bs, "death_slime", BotRandomOpponentName(bs), NULL); - else if (bs->botdeathtype == MOD_LAVA) - BotAI_BotInitialChat(bs, "death_lava", BotRandomOpponentName(bs), NULL); - else if (bs->botdeathtype == MOD_FALLING) - BotAI_BotInitialChat(bs, "death_cratered", BotRandomOpponentName(bs), NULL); - else if (bs->botsuicide || //all other suicides by own weapon - bs->botdeathtype == MOD_CRUSH || - bs->botdeathtype == MOD_SUICIDE || - bs->botdeathtype == MOD_TARGET_LASER || - bs->botdeathtype == MOD_TRIGGER_HURT || - bs->botdeathtype == MOD_UNKNOWN) - BotAI_BotInitialChat(bs, "death_suicide", BotRandomOpponentName(bs), NULL); - else if (bs->botdeathtype == MOD_TELEFRAG) - BotAI_BotInitialChat(bs, "death_telefrag", name, NULL); -#ifdef MISSIONPACK - else if (bs->botdeathtype == MOD_KAMIKAZE && trap_BotNumInitialChats(bs->cs, "death_kamikaze")) - BotAI_BotInitialChat(bs, "death_kamikaze", name, NULL); -#endif - else { - if ((bs->botdeathtype == MOD_GAUNTLET || - bs->botdeathtype == MOD_RAILGUN || - bs->botdeathtype == MOD_BFG || - bs->botdeathtype == MOD_BFG_SPLASH) && random() < 0.5) { - - if (bs->botdeathtype == MOD_GAUNTLET) - BotAI_BotInitialChat(bs, "death_gauntlet", - name, // 0 - BotWeaponNameForMeansOfDeath(bs->botdeathtype), // 1 - NULL); - else if (bs->botdeathtype == MOD_RAILGUN) - BotAI_BotInitialChat(bs, "death_rail", - name, // 0 - BotWeaponNameForMeansOfDeath(bs->botdeathtype), // 1 - NULL); - else - BotAI_BotInitialChat(bs, "death_bfg", - name, // 0 - BotWeaponNameForMeansOfDeath(bs->botdeathtype), // 1 - NULL); - } - //choose between insult and praise - else if (random() < trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_INSULT, 0, 1)) { - BotAI_BotInitialChat(bs, "death_insult", - name, // 0 - BotWeaponNameForMeansOfDeath(bs->botdeathtype), // 1 - NULL); - } - else { - BotAI_BotInitialChat(bs, "death_praise", - name, // 0 - BotWeaponNameForMeansOfDeath(bs->botdeathtype), // 1 - NULL); - } - } - bs->chatto = CHAT_ALL; - } - bs->lastchat_time = FloatTime(); - return qtrue; -} - -/* -================== -BotChat_Kill -================== -*/ -int BotChat_Kill(bot_state_t *bs) { - char name[32]; - float rnd; - - if (bot_nochat.integer) return qfalse; - if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse; - rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_KILL, 0, 1); - // don't chat in tournament mode - if (gametype == GT_TOURNAMENT) return qfalse; - //if fast chat is off - if (!bot_fastchat.integer) { - if (random() > rnd) return qfalse; - } - if (bs->lastkilledplayer == bs->client) return qfalse; - if (BotNumActivePlayers() <= 1) return qfalse; - if (!BotValidChatPosition(bs)) return qfalse; - // - if (BotVisibleEnemies(bs)) return qfalse; - // - EasyClientName(bs->lastkilledplayer, name, 32); - // - bs->chatto = CHAT_ALL; - if (TeamPlayIsOn() && BotSameTeam(bs, bs->lastkilledplayer)) { - BotAI_BotInitialChat(bs, "kill_teammate", name, NULL); - bs->chatto = CHAT_TEAM; - } - else - { - //don't chat in teamplay - if (TeamPlayIsOn()) { - trap_EA_Command(bs->client, "vtaunt"); - return qfalse; // don't wait - } - // - if (bs->enemydeathtype == MOD_GAUNTLET) { - BotAI_BotInitialChat(bs, "kill_gauntlet", name, NULL); - } - else if (bs->enemydeathtype == MOD_RAILGUN) { - BotAI_BotInitialChat(bs, "kill_rail", name, NULL); - } - else if (bs->enemydeathtype == MOD_TELEFRAG) { - BotAI_BotInitialChat(bs, "kill_telefrag", name, NULL); - } -#ifdef MISSIONPACK - else if (bs->botdeathtype == MOD_KAMIKAZE && trap_BotNumInitialChats(bs->cs, "kill_kamikaze")) - BotAI_BotInitialChat(bs, "kill_kamikaze", name, NULL); -#endif - //choose between insult and praise - else if (random() < trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_INSULT, 0, 1)) { - BotAI_BotInitialChat(bs, "kill_insult", name, NULL); - } - else { - BotAI_BotInitialChat(bs, "kill_praise", name, NULL); - } - } - bs->lastchat_time = FloatTime(); - return qtrue; -} - -/* -================== -BotChat_EnemySuicide -================== -*/ -int BotChat_EnemySuicide(bot_state_t *bs) { - char name[32]; - float rnd; - - if (bot_nochat.integer) return qfalse; - if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse; - if (BotNumActivePlayers() <= 1) return qfalse; - // - rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_KILL, 0, 1); - //don't chat in teamplay - if (TeamPlayIsOn()) return qfalse; - // don't chat in tournament mode - if (gametype == GT_TOURNAMENT) return qfalse; - //if fast chat is off - if (!bot_fastchat.integer) { - if (random() > rnd) return qfalse; - } - if (!BotValidChatPosition(bs)) return qfalse; - // - if (BotVisibleEnemies(bs)) return qfalse; - // - if (bs->enemy >= 0) EasyClientName(bs->enemy, name, 32); - else strcpy(name, ""); - BotAI_BotInitialChat(bs, "enemy_suicide", name, NULL); - bs->lastchat_time = FloatTime(); - bs->chatto = CHAT_ALL; - return qtrue; -} - -/* -================== -BotChat_HitTalking -================== -*/ -int BotChat_HitTalking(bot_state_t *bs) { - char name[32], *weap; - int lasthurt_client; - float rnd; - - if (bot_nochat.integer) return qfalse; - if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse; - if (BotNumActivePlayers() <= 1) return qfalse; - lasthurt_client = g_entities[bs->client].client->lasthurt_client; - if (!lasthurt_client) return qfalse; - if (lasthurt_client == bs->client) return qfalse; - // - if (lasthurt_client < 0 || lasthurt_client >= MAX_CLIENTS) return qfalse; - // - rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_HITTALKING, 0, 1); - //don't chat in teamplay - if (TeamPlayIsOn()) return qfalse; - // don't chat in tournament mode - if (gametype == GT_TOURNAMENT) return qfalse; - //if fast chat is off - if (!bot_fastchat.integer) { - if (random() > rnd * 0.5) return qfalse; - } - if (!BotValidChatPosition(bs)) return qfalse; - // - ClientName(g_entities[bs->client].client->lasthurt_client, name, sizeof(name)); - weap = BotWeaponNameForMeansOfDeath(g_entities[bs->client].client->lasthurt_client); - // - BotAI_BotInitialChat(bs, "hit_talking", name, weap, NULL); - bs->lastchat_time = FloatTime(); - bs->chatto = CHAT_ALL; - return qtrue; -} - -/* -================== -BotChat_HitNoDeath -================== -*/ -int BotChat_HitNoDeath(bot_state_t *bs) { - char name[32], *weap; - float rnd; - int lasthurt_client; - aas_entityinfo_t entinfo; - - lasthurt_client = g_entities[bs->client].client->lasthurt_client; - if (!lasthurt_client) return qfalse; - if (lasthurt_client == bs->client) return qfalse; - // - if (lasthurt_client < 0 || lasthurt_client >= MAX_CLIENTS) return qfalse; - // - if (bot_nochat.integer) return qfalse; - if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse; - if (BotNumActivePlayers() <= 1) return qfalse; - rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_HITNODEATH, 0, 1); - //don't chat in teamplay - if (TeamPlayIsOn()) return qfalse; - // don't chat in tournament mode - if (gametype == GT_TOURNAMENT) return qfalse; - //if fast chat is off - if (!bot_fastchat.integer) { - if (random() > rnd * 0.5) return qfalse; - } - if (!BotValidChatPosition(bs)) return qfalse; - // - if (BotVisibleEnemies(bs)) return qfalse; - // - BotEntityInfo(bs->enemy, &entinfo); - if (EntityIsShooting(&entinfo)) return qfalse; - // - ClientName(lasthurt_client, name, sizeof(name)); - weap = BotWeaponNameForMeansOfDeath(g_entities[bs->client].client->lasthurt_mod); - // - BotAI_BotInitialChat(bs, "hit_nodeath", name, weap, NULL); - bs->lastchat_time = FloatTime(); - bs->chatto = CHAT_ALL; - return qtrue; -} - -/* -================== -BotChat_HitNoKill -================== -*/ -int BotChat_HitNoKill(bot_state_t *bs) { - char name[32], *weap; - float rnd; - aas_entityinfo_t entinfo; - - if (bot_nochat.integer) return qfalse; - if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse; - if (BotNumActivePlayers() <= 1) return qfalse; - rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_HITNOKILL, 0, 1); - //don't chat in teamplay - if (TeamPlayIsOn()) return qfalse; - // don't chat in tournament mode - if (gametype == GT_TOURNAMENT) return qfalse; - //if fast chat is off - if (!bot_fastchat.integer) { - if (random() > rnd * 0.5) return qfalse; - } - if (!BotValidChatPosition(bs)) return qfalse; - // - if (BotVisibleEnemies(bs)) return qfalse; - // - BotEntityInfo(bs->enemy, &entinfo); - if (EntityIsShooting(&entinfo)) return qfalse; - // - ClientName(bs->enemy, name, sizeof(name)); - weap = BotWeaponNameForMeansOfDeath(g_entities[bs->enemy].client->lasthurt_mod); - // - BotAI_BotInitialChat(bs, "hit_nokill", name, weap, NULL); - bs->lastchat_time = FloatTime(); - bs->chatto = CHAT_ALL; - return qtrue; -} - -/* -================== -BotChat_Random -================== -*/ -int BotChat_Random(bot_state_t *bs) { - float rnd; - char name[32]; - - if (bot_nochat.integer) return qfalse; - if (BotIsObserver(bs)) return qfalse; - if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse; - // don't chat in tournament mode - if (gametype == GT_TOURNAMENT) return qfalse; - //don't chat when doing something important :) - if (bs->ltgtype == LTG_TEAMHELP || - bs->ltgtype == LTG_TEAMACCOMPANY || - bs->ltgtype == LTG_RUSHBASE) return qfalse; - // - rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_RANDOM, 0, 1); - if (random() > bs->thinktime * 0.1) return qfalse; - if (!bot_fastchat.integer) { - if (random() > rnd) return qfalse; - if (random() > 0.25) return qfalse; - } - if (BotNumActivePlayers() <= 1) return qfalse; - // - if (!BotValidChatPosition(bs)) return qfalse; - // - if (BotVisibleEnemies(bs)) return qfalse; - // - if (bs->lastkilledplayer == bs->client) { - strcpy(name, BotRandomOpponentName(bs)); - } - else { - EasyClientName(bs->lastkilledplayer, name, sizeof(name)); - } - if (TeamPlayIsOn()) { - trap_EA_Command(bs->client, "vtaunt"); - return qfalse; // don't wait - } - // - if (random() < trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_MISC, 0, 1)) { - BotAI_BotInitialChat(bs, "random_misc", - BotRandomOpponentName(bs), // 0 - name, // 1 - "[invalid var]", // 2 - "[invalid var]", // 3 - BotMapTitle(), // 4 - BotRandomWeaponName(), // 5 - NULL); - } - else { - BotAI_BotInitialChat(bs, "random_insult", - BotRandomOpponentName(bs), // 0 - name, // 1 - "[invalid var]", // 2 - "[invalid var]", // 3 - BotMapTitle(), // 4 - BotRandomWeaponName(), // 5 - NULL); - } - bs->lastchat_time = FloatTime(); - bs->chatto = CHAT_ALL; - return qtrue; -} - -/* -================== -BotChatTime -================== -*/ -float BotChatTime(bot_state_t *bs) { - int cpm; - - cpm = trap_Characteristic_BInteger(bs->character, CHARACTERISTIC_CHAT_CPM, 1, 4000); - - return 2.0; //(float) trap_BotChatLength(bs->cs) * 30 / cpm; -} - -/* -================== -BotChatTest -================== -*/ -void BotChatTest(bot_state_t *bs) { - - char name[32]; - char *weap; - int num, i; - - num = trap_BotNumInitialChats(bs->cs, "game_enter"); - for (i = 0; i < num; i++) - { - BotAI_BotInitialChat(bs, "game_enter", - EasyClientName(bs->client, name, 32), // 0 - BotRandomOpponentName(bs), // 1 - "[invalid var]", // 2 - "[invalid var]", // 3 - BotMapTitle(), // 4 - NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_ALL); - } - num = trap_BotNumInitialChats(bs->cs, "game_exit"); - for (i = 0; i < num; i++) - { - BotAI_BotInitialChat(bs, "game_exit", - EasyClientName(bs->client, name, 32), // 0 - BotRandomOpponentName(bs), // 1 - "[invalid var]", // 2 - "[invalid var]", // 3 - BotMapTitle(), // 4 - NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_ALL); - } - num = trap_BotNumInitialChats(bs->cs, "level_start"); - for (i = 0; i < num; i++) - { - BotAI_BotInitialChat(bs, "level_start", - EasyClientName(bs->client, name, 32), // 0 - NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_ALL); - } - num = trap_BotNumInitialChats(bs->cs, "level_end_victory"); - for (i = 0; i < num; i++) - { - BotAI_BotInitialChat(bs, "level_end_victory", - EasyClientName(bs->client, name, 32), // 0 - BotRandomOpponentName(bs), // 1 - BotFirstClientInRankings(), // 2 - BotLastClientInRankings(), // 3 - BotMapTitle(), // 4 - NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_ALL); - } - num = trap_BotNumInitialChats(bs->cs, "level_end_lose"); - for (i = 0; i < num; i++) - { - BotAI_BotInitialChat(bs, "level_end_lose", - EasyClientName(bs->client, name, 32), // 0 - BotRandomOpponentName(bs), // 1 - BotFirstClientInRankings(), // 2 - BotLastClientInRankings(), // 3 - BotMapTitle(), // 4 - NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_ALL); - } - num = trap_BotNumInitialChats(bs->cs, "level_end"); - for (i = 0; i < num; i++) - { - BotAI_BotInitialChat(bs, "level_end", - EasyClientName(bs->client, name, 32), // 0 - BotRandomOpponentName(bs), // 1 - BotFirstClientInRankings(), // 2 - BotLastClientInRankings(), // 3 - BotMapTitle(), // 4 - NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_ALL); - } - EasyClientName(bs->lastkilledby, name, sizeof(name)); - num = trap_BotNumInitialChats(bs->cs, "death_drown"); - for (i = 0; i < num; i++) - { - // - BotAI_BotInitialChat(bs, "death_drown", name, NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_ALL); - } - num = trap_BotNumInitialChats(bs->cs, "death_slime"); - for (i = 0; i < num; i++) - { - BotAI_BotInitialChat(bs, "death_slime", name, NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_ALL); - } - num = trap_BotNumInitialChats(bs->cs, "death_lava"); - for (i = 0; i < num; i++) - { - BotAI_BotInitialChat(bs, "death_lava", name, NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_ALL); - } - num = trap_BotNumInitialChats(bs->cs, "death_cratered"); - for (i = 0; i < num; i++) - { - BotAI_BotInitialChat(bs, "death_cratered", name, NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_ALL); - } - num = trap_BotNumInitialChats(bs->cs, "death_suicide"); - for (i = 0; i < num; i++) - { - BotAI_BotInitialChat(bs, "death_suicide", name, NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_ALL); - } - num = trap_BotNumInitialChats(bs->cs, "death_telefrag"); - for (i = 0; i < num; i++) - { - BotAI_BotInitialChat(bs, "death_telefrag", name, NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_ALL); - } - num = trap_BotNumInitialChats(bs->cs, "death_gauntlet"); - for (i = 0; i < num; i++) - { - BotAI_BotInitialChat(bs, "death_gauntlet", - name, // 0 - BotWeaponNameForMeansOfDeath(bs->botdeathtype), // 1 - NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_ALL); - } - num = trap_BotNumInitialChats(bs->cs, "death_rail"); - for (i = 0; i < num; i++) - { - BotAI_BotInitialChat(bs, "death_rail", - name, // 0 - BotWeaponNameForMeansOfDeath(bs->botdeathtype), // 1 - NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_ALL); - } - num = trap_BotNumInitialChats(bs->cs, "death_bfg"); - for (i = 0; i < num; i++) - { - BotAI_BotInitialChat(bs, "death_bfg", - name, // 0 - BotWeaponNameForMeansOfDeath(bs->botdeathtype), // 1 - NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_ALL); - } - num = trap_BotNumInitialChats(bs->cs, "death_insult"); - for (i = 0; i < num; i++) - { - BotAI_BotInitialChat(bs, "death_insult", - name, // 0 - BotWeaponNameForMeansOfDeath(bs->botdeathtype), // 1 - NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_ALL); - } - num = trap_BotNumInitialChats(bs->cs, "death_praise"); - for (i = 0; i < num; i++) - { - BotAI_BotInitialChat(bs, "death_praise", - name, // 0 - BotWeaponNameForMeansOfDeath(bs->botdeathtype), // 1 - NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_ALL); - } - // - EasyClientName(bs->lastkilledplayer, name, 32); - // - num = trap_BotNumInitialChats(bs->cs, "kill_gauntlet"); - for (i = 0; i < num; i++) - { - // - BotAI_BotInitialChat(bs, "kill_gauntlet", name, NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_ALL); - } - num = trap_BotNumInitialChats(bs->cs, "kill_rail"); - for (i = 0; i < num; i++) - { - BotAI_BotInitialChat(bs, "kill_rail", name, NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_ALL); - } - num = trap_BotNumInitialChats(bs->cs, "kill_telefrag"); - for (i = 0; i < num; i++) - { - BotAI_BotInitialChat(bs, "kill_telefrag", name, NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_ALL); - } - num = trap_BotNumInitialChats(bs->cs, "kill_insult"); - for (i = 0; i < num; i++) - { - BotAI_BotInitialChat(bs, "kill_insult", name, NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_ALL); - } - num = trap_BotNumInitialChats(bs->cs, "kill_praise"); - for (i = 0; i < num; i++) - { - BotAI_BotInitialChat(bs, "kill_praise", name, NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_ALL); - } - num = trap_BotNumInitialChats(bs->cs, "enemy_suicide"); - for (i = 0; i < num; i++) - { - BotAI_BotInitialChat(bs, "enemy_suicide", name, NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_ALL); - } - ClientName(g_entities[bs->client].client->lasthurt_client, name, sizeof(name)); - weap = BotWeaponNameForMeansOfDeath(g_entities[bs->client].client->lasthurt_client); - num = trap_BotNumInitialChats(bs->cs, "hit_talking"); - for (i = 0; i < num; i++) - { - BotAI_BotInitialChat(bs, "hit_talking", name, weap, NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_ALL); - } - num = trap_BotNumInitialChats(bs->cs, "hit_nodeath"); - for (i = 0; i < num; i++) - { - BotAI_BotInitialChat(bs, "hit_nodeath", name, weap, NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_ALL); - } - num = trap_BotNumInitialChats(bs->cs, "hit_nokill"); - for (i = 0; i < num; i++) - { - BotAI_BotInitialChat(bs, "hit_nokill", name, weap, NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_ALL); - } - // - if (bs->lastkilledplayer == bs->client) { - strcpy(name, BotRandomOpponentName(bs)); - } - else { - EasyClientName(bs->lastkilledplayer, name, sizeof(name)); - } - // - num = trap_BotNumInitialChats(bs->cs, "random_misc"); - for (i = 0; i < num; i++) - { - // - BotAI_BotInitialChat(bs, "random_misc", - BotRandomOpponentName(bs), // 0 - name, // 1 - "[invalid var]", // 2 - "[invalid var]", // 3 - BotMapTitle(), // 4 - BotRandomWeaponName(), // 5 - NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_ALL); - } - num = trap_BotNumInitialChats(bs->cs, "random_insult"); - for (i = 0; i < num; i++) - { - BotAI_BotInitialChat(bs, "random_insult", - BotRandomOpponentName(bs), // 0 - name, // 1 - "[invalid var]", // 2 - "[invalid var]", // 3 - BotMapTitle(), // 4 - BotRandomWeaponName(), // 5 - NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_ALL); - } -} diff --git a/reaction/game/.#ai_cmd.c.1.2 b/reaction/game/.#ai_cmd.c.1.2 deleted file mode 100644 index 1de0fe04..00000000 --- a/reaction/game/.#ai_cmd.c.1.2 +++ /dev/null @@ -1,1977 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// - -/***************************************************************************** - * name: ai_cmd.c - * - * desc: Quake3 bot AI - * - * $Archive: /MissionPack/code/game/ai_cmd.c $ - * $Author$ - * $Revision$ - * $Modtime: 11/28/00 9:12a $ - * $Date$ - * - *****************************************************************************/ - -#include "g_local.h" -#include "botlib.h" -#include "be_aas.h" -#include "be_ea.h" -#include "be_ai_char.h" -#include "be_ai_chat.h" -#include "be_ai_gen.h" -#include "be_ai_goal.h" -#include "be_ai_move.h" -#include "be_ai_weap.h" -// -#include "ai_main.h" -#include "ai_dmq3.h" -#include "ai_chat.h" -#include "ai_cmd.h" -#include "ai_dmnet.h" -#include "ai_team.h" -// -#include "chars.h" //characteristics -#include "inv.h" //indexes into the inventory -#include "syn.h" //synonyms -#include "match.h" //string matching types and vars - -// for the voice chats -//Blaze: Was there a extra ../? -#include "../ui/menudef.h" - -int notleader[MAX_CLIENTS]; - -#ifdef DEBUG -/* -================== -BotPrintTeamGoal -================== -*/ -void BotPrintTeamGoal(bot_state_t *bs) { - char netname[MAX_NETNAME]; - float t; - - ClientName(bs->client, netname, sizeof(netname)); - t = bs->teamgoal_time - FloatTime(); - switch(bs->ltgtype) { - case LTG_TEAMHELP: - { - BotAI_Print(PRT_MESSAGE, "%s: I'm gonna help a team mate for %1.0f secs\n", netname, t); - break; - } - case LTG_TEAMACCOMPANY: - { - BotAI_Print(PRT_MESSAGE, "%s: I'm gonna accompany a team mate for %1.0f secs\n", netname, t); - break; - } - case LTG_GETFLAG: - { - BotAI_Print(PRT_MESSAGE, "%s: I'm gonna get the flag for %1.0f secs\n", netname, t); - break; - } - case LTG_RUSHBASE: - { - BotAI_Print(PRT_MESSAGE, "%s: I'm gonna rush to the base for %1.0f secs\n", netname, t); - break; - } - case LTG_RETURNFLAG: - { - BotAI_Print(PRT_MESSAGE, "%s: I'm gonna try to return the flag for %1.0f secs\n", netname, t); - break; - } -#ifdef MISSIONPACK - case LTG_ATTACKENEMYBASE: - { - BotAI_Print(PRT_MESSAGE, "%s: I'm gonna attack the enemy base for %1.0f secs\n", netname, t); - break; - } - case LTG_HARVEST: - { - BotAI_Print(PRT_MESSAGE, "%s: I'm gonna harvest for %1.0f secs\n", netname, t); - break; - } -#endif - case LTG_DEFENDKEYAREA: - { - BotAI_Print(PRT_MESSAGE, "%s: I'm gonna defend a key area for %1.0f secs\n", netname, t); - break; - } - case LTG_GETITEM: - { - BotAI_Print(PRT_MESSAGE, "%s: I'm gonna get an item for %1.0f secs\n", netname, t); - break; - } - case LTG_KILL: - { - BotAI_Print(PRT_MESSAGE, "%s: I'm gonna kill someone for %1.0f secs\n", netname, t); - break; - } - case LTG_CAMP: - case LTG_CAMPORDER: - { - BotAI_Print(PRT_MESSAGE, "%s: I'm gonna camp for %1.0f secs\n", netname, t); - break; - } - case LTG_PATROL: - { - BotAI_Print(PRT_MESSAGE, "%s: I'm gonna patrol for %1.0f secs\n", netname, t); - break; - } - default: - { - if (bs->ctfroam_time > FloatTime()) { - t = bs->ctfroam_time - FloatTime(); - BotAI_Print(PRT_MESSAGE, "%s: I'm gonna roam for %1.0f secs\n", netname, t); - } - else { - BotAI_Print(PRT_MESSAGE, "%s: I've got a regular goal\n", netname); - } - } - } -} -#endif //DEBUG - -/* -================== -BotGetItemTeamGoal - -FIXME: add stuff like "upper rocket launcher" -"the rl near the railgun", "lower grenade launcher" etc. -================== -*/ -int BotGetItemTeamGoal(char *goalname, bot_goal_t *goal) { - int i; - - if (!strlen(goalname)) return qfalse; - i = -1; - do { - i = trap_BotGetLevelItemGoal(i, goalname, goal); - if (i > 0) { - //do NOT defend dropped items - if (goal->flags & GFL_DROPPED) - continue; - return qtrue; - } - } while(i > 0); - return qfalse; -} - -/* -================== -BotGetMessageTeamGoal -================== -*/ -int BotGetMessageTeamGoal(bot_state_t *bs, char *goalname, bot_goal_t *goal) { - bot_waypoint_t *cp; - - if (BotGetItemTeamGoal(goalname, goal)) return qtrue; - - cp = BotFindWayPoint(bs->checkpoints, goalname); - if (cp) { - memcpy(goal, &cp->goal, sizeof(bot_goal_t)); - return qtrue; - } - return qfalse; -} - -/* -================== -BotGetTime -================== -*/ -float BotGetTime(bot_match_t *match) { - bot_match_t timematch; - char timestring[MAX_MESSAGE_SIZE]; - float t; - - //if the matched string has a time - if (match->subtype & ST_TIME) { - //get the time string - trap_BotMatchVariable(match, TIME, timestring, MAX_MESSAGE_SIZE); - //match it to find out if the time is in seconds or minutes - if (trap_BotFindMatch(timestring, &timematch, MTCONTEXT_TIME)) { - if (timematch.type == MSG_FOREVER) { - t = 99999999.0f; - } - else if (timematch.type == MSG_FORAWHILE) { - t = 10 * 60; // 10 minutes - } - else if (timematch.type == MSG_FORALONGTIME) { - t = 30 * 60; // 30 minutes - } - else { - trap_BotMatchVariable(&timematch, TIME, timestring, MAX_MESSAGE_SIZE); - if (timematch.type == MSG_MINUTES) t = atof(timestring) * 60; - else if (timematch.type == MSG_SECONDS) t = atof(timestring); - else t = 0; - } - //if there's a valid time - if (t > 0) return FloatTime() + t; - } - } - return 0; -} - -/* -================== -FindClientByName -================== -*/ -int FindClientByName(char *name) { - int i; - char buf[MAX_INFO_STRING]; - static int maxclients; - - if (!maxclients) - maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients"); - for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) { - ClientName(i, buf, sizeof(buf)); - if (!Q_stricmp(buf, name)) return i; - } - for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) { - ClientName(i, buf, sizeof(buf)); - if (stristr(buf, name)) return i; - } - return -1; -} - -/* -================== -FindEnemyByName -================== -*/ -int FindEnemyByName(bot_state_t *bs, char *name) { - int i; - char buf[MAX_INFO_STRING]; - static int maxclients; - - if (!maxclients) - maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients"); - for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) { - if (BotSameTeam(bs, i)) continue; - ClientName(i, buf, sizeof(buf)); - if (!Q_stricmp(buf, name)) return i; - } - for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) { - if (BotSameTeam(bs, i)) continue; - ClientName(i, buf, sizeof(buf)); - if (stristr(buf, name)) return i; - } - return -1; -} - -/* -================== -NumPlayersOnSameTeam -================== -*/ -int NumPlayersOnSameTeam(bot_state_t *bs) { - int i, num; - char buf[MAX_INFO_STRING]; - static int maxclients; - - if (!maxclients) - maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients"); - - num = 0; - for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) { - trap_GetConfigstring(CS_PLAYERS+i, buf, MAX_INFO_STRING); - if (strlen(buf)) { - if (BotSameTeam(bs, i+1)) num++; - } - } - return num; -} - -/* -================== -TeamPlayIsOn -================== -*/ -int BotGetPatrolWaypoints(bot_state_t *bs, bot_match_t *match) { - char keyarea[MAX_MESSAGE_SIZE]; - int patrolflags; - bot_waypoint_t *wp, *newwp, *newpatrolpoints; - bot_match_t keyareamatch; - bot_goal_t goal; - - newpatrolpoints = NULL; - patrolflags = 0; - // - trap_BotMatchVariable(match, KEYAREA, keyarea, MAX_MESSAGE_SIZE); - // - while(1) { - if (!trap_BotFindMatch(keyarea, &keyareamatch, MTCONTEXT_PATROLKEYAREA)) { - trap_EA_SayTeam(bs->client, "what do you say?"); - BotFreeWaypoints(newpatrolpoints); - bs->patrolpoints = NULL; - return qfalse; - } - trap_BotMatchVariable(&keyareamatch, KEYAREA, keyarea, MAX_MESSAGE_SIZE); - if (!BotGetMessageTeamGoal(bs, keyarea, &goal)) { - //BotAI_BotInitialChat(bs, "cannotfind", keyarea, NULL); - //trap_BotEnterChat(bs->cs, 0, CHAT_TEAM); - BotFreeWaypoints(newpatrolpoints); - bs->patrolpoints = NULL; - return qfalse; - } - //create a new waypoint - newwp = BotCreateWayPoint(keyarea, goal.origin, goal.areanum); - if (!newwp) - break; - //add the waypoint to the patrol points - newwp->next = NULL; - for (wp = newpatrolpoints; wp && wp->next; wp = wp->next); - if (!wp) { - newpatrolpoints = newwp; - newwp->prev = NULL; - } - else { - wp->next = newwp; - newwp->prev = wp; - } - // - if (keyareamatch.subtype & ST_BACK) { - patrolflags = PATROL_LOOP; - break; - } - else if (keyareamatch.subtype & ST_REVERSE) { - patrolflags = PATROL_REVERSE; - break; - } - else if (keyareamatch.subtype & ST_MORE) { - trap_BotMatchVariable(&keyareamatch, MORE, keyarea, MAX_MESSAGE_SIZE); - } - else { - break; - } - } - // - if (!newpatrolpoints || !newpatrolpoints->next) { - trap_EA_SayTeam(bs->client, "I need more key points to patrol\n"); - BotFreeWaypoints(newpatrolpoints); - newpatrolpoints = NULL; - return qfalse; - } - // - BotFreeWaypoints(bs->patrolpoints); - bs->patrolpoints = newpatrolpoints; - // - bs->curpatrolpoint = bs->patrolpoints; - bs->patrolflags = patrolflags; - // - return qtrue; -} - -/* -================== -BotAddressedToBot -================== -*/ -int BotAddressedToBot(bot_state_t *bs, bot_match_t *match) { - char addressedto[MAX_MESSAGE_SIZE]; - char netname[MAX_MESSAGE_SIZE]; - char name[MAX_MESSAGE_SIZE]; - char botname[128]; - int client; - bot_match_t addresseematch; - - trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname)); - client = ClientOnSameTeamFromName(bs, netname); - if (client < 0) return qfalse; - //if the message is addressed to someone - if (match->subtype & ST_ADDRESSED) { - trap_BotMatchVariable(match, ADDRESSEE, addressedto, sizeof(addressedto)); - //the name of this bot - ClientName(bs->client, botname, 128); - // - while(trap_BotFindMatch(addressedto, &addresseematch, MTCONTEXT_ADDRESSEE)) { - if (addresseematch.type == MSG_EVERYONE) { - return qtrue; - } - else if (addresseematch.type == MSG_MULTIPLENAMES) { - trap_BotMatchVariable(&addresseematch, TEAMMATE, name, sizeof(name)); - if (strlen(name)) { - if (stristr(botname, name)) return qtrue; - if (stristr(bs->subteam, name)) return qtrue; - } - trap_BotMatchVariable(&addresseematch, MORE, addressedto, MAX_MESSAGE_SIZE); - } - else { - trap_BotMatchVariable(&addresseematch, TEAMMATE, name, MAX_MESSAGE_SIZE); - if (strlen(name)) { - if (stristr(botname, name)) return qtrue; - if (stristr(bs->subteam, name)) return qtrue; - } - break; - } - } - //Com_sprintf(buf, sizeof(buf), "not addressed to me but %s", addressedto); - //trap_EA_Say(bs->client, buf); - return qfalse; - } - else { - bot_match_t tellmatch; - - tellmatch.type = 0; - //if this message wasn't directed solely to this bot - if (!trap_BotFindMatch(match->string, &tellmatch, MTCONTEXT_REPLYCHAT) || - tellmatch.type != MSG_CHATTELL) { - //make sure not everyone reacts to this message - if (random() > (float ) 1.0 / (NumPlayersOnSameTeam(bs)-1)) return qfalse; - } - } - return qtrue; -} - -/* -================== -BotGPSToPosition -================== -*/ -int BotGPSToPosition(char *buf, vec3_t position) { - int i, j = 0; - int num, sign; - - for (i = 0; i < 3; i++) { - num = 0; - while(buf[j] == ' ') j++; - if (buf[j] == '-') { - j++; - sign = -1; - } - else { - sign = 1; - } - while (buf[j]) { - if (buf[j] >= '0' && buf[j] <= '9') { - num = num * 10 + buf[j] - '0'; - j++; - } - else { - j++; - break; - } - } - BotAI_Print(PRT_MESSAGE, "%d\n", sign * num); - position[i] = (float) sign * num; - } - return qtrue; -} - -/* -================== -BotMatch_HelpAccompany -================== -*/ -void BotMatch_HelpAccompany(bot_state_t *bs, bot_match_t *match) { - int client, other, areanum; - char teammate[MAX_MESSAGE_SIZE]; - char netname[MAX_MESSAGE_SIZE]; - char itemname[MAX_MESSAGE_SIZE]; - bot_match_t teammatematch; - aas_entityinfo_t entinfo; - - if (!TeamPlayIsOn()) return; - //if not addressed to this bot - if (!BotAddressedToBot(bs, match)) return; - //get the team mate name - trap_BotMatchVariable(match, TEAMMATE, teammate, sizeof(teammate)); - //get the client to help - if (trap_BotFindMatch(teammate, &teammatematch, MTCONTEXT_TEAMMATE) && - //if someone asks for him or herself - teammatematch.type == MSG_ME) { - //get the netname - trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname)); - client = ClientFromName(netname); - other = qfalse; - } - else { - //asked for someone else - client = FindClientByName(teammate); - //if this is the bot self - if (client == bs->client) { - other = qfalse; - } - else if (!BotSameTeam(bs, client)) { - //FIXME: say "I don't help the enemy" - return; - } - else { - other = qtrue; - } - } - //if the bot doesn't know who to help (FindClientByName returned -1) - if (client < 0) { - if (other) BotAI_BotInitialChat(bs, "whois", teammate, NULL); - else BotAI_BotInitialChat(bs, "whois", netname, NULL); - client = ClientFromName(netname); - trap_BotEnterChat(bs->cs, client, CHAT_TELL); - return; - } - //don't help or accompany yourself - if (client == bs->client) { - return; - } - // - bs->teamgoal.entitynum = -1; - BotEntityInfo(client, &entinfo); - //if info is valid (in PVS) - if (entinfo.valid) { - areanum = BotPointAreaNum(entinfo.origin); - if (areanum) {// && trap_AAS_AreaReachability(areanum)) { - bs->teamgoal.entitynum = client; - bs->teamgoal.areanum = areanum; - VectorCopy(entinfo.origin, bs->teamgoal.origin); - VectorSet(bs->teamgoal.mins, -8, -8, -8); - VectorSet(bs->teamgoal.maxs, 8, 8, 8); - } - } - //if no teamgoal yet - if (bs->teamgoal.entitynum < 0) { - //if near an item - if (match->subtype & ST_NEARITEM) { - //get the match variable - trap_BotMatchVariable(match, ITEM, itemname, sizeof(itemname)); - // - if (!BotGetMessageTeamGoal(bs, itemname, &bs->teamgoal)) { - //BotAI_BotInitialChat(bs, "cannotfind", itemname, NULL); - //trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM); - return; - } - } - } - // - if (bs->teamgoal.entitynum < 0) { - if (other) BotAI_BotInitialChat(bs, "whereis", teammate, NULL); - else BotAI_BotInitialChat(bs, "whereareyou", netname, NULL); - client = ClientFromName(netname); - trap_BotEnterChat(bs->cs, client, CHAT_TEAM); - return; - } - //the team mate - bs->teammate = client; - // - trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname)); - // - client = ClientFromName(netname); - //the team mate who ordered - bs->decisionmaker = client; - bs->ordered = qtrue; - bs->order_time = FloatTime(); - //last time the team mate was assumed visible - bs->teammatevisible_time = FloatTime(); - //set the time to send a message to the team mates - bs->teammessage_time = FloatTime() + 2 * random(); - //get the team goal time - bs->teamgoal_time = BotGetTime(match); - //set the ltg type - if (match->type == MSG_HELP) { - bs->ltgtype = LTG_TEAMHELP; - if (!bs->teamgoal_time) bs->teamgoal_time = FloatTime() + TEAM_HELP_TIME; - } - else { - bs->ltgtype = LTG_TEAMACCOMPANY; - if (!bs->teamgoal_time) bs->teamgoal_time = FloatTime() + TEAM_ACCOMPANY_TIME; - bs->formation_dist = 3.5 * 32; //3.5 meter - bs->arrive_time = 0; - // - BotSetTeamStatus(bs); - // remember last ordered task - BotRememberLastOrderedTask(bs); - } -#ifdef DEBUG - BotPrintTeamGoal(bs); -#endif //DEBUG -} - -/* -================== -BotMatch_DefendKeyArea -================== -*/ -void BotMatch_DefendKeyArea(bot_state_t *bs, bot_match_t *match) { - char itemname[MAX_MESSAGE_SIZE]; - char netname[MAX_MESSAGE_SIZE]; - int client; - - if (!TeamPlayIsOn()) return; - //if not addressed to this bot - if (!BotAddressedToBot(bs, match)) return; - //get the match variable - trap_BotMatchVariable(match, KEYAREA, itemname, sizeof(itemname)); - // - if (!BotGetMessageTeamGoal(bs, itemname, &bs->teamgoal)) { - //BotAI_BotInitialChat(bs, "cannotfind", itemname, NULL); - //trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM); - return; - } - // - trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname)); - // - client = ClientFromName(netname); - //the team mate who ordered - bs->decisionmaker = client; - bs->ordered = qtrue; - bs->order_time = FloatTime(); - //set the time to send a message to the team mates - bs->teammessage_time = FloatTime() + 2 * random(); - //set the ltg type - bs->ltgtype = LTG_DEFENDKEYAREA; - //get the team goal time - bs->teamgoal_time = BotGetTime(match); - //set the team goal time - if (!bs->teamgoal_time) bs->teamgoal_time = FloatTime() + TEAM_DEFENDKEYAREA_TIME; - //away from defending - bs->defendaway_time = 0; - // - BotSetTeamStatus(bs); - // remember last ordered task - BotRememberLastOrderedTask(bs); -#ifdef DEBUG - BotPrintTeamGoal(bs); -#endif //DEBUG -} - -/* -================== -BotMatch_GetItem -================== -*/ -void BotMatch_GetItem(bot_state_t *bs, bot_match_t *match) { - char itemname[MAX_MESSAGE_SIZE]; - char netname[MAX_MESSAGE_SIZE]; - int client; - - if (!TeamPlayIsOn()) return; - //if not addressed to this bot - if (!BotAddressedToBot(bs, match)) return; - //get the match variable - trap_BotMatchVariable(match, ITEM, itemname, sizeof(itemname)); - // - if (!BotGetMessageTeamGoal(bs, itemname, &bs->teamgoal)) { - //BotAI_BotInitialChat(bs, "cannotfind", itemname, NULL); - //trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM); - return; - } - trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname)); - client = ClientOnSameTeamFromName(bs, netname); - // - bs->decisionmaker = client; - bs->ordered = qtrue; - bs->order_time = FloatTime(); - //set the time to send a message to the team mates - bs->teammessage_time = FloatTime() + 2 * random(); - //set the ltg type - bs->ltgtype = LTG_GETITEM; - //set the team goal time - bs->teamgoal_time = FloatTime() + TEAM_GETITEM_TIME; - // - BotSetTeamStatus(bs); -#ifdef DEBUG - BotPrintTeamGoal(bs); -#endif //DEBUG -} - -/* -================== -BotMatch_Camp -================== -*/ -void BotMatch_Camp(bot_state_t *bs, bot_match_t *match) { - int client, areanum; - char netname[MAX_MESSAGE_SIZE]; - char itemname[MAX_MESSAGE_SIZE]; - aas_entityinfo_t entinfo; - - if (!TeamPlayIsOn()) return; - //if not addressed to this bot - if (!BotAddressedToBot(bs, match)) return; - // - trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname)); - //asked for someone else - client = FindClientByName(netname); - //if there's no valid client with this name - if (client < 0) { - BotAI_BotInitialChat(bs, "whois", netname, NULL); - trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM); - return; - } - //get the match variable - trap_BotMatchVariable(match, KEYAREA, itemname, sizeof(itemname)); - //in CTF it could be the base - if (match->subtype & ST_THERE) { - //camp at the spot the bot is currently standing - bs->teamgoal.entitynum = bs->entitynum; - bs->teamgoal.areanum = bs->areanum; - VectorCopy(bs->origin, bs->teamgoal.origin); - VectorSet(bs->teamgoal.mins, -8, -8, -8); - VectorSet(bs->teamgoal.maxs, 8, 8, 8); - } - else if (match->subtype & ST_HERE) { - //if this is the bot self - if (client == bs->client) return; - // - bs->teamgoal.entitynum = -1; - BotEntityInfo(client, &entinfo); - //if info is valid (in PVS) - if (entinfo.valid) { - areanum = BotPointAreaNum(entinfo.origin); - if (areanum) {// && trap_AAS_AreaReachability(areanum)) { - //NOTE: just assume the bot knows where the person is - //if (BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, client)) { - bs->teamgoal.entitynum = client; - bs->teamgoal.areanum = areanum; - VectorCopy(entinfo.origin, bs->teamgoal.origin); - VectorSet(bs->teamgoal.mins, -8, -8, -8); - VectorSet(bs->teamgoal.maxs, 8, 8, 8); - //} - } - } - //if the other is not visible - if (bs->teamgoal.entitynum < 0) { - BotAI_BotInitialChat(bs, "whereareyou", netname, NULL); - client = ClientFromName(netname); - trap_BotEnterChat(bs->cs, client, CHAT_TELL); - return; - } - } - else if (!BotGetMessageTeamGoal(bs, itemname, &bs->teamgoal)) { - //BotAI_BotInitialChat(bs, "cannotfind", itemname, NULL); - //client = ClientFromName(netname); - //trap_BotEnterChat(bs->cs, client, CHAT_TELL); - return; - } - // - bs->decisionmaker = client; - bs->ordered = qtrue; - bs->order_time = FloatTime(); - //set the time to send a message to the team mates - bs->teammessage_time = FloatTime() + 2 * random(); - //set the ltg type - bs->ltgtype = LTG_CAMPORDER; - //get the team goal time - bs->teamgoal_time = BotGetTime(match); - //set the team goal time - if (!bs->teamgoal_time) bs->teamgoal_time = FloatTime() + TEAM_CAMP_TIME; - //not arrived yet - bs->arrive_time = 0; - // - BotSetTeamStatus(bs); - // remember last ordered task - BotRememberLastOrderedTask(bs); -#ifdef DEBUG - BotPrintTeamGoal(bs); -#endif //DEBUG -} - -/* -================== -BotMatch_Patrol -================== -*/ -void BotMatch_Patrol(bot_state_t *bs, bot_match_t *match) { - char netname[MAX_MESSAGE_SIZE]; - int client; - - if (!TeamPlayIsOn()) return; - //if not addressed to this bot - if (!BotAddressedToBot(bs, match)) return; - //get the patrol waypoints - if (!BotGetPatrolWaypoints(bs, match)) return; - // - trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname)); - // - client = FindClientByName(netname); - // - bs->decisionmaker = client; - bs->ordered = qtrue; - bs->order_time = FloatTime(); - //set the time to send a message to the team mates - bs->teammessage_time = FloatTime() + 2 * random(); - //set the ltg type - bs->ltgtype = LTG_PATROL; - //get the team goal time - bs->teamgoal_time = BotGetTime(match); - //set the team goal time if not set already - if (!bs->teamgoal_time) bs->teamgoal_time = FloatTime() + TEAM_PATROL_TIME; - // - BotSetTeamStatus(bs); - // remember last ordered task - BotRememberLastOrderedTask(bs); -#ifdef DEBUG - BotPrintTeamGoal(bs); -#endif //DEBUG -} - -/* -================== -BotMatch_GetFlag -================== -*/ -void BotMatch_GetFlag(bot_state_t *bs, bot_match_t *match) { - char netname[MAX_MESSAGE_SIZE]; - int client; - - if (gametype == GT_CTF) { - if (!ctf_redflag.areanum || !ctf_blueflag.areanum) - return; - } -#ifdef MISSIONPACK - else if (gametype == GT_1FCTF) { - if (!ctf_neutralflag.areanum || !ctf_redflag.areanum || !ctf_blueflag.areanum) - return; - } -#endif - else { - return; - } - //if not addressed to this bot - if (!BotAddressedToBot(bs, match)) return; - // - trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname)); - // - client = FindClientByName(netname); - // - bs->decisionmaker = client; - bs->ordered = qtrue; - bs->order_time = FloatTime(); - //set the time to send a message to the team mates - bs->teammessage_time = FloatTime() + 2 * random(); - //set the ltg type - bs->ltgtype = LTG_GETFLAG; - //set the team goal time - bs->teamgoal_time = FloatTime() + CTF_GETFLAG_TIME; - // get an alternate route in ctf - if (gametype == GT_CTF) { - //get an alternative route goal towards the enemy base - BotGetAlternateRouteGoal(bs, BotOppositeTeam(bs)); - } - // - BotSetTeamStatus(bs); - // remember last ordered task - BotRememberLastOrderedTask(bs); -#ifdef DEBUG - BotPrintTeamGoal(bs); -#endif //DEBUG -} - -/* -================== -BotMatch_AttackEnemyBase -================== -*/ -void BotMatch_AttackEnemyBase(bot_state_t *bs, bot_match_t *match) { - char netname[MAX_MESSAGE_SIZE]; - int client; - - if (gametype == GT_CTF) { - BotMatch_GetFlag(bs, match); - } -#ifdef MISSIONPACK - else if (gametype == GT_1FCTF || gametype == GT_OBELISK || gametype == GT_HARVESTER) { - if (!redobelisk.areanum || !blueobelisk.areanum) - return; - } -#endif - else { - return; - } - //if not addressed to this bot - if (!BotAddressedToBot(bs, match)) return; - // - trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname)); - // - client = FindClientByName(netname); - // - bs->decisionmaker = client; - bs->ordered = qtrue; - bs->order_time = FloatTime(); - //set the time to send a message to the team mates - bs->teammessage_time = FloatTime() + 2 * random(); - //set the ltg type - bs->ltgtype = LTG_ATTACKENEMYBASE; - //set the team goal time - bs->teamgoal_time = FloatTime() + TEAM_ATTACKENEMYBASE_TIME; - bs->attackaway_time = 0; - // - BotSetTeamStatus(bs); - // remember last ordered task - BotRememberLastOrderedTask(bs); -#ifdef DEBUG - BotPrintTeamGoal(bs); -#endif //DEBUG -} - -#ifdef MISSIONPACK -/* -================== -BotMatch_Harvest -================== -*/ -void BotMatch_Harvest(bot_state_t *bs, bot_match_t *match) { - char netname[MAX_MESSAGE_SIZE]; - int client; - - if (gametype == GT_HARVESTER) { - if (!neutralobelisk.areanum || !redobelisk.areanum || !blueobelisk.areanum) - return; - } - else { - return; - } - //if not addressed to this bot - if (!BotAddressedToBot(bs, match)) return; - // - trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname)); - // - client = FindClientByName(netname); - // - bs->decisionmaker = client; - bs->ordered = qtrue; - bs->order_time = FloatTime(); - //set the time to send a message to the team mates - bs->teammessage_time = FloatTime() + 2 * random(); - //set the ltg type - bs->ltgtype = LTG_HARVEST; - //set the team goal time - bs->teamgoal_time = FloatTime() + TEAM_HARVEST_TIME; - bs->harvestaway_time = 0; - // - BotSetTeamStatus(bs); - // remember last ordered task - BotRememberLastOrderedTask(bs); -#ifdef DEBUG - BotPrintTeamGoal(bs); -#endif //DEBUG -} -#endif - -/* -================== -BotMatch_RushBase -================== -*/ -void BotMatch_RushBase(bot_state_t *bs, bot_match_t *match) { - char netname[MAX_MESSAGE_SIZE]; - int client; - - if (gametype == GT_CTF) { - if (!ctf_redflag.areanum || !ctf_blueflag.areanum) - return; - } -#ifdef MISSIONPACK - else if (gametype == GT_1FCTF || gametype == GT_HARVESTER) { - if (!redobelisk.areanum || !blueobelisk.areanum) - return; - } -#endif - else { - return; - } - //if not addressed to this bot - if (!BotAddressedToBot(bs, match)) return; - // - trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname)); - // - client = FindClientByName(netname); - // - bs->decisionmaker = client; - bs->ordered = qtrue; - bs->order_time = FloatTime(); - //set the time to send a message to the team mates - bs->teammessage_time = FloatTime() + 2 * random(); - //set the ltg type - bs->ltgtype = LTG_RUSHBASE; - //set the team goal time - bs->teamgoal_time = FloatTime() + CTF_RUSHBASE_TIME; - bs->rushbaseaway_time = 0; - // - BotSetTeamStatus(bs); -#ifdef DEBUG - BotPrintTeamGoal(bs); -#endif //DEBUG -} - -/* -================== -BotMatch_TaskPreference -================== -*/ -void BotMatch_TaskPreference(bot_state_t *bs, bot_match_t *match) { - char netname[MAX_NETNAME]; - char teammatename[MAX_MESSAGE_SIZE]; - int teammate, preference; - - ClientName(bs->client, netname, sizeof(netname)); - if (Q_stricmp(netname, bs->teamleader) != 0) return; - - trap_BotMatchVariable(match, NETNAME, teammatename, sizeof(teammatename)); - teammate = ClientFromName(teammatename); - if (teammate < 0) return; - - preference = BotGetTeamMateTaskPreference(bs, teammate); - switch(match->subtype) - { - case ST_DEFENDER: - { - preference &= ~TEAMTP_ATTACKER; - preference |= TEAMTP_DEFENDER; - break; - } - case ST_ATTACKER: - { - preference &= ~TEAMTP_DEFENDER; - preference |= TEAMTP_ATTACKER; - break; - } - case ST_ROAMER: - { - preference &= ~(TEAMTP_ATTACKER|TEAMTP_DEFENDER); - break; - } - } - BotSetTeamMateTaskPreference(bs, teammate, preference); - // - EasyClientName(teammate, teammatename, sizeof(teammatename)); - BotAI_BotInitialChat(bs, "keepinmind", teammatename, NULL); - trap_BotEnterChat(bs->cs, teammate, CHAT_TELL); - BotVoiceChatOnly(bs, teammate, VOICECHAT_YES); - trap_EA_Action(bs->client, ACTION_AFFIRMATIVE); -} - -/* -================== -BotMatch_ReturnFlag -================== -*/ -void BotMatch_ReturnFlag(bot_state_t *bs, bot_match_t *match) { - char netname[MAX_MESSAGE_SIZE]; - int client; - - //if not in CTF mode - if ( - gametype != GT_CTF -#ifdef MISSIONPACK - && gametype != GT_1FCTF -#endif - ) - return; - //if not addressed to this bot - if (!BotAddressedToBot(bs, match)) - return; - // - trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname)); - // - client = FindClientByName(netname); - // - bs->decisionmaker = client; - bs->ordered = qtrue; - bs->order_time = FloatTime(); - //set the time to send a message to the team mates - bs->teammessage_time = FloatTime() + 2 * random(); - //set the ltg type - bs->ltgtype = LTG_RETURNFLAG; - //set the team goal time - bs->teamgoal_time = FloatTime() + CTF_RETURNFLAG_TIME; - bs->rushbaseaway_time = 0; - // - BotSetTeamStatus(bs); -#ifdef DEBUG - BotPrintTeamGoal(bs); -#endif //DEBUG -} - -/* -================== -BotMatch_JoinSubteam -================== -*/ -void BotMatch_JoinSubteam(bot_state_t *bs, bot_match_t *match) { - char teammate[MAX_MESSAGE_SIZE]; - char netname[MAX_MESSAGE_SIZE]; - int client; - - if (!TeamPlayIsOn()) return; - //if not addressed to this bot - if (!BotAddressedToBot(bs, match)) return; - //get the sub team name - trap_BotMatchVariable(match, TEAMNAME, teammate, sizeof(teammate)); - //set the sub team name - strncpy(bs->subteam, teammate, 32); - bs->subteam[31] = '\0'; - // - trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname)); - BotAI_BotInitialChat(bs, "joinedteam", teammate, NULL); - client = ClientFromName(netname); - trap_BotEnterChat(bs->cs, client, CHAT_TELL); -} - -/* -================== -BotMatch_LeaveSubteam -================== -*/ -void BotMatch_LeaveSubteam(bot_state_t *bs, bot_match_t *match) { - char netname[MAX_MESSAGE_SIZE]; - int client; - - if (!TeamPlayIsOn()) return; - //if not addressed to this bot - if (!BotAddressedToBot(bs, match)) return; - // - if (strlen(bs->subteam)) - { - BotAI_BotInitialChat(bs, "leftteam", bs->subteam, NULL); - trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname)); - client = ClientFromName(netname); - trap_BotEnterChat(bs->cs, client, CHAT_TELL); - } //end if - strcpy(bs->subteam, ""); -} - -/* -================== -BotMatch_LeaveSubteam -================== -*/ -void BotMatch_WhichTeam(bot_state_t *bs, bot_match_t *match) { - if (!TeamPlayIsOn()) return; - //if not addressed to this bot - if (!BotAddressedToBot(bs, match)) return; - // - if (strlen(bs->subteam)) { - BotAI_BotInitialChat(bs, "inteam", bs->subteam, NULL); - } - else { - BotAI_BotInitialChat(bs, "noteam", NULL); - } - trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM); -} - -/* -================== -BotMatch_CheckPoint -================== -*/ -void BotMatch_CheckPoint(bot_state_t *bs, bot_match_t *match) { - int areanum, client; - char buf[MAX_MESSAGE_SIZE]; - char netname[MAX_MESSAGE_SIZE]; - vec3_t position; - bot_waypoint_t *cp; - - if (!TeamPlayIsOn()) return; - // - trap_BotMatchVariable(match, POSITION, buf, MAX_MESSAGE_SIZE); - VectorClear(position); - // - trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname)); - client = ClientFromName(netname); - //BotGPSToPosition(buf, position); - sscanf(buf, "%f %f %f", &position[0], &position[1], &position[2]); - position[2] += 0.5; - areanum = BotPointAreaNum(position); - if (!areanum) { - if (BotAddressedToBot(bs, match)) { - BotAI_BotInitialChat(bs, "checkpoint_invalid", NULL); - trap_BotEnterChat(bs->cs, client, CHAT_TELL); - } - return; - } - // - trap_BotMatchVariable(match, NAME, buf, MAX_MESSAGE_SIZE); - //check if there already exists a checkpoint with this name - cp = BotFindWayPoint(bs->checkpoints, buf); - if (cp) { - if (cp->next) cp->next->prev = cp->prev; - if (cp->prev) cp->prev->next = cp->next; - else bs->checkpoints = cp->next; - cp->inuse = qfalse; - } - //create a new check point - cp = BotCreateWayPoint(buf, position, areanum); - //add the check point to the bot's known chech points - cp->next = bs->checkpoints; - if (bs->checkpoints) bs->checkpoints->prev = cp; - bs->checkpoints = cp; - // - if (BotAddressedToBot(bs, match)) { - Com_sprintf(buf, sizeof(buf), "%1.0f %1.0f %1.0f", cp->goal.origin[0], - cp->goal.origin[1], - cp->goal.origin[2]); - - BotAI_BotInitialChat(bs, "checkpoint_confirm", cp->name, buf, NULL); - trap_BotEnterChat(bs->cs, client, CHAT_TELL); - } -} - -/* -================== -BotMatch_FormationSpace -================== -*/ -void BotMatch_FormationSpace(bot_state_t *bs, bot_match_t *match) { - char buf[MAX_MESSAGE_SIZE]; - float space; - - if (!TeamPlayIsOn()) return; - //if not addressed to this bot - if (!BotAddressedToBot(bs, match)) return; - // - trap_BotMatchVariable(match, NUMBER, buf, MAX_MESSAGE_SIZE); - //if it's the distance in feet - if (match->subtype & ST_FEET) space = 0.3048 * 32 * atof(buf); - //else it's in meters - else space = 32 * atof(buf); - //check if the formation intervening space is valid - if (space < 48 || space > 500) space = 100; - bs->formation_dist = space; -} - -/* -================== -BotMatch_Dismiss -================== -*/ -void BotMatch_Dismiss(bot_state_t *bs, bot_match_t *match) { - char netname[MAX_MESSAGE_SIZE]; - int client; - - if (!TeamPlayIsOn()) return; - //if not addressed to this bot - if (!BotAddressedToBot(bs, match)) return; - trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname)); - client = ClientFromName(netname); - // - bs->decisionmaker = client; - // - bs->ltgtype = 0; - bs->lead_time = 0; - bs->lastgoal_ltgtype = 0; - // - BotAI_BotInitialChat(bs, "dismissed", NULL); - trap_BotEnterChat(bs->cs, client, CHAT_TELL); -} - -/* -================== -BotMatch_Suicide -================== -*/ -void BotMatch_Suicide(bot_state_t *bs, bot_match_t *match) { - char netname[MAX_MESSAGE_SIZE]; - int client; - - if (!TeamPlayIsOn()) return; - //if not addressed to this bot - if (!BotAddressedToBot(bs, match)) return; - // - trap_EA_Command(bs->client, "kill"); - // - trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname)); - client = ClientFromName(netname); - // - BotVoiceChat(bs, client, VOICECHAT_TAUNT); - trap_EA_Action(bs->client, ACTION_AFFIRMATIVE); -} - -/* -================== -BotMatch_StartTeamLeaderShip -================== -*/ -void BotMatch_StartTeamLeaderShip(bot_state_t *bs, bot_match_t *match) { - int client; - char teammate[MAX_MESSAGE_SIZE]; - - if (!TeamPlayIsOn()) return; - //if chats for him or herself - if (match->subtype & ST_I) { - //get the team mate that will be the team leader - trap_BotMatchVariable(match, NETNAME, teammate, sizeof(teammate)); - strncpy(bs->teamleader, teammate, sizeof(bs->teamleader)); - bs->teamleader[sizeof(bs->teamleader)] = '\0'; - } - //chats for someone else - else { - //get the team mate that will be the team leader - trap_BotMatchVariable(match, TEAMMATE, teammate, sizeof(teammate)); - client = FindClientByName(teammate); - if (client >= 0) ClientName(client, bs->teamleader, sizeof(bs->teamleader)); - } -} - -/* -================== -BotMatch_StopTeamLeaderShip -================== -*/ -void BotMatch_StopTeamLeaderShip(bot_state_t *bs, bot_match_t *match) { - int client; - char teammate[MAX_MESSAGE_SIZE]; - char netname[MAX_MESSAGE_SIZE]; - - if (!TeamPlayIsOn()) return; - //get the team mate that stops being the team leader - trap_BotMatchVariable(match, TEAMMATE, teammate, sizeof(teammate)); - //if chats for him or herself - if (match->subtype & ST_I) { - trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname)); - client = FindClientByName(netname); - } - //chats for someone else - else { - client = FindClientByName(teammate); - } //end else - if (client >= 0) { - if (!Q_stricmp(bs->teamleader, ClientName(client, netname, sizeof(netname)))) { - bs->teamleader[0] = '\0'; - notleader[client] = qtrue; - } - } -} - -/* -================== -BotMatch_WhoIsTeamLeader -================== -*/ -void BotMatch_WhoIsTeamLeader(bot_state_t *bs, bot_match_t *match) { - char netname[MAX_MESSAGE_SIZE]; - - if (!TeamPlayIsOn()) return; - - ClientName(bs->client, netname, sizeof(netname)); - //if this bot IS the team leader - if (!Q_stricmp(netname, bs->teamleader)) { - trap_EA_SayTeam(bs->client, "I'm the team leader\n"); - } -} - -/* -================== -BotMatch_WhatAreYouDoing -================== -*/ -void BotMatch_WhatAreYouDoing(bot_state_t *bs, bot_match_t *match) { - char netname[MAX_MESSAGE_SIZE]; - char goalname[MAX_MESSAGE_SIZE]; - int client; - - //if not addressed to this bot - if (!BotAddressedToBot(bs, match)) return; - // - switch(bs->ltgtype) { - case LTG_TEAMHELP: - { - EasyClientName(bs->teammate, netname, sizeof(netname)); - BotAI_BotInitialChat(bs, "helping", netname, NULL); - break; - } - case LTG_TEAMACCOMPANY: - { - EasyClientName(bs->teammate, netname, sizeof(netname)); - BotAI_BotInitialChat(bs, "accompanying", netname, NULL); - break; - } - case LTG_DEFENDKEYAREA: - { - trap_BotGoalName(bs->teamgoal.number, goalname, sizeof(goalname)); - BotAI_BotInitialChat(bs, "defending", goalname, NULL); - break; - } - case LTG_GETITEM: - { - trap_BotGoalName(bs->teamgoal.number, goalname, sizeof(goalname)); - BotAI_BotInitialChat(bs, "gettingitem", goalname, NULL); - break; - } - case LTG_KILL: - { - ClientName(bs->teamgoal.entitynum, netname, sizeof(netname)); - BotAI_BotInitialChat(bs, "killing", netname, NULL); - break; - } - case LTG_CAMP: - case LTG_CAMPORDER: - { - BotAI_BotInitialChat(bs, "camping", NULL); - break; - } - case LTG_PATROL: - { - BotAI_BotInitialChat(bs, "patrolling", NULL); - break; - } - case LTG_GETFLAG: - { - BotAI_BotInitialChat(bs, "capturingflag", NULL); - break; - } - case LTG_RUSHBASE: - { - BotAI_BotInitialChat(bs, "rushingbase", NULL); - break; - } - case LTG_RETURNFLAG: - { - BotAI_BotInitialChat(bs, "returningflag", NULL); - break; - } -#ifdef MISSIONPACK - case LTG_ATTACKENEMYBASE: - { - BotAI_BotInitialChat(bs, "attackingenemybase", NULL); - break; - } - case LTG_HARVEST: - { - BotAI_BotInitialChat(bs, "harvesting", NULL); - break; - } -#endif - default: - { - BotAI_BotInitialChat(bs, "roaming", NULL); - break; - } - } - //chat what the bot is doing - trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname)); - client = ClientFromName(netname); - trap_BotEnterChat(bs->cs, client, CHAT_TELL); -} - -/* -================== -BotMatch_WhatIsMyCommand -================== -*/ -void BotMatch_WhatIsMyCommand(bot_state_t *bs, bot_match_t *match) { - char netname[MAX_NETNAME]; - - ClientName(bs->client, netname, sizeof(netname)); - if (Q_stricmp(netname, bs->teamleader) != 0) return; - bs->forceorders = qtrue; -} - -/* -================== -BotNearestVisibleItem -================== -*/ -float BotNearestVisibleItem(bot_state_t *bs, char *itemname, bot_goal_t *goal) { - int i; - char name[64]; - bot_goal_t tmpgoal; - float dist, bestdist; - vec3_t dir; - bsp_trace_t trace; - - bestdist = 999999; - i = -1; - do { - i = trap_BotGetLevelItemGoal(i, itemname, &tmpgoal); - trap_BotGoalName(tmpgoal.number, name, sizeof(name)); - if (Q_stricmp(itemname, name) != 0) - continue; - VectorSubtract(tmpgoal.origin, bs->origin, dir); - dist = VectorLength(dir); - if (dist < bestdist) { - //trace from start to end - BotAI_Trace(&trace, bs->eye, NULL, NULL, tmpgoal.origin, bs->client, CONTENTS_SOLID|CONTENTS_PLAYERCLIP); - if (trace.fraction >= 1.0) { - bestdist = dist; - memcpy(goal, &tmpgoal, sizeof(bot_goal_t)); - } - } - } while(i > 0); - return bestdist; -} - -/* -================== -BotMatch_WhereAreYou -================== -*/ -void BotMatch_WhereAreYou(bot_state_t *bs, bot_match_t *match) { - float dist, bestdist; - int i, bestitem, redtt, bluett, client; - bot_goal_t goal; - char netname[MAX_MESSAGE_SIZE]; - char *nearbyitems[] = { - "Shotgun", - "Grenade Launcher", - "Rocket Launcher", - "Plasmagun", - "Railgun", - "Lightning Gun", - "BFG10K", - "Quad Damage", - "Regeneration", - "Battle Suit", - "Speed", - "Invisibility", - "Flight", - "Armor", - "Heavy Armor", - "Red Flag", - "Blue Flag", -#ifdef MISSIONPACK - "Nailgun", - "Prox Launcher", - "Chaingun", - "Scout", - "Guard", - "Doubler", - "Ammo Regen", - "Neutral Flag", - "Red Obelisk", - "Blue Obelisk", - "Neutral Obelisk", -#endif - NULL - }; - // - if (!TeamPlayIsOn()) - return; - //if not addressed to this bot - if (!BotAddressedToBot(bs, match)) - return; - - bestitem = -1; - bestdist = 999999; - for (i = 0; nearbyitems[i]; i++) { - dist = BotNearestVisibleItem(bs, nearbyitems[i], &goal); - if (dist < bestdist) { - bestdist = dist; - bestitem = i; - } - } - if (bestitem != -1) { - if (gametype == GT_CTF -#ifdef MISSIONPACK - || gametype == GT_1FCTF -#endif - ) { - redtt = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, ctf_redflag.areanum, TFL_DEFAULT); - bluett = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, ctf_blueflag.areanum, TFL_DEFAULT); - if (redtt < (redtt + bluett) * 0.4) { - BotAI_BotInitialChat(bs, "teamlocation", nearbyitems[bestitem], "red", NULL); - } - else if (bluett < (redtt + bluett) * 0.4) { - BotAI_BotInitialChat(bs, "teamlocation", nearbyitems[bestitem], "blue", NULL); - } - else { - BotAI_BotInitialChat(bs, "location", nearbyitems[bestitem], NULL); - } - } -#ifdef MISSIONPACK - else if (gametype == GT_OBELISK || gametype == GT_HARVESTER) { - redtt = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, redobelisk.areanum, TFL_DEFAULT); - bluett = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, blueobelisk.areanum, TFL_DEFAULT); - if (redtt < (redtt + bluett) * 0.4) { - BotAI_BotInitialChat(bs, "teamlocation", nearbyitems[bestitem], "red", NULL); - } - else if (bluett < (redtt + bluett) * 0.4) { - BotAI_BotInitialChat(bs, "teamlocation", nearbyitems[bestitem], "blue", NULL); - } - else { - BotAI_BotInitialChat(bs, "location", nearbyitems[bestitem], NULL); - } - } -#endif - else { - BotAI_BotInitialChat(bs, "location", nearbyitems[bestitem], NULL); - } - trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname)); - client = ClientFromName(netname); - trap_BotEnterChat(bs->cs, client, CHAT_TELL); - } -} - -/* -================== -BotMatch_LeadTheWay -================== -*/ -void BotMatch_LeadTheWay(bot_state_t *bs, bot_match_t *match) { - aas_entityinfo_t entinfo; - char netname[MAX_MESSAGE_SIZE], teammate[MAX_MESSAGE_SIZE]; - int client, areanum, other; - - if (!TeamPlayIsOn()) return; - //if not addressed to this bot - if (!BotAddressedToBot(bs, match)) return; - //if someone asks for someone else - if (match->subtype & ST_SOMEONE) { - //get the team mate name - trap_BotMatchVariable(match, TEAMMATE, teammate, sizeof(teammate)); - client = FindClientByName(teammate); - //if this is the bot self - if (client == bs->client) { - other = qfalse; - } - else if (!BotSameTeam(bs, client)) { - //FIXME: say "I don't help the enemy" - return; - } - else { - other = qtrue; - } - } - else { - //get the netname - trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname)); - client = ClientFromName(netname); - other = qfalse; - } - //if the bot doesn't know who to help (FindClientByName returned -1) - if (client < 0) { - BotAI_BotInitialChat(bs, "whois", netname, NULL); - trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM); - return; - } - // - bs->lead_teamgoal.entitynum = -1; - BotEntityInfo(client, &entinfo); - //if info is valid (in PVS) - if (entinfo.valid) { - areanum = BotPointAreaNum(entinfo.origin); - if (areanum) { // && trap_AAS_AreaReachability(areanum)) { - bs->lead_teamgoal.entitynum = client; - bs->lead_teamgoal.areanum = areanum; - VectorCopy(entinfo.origin, bs->lead_teamgoal.origin); - VectorSet(bs->lead_teamgoal.mins, -8, -8, -8); - VectorSet(bs->lead_teamgoal.maxs, 8, 8, 8); - } - } - - if (bs->teamgoal.entitynum < 0) { - if (other) BotAI_BotInitialChat(bs, "whereis", teammate, NULL); - else BotAI_BotInitialChat(bs, "whereareyou", netname, NULL); - trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM); - return; - } - bs->lead_teammate = client; - bs->lead_time = FloatTime() + TEAM_LEAD_TIME; - bs->leadvisible_time = 0; - bs->leadmessage_time = -(FloatTime() + 2 * random()); -} - -/* -================== -BotMatch_Kill -================== -*/ -void BotMatch_Kill(bot_state_t *bs, bot_match_t *match) { - char enemy[MAX_MESSAGE_SIZE]; - char netname[MAX_MESSAGE_SIZE]; - int client; - - if (!TeamPlayIsOn()) return; - //if not addressed to this bot - if (!BotAddressedToBot(bs, match)) return; - - trap_BotMatchVariable(match, ENEMY, enemy, sizeof(enemy)); - // - client = FindEnemyByName(bs, enemy); - if (client < 0) { - BotAI_BotInitialChat(bs, "whois", enemy, NULL); - trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname)); - client = ClientFromName(netname); - trap_BotEnterChat(bs->cs, client, CHAT_TELL); - return; - } - bs->teamgoal.entitynum = client; - //set the time to send a message to the team mates - bs->teammessage_time = FloatTime() + 2 * random(); - //set the ltg type - bs->ltgtype = LTG_KILL; - //set the team goal time - bs->teamgoal_time = FloatTime() + TEAM_KILL_SOMEONE; - // - BotSetTeamStatus(bs); -#ifdef DEBUG - BotPrintTeamGoal(bs); -#endif //DEBUG -} - -/* -================== -BotMatch_CTF -================== -*/ -void BotMatch_CTF(bot_state_t *bs, bot_match_t *match) { - - char flag[128], netname[MAX_NETNAME]; - - if (gametype == GT_CTF) { - trap_BotMatchVariable(match, FLAG, flag, sizeof(flag)); - if (match->subtype & ST_GOTFLAG) { - if (!Q_stricmp(flag, "red")) { - bs->redflagstatus = 1; - if (BotTeam(bs) == TEAM_BLUE) { - trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname)); - bs->flagcarrier = ClientFromName(netname); - } - } - else { - bs->blueflagstatus = 1; - if (BotTeam(bs) == TEAM_RED) { - trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname)); - bs->flagcarrier = ClientFromName(netname); - } - } - bs->flagstatuschanged = 1; - bs->lastflagcapture_time = FloatTime(); - } - else if (match->subtype & ST_CAPTUREDFLAG) { - bs->redflagstatus = 0; - bs->blueflagstatus = 0; - bs->flagcarrier = 0; - bs->flagstatuschanged = 1; - } - else if (match->subtype & ST_RETURNEDFLAG) { - if (!Q_stricmp(flag, "red")) bs->redflagstatus = 0; - else bs->blueflagstatus = 0; - bs->flagstatuschanged = 1; - } -} -#ifdef MISSIONPACK - else if (gametype == GT_1FCTF) { - if (match->subtype & ST_1FCTFGOTFLAG) { - trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname)); - bs->flagcarrier = ClientFromName(netname); - } - } -#endif -} - -void BotMatch_EnterGame(bot_state_t *bs, bot_match_t *match) { - int client; - char netname[MAX_NETNAME]; - - trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname)); - client = FindClientByName(netname); - if (client >= 0) { - notleader[client] = qfalse; - } - //NOTE: eliza chats will catch this - //Com_sprintf(buf, sizeof(buf), "heya %s", netname); - //EA_Say(bs->client, buf); -} - -void BotMatch_NewLeader(bot_state_t *bs, bot_match_t *match) { - int client; - char netname[MAX_NETNAME]; - - trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname)); - client = FindClientByName(netname); - if (!BotSameTeam(bs, client)) - return; - Q_strncpyz(bs->teamleader, netname, sizeof(bs->teamleader)); -} - -/* -================== -BotMatchMessage -================== -*/ -int BotMatchMessage(bot_state_t *bs, char *message) { - bot_match_t match; - - match.type = 0; - //if it is an unknown message - if (!trap_BotFindMatch(message, &match, MTCONTEXT_MISC - |MTCONTEXT_INITIALTEAMCHAT - |MTCONTEXT_CTF)) { - return qfalse; - } - //react to the found message - switch(match.type) - { - case MSG_HELP: //someone calling for help - case MSG_ACCOMPANY: //someone calling for company - { - BotMatch_HelpAccompany(bs, &match); - break; - } - case MSG_DEFENDKEYAREA: //teamplay defend a key area - { - BotMatch_DefendKeyArea(bs, &match); - break; - } - case MSG_CAMP: //camp somewhere - { - BotMatch_Camp(bs, &match); - break; - } - case MSG_PATROL: //patrol between several key areas - { - BotMatch_Patrol(bs, &match); - break; - } - //CTF & 1FCTF - case MSG_GETFLAG: //ctf get the enemy flag - { - BotMatch_GetFlag(bs, &match); - break; - } -#ifdef MISSIONPACK - //CTF & 1FCTF & Obelisk & Harvester - case MSG_ATTACKENEMYBASE: - { - BotMatch_AttackEnemyBase(bs, &match); - break; - } - //Harvester - case MSG_HARVEST: - { - BotMatch_Harvest(bs, &match); - break; - } -#endif - //CTF & 1FCTF & Harvester - case MSG_RUSHBASE: //ctf rush to the base - { - BotMatch_RushBase(bs, &match); - break; - } - //CTF & 1FCTF - case MSG_RETURNFLAG: - { - BotMatch_ReturnFlag(bs, &match); - break; - } - //CTF & 1FCTF & Obelisk & Harvester - case MSG_TASKPREFERENCE: - { - BotMatch_TaskPreference(bs, &match); - break; - } - //CTF & 1FCTF - case MSG_CTF: - { - BotMatch_CTF(bs, &match); - break; - } - case MSG_GETITEM: - { - BotMatch_GetItem(bs, &match); - break; - } - case MSG_JOINSUBTEAM: //join a sub team - { - BotMatch_JoinSubteam(bs, &match); - break; - } - case MSG_LEAVESUBTEAM: //leave a sub team - { - BotMatch_LeaveSubteam(bs, &match); - break; - } - case MSG_WHICHTEAM: - { - BotMatch_WhichTeam(bs, &match); - break; - } - case MSG_CHECKPOINT: //remember a check point - { - BotMatch_CheckPoint(bs, &match); - break; - } - case MSG_CREATENEWFORMATION: //start the creation of a new formation - { - trap_EA_SayTeam(bs->client, "the part of my brain to create formations has been damaged"); - break; - } - case MSG_FORMATIONPOSITION: //tell someone his/her position in the formation - { - trap_EA_SayTeam(bs->client, "the part of my brain to create formations has been damaged"); - break; - } - case MSG_FORMATIONSPACE: //set the formation space - { - BotMatch_FormationSpace(bs, &match); - break; - } - case MSG_DOFORMATION: //form a certain formation - { - break; - } - case MSG_DISMISS: //dismiss someone - { - BotMatch_Dismiss(bs, &match); - break; - } - case MSG_STARTTEAMLEADERSHIP: //someone will become the team leader - { - BotMatch_StartTeamLeaderShip(bs, &match); - break; - } - case MSG_STOPTEAMLEADERSHIP: //someone will stop being the team leader - { - BotMatch_StopTeamLeaderShip(bs, &match); - break; - } - case MSG_WHOISTEAMLAEDER: - { - BotMatch_WhoIsTeamLeader(bs, &match); - break; - } - case MSG_WHATAREYOUDOING: //ask a bot what he/she is doing - { - BotMatch_WhatAreYouDoing(bs, &match); - break; - } - case MSG_WHATISMYCOMMAND: - { - BotMatch_WhatIsMyCommand(bs, &match); - break; - } - case MSG_WHEREAREYOU: - { - BotMatch_WhereAreYou(bs, &match); - break; - } - case MSG_LEADTHEWAY: - { - BotMatch_LeadTheWay(bs, &match); - break; - } - case MSG_KILL: - { - BotMatch_Kill(bs, &match); - break; - } - case MSG_ENTERGAME: //someone entered the game - { - BotMatch_EnterGame(bs, &match); - break; - } - case MSG_NEWLEADER: - { - BotMatch_NewLeader(bs, &match); - break; - } - case MSG_WAIT: - { - break; - } - case MSG_SUICIDE: - { - BotMatch_Suicide(bs, &match); - break; - } - default: - { - BotAI_Print(PRT_MESSAGE, "unknown match type\n"); - break; - } - } - return qtrue; -} diff --git a/reaction/game/.#ai_dmnet.c.1.2 b/reaction/game/.#ai_dmnet.c.1.2 deleted file mode 100644 index 302d7e43..00000000 --- a/reaction/game/.#ai_dmnet.c.1.2 +++ /dev/null @@ -1,2593 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// - -/***************************************************************************** - * name: ai_dmnet.c - * - * desc: Quake3 bot AI - * - * $Archive: /MissionPack/code/game/ai_dmnet.c $ - * $Author$ - * $Revision$ - * $Modtime: 11/14/00 2:42p $ - * $Date$ - * - *****************************************************************************/ - -#include "g_local.h" -#include "botlib.h" -#include "be_aas.h" -#include "be_ea.h" -#include "be_ai_char.h" -#include "be_ai_chat.h" -#include "be_ai_gen.h" -#include "be_ai_goal.h" -#include "be_ai_move.h" -#include "be_ai_weap.h" -// -#include "ai_main.h" -#include "ai_dmq3.h" -#include "ai_chat.h" -#include "ai_cmd.h" -#include "ai_dmnet.h" -#include "ai_team.h" -//data file headers -#include "chars.h" //characteristics -#include "inv.h" //indexes into the inventory -#include "syn.h" //synonyms -#include "match.h" //string matching types and vars - -// for the voice chats -//Blaze: was there a extra ../ here? -#include "../ui/menudef.h" - -//goal flag, see be_ai_goal.h for the other GFL_* -#define GFL_AIR 128 - -int numnodeswitches; -char nodeswitch[MAX_NODESWITCHES+1][144]; - -#define LOOKAHEAD_DISTANCE 300 - -/* -================== -BotResetNodeSwitches -================== -*/ -void BotResetNodeSwitches(void) { - numnodeswitches = 0; -} - -/* -================== -BotDumpNodeSwitches -================== -*/ -void BotDumpNodeSwitches(bot_state_t *bs) { - int i; - char netname[MAX_NETNAME]; - - ClientName(bs->client, netname, sizeof(netname)); - BotAI_Print(PRT_MESSAGE, "%s at %1.1f switched more than %d AI nodes\n", netname, FloatTime(), MAX_NODESWITCHES); - for (i = 0; i < numnodeswitches; i++) { - BotAI_Print(PRT_MESSAGE, nodeswitch[i]); - } - BotAI_Print(PRT_FATAL, ""); -} - -/* -================== -BotRecordNodeSwitch -================== -*/ -void BotRecordNodeSwitch(bot_state_t *bs, char *node, char *str) { - char netname[MAX_NETNAME]; - - ClientName(bs->client, netname, sizeof(netname)); - Com_sprintf(nodeswitch[numnodeswitches], 144, "%s at %2.1f entered %s: %s\n", netname, FloatTime(), node, str); -#ifdef DEBUG - if (0) { - BotAI_Print(PRT_MESSAGE, nodeswitch[numnodeswitches]); - } -#endif //DEBUG - numnodeswitches++; -} - -/* -================== -BotGetAirGoal -================== -*/ -int BotGetAirGoal(bot_state_t *bs, bot_goal_t *goal) { - bsp_trace_t bsptrace; - vec3_t end, mins = {-15, -15, -2}, maxs = {15, 15, 2}; - int areanum; - - //trace up until we hit solid - VectorCopy(bs->origin, end); - end[2] += 1000; - BotAI_Trace(&bsptrace, bs->origin, mins, maxs, end, bs->entitynum, CONTENTS_SOLID|CONTENTS_PLAYERCLIP); - //trace down until we hit water - VectorCopy(bsptrace.endpos, end); - BotAI_Trace(&bsptrace, end, mins, maxs, bs->origin, bs->entitynum, CONTENTS_WATER|CONTENTS_SLIME|CONTENTS_LAVA); - //if we found the water surface - if (bsptrace.fraction > 0) { - areanum = BotPointAreaNum(bsptrace.endpos); - if (areanum) { - VectorCopy(bsptrace.endpos, goal->origin); - goal->origin[2] -= 2; - goal->areanum = areanum; - goal->mins[0] = -15; - goal->mins[1] = -15; - goal->mins[2] = -1; - goal->maxs[0] = 15; - goal->maxs[1] = 15; - goal->maxs[2] = 1; - goal->flags = GFL_AIR; - goal->number = 0; - goal->iteminfo = 0; - goal->entitynum = 0; - return qtrue; - } - } - return qfalse; -} - -/* -================== -BotGoForAir -================== -*/ -int BotGoForAir(bot_state_t *bs, int tfl, bot_goal_t *ltg, float range) { - bot_goal_t goal; - - //if the bot needs air - if (bs->lastair_time < FloatTime() - 6) { - // -#ifdef DEBUG - //BotAI_Print(PRT_MESSAGE, "going for air\n"); -#endif //DEBUG - //if we can find an air goal - if (BotGetAirGoal(bs, &goal)) { - trap_BotPushGoal(bs->gs, &goal); - return qtrue; - } - else { - //get a nearby goal outside the water - while(trap_BotChooseNBGItem(bs->gs, bs->origin, bs->inventory, tfl, ltg, range)) { - trap_BotGetTopGoal(bs->gs, &goal); - //if the goal is not in water - if (!(trap_AAS_PointContents(goal.origin) & (CONTENTS_WATER|CONTENTS_SLIME|CONTENTS_LAVA))) { - return qtrue; - } - trap_BotPopGoal(bs->gs); - } - trap_BotResetAvoidGoals(bs->gs); - } - } - return qfalse; -} - -/* -================== -BotNearbyGoal -================== -*/ -int BotNearbyGoal(bot_state_t *bs, int tfl, bot_goal_t *ltg, float range) { - int ret; - - //check if the bot should go for air - if (BotGoForAir(bs, tfl, ltg, range)) return qtrue; - //if the bot is carrying the enemy flag - if (BotCTFCarryingFlag(bs)) { - //if the bot is just a few secs away from the base - if (trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, - bs->teamgoal.areanum, TFL_DEFAULT) < 300) { - //make the range really small - range = 50; - } - } - // - ret = trap_BotChooseNBGItem(bs->gs, bs->origin, bs->inventory, tfl, ltg, range); - /* - if (ret) - { - char buf[128]; - //get the goal at the top of the stack - trap_BotGetTopGoal(bs->gs, &goal); - trap_BotGoalName(goal.number, buf, sizeof(buf)); - BotAI_Print(PRT_MESSAGE, "%1.1f: new nearby goal %s\n", FloatTime(), buf); - } - //*/ - return ret; -} - -/* -================== -BotReachedGoal -================== -*/ -int BotReachedGoal(bot_state_t *bs, bot_goal_t *goal) { - if (goal->flags & GFL_ITEM) { - //if touching the goal - if (trap_BotTouchingGoal(bs->origin, goal)) { - if (!(goal->flags & GFL_DROPPED)) { - trap_BotSetAvoidGoalTime(bs->gs, goal->number, -1); - } - return qtrue; - } - //if the goal isn't there - if (trap_BotItemGoalInVisButNotVisible(bs->entitynum, bs->eye, bs->viewangles, goal)) { - /* - float avoidtime; - int t; - - avoidtime = trap_BotAvoidGoalTime(bs->gs, goal->number); - if (avoidtime > 0) { - t = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, goal->areanum, bs->tfl); - if ((float) t * 0.009 < avoidtime) - return qtrue; - } - */ - return qtrue; - } - //if in the goal area and below or above the goal and not swimming - if (bs->areanum == goal->areanum) { - if (bs->origin[0] > goal->origin[0] + goal->mins[0] && bs->origin[0] < goal->origin[0] + goal->maxs[0]) { - if (bs->origin[1] > goal->origin[1] + goal->mins[1] && bs->origin[1] < goal->origin[1] + goal->maxs[1]) { - if (!trap_AAS_Swimming(bs->origin)) { - return qtrue; - } - } - } - } - } - else if (goal->flags & GFL_AIR) { - //if touching the goal - if (trap_BotTouchingGoal(bs->origin, goal)) return qtrue; - //if the bot got air - if (bs->lastair_time > FloatTime() - 1) return qtrue; - } - else { - //if touching the goal - if (trap_BotTouchingGoal(bs->origin, goal)) return qtrue; - } - return qfalse; -} - -/* -================== -BotGetItemLongTermGoal -================== -*/ -int BotGetItemLongTermGoal(bot_state_t *bs, int tfl, bot_goal_t *goal) { - //if the bot has no goal - if (!trap_BotGetTopGoal(bs->gs, goal)) { - //BotAI_Print(PRT_MESSAGE, "no ltg on stack\n"); - bs->ltg_time = 0; - } - //if the bot touches the current goal - else if (BotReachedGoal(bs, goal)) { - BotChooseWeapon(bs); - bs->ltg_time = 0; - } - //if it is time to find a new long term goal - if (bs->ltg_time < FloatTime()) { - //pop the current goal from the stack - trap_BotPopGoal(bs->gs); - //BotAI_Print(PRT_MESSAGE, "%s: choosing new ltg\n", ClientName(bs->client, netname, sizeof(netname))); - //choose a new goal - //BotAI_Print(PRT_MESSAGE, "%6.1f client %d: BotChooseLTGItem\n", FloatTime(), bs->client); - if (trap_BotChooseLTGItem(bs->gs, bs->origin, bs->inventory, tfl)) { - /* - char buf[128]; - //get the goal at the top of the stack - trap_BotGetTopGoal(bs->gs, goal); - trap_BotGoalName(goal->number, buf, sizeof(buf)); - BotAI_Print(PRT_MESSAGE, "%1.1f: new long term goal %s\n", FloatTime(), buf); - //*/ - bs->ltg_time = FloatTime() + 20; - } - else {//the bot gets sorta stuck with all the avoid timings, shouldn't happen though - // -#ifdef DEBUG - char netname[128]; - - BotAI_Print(PRT_MESSAGE, "%s: no valid ltg (probably stuck)\n", ClientName(bs->client, netname, sizeof(netname))); -#endif - //trap_BotDumpAvoidGoals(bs->gs); - //reset the avoid goals and the avoid reach - trap_BotResetAvoidGoals(bs->gs); - trap_BotResetAvoidReach(bs->ms); - } - //get the goal at the top of the stack - return trap_BotGetTopGoal(bs->gs, goal); - } - return qtrue; -} - -/* -================== -BotGetLongTermGoal - -we could also create a seperate AI node for every long term goal type -however this saves us a lot of code -================== -*/ -int BotGetLongTermGoal(bot_state_t *bs, int tfl, int retreat, bot_goal_t *goal) { - vec3_t target, dir, dir2; - char netname[MAX_NETNAME]; - char buf[MAX_MESSAGE_SIZE]; - int areanum; - float croucher; - aas_entityinfo_t entinfo, botinfo; - bot_waypoint_t *wp; - - if (bs->ltgtype == LTG_TEAMHELP && !retreat) { - //check for bot typing status message - if (bs->teammessage_time && bs->teammessage_time < FloatTime()) { - BotAI_BotInitialChat(bs, "help_start", EasyClientName(bs->teammate, netname, sizeof(netname)), NULL); - trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL); - BotVoiceChatOnly(bs, bs->decisionmaker, VOICECHAT_YES); - trap_EA_Action(bs->client, ACTION_AFFIRMATIVE); - bs->teammessage_time = 0; - } - //if trying to help the team mate for more than a minute - if (bs->teamgoal_time < FloatTime()) - bs->ltgtype = 0; - //if the team mate IS visible for quite some time - if (bs->teammatevisible_time < FloatTime() - 10) bs->ltgtype = 0; - //get entity information of the companion - BotEntityInfo(bs->teammate, &entinfo); - //if the team mate is visible - if (BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, bs->teammate)) { - //if close just stand still there - VectorSubtract(entinfo.origin, bs->origin, dir); - if (VectorLengthSquared(dir) < Square(100)) { - trap_BotResetAvoidReach(bs->ms); - return qfalse; - } - } - else { - //last time the bot was NOT visible - bs->teammatevisible_time = FloatTime(); - } - //if the entity information is valid (entity in PVS) - if (entinfo.valid) { - areanum = BotPointAreaNum(entinfo.origin); - if (areanum && trap_AAS_AreaReachability(areanum)) { - //update team goal - bs->teamgoal.entitynum = bs->teammate; - bs->teamgoal.areanum = areanum; - VectorCopy(entinfo.origin, bs->teamgoal.origin); - VectorSet(bs->teamgoal.mins, -8, -8, -8); - VectorSet(bs->teamgoal.maxs, 8, 8, 8); - } - } - memcpy(goal, &bs->teamgoal, sizeof(bot_goal_t)); - return qtrue; - } - //if the bot accompanies someone - if (bs->ltgtype == LTG_TEAMACCOMPANY && !retreat) { - //check for bot typing status message - if (bs->teammessage_time && bs->teammessage_time < FloatTime()) { - BotAI_BotInitialChat(bs, "accompany_start", EasyClientName(bs->teammate, netname, sizeof(netname)), NULL); - trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL); - BotVoiceChatOnly(bs, bs->decisionmaker, VOICECHAT_YES); - trap_EA_Action(bs->client, ACTION_AFFIRMATIVE); - bs->teammessage_time = 0; - } - //if accompanying the companion for 3 minutes - if (bs->teamgoal_time < FloatTime()) { - BotAI_BotInitialChat(bs, "accompany_stop", EasyClientName(bs->teammate, netname, sizeof(netname)), NULL); - trap_BotEnterChat(bs->cs, bs->teammate, CHAT_TELL); - bs->ltgtype = 0; - } - //get entity information of the companion - BotEntityInfo(bs->teammate, &entinfo); - //if the companion is visible - if (BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, bs->teammate)) { - //update visible time - bs->teammatevisible_time = FloatTime(); - VectorSubtract(entinfo.origin, bs->origin, dir); - if (VectorLengthSquared(dir) < Square(bs->formation_dist)) { - // - // if the client being followed bumps into this bot then - // the bot should back up - BotEntityInfo(bs->entitynum, &botinfo); - // if the followed client is not standing ontop of the bot - if (botinfo.origin[2] + botinfo.maxs[2] > entinfo.origin[2] + entinfo.mins[2]) { - // if the bounding boxes touch each other - if (botinfo.origin[0] + botinfo.maxs[0] > entinfo.origin[0] + entinfo.mins[0] - 4&& - botinfo.origin[0] + botinfo.mins[0] < entinfo.origin[0] + entinfo.maxs[0] + 4) { - if (botinfo.origin[1] + botinfo.maxs[1] > entinfo.origin[1] + entinfo.mins[1] - 4 && - botinfo.origin[1] + botinfo.mins[1] < entinfo.origin[1] + entinfo.maxs[1] + 4) { - if (botinfo.origin[2] + botinfo.maxs[2] > entinfo.origin[2] + entinfo.mins[2] - 4 && - botinfo.origin[2] + botinfo.mins[2] < entinfo.origin[2] + entinfo.maxs[2] + 4) { - // if the followed client looks in the direction of this bot - AngleVectors(entinfo.angles, dir, NULL, NULL); - dir[2] = 0; - VectorNormalize(dir); - //VectorSubtract(entinfo.origin, entinfo.lastvisorigin, dir); - VectorSubtract(bs->origin, entinfo.origin, dir2); - VectorNormalize(dir2); - if (DotProduct(dir, dir2) > 0.7) { - // back up - BotSetupForMovement(bs); - trap_BotMoveInDirection(bs->ms, dir2, 400, MOVE_WALK); - } - } - } - } - } - //check if the bot wants to crouch - //don't crouch if crouched less than 5 seconds ago - if (bs->attackcrouch_time < FloatTime() - 5) { - croucher = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CROUCHER, 0, 1); - if (random() < bs->thinktime * croucher) { - bs->attackcrouch_time = FloatTime() + 5 + croucher * 15; - } - } - //don't crouch when swimming - if (trap_AAS_Swimming(bs->origin)) bs->attackcrouch_time = FloatTime() - 1; - //if not arrived yet or arived some time ago - if (bs->arrive_time < FloatTime() - 2) { - //if not arrived yet - if (!bs->arrive_time) { - trap_EA_Gesture(bs->client); - BotAI_BotInitialChat(bs, "accompany_arrive", EasyClientName(bs->teammate, netname, sizeof(netname)), NULL); - trap_BotEnterChat(bs->cs, bs->teammate, CHAT_TELL); - bs->arrive_time = FloatTime(); - } - //if the bot wants to crouch - else if (bs->attackcrouch_time > FloatTime()) { - trap_EA_Crouch(bs->client); - } - //else do some model taunts - else if (random() < bs->thinktime * 0.05) { - //do a gesture :) - trap_EA_Gesture(bs->client); - } - } - //if just arrived look at the companion - if (bs->arrive_time > FloatTime() - 2) { - VectorSubtract(entinfo.origin, bs->origin, dir); - vectoangles(dir, bs->ideal_viewangles); - bs->ideal_viewangles[2] *= 0.5; - } - //else look strategically around for enemies - else if (random() < bs->thinktime * 0.8) { - BotRoamGoal(bs, target); - VectorSubtract(target, bs->origin, dir); - vectoangles(dir, bs->ideal_viewangles); - bs->ideal_viewangles[2] *= 0.5; - } - //check if the bot wants to go for air - if (BotGoForAir(bs, bs->tfl, &bs->teamgoal, 400)) { - trap_BotResetLastAvoidReach(bs->ms); - //get the goal at the top of the stack - //trap_BotGetTopGoal(bs->gs, &tmpgoal); - //trap_BotGoalName(tmpgoal.number, buf, 144); - //BotAI_Print(PRT_MESSAGE, "new nearby goal %s\n", buf); - //time the bot gets to pick up the nearby goal item - bs->nbg_time = FloatTime() + 8; - AIEnter_Seek_NBG(bs); - return qfalse; - } - // - trap_BotResetAvoidReach(bs->ms); - return qfalse; - } - } - //if the entity information is valid (entity in PVS) - if (entinfo.valid) { - areanum = BotPointAreaNum(entinfo.origin); - if (areanum && trap_AAS_AreaReachability(areanum)) { - //update team goal - bs->teamgoal.entitynum = bs->teammate; - bs->teamgoal.areanum = areanum; - VectorCopy(entinfo.origin, bs->teamgoal.origin); - VectorSet(bs->teamgoal.mins, -8, -8, -8); - VectorSet(bs->teamgoal.maxs, 8, 8, 8); - } - } - //the goal the bot should go for - memcpy(goal, &bs->teamgoal, sizeof(bot_goal_t)); - //if the companion is NOT visible for too long - if (bs->teammatevisible_time < FloatTime() - 60) { - BotAI_BotInitialChat(bs, "accompany_cannotfind", EasyClientName(bs->teammate, netname, sizeof(netname)), NULL); - trap_BotEnterChat(bs->cs, bs->teammate, CHAT_TELL); - bs->ltgtype = 0; - // just to make sure the bot won't spam this message - bs->teammatevisible_time = FloatTime(); - } - return qtrue; - } - // - if (bs->ltgtype == LTG_DEFENDKEYAREA) { - if (trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, - bs->teamgoal.areanum, TFL_DEFAULT) > bs->defendaway_range) { - bs->defendaway_time = 0; - } - } - //if defending a key area - if (bs->ltgtype == LTG_DEFENDKEYAREA && !retreat && - bs->defendaway_time < FloatTime()) { - //check for bot typing status message - if (bs->teammessage_time && bs->teammessage_time < FloatTime()) { - trap_BotGoalName(bs->teamgoal.number, buf, sizeof(buf)); - BotAI_BotInitialChat(bs, "defend_start", buf, NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_TEAM); - BotVoiceChatOnly(bs, -1, VOICECHAT_ONDEFENSE); - bs->teammessage_time = 0; - } - //set the bot goal - memcpy(goal, &bs->teamgoal, sizeof(bot_goal_t)); - //stop after 2 minutes - if (bs->teamgoal_time < FloatTime()) { - trap_BotGoalName(bs->teamgoal.number, buf, sizeof(buf)); - BotAI_BotInitialChat(bs, "defend_stop", buf, NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_TEAM); - bs->ltgtype = 0; - } - //if very close... go away for some time - VectorSubtract(goal->origin, bs->origin, dir); - if (VectorLengthSquared(dir) < Square(70)) { - trap_BotResetAvoidReach(bs->ms); - bs->defendaway_time = FloatTime() + 3 + 3 * random(); - if (BotHasPersistantPowerupAndWeapon(bs)) { - bs->defendaway_range = 100; - } - else { - bs->defendaway_range = 350; - } - } - return qtrue; - } - //going to kill someone - if (bs->ltgtype == LTG_KILL && !retreat) { - //check for bot typing status message - if (bs->teammessage_time && bs->teammessage_time < FloatTime()) { - EasyClientName(bs->teamgoal.entitynum, buf, sizeof(buf)); - BotAI_BotInitialChat(bs, "kill_start", buf, NULL); - trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL); - bs->teammessage_time = 0; - } - // - if (bs->lastkilledplayer == bs->teamgoal.entitynum) { - EasyClientName(bs->teamgoal.entitynum, buf, sizeof(buf)); - BotAI_BotInitialChat(bs, "kill_done", buf, NULL); - trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL); - bs->lastkilledplayer = -1; - bs->ltgtype = 0; - } - // - if (bs->teamgoal_time < FloatTime()) { - bs->ltgtype = 0; - } - //just roam around - return BotGetItemLongTermGoal(bs, tfl, goal); - } - //get an item - if (bs->ltgtype == LTG_GETITEM && !retreat) { - //check for bot typing status message - if (bs->teammessage_time && bs->teammessage_time < FloatTime()) { - trap_BotGoalName(bs->teamgoal.number, buf, sizeof(buf)); - BotAI_BotInitialChat(bs, "getitem_start", buf, NULL); - trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL); - BotVoiceChatOnly(bs, bs->decisionmaker, VOICECHAT_YES); - trap_EA_Action(bs->client, ACTION_AFFIRMATIVE); - bs->teammessage_time = 0; - } - //set the bot goal - memcpy(goal, &bs->teamgoal, sizeof(bot_goal_t)); - //stop after some time - if (bs->teamgoal_time < FloatTime()) { - bs->ltgtype = 0; - } - // - if (trap_BotItemGoalInVisButNotVisible(bs->entitynum, bs->eye, bs->viewangles, goal)) { - trap_BotGoalName(bs->teamgoal.number, buf, sizeof(buf)); - BotAI_BotInitialChat(bs, "getitem_notthere", buf, NULL); - trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL); - bs->ltgtype = 0; - } - else if (BotReachedGoal(bs, goal)) { - trap_BotGoalName(bs->teamgoal.number, buf, sizeof(buf)); - BotAI_BotInitialChat(bs, "getitem_gotit", buf, NULL); - trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL); - bs->ltgtype = 0; - } - return qtrue; - } - //if camping somewhere - if ((bs->ltgtype == LTG_CAMP || bs->ltgtype == LTG_CAMPORDER) && !retreat) { - //check for bot typing status message - if (bs->teammessage_time && bs->teammessage_time < FloatTime()) { - if (bs->ltgtype == LTG_CAMPORDER) { - BotAI_BotInitialChat(bs, "camp_start", EasyClientName(bs->teammate, netname, sizeof(netname)), NULL); - trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL); - BotVoiceChatOnly(bs, bs->decisionmaker, VOICECHAT_YES); - trap_EA_Action(bs->client, ACTION_AFFIRMATIVE); - } - bs->teammessage_time = 0; - } - //set the bot goal - memcpy(goal, &bs->teamgoal, sizeof(bot_goal_t)); - // - if (bs->teamgoal_time < FloatTime()) { - if (bs->ltgtype == LTG_CAMPORDER) { - BotAI_BotInitialChat(bs, "camp_stop", NULL); - trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL); - } - bs->ltgtype = 0; - } - //if really near the camp spot - VectorSubtract(goal->origin, bs->origin, dir); - if (VectorLengthSquared(dir) < Square(60)) - { - //if not arrived yet - if (!bs->arrive_time) { - if (bs->ltgtype == LTG_CAMPORDER) { - BotAI_BotInitialChat(bs, "camp_arrive", EasyClientName(bs->teammate, netname, sizeof(netname)), NULL); - trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL); - BotVoiceChatOnly(bs, bs->decisionmaker, VOICECHAT_INPOSITION); - } - bs->arrive_time = FloatTime(); - } - //look strategically around for enemies - if (random() < bs->thinktime * 0.8) { - BotRoamGoal(bs, target); - VectorSubtract(target, bs->origin, dir); - vectoangles(dir, bs->ideal_viewangles); - bs->ideal_viewangles[2] *= 0.5; - } - //check if the bot wants to crouch - //don't crouch if crouched less than 5 seconds ago - if (bs->attackcrouch_time < FloatTime() - 5) { - croucher = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CROUCHER, 0, 1); - if (random() < bs->thinktime * croucher) { - bs->attackcrouch_time = FloatTime() + 5 + croucher * 15; - } - } - //if the bot wants to crouch - if (bs->attackcrouch_time > FloatTime()) { - trap_EA_Crouch(bs->client); - } - //don't crouch when swimming - if (trap_AAS_Swimming(bs->origin)) bs->attackcrouch_time = FloatTime() - 1; - //make sure the bot is not gonna drown - if (trap_PointContents(bs->eye,bs->entitynum) & (CONTENTS_WATER|CONTENTS_SLIME|CONTENTS_LAVA)) { - if (bs->ltgtype == LTG_CAMPORDER) { - BotAI_BotInitialChat(bs, "camp_stop", NULL); - trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL); - // - if (bs->lastgoal_ltgtype == LTG_CAMPORDER) { - bs->lastgoal_ltgtype = 0; - } - } - bs->ltgtype = 0; - } - // - if (bs->camp_range > 0) { - //FIXME: move around a bit - } - // - trap_BotResetAvoidReach(bs->ms); - return qfalse; - } - return qtrue; - } - //patrolling along several waypoints - if (bs->ltgtype == LTG_PATROL && !retreat) { - //check for bot typing status message - if (bs->teammessage_time && bs->teammessage_time < FloatTime()) { - strcpy(buf, ""); - for (wp = bs->patrolpoints; wp; wp = wp->next) { - strcat(buf, wp->name); - if (wp->next) strcat(buf, " to "); - } - BotAI_BotInitialChat(bs, "patrol_start", buf, NULL); - trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL); - BotVoiceChatOnly(bs, bs->decisionmaker, VOICECHAT_YES); - trap_EA_Action(bs->client, ACTION_AFFIRMATIVE); - bs->teammessage_time = 0; - } - // - if (!bs->curpatrolpoint) { - bs->ltgtype = 0; - return qfalse; - } - //if the bot touches the current goal - if (trap_BotTouchingGoal(bs->origin, &bs->curpatrolpoint->goal)) { - if (bs->patrolflags & PATROL_BACK) { - if (bs->curpatrolpoint->prev) { - bs->curpatrolpoint = bs->curpatrolpoint->prev; - } - else { - bs->curpatrolpoint = bs->curpatrolpoint->next; - bs->patrolflags &= ~PATROL_BACK; - } - } - else { - if (bs->curpatrolpoint->next) { - bs->curpatrolpoint = bs->curpatrolpoint->next; - } - else { - bs->curpatrolpoint = bs->curpatrolpoint->prev; - bs->patrolflags |= PATROL_BACK; - } - } - } - //stop after 5 minutes - if (bs->teamgoal_time < FloatTime()) { - BotAI_BotInitialChat(bs, "patrol_stop", NULL); - trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL); - bs->ltgtype = 0; - } - if (!bs->curpatrolpoint) { - bs->ltgtype = 0; - return qfalse; - } - memcpy(goal, &bs->curpatrolpoint->goal, sizeof(bot_goal_t)); - return qtrue; - } -#ifdef CTF - if (gametype == GT_CTF) { - //if going for enemy flag - if (bs->ltgtype == LTG_GETFLAG) { - //check for bot typing status message - if (bs->teammessage_time && bs->teammessage_time < FloatTime()) { - BotAI_BotInitialChat(bs, "captureflag_start", NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_TEAM); - BotVoiceChatOnly(bs, -1, VOICECHAT_ONGETFLAG); - bs->teammessage_time = 0; - } - // - switch(BotTeam(bs)) { - case TEAM_RED: memcpy(goal, &ctf_blueflag, sizeof(bot_goal_t)); break; - case TEAM_BLUE: memcpy(goal, &ctf_redflag, sizeof(bot_goal_t)); break; - default: bs->ltgtype = 0; return qfalse; - } - //if touching the flag - if (trap_BotTouchingGoal(bs->origin, goal)) { - // make sure the bot knows the flag isn't there anymore - switch(BotTeam(bs)) { - case TEAM_RED: bs->blueflagstatus = 1; break; - case TEAM_BLUE: bs->redflagstatus = 1; break; - } - bs->ltgtype = 0; - } - //stop after 3 minutes - if (bs->teamgoal_time < FloatTime()) { - bs->ltgtype = 0; - } - BotAlternateRoute(bs, goal); - return qtrue; - } - //if rushing to the base - if (bs->ltgtype == LTG_RUSHBASE && bs->rushbaseaway_time < FloatTime()) { - switch(BotTeam(bs)) { - case TEAM_RED: memcpy(goal, &ctf_redflag, sizeof(bot_goal_t)); break; - case TEAM_BLUE: memcpy(goal, &ctf_blueflag, sizeof(bot_goal_t)); break; - default: bs->ltgtype = 0; return qfalse; - } - //if not carrying the flag anymore - if (!BotCTFCarryingFlag(bs)) bs->ltgtype = 0; - //quit rushing after 2 minutes - if (bs->teamgoal_time < FloatTime()) bs->ltgtype = 0; - //if touching the base flag the bot should loose the enemy flag - if (trap_BotTouchingGoal(bs->origin, goal)) { - //if the bot is still carrying the enemy flag then the - //base flag is gone, now just walk near the base a bit - if (BotCTFCarryingFlag(bs)) { - trap_BotResetAvoidReach(bs->ms); - bs->rushbaseaway_time = FloatTime() + 5 + 10 * random(); - //FIXME: add chat to tell the others to get back the flag - } - else { - bs->ltgtype = 0; - } - } - BotAlternateRoute(bs, goal); - return qtrue; - } - //returning flag - if (bs->ltgtype == LTG_RETURNFLAG) { - //check for bot typing status message - if (bs->teammessage_time && bs->teammessage_time < FloatTime()) { - BotAI_BotInitialChat(bs, "returnflag_start", NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_TEAM); - BotVoiceChatOnly(bs, -1, VOICECHAT_ONRETURNFLAG); - bs->teammessage_time = 0; - } - // - switch(BotTeam(bs)) { - case TEAM_RED: memcpy(goal, &ctf_blueflag, sizeof(bot_goal_t)); break; - case TEAM_BLUE: memcpy(goal, &ctf_redflag, sizeof(bot_goal_t)); break; - default: bs->ltgtype = 0; return qfalse; - } - //if touching the flag - if (trap_BotTouchingGoal(bs->origin, goal)) bs->ltgtype = 0; - //stop after 3 minutes - if (bs->teamgoal_time < FloatTime()) { - bs->ltgtype = 0; - } - BotAlternateRoute(bs, goal); - return qtrue; - } - } -#endif //CTF -#ifdef MISSIONPACK - else if (gametype == GT_1FCTF) { - if (bs->ltgtype == LTG_GETFLAG) { - //check for bot typing status message - if (bs->teammessage_time && bs->teammessage_time < FloatTime()) { - BotAI_BotInitialChat(bs, "captureflag_start", NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_TEAM); - BotVoiceChatOnly(bs, -1, VOICECHAT_ONGETFLAG); - bs->teammessage_time = 0; - } - memcpy(goal, &ctf_neutralflag, sizeof(bot_goal_t)); - //if touching the flag - if (trap_BotTouchingGoal(bs->origin, goal)) { - bs->ltgtype = 0; - } - //stop after 3 minutes - if (bs->teamgoal_time < FloatTime()) { - bs->ltgtype = 0; - } - return qtrue; - } - //if rushing to the base - if (bs->ltgtype == LTG_RUSHBASE) { - switch(BotTeam(bs)) { - case TEAM_RED: memcpy(goal, &ctf_blueflag, sizeof(bot_goal_t)); break; - case TEAM_BLUE: memcpy(goal, &ctf_redflag, sizeof(bot_goal_t)); break; - default: bs->ltgtype = 0; return qfalse; - } - //if not carrying the flag anymore - if (!Bot1FCTFCarryingFlag(bs)) { - bs->ltgtype = 0; - } - //quit rushing after 2 minutes - if (bs->teamgoal_time < FloatTime()) { - bs->ltgtype = 0; - } - //if touching the base flag the bot should loose the enemy flag - if (trap_BotTouchingGoal(bs->origin, goal)) { - bs->ltgtype = 0; - } - BotAlternateRoute(bs, goal); - return qtrue; - } - //attack the enemy base - if (bs->ltgtype == LTG_ATTACKENEMYBASE && - bs->attackaway_time < FloatTime()) { - //check for bot typing status message - if (bs->teammessage_time && bs->teammessage_time < FloatTime()) { - BotAI_BotInitialChat(bs, "attackenemybase_start", NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_TEAM); - BotVoiceChatOnly(bs, -1, VOICECHAT_ONOFFENSE); - bs->teammessage_time = 0; - } - switch(BotTeam(bs)) { - case TEAM_RED: memcpy(goal, &ctf_blueflag, sizeof(bot_goal_t)); break; - case TEAM_BLUE: memcpy(goal, &ctf_redflag, sizeof(bot_goal_t)); break; - default: bs->ltgtype = 0; return qfalse; - } - //quit rushing after 2 minutes - if (bs->teamgoal_time < FloatTime()) { - bs->ltgtype = 0; - } - //if touching the base flag the bot should loose the enemy flag - if (trap_BotTouchingGoal(bs->origin, goal)) { - bs->attackaway_time = FloatTime() + 2 + 5 * random(); - } - return qtrue; - } - //returning flag - if (bs->ltgtype == LTG_RETURNFLAG) { - //check for bot typing status message - if (bs->teammessage_time && bs->teammessage_time < FloatTime()) { - BotAI_BotInitialChat(bs, "returnflag_start", NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_TEAM); - BotVoiceChatOnly(bs, -1, VOICECHAT_ONRETURNFLAG); - bs->teammessage_time = 0; - } - // - if (bs->teamgoal_time < FloatTime()) { - bs->ltgtype = 0; - } - //just roam around - return BotGetItemLongTermGoal(bs, tfl, goal); - } - } - else if (gametype == GT_OBELISK) { - if (bs->ltgtype == LTG_ATTACKENEMYBASE && - bs->attackaway_time < FloatTime()) { - - //check for bot typing status message - if (bs->teammessage_time && bs->teammessage_time < FloatTime()) { - BotAI_BotInitialChat(bs, "attackenemybase_start", NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_TEAM); - BotVoiceChatOnly(bs, -1, VOICECHAT_ONOFFENSE); - bs->teammessage_time = 0; - } - switch(BotTeam(bs)) { - case TEAM_RED: memcpy(goal, &blueobelisk, sizeof(bot_goal_t)); break; - case TEAM_BLUE: memcpy(goal, &redobelisk, sizeof(bot_goal_t)); break; - default: bs->ltgtype = 0; return qfalse; - } - //if the bot no longer wants to attack the obelisk - if (BotFeelingBad(bs) > 50) { - return BotGetItemLongTermGoal(bs, tfl, goal); - } - //if touching the obelisk - if (trap_BotTouchingGoal(bs->origin, goal)) { - bs->attackaway_time = FloatTime() + 3 + 5 * random(); - } - // or very close to the obelisk - VectorSubtract(bs->origin, goal->origin, dir); - if (VectorLengthSquared(dir) < Square(60)) { - bs->attackaway_time = FloatTime() + 3 + 5 * random(); - } - //quit rushing after 2 minutes - if (bs->teamgoal_time < FloatTime()) { - bs->ltgtype = 0; - } - BotAlternateRoute(bs, goal); - //just move towards the obelisk - return qtrue; - } - } - else if (gametype == GT_HARVESTER) { - //if rushing to the base - if (bs->ltgtype == LTG_RUSHBASE) { - switch(BotTeam(bs)) { - case TEAM_RED: memcpy(goal, &blueobelisk, sizeof(bot_goal_t)); break; - case TEAM_BLUE: memcpy(goal, &redobelisk, sizeof(bot_goal_t)); break; - default: BotGoHarvest(bs); return qfalse; - } - //if not carrying any cubes - if (!BotHarvesterCarryingCubes(bs)) { - BotGoHarvest(bs); - return qfalse; - } - //quit rushing after 2 minutes - if (bs->teamgoal_time < FloatTime()) { - BotGoHarvest(bs); - return qfalse; - } - //if touching the base flag the bot should loose the enemy flag - if (trap_BotTouchingGoal(bs->origin, goal)) { - BotGoHarvest(bs); - return qfalse; - } - BotAlternateRoute(bs, goal); - return qtrue; - } - //attack the enemy base - if (bs->ltgtype == LTG_ATTACKENEMYBASE && - bs->attackaway_time < FloatTime()) { - //check for bot typing status message - if (bs->teammessage_time && bs->teammessage_time < FloatTime()) { - BotAI_BotInitialChat(bs, "attackenemybase_start", NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_TEAM); - BotVoiceChatOnly(bs, -1, VOICECHAT_ONOFFENSE); - bs->teammessage_time = 0; - } - switch(BotTeam(bs)) { - case TEAM_RED: memcpy(goal, &blueobelisk, sizeof(bot_goal_t)); break; - case TEAM_BLUE: memcpy(goal, &redobelisk, sizeof(bot_goal_t)); break; - default: bs->ltgtype = 0; return qfalse; - } - //quit rushing after 2 minutes - if (bs->teamgoal_time < FloatTime()) { - bs->ltgtype = 0; - } - //if touching the base flag the bot should loose the enemy flag - if (trap_BotTouchingGoal(bs->origin, goal)) { - bs->attackaway_time = FloatTime() + 2 + 5 * random(); - } - return qtrue; - } - //harvest cubes - if (bs->ltgtype == LTG_HARVEST && - bs->harvestaway_time < FloatTime()) { - //check for bot typing status message - if (bs->teammessage_time && bs->teammessage_time < FloatTime()) { - BotAI_BotInitialChat(bs, "harvest_start", NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_TEAM); - BotVoiceChatOnly(bs, -1, VOICECHAT_ONOFFENSE); - bs->teammessage_time = 0; - } - memcpy(goal, &neutralobelisk, sizeof(bot_goal_t)); - // - if (bs->teamgoal_time < FloatTime()) { - bs->ltgtype = 0; - } - // - if (trap_BotTouchingGoal(bs->origin, goal)) { - bs->harvestaway_time = FloatTime() + 4 + 3 * random(); - } - return qtrue; - } - } -#endif - //normal goal stuff - return BotGetItemLongTermGoal(bs, tfl, goal); -} - -/* -================== -BotLongTermGoal -================== -*/ -int BotLongTermGoal(bot_state_t *bs, int tfl, int retreat, bot_goal_t *goal) { - aas_entityinfo_t entinfo; - char teammate[MAX_MESSAGE_SIZE]; - float squaredist; - int areanum; - vec3_t dir; - - //FIXME: also have air long term goals? - // - //if the bot is leading someone and not retreating - if (bs->lead_time > 0 && !retreat) { - if (bs->lead_time < FloatTime()) { - BotAI_BotInitialChat(bs, "lead_stop", EasyClientName(bs->lead_teammate, teammate, sizeof(teammate)), NULL); - trap_BotEnterChat(bs->cs, bs->teammate, CHAT_TELL); - bs->lead_time = 0; - return BotGetLongTermGoal(bs, tfl, retreat, goal); - } - // - if (bs->leadmessage_time < 0 && -bs->leadmessage_time < FloatTime()) { - BotAI_BotInitialChat(bs, "followme", EasyClientName(bs->lead_teammate, teammate, sizeof(teammate)), NULL); - trap_BotEnterChat(bs->cs, bs->teammate, CHAT_TELL); - bs->leadmessage_time = FloatTime(); - } - //get entity information of the companion - BotEntityInfo(bs->lead_teammate, &entinfo); - // - if (entinfo.valid) { - areanum = BotPointAreaNum(entinfo.origin); - if (areanum && trap_AAS_AreaReachability(areanum)) { - //update team goal - bs->lead_teamgoal.entitynum = bs->lead_teammate; - bs->lead_teamgoal.areanum = areanum; - VectorCopy(entinfo.origin, bs->lead_teamgoal.origin); - VectorSet(bs->lead_teamgoal.mins, -8, -8, -8); - VectorSet(bs->lead_teamgoal.maxs, 8, 8, 8); - } - } - //if the team mate is visible - if (BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, bs->lead_teammate)) { - bs->leadvisible_time = FloatTime(); - } - //if the team mate is not visible for 1 seconds - if (bs->leadvisible_time < FloatTime() - 1) { - bs->leadbackup_time = FloatTime() + 2; - } - //distance towards the team mate - VectorSubtract(bs->origin, bs->lead_teamgoal.origin, dir); - squaredist = VectorLengthSquared(dir); - //if backing up towards the team mate - if (bs->leadbackup_time > FloatTime()) { - if (bs->leadmessage_time < FloatTime() - 20) { - BotAI_BotInitialChat(bs, "followme", EasyClientName(bs->lead_teammate, teammate, sizeof(teammate)), NULL); - trap_BotEnterChat(bs->cs, bs->teammate, CHAT_TELL); - bs->leadmessage_time = FloatTime(); - } - //if very close to the team mate - if (squaredist < Square(100)) { - bs->leadbackup_time = 0; - } - //the bot should go back to the team mate - memcpy(goal, &bs->lead_teamgoal, sizeof(bot_goal_t)); - return qtrue; - } - else { - //if quite distant from the team mate - if (squaredist > Square(500)) { - if (bs->leadmessage_time < FloatTime() - 20) { - BotAI_BotInitialChat(bs, "followme", EasyClientName(bs->lead_teammate, teammate, sizeof(teammate)), NULL); - trap_BotEnterChat(bs->cs, bs->teammate, CHAT_TELL); - bs->leadmessage_time = FloatTime(); - } - //look at the team mate - VectorSubtract(entinfo.origin, bs->origin, dir); - vectoangles(dir, bs->ideal_viewangles); - bs->ideal_viewangles[2] *= 0.5; - //just wait for the team mate - return qfalse; - } - } - } - return BotGetLongTermGoal(bs, tfl, retreat, goal); -} - -/* -================== -AIEnter_Intermission -================== -*/ -void AIEnter_Intermission(bot_state_t *bs) { - BotRecordNodeSwitch(bs, "intermission", ""); - //reset the bot state - BotResetState(bs); - //check for end level chat - if (BotChat_EndLevel(bs)) { - trap_BotEnterChat(bs->cs, 0, bs->chatto); - } - bs->ainode = AINode_Intermission; -} - -/* -================== -AINode_Intermission -================== -*/ -int AINode_Intermission(bot_state_t *bs) { - //if the intermission ended - if (!BotIntermission(bs)) { - if (BotChat_StartLevel(bs)) { - bs->stand_time = FloatTime() + BotChatTime(bs); - } - else { - bs->stand_time = FloatTime() + 2; - } - AIEnter_Stand(bs); - } - return qtrue; -} - -/* -================== -AIEnter_Observer -================== -*/ -void AIEnter_Observer(bot_state_t *bs) { - BotRecordNodeSwitch(bs, "observer", ""); - //reset the bot state - BotResetState(bs); - bs->ainode = AINode_Observer; -} - -/* -================== -AINode_Observer -================== -*/ -int AINode_Observer(bot_state_t *bs) { - //if the bot left observer mode - if (!BotIsObserver(bs)) { - AIEnter_Stand(bs); - } - return qtrue; -} - -/* -================== -AIEnter_Stand -================== -*/ -void AIEnter_Stand(bot_state_t *bs) { - BotRecordNodeSwitch(bs, "stand", ""); - bs->standfindenemy_time = FloatTime() + 1; - bs->ainode = AINode_Stand; -} - -/* -================== -AINode_Stand -================== -*/ -int AINode_Stand(bot_state_t *bs) { - - //if the bot's health decreased - if (bs->lastframe_health > bs->inventory[INVENTORY_HEALTH]) { - if (BotChat_HitTalking(bs)) { - bs->standfindenemy_time = FloatTime() + BotChatTime(bs) + 0.1; - bs->stand_time = FloatTime() + BotChatTime(bs) + 0.1; - } - } - if (bs->standfindenemy_time < FloatTime()) { - if (BotFindEnemy(bs, -1)) { - AIEnter_Battle_Fight(bs); - return qfalse; - } - bs->standfindenemy_time = FloatTime() + 1; - } - // put up chat icon - trap_EA_Talk(bs->client); - // when done standing - if (bs->stand_time < FloatTime()) { - trap_BotEnterChat(bs->cs, 0, bs->chatto); - AIEnter_Seek_LTG(bs); - return qfalse; - } - // - return qtrue; -} - -/* -================== -AIEnter_Respawn -================== -*/ -void AIEnter_Respawn(bot_state_t *bs) { - BotRecordNodeSwitch(bs, "respawn", ""); - //reset some states - trap_BotResetMoveState(bs->ms); - trap_BotResetGoalState(bs->gs); - trap_BotResetAvoidGoals(bs->gs); - trap_BotResetAvoidReach(bs->ms); - //if the bot wants to chat - if (BotChat_Death(bs)) { - bs->respawn_time = FloatTime() + BotChatTime(bs); - bs->respawnchat_time = FloatTime(); - } - else { - bs->respawn_time = FloatTime() + 1 + random(); - bs->respawnchat_time = 0; - } - //set respawn state - bs->respawn_wait = qfalse; - bs->ainode = AINode_Respawn; -} - -/* -================== -AINode_Respawn -================== -*/ -int AINode_Respawn(bot_state_t *bs) { - // if waiting for the actual respawn - if (bs->respawn_wait) { - if (!BotIsDead(bs)) { - AIEnter_Seek_LTG(bs); - } - else { - trap_EA_Respawn(bs->client); - } - } - else if (bs->respawn_time < FloatTime()) { - //wait until respawned - bs->respawn_wait = qtrue; - //elementary action respawn - trap_EA_Respawn(bs->client); - // - if (bs->respawnchat_time) { - trap_BotEnterChat(bs->cs, 0, bs->chatto); - bs->enemy = -1; - } - } - if (bs->respawnchat_time && bs->respawnchat_time < FloatTime() - 0.5) { - trap_EA_Talk(bs->client); - } - // - return qtrue; -} - -/* -================== -BotSelectActivateWeapon -================== -*/ -int BotSelectActivateWeapon(bot_state_t *bs) { - // - if (bs->inventory[INVENTORY_MACHINEGUN] > 0 && bs->inventory[INVENTORY_BULLETS] > 0) - return WEAPONINDEX_MACHINEGUN; - else if (bs->inventory[INVENTORY_SHOTGUN] > 0 && bs->inventory[INVENTORY_SHELLS] > 0) - return WEAPONINDEX_SHOTGUN; - else if (bs->inventory[INVENTORY_PLASMAGUN] > 0 && bs->inventory[INVENTORY_CELLS] > 0) - return WEAPONINDEX_PLASMAGUN; - else if (bs->inventory[INVENTORY_LIGHTNING] > 0 && bs->inventory[INVENTORY_LIGHTNINGAMMO] > 0) - return WEAPONINDEX_LIGHTNING; -#ifdef MISSIONPACK - else if (bs->inventory[INVENTORY_CHAINGUN] > 0 && bs->inventory[INVENTORY_BELT] > 0) - return WEAPONINDEX_CHAINGUN; - else if (bs->inventory[INVENTORY_NAILGUN] > 0 && bs->inventory[INVENTORY_NAILS] > 0) - return WEAPONINDEX_NAILGUN; -#endif - else if (bs->inventory[INVENTORY_RAILGUN] > 0 && bs->inventory[INVENTORY_SLUGS] > 0) - return WEAPONINDEX_RAILGUN; - else if (bs->inventory[INVENTORY_ROCKETLAUNCHER] > 0 && bs->inventory[INVENTORY_ROCKETS] > 0) - return WEAPONINDEX_ROCKET_LAUNCHER; - else if (bs->inventory[INVENTORY_BFG10K] > 0 && bs->inventory[INVENTORY_BFGAMMO] > 0) - return WEAPONINDEX_BFG; - else { - return -1; - } -} - -/* -================== -BotClearPath - - try to deactivate obstacles like proximity mines on the bot's path -================== -*/ -void BotClearPath(bot_state_t *bs, bot_moveresult_t *moveresult) { - int i, bestmine; - float dist, bestdist; - vec3_t target, dir; - bsp_trace_t bsptrace; - entityState_t state; - - // if there is a dead body wearing kamikze nearby - if (bs->kamikazebody) { - // if the bot's view angles and weapon are not used for movement - if ( !(moveresult->flags & (MOVERESULT_MOVEMENTVIEW | MOVERESULT_MOVEMENTWEAPON)) ) { - // - BotAI_GetEntityState(bs->kamikazebody, &state); - VectorCopy(state.pos.trBase, target); - target[2] += 8; - VectorSubtract(target, bs->eye, dir); - vectoangles(dir, moveresult->ideal_viewangles); - // - moveresult->weapon = BotSelectActivateWeapon(bs); - if (moveresult->weapon == -1) { - // FIXME: run away! - moveresult->weapon = 0; - } - if (moveresult->weapon) { - // - moveresult->flags |= MOVERESULT_MOVEMENTWEAPON | MOVERESULT_MOVEMENTVIEW; - // if holding the right weapon - if (bs->cur_ps.weapon == moveresult->weapon) { - // if the bot is pretty close with it's aim - if (InFieldOfVision(bs->viewangles, 20, moveresult->ideal_viewangles)) { - // - BotAI_Trace(&bsptrace, bs->eye, NULL, NULL, target, bs->entitynum, MASK_SHOT); - // if the mine is visible from the current position - if (bsptrace.fraction >= 1.0 || bsptrace.ent == state.number) { - // shoot at the mine - trap_EA_Attack(bs->client); - } - } - } - } - } - } - if (moveresult->flags & MOVERESULT_BLOCKEDBYAVOIDSPOT) { - bs->blockedbyavoidspot_time = FloatTime() + 5; - } - // if blocked by an avoid spot and the view angles and weapon are used for movement - if (bs->blockedbyavoidspot_time > FloatTime() && - !(moveresult->flags & (MOVERESULT_MOVEMENTVIEW | MOVERESULT_MOVEMENTWEAPON)) ) { - bestdist = 300; - bestmine = -1; - for (i = 0; i < bs->numproxmines; i++) { - BotAI_GetEntityState(bs->proxmines[i], &state); - VectorSubtract(state.pos.trBase, bs->origin, dir); - dist = VectorLength(dir); - if (dist < bestdist) { - bestdist = dist; - bestmine = i; - } - } - if (bestmine != -1) { - // - // state->generic1 == TEAM_RED || state->generic1 == TEAM_BLUE - // - // deactivate prox mines in the bot's path by shooting - // rockets or plasma cells etc. at them - BotAI_GetEntityState(bs->proxmines[bestmine], &state); - VectorCopy(state.pos.trBase, target); - target[2] += 2; - VectorSubtract(target, bs->eye, dir); - vectoangles(dir, moveresult->ideal_viewangles); - // if the bot has a weapon that does splash damage - if (bs->inventory[INVENTORY_PLASMAGUN] > 0 && bs->inventory[INVENTORY_CELLS] > 0) - moveresult->weapon = WEAPONINDEX_PLASMAGUN; - else if (bs->inventory[INVENTORY_ROCKETLAUNCHER] > 0 && bs->inventory[INVENTORY_ROCKETS] > 0) - moveresult->weapon = WEAPONINDEX_ROCKET_LAUNCHER; - else if (bs->inventory[INVENTORY_BFG10K] > 0 && bs->inventory[INVENTORY_BFGAMMO] > 0) - moveresult->weapon = WEAPONINDEX_BFG; - else { - moveresult->weapon = 0; - } - if (moveresult->weapon) { - // - moveresult->flags |= MOVERESULT_MOVEMENTWEAPON | MOVERESULT_MOVEMENTVIEW; - // if holding the right weapon - if (bs->cur_ps.weapon == moveresult->weapon) { - // if the bot is pretty close with it's aim - if (InFieldOfVision(bs->viewangles, 20, moveresult->ideal_viewangles)) { - // - BotAI_Trace(&bsptrace, bs->eye, NULL, NULL, target, bs->entitynum, MASK_SHOT); - // if the mine is visible from the current position - if (bsptrace.fraction >= 1.0 || bsptrace.ent == state.number) { - // shoot at the mine - trap_EA_Attack(bs->client); - } - } - } - } - } - } -} - -/* -================== -AIEnter_Seek_ActivateEntity -================== -*/ -void AIEnter_Seek_ActivateEntity(bot_state_t *bs) { - BotRecordNodeSwitch(bs, "activate entity", ""); - bs->ainode = AINode_Seek_ActivateEntity; -} - -/* -================== -AINode_Seek_Activate_Entity -================== -*/ -int AINode_Seek_ActivateEntity(bot_state_t *bs) { - bot_goal_t *goal; - vec3_t target, dir, ideal_viewangles; - bot_moveresult_t moveresult; - int targetvisible; - bsp_trace_t bsptrace; - aas_entityinfo_t entinfo; - - if (BotIsObserver(bs)) { - BotClearActivateGoalStack(bs); - AIEnter_Observer(bs); - return qfalse; - } - //if in the intermission - if (BotIntermission(bs)) { - BotClearActivateGoalStack(bs); - AIEnter_Intermission(bs); - return qfalse; - } - //respawn if dead - if (BotIsDead(bs)) { - BotClearActivateGoalStack(bs); - AIEnter_Respawn(bs); - return qfalse; - } - // - bs->tfl = TFL_DEFAULT; - if (bot_grapple.integer) bs->tfl |= TFL_GRAPPLEHOOK; - //if in lava or slime the bot should be able to get out - if (BotInLavaOrSlime(bs)) bs->tfl |= TFL_LAVA|TFL_SLIME; - //map specific code - BotMapScripts(bs); - //no enemy - bs->enemy = -1; - // if the bot has no activate goal - if (!bs->activatestack) { - BotClearActivateGoalStack(bs); - AIEnter_Seek_NBG(bs); - return qfalse; - } - // - goal = &bs->activatestack->goal; - // initialize target being visible to false - targetvisible = qfalse; - // if the bot has to shoot at a target to activate something - if (bs->activatestack->shoot) { - // - BotAI_Trace(&bsptrace, bs->eye, NULL, NULL, bs->activatestack->target, bs->entitynum, MASK_SHOT); - // if the shootable entity is visible from the current position - if (bsptrace.fraction >= 1.0 || bsptrace.ent == goal->entitynum) { - targetvisible = qtrue; - // if holding the right weapon - if (bs->cur_ps.weapon == bs->activatestack->weapon) { - VectorSubtract(bs->activatestack->target, bs->eye, dir); - vectoangles(dir, ideal_viewangles); - // if the bot is pretty close with it's aim - if (InFieldOfVision(bs->viewangles, 20, ideal_viewangles)) { - trap_EA_Attack(bs->client); - } - } - } - } - // if the shoot target is visible - if (targetvisible) { - // get the entity info of the entity the bot is shooting at - BotEntityInfo(goal->entitynum, &entinfo); - // if the entity the bot shoots at moved - if (!VectorCompare(bs->activatestack->origin, entinfo.origin)) { -#ifdef DEBUG - BotAI_Print(PRT_MESSAGE, "hit shootable button or trigger\n"); -#endif //DEBUG - bs->activatestack->time = 0; - } - // if the activate goal has been activated or the bot takes too long - if (bs->activatestack->time < FloatTime()) { - BotPopFromActivateGoalStack(bs); - // if there are more activate goals on the stack - if (bs->activatestack) { - bs->activatestack->time = FloatTime() + 10; - return qfalse; - } - AIEnter_Seek_NBG(bs); - return qfalse; - } - memset(&moveresult, 0, sizeof(bot_moveresult_t)); - } - else { - //if the bot has no goal - if (!goal) { - bs->activatestack->time = 0; - } - // if the bot does not have a shoot goal - else if (!bs->activatestack->shoot) { - //if the bot touches the current goal - if (trap_BotTouchingGoal(bs->origin, goal)) { -#ifdef DEBUG - BotAI_Print(PRT_MESSAGE, "touched button or trigger\n"); -#endif //DEBUG - bs->activatestack->time = 0; - } - } - // if the activate goal has been activated or the bot takes too long - if (bs->activatestack->time < FloatTime()) { - BotPopFromActivateGoalStack(bs); - // if there are more activate goals on the stack - if (bs->activatestack) { - bs->activatestack->time = FloatTime() + 10; - return qfalse; - } - AIEnter_Seek_NBG(bs); - return qfalse; - } - //predict obstacles - if (BotAIPredictObstacles(bs, goal)) - return qfalse; - //initialize the movement state - BotSetupForMovement(bs); - //move towards the goal - trap_BotMoveToGoal(&moveresult, bs->ms, goal, bs->tfl); - //if the movement failed - if (moveresult.failure) { - //reset the avoid reach, otherwise bot is stuck in current area - trap_BotResetAvoidReach(bs->ms); - // - bs->activatestack->time = 0; - } - //check if the bot is blocked - BotAIBlocked(bs, &moveresult, qtrue); - } - // - BotClearPath(bs, &moveresult); - // if the bot has to shoot to activate - if (bs->activatestack->shoot) { - // if the view angles aren't yet used for the movement - if (!(moveresult.flags & MOVERESULT_MOVEMENTVIEW)) { - VectorSubtract(bs->activatestack->target, bs->eye, dir); - vectoangles(dir, moveresult.ideal_viewangles); - moveresult.flags |= MOVERESULT_MOVEMENTVIEW; - } - // if there's no weapon yet used for the movement - if (!(moveresult.flags & MOVERESULT_MOVEMENTWEAPON)) { - moveresult.flags |= MOVERESULT_MOVEMENTWEAPON; - // - bs->activatestack->weapon = BotSelectActivateWeapon(bs); - if (bs->activatestack->weapon == -1) { - //FIXME: find a decent weapon first - bs->activatestack->weapon = 0; - } - moveresult.weapon = bs->activatestack->weapon; - } - } - // if the ideal view angles are set for movement - if (moveresult.flags & (MOVERESULT_MOVEMENTVIEWSET|MOVERESULT_MOVEMENTVIEW|MOVERESULT_SWIMVIEW)) { - VectorCopy(moveresult.ideal_viewangles, bs->ideal_viewangles); - } - //if waiting for something - else if (moveresult.flags & MOVERESULT_WAITING) { - if (random() < bs->thinktime * 0.8) { - BotRoamGoal(bs, target); - VectorSubtract(target, bs->origin, dir); - vectoangles(dir, bs->ideal_viewangles); - bs->ideal_viewangles[2] *= 0.5; - } - } - else if (!(bs->flags & BFL_IDEALVIEWSET)) { - if (trap_BotMovementViewTarget(bs->ms, goal, bs->tfl, 300, target)) { - VectorSubtract(target, bs->origin, dir); - vectoangles(dir, bs->ideal_viewangles); - } - else { - vectoangles(moveresult.movedir, bs->ideal_viewangles); - } - bs->ideal_viewangles[2] *= 0.5; - } - //if the weapon is used for the bot movement - if (moveresult.flags & MOVERESULT_MOVEMENTWEAPON) - bs->weaponnum = moveresult.weapon; - //if there is an enemy - if (BotFindEnemy(bs, -1)) { - if (BotWantsToRetreat(bs)) { - //keep the current long term goal and retreat - AIEnter_Battle_NBG(bs); - } - else { - trap_BotResetLastAvoidReach(bs->ms); - //empty the goal stack - trap_BotEmptyGoalStack(bs->gs); - //go fight - AIEnter_Battle_Fight(bs); - } - BotClearActivateGoalStack(bs); - } - return qtrue; -} - -/* -================== -AIEnter_Seek_NBG -================== -*/ -void AIEnter_Seek_NBG(bot_state_t *bs) { - bot_goal_t goal; - char buf[144]; - - if (trap_BotGetTopGoal(bs->gs, &goal)) { - trap_BotGoalName(goal.number, buf, 144); - BotRecordNodeSwitch(bs, "seek NBG", buf); - } - else { - BotRecordNodeSwitch(bs, "seek NBG", "no goal"); - } - bs->ainode = AINode_Seek_NBG; -} - -/* -================== -AINode_Seek_NBG -================== -*/ -int AINode_Seek_NBG(bot_state_t *bs) { - bot_goal_t goal; - vec3_t target, dir; - bot_moveresult_t moveresult; - - if (BotIsObserver(bs)) { - AIEnter_Observer(bs); - return qfalse; - } - //if in the intermission - if (BotIntermission(bs)) { - AIEnter_Intermission(bs); - return qfalse; - } - //respawn if dead - if (BotIsDead(bs)) { - AIEnter_Respawn(bs); - return qfalse; - } - // - bs->tfl = TFL_DEFAULT; - if (bot_grapple.integer) bs->tfl |= TFL_GRAPPLEHOOK; - //if in lava or slime the bot should be able to get out - if (BotInLavaOrSlime(bs)) bs->tfl |= TFL_LAVA|TFL_SLIME; - // - if (BotCanAndWantsToRocketJump(bs)) { - bs->tfl |= TFL_ROCKETJUMP; - } - //map specific code - BotMapScripts(bs); - //no enemy - bs->enemy = -1; - //if the bot has no goal - if (!trap_BotGetTopGoal(bs->gs, &goal)) bs->nbg_time = 0; - //if the bot touches the current goal - else if (BotReachedGoal(bs, &goal)) { - BotChooseWeapon(bs); - bs->nbg_time = 0; - } - // - if (bs->nbg_time < FloatTime()) { - //pop the current goal from the stack - trap_BotPopGoal(bs->gs); - //check for new nearby items right away - //NOTE: we canNOT reset the check_time to zero because it would create an endless loop of node switches - bs->check_time = FloatTime() + 0.05; - //go back to seek ltg - AIEnter_Seek_LTG(bs); - return qfalse; - } - //predict obstacles - if (BotAIPredictObstacles(bs, &goal)) - return qfalse; - //initialize the movement state - BotSetupForMovement(bs); - //move towards the goal - trap_BotMoveToGoal(&moveresult, bs->ms, &goal, bs->tfl); - //if the movement failed - if (moveresult.failure) { - //reset the avoid reach, otherwise bot is stuck in current area - trap_BotResetAvoidReach(bs->ms); - bs->nbg_time = 0; - } - //check if the bot is blocked - BotAIBlocked(bs, &moveresult, qtrue); - // - BotClearPath(bs, &moveresult); - //if the viewangles are used for the movement - if (moveresult.flags & (MOVERESULT_MOVEMENTVIEWSET|MOVERESULT_MOVEMENTVIEW|MOVERESULT_SWIMVIEW)) { - VectorCopy(moveresult.ideal_viewangles, bs->ideal_viewangles); - } - //if waiting for something - else if (moveresult.flags & MOVERESULT_WAITING) { - if (random() < bs->thinktime * 0.8) { - BotRoamGoal(bs, target); - VectorSubtract(target, bs->origin, dir); - vectoangles(dir, bs->ideal_viewangles); - bs->ideal_viewangles[2] *= 0.5; - } - } - else if (!(bs->flags & BFL_IDEALVIEWSET)) { - if (!trap_BotGetSecondGoal(bs->gs, &goal)) trap_BotGetTopGoal(bs->gs, &goal); - if (trap_BotMovementViewTarget(bs->ms, &goal, bs->tfl, 300, target)) { - VectorSubtract(target, bs->origin, dir); - vectoangles(dir, bs->ideal_viewangles); - } - //FIXME: look at cluster portals? - else vectoangles(moveresult.movedir, bs->ideal_viewangles); - bs->ideal_viewangles[2] *= 0.5; - } - //if the weapon is used for the bot movement - if (moveresult.flags & MOVERESULT_MOVEMENTWEAPON) bs->weaponnum = moveresult.weapon; - //if there is an enemy - if (BotFindEnemy(bs, -1)) { - if (BotWantsToRetreat(bs)) { - //keep the current long term goal and retreat - AIEnter_Battle_NBG(bs); - } - else { - trap_BotResetLastAvoidReach(bs->ms); - //empty the goal stack - trap_BotEmptyGoalStack(bs->gs); - //go fight - AIEnter_Battle_Fight(bs); - } - } - return qtrue; -} - -/* -================== -AIEnter_Seek_LTG -================== -*/ -void AIEnter_Seek_LTG(bot_state_t *bs) { - bot_goal_t goal; - char buf[144]; - - if (trap_BotGetTopGoal(bs->gs, &goal)) { - trap_BotGoalName(goal.number, buf, 144); - BotRecordNodeSwitch(bs, "seek LTG", buf); - } - else { - BotRecordNodeSwitch(bs, "seek LTG", "no goal"); - } - bs->ainode = AINode_Seek_LTG; -} - -/* -================== -AINode_Seek_LTG -================== -*/ -int AINode_Seek_LTG(bot_state_t *bs) -{ - bot_goal_t goal; - vec3_t target, dir; - bot_moveresult_t moveresult; - int range; - //char buf[128]; - //bot_goal_t tmpgoal; - - if (BotIsObserver(bs)) { - AIEnter_Observer(bs); - return qfalse; - } - //if in the intermission - if (BotIntermission(bs)) { - AIEnter_Intermission(bs); - return qfalse; - } - //respawn if dead - if (BotIsDead(bs)) { - AIEnter_Respawn(bs); - return qfalse; - } - // - if (BotChat_Random(bs)) { - bs->stand_time = FloatTime() + BotChatTime(bs); - AIEnter_Stand(bs); - return qfalse; - } - // - bs->tfl = TFL_DEFAULT; - if (bot_grapple.integer) bs->tfl |= TFL_GRAPPLEHOOK; - //if in lava or slime the bot should be able to get out - if (BotInLavaOrSlime(bs)) bs->tfl |= TFL_LAVA|TFL_SLIME; - // - if (BotCanAndWantsToRocketJump(bs)) { - bs->tfl |= TFL_ROCKETJUMP; - } - //map specific code - BotMapScripts(bs); - //no enemy - bs->enemy = -1; - // - if (bs->killedenemy_time > FloatTime() - 2) { - if (random() < bs->thinktime * 1) { - trap_EA_Gesture(bs->client); - } - } - //if there is an enemy - if (BotFindEnemy(bs, -1)) { - if (BotWantsToRetreat(bs)) { - //keep the current long term goal and retreat - AIEnter_Battle_Retreat(bs); - return qfalse; - } - else { - trap_BotResetLastAvoidReach(bs->ms); - //empty the goal stack - trap_BotEmptyGoalStack(bs->gs); - //go fight - AIEnter_Battle_Fight(bs); - return qfalse; - } - } - // - BotTeamGoals(bs, qfalse); - //get the current long term goal - if (!BotLongTermGoal(bs, bs->tfl, qfalse, &goal)) { - return qtrue; - } - //check for nearby goals periodicly - if (bs->check_time < FloatTime()) { - bs->check_time = FloatTime() + 0.5; - //check if the bot wants to camp - BotWantsToCamp(bs); - // - if (bs->ltgtype == LTG_DEFENDKEYAREA) range = 400; - else range = 150; - // -#ifdef CTF - if (gametype == GT_CTF) { - //if carrying a flag the bot shouldn't be distracted too much - if (BotCTFCarryingFlag(bs)) - range = 50; - } -#endif //CTF -#ifdef MISSIONPACK - else if (gametype == GT_1FCTF) { - if (Bot1FCTFCarryingFlag(bs)) - range = 50; - } - else if (gametype == GT_HARVESTER) { - if (BotHarvesterCarryingCubes(bs)) - range = 80; - } -#endif - // - if (BotNearbyGoal(bs, bs->tfl, &goal, range)) { - trap_BotResetLastAvoidReach(bs->ms); - //get the goal at the top of the stack - //trap_BotGetTopGoal(bs->gs, &tmpgoal); - //trap_BotGoalName(tmpgoal.number, buf, 144); - //BotAI_Print(PRT_MESSAGE, "new nearby goal %s\n", buf); - //time the bot gets to pick up the nearby goal item - bs->nbg_time = FloatTime() + 4 + range * 0.01; - AIEnter_Seek_NBG(bs); - return qfalse; - } - } - //predict obstacles - if (BotAIPredictObstacles(bs, &goal)) - return qfalse; - //initialize the movement state - BotSetupForMovement(bs); - //move towards the goal - trap_BotMoveToGoal(&moveresult, bs->ms, &goal, bs->tfl); - //if the movement failed - if (moveresult.failure) { - //reset the avoid reach, otherwise bot is stuck in current area - trap_BotResetAvoidReach(bs->ms); - //BotAI_Print(PRT_MESSAGE, "movement failure %d\n", moveresult.traveltype); - bs->ltg_time = 0; - } - // - BotAIBlocked(bs, &moveresult, qtrue); - // - BotClearPath(bs, &moveresult); - //if the viewangles are used for the movement - if (moveresult.flags & (MOVERESULT_MOVEMENTVIEWSET|MOVERESULT_MOVEMENTVIEW|MOVERESULT_SWIMVIEW)) { - VectorCopy(moveresult.ideal_viewangles, bs->ideal_viewangles); - } - //if waiting for something - else if (moveresult.flags & MOVERESULT_WAITING) { - if (random() < bs->thinktime * 0.8) { - BotRoamGoal(bs, target); - VectorSubtract(target, bs->origin, dir); - vectoangles(dir, bs->ideal_viewangles); - bs->ideal_viewangles[2] *= 0.5; - } - } - else if (!(bs->flags & BFL_IDEALVIEWSET)) { - if (trap_BotMovementViewTarget(bs->ms, &goal, bs->tfl, 300, target)) { - VectorSubtract(target, bs->origin, dir); - vectoangles(dir, bs->ideal_viewangles); - } - //FIXME: look at cluster portals? - else if (VectorLengthSquared(moveresult.movedir)) { - vectoangles(moveresult.movedir, bs->ideal_viewangles); - } - else if (random() < bs->thinktime * 0.8) { - BotRoamGoal(bs, target); - VectorSubtract(target, bs->origin, dir); - vectoangles(dir, bs->ideal_viewangles); - bs->ideal_viewangles[2] *= 0.5; - } - bs->ideal_viewangles[2] *= 0.5; - } - //if the weapon is used for the bot movement - if (moveresult.flags & MOVERESULT_MOVEMENTWEAPON) bs->weaponnum = moveresult.weapon; - // - return qtrue; -} - -/* -================== -AIEnter_Battle_Fight -================== -*/ -void AIEnter_Battle_Fight(bot_state_t *bs) { - BotRecordNodeSwitch(bs, "battle fight", ""); - trap_BotResetLastAvoidReach(bs->ms); - bs->ainode = AINode_Battle_Fight; -} - -/* -================== -AIEnter_Battle_Fight -================== -*/ -void AIEnter_Battle_SuicidalFight(bot_state_t *bs) { - BotRecordNodeSwitch(bs, "battle fight", ""); - trap_BotResetLastAvoidReach(bs->ms); - bs->ainode = AINode_Battle_Fight; - bs->flags |= BFL_FIGHTSUICIDAL; -} - -/* -================== -AINode_Battle_Fight -================== -*/ -int AINode_Battle_Fight(bot_state_t *bs) { - int areanum; - vec3_t target; - aas_entityinfo_t entinfo; - bot_moveresult_t moveresult; - - if (BotIsObserver(bs)) { - AIEnter_Observer(bs); - return qfalse; - } - - //if in the intermission - if (BotIntermission(bs)) { - AIEnter_Intermission(bs); - return qfalse; - } - //respawn if dead - if (BotIsDead(bs)) { - AIEnter_Respawn(bs); - return qfalse; - } - //if there is another better enemy - if (BotFindEnemy(bs, bs->enemy)) { -#ifdef DEBUG - BotAI_Print(PRT_MESSAGE, "found new better enemy\n"); -#endif - } - //if no enemy - if (bs->enemy < 0) { - AIEnter_Seek_LTG(bs); - return qfalse; - } - // - BotEntityInfo(bs->enemy, &entinfo); - //if the enemy is dead - if (bs->enemydeath_time) { - if (bs->enemydeath_time < FloatTime() - 1.0) { - bs->enemydeath_time = 0; - if (bs->enemysuicide) { - BotChat_EnemySuicide(bs); - } - if (bs->lastkilledplayer == bs->enemy && BotChat_Kill(bs)) { - bs->stand_time = FloatTime() + BotChatTime(bs); - AIEnter_Stand(bs); - } - else { - bs->ltg_time = 0; - AIEnter_Seek_LTG(bs); - } - return qfalse; - } - } - else { - if (EntityIsDead(&entinfo)) { - bs->enemydeath_time = FloatTime(); - } - } - //if the enemy is invisible and not shooting the bot looses track easily - if (EntityIsInvisible(&entinfo) && !EntityIsShooting(&entinfo)) { - if (random() < 0.2) { - AIEnter_Seek_LTG(bs); - return qfalse; - } - } - // - VectorCopy(entinfo.origin, target); - // if not a player enemy - if (bs->enemy >= MAX_CLIENTS) { -#ifdef MISSIONPACK - // if attacking an obelisk - if ( bs->enemy == redobelisk.entitynum || - bs->enemy == blueobelisk.entitynum ) { - target[2] += 16; - } -#endif - } - //update the reachability area and origin if possible - areanum = BotPointAreaNum(target); - if (areanum && trap_AAS_AreaReachability(areanum)) { - VectorCopy(target, bs->lastenemyorigin); - bs->lastenemyareanum = areanum; - } - //update the attack inventory values - BotUpdateBattleInventory(bs, bs->enemy); - //if the bot's health decreased - if (bs->lastframe_health > bs->inventory[INVENTORY_HEALTH]) { - if (BotChat_HitNoDeath(bs)) { - bs->stand_time = FloatTime() + BotChatTime(bs); - AIEnter_Stand(bs); - return qfalse; - } - } - //if the bot hit someone - if (bs->cur_ps.persistant[PERS_HITS] > bs->lasthitcount) { - if (BotChat_HitNoKill(bs)) { - bs->stand_time = FloatTime() + BotChatTime(bs); - AIEnter_Stand(bs); - return qfalse; - } - } - //if the enemy is not visible - if (!BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, bs->enemy)) { - if (BotWantsToChase(bs)) { - AIEnter_Battle_Chase(bs); - return qfalse; - } - else { - AIEnter_Seek_LTG(bs); - return qfalse; - } - } - //use holdable items - BotBattleUseItems(bs); - // - bs->tfl = TFL_DEFAULT; - if (bot_grapple.integer) bs->tfl |= TFL_GRAPPLEHOOK; - //if in lava or slime the bot should be able to get out - if (BotInLavaOrSlime(bs)) bs->tfl |= TFL_LAVA|TFL_SLIME; - // - if (BotCanAndWantsToRocketJump(bs)) { - bs->tfl |= TFL_ROCKETJUMP; - } - //choose the best weapon to fight with - BotChooseWeapon(bs); - //do attack movements - moveresult = BotAttackMove(bs, bs->tfl); - //if the movement failed - if (moveresult.failure) { - //reset the avoid reach, otherwise bot is stuck in current area - trap_BotResetAvoidReach(bs->ms); - //BotAI_Print(PRT_MESSAGE, "movement failure %d\n", moveresult.traveltype); - bs->ltg_time = 0; - } - // - BotAIBlocked(bs, &moveresult, qfalse); - //aim at the enemy - BotAimAtEnemy(bs); - //attack the enemy if possible - BotCheckAttack(bs); - //if the bot wants to retreat - if (!(bs->flags & BFL_FIGHTSUICIDAL)) { - if (BotWantsToRetreat(bs)) { - AIEnter_Battle_Retreat(bs); - return qtrue; - } - } - return qtrue; -} - -/* -================== -AIEnter_Battle_Chase -================== -*/ -void AIEnter_Battle_Chase(bot_state_t *bs) { - BotRecordNodeSwitch(bs, "battle chase", ""); - bs->chase_time = FloatTime(); - bs->ainode = AINode_Battle_Chase; -} - -/* -================== -AINode_Battle_Chase -================== -*/ -int AINode_Battle_Chase(bot_state_t *bs) -{ - bot_goal_t goal; - vec3_t target, dir; - bot_moveresult_t moveresult; - float range; - - if (BotIsObserver(bs)) { - AIEnter_Observer(bs); - return qfalse; - } - //if in the intermission - if (BotIntermission(bs)) { - AIEnter_Intermission(bs); - return qfalse; - } - //respawn if dead - if (BotIsDead(bs)) { - AIEnter_Respawn(bs); - return qfalse; - } - //if no enemy - if (bs->enemy < 0) { - AIEnter_Seek_LTG(bs); - return qfalse; - } - //if the enemy is visible - if (BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, bs->enemy)) { - AIEnter_Battle_Fight(bs); - return qfalse; - } - //if there is another enemy - if (BotFindEnemy(bs, -1)) { - AIEnter_Battle_Fight(bs); - return qfalse; - } - //there is no last enemy area - if (!bs->lastenemyareanum) { - AIEnter_Seek_LTG(bs); - return qfalse; - } - // - bs->tfl = TFL_DEFAULT; - if (bot_grapple.integer) bs->tfl |= TFL_GRAPPLEHOOK; - //if in lava or slime the bot should be able to get out - if (BotInLavaOrSlime(bs)) bs->tfl |= TFL_LAVA|TFL_SLIME; - // - if (BotCanAndWantsToRocketJump(bs)) { - bs->tfl |= TFL_ROCKETJUMP; - } - //map specific code - BotMapScripts(bs); - //create the chase goal - goal.entitynum = bs->enemy; - goal.areanum = bs->lastenemyareanum; - VectorCopy(bs->lastenemyorigin, goal.origin); - VectorSet(goal.mins, -8, -8, -8); - VectorSet(goal.maxs, 8, 8, 8); - //if the last seen enemy spot is reached the enemy could not be found - if (trap_BotTouchingGoal(bs->origin, &goal)) bs->chase_time = 0; - //if there's no chase time left - if (!bs->chase_time || bs->chase_time < FloatTime() - 10) { - AIEnter_Seek_LTG(bs); - return qfalse; - } - //check for nearby goals periodicly - if (bs->check_time < FloatTime()) { - bs->check_time = FloatTime() + 1; - range = 150; - // - if (BotNearbyGoal(bs, bs->tfl, &goal, range)) { - //the bot gets 5 seconds to pick up the nearby goal item - bs->nbg_time = FloatTime() + 0.1 * range + 1; - trap_BotResetLastAvoidReach(bs->ms); - AIEnter_Battle_NBG(bs); - return qfalse; - } - } - // - BotUpdateBattleInventory(bs, bs->enemy); - //initialize the movement state - BotSetupForMovement(bs); - //move towards the goal - trap_BotMoveToGoal(&moveresult, bs->ms, &goal, bs->tfl); - //if the movement failed - if (moveresult.failure) { - //reset the avoid reach, otherwise bot is stuck in current area - trap_BotResetAvoidReach(bs->ms); - //BotAI_Print(PRT_MESSAGE, "movement failure %d\n", moveresult.traveltype); - bs->ltg_time = 0; - } - // - BotAIBlocked(bs, &moveresult, qfalse); - // - if (moveresult.flags & (MOVERESULT_MOVEMENTVIEWSET|MOVERESULT_MOVEMENTVIEW|MOVERESULT_SWIMVIEW)) { - VectorCopy(moveresult.ideal_viewangles, bs->ideal_viewangles); - } - else if (!(bs->flags & BFL_IDEALVIEWSET)) { - if (bs->chase_time > FloatTime() - 2) { - BotAimAtEnemy(bs); - } - else { - if (trap_BotMovementViewTarget(bs->ms, &goal, bs->tfl, 300, target)) { - VectorSubtract(target, bs->origin, dir); - vectoangles(dir, bs->ideal_viewangles); - } - else { - vectoangles(moveresult.movedir, bs->ideal_viewangles); - } - } - bs->ideal_viewangles[2] *= 0.5; - } - //if the weapon is used for the bot movement - if (moveresult.flags & MOVERESULT_MOVEMENTWEAPON) bs->weaponnum = moveresult.weapon; - //if the bot is in the area the enemy was last seen in - if (bs->areanum == bs->lastenemyareanum) bs->chase_time = 0; - //if the bot wants to retreat (the bot could have been damage during the chase) - if (BotWantsToRetreat(bs)) { - AIEnter_Battle_Retreat(bs); - return qtrue; - } - return qtrue; -} - -/* -================== -AIEnter_Battle_Retreat -================== -*/ -void AIEnter_Battle_Retreat(bot_state_t *bs) { - BotRecordNodeSwitch(bs, "battle retreat", ""); - bs->ainode = AINode_Battle_Retreat; -} - -/* -================== -AINode_Battle_Retreat -================== -*/ -int AINode_Battle_Retreat(bot_state_t *bs) { - bot_goal_t goal; - aas_entityinfo_t entinfo; - bot_moveresult_t moveresult; - vec3_t target, dir; - float attack_skill, range; - int areanum; - - if (BotIsObserver(bs)) { - AIEnter_Observer(bs); - return qfalse; - } - //if in the intermission - if (BotIntermission(bs)) { - AIEnter_Intermission(bs); - return qfalse; - } - //respawn if dead - if (BotIsDead(bs)) { - AIEnter_Respawn(bs); - return qfalse; - } - //if no enemy - if (bs->enemy < 0) { - AIEnter_Seek_LTG(bs); - return qfalse; - } - // - BotEntityInfo(bs->enemy, &entinfo); - if (EntityIsDead(&entinfo)) { - AIEnter_Seek_LTG(bs); - return qfalse; - } - //if there is another better enemy - if (BotFindEnemy(bs, bs->enemy)) { -#ifdef DEBUG - BotAI_Print(PRT_MESSAGE, "found new better enemy\n"); -#endif - } - // - bs->tfl = TFL_DEFAULT; - if (bot_grapple.integer) bs->tfl |= TFL_GRAPPLEHOOK; - //if in lava or slime the bot should be able to get out - if (BotInLavaOrSlime(bs)) bs->tfl |= TFL_LAVA|TFL_SLIME; - //map specific code - BotMapScripts(bs); - //update the attack inventory values - BotUpdateBattleInventory(bs, bs->enemy); - //if the bot doesn't want to retreat anymore... probably picked up some nice items - if (BotWantsToChase(bs)) { - //empty the goal stack, when chasing, only the enemy is the goal - trap_BotEmptyGoalStack(bs->gs); - //go chase the enemy - AIEnter_Battle_Chase(bs); - return qfalse; - } - //update the last time the enemy was visible - if (BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, bs->enemy)) { - bs->enemyvisible_time = FloatTime(); - VectorCopy(entinfo.origin, target); - // if not a player enemy - if (bs->enemy >= MAX_CLIENTS) { -#ifdef MISSIONPACK - // if attacking an obelisk - if ( bs->enemy == redobelisk.entitynum || - bs->enemy == blueobelisk.entitynum ) { - target[2] += 16; - } -#endif - } - //update the reachability area and origin if possible - areanum = BotPointAreaNum(target); - if (areanum && trap_AAS_AreaReachability(areanum)) { - VectorCopy(target, bs->lastenemyorigin); - bs->lastenemyareanum = areanum; - } - } - //if the enemy is NOT visible for 4 seconds - if (bs->enemyvisible_time < FloatTime() - 4) { - AIEnter_Seek_LTG(bs); - return qfalse; - } - //else if the enemy is NOT visible - else if (bs->enemyvisible_time < FloatTime()) { - //if there is another enemy - if (BotFindEnemy(bs, -1)) { - AIEnter_Battle_Fight(bs); - return qfalse; - } - } - // - BotTeamGoals(bs, qtrue); - //use holdable items - BotBattleUseItems(bs); - //get the current long term goal while retreating - if (!BotLongTermGoal(bs, bs->tfl, qtrue, &goal)) { - AIEnter_Battle_SuicidalFight(bs); - return qfalse; - } - //check for nearby goals periodicly - if (bs->check_time < FloatTime()) { - bs->check_time = FloatTime() + 1; - range = 150; -#ifdef CTF - if (gametype == GT_CTF) { - //if carrying a flag the bot shouldn't be distracted too much - if (BotCTFCarryingFlag(bs)) - range = 50; - } -#endif //CTF -#ifdef MISSIONPACK - else if (gametype == GT_1FCTF) { - if (Bot1FCTFCarryingFlag(bs)) - range = 50; - } - else if (gametype == GT_HARVESTER) { - if (BotHarvesterCarryingCubes(bs)) - range = 80; - } -#endif - // - if (BotNearbyGoal(bs, bs->tfl, &goal, range)) { - trap_BotResetLastAvoidReach(bs->ms); - //time the bot gets to pick up the nearby goal item - bs->nbg_time = FloatTime() + range / 100 + 1; - AIEnter_Battle_NBG(bs); - return qfalse; - } - } - //initialize the movement state - BotSetupForMovement(bs); - //move towards the goal - trap_BotMoveToGoal(&moveresult, bs->ms, &goal, bs->tfl); - //if the movement failed - if (moveresult.failure) { - //reset the avoid reach, otherwise bot is stuck in current area - trap_BotResetAvoidReach(bs->ms); - //BotAI_Print(PRT_MESSAGE, "movement failure %d\n", moveresult.traveltype); - bs->ltg_time = 0; - } - // - BotAIBlocked(bs, &moveresult, qfalse); - //choose the best weapon to fight with - BotChooseWeapon(bs); - //if the view is fixed for the movement - if (moveresult.flags & (MOVERESULT_MOVEMENTVIEW|MOVERESULT_SWIMVIEW)) { - VectorCopy(moveresult.ideal_viewangles, bs->ideal_viewangles); - } - else if (!(moveresult.flags & MOVERESULT_MOVEMENTVIEWSET) - && !(bs->flags & BFL_IDEALVIEWSET) ) { - attack_skill = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_ATTACK_SKILL, 0, 1); - //if the bot is skilled anough - if (attack_skill > 0.3) { - BotAimAtEnemy(bs); - } - else { - if (trap_BotMovementViewTarget(bs->ms, &goal, bs->tfl, 300, target)) { - VectorSubtract(target, bs->origin, dir); - vectoangles(dir, bs->ideal_viewangles); - } - else { - vectoangles(moveresult.movedir, bs->ideal_viewangles); - } - bs->ideal_viewangles[2] *= 0.5; - } - } - //if the weapon is used for the bot movement - if (moveresult.flags & MOVERESULT_MOVEMENTWEAPON) bs->weaponnum = moveresult.weapon; - //attack the enemy if possible - BotCheckAttack(bs); - // - return qtrue; -} - -/* -================== -AIEnter_Battle_NBG -================== -*/ -void AIEnter_Battle_NBG(bot_state_t *bs) { - BotRecordNodeSwitch(bs, "battle NBG", ""); - bs->ainode = AINode_Battle_NBG; -} - -/* -================== -AINode_Battle_NBG -================== -*/ -int AINode_Battle_NBG(bot_state_t *bs) { - int areanum; - bot_goal_t goal; - aas_entityinfo_t entinfo; - bot_moveresult_t moveresult; - float attack_skill; - vec3_t target, dir; - - if (BotIsObserver(bs)) { - AIEnter_Observer(bs); - return qfalse; - } - //if in the intermission - if (BotIntermission(bs)) { - AIEnter_Intermission(bs); - return qfalse; - } - //respawn if dead - if (BotIsDead(bs)) { - AIEnter_Respawn(bs); - return qfalse; - } - //if no enemy - if (bs->enemy < 0) { - AIEnter_Seek_NBG(bs); - return qfalse; - } - // - BotEntityInfo(bs->enemy, &entinfo); - if (EntityIsDead(&entinfo)) { - AIEnter_Seek_NBG(bs); - return qfalse; - } - // - bs->tfl = TFL_DEFAULT; - if (bot_grapple.integer) bs->tfl |= TFL_GRAPPLEHOOK; - //if in lava or slime the bot should be able to get out - if (BotInLavaOrSlime(bs)) bs->tfl |= TFL_LAVA|TFL_SLIME; - // - if (BotCanAndWantsToRocketJump(bs)) { - bs->tfl |= TFL_ROCKETJUMP; - } - //map specific code - BotMapScripts(bs); - //update the last time the enemy was visible - if (BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, bs->enemy)) { - bs->enemyvisible_time = FloatTime(); - VectorCopy(entinfo.origin, target); - // if not a player enemy - if (bs->enemy >= MAX_CLIENTS) { -#ifdef MISSIONPACK - // if attacking an obelisk - if ( bs->enemy == redobelisk.entitynum || - bs->enemy == blueobelisk.entitynum ) { - target[2] += 16; - } -#endif - } - //update the reachability area and origin if possible - areanum = BotPointAreaNum(target); - if (areanum && trap_AAS_AreaReachability(areanum)) { - VectorCopy(target, bs->lastenemyorigin); - bs->lastenemyareanum = areanum; - } - } - //if the bot has no goal or touches the current goal - if (!trap_BotGetTopGoal(bs->gs, &goal)) { - bs->nbg_time = 0; - } - else if (BotReachedGoal(bs, &goal)) { - bs->nbg_time = 0; - } - // - if (bs->nbg_time < FloatTime()) { - //pop the current goal from the stack - trap_BotPopGoal(bs->gs); - //if the bot still has a goal - if (trap_BotGetTopGoal(bs->gs, &goal)) AIEnter_Battle_Retreat(bs); - else AIEnter_Battle_Fight(bs); - // - return qfalse; - } - //initialize the movement state - BotSetupForMovement(bs); - //move towards the goal - trap_BotMoveToGoal(&moveresult, bs->ms, &goal, bs->tfl); - //if the movement failed - if (moveresult.failure) { - //reset the avoid reach, otherwise bot is stuck in current area - trap_BotResetAvoidReach(bs->ms); - //BotAI_Print(PRT_MESSAGE, "movement failure %d\n", moveresult.traveltype); - bs->nbg_time = 0; - } - // - BotAIBlocked(bs, &moveresult, qfalse); - //update the attack inventory values - BotUpdateBattleInventory(bs, bs->enemy); - //choose the best weapon to fight with - BotChooseWeapon(bs); - //if the view is fixed for the movement - if (moveresult.flags & (MOVERESULT_MOVEMENTVIEW|MOVERESULT_SWIMVIEW)) { - VectorCopy(moveresult.ideal_viewangles, bs->ideal_viewangles); - } - else if (!(moveresult.flags & MOVERESULT_MOVEMENTVIEWSET) - && !(bs->flags & BFL_IDEALVIEWSET)) { - attack_skill = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_ATTACK_SKILL, 0, 1); - //if the bot is skilled anough and the enemy is visible - if (attack_skill > 0.3) { - //&& BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, bs->enemy) - BotAimAtEnemy(bs); - } - else { - if (trap_BotMovementViewTarget(bs->ms, &goal, bs->tfl, 300, target)) { - VectorSubtract(target, bs->origin, dir); - vectoangles(dir, bs->ideal_viewangles); - } - else { - vectoangles(moveresult.movedir, bs->ideal_viewangles); - } - bs->ideal_viewangles[2] *= 0.5; - } - } - //if the weapon is used for the bot movement - if (moveresult.flags & MOVERESULT_MOVEMENTWEAPON) bs->weaponnum = moveresult.weapon; - //attack the enemy if possible - BotCheckAttack(bs); - // - return qtrue; -} - diff --git a/reaction/game/.#ai_dmq3.c.1.4 b/reaction/game/.#ai_dmq3.c.1.4 deleted file mode 100644 index d462f0ae..00000000 --- a/reaction/game/.#ai_dmq3.c.1.4 +++ /dev/null @@ -1,5433 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// - -/***************************************************************************** - * name: ai_dmq3.c - * - * desc: Quake3 bot AI - * - * $Archive: /MissionPack/code/game/ai_dmq3.c $ - * $Author$ - * $Revision$ - * $Modtime: 11/28/00 9:12a $ - * $Date$ - * - *****************************************************************************/ - - -#include "g_local.h" -#include "botlib.h" -#include "be_aas.h" -#include "be_ea.h" -#include "be_ai_char.h" -#include "be_ai_chat.h" -#include "be_ai_gen.h" -#include "be_ai_goal.h" -#include "be_ai_move.h" -#include "be_ai_weap.h" -// -#include "ai_main.h" -#include "ai_dmq3.h" -#include "ai_chat.h" -#include "ai_cmd.h" -#include "ai_dmnet.h" -#include "ai_team.h" -// -#include "chars.h" //characteristics -#include "inv.h" //indexes into the inventory -#include "syn.h" //synonyms -#include "match.h" //string matching types and vars - -// for the voice chats -//Blaze: was there a extra ../ here? -#include "../ui/menudef.h" - -// from aasfile.h -#define AREACONTENTS_MOVER 1024 -#define AREACONTENTS_MODELNUMSHIFT 24 -#define AREACONTENTS_MAXMODELNUM 0xFF -#define AREACONTENTS_MODELNUM (AREACONTENTS_MAXMODELNUM << AREACONTENTS_MODELNUMSHIFT) - -#define IDEAL_ATTACKDIST 140 - -#define MAX_WAYPOINTS 128 -// -bot_waypoint_t botai_waypoints[MAX_WAYPOINTS]; -bot_waypoint_t *botai_freewaypoints; - -//NOTE: not using a cvars which can be updated because the game should be reloaded anyway -int gametype; //game type -int maxclients; //maximum number of clients - -vmCvar_t bot_grapple; -vmCvar_t bot_rocketjump; -vmCvar_t bot_fastchat; -vmCvar_t bot_nochat; -vmCvar_t bot_testrchat; -vmCvar_t bot_challenge; -vmCvar_t bot_predictobstacles; -vmCvar_t g_spSkill; - -extern vmCvar_t bot_developer; - -vec3_t lastteleport_origin; //last teleport event origin -float lastteleport_time; //last teleport event time -int max_bspmodelindex; //maximum BSP model index - -//CTF flag goals -bot_goal_t ctf_redflag; -bot_goal_t ctf_blueflag; -#ifdef MISSIONPACK -bot_goal_t ctf_neutralflag; -bot_goal_t redobelisk; -bot_goal_t blueobelisk; -bot_goal_t neutralobelisk; -#endif - -#define MAX_ALTROUTEGOALS 32 - -int altroutegoals_setup; -aas_altroutegoal_t red_altroutegoals[MAX_ALTROUTEGOALS]; -int red_numaltroutegoals; -aas_altroutegoal_t blue_altroutegoals[MAX_ALTROUTEGOALS]; -int blue_numaltroutegoals; - - -/* -================== -BotSetUserInfo -================== -*/ -void BotSetUserInfo(bot_state_t *bs, char *key, char *value) { - char userinfo[MAX_INFO_STRING]; - - trap_GetUserinfo(bs->client, userinfo, sizeof(userinfo)); - Info_SetValueForKey(userinfo, key, value); - trap_SetUserinfo(bs->client, userinfo); - ClientUserinfoChanged( bs->client ); -} - -/* -================== -BotCTFCarryingFlag -================== -*/ -int BotCTFCarryingFlag(bot_state_t *bs) { - if (gametype != GT_CTF) return CTF_FLAG_NONE; - - if (bs->inventory[INVENTORY_REDFLAG] > 0) return CTF_FLAG_RED; - else if (bs->inventory[INVENTORY_BLUEFLAG] > 0) return CTF_FLAG_BLUE; - return CTF_FLAG_NONE; -} - -/* -================== -BotTeam -================== -*/ -int BotTeam(bot_state_t *bs) { - char info[1024]; - - if (bs->client < 0 || bs->client >= MAX_CLIENTS) { - //BotAI_Print(PRT_ERROR, "BotCTFTeam: client out of range\n"); - return qfalse; - } - trap_GetConfigstring(CS_PLAYERS+bs->client, info, sizeof(info)); - // - if (atoi(Info_ValueForKey(info, "t")) == TEAM_RED) return TEAM_RED; - else if (atoi(Info_ValueForKey(info, "t")) == TEAM_BLUE) return TEAM_BLUE; - return TEAM_FREE; -} - -/* -================== -BotOppositeTeam -================== -*/ -int BotOppositeTeam(bot_state_t *bs) { - switch(BotTeam(bs)) { - case TEAM_RED: return TEAM_BLUE; - case TEAM_BLUE: return TEAM_RED; - default: return TEAM_FREE; - } -} - -/* -================== -BotEnemyFlag -================== -*/ -bot_goal_t *BotEnemyFlag(bot_state_t *bs) { - if (BotTeam(bs) == TEAM_RED) { - return &ctf_blueflag; - } - else { - return &ctf_redflag; - } -} - -/* -================== -BotTeamFlag -================== -*/ -bot_goal_t *BotTeamFlag(bot_state_t *bs) { - if (BotTeam(bs) == TEAM_RED) { - return &ctf_redflag; - } - else { - return &ctf_blueflag; - } -} - - -/* -================== -EntityIsDead -================== -*/ -qboolean EntityIsDead(aas_entityinfo_t *entinfo) { - playerState_t ps; - - if (entinfo->number >= 0 && entinfo->number < MAX_CLIENTS) { - //retrieve the current client state - BotAI_GetClientState( entinfo->number, &ps ); - if (ps.pm_type != PM_NORMAL) return qtrue; - } - return qfalse; -} - -/* -================== -EntityIsInvisible -================== -*/ -qboolean EntityIsInvisible(aas_entityinfo_t *entinfo) { - if (entinfo->powerups & (1 << PW_INVIS)) { - return qtrue; - } - return qfalse; -} - -/* -================== -EntityCarriesFlag -================== -*/ -qboolean EntityCarriesFlag(aas_entityinfo_t *entinfo) { - if ( entinfo->powerups & ( 1 << PW_REDFLAG ) ) - return qtrue; - if ( entinfo->powerups & ( 1 << PW_BLUEFLAG ) ) - return qtrue; -#ifdef MISSIONPACK - if ( entinfo->powerups & ( 1 << PW_NEUTRALFLAG ) ) - return qtrue; -#endif - return qfalse; -} - -/* -================== -EntityIsShooting -================== -*/ -qboolean EntityIsShooting(aas_entityinfo_t *entinfo) { - if (entinfo->flags & EF_FIRING) { - return qtrue; - } - return qfalse; -} - -/* -================== -EntityIsChatting -================== -*/ -qboolean EntityIsChatting(aas_entityinfo_t *entinfo) { - if (entinfo->flags & EF_TALK) { - return qtrue; - } - return qfalse; -} - -/* -================== -EntityHasQuad -================== -*/ -qboolean EntityHasQuad(aas_entityinfo_t *entinfo) { - if (entinfo->powerups & (1 << PW_QUAD)) { - return qtrue; - } - return qfalse; -} - -#ifdef MISSIONPACK -/* -================== -EntityHasKamikze -================== -*/ -qboolean EntityHasKamikaze(aas_entityinfo_t *entinfo) { - if (entinfo->flags & EF_KAMIKAZE) { - return qtrue; - } - return qfalse; -} - -/* -================== -EntityCarriesCubes -================== -*/ -qboolean EntityCarriesCubes(aas_entityinfo_t *entinfo) { - entityState_t state; - - if (gametype != GT_HARVESTER) - return qfalse; - //FIXME: get this info from the aas_entityinfo_t ? - BotAI_GetEntityState(entinfo->number, &state); - if (state.generic1 > 0) - return qtrue; - return qfalse; -} - -/* -================== -Bot1FCTFCarryingFlag -================== -*/ -int Bot1FCTFCarryingFlag(bot_state_t *bs) { - if (gametype != GT_1FCTF) return qfalse; - - if (bs->inventory[INVENTORY_NEUTRALFLAG] > 0) return qtrue; - return qfalse; -} - -/* -================== -BotHarvesterCarryingCubes -================== -*/ -int BotHarvesterCarryingCubes(bot_state_t *bs) { - if (gametype != GT_HARVESTER) return qfalse; - - if (bs->inventory[INVENTORY_REDCUBE] > 0) return qtrue; - if (bs->inventory[INVENTORY_BLUECUBE] > 0) return qtrue; - return qfalse; -} -#endif - -/* -================== -BotRememberLastOrderedTask -================== -*/ -void BotRememberLastOrderedTask(bot_state_t *bs) { - if (!bs->ordered) { - return; - } - bs->lastgoal_decisionmaker = bs->decisionmaker; - bs->lastgoal_ltgtype = bs->ltgtype; - memcpy(&bs->lastgoal_teamgoal, &bs->teamgoal, sizeof(bot_goal_t)); - bs->lastgoal_teammate = bs->teammate; -} - -/* -================== -BotSetTeamStatus -================== -*/ -void BotSetTeamStatus(bot_state_t *bs) { -#ifdef MISSIONPACK - int teamtask; - aas_entityinfo_t entinfo; - - teamtask = TEAMTASK_PATROL; - - switch(bs->ltgtype) { - case LTG_TEAMHELP: - break; - case LTG_TEAMACCOMPANY: - BotEntityInfo(bs->teammate, &entinfo); - if ( ( (gametype == GT_CTF || gametype == GT_1FCTF) && EntityCarriesFlag(&entinfo)) - || ( gametype == GT_HARVESTER && EntityCarriesCubes(&entinfo)) ) { - teamtask = TEAMTASK_ESCORT; - } - else { - teamtask = TEAMTASK_FOLLOW; - } - break; - case LTG_DEFENDKEYAREA: - teamtask = TEAMTASK_DEFENSE; - break; - case LTG_GETFLAG: - teamtask = TEAMTASK_OFFENSE; - break; - case LTG_RUSHBASE: - teamtask = TEAMTASK_DEFENSE; - break; - case LTG_RETURNFLAG: - teamtask = TEAMTASK_RETRIEVE; - break; - case LTG_CAMP: - case LTG_CAMPORDER: - teamtask = TEAMTASK_CAMP; - break; - case LTG_PATROL: - teamtask = TEAMTASK_PATROL; - break; - case LTG_GETITEM: - teamtask = TEAMTASK_PATROL; - break; - case LTG_KILL: - teamtask = TEAMTASK_PATROL; - break; - case LTG_HARVEST: - teamtask = TEAMTASK_OFFENSE; - break; - case LTG_ATTACKENEMYBASE: - teamtask = TEAMTASK_OFFENSE; - break; - default: - teamtask = TEAMTASK_PATROL; - break; - } - BotSetUserInfo(bs, "teamtask", va("%d", teamtask)); -#endif -} - -/* -================== -BotSetLastOrderedTask -================== -*/ -int BotSetLastOrderedTask(bot_state_t *bs) { - - if (gametype == GT_CTF) { - // don't go back to returning the flag if it's at the base - if ( bs->lastgoal_ltgtype == LTG_RETURNFLAG ) { - if ( BotTeam(bs) == TEAM_RED ) { - if ( bs->redflagstatus == 0 ) { - bs->lastgoal_ltgtype = 0; - } - } - else { - if ( bs->blueflagstatus == 0 ) { - bs->lastgoal_ltgtype = 0; - } - } - } - } - - if ( bs->lastgoal_ltgtype ) { - bs->decisionmaker = bs->lastgoal_decisionmaker; - bs->ordered = qtrue; - bs->ltgtype = bs->lastgoal_ltgtype; - memcpy(&bs->teamgoal, &bs->lastgoal_teamgoal, sizeof(bot_goal_t)); - bs->teammate = bs->lastgoal_teammate; - bs->teamgoal_time = FloatTime() + 300; - BotSetTeamStatus(bs); - // - if ( gametype == GT_CTF ) { - if ( bs->ltgtype == LTG_GETFLAG ) { - bot_goal_t *tb, *eb; - int tt, et; - - tb = BotTeamFlag(bs); - eb = BotEnemyFlag(bs); - tt = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, tb->areanum, TFL_DEFAULT); - et = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, eb->areanum, TFL_DEFAULT); - // if the travel time towards the enemy base is larger than towards our base - if (et > tt) { - //get an alternative route goal towards the enemy base - BotGetAlternateRouteGoal(bs, BotOppositeTeam(bs)); - } - } - } - return qtrue; - } - return qfalse; -} - -/* -================== -BotRefuseOrder -================== -*/ -void BotRefuseOrder(bot_state_t *bs) { - if (!bs->ordered) - return; - // if the bot was ordered to do something - if ( bs->order_time && bs->order_time > FloatTime() - 10 ) { - trap_EA_Action(bs->client, ACTION_NEGATIVE); - BotVoiceChat(bs, bs->decisionmaker, VOICECHAT_NO); - bs->order_time = 0; - } -} - -/* -================== -BotCTFSeekGoals -================== -*/ -void BotCTFSeekGoals(bot_state_t *bs) { - float rnd, l1, l2; - int flagstatus, c; - vec3_t dir; - aas_entityinfo_t entinfo; - - //when carrying a flag in ctf the bot should rush to the base - if (BotCTFCarryingFlag(bs)) { - //if not already rushing to the base - if (bs->ltgtype != LTG_RUSHBASE) { - BotRefuseOrder(bs); - bs->ltgtype = LTG_RUSHBASE; - bs->teamgoal_time = FloatTime() + CTF_RUSHBASE_TIME; - bs->rushbaseaway_time = 0; - bs->decisionmaker = bs->client; - bs->ordered = qfalse; - // - switch(BotTeam(bs)) { - case TEAM_RED: VectorSubtract(bs->origin, ctf_blueflag.origin, dir); break; - case TEAM_BLUE: VectorSubtract(bs->origin, ctf_redflag.origin, dir); break; - default: VectorSet(dir, 999, 999, 999); break; - } - // if the bot picked up the flag very close to the enemy base - if ( VectorLength(dir) < 128 ) { - // get an alternative route goal through the enemy base - BotGetAlternateRouteGoal(bs, BotOppositeTeam(bs)); - } else { - // don't use any alt route goal, just get the hell out of the base - bs->altroutegoal.areanum = 0; - } - BotSetUserInfo(bs, "teamtask", va("%d", TEAMTASK_OFFENSE)); - BotVoiceChat(bs, -1, VOICECHAT_IHAVEFLAG); - } - else if (bs->rushbaseaway_time > FloatTime()) { - if (BotTeam(bs) == TEAM_RED) flagstatus = bs->redflagstatus; - else flagstatus = bs->blueflagstatus; - //if the flag is back - if (flagstatus == 0) { - bs->rushbaseaway_time = 0; - } - } - return; - } - // if the bot decided to follow someone - if ( bs->ltgtype == LTG_TEAMACCOMPANY && !bs->ordered ) { - // if the team mate being accompanied no longer carries the flag - BotEntityInfo(bs->teammate, &entinfo); - if (!EntityCarriesFlag(&entinfo)) { - bs->ltgtype = 0; - } - } - // - if (BotTeam(bs) == TEAM_RED) flagstatus = bs->redflagstatus * 2 + bs->blueflagstatus; - else flagstatus = bs->blueflagstatus * 2 + bs->redflagstatus; - //if our team has the enemy flag and our flag is at the base - if (flagstatus == 1) { - // - if (bs->owndecision_time < FloatTime()) { - //if Not defending the base already - if (!(bs->ltgtype == LTG_DEFENDKEYAREA && - (bs->teamgoal.number == ctf_redflag.number || - bs->teamgoal.number == ctf_blueflag.number))) { - //if there is avisible team mate flag carrier - c = BotTeamFlagCarrierVisible(bs); - if (c >= 0 && - // and not already following the team mate flag carrier - (bs->ltgtype != LTG_TEAMACCOMPANY || bs->teammate != c)) { - // - BotRefuseOrder(bs); - //follow the flag carrier - bs->decisionmaker = bs->client; - bs->ordered = qfalse; - //the team mate - bs->teammate = c; - //last time the team mate was visible - bs->teammatevisible_time = FloatTime(); - //no message - bs->teammessage_time = 0; - //no arrive message - bs->arrive_time = 1; - // - BotVoiceChat(bs, bs->teammate, VOICECHAT_ONFOLLOW); - //get the team goal time - bs->teamgoal_time = FloatTime() + TEAM_ACCOMPANY_TIME; - bs->ltgtype = LTG_TEAMACCOMPANY; - bs->formation_dist = 3.5 * 32; //3.5 meter - BotSetTeamStatus(bs); - bs->owndecision_time = FloatTime() + 5; - } - } - } - return; - } - //if the enemy has our flag - else if (flagstatus == 2) { - // - if (bs->owndecision_time < FloatTime()) { - //if enemy flag carrier is visible - c = BotEnemyFlagCarrierVisible(bs); - if (c >= 0) { - //FIXME: fight enemy flag carrier - } - //if not already doing something important - if (bs->ltgtype != LTG_GETFLAG && - bs->ltgtype != LTG_RETURNFLAG && - bs->ltgtype != LTG_TEAMHELP && - bs->ltgtype != LTG_TEAMACCOMPANY && - bs->ltgtype != LTG_CAMPORDER && - bs->ltgtype != LTG_PATROL && - bs->ltgtype != LTG_GETITEM) { - - BotRefuseOrder(bs); - bs->decisionmaker = bs->client; - bs->ordered = qfalse; - // - if (random() < 0.5) { - //go for the enemy flag - bs->ltgtype = LTG_GETFLAG; - } - else { - bs->ltgtype = LTG_RETURNFLAG; - } - //no team message - bs->teammessage_time = 0; - //set the time the bot will stop getting the flag - bs->teamgoal_time = FloatTime() + CTF_GETFLAG_TIME; - //get an alternative route goal towards the enemy base - BotGetAlternateRouteGoal(bs, BotOppositeTeam(bs)); - // - BotSetTeamStatus(bs); - bs->owndecision_time = FloatTime() + 5; - } - } - return; - } - //if both flags Not at their bases - else if (flagstatus == 3) { - // - if (bs->owndecision_time < FloatTime()) { - // if not trying to return the flag and not following the team flag carrier - if ( bs->ltgtype != LTG_RETURNFLAG && bs->ltgtype != LTG_TEAMACCOMPANY ) { - // - c = BotTeamFlagCarrierVisible(bs); - // if there is a visible team mate flag carrier - if (c >= 0) { - BotRefuseOrder(bs); - //follow the flag carrier - bs->decisionmaker = bs->client; - bs->ordered = qfalse; - //the team mate - bs->teammate = c; - //last time the team mate was visible - bs->teammatevisible_time = FloatTime(); - //no message - bs->teammessage_time = 0; - //no arrive message - bs->arrive_time = 1; - // - BotVoiceChat(bs, bs->teammate, VOICECHAT_ONFOLLOW); - //get the team goal time - bs->teamgoal_time = FloatTime() + TEAM_ACCOMPANY_TIME; - bs->ltgtype = LTG_TEAMACCOMPANY; - bs->formation_dist = 3.5 * 32; //3.5 meter - // - BotSetTeamStatus(bs); - bs->owndecision_time = FloatTime() + 5; - } - else { - BotRefuseOrder(bs); - bs->decisionmaker = bs->client; - bs->ordered = qfalse; - //get the enemy flag - bs->teammessage_time = FloatTime() + 2 * random(); - //get the flag - bs->ltgtype = LTG_RETURNFLAG; - //set the time the bot will stop getting the flag - bs->teamgoal_time = FloatTime() + CTF_RETURNFLAG_TIME; - //get an alternative route goal towards the enemy base - BotGetAlternateRouteGoal(bs, BotOppositeTeam(bs)); - // - BotSetTeamStatus(bs); - bs->owndecision_time = FloatTime() + 5; - } - } - } - return; - } - // don't just do something wait for the bot team leader to give orders - if (BotTeamLeader(bs)) { - return; - } - // if the bot is ordered to do something - if ( bs->lastgoal_ltgtype ) { - bs->teamgoal_time += 60; - } - // if the bot decided to do something on it's own and has a last ordered goal - if ( !bs->ordered && bs->lastgoal_ltgtype ) { - bs->ltgtype = 0; - } - //if already a CTF or team goal - if (bs->ltgtype == LTG_TEAMHELP || - bs->ltgtype == LTG_TEAMACCOMPANY || - bs->ltgtype == LTG_DEFENDKEYAREA || - bs->ltgtype == LTG_GETFLAG || - bs->ltgtype == LTG_RUSHBASE || - bs->ltgtype == LTG_RETURNFLAG || - bs->ltgtype == LTG_CAMPORDER || - bs->ltgtype == LTG_PATROL || - bs->ltgtype == LTG_GETITEM || - bs->ltgtype == LTG_MAKELOVE_UNDER || - bs->ltgtype == LTG_MAKELOVE_ONTOP) { - return; - } - // - if (BotSetLastOrderedTask(bs)) - return; - // - if (bs->owndecision_time > FloatTime()) - return;; - //if the bot is roaming - if (bs->ctfroam_time > FloatTime()) - return; - //if the bot has anough aggression to decide what to do - if (BotAggression(bs) < 50) - return; - //set the time to send a message to the team mates - bs->teammessage_time = FloatTime() + 2 * random(); - // - if (bs->teamtaskpreference & (TEAMTP_ATTACKER|TEAMTP_DEFENDER)) { - if (bs->teamtaskpreference & TEAMTP_ATTACKER) { - l1 = 0.7f; - } - else { - l1 = 0.2f; - } - l2 = 0.9f; - } - else { - l1 = 0.4f; - l2 = 0.7f; - } - //get the flag or defend the base - rnd = random(); - if (rnd < l1 && ctf_redflag.areanum && ctf_blueflag.areanum) { - bs->decisionmaker = bs->client; - bs->ordered = qfalse; - bs->ltgtype = LTG_GETFLAG; - //set the time the bot will stop getting the flag - bs->teamgoal_time = FloatTime() + CTF_GETFLAG_TIME; - //get an alternative route goal towards the enemy base - BotGetAlternateRouteGoal(bs, BotOppositeTeam(bs)); - BotSetTeamStatus(bs); - } - else if (rnd < l2 && ctf_redflag.areanum && ctf_blueflag.areanum) { - bs->decisionmaker = bs->client; - bs->ordered = qfalse; - // - if (BotTeam(bs) == TEAM_RED) memcpy(&bs->teamgoal, &ctf_redflag, sizeof(bot_goal_t)); - else memcpy(&bs->teamgoal, &ctf_blueflag, sizeof(bot_goal_t)); - //set the ltg type - bs->ltgtype = LTG_DEFENDKEYAREA; - //set the time the bot stops defending the base - bs->teamgoal_time = FloatTime() + TEAM_DEFENDKEYAREA_TIME; - bs->defendaway_time = 0; - BotSetTeamStatus(bs); - } - else { - bs->ltgtype = 0; - //set the time the bot will stop roaming - bs->ctfroam_time = FloatTime() + CTF_ROAM_TIME; - BotSetTeamStatus(bs); - } - bs->owndecision_time = FloatTime() + 5; -#ifdef DEBUG - BotPrintTeamGoal(bs); -#endif //DEBUG -} - -/* -================== -BotCTFRetreatGoals -================== -*/ -void BotCTFRetreatGoals(bot_state_t *bs) { - //when carrying a flag in ctf the bot should rush to the base - if (BotCTFCarryingFlag(bs)) { - //if not already rushing to the base - if (bs->ltgtype != LTG_RUSHBASE) { - BotRefuseOrder(bs); - bs->ltgtype = LTG_RUSHBASE; - bs->teamgoal_time = FloatTime() + CTF_RUSHBASE_TIME; - bs->rushbaseaway_time = 0; - bs->decisionmaker = bs->client; - bs->ordered = qfalse; - BotSetTeamStatus(bs); - } - } -} - -#ifdef MISSIONPACK -/* -================== -Bot1FCTFSeekGoals -================== -*/ -void Bot1FCTFSeekGoals(bot_state_t *bs) { - aas_entityinfo_t entinfo; - float rnd, l1, l2; - int c; - - //when carrying a flag in ctf the bot should rush to the base - if (Bot1FCTFCarryingFlag(bs)) { - //if not already rushing to the base - if (bs->ltgtype != LTG_RUSHBASE) { - BotRefuseOrder(bs); - bs->ltgtype = LTG_RUSHBASE; - bs->teamgoal_time = FloatTime() + CTF_RUSHBASE_TIME; - bs->rushbaseaway_time = 0; - bs->decisionmaker = bs->client; - bs->ordered = qfalse; - //get an alternative route goal towards the enemy base - BotGetAlternateRouteGoal(bs, BotOppositeTeam(bs)); - // - BotSetTeamStatus(bs); - BotVoiceChat(bs, -1, VOICECHAT_IHAVEFLAG); - } - return; - } - // if the bot decided to follow someone - if ( bs->ltgtype == LTG_TEAMACCOMPANY && !bs->ordered ) { - // if the team mate being accompanied no longer carries the flag - BotEntityInfo(bs->teammate, &entinfo); - if (!EntityCarriesFlag(&entinfo)) { - bs->ltgtype = 0; - } - } - //our team has the flag - if (bs->neutralflagstatus == 1) { - if (bs->owndecision_time < FloatTime()) { - // if not already following someone - if (bs->ltgtype != LTG_TEAMACCOMPANY) { - //if there is a visible team mate flag carrier - c = BotTeamFlagCarrierVisible(bs); - if (c >= 0) { - BotRefuseOrder(bs); - //follow the flag carrier - bs->decisionmaker = bs->client; - bs->ordered = qfalse; - //the team mate - bs->teammate = c; - //last time the team mate was visible - bs->teammatevisible_time = FloatTime(); - //no message - bs->teammessage_time = 0; - //no arrive message - bs->arrive_time = 1; - // - BotVoiceChat(bs, bs->teammate, VOICECHAT_ONFOLLOW); - //get the team goal time - bs->teamgoal_time = FloatTime() + TEAM_ACCOMPANY_TIME; - bs->ltgtype = LTG_TEAMACCOMPANY; - bs->formation_dist = 3.5 * 32; //3.5 meter - BotSetTeamStatus(bs); - bs->owndecision_time = FloatTime() + 5; - return; - } - } - //if already a CTF or team goal - if (bs->ltgtype == LTG_TEAMHELP || - bs->ltgtype == LTG_TEAMACCOMPANY || - bs->ltgtype == LTG_DEFENDKEYAREA || - bs->ltgtype == LTG_GETFLAG || - bs->ltgtype == LTG_RUSHBASE || - bs->ltgtype == LTG_CAMPORDER || - bs->ltgtype == LTG_PATROL || - bs->ltgtype == LTG_ATTACKENEMYBASE || - bs->ltgtype == LTG_GETITEM || - bs->ltgtype == LTG_MAKELOVE_UNDER || - bs->ltgtype == LTG_MAKELOVE_ONTOP) { - return; - } - //if not already attacking the enemy base - if (bs->ltgtype != LTG_ATTACKENEMYBASE) { - BotRefuseOrder(bs); - bs->decisionmaker = bs->client; - bs->ordered = qfalse; - // - if (BotTeam(bs) == TEAM_RED) memcpy(&bs->teamgoal, &ctf_blueflag, sizeof(bot_goal_t)); - else memcpy(&bs->teamgoal, &ctf_redflag, sizeof(bot_goal_t)); - //set the ltg type - bs->ltgtype = LTG_ATTACKENEMYBASE; - //set the time the bot will stop getting the flag - bs->teamgoal_time = FloatTime() + TEAM_ATTACKENEMYBASE_TIME; - BotSetTeamStatus(bs); - bs->owndecision_time = FloatTime() + 5; - } - } - return; - } - //enemy team has the flag - else if (bs->neutralflagstatus == 2) { - if (bs->owndecision_time < FloatTime()) { - c = BotEnemyFlagCarrierVisible(bs); - if (c >= 0) { - //FIXME: attack enemy flag carrier - } - //if already a CTF or team goal - if (bs->ltgtype == LTG_TEAMHELP || - bs->ltgtype == LTG_TEAMACCOMPANY || - bs->ltgtype == LTG_CAMPORDER || - bs->ltgtype == LTG_PATROL || - bs->ltgtype == LTG_GETITEM) { - return; - } - // if not already defending the base - if (bs->ltgtype != LTG_DEFENDKEYAREA) { - BotRefuseOrder(bs); - bs->decisionmaker = bs->client; - bs->ordered = qfalse; - // - if (BotTeam(bs) == TEAM_RED) memcpy(&bs->teamgoal, &ctf_redflag, sizeof(bot_goal_t)); - else memcpy(&bs->teamgoal, &ctf_blueflag, sizeof(bot_goal_t)); - //set the ltg type - bs->ltgtype = LTG_DEFENDKEYAREA; - //set the time the bot stops defending the base - bs->teamgoal_time = FloatTime() + TEAM_DEFENDKEYAREA_TIME; - bs->defendaway_time = 0; - BotSetTeamStatus(bs); - bs->owndecision_time = FloatTime() + 5; - } - } - return; - } - // don't just do something wait for the bot team leader to give orders - if (BotTeamLeader(bs)) { - return; - } - // if the bot is ordered to do something - if ( bs->lastgoal_ltgtype ) { - bs->teamgoal_time += 60; - } - // if the bot decided to do something on it's own and has a last ordered goal - if ( !bs->ordered && bs->lastgoal_ltgtype ) { - bs->ltgtype = 0; - } - //if already a CTF or team goal - if (bs->ltgtype == LTG_TEAMHELP || - bs->ltgtype == LTG_TEAMACCOMPANY || - bs->ltgtype == LTG_DEFENDKEYAREA || - bs->ltgtype == LTG_GETFLAG || - bs->ltgtype == LTG_RUSHBASE || - bs->ltgtype == LTG_RETURNFLAG || - bs->ltgtype == LTG_CAMPORDER || - bs->ltgtype == LTG_PATROL || - bs->ltgtype == LTG_ATTACKENEMYBASE || - bs->ltgtype == LTG_GETITEM || - bs->ltgtype == LTG_MAKELOVE_UNDER || - bs->ltgtype == LTG_MAKELOVE_ONTOP) { - return; - } - // - if (BotSetLastOrderedTask(bs)) - return; - // - if (bs->owndecision_time > FloatTime()) - return;; - //if the bot is roaming - if (bs->ctfroam_time > FloatTime()) - return; - //if the bot has anough aggression to decide what to do - if (BotAggression(bs) < 50) - return; - //set the time to send a message to the team mates - bs->teammessage_time = FloatTime() + 2 * random(); - // - if (bs->teamtaskpreference & (TEAMTP_ATTACKER|TEAMTP_DEFENDER)) { - if (bs->teamtaskpreference & TEAMTP_ATTACKER) { - l1 = 0.7f; - } - else { - l1 = 0.2f; - } - l2 = 0.9f; - } - else { - l1 = 0.4f; - l2 = 0.7f; - } - //get the flag or defend the base - rnd = random(); - if (rnd < l1 && ctf_neutralflag.areanum) { - bs->decisionmaker = bs->client; - bs->ordered = qfalse; - bs->ltgtype = LTG_GETFLAG; - //set the time the bot will stop getting the flag - bs->teamgoal_time = FloatTime() + CTF_GETFLAG_TIME; - BotSetTeamStatus(bs); - } - else if (rnd < l2 && ctf_redflag.areanum && ctf_blueflag.areanum) { - bs->decisionmaker = bs->client; - bs->ordered = qfalse; - // - if (BotTeam(bs) == TEAM_RED) memcpy(&bs->teamgoal, &ctf_redflag, sizeof(bot_goal_t)); - else memcpy(&bs->teamgoal, &ctf_blueflag, sizeof(bot_goal_t)); - //set the ltg type - bs->ltgtype = LTG_DEFENDKEYAREA; - //set the time the bot stops defending the base - bs->teamgoal_time = FloatTime() + TEAM_DEFENDKEYAREA_TIME; - bs->defendaway_time = 0; - BotSetTeamStatus(bs); - } - else { - bs->ltgtype = 0; - //set the time the bot will stop roaming - bs->ctfroam_time = FloatTime() + CTF_ROAM_TIME; - BotSetTeamStatus(bs); - } - bs->owndecision_time = FloatTime() + 5; -#ifdef DEBUG - BotPrintTeamGoal(bs); -#endif //DEBUG -} - -/* -================== -Bot1FCTFRetreatGoals -================== -*/ -void Bot1FCTFRetreatGoals(bot_state_t *bs) { - //when carrying a flag in ctf the bot should rush to the enemy base - if (Bot1FCTFCarryingFlag(bs)) { - //if not already rushing to the base - if (bs->ltgtype != LTG_RUSHBASE) { - BotRefuseOrder(bs); - bs->ltgtype = LTG_RUSHBASE; - bs->teamgoal_time = FloatTime() + CTF_RUSHBASE_TIME; - bs->rushbaseaway_time = 0; - bs->decisionmaker = bs->client; - bs->ordered = qfalse; - //get an alternative route goal towards the enemy base - BotGetAlternateRouteGoal(bs, BotOppositeTeam(bs)); - BotSetTeamStatus(bs); - } - } -} - -/* -================== -BotObeliskSeekGoals -================== -*/ -void BotObeliskSeekGoals(bot_state_t *bs) { - float rnd, l1, l2; - - // don't just do something wait for the bot team leader to give orders - if (BotTeamLeader(bs)) { - return; - } - // if the bot is ordered to do something - if ( bs->lastgoal_ltgtype ) { - bs->teamgoal_time += 60; - } - //if already a team goal - if (bs->ltgtype == LTG_TEAMHELP || - bs->ltgtype == LTG_TEAMACCOMPANY || - bs->ltgtype == LTG_DEFENDKEYAREA || - bs->ltgtype == LTG_GETFLAG || - bs->ltgtype == LTG_RUSHBASE || - bs->ltgtype == LTG_RETURNFLAG || - bs->ltgtype == LTG_CAMPORDER || - bs->ltgtype == LTG_PATROL || - bs->ltgtype == LTG_ATTACKENEMYBASE || - bs->ltgtype == LTG_GETITEM || - bs->ltgtype == LTG_MAKELOVE_UNDER || - bs->ltgtype == LTG_MAKELOVE_ONTOP) { - return; - } - // - if (BotSetLastOrderedTask(bs)) - return; - //if the bot is roaming - if (bs->ctfroam_time > FloatTime()) - return; - //if the bot has anough aggression to decide what to do - if (BotAggression(bs) < 50) - return; - //set the time to send a message to the team mates - bs->teammessage_time = FloatTime() + 2 * random(); - // - if (bs->teamtaskpreference & (TEAMTP_ATTACKER|TEAMTP_DEFENDER)) { - if (bs->teamtaskpreference & TEAMTP_ATTACKER) { - l1 = 0.7f; - } - else { - l1 = 0.2f; - } - l2 = 0.9f; - } - else { - l1 = 0.4f; - l2 = 0.7f; - } - //get the flag or defend the base - rnd = random(); - if (rnd < l1 && redobelisk.areanum && blueobelisk.areanum) { - bs->decisionmaker = bs->client; - bs->ordered = qfalse; - // - if (BotTeam(bs) == TEAM_RED) memcpy(&bs->teamgoal, &blueobelisk, sizeof(bot_goal_t)); - else memcpy(&bs->teamgoal, &redobelisk, sizeof(bot_goal_t)); - //set the ltg type - bs->ltgtype = LTG_ATTACKENEMYBASE; - //set the time the bot will stop attacking the enemy base - bs->teamgoal_time = FloatTime() + TEAM_ATTACKENEMYBASE_TIME; - //get an alternate route goal towards the enemy base - BotGetAlternateRouteGoal(bs, BotOppositeTeam(bs)); - BotSetTeamStatus(bs); - } - else if (rnd < l2 && redobelisk.areanum && blueobelisk.areanum) { - bs->decisionmaker = bs->client; - bs->ordered = qfalse; - // - if (BotTeam(bs) == TEAM_RED) memcpy(&bs->teamgoal, &redobelisk, sizeof(bot_goal_t)); - else memcpy(&bs->teamgoal, &blueobelisk, sizeof(bot_goal_t)); - //set the ltg type - bs->ltgtype = LTG_DEFENDKEYAREA; - //set the time the bot stops defending the base - bs->teamgoal_time = FloatTime() + TEAM_DEFENDKEYAREA_TIME; - bs->defendaway_time = 0; - BotSetTeamStatus(bs); - } - else { - bs->ltgtype = 0; - //set the time the bot will stop roaming - bs->ctfroam_time = FloatTime() + CTF_ROAM_TIME; - BotSetTeamStatus(bs); - } -} - -/* -================== -BotGoHarvest -================== -*/ -void BotGoHarvest(bot_state_t *bs) { - // - if (BotTeam(bs) == TEAM_RED) memcpy(&bs->teamgoal, &blueobelisk, sizeof(bot_goal_t)); - else memcpy(&bs->teamgoal, &redobelisk, sizeof(bot_goal_t)); - //set the ltg type - bs->ltgtype = LTG_HARVEST; - //set the time the bot will stop harvesting - bs->teamgoal_time = FloatTime() + TEAM_HARVEST_TIME; - bs->harvestaway_time = 0; - BotSetTeamStatus(bs); -} - -/* -================== -BotObeliskRetreatGoals -================== -*/ -void BotObeliskRetreatGoals(bot_state_t *bs) { - //nothing special -} - -/* -================== -BotHarvesterSeekGoals -================== -*/ -void BotHarvesterSeekGoals(bot_state_t *bs) { - aas_entityinfo_t entinfo; - float rnd, l1, l2; - int c; - - //when carrying cubes in harvester the bot should rush to the base - if (BotHarvesterCarryingCubes(bs)) { - //if not already rushing to the base - if (bs->ltgtype != LTG_RUSHBASE) { - BotRefuseOrder(bs); - bs->ltgtype = LTG_RUSHBASE; - bs->teamgoal_time = FloatTime() + CTF_RUSHBASE_TIME; - bs->rushbaseaway_time = 0; - bs->decisionmaker = bs->client; - bs->ordered = qfalse; - //get an alternative route goal towards the enemy base - BotGetAlternateRouteGoal(bs, BotOppositeTeam(bs)); - // - BotSetTeamStatus(bs); - } - return; - } - // don't just do something wait for the bot team leader to give orders - if (BotTeamLeader(bs)) { - return; - } - // if the bot decided to follow someone - if ( bs->ltgtype == LTG_TEAMACCOMPANY && !bs->ordered ) { - // if the team mate being accompanied no longer carries the flag - BotEntityInfo(bs->teammate, &entinfo); - if (!EntityCarriesCubes(&entinfo)) { - bs->ltgtype = 0; - } - } - // if the bot is ordered to do something - if ( bs->lastgoal_ltgtype ) { - bs->teamgoal_time += 60; - } - //if not yet doing something - if (bs->ltgtype == LTG_TEAMHELP || - bs->ltgtype == LTG_TEAMACCOMPANY || - bs->ltgtype == LTG_DEFENDKEYAREA || - bs->ltgtype == LTG_GETFLAG || - bs->ltgtype == LTG_CAMPORDER || - bs->ltgtype == LTG_PATROL || - bs->ltgtype == LTG_ATTACKENEMYBASE || - bs->ltgtype == LTG_HARVEST || - bs->ltgtype == LTG_GETITEM || - bs->ltgtype == LTG_MAKELOVE_UNDER || - bs->ltgtype == LTG_MAKELOVE_ONTOP) { - return; - } - // - if (BotSetLastOrderedTask(bs)) - return; - //if the bot is roaming - if (bs->ctfroam_time > FloatTime()) - return; - //if the bot has anough aggression to decide what to do - if (BotAggression(bs) < 50) - return; - //set the time to send a message to the team mates - bs->teammessage_time = FloatTime() + 2 * random(); - // - c = BotEnemyCubeCarrierVisible(bs); - if (c >= 0) { - //FIXME: attack enemy cube carrier - } - if (bs->ltgtype != LTG_TEAMACCOMPANY) { - //if there is a visible team mate carrying cubes - c = BotTeamCubeCarrierVisible(bs); - if (c >= 0) { - //follow the team mate carrying cubes - bs->decisionmaker = bs->client; - bs->ordered = qfalse; - //the team mate - bs->teammate = c; - //last time the team mate was visible - bs->teammatevisible_time = FloatTime(); - //no message - bs->teammessage_time = 0; - //no arrive message - bs->arrive_time = 1; - // - BotVoiceChat(bs, bs->teammate, VOICECHAT_ONFOLLOW); - //get the team goal time - bs->teamgoal_time = FloatTime() + TEAM_ACCOMPANY_TIME; - bs->ltgtype = LTG_TEAMACCOMPANY; - bs->formation_dist = 3.5 * 32; //3.5 meter - BotSetTeamStatus(bs); - return; - } - } - // - if (bs->teamtaskpreference & (TEAMTP_ATTACKER|TEAMTP_DEFENDER)) { - if (bs->teamtaskpreference & TEAMTP_ATTACKER) { - l1 = 0.7f; - } - else { - l1 = 0.2f; - } - l2 = 0.9f; - } - else { - l1 = 0.4f; - l2 = 0.7f; - } - // - rnd = random(); - if (rnd < l1 && redobelisk.areanum && blueobelisk.areanum) { - bs->decisionmaker = bs->client; - bs->ordered = qfalse; - BotGoHarvest(bs); - } - else if (rnd < l2 && redobelisk.areanum && blueobelisk.areanum) { - bs->decisionmaker = bs->client; - bs->ordered = qfalse; - // - if (BotTeam(bs) == TEAM_RED) memcpy(&bs->teamgoal, &redobelisk, sizeof(bot_goal_t)); - else memcpy(&bs->teamgoal, &blueobelisk, sizeof(bot_goal_t)); - //set the ltg type - bs->ltgtype = LTG_DEFENDKEYAREA; - //set the time the bot stops defending the base - bs->teamgoal_time = FloatTime() + TEAM_DEFENDKEYAREA_TIME; - bs->defendaway_time = 0; - BotSetTeamStatus(bs); - } - else { - bs->ltgtype = 0; - //set the time the bot will stop roaming - bs->ctfroam_time = FloatTime() + CTF_ROAM_TIME; - BotSetTeamStatus(bs); - } -} - -/* -================== -BotHarvesterRetreatGoals -================== -*/ -void BotHarvesterRetreatGoals(bot_state_t *bs) { - //when carrying cubes in harvester the bot should rush to the base - if (BotHarvesterCarryingCubes(bs)) { - //if not already rushing to the base - if (bs->ltgtype != LTG_RUSHBASE) { - BotRefuseOrder(bs); - bs->ltgtype = LTG_RUSHBASE; - bs->teamgoal_time = FloatTime() + CTF_RUSHBASE_TIME; - bs->rushbaseaway_time = 0; - bs->decisionmaker = bs->client; - bs->ordered = qfalse; - BotSetTeamStatus(bs); - } - return; - } -} -#endif - -/* -================== -BotTeamGoals -================== -*/ -void BotTeamGoals(bot_state_t *bs, int retreat) { - - if ( retreat ) { - if (gametype == GT_CTF) { - BotCTFRetreatGoals(bs); - } -#ifdef MISSIONPACK - else if (gametype == GT_1FCTF) { - Bot1FCTFRetreatGoals(bs); - } - else if (gametype == GT_OBELISK) { - BotObeliskRetreatGoals(bs); - } - else if (gametype == GT_HARVESTER) { - BotHarvesterRetreatGoals(bs); - } -#endif - } - else { - if (gametype == GT_CTF) { - //decide what to do in CTF mode - BotCTFSeekGoals(bs); - } -#ifdef MISSIONPACK - else if (gametype == GT_1FCTF) { - Bot1FCTFSeekGoals(bs); - } - else if (gametype == GT_OBELISK) { - BotObeliskSeekGoals(bs); - } - else if (gametype == GT_HARVESTER) { - BotHarvesterSeekGoals(bs); - } -#endif - } - // reset the order time which is used to see if - // we decided to refuse an order - bs->order_time = 0; -} - -/* -================== -BotPointAreaNum -================== -*/ -int BotPointAreaNum(vec3_t origin) { - int areanum, numareas, areas[10]; - vec3_t end; - - areanum = trap_AAS_PointAreaNum(origin); - if (areanum) return areanum; - VectorCopy(origin, end); - end[2] += 10; - numareas = trap_AAS_TraceAreas(origin, end, areas, NULL, 10); - if (numareas > 0) return areas[0]; - return 0; -} - -/* -================== -ClientName -================== -*/ -char *ClientName(int client, char *name, int size) { - char buf[MAX_INFO_STRING]; - - if (client < 0 || client >= MAX_CLIENTS) { - BotAI_Print(PRT_ERROR, "ClientName: client out of range\n"); - return "[client out of range]"; - } - trap_GetConfigstring(CS_PLAYERS+client, buf, sizeof(buf)); - strncpy(name, Info_ValueForKey(buf, "n"), size-1); - name[size-1] = '\0'; - Q_CleanStr( name ); - return name; -} - -/* -================== -ClientSkin -================== -*/ -char *ClientSkin(int client, char *skin, int size) { - char buf[MAX_INFO_STRING]; - - if (client < 0 || client >= MAX_CLIENTS) { - BotAI_Print(PRT_ERROR, "ClientSkin: client out of range\n"); - return "[client out of range]"; - } - trap_GetConfigstring(CS_PLAYERS+client, buf, sizeof(buf)); - strncpy(skin, Info_ValueForKey(buf, "model"), size-1); - skin[size-1] = '\0'; - return skin; -} - -/* -================== -ClientFromName -================== -*/ -int ClientFromName(char *name) { - int i; - char buf[MAX_INFO_STRING]; - static int maxclients; - - if (!maxclients) - maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients"); - for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) { - trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf)); - Q_CleanStr( buf ); - if (!Q_stricmp(Info_ValueForKey(buf, "n"), name)) return i; - } - return -1; -} - -/* -================== -ClientOnSameTeamFromName -================== -*/ -int ClientOnSameTeamFromName(bot_state_t *bs, char *name) { - int i; - char buf[MAX_INFO_STRING]; - static int maxclients; - - if (!maxclients) - maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients"); - for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) { - if (!BotSameTeam(bs, i)) - continue; - trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf)); - Q_CleanStr( buf ); - if (!Q_stricmp(Info_ValueForKey(buf, "n"), name)) return i; - } - return -1; -} - -/* -================== -stristr -================== -*/ -char *stristr(char *str, char *charset) { - int i; - - while(*str) { - for (i = 0; charset[i] && str[i]; i++) { - if (toupper(charset[i]) != toupper(str[i])) break; - } - if (!charset[i]) return str; - str++; - } - return NULL; -} - -/* -================== -EasyClientName -================== -*/ -char *EasyClientName(int client, char *buf, int size) { - int i; - char *str1, *str2, *ptr, c; - char name[128]; - - strcpy(name, ClientName(client, name, sizeof(name))); - for (i = 0; name[i]; i++) name[i] &= 127; - //remove all spaces - for (ptr = strstr(name, " "); ptr; ptr = strstr(name, " ")) { - memmove(ptr, ptr+1, strlen(ptr+1)+1); - } - //check for [x] and ]x[ clan names - str1 = strstr(name, "["); - str2 = strstr(name, "]"); - if (str1 && str2) { - if (str2 > str1) memmove(str1, str2+1, strlen(str2+1)+1); - else memmove(str2, str1+1, strlen(str1+1)+1); - } - //remove Mr prefix - if ((name[0] == 'm' || name[0] == 'M') && - (name[1] == 'r' || name[1] == 'R')) { - memmove(name, name+2, strlen(name+2)+1); - } - //only allow lower case alphabet characters - ptr = name; - while(*ptr) { - c = *ptr; - if ((c >= 'a' && c <= 'z') || - (c >= '0' && c <= '9') || c == '_') { - ptr++; - } - else if (c >= 'A' && c <= 'Z') { - *ptr += 'a' - 'A'; - ptr++; - } - else { - memmove(ptr, ptr+1, strlen(ptr + 1)+1); - } - } - strncpy(buf, name, size-1); - buf[size-1] = '\0'; - return buf; -} - -/* -================== -BotSynonymContext -================== -*/ -int BotSynonymContext(bot_state_t *bs) { - int context; - - context = CONTEXT_NORMAL|CONTEXT_NEARBYITEM|CONTEXT_NAMES; - // - if (gametype == GT_CTF -#ifdef MISSIONPACK - || gametype == GT_1FCTF -#endif - ) { - if (BotTeam(bs) == TEAM_RED) context |= CONTEXT_CTFREDTEAM; - else context |= CONTEXT_CTFBLUETEAM; - } -#ifdef MISSIONPACK - else if (gametype == GT_OBELISK) { - if (BotTeam(bs) == TEAM_RED) context |= CONTEXT_OBELISKREDTEAM; - else context |= CONTEXT_OBELISKBLUETEAM; - } - else if (gametype == GT_HARVESTER) { - if (BotTeam(bs) == TEAM_RED) context |= CONTEXT_HARVESTERREDTEAM; - else context |= CONTEXT_HARVESTERBLUETEAM; - } -#endif - return context; -} - -/* -================== -BotChooseWeapon -================== -*/ -void BotChooseWeapon(bot_state_t *bs) { - int newweaponnum; - - if (bs->cur_ps.weaponstate == WEAPON_RAISING || - bs->cur_ps.weaponstate == WEAPON_DROPPING) { - trap_EA_SelectWeapon(bs->client, bs->weaponnum); - } - else { - newweaponnum = trap_BotChooseBestFightWeapon(bs->ws, bs->inventory); - if (bs->weaponnum != newweaponnum) bs->weaponchange_time = FloatTime(); - bs->weaponnum = newweaponnum; - //BotAI_Print(PRT_MESSAGE, "bs->weaponnum = %d\n", bs->weaponnum); - trap_EA_SelectWeapon(bs->client, bs->weaponnum); - } -} - -/* -================== -BotSetupForMovement -================== -*/ -void BotSetupForMovement(bot_state_t *bs) { - bot_initmove_t initmove; - - memset(&initmove, 0, sizeof(bot_initmove_t)); - VectorCopy(bs->cur_ps.origin, initmove.origin); - VectorCopy(bs->cur_ps.velocity, initmove.velocity); - VectorCopy(bs->cur_ps.origin, initmove.viewoffset); - initmove.viewoffset[2] += bs->cur_ps.viewheight; - initmove.entitynum = bs->entitynum; - initmove.client = bs->client; - initmove.thinktime = bs->thinktime; - //set the onground flag - if (bs->cur_ps.groundEntityNum != ENTITYNUM_NONE) initmove.or_moveflags |= MFL_ONGROUND; - //set the teleported flag - if ((bs->cur_ps.pm_flags & PMF_TIME_KNOCKBACK) && (bs->cur_ps.pm_time > 0)) { - initmove.or_moveflags |= MFL_TELEPORTED; - } - //set the waterjump flag - if ((bs->cur_ps.pm_flags & PMF_TIME_WATERJUMP) && (bs->cur_ps.pm_time > 0)) { - initmove.or_moveflags |= MFL_WATERJUMP; - } - //set presence type - if (bs->cur_ps.pm_flags & PMF_DUCKED) initmove.presencetype = PRESENCE_CROUCH; - else initmove.presencetype = PRESENCE_NORMAL; - // - if (bs->walker > 0.5) initmove.or_moveflags |= MFL_WALK; - // - VectorCopy(bs->viewangles, initmove.viewangles); - // - trap_BotInitMoveState(bs->ms, &initmove); -} - -/* -================== -BotCheckItemPickup -================== -*/ -void BotCheckItemPickup(bot_state_t *bs, int *oldinventory) { -#ifdef MISSIONPACK - int offence, leader; - - if (gametype <= GT_TEAM) - return; - - offence = -1; - // go into offence if picked up the kamikaze or invulnerability - if (!oldinventory[INVENTORY_KAMIKAZE] && bs->inventory[INVENTORY_KAMIKAZE] >= 1) { - offence = qtrue; - } - if (!oldinventory[INVENTORY_INVULNERABILITY] && bs->inventory[INVENTORY_INVULNERABILITY] >= 1) { - offence = qtrue; - } - // if not already wearing the kamikaze or invulnerability - if (!bs->inventory[INVENTORY_KAMIKAZE] && !bs->inventory[INVENTORY_INVULNERABILITY]) { - if (!oldinventory[INVENTORY_SCOUT] && bs->inventory[INVENTORY_SCOUT] >= 1) { - offence = qtrue; - } - if (!oldinventory[INVENTORY_GUARD] && bs->inventory[INVENTORY_GUARD] >= 1) { - offence = qtrue; - } - if (!oldinventory[INVENTORY_DOUBLER] && bs->inventory[INVENTORY_DOUBLER] >= 1) { - offence = qfalse; - } - if (!oldinventory[INVENTORY_AMMOREGEN] && bs->inventory[INVENTORY_AMMOREGEN] >= 1) { - offence = qfalse; - } - } - - if (offence >= 0) { - leader = ClientFromName(bs->teamleader); - if (offence) { - if (!(bs->teamtaskpreference & TEAMTP_ATTACKER)) { - // if we have a bot team leader - if (BotTeamLeader(bs)) { - // tell the leader we want to be on offence - BotVoiceChat(bs, leader, VOICECHAT_WANTONOFFENSE); - //BotAI_BotInitialChat(bs, "wantoffence", NULL); - //trap_BotEnterChat(bs->cs, leader, CHAT_TELL); - } - else if (g_spSkill.integer <= 3) { - if ( bs->ltgtype != LTG_GETFLAG && - bs->ltgtype != LTG_ATTACKENEMYBASE && - bs->ltgtype != LTG_HARVEST ) { - // - if ((gametype != GT_CTF || (bs->redflagstatus == 0 && bs->blueflagstatus == 0)) && - (gametype != GT_1FCTF || bs->neutralflagstatus == 0) ) { - // tell the leader we want to be on offence - BotVoiceChat(bs, leader, VOICECHAT_WANTONOFFENSE); - //BotAI_BotInitialChat(bs, "wantoffence", NULL); - //trap_BotEnterChat(bs->cs, leader, CHAT_TELL); - } - } - bs->teamtaskpreference |= TEAMTP_ATTACKER; - } - } - bs->teamtaskpreference &= ~TEAMTP_DEFENDER; - } - else { - if (!(bs->teamtaskpreference & TEAMTP_DEFENDER)) { - // if we have a bot team leader - if (BotTeamLeader(bs)) { - // tell the leader we want to be on defense - BotVoiceChat(bs, -1, VOICECHAT_WANTONDEFENSE); - //BotAI_BotInitialChat(bs, "wantdefence", NULL); - //trap_BotEnterChat(bs->cs, leader, CHAT_TELL); - } - else if (g_spSkill.integer <= 3) { - if ( bs->ltgtype != LTG_DEFENDKEYAREA ) { - // - if ((gametype != GT_CTF || (bs->redflagstatus == 0 && bs->blueflagstatus == 0)) && - (gametype != GT_1FCTF || bs->neutralflagstatus == 0) ) { - // tell the leader we want to be on defense - BotVoiceChat(bs, -1, VOICECHAT_WANTONDEFENSE); - //BotAI_BotInitialChat(bs, "wantdefence", NULL); - //trap_BotEnterChat(bs->cs, leader, CHAT_TELL); - } - } - } - bs->teamtaskpreference |= TEAMTP_DEFENDER; - } - bs->teamtaskpreference &= ~TEAMTP_ATTACKER; - } - } -#endif -} - -/* -================== -BotUpdateInventory -================== -*/ -void BotUpdateInventory(bot_state_t *bs) { - int oldinventory[MAX_ITEMS]; - - memcpy(oldinventory, bs->inventory, sizeof(oldinventory)); - //armor - bs->inventory[INVENTORY_ARMOR] = bs->cur_ps.stats[STAT_ARMOR]; - //weapons - //Blaze: Reaction Weapons - bs->inventory[INVENTORY_KNIFE] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_KNIFE)) !=0; - bs->inventory[INVENTORY_PISTOL] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_PISTOL)) != 0; - bs->inventory[INVENTORY_M4] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_M4)) != 0; - bs->inventory[INVENTORY_SSG3000] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_SSG3000)) != 0; - bs->inventory[INVENTORY_MP5] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_MP5)) != 0; - bs->inventory[INVENTORY_HANDCANNON] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_HANDCANNON)) != 0; - bs->inventory[INVENTORY_M3] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_M3)) != 0; - bs->inventory[INVENTORY_AKIMBO] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_AKIMBO)) != 0; - bs->inventory[INVENTORY_GRENADE] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_GRENADE)) != 0; - //ammo - bs->inventory[INVENTORY_PISTOLAMMO] = bs->cur_ps.ammo[WP_PISTOL]; - bs->inventory[INVENTORY_KNIFEAMMO] = bs->cur_ps.ammo[WP_KNIFE]; - bs->inventory[INVENTORY_M4AMMO] = bs->cur_ps.ammo[WP_M4]; - bs->inventory[INVENTORY_SSG3000AMMO] = bs->cur_ps.ammo[WP_SSG3000]; - bs->inventory[INVENTORY_MP5AMMO] = bs->cur_ps.ammo[WP_MP5]; - //Blaze: Same ammo for shotgun and handcannon - bs->inventory[INVENTORY_SHOTGUNAMMO] = bs->cur_ps.ammo[WP_HANDCANNON]; - bs->inventory[INVENTORY_SHOTGUNAMMO] = bs->cur_ps.ammo[WP_M3]; - //Blaze: Same ammo for Pistol and Akimbo Pistols - bs->inventory[INVENTORY_PISTOLAMMO] = bs->cur_ps.ammo[WP_AKIMBO]; - bs->inventory[INVENTORY_GRENADEAMMO] = bs->cur_ps.ammo[WP_GRENADE]; - -// bs->inventory[INVENTORY_BFGAMMO] = bs->cur_ps.ammo[WP_BFG]; - //powerups - bs->inventory[INVENTORY_HEALTH] = bs->cur_ps.stats[STAT_HEALTH]; - bs->inventory[INVENTORY_TELEPORTER] = bs->cur_ps.stats[STAT_HOLDABLE_ITEM] == MODELINDEX_TELEPORTER; - bs->inventory[INVENTORY_MEDKIT] = bs->cur_ps.stats[STAT_HOLDABLE_ITEM] == MODELINDEX_MEDKIT; -#ifdef MISSIONPACK - bs->inventory[INVENTORY_KAMIKAZE] = bs->cur_ps.stats[STAT_HOLDABLE_ITEM] == MODELINDEX_KAMIKAZE; - bs->inventory[INVENTORY_PORTAL] = bs->cur_ps.stats[STAT_HOLDABLE_ITEM] == MODELINDEX_PORTAL; - bs->inventory[INVENTORY_INVULNERABILITY] = bs->cur_ps.stats[STAT_HOLDABLE_ITEM] == MODELINDEX_INVULNERABILITY; -#endif - bs->inventory[INVENTORY_QUAD] = bs->cur_ps.powerups[PW_QUAD] != 0; - bs->inventory[INVENTORY_ENVIRONMENTSUIT] = bs->cur_ps.powerups[PW_BATTLESUIT] != 0; - bs->inventory[INVENTORY_HASTE] = bs->cur_ps.powerups[PW_HASTE] != 0; - bs->inventory[INVENTORY_INVISIBILITY] = bs->cur_ps.powerups[PW_INVIS] != 0; - bs->inventory[INVENTORY_REGEN] = bs->cur_ps.powerups[PW_REGEN] != 0; - bs->inventory[INVENTORY_FLIGHT] = bs->cur_ps.powerups[PW_FLIGHT] != 0; -#ifdef MISSIONPACK - bs->inventory[INVENTORY_SCOUT] = bs->cur_ps.stats[STAT_PERSISTANT_POWERUP] == MODELINDEX_SCOUT; - bs->inventory[INVENTORY_GUARD] = bs->cur_ps.stats[STAT_PERSISTANT_POWERUP] == MODELINDEX_GUARD; - bs->inventory[INVENTORY_DOUBLER] = bs->cur_ps.stats[STAT_PERSISTANT_POWERUP] == MODELINDEX_DOUBLER; - bs->inventory[INVENTORY_AMMOREGEN] = bs->cur_ps.stats[STAT_PERSISTANT_POWERUP] == MODELINDEX_AMMOREGEN; -#endif - bs->inventory[INVENTORY_REDFLAG] = bs->cur_ps.powerups[PW_REDFLAG] != 0; - bs->inventory[INVENTORY_BLUEFLAG] = bs->cur_ps.powerups[PW_BLUEFLAG] != 0; -#ifdef MISSIONPACK - bs->inventory[INVENTORY_NEUTRALFLAG] = bs->cur_ps.powerups[PW_NEUTRALFLAG] != 0; - if (BotTeam(bs) == TEAM_RED) { - bs->inventory[INVENTORY_REDCUBE] = bs->cur_ps.generic1; - bs->inventory[INVENTORY_BLUECUBE] = 0; - } - else { - bs->inventory[INVENTORY_REDCUBE] = 0; - bs->inventory[INVENTORY_BLUECUBE] = bs->cur_ps.generic1; - } -#endif - BotCheckItemPickup(bs, oldinventory); -} - -/* -================== -BotUpdateBattleInventory -================== -*/ -void BotUpdateBattleInventory(bot_state_t *bs, int enemy) { - vec3_t dir; - aas_entityinfo_t entinfo; - - BotEntityInfo(enemy, &entinfo); - VectorSubtract(entinfo.origin, bs->origin, dir); - bs->inventory[ENEMY_HEIGHT] = (int) dir[2]; - dir[2] = 0; - bs->inventory[ENEMY_HORIZONTAL_DIST] = (int) VectorLength(dir); - //FIXME: add num visible enemies and num visible team mates to the inventory -} - -#ifdef MISSIONPACK -/* -================== -BotUseKamikaze -================== -*/ -#define KAMIKAZE_DIST 1024 - -void BotUseKamikaze(bot_state_t *bs) { - int c, teammates, enemies; - aas_entityinfo_t entinfo; - vec3_t dir, target; - bot_goal_t *goal; - bsp_trace_t trace; - - //if the bot has no kamikaze - if (bs->inventory[INVENTORY_KAMIKAZE] <= 0) - return; - if (bs->kamikaze_time > FloatTime()) - return; - bs->kamikaze_time = FloatTime() + 0.2; - if (gametype == GT_CTF) { - //never use kamikaze if the team flag carrier is visible - if (BotCTFCarryingFlag(bs)) - return; - c = BotTeamFlagCarrierVisible(bs); - if (c >= 0) { - BotEntityInfo(c, &entinfo); - VectorSubtract(entinfo.origin, bs->origin, dir); - if (VectorLengthSquared(dir) < Square(KAMIKAZE_DIST)) - return; - } - c = BotEnemyFlagCarrierVisible(bs); - if (c >= 0) { - BotEntityInfo(c, &entinfo); - VectorSubtract(entinfo.origin, bs->origin, dir); - if (VectorLengthSquared(dir) < Square(KAMIKAZE_DIST)) { - trap_EA_Use(bs->client); - return; - } - } - } - else if (gametype == GT_1FCTF) { - //never use kamikaze if the team flag carrier is visible - if (Bot1FCTFCarryingFlag(bs)) - return; - c = BotTeamFlagCarrierVisible(bs); - if (c >= 0) { - BotEntityInfo(c, &entinfo); - VectorSubtract(entinfo.origin, bs->origin, dir); - if (VectorLengthSquared(dir) < Square(KAMIKAZE_DIST)) - return; - } - c = BotEnemyFlagCarrierVisible(bs); - if (c >= 0) { - BotEntityInfo(c, &entinfo); - VectorSubtract(entinfo.origin, bs->origin, dir); - if (VectorLengthSquared(dir) < Square(KAMIKAZE_DIST)) { - trap_EA_Use(bs->client); - return; - } - } - } - else if (gametype == GT_OBELISK) { - switch(BotTeam(bs)) { - case TEAM_RED: goal = &blueobelisk; break; - default: goal = &redobelisk; break; - } - //if the obelisk is visible - VectorCopy(goal->origin, target); - target[2] += 1; - VectorSubtract(bs->origin, target, dir); - if (VectorLengthSquared(dir) < Square(KAMIKAZE_DIST * 0.9)) { - BotAI_Trace(&trace, bs->eye, NULL, NULL, target, bs->client, CONTENTS_SOLID); - if (trace.fraction >= 1 || trace.ent == goal->entitynum) { - trap_EA_Use(bs->client); - return; - } - } - } - else if (gametype == GT_HARVESTER) { - // - if (BotHarvesterCarryingCubes(bs)) - return; - //never use kamikaze if a team mate carrying cubes is visible - c = BotTeamCubeCarrierVisible(bs); - if (c >= 0) { - BotEntityInfo(c, &entinfo); - VectorSubtract(entinfo.origin, bs->origin, dir); - if (VectorLengthSquared(dir) < Square(KAMIKAZE_DIST)) - return; - } - c = BotEnemyCubeCarrierVisible(bs); - if (c >= 0) { - BotEntityInfo(c, &entinfo); - VectorSubtract(entinfo.origin, bs->origin, dir); - if (VectorLengthSquared(dir) < Square(KAMIKAZE_DIST)) { - trap_EA_Use(bs->client); - return; - } - } - } - // - BotVisibleTeamMatesAndEnemies(bs, &teammates, &enemies, KAMIKAZE_DIST); - // - if (enemies > 2 && enemies > teammates+1) { - trap_EA_Use(bs->client); - return; - } -} - -/* -================== -BotUseInvulnerability -================== -*/ -void BotUseInvulnerability(bot_state_t *bs) { - int c; - vec3_t dir, target; - bot_goal_t *goal; - bsp_trace_t trace; - - //if the bot has no invulnerability - if (bs->inventory[INVENTORY_INVULNERABILITY] <= 0) - return; - if (bs->invulnerability_time > FloatTime()) - return; - bs->invulnerability_time = FloatTime() + 0.2; - if (gametype == GT_CTF) { - //never use kamikaze if the team flag carrier is visible - if (BotCTFCarryingFlag(bs)) - return; - c = BotEnemyFlagCarrierVisible(bs); - if (c >= 0) - return; - //if near enemy flag and the flag is visible - switch(BotTeam(bs)) { - case TEAM_RED: goal = &ctf_blueflag; break; - default: goal = &ctf_redflag; break; - } - //if the obelisk is visible - VectorCopy(goal->origin, target); - target[2] += 1; - VectorSubtract(bs->origin, target, dir); - if (VectorLengthSquared(dir) < Square(200)) { - BotAI_Trace(&trace, bs->eye, NULL, NULL, target, bs->client, CONTENTS_SOLID); - if (trace.fraction >= 1 || trace.ent == goal->entitynum) { - trap_EA_Use(bs->client); - return; - } - } - } - else if (gametype == GT_1FCTF) { - //never use kamikaze if the team flag carrier is visible - if (Bot1FCTFCarryingFlag(bs)) - return; - c = BotEnemyFlagCarrierVisible(bs); - if (c >= 0) - return; - //if near enemy flag and the flag is visible - switch(BotTeam(bs)) { - case TEAM_RED: goal = &ctf_blueflag; break; - default: goal = &ctf_redflag; break; - } - //if the obelisk is visible - VectorCopy(goal->origin, target); - target[2] += 1; - VectorSubtract(bs->origin, target, dir); - if (VectorLengthSquared(dir) < Square(200)) { - BotAI_Trace(&trace, bs->eye, NULL, NULL, target, bs->client, CONTENTS_SOLID); - if (trace.fraction >= 1 || trace.ent == goal->entitynum) { - trap_EA_Use(bs->client); - return; - } - } - } - else if (gametype == GT_OBELISK) { - switch(BotTeam(bs)) { - case TEAM_RED: goal = &blueobelisk; break; - default: goal = &redobelisk; break; - } - //if the obelisk is visible - VectorCopy(goal->origin, target); - target[2] += 1; - VectorSubtract(bs->origin, target, dir); - if (VectorLengthSquared(dir) < Square(300)) { - BotAI_Trace(&trace, bs->eye, NULL, NULL, target, bs->client, CONTENTS_SOLID); - if (trace.fraction >= 1 || trace.ent == goal->entitynum) { - trap_EA_Use(bs->client); - return; - } - } - } - else if (gametype == GT_HARVESTER) { - // - if (BotHarvesterCarryingCubes(bs)) - return; - c = BotEnemyCubeCarrierVisible(bs); - if (c >= 0) - return; - //if near enemy base and enemy base is visible - switch(BotTeam(bs)) { - case TEAM_RED: goal = &blueobelisk; break; - default: goal = &redobelisk; break; - } - //if the obelisk is visible - VectorCopy(goal->origin, target); - target[2] += 1; - VectorSubtract(bs->origin, target, dir); - if (VectorLengthSquared(dir) < Square(200)) { - BotAI_Trace(&trace, bs->eye, NULL, NULL, target, bs->client, CONTENTS_SOLID); - if (trace.fraction >= 1 || trace.ent == goal->entitynum) { - trap_EA_Use(bs->client); - return; - } - } - } -} -#endif - -/* -================== -BotBattleUseItems -================== -*/ -void BotBattleUseItems(bot_state_t *bs) { - if (bs->inventory[INVENTORY_HEALTH] < 40) { - if (bs->inventory[INVENTORY_TELEPORTER] > 0) { - if (!BotCTFCarryingFlag(bs) -#ifdef MISSIONPACK - && !Bot1FCTFCarryingFlag(bs) - && !BotHarvesterCarryingCubes(bs) -#endif - ) { - trap_EA_Use(bs->client); - } - } - } - if (bs->inventory[INVENTORY_HEALTH] < 60) { - if (bs->inventory[INVENTORY_MEDKIT] > 0) { - trap_EA_Use(bs->client); - } - } -#ifdef MISSIONPACK - BotUseKamikaze(bs); - BotUseInvulnerability(bs); -#endif -} - -/* -================== -BotSetTeleportTime -================== -*/ -void BotSetTeleportTime(bot_state_t *bs) { - if ((bs->cur_ps.eFlags ^ bs->last_eFlags) & EF_TELEPORT_BIT) { - bs->teleport_time = FloatTime(); - } - bs->last_eFlags = bs->cur_ps.eFlags; -} - -/* -================== -BotIsDead -================== -*/ -qboolean BotIsDead(bot_state_t *bs) { - return (bs->cur_ps.pm_type == PM_DEAD); -} - -/* -================== -BotIsObserver -================== -*/ -qboolean BotIsObserver(bot_state_t *bs) { - char buf[MAX_INFO_STRING]; - if (bs->cur_ps.pm_type == PM_SPECTATOR) return qtrue; - trap_GetConfigstring(CS_PLAYERS+bs->client, buf, sizeof(buf)); - if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR) return qtrue; - return qfalse; -} - -/* -================== -BotIntermission -================== -*/ -qboolean BotIntermission(bot_state_t *bs) { - //NOTE: we shouldn't be looking at the game code... - if (level.intermissiontime) return qtrue; - return (bs->cur_ps.pm_type == PM_FREEZE || bs->cur_ps.pm_type == PM_INTERMISSION); -} - -/* -================== -BotInLavaOrSlime -================== -*/ -qboolean BotInLavaOrSlime(bot_state_t *bs) { - vec3_t feet; - - VectorCopy(bs->origin, feet); - feet[2] -= 23; - return (trap_AAS_PointContents(feet) & (CONTENTS_LAVA|CONTENTS_SLIME)); -} - -/* -================== -BotCreateWayPoint -================== -*/ -bot_waypoint_t *BotCreateWayPoint(char *name, vec3_t origin, int areanum) { - bot_waypoint_t *wp; - vec3_t waypointmins = {-8, -8, -8}, waypointmaxs = {8, 8, 8}; - - wp = botai_freewaypoints; - if ( !wp ) { - BotAI_Print( PRT_WARNING, "BotCreateWayPoint: Out of waypoints\n" ); - return NULL; - } - botai_freewaypoints = botai_freewaypoints->next; - - Q_strncpyz( wp->name, name, sizeof(wp->name) ); - VectorCopy(origin, wp->goal.origin); - VectorCopy(waypointmins, wp->goal.mins); - VectorCopy(waypointmaxs, wp->goal.maxs); - wp->goal.areanum = areanum; - wp->next = NULL; - wp->prev = NULL; - return wp; -} - -/* -================== -BotFindWayPoint -================== -*/ -bot_waypoint_t *BotFindWayPoint(bot_waypoint_t *waypoints, char *name) { - bot_waypoint_t *wp; - - for (wp = waypoints; wp; wp = wp->next) { - if (!Q_stricmp(wp->name, name)) return wp; - } - return NULL; -} - -/* -================== -BotFreeWaypoints -================== -*/ -void BotFreeWaypoints(bot_waypoint_t *wp) { - bot_waypoint_t *nextwp; - - for (; wp; wp = nextwp) { - nextwp = wp->next; - wp->next = botai_freewaypoints; - botai_freewaypoints = wp; - } -} - -/* -================== -BotInitWaypoints -================== -*/ -void BotInitWaypoints(void) { - int i; - - botai_freewaypoints = NULL; - for (i = 0; i < MAX_WAYPOINTS; i++) { - botai_waypoints[i].next = botai_freewaypoints; - botai_freewaypoints = &botai_waypoints[i]; - } -} - -/* -================== -TeamPlayIsOn -================== -*/ -int TeamPlayIsOn(void) { - return ( gametype >= GT_TEAM ); -} - -/* -================== -BotAggression -================== -*/ -float BotAggression(bot_state_t *bs) { - //if the bot has quad - if (bs->inventory[INVENTORY_QUAD]) { - //if the bot is not holding the gauntlet or the enemy is really nearby - //Blaze: Check for knife probably same logic as slashing as gauntlet??? - if (bs->weaponnum != WP_KNIFE || - bs->inventory[ENEMY_HORIZONTAL_DIST] < 80) { - return 70; - } - } - //if the enemy is located way higher than the bot - if (bs->inventory[ENEMY_HEIGHT] > 200) return 0; - //if the bot is very low on health - if (bs->inventory[INVENTORY_HEALTH] < 60) return 0; - //if the bot is low on health - if (bs->inventory[INVENTORY_HEALTH] < 80) { - //if the bot has insufficient armor - if (bs->inventory[INVENTORY_ARMOR] < 40) return 0; - } - //if the bot can use the bfg - if (bs->inventory[INVENTORY_BFG10K] > 0 && - bs->inventory[INVENTORY_BFGAMMO] > 7) return 100; - //if the bot can use the railgun - if (bs->inventory[INVENTORY_RAILGUN] > 0 && - bs->inventory[INVENTORY_SLUGS] > 5) return 95; - //if the bot can use the lightning gun - if (bs->inventory[INVENTORY_LIGHTNING] > 0 && - bs->inventory[INVENTORY_LIGHTNINGAMMO] > 50) return 90; - //if the bot can use the rocketlauncher - if (bs->inventory[INVENTORY_ROCKETLAUNCHER] > 0 && - bs->inventory[INVENTORY_ROCKETS] > 5) return 90; - //if the bot can use the plasmagun - if (bs->inventory[INVENTORY_PLASMAGUN] > 0 && - bs->inventory[INVENTORY_CELLS] > 40) return 85; - //if the bot can use the grenade launcher - if (bs->inventory[INVENTORY_GRENADELAUNCHER] > 0 && - bs->inventory[INVENTORY_GRENADES] > 10) return 80; - //if the bot can use the shotgun - //if (bs->inventory[INVENTORY_SHOTGUN] > 0 && - // bs->inventory[INVENTORY_SHELLS] > 10) return 50; - //otherwise the bot is not feeling too good - return 0; -} - -/* -================== -BotFeelingBad -================== -*/ -float BotFeelingBad(bot_state_t *bs) { - if (bs->weaponnum == WP_KNIFE) { - return 100; - } - if (bs->inventory[INVENTORY_HEALTH] < 40) { - return 100; - } - if (bs->weaponnum == WP_PISTOL) { - return 90; - } - if (bs->inventory[INVENTORY_HEALTH] < 60) { - return 80; - } - return 0; -} - -/* -================== -BotWantsToRetreat -================== -*/ -int BotWantsToRetreat(bot_state_t *bs) { - aas_entityinfo_t entinfo; - - if (gametype == GT_CTF) { - //always retreat when carrying a CTF flag - if (BotCTFCarryingFlag(bs)) - return qtrue; - } -#ifdef MISSIONPACK - else if (gametype == GT_1FCTF) { - //if carrying the flag then always retreat - if (Bot1FCTFCarryingFlag(bs)) - return qtrue; - } - else if (gametype == GT_OBELISK) { - //the bots should be dedicated to attacking the enemy obelisk - if (bs->ltgtype == LTG_ATTACKENEMYBASE) { - if (bs->enemy != redobelisk.entitynum || - bs->enemy != blueobelisk.entitynum) { - return qtrue; - } - } - if (BotFeelingBad(bs) > 50) { - return qtrue; - } - return qfalse; - } - else if (gametype == GT_HARVESTER) { - //if carrying cubes then always retreat - if (BotHarvesterCarryingCubes(bs)) return qtrue; - } -#endif - // - if (bs->enemy >= 0) { - //if the enemy is carrying a flag - BotEntityInfo(bs->enemy, &entinfo); - if (EntityCarriesFlag(&entinfo)) - return qfalse; - } - //if the bot is getting the flag - if (bs->ltgtype == LTG_GETFLAG) - return qtrue; - // - if (BotAggression(bs) < 50) - return qtrue; - return qfalse; -} - -/* -================== -BotWantsToChase -================== -*/ -int BotWantsToChase(bot_state_t *bs) { - aas_entityinfo_t entinfo; - - if (gametype == GT_CTF) { - //never chase when carrying a CTF flag - if (BotCTFCarryingFlag(bs)) - return qfalse; - //always chase if the enemy is carrying a flag - BotEntityInfo(bs->enemy, &entinfo); - if (EntityCarriesFlag(&entinfo)) - return qtrue; - } -#ifdef MISSIONPACK - else if (gametype == GT_1FCTF) { - //never chase if carrying the flag - if (Bot1FCTFCarryingFlag(bs)) - return qfalse; - //always chase if the enemy is carrying a flag - BotEntityInfo(bs->enemy, &entinfo); - if (EntityCarriesFlag(&entinfo)) - return qtrue; - } - else if (gametype == GT_OBELISK) { - //the bots should be dedicated to attacking the enemy obelisk - if (bs->ltgtype == LTG_ATTACKENEMYBASE) { - if (bs->enemy != redobelisk.entitynum || - bs->enemy != blueobelisk.entitynum) { - return qfalse; - } - } - } - else if (gametype == GT_HARVESTER) { - //never chase if carrying cubes - if (BotHarvesterCarryingCubes(bs)) - return qfalse; - } -#endif - //if the bot is getting the flag - if (bs->ltgtype == LTG_GETFLAG) - return qfalse; - // - if (BotAggression(bs) > 50) - return qtrue; - return qfalse; -} - -/* -================== -BotWantsToHelp -================== -*/ -int BotWantsToHelp(bot_state_t *bs) { - return qtrue; -} - -/* -================== -BotCanAndWantsToRocketJump -================== -*/ -int BotCanAndWantsToRocketJump(bot_state_t *bs) { - float rocketjumper; - - //if rocket jumping is disabled - if (!bot_rocketjump.integer) return qfalse; - //if no rocket launcher - if (bs->inventory[INVENTORY_ROCKETLAUNCHER] <= 0) return qfalse; - //if low on rockets - if (bs->inventory[INVENTORY_ROCKETS] < 3) return qfalse; - //never rocket jump with the Quad - if (bs->inventory[INVENTORY_QUAD]) return qfalse; - //if low on health - if (bs->inventory[INVENTORY_HEALTH] < 60) return qfalse; - //if not full health - if (bs->inventory[INVENTORY_HEALTH] < 90) { - //if the bot has insufficient armor - if (bs->inventory[INVENTORY_ARMOR] < 40) return qfalse; - } - rocketjumper = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_WEAPONJUMPING, 0, 1); - if (rocketjumper < 0.5) return qfalse; - return qtrue; -} - -/* -================== -BotHasPersistantPowerupAndWeapon -================== -*/ -int BotHasPersistantPowerupAndWeapon(bot_state_t *bs) { -#ifdef MISSIONPACK - // if the bot does not have a persistant powerup - if (!bs->inventory[INVENTORY_SCOUT] && - !bs->inventory[INVENTORY_GUARD] && - !bs->inventory[INVENTORY_DOUBLER] && - !bs->inventory[INVENTORY_AMMOREGEN] ) { - return qfalse; - } -#endif - //if the bot is very low on health - if (bs->inventory[INVENTORY_HEALTH] < 60) return qfalse; - //if the bot is low on health - if (bs->inventory[INVENTORY_HEALTH] < 80) { - //if the bot has insufficient armor - if (bs->inventory[INVENTORY_ARMOR] < 40) return qfalse; - } - //if the bot can use the bfg - if (bs->inventory[INVENTORY_BFG10K] > 0 && - bs->inventory[INVENTORY_BFGAMMO] > 7) return qtrue; - //if the bot can use the railgun - if (bs->inventory[INVENTORY_RAILGUN] > 0 && - bs->inventory[INVENTORY_SLUGS] > 5) return qtrue; - //if the bot can use the lightning gun - if (bs->inventory[INVENTORY_LIGHTNING] > 0 && - bs->inventory[INVENTORY_LIGHTNINGAMMO] > 50) return qtrue; - //if the bot can use the rocketlauncher - if (bs->inventory[INVENTORY_ROCKETLAUNCHER] > 0 && - bs->inventory[INVENTORY_ROCKETS] > 5) return qtrue; - // - if (bs->inventory[INVENTORY_NAILGUN] > 0 && - bs->inventory[INVENTORY_NAILS] > 5) return qtrue; - // - if (bs->inventory[INVENTORY_PROXLAUNCHER] > 0 && - bs->inventory[INVENTORY_MINES] > 5) return qtrue; - // - if (bs->inventory[INVENTORY_CHAINGUN] > 0 && - bs->inventory[INVENTORY_BELT] > 40) return qtrue; - //if the bot can use the plasmagun - if (bs->inventory[INVENTORY_PLASMAGUN] > 0 && - bs->inventory[INVENTORY_CELLS] > 20) return qtrue; - return qfalse; -} - -/* -================== -BotGoCamp -================== -*/ -void BotGoCamp(bot_state_t *bs, bot_goal_t *goal) { - float camper; - - bs->decisionmaker = bs->client; - //set message time to zero so bot will NOT show any message - bs->teammessage_time = 0; - //set the ltg type - bs->ltgtype = LTG_CAMP; - //set the team goal - memcpy(&bs->teamgoal, goal, sizeof(bot_goal_t)); - //get the team goal time - camper = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CAMPER, 0, 1); - if (camper > 0.99) bs->teamgoal_time = FloatTime() + 99999; - else bs->teamgoal_time = FloatTime() + 120 + 180 * camper + random() * 15; - //set the last time the bot started camping - bs->camp_time = FloatTime(); - //the teammate that requested the camping - bs->teammate = 0; - //do NOT type arrive message - bs->arrive_time = 1; -} - -/* -================== -BotWantsToCamp -================== -*/ -int BotWantsToCamp(bot_state_t *bs) { - float camper; - int cs, traveltime, besttraveltime; - bot_goal_t goal, bestgoal; - - camper = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CAMPER, 0, 1); - if (camper < 0.1) return qfalse; - //if the bot has a team goal - if (bs->ltgtype == LTG_TEAMHELP || - bs->ltgtype == LTG_TEAMACCOMPANY || - bs->ltgtype == LTG_DEFENDKEYAREA || - bs->ltgtype == LTG_GETFLAG || - bs->ltgtype == LTG_RUSHBASE || - bs->ltgtype == LTG_CAMP || - bs->ltgtype == LTG_CAMPORDER || - bs->ltgtype == LTG_PATROL) { - return qfalse; - } - //if camped recently - if (bs->camp_time > FloatTime() - 60 + 300 * (1-camper)) return qfalse; - // - if (random() > camper) { - bs->camp_time = FloatTime(); - return qfalse; - } - //if the bot isn't healthy anough - if (BotAggression(bs) < 50) return qfalse; - //the bot should have at least have the rocket launcher, the railgun or the bfg10k with some ammo - if ((bs->inventory[INVENTORY_ROCKETLAUNCHER] <= 0 || bs->inventory[INVENTORY_ROCKETS < 10]) && - (bs->inventory[INVENTORY_RAILGUN] <= 0 || bs->inventory[INVENTORY_SLUGS] < 10) && - (bs->inventory[INVENTORY_BFG10K] <= 0 || bs->inventory[INVENTORY_BFGAMMO] < 10)) { - return qfalse; - } - //find the closest camp spot - besttraveltime = 99999; - for (cs = trap_BotGetNextCampSpotGoal(0, &goal); cs; cs = trap_BotGetNextCampSpotGoal(cs, &goal)) { - traveltime = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, goal.areanum, TFL_DEFAULT); - if (traveltime && traveltime < besttraveltime) { - besttraveltime = traveltime; - memcpy(&bestgoal, &goal, sizeof(bot_goal_t)); - } - } - if (besttraveltime > 150) return qfalse; - //ok found a camp spot, go camp there - BotGoCamp(bs, &bestgoal); - bs->ordered = qfalse; - // - return qtrue; -} - -/* -================== -BotDontAvoid -================== -*/ -void BotDontAvoid(bot_state_t *bs, char *itemname) { - bot_goal_t goal; - int num; - - num = trap_BotGetLevelItemGoal(-1, itemname, &goal); - while(num >= 0) { - trap_BotRemoveFromAvoidGoals(bs->gs, goal.number); - num = trap_BotGetLevelItemGoal(num, itemname, &goal); - } -} - -/* -================== -BotGoForPowerups -================== -*/ -void BotGoForPowerups(bot_state_t *bs) { - - //don't avoid any of the powerups anymore - BotDontAvoid(bs, "Quad Damage"); - BotDontAvoid(bs, "Regeneration"); - BotDontAvoid(bs, "Battle Suit"); - BotDontAvoid(bs, "Speed"); - BotDontAvoid(bs, "Invisibility"); - //BotDontAvoid(bs, "Flight"); - //reset the long term goal time so the bot will go for the powerup - //NOTE: the long term goal type doesn't change - bs->ltg_time = 0; -} - -/* -================== -BotRoamGoal -================== -*/ -void BotRoamGoal(bot_state_t *bs, vec3_t goal) { - int pc, i; - float len, rnd; - vec3_t dir, bestorg, belowbestorg; - bsp_trace_t trace; - - for (i = 0; i < 10; i++) { - //start at the bot origin - VectorCopy(bs->origin, bestorg); - rnd = random(); - if (rnd > 0.25) { - //add a random value to the x-coordinate - if (random() < 0.5) bestorg[0] -= 800 * random() + 100; - else bestorg[0] += 800 * random() + 100; - } - if (rnd < 0.75) { - //add a random value to the y-coordinate - if (random() < 0.5) bestorg[1] -= 800 * random() + 100; - else bestorg[1] += 800 * random() + 100; - } - //add a random value to the z-coordinate (NOTE: 48 = maxjump?) - bestorg[2] += 2 * 48 * crandom(); - //trace a line from the origin to the roam target - BotAI_Trace(&trace, bs->origin, NULL, NULL, bestorg, bs->entitynum, MASK_SOLID); - //direction and length towards the roam target - VectorSubtract(trace.endpos, bs->origin, dir); - len = VectorNormalize(dir); - //if the roam target is far away anough - if (len > 200) { - //the roam target is in the given direction before walls - VectorScale(dir, len * trace.fraction - 40, dir); - VectorAdd(bs->origin, dir, bestorg); - //get the coordinates of the floor below the roam target - belowbestorg[0] = bestorg[0]; - belowbestorg[1] = bestorg[1]; - belowbestorg[2] = bestorg[2] - 800; - BotAI_Trace(&trace, bestorg, NULL, NULL, belowbestorg, bs->entitynum, MASK_SOLID); - // - if (!trace.startsolid) { - trace.endpos[2]++; - pc = trap_PointContents(trace.endpos, bs->entitynum); - if (!(pc & (CONTENTS_LAVA | CONTENTS_SLIME))) { - VectorCopy(bestorg, goal); - return; - } - } - } - } - VectorCopy(bestorg, goal); -} - -/* -================== -BotAttackMove -================== -*/ -bot_moveresult_t BotAttackMove(bot_state_t *bs, int tfl) { - int movetype, i, attackentity; - float attack_skill, jumper, croucher, dist, strafechange_time; - float attack_dist, attack_range; - vec3_t forward, backward, sideward, hordir, up = {0, 0, 1}; - aas_entityinfo_t entinfo; - bot_moveresult_t moveresult; - bot_goal_t goal; - - attackentity = bs->enemy; - // - if (bs->attackchase_time > FloatTime()) { - //create the chase goal - goal.entitynum = attackentity; - goal.areanum = bs->lastenemyareanum; - VectorCopy(bs->lastenemyorigin, goal.origin); - VectorSet(goal.mins, -8, -8, -8); - VectorSet(goal.maxs, 8, 8, 8); - //initialize the movement state - BotSetupForMovement(bs); - //move towards the goal - trap_BotMoveToGoal(&moveresult, bs->ms, &goal, tfl); - return moveresult; - } - // - memset(&moveresult, 0, sizeof(bot_moveresult_t)); - // - attack_skill = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_ATTACK_SKILL, 0, 1); - jumper = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_JUMPER, 0, 1); - croucher = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CROUCHER, 0, 1); - //if the bot is really stupid - if (attack_skill < 0.2) return moveresult; - //initialize the movement state - BotSetupForMovement(bs); - //get the enemy entity info - BotEntityInfo(attackentity, &entinfo); - //direction towards the enemy - VectorSubtract(entinfo.origin, bs->origin, forward); - //the distance towards the enemy - dist = VectorNormalize(forward); - VectorNegate(forward, backward); - //walk, crouch or jump - movetype = MOVE_WALK; - // - if (bs->attackcrouch_time < FloatTime() - 1) { - if (random() < jumper) { - movetype = MOVE_JUMP; - } - //wait at least one second before crouching again - else if (bs->attackcrouch_time < FloatTime() - 1 && random() < croucher) { - bs->attackcrouch_time = FloatTime() + croucher * 5; - } - } - if (bs->attackcrouch_time > FloatTime()) movetype = MOVE_CROUCH; - //if the bot should jump - if (movetype == MOVE_JUMP) { - //if jumped last frame - if (bs->attackjump_time > FloatTime()) { - movetype = MOVE_WALK; - } - else { - bs->attackjump_time = FloatTime() + 1; - } - } - if (bs->cur_ps.weapon == WP_KNIFE) { - attack_dist = 0; - attack_range = 0; - } - else { - attack_dist = IDEAL_ATTACKDIST; - attack_range = 40; - } - //if the bot is stupid - if (attack_skill <= 0.4) { - //just walk to or away from the enemy - if (dist > attack_dist + attack_range) { - if (trap_BotMoveInDirection(bs->ms, forward, 400, movetype)) return moveresult; - } - if (dist < attack_dist - attack_range) { - if (trap_BotMoveInDirection(bs->ms, backward, 400, movetype)) return moveresult; - } - return moveresult; - } - //increase the strafe time - bs->attackstrafe_time += bs->thinktime; - //get the strafe change time - strafechange_time = 0.4 + (1 - attack_skill) * 0.2; - if (attack_skill > 0.7) strafechange_time += crandom() * 0.2; - //if the strafe direction should be changed - if (bs->attackstrafe_time > strafechange_time) { - //some magic number :) - if (random() > 0.935) { - //flip the strafe direction - bs->flags ^= BFL_STRAFERIGHT; - bs->attackstrafe_time = 0; - } - } - // - for (i = 0; i < 2; i++) { - hordir[0] = forward[0]; - hordir[1] = forward[1]; - hordir[2] = 0; - VectorNormalize(hordir); - //get the sideward vector - CrossProduct(hordir, up, sideward); - //reverse the vector depending on the strafe direction - if (bs->flags & BFL_STRAFERIGHT) VectorNegate(sideward, sideward); - //randomly go back a little - if (random() > 0.9) { - VectorAdd(sideward, backward, sideward); - } - else { - //walk forward or backward to get at the ideal attack distance - if (dist > attack_dist + attack_range) { - VectorAdd(sideward, forward, sideward); - } - else if (dist < attack_dist - attack_range) { - VectorAdd(sideward, backward, sideward); - } - } - //perform the movement - if (trap_BotMoveInDirection(bs->ms, sideward, 400, movetype)) - return moveresult; - //movement failed, flip the strafe direction - bs->flags ^= BFL_STRAFERIGHT; - bs->attackstrafe_time = 0; - } - //bot couldn't do any usefull movement -// bs->attackchase_time = AAS_Time() + 6; - return moveresult; -} - -/* -================== -BotSameTeam -================== -*/ -int BotSameTeam(bot_state_t *bs, int entnum) { - char info1[1024], info2[1024]; - - if (bs->client < 0 || bs->client >= MAX_CLIENTS) { - //BotAI_Print(PRT_ERROR, "BotSameTeam: client out of range\n"); - return qfalse; - } - if (entnum < 0 || entnum >= MAX_CLIENTS) { - //BotAI_Print(PRT_ERROR, "BotSameTeam: client out of range\n"); - return qfalse; - } - if ( gametype >= GT_TEAM ) { - trap_GetConfigstring(CS_PLAYERS+bs->client, info1, sizeof(info1)); - trap_GetConfigstring(CS_PLAYERS+entnum, info2, sizeof(info2)); - // - if (atoi(Info_ValueForKey(info1, "t")) == atoi(Info_ValueForKey(info2, "t"))) return qtrue; - } - return qfalse; -} - -/* -================== -InFieldOfVision -================== -*/ -qboolean InFieldOfVision(vec3_t viewangles, float fov, vec3_t angles) -{ - int i; - float diff, angle; - - for (i = 0; i < 2; i++) { - angle = AngleMod(viewangles[i]); - angles[i] = AngleMod(angles[i]); - diff = angles[i] - angle; - if (angles[i] > angle) { - if (diff > 180.0) diff -= 360.0; - } - else { - if (diff < -180.0) diff += 360.0; - } - if (diff > 0) { - if (diff > fov * 0.5) return qfalse; - } - else { - if (diff < -fov * 0.5) return qfalse; - } - } - return qtrue; -} - -/* -================== -BotEntityVisible - -returns visibility in the range [0, 1] taking fog and water surfaces into account -================== -*/ -float BotEntityVisible(int viewer, vec3_t eye, vec3_t viewangles, float fov, int ent) { - int i, contents_mask, passent, hitent, infog, inwater, otherinfog, pc; - float squaredfogdist, waterfactor, vis, bestvis; - bsp_trace_t trace; - aas_entityinfo_t entinfo; - vec3_t dir, entangles, start, end, middle; - - //calculate middle of bounding box - BotEntityInfo(ent, &entinfo); - VectorAdd(entinfo.mins, entinfo.maxs, middle); - VectorScale(middle, 0.5, middle); - VectorAdd(entinfo.origin, middle, middle); - //check if entity is within field of vision - VectorSubtract(middle, eye, dir); - vectoangles(dir, entangles); - if (!InFieldOfVision(viewangles, fov, entangles)) return 0; - // - pc = trap_AAS_PointContents(eye); - infog = (pc & CONTENTS_FOG); - inwater = (pc & (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER)); - // - bestvis = 0; - for (i = 0; i < 3; i++) { - //if the point is not in potential visible sight - //if (!AAS_inPVS(eye, middle)) continue; - // - contents_mask = CONTENTS_SOLID|CONTENTS_PLAYERCLIP; - passent = viewer; - hitent = ent; - VectorCopy(eye, start); - VectorCopy(middle, end); - //if the entity is in water, lava or slime - if (trap_AAS_PointContents(middle) & (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER)) { - contents_mask |= (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER); - } - //if eye is in water, lava or slime - if (inwater) { - if (!(contents_mask & (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER))) { - passent = ent; - hitent = viewer; - VectorCopy(middle, start); - VectorCopy(eye, end); - } - contents_mask ^= (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER); - } - //trace from start to end - BotAI_Trace(&trace, start, NULL, NULL, end, passent, contents_mask); - //if water was hit - waterfactor = 1.0; - if (trace.contents & (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER)) { - //if the water surface is translucent - if (1) { - //trace through the water - contents_mask &= ~(CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER); - BotAI_Trace(&trace, trace.endpos, NULL, NULL, end, passent, contents_mask); - waterfactor = 0.5; - } - } - //if a full trace or the hitent was hit - if (trace.fraction >= 1 || trace.ent == hitent) { - //check for fog, assuming there's only one fog brush where - //either the viewer or the entity is in or both are in - otherinfog = (trap_AAS_PointContents(middle) & CONTENTS_FOG); - if (infog && otherinfog) { - VectorSubtract(trace.endpos, eye, dir); - squaredfogdist = VectorLengthSquared(dir); - } - else if (infog) { - VectorCopy(trace.endpos, start); - BotAI_Trace(&trace, start, NULL, NULL, eye, viewer, CONTENTS_FOG); - VectorSubtract(eye, trace.endpos, dir); - squaredfogdist = VectorLengthSquared(dir); - } - else if (otherinfog) { - VectorCopy(trace.endpos, end); - BotAI_Trace(&trace, eye, NULL, NULL, end, viewer, CONTENTS_FOG); - VectorSubtract(end, trace.endpos, dir); - squaredfogdist = VectorLengthSquared(dir); - } - else { - //if the entity and the viewer are not in fog assume there's no fog in between - squaredfogdist = 0; - } - //decrease visibility with the view distance through fog - vis = 1 / ((squaredfogdist * 0.001) < 1 ? 1 : (squaredfogdist * 0.001)); - //if entering water visibility is reduced - vis *= waterfactor; - // - if (vis > bestvis) bestvis = vis; - //if pretty much no fog - if (bestvis >= 0.95) return bestvis; - } - //check bottom and top of bounding box as well - if (i == 0) middle[2] += entinfo.mins[2]; - else if (i == 1) middle[2] += entinfo.maxs[2] - entinfo.mins[2]; - } - return bestvis; -} - -/* -================== -BotFindEnemy -================== -*/ -int BotFindEnemy(bot_state_t *bs, int curenemy) { - int i, healthdecrease; - float f, alertness, easyfragger, vis; - float squaredist, cursquaredist; - aas_entityinfo_t entinfo, curenemyinfo; - vec3_t dir, angles; - - alertness = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_ALERTNESS, 0, 1); - easyfragger = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_EASY_FRAGGER, 0, 1); - //check if the health decreased - healthdecrease = bs->lasthealth > bs->inventory[INVENTORY_HEALTH]; - //remember the current health value - bs->lasthealth = bs->inventory[INVENTORY_HEALTH]; - // - if (curenemy >= 0) { - BotEntityInfo(curenemy, &curenemyinfo); - if (EntityCarriesFlag(&curenemyinfo)) return qfalse; - VectorSubtract(curenemyinfo.origin, bs->origin, dir); - cursquaredist = VectorLengthSquared(dir); - } - else { - cursquaredist = 0; - } -#ifdef MISSIONPACK - if (gametype == GT_OBELISK) { - vec3_t target; - bot_goal_t *goal; - bsp_trace_t trace; - - if (BotTeam(bs) == TEAM_RED) - goal = &blueobelisk; - else - goal = &redobelisk; - //if the obelisk is visible - VectorCopy(goal->origin, target); - target[2] += 1; - BotAI_Trace(&trace, bs->eye, NULL, NULL, target, bs->client, CONTENTS_SOLID); - if (trace.fraction >= 1 || trace.ent == goal->entitynum) { - if (goal->entitynum == bs->enemy) { - return qfalse; - } - bs->enemy = goal->entitynum; - bs->enemysight_time = FloatTime(); - bs->enemysuicide = qfalse; - bs->enemydeath_time = 0; - return qtrue; - } - } -#endif - // - for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) { - - if (i == bs->client) continue; - //if it's the current enemy - if (i == curenemy) continue; - // - BotEntityInfo(i, &entinfo); - // - if (!entinfo.valid) continue; - //if the enemy isn't dead and the enemy isn't the bot self - if (EntityIsDead(&entinfo) || entinfo.number == bs->entitynum) continue; - //if the enemy is invisible and not shooting - if (EntityIsInvisible(&entinfo) && !EntityIsShooting(&entinfo)) { - continue; - } - //if not an easy fragger don't shoot at chatting players - if (easyfragger < 0.5 && EntityIsChatting(&entinfo)) continue; - // - if (lastteleport_time > FloatTime() - 3) { - VectorSubtract(entinfo.origin, lastteleport_origin, dir); - if (VectorLengthSquared(dir) < Square(70)) continue; - } - //calculate the distance towards the enemy - VectorSubtract(entinfo.origin, bs->origin, dir); - squaredist = VectorLengthSquared(dir); - //if this entity is not carrying a flag - if (!EntityCarriesFlag(&entinfo)) - { - //if this enemy is further away than the current one - if (curenemy >= 0 && squaredist > cursquaredist) continue; - } //end if - //if the bot has no - if (squaredist > Square(900.0 + alertness * 4000.0)) continue; - //if on the same team - if (BotSameTeam(bs, i)) continue; - //if the bot's health decreased or the enemy is shooting - if (curenemy < 0 && (healthdecrease || EntityIsShooting(&entinfo))) - f = 360; - else - f = 90 + 90 - (90 - (squaredist > Square(810) ? Square(810) : squaredist) / (810 * 9)); - //check if the enemy is visible - vis = BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, f, i); - if (vis <= 0) continue; - //if the enemy is quite far away, not shooting and the bot is not damaged - if (curenemy < 0 && squaredist > Square(100) && !healthdecrease && !EntityIsShooting(&entinfo)) - { - //check if we can avoid this enemy - VectorSubtract(bs->origin, entinfo.origin, dir); - vectoangles(dir, angles); - //if the bot isn't in the fov of the enemy - if (!InFieldOfVision(entinfo.angles, 90, angles)) { - //update some stuff for this enemy - BotUpdateBattleInventory(bs, i); - //if the bot doesn't really want to fight - if (BotWantsToRetreat(bs)) continue; - } - } - //found an enemy - bs->enemy = entinfo.number; - if (curenemy >= 0) bs->enemysight_time = FloatTime() - 2; - else bs->enemysight_time = FloatTime(); - bs->enemysuicide = qfalse; - bs->enemydeath_time = 0; - return qtrue; - } - return qfalse; -} - -/* -================== -BotTeamFlagCarrierVisible -================== -*/ -int BotTeamFlagCarrierVisible(bot_state_t *bs) { - int i; - float vis; - aas_entityinfo_t entinfo; - - for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) { - if (i == bs->client) - continue; - // - BotEntityInfo(i, &entinfo); - //if this player is active - if (!entinfo.valid) - continue; - //if this player is carrying a flag - if (!EntityCarriesFlag(&entinfo)) - continue; - //if the flag carrier is not on the same team - if (!BotSameTeam(bs, i)) - continue; - //if the flag carrier is not visible - vis = BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, i); - if (vis <= 0) - continue; - // - return i; - } - return -1; -} - -/* -================== -BotTeamFlagCarrier -================== -*/ -int BotTeamFlagCarrier(bot_state_t *bs) { - int i; - aas_entityinfo_t entinfo; - - for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) { - if (i == bs->client) - continue; - // - BotEntityInfo(i, &entinfo); - //if this player is active - if (!entinfo.valid) - continue; - //if this player is carrying a flag - if (!EntityCarriesFlag(&entinfo)) - continue; - //if the flag carrier is not on the same team - if (!BotSameTeam(bs, i)) - continue; - // - return i; - } - return -1; -} - -/* -================== -BotEnemyFlagCarrierVisible -================== -*/ -int BotEnemyFlagCarrierVisible(bot_state_t *bs) { - int i; - float vis; - aas_entityinfo_t entinfo; - - for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) { - if (i == bs->client) - continue; - // - BotEntityInfo(i, &entinfo); - //if this player is active - if (!entinfo.valid) - continue; - //if this player is carrying a flag - if (!EntityCarriesFlag(&entinfo)) - continue; - //if the flag carrier is on the same team - if (BotSameTeam(bs, i)) - continue; - //if the flag carrier is not visible - vis = BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, i); - if (vis <= 0) - continue; - // - return i; - } - return -1; -} - -/* -================== -BotVisibleTeamMatesAndEnemies -================== -*/ -void BotVisibleTeamMatesAndEnemies(bot_state_t *bs, int *teammates, int *enemies, float range) { - int i; - float vis; - aas_entityinfo_t entinfo; - vec3_t dir; - - if (teammates) - *teammates = 0; - if (enemies) - *enemies = 0; - for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) { - if (i == bs->client) - continue; - // - BotEntityInfo(i, &entinfo); - //if this player is active - if (!entinfo.valid) - continue; - //if this player is carrying a flag - if (!EntityCarriesFlag(&entinfo)) - continue; - //if not within range - VectorSubtract(entinfo.origin, bs->origin, dir); - if (VectorLengthSquared(dir) > Square(range)) - continue; - //if the flag carrier is not visible - vis = BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, i); - if (vis <= 0) - continue; - //if the flag carrier is on the same team - if (BotSameTeam(bs, i)) { - if (teammates) - (*teammates)++; - } - else { - if (enemies) - (*enemies)++; - } - } -} - -#ifdef MISSIONPACK -/* -================== -BotTeamCubeCarrierVisible -================== -*/ -int BotTeamCubeCarrierVisible(bot_state_t *bs) { - int i; - float vis; - aas_entityinfo_t entinfo; - - for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) { - if (i == bs->client) continue; - // - BotEntityInfo(i, &entinfo); - //if this player is active - if (!entinfo.valid) continue; - //if this player is carrying a flag - if (!EntityCarriesCubes(&entinfo)) continue; - //if the flag carrier is not on the same team - if (!BotSameTeam(bs, i)) continue; - //if the flag carrier is not visible - vis = BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, i); - if (vis <= 0) continue; - // - return i; - } - return -1; -} - -/* -================== -BotEnemyCubeCarrierVisible -================== -*/ -int BotEnemyCubeCarrierVisible(bot_state_t *bs) { - int i; - float vis; - aas_entityinfo_t entinfo; - - for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) { - if (i == bs->client) - continue; - // - BotEntityInfo(i, &entinfo); - //if this player is active - if (!entinfo.valid) - continue; - //if this player is carrying a flag - if (!EntityCarriesCubes(&entinfo)) continue; - //if the flag carrier is on the same team - if (BotSameTeam(bs, i)) - continue; - //if the flag carrier is not visible - vis = BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, i); - if (vis <= 0) - continue; - // - return i; - } - return -1; -} -#endif - -/* -================== -BotAimAtEnemy -================== -*/ -void BotAimAtEnemy(bot_state_t *bs) { - int i, enemyvisible; - float dist, f, aim_skill, aim_accuracy, speed, reactiontime; - vec3_t dir, bestorigin, end, start, groundtarget, cmdmove, enemyvelocity; - vec3_t mins = {-4,-4,-4}, maxs = {4, 4, 4}; - weaponinfo_t wi; - aas_entityinfo_t entinfo; - bot_goal_t goal; - bsp_trace_t trace; - vec3_t target; - - //if the bot has no enemy - if (bs->enemy < 0) { - return; - } - //get the enemy entity information - BotEntityInfo(bs->enemy, &entinfo); - //if this is not a player (should be an obelisk) - if (bs->enemy >= MAX_CLIENTS) { - //if the obelisk is visible - VectorCopy(entinfo.origin, target); -#ifdef MISSIONPACK - // if attacking an obelisk - if ( bs->enemy == redobelisk.entitynum || - bs->enemy == blueobelisk.entitynum ) { - target[2] += 32; - } -#endif - //aim at the obelisk - VectorSubtract(target, bs->eye, dir); - vectoangles(dir, bs->ideal_viewangles); - //set the aim target before trying to attack - VectorCopy(target, bs->aimtarget); - return; - } - // - //BotAI_Print(PRT_MESSAGE, "client %d: aiming at client %d\n", bs->entitynum, bs->enemy); - // - aim_skill = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_SKILL, 0, 1); - aim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY, 0, 1); - // - if (aim_skill > 0.95) { - //don't aim too early - reactiontime = 0.5 * trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_REACTIONTIME, 0, 1); - if (bs->enemysight_time > FloatTime() - reactiontime) return; - if (bs->teleport_time > FloatTime() - reactiontime) return; - } - - //get the weapon information - trap_BotGetWeaponInfo(bs->ws, bs->weaponnum, &wi); - //get the weapon specific aim accuracy and or aim skill - -//Blaze: just gonna set the Characteristic aim to machinegun for all of these, but I am still doing the if's so we can edit it later for bot support -//Blaze: Reaction Pistol - if (wi.number == WP_PISTOL) { - aim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY_MACHINEGUN, 0, 1); - } -//Blaze: Reaction Knife - if (wi.number == WP_KNIFE) { - aim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY_MACHINEGUN, 0, 1); - } -//Blaze: Reaction M4 - if (wi.number == WP_M4) { - aim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY_MACHINEGUN, 0, 1); - } -//Blaze: Reaction SSG3000 - if (wi.number == WP_SSG3000) { - aim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY_MACHINEGUN, 0, 1); - } -//Blaze: Reaction MP5 - if (wi.number == WP_MP5) { - aim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY_MACHINEGUN, 0, 1); - } -//Blaze: Reaction HandCannon - if (wi.number == WP_HANDCANNON) { - aim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY_MACHINEGUN, 0, 1); - } -//Blaze: Reaction Shotgun - if (wi.number == WP_M3) { - aim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY_MACHINEGUN, 0, 1); - } -//Blaze: Reaction Akimbo - if (wi.number == WP_AKIMBO) { - aim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY_MACHINEGUN, 0, 1); - } -//Blaze: Reaction Grenade - if (wi.number == WP_GRENADE) { - aim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY_MACHINEGUN, 0, 1); - } - // - if (aim_accuracy <= 0) aim_accuracy = 0.0001f; - //get the enemy entity information - BotEntityInfo(bs->enemy, &entinfo); - //if the enemy is invisible then shoot crappy most of the time - if (EntityIsInvisible(&entinfo)) { - if (random() > 0.1) aim_accuracy *= 0.4f; - } - // - VectorSubtract(entinfo.origin, entinfo.lastvisorigin, enemyvelocity); - VectorScale(enemyvelocity, 1 / entinfo.update_time, enemyvelocity); - //enemy origin and velocity is remembered every 0.5 seconds - if (bs->enemyposition_time < FloatTime()) { - // - bs->enemyposition_time = FloatTime() + 0.5; - VectorCopy(enemyvelocity, bs->enemyvelocity); - VectorCopy(entinfo.origin, bs->enemyorigin); - } - //if not extremely skilled - if (aim_skill < 0.9) { - VectorSubtract(entinfo.origin, bs->enemyorigin, dir); - //if the enemy moved a bit - if (VectorLengthSquared(dir) > Square(48)) { - //if the enemy changed direction - if (DotProduct(bs->enemyvelocity, enemyvelocity) < 0) { - //aim accuracy should be worse now - aim_accuracy *= 0.7f; - } - } - } - //check visibility of enemy - enemyvisible = BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, bs->enemy); - //if the enemy is visible - if (enemyvisible) { - // - VectorCopy(entinfo.origin, bestorigin); - bestorigin[2] += 8; - //get the start point shooting from - //NOTE: the x and y projectile start offsets are ignored - VectorCopy(bs->origin, start); - start[2] += bs->cur_ps.viewheight; - start[2] += wi.offset[2]; - // - BotAI_Trace(&trace, start, mins, maxs, bestorigin, bs->entitynum, MASK_SHOT); - //if the enemy is NOT hit - if (trace.fraction <= 1 && trace.ent != entinfo.number) { - bestorigin[2] += 16; - } - //if it is not an instant hit weapon the bot might want to predict the enemy - if (wi.speed) { - // - VectorSubtract(bestorigin, bs->origin, dir); - dist = VectorLength(dir); - VectorSubtract(entinfo.origin, bs->enemyorigin, dir); - //if the enemy is NOT pretty far away and strafing just small steps left and right - if (!(dist > 100 && VectorLengthSquared(dir) < Square(32))) { - //if skilled anough do exact prediction - if (aim_skill > 0.8 && - //if the weapon is ready to fire - bs->cur_ps.weaponstate == WEAPON_READY) { - aas_clientmove_t move; - vec3_t origin; - - VectorSubtract(entinfo.origin, bs->origin, dir); - //distance towards the enemy - dist = VectorLength(dir); - //direction the enemy is moving in - VectorSubtract(entinfo.origin, entinfo.lastvisorigin, dir); - // - VectorScale(dir, 1 / entinfo.update_time, dir); - // - VectorCopy(entinfo.origin, origin); - origin[2] += 1; - // - VectorClear(cmdmove); - //AAS_ClearShownDebugLines(); - trap_AAS_PredictClientMovement(&move, bs->enemy, origin, - PRESENCE_CROUCH, qfalse, - dir, cmdmove, 0, - dist * 10 / wi.speed, 0.1f, 0, 0, qfalse); - VectorCopy(move.endpos, bestorigin); - //BotAI_Print(PRT_MESSAGE, "%1.1f predicted speed = %f, frames = %f\n", FloatTime(), VectorLength(dir), dist * 10 / wi.speed); - } - //if not that skilled do linear prediction - else if (aim_skill > 0.4) { - VectorSubtract(entinfo.origin, bs->origin, dir); - //distance towards the enemy - dist = VectorLength(dir); - //direction the enemy is moving in - VectorSubtract(entinfo.origin, entinfo.lastvisorigin, dir); - dir[2] = 0; - // - speed = VectorNormalize(dir) / entinfo.update_time; - //botimport.Print(PRT_MESSAGE, "speed = %f, wi->speed = %f\n", speed, wi->speed); - //best spot to aim at - VectorMA(entinfo.origin, (dist / wi.speed) * speed, dir, bestorigin); - } - } - } - //if the projectile does radial damage - if (aim_skill > 0.6 && wi.proj.damagetype & DAMAGETYPE_RADIAL) { - //if the enemy isn't standing significantly higher than the bot - if (entinfo.origin[2] < bs->origin[2] + 16) { - //try to aim at the ground in front of the enemy - VectorCopy(entinfo.origin, end); - end[2] -= 64; - BotAI_Trace(&trace, entinfo.origin, NULL, NULL, end, entinfo.number, MASK_SHOT); - // - VectorCopy(bestorigin, groundtarget); - if (trace.startsolid) groundtarget[2] = entinfo.origin[2] - 16; - else groundtarget[2] = trace.endpos[2] - 8; - //trace a line from projectile start to ground target - BotAI_Trace(&trace, start, NULL, NULL, groundtarget, bs->entitynum, MASK_SHOT); - //if hitpoint is not vertically too far from the ground target - if (fabs(trace.endpos[2] - groundtarget[2]) < 50) { - VectorSubtract(trace.endpos, groundtarget, dir); - //if the hitpoint is near anough the ground target - if (VectorLengthSquared(dir) < Square(60)) { - VectorSubtract(trace.endpos, start, dir); - //if the hitpoint is far anough from the bot - if (VectorLengthSquared(dir) > Square(100)) { - //check if the bot is visible from the ground target - trace.endpos[2] += 1; - BotAI_Trace(&trace, trace.endpos, NULL, NULL, entinfo.origin, entinfo.number, MASK_SHOT); - if (trace.fraction >= 1) { - //botimport.Print(PRT_MESSAGE, "%1.1f aiming at ground\n", AAS_Time()); - VectorCopy(groundtarget, bestorigin); - } - } - } - } - } - } - bestorigin[0] += 20 * crandom() * (1 - aim_accuracy); - bestorigin[1] += 20 * crandom() * (1 - aim_accuracy); - bestorigin[2] += 10 * crandom() * (1 - aim_accuracy); - } - else { - // - VectorCopy(bs->lastenemyorigin, bestorigin); - bestorigin[2] += 8; - //if the bot is skilled anough - if (aim_skill > 0.5) { - //do prediction shots around corners - //Blaze: Knifes are the only thing bots would need to do predictions shots with, but will need lots of tweaking - if (wi.number == WP_KNIFE ) { - //create the chase goal - goal.entitynum = bs->client; - goal.areanum = bs->areanum; - VectorCopy(bs->eye, goal.origin); - VectorSet(goal.mins, -8, -8, -8); - VectorSet(goal.maxs, 8, 8, 8); - // - if (trap_BotPredictVisiblePosition(bs->lastenemyorigin, bs->lastenemyareanum, &goal, TFL_DEFAULT, target)) { - VectorSubtract(target, bs->eye, dir); - if (VectorLengthSquared(dir) > Square(80)) { - VectorCopy(target, bestorigin); - bestorigin[2] -= 20; - } - } - aim_accuracy = 1; - } - } - } - // - if (enemyvisible) { - BotAI_Trace(&trace, bs->eye, NULL, NULL, bestorigin, bs->entitynum, MASK_SHOT); - VectorCopy(trace.endpos, bs->aimtarget); - } - else { - VectorCopy(bestorigin, bs->aimtarget); - } - //get aim direction - VectorSubtract(bestorigin, bs->eye, dir); - // - //Blaze: dont wanna have non hitscan weapons here I think like the knife or Grenades - if (wi.number == WP_PISTOL || - wi.number == WP_M4 || - wi.number == WP_SSG3000 || - wi.number == WP_MP5 || - wi.number == WP_HANDCANNON || - wi.number == WP_M3 || - wi.number == WP_AKIMBO) { - //distance towards the enemy - dist = VectorLength(dir); - if (dist > 150) dist = 150; - f = 0.6 + dist / 150 * 0.4; - aim_accuracy *= f; - } - //add some random stuff to the aim direction depending on the aim accuracy - if (aim_accuracy < 0.8) { - VectorNormalize(dir); - for (i = 0; i < 3; i++) dir[i] += 0.3 * crandom() * (1 - aim_accuracy); - } - //set the ideal view angles - vectoangles(dir, bs->ideal_viewangles); - //take the weapon spread into account for lower skilled bots - bs->ideal_viewangles[PITCH] += 6 * wi.vspread * crandom() * (1 - aim_accuracy); - bs->ideal_viewangles[PITCH] = AngleMod(bs->ideal_viewangles[PITCH]); - bs->ideal_viewangles[YAW] += 6 * wi.hspread * crandom() * (1 - aim_accuracy); - bs->ideal_viewangles[YAW] = AngleMod(bs->ideal_viewangles[YAW]); - //if the bots should be really challenging - if (bot_challenge.integer) { - //if the bot is really accurate and has the enemy in view for some time - if (aim_accuracy > 0.9 && bs->enemysight_time < FloatTime() - 1) { - //set the view angles directly - if (bs->ideal_viewangles[PITCH] > 180) bs->ideal_viewangles[PITCH] -= 360; - VectorCopy(bs->ideal_viewangles, bs->viewangles); - trap_EA_View(bs->client, bs->viewangles); - } - } -} - -/* -================== -BotCheckAttack -================== -*/ -void BotCheckAttack(bot_state_t *bs) { - float points, reactiontime, fov, firethrottle; - int attackentity; - bsp_trace_t bsptrace; - //float selfpreservation; - vec3_t forward, right, start, end, dir, angles; - weaponinfo_t wi; - bsp_trace_t trace; - aas_entityinfo_t entinfo; - vec3_t mins = {-8, -8, -8}, maxs = {8, 8, 8}; - - attackentity = bs->enemy; - // - BotEntityInfo(attackentity, &entinfo); - // if not attacking a player - if (attackentity >= MAX_CLIENTS) { -#ifdef MISSIONPACK - // if attacking an obelisk - if ( entinfo.number == redobelisk.entitynum || - entinfo.number == blueobelisk.entitynum ) { - // if obelisk is respawning return - if ( g_entities[entinfo.number].activator && - g_entities[entinfo.number].activator->s.frame == 2 ) { - return; - } - } -#endif - } - // - reactiontime = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_REACTIONTIME, 0, 1); - if (bs->enemysight_time > FloatTime() - reactiontime) return; - if (bs->teleport_time > FloatTime() - reactiontime) return; - //if changing weapons - if (bs->weaponchange_time > FloatTime() - 0.1) return; - //check fire throttle characteristic - if (bs->firethrottlewait_time > FloatTime()) return; - firethrottle = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_FIRETHROTTLE, 0, 1); - if (bs->firethrottleshoot_time < FloatTime()) { - if (random() > firethrottle) { - bs->firethrottlewait_time = FloatTime() + firethrottle; - bs->firethrottleshoot_time = 0; - } - else { - bs->firethrottleshoot_time = FloatTime() + 1 - firethrottle; - bs->firethrottlewait_time = 0; - } - } - // - if (bs->weaponnum == WP_KNIFE) { - if (VectorLengthSquared(dir) > Square(60)) { - return; - } - } - // - VectorSubtract(bs->aimtarget, bs->eye, dir); - // - if (VectorLengthSquared(dir) < Square(100)) - fov = 120; - else - fov = 50; - // - vectoangles(dir, angles); - if (!InFieldOfVision(bs->viewangles, fov, angles)) - return; - BotAI_Trace(&bsptrace, bs->eye, NULL, NULL, bs->aimtarget, bs->client, CONTENTS_SOLID|CONTENTS_PLAYERCLIP); - if (bsptrace.fraction < 1 && bsptrace.ent != attackentity) - return; - - //get the weapon info - trap_BotGetWeaponInfo(bs->ws, bs->weaponnum, &wi); - //get the start point shooting from - VectorCopy(bs->origin, start); - start[2] += bs->cur_ps.viewheight; - AngleVectors(bs->viewangles, forward, right, NULL); - start[0] += forward[0] * wi.offset[0] + right[0] * wi.offset[1]; - start[1] += forward[1] * wi.offset[0] + right[1] * wi.offset[1]; - start[2] += forward[2] * wi.offset[0] + right[2] * wi.offset[1] + wi.offset[2]; - //end point aiming at - VectorMA(start, 1000, forward, end); - //a little back to make sure not inside a very close enemy - VectorMA(start, -12, forward, start); - BotAI_Trace(&trace, start, mins, maxs, end, bs->entitynum, MASK_SHOT); - //if the entity is a client - if (trace.ent > 0 && trace.ent <= MAX_CLIENTS) { - if (trace.ent != attackentity) { - //if a teammate is hit - if (BotSameTeam(bs, trace.ent)) - return; - } - } - //if won't hit the enemy or not attacking a player (obelisk) - if (trace.ent != attackentity || attackentity >= MAX_CLIENTS) { - //if the projectile does radial damage - if (wi.proj.damagetype & DAMAGETYPE_RADIAL) { - if (trace.fraction * 1000 < wi.proj.radius) { - points = (wi.proj.damage - 0.5 * trace.fraction * 1000) * 0.5; - if (points > 0) { - return; - } - } - //FIXME: check if a teammate gets radial damage - } - } - //if fire has to be release to activate weapon - if (wi.flags & WFL_FIRERELEASED) { - if (bs->flags & BFL_ATTACKED) { - trap_EA_Attack(bs->client); - } - } - else { - trap_EA_Attack(bs->client); - } - bs->flags ^= BFL_ATTACKED; -} - -/* -================== -BotMapScripts -================== -*/ -void BotMapScripts(bot_state_t *bs) { - char info[1024]; - char mapname[128]; - int i, shootbutton; - float aim_accuracy; - aas_entityinfo_t entinfo; - vec3_t dir; - - trap_GetServerinfo(info, sizeof(info)); - - strncpy(mapname, Info_ValueForKey( info, "mapname" ), sizeof(mapname)-1); - mapname[sizeof(mapname)-1] = '\0'; - - if (!Q_stricmp(mapname, "q3tourney6")) { - vec3_t mins = {700, 204, 672}, maxs = {964, 468, 680}; - vec3_t buttonorg = {304, 352, 920}; - //NOTE: NEVER use the func_bobbing in q3tourney6 - bs->tfl &= ~TFL_FUNCBOB; - //if the bot is below the bounding box - if (bs->origin[0] > mins[0] && bs->origin[0] < maxs[0]) { - if (bs->origin[1] > mins[1] && bs->origin[1] < maxs[1]) { - if (bs->origin[2] < mins[2]) { - return; - } - } - } - shootbutton = qfalse; - //if an enemy is below this bounding box then shoot the button - for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) { - - if (i == bs->client) continue; - // - BotEntityInfo(i, &entinfo); - // - if (!entinfo.valid) continue; - //if the enemy isn't dead and the enemy isn't the bot self - if (EntityIsDead(&entinfo) || entinfo.number == bs->entitynum) continue; - // - if (entinfo.origin[0] > mins[0] && entinfo.origin[0] < maxs[0]) { - if (entinfo.origin[1] > mins[1] && entinfo.origin[1] < maxs[1]) { - if (entinfo.origin[2] < mins[2]) { - //if there's a team mate below the crusher - if (BotSameTeam(bs, i)) { - shootbutton = qfalse; - break; - } - else { - shootbutton = qtrue; - } - } - } - } - } - if (shootbutton) { - bs->flags |= BFL_IDEALVIEWSET; - VectorSubtract(buttonorg, bs->eye, dir); - vectoangles(dir, bs->ideal_viewangles); - aim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY, 0, 1); - bs->ideal_viewangles[PITCH] += 8 * crandom() * (1 - aim_accuracy); - bs->ideal_viewangles[PITCH] = AngleMod(bs->ideal_viewangles[PITCH]); - bs->ideal_viewangles[YAW] += 8 * crandom() * (1 - aim_accuracy); - bs->ideal_viewangles[YAW] = AngleMod(bs->ideal_viewangles[YAW]); - // - if (InFieldOfVision(bs->viewangles, 20, bs->ideal_viewangles)) { - trap_EA_Attack(bs->client); - } - } - } - else if (!Q_stricmp(mapname, "mpq3tourney6")) { - //NOTE: NEVER use the func_bobbing in mpq3tourney6 - bs->tfl &= ~TFL_FUNCBOB; - } -} - -/* -================== -BotSetMovedir -================== -*/ -vec3_t VEC_UP = {0, -1, 0}; -vec3_t MOVEDIR_UP = {0, 0, 1}; -vec3_t VEC_DOWN = {0, -2, 0}; -vec3_t MOVEDIR_DOWN = {0, 0, -1}; - -void BotSetMovedir(vec3_t angles, vec3_t movedir) { - if (VectorCompare(angles, VEC_UP)) { - VectorCopy(MOVEDIR_UP, movedir); - } - else if (VectorCompare(angles, VEC_DOWN)) { - VectorCopy(MOVEDIR_DOWN, movedir); - } - else { - AngleVectors(angles, movedir, NULL, NULL); - } -} - -/* -================== -BotModelMinsMaxs - -this is ugly -================== -*/ -int BotModelMinsMaxs(int modelindex, int eType, int contents, vec3_t mins, vec3_t maxs) { - gentity_t *ent; - int i; - - ent = &g_entities[0]; - for (i = 0; i < level.num_entities; i++, ent++) { - if ( !ent->inuse ) { - continue; - } - if ( eType && ent->s.eType != eType) { - continue; - } - if ( contents && ent->r.contents != contents) { - continue; - } - if (ent->s.modelindex == modelindex) { - if (mins) - VectorAdd(ent->r.currentOrigin, ent->r.mins, mins); - if (maxs) - VectorAdd(ent->r.currentOrigin, ent->r.maxs, maxs); - return i; - } - } - if (mins) - VectorClear(mins); - if (maxs) - VectorClear(maxs); - return 0; -} - -/* -================== -BotFuncButtonGoal -================== -*/ -int BotFuncButtonActivateGoal(bot_state_t *bs, int bspent, bot_activategoal_t *activategoal) { - int i, areas[10], numareas, modelindex, entitynum; - char model[128]; - float lip, dist, health, angle; - vec3_t size, start, end, mins, maxs, angles, points[10]; - vec3_t movedir, origin, goalorigin, bboxmins, bboxmaxs; - vec3_t extramins = {1, 1, 1}, extramaxs = {-1, -1, -1}; - bsp_trace_t bsptrace; - - activategoal->shoot = qfalse; - VectorClear(activategoal->target); - //create a bot goal towards the button - trap_AAS_ValueForBSPEpairKey(bspent, "model", model, sizeof(model)); - if (!*model) - return qfalse; - modelindex = atoi(model+1); - if (!modelindex) - return qfalse; - VectorClear(angles); - entitynum = BotModelMinsMaxs(modelindex, ET_MOVER, 0, mins, maxs); - //get the lip of the button - trap_AAS_FloatForBSPEpairKey(bspent, "lip", &lip); - if (!lip) lip = 4; - //get the move direction from the angle - trap_AAS_FloatForBSPEpairKey(bspent, "angle", &angle); - VectorSet(angles, 0, angle, 0); - BotSetMovedir(angles, movedir); - //button size - VectorSubtract(maxs, mins, size); - //button origin - VectorAdd(mins, maxs, origin); - VectorScale(origin, 0.5, origin); - //touch distance of the button - dist = fabs(movedir[0]) * size[0] + fabs(movedir[1]) * size[1] + fabs(movedir[2]) * size[2]; - dist *= 0.5; - // - trap_AAS_FloatForBSPEpairKey(bspent, "health", &health); - //if the button is shootable - if (health) { - //calculate the shoot target - VectorMA(origin, -dist, movedir, goalorigin); - // - VectorCopy(goalorigin, activategoal->target); - activategoal->shoot = qtrue; - // - BotAI_Trace(&bsptrace, bs->eye, NULL, NULL, goalorigin, bs->entitynum, MASK_SHOT); - // if the button is visible from the current position - if (bsptrace.fraction >= 1.0 || bsptrace.ent == entitynum) { - // - activategoal->goal.entitynum = entitynum; //NOTE: this is the entity number of the shootable button - activategoal->goal.number = 0; - activategoal->goal.flags = 0; - VectorCopy(bs->origin, activategoal->goal.origin); - activategoal->goal.areanum = bs->areanum; - VectorSet(activategoal->goal.mins, -8, -8, -8); - VectorSet(activategoal->goal.maxs, 8, 8, 8); - // - return qtrue; - } - else { - //create a goal from where the button is visible and shoot at the button from there - //add bounding box size to the dist - trap_AAS_PresenceTypeBoundingBox(PRESENCE_CROUCH, bboxmins, bboxmaxs); - for (i = 0; i < 3; i++) { - if (movedir[i] < 0) dist += fabs(movedir[i]) * fabs(bboxmaxs[i]); - else dist += fabs(movedir[i]) * fabs(bboxmins[i]); - } - //calculate the goal origin - VectorMA(origin, -dist, movedir, goalorigin); - // - VectorCopy(goalorigin, start); - start[2] += 24; - VectorCopy(start, end); - end[2] -= 512; - numareas = trap_AAS_TraceAreas(start, end, areas, points, 10); - // - for (i = numareas-1; i >= 0; i--) { - if (trap_AAS_AreaReachability(areas[i])) { - break; - } - } - if (i < 0) { - // FIXME: trace forward and maybe in other directions to find a valid area - } - if (i >= 0) { - // - VectorCopy(points[i], activategoal->goal.origin); - activategoal->goal.areanum = areas[i]; - VectorSet(activategoal->goal.mins, 8, 8, 8); - VectorSet(activategoal->goal.maxs, -8, -8, -8); - // - for (i = 0; i < 3; i++) - { - if (movedir[i] < 0) activategoal->goal.maxs[i] += fabs(movedir[i]) * fabs(extramaxs[i]); - else activategoal->goal.mins[i] += fabs(movedir[i]) * fabs(extramins[i]); - } //end for - // - activategoal->goal.entitynum = entitynum; - activategoal->goal.number = 0; - activategoal->goal.flags = 0; - return qtrue; - } - } - return qfalse; - } - else { - //add bounding box size to the dist - trap_AAS_PresenceTypeBoundingBox(PRESENCE_CROUCH, bboxmins, bboxmaxs); - for (i = 0; i < 3; i++) { - if (movedir[i] < 0) dist += fabs(movedir[i]) * fabs(bboxmaxs[i]); - else dist += fabs(movedir[i]) * fabs(bboxmins[i]); - } - //calculate the goal origin - VectorMA(origin, -dist, movedir, goalorigin); - // - VectorCopy(goalorigin, start); - start[2] += 24; - VectorCopy(start, end); - end[2] -= 100; - numareas = trap_AAS_TraceAreas(start, end, areas, NULL, 10); - // - for (i = 0; i < numareas; i++) { - if (trap_AAS_AreaReachability(areas[i])) { - break; - } - } - if (i < numareas) { - // - VectorCopy(origin, activategoal->goal.origin); - activategoal->goal.areanum = areas[i]; - VectorSubtract(mins, origin, activategoal->goal.mins); - VectorSubtract(maxs, origin, activategoal->goal.maxs); - // - for (i = 0; i < 3; i++) - { - if (movedir[i] < 0) activategoal->goal.maxs[i] += fabs(movedir[i]) * fabs(extramaxs[i]); - else activategoal->goal.mins[i] += fabs(movedir[i]) * fabs(extramins[i]); - } //end for - // - activategoal->goal.entitynum = entitynum; - activategoal->goal.number = 0; - activategoal->goal.flags = 0; - return qtrue; - } - } - return qfalse; - } - -/* -================== -BotFuncDoorGoal -================== -*/ -int BotFuncDoorActivateGoal(bot_state_t *bs, int bspent, bot_activategoal_t *activategoal) { - int modelindex, entitynum; - char model[MAX_INFO_STRING]; - vec3_t mins, maxs, origin, angles; - - //shoot at the shootable door - trap_AAS_ValueForBSPEpairKey(bspent, "model", model, sizeof(model)); - if (!*model) - return qfalse; - modelindex = atoi(model+1); - if (!modelindex) - return qfalse; - VectorClear(angles); - entitynum = BotModelMinsMaxs(modelindex, ET_MOVER, 0, mins, maxs); - //door origin - VectorAdd(mins, maxs, origin); - VectorScale(origin, 0.5, origin); - VectorCopy(origin, activategoal->target); - activategoal->shoot = qtrue; - // - activategoal->goal.entitynum = entitynum; //NOTE: this is the entity number of the shootable door - activategoal->goal.number = 0; - activategoal->goal.flags = 0; - VectorCopy(bs->origin, activategoal->goal.origin); - activategoal->goal.areanum = bs->areanum; - VectorSet(activategoal->goal.mins, -8, -8, -8); - VectorSet(activategoal->goal.maxs, 8, 8, 8); - return qtrue; -} - -/* -================== -BotTriggerMultipleGoal -================== -*/ -int BotTriggerMultipleActivateGoal(bot_state_t *bs, int bspent, bot_activategoal_t *activategoal) { - int i, areas[10], numareas, modelindex, entitynum; - char model[128]; - vec3_t start, end, mins, maxs, angles; - vec3_t origin, goalorigin; - - activategoal->shoot = qfalse; - VectorClear(activategoal->target); - //create a bot goal towards the trigger - trap_AAS_ValueForBSPEpairKey(bspent, "model", model, sizeof(model)); - if (!*model) - return qfalse; - modelindex = atoi(model+1); - if (!modelindex) - return qfalse; - VectorClear(angles); - entitynum = BotModelMinsMaxs(modelindex, 0, CONTENTS_TRIGGER, mins, maxs); - //trigger origin - VectorAdd(mins, maxs, origin); - VectorScale(origin, 0.5, origin); - VectorCopy(origin, goalorigin); - // - VectorCopy(goalorigin, start); - start[2] += 24; - VectorCopy(start, end); - end[2] -= 100; - numareas = trap_AAS_TraceAreas(start, end, areas, NULL, 10); - // - for (i = 0; i < numareas; i++) { - if (trap_AAS_AreaReachability(areas[i])) { - break; - } - } - if (i < numareas) { - VectorCopy(origin, activategoal->goal.origin); - activategoal->goal.areanum = areas[i]; - VectorSubtract(mins, origin, activategoal->goal.mins); - VectorSubtract(maxs, origin, activategoal->goal.maxs); - // - activategoal->goal.entitynum = entitynum; - activategoal->goal.number = 0; - activategoal->goal.flags = 0; - return qtrue; - } - return qfalse; -} - -/* -================== -BotPopFromActivateGoalStack -================== -*/ -int BotPopFromActivateGoalStack(bot_state_t *bs) { - if (!bs->activatestack) - return qfalse; - BotEnableActivateGoalAreas(bs->activatestack, qtrue); - bs->activatestack->inuse = qfalse; - bs->activatestack->justused_time = FloatTime(); - bs->activatestack = bs->activatestack->next; - return qtrue; -} - -/* -================== -BotPushOntoActivateGoalStack -================== -*/ -int BotPushOntoActivateGoalStack(bot_state_t *bs, bot_activategoal_t *activategoal) { - int i, best; - float besttime; - - best = -1; - besttime = FloatTime() + 9999; - // - for (i = 0; i < MAX_ACTIVATESTACK; i++) { - if (!bs->activategoalheap[i].inuse) { - if (bs->activategoalheap[i].justused_time < besttime) { - besttime = bs->activategoalheap[i].justused_time; - best = i; - } - } - } - if (best != -1) { - memcpy(&bs->activategoalheap[best], activategoal, sizeof(bot_activategoal_t)); - bs->activategoalheap[best].inuse = qtrue; - bs->activategoalheap[best].next = bs->activatestack; - bs->activatestack = &bs->activategoalheap[best]; - return qtrue; - } - return qfalse; -} - -/* -================== -BotClearActivateGoalStack -================== -*/ -void BotClearActivateGoalStack(bot_state_t *bs) { - while(bs->activatestack) - BotPopFromActivateGoalStack(bs); -} - -/* -================== -BotEnableActivateGoalAreas -================== -*/ -void BotEnableActivateGoalAreas(bot_activategoal_t *activategoal, int enable) { - int i; - - if (activategoal->areasdisabled == !enable) - return; - for (i = 0; i < activategoal->numareas; i++) - trap_AAS_EnableRoutingArea( activategoal->areas[i], enable ); - activategoal->areasdisabled = !enable; - } - -/* -================== -BotIsGoingToActivateEntity -================== -*/ -int BotIsGoingToActivateEntity(bot_state_t *bs, int entitynum) { - bot_activategoal_t *a; - int i; - - for (a = bs->activatestack; a; a = a->next) { - if (a->time < FloatTime()) - continue; - if (a->goal.entitynum == entitynum) - return qtrue; - } - for (i = 0; i < MAX_ACTIVATESTACK; i++) { - if (bs->activategoalheap[i].inuse) - continue; - // - if (bs->activategoalheap[i].goal.entitynum == entitynum) { - // if the bot went for this goal less than 2 seconds ago - if (bs->activategoalheap[i].justused_time > FloatTime() - 2) - return qtrue; - } - } - return qfalse; -} - -/* -================== -BotGetActivateGoal - - returns the number of the bsp entity to activate - goal->entitynum will be set to the game entity to activate -================== -*/ -//#define OBSTACLEDEBUG - -int BotGetActivateGoal(bot_state_t *bs, int entitynum, bot_activategoal_t *activategoal) { - int i, ent, cur_entities[10], spawnflags, modelindex, areas[10], numareas, t; - char model[MAX_INFO_STRING], tmpmodel[128]; - char target[128], classname[128]; - float health; - char targetname[10][128]; - aas_entityinfo_t entinfo; - aas_areainfo_t areainfo; - vec3_t origin, angles, absmins, absmaxs; - - memset(activategoal, 0, sizeof(bot_activategoal_t)); - BotEntityInfo(entitynum, &entinfo); - Com_sprintf(model, sizeof( model ), "*%d", entinfo.modelindex); - for (ent = trap_AAS_NextBSPEntity(0); ent; ent = trap_AAS_NextBSPEntity(ent)) { - if (!trap_AAS_ValueForBSPEpairKey(ent, "model", tmpmodel, sizeof(tmpmodel))) continue; - if (!strcmp(model, tmpmodel)) break; - } - if (!ent) { - BotAI_Print(PRT_ERROR, "BotGetActivateGoal: no entity found with model %s\n", model); - return 0; - } - trap_AAS_ValueForBSPEpairKey(ent, "classname", classname, sizeof(classname)); - if (!classname) { - BotAI_Print(PRT_ERROR, "BotGetActivateGoal: entity with model %s has no classname\n", model); - return 0; - } - //if it is a door - if (!strcmp(classname, "func_door")) { - if (trap_AAS_FloatForBSPEpairKey(ent, "health", &health)) { - //if the door has health then the door must be shot to open - if (health) { - BotFuncDoorActivateGoal(bs, ent, activategoal); - return ent; - } - } - // - trap_AAS_IntForBSPEpairKey(ent, "spawnflags", &spawnflags); - // if the door starts open then just wait for the door to return - if ( spawnflags & 1 ) - return 0; - //get the door origin - if (!trap_AAS_VectorForBSPEpairKey(ent, "origin", origin)) { - VectorClear(origin); - } - //if the door is open or opening already - if (!VectorCompare(origin, entinfo.origin)) - return 0; - // store all the areas the door is in - trap_AAS_ValueForBSPEpairKey(ent, "model", model, sizeof(model)); - if (*model) { - modelindex = atoi(model+1); - if (modelindex) { - VectorClear(angles); - BotModelMinsMaxs(modelindex, ET_MOVER, 0, absmins, absmaxs); - // - numareas = trap_AAS_BBoxAreas(absmins, absmaxs, areas, 10); - for (i = 0; i < numareas; i++) { - trap_AAS_AreaInfo(areas[i], &areainfo); - if (areainfo.contents & AREACONTENTS_MOVER) { - activategoal->areas[activategoal->numareas++] = areas[i]; - if (activategoal->numareas >= MAX_ACTIVATEAREAS) - break; - } - } - } - } - } - // if the bot is blocked by or standing on top of a button - if (!strcmp(classname, "func_button")) { - return 0; - } - // get the targetname so we can find an entity with a matching target - if (!trap_AAS_ValueForBSPEpairKey(ent, "targetname", targetname[0], sizeof(targetname[0]))) { - if (bot_developer.integer) { - BotAI_Print(PRT_ERROR, "BotGetActivateGoal: entity with model \"%s\" has no targetname\n", model); - } - return 0; - } - // allow tree-like activation - cur_entities[0] = trap_AAS_NextBSPEntity(0); - for (i = 0; i >= 0 && i < 10;) { - for (ent = cur_entities[i]; ent; ent = trap_AAS_NextBSPEntity(ent)) { - if (!trap_AAS_ValueForBSPEpairKey(ent, "target", target, sizeof(target))) continue; - if (!strcmp(targetname[i], target)) { - cur_entities[i] = trap_AAS_NextBSPEntity(ent); - break; - } - } - if (!ent) { - if (bot_developer.integer) { - BotAI_Print(PRT_ERROR, "BotGetActivateGoal: no entity with target \"%s\"\n", targetname[i]); - } - i--; - continue; - } - if (!trap_AAS_ValueForBSPEpairKey(ent, "classname", classname, sizeof(classname))) { - if (bot_developer.integer) { - BotAI_Print(PRT_ERROR, "BotGetActivateGoal: entity with target \"%s\" has no classname\n", targetname[i]); - } - continue; - } - // BSP button model - if (!strcmp(classname, "func_button")) { - // - if (!BotFuncButtonActivateGoal(bs, ent, activategoal)) - continue; - // if the bot tries to activate this button already - if ( bs->activatestack && bs->activatestack->inuse && - bs->activatestack->goal.entitynum == activategoal->goal.entitynum && - bs->activatestack->time > FloatTime() && - bs->activatestack->start_time < FloatTime() - 2) - continue; - // if the bot is in a reachability area - if ( trap_AAS_AreaReachability(bs->areanum) ) { - // disable all areas the blocking entity is in - BotEnableActivateGoalAreas( activategoal, qfalse ); - // - t = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, activategoal->goal.areanum, bs->tfl); - // if the button is not reachable - if (!t) { - continue; - } - activategoal->time = FloatTime() + t * 0.01 + 5; - } - return ent; - } - // invisible trigger multiple box - else if (!strcmp(classname, "trigger_multiple")) { - // - if (!BotTriggerMultipleActivateGoal(bs, ent, activategoal)) - continue; - // if the bot tries to activate this trigger already - if ( bs->activatestack && bs->activatestack->inuse && - bs->activatestack->goal.entitynum == activategoal->goal.entitynum && - bs->activatestack->time > FloatTime() && - bs->activatestack->start_time < FloatTime() - 2) - continue; - // if the bot is in a reachability area - if ( trap_AAS_AreaReachability(bs->areanum) ) { - // disable all areas the blocking entity is in - BotEnableActivateGoalAreas( activategoal, qfalse ); - // - t = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, activategoal->goal.areanum, bs->tfl); - // if the trigger is not reachable - if (!t) { - continue; - } - activategoal->time = FloatTime() + t * 0.01 + 5; - } - return ent; - } - else if (!strcmp(classname, "func_timer")) { - // just skip the func_timer - continue; - } - // the actual button or trigger might be linked through a target_relay or target_delay - else if (!strcmp(classname, "target_relay") || !strcmp(classname, "target_delay")) { - if (trap_AAS_ValueForBSPEpairKey(ent, "targetname", targetname[i+1], sizeof(targetname[0]))) { - i++; - cur_entities[i] = trap_AAS_NextBSPEntity(0); - } - } - } -#ifdef OBSTACLEDEBUG - BotAI_Print(PRT_ERROR, "BotGetActivateGoal: no valid activator for entity with target \"%s\"\n", targetname[0]); -#endif - return 0; -} - -/* -================== -BotGoForActivateGoal -================== -*/ -int BotGoForActivateGoal(bot_state_t *bs, bot_activategoal_t *activategoal) { - aas_entityinfo_t activateinfo; - - activategoal->inuse = qtrue; - if (!activategoal->time) - activategoal->time = FloatTime() + 10; - activategoal->start_time = FloatTime(); - BotEntityInfo(activategoal->goal.entitynum, &activateinfo); - VectorCopy(activateinfo.origin, activategoal->origin); - // - if (BotPushOntoActivateGoalStack(bs, activategoal)) { - // enter the activate entity AI node - AIEnter_Seek_ActivateEntity(bs); - return qtrue; - } - else { - // enable any routing areas that were disabled - BotEnableActivateGoalAreas(activategoal, qtrue); - return qfalse; - } -} - -/* -================== -BotPrintActivateGoalInfo -================== -*/ -void BotPrintActivateGoalInfo(bot_state_t *bs, bot_activategoal_t *activategoal, int bspent) { - char netname[MAX_NETNAME]; - char classname[128]; - char buf[128]; - - ClientName(bs->client, netname, sizeof(netname)); - trap_AAS_ValueForBSPEpairKey(bspent, "classname", classname, sizeof(classname)); - if (activategoal->shoot) { - Com_sprintf(buf, sizeof(buf), "%s: I have to shoot at a %s from %1.1f %1.1f %1.1f in area %d\n", - netname, classname, - activategoal->goal.origin[0], - activategoal->goal.origin[1], - activategoal->goal.origin[2], - activategoal->goal.areanum); - } - else { - Com_sprintf(buf, sizeof(buf), "%s: I have to activate a %s at %1.1f %1.1f %1.1f in area %d\n", - netname, classname, - activategoal->goal.origin[0], - activategoal->goal.origin[1], - activategoal->goal.origin[2], - activategoal->goal.areanum); - } - trap_EA_Say(bs->client, buf); -} - -/* -================== -BotRandomMove -================== -*/ -void BotRandomMove(bot_state_t *bs, bot_moveresult_t *moveresult) { - vec3_t dir, angles; - - angles[0] = 0; - angles[1] = random() * 360; - angles[2] = 0; - AngleVectors(angles, dir, NULL, NULL); - - trap_BotMoveInDirection(bs->ms, dir, 400, MOVE_WALK); - - moveresult->failure = qfalse; - VectorCopy(dir, moveresult->movedir); -} - -/* -================== -BotAIBlocked - -Very basic handling of bots being blocked by other entities. -Check what kind of entity is blocking the bot and try to activate -it. If that's not an option then try to walk around or over the entity. -Before the bot ends in this part of the AI it should predict which doors to -open, which buttons to activate etc. -================== -*/ -void BotAIBlocked(bot_state_t *bs, bot_moveresult_t *moveresult, int activate) { - int movetype, bspent; - vec3_t hordir, start, end, mins, maxs, sideward, angles, up = {0, 0, 1}; - aas_entityinfo_t entinfo; - bot_activategoal_t activategoal; - - // if the bot is not blocked by anything - if (!moveresult->blocked) { - bs->notblocked_time = FloatTime(); - return; - } - // if stuck in a solid area - if ( moveresult->type == RESULTTYPE_INSOLIDAREA ) { - // move in a random direction in the hope to get out - BotRandomMove(bs, moveresult); - // - return; - } - // get info for the entity that is blocking the bot - BotEntityInfo(moveresult->blockentity, &entinfo); -#ifdef OBSTACLEDEBUG - ClientName(bs->client, netname, sizeof(netname)); - BotAI_Print(PRT_MESSAGE, "%s: I'm blocked by model %d\n", netname, entinfo.modelindex); -#endif OBSTACLEDEBUG - // if blocked by a bsp model and the bot wants to activate it - if (activate && entinfo.modelindex > 0 && entinfo.modelindex <= max_bspmodelindex) { - // find the bsp entity which should be activated in order to get the blocking entity out of the way - bspent = BotGetActivateGoal(bs, entinfo.number, &activategoal); - if (bspent) { - // - if (bs->activatestack && !bs->activatestack->inuse) - bs->activatestack = NULL; - // if not already trying to activate this entity - if (!BotIsGoingToActivateEntity(bs, activategoal.goal.entitynum)) { - // - BotGoForActivateGoal(bs, &activategoal); - } - // if ontop of an obstacle or - // if the bot is not in a reachability area it'll still - // need some dynamic obstacle avoidance, otherwise return - if (!(moveresult->flags & MOVERESULT_ONTOPOFOBSTACLE) && - trap_AAS_AreaReachability(bs->areanum)) - return; - } - else { - // enable any routing areas that were disabled - BotEnableActivateGoalAreas(&activategoal, qtrue); - } - } - //just some basic dynamic obstacle avoidance code - hordir[0] = moveresult->movedir[0]; - hordir[1] = moveresult->movedir[1]; - hordir[2] = 0; - //if no direction just take a random direction - if (VectorNormalize(hordir) < 0.1) { - VectorSet(angles, 0, 360 * random(), 0); - AngleVectors(angles, hordir, NULL, NULL); - } - // - //if (moveresult->flags & MOVERESULT_ONTOPOFOBSTACLE) movetype = MOVE_JUMP; - //else - movetype = MOVE_WALK; - //if there's an obstacle at the bot's feet and head then - //the bot might be able to crouch through - VectorCopy(bs->origin, start); - start[2] += 18; - VectorMA(start, 5, hordir, end); - VectorSet(mins, -16, -16, -24); - VectorSet(maxs, 16, 16, 4); - // - //bsptrace = AAS_Trace(start, mins, maxs, end, bs->entitynum, MASK_PLAYERSOLID); - //if (bsptrace.fraction >= 1) movetype = MOVE_CROUCH; - //get the sideward vector - CrossProduct(hordir, up, sideward); - // - if (bs->flags & BFL_AVOIDRIGHT) VectorNegate(sideward, sideward); - //try to crouch straight forward? - if (movetype != MOVE_CROUCH || !trap_BotMoveInDirection(bs->ms, hordir, 400, movetype)) { - //perform the movement - if (!trap_BotMoveInDirection(bs->ms, sideward, 400, movetype)) { - //flip the avoid direction flag - bs->flags ^= BFL_AVOIDRIGHT; - //flip the direction - // VectorNegate(sideward, sideward); - VectorMA(sideward, -1, hordir, sideward); - //move in the other direction - trap_BotMoveInDirection(bs->ms, sideward, 400, movetype); - } - } - // - if (bs->notblocked_time < FloatTime() - 0.4) { - // just reset goals and hope the bot will go into another direction? - //is this still needed?? - if (bs->ainode == AINode_Seek_NBG) bs->nbg_time = 0; - else if (bs->ainode == AINode_Seek_LTG) bs->ltg_time = 0; - } -} - -/* -================== -BotAIPredictObstacles - -Predict the route towards the goal and check if the bot -will be blocked by certain obstacles. When the bot has obstacles -on it's path the bot should figure out if they can be removed -by activating certain entities. -================== -*/ -int BotAIPredictObstacles(bot_state_t *bs, bot_goal_t *goal) { - int modelnum, entitynum, bspent; - bot_activategoal_t activategoal; - aas_predictroute_t route; - - if (!bot_predictobstacles.integer) - return qfalse; - - // always predict when the goal change or at regular intervals - if (bs->predictobstacles_goalareanum == goal->areanum && - bs->predictobstacles_time > FloatTime() - 6) { - return qfalse; - } - bs->predictobstacles_goalareanum = goal->areanum; - bs->predictobstacles_time = FloatTime(); - - // predict at most 100 areas or 10 seconds ahead - trap_AAS_PredictRoute(&route, bs->areanum, bs->origin, - goal->areanum, bs->tfl, 100, 1000, - RSE_USETRAVELTYPE|RSE_ENTERCONTENTS, - AREACONTENTS_MOVER, TFL_BRIDGE, 0); - // if bot has to travel through an area with a mover - if (route.stopevent & RSE_ENTERCONTENTS) { - // if the bot will run into a mover - if (route.endcontents & AREACONTENTS_MOVER) { - //NOTE: this only works with bspc 2.1 or higher - modelnum = (route.endcontents & AREACONTENTS_MODELNUM) >> AREACONTENTS_MODELNUMSHIFT; - if (modelnum) { - // - entitynum = BotModelMinsMaxs(modelnum, ET_MOVER, 0, NULL, NULL); - if (entitynum) { - //NOTE: BotGetActivateGoal already checks if the door is open or not - bspent = BotGetActivateGoal(bs, entitynum, &activategoal); - if (bspent) { - // - if (bs->activatestack && !bs->activatestack->inuse) - bs->activatestack = NULL; - // if not already trying to activate this entity - if (!BotIsGoingToActivateEntity(bs, activategoal.goal.entitynum)) { - // - //BotAI_Print(PRT_MESSAGE, "blocked by mover model %d, entity %d ?\n", modelnum, entitynum); - // - BotGoForActivateGoal(bs, &activategoal); - return qtrue; - } - else { - // enable any routing areas that were disabled - BotEnableActivateGoalAreas(&activategoal, qtrue); - } - } - } - } - } - } - else if (route.stopevent & RSE_USETRAVELTYPE) { - if (route.endtravelflags & TFL_BRIDGE) { - //FIXME: check if the bridge is available to travel over - } - } - return qfalse; -} - -/* -================== -BotCheckConsoleMessages -================== -*/ -void BotCheckConsoleMessages(bot_state_t *bs) { - char botname[MAX_NETNAME], message[MAX_MESSAGE_SIZE], netname[MAX_NETNAME], *ptr; - float chat_reply; - int context, handle; - bot_consolemessage_t m; - bot_match_t match; - - //the name of this bot - ClientName(bs->client, botname, sizeof(botname)); - // - while((handle = trap_BotNextConsoleMessage(bs->cs, &m)) != 0) { - //if the chat state is flooded with messages the bot will read them quickly - if (trap_BotNumConsoleMessages(bs->cs) < 10) { - //if it is a chat message the bot needs some time to read it - if (m.type == CMS_CHAT && m.time > FloatTime() - (1 + random())) break; - } - // - ptr = m.message; - //if it is a chat message then don't unify white spaces and don't - //replace synonyms in the netname - if (m.type == CMS_CHAT) { - // - if (trap_BotFindMatch(m.message, &match, MTCONTEXT_REPLYCHAT)) { - ptr = m.message + match.variables[MESSAGE].offset; - } - } - //unify the white spaces in the message - trap_UnifyWhiteSpaces(ptr); - //replace synonyms in the right context - context = BotSynonymContext(bs); - trap_BotReplaceSynonyms(ptr, context); - //if there's no match - if (!BotMatchMessage(bs, m.message)) { - //if it is a chat message - if (m.type == CMS_CHAT && !bot_nochat.integer) { - // - if (!trap_BotFindMatch(m.message, &match, MTCONTEXT_REPLYCHAT)) { - trap_BotRemoveConsoleMessage(bs->cs, handle); - continue; - } - //don't use eliza chats with team messages - if (match.subtype & ST_TEAM) { - trap_BotRemoveConsoleMessage(bs->cs, handle); - continue; - } - // - trap_BotMatchVariable(&match, NETNAME, netname, sizeof(netname)); - trap_BotMatchVariable(&match, MESSAGE, message, sizeof(message)); - //if this is a message from the bot self - if (bs->client == ClientFromName(netname)) { - trap_BotRemoveConsoleMessage(bs->cs, handle); - continue; - } - //unify the message - trap_UnifyWhiteSpaces(message); - // - trap_Cvar_Update(&bot_testrchat); - if (bot_testrchat.integer) { - // - trap_BotLibVarSet("bot_testrchat", "1"); - //if bot replies with a chat message - if (trap_BotReplyChat(bs->cs, message, context, CONTEXT_REPLY, - NULL, NULL, - NULL, NULL, - NULL, NULL, - botname, netname)) { - BotAI_Print(PRT_MESSAGE, "------------------------\n"); - } - else { - BotAI_Print(PRT_MESSAGE, "**** no valid reply ****\n"); - } - } - //if at a valid chat position and not chatting already and not in teamplay - else if (bs->ainode != AINode_Stand && BotValidChatPosition(bs) && !TeamPlayIsOn()) { - chat_reply = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_REPLY, 0, 1); - if (random() < 1.5 / (NumBots()+1) && random() < chat_reply) { - //if bot replies with a chat message - if (trap_BotReplyChat(bs->cs, message, context, CONTEXT_REPLY, - NULL, NULL, - NULL, NULL, - NULL, NULL, - botname, netname)) { - //remove the console message - trap_BotRemoveConsoleMessage(bs->cs, handle); - bs->stand_time = FloatTime() + BotChatTime(bs); - AIEnter_Stand(bs); - //EA_Say(bs->client, bs->cs.chatmessage); - break; - } - } - } - } - } - //remove the console message - trap_BotRemoveConsoleMessage(bs->cs, handle); - } -} - -/* -================== -BotCheckEvents -================== -*/ -void BotCheckForGrenades(bot_state_t *bs, entityState_t *state) { - // if this is not a grenade - if (state->eType != ET_MISSILE || state->weapon != WP_GRENADE) - return; - // try to avoid the grenade - trap_BotAddAvoidSpot(bs->ms, state->pos.trBase, 160, AVOID_ALWAYS); -} - -#ifdef MISSIONPACK -/* -================== -BotCheckForProxMines -================== -*/ -void BotCheckForProxMines(bot_state_t *bs, entityState_t *state) { - // if this is not a prox mine - if (state->eType != ET_MISSILE || state->weapon != WP_PROX_LAUNCHER) - return; - // if this prox mine is from someone on our own team - if (state->generic1 == BotTeam(bs)) - return; - // if the bot doesn't have a weapon to deactivate the mine - if (!(bs->inventory[INVENTORY_PLASMAGUN] > 0 && bs->inventory[INVENTORY_CELLS] > 0) && - !(bs->inventory[INVENTORY_ROCKETLAUNCHER] > 0 && bs->inventory[INVENTORY_ROCKETS] > 0) && - !(bs->inventory[INVENTORY_BFG10K] > 0 && bs->inventory[INVENTORY_BFGAMMO] > 0) ) { - return; - } - // try to avoid the prox mine - trap_BotAddAvoidSpot(bs->ms, state->pos.trBase, 160, AVOID_ALWAYS); - // - if (bs->numproxmines >= MAX_PROXMINES) - return; - bs->proxmines[bs->numproxmines] = state->number; - bs->numproxmines++; -} - -/* -================== -BotCheckForKamikazeBody -================== -*/ -void BotCheckForKamikazeBody(bot_state_t *bs, entityState_t *state) { - // if this entity is not wearing the kamikaze - if (!(state->eFlags & EF_KAMIKAZE)) - return; - // if this entity isn't dead - if (!(state->eFlags & EF_DEAD)) - return; - //remember this kamikaze body - bs->kamikazebody = state->number; -} -#endif - -/* -================== -BotCheckEvents -================== -*/ -void BotCheckEvents(bot_state_t *bs, entityState_t *state) { - int event; - char buf[128]; -#ifdef MISSIONPACK - aas_entityinfo_t entinfo; -#endif - - //NOTE: this sucks, we're accessing the gentity_t directly - //but there's no other fast way to do it right now - if (bs->entityeventTime[state->number] == g_entities[state->number].eventTime) { - return; - } - bs->entityeventTime[state->number] = g_entities[state->number].eventTime; - //if it's an event only entity - if (state->eType > ET_EVENTS) { - event = (state->eType - ET_EVENTS) & ~EV_EVENT_BITS; - } - else { - event = state->event & ~EV_EVENT_BITS; - } - // - switch(event) { - //client obituary event - case EV_OBITUARY: - { - int target, attacker, mod; - - target = state->otherEntityNum; - attacker = state->otherEntityNum2; - mod = state->eventParm; - // - if (target == bs->client) { - bs->botdeathtype = mod; - bs->lastkilledby = attacker; - // - if (target == attacker || - target == ENTITYNUM_NONE || - target == ENTITYNUM_WORLD) bs->botsuicide = qtrue; - else bs->botsuicide = qfalse; - // - bs->num_deaths++; - } - //else if this client was killed by the bot - else if (attacker == bs->client) { - bs->enemydeathtype = mod; - bs->lastkilledplayer = target; - bs->killedenemy_time = FloatTime(); - // - bs->num_kills++; - } - else if (attacker == bs->enemy && target == attacker) { - bs->enemysuicide = qtrue; - } - // -#ifdef MISSIONPACK - if (gametype == GT_1FCTF) { - // - BotEntityInfo(target, &entinfo); - if ( entinfo.powerups & ( 1 << PW_NEUTRALFLAG ) ) { - if (!BotSameTeam(bs, target)) { - bs->neutralflagstatus = 3; //enemy dropped the flag - bs->flagstatuschanged = qtrue; - } - } - } -#endif - break; - } - case EV_GLOBAL_SOUND: - { - if (state->eventParm < 0 || state->eventParm > MAX_SOUNDS) { - BotAI_Print(PRT_ERROR, "EV_GLOBAL_SOUND: eventParm (%d) out of range\n", state->eventParm); - break; - } - trap_GetConfigstring(CS_SOUNDS + state->eventParm, buf, sizeof(buf)); - /* - if (!strcmp(buf, "sound/teamplay/flagret_red.wav")) { - //red flag is returned - bs->redflagstatus = 0; - bs->flagstatuschanged = qtrue; - } - else if (!strcmp(buf, "sound/teamplay/flagret_blu.wav")) { - //blue flag is returned - bs->blueflagstatus = 0; - bs->flagstatuschanged = qtrue; - } - else*/ -#ifdef MISSIONPACK - if (!strcmp(buf, "sound/items/kamikazerespawn.wav" )) { - //the kamikaze respawned so dont avoid it - BotDontAvoid(bs, "Kamikaze"); - } - else -#endif - if (!strcmp(buf, "sound/items/poweruprespawn.wav")) { - //powerup respawned... go get it - BotGoForPowerups(bs); - } - break; - } - case EV_GLOBAL_TEAM_SOUND: - { - if (gametype == GT_CTF) { - switch(state->eventParm) { - case GTS_RED_CAPTURE: - bs->blueflagstatus = 0; - bs->redflagstatus = 0; - bs->flagstatuschanged = qtrue; - break; //see BotMatch_CTF - case GTS_BLUE_CAPTURE: - bs->blueflagstatus = 0; - bs->redflagstatus = 0; - bs->flagstatuschanged = qtrue; - break; //see BotMatch_CTF - case GTS_RED_RETURN: - //blue flag is returned - bs->blueflagstatus = 0; - bs->flagstatuschanged = qtrue; - break; - case GTS_BLUE_RETURN: - //red flag is returned - bs->redflagstatus = 0; - bs->flagstatuschanged = qtrue; - break; - case GTS_RED_TAKEN: - //blue flag is taken - bs->blueflagstatus = 1; - bs->flagstatuschanged = qtrue; - break; //see BotMatch_CTF - case GTS_BLUE_TAKEN: - //red flag is taken - bs->redflagstatus = 1; - bs->flagstatuschanged = qtrue; - break; //see BotMatch_CTF - } - } -#ifdef MISSIONPACK - else if (gametype == GT_1FCTF) { - switch(state->eventParm) { - case GTS_RED_CAPTURE: - bs->neutralflagstatus = 0; - bs->flagstatuschanged = qtrue; - break; - case GTS_BLUE_CAPTURE: - bs->neutralflagstatus = 0; - bs->flagstatuschanged = qtrue; - break; - case GTS_RED_RETURN: - //flag has returned - bs->neutralflagstatus = 0; - bs->flagstatuschanged = qtrue; - break; - case GTS_BLUE_RETURN: - //flag has returned - bs->neutralflagstatus = 0; - bs->flagstatuschanged = qtrue; - break; - case GTS_RED_TAKEN: - bs->neutralflagstatus = BotTeam(bs) == TEAM_RED ? 2 : 1; //FIXME: check Team_TakeFlagSound in g_team.c - bs->flagstatuschanged = qtrue; - break; - case GTS_BLUE_TAKEN: - bs->neutralflagstatus = BotTeam(bs) == TEAM_BLUE ? 2 : 1; //FIXME: check Team_TakeFlagSound in g_team.c - bs->flagstatuschanged = qtrue; - break; - } - } -#endif - break; - } - case EV_PLAYER_TELEPORT_IN: - { - VectorCopy(state->origin, lastteleport_origin); - lastteleport_time = FloatTime(); - break; - } - case EV_GENERAL_SOUND: - { - //if this sound is played on the bot - if (state->number == bs->client) { - if (state->eventParm < 0 || state->eventParm > MAX_SOUNDS) { - BotAI_Print(PRT_ERROR, "EV_GENERAL_SOUND: eventParm (%d) out of range\n", state->eventParm); - break; - } - //check out the sound - trap_GetConfigstring(CS_SOUNDS + state->eventParm, buf, sizeof(buf)); - //if falling into a death pit - if (!strcmp(buf, "*falling1.wav")) { - //if the bot has a personal teleporter - if (bs->inventory[INVENTORY_TELEPORTER] > 0) { - //use the holdable item - trap_EA_Use(bs->client); - } - } - } - break; - } - case EV_FOOTSTEP: - case EV_FOOTSTEP_METAL: - case EV_FOOTSPLASH: - case EV_FOOTWADE: - case EV_SWIM: - case EV_FALL_SHORT: - case EV_FALL_MEDIUM: - case EV_FALL_FAR: - case EV_STEP_4: - case EV_STEP_8: - case EV_STEP_12: - case EV_STEP_16: - case EV_JUMP_PAD: - case EV_JUMP: - case EV_TAUNT: - case EV_WATER_TOUCH: - case EV_WATER_LEAVE: - case EV_WATER_UNDER: - case EV_WATER_CLEAR: - case EV_ITEM_PICKUP: - case EV_GLOBAL_ITEM_PICKUP: - case EV_NOAMMO: - case EV_CHANGE_WEAPON: - case EV_FIRE_WEAPON: - //FIXME: either add to sound queue or mark player as someone making noise - break; - case EV_USE_ITEM0: - case EV_USE_ITEM1: - case EV_USE_ITEM2: - case EV_USE_ITEM3: - case EV_USE_ITEM4: - case EV_USE_ITEM5: - case EV_USE_ITEM6: - case EV_USE_ITEM7: - case EV_USE_ITEM8: - case EV_USE_ITEM9: - case EV_USE_ITEM10: - case EV_USE_ITEM11: - case EV_USE_ITEM12: - case EV_USE_ITEM13: - case EV_USE_ITEM14: - break; - } -} - -/* -================== -BotCheckSnapshot -================== -*/ -void BotCheckSnapshot(bot_state_t *bs) { - int ent; - entityState_t state; - - //remove all avoid spots - trap_BotAddAvoidSpot(bs->ms, vec3_origin, 0, AVOID_CLEAR); - //reset kamikaze body - bs->kamikazebody = 0; - //reset number of proxmines - bs->numproxmines = 0; - // - ent = 0; - while( ( ent = BotAI_GetSnapshotEntity( bs->client, ent, &state ) ) != -1 ) { - //check the entity state for events - BotCheckEvents(bs, &state); - //check for grenades the bot should avoid - BotCheckForGrenades(bs, &state); - // -#ifdef MISSIONPACK - //check for proximity mines which the bot should deactivate - BotCheckForProxMines(bs, &state); - //check for dead bodies with the kamikaze effect which should be gibbed - BotCheckForKamikazeBody(bs, &state); -#endif - } - //check the player state for events - BotAI_GetEntityState(bs->client, &state); - //copy the player state events to the entity state - state.event = bs->cur_ps.externalEvent; - state.eventParm = bs->cur_ps.externalEventParm; - // - BotCheckEvents(bs, &state); -} - -/* -================== -BotCheckAir -================== -*/ -void BotCheckAir(bot_state_t *bs) { - if (bs->inventory[INVENTORY_ENVIRONMENTSUIT] <= 0) { - if (trap_AAS_PointContents(bs->eye) & (CONTENTS_WATER|CONTENTS_SLIME|CONTENTS_LAVA)) { - return; - } - } - bs->lastair_time = FloatTime(); -} - -/* -================== -BotAlternateRoute -================== -*/ -bot_goal_t *BotAlternateRoute(bot_state_t *bs, bot_goal_t *goal) { - int t; - - // if the bot has an alternative route goal - if (bs->altroutegoal.areanum) { - // - if (bs->reachedaltroutegoal_time) - return goal; - // travel time towards alternative route goal - t = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, bs->altroutegoal.areanum, bs->tfl); - if (t && t < 20) { - //BotAI_Print(PRT_MESSAGE, "reached alternate route goal\n"); - bs->reachedaltroutegoal_time = FloatTime(); - } - memcpy(goal, &bs->altroutegoal, sizeof(bot_goal_t)); - return &bs->altroutegoal; - } - return goal; -} - -/* -================== -BotGetAlternateRouteGoal -================== -*/ -int BotGetAlternateRouteGoal(bot_state_t *bs, int base) { - aas_altroutegoal_t *altroutegoals; - bot_goal_t *goal; - int numaltroutegoals, rnd; - - if (base == TEAM_RED) { - altroutegoals = red_altroutegoals; - numaltroutegoals = red_numaltroutegoals; - } - else { - altroutegoals = blue_altroutegoals; - numaltroutegoals = blue_numaltroutegoals; - } - if (!numaltroutegoals) - return qfalse; - rnd = (float) random() * numaltroutegoals; - if (rnd >= numaltroutegoals) - rnd = numaltroutegoals-1; - goal = &bs->altroutegoal; - goal->areanum = altroutegoals[rnd].areanum; - VectorCopy(altroutegoals[rnd].origin, goal->origin); - VectorSet(goal->mins, -8, -8, -8); - VectorSet(goal->maxs, 8, 8, 8); - goal->entitynum = 0; - goal->iteminfo = 0; - goal->number = 0; - goal->flags = 0; - // - bs->reachedaltroutegoal_time = 0; - return qtrue; -} - -/* -================== -BotSetupAlternateRouteGoals -================== -*/ -void BotSetupAlternativeRouteGoals(void) { - - if (altroutegoals_setup) - return; -#ifdef MISSIONPACK - if (gametype == GT_CTF) { - if (trap_BotGetLevelItemGoal(-1, "Neutral Flag", &ctf_neutralflag) < 0) - BotAI_Print(PRT_WARNING, "no alt routes without Neutral Flag\n"); - if (ctf_neutralflag.areanum) { - // - red_numaltroutegoals = trap_AAS_AlternativeRouteGoals( - ctf_neutralflag.origin, ctf_neutralflag.areanum, - ctf_redflag.origin, ctf_redflag.areanum, TFL_DEFAULT, - red_altroutegoals, MAX_ALTROUTEGOALS, - ALTROUTEGOAL_CLUSTERPORTALS| - ALTROUTEGOAL_VIEWPORTALS); - blue_numaltroutegoals = trap_AAS_AlternativeRouteGoals( - ctf_neutralflag.origin, ctf_neutralflag.areanum, - ctf_blueflag.origin, ctf_blueflag.areanum, TFL_DEFAULT, - blue_altroutegoals, MAX_ALTROUTEGOALS, - ALTROUTEGOAL_CLUSTERPORTALS| - ALTROUTEGOAL_VIEWPORTALS); - } - } - else if (gametype == GT_1FCTF) { - // - red_numaltroutegoals = trap_AAS_AlternativeRouteGoals( - ctf_neutralflag.origin, ctf_neutralflag.areanum, - ctf_redflag.origin, ctf_redflag.areanum, TFL_DEFAULT, - red_altroutegoals, MAX_ALTROUTEGOALS, - ALTROUTEGOAL_CLUSTERPORTALS| - ALTROUTEGOAL_VIEWPORTALS); - blue_numaltroutegoals = trap_AAS_AlternativeRouteGoals( - ctf_neutralflag.origin, ctf_neutralflag.areanum, - ctf_blueflag.origin, ctf_blueflag.areanum, TFL_DEFAULT, - blue_altroutegoals, MAX_ALTROUTEGOALS, - ALTROUTEGOAL_CLUSTERPORTALS| - ALTROUTEGOAL_VIEWPORTALS); - } - else if (gametype == GT_OBELISK) { - if (trap_BotGetLevelItemGoal(-1, "Neutral Obelisk", &neutralobelisk) < 0) - BotAI_Print(PRT_WARNING, "Harvester without neutral obelisk\n"); - // - red_numaltroutegoals = trap_AAS_AlternativeRouteGoals( - neutralobelisk.origin, neutralobelisk.areanum, - redobelisk.origin, redobelisk.areanum, TFL_DEFAULT, - red_altroutegoals, MAX_ALTROUTEGOALS, - ALTROUTEGOAL_CLUSTERPORTALS| - ALTROUTEGOAL_VIEWPORTALS); - blue_numaltroutegoals = trap_AAS_AlternativeRouteGoals( - neutralobelisk.origin, neutralobelisk.areanum, - blueobelisk.origin, blueobelisk.areanum, TFL_DEFAULT, - blue_altroutegoals, MAX_ALTROUTEGOALS, - ALTROUTEGOAL_CLUSTERPORTALS| - ALTROUTEGOAL_VIEWPORTALS); - } - else if (gametype == GT_HARVESTER) { - // - red_numaltroutegoals = trap_AAS_AlternativeRouteGoals( - neutralobelisk.origin, neutralobelisk.areanum, - redobelisk.origin, redobelisk.areanum, TFL_DEFAULT, - red_altroutegoals, MAX_ALTROUTEGOALS, - ALTROUTEGOAL_CLUSTERPORTALS| - ALTROUTEGOAL_VIEWPORTALS); - blue_numaltroutegoals = trap_AAS_AlternativeRouteGoals( - neutralobelisk.origin, neutralobelisk.areanum, - blueobelisk.origin, blueobelisk.areanum, TFL_DEFAULT, - blue_altroutegoals, MAX_ALTROUTEGOALS, - ALTROUTEGOAL_CLUSTERPORTALS| - ALTROUTEGOAL_VIEWPORTALS); - } -#endif - altroutegoals_setup = qtrue; -} - -/* -================== -BotDeathmatchAI -================== -*/ -void BotDeathmatchAI(bot_state_t *bs, float thinktime) { - char gender[144], name[144], buf[144]; - char userinfo[MAX_INFO_STRING]; - int i; - - //if the bot has just been setup - if (bs->setupcount > 0) { - bs->setupcount--; - if (bs->setupcount > 0) return; - //get the gender characteristic - trap_Characteristic_String(bs->character, CHARACTERISTIC_GENDER, gender, sizeof(gender)); - //set the bot gender - trap_GetUserinfo(bs->client, userinfo, sizeof(userinfo)); - Info_SetValueForKey(userinfo, "sex", gender); - trap_SetUserinfo(bs->client, userinfo); - //set the team - if ( !bs->map_restart && g_gametype.integer != GT_TOURNAMENT ) { - Com_sprintf(buf, sizeof(buf), "team %s", bs->settings.team); - trap_EA_Command(bs->client, buf); - } - //set the chat gender - if (gender[0] == 'm') trap_BotSetChatGender(bs->cs, CHAT_GENDERMALE); - else if (gender[0] == 'f') trap_BotSetChatGender(bs->cs, CHAT_GENDERFEMALE); - else trap_BotSetChatGender(bs->cs, CHAT_GENDERLESS); - //set the chat name - ClientName(bs->client, name, sizeof(name)); - trap_BotSetChatName(bs->cs, name, bs->client); - // - bs->lastframe_health = bs->inventory[INVENTORY_HEALTH]; - bs->lasthitcount = bs->cur_ps.persistant[PERS_HITS]; - // - bs->setupcount = 0; - // - BotSetupAlternativeRouteGoals(); - } - //no ideal view set - bs->flags &= ~BFL_IDEALVIEWSET; - // - if (!BotIntermission(bs)) { - //set the teleport time - BotSetTeleportTime(bs); - //update some inventory values - BotUpdateInventory(bs); - //check out the snapshot - BotCheckSnapshot(bs); - //check for air - BotCheckAir(bs); - } - //check the console messages - BotCheckConsoleMessages(bs); - //if not in the intermission and not in observer mode - if (!BotIntermission(bs) && !BotIsObserver(bs)) { - //do team AI - BotTeamAI(bs); - } - //if the bot has no ai node - if (!bs->ainode) { - AIEnter_Seek_LTG(bs); - } - //if the bot entered the game less than 8 seconds ago - if (!bs->entergamechat && bs->entergame_time > FloatTime() - 8) { - if (BotChat_EnterGame(bs)) { - bs->stand_time = FloatTime() + BotChatTime(bs); - AIEnter_Stand(bs); - } - bs->entergamechat = qtrue; - } - //reset the node switches from the previous frame - BotResetNodeSwitches(); - //execute AI nodes - for (i = 0; i < MAX_NODESWITCHES; i++) { - if (bs->ainode(bs)) break; - } - //if the bot removed itself :) - if (!bs->inuse) return; - //if the bot executed too many AI nodes - if (i >= MAX_NODESWITCHES) { - trap_BotDumpGoalStack(bs->gs); - trap_BotDumpAvoidGoals(bs->gs); - BotDumpNodeSwitches(bs); - ClientName(bs->client, name, sizeof(name)); - BotAI_Print(PRT_ERROR, "%s at %1.1f switched more than %d AI nodes\n", name, FloatTime(), MAX_NODESWITCHES); - } - // - bs->lastframe_health = bs->inventory[INVENTORY_HEALTH]; - bs->lasthitcount = bs->cur_ps.persistant[PERS_HITS]; -} - -/* -================== -BotSetEntityNumForGoalWithModel -================== -*/ -void BotSetEntityNumForGoalWithModel(bot_goal_t *goal, int eType, char *modelname) { - gentity_t *ent; - int i, modelindex; - vec3_t dir; - - modelindex = G_ModelIndex( modelname ); - ent = &g_entities[0]; - for (i = 0; i < level.num_entities; i++, ent++) { - if ( !ent->inuse ) { - continue; - } - if ( eType && ent->s.eType != eType) { - continue; - } - if (ent->s.modelindex != modelindex) { - continue; - } - VectorSubtract(goal->origin, ent->s.origin, dir); - if (VectorLengthSquared(dir) < Square(10)) { - goal->entitynum = i; - return; - } - } -} - -/* -================== -BotSetEntityNumForGoal -================== -*/ -void BotSetEntityNumForGoal(bot_goal_t *goal, char *classname) { - gentity_t *ent; - int i; - vec3_t dir; - - ent = &g_entities[0]; - for (i = 0; i < level.num_entities; i++, ent++) { - if ( !ent->inuse ) { - continue; - } - if ( !Q_stricmp(ent->classname, classname) ) { - continue; - } - VectorSubtract(goal->origin, ent->s.origin, dir); - if (VectorLengthSquared(dir) < Square(10)) { - goal->entitynum = i; - return; - } - } -} - -/* -================== -BotGoalForBSPEntity -================== -*/ -int BotGoalForBSPEntity( char *classname, bot_goal_t *goal ) { - char value[MAX_INFO_STRING]; - vec3_t origin, start, end; - int ent, numareas, areas[10]; - - memset(goal, 0, sizeof(bot_goal_t)); - for (ent = trap_AAS_NextBSPEntity(0); ent; ent = trap_AAS_NextBSPEntity(ent)) { - if (!trap_AAS_ValueForBSPEpairKey(ent, "classname", value, sizeof(value))) - continue; - if (!strcmp(value, classname)) { - if (!trap_AAS_VectorForBSPEpairKey(ent, "origin", origin)) - return qfalse; - VectorCopy(origin, goal->origin); - VectorCopy(origin, start); - start[2] -= 32; - VectorCopy(origin, end); - end[2] += 32; - numareas = trap_AAS_TraceAreas(start, end, areas, NULL, 10); - if (!numareas) - return qfalse; - goal->areanum = areas[0]; - return qtrue; - } - } - return qfalse; -} - -/* -================== -BotSetupDeathmatchAI -================== -*/ -void BotSetupDeathmatchAI(void) { - int ent, modelnum; - char model[128]; - - gametype = trap_Cvar_VariableIntegerValue("g_gametype"); - maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients"); - - trap_Cvar_Register(&bot_rocketjump, "bot_rocketjump", "1", 0); - trap_Cvar_Register(&bot_grapple, "bot_grapple", "0", 0); - trap_Cvar_Register(&bot_fastchat, "bot_fastchat", "0", 0); - trap_Cvar_Register(&bot_nochat, "bot_nochat", "0", 0); - trap_Cvar_Register(&bot_testrchat, "bot_testrchat", "0", 0); - trap_Cvar_Register(&bot_challenge, "bot_challenge", "0", 0); - trap_Cvar_Register(&bot_predictobstacles, "bot_predictobstacles", "1", 0); - trap_Cvar_Register(&g_spSkill, "g_spSkill", "2", 0); - // - if (gametype == GT_CTF) { - if (trap_BotGetLevelItemGoal(-1, "Red Flag", &ctf_redflag) < 0) - BotAI_Print(PRT_WARNING, "CTF without Red Flag\n"); - if (trap_BotGetLevelItemGoal(-1, "Blue Flag", &ctf_blueflag) < 0) - BotAI_Print(PRT_WARNING, "CTF without Blue Flag\n"); - } -#ifdef MISSIONPACK - else if (gametype == GT_1FCTF) { - if (trap_BotGetLevelItemGoal(-1, "Neutral Flag", &ctf_neutralflag) < 0) - BotAI_Print(PRT_WARNING, "One Flag CTF without Neutral Flag\n"); - if (trap_BotGetLevelItemGoal(-1, "Red Flag", &ctf_redflag) < 0) - BotAI_Print(PRT_WARNING, "CTF without Red Flag\n"); - if (trap_BotGetLevelItemGoal(-1, "Blue Flag", &ctf_blueflag) < 0) - BotAI_Print(PRT_WARNING, "CTF without Blue Flag\n"); - } - else if (gametype == GT_OBELISK) { - if (trap_BotGetLevelItemGoal(-1, "Red Obelisk", &redobelisk) < 0) - BotAI_Print(PRT_WARNING, "Obelisk without red obelisk\n"); - BotSetEntityNumForGoal(&redobelisk, "team_redobelisk"); - if (trap_BotGetLevelItemGoal(-1, "Blue Obelisk", &blueobelisk) < 0) - BotAI_Print(PRT_WARNING, "Obelisk without blue obelisk\n"); - BotSetEntityNumForGoal(&blueobelisk, "team_blueobelisk"); - } - else if (gametype == GT_HARVESTER) { - if (trap_BotGetLevelItemGoal(-1, "Red Obelisk", &redobelisk) < 0) - BotAI_Print(PRT_WARNING, "Harvester without red obelisk\n"); - BotSetEntityNumForGoal(&redobelisk, "team_redobelisk"); - if (trap_BotGetLevelItemGoal(-1, "Blue Obelisk", &blueobelisk) < 0) - BotAI_Print(PRT_WARNING, "Harvester without blue obelisk\n"); - BotSetEntityNumForGoal(&blueobelisk, "team_blueobelisk"); - if (trap_BotGetLevelItemGoal(-1, "Neutral Obelisk", &neutralobelisk) < 0) - BotAI_Print(PRT_WARNING, "Harvester without neutral obelisk\n"); - BotSetEntityNumForGoal(&neutralobelisk, "team_neutralobelisk"); - } -#endif - - max_bspmodelindex = 0; - for (ent = trap_AAS_NextBSPEntity(0); ent; ent = trap_AAS_NextBSPEntity(ent)) { - if (!trap_AAS_ValueForBSPEpairKey(ent, "model", model, sizeof(model))) continue; - if (model[0] == '*') { - modelnum = atoi(model+1); - if (modelnum > max_bspmodelindex) - max_bspmodelindex = modelnum; - } - } - //initialize the waypoint heap - BotInitWaypoints(); -} - -/* -================== -BotShutdownDeathmatchAI -================== -*/ -void BotShutdownDeathmatchAI(void) { - altroutegoals_setup = qfalse; -} - diff --git a/reaction/game/.#ai_team.c.1.2 b/reaction/game/.#ai_team.c.1.2 deleted file mode 100644 index 3c74b8eb..00000000 --- a/reaction/game/.#ai_team.c.1.2 +++ /dev/null @@ -1,2065 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// - -/***************************************************************************** - * name: ai_team.c - * - * desc: Quake3 bot AI - * - * $Archive: /MissionPack/code/game/ai_team.c $ - * $Author$ - * $Revision$ - * $Modtime: 11/16/00 11:35a $ - * $Date$ - * - *****************************************************************************/ - -#include "g_local.h" -#include "botlib.h" -#include "be_aas.h" -#include "be_ea.h" -#include "be_ai_char.h" -#include "be_ai_chat.h" -#include "be_ai_gen.h" -#include "be_ai_goal.h" -#include "be_ai_move.h" -#include "be_ai_weap.h" -// -#include "ai_main.h" -#include "ai_dmq3.h" -#include "ai_chat.h" -#include "ai_cmd.h" -#include "ai_dmnet.h" -#include "ai_team.h" -#include "ai_vcmd.h" - -#include "match.h" - -// for the voice chats -//Blaze: was there a extra ../ here? -#include "../ui/menudef.h" - -//ctf task preferences for a client -typedef struct bot_ctftaskpreference_s -{ - char name[36]; - int preference; -} bot_ctftaskpreference_t; - -bot_ctftaskpreference_t ctftaskpreferences[MAX_CLIENTS]; - - -/* -================== -BotValidTeamLeader -================== -*/ -int BotValidTeamLeader(bot_state_t *bs) { - if (!strlen(bs->teamleader)) return qfalse; - if (ClientFromName(bs->teamleader) == -1) return qfalse; - return qtrue; -} - -/* -================== -BotNumTeamMates -================== -*/ -int BotNumTeamMates(bot_state_t *bs) { - int i, numplayers; - char buf[MAX_INFO_STRING]; - static int maxclients; - - if (!maxclients) - maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients"); - - numplayers = 0; - for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) { - trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf)); - //if no config string or no name - if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue; - //skip spectators - if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR) continue; - // - if (BotSameTeam(bs, i)) { - numplayers++; - } - } - return numplayers; -} - -/* -================== -BotClientTravelTimeToGoal -================== -*/ -int BotClientTravelTimeToGoal(int client, bot_goal_t *goal) { - playerState_t ps; - int areanum; - - BotAI_GetClientState(client, &ps); - areanum = BotPointAreaNum(ps.origin); - if (!areanum) return 1; - return trap_AAS_AreaTravelTimeToGoalArea(areanum, ps.origin, goal->areanum, TFL_DEFAULT); -} - -/* -================== -BotSortTeamMatesByBaseTravelTime -================== -*/ -int BotSortTeamMatesByBaseTravelTime(bot_state_t *bs, int *teammates, int maxteammates) { - - int i, j, k, numteammates, traveltime; - char buf[MAX_INFO_STRING]; - static int maxclients; - int traveltimes[MAX_CLIENTS]; - bot_goal_t *goal; - - if (gametype == GT_CTF || gametype == GT_1FCTF) { - if (BotTeam(bs) == TEAM_RED) - goal = &ctf_redflag; - else - goal = &ctf_blueflag; - } -#ifdef MISSIONPACK - else { - if (BotTeam(bs) == TEAM_RED) - goal = &redobelisk; - else - goal = &blueobelisk; - } -#endif - if (!maxclients) - maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients"); - - numteammates = 0; - for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) { - trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf)); - //if no config string or no name - if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue; - //skip spectators - if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR) continue; - // - if (BotSameTeam(bs, i)) { - // - traveltime = BotClientTravelTimeToGoal(i, goal); - // - for (j = 0; j < numteammates; j++) { - if (traveltime < traveltimes[j]) { - for (k = numteammates; k > j; k--) { - traveltimes[k] = traveltimes[k-1]; - teammates[k] = teammates[k-1]; - } - break; - } - } - traveltimes[j] = traveltime; - teammates[j] = i; - numteammates++; - if (numteammates >= maxteammates) break; - } - } - return numteammates; -} - -/* -================== -BotSetTeamMateTaskPreference -================== -*/ -void BotSetTeamMateTaskPreference(bot_state_t *bs, int teammate, int preference) { - char teammatename[MAX_NETNAME]; - - ctftaskpreferences[teammate].preference = preference; - ClientName(teammate, teammatename, sizeof(teammatename)); - strcpy(ctftaskpreferences[teammate].name, teammatename); -} - -/* -================== -BotGetTeamMateTaskPreference -================== -*/ -int BotGetTeamMateTaskPreference(bot_state_t *bs, int teammate) { - char teammatename[MAX_NETNAME]; - - if (!ctftaskpreferences[teammate].preference) return 0; - ClientName(teammate, teammatename, sizeof(teammatename)); - if (Q_stricmp(teammatename, ctftaskpreferences[teammate].name)) return 0; - return ctftaskpreferences[teammate].preference; -} - -/* -================== -BotSortTeamMatesByTaskPreference -================== -*/ -int BotSortTeamMatesByTaskPreference(bot_state_t *bs, int *teammates, int numteammates) { - int defenders[MAX_CLIENTS], numdefenders; - int attackers[MAX_CLIENTS], numattackers; - int roamers[MAX_CLIENTS], numroamers; - int i, preference; - - numdefenders = numattackers = numroamers = 0; - for (i = 0; i < numteammates; i++) { - preference = BotGetTeamMateTaskPreference(bs, teammates[i]); - if (preference & TEAMTP_DEFENDER) { - defenders[numdefenders++] = teammates[i]; - } - else if (preference & TEAMTP_ATTACKER) { - attackers[numattackers++] = teammates[i]; - } - else { - roamers[numroamers++] = teammates[i]; - } - } - numteammates = 0; - //defenders at the front of the list - memcpy(&teammates[numteammates], defenders, numdefenders * sizeof(int)); - numteammates += numdefenders; - //roamers in the middle - memcpy(&teammates[numteammates], roamers, numroamers * sizeof(int)); - numteammates += numroamers; - //attacker in the back of the list - memcpy(&teammates[numteammates], attackers, numattackers * sizeof(int)); - numteammates += numattackers; - - return numteammates; -} - -/* -================== -BotSayTeamOrders -================== -*/ -void BotSayTeamOrderAlways(bot_state_t *bs, int toclient) { - char teamchat[MAX_MESSAGE_SIZE]; - char buf[MAX_MESSAGE_SIZE]; - char name[MAX_NETNAME]; - - //if the bot is talking to itself - if (bs->client == toclient) { - //don't show the message just put it in the console message queue - trap_BotGetChatMessage(bs->cs, buf, sizeof(buf)); - ClientName(bs->client, name, sizeof(name)); - Com_sprintf(teamchat, sizeof(teamchat), EC"(%s"EC")"EC": %s", name, buf); - trap_BotQueueConsoleMessage(bs->cs, CMS_CHAT, teamchat); - } - else { - trap_BotEnterChat(bs->cs, toclient, CHAT_TELL); - } -} - -/* -================== -BotSayTeamOrders -================== -*/ -void BotSayTeamOrder(bot_state_t *bs, int toclient) { -#ifdef MISSIONPACK - // voice chats only - char buf[MAX_MESSAGE_SIZE]; - - trap_BotGetChatMessage(bs->cs, buf, sizeof(buf)); -#else - BotSayTeamOrderAlways(bs, toclient); -#endif -} - -/* -================== -BotVoiceChat -================== -*/ -void BotVoiceChat(bot_state_t *bs, int toclient, char *voicechat) { -#ifdef MISSIONPACK - if (toclient == -1) - // voice only say team - trap_EA_Command(bs->client, va("vsay_team %s", voicechat)); - else - // voice only tell single player - trap_EA_Command(bs->client, va("vtell %d %s", toclient, voicechat)); -#endif -} - -/* -================== -BotVoiceChatOnly -================== -*/ -void BotVoiceChatOnly(bot_state_t *bs, int toclient, char *voicechat) { -#ifdef MISSIONPACK - if (toclient == -1) - // voice only say team - trap_EA_Command(bs->client, va("vosay_team %s", voicechat)); - else - // voice only tell single player - trap_EA_Command(bs->client, va("votell %d %s", toclient, voicechat)); -#endif -} - -/* -================== -BotSayVoiceTeamOrder -================== -*/ -void BotSayVoiceTeamOrder(bot_state_t *bs, int toclient, char *voicechat) { -#ifdef MISSIONPACK - BotVoiceChat(bs, toclient, voicechat); -#endif -} - -/* -================== -BotCTFOrders -================== -*/ -void BotCTFOrders_BothFlagsNotAtBase(bot_state_t *bs) { - int numteammates, defenders, attackers, i, other; - int teammates[MAX_CLIENTS]; - char name[MAX_NETNAME], carriername[MAX_NETNAME]; - - numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates)); - BotSortTeamMatesByTaskPreference(bs, teammates, numteammates); - //different orders based on the number of team mates - switch(bs->numteammates) { - case 1: break; - case 2: - { - //tell the one not carrying the flag to attack the enemy base - if (teammates[0] != bs->flagcarrier) other = teammates[0]; - else other = teammates[1]; - ClientName(other, name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayTeamOrder(bs, other); - BotSayVoiceTeamOrder(bs, other, VOICECHAT_GETFLAG); - break; - } - case 3: - { - //tell the one closest to the base not carrying the flag to accompany the flag carrier - if (teammates[0] != bs->flagcarrier) other = teammates[0]; - else other = teammates[1]; - ClientName(other, name, sizeof(name)); - if ( bs->flagcarrier != -1 ) { - ClientName(bs->flagcarrier, carriername, sizeof(carriername)); - if (bs->flagcarrier == bs->client) { - BotAI_BotInitialChat(bs, "cmd_accompanyme", name, NULL); - BotSayVoiceTeamOrder(bs, other, VOICECHAT_FOLLOWME); - } - else { - BotAI_BotInitialChat(bs, "cmd_accompany", name, carriername, NULL); - BotSayVoiceTeamOrder(bs, other, VOICECHAT_FOLLOWFLAGCARRIER); - } - } - else { - // - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayVoiceTeamOrder(bs, other, VOICECHAT_GETFLAG); - } - BotSayTeamOrder(bs, other); - //tell the one furthest from the the base not carrying the flag to get the enemy flag - if (teammates[2] != bs->flagcarrier) other = teammates[2]; - else other = teammates[1]; - ClientName(other, name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayTeamOrder(bs, other); - BotSayVoiceTeamOrder(bs, other, VOICECHAT_RETURNFLAG); - break; - } - default: - { - defenders = (int) (float) numteammates * 0.4 + 0.5; - if (defenders > 4) defenders = 4; - attackers = (int) (float) numteammates * 0.5 + 0.5; - if (attackers > 5) attackers = 5; - if (bs->flagcarrier != -1) { - ClientName(bs->flagcarrier, carriername, sizeof(carriername)); - for (i = 0; i < defenders; i++) { - // - if (teammates[i] == bs->flagcarrier) { - continue; - } - // - ClientName(teammates[i], name, sizeof(name)); - if (bs->flagcarrier == bs->client) { - BotAI_BotInitialChat(bs, "cmd_accompanyme", name, NULL); - BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_FOLLOWME); - } - else { - BotAI_BotInitialChat(bs, "cmd_accompany", name, carriername, NULL); - BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_FOLLOWFLAGCARRIER); - } - BotSayTeamOrder(bs, teammates[i]); - } - } - else { - for (i = 0; i < defenders; i++) { - // - if (teammates[i] == bs->flagcarrier) { - continue; - } - // - ClientName(teammates[i], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_GETFLAG); - BotSayTeamOrder(bs, teammates[i]); - } - } - for (i = 0; i < attackers; i++) { - // - if (teammates[numteammates - i - 1] == bs->flagcarrier) { - continue; - } - // - ClientName(teammates[numteammates - i - 1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayTeamOrder(bs, teammates[numteammates - i - 1]); - BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_RETURNFLAG); - } - // - break; - } - } -} - -/* -================== -BotCTFOrders -================== -*/ -void BotCTFOrders_FlagNotAtBase(bot_state_t *bs) { - int numteammates, defenders, attackers, i; - int teammates[MAX_CLIENTS]; - char name[MAX_NETNAME]; - - numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates)); - BotSortTeamMatesByTaskPreference(bs, teammates, numteammates); - //passive strategy - if (!(bs->ctfstrategy & CTFS_AGRESSIVE)) { - //different orders based on the number of team mates - switch(bs->numteammates) { - case 1: break; - case 2: - { - //both will go for the enemy flag - ClientName(teammates[0], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[0]); - BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_GETFLAG); - // - ClientName(teammates[1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayTeamOrder(bs, teammates[1]); - BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG); - break; - } - case 3: - { - //keep one near the base for when the flag is returned - ClientName(teammates[0], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[0]); - BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND); - //the other two get the flag - ClientName(teammates[1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayTeamOrder(bs, teammates[1]); - BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG); - // - ClientName(teammates[2], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayTeamOrder(bs, teammates[2]); - BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_GETFLAG); - break; - } - default: - { - //keep some people near the base for when the flag is returned - defenders = (int) (float) numteammates * 0.3 + 0.5; - if (defenders > 3) defenders = 3; - attackers = (int) (float) numteammates * 0.7 + 0.5; - if (attackers > 6) attackers = 6; - for (i = 0; i < defenders; i++) { - // - ClientName(teammates[i], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[i]); - BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND); - } - for (i = 0; i < attackers; i++) { - // - ClientName(teammates[numteammates - i - 1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayTeamOrder(bs, teammates[numteammates - i - 1]); - BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_GETFLAG); - } - // - break; - } - } - } - else { - //different orders based on the number of team mates - switch(bs->numteammates) { - case 1: break; - case 2: - { - //both will go for the enemy flag - ClientName(teammates[0], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayTeamOrder(bs, teammates[0]); - BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_GETFLAG); - // - ClientName(teammates[1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayTeamOrder(bs, teammates[1]); - BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG); - break; - } - case 3: - { - //everyone go for the flag - ClientName(teammates[0], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[0]); - BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_GETFLAG); - // - ClientName(teammates[1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayTeamOrder(bs, teammates[1]); - BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG); - // - ClientName(teammates[2], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayTeamOrder(bs, teammates[2]); - BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_GETFLAG); - break; - } - default: - { - //keep some people near the base for when the flag is returned - defenders = (int) (float) numteammates * 0.2 + 0.5; - if (defenders > 2) defenders = 2; - attackers = (int) (float) numteammates * 0.7 + 0.5; - if (attackers > 7) attackers = 7; - for (i = 0; i < defenders; i++) { - // - ClientName(teammates[i], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[i]); - BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND); - } - for (i = 0; i < attackers; i++) { - // - ClientName(teammates[numteammates - i - 1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayTeamOrder(bs, teammates[numteammates - i - 1]); - BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG); - } - // - break; - } - } - } -} - -/* -================== -BotCTFOrders -================== -*/ -void BotCTFOrders_EnemyFlagNotAtBase(bot_state_t *bs) { - int numteammates, defenders, attackers, i, other; - int teammates[MAX_CLIENTS]; - char name[MAX_NETNAME], carriername[MAX_NETNAME]; - - numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates)); - BotSortTeamMatesByTaskPreference(bs, teammates, numteammates); - //different orders based on the number of team mates - switch(numteammates) { - case 1: break; - case 2: - { - //tell the one not carrying the flag to defend the base - if (teammates[0] == bs->flagcarrier) other = teammates[1]; - else other = teammates[0]; - ClientName(other, name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, other); - BotSayVoiceTeamOrder(bs, other, VOICECHAT_DEFEND); - break; - } - case 3: - { - //tell the one closest to the base not carrying the flag to defend the base - if (teammates[0] != bs->flagcarrier) other = teammates[0]; - else other = teammates[1]; - ClientName(other, name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, other); - BotSayVoiceTeamOrder(bs, other, VOICECHAT_DEFEND); - //tell the other also to defend the base - if (teammates[2] != bs->flagcarrier) other = teammates[2]; - else other = teammates[1]; - ClientName(other, name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, other); - BotSayVoiceTeamOrder(bs, other, VOICECHAT_DEFEND); - break; - } - default: - { - //60% will defend the base - defenders = (int) (float) numteammates * 0.6 + 0.5; - if (defenders > 6) defenders = 6; - //30% accompanies the flag carrier - attackers = (int) (float) numteammates * 0.3 + 0.5; - if (attackers > 3) attackers = 3; - for (i = 0; i < defenders; i++) { - // - if (teammates[i] == bs->flagcarrier) { - continue; - } - ClientName(teammates[i], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[i]); - BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND); - } - // if we have a flag carrier - if ( bs->flagcarrier != -1 ) { - ClientName(bs->flagcarrier, carriername, sizeof(carriername)); - for (i = 0; i < attackers; i++) { - // - if (teammates[numteammates - i - 1] == bs->flagcarrier) { - continue; - } - // - ClientName(teammates[numteammates - i - 1], name, sizeof(name)); - if (bs->flagcarrier == bs->client) { - BotAI_BotInitialChat(bs, "cmd_accompanyme", name, NULL); - BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_FOLLOWME); - } - else { - BotAI_BotInitialChat(bs, "cmd_accompany", name, carriername, NULL); - BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_FOLLOWFLAGCARRIER); - } - BotSayTeamOrder(bs, teammates[numteammates - i - 1]); - } - } - else { - for (i = 0; i < attackers; i++) { - // - if (teammates[numteammates - i - 1] == bs->flagcarrier) { - continue; - } - // - ClientName(teammates[numteammates - i - 1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG); - BotSayTeamOrder(bs, teammates[numteammates - i - 1]); - } - } - // - break; - } - } -} - - -/* -================== -BotCTFOrders -================== -*/ -void BotCTFOrders_BothFlagsAtBase(bot_state_t *bs) { - int numteammates, defenders, attackers, i; - int teammates[MAX_CLIENTS]; - char name[MAX_NETNAME]; - - //sort team mates by travel time to base - numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates)); - //sort team mates by CTF preference - BotSortTeamMatesByTaskPreference(bs, teammates, numteammates); - //passive strategy - if (!(bs->ctfstrategy & CTFS_AGRESSIVE)) { - //different orders based on the number of team mates - switch(numteammates) { - case 1: break; - case 2: - { - //the one closest to the base will defend the base - ClientName(teammates[0], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[0]); - BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND); - //the other will get the flag - ClientName(teammates[1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayTeamOrder(bs, teammates[1]); - BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG); - break; - } - case 3: - { - //the one closest to the base will defend the base - ClientName(teammates[0], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[0]); - BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND); - //the second one closest to the base will defend the base - ClientName(teammates[1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[1]); - BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_DEFEND); - //the other will get the flag - ClientName(teammates[2], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayTeamOrder(bs, teammates[2]); - BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_GETFLAG); - break; - } - default: - { - defenders = (int) (float) numteammates * 0.5 + 0.5; - if (defenders > 5) defenders = 5; - attackers = (int) (float) numteammates * 0.4 + 0.5; - if (attackers > 4) attackers = 4; - for (i = 0; i < defenders; i++) { - // - ClientName(teammates[i], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[i]); - BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND); - } - for (i = 0; i < attackers; i++) { - // - ClientName(teammates[numteammates - i - 1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayTeamOrder(bs, teammates[numteammates - i - 1]); - BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG); - } - // - break; - } - } - } - else { - //different orders based on the number of team mates - switch(numteammates) { - case 1: break; - case 2: - { - //the one closest to the base will defend the base - ClientName(teammates[0], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[0]); - BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND); - //the other will get the flag - ClientName(teammates[1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayTeamOrder(bs, teammates[1]); - BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG); - break; - } - case 3: - { - //the one closest to the base will defend the base - ClientName(teammates[0], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[0]); - BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND); - //the others should go for the enemy flag - ClientName(teammates[1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayTeamOrder(bs, teammates[1]); - BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG); - // - ClientName(teammates[2], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayTeamOrder(bs, teammates[2]); - BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_GETFLAG); - break; - } - default: - { - defenders = (int) (float) numteammates * 0.4 + 0.5; - if (defenders > 4) defenders = 4; - attackers = (int) (float) numteammates * 0.5 + 0.5; - if (attackers > 5) attackers = 5; - for (i = 0; i < defenders; i++) { - // - ClientName(teammates[i], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[i]); - BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND); - } - for (i = 0; i < attackers; i++) { - // - ClientName(teammates[numteammates - i - 1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayTeamOrder(bs, teammates[numteammates - i - 1]); - BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG); - } - // - break; - } - } - } -} - -/* -================== -BotCTFOrders -================== -*/ -void BotCTFOrders(bot_state_t *bs) { - int flagstatus; - - // - if (BotTeam(bs) == TEAM_RED) flagstatus = bs->redflagstatus * 2 + bs->blueflagstatus; - else flagstatus = bs->blueflagstatus * 2 + bs->redflagstatus; - // - switch(flagstatus) { - case 0: BotCTFOrders_BothFlagsAtBase(bs); break; - case 1: BotCTFOrders_EnemyFlagNotAtBase(bs); break; - case 2: BotCTFOrders_FlagNotAtBase(bs); break; - case 3: BotCTFOrders_BothFlagsNotAtBase(bs); break; - } -} - - -/* -================== -BotCreateGroup -================== -*/ -void BotCreateGroup(bot_state_t *bs, int *teammates, int groupsize) { - char name[MAX_NETNAME], leadername[MAX_NETNAME]; - int i; - - // the others in the group will follow the teammates[0] - ClientName(teammates[0], leadername, sizeof(leadername)); - for (i = 1; i < groupsize; i++) - { - ClientName(teammates[i], name, sizeof(name)); - if (teammates[0] == bs->client) { - BotAI_BotInitialChat(bs, "cmd_accompanyme", name, NULL); - } - else { - BotAI_BotInitialChat(bs, "cmd_accompany", name, leadername, NULL); - } - BotSayTeamOrderAlways(bs, teammates[i]); - } -} - -/* -================== -BotTeamOrders - - FIXME: defend key areas? -================== -*/ -void BotTeamOrders(bot_state_t *bs) { - int teammates[MAX_CLIENTS]; - int numteammates, i; - char buf[MAX_INFO_STRING]; - static int maxclients; - - if (!maxclients) - maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients"); - - numteammates = 0; - for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) { - trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf)); - //if no config string or no name - if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue; - //skip spectators - if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR) continue; - // - if (BotSameTeam(bs, i)) { - teammates[numteammates] = i; - numteammates++; - } - } - // - switch(numteammates) { - case 1: break; - case 2: - { - //nothing special - break; - } - case 3: - { - //have one follow another and one free roaming - BotCreateGroup(bs, teammates, 2); - break; - } - case 4: - { - BotCreateGroup(bs, teammates, 2); //a group of 2 - BotCreateGroup(bs, &teammates[2], 2); //a group of 2 - break; - } - case 5: - { - BotCreateGroup(bs, teammates, 2); //a group of 2 - BotCreateGroup(bs, &teammates[2], 3); //a group of 3 - break; - } - default: - { - if (numteammates <= 10) { - for (i = 0; i < numteammates / 2; i++) { - BotCreateGroup(bs, &teammates[i*2], 2); //groups of 2 - } - } - break; - } - } -} - -#ifdef MISSIONPACK - -/* -================== -Bot1FCTFOrders_FlagAtCenter - - X% defend the base, Y% get the flag -================== -*/ -void Bot1FCTFOrders_FlagAtCenter(bot_state_t *bs) { - int numteammates, defenders, attackers, i; - int teammates[MAX_CLIENTS]; - char name[MAX_NETNAME]; - - //sort team mates by travel time to base - numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates)); - //sort team mates by CTF preference - BotSortTeamMatesByTaskPreference(bs, teammates, numteammates); - //passive strategy - if (!(bs->ctfstrategy & CTFS_AGRESSIVE)) { - //different orders based on the number of team mates - switch(numteammates) { - case 1: break; - case 2: - { - //the one closest to the base will defend the base - ClientName(teammates[0], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[0]); - BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND); - //the other will get the flag - ClientName(teammates[1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayTeamOrder(bs, teammates[1]); - BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG); - break; - } - case 3: - { - //the one closest to the base will defend the base - ClientName(teammates[0], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[0]); - BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND); - //the second one closest to the base will defend the base - ClientName(teammates[1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[1]); - BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND); - //the other will get the flag - ClientName(teammates[2], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayTeamOrder(bs, teammates[2]); - BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_GETFLAG); - break; - } - default: - { - //50% defend the base - defenders = (int) (float) numteammates * 0.5 + 0.5; - if (defenders > 5) defenders = 5; - //40% get the flag - attackers = (int) (float) numteammates * 0.4 + 0.5; - if (attackers > 4) attackers = 4; - for (i = 0; i < defenders; i++) { - // - ClientName(teammates[i], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[i]); - BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND); - } - for (i = 0; i < attackers; i++) { - // - ClientName(teammates[numteammates - i - 1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayTeamOrder(bs, teammates[numteammates - i - 1]); - BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG); - } - // - break; - } - } - } - else { //agressive - //different orders based on the number of team mates - switch(numteammates) { - case 1: break; - case 2: - { - //the one closest to the base will defend the base - ClientName(teammates[0], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[0]); - BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND); - //the other will get the flag - ClientName(teammates[1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayTeamOrder(bs, teammates[1]); - BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG); - break; - } - case 3: - { - //the one closest to the base will defend the base - ClientName(teammates[0], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[0]); - BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND); - //the others should go for the enemy flag - ClientName(teammates[1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayTeamOrder(bs, teammates[1]); - BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG); - // - ClientName(teammates[2], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayTeamOrder(bs, teammates[2]); - BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_GETFLAG); - break; - } - default: - { - //30% defend the base - defenders = (int) (float) numteammates * 0.3 + 0.5; - if (defenders > 3) defenders = 3; - //60% get the flag - attackers = (int) (float) numteammates * 0.6 + 0.5; - if (attackers > 6) attackers = 6; - for (i = 0; i < defenders; i++) { - // - ClientName(teammates[i], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[i]); - BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND); - } - for (i = 0; i < attackers; i++) { - // - ClientName(teammates[numteammates - i - 1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayTeamOrder(bs, teammates[numteammates - i - 1]); - BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG); - } - // - break; - } - } - } -} - -/* -================== -Bot1FCTFOrders_TeamHasFlag - - X% towards neutral flag, Y% go towards enemy base and accompany flag carrier if visible -================== -*/ -void Bot1FCTFOrders_TeamHasFlag(bot_state_t *bs) { - int numteammates, defenders, attackers, i, other; - int teammates[MAX_CLIENTS]; - char name[MAX_NETNAME], carriername[MAX_NETNAME]; - - //sort team mates by travel time to base - numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates)); - //sort team mates by CTF preference - BotSortTeamMatesByTaskPreference(bs, teammates, numteammates); - //passive strategy - if (!(bs->ctfstrategy & CTFS_AGRESSIVE)) { - //different orders based on the number of team mates - switch(numteammates) { - case 1: break; - case 2: - { - //tell the one not carrying the flag to attack the enemy base - if (teammates[0] == bs->flagcarrier) other = teammates[1]; - else other = teammates[0]; - ClientName(other, name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_attackenemybase", name, NULL); - BotSayTeamOrder(bs, other); - BotSayVoiceTeamOrder(bs, other, VOICECHAT_OFFENSE); - break; - } - case 3: - { - //tell the one closest to the base not carrying the flag to defend the base - if (teammates[0] != bs->flagcarrier) other = teammates[0]; - else other = teammates[1]; - ClientName(other, name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, other); - BotSayVoiceTeamOrder(bs, other, VOICECHAT_DEFEND); - //tell the one furthest from the base not carrying the flag to accompany the flag carrier - if (teammates[2] != bs->flagcarrier) other = teammates[2]; - else other = teammates[1]; - ClientName(other, name, sizeof(name)); - if ( bs->flagcarrier != -1 ) { - ClientName(bs->flagcarrier, carriername, sizeof(carriername)); - if (bs->flagcarrier == bs->client) { - BotAI_BotInitialChat(bs, "cmd_accompanyme", name, NULL); - BotSayVoiceTeamOrder(bs, other, VOICECHAT_FOLLOWME); - } - else { - BotAI_BotInitialChat(bs, "cmd_accompany", name, carriername, NULL); - BotSayVoiceTeamOrder(bs, other, VOICECHAT_FOLLOWFLAGCARRIER); - } - } - else { - // - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayVoiceTeamOrder(bs, other, VOICECHAT_GETFLAG); - } - BotSayTeamOrder(bs, other); - break; - } - default: - { - //30% will defend the base - defenders = (int) (float) numteammates * 0.3 + 0.5; - if (defenders > 3) defenders = 3; - //70% accompanies the flag carrier - attackers = (int) (float) numteammates * 0.7 + 0.5; - if (attackers > 7) attackers = 7; - for (i = 0; i < defenders; i++) { - // - if (teammates[i] == bs->flagcarrier) { - continue; - } - ClientName(teammates[i], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[i]); - BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND); - } - if (bs->flagcarrier != -1) { - ClientName(bs->flagcarrier, carriername, sizeof(carriername)); - for (i = 0; i < attackers; i++) { - // - if (teammates[numteammates - i - 1] == bs->flagcarrier) { - continue; - } - // - ClientName(teammates[numteammates - i - 1], name, sizeof(name)); - if (bs->flagcarrier == bs->client) { - BotAI_BotInitialChat(bs, "cmd_accompanyme", name, NULL); - BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_FOLLOWME); - } - else { - BotAI_BotInitialChat(bs, "cmd_accompany", name, carriername, NULL); - BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_FOLLOWFLAGCARRIER); - } - BotSayTeamOrder(bs, teammates[numteammates - i - 1]); - } - } - else { - for (i = 0; i < attackers; i++) { - // - if (teammates[numteammates - i - 1] == bs->flagcarrier) { - continue; - } - // - ClientName(teammates[numteammates - i - 1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayTeamOrder(bs, teammates[numteammates - i - 1]); - BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG); - } - } - // - break; - } - } -} - else { //agressive - //different orders based on the number of team mates - switch(numteammates) { - case 1: break; - case 2: - { - //tell the one not carrying the flag to defend the base - if (teammates[0] == bs->flagcarrier) other = teammates[1]; - else other = teammates[0]; - ClientName(other, name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, other); - BotSayVoiceTeamOrder(bs, other, VOICECHAT_DEFEND); - break; - } - case 3: - { - //tell the one closest to the base not carrying the flag to defend the base - if (teammates[0] != bs->flagcarrier) other = teammates[0]; - else other = teammates[1]; - ClientName(other, name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, other); - BotSayVoiceTeamOrder(bs, other, VOICECHAT_DEFEND); - //tell the one furthest from the base not carrying the flag to accompany the flag carrier - if (teammates[2] != bs->flagcarrier) other = teammates[2]; - else other = teammates[1]; - ClientName(other, name, sizeof(name)); - ClientName(bs->flagcarrier, carriername, sizeof(carriername)); - if (bs->flagcarrier == bs->client) { - BotAI_BotInitialChat(bs, "cmd_accompanyme", name, NULL); - BotSayVoiceTeamOrder(bs, other, VOICECHAT_FOLLOWME); - } - else { - BotAI_BotInitialChat(bs, "cmd_accompany", name, carriername, NULL); - BotSayVoiceTeamOrder(bs, other, VOICECHAT_FOLLOWFLAGCARRIER); - } - BotSayTeamOrder(bs, other); - break; - } - default: - { - //20% will defend the base - defenders = (int) (float) numteammates * 0.2 + 0.5; - if (defenders > 2) defenders = 2; - //80% accompanies the flag carrier - attackers = (int) (float) numteammates * 0.8 + 0.5; - if (attackers > 8) attackers = 8; - for (i = 0; i < defenders; i++) { - // - if (teammates[i] == bs->flagcarrier) { - continue; - } - ClientName(teammates[i], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[i]); - BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND); - } - ClientName(bs->flagcarrier, carriername, sizeof(carriername)); - for (i = 0; i < attackers; i++) { - // - if (teammates[numteammates - i - 1] == bs->flagcarrier) { - continue; - } - // - ClientName(teammates[numteammates - i - 1], name, sizeof(name)); - if (bs->flagcarrier == bs->client) { - BotAI_BotInitialChat(bs, "cmd_accompanyme", name, NULL); - BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_FOLLOWME); - } - else { - BotAI_BotInitialChat(bs, "cmd_accompany", name, carriername, NULL); - BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_FOLLOWFLAGCARRIER); - } - BotSayTeamOrder(bs, teammates[numteammates - i - 1]); - } - // - break; - } - } - } -} - -/* -================== -Bot1FCTFOrders_EnemyHasFlag - - X% defend the base, Y% towards neutral flag -================== -*/ -void Bot1FCTFOrders_EnemyHasFlag(bot_state_t *bs) { - int numteammates, defenders, attackers, i; - int teammates[MAX_CLIENTS]; - char name[MAX_NETNAME]; - - //sort team mates by travel time to base - numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates)); - //sort team mates by CTF preference - BotSortTeamMatesByTaskPreference(bs, teammates, numteammates); - //passive strategy - if (!(bs->ctfstrategy & CTFS_AGRESSIVE)) { - //different orders based on the number of team mates - switch(numteammates) { - case 1: break; - case 2: - { - //both defend the base - ClientName(teammates[0], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[0]); - BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND); - // - ClientName(teammates[1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[1]); - BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_DEFEND); - break; - } - case 3: - { - //the one closest to the base will defend the base - ClientName(teammates[0], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[0]); - BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND); - //the second one closest to the base will defend the base - ClientName(teammates[1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[1]); - BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_DEFEND); - //the other will also defend the base - ClientName(teammates[2], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[2]); - BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_DEFEND); - break; - } - default: - { - //80% will defend the base - defenders = (int) (float) numteammates * 0.8 + 0.5; - if (defenders > 8) defenders = 8; - //10% will try to return the flag - attackers = (int) (float) numteammates * 0.1 + 0.5; - if (attackers > 2) attackers = 2; - for (i = 0; i < defenders; i++) { - // - ClientName(teammates[i], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[i]); - BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND); - } - for (i = 0; i < attackers; i++) { - // - ClientName(teammates[numteammates - i - 1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_returnflag", name, NULL); - BotSayTeamOrder(bs, teammates[numteammates - i - 1]); - BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG); - } - // - break; - } - } - } - else { //agressive - //different orders based on the number of team mates - switch(numteammates) { - case 1: break; - case 2: - { - //the one closest to the base will defend the base - ClientName(teammates[0], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[0]); - BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND); - //the other will get the flag - ClientName(teammates[1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[1]); - BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_DEFEND); - break; - } - case 3: - { - //the one closest to the base will defend the base - ClientName(teammates[0], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[0]); - BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND); - //the others should go for the enemy flag - ClientName(teammates[1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[1]); - BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_DEFEND); - // - ClientName(teammates[2], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_returnflag", name, NULL); - BotSayTeamOrder(bs, teammates[2]); - BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_GETFLAG); - break; - } - default: - { - //70% defend the base - defenders = (int) (float) numteammates * 0.7 + 0.5; - if (defenders > 8) defenders = 8; - //20% try to return the flag - attackers = (int) (float) numteammates * 0.2 + 0.5; - if (attackers > 2) attackers = 2; - for (i = 0; i < defenders; i++) { - // - ClientName(teammates[i], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[i]); - BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND); - } - for (i = 0; i < attackers; i++) { - // - ClientName(teammates[numteammates - i - 1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_returnflag", name, NULL); - BotSayTeamOrder(bs, teammates[numteammates - i - 1]); - BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG); - } - // - break; - } - } - } -} - -/* -================== -Bot1FCTFOrders_EnemyDroppedFlag - - X% defend the base, Y% get the flag -================== -*/ -void Bot1FCTFOrders_EnemyDroppedFlag(bot_state_t *bs) { - int numteammates, defenders, attackers, i; - int teammates[MAX_CLIENTS]; - char name[MAX_NETNAME]; - - //sort team mates by travel time to base - numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates)); - //sort team mates by CTF preference - BotSortTeamMatesByTaskPreference(bs, teammates, numteammates); - //passive strategy - if (!(bs->ctfstrategy & CTFS_AGRESSIVE)) { - //different orders based on the number of team mates - switch(numteammates) { - case 1: break; - case 2: - { - //the one closest to the base will defend the base - ClientName(teammates[0], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[0]); - BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND); - //the other will get the flag - ClientName(teammates[1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayTeamOrder(bs, teammates[1]); - BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG); - break; - } - case 3: - { - //the one closest to the base will defend the base - ClientName(teammates[0], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[0]); - BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND); - //the second one closest to the base will defend the base - ClientName(teammates[1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[1]); - BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_DEFEND); - //the other will get the flag - ClientName(teammates[2], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayTeamOrder(bs, teammates[2]); - BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_GETFLAG); - break; - } - default: - { - //50% defend the base - defenders = (int) (float) numteammates * 0.5 + 0.5; - if (defenders > 5) defenders = 5; - //40% get the flag - attackers = (int) (float) numteammates * 0.4 + 0.5; - if (attackers > 4) attackers = 4; - for (i = 0; i < defenders; i++) { - // - ClientName(teammates[i], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[i]); - BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND); - } - for (i = 0; i < attackers; i++) { - // - ClientName(teammates[numteammates - i - 1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayTeamOrder(bs, teammates[numteammates - i - 1]); - BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG); - } - // - break; - } - } - } - else { //agressive - //different orders based on the number of team mates - switch(numteammates) { - case 1: break; - case 2: - { - //the one closest to the base will defend the base - ClientName(teammates[0], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[0]); - BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND); - //the other will get the flag - ClientName(teammates[1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayTeamOrder(bs, teammates[1]); - BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG); - break; - } - case 3: - { - //the one closest to the base will defend the base - ClientName(teammates[0], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[0]); - BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND); - //the others should go for the enemy flag - ClientName(teammates[1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayTeamOrder(bs, teammates[1]); - BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG); - // - ClientName(teammates[2], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayTeamOrder(bs, teammates[2]); - BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_GETFLAG); - break; - } - default: - { - //30% defend the base - defenders = (int) (float) numteammates * 0.3 + 0.5; - if (defenders > 3) defenders = 3; - //60% get the flag - attackers = (int) (float) numteammates * 0.6 + 0.5; - if (attackers > 6) attackers = 6; - for (i = 0; i < defenders; i++) { - // - ClientName(teammates[i], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[i]); - BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND); - } - for (i = 0; i < attackers; i++) { - // - ClientName(teammates[numteammates - i - 1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayTeamOrder(bs, teammates[numteammates - i - 1]); - BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_DEFEND); - } - // - break; - } - } - } -} - -/* -================== -Bot1FCTFOrders -================== -*/ -void Bot1FCTFOrders(bot_state_t *bs) { - switch(bs->neutralflagstatus) { - case 0: Bot1FCTFOrders_FlagAtCenter(bs); break; - case 1: Bot1FCTFOrders_TeamHasFlag(bs); break; - case 2: Bot1FCTFOrders_EnemyHasFlag(bs); break; - case 3: Bot1FCTFOrders_EnemyDroppedFlag(bs); break; - } -} - -/* -================== -BotObeliskOrders - - X% in defence Y% in offence -================== -*/ -void BotObeliskOrders(bot_state_t *bs) { - int numteammates, defenders, attackers, i; - int teammates[MAX_CLIENTS]; - char name[MAX_NETNAME]; - - //sort team mates by travel time to base - numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates)); - //sort team mates by CTF preference - BotSortTeamMatesByTaskPreference(bs, teammates, numteammates); - //passive strategy - if (!(bs->ctfstrategy & CTFS_AGRESSIVE)) { - //different orders based on the number of team mates - switch(numteammates) { - case 1: break; - case 2: - { - //the one closest to the base will defend the base - ClientName(teammates[0], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[0]); - BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND); - //the other will attack the enemy base - ClientName(teammates[1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_attackenemybase", name, NULL); - BotSayTeamOrder(bs, teammates[1]); - BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_OFFENSE); - break; - } - case 3: - { - //the one closest to the base will defend the base - ClientName(teammates[0], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[0]); - BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND); - //the one second closest to the base also defends the base - ClientName(teammates[1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[1]); - BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_DEFEND); - //the other one attacks the enemy base - ClientName(teammates[2], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_attackenemybase", name, NULL); - BotSayTeamOrder(bs, teammates[2]); - BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_OFFENSE); - break; - } - default: - { - //50% defend the base - defenders = (int) (float) numteammates * 0.5 + 0.5; - if (defenders > 5) defenders = 5; - //40% attack the enemy base - attackers = (int) (float) numteammates * 0.4 + 0.5; - if (attackers > 4) attackers = 4; - for (i = 0; i < defenders; i++) { - // - ClientName(teammates[i], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[i]); - BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND); - } - for (i = 0; i < attackers; i++) { - // - ClientName(teammates[numteammates - i - 1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_attackenemybase", name, NULL); - BotSayTeamOrder(bs, teammates[numteammates - i - 1]); - BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_OFFENSE); - } - // - break; - } - } - } - else { - //different orders based on the number of team mates - switch(numteammates) { - case 1: break; - case 2: - { - //the one closest to the base will defend the base - ClientName(teammates[0], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[0]); - BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND); - //the other will attack the enemy base - ClientName(teammates[1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_attackenemybase", name, NULL); - BotSayTeamOrder(bs, teammates[1]); - BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_OFFENSE); - break; - } - case 3: - { - //the one closest to the base will defend the base - ClientName(teammates[0], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[0]); - BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND); - //the others attack the enemy base - ClientName(teammates[1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_attackenemybase", name, NULL); - BotSayTeamOrder(bs, teammates[1]); - BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_OFFENSE); - // - ClientName(teammates[2], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_attackenemybase", name, NULL); - BotSayTeamOrder(bs, teammates[2]); - BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_OFFENSE); - break; - } - default: - { - //30% defend the base - defenders = (int) (float) numteammates * 0.3 + 0.5; - if (defenders > 3) defenders = 3; - //70% attack the enemy base - attackers = (int) (float) numteammates * 0.7 + 0.5; - if (attackers > 7) attackers = 7; - for (i = 0; i < defenders; i++) { - // - ClientName(teammates[i], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[i]); - BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND); - } - for (i = 0; i < attackers; i++) { - // - ClientName(teammates[numteammates - i - 1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_attackenemybase", name, NULL); - BotSayTeamOrder(bs, teammates[numteammates - i - 1]); - BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_OFFENSE); - } - // - break; - } - } - } -} - -/* -================== -BotHarvesterOrders - - X% defend the base, Y% harvest -================== -*/ -void BotHarvesterOrders(bot_state_t *bs) { - int numteammates, defenders, attackers, i; - int teammates[MAX_CLIENTS]; - char name[MAX_NETNAME]; - - //sort team mates by travel time to base - numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates)); - //sort team mates by CTF preference - BotSortTeamMatesByTaskPreference(bs, teammates, numteammates); - //passive strategy - if (!(bs->ctfstrategy & CTFS_AGRESSIVE)) { - //different orders based on the number of team mates - switch(numteammates) { - case 1: break; - case 2: - { - //the one closest to the base will defend the base - ClientName(teammates[0], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[0]); - BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND); - //the other will harvest - ClientName(teammates[1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_harvest", name, NULL); - BotSayTeamOrder(bs, teammates[1]); - BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_OFFENSE); - break; - } - case 3: - { - //the one closest to the base will defend the base - ClientName(teammates[0], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[0]); - BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND); - //the one second closest to the base also defends the base - ClientName(teammates[1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[1]); - BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_DEFEND); - //the other one goes harvesting - ClientName(teammates[2], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_harvest", name, NULL); - BotSayTeamOrder(bs, teammates[2]); - BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_OFFENSE); - break; - } - default: - { - //50% defend the base - defenders = (int) (float) numteammates * 0.5 + 0.5; - if (defenders > 5) defenders = 5; - //40% goes harvesting - attackers = (int) (float) numteammates * 0.4 + 0.5; - if (attackers > 4) attackers = 4; - for (i = 0; i < defenders; i++) { - // - ClientName(teammates[i], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[i]); - BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND); - } - for (i = 0; i < attackers; i++) { - // - ClientName(teammates[numteammates - i - 1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_harvest", name, NULL); - BotSayTeamOrder(bs, teammates[numteammates - i - 1]); - BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_OFFENSE); - } - // - break; - } - } - } - else { - //different orders based on the number of team mates - switch(numteammates) { - case 1: break; - case 2: - { - //the one closest to the base will defend the base - ClientName(teammates[0], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[0]); - BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND); - //the other will harvest - ClientName(teammates[1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_harvest", name, NULL); - BotSayTeamOrder(bs, teammates[1]); - BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_OFFENSE); - break; -} - case 3: - { - //the one closest to the base will defend the base - ClientName(teammates[0], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[0]); - BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND); - //the others go harvesting - ClientName(teammates[1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_harvest", name, NULL); - BotSayTeamOrder(bs, teammates[1]); - BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_OFFENSE); - // - ClientName(teammates[2], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_harvest", name, NULL); - BotSayTeamOrder(bs, teammates[2]); - BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_OFFENSE); - break; - } - default: - { - //30% defend the base - defenders = (int) (float) numteammates * 0.3 + 0.5; - if (defenders > 3) defenders = 3; - //70% go harvesting - attackers = (int) (float) numteammates * 0.7 + 0.5; - if (attackers > 7) attackers = 7; - for (i = 0; i < defenders; i++) { - // - ClientName(teammates[i], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[i]); - BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND); - } - for (i = 0; i < attackers; i++) { - // - ClientName(teammates[numteammates - i - 1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_harvest", name, NULL); - BotSayTeamOrder(bs, teammates[numteammates - i - 1]); - BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_OFFENSE); - } - // - break; - } - } - } -} -#endif - -/* -================== -FindHumanTeamLeader -================== -*/ -int FindHumanTeamLeader(bot_state_t *bs) { - int i; - - for (i = 0; i < MAX_CLIENTS; i++) { - if ( g_entities[i].inuse ) { - // if this player is not a bot - if ( !(g_entities[i].r.svFlags & SVF_BOT) ) { - // if this player is ok with being the leader - if (!notleader[i]) { - // if this player is on the same team - if ( BotSameTeam(bs, i) ) { - ClientName(i, bs->teamleader, sizeof(bs->teamleader)); - // if not yet ordered to do anything - if ( !BotSetLastOrderedTask(bs) ) { - // go on defense by default - BotVoiceChat_Defend(bs, i, SAY_TELL); - } - return qtrue; - } - } - } - } - } - return qfalse; -} - -/* -================== -BotTeamAI -================== -*/ -void BotTeamAI(bot_state_t *bs) { - int numteammates; - char netname[MAX_NETNAME]; - - // - if ( gametype < GT_TEAM ) - return; - //make sure we've got a valid team leader - if (!BotValidTeamLeader(bs)) { - // - if (!FindHumanTeamLeader(bs)) { - // - if (!bs->askteamleader_time && !bs->becometeamleader_time) { - if (bs->entergame_time + 10 > FloatTime()) { - bs->askteamleader_time = FloatTime() + 5 + random() * 10; - } - else { - bs->becometeamleader_time = FloatTime() + 5 + random() * 10; - } - } - if (bs->askteamleader_time && bs->askteamleader_time < FloatTime()) { - // if asked for a team leader and no response - BotAI_BotInitialChat(bs, "whoisteamleader", NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_TEAM); - bs->askteamleader_time = 0; - bs->becometeamleader_time = FloatTime() + 8 + random() * 10; - } - if (bs->becometeamleader_time && bs->becometeamleader_time < FloatTime()) { - BotAI_BotInitialChat(bs, "iamteamleader", NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_TEAM); - BotSayVoiceTeamOrder(bs, -1, VOICECHAT_STARTLEADER); - ClientName(bs->client, netname, sizeof(netname)); - strncpy(bs->teamleader, netname, sizeof(bs->teamleader)); - bs->teamleader[sizeof(bs->teamleader)] = '\0'; - bs->becometeamleader_time = 0; - } - return; - } - } - bs->askteamleader_time = 0; - bs->becometeamleader_time = 0; - - //return if this bot is NOT the team leader - ClientName(bs->client, netname, sizeof(netname)); - if (Q_stricmp(netname, bs->teamleader) != 0) return; - // - numteammates = BotNumTeamMates(bs); - //give orders - switch(gametype) { - case GT_TEAM: - { - if (bs->numteammates != numteammates || bs->forceorders) { - bs->teamgiveorders_time = FloatTime(); - bs->numteammates = numteammates; - bs->forceorders = qfalse; - } - //if it's time to give orders - if (bs->teamgiveorders_time && bs->teamgiveorders_time < FloatTime() - 5) { - BotTeamOrders(bs); - //give orders again after 120 seconds - bs->teamgiveorders_time = FloatTime() + 120; - } - break; - } - case GT_CTF: - { - //if the number of team mates changed or the flag status changed - //or someone wants to know what to do - if (bs->numteammates != numteammates || bs->flagstatuschanged || bs->forceorders) { - bs->teamgiveorders_time = FloatTime(); - bs->numteammates = numteammates; - bs->flagstatuschanged = qfalse; - bs->forceorders = qfalse; - } - //if there were no flag captures the last 3 minutes - if (bs->lastflagcapture_time < FloatTime() - 240) { - bs->lastflagcapture_time = FloatTime(); - //randomly change the CTF strategy - if (random() < 0.4) { - bs->ctfstrategy ^= CTFS_AGRESSIVE; - bs->teamgiveorders_time = FloatTime(); - } - } - //if it's time to give orders - if (bs->teamgiveorders_time && bs->teamgiveorders_time < FloatTime() - 3) { - BotCTFOrders(bs); - // - bs->teamgiveorders_time = 0; - } - break; - } -#ifdef MISSIONPACK - case GT_1FCTF: - { - if (bs->numteammates != numteammates || bs->flagstatuschanged || bs->forceorders) { - bs->teamgiveorders_time = FloatTime(); - bs->numteammates = numteammates; - bs->flagstatuschanged = qfalse; - bs->forceorders = qfalse; - } - //if there were no flag captures the last 4 minutes - if (bs->lastflagcapture_time < FloatTime() - 240) { - bs->lastflagcapture_time = FloatTime(); - //randomly change the CTF strategy - if (random() < 0.4) { - bs->ctfstrategy ^= CTFS_AGRESSIVE; - bs->teamgiveorders_time = FloatTime(); - } - } - //if it's time to give orders - if (bs->teamgiveorders_time && bs->teamgiveorders_time < FloatTime() - 2) { - Bot1FCTFOrders(bs); - // - bs->teamgiveorders_time = 0; - } - break; - } - case GT_OBELISK: - { - if (bs->numteammates != numteammates || bs->forceorders) { - bs->teamgiveorders_time = FloatTime(); - bs->numteammates = numteammates; - bs->forceorders = qfalse; - } - //if it's time to give orders - if (bs->teamgiveorders_time && bs->teamgiveorders_time < FloatTime() - 5) { - BotObeliskOrders(bs); - //give orders again after 30 seconds - bs->teamgiveorders_time = FloatTime() + 30; - } - break; - } - case GT_HARVESTER: - { - if (bs->numteammates != numteammates || bs->forceorders) { - bs->teamgiveorders_time = FloatTime(); - bs->numteammates = numteammates; - bs->forceorders = qfalse; - } - //if it's time to give orders - if (bs->teamgiveorders_time && bs->teamgiveorders_time < FloatTime() - 5) { - BotHarvesterOrders(bs); - //give orders again after 30 seconds - bs->teamgiveorders_time = FloatTime() + 30; - } - break; - } -#endif - } -} - diff --git a/reaction/game/.#ai_vcmd.c.1.1 b/reaction/game/.#ai_vcmd.c.1.1 deleted file mode 100644 index 69cce4c6..00000000 --- a/reaction/game/.#ai_vcmd.c.1.1 +++ /dev/null @@ -1,535 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// - -/***************************************************************************** - * name: ai_vcmd.c - * - * desc: Quake3 bot AI - * - * $Archive: /MissionPack/code/game/ai_vcmd.c $ - * $Author$ - * $Revision$ - * $Modtime: 11/17/00 5:37a $ - * $Date$ - * - *****************************************************************************/ - -#include "g_local.h" -#include "botlib.h" -#include "be_aas.h" -#include "be_ea.h" -#include "be_ai_char.h" -#include "be_ai_chat.h" -#include "be_ai_gen.h" -#include "be_ai_goal.h" -#include "be_ai_move.h" -#include "be_ai_weap.h" -// -#include "ai_main.h" -#include "ai_dmq3.h" -#include "ai_chat.h" -#include "ai_cmd.h" -#include "ai_dmnet.h" -#include "ai_team.h" -#include "ai_vcmd.h" -// -#include "chars.h" //characteristics -#include "inv.h" //indexes into the inventory -#include "syn.h" //synonyms -#include "match.h" //string matching types and vars - -// for the voice chats -//Blaze: was there a extra ../ here? -#include "../ui/menudef.h" - - -typedef struct voiceCommand_s -{ - char *cmd; - void (*func)(bot_state_t *bs, int client, int mode); -} voiceCommand_t; - -/* -================== -BotVoiceChat_GetFlag -================== -*/ -void BotVoiceChat_GetFlag(bot_state_t *bs, int client, int mode) { - // - if (gametype == GT_CTF) { - if (!ctf_redflag.areanum || !ctf_blueflag.areanum) - return; - } -#ifdef MISSIONPACK - else if (gametype == GT_1FCTF) { - if (!ctf_neutralflag.areanum || !ctf_redflag.areanum || !ctf_blueflag.areanum) - return; - } -#endif - else { - return; - } - // - bs->decisionmaker = client; - bs->ordered = qtrue; - bs->order_time = FloatTime(); - //set the time to send a message to the team mates - bs->teammessage_time = FloatTime() + 2 * random(); - //set the ltg type - bs->ltgtype = LTG_GETFLAG; - //set the team goal time - bs->teamgoal_time = FloatTime() + CTF_GETFLAG_TIME; - // get an alternate route in ctf - if (gametype == GT_CTF) { - //get an alternative route goal towards the enemy base - BotGetAlternateRouteGoal(bs, BotOppositeTeam(bs)); - } - // - BotSetTeamStatus(bs); - // remember last ordered task - BotRememberLastOrderedTask(bs); -#ifdef DEBUG - BotPrintTeamGoal(bs); -#endif //DEBUG -} - -/* -================== -BotVoiceChat_Offense -================== -*/ -void BotVoiceChat_Offense(bot_state_t *bs, int client, int mode) { - if ( gametype == GT_CTF -#ifdef MISSIONPACK - || gametype == GT_1FCTF -#endif - ) { - BotVoiceChat_GetFlag(bs, client, mode); - return; - } -#ifdef MISSIONPACK - if (gametype == GT_HARVESTER) { - // - bs->decisionmaker = client; - bs->ordered = qtrue; - bs->order_time = FloatTime(); - //set the time to send a message to the team mates - bs->teammessage_time = FloatTime() + 2 * random(); - //set the ltg type - bs->ltgtype = LTG_HARVEST; - //set the team goal time - bs->teamgoal_time = FloatTime() + TEAM_HARVEST_TIME; - bs->harvestaway_time = 0; - // - BotSetTeamStatus(bs); - // remember last ordered task - BotRememberLastOrderedTask(bs); - } - else -#endif - { - // - bs->decisionmaker = client; - bs->ordered = qtrue; - bs->order_time = FloatTime(); - //set the time to send a message to the team mates - bs->teammessage_time = FloatTime() + 2 * random(); - //set the ltg type - bs->ltgtype = LTG_ATTACKENEMYBASE; - //set the team goal time - bs->teamgoal_time = FloatTime() + TEAM_ATTACKENEMYBASE_TIME; - bs->attackaway_time = 0; - // - BotSetTeamStatus(bs); - // remember last ordered task - BotRememberLastOrderedTask(bs); - } -#ifdef DEBUG - BotPrintTeamGoal(bs); -#endif //DEBUG -} - -/* -================== -BotVoiceChat_Defend -================== -*/ -void BotVoiceChat_Defend(bot_state_t *bs, int client, int mode) { -#ifdef MISSIONPACK - if ( gametype == GT_OBELISK || gametype == GT_HARVESTER) { - // - switch(BotTeam(bs)) { - case TEAM_RED: memcpy(&bs->teamgoal, &redobelisk, sizeof(bot_goal_t)); break; - case TEAM_BLUE: memcpy(&bs->teamgoal, &blueobelisk, sizeof(bot_goal_t)); break; - default: return; - } - } - else -#endif - if (gametype == GT_CTF -#ifdef MISSIONPACK - || gametype == GT_1FCTF -#endif - ) { - // - switch(BotTeam(bs)) { - case TEAM_RED: memcpy(&bs->teamgoal, &ctf_redflag, sizeof(bot_goal_t)); break; - case TEAM_BLUE: memcpy(&bs->teamgoal, &ctf_blueflag, sizeof(bot_goal_t)); break; - default: return; - } - } - else { - return; - } - // - bs->decisionmaker = client; - bs->ordered = qtrue; - bs->order_time = FloatTime(); - //set the time to send a message to the team mates - bs->teammessage_time = FloatTime() + 2 * random(); - //set the ltg type - bs->ltgtype = LTG_DEFENDKEYAREA; - //get the team goal time - bs->teamgoal_time = FloatTime() + TEAM_DEFENDKEYAREA_TIME; - //away from defending - bs->defendaway_time = 0; - // - BotSetTeamStatus(bs); - // remember last ordered task - BotRememberLastOrderedTask(bs); -#ifdef DEBUG - BotPrintTeamGoal(bs); -#endif //DEBUG -} - -/* -================== -BotVoiceChat_DefendFlag -================== -*/ -void BotVoiceChat_DefendFlag(bot_state_t *bs, int client, int mode) { - BotVoiceChat_Defend(bs, client, mode); -} - -/* -================== -BotVoiceChat_Patrol -================== -*/ -void BotVoiceChat_Patrol(bot_state_t *bs, int client, int mode) { - // - bs->decisionmaker = client; - // - bs->ltgtype = 0; - bs->lead_time = 0; - bs->lastgoal_ltgtype = 0; - // - BotAI_BotInitialChat(bs, "dismissed", NULL); - trap_BotEnterChat(bs->cs, client, CHAT_TELL); - BotVoiceChatOnly(bs, -1, VOICECHAT_ONPATROL); - // - BotSetTeamStatus(bs); -#ifdef DEBUG - BotPrintTeamGoal(bs); -#endif //DEBUG -} - -/* -================== -BotVoiceChat_Camp -================== -*/ -void BotVoiceChat_Camp(bot_state_t *bs, int client, int mode) { - int areanum; - aas_entityinfo_t entinfo; - char netname[MAX_NETNAME]; - - // - bs->teamgoal.entitynum = -1; - BotEntityInfo(client, &entinfo); - //if info is valid (in PVS) - if (entinfo.valid) { - areanum = BotPointAreaNum(entinfo.origin); - if (areanum) { // && trap_AAS_AreaReachability(areanum)) { - //NOTE: just assume the bot knows where the person is - //if (BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, client)) { - bs->teamgoal.entitynum = client; - bs->teamgoal.areanum = areanum; - VectorCopy(entinfo.origin, bs->teamgoal.origin); - VectorSet(bs->teamgoal.mins, -8, -8, -8); - VectorSet(bs->teamgoal.maxs, 8, 8, 8); - //} - } - } - //if the other is not visible - if (bs->teamgoal.entitynum < 0) { - BotAI_BotInitialChat(bs, "whereareyou", EasyClientName(client, netname, sizeof(netname)), NULL); - trap_BotEnterChat(bs->cs, client, CHAT_TELL); - return; - } - // - bs->decisionmaker = client; - bs->ordered = qtrue; - bs->order_time = FloatTime(); - //set the time to send a message to the team mates - bs->teammessage_time = FloatTime() + 2 * random(); - //set the ltg type - bs->ltgtype = LTG_CAMPORDER; - //get the team goal time - bs->teamgoal_time = FloatTime() + TEAM_CAMP_TIME; - //the teammate that requested the camping - bs->teammate = client; - //not arrived yet - bs->arrive_time = 0; - // - BotSetTeamStatus(bs); - // remember last ordered task - BotRememberLastOrderedTask(bs); -#ifdef DEBUG - BotPrintTeamGoal(bs); -#endif //DEBUG -} - -/* -================== -BotVoiceChat_FollowMe -================== -*/ -void BotVoiceChat_FollowMe(bot_state_t *bs, int client, int mode) { - int areanum; - aas_entityinfo_t entinfo; - char netname[MAX_NETNAME]; - - bs->teamgoal.entitynum = -1; - BotEntityInfo(client, &entinfo); - //if info is valid (in PVS) - if (entinfo.valid) { - areanum = BotPointAreaNum(entinfo.origin); - if (areanum) { // && trap_AAS_AreaReachability(areanum)) { - bs->teamgoal.entitynum = client; - bs->teamgoal.areanum = areanum; - VectorCopy(entinfo.origin, bs->teamgoal.origin); - VectorSet(bs->teamgoal.mins, -8, -8, -8); - VectorSet(bs->teamgoal.maxs, 8, 8, 8); - } - } - //if the other is not visible - if (bs->teamgoal.entitynum < 0) { - BotAI_BotInitialChat(bs, "whereareyou", EasyClientName(client, netname, sizeof(netname)), NULL); - trap_BotEnterChat(bs->cs, client, CHAT_TELL); - return; - } - // - bs->decisionmaker = client; - bs->ordered = qtrue; - bs->order_time = FloatTime(); - //the team mate - bs->teammate = client; - //last time the team mate was assumed visible - bs->teammatevisible_time = FloatTime(); - //set the time to send a message to the team mates - bs->teammessage_time = FloatTime() + 2 * random(); - //get the team goal time - bs->teamgoal_time = FloatTime() + TEAM_ACCOMPANY_TIME; - //set the ltg type - bs->ltgtype = LTG_TEAMACCOMPANY; - bs->formation_dist = 3.5 * 32; //3.5 meter - bs->arrive_time = 0; - // - BotSetTeamStatus(bs); - // remember last ordered task - BotRememberLastOrderedTask(bs); -#ifdef DEBUG - BotPrintTeamGoal(bs); -#endif //DEBUG -} - -/* -================== -BotVoiceChat_FollowFlagCarrier -================== -*/ -void BotVoiceChat_FollowFlagCarrier(bot_state_t *bs, int client, int mode) { - int carrier; - - carrier = BotTeamFlagCarrier(bs); - if (carrier >= 0) - BotVoiceChat_FollowMe(bs, carrier, mode); -#ifdef DEBUG - BotPrintTeamGoal(bs); -#endif //DEBUG -} - -/* -================== -BotVoiceChat_ReturnFlag -================== -*/ -void BotVoiceChat_ReturnFlag(bot_state_t *bs, int client, int mode) { - //if not in CTF mode - if ( - gametype != GT_CTF -#ifdef MISSIONPACK - && gametype != GT_1FCTF -#endif - ) { - return; - } - // - bs->decisionmaker = client; - bs->ordered = qtrue; - bs->order_time = FloatTime(); - //set the time to send a message to the team mates - bs->teammessage_time = FloatTime() + 2 * random(); - //set the ltg type - bs->ltgtype = LTG_RETURNFLAG; - //set the team goal time - bs->teamgoal_time = FloatTime() + CTF_RETURNFLAG_TIME; - bs->rushbaseaway_time = 0; - BotSetTeamStatus(bs); -#ifdef DEBUG - BotPrintTeamGoal(bs); -#endif //DEBUG -} - -/* -================== -BotVoiceChat_StartLeader -================== -*/ -void BotVoiceChat_StartLeader(bot_state_t *bs, int client, int mode) { - ClientName(client, bs->teamleader, sizeof(bs->teamleader)); -} - -/* -================== -BotVoiceChat_StopLeader -================== -*/ -void BotVoiceChat_StopLeader(bot_state_t *bs, int client, int mode) { - char netname[MAX_MESSAGE_SIZE]; - - if (!Q_stricmp(bs->teamleader, ClientName(client, netname, sizeof(netname)))) { - bs->teamleader[0] = '\0'; - notleader[client] = qtrue; - } -} - -/* -================== -BotVoiceChat_WhoIsLeader -================== -*/ -void BotVoiceChat_WhoIsLeader(bot_state_t *bs, int client, int mode) { - char netname[MAX_MESSAGE_SIZE]; - - if (!TeamPlayIsOn()) return; - - ClientName(bs->client, netname, sizeof(netname)); - //if this bot IS the team leader - if (!Q_stricmp(netname, bs->teamleader)) { - BotAI_BotInitialChat(bs, "iamteamleader", NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_TEAM); - BotVoiceChatOnly(bs, -1, VOICECHAT_STARTLEADER); - } -} - -/* -================== -BotVoiceChat_WantOnDefense -================== -*/ -void BotVoiceChat_WantOnDefense(bot_state_t *bs, int client, int mode) { - char netname[MAX_NETNAME]; - int preference; - - preference = BotGetTeamMateTaskPreference(bs, client); - preference &= ~TEAMTP_ATTACKER; - preference |= TEAMTP_DEFENDER; - BotSetTeamMateTaskPreference(bs, client, preference); - // - EasyClientName(client, netname, sizeof(netname)); - BotAI_BotInitialChat(bs, "keepinmind", netname, NULL); - trap_BotEnterChat(bs->cs, client, CHAT_TELL); - BotVoiceChatOnly(bs, client, VOICECHAT_YES); - trap_EA_Action(bs->client, ACTION_AFFIRMATIVE); -} - -/* -================== -BotVoiceChat_WantOnOffense -================== -*/ -void BotVoiceChat_WantOnOffense(bot_state_t *bs, int client, int mode) { - char netname[MAX_NETNAME]; - int preference; - - preference = BotGetTeamMateTaskPreference(bs, client); - preference &= ~TEAMTP_DEFENDER; - preference |= TEAMTP_ATTACKER; - BotSetTeamMateTaskPreference(bs, client, preference); - // - EasyClientName(client, netname, sizeof(netname)); - BotAI_BotInitialChat(bs, "keepinmind", netname, NULL); - trap_BotEnterChat(bs->cs, client, CHAT_TELL); - BotVoiceChatOnly(bs, client, VOICECHAT_YES); - trap_EA_Action(bs->client, ACTION_AFFIRMATIVE); -} - -void BotVoiceChat_Dummy(bot_state_t *bs, int client, int mode) { -} - -voiceCommand_t voiceCommands[] = { - {VOICECHAT_GETFLAG, BotVoiceChat_GetFlag}, - {VOICECHAT_OFFENSE, BotVoiceChat_Offense }, - {VOICECHAT_DEFEND, BotVoiceChat_Defend }, - {VOICECHAT_DEFENDFLAG, BotVoiceChat_DefendFlag }, - {VOICECHAT_PATROL, BotVoiceChat_Patrol }, - {VOICECHAT_CAMP, BotVoiceChat_Camp }, - {VOICECHAT_FOLLOWME, BotVoiceChat_FollowMe }, - {VOICECHAT_FOLLOWFLAGCARRIER, BotVoiceChat_FollowFlagCarrier }, - {VOICECHAT_RETURNFLAG, BotVoiceChat_ReturnFlag }, - {VOICECHAT_STARTLEADER, BotVoiceChat_StartLeader }, - {VOICECHAT_STOPLEADER, BotVoiceChat_StopLeader }, - {VOICECHAT_WHOISLEADER, BotVoiceChat_WhoIsLeader }, - {VOICECHAT_WANTONDEFENSE, BotVoiceChat_WantOnDefense }, - {VOICECHAT_WANTONOFFENSE, BotVoiceChat_WantOnOffense }, - {NULL, BotVoiceChat_Dummy} -}; - -int BotVoiceChatCommand(bot_state_t *bs, int mode, char *voiceChat) { - int i, voiceOnly, clientNum, color; - char *ptr, buf[MAX_MESSAGE_SIZE], *cmd; - - if (!TeamPlayIsOn()) { - return qfalse; - } - - if ( mode == SAY_ALL ) { - return qfalse; // don't do anything with voice chats to everyone - } - - Q_strncpyz(buf, voiceChat, sizeof(buf)); - cmd = buf; - for (ptr = cmd; *cmd && *cmd > ' '; cmd++); - while (*cmd && *cmd <= ' ') *cmd++ = '\0'; - voiceOnly = atoi(ptr); - for (ptr = cmd; *cmd && *cmd > ' '; cmd++); - while (*cmd && *cmd <= ' ') *cmd++ = '\0'; - clientNum = atoi(ptr); - for (ptr = cmd; *cmd && *cmd > ' '; cmd++); - while (*cmd && *cmd <= ' ') *cmd++ = '\0'; - color = atoi(ptr); - - if (!BotSameTeam(bs, clientNum)) { - return qfalse; - } - - for (i = 0; voiceCommands[i].cmd; i++) { - if (!Q_stricmp(cmd, voiceCommands[i].cmd)) { - voiceCommands[i].func(bs, clientNum, mode); - return qtrue; - } - } - return qfalse; -} diff --git a/reaction/game/.#bg_misc.c.1.13 b/reaction/game/.#bg_misc.c.1.13 deleted file mode 100644 index c3b366a3..00000000 --- a/reaction/game/.#bg_misc.c.1.13 +++ /dev/null @@ -1,1454 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// -// bg_misc.c -- both games misc functions, all completely stateless - -#include "q_shared.h" -#include "bg_public.h" - -/*QUAKED item_***** ( 0 0 0 ) (-16 -16 -16) (16 16 16) suspended -DO NOT USE THIS CLASS, IT JUST HOLDS GENERAL INFORMATION. -The suspended flag will allow items to hang in the air, otherwise they are dropped to the next surface. - -If an item is the target of another entity, it will not spawn in until fired. - -An item fires all of its targets when it is picked up. If the toucher can't carry it, the targets won't be fired. - -"notfree" if set to 1, don't spawn in free for all games -"notteam" if set to 1, don't spawn in team games -"notsingle" if set to 1, don't spawn in single player games -"wait" override the default wait before respawning. -1 = never respawn automatically, which can be used with targeted spawning. -"random" random number of plus or minus seconds varied from the respawn time -"count" override quantity or duration on most items. -*/ - - -gitem_t bg_itemlist[] = -{ - { - NULL, - NULL, - { NULL, - NULL, - 0, 0} , -/* icon */ NULL, -/* pickup */ NULL, - 0, - 0, - 0, -/* precache */ "", -/* sounds */ "" - }, // leave index 0 alone - - // - // ARMOR - // - - // - // WEAPONS - // - - -//Blaze: Reaction weapons -//Knife - { - "weapon_knife", - "sound/weapons/knife/knife.wav", - {"models/weapons2/knife/knife.md3",0,0,0}, - "icons/iconw_knife", - "Knife", - 1, - IT_WEAPON, - WP_KNIFE, - "", - "" - }, - -//Pistol - { - "weapon_pistol", - "sound/weapons/mk23/mk23slide.wav", - { "models/weapons2/mk23/mk23.md3", - 0, 0, 0}, -/* icon */ "icons/iconw_mk23", -/* pickup */ "MK23", - 12, - IT_WEAPON, - WP_PISTOL, -/* precache */ "", -/* sounds */ "" - }, - -//M4 - { - "weapon_m4", - "sound/weapons/m4/m4slide.wav", - { "models/weapons2/m4/m4.md3", - 0, 0, 0}, -/* icon */ "icons/iconw_m4", -/* pickup */ "M4", - 24, - IT_WEAPON, - WP_M4, -/* precache */ "", -/* sounds */ "" - }, - -//SSG3000 - { - "weapon_ssg3000", - "sound/weapons/ssg3000/ssgin.wav", - { "models/weapons2/ssg3000/ssg3000.md3", - 0, 0, 0}, -/* icon */ "icons/iconw_ssg", -/* pickup */ "SSG3000", - 6, - IT_WEAPON, - WP_SSG3000, -/* precache */ "", -/* sounds */ "" - }, - -//MP5 - { - "weapon_mp5", - "sound/weapons/mp5/mp5slide.wav", - { "models/weapons2/mp5/mp5.md3", - 0, 0, 0}, -/* icon */ "icons/iconw_mp5", -/* pickup */ "MP5", - 30, - IT_WEAPON, - WP_MP5, -/* precache */ "", -/* sounds */ "" - }, - -//Handcannon - { - "weapon_handcannon", - "sound/weapons/handcannon/copen.wav", - { "models/weapons2/handcannon/handcannon.md3", - 0, 0, 0}, -/* icon */ "icons/iconw_sawedoff", -/* pickup */ "Hand Cannon", - 2, - IT_WEAPON, - WP_HANDCANNON, -/* precache */ "", -/* sounds */ "" - }, - -//Shotgun - { - "weapon_m3", - "sound/weapons/shotgun/m3in.wav", - { "models/weapons2/shotgun/shotgun.md3", - 0, 0, 0}, -/* icon */ "icons/iconw_m3", -/* pickup */ "M3 Super Shotgun", - 7, - IT_WEAPON, - WP_M3, -/* precache */ "", -/* sounds */ "" - }, - -//Akimbo Placeholder - { - "weapon_akimbo", - "sound/weapons/mk23/mk23slide.wav", - { "models/weapons2/mk23/mk23.md3", - 0, 0, 0}, -/* icon */ "icons/iconw_akimbo", -/* pickup */ "Akimbo Pistols", - 24, - IT_WEAPON, - WP_AKIMBO, -/* precache */ "", -/* sounds */ "" - }, - - -//Grenade - { - "weapon_grenade", - "sound/grenade/tink2.wav", - { "models/weapons2/grenade/grenade.md3", - 0, 0, 0}, -/* icon */ "icons/iconw_grenade", -/* pickup */ "Grenade", - 1, - IT_WEAPON, - WP_GRENADE, -/* precache */ "", -/* sounds */ "" - }, -//Blaze: 3rd Person Models -//Knife - - { - "3rd_knife", - NULL, - {"models/weapons2/knife/3rd_knife.md3",0,0,0}, - "icons/iconw_knife", - "Knife", - 1, - IT_WEAPON, - WP_KNIFE, - "", - "" - }, - -//Pistol - { - "3rd_pistol", - NULL, - { "models/weapons2/mk23/3rd_mk23.md3", - 0, 0, 0}, - "icons/iconw_mk23", - "MK23", - 12, - IT_WEAPON, - WP_PISTOL, - "", - "" - }, - -//M4 - { - "3rd_m4", - NULL, - { "models/weapons2/m4/3rd_m4.md3", - 0, 0, 0}, - "icons/iconw_m4", - "M4", - 24, - IT_WEAPON, - WP_M4, - "", - "" - }, - -//SSG3000 - { - "3rd_ssg3000", - NULL, - { "models/weapons2/ssg3000/3rd_ssg3000.md3", - 0, 0, 0}, - "icons/iconw_ssg", - "SSG3000", - 6, - IT_WEAPON, - WP_SSG3000, - "", - "" - }, - -//MP5 - { - "3rd_mp5", - NULL, - { "models/weapons2/mp5/3rd_mp5.md3", - 0, 0, 0}, - "icons/iconw_mp5", - "MP5", - 30, - IT_WEAPON, - WP_MP5, - "", - "" - }, - -//Handcannon - { - "3rd_handcannon", - NULL, - { "models/weapons2/handcannon/3rd_handcannon.md3", - 0, 0, 0}, - "icons/iconw_sawedoff", - "Hand Cannon", - 2, - IT_WEAPON, - WP_HANDCANNON, - "", - "" - }, - -//Shotgun - { - "3rd_m3", - NULL, - { "models/weapons2/shotgun/3rd_shotgun.md3", - 0, 0, 0}, - "icons/iconw_m3", - "M3 Super Shotgun", - 7, - IT_WEAPON, - WP_M3, - "", - "" - }, - -//Akimbo Placeholder - { - "3rd_akimbo", - NULL, - { "models/weapons2/mk23/3rd_mk23.md3", - 0, 0, 0}, - "icons/iconw_akimbo", - "Akimbo Pistols", - 24, - IT_WEAPON, - WP_AKIMBO, - "", - "" - }, - - -//Grenade - { - "3rd_grenade", - NULL, - { "models/weapons2/grenade/3rd_grenade.md3", - 0, 0, 0}, - "icons/iconw_grenade", - "Grenade", - 1, - IT_WEAPON, - WP_GRENADE, - "", - "" - }, - - - - // - // AMMO ITEMS - // -/*QUAKED ammo_bullets (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - { - "ammo_bullets", - "sound/misc/am_pkup.wav", - { "models/ammo/mk23.md3", - 0, 0, 0}, -/* icon */ "icons/icona_mk23clip", -/* pickup */ "MK23 Clip", - 1, - IT_AMMO, - //Blaze: Changed from WP_MACHINEGUN to WP_PISTOL - WP_PISTOL, -/* precache */ "", -/* sounds */ "" - }, - -/*QUAKED ammo_shells (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - { - "ammo_shells", - "sound/misc/am_pkup.wav", - { "models/ammo/m4.md3", - 0, 0, 0}, -/* icon */ "icons/icona_m4clip", -/* pickup */ "M4 Clip", - 1, - IT_AMMO, - //Blaze: changed from WP_SHOTGUN to WP_M4 - WP_M4, -/* precache */ "", -/* sounds */ "" - }, - - -/*QUAKED ammo_slugs (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - { - "ammo_slugs", - "sound/misc/am_pkup.wav", - { "models/ammo/ssg3000.md3", - 0, 0, 0}, -/* icon */ "icons/icona_ssgammo", -/* pickup */ "Sniper Ammo", - 10, - IT_AMMO, - //Blaze: Changed from WP_RAILGUN to WP_GRENADE - WP_SSG3000, -/* precache */ "", -/* sounds */ "" - }, - -/*QUAKED ammo_cells (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - { - "ammo_cells", - "sound/misc/am_pkup.wav", - { "models/ammo/mp5.md3", - 0, 0, 0}, -/* icon */ "icons/icona_mp5clip", -/* pickup */ "MP5 Clip", - 1, - IT_AMMO, - //Blaze: Changed from WP_PLASMAGUN to WP_MP5 - WP_MP5, -/* precache */ "", -/* sounds */ "" - }, - -/*QUAKED ammo_lightning (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ -//Blaze: HC and M3 use same ammo -// { -// "ammo_lightning", -// "sound/misc/am_pkup.wav", -// { "models/powerups/ammo/lightningam.md3", -// 0, 0, 0}, -/* icon */// "icons/icona_lightning", -/* pickup */// "Shotgun Shells", - //7, - //IT_AMMO, - //Blaze: Changed from WP_LIGHTNING to WP_HANDCANNON - //WP_HANDCANNON, -/* precache */// "", -/* sounds */ //"" -// }, - -/*QUAKED ammo_rockets (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - { - "ammo_rockets", - "sound/misc/am_pkup.wav", - { "models/ammo/m3.md3", - 0, 0, 0}, -/* icon */ "icons/icona_shells", -/* pickup */ "Shotgun Shells", - 7, - IT_AMMO, - //Blaze: Changed from WP_ROCKET_LAUNCHER to WP_SHOTGUN - WP_M3, -/* precache */ "", -/* sounds */ "" - }, - - -/*QUAKED team_CTF_redflag (1 0 0) (-16 -16 -16) (16 16 16) -Only in CTF games -*/ - { - "team_CTF_redflag", - NULL, - { "models/flags/r_flag.md3", - 0, 0, 0 }, -/* icon */ "icons/iconf_red1", -/* pickup */ "Red Flag", - 0, - IT_TEAM, - PW_REDFLAG, -/* precache */ "", -/* sounds */ "" - }, - -/*QUAKED team_CTF_blueflag (0 0 1) (-16 -16 -16) (16 16 16) -Only in CTF games -*/ - { - "team_CTF_blueflag", - NULL, - { "models/flags/b_flag.md3", - 0, 0, 0 }, -/* icon */ "icons/iconf_blu1", -/* pickup */ "Blue Flag", - 0, - IT_TEAM, - PW_BLUEFLAG, -/* precache */ "", -/* sounds */ "" - }, - -#ifdef MISSIONPACK -/*QUAKED holdable_kamikaze (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - { - "holdable_kamikaze", - "sound/items/holdable.wav", - { "models/powerups/kamikazi.md3", - 0, 0, 0}, -/* icon */ "icons/kamikaze", -/* pickup */ "Kamikaze", - 60, - IT_HOLDABLE, - HI_KAMIKAZE, -/* precache */ "", -/* sounds */ "sound/items/kamikazerespawn.wav" - }, - -/*QUAKED holdable_portal (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - { - "holdable_portal", - "sound/items/holdable.wav", - { "models/powerups/holdable/porter.md3", - 0, 0, 0}, -/* icon */ "icons/portal", -/* pickup */ "Portal", - 60, - IT_HOLDABLE, - HI_PORTAL, -/* precache */ "", -/* sounds */ "" - }, - -/*QUAKED holdable_invulnerability (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - { - "holdable_invulnerability", - "sound/items/holdable.wav", - { "models/powerups/holdable/invulnerability.md3", - 0, 0, 0}, -/* icon */ "icons/invulnerability", -/* pickup */ "Invulnerability", - 60, - IT_HOLDABLE, - HI_INVULNERABILITY, -/* precache */ "", -/* sounds */ "" - }, - -/*QUAKED ammo_nails (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - { - "ammo_nails", - "sound/misc/am_pkup.wav", - { "models/powerups/ammo/nailgunam.md3", - 0, 0, 0}, -/* icon */ "icons/icona_nailgun", -/* pickup */ "Nails", - 20, - IT_AMMO, - WP_NAILGUN, -/* precache */ "", -/* sounds */ "" - }, - -/*QUAKED ammo_mines (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - { - "ammo_mines", - "sound/misc/am_pkup.wav", - { "models/powerups/ammo/proxmineam.md3", - 0, 0, 0}, -/* icon */ "icons/icona_proxlauncher", -/* pickup */ "Proximity Mines", - 10, - IT_AMMO, - WP_PROX_LAUNCHER, -/* precache */ "", -/* sounds */ "" - }, - -/*QUAKED ammo_belt (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - { - "ammo_belt", - "sound/misc/am_pkup.wav", - { "models/powerups/ammo/chaingunam.md3", - 0, 0, 0}, -/* icon */ "icons/icona_chaingun", -/* pickup */ "Chaingun Belt", - 100, - IT_AMMO, - WP_CHAINGUN, -/* precache */ "", -/* sounds */ "" - }, - - // - // PERSISTANT POWERUP ITEMS - // -/*QUAKED item_scout (.3 .3 1) (-16 -16 -16) (16 16 16) suspended redTeam blueTeam -*/ - { - "item_scout", - "sound/items/scout.wav", - { "models/powerups/scout.md3", - 0, 0, 0 }, -/* icon */ "icons/scout", -/* pickup */ "Scout", - 30, - IT_PERSISTANT_POWERUP, - PW_SCOUT, -/* precache */ "", -/* sounds */ "" - }, - -/*QUAKED item_guard (.3 .3 1) (-16 -16 -16) (16 16 16) suspended redTeam blueTeam -*/ - { - "item_guard", - "sound/items/guard.wav", - { "models/powerups/guard.md3", - 0, 0, 0 }, -/* icon */ "icons/guard", -/* pickup */ "Guard", - 30, - IT_PERSISTANT_POWERUP, - PW_GUARD, -/* precache */ "", -/* sounds */ "" - }, - -/*QUAKED item_doubler (.3 .3 1) (-16 -16 -16) (16 16 16) suspended redTeam blueTeam -*/ - { - "item_doubler", - "sound/items/doubler.wav", - { "models/powerups/doubler.md3", - 0, 0, 0 }, -/* icon */ "icons/doubler", -/* pickup */ "Doubler", - 30, - IT_PERSISTANT_POWERUP, - PW_DOUBLER, -/* precache */ "", -/* sounds */ "" - }, - -/*QUAKED item_doubler (.3 .3 1) (-16 -16 -16) (16 16 16) suspended redTeam blueTeam -*/ - { - "item_ammoregen", - "sound/items/ammoregen.wav", - { "models/powerups/ammo.md3", - 0, 0, 0 }, -/* icon */ "icons/ammo_regen", -/* pickup */ "Ammo Regen", - 30, - IT_PERSISTANT_POWERUP, - PW_AMMOREGEN, -/* precache */ "", -/* sounds */ "" - }, - - /*QUAKED team_CTF_neutralflag (0 0 1) (-16 -16 -16) (16 16 16) -Only in One Flag CTF games -*/ - { - "team_CTF_neutralflag", - NULL, - { "models/flags/n_flag.md3", - 0, 0, 0 }, -/* icon */ "icons/iconf_neutral1", -/* pickup */ "Neutral Flag", - 0, - IT_TEAM, - PW_NEUTRALFLAG, -/* precache */ "", -/* sounds */ "" - }, - - { - "item_redcube", - "sound/misc/am_pkup.wav", - { "models/powerups/orb/r_orb.md3", - 0, 0, 0 }, -/* icon */ "icons/iconh_rorb", -/* pickup */ "Red Cube", - 0, - IT_TEAM, - 0, -/* precache */ "", -/* sounds */ "" - }, - - { - "item_bluecube", - "sound/misc/am_pkup.wav", - { "models/powerups/orb/b_orb.md3", - 0, 0, 0 }, -/* icon */ "icons/iconh_borb", -/* pickup */ "Blue Cube", - 0, - IT_TEAM, - 0, -/* precache */ "", -/* sounds */ "" - }, -/*QUAKED weapon_nailgun (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - { - "weapon_nailgun", - "sound/misc/w_pkup.wav", - { "models/weapons/nailgun/nailgun.md3", - 0, 0, 0}, -/* icon */ "icons/iconw_nailgun", -/* pickup */ "Nailgun", - 10, - IT_WEAPON, - WP_NAILGUN, -/* precache */ "", -/* sounds */ "" - }, - -/*QUAKED weapon_prox_launcher (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - { - "weapon_prox_launcher", - "sound/misc/w_pkup.wav", - { "models/weapons/proxmine/proxmine.md3", - 0, 0, 0}, -/* icon */ "icons/iconw_proxlauncher", -/* pickup */ "Prox Launcher", - 5, - IT_WEAPON, - WP_PROX_LAUNCHER, -/* precache */ "", -/* sounds */ "sound/weapons/proxmine/wstbtick.wav " - "sound/weapons/proxmine/wstbactv.wav " - "sound/weapons/proxmine/wstbimpl.wav " - "sound/weapons/proxmine/wstbimpm.wav " - "sound/weapons/proxmine/wstbimpd.wav " - "sound/weapons/proxmine/wstbactv.wav" - }, - -/*QUAKED weapon_chaingun (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - { - "weapon_chaingun", - "sound/misc/w_pkup.wav", - { "models/weapons/vulcan/vulcan.md3", - 0, 0, 0}, -/* icon */ "icons/iconw_chaingun", -/* pickup */ "Chaingun", - 80, - IT_WEAPON, - WP_CHAINGUN, -/* precache */ "", -/* sounds */ "sound/weapons/vulcan/wvulwind.wav" - }, -#endif - - // end of list marker - {NULL} -}; - -int bg_numItems = sizeof(bg_itemlist) / sizeof(bg_itemlist[0]) - 1; - - -/* -============== -BG_FindItemForPowerup -============== -*/ -gitem_t *BG_FindItemForPowerup( powerup_t pw ) { - int i; - - for ( i = 0 ; i < bg_numItems ; i++ ) { - if ( (bg_itemlist[i].giType == IT_POWERUP || - bg_itemlist[i].giType == IT_TEAM || - bg_itemlist[i].giType == IT_PERSISTANT_POWERUP) && - bg_itemlist[i].giTag == pw ) { - return &bg_itemlist[i]; - } - } - - return NULL; -} - - -/* -============== -BG_FindItemForHoldable -============== -*/ -gitem_t *BG_FindItemForHoldable( holdable_t pw ) { - int i; - - for ( i = 0 ; i < bg_numItems ; i++ ) { - if ( bg_itemlist[i].giType == IT_HOLDABLE && bg_itemlist[i].giTag == pw ) { - return &bg_itemlist[i]; - } - } - - Com_Error( ERR_DROP, "HoldableItem not found" ); - - return NULL; -} - - -/* -=============== -BG_FindItemForWeapon - -=============== -*/ -gitem_t *BG_FindItemForWeapon( weapon_t weapon ) { - gitem_t *it; - - for ( it = bg_itemlist + 1 ; it->classname ; it++) { - if ( it->giType == IT_WEAPON && it->giTag == weapon ) { - return it; - } - } - - Com_Error( ERR_DROP, "Couldn't find item for weapon %i", weapon); - return NULL; -} - -/* -=============== -BG_FindItem - -=============== -*/ -gitem_t *BG_FindItem( const char *pickupName ) { - gitem_t *it; - - for ( it = bg_itemlist + 1 ; it->classname ; it++ ) { - if ( !Q_stricmp( it->pickup_name, pickupName ) ) - return it; - } - - return NULL; -} - -/* -============ -BG_PlayerTouchesItem - -Items can be picked up without actually touching their physical bounds to make -grabbing them easier -============ -*/ -qboolean BG_PlayerTouchesItem( playerState_t *ps, entityState_t *item, int atTime ) { - vec3_t origin; - - BG_EvaluateTrajectory( &item->pos, atTime, origin ); - - // we are ignoring ducked differences here - if ( ps->origin[0] - origin[0] > 44 - || ps->origin[0] - origin[0] < -50 - || ps->origin[1] - origin[1] > 36 - || ps->origin[1] - origin[1] < -36 - || ps->origin[2] - origin[2] > 36 - || ps->origin[2] - origin[2] < -36 ) { - return qfalse; - } - - return qtrue; -} - - -/* -================== - ClipAmountForWeapon for Cmd_Reload - Added by Duffman - Returns the amount of ammo a weapon can hold -================== -*/ - - -int ClipAmountForWeapon( int w ) { - //How much each clip holds - switch(w){ - case WP_PISTOL: - return 12; - case WP_KNIFE: - return 1; - case WP_M4: - return 24; - case WP_SSG3000: - return 1; - case WP_MP5: - return 30; - case WP_HANDCANNON: - return 2; - case WP_M3: - return 1; - case WP_AKIMBO: - return 24; - case WP_GRENADE: - return 1; - default: - return 12; - } -// return 12; //this wont happen unless you copy-and-paste too much -} - -/* -================ -BG_CanItemBeGrabbed - -Returns false if the item should not be picked up. -This needs to be the same for client side prediction and server use. -================ -*/ - - -qboolean BG_CanItemBeGrabbed( int gametype, const entityState_t *ent, const playerState_t *ps ) { - gitem_t *item; -#ifdef MISSIONPACK - int upperBound; -#endif - - if ( ent->modelindex < 1 || ent->modelindex >= bg_numItems ) { - Com_Error( ERR_DROP, "BG_CanItemBeGrabbed: index out of range" ); - } - - item = &bg_itemlist[ent->modelindex]; - - switch( item->giType ) { - case IT_WEAPON: - return qtrue; // weapons are always picked up - - case IT_AMMO: - - //Blaze: pick up all ammo - //Blaze: make sure you dont go over max amount of clips - //if ( ps->stats[STAT_CLIPS] >= 2) - //if ( ps->ammo[ item->giTag ] >= ClipAmountForWeapon(item->giTag )) { - //{ - // return qfalse; // can't hold any more - //} - return qtrue; - - case IT_ARMOR: -#ifdef MISSIONPACK - if( bg_itemlist[ps->stats[STAT_PERSISTANT_POWERUP]].giTag == PW_SCOUT ) { - return qfalse; - } - - // we also clamp armor to the maxhealth for handicapping - if( bg_itemlist[ps->stats[STAT_PERSISTANT_POWERUP]].giTag == PW_GUARD ) { - upperBound = ps->stats[STAT_MAX_HEALTH]; - } - else { - upperBound = ps->stats[STAT_MAX_HEALTH] * 2; - } - - if ( ps->stats[STAT_ARMOR] >= upperBound ) { - return qfalse; - } -#else - if ( ps->stats[STAT_ARMOR] >= ps->stats[STAT_MAX_HEALTH] * 2 ) { - return qfalse; - } -#endif - return qtrue; - - case IT_HEALTH: - // small and mega healths will go over the max, otherwise - // don't pick up if already at max -#ifdef MISSIONPACK - if( bg_itemlist[ps->stats[STAT_PERSISTANT_POWERUP]].giTag == PW_GUARD ) { - upperBound = ps->stats[STAT_MAX_HEALTH]; - } - else -#endif - if ( item->quantity == 5 || item->quantity == 100 ) { - if ( ps->stats[STAT_HEALTH] >= ps->stats[STAT_MAX_HEALTH] * 2 ) { - return qfalse; - } - return qtrue; - } - - if ( ps->stats[STAT_HEALTH] >= ps->stats[STAT_MAX_HEALTH] ) { - return qfalse; - } - return qtrue; - - case IT_POWERUP: - return qtrue; // powerups are always picked up - -#ifdef MISSIONPACK - case IT_PERSISTANT_POWERUP: - // can only hold one item at a time - if ( ps->stats[STAT_PERSISTANT_POWERUP] ) { - return qfalse; - } - - // check team only - if( ( ent->generic1 & 2 ) && ( ps->persistant[PERS_TEAM] != TEAM_RED ) ) { - return qfalse; - } - if( ( ent->generic1 & 4 ) && ( ps->persistant[PERS_TEAM] != TEAM_BLUE ) ) { - return qfalse; - } - - return qtrue; -#endif - - case IT_TEAM: // team items, such as flags -#ifdef MISSIONPACK - if( gametype == GT_1FCTF ) { - // neutral flag can always be picked up - if( item->giTag == PW_NEUTRALFLAG ) { - return qtrue; - } - if (ps->persistant[PERS_TEAM] == TEAM_RED) { - if (item->giTag == PW_BLUEFLAG && ps->powerups[PW_NEUTRALFLAG] ) { - return qtrue; - } - } else if (ps->persistant[PERS_TEAM] == TEAM_BLUE) { - if (item->giTag == PW_REDFLAG && ps->powerups[PW_NEUTRALFLAG] ) { - return qtrue; - } - } - } -#endif - if( gametype == GT_CTF ) { - // ent->modelindex2 is non-zero on items if they are dropped - // we need to know this because we can pick up our dropped flag (and return it) - // but we can't pick up our flag at base - if (ps->persistant[PERS_TEAM] == TEAM_RED) { - if (item->giTag == PW_BLUEFLAG || - (item->giTag == PW_REDFLAG && ent->modelindex2) || - (item->giTag == PW_REDFLAG && ps->powerups[PW_BLUEFLAG])) - return qtrue; - } else if (ps->persistant[PERS_TEAM] == TEAM_BLUE) { - if (item->giTag == PW_REDFLAG || - (item->giTag == PW_BLUEFLAG && ent->modelindex2) || - (item->giTag == PW_BLUEFLAG && ps->powerups[PW_REDFLAG])) - return qtrue; - } - } - -#ifdef MISSIONPACK - if( gametype == GT_HARVESTER ) { - return qtrue; - } -#endif - return qfalse; - - case IT_HOLDABLE: - // can only hold one item at a time - if ( ps->stats[STAT_HOLDABLE_ITEM] ) { - return qfalse; - } - return qtrue; - - case IT_BAD: - Com_Error( ERR_DROP, "BG_CanItemBeGrabbed: IT_BAD" ); - } - - return qfalse; -} - -//====================================================================== - -/* -================ -BG_EvaluateTrajectory - -================ -*/ -void BG_EvaluateTrajectory( const trajectory_t *tr, int atTime, vec3_t result ) { - float deltaTime; - float phase; - - switch( tr->trType ) { - case TR_STATIONARY: - case TR_INTERPOLATE: - VectorCopy( tr->trBase, result ); - break; - case TR_LINEAR: - deltaTime = ( atTime - tr->trTime ) * 0.001; // milliseconds to seconds - VectorMA( tr->trBase, deltaTime, tr->trDelta, result ); - break; - case TR_SINE: - deltaTime = ( atTime - tr->trTime ) / (float) tr->trDuration; - phase = sin( deltaTime * M_PI * 2 ); - VectorMA( tr->trBase, phase, tr->trDelta, result ); - break; - case TR_LINEAR_STOP: - if ( atTime > tr->trTime + tr->trDuration ) { - atTime = tr->trTime + tr->trDuration; - } - deltaTime = ( atTime - tr->trTime ) * 0.001; // milliseconds to seconds - if ( deltaTime < 0 ) { - deltaTime = 0; - } - VectorMA( tr->trBase, deltaTime, tr->trDelta, result ); - break; - case TR_GRAVITY: - deltaTime = ( atTime - tr->trTime ) * 0.001; // milliseconds to seconds - VectorMA( tr->trBase, deltaTime, tr->trDelta, result ); - result[2] -= 0.5 * DEFAULT_GRAVITY * deltaTime * deltaTime; // FIXME: local gravity... - break; - default: - Com_Error( ERR_DROP, "BG_EvaluateTrajectory: unknown trType: %i", tr->trTime ); - break; - } -} - -/* -================ -BG_EvaluateTrajectoryDelta - -For determining velocity at a given time -================ -*/ -void BG_EvaluateTrajectoryDelta( const trajectory_t *tr, int atTime, vec3_t result ) { - float deltaTime; - float phase; - - switch( tr->trType ) { - case TR_STATIONARY: - case TR_INTERPOLATE: - VectorClear( result ); - break; - case TR_LINEAR: - VectorCopy( tr->trDelta, result ); - break; - case TR_SINE: - deltaTime = ( atTime - tr->trTime ) / (float) tr->trDuration; - phase = cos( deltaTime * M_PI * 2 ); // derivative of sin = cos - phase *= 0.5; - VectorScale( tr->trDelta, phase, result ); - break; - case TR_LINEAR_STOP: - if ( atTime > tr->trTime + tr->trDuration ) { - VectorClear( result ); - return; - } - VectorCopy( tr->trDelta, result ); - break; - case TR_GRAVITY: - deltaTime = ( atTime - tr->trTime ) * 0.001; // milliseconds to seconds - VectorCopy( tr->trDelta, result ); - result[2] -= DEFAULT_GRAVITY * deltaTime; // FIXME: local gravity... - break; - default: - Com_Error( ERR_DROP, "BG_EvaluateTrajectoryDelta: unknown trType: %i", tr->trTime ); - break; - } -} - -char *eventnames[] = { - "EV_NONE", - - "EV_FOOTSTEP", - "EV_FOOTSTEP_METAL", - "EV_FOOTSPLASH", - "EV_FOOTWADE", - "EV_SWIM", - - "EV_STEP_4", - "EV_STEP_8", - "EV_STEP_12", - "EV_STEP_16", - - "EV_FALL_SHORT", - "EV_FALL_MEDIUM", - "EV_FALL_FAR", - - "EV_JUMP_PAD", // boing sound at origin", jump sound on player - - "EV_JUMP", - "EV_WATER_TOUCH", // foot touches - "EV_WATER_LEAVE", // foot leaves - "EV_WATER_UNDER", // head touches - "EV_WATER_CLEAR", // head leaves - - "EV_ITEM_PICKUP", // normal item pickups are predictable - "EV_GLOBAL_ITEM_PICKUP", // powerup / team sounds are broadcast to everyone - - "EV_NOAMMO", - "EV_CHANGE_WEAPON", - "EV_FIRE_WEAPON", - - "EV_USE_ITEM0", - "EV_USE_ITEM1", - "EV_USE_ITEM2", - "EV_USE_ITEM3", - "EV_USE_ITEM4", - "EV_USE_ITEM5", - "EV_USE_ITEM6", - "EV_USE_ITEM7", - "EV_USE_ITEM8", - "EV_USE_ITEM9", - "EV_USE_ITEM10", - "EV_USE_ITEM11", - "EV_USE_ITEM12", - "EV_USE_ITEM13", - "EV_USE_ITEM14", - "EV_USE_ITEM15", - - "EV_ITEM_RESPAWN", - "EV_ITEM_POP", - "EV_PLAYER_TELEPORT_IN", - "EV_PLAYER_TELEPORT_OUT", - - "EV_GRENADE_BOUNCE", // eventParm will be the soundindex - - "EV_GENERAL_SOUND", - "EV_GLOBAL_SOUND", // no attenuation - "EV_GLOBAL_TEAM_SOUND", - - "EV_BULLET_HIT_FLESH", - "EV_BULLET_HIT_WALL", - - "EV_MISSILE_HIT", - "EV_MISSILE_MISS", - "EV_MISSILE_MISS_METAL", - "EV_RAILTRAIL", - "EV_SHOTGUN", - "EV_HANDCANNON", - "EV_BULLET", // otherEntity is the shooter - - "EV_PAIN", - "EV_DEATH1", - "EV_DEATH2", - "EV_DEATH3", - "EV_OBITUARY", - - "EV_POWERUP_QUAD", - "EV_POWERUP_BATTLESUIT", - "EV_POWERUP_REGEN", - - "EV_GIB_PLAYER", // gib a previously living player - "EV_SCOREPLUM", // score plum - -//#ifdef MISSIONPACK - "EV_PROXIMITY_MINE_STICK", - "EV_PROXIMITY_MINE_TRIGGER", - "EV_KAMIKAZE", // kamikaze explodes - "EV_OBELISKEXPLODE", // obelisk explodes - "EV_INVUL_IMPACT", // invulnerability sphere impact - "EV_JUICED", // invulnerability juiced effect - "EV_LIGHTNINGBOLT", // lightning bolt bounced of invulnerability sphere -//#endif - - "EV_DEBUG_LINE", - "EV_STOPLOOPINGSOUND", - "EV_TAUNT" - -}; - -/* -=============== -BG_AddPredictableEventToPlayerstate - -Handles the sequence numbers -=============== -*/ - -void trap_Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize ); - -void BG_AddPredictableEventToPlayerstate( int newEvent, int eventParm, playerState_t *ps ) { - -#ifdef _DEBUG - { - char buf[256]; - trap_Cvar_VariableStringBuffer("showevents", buf, sizeof(buf)); - if ( atof(buf) != 0 ) { -#ifdef QAGAME - Com_Printf(" game event svt %5d -> %5d: num = %20s parm %d\n", ps->pmove_framecount/*ps->commandTime*/, ps->eventSequence, eventnames[newEvent], eventParm); -#else - Com_Printf("Cgame event svt %5d -> %5d: num = %20s parm %d\n", ps->pmove_framecount/*ps->commandTime*/, ps->eventSequence, eventnames[newEvent], eventParm); -#endif - } - } -#endif - ps->events[ps->eventSequence & (MAX_PS_EVENTS-1)] = newEvent; - ps->eventParms[ps->eventSequence & (MAX_PS_EVENTS-1)] = eventParm; - ps->eventSequence++; -} - -/* -======================== -BG_TouchJumpPad -======================== -*/ -void BG_TouchJumpPad( playerState_t *ps, entityState_t *jumppad ) { - vec3_t angles; - float p; - int effectNum; - - // spectators don't use jump pads - if ( ps->pm_type != PM_NORMAL ) { - return; - } - - // flying characters don't hit bounce pads - if ( ps->powerups[PW_FLIGHT] ) { - return; - } - - // if we didn't hit this same jumppad the previous frame - // then don't play the event sound again if we are in a fat trigger - if ( ps->jumppad_ent != jumppad->number ) { - - vectoangles( jumppad->origin2, angles); - p = fabs( AngleNormalize180( angles[PITCH] ) ); - if( p < 45 ) { - effectNum = 0; - } else { - effectNum = 1; - } - BG_AddPredictableEventToPlayerstate( EV_JUMP_PAD, effectNum, ps ); - } - // remember hitting this jumppad this frame - ps->jumppad_ent = jumppad->number; - ps->jumppad_frame = ps->pmove_framecount; - // give the player the velocity from the jumppad - VectorCopy( jumppad->origin2, ps->velocity ); -} - -/* -======================== -BG_PlayerStateToEntityState - -This is done after each set of usercmd_t on the server, -and after local prediction on the client -======================== -*/ -void BG_PlayerStateToEntityState( playerState_t *ps, entityState_t *s, qboolean snap ) { - int i; - - if ( ps->pm_type == PM_INTERMISSION || ps->pm_type == PM_SPECTATOR ) { - s->eType = ET_INVISIBLE; - } else if ( ps->stats[STAT_HEALTH] <= GIB_HEALTH ) { - s->eType = ET_INVISIBLE; - } else { - s->eType = ET_PLAYER; - } - - s->number = ps->clientNum; - - s->pos.trType = TR_INTERPOLATE; - VectorCopy( ps->origin, s->pos.trBase ); - if ( snap ) { - SnapVector( s->pos.trBase ); - } - // set the trDelta for flag direction - VectorCopy( ps->velocity, s->pos.trDelta ); - - s->apos.trType = TR_INTERPOLATE; - VectorCopy( ps->viewangles, s->apos.trBase ); - if ( snap ) { - SnapVector( s->apos.trBase ); - } - - s->angles2[YAW] = ps->movementDir; - s->legsAnim = ps->legsAnim; - s->torsoAnim = ps->torsoAnim; - s->clientNum = ps->clientNum; // ET_PLAYER looks here instead of at number - // so corpses can also reference the proper config - s->eFlags = ps->eFlags; - if ( ps->stats[STAT_HEALTH] <= 0 ) { - s->eFlags |= EF_DEAD; - } else { - s->eFlags &= ~EF_DEAD; - } - - if ( ps->externalEvent ) { - s->event = ps->externalEvent; - s->eventParm = ps->externalEventParm; - } else { - int seq; - - if ( ps->entityEventSequence < ps->eventSequence - MAX_PS_EVENTS) { - ps->entityEventSequence = ps->eventSequence - MAX_PS_EVENTS; - } - seq = (ps->entityEventSequence-1) & (MAX_PS_EVENTS-1); - s->event = ps->events[ seq ] | ( ( ps->entityEventSequence & 3 ) << 8 ); - s->eventParm = ps->eventParms[ seq ]; - if ( ps->entityEventSequence < ps->eventSequence ) { - ps->entityEventSequence++; - } - } - - s->weapon = ps->weapon; - s->groundEntityNum = ps->groundEntityNum; - - s->powerups = 0; - for ( i = 0 ; i < MAX_POWERUPS ; i++ ) { - if ( ps->powerups[ i ] ) { - s->powerups |= 1 << i; - } - } - - s->loopSound = ps->loopSound; - s->generic1 = ps->generic1; -} - -/* -======================== -BG_PlayerStateToEntityStateExtraPolate - -This is done after each set of usercmd_t on the server, -and after local prediction on the client -======================== -*/ -void BG_PlayerStateToEntityStateExtraPolate( playerState_t *ps, entityState_t *s, int time, qboolean snap ) { - int i; - - if ( ps->pm_type == PM_INTERMISSION || ps->pm_type == PM_SPECTATOR ) { - s->eType = ET_INVISIBLE; - } else if ( ps->stats[STAT_HEALTH] <= GIB_HEALTH ) { - s->eType = ET_INVISIBLE; - } else { - s->eType = ET_PLAYER; - } - - s->number = ps->clientNum; - - s->pos.trType = TR_LINEAR_STOP; - VectorCopy( ps->origin, s->pos.trBase ); - if ( snap ) { - SnapVector( s->pos.trBase ); - } - // set the trDelta for flag direction and linear prediction - VectorCopy( ps->velocity, s->pos.trDelta ); - // set the time for linear prediction - s->pos.trTime = time; - // set maximum extra polation time - s->pos.trDuration = 50; // 1000 / sv_fps (default = 20) - - s->apos.trType = TR_INTERPOLATE; - VectorCopy( ps->viewangles, s->apos.trBase ); - if ( snap ) { - SnapVector( s->apos.trBase ); - } - - s->angles2[YAW] = ps->movementDir; - s->legsAnim = ps->legsAnim; - s->torsoAnim = ps->torsoAnim; - s->clientNum = ps->clientNum; // ET_PLAYER looks here instead of at number - // so corpses can also reference the proper config - s->eFlags = ps->eFlags; - if ( ps->stats[STAT_HEALTH] <= 0 ) { - s->eFlags |= EF_DEAD; - } else { - s->eFlags &= ~EF_DEAD; - } - - if ( ps->externalEvent ) { - s->event = ps->externalEvent; - s->eventParm = ps->externalEventParm; - } else { - int seq; - - if ( ps->entityEventSequence < ps->eventSequence - MAX_PS_EVENTS) { - ps->entityEventSequence = ps->eventSequence - MAX_PS_EVENTS; - } - seq = (ps->entityEventSequence-1) & (MAX_PS_EVENTS-1); - s->event = ps->events[ seq ] | ( ( ps->entityEventSequence & 3 ) << 8 ); - s->eventParm = ps->eventParms[ seq ]; - if ( ps->entityEventSequence < ps->eventSequence ) { - ps->entityEventSequence++; - } - } - - s->weapon = ps->weapon; - s->groundEntityNum = ps->groundEntityNum; - - s->powerups = 0; - for ( i = 0 ; i < MAX_POWERUPS ; i++ ) { - if ( ps->powerups[ i ] ) { - s->powerups |= 1 << i; - } - } - - s->loopSound = ps->loopSound; - s->generic1 = ps->generic1; -} diff --git a/reaction/game/.#bg_public.h.1.11 b/reaction/game/.#bg_public.h.1.11 deleted file mode 100644 index 8c96b48d..00000000 --- a/reaction/game/.#bg_public.h.1.11 +++ /dev/null @@ -1,766 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// -// bg_public.h -- definitions shared by both the server game and client game modules - -// because games can change separately from the main system version, we need a -// second version that must match between game and cgame - -#define GAME_VERSION "baseq3-1" - -#define DEFAULT_GRAVITY 800 -#define GIB_HEALTH -40 -#define ARMOR_PROTECTION 0.66 - -#define MAX_ITEMS 256 - -#define RANK_TIED_FLAG 0x4000 - -#define DEFAULT_SHOTGUN_SPREAD 700 -#define DEFAULT_HANDCANNON_SPREAD 1400 -#define DEFAULT_SHOTGUN_COUNT 11 - -#define ITEM_RADIUS 15 // item sizes are needed for client side pickup detection - -#define LIGHTNING_RANGE 768 -//Blaze: Distance the knife reaches -#define KNIFE_RANGE 45 - -#define SCORE_NOT_PRESENT -9999 // for the CS_SCORES[12] when only one player is present - -#define VOTE_TIME 30000 // 30 seconds before vote times out - -#define MINS_Z -24 -#define DEFAULT_VIEWHEIGHT 26 -#define CROUCH_VIEWHEIGHT 12 -#define DEAD_VIEWHEIGHT -16 - -// -// config strings are a general means of communicating variable length strings -// from the server to all connected clients. -// - -// CS_SERVERINFO and CS_SYSTEMINFO are defined in q_shared.h -#define CS_MUSIC 2 -#define CS_MESSAGE 3 // from the map worldspawn's message field -#define CS_MOTD 4 // g_motd string for server message of the day -#define CS_WARMUP 5 // server time when the match will be restarted -#define CS_SCORES1 6 -#define CS_SCORES2 7 -#define CS_VOTE_TIME 8 -#define CS_VOTE_STRING 9 -#define CS_VOTE_YES 10 -#define CS_VOTE_NO 11 - -#define CS_TEAMVOTE_TIME 12 -#define CS_TEAMVOTE_STRING 14 -#define CS_TEAMVOTE_YES 16 -#define CS_TEAMVOTE_NO 18 - -#define CS_GAME_VERSION 20 -#define CS_LEVEL_START_TIME 21 // so the timer only shows the current level -#define CS_INTERMISSION 22 // when 1, fraglimit/timelimit has been hit and intermission will start in a second or two -#define CS_FLAGSTATUS 23 // string indicating flag status in CTF -#define CS_SHADERSTATE 24 -#define CS_BOTINFO 25 - -#define CS_ITEMS 27 // string of 0's and 1's that tell which items are present - -#define CS_MODELS 32 -#define CS_SOUNDS (CS_MODELS+MAX_MODELS) -#define CS_PLAYERS (CS_SOUNDS+MAX_SOUNDS) -#define CS_LOCATIONS (CS_PLAYERS+MAX_CLIENTS) - -#define CS_MAX (CS_LOCATIONS+MAX_LOCATIONS) - -#if (CS_MAX) > MAX_CONFIGSTRINGS -#error overflow: (CS_MAX) > MAX_CONFIGSTRINGS -#endif - -typedef enum { - GT_FFA, // free for all - GT_TOURNAMENT, // one on one tournament - GT_SINGLE_PLAYER, // single player ffa - - //-- team games go after this -- - - GT_TEAM, // team deathmatch - GT_CTF, // capture the flag - GT_1FCTF, - GT_OBELISK, - GT_HARVESTER, - GT_MAX_GAME_TYPE -} gametype_t; - -typedef enum { GENDER_MALE, GENDER_FEMALE, GENDER_NEUTER } gender_t; - -/* -=================================================================================== - -PMOVE MODULE - -The pmove code takes a player_state_t and a usercmd_t and generates a new player_state_t -and some other output data. Used for local prediction on the client game and true -movement on the server game. -=================================================================================== -*/ - -typedef enum { - PM_NORMAL, // can accelerate and turn - PM_NOCLIP, // noclip movement - PM_SPECTATOR, // still run into walls - PM_DEAD, // no acceleration or turning, but free falling - PM_FREEZE, // stuck in place with no control - PM_INTERMISSION, // no movement or status bar - PM_SPINTERMISSION // no movement or status bar -} pmtype_t; - -typedef enum { - WEAPON_READY, - WEAPON_RAISING, - WEAPON_DROPPING, - WEAPON_FIRING//, - //WEAPON_RELOADING -} weaponstate_t; - -// pmove->pm_flags -#define PMF_DUCKED 1 -#define PMF_JUMP_HELD 2 -#define PMF_BACKWARDS_JUMP 8 // go into backwards land -#define PMF_BACKWARDS_RUN 16 // coast down to backwards run -#define PMF_TIME_LAND 32 // pm_time is time before rejump -#define PMF_TIME_KNOCKBACK 64 // pm_time is an air-accelerate only time -#define PMF_TIME_WATERJUMP 256 // pm_time is waterjump -#define PMF_RESPAWNED 512 // clear after attack and jump buttons come up -#define PMF_USE_ITEM_HELD 1024 -#define PMF_GRAPPLE_PULL 2048 // pull towards grapple location -#define PMF_FOLLOW 4096 // spectate following another player -#define PMF_SCOREBOARD 8192 // spectate as a scoreboard -#define PMF_INVULEXPAND 16384 // invulnerability sphere set to full size - -#define PMF_ALL_TIMES (PMF_TIME_WATERJUMP|PMF_TIME_LAND|PMF_TIME_KNOCKBACK) - -#define MAXTOUCH 32 -typedef struct { - // state (in / out) - playerState_t *ps; - - // command (in) - usercmd_t cmd; - int tracemask; // collide against these types of surfaces - int debugLevel; // if set, diagnostic output will be printed - qboolean noFootsteps; // if the game is setup for no footsteps by the server - qboolean gauntletHit; // true if a gauntlet attack would actually hit something - - int framecount; - - // results (out) - int numtouch; - int touchents[MAXTOUCH]; - - vec3_t mins, maxs; // bounding box size - - int watertype; - int waterlevel; - - float xyspeed; - - // for fixed msec Pmove - int pmove_fixed; - int pmove_msec; - - // callbacks to test the world - // these will be different functions during game and cgame - void (*trace)( trace_t *results, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int passEntityNum, int contentMask ); - int (*pointcontents)( const vec3_t point, int passEntityNum ); -} pmove_t; - -// if a full pmove isn't done on the client, you can just update the angles -void PM_UpdateViewAngles( playerState_t *ps, const usercmd_t *cmd ); -void Pmove (pmove_t *pmove); - -//=================================================================================== - - -// player_state->stats[] indexes -// NOTE: may not have more than 16 -typedef enum { - STAT_HEALTH, - STAT_HOLDABLE_ITEM, -#ifdef MISSIONPACK - STAT_PERSISTANT_POWERUP, -#endif - STAT_WEAPONS, // 16 bit fields - STAT_ARMOR, - STAT_DEAD_YAW, // look this direction when dead (FIXME: get rid of?) -// Begin Duffman - STAT_CLIPS, // Num Clips player currently has -// End Duffman - STAT_CLIENTS_READY, // bit mask of clients wishing to exit the intermission (FIXME: configstring?) - STAT_MAX_HEALTH, // health / armor limit, changable by handicap - STAT_JUMPTIME, //Blaze RE: Double jump - STAT_UNIQUEWEAPONS, -} statIndex_t; - - -// player_state->persistant[] indexes -// these fields are the only part of player_state that isn't -// cleared on respawn -// NOTE: may not have more than 16 -typedef enum { - PERS_SCORE, // !!! MUST NOT CHANGE, SERVER AND GAME BOTH REFERENCE !!! - PERS_HITS, // total points damage inflicted so damage beeps can sound on change - PERS_RANK, // player rank or team rank - PERS_TEAM, // player team - PERS_SPAWN_COUNT, // incremented every respawn - PERS_PLAYEREVENTS, // 16 bits that can be flipped for events - PERS_ATTACKER, // clientnum of last damage inflicter - PERS_ATTACKEE_ARMOR, // health/armor of last person we attacked - PERS_KILLED, // count of the number of times you died - // player awards tracking - PERS_IMPRESSIVE_COUNT, // two railgun hits in a row - PERS_EXCELLENT_COUNT, // two successive kills in a short amount of time - PERS_DEFEND_COUNT, // defend awards - PERS_ASSIST_COUNT, // assist awards - PERS_GAUNTLET_FRAG_COUNT, // kills with the guantlet - PERS_CAPTURES // captures -} persEnum_t; - - -// entityState_t->eFlags -#define EF_DEAD 0x00000001 // don't draw a foe marker over players with EF_DEAD -#ifdef MISSIONPACK -#define EF_TICKING 0x00000002 // used to make players play the prox mine ticking sound -#endif -#define EF_TELEPORT_BIT 0x00000004 // toggled every time the origin abruptly changes -#define EF_AWARD_EXCELLENT 0x00000008 // draw an excellent sprite -#define EF_BOUNCE 0x00000010 // for missiles -#define EF_BOUNCE_HALF 0x00000020 // for missiles -#define EF_AWARD_GAUNTLET 0x00000040 // draw a gauntlet sprite -#define EF_NODRAW 0x00000080 // may have an event, but no model (unspawned items) -#define EF_FIRING 0x00000100 // for lightning gun -#define EF_KAMIKAZE 0x00000200 -#define EF_MOVER_STOP 0x00000400 // will push otherwise -#define EF_AWARD_CAP 0x00000800 // draw the capture sprite -#define EF_TALK 0x00001000 // draw a talk balloon -#define EF_CONNECTION 0x00002000 // draw a connection trouble sprite -#define EF_VOTED 0x00004000 // already cast a vote -#define EF_AWARD_IMPRESSIVE 0x00008000 // draw an impressive sprite -#define EF_AWARD_DEFEND 0x00010000 // draw a defend sprite -#define EF_AWARD_ASSIST 0x00020000 // draw a assist sprite -#define EF_AWARD_DENIED 0x00040000 // denied -#define EF_TEAMVOTED 0x00080000 // already cast a team vote - -// NOTE: may not have more than 16 -typedef enum { - PW_NONE, - - PW_QUAD, - PW_BATTLESUIT, - PW_HASTE, - PW_INVIS, - PW_REGEN, - PW_FLIGHT, - - PW_REDFLAG, - PW_BLUEFLAG, - PW_NEUTRALFLAG, - - PW_SCOUT, - PW_GUARD, - PW_DOUBLER, - PW_AMMOREGEN, - PW_INVULNERABILITY, - - PW_NUM_POWERUPS - -} powerup_t; - -typedef enum { - HI_NONE, - - HI_TELEPORTER, - HI_MEDKIT, - HI_KAMIKAZE, - HI_PORTAL, - HI_INVULNERABILITY, - - HI_NUM_HOLDABLE -} holdable_t; - - -typedef enum { - WP_NONE, -//Blaze: Reaction Weapons -//Remember to put them in the right spots - WP_KNIFE, - WP_PISTOL, - WP_M4, - WP_SSG3000, - WP_MP5, - WP_M3, - WP_HANDCANNON, - WP_AKIMBO, - WP_GRENADE, -#ifdef MISSIONPACK - WP_NAILGUN, - WP_PROX_LAUNCHER, - WP_CHAINGUN, -#endif - - WP_NUM_WEAPONS -} weapon_t; - - -// reward sounds (stored in ps->persistant[PERS_PLAYEREVENTS]) -#define PLAYEREVENT_DENIEDREWARD 0x0001 -#define PLAYEREVENT_GAUNTLETREWARD 0x0002 -#define PLAYEREVENT_HOLYSHIT 0x0004 - -// entityState_t->event values -// entity events are for effects that take place reletive -// to an existing entities origin. Very network efficient. - -// two bits at the top of the entityState->event field -// will be incremented with each change in the event so -// that an identical event started twice in a row can -// be distinguished. And off the value with ~EV_EVENT_BITS -// to retrieve the actual event number -#define EV_EVENT_BIT1 0x00000100 -#define EV_EVENT_BIT2 0x00000200 -#define EV_EVENT_BITS (EV_EVENT_BIT1|EV_EVENT_BIT2) - -typedef enum { - EV_NONE, - - EV_FOOTSTEP, - EV_FOOTSTEP_METAL, - EV_FOOTSPLASH, - EV_FOOTWADE, - EV_SWIM, - - EV_STEP_4, - EV_STEP_8, - EV_STEP_12, - EV_STEP_16, - - EV_FALL_SHORT, - EV_FALL_MEDIUM, - EV_FALL_FAR, - - EV_JUMP_PAD, // boing sound at origin, jump sound on player - - EV_JUMP, - EV_WATER_TOUCH, // foot touches - EV_WATER_LEAVE, // foot leaves - EV_WATER_UNDER, // head touches - EV_WATER_CLEAR, // head leaves - - EV_ITEM_PICKUP, // normal item pickups are predictable - EV_GLOBAL_ITEM_PICKUP, // powerup / team sounds are broadcast to everyone - - EV_NOAMMO, - EV_CHANGE_WEAPON, - EV_FIRE_WEAPON, - - EV_USE_ITEM0, - EV_USE_ITEM1, - EV_USE_ITEM2, - EV_USE_ITEM3, - EV_USE_ITEM4, - EV_USE_ITEM5, - EV_USE_ITEM6, - EV_USE_ITEM7, - EV_USE_ITEM8, - EV_USE_ITEM9, - EV_USE_ITEM10, - EV_USE_ITEM11, - EV_USE_ITEM12, - EV_USE_ITEM13, - EV_USE_ITEM14, - EV_USE_ITEM15, - - EV_ITEM_RESPAWN, - EV_ITEM_POP, - EV_PLAYER_TELEPORT_IN, - EV_PLAYER_TELEPORT_OUT, - - EV_GRENADE_BOUNCE, // eventParm will be the soundindex - - EV_GENERAL_SOUND, - EV_GLOBAL_SOUND, // no attenuation - EV_GLOBAL_TEAM_SOUND, - - EV_BULLET_HIT_FLESH, - EV_BULLET_HIT_WALL, - - EV_MISSILE_HIT, - EV_MISSILE_MISS, - EV_MISSILE_MISS_METAL, - EV_RAILTRAIL, - EV_SHOTGUN, - EV_HANDCANNON, - EV_BULLET, // otherEntity is the shooter - - EV_PAIN, - EV_DEATH1, - EV_DEATH2, - EV_DEATH3, - EV_OBITUARY, - - EV_POWERUP_QUAD, - EV_POWERUP_BATTLESUIT, - EV_POWERUP_REGEN, - - EV_GIB_PLAYER, // gib a previously living player - EV_BREAK_GLASS, // Blaze: Breakable glass - EV_SCOREPLUM, // score plum - -//#ifdef MISSIONPACK - EV_PROXIMITY_MINE_STICK, - EV_PROXIMITY_MINE_TRIGGER, - EV_KAMIKAZE, // kamikaze explodes - EV_OBELISKEXPLODE, // obelisk explodes - EV_OBELISKPAIN, // obelisk is in pain - EV_INVUL_IMPACT, // invulnerability sphere impact - EV_JUICED, // invulnerability juiced effect - EV_LIGHTNINGBOLT, // lightning bolt bounced of invulnerability sphere -//#endif - - EV_DEBUG_LINE, - EV_STOPLOOPINGSOUND, - EV_TAUNT, - EV_TAUNT_YES, - EV_TAUNT_NO, - EV_TAUNT_FOLLOWME, - EV_TAUNT_GETFLAG, - EV_TAUNT_GUARDBASE, - EV_TAUNT_PATROL - -} entity_event_t; - - -typedef enum { - GTS_RED_CAPTURE, - GTS_BLUE_CAPTURE, - GTS_RED_RETURN, - GTS_BLUE_RETURN, - GTS_RED_TAKEN, - GTS_BLUE_TAKEN, - GTS_REDOBELISK_ATTACKED, - GTS_BLUEOBELISK_ATTACKED, - GTS_REDTEAM_SCORED, - GTS_BLUETEAM_SCORED, - GTS_REDTEAM_TOOK_LEAD, - GTS_BLUETEAM_TOOK_LEAD, - GTS_TEAMS_ARE_TIED, - GTS_KAMIKAZE -} global_team_sound_t; - -// animations -typedef enum { - BOTH_DEATH1, - BOTH_DEAD1, - BOTH_DEATH2, - BOTH_DEAD2, - BOTH_DEATH3, - BOTH_DEAD3, - - TORSO_GESTURE, - - TORSO_ATTACK, - TORSO_ATTACK2, - - TORSO_DROP, - TORSO_RAISE, - - TORSO_STAND, - TORSO_STAND2, - - LEGS_WALKCR, - LEGS_WALK, - LEGS_RUN, - LEGS_BACK, - LEGS_SWIM, - - LEGS_JUMP, - LEGS_LAND, - - LEGS_JUMPB, - LEGS_LANDB, - - LEGS_IDLE, - LEGS_IDLECR, - - LEGS_TURN, -//Blaze: Weapon reload animation -// WEAPON_RELOAD, - -#ifdef NEW_ANIMS - TORSO_GETFLAG, - TORSO_GUARDBASE, - TORSO_PATROL, - TORSO_FOLLOWME, - TORSO_AFFIRMATIVE, - TORSO_NEGATIVE, -#endif - - MAX_ANIMATIONS, - - LEGS_BACKCR, - LEGS_BACKWALK, - FLAG_RUN, - FLAG_STAND, - FLAG_STAND2RUN, - - MAX_TOTALANIMATIONS -} animNumber_t; - - -typedef struct animation_s { - int firstFrame; - int numFrames; - int loopFrames; // 0 to numFrames - int frameLerp; // msec between frames - int initialLerp; // msec to get to first frame - int reversed; // true if animation is reversed - int flipflop; // true if animation should flipflop back to base -} animation_t; - - -// flip the togglebit every time an animation -// changes so a restart of the same anim can be detected -#define ANIM_TOGGLEBIT 128 - - -typedef enum { - TEAM_FREE, - TEAM_RED, - TEAM_BLUE, - TEAM_SPECTATOR, - - TEAM_NUM_TEAMS -} team_t; - -// Time between location updates -#define TEAM_LOCATION_UPDATE_TIME 1000 - -// How many players on the overlay -#define TEAM_MAXOVERLAY 32 - - -// Begin Duffman -// Location Damage -// Height layers -#define LOCATION_NONE 0x00000000 - -#define LOCATION_HEAD 0x00000001 // [F,B,L,R] Top of head -#define LOCATION_FACE 0x00000002 // [F] Face [B,L,R] Head -#define LOCATION_SHOULDER 0x00000004 // [L,R] Shoulder [F] Throat, [B] Neck -#define LOCATION_CHEST 0x00000008 // [F] Chest [B] Back [L,R] Arm -#define LOCATION_STOMACH 0x00000010 // [L,R] Sides [F] Stomach [B] Lower Back -#define LOCATION_GROIN 0x00000020 // [F] Groin [B] Butt [L,R] Hip -#define LOCATION_LEG 0x00000040 // [F,B,L,R] Legs -#define LOCATION_FOOT 0x00000080 // [F,B,L,R] Bottom of Feet - - -// Relative direction strike came from - -#define LOCATION_LEFT 0x00000100 -#define LOCATION_RIGHT 0x00000200 -#define LOCATION_FRONT 0x00000400 -#define LOCATION_BACK 0x00000800 -// End Duffman - -//team task -typedef enum { - TEAMTASK_NONE, - TEAMTASK_OFFENSE, - TEAMTASK_DEFENSE, - TEAMTASK_PATROL, - TEAMTASK_FOLLOW, - TEAMTASK_RETRIEVE, - TEAMTASK_ESCORT, - TEAMTASK_CAMP -} teamtask_t; - -// means of death -typedef enum { - MOD_UNKNOWN, - MOD_SHOTGUN, - MOD_GAUNTLET, - MOD_MACHINEGUN, - MOD_GRENADE, - MOD_GRENADE_SPLASH, - MOD_ROCKET, - MOD_ROCKET_SPLASH, - MOD_PLASMA, - MOD_PLASMA_SPLASH, - MOD_RAILGUN, - MOD_LIGHTNING, - MOD_BFG, - MOD_BFG_SPLASH, - MOD_WATER, - MOD_SLIME, - MOD_LAVA, - MOD_CRUSH, - MOD_TELEFRAG, - MOD_FALLING, - MOD_SUICIDE, - MOD_TARGET_LASER, - MOD_TRIGGER_HURT, -#ifdef MISSIONPACK - MOD_NAIL, - MOD_CHAINGUN, - MOD_PROXIMITY_MINE, - MOD_KAMIKAZE, - MOD_JUICED, -#endif - MOD_GRAPPLE, - //Blaze: Reaction Deaths - MOD_KNIFE, - MOD_KNIFE_THROWN, - MOD_PISTOL, - MOD_M4, - MOD_SNIPER, - MOD_MP5, - MOD_AKIMBO, - MOD_M3, - MOD_HANDCANNON, - MOD_KICK, - MOD_BLEEDING -} meansOfDeath_t; - - -//--------------------------------------------------------- - -// gitem_t->type -typedef enum { - IT_BAD, - IT_WEAPON, // EFX: rotate + upscale + minlight - IT_AMMO, // EFX: rotate - IT_ARMOR, // EFX: rotate + minlight - IT_HEALTH, // EFX: static external sphere + rotating internal - IT_POWERUP, // instant on, timer based - // EFX: rotate + external ring that rotates - IT_HOLDABLE, // single use, holdable item - // EFX: rotate + bob - IT_PERSISTANT_POWERUP, - IT_TEAM -} itemType_t; - -#define MAX_ITEM_MODELS 4 - -typedef struct gitem_s { - char *classname; // spawning name - char *pickup_sound; - char *world_model[MAX_ITEM_MODELS]; - - char *icon; - char *pickup_name; // for printing on pickup - - int quantity; // for ammo how much, or duration of powerup - itemType_t giType; // IT_* flags - - int giTag; - - char *precaches; // string of all models and images this item will use - char *sounds; // string of all sounds this item will use -} gitem_t; - -// included in both the game dll and the client -extern gitem_t bg_itemlist[]; -extern int bg_numItems; - -gitem_t *BG_FindItem( const char *pickupName ); -gitem_t *BG_FindItemForWeapon( weapon_t weapon ); -gitem_t *BG_FindItemForPowerup( powerup_t pw ); -gitem_t *BG_FindItemForHoldable( holdable_t pw ); -#define ITEM_INDEX(x) ((x)-bg_itemlist) - -qboolean BG_CanItemBeGrabbed( int gametype, const entityState_t *ent, const playerState_t *ps ); - - -// g_dmflags->integer flags -#define DF_NO_FALLING 8 -#define DF_FIXED_FOV 16 -#define DF_NO_FOOTSTEPS 32 - -// content masks -#define MASK_ALL (-1) -#define MASK_SOLID (CONTENTS_SOLID) -#define MASK_PLAYERSOLID (CONTENTS_SOLID|CONTENTS_PLAYERCLIP|CONTENTS_BODY) -#define MASK_DEADSOLID (CONTENTS_SOLID|CONTENTS_PLAYERCLIP) -#define MASK_WATER (CONTENTS_WATER|CONTENTS_LAVA|CONTENTS_SLIME) -#define MASK_OPAQUE (CONTENTS_SOLID|CONTENTS_SLIME|CONTENTS_LAVA) -#define MASK_SHOT (CONTENTS_SOLID|CONTENTS_BODY|CONTENTS_CORPSE) - - -// -// entityState_t->eType -// -typedef enum { - ET_GENERAL, - ET_PLAYER, - ET_ITEM, - ET_MISSILE, - ET_MOVER, - ET_BREAKABLE,//Blaze: Breakable glass - ET_BEAM, - ET_PORTAL, - ET_SPEAKER, - ET_PUSH_TRIGGER, - ET_TELEPORT_TRIGGER, - ET_INVISIBLE, - ET_GRAPPLE, // grapple hooked on wall - ET_TEAM, - - ET_EVENTS // any of the EV_* events can be added freestanding - // by setting eType to ET_EVENTS + eventNum - // this avoids having to set eFlags and eventNum -} entityType_t; - - - -void BG_EvaluateTrajectory( const trajectory_t *tr, int atTime, vec3_t result ); -void BG_EvaluateTrajectoryDelta( const trajectory_t *tr, int atTime, vec3_t result ); - -void BG_AddPredictableEventToPlayerstate( int newEvent, int eventParm, playerState_t *ps ); - -void BG_TouchJumpPad( playerState_t *ps, entityState_t *jumppad ); - -void BG_PlayerStateToEntityState( playerState_t *ps, entityState_t *s, qboolean snap ); -void BG_PlayerStateToEntityStateExtraPolate( playerState_t *ps, entityState_t *s, int time, qboolean snap ); - -qboolean BG_PlayerTouchesItem( playerState_t *ps, entityState_t *item, int atTime ); - - -#define ARENAS_PER_TIER 4 -#define MAX_ARENAS 1024 -#define MAX_ARENAS_TEXT 8192 - -#define MAX_BOTS 1024 -#define MAX_BOTS_TEXT 8192 - - -// Kamikaze - -// 1st shockwave times -#define KAMI_SHOCKWAVE_STARTTIME 0 -#define KAMI_SHOCKWAVEFADE_STARTTIME 1500 -#define KAMI_SHOCKWAVE_ENDTIME 2000 -// explosion/implosion times -#define KAMI_EXPLODE_STARTTIME 250 -#define KAMI_IMPLODE_STARTTIME 2000 -#define KAMI_IMPLODE_ENDTIME 2250 -// 2nd shockwave times -#define KAMI_SHOCKWAVE2_STARTTIME 2000 -#define KAMI_SHOCKWAVE2FADE_STARTTIME 2500 -#define KAMI_SHOCKWAVE2_ENDTIME 3000 -// radius of the models without scaling -#define KAMI_SHOCKWAVEMODEL_RADIUS 88 -#define KAMI_BOOMSPHEREMODEL_RADIUS 72 -// maximum radius of the models during the effect -#define KAMI_SHOCKWAVE_MAXRADIUS 1320 -#define KAMI_BOOMSPHERE_MAXRADIUS 720 -#define KAMI_SHOCKWAVE2_MAXRADIUS 704 - diff --git a/reaction/game/.#g_cmds.c.1.13 b/reaction/game/.#g_cmds.c.1.13 deleted file mode 100644 index 739d7905..00000000 --- a/reaction/game/.#g_cmds.c.1.13 +++ /dev/null @@ -1,1930 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// -#include "g_local.h" - -//Blaze: was there a extra ../ here? -#include "../ui/menudef.h" // for the voice chats -//Blaze for door code -void Use_BinaryMover( gentity_t *ent, gentity_t *other, gentity_t *activator ); -//Blaze: Get amount of ammo a clip holds -int ClipAmountForWeapon( int ); -/* -================== -DeathmatchScoreboardMessage - -================== -*/ -void DeathmatchScoreboardMessage( gentity_t *ent ) { - char entry[1024]; - char string[1400]; - int stringlength; - int i, j; - gclient_t *cl; - int numSorted, scoreFlags, accuracy, perfect; - - // send the latest information on all clients - string[0] = 0; - stringlength = 0; - scoreFlags = 0; - - numSorted = level.numConnectedClients; - - for (i=0 ; i < numSorted ; i++) { - int ping; - - cl = &level.clients[level.sortedClients[i]]; - - if ( cl->pers.connected == CON_CONNECTING ) { - ping = -1; - } else { - ping = cl->ps.ping < 999 ? cl->ps.ping : 999; - } - - if( cl->accuracy_shots ) { - accuracy = cl->accuracy_hits * 100 / cl->accuracy_shots; - } - else { - accuracy = 0; - } - perfect = ( cl->ps.persistant[PERS_RANK] == 0 && cl->ps.persistant[PERS_KILLED] == 0 ) ? 1 : 0; - - Com_sprintf (entry, sizeof(entry), - " %i %i %i %i %i %i %i %i %i %i %i %i %i %i", level.sortedClients[i], - cl->ps.persistant[PERS_SCORE], ping, (level.time - cl->pers.enterTime)/60000, - scoreFlags, g_entities[level.sortedClients[i]].s.powerups, accuracy, - cl->ps.persistant[PERS_IMPRESSIVE_COUNT], - cl->ps.persistant[PERS_EXCELLENT_COUNT], - cl->ps.persistant[PERS_GAUNTLET_FRAG_COUNT], - cl->ps.persistant[PERS_DEFEND_COUNT], - cl->ps.persistant[PERS_ASSIST_COUNT], - perfect, - cl->ps.persistant[PERS_CAPTURES]); - j = strlen(entry); - if (stringlength + j > 1024) - break; - strcpy (string + stringlength, entry); - stringlength += j; - } - - trap_SendServerCommand( ent-g_entities, va("scores %i %i %i%s", i, - level.teamScores[TEAM_RED], level.teamScores[TEAM_BLUE], - string ) ); -} - - -/* -================== -Cmd_Score_f - -Request current scoreboard information -================== -*/ -void Cmd_Score_f( gentity_t *ent ) { - DeathmatchScoreboardMessage( ent ); -} - - - -/* -================== -CheatsOk -================== -*/ -qboolean CheatsOk( gentity_t *ent ) { - if ( !g_cheats.integer ) { - trap_SendServerCommand( ent-g_entities, va("print \"Cheats are not enabled on this server.\n\"")); - return qfalse; - } - if ( ent->health <= 0 ) { - trap_SendServerCommand( ent-g_entities, va("print \"You must be alive to use this command.\n\"")); - return qfalse; - } - return qtrue; -} - - -/* -================== -ConcatArgs -================== -*/ -char *ConcatArgs( int start ) { - int i, c, tlen; - static char line[MAX_STRING_CHARS]; - int len; - char arg[MAX_STRING_CHARS]; - - len = 0; - c = trap_Argc(); - for ( i = start ; i < c ; i++ ) { - trap_Argv( i, arg, sizeof( arg ) ); - tlen = strlen( arg ); - if ( len + tlen >= MAX_STRING_CHARS - 1 ) { - break; - } - memcpy( line + len, arg, tlen ); - len += tlen; - if ( i != c - 1 ) { - line[len] = ' '; - len++; - } - } - - line[len] = 0; - - return line; -} - -/* -================== -SanitizeString - -Remove case and control characters -================== -*/ -void SanitizeString( char *in, char *out ) { - while ( *in ) { - if ( *in == 27 ) { - in += 2; // skip color code - continue; - } - if ( *in < 32 ) { - in++; - continue; - } - *out++ = tolower( *in++ ); - } - - *out = 0; -} - -/* -================== -ClientNumberFromString - -Returns a player number for either a number or name string -Returns -1 if invalid -================== -*/ -int ClientNumberFromString( gentity_t *to, char *s ) { - gclient_t *cl; - int idnum; - char s2[MAX_STRING_CHARS]; - char n2[MAX_STRING_CHARS]; - - // numeric values are just slot numbers - if (s[0] >= '0' && s[0] <= '9') { - idnum = atoi( s ); - if ( idnum < 0 || idnum >= level.maxclients ) { - trap_SendServerCommand( to-g_entities, va("print \"Bad client slot: %i\n\"", idnum)); - return -1; - } - - cl = &level.clients[idnum]; - if ( cl->pers.connected != CON_CONNECTED ) { - trap_SendServerCommand( to-g_entities, va("print \"Client %i is not active\n\"", idnum)); - return -1; - } - return idnum; - } - - // check for a name match - SanitizeString( s, s2 ); - for ( idnum=0,cl=level.clients ; idnum < level.maxclients ; idnum++,cl++ ) { - if ( cl->pers.connected != CON_CONNECTED ) { - continue; - } - SanitizeString( cl->pers.netname, n2 ); - if ( !strcmp( n2, s2 ) ) { - return idnum; - } - } - - trap_SendServerCommand( to-g_entities, va("print \"User %s is not on the server\n\"", s)); - return -1; -} - -/* -================== -Cmd_Give_f - -Give items to a client -================== -*/ -void Cmd_Give_f (gentity_t *ent) -{ - char *name; - gitem_t *it; - int i; - qboolean give_all; - gentity_t *it_ent; - trace_t trace; - - if ( !CheatsOk( ent ) ) { - return; - } - - name = ConcatArgs( 1 ); - - if (Q_stricmp(name, "all") == 0) - give_all = qtrue; - else - give_all = qfalse; - - if (give_all || Q_stricmp( name, "health") == 0) - { - ent->health = ent->client->ps.stats[STAT_MAX_HEALTH]; - if (!give_all) - return; - } - - if (give_all || Q_stricmp(name, "weapons") == 0) - { - //Blaze: Removed ( 1 << WP_GRAPPLING_HOOK ) - - //I have no clue what that does - ent->client->ps.stats[STAT_WEAPONS] = (1 << WP_NUM_WEAPONS) - 1 - ( 1 << WP_NONE ); - - if (!give_all) - return; - } - - if (give_all || Q_stricmp(name, "ammo") == 0) - { - for ( i = 0 ; i < MAX_WEAPONS ; i++ ) { - //Blaze: Give right amount of shots to each gun - ent->client->ps.ammo[i] = ClipAmountForWeapon(i); - } - if (!give_all) - return; - } - -//Blaze: No armor in reaction, so give all should not give you any for testing -/* - if (give_all || Q_stricmp(name, "armor") == 0) - { - ent->client->ps.stats[STAT_ARMOR] = 200; - - if (!give_all) - return; - } -*/ - - if (Q_stricmp(name, "excellent") == 0) { - ent->client->ps.persistant[PERS_EXCELLENT_COUNT]++; - return; - } - if (Q_stricmp(name, "impressive") == 0) { - ent->client->ps.persistant[PERS_IMPRESSIVE_COUNT]++; - return; - } - if (Q_stricmp(name, "gauntletaward") == 0) { - ent->client->ps.persistant[PERS_GAUNTLET_FRAG_COUNT]++; - return; - } - if (Q_stricmp(name, "defend") == 0) { - ent->client->ps.persistant[PERS_DEFEND_COUNT]++; - return; - } - if (Q_stricmp(name, "assist") == 0) { - ent->client->ps.persistant[PERS_ASSIST_COUNT]++; - return; - } - - // spawn a specific item right on the player - if ( !give_all ) { - it = BG_FindItem (name); - if (!it) { - return; - } - - it_ent = G_Spawn(); - VectorCopy( ent->r.currentOrigin, it_ent->s.origin ); - it_ent->classname = it->classname; - G_SpawnItem (it_ent, it); - FinishSpawningItem(it_ent ); - memset( &trace, 0, sizeof( trace ) ); - Touch_Item (it_ent, ent, &trace); - if (it_ent->inuse) { - G_FreeEntity( it_ent ); - } - } -} - - -/* -================== -Cmd_God_f - -Sets client to godmode - -argv(0) god -================== -*/ -void Cmd_God_f (gentity_t *ent) -{ - char *msg; - - if ( !CheatsOk( ent ) ) { - return; - } - - ent->flags ^= FL_GODMODE; - if (!(ent->flags & FL_GODMODE) ) - msg = "godmode OFF\n"; - else - msg = "godmode ON\n"; - - trap_SendServerCommand( ent-g_entities, va("print \"%s\"", msg)); -} - - -/* -================== -Cmd_Notarget_f - -Sets client to notarget - -argv(0) notarget -================== -*/ -void Cmd_Notarget_f( gentity_t *ent ) { - char *msg; - - if ( !CheatsOk( ent ) ) { - return; - } - - ent->flags ^= FL_NOTARGET; - if (!(ent->flags & FL_NOTARGET) ) - msg = "notarget OFF\n"; - else - msg = "notarget ON\n"; - - trap_SendServerCommand( ent-g_entities, va("print \"%s\"", msg)); -} - - -/* -================== -Cmd_Noclip_f - -argv(0) noclip -================== -*/ -void Cmd_Noclip_f( gentity_t *ent ) { - char *msg; - - if ( !CheatsOk( ent ) ) { - return; - } - - if ( ent->client->noclip ) { - msg = "noclip OFF\n"; - } else { - msg = "noclip ON\n"; - } - ent->client->noclip = !ent->client->noclip; - - trap_SendServerCommand( ent-g_entities, va("print \"%s\"", msg)); -} - - -/* -================== -Cmd_LevelShot_f - -This is just to help generate the level pictures -for the menus. It goes to the intermission immediately -and sends over a command to the client to resize the view, -hide the scoreboard, and take a special screenshot -================== -*/ -void Cmd_LevelShot_f( gentity_t *ent ) { - if ( !CheatsOk( ent ) ) { - return; - } - - // doesn't work in single player - if ( g_gametype.integer != 0 ) { - trap_SendServerCommand( ent-g_entities, - "print \"Must be in g_gametype 0 for levelshot\n\"" ); - return; - } - - BeginIntermission(); - trap_SendServerCommand( ent-g_entities, "clientLevelShot" ); -} - - -/* -================== -Cmd_LevelShot_f - -This is just to help generate the level pictures -for the menus. It goes to the intermission immediately -and sends over a command to the client to resize the view, -hide the scoreboard, and take a special screenshot -================== -*/ -void Cmd_TeamTask_f( gentity_t *ent ) { - char userinfo[MAX_INFO_STRING]; - char arg[MAX_TOKEN_CHARS]; - int task; - int client = ent->client - level.clients; - - if ( trap_Argc() != 2 ) { - return; - } - trap_Argv( 1, arg, sizeof( arg ) ); - task = atoi( arg ); - - trap_GetUserinfo(client, userinfo, sizeof(userinfo)); - Info_SetValueForKey(userinfo, "teamtask", va("%d", task)); - trap_SetUserinfo(client, userinfo); - ClientUserinfoChanged(client); -} - - - -/* -================= -Cmd_Kill_f -================= -*/ -void Cmd_Kill_f( gentity_t *ent ) { - if ( ent->client->sess.sessionTeam == TEAM_SPECTATOR ) { - return; - } - if (ent->health <= 0) { - return; - } - ent->flags &= ~FL_GODMODE; - ent->client->ps.stats[STAT_HEALTH] = ent->health = -999; - player_die (ent, ent, ent, 100000, MOD_SUICIDE); -} - -/* -================= -BroadCastTeamChange - -Let everyone know about a team change -================= -*/ -void BroadcastTeamChange( gclient_t *client, int oldTeam ) -{ - if ( client->sess.sessionTeam == TEAM_RED ) { - trap_SendServerCommand( -1, va("cp \"%s" S_COLOR_WHITE " joined the red team.\n\"", - client->pers.netname) ); - } else if ( client->sess.sessionTeam == TEAM_BLUE ) { - trap_SendServerCommand( -1, va("cp \"%s" S_COLOR_WHITE " joined the blue team.\n\"", - client->pers.netname)); - } else if ( client->sess.sessionTeam == TEAM_SPECTATOR && oldTeam != TEAM_SPECTATOR ) { - trap_SendServerCommand( -1, va("cp \"%s" S_COLOR_WHITE " joined the spectators.\n\"", - client->pers.netname)); - } else if ( client->sess.sessionTeam == TEAM_FREE ) { - trap_SendServerCommand( -1, va("cp \"%s" S_COLOR_WHITE " joined the battle.\n\"", - client->pers.netname)); - } -} - -/* -================= -SetTeam -================= -*/ -void SetTeam( gentity_t *ent, char *s ) { - int team, oldTeam; - gclient_t *client; - int clientNum; - spectatorState_t specState; - int specClient; - int teamLeader; - - // - // see what change is requested - // - client = ent->client; - - clientNum = client - level.clients; - specClient = 0; - specState = SPECTATOR_NOT; - if ( !Q_stricmp( s, "scoreboard" ) || !Q_stricmp( s, "score" ) ) { - team = TEAM_SPECTATOR; - specState = SPECTATOR_SCOREBOARD; - } else if ( !Q_stricmp( s, "follow1" ) ) { - team = TEAM_SPECTATOR; - specState = SPECTATOR_FOLLOW; - specClient = -1; - } else if ( !Q_stricmp( s, "follow2" ) ) { - team = TEAM_SPECTATOR; - specState = SPECTATOR_FOLLOW; - specClient = -2; - } else if ( !Q_stricmp( s, "spectator" ) || !Q_stricmp( s, "s" ) ) { - team = TEAM_SPECTATOR; - specState = SPECTATOR_FREE; - } else if ( g_gametype.integer >= GT_TEAM ) { - // if running a team game, assign player to one of the teams - specState = SPECTATOR_NOT; - if ( !Q_stricmp( s, "red" ) || !Q_stricmp( s, "r" ) ) { - team = TEAM_RED; - } else if ( !Q_stricmp( s, "blue" ) || !Q_stricmp( s, "b" ) ) { - team = TEAM_BLUE; - } else { - // pick the team with the least number of players - team = PickTeam( clientNum ); - } - - if ( g_teamForceBalance.integer ) { - int counts[TEAM_NUM_TEAMS]; - - counts[TEAM_BLUE] = TeamCount( ent->client->ps.clientNum, TEAM_BLUE ); - counts[TEAM_RED] = TeamCount( ent->client->ps.clientNum, TEAM_RED ); - - // We allow a spread of two - if ( team == TEAM_RED && counts[TEAM_RED] - counts[TEAM_BLUE] > 1 ) { - trap_SendServerCommand( ent->client->ps.clientNum, - "cp \"Red team has too many players.\n\"" ); - return; // ignore the request - } - if ( team == TEAM_BLUE && counts[TEAM_BLUE] - counts[TEAM_RED] > 1 ) { - trap_SendServerCommand( ent->client->ps.clientNum, - "cp \"Red team has too many players.\n\"" ); - return; // ignore the request - } - - // It's ok, the team we are switching to has less or same number of players - } - - } else { - // force them to spectators if there aren't any spots free - team = TEAM_FREE; - } - - // override decision if limiting the players - if ( (g_gametype.integer == GT_TOURNAMENT) - && level.numNonSpectatorClients >= 2 ) { - team = TEAM_SPECTATOR; - } else if ( g_maxGameClients.integer > 0 && - level.numNonSpectatorClients >= g_maxGameClients.integer ) { - team = TEAM_SPECTATOR; - } - - // - // decide if we will allow the change - // - oldTeam = client->sess.sessionTeam; - if ( team == oldTeam && team != TEAM_SPECTATOR ) { - return; - } - - // - // execute the team change - // - - // if the player was dead leave the body - if ( client->ps.stats[STAT_HEALTH] <= 0 ) { - CopyToBodyQue(ent); - } - - // he starts at 'base' - client->pers.teamState.state = TEAM_BEGIN; - if ( oldTeam != TEAM_SPECTATOR ) { - // Kill him (makes sure he loses flags, etc) - ent->flags &= ~FL_GODMODE; - ent->client->ps.stats[STAT_HEALTH] = ent->health = 0; - player_die (ent, ent, ent, 100000, MOD_SUICIDE); - - } - // they go to the end of the line for tournements - if ( team == TEAM_SPECTATOR ) { - client->sess.spectatorTime = level.time; - } - - client->sess.sessionTeam = team; - client->sess.spectatorState = specState; - client->sess.spectatorClient = specClient; - - client->sess.teamLeader = qfalse; - if ( team == TEAM_RED || team == TEAM_BLUE ) { - teamLeader = TeamLeader( team ); - // if there is no team leader or the team leader is a bot and this client is not a bot - if ( teamLeader == -1 || ( !(g_entities[clientNum].r.svFlags & SVF_BOT) && (g_entities[teamLeader].r.svFlags & SVF_BOT) ) ) { - SetLeader( team, clientNum ); - } - } - // make sure there is a team leader on the team the player came from - if ( oldTeam == TEAM_RED || oldTeam == TEAM_BLUE ) { - CheckTeamLeader( oldTeam ); - } - - BroadcastTeamChange( client, oldTeam ); - - // get and distribute relevent paramters - ClientUserinfoChanged( clientNum ); - - ClientBegin( clientNum ); -} - -/* -================= -StopFollowing - -If the client being followed leaves the game, or you just want to drop -to free floating spectator mode -================= -*/ -void StopFollowing( gentity_t *ent ) { - ent->client->ps.persistant[ PERS_TEAM ] = TEAM_SPECTATOR; - ent->client->sess.sessionTeam = TEAM_SPECTATOR; - ent->client->sess.spectatorState = SPECTATOR_FREE; - ent->client->ps.pm_flags &= ~PMF_FOLLOW; - ent->r.svFlags &= ~SVF_BOT; - ent->client->ps.clientNum = ent - g_entities; -} - -/* -================= -Cmd_Team_f -================= -*/ -void Cmd_Team_f( gentity_t *ent ) { - int oldTeam; - char s[MAX_TOKEN_CHARS]; - - if ( trap_Argc() != 2 ) { - oldTeam = ent->client->sess.sessionTeam; - switch ( oldTeam ) { - case TEAM_BLUE: - trap_SendServerCommand( ent-g_entities, "print \"Blue team\n\"" ); - break; - case TEAM_RED: - trap_SendServerCommand( ent-g_entities, "print \"Red team\n\"" ); - break; - case TEAM_FREE: - trap_SendServerCommand( ent-g_entities, "print \"Free team\n\"" ); - break; - case TEAM_SPECTATOR: - trap_SendServerCommand( ent-g_entities, "print \"Spectator team\n\"" ); - break; - } - return; - } - - if ( ent->client->switchTeamTime > level.time ) { - trap_SendServerCommand( ent-g_entities, "print \"May not switch teams more than once per 5 seconds.\n\"" ); - return; - } - - // if they are playing a tournement game, count as a loss - if ( (g_gametype.integer == GT_TOURNAMENT ) - && ent->client->sess.sessionTeam == TEAM_FREE ) { - ent->client->sess.losses++; - } - - trap_Argv( 1, s, sizeof( s ) ); - - SetTeam( ent, s ); - - ent->client->switchTeamTime = level.time + 5000; -} - - -/* -================= -Cmd_Follow_f -================= -*/ -void Cmd_Follow_f( gentity_t *ent ) { - int i; - char arg[MAX_TOKEN_CHARS]; - - if ( trap_Argc() != 2 ) { - if ( ent->client->sess.spectatorState == SPECTATOR_FOLLOW ) { - StopFollowing( ent ); - } - return; - } - - trap_Argv( 1, arg, sizeof( arg ) ); - i = ClientNumberFromString( ent, arg ); - if ( i == -1 ) { - return; - } - - // can't follow self - if ( &level.clients[ i ] == ent->client ) { - return; - } - - // can't follow another spectator - if ( level.clients[ i ].sess.sessionTeam == TEAM_SPECTATOR ) { - return; - } - - // if they are playing a tournement game, count as a loss - if ( (g_gametype.integer == GT_TOURNAMENT ) - && ent->client->sess.sessionTeam == TEAM_FREE ) { - ent->client->sess.losses++; - } - - // first set them to spectator - if ( ent->client->sess.sessionTeam != TEAM_SPECTATOR ) { - SetTeam( ent, "spectator" ); - } - - ent->client->sess.spectatorState = SPECTATOR_FOLLOW; - ent->client->sess.spectatorClient = i; -} - -/* -================= -Cmd_FollowCycle_f -================= -*/ -void Cmd_FollowCycle_f( gentity_t *ent, int dir ) { - int clientnum; - int original; - - // if they are playing a tournement game, count as a loss - if ( (g_gametype.integer == GT_TOURNAMENT ) - && ent->client->sess.sessionTeam == TEAM_FREE ) { - ent->client->sess.losses++; - } - // first set them to spectator - if ( ent->client->sess.spectatorState == SPECTATOR_NOT ) { - SetTeam( ent, "spectator" ); - } - - if ( dir != 1 && dir != -1 ) { - G_Error( "Cmd_FollowCycle_f: bad dir %i", dir ); - } - - clientnum = ent->client->sess.spectatorClient; - original = clientnum; - do { - clientnum += dir; - if ( clientnum >= level.maxclients ) { - clientnum = 0; - } - if ( clientnum < 0 ) { - clientnum = level.maxclients - 1; - } - - // can only follow connected clients - if ( level.clients[ clientnum ].pers.connected != CON_CONNECTED ) { - continue; - } - - // can't follow another spectator - if ( level.clients[ clientnum ].sess.sessionTeam == TEAM_SPECTATOR ) { - continue; - } - - // this is good, we can use it - ent->client->sess.spectatorClient = clientnum; - ent->client->sess.spectatorState = SPECTATOR_FOLLOW; - return; - } while ( clientnum != original ); - - // leave it where it was -} - - -/* -================== -G_Say -================== -*/ - -static void G_SayTo( gentity_t *ent, gentity_t *other, int mode, int color, const char *name, const char *message ) { - if (!other) { - return; - } - if (!other->inuse) { - return; - } - if (!other->client) { - return; - } - if ( mode == SAY_TEAM && !OnSameTeam(ent, other) ) { - return; - } - // no chatting to players in tournements - if ( (g_gametype.integer == GT_TOURNAMENT ) - && other->client->sess.sessionTeam == TEAM_FREE - && ent->client->sess.sessionTeam != TEAM_FREE ) { - return; - } - - trap_SendServerCommand( other-g_entities, va("%s \"%s%c%c%s\"", - mode == SAY_TEAM ? "tchat" : "chat", - name, Q_COLOR_ESCAPE, color, message)); -} - -#define EC "\x19" - -void G_Say( gentity_t *ent, gentity_t *target, int mode, const char *chatText ) { - int j; - gentity_t *other; - int color; - char name[64]; - // don't let text be too long for malicious reasons - char text[MAX_SAY_TEXT]; - char location[64]; - - if ( g_gametype.integer < GT_TEAM && mode == SAY_TEAM ) { - mode = SAY_ALL; - } - - switch ( mode ) { - default: - case SAY_ALL: - G_LogPrintf( "say: %s: %s\n", ent->client->pers.netname, chatText ); - Com_sprintf (name, sizeof(name), "%s%c%c"EC": ", ent->client->pers.netname, Q_COLOR_ESCAPE, COLOR_WHITE ); - color = COLOR_GREEN; - break; - case SAY_TEAM: - G_LogPrintf( "sayteam: %s: %s\n", ent->client->pers.netname, chatText ); - if (Team_GetLocationMsg(ent, location, sizeof(location))) - Com_sprintf (name, sizeof(name), EC"(%s%c%c"EC") (%s)"EC": ", - ent->client->pers.netname, Q_COLOR_ESCAPE, COLOR_WHITE, location); - else - Com_sprintf (name, sizeof(name), EC"(%s%c%c"EC")"EC": ", - ent->client->pers.netname, Q_COLOR_ESCAPE, COLOR_WHITE ); - color = COLOR_CYAN; - break; - case SAY_TELL: - if (target && g_gametype.integer >= GT_TEAM && - target->client->sess.sessionTeam == ent->client->sess.sessionTeam && - Team_GetLocationMsg(ent, location, sizeof(location))) - Com_sprintf (name, sizeof(name), EC"[%s%c%c"EC"] (%s)"EC": ", ent->client->pers.netname, Q_COLOR_ESCAPE, COLOR_WHITE, location ); - else - Com_sprintf (name, sizeof(name), EC"[%s%c%c"EC"]"EC": ", ent->client->pers.netname, Q_COLOR_ESCAPE, COLOR_WHITE ); - color = COLOR_MAGENTA; - break; - } - - Q_strncpyz( text, chatText, sizeof(text) ); - - if ( target ) { - G_SayTo( ent, target, mode, color, name, text ); - return; - } - - // echo the text to the console - if ( g_dedicated.integer ) { - G_Printf( "%s%s\n", name, text); - } - - // send it to all the apropriate clients - for (j = 0; j < level.maxclients; j++) { - other = &g_entities[j]; - G_SayTo( ent, other, mode, color, name, text ); - } -} - - -/* -================== -Cmd_Say_f -================== -*/ -static void Cmd_Say_f( gentity_t *ent, int mode, qboolean arg0 ) { - char *p; - - if ( trap_Argc () < 2 && !arg0 ) { - return; - } - - if (arg0) - { - p = ConcatArgs( 0 ); - } - else - { - p = ConcatArgs( 1 ); - } - - G_Say( ent, NULL, mode, p ); -} - -/* -================== -Cmd_Tell_f -================== -*/ -static void Cmd_Tell_f( gentity_t *ent ) { - int targetNum; - gentity_t *target; - char *p; - char arg[MAX_TOKEN_CHARS]; - - if ( trap_Argc () < 2 ) { - return; - } - - trap_Argv( 1, arg, sizeof( arg ) ); - targetNum = atoi( arg ); - if ( targetNum < 0 || targetNum >= level.maxclients ) { - return; - } - - target = &g_entities[targetNum]; - if ( !target || !target->inuse || !target->client ) { - return; - } - - p = ConcatArgs( 2 ); - - G_LogPrintf( "tell: %s to %s: %s\n", ent->client->pers.netname, target->client->pers.netname, p ); - G_Say( ent, target, SAY_TELL, p ); - // don't tell to the player self if it was already directed to this player - // also don't send the chat back to a bot - if ( ent != target && !(ent->r.svFlags & SVF_BOT)) { - G_Say( ent, ent, SAY_TELL, p ); -} -} - - -static void G_VoiceTo( gentity_t *ent, gentity_t *other, int mode, const char *id, qboolean voiceonly ) { - int color; - char *cmd; - - if (!other) { - return; - } - if (!other->inuse) { - return; - } - if (!other->client) { - return; - } - if ( mode == SAY_TEAM && !OnSameTeam(ent, other) ) { - return; - } - // no chatting to players in tournements - if ( (g_gametype.integer == GT_TOURNAMENT )) { - return; - } - - if (mode == SAY_TEAM) { - color = COLOR_CYAN; - cmd = "vtchat"; - } - else if (mode == SAY_TELL) { - color = COLOR_MAGENTA; - cmd = "vtell"; - } - else { - color = COLOR_GREEN; - cmd = "vchat"; - } - - trap_SendServerCommand( other-g_entities, va("%s %d %d %d %s", cmd, voiceonly, ent->s.number, color, id)); -} - -void G_Voice( gentity_t *ent, gentity_t *target, int mode, const char *id, qboolean voiceonly ) { - int j; - gentity_t *other; - - if ( g_gametype.integer < GT_TEAM && mode == SAY_TEAM ) { - mode = SAY_ALL; - } - - if ( target ) { - G_VoiceTo( ent, target, mode, id, voiceonly ); - return; - } - - // echo the text to the console - if ( g_dedicated.integer ) { - G_Printf( "voice: %s %s\n", ent->client->pers.netname, id); - } - - // send it to all the apropriate clients - for (j = 0; j < level.maxclients; j++) { - other = &g_entities[j]; - G_VoiceTo( ent, other, mode, id, voiceonly ); - } -} - -/* -================== -Cmd_Voice_f -================== -*/ -static void Cmd_Voice_f( gentity_t *ent, int mode, qboolean arg0, qboolean voiceonly ) { - char *p; - - if ( trap_Argc () < 2 && !arg0 ) { - return; - } - - if (arg0) - { - p = ConcatArgs( 0 ); - } - else - { - p = ConcatArgs( 1 ); - } - - G_Voice( ent, NULL, mode, p, voiceonly ); -} - -/* -================== -Cmd_VoiceTell_f -================== -*/ -static void Cmd_VoiceTell_f( gentity_t *ent, qboolean voiceonly ) { - int targetNum; - gentity_t *target; - char *id; - char arg[MAX_TOKEN_CHARS]; - - if ( trap_Argc () < 2 ) { - return; - } - - trap_Argv( 1, arg, sizeof( arg ) ); - targetNum = atoi( arg ); - if ( targetNum < 0 || targetNum >= level.maxclients ) { - return; - } - - target = &g_entities[targetNum]; - if ( !target || !target->inuse || !target->client ) { - return; - } - - id = ConcatArgs( 2 ); - - G_LogPrintf( "vtell: %s to %s: %s\n", ent->client->pers.netname, target->client->pers.netname, id ); - G_Voice( ent, target, SAY_TELL, id, voiceonly ); - // don't tell to the player self if it was already directed to this player - // also don't send the chat back to a bot - if ( ent != target && !(ent->r.svFlags & SVF_BOT)) { - G_Voice( ent, ent, SAY_TELL, id, voiceonly ); - } -} - - -/* -================== -Cmd_VoiceTaunt_f -================== -*/ -static void Cmd_VoiceTaunt_f( gentity_t *ent ) { - gentity_t *who; - int i; - - if (!ent->client) { - return; - } - - // insult someone who just killed you - if (ent->enemy && ent->enemy->client && ent->enemy->client->lastkilled_client == ent->s.number) { - // i am a dead corpse - if (!(ent->enemy->r.svFlags & SVF_BOT)) { - G_Voice( ent, ent->enemy, SAY_TELL, VOICECHAT_DEATHINSULT, qfalse ); - } - if (!(ent->r.svFlags & SVF_BOT)) { - G_Voice( ent, ent, SAY_TELL, VOICECHAT_DEATHINSULT, qfalse ); - } - ent->enemy = NULL; - return; - } - // insult someone you just killed - if (ent->client->lastkilled_client >= 0 && ent->client->lastkilled_client != ent->s.number) { - who = g_entities + ent->client->lastkilled_client; - if (who->client) { - // who is the person I just killed - if (who->client->lasthurt_mod == MOD_GAUNTLET) { - if (!(who->r.svFlags & SVF_BOT)) { - G_Voice( ent, who, SAY_TELL, VOICECHAT_KILLGAUNTLET, qfalse ); // and I killed them with a gauntlet - } - if (!(ent->r.svFlags & SVF_BOT)) { - G_Voice( ent, ent, SAY_TELL, VOICECHAT_KILLGAUNTLET, qfalse ); - } - } else { - if (!(who->r.svFlags & SVF_BOT)) { - G_Voice( ent, who, SAY_TELL, VOICECHAT_KILLINSULT, qfalse ); // and I killed them with something else - } - if (!(ent->r.svFlags & SVF_BOT)) { - G_Voice( ent, ent, SAY_TELL, VOICECHAT_KILLINSULT, qfalse ); - } - } - ent->client->lastkilled_client = -1; - return; - } - } - - if (g_gametype.integer >= GT_TEAM) { - // praise a team mate who just got a reward - for(i = 0; i < MAX_CLIENTS; i++) { - who = g_entities + i; - if (who->client && who != ent && who->client->sess.sessionTeam == ent->client->sess.sessionTeam) { - if (who->client->rewardTime > level.time) { - if (!(who->r.svFlags & SVF_BOT)) { - G_Voice( ent, who, SAY_TELL, VOICECHAT_PRAISE, qfalse ); - } - if (!(ent->r.svFlags & SVF_BOT)) { - G_Voice( ent, ent, SAY_TELL, VOICECHAT_PRAISE, qfalse ); - } - return; - } - } - } - } - - // just say something - G_Voice( ent, NULL, SAY_ALL, VOICECHAT_TAUNT, qfalse ); -} - - - -static char *gc_orders[] = { - "hold your position", - "hold this position", - "come here", - "cover me", - "guard location", - "search and destroy", - "report" -}; - -void Cmd_GameCommand_f( gentity_t *ent ) { - int player; - int order; - char str[MAX_TOKEN_CHARS]; - - trap_Argv( 1, str, sizeof( str ) ); - player = atoi( str ); - trap_Argv( 2, str, sizeof( str ) ); - order = atoi( str ); - - if ( player < 0 || player >= MAX_CLIENTS ) { - return; - } - if ( order < 0 || order > sizeof(gc_orders)/sizeof(char *) ) { - return; - } - G_Say( ent, &g_entities[player], SAY_TELL, gc_orders[order] ); - G_Say( ent, ent, SAY_TELL, gc_orders[order] ); -} - -/* -================== -Cmd_Where_f -================== -*/ -void Cmd_Where_f( gentity_t *ent ) { - trap_SendServerCommand( ent-g_entities, va("print \"%s\n\"", vtos( ent->s.origin ) ) ); -} - -static const char *gameNames[] = { - "Free For All", - "Tournament", - "Single Player", - "Team Deathmatch", - "Capture the Flag", - "One Flag CTF", - "Overload", - "Harvester" -}; - -/* -================== -Cmd_CallVote_f -================== -*/ -void Cmd_CallVote_f( gentity_t *ent ) { - int i; - char arg1[MAX_STRING_TOKENS]; - char arg2[MAX_STRING_TOKENS]; - - if ( !g_allowVote.integer ) { - trap_SendServerCommand( ent-g_entities, "print \"Voting not allowed here.\n\"" ); - return; - } - - if ( level.voteTime ) { - trap_SendServerCommand( ent-g_entities, "print \"A vote is already in progress.\n\"" ); - return; - } - if ( ent->client->pers.voteCount >= MAX_VOTE_COUNT ) { - trap_SendServerCommand( ent-g_entities, "print \"You have called the maximum number of votes.\n\"" ); - return; - } - if ( ent->client->sess.sessionTeam == TEAM_SPECTATOR ) { - trap_SendServerCommand( ent-g_entities, "print \"Not allowed to call a vote as spectator.\n\"" ); - return; - } - - // make sure it is a valid command to vote on - trap_Argv( 1, arg1, sizeof( arg1 ) ); - trap_Argv( 2, arg2, sizeof( arg2 ) ); - - if( strchr( arg1, ';' ) || strchr( arg2, ';' ) ) { - trap_SendServerCommand( ent-g_entities, "print \"Invalid vote string.\n\"" ); - return; - } - - if ( !Q_stricmp( arg1, "map_restart" ) ) { - } else if ( !Q_stricmp( arg1, "nextmap" ) ) { - } else if ( !Q_stricmp( arg1, "map" ) ) { - } else if ( !Q_stricmp( arg1, "g_gametype" ) ) { - } else if ( !Q_stricmp( arg1, "kick" ) ) { - } else if ( !Q_stricmp( arg1, "clientkick" ) ) { - } else if ( !Q_stricmp( arg1, "g_doWarmup" ) ) { - } else if ( !Q_stricmp( arg1, "timelimit" ) ) { - } else if ( !Q_stricmp( arg1, "fraglimit" ) ) { - } else { - trap_SendServerCommand( ent-g_entities, "print \"Invalid vote string.\n\"" ); - trap_SendServerCommand( ent-g_entities, "print \"Vote commands are: map_restart, nextmap, mapBuild Log
----------------------Configuration: cgame - Win32 Debug-------------------- -
-Command Lines
-Creating temporary file "C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\RSP72.tmp" with contents -[ -/nologo /G5 /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR"Debug/" /Fp"Debug/cgame.pch" /YX /Fo"Debug/" /Fd"Debug/" /FD /c -"c:\reaction\cgame\cg_weapons.c" -] -Creating command line "cl.exe @C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\RSP72.tmp" -Creating temporary file "C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\RSP73.tmp" with contents -[ -/nologo /base:"0x30000000" /subsystem:windows /dll /incremental:yes /pdb:"Debug/cgamex86.pdb" /map:"Debug/cgamex86.map" /debug /machine:I386 /def:".\cgame.def" /out:"../Debug/cgamex86.dll" /implib:"Debug/cgamex86.lib" -.\Debug\bg_misc.obj -.\Debug\bg_pmove.obj -.\Debug\bg_slidemove.obj -.\Debug\cg_consolecmds.obj -.\Debug\cg_draw.obj -.\Debug\cg_drawtools.obj -.\Debug\cg_effects.obj -.\Debug\cg_ents.obj -.\Debug\cg_event.obj -.\Debug\cg_info.obj -.\Debug\cg_localents.obj -.\Debug\cg_main.obj -.\Debug\cg_marks.obj -.\Debug\cg_players.obj -.\Debug\cg_playerstate.obj -.\Debug\cg_predict.obj -.\Debug\cg_scoreboard.obj -.\Debug\cg_servercmds.obj -.\Debug\cg_snapshot.obj -.\Debug\cg_syscalls.obj -.\Debug\cg_view.obj -.\Debug\cg_weapons.obj -.\Debug\q_math.obj -.\Debug\q_shared.obj -.\Debug\ui_shared.obj -] -Creating command line "link.exe @C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\RSP73.tmp" -Output Window
-Compiling... -cg_weapons.c -Linking... - Creating library Debug/cgamex86.lib and object Debug/cgamex86.exp - - - -Results
-cgamex86.dll - 0 error(s), 0 warning(s) -