/////////////////////////////////////////////////////////////////////// // Check for adding ladder nodes /////////////////////////////////////////////////////////////////////// qboolean ACEND_CheckForLadder(edict_t *self) { int closest_node; // If there is a ladder and we are moving up, see if we should add a ladder node if (gi.pointcontents(self->s.origin) & CONTENTS_LADDER && self->velocity[2] > 0) { //debug_printf("contents: %x\n",tr.contents); closest_node = ACEND_FindClosestReachableNode(self,NODE_DENSITY,NODE_LADDER); if(closest_node == -1) { closest_node = ACEND_AddNode(self,NODE_LADDER); // Now add link ACEND_UpdateNodeEdge(self->last_node,closest_node); // Set current to last self->last_node = closest_node; } else { ACEND_UpdateNodeEdge(self->last_node,closest_node); self->last_node = closest_node; // set visited to last } return true; } return false; }
/////////////////////////////////////////////////////////////////////// // Capture when the grappling hook has been fired for mapping purposes. /////////////////////////////////////////////////////////////////////// void ACEND_GrapFired(edict_t *self) { int closest_node; if(!self->owner) return; // should not be here // Check to see if the grapple is in pull mode if(self->owner->client->ctf_grapplestate == CTF_GRAPPLE_STATE_PULL) { // Look for the closest node of type grapple closest_node = ACEND_FindClosestReachableNode(self,NODE_DENSITY,NODE_GRAPPLE); if(closest_node == -1 ) // we need to drop a node { closest_node = ACEND_AddNode(self,NODE_GRAPPLE); // Add an edge ACEND_UpdateNodeEdge(self->owner->last_node,closest_node); self->owner->last_node = closest_node; } else self->owner->last_node = closest_node; // zero out so other nodes will not be linked } }
/////////////////////////////////////////////////////////////////////// // Special command processor /////////////////////////////////////////////////////////////////////// qboolean ACECM_Commands(edict_t *ent) { char *cmd; int node; cmd = gi.argv(0); if ((Q_strcasecmp(cmd, "addnode") == 0) && debug_mode) { ent->last_node = ACEND_AddNode(ent, atoi(gi.argv(1))); } else if ((Q_strcasecmp(cmd, "removelink") == 0) && debug_mode) { ACEND_RemoveNodeEdge(ent, atoi(gi.argv(1)), atoi(gi.argv(2))); } else if ((Q_strcasecmp(cmd, "addlink") == 0) && debug_mode) { ACEND_UpdateNodeEdge(atoi(gi.argv(1)), atoi(gi.argv(2))); } else if ((Q_strcasecmp(cmd, "showpath") == 0) && debug_mode) { ACEND_ShowPath(ent, atoi(gi.argv(1))); } else if ((Q_strcasecmp(cmd, "findnode") == 0) && debug_mode) { node = ACEND_FindClosestReachableNode(ent, NODE_DENSITY, NODE_ALL); safe_bprintf(PRINT_MEDIUM, "node: %d type: %d x: %f y: %f z %f\n", node, nodes[node].type, nodes[node].origin[0], nodes[node].origin[1], nodes[node].origin[2]); } else if ((Q_strcasecmp(cmd, "movenode") == 0) && debug_mode) { node = atoi(gi.argv(1)); nodes[node].origin[0] = atof(gi.argv(2)); nodes[node].origin[1] = atof(gi.argv(3)); nodes[node].origin[2] = atof(gi.argv(4)); safe_bprintf(PRINT_MEDIUM, "node: %d moved to x: %f y: %f z %f\n", node, nodes[node].origin[0], nodes[node].origin[1], nodes[node].origin[2]); } else { return false; } return true; }
/////////////////////////////////////////////////////////////////////// // Add a node of type ? /////////////////////////////////////////////////////////////////////// int ACEND_AddNode(edict_t *self, int type) { vec3_t v1,v2; // Block if we exceed maximum if (numnodes + 1 > MAX_NODES) return false; // Set location VectorCopy(self->s.origin,nodes[numnodes].origin); // Set type nodes[numnodes].type = type; ///////////////////////////////////////////////////// // ITEMS // Move the z location up just a bit. if(type == NODE_ITEM) { nodes[numnodes].origin[2] += 16; numitemnodes++; } // Teleporters if(type == NODE_TELEPORTER) { // Up 32 nodes[numnodes].origin[2] += 32; } if(type == NODE_LADDER) { nodes[numnodes].type = NODE_LADDER; if(debug_mode) { debug_printf("Node added %d type: Ladder\n",numnodes); ACEND_ShowNode(numnodes); } numnodes++; return numnodes-1; // return the node added } // For platforms drop two nodes one at top, one at bottom if(type == NODE_PLATFORM) { VectorCopy(self->maxs,v1); VectorCopy(self->mins,v2); // To get the center nodes[numnodes].origin[0] = (v1[0] - v2[0]) / 2 + v2[0]; nodes[numnodes].origin[1] = (v1[1] - v2[1]) / 2 + v2[1]; nodes[numnodes].origin[2] = self->maxs[2]; if(debug_mode) ACEND_ShowNode(numnodes); numnodes++; nodes[numnodes].origin[0] = nodes[numnodes-1].origin[0]; nodes[numnodes].origin[1] = nodes[numnodes-1].origin[1]; nodes[numnodes].origin[2] = self->mins[2]+64; nodes[numnodes].type = NODE_PLATFORM; // Add a link ACEND_UpdateNodeEdge(numnodes,numnodes-1); if(debug_mode) { debug_printf("Node added %d type: Platform\n",numnodes); ACEND_ShowNode(numnodes); } numnodes++; return numnodes -1; } if(debug_mode) { if(nodes[numnodes].type == NODE_MOVE) debug_printf("Node added %d type: Move\n",numnodes); else if(nodes[numnodes].type == NODE_TELEPORTER) debug_printf("Node added %d type: Teleporter\n",numnodes); else if(nodes[numnodes].type == NODE_ITEM) debug_printf("Node added %d type: Item\n",numnodes); else if(nodes[numnodes].type == NODE_WATER) debug_printf("Node added %d type: Water\n",numnodes); else if(nodes[numnodes].type == NODE_GRAPPLE) debug_printf("Node added %d type: Grapple\n",numnodes); ACEND_ShowNode(numnodes); } numnodes++; return numnodes-1; // return the node added }
/////////////////////////////////////////////////////////////////////// // This routine is called to hook in the pathing code and sets // the current node if valid. /////////////////////////////////////////////////////////////////////// void ACEND_PathMap(edict_t *self) { int closest_node; static float last_update=0; // start off low vec3_t v; if(level.time < last_update) return; last_update = level.time + 0.15; // slow down updates a bit // Special node drawing code for debugging if(show_path_to != -1) ACEND_DrawPath(); //////////////////////////////////////////////////////// // Special check for ladder nodes /////////////////////////////////////////////////////// if(ACEND_CheckForLadder(self)) // check for ladder nodes return; // Not on ground, and not in the water, so bail if(!self->groundentity && !self->waterlevel) return; //////////////////////////////////////////////////////// // Lava/Slime //////////////////////////////////////////////////////// VectorCopy(self->s.origin,v); v[2] -= 18; if(gi.pointcontents(v) & (CONTENTS_LAVA|CONTENTS_SLIME)) return; // no nodes in slime //////////////////////////////////////////////////////// // Jumping /////////////////////////////////////////////////////// if(self->is_jumping) { // See if there is a closeby jump landing node (prevent adding too many) closest_node = ACEND_FindClosestReachableNode(self, 64, NODE_JUMP); if(closest_node == INVALID) closest_node = ACEND_AddNode(self,NODE_JUMP); // Now add link if(self->last_node != -1) ACEND_UpdateNodeEdge(self->last_node, closest_node); self->is_jumping = false; return; } //////////////////////////////////////////////////////////// // Grapple // Do not add nodes during grapple, added elsewhere manually //////////////////////////////////////////////////////////// if(ctf->value && self->client->ctf_grapplestate == CTF_GRAPPLE_STATE_PULL) return; // Iterate through all nodes to make sure far enough apart closest_node = ACEND_FindClosestReachableNode(self, NODE_DENSITY, NODE_ALL); //////////////////////////////////////////////////////// // Special Check for Platforms //////////////////////////////////////////////////////// if(self->groundentity && self->groundentity->use == Use_Plat) { if(closest_node == INVALID) return; // Do not want to do anything here. // Here we want to add links if(closest_node != self->last_node && self->last_node != INVALID) ACEND_UpdateNodeEdge(self->last_node,closest_node); self->last_node = closest_node; // set visited to last return; } //////////////////////////////////////////////////////// // Add Nodes as needed //////////////////////////////////////////////////////// if(closest_node == INVALID) { // Add nodes in the water as needed if(self->waterlevel) closest_node = ACEND_AddNode(self,NODE_WATER); else closest_node = ACEND_AddNode(self,NODE_MOVE); // Now add link if(self->last_node != -1) ACEND_UpdateNodeEdge(self->last_node, closest_node); } else if(closest_node != self->last_node && self->last_node != INVALID) ACEND_UpdateNodeEdge(self->last_node,closest_node); self->last_node = closest_node; // set visited to last }
// This routine is called to hook in the pathing code and sets // the current node if valid. void ACEND_PathMap(gentity_t * self) { int closestNode; static float lastUpdate = 0; // start off low vec3_t v; //qboolean isJumping; //int i; #if 0 if(level.time < lastUpdate) return; #endif lastUpdate = level.time + 150; // slow down updates a bit #if 0 if(self->r.svFlags & SVF_BOT) return; #endif // don't add links when you went into a trap if(self->health <= 0) return; #if 1 if(self->s.groundEntityNum == ENTITYNUM_NONE && !(self->r.svFlags & SVF_BOT)) { #if 0 isJumping = qfalse; for(i = 0; i < self->client->ps.eventSequence; i++) { if(self->client->ps.events[i] == EV_JUMP) isJumping = qtrue; } if(isJumping) #else if((self->client->ps.pm_flags & PMF_JUMP_HELD)) #endif { if(ace_debug.integer) trap_SendServerCommand(-1, va("print \"%s: jumping\n\"", self->client->pers.netname)); // see if there is a closeby jump landing node (prevent adding too many) closestNode = ACEND_FindClosestReachableNode(self, 64, NODE_JUMP); if(closestNode == INVALID) closestNode = ACEND_AddNode(self, NODE_JUMP); // now add link if(self->bs.lastNode != INVALID) ACEND_UpdateNodeEdge(self->bs.lastNode, closestNode); self->bs.isJumping = qfalse; return; } } #endif // not on ground, and not in the water, so bail if(self->s.groundEntityNum == ENTITYNUM_NONE) { /* if(self->bs.lastNode != INVALID) { // we might have been pushed by a jump pad if(nodes[self->bs.lastNode].type != NODE_JUMPPAD) return; } else if(!self->waterlevel) { return; } */ } // lava / slime VectorCopy(self->client->ps.origin, v); v[2] -= 18; if(trap_PointContents(self->client->ps.origin, -1) & (CONTENTS_LAVA | CONTENTS_SLIME)) return; // no nodes in slime // Grapple // Do not add nodes during grapple, added elsewhere manually /* if(ctf->value && self->client->ctf_grapplestate == CTF_GRAPPLE_STATE_PULL) return; */ // iterate through all nodes to make sure far enough apart closestNode = ACEND_FindClosestReachableNode(self, NODE_DENSITY, NODE_ALL); // Special Check for Platforms /* FIXME if(self->groundentity && self->groundentity->use == Use_Plat) { if(closestNode == INVALID) return; // Do not want to do anything here. // Here we want to add links if(closestNode != self->lastNode && self->lastNode != INVALID) ACEND_UpdateNodeEdge(self->lastNode, closestNode); self->lastNode = closestNode; // set visited to last return; } */ if(closestNode != INVALID) { // add automatically some links between nodes if(closestNode != self->bs.lastNode && self->bs.lastNode != INVALID) { ACEND_UpdateNodeEdge(self->bs.lastNode, closestNode); if(ace_showLinks.integer) ACEND_DrawPath(self->bs.lastNode, closestNode); } self->bs.lastNode = closestNode; // set visited to last } #if 1 else if(closestNode == INVALID && self->s.groundEntityNum != ENTITYNUM_NONE) { // add nodes in the water as needed if(self->waterlevel) closestNode = ACEND_AddNode(self, NODE_WATER); else closestNode = ACEND_AddNode(self, NODE_MOVE); // now add link if(self->bs.lastNode != INVALID) { ACEND_UpdateNodeEdge(self->bs.lastNode, closestNode); if(ace_showLinks.integer) ACEND_DrawPath(self->bs.lastNode, closestNode); } self->bs.lastNode = closestNode; // set visited to last } #endif }