/////////////////////////////////////////////////////////////////////// // Move closer to goal by pointing the bot to the next node // that is closer to the goal /////////////////////////////////////////////////////////////////////// qboolean ACEND_FollowPath(edict_t *self) { vec3_t v; ////////////////////////////////////////// // Show the path (uncomment for debugging) // show_path_from = self->current_node; // show_path_to = self->goal_node; // ACEND_DrawPath(); ////////////////////////////////////////// // Try again? if(self->node_timeout ++ > 30) { if(self->tries++ > 3) return false; else ACEND_SetGoal(self,self->goal_node); } // Are we there yet? VectorSubtract(self->s.origin,nodes[self->next_node].origin,v); if(VectorLength(v) < 32) { // reset timeout self->node_timeout = 0; if(self->next_node == self->goal_node) { if(debug_mode) debug_printf("%s reached goal!\n",self->client->pers.netname); ACEAI_PickLongRangeGoal(self); // Pick a new goal } else { self->current_node = self->next_node; self->next_node = path_table[self->current_node][self->goal_node]; } } if(self->current_node == -1 || self->next_node ==-1) return false; // Set bot's movement vector VectorSubtract (nodes[self->next_node].origin, self->s.origin , self->move_vector); return true; }
// Move closer to goal by pointing the bot to the next node // that is closer to the goal qboolean ACEND_FollowPath(gentity_t * self) { // try again? if(self->bs.node_timeout++ > 30) { if(self->bs.tries++ > 3) return qfalse; else ACEND_SetGoal(self, self->bs.goalNode); } // are we there yet? //if(Distance(self->client->ps.origin, nodes[self->bs.nextNode].origin) < 32) if(BoundsIntersectPoint(self->r.absmin, self->r.absmax, nodes[self->bs.nextNode].origin)) { // reset timeout self->bs.node_timeout = 0; if(self->bs.nextNode == self->bs.goalNode) { if(ace_debug.integer) trap_SendServerCommand(-1, va("print \"%s: reached goal!\n\"", self->client->pers.netname)); ACEAI_PickLongRangeGoal(self); // pick a new goal } else { self->bs.currentNode = self->bs.nextNode; self->bs.nextNode = path_table[self->bs.currentNode][self->bs.goalNode]; } } if(self->bs.currentNode == INVALID || self->bs.nextNode == INVALID) return qfalse; // set bot's movement vector VectorSubtract(nodes[self->bs.nextNode].origin, self->client->ps.origin, self->bs.moveVector); return qtrue; }
/////////////////////////////////////////////////////////////////////// // Evaluate the best long range goal and send the bot on // its way. This is a good time waster, so use it sparingly. // Do not call it for every think cycle. /////////////////////////////////////////////////////////////////////// void ACEAI_PickLongRangeGoal(edict_t *self) { int i; int node; float weight,best_weight=0.0; int current_node,goal_node; edict_t *goal_ent; float cost; // look for a target current_node = ACEND_FindClosestReachableNode(self,NODE_DENSITY,NODE_ALL); self->current_node = current_node; if(current_node == -1) { self->state = STATE_WANDER; self->wander_timeout = level.time + 1.0; self->goal_node = -1; return; } /////////////////////////////////////////////////////// // Items /////////////////////////////////////////////////////// for (i=0; i<num_items; i++) { // ignore items that are not there. if (!item_table[i].ent || !item_table[i].ent->inuse || item_table[i].ent->solid == SOLID_NOT) continue; cost = ACEND_FindCost(current_node,item_table[i].node); if (cost == INVALID || cost < 2) // ignore invalid and very short hops continue; weight = ACEIT_ItemNeed(self, item_table[i].item); // If I am on team one and I have the flag for the other team....return it // Knightmare- rewrote for 3Team CTF //if (ctf->value && (item_table[i].item == ITEMLIST_FLAG2 || item_table[i].item == ITEMLIST_FLAG1) && // (self->client->resp.ctf_team == CTF_TEAM1 && self->client->pers.inventory[ITEMLIST_FLAG2] || // self->client->resp.ctf_team == CTF_TEAM2 && self->client->pers.inventory[ITEMLIST_FLAG1])) if (ctf->value && ( (item_table[i].item == ITEMLIST_FLAG1 && self->client->resp.ctf_team == CTF_TEAM1 && (self->client->pers.inventory[ITEMLIST_FLAG2] || self->client->pers.inventory[ITEMLIST_FLAG3]) ) || (item_table[i].item == ITEMLIST_FLAG2 && self->client->resp.ctf_team == CTF_TEAM2 && (self->client->pers.inventory[ITEMLIST_FLAG1] || self->client->pers.inventory[ITEMLIST_FLAG3]) ) || (item_table[i].item == ITEMLIST_FLAG3 && self->client->resp.ctf_team == CTF_TEAM3 && (self->client->pers.inventory[ITEMLIST_FLAG1] || self->client->pers.inventory[ITEMLIST_FLAG2]) ) )) weight = 10.0; // Knightmare- in 3Team CTF mode, make double captures a lower priority than // getting back to base with the flag we already have. if (ttctf->value && ( (self->client->resp.ctf_team == CTF_TEAM1 && (self->client->pers.inventory[ITEMLIST_FLAG2] || self->client->pers.inventory[ITEMLIST_FLAG3]) && (item_table[i].item == ITEMLIST_FLAG2 || item_table[i].item == ITEMLIST_FLAG3) ) || (self->client->resp.ctf_team == CTF_TEAM2 && (self->client->pers.inventory[ITEMLIST_FLAG1] || self->client->pers.inventory[ITEMLIST_FLAG3]) && (item_table[i].item == ITEMLIST_FLAG1 || item_table[i].item == ITEMLIST_FLAG3) ) || (self->client->resp.ctf_team == CTF_TEAM3 && (self->client->pers.inventory[ITEMLIST_FLAG1] || self->client->pers.inventory[ITEMLIST_FLAG2]) && (item_table[i].item == ITEMLIST_FLAG1 || item_table[i].item == ITEMLIST_FLAG2) ) )) weight = 6.5; weight *= random(); // Allow random variations weight /= cost; // Check against cost of getting there if (weight > best_weight) { best_weight = weight; goal_node = item_table[i].node; goal_ent = item_table[i].ent; } } /////////////////////////////////////////////////////// // Players /////////////////////////////////////////////////////// // This should be its own function and is for now just // finds a player to set as the goal. for(i=0;i<num_players;i++) { if(players[i] == self) continue; node = ACEND_FindClosestReachableNode(players[i],NODE_DENSITY,NODE_ALL); cost = ACEND_FindCost(current_node, node); if(cost == INVALID || cost < 3) // ignore invalid and very short hops continue; // Player carrying the flag? if(ctf->value && (players[i]->client->pers.inventory[ITEMLIST_FLAG2] || players[i]->client->pers.inventory[ITEMLIST_FLAG1])) weight = 2.0; else weight = 0.3; weight *= random(); // Allow random variations weight /= cost; // Check against cost of getting there if(weight > best_weight) { best_weight = weight; goal_node = node; goal_ent = players[i]; } } // If do not find a goal, go wandering.... if(best_weight == 0.0 || goal_node == INVALID) { self->goal_node = INVALID; self->state = STATE_WANDER; self->wander_timeout = level.time + 1.0; if(debug_mode) debug_printf("%s did not find a LR goal, wandering.\n",self->client->pers.netname); return; // no path? } // OK, everything valid, let's start moving to our goal. self->state = STATE_MOVE; self->tries = 0; // Reset the count of how many times we tried this goal if(goal_ent != NULL && debug_mode) debug_printf("%s selected a %s at node %d for LR goal.\n",self->client->pers.netname, goal_ent->classname, goal_node); ACEND_SetGoal(self,goal_node); }