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"; }
/* ============ 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() ); }