char *AIFunc_StimSoldierAttack1Start( cast_state_t *cs ) {
	gentity_t   *ent;
	//static vec3_t mins={-96,-96,0}, maxs={96,96,72};
	vec3_t pos, dir;
	trace_t tr;
	//
	cs->weaponFireTimes[cs->bs->weaponnum] = level.time;
	ent = &g_entities[cs->entityNum];
	//
	// face them
	AICast_AimAtEnemy( cs );
	// first, check if this is a good place to start the flying attack
	AngleVectors( cs->bs->ideal_viewangles, dir, NULL, NULL );
	VectorMA( cs->bs->origin, 300, dir, pos );
	pos[2] += 128;
	trap_Trace( &tr, cs->bs->origin, cs->bs->cur_ps.mins, cs->bs->cur_ps.maxs, pos, cs->entityNum, MASK_PLAYERSOLID );
	if ( tr.startsolid || tr.allsolid ) {
		return NULL;    // not a good place
	}
	// check we can attack them from there
	// select our special weapon (rocket launcher or tesla)
	if ( COM_BitCheck( cs->bs->cur_ps.weapons, WP_ROCKET_LAUNCHER ) ) {
		cs->bs->weaponnum = WP_ROCKET_LAUNCHER;
	} else if ( COM_BitCheck( cs->bs->cur_ps.weapons, WP_TESLA ) ) {
		cs->bs->weaponnum = WP_TESLA;
	} else {    // no weapon?
		G_Error( "stim soldier tried special jump attack without a tesla or rocket launcher\n" );
	}
	if ( !AICast_CheckAttackAtPos( cs->entityNum, cs->bs->enemy, pos, qfalse, qfalse ) ) {
		AICast_ChooseWeapon( cs, qfalse );
		return NULL;
	}
	// play the animation
	ent->client->ps.legsAnim =
		( ( ent->client->ps.legsAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | STIMSOLDIER_FLYJUMP_ANIM;
	ent->client->ps.legsTimer = STIMSOLDIER_FLYJUMP_DELAY;  // stay down until attack is finished
	//
	cs->aiFlags &= ~AIFL_LAND_ANIM_PLAYED;
	// play the buildup sound
	// TODO
	//
	cs->aifunc = AIFunc_StimSoldierAttack1;
	return "AIFunc_StimSoldierAttack1";
}
Ejemplo n.º 2
0
/*
============
AICast_GetAvoid
============
*/
qboolean AICast_GetAvoid( cast_state_t *cs, bot_goal_t *goal, vec3_t outpos, qboolean reverse, int blockEnt ) {
	float yaw, oldyaw, distmoved, bestmoved, bestyaw;
	vec3_t bestpos;
	aicast_predictmove_t castmove;
	usercmd_t ucmd;
	qboolean enemyVisible;
	float angleDiff;
	// TTimo might be used uninitialized
	int starttraveltime = 0;
	int besttraveltime, traveltime;
	int invert;
	float inc;
	qboolean averting = qfalse;
	float maxYaw, simTime;
	static int lastTime;

	VectorCopy( vec3_origin, bestpos );

	//
	// if we are in the air, no chance of avoiding
	if ( cs->bs->cur_ps.groundEntityNum == ENTITYNUM_NONE && g_entities[cs->entityNum].waterlevel <= 1 ) {
		return qfalse;
	}
	//
	if ( cs->lastAvoid > level.time - rand() % 500 ) {
		return qfalse;
	}
	cs->lastAvoid = level.time + 50 + rand() % 500;
	//
	if ( lastTime == level.time ) {
		return qfalse;
	}
	lastTime = level.time;

	// if they have an enemy, and can currently see them, don't move out of their view
	enemyVisible =  ( cs->bs->enemy >= 0 ) &&
				   ( AICast_CheckAttack( cs, cs->bs->enemy, qfalse ) );
	//
	// look for a good direction to move out of the way
	bestmoved = 0;
	bestyaw = 360;
	besttraveltime = 9999999;
	if ( goal ) {
		starttraveltime = trap_AAS_AreaTravelTimeToGoalArea( cs->bs->areanum, cs->bs->origin, goal->areanum, cs->travelflags );
	}
	memcpy( &ucmd, &cs->bs->lastucmd, sizeof( usercmd_t ) );
	ucmd.forwardmove = 127;
	ucmd.rightmove = 0;
	ucmd.upmove = 0;
	if ( cs->dangerEntity >= 0 && cs->dangerEntityValidTime >= level.time ) {
		averting = qtrue;
	} else if ( !goal ) {
		averting = qtrue;   // not heading for a goal, so we must be getting out of someone's way
	}
	//
	maxYaw = 0;
	simTime = 1.2;
	//
	if ( averting ) {
		// avoiding danger, go anywhere!
		angleDiff = 300;
		inc = 60;
		invert = 1;
	} else {
		if ( level.time % 1000 < 500 ) {
			invert = 1;
		} else {
			invert = -1;
		}
		angleDiff = 140;
		inc = 35;
	}
	if ( blockEnt > aicast_maxclients ) {
		maxYaw = angleDiff;
		simTime = 0.5;
	}
	//
	for ( yaw = -angleDiff * invert; yaw*invert <= maxYaw; yaw += inc * invert ) {
		if ( !averting && !yaw ) {
			continue;
		}
		oldyaw = cs->bs->cur_ps.viewangles[YAW];
		cs->bs->cur_ps.viewangles[YAW] += yaw + reverse * 180;
		//
		ucmd.angles[YAW] = ANGLE2SHORT( AngleMod( cs->bs->cur_ps.viewangles[YAW] ) );
		//
		AICast_PredictMovement( cs, 5, 0.4, &castmove, &ucmd, -1 );
		// if we have a danger entity, try and get away from it at all costs
		if ( cs->dangerEntity >= 0 && cs->dangerEntityValidTime >= level.time ) {
			distmoved = Distance( castmove.endpos, cs->dangerEntityPos );
		} else if ( goal ) {
			//distmoved = 99999 - trap_AAS_AreaTravelTimeToGoalArea( BotPointAreaNum(castmove.endpos), castmove.endpos, goal->areanum, cs->travelflags );
			distmoved = 99999 - Distance( castmove.endpos, goal->origin );
		} else {
			distmoved = Distance( castmove.endpos, cs->bs->cur_ps.origin );
		}
		if (    ( distmoved > bestmoved )
				//&&	((cs->bs->origin[2] - castmove.endpos[2]) < 64)	// allow up, but not down (falling)
				&&  ( castmove.groundEntityNum != ENTITYNUM_NONE ) ) {
			// they all passed, check any other stuff
			if ( !enemyVisible || AICast_CheckAttackAtPos( cs->entityNum, cs->bs->enemy, castmove.endpos, qfalse, qfalse ) ) {
				if ( !goal || ( traveltime = trap_AAS_AreaTravelTimeToGoalArea( BotPointAreaNum( castmove.endpos ), castmove.endpos, goal->areanum, cs->travelflags ) ) < ( starttraveltime + 200 ) ) {
					bestyaw = yaw;
					bestmoved = distmoved;
					besttraveltime = traveltime;
					VectorCopy( castmove.endpos, bestpos );
				}
			}
		}
		//
		cs->bs->cur_ps.viewangles[YAW] = oldyaw;
	}
	//
	if ( bestmoved > 0 ) {
		VectorCopy( bestpos, outpos );
		return qtrue;
	} else {
		return qfalse;
	}

//G_Printf("GetAvoid: %i ms\n", -pretime + Sys_MilliSeconds() );
}