/* ============ AIChar_AIScript_AlertEntity triggered spawning, called from AI scripting ============ */ void AIChar_AIScript_AlertEntity( gentity_t *ent ) { vec3_t mins, maxs; int numTouch, touch[10], i; cast_state_t *cs; if ( !ent->aiInactive ) { return; } cs = AICast_GetCastState( ent->s.number ); // if the current bounding box is invalid, then wait VectorAdd( ent->r.currentOrigin, ent->r.mins, mins ); VectorAdd( ent->r.currentOrigin, ent->r.maxs, maxs ); trap_UnlinkEntity( ent ); numTouch = trap_EntitiesInBox( mins, maxs, touch, 10 ); // check that another client isn't inside us if ( numTouch ) { for ( i = 0; i < numTouch; i++ ) { // RF, note we should only check against clients since zombies need to spawn inside func_explosive (so they dont clip into view after it explodes) if ( g_entities[touch[i]].client && g_entities[touch[i]].r.contents == CONTENTS_BODY ) { //if (g_entities[touch[i]].r.contents & MASK_PLAYERSOLID) break; } } if ( i == numTouch ) { numTouch = 0; } } if ( numTouch ) { // invalid location cs->aiFlags |= AIFL_WAITINGTOSPAWN; return; } // RF, has to disable this so I could test some maps which have erroneously placed alertentity calls //ent->AIScript_AlertEntity = NULL; cs->aiFlags &= ~AIFL_WAITINGTOSPAWN; ent->aiInactive = qfalse; trap_LinkEntity( ent ); // trigger a spawn script event AICast_ScriptEvent( AICast_GetCastState( ent->s.number ), "spawn", "" ); // make it think so we update animations/angles AICast_Think( ent->s.number, (float)FRAMETIME / 1000 ); cs->lastThink = level.time; AICast_UpdateInput( cs, FRAMETIME ); trap_BotUserCommand( cs->bs->client, &( cs->lastucmd ) ); }
/* ============ AICast_StartServerFrame Do movements, sighting, etc ============ */ void AICast_StartServerFrame( int time ) { int i, elapsed, count, clCount; cast_state_t *cs; int castcount; static int lasttime; static vmCvar_t aicast_disable; gentity_t *ent; cast_state_t *pcs; // int oldLegsTimer; if ( trap_Cvar_VariableIntegerValue( "savegame_loading" ) ) { return; } if ( g_gametype.integer != GT_SINGLE_PLAYER ) { return; } if ( saveGamePending ) { return; } // if waiting at intermission, don't think if ( strlen( g_missionStats.string ) > 1 ) { return; } if ( !aicast_disable.handle ) { trap_Cvar_Register( &aicast_disable, "aicast_disable", "0", CVAR_CHEAT ); } else { trap_Cvar_Update( &aicast_disable ); if ( aicast_disable.integer ) { return; } } trap_Cvar_Update( &aicast_debug ); // no need to think during the intermission if ( level.intermissiontime ) { return; } // // make sure the AAS gets updated trap_BotLibStartFrame( (float) time / 1000 ); // // elapsed = time - lasttime; if ( elapsed == 0 ) { return; // no time has elapsed } pcs = AICast_GetCastState( 0 ); //G_Printf( "AI startserverframe: %i\n", time ); if ( elapsed < 0 ) { elapsed = 0; lasttime = time; } // don't let the framerate drop below 10 if ( elapsed > 100 ) { elapsed = 100; } // // process player's current script if it exists AICast_ScriptRun( AICast_GetCastState( 0 ), qfalse ); // AICast_SightUpdate( (int)( (float)SIGHT_PER_SEC * ( (float)elapsed / 1000 ) ) ); // count = 0; castcount = 0; clCount = 0; ent = g_entities; // //update the AI characters // TTimo gcc: left-hand operand of comma expression has no effect // initial line: for (i = 0; i < aicast_maxclients, clCount < level.numPlayingClients; i++, ent++) for ( i = 0; ( i < aicast_maxclients ) && ( clCount < level.numPlayingClients ) ; i++, ent++ ) { if ( ent->client ) { clCount++; } // cs = AICast_GetCastState( i ); // is this a cast AI? if ( cs->bs ) { if ( ent->aiInactive == qfalse && ent->inuse ) { // elapsed = level.time - cs->lastMoveThink; // // optimization, if they're not in the player's PVS, and they aren't trying to move, then don't bother thinking if ( ( ( ent->health > 0 ) && ( elapsed > 300 ) ) || ( g_entities[0].client && g_entities[0].client->cameraPortal ) || ( cs->vislist[0].visible_timestamp == cs->vislist[0].lastcheck_timestamp ) || ( pcs->vislist[cs->entityNum].visible_timestamp == pcs->vislist[cs->entityNum].lastcheck_timestamp ) || ( VectorLength( ent->client->ps.velocity ) > 0 ) || ( cs->bs->lastucmd.forwardmove || cs->bs->lastucmd.rightmove || cs->bs->lastucmd.upmove > 0 || cs->bs->lastucmd.buttons || cs->bs->lastucmd.wbuttons ) || ( trap_InPVS( cs->bs->origin, g_entities[0].s.pos.trBase ) ) ) { // do pvs check last, since it's the most expensive to call // oldLegsTimer = ent->client->ps.legsTimer; // // send it's movement commands // serverTime = time; AICast_UpdateInput( cs, elapsed ); trap_BotUserCommand( cs->bs->client, &( cs->bs->lastucmd ) ); cs->lastMoveThink = level.time; // // check for anim changes that may require us to stay still // /* if (oldLegsTimer != ent->client->ps.legsTimer) { // dont move until they are finished if (cs->castScriptStatus.scriptNoMoveTime < level.time + ent->client->ps.legsTimer) { cs->castScriptStatus.scriptNoMoveTime = level.time + ent->client->ps.legsTimer; } } */ } } else { trap_UnlinkEntity( ent ); } // // see if we've checked all cast AI's if ( ++castcount >= numcast ) { break; } } } // lasttime = time; }