コード例 #1
0
ファイル: be_aas_sample.cpp プロジェクト: Razish/CompJA
//===========================================================================
//
// Parameter:			-
// Returns:				-
// Changes Globals:		-
//===========================================================================
int AAS_PointReachabilityAreaIndex( vec3_t origin )
{
	int areanum, cluster, i, index;

	if (!aasworld.initialized)
		return 0;

	if ( !origin )
	{
		index = 0;
		for (i = 0; i < aasworld.numclusters; i++)
		{
			index += aasworld.clusters[i].numreachabilityareas;
		} //end for
		return index;
	} //end if

	areanum = AAS_PointAreaNum( origin );
	if ( !areanum || !AAS_AreaReachability(areanum) )
		return 0;
	cluster = aasworld.areasettings[areanum].cluster;
	areanum = aasworld.areasettings[areanum].clusterareanum;
	if (cluster < 0)
	{
		cluster = aasworld.portals[-cluster].frontcluster;
		areanum = aasworld.portals[-cluster].clusterareanum[0];
	} //end if

	index = 0;
	for (i = 0; i < cluster; i++)
	{
		index += aasworld.clusters[i].numreachabilityareas;
	} //end for
	index += areanum;
	return index;
} //end of the function AAS_PointReachabilityAreaIndex
コード例 #2
0
//===========================================================================
//
// Parameter:				-
// Returns:					-
// Changes Globals:		-
//===========================================================================
int AAS_AlternativeRouteGoals(vec3_t start, int startareanum, vec3_t goal, int goalareanum, int travelflags,
										 aas_altroutegoal_t *altroutegoals, int maxaltroutegoals,
										 int type)
{
#ifndef ENABLE_ALTROUTING
	return 0;
#else
	int i, j, bestareanum;
	int numaltroutegoals, nummidrangeareas;
	int starttime, goaltime, goaltraveltime;
	float dist, bestdist;
	vec3_t mid, dir;
#ifdef ALTROUTE_DEBUG
	int startmillisecs;

	startmillisecs = Sys_MilliSeconds();
#endif

	if (!startareanum || !goalareanum)
		return 0;
	//travel time towards the goal area
	goaltraveltime = AAS_AreaTravelTimeToGoalArea(startareanum, start, goalareanum, travelflags);
	//clear the midrange areas
	Com_Memset(midrangeareas, 0, aasworld.numareas * sizeof(midrangearea_t));
	numaltroutegoals = 0;
	//
	nummidrangeareas = 0;
	//
	for (i = 1; i < aasworld.numareas; i++)
	{
		//
		if (!(type & ALTROUTEGOAL_ALL))
		{
			if (!(type & ALTROUTEGOAL_CLUSTERPORTALS && (aasworld.areasettings[i].contents & AREACONTENTS_CLUSTERPORTAL)))
			{
				if (!(type & ALTROUTEGOAL_VIEWPORTALS && (aasworld.areasettings[i].contents & AREACONTENTS_VIEWPORTAL)))
				{
					continue;
				} //end if
			} //end if
		} //end if
		//if the area has no reachabilities
		if (!AAS_AreaReachability(i)) continue;
		//tavel time from the area to the start area
		starttime = AAS_AreaTravelTimeToGoalArea(startareanum, start, i, travelflags);
		if (!starttime) continue;
		//if the travel time from the start to the area is greater than the shortest goal travel time
		if (starttime > (float) 1.1 * goaltraveltime) continue;
		//travel time from the area to the goal area
		goaltime = AAS_AreaTravelTimeToGoalArea(i, NULL, goalareanum, travelflags);
		if (!goaltime) continue;
		//if the travel time from the area to the goal is greater than the shortest goal travel time
		if (goaltime > (float) 0.8 * goaltraveltime) continue;
		//this is a mid range area
		midrangeareas[i].valid = qtrue;
		midrangeareas[i].starttime = starttime;
		midrangeareas[i].goaltime = goaltime;
		Log_Write("%d midrange area %d", nummidrangeareas, i);
		nummidrangeareas++;
	} //end for
	//
	for (i = 1; i < aasworld.numareas; i++)
	{
		if (!midrangeareas[i].valid) continue;
		//get the areas in one cluster
		numclusterareas = 0;
		AAS_AltRoutingFloodCluster_r(i);
		//now we've got a cluster with areas through which an alternative route could go
		//get the 'center' of the cluster
		VectorClear(mid);
		for (j = 0; j < numclusterareas; j++)
		{
			VectorAdd(mid, aasworld.areas[clusterareas[j]].center, mid);
		} //end for
		VectorScale(mid, 1.0 / numclusterareas, mid);
		//get the area closest to the center of the cluster
		bestdist = 999999;
		bestareanum = 0;
		for (j = 0; j < numclusterareas; j++)
		{
			VectorSubtract(mid, aasworld.areas[clusterareas[j]].center, dir);
			dist = VectorLength(dir);
			if (dist < bestdist)
			{
				bestdist = dist;
				bestareanum = clusterareas[j];
			} //end if
		} //end for
		//now we've got an area for an alternative route
		//FIXME: add alternative goal origin
		VectorCopy(aasworld.areas[bestareanum].center, altroutegoals[numaltroutegoals].origin);
		altroutegoals[numaltroutegoals].areanum = bestareanum;
		altroutegoals[numaltroutegoals].starttraveltime = midrangeareas[bestareanum].starttime;
		altroutegoals[numaltroutegoals].goaltraveltime = midrangeareas[bestareanum].goaltime;
		altroutegoals[numaltroutegoals].extratraveltime =
					(midrangeareas[bestareanum].starttime + midrangeareas[bestareanum].goaltime) -
								goaltraveltime;
		numaltroutegoals++;
		//
#ifdef ALTROUTE_DEBUG
		AAS_ShowAreaPolygons(bestareanum, 1, qtrue);
#endif
		//don't return more than the maximum alternative route goals
		if (numaltroutegoals >= maxaltroutegoals) break;
	} //end for
#ifdef ALTROUTE_DEBUG
	botimport.Print(PRT_MESSAGE, "alternative route goals in %d msec\n", Sys_MilliSeconds() - startmillisecs);
#endif
	return numaltroutegoals;
#endif
} //end of the function AAS_AlternativeRouteGoals
コード例 #3
0
int AAS_AlternativeRouteGoals(vec3_t start, vec3_t goal, int travelflags,
                              aas_altroutegoal_t *altroutegoals, int maxaltroutegoals,
                              int color)
{
#ifndef ENABLE_ALTROUTING
	return 0;
#else
	int    i, j, startareanum, goalareanum, bestareanum;
	int    numaltroutegoals, nummidrangeareas;
	int    starttime, goaltime, goaltraveltime;
	float  dist, bestdist;
	vec3_t mid, dir;
	int    reachnum, time;
	int    a1, a2;
/*#ifdef DEBUG
    int startmillisecs;

    startmillisecs = Sys_MilliSeconds();
#endif*/

	startareanum = AAS_PointAreaNum(start);
	if (!startareanum)
	{
		return 0;
	}
	goalareanum = AAS_PointAreaNum(goal);
	if (!goalareanum)
	{
		VectorCopy(goal, dir);
		dir[2]     += 30;
		goalareanum = AAS_PointAreaNum(dir);
		if (!goalareanum)
		{
			return 0;
		}
	}
	//travel time towards the goal area
	goaltraveltime = AAS_AreaTravelTimeToGoalArea(startareanum, start, goalareanum, travelflags);
	//clear the midrange areas
	memset(midrangeareas, 0, (*aasworld).numareas * sizeof(midrangearea_t));
	numaltroutegoals = 0;
	//
	nummidrangeareas = 0;
	//
	for (i = 1; i < (*aasworld).numareas; i++)
	{
		//
		if (!((*aasworld).areasettings[i].contents & AREACONTENTS_ROUTEPORTAL) &&
		    !((*aasworld).areasettings[i].contents & AREACONTENTS_CLUSTERPORTAL))
		{
			continue;
		}
		//if the area has no reachabilities
		if (!AAS_AreaReachability(i))
		{
			continue;
		}
		//tavel time from the area to the start area
		starttime = AAS_AreaTravelTimeToGoalArea(startareanum, start, i, travelflags);
		if (!starttime)
		{
			continue;
		}
		//if the travel time from the start to the area is greater than the shortest goal travel time
		if (starttime > 500 + 3.0 * goaltraveltime)
		{
			continue;
		}
		//travel time from the area to the goal area
		goaltime = AAS_AreaTravelTimeToGoalArea(i, NULL, goalareanum, travelflags);
		if (!goaltime)
		{
			continue;
		}
		//if the travel time from the area to the goal is greater than the shortest goal travel time
		if (goaltime > 500 + 3.0 * goaltraveltime)
		{
			continue;
		}
		//this is a mid range area
		midrangeareas[i].valid     = qtrue;
		midrangeareas[i].starttime = starttime;
		midrangeareas[i].goaltime  = goaltime;
		Log_Write("%d midrange area %d", nummidrangeareas, i);
		nummidrangeareas++;
	} //end for
	  //
	for (i = 1; i < (*aasworld).numareas; i++)
	{
		if (!midrangeareas[i].valid)
		{
			continue;
		}
		//get the areas in one cluster
		numclusterareas = 0;
		AAS_AltRoutingFloodCluster_r(i);
		//now we've got a cluster with areas through which an alternative route could go
		//get the 'center' of the cluster
		VectorClear(mid);
		for (j = 0; j < numclusterareas; j++)
		{
			VectorAdd(mid, (*aasworld).areas[clusterareas[j]].center, mid);
		} //end for
		VectorScale(mid, 1.0 / numclusterareas, mid);
		//get the area closest to the center of the cluster
		bestdist    = 999999;
		bestareanum = 0;
		for (j = 0; j < numclusterareas; j++)
		{
			VectorSubtract(mid, (*aasworld).areas[clusterareas[j]].center, dir);
			dist = VectorLength(dir);
			if (dist < bestdist)
			{
				bestdist    = dist;
				bestareanum = clusterareas[j];
			} //end if
		} //end for
		  // make sure the route to the destination isn't in the same direction as the route to the source
		if (!AAS_AreaRouteToGoalArea(bestareanum, (*aasworld).areawaypoints[bestareanum], goalareanum, travelflags, &time, &reachnum))
		{
			continue;
		}
		a1 = (*aasworld).reachability[reachnum].areanum;
		if (!AAS_AreaRouteToGoalArea(bestareanum, (*aasworld).areawaypoints[bestareanum], startareanum, travelflags, &time, &reachnum))
		{
			continue;
		}
		a2 = (*aasworld).reachability[reachnum].areanum;
		if (a1 == a2)
		{
			continue;
		}
		//now we've got an area for an alternative route
		//FIXME: add alternative goal origin
		VectorCopy((*aasworld).areawaypoints[bestareanum], altroutegoals[numaltroutegoals].origin);
		altroutegoals[numaltroutegoals].areanum         = bestareanum;
		altroutegoals[numaltroutegoals].starttraveltime = midrangeareas[bestareanum].starttime;
		altroutegoals[numaltroutegoals].goaltraveltime  = midrangeareas[bestareanum].goaltime;
		altroutegoals[numaltroutegoals].extratraveltime =
		    (midrangeareas[bestareanum].starttime + midrangeareas[bestareanum].goaltime) -
		    goaltraveltime;
		numaltroutegoals++;
		//
/*#ifdef DEBUG
        botimport.Print(PRT_MESSAGE, "alternative route goal area %d, numclusterareas = %d\n", bestareanum, numclusterareas);
        if (color)
        {
            AAS_DrawPermanentCross((*aasworld).areas[bestareanum].center, 10, color);
        } //end if
        //AAS_ShowArea(bestarea, qtrue);
#endif*/
		//don't return more than the maximum alternative route goals
		if (numaltroutegoals >= maxaltroutegoals)
		{
			break;
		}
	} //end for
	  //botimport.Print(PRT_MESSAGE, "%d alternative route goals\n", numaltroutegoals);
#ifdef DEBUG
//	botimport.Print(PRT_MESSAGE, "alternative route goals in %d msec\n", Sys_MilliSeconds() - startmillisecs);
#endif
	return numaltroutegoals;
#endif
} //end of the function AAS_AlternativeRouteGoals
コード例 #4
0
ファイル: be_aas_cluster.c プロジェクト: OADoctor/SmokinGuns
//===========================================================================
//
// Parameter:			-
// Returns:				-
// Changes Globals:		-
//===========================================================================
void AAS_NumberClusterAreas(int clusternum)
{
	int i, portalnum;
	aas_cluster_t *cluster;
	aas_portal_t *portal;

	aasworld.clusters[clusternum].numareas = 0;
	aasworld.clusters[clusternum].numreachabilityareas = 0;
	//number all areas in this cluster WITH reachabilities
	for (i = 1; i < aasworld.numareas; i++)
	{
		//
		if (aasworld.areasettings[i].cluster != clusternum) continue;
		//
		if (!AAS_AreaReachability(i)) continue;
		//
		aasworld.areasettings[i].clusterareanum = aasworld.clusters[clusternum].numareas;
		//the cluster has an extra area
		aasworld.clusters[clusternum].numareas++;
		aasworld.clusters[clusternum].numreachabilityareas++;
	} //end for
	//number all portals in this cluster WITH reachabilities
	cluster = &aasworld.clusters[clusternum];
	for (i = 0; i < cluster->numportals; i++)
	{
		portalnum = aasworld.portalindex[cluster->firstportal + i];
		portal = &aasworld.portals[portalnum];
		if (!AAS_AreaReachability(portal->areanum)) continue;
		if (portal->frontcluster == clusternum)
		{
			portal->clusterareanum[0] = cluster->numareas++;
			aasworld.clusters[clusternum].numreachabilityareas++;
		} //end if
		else
		{
			portal->clusterareanum[1] = cluster->numareas++;
			aasworld.clusters[clusternum].numreachabilityareas++;
		} //end else
	} //end for
	//number all areas in this cluster WITHOUT reachabilities
	for (i = 1; i < aasworld.numareas; i++)
	{
		//
		if (aasworld.areasettings[i].cluster != clusternum) continue;
		//
		if (AAS_AreaReachability(i)) continue;
		//
		aasworld.areasettings[i].clusterareanum = aasworld.clusters[clusternum].numareas;
		//the cluster has an extra area
		aasworld.clusters[clusternum].numareas++;
	} //end for
	//number all portals in this cluster WITHOUT reachabilities
	cluster = &aasworld.clusters[clusternum];
	for (i = 0; i < cluster->numportals; i++)
	{
		portalnum = aasworld.portalindex[cluster->firstportal + i];
		portal = &aasworld.portals[portalnum];
		if (AAS_AreaReachability(portal->areanum)) continue;
		if (portal->frontcluster == clusternum)
		{
			portal->clusterareanum[0] = cluster->numareas++;
		} //end if
		else
		{
			portal->clusterareanum[1] = cluster->numareas++;
		} //end else
	} //end for
} //end of the function AAS_NumberClusterAreas
コード例 #5
0
ファイル: be_ai_goal.c プロジェクト: JackalFrost/RTCW-WSGF
//===========================================================================
//
// Parameter:				-
// Returns:					-
// Changes Globals:		-
//===========================================================================
int BotChooseNBGItem( int goalstate, vec3_t origin, int *inventory, int travelflags,
					  bot_goal_t *ltg, float maxtime ) {
	int areanum, t, weightnum, ltg_time;
	float weight, bestweight, avoidtime;
	iteminfo_t *iteminfo;
	itemconfig_t *ic;
	levelitem_t *li, *bestitem;
	bot_goal_t goal;
	bot_goalstate_t *gs;

	gs = BotGoalStateFromHandle( goalstate );
	if ( !gs ) {
		return qfalse;
	}
	if ( !gs->itemweightconfig ) {
		return qfalse;
	}
	//get the area the bot is in
	areanum = BotReachabilityArea( origin, gs->client );
	//if the bot is in solid or if the area the bot is in has no reachability links
	if ( !areanum || !AAS_AreaReachability( areanum ) ) {
		//use the last valid area the bot was in
		areanum = gs->lastreachabilityarea;
	} //end if
	  //remember the last area with reachabilities the bot was in
	gs->lastreachabilityarea = areanum;
	//if still in solid
	if ( !areanum ) {
		return qfalse;
	}
	//
	if ( ltg ) {
		ltg_time = AAS_AreaTravelTimeToGoalArea( areanum, origin, ltg->areanum, travelflags );
	} else { ltg_time = 99999;}
	//the item configuration
	ic = itemconfig;
	if ( !itemconfig ) {
		return qfalse;
	}
	//best weight and item so far
	bestweight = 0;
	bestitem = NULL;
	memset( &goal, 0, sizeof( bot_goal_t ) );
	//go through the items in the level
	for ( li = levelitems; li; li = li->next )
	{
		if ( g_gametype == GT_SINGLE_PLAYER ) {
			if ( li->notsingle ) {
				continue;
			}
		} else if ( g_gametype >= GT_TEAM )     {
			if ( li->notteam ) {
				continue;
			}
		} else {
			if ( li->notfree ) {
				continue;
			}
		}
		//if the item is in a possible goal area
		if ( !li->goalareanum ) {
			continue;
		}
		//get the fuzzy weight function for this item
		iteminfo = &ic->iteminfo[li->iteminfo];
		weightnum = gs->itemweightindex[iteminfo->number];
		if ( weightnum < 0 ) {
			continue;
		}
		//if this goal is in the avoid goals
		if ( BotAvoidGoalTime( goalstate, li->number ) > 0 ) {
			continue;
		}
		//
#ifdef UNDECIDEDFUZZY
		weight = FuzzyWeightUndecided( inventory, gs->itemweightconfig, weightnum );
#else
		weight = FuzzyWeight( inventory, gs->itemweightconfig, weightnum );
#endif //UNDECIDEDFUZZY
#ifdef DROPPEDWEIGHT
		//HACK: to make dropped items more attractive
		if ( li->timeout ) {
			weight += 1000;
		}
#endif //DROPPEDWEIGHT
		if ( weight > 0 ) {
			//get the travel time towards the goal area
			t = AAS_AreaTravelTimeToGoalArea( areanum, origin, li->goalareanum, travelflags );
			//if the goal is reachable
			if ( t > 0 && t < maxtime ) {
				weight /= (float) t * TRAVELTIME_SCALE;
				//
				if ( weight > bestweight ) {
					t = 0;
					if ( ltg && !li->timeout ) {
						//get the travel time from the goal to the long term goal
						t = AAS_AreaTravelTimeToGoalArea( li->goalareanum, li->goalorigin, ltg->areanum, travelflags );
					} //end if
					  //if the travel back is possible and doesn't take too long
					if ( t <= ltg_time ) {
						bestweight = weight;
						bestitem = li;
					} //end if
				} //end if
			} //end if
		} //end if
	} //end for
	  //if no goal item found
	if ( !bestitem ) {
		return qfalse;
	}
	//create a bot goal for this item
	iteminfo = &ic->iteminfo[bestitem->iteminfo];
	VectorCopy( bestitem->goalorigin, goal.origin );
	VectorCopy( iteminfo->mins, goal.mins );
	VectorCopy( iteminfo->maxs, goal.maxs );
	goal.areanum = bestitem->goalareanum;
	goal.entitynum = bestitem->entitynum;
	goal.number = bestitem->number;
	goal.flags = GFL_ITEM;
	goal.iteminfo = bestitem->iteminfo;
	//add the chosen goal to the goals to avoid for a while
	avoidtime = iteminfo->respawntime * 0.5;
	if ( avoidtime < 10 ) {
		avoidtime = AVOID_TIME;
	}
	//if it's a dropped item
	if ( bestitem->timeout ) {
		avoidtime = AVOIDDROPPED_TIME;
	}
	BotAddToAvoidGoals( gs, bestitem->number, avoidtime );
	//push the goal on the stack
	BotPushGoal( goalstate, &goal );
	//
#ifdef DEBUG_AI_GOAL
	if ( bestitem->timeout ) {
		botimport.Print( PRT_MESSAGE, "new nbg dropped item %s\n", ic->iteminfo[bestitem->iteminfo].classname );
	} //end if
	iteminfo = &ic->iteminfo[bestitem->iteminfo];
	botimport.Print( PRT_MESSAGE, "new nbg \"%s\"\n", iteminfo->classname );
#endif //DEBUG_AI_GOAL
	return qtrue;
} //end of the function BotChooseNBGItem
コード例 #6
0
ファイル: ai_goal.cpp プロジェクト: janisl/jlquake
static bool BotChooseNBGItem( int goalstate, const vec3_t origin, const int* inventory, int travelflags,
	const bot_goal_t* ltg, float maxtime ) {
	bot_goalstate_t* gs = BotGoalStateFromHandle( goalstate );
	if ( !gs ) {
		return false;
	}
	if ( !gs->itemweightconfig ) {
		return false;
	}
	//get the area the bot is in
	int areanum = BotReachabilityArea( origin, gs->client );
	//if the bot is in solid or if the area the bot is in has no reachability links
	if ( !areanum || !AAS_AreaReachability( areanum ) ) {
		//use the last valid area the bot was in
		areanum = gs->lastreachabilityarea;
	}
	//remember the last area with reachabilities the bot was in
	gs->lastreachabilityarea = areanum;
	//if still in solid
	if ( !areanum ) {
		return false;
	}

	int ltg_time;
	if ( ltg ) {
		ltg_time = AAS_AreaTravelTimeToGoalArea( areanum, origin, ltg->areanum, travelflags );
	} else {
		ltg_time = 99999;
	}
	//the item configuration
	itemconfig_t* ic = itemconfig;
	if ( !itemconfig ) {
		return false;
	}
	//best weight and item so far
	float bestweight = 0;
	levelitem_t* bestitem = NULL;
	//go through the items in the level
	for ( levelitem_t* li = levelitems; li; li = li->next ) {
		if ( GGameType & GAME_ET ) {
			if ( g_singleplayer ) {
				if ( li->flags & IFL_NOTSINGLE ) {
					continue;
				}
			}
		} else {
			if ( g_gametype == Q3GT_SINGLE_PLAYER ) {
				if ( li->flags & IFL_NOTSINGLE ) {
					continue;
				}
			} else if ( g_gametype >= Q3GT_TEAM ) {
				if ( li->flags & IFL_NOTTEAM ) {
					continue;
				}
			} else {
				if ( li->flags & IFL_NOTFREE ) {
					continue;
				}
			}
		}
		if ( GGameType & GAME_Quake3 && li->flags & IFL_NOTBOT ) {
			continue;
		}
		//if the item is in a possible goal area
		if ( !li->goalareanum ) {
			continue;
		}
		//FIXME: is this a good thing? added this for items that never spawned into the game (f.i. CTF flags in obelisk)
		if ( GGameType & GAME_Quake3 && !li->entitynum && !( li->flags & IFL_ROAM ) ) {
			continue;
		}
		//get the fuzzy weight function for this item
		iteminfo_t* iteminfo = &ic->iteminfo[ li->iteminfo ];
		int weightnum = gs->itemweightindex[ iteminfo->number ];
		if ( weightnum < 0 ) {
			continue;
		}
		//if this goal is in the avoid goals
		if ( !( GGameType & GAME_Quake3 ) && BotAvoidGoalTime( goalstate, li->number ) > 0 ) {
			continue;
		}

		float weight = FuzzyWeightUndecided( inventory, gs->itemweightconfig, weightnum );
		//HACK: to make dropped items more attractive
		if ( li->timeout ) {
			weight += GGameType & GAME_Quake3 ? droppedweight->value : 1000;
		}
		//use weight scale for item_botroam
		if ( GGameType & GAME_Quake3 && li->flags & IFL_ROAM ) {
			weight *= li->weight;
		}

		if ( weight > 0 ) {
			//get the travel time towards the goal area
			int t = AAS_AreaTravelTimeToGoalArea( areanum, origin, li->goalareanum, travelflags );
			//if the goal is reachable
			if ( t > 0 && t < maxtime ) {
				if ( GGameType & GAME_Quake3 ) {
					//if this item won't respawn before we get there
					float avoidtime = BotAvoidGoalTime( goalstate, li->number );
					if ( avoidtime - t * 0.009 > 0 ) {
						continue;
					}
				}

				weight /= ( float )t * TRAVELTIME_SCALE;

				if ( weight > bestweight ) {
					t = 0;
					if ( ltg && !li->timeout ) {
						//get the travel time from the goal to the long term goal
						t = AAS_AreaTravelTimeToGoalArea( li->goalareanum, li->goalorigin, ltg->areanum, travelflags );
					}
					//if the travel back is possible and doesn't take too long
					if ( t <= ltg_time ) {
						bestweight = weight;
						bestitem = li;
					}
				}
			}
		}
	}
	//if no goal item found
	if ( !bestitem ) {
		return false;
	}
	//create a bot goal for this item
	bot_goal_t goal;
	Com_Memset( &goal, 0, sizeof ( bot_goal_t ) );
	iteminfo_t* iteminfo = &ic->iteminfo[ bestitem->iteminfo ];
	VectorCopy( bestitem->goalorigin, goal.origin );
	VectorCopy( iteminfo->mins, goal.mins );
	VectorCopy( iteminfo->maxs, goal.maxs );
	goal.areanum = bestitem->goalareanum;
	goal.entitynum = bestitem->entitynum;
	goal.number = bestitem->number;
	goal.flags = GFL_ITEM;
	if ( GGameType & GAME_Quake3 ) {
		if ( bestitem->timeout ) {
			goal.flags |= GFL_DROPPED;
		}
		if ( bestitem->flags & IFL_ROAM ) {
			goal.flags |= GFL_ROAM;
		}
	}
	goal.iteminfo = bestitem->iteminfo;
	float avoidtime;
	if ( GGameType & GAME_Quake3 ) {
		//if it's a dropped item
		if ( bestitem->timeout ) {
			avoidtime = AVOID_DROPPED_TIME;
		} else {
			avoidtime = iteminfo->respawntime;
			if ( !avoidtime ) {
				avoidtime = AVOID_DEFAULT_TIME;
			}
			if ( avoidtime < AVOID_MINIMUM_TIME ) {
				avoidtime = AVOID_MINIMUM_TIME;
			}
		}
	} else {
		avoidtime = iteminfo->respawntime * 0.5;
		if ( avoidtime < 10 ) {
			avoidtime = AVOID_DEFAULT_TIME;
		}
		//if it's a dropped item
		if ( bestitem->timeout ) {
			avoidtime = AVOID_DROPPED_TIME_WOLF;
		}
	}
	//add the chosen goal to the goals to avoid for a while
	BotAddToAvoidGoals( gs, bestitem->number, avoidtime );
	//push the goal on the stack
	BotPushGoal( goalstate, &goal, sizeof ( goal ) );
	return true;
}