1 /*
2 Copyright (C) 1997-2001 Id Software, Inc.
3 
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8 
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 
13 See the GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18 --------------------------------------------------------------
19 The ACE Bot is a product of Steve Yeager, and is available from
20 the ACE Bot homepage, at http://www.axionfx.com/ace.
21 
22 This program is a modification of the ACE Bot, and is therefore
23 in NO WAY supported by Steve Yeager.
24 */
25 
26 #include "../g_local.h"
27 #include "ai_local.h"
28 
29 
30 
31 //==========================================
32 // AI_FindCost
33 // Determine cost of moving from one node to another
34 //==========================================
AI_FindCost(int from,int to,int movetypes)35 int AI_FindCost(int from, int to, int movetypes)
36 {
37 	astarpath_t	path;
38 
39 	if( !AStar_GetPath( from, to, movetypes, &path ) )
40 		return -1;
41 
42 	return path.numNodes;
43 }
44 
45 
46 //==========================================
47 // AI_FindClosestReachableNode
48 // Find the closest node to the player within a certain range
49 //==========================================
AI_FindClosestReachableNode(vec3_t origin,edict_t * passent,int range,int flagsmask)50 int AI_FindClosestReachableNode( vec3_t origin, edict_t *passent, int range, int flagsmask )
51 {
52 	int			i;
53 	float		closest = 99999;
54 	float		dist;
55 	int			node=-1;
56 	vec3_t		v;
57 	trace_t		tr;
58 	float		rng;
59 	vec3_t		maxs,mins;
60 
61 	VectorSet( mins, -15, -15, -15 );
62 	VectorSet( maxs, 15, 15, 15 );
63 
64 	// For Ladders, do not worry so much about reachability
65 	if( flagsmask & NODEFLAGS_LADDER )
66 	{
67 		VectorCopy(vec3_origin,maxs);
68 		VectorCopy(vec3_origin,mins);
69 	}
70 
71 	rng = (float)(range * range); // square range for distance comparison (eliminate sqrt)
72 
73 	for(i=0;i<nav.num_nodes;i++)
74 	{
75 		if( flagsmask == NODE_ALL || nodes[i].flags & flagsmask )
76 		{
77 			VectorSubtract( nodes[i].origin, origin, v );
78 
79 			dist = v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
80 
81 			if(dist < closest && dist < rng)
82 			{
83 				// make sure it is visible
84 				tr = gi.trace( origin, mins, maxs, nodes[i].origin, passent, MASK_AISOLID);
85 				if(tr.fraction == 1.0)
86 				{
87 					node = i;
88 					closest = dist;
89 				}
90 			}
91 		}
92 	}
93 	return node;
94 }
95 
96 
97 //==========================================
98 // AI_SetGoal
99 // set the goal //jabot092
100 //==========================================
AI_SetGoal(edict_t * self,int goal_node)101 void AI_SetGoal(edict_t *self, int goal_node)
102 {
103 	int			node;
104 
105 	self->ai->goal_node = goal_node;
106 	node = AI_FindClosestReachableNode( self->s.origin, self, NODE_DENSITY*3, NODE_ALL );
107 
108 	if(node == -1) {
109 		AI_SetUpMoveWander(self);
110 		return;
111 	}
112 
113 	//------- ASTAR -----------
114 	if( !AStar_GetPath( node, goal_node, self->ai->pers.moveTypesMask, &self->ai->path ) )
115 	{
116 		AI_SetUpMoveWander(self);
117 		return;
118 	}
119 	self->ai->current_node = self->ai->path.nodes[self->ai->path.numNodes];
120 	//-------------------------
121 
122 //	if(AIDevel.debugChased && bot_showlrgoal->value)
123 //		G_PrintMsg (AIDevel.chaseguy, PRINT_HIGH, "%s: GOAL: new START NODE selected %d\n", self->ai->pers.netname, node);
124 
125 	self->ai->next_node = self->ai->current_node; // make sure we get to the nearest node first
126 	self->ai->node_timeout = 0;
127 }
128 
129 
130 //==========================================
131 // AI_FollowPath
132 // Move closer to goal by pointing the bot to the next node
133 // that is closer to the goal //jabot092 (path-> to path.)
134 //==========================================
AI_FollowPath(edict_t * self)135 qboolean AI_FollowPath( edict_t *self )
136 {
137 	vec3_t			v;
138 	float			dist;
139 
140 	// Show the path
141 	if(bot_showpath->value)
142 	{
143 		if( AIDevel.debugChased )
144 			AITools_DrawPath(self, self->ai->current_node, self->ai->goal_node);
145 	}
146 
147 	if( self->ai->goal_node == INVALID )
148 		return false;
149 
150 	// Try again?
151 	if(self->ai->node_timeout++ > 30)
152 	{
153 		if(self->ai->tries++ > 3)
154 			return false;
155 		else
156 			AI_SetGoal( self, self->ai->goal_node );
157 	}
158 
159 	// Are we there yet?
160 	VectorSubtract( self->s.origin, nodes[self->ai->next_node].origin, v );
161 	dist = VectorLength(v);
162 
163 	//special lower plat reached check
164 	if( dist < 64
165 		&& nodes[self->ai->current_node].flags & NODEFLAGS_PLATFORM
166 		&& nodes[self->ai->next_node].flags & NODEFLAGS_PLATFORM
167 		&& self->groundentity && self->groundentity->use == Use_Plat)
168 		dist = 16;
169 
170 	if( (dist < 32 && nodes[self->ai->next_node].flags != NODEFLAGS_JUMPPAD && nodes[self->ai->next_node].flags != NODEFLAGS_TELEPORTER_IN)
171 		|| (self->ai->status.jumpadReached && nodes[self->ai->next_node].flags & NODEFLAGS_JUMPPAD)
172 		|| (self->ai->status.TeleportReached && nodes[self->ai->next_node].flags & NODEFLAGS_TELEPORTER_IN) )
173 	{
174 		// reset timeout
175 		self->ai->node_timeout = 0;
176 
177 		if( self->ai->next_node == self->ai->goal_node )
178 		{
179 			//if(AIDevel.debugChased && bot_showlrgoal->value)
180 			//	G_PrintMsg (AIDevel.chaseguy, PRINT_HIGH, "%s: GOAL REACHED!\n", self->ai->pers.netname);
181 
182 			//if botroam, setup a timeout for it
183 			if( nodes[self->ai->goal_node].flags & NODEFLAGS_BOTROAM )
184 			{
185 				int		i;
186 				for( i=0; i<nav.num_broams; i++) {	//find the broam
187 					if( nav.broams[i].node != self->ai->goal_node )
188 						continue;
189 
190 					//if(AIDevel.debugChased && bot_showlrgoal->integer)
191 					//	G_PrintMsg (AIDevel.chaseguy, PRINT_HIGH, "%s: BotRoam Time Out set up for node %i\n", self->ai->pers.netname, nav.broams[i].node);
192 					//Com_Printf( "%s: BotRoam Time Out set up for node %i\n", self->ai->pers.netname, nav.broams[i].node);
193 					self->ai->status.broam_timeouts[i] = level.time + 15.0;
194 					break;
195 				}
196 			}
197 
198 			// Pick a new goal
199 			AI_PickLongRangeGoal(self);
200 		}
201 		else
202 		{
203 			self->ai->current_node = self->ai->next_node;
204 			if( self->ai->path.numNodes )
205 				self->ai->path.numNodes--;
206 			self->ai->next_node = self->ai->path.nodes[self->ai->path.numNodes];
207 		}
208 	}
209 
210 	if(self->ai->current_node == -1 || self->ai->next_node == -1)
211 		return false;
212 
213 	// Set bot's movement vector
214 	VectorSubtract( nodes[self->ai->next_node].origin, self->s.origin , self->ai->move_vector );
215 	return true;
216 }
217