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